def test_contruct_array_lincomb(): """Test BaseOneIndex.construct_array_lincomb.""" contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) sph_transform = generate_transformation( 1, contractions.angmom_components_cart, contractions.angmom_components_sph, "left" ) orb_transform = np.random.rand(3, 3) Test = disable_abstract( # noqa: N806 BaseOneIndex, dict_overwrite={ "construct_array_contraction": lambda self, cont, a=2: np.arange( 9, dtype=float ).reshape(1, 3, 3) * a }, ) test = Test([contractions]) assert np.allclose( test.construct_array_lincomb(orb_transform, "cartesian"), orb_transform.dot(np.arange(9).reshape(3, 3)) * 2, ) assert np.allclose( test.construct_array_lincomb(orb_transform, "spherical"), orb_transform.dot(sph_transform).dot(np.arange(9).reshape(3, 3)) * 2, ) assert np.allclose( test.construct_array_lincomb(orb_transform, "spherical", a=3), orb_transform.dot(sph_transform).dot(np.arange(9).reshape(3, 3)) * 3, ) with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform, "bad") with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform, "spherical", bad_keyword=3) orb_transform = np.random.rand(3, 6) test = Test([contractions, contractions]) assert np.allclose( test.construct_array_lincomb(orb_transform, "spherical"), orb_transform.dot( np.vstack([sph_transform.dot(np.arange(9, dtype=float).reshape(3, 3)) * 2] * 2) ), ) assert np.allclose( test.construct_array_lincomb(orb_transform, ["spherical", "cartesian"]), orb_transform.dot( np.vstack( [ sph_transform.dot(np.arange(9, dtype=float).reshape(3, 3)) * 2, np.arange(9, dtype=float).reshape(3, 3) * 2, ] ) ), )
def construct_array_spherical(self, **kwargs): """Return the array associated with contracted spherical Gaussians (atomic orbitals). Parameters ---------- kwargs : dict Other keyword arguments that will be used to construct the array. These keyword arguments are passed entirely to `construct_array_contraction`. See `construct_array_contraction` for details on the keyword arguments. Returns ------- array : np.ndarray(K_sph, ...) Array associated with the atomic orbitals associated with the given set of contracted Cartesian Gaussians. Dimension 0 is associated with the contracted spherical Gaussian. `K_sph` is the total number of Cartesian contractions within the instance. """ matrices_spherical = [] for cont in self.contractions: # get transformation from cartesian to spherical (applied to left) transform = generate_transformation(cont.angmom, cont.angmom_components_cart, cont.angmom_components_sph, "left") # evaluate the function at the given points matrix_contraction = self.construct_array_contraction( cont, **kwargs) # normalize contractions matrix_contraction *= cont.norm_cont.reshape( *matrix_contraction.shape[:2], *[1 for _ in matrix_contraction.shape[2:]]) # transform # ASSUME array always has shape (M, L, ...) matrix_contraction = np.tensordot(transform, matrix_contraction, (1, 1)) matrix_contraction = np.concatenate(np.swapaxes( matrix_contraction, 0, 1), axis=0) # store matrices_spherical.append(matrix_contraction) return np.concatenate(matrices_spherical, axis=0)
def construct_array_mix(self, coord_types, **kwargs): """Return the array associated with set of Gaussians of the given coordinate systems. Parameters ---------- coord_types : list/tuple of str Types of the coordinate system for each GeneralizedContractionShell. Each entry must be one of "cartesian" or "spherical". kwargs : dict Other keyword arguments that will be used to construct the array. Returns ------- array : np.ndarray(K_cont, K_cont, ...) Array associated with the atomic orbitals associated with the given set of contracted Cartesian Gaussians. First and second indices of the array are associated with two contractions in the given coordinate system. `K_cont` is the total number of contractions within the instance. Raises ------ TypeError If `coord_types` is not a list/tuple. ValueError If `coord_types` has an entry that is not "cartesian" or "spherical". If `coord_types` has different number of entries as the number of GeneralizedContractionShell (`contractions`) in instance. """ if not isinstance(coord_types, (list, tuple)): raise TypeError("`coord_types` must be a list or a tuple.") if not all(i in ["cartesian", "spherical"] for i in coord_types): raise ValueError( "Each entry of `coord_types` must be one of 'cartesian' or 'spherical'." ) if len(coord_types) != len(self.contractions): raise ValueError( "`coord_types` must have the same number of entries as the number of " "GeneralizedContractionShell in the instance.") triu_blocks = [] for i, (cont_one, type_one) in enumerate(zip(self.contractions, coord_types)): # get transformation from cartesian to spherical (applied to left) transform_one = generate_transformation( cont_one.angmom, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left", ) for cont_two, type_two in zip(self.contractions[i:], coord_types[i:]): transform_two = generate_transformation( cont_two.angmom, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left", ) # evaluate block = self.construct_array_contraction( cont_one, cont_two, **kwargs) # normalize contractions block *= cont_one.norm_cont.reshape( *block.shape[:2], *[1 for i in block.shape[2:]]) block *= cont_two.norm_cont.reshape( 1, 1, *block.shape[2:4], *[1 for i in block.shape[4:]]) # assume array has shape (M_1, L_1, M_2, L_2, ...) if type_one == "spherical": # transform block = np.tensordot(transform_one, block, (1, 1)) block = np.swapaxes(block, 0, 1) block = np.concatenate(block, axis=0) # array now has shape (M_1 L_1, M_2, L_2, ...) if type_two == "spherical": block = np.tensordot(transform_two, block, (1, 2)) block = np.swapaxes(np.swapaxes(block, 0, 1), 0, 2) else: block = np.swapaxes(np.swapaxes(block, 0, 1), 1, 2) block = np.concatenate(block, axis=0) block = np.swapaxes(block, 0, 1) # array now has shape (M_1 L_1, M_2 L_2, ...) # store triu_blocks.append(block) # use numpy triu and tril indices to create blocks num_blocks_side = len(self.contractions) all_blocks = np.zeros((num_blocks_side, num_blocks_side), dtype=object) all_blocks[np.triu_indices(num_blocks_side)] = triu_blocks all_blocks[np.tril_indices(num_blocks_side)] = [ np.swapaxes(block, 0, 1) for block in all_blocks.T[np.tril_indices(num_blocks_side)] ] # concatenate return np.concatenate( [np.concatenate(row_blocks, axis=1) for row_blocks in all_blocks], axis=0)
def construct_array_spherical(self, **kwargs): """Return the array associated with two contracted spherical Gaussians (atomic orbitals). Parameters ---------- kwargs : dict Other keyword arguments that will be used to construct the array. These keyword arguments are passed entirely to `construct_array_contraction`. See `construct_array_contraction` for details on the keyword arguments. Returns ------- array : np.ndarray(K_sph, K_sph, ...) Array associated with the atomic orbitals associated with the given set(s) of contracted Cartesian Gaussians. First and second indices of the array are associated with two contracted spherical Gaussians (atomic orbitals). `K_sph` is the total number of spherical contractions within the instance. Notes ----- The blocks along the diagonal, i.e. blocks where the first two axes belong to the same set of contractions, are transposed in the process of constructing the whole array. It is assumed that the array returned from `construct_array_contraction` is symmetric with respect to the swapping of the first and second axes. """ triu_blocks = [] for i, cont_one in enumerate(self.contractions): # get transformation from cartesian to spherical (applied to left) transform_one = generate_transformation( cont_one.angmom, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left", ) for cont_two in self.contractions[i:]: transform_two = generate_transformation( cont_two.angmom, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left", ) # evaluate block_sph = self.construct_array_contraction( cont_one, cont_two, **kwargs) # normalize contractions block_sph *= cont_one.norm_cont.reshape( *block_sph.shape[:2], *[1 for i in block_sph.shape[2:]]) block_sph *= cont_two.norm_cont.reshape( 1, 1, *block_sph.shape[2:4], *[1 for i in block_sph.shape[4:]]) # assume array has shape (M_1, L_1, M_2, L_2, ...) # transform block_sph = np.tensordot(transform_one, block_sph, (1, 1)) block_sph = np.concatenate(np.swapaxes(block_sph, 0, 1), axis=0) # array now has shape (M_1 L_1, M_2, L_2, ...) block_sph = np.tensordot(transform_two, block_sph, (1, 2)) block_sph = np.swapaxes(np.swapaxes(block_sph, 0, 1), 0, 2) block_sph = np.concatenate(block_sph, axis=0) block_sph = np.swapaxes(block_sph, 0, 1) # array now has shape (M_1 L_1, M_2 L_2, ...) # store triu_blocks.append(block_sph) # use numpy triu and tril indices to create blocks num_blocks_side = len(self.contractions) all_blocks = np.zeros((num_blocks_side, num_blocks_side), dtype=object) all_blocks[np.triu_indices(num_blocks_side)] = triu_blocks all_blocks[np.tril_indices(num_blocks_side)] = [ np.swapaxes(block, 0, 1) for block in all_blocks.T[np.tril_indices(num_blocks_side)] ] # concatenate return np.concatenate( [np.concatenate(row_blocks, axis=1) for row_blocks in all_blocks], axis=0)
def construct_array_mix(self, coord_types_one, coord_types_two, **kwargs): """Return the array associated with set of Gaussians of the given coordinate systems. Parameters ---------- coord_types_one : list/tuple of str Types of the coordinate system for GeneralizedContractionShell associated with the first index of the array. Each entry must be one of "cartesian" or "spherical". coord_types_two : list/tuple of str Types of the coordinate system for GeneralizedContractionShell associated with the second index of the array. Each entry must be one of "cartesian" or "spherical". kwargs : dict Other keyword arguments that will be used to construct the array. Returns ------- array : np.ndarray(K_cont, K_cont, ...) Array associated with the atomic orbitals associated with the given set of contracted Cartesian Gaussians. First and second indices of the array are associated with two contractions in the given coordinate system. `K_cont` is the total number of contractions within the instance. Raises ------ TypeError If `coord_types_one` is not a list/tuple. If `coord_types_two` is not a list/tuple. ValueError If `coord_types_one` has an entry that is not "cartesian" or "spherical". If `coord_types_one` has different number of entries as the number of GeneralizedContractionShell (`contractions`) in instance. If `coord_types_two` has an entry that is not "cartesian" or "spherical". If `coord_types_two` has different number of entries as the number of GeneralizedContractionShell (`contractions`) in instance. """ if not isinstance(coord_types_one, (list, tuple)): raise TypeError("`coord_types_one` must be a list or a tuple.") if not isinstance(coord_types_two, (list, tuple)): raise TypeError("`coord_types_two` must be a list or a tuple.") if not all(i in ["cartesian", "spherical"] for i in coord_types_one): raise ValueError( "Each entry of `coord_types_one` must be one of 'cartesian' or 'spherical'." ) if not all(i in ["cartesian", "spherical"] for i in coord_types_two): raise ValueError( "Each entry of `coord_types_two` must be two of 'cartesian' or 'spherical'." ) if len(coord_types_one) != len(self.contractions_one): raise ValueError( "`coord_types_one` must have the same number of entries as the number of " "GeneralizedContractionShell in the instance.") if len(coord_types_two) != len(self.contractions_two): raise ValueError( "`coord_types_two` must have the same number of entries as the number of " "GeneralizedContractionShell in the instance.") matrices_spherical = [] for cont_one, type_one in zip(self.contractions_one, coord_types_one): # get transformation from cartesian to spherical for the first index (applied to left) transform_one = generate_transformation( cont_one.angmom, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left", ) matrices_spherical_cols = [] for cont_two, type_two in zip(self.contractions_two, coord_types_two): # get transformation from cartesian to spherical for the first index (applied to # left) transform_two = generate_transformation( cont_two.angmom, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left", ) # evaluate block = self.construct_array_contraction( cont_one, cont_two, **kwargs) # normalize contractions block *= cont_one.norm_cont.reshape( *block.shape[:2], *[1 for i in block.shape[2:]]) block *= cont_two.norm_cont.reshape( 1, 1, *block.shape[2:4], *[1 for i in block.shape[4:]]) # transform # assume array always has shape (M_1, L_1, M_2, L_2, ...) if type_one == "spherical": block = np.tensordot(transform_one, block, (1, 1)) block = np.swapaxes(block, 0, 1) block = np.concatenate(block, axis=0) # array now has shape (M_1 L_1, M_2, L_2, ...) if type_two == "spherical": block = np.tensordot(transform_two, block, (1, 2)) block = np.swapaxes(np.swapaxes(block, 0, 1), 0, 2) else: block = np.swapaxes(np.swapaxes(block, 0, 1), 1, 2) block = np.concatenate(block, axis=0) block = np.swapaxes(block, 0, 1) # array now has shape (M_1 L_1, M_2 L_2, ...) # store matrices_spherical_cols.append(block) matrices_spherical.append( np.concatenate(matrices_spherical_cols, axis=1)) return np.concatenate(matrices_spherical, axis=0)
def construct_array_spherical(self, **kwargs): """Return the array associated with two contracted spherical Gaussians (atomic orbitals). Parameters ---------- kwargs : dict Other keyword arguments that will be used to construct the array. These keyword arguments are passed entirely to `construct_array_contraction`. See `construct_array_contraction` for details on the keyword arguments. Returns ------- array : np.ndarray(K_sph_1, K_sph_2, ...) Array associated with the atomic orbitals associated with the given set(s) of contracted Cartesian Gaussians. First index corresponds to the spherical contraction within the `contractions_one`. `K_sph_1` is the total number of spherical contractions within the `contractions_one`. Second index corresponds to the spherical contraction within the `contractions_two`. `K_sph_2` is the total number of spherical contractions within the `contractions_two`. """ matrices_spherical = [] for cont_one in self.contractions_one: # get transformation from cartesian to spherical for the first index (applied to left) transform_one = generate_transformation( cont_one.angmom, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left", ) matrices_spherical_cols = [] for cont_two in self.contractions_two: # get transformation from cartesian to spherical for the first index (applied to # left) transform_two = generate_transformation( cont_two.angmom, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left", ) # evaluate matrix_contraction = self.construct_array_contraction( cont_one, cont_two, **kwargs) # normalize contractions matrix_contraction *= cont_one.norm_cont.reshape( *matrix_contraction.shape[:2], *[1 for i in matrix_contraction.shape[2:]]) matrix_contraction *= cont_two.norm_cont.reshape( 1, 1, *matrix_contraction.shape[2:4], *[1 for i in matrix_contraction.shape[4:]]) # transform # assume array always has shape (M_1, L_1, M_2, L_2, ...) matrix_contraction = np.tensordot(transform_one, matrix_contraction, (1, 1)) matrix_contraction = np.concatenate(np.swapaxes( matrix_contraction, 0, 1), axis=0) # array now has shape (M_1 L_1, M_2, L_2, ...) matrix_contraction = np.tensordot(transform_two, matrix_contraction, (1, 2)) matrix_contraction = np.swapaxes( np.swapaxes(matrix_contraction, 0, 1), 0, 2) matrix_contraction = np.concatenate(matrix_contraction, axis=0) matrix_contraction = np.swapaxes(matrix_contraction, 0, 1) # array now has shape (M_1 L_1, M_2 L_2, ...) # store matrices_spherical_cols.append(matrix_contraction) matrices_spherical.append( np.concatenate(matrices_spherical_cols, axis=1)) return np.concatenate(matrices_spherical, axis=0)
def test_contruct_array_spherical(): """Test BaseOneIndex.construct_array_spherical.""" contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) transform = generate_transformation( 1, contractions.angmom_components_cart, contractions.angmom_components_sph, "left" ) Test = disable_abstract( # noqa: N806 BaseOneIndex, dict_overwrite={ "construct_array_contraction": lambda self, cont, a=2: np.arange( 9, dtype=float ).reshape(1, 3, 3) * a }, ) test = Test([contractions]) assert np.allclose( test.construct_array_spherical(), transform.dot(np.arange(9).reshape(3, 3)) * 2 ) assert np.allclose( test.construct_array_spherical(a=3), transform.dot(np.arange(9).reshape(3, 3)) * 3 ) with pytest.raises(TypeError): test.construct_array_spherical(bad_keyword=3) test = Test([contractions, contractions]) assert np.allclose( test.construct_array_spherical(), np.vstack([transform.dot(np.arange(9).reshape(3, 3)) * 2] * 2), ) contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones((1, 2)), np.ones(1)) Test = disable_abstract( # noqa: N806 BaseOneIndex, dict_overwrite={ "construct_array_contraction": ( lambda self, cont, a=2: np.arange(18, dtype=float).reshape(2, 3, 3) * a ) }, ) test = Test([contractions]) assert np.allclose( test.construct_array_spherical(), np.vstack( [ transform.dot(np.arange(9).reshape(3, 3)), transform.dot(np.arange(9, 18).reshape(3, 3)), ] ) * 2, ) assert np.allclose( test.construct_array_spherical(a=3), np.vstack( [ transform.dot(np.arange(9).reshape(3, 3)), transform.dot(np.arange(9, 18).reshape(3, 3)), ] ) * 3, ) test = Test([contractions, contractions]) assert np.allclose( test.construct_array_spherical(), np.vstack( [ transform.dot(np.arange(9).reshape(3, 3)), transform.dot(np.arange(9, 18).reshape(3, 3)), ] * 2 ) * 2, )
def test_contruct_array_spherical(): """Test BaseTwoIndexAsymmetric.construct_array_spherical.""" contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) transform = generate_transformation(1, contractions.angmom_components_cart, contractions.angmom_components_sph, "left") Test = disable_abstract( # noqa: N806 BaseTwoIndexAsymmetric, dict_overwrite={ "construct_array_contraction": ( lambda self, cont_one, cont_two, a=2: np.arange(9, dtype=float).reshape(1, 3, 1, 3) * a ) }, ) contractions.norm_cont = np.ones((1, 3)) test = Test([contractions], [contractions]) assert np.allclose( test.construct_array_spherical(), transform.dot(np.arange(9).reshape(3, 3)).dot(transform.T) * 2, ) assert np.allclose( test.construct_array_spherical(a=3), transform.dot(np.arange(9).reshape(3, 3)).dot(transform.T) * 3, ) with pytest.raises(TypeError): test.construct_array_spherical(bad_keyword=3) test = Test([contractions, contractions], [contractions]) assert np.allclose( test.construct_array_spherical(), np.vstack( [transform.dot(np.arange(9).reshape(3, 3).dot(transform.T)) * 2] * 2), ) matrix = np.arange(36, dtype=float).reshape(2, 3, 2, 3) Test = disable_abstract( # noqa: N806 BaseTwoIndexAsymmetric, dict_overwrite={ "construct_array_contraction": lambda self, cont_one, cont_two, a=2: matrix * a }, ) contractions.norm_cont = np.ones((2, 3)) test = Test([contractions], [contractions]) assert np.allclose( test.construct_array_spherical(), np.vstack([ np.hstack([ transform.dot(matrix[0, :, 0, :]).dot(transform.T), transform.dot(matrix[0, :, 1, :]).dot(transform.T), ]), np.hstack([ transform.dot(matrix[1, :, 0, :]).dot(transform.T), transform.dot(matrix[1, :, 1, :]).dot(transform.T), ]), ]) * 2, ) test = Test([contractions, contractions], [contractions]) assert np.allclose( test.construct_array_spherical(), np.vstack([ np.hstack([ transform.dot(matrix[0, :, 0, :]).dot(transform.T), transform.dot(matrix[0, :, 1, :]).dot(transform.T), ]), np.hstack([ transform.dot(matrix[1, :, 0, :]).dot(transform.T), transform.dot(matrix[1, :, 1, :]).dot(transform.T), ]), ] * 2) * 2, )
def construct_array_spherical(self, **kwargs): """Return the array associated with four contracted spherical Gaussians (atomic orbitals). Parameters ---------- kwargs : dict Other keyword arguments that will be used to construct the array. These keyword arguments are passed entirely to `construct_array_contraction`. See `construct_array_contraction` for details on the keyword arguments. Returns ------- array : np.ndarray(K_sph, K_sph, K_sph, K_sph, ...) Array associated with the atomic orbitals associated with the given set(s) of contracted Cartesian Gaussians. Dimensions 0, 1, 2 and 3 of the array are associated with four contracted spherical Gaussians (atomic orbitals). `K_sph` is the total number of spherical contractions within the instance. Notes ----- The blocks along the diagonal, i.e. blocks where the first two axes belong to the same set of contractions, are transposed in the process of constructing the whole array. It is assumed that the array returned from `construct_array_contraction` is symmetric with respect to the swapping of the axes 0 and 1. """ # pylint: disable=C0103,R0914 all_blocks = np.zeros((len(self.contractions),) * 4, dtype=object) # NOTE: we get list of unique pairs of (index, contraction_instance) to avoid double # counting the ij and kl. e.g. 0, 1, 0, 0 and 0, 0, 0, 1 will both be present with the # previous approach pair_i_cont = list(it.combinations_with_replacement(enumerate(self.contractions), 2)) for pair_ind, ((i, cont_one), (j, cont_two)) in enumerate(pair_i_cont): transform_one = generate_transformation( cont_one.angmom, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left", ) transform_two = generate_transformation( cont_two.angmom, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left", ) for (k, cont_three), (l, cont_four) in pair_i_cont[pair_ind:]: transform_three = generate_transformation( cont_three.angmom, cont_three.angmom_components_cart, cont_three.angmom_components_sph, "left", ) transform_four = generate_transformation( cont_four.angmom, cont_four.angmom_components_cart, cont_four.angmom_components_sph, "left", ) block = self.construct_array_contraction( cont_one, cont_two, cont_three, cont_four, **kwargs ) # normalize contractions block *= cont_one.norm_cont.reshape(*block.shape[:2], *[1 for _ in block.shape[2:]]) block *= cont_two.norm_cont.reshape( 1, 1, *block.shape[2:4], *[1 for _ in block.shape[4:]] ) block *= cont_three.norm_cont.reshape( 1, 1, 1, 1, *block.shape[4:6], *[1 for _ in block.shape[6:]] ) block *= cont_four.norm_cont.reshape( 1, 1, 1, 1, 1, 1, *block.shape[6:8], *[1 for _ in block.shape[8:]] ) # transform block = np.tensordot(transform_one, block, (1, 1)) block = np.swapaxes(block, 0, 1) block = np.tensordot(transform_two, block, (1, 3)) block = np.swapaxes(np.swapaxes(np.swapaxes(block, 0, 1), 1, 2), 2, 3) block = np.tensordot(transform_three, block, (1, 5)) block = np.swapaxes( np.swapaxes( np.swapaxes(np.swapaxes(np.swapaxes(block, 0, 1), 1, 2), 2, 3), 3, 4 ), 4, 5, ) block = np.tensordot(transform_four, block, (1, 7)) block = np.swapaxes( np.swapaxes( np.swapaxes( np.swapaxes( np.swapaxes(np.swapaxes(np.swapaxes(block, 0, 1), 1, 2), 2, 3), 3, 4 ), 4, 5, ), 5, 6, ), 6, 7, ) # array has shape (M_1, L_1, M_2, L_2, M_3, L_3, M_4, L_4, ..) block = block.reshape( block.shape[0] * block.shape[1], block.shape[2] * block.shape[3], block.shape[4] * block.shape[5], block.shape[6] * block.shape[7], *block.shape[8:], ) # array now has shape (M_1 L_1, M_2 L_2, M_3, L_3, M_4, L_4, ...) all_blocks[i, j, k, l] = block all_blocks[i, j, l, k] = np.swapaxes(block, 2, 3) all_blocks[j, i, k, l] = np.swapaxes(block, 0, 1) all_blocks[j, i, l, k] = np.swapaxes(np.swapaxes(block, 2, 3), 0, 1) all_blocks[k, l, i, j] = np.swapaxes(np.swapaxes(block, 1, 3), 0, 2) all_blocks[l, k, i, j] = np.swapaxes( np.swapaxes(np.swapaxes(block, 1, 3), 0, 2), 0, 1 ) all_blocks[k, l, j, i] = np.swapaxes( np.swapaxes(np.swapaxes(block, 1, 3), 0, 2), 2, 3 ) all_blocks[l, k, j, i] = np.swapaxes(np.swapaxes(block, 1, 2), 0, 3) # concatenate return np.concatenate( [ np.concatenate( [ np.concatenate( [np.concatenate(blocks_three, axis=3) for blocks_three in blocks_two], axis=2, ) for blocks_two in blocks_one ], axis=1, ) for blocks_one in all_blocks ], axis=0, )
def test_contruct_array_lincomb(): """Test BaseTwoIndexSymmetric.construct_array_lincomb.""" contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) sph_transform = generate_transformation( 1, contractions.angmom_components_cart, contractions.angmom_components_sph, "left") orb_transform = np.random.rand(3, 3) Test = disable_abstract( # noqa: N806 BaseTwoIndexSymmetric, dict_overwrite={ "construct_array_contraction": ( lambda self, cont_one, cont_two, a=2: np.arange(9, dtype=float).reshape(1, 3, 1, 3) * a ) }, ) contractions.norm_cont = np.ones((1, 3)) test = Test([contractions]) assert np.allclose( test.construct_array_lincomb(orb_transform, "cartesian"), (orb_transform.dot(np.arange(9).reshape(3, 3)).dot(orb_transform.T).T * 2), ) assert np.allclose( test.construct_array_lincomb(orb_transform, "spherical"), (orb_transform.dot(sph_transform).dot(np.arange(9).reshape(3, 3)).dot( sph_transform.T).dot(orb_transform.T).T * 2), ) assert np.allclose( test.construct_array_lincomb(orb_transform, "spherical", a=3), (orb_transform.dot(sph_transform).dot(np.arange(9).reshape(3, 3)).dot( sph_transform.T).dot(orb_transform.T).T * 3), ) with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform, "spherical", bad_keyword=3) with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform, "bad", keyword=3) Test = disable_abstract( # noqa: N806 BaseTwoIndexSymmetric, dict_overwrite={ "construct_array_contraction": lambda self, cont_one, cont_two, a=2: ( np.arange(cont_one.num_cart * cont_two.num_cart * 2, dtype=float).reshape( 1, cont_one.num_cart, 1, cont_two.num_cart, 2 ) * a ) }, ) cont_one = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) cont_two = GeneralizedContractionShell(2, np.array([1, 2, 3]), np.ones(1), np.ones(1)) cont_one.norm_cont = np.ones((1, cont_one.num_cart)) cont_two.norm_cont = np.ones((1, cont_two.num_cart)) test = Test([cont_one, cont_two]) sph_transform_one = generate_transformation( 1, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left") sph_transform_two = generate_transformation( 2, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left") orb_transform = np.random.rand(8, 8) assert np.allclose( test.construct_array_lincomb(orb_transform, "spherical", a=4), np.swapaxes( np.tensordot( orb_transform, np.tensordot( orb_transform, np.concatenate( [ np.concatenate( [ np.tensordot( sph_transform_one, np.tensordot( sph_transform_one, np.arange(18).reshape(3, 3, 2), (1, 0), ), (1, 1), ) * 4, np.swapaxes( np.tensordot( sph_transform_two, np.tensordot( sph_transform_one, np.arange(36).reshape(3, 6, 2), (1, 0), ), (1, 1), ), 0, 1, ) * 4, ], axis=1, ), np.concatenate( [ np.tensordot( sph_transform_two, np.tensordot( sph_transform_one, np.arange(36).reshape(3, 6, 2), (1, 0), ), (1, 1), ) * 4, np.tensordot( sph_transform_two, np.tensordot( sph_transform_two, np.arange(72).reshape(6, 6, 2), (1, 0), ), (1, 1), ) * 4, ], axis=1, ), ], axis=0, ), (1, 0), ), (1, 1), ), 0, 1, ), ) orb_transform = np.random.rand(9, 9) assert np.allclose( test.construct_array_lincomb(orb_transform, ("spherical", "cartesian"), a=4), np.swapaxes( np.tensordot( orb_transform, np.tensordot( orb_transform, np.concatenate( [ np.concatenate( [ np.tensordot( sph_transform_one, np.tensordot( sph_transform_one, np.arange(18).reshape(3, 3, 2), (1, 0), ), (1, 1), ) * 4, np.tensordot( sph_transform_one, np.arange(36).reshape(3, 6, 2), (1, 0)) * 4, ], axis=1, ), np.concatenate( [ np.swapaxes( np.tensordot( sph_transform_one, np.arange(36).reshape(3, 6, 2), (1, 0), ), 0, 1, ) * 4, np.swapaxes( np.arange(72).reshape(6, 6, 2), 0, 1) * 4, ], axis=1, ), ], axis=0, ), (1, 0), ), (1, 1), ), 0, 1, ), )
def test_contruct_array_spherical(): """Test BaseTwoIndexSymmetric.construct_array_spherical.""" contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) transform = generate_transformation(1, contractions.angmom_components_cart, contractions.angmom_components_sph, "left") Test = disable_abstract( # noqa: N806 BaseTwoIndexSymmetric, dict_overwrite={ "construct_array_contraction": ( lambda self, cont_one, cont_two, a=2: np.arange(9, dtype=float).reshape(1, 3, 1, 3) * a ) }, ) contractions.norm_cont = np.ones((1, 3)) test = Test([contractions]) assert np.allclose( test.construct_array_spherical(), (transform.dot(np.arange(9).reshape(3, 3)).dot(transform.T)).T * 2, ) assert np.allclose( test.construct_array_spherical(a=3), (transform.dot(np.arange(9).reshape(3, 3)).dot(transform.T)).T * 3, ) with pytest.raises(TypeError): test.construct_array_spherical(bad_keyword=3) cont_one = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) cont_two = GeneralizedContractionShell(2, np.array([1, 2, 3]), np.ones(1), np.ones(1)) transform_one = generate_transformation(1, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left") transform_two = generate_transformation(2, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left") Test = disable_abstract( # noqa: N806 BaseTwoIndexSymmetric, dict_overwrite={ "construct_array_contraction": lambda self, cont_one, cont_two, a=2: ( np.arange(cont_one.num_cart * cont_two.num_cart * 2, dtype=float).reshape( 1, cont_one.num_cart, 1, cont_two.num_cart, 2 ) * a ) }, ) cont_one.norm_cont = np.ones((1, cont_one.num_cart)) cont_two.norm_cont = np.ones((1, cont_two.num_cart)) test = Test([cont_one, cont_two]) assert np.allclose( test.construct_array_spherical(a=4), np.concatenate( [ np.concatenate( [ np.tensordot( transform_one, np.tensordot(transform_one, np.arange(18).reshape(3, 3, 2), (1, 0)), (1, 1), ) * 4, np.swapaxes( np.tensordot( transform_two, np.tensordot(transform_one, np.arange(36).reshape(3, 6, 2), (1, 0)), (1, 1), ), 0, 1, ) * 4, ], axis=1, ), np.concatenate( [ np.tensordot( transform_two, np.tensordot(transform_one, np.arange(36).reshape(3, 6, 2), (1, 0)), (1, 1), ) * 4, np.tensordot( transform_two, np.tensordot(transform_two, np.arange(72).reshape(6, 6, 2), (1, 0)), (1, 1), ) * 4, ], axis=1, ), ], axis=0, ), ) Test = disable_abstract( # noqa: N806 BaseTwoIndexSymmetric, dict_overwrite={ "construct_array_contraction": lambda self, cont_one, cont_two, a=2: ( np.arange(2 * cont_one.num_cart * 2 * cont_two.num_cart, dtype=float).reshape( 2, cont_one.num_cart, 2, cont_two.num_cart ) * a ) }, ) cont_one.norm_cont = np.ones((2, cont_one.num_cart)) cont_two.norm_cont = np.ones((2, cont_two.num_cart)) test = Test([cont_one, cont_two]) matrix_11 = np.arange(2 * cont_one.num_cart * 2 * cont_one.num_cart).reshape(2, cont_one.num_cart, 2, cont_one.num_cart) matrix_11 = np.swapaxes(np.tensordot(transform_one, matrix_11, (1, 1)), 0, 1) matrix_11 = np.moveaxis(np.tensordot(transform_one, matrix_11, (1, 3)), 0, 3) matrix_12 = np.arange(2 * cont_one.num_cart * 2 * cont_two.num_cart).reshape(2, cont_one.num_cart, 2, cont_two.num_cart) matrix_12 = np.swapaxes(np.tensordot(transform_one, matrix_12, (1, 1)), 0, 1) matrix_12 = np.moveaxis(np.tensordot(transform_two, matrix_12, (1, 3)), 0, 3) matrix_22 = np.arange(2 * cont_two.num_cart * 2 * cont_two.num_cart).reshape(2, cont_two.num_cart, 2, cont_two.num_cart) matrix_22 = np.swapaxes(np.tensordot(transform_two, matrix_22, (1, 1)), 0, 1) matrix_22 = np.moveaxis(np.tensordot(transform_two, matrix_22, (1, 3)), 0, 3) assert np.allclose( test.construct_array_spherical(), np.vstack([ np.hstack([ np.vstack([ np.hstack([matrix_11[0, :, 0, :], matrix_11[0, :, 1, :]]), np.hstack([matrix_11[1, :, 0, :], matrix_11[1, :, 1, :]]), ]).T, np.vstack([ np.hstack([matrix_12[0, :, 0, :], matrix_12[0, :, 1, :]]), np.hstack([matrix_12[1, :, 0, :], matrix_12[1, :, 1, :]]), ]), ]), np.hstack([ np.vstack([ np.hstack([matrix_12[0, :, 0, :], matrix_12[0, :, 1, :]]), np.hstack([matrix_12[1, :, 0, :], matrix_12[1, :, 1, :]]), ]).T, np.vstack([ np.hstack([matrix_22[0, :, 0, :], matrix_22[0, :, 1, :]]), np.hstack([matrix_22[1, :, 0, :], matrix_22[1, :, 1, :]]), ]).T, ]), ]) * 2, )
def test_generate_transformation_horton_high_angmom(): """Test spherical.generate_transformation using horton reference for high angular momentum. Answer obtained from https://github.com/theochem/horton/blob/master/horton/gbasis/cartpure.cpp. """ # taken from HORTON's gbasis/cartpure.cpp horton_transform = [ [0, 0, 0.375], [0, 3, 0.21957751641341996535], [0, 5, -0.87831006565367986142], [0, 10, 0.375], [0, 12, -0.87831006565367986142], [0, 14, 1.0], [1, 2, -0.89642145700079522998], [1, 7, -0.40089186286863657703], [1, 9, 1.19522860933439364], [2, 4, -0.40089186286863657703], [2, 11, -0.89642145700079522998], [2, 13, 1.19522860933439364], [3, 0, -0.5590169943749474241], [3, 5, 0.9819805060619657157], [3, 10, 0.5590169943749474241], [3, 12, -0.9819805060619657157], [4, 1, -0.42257712736425828875], [4, 6, -0.42257712736425828875], [4, 8, 1.1338934190276816816], [5, 2, 0.790569415042094833], [5, 7, -1.0606601717798212866], [6, 4, 1.0606601717798212866], [6, 11, -0.790569415042094833], [7, 0, 0.73950997288745200532], [7, 3, -1.2990381056766579701], [7, 10, 0.73950997288745200532], [8, 1, 1.1180339887498948482], [8, 6, -1.1180339887498948482], ] answer = np.zeros((9, 15)) for i in horton_transform: answer[i[0], i[1]] = i[2] assert np.allclose( generate_transformation( 4, np.array([ [4, 0, 0], [3, 1, 0], [3, 0, 1], [2, 2, 0], [2, 1, 1], [2, 0, 2], [1, 3, 0], [1, 2, 1], [1, 1, 2], [1, 0, 3], [0, 4, 0], [0, 3, 1], [0, 2, 2], [0, 1, 3], [0, 0, 4], ]), (0, 1, -1, 2, -2, 3, -3, 4, -4), "left", ), answer, ) # taken from HORTON's gbasis/cartpure.cpp horton_transform = [ [0, 2, 0.625], [0, 7, 0.36596252735569994226], [0, 9, -1.0910894511799619063], [0, 16, 0.625], [0, 18, -1.0910894511799619063], [0, 20, 1.0], [1, 0, 0.48412291827592711065], [1, 3, 0.21128856368212914438], [1, 5, -1.2677313820927748663], [1, 10, 0.16137430609197570355], [1, 12, -0.56694670951384084082], [1, 14, 1.2909944487358056284], [2, 1, 0.16137430609197570355], [2, 6, 0.21128856368212914438], [2, 8, -0.56694670951384084082], [2, 15, 0.48412291827592711065], [2, 17, -1.2677313820927748663], [2, 19, 1.2909944487358056284], [3, 2, -0.85391256382996653193], [3, 9, 1.1180339887498948482], [3, 16, 0.85391256382996653193], [3, 18, -1.1180339887498948482], [4, 4, -0.6454972243679028142], [4, 11, -0.6454972243679028142], [4, 13, 1.2909944487358056284], [5, 0, -0.52291251658379721749], [5, 3, 0.22821773229381921394], [5, 5, 0.91287092917527685576], [5, 10, 0.52291251658379721749], [5, 12, -1.2247448713915890491], [6, 1, -0.52291251658379721749], [6, 6, -0.22821773229381921394], [6, 8, 1.2247448713915890491], [6, 15, 0.52291251658379721749], [6, 17, -0.91287092917527685576], [7, 2, 0.73950997288745200532], [7, 7, -1.2990381056766579701], [7, 16, 0.73950997288745200532], [8, 4, 1.1180339887498948482], [8, 11, -1.1180339887498948482], [9, 0, 0.7015607600201140098], [9, 3, -1.5309310892394863114], [9, 10, 1.169267933366856683], [10, 1, 1.169267933366856683], [10, 6, -1.5309310892394863114], [10, 15, 0.7015607600201140098], ] answer = np.zeros((11, 21)) for i in horton_transform: answer[i[0], i[1]] = i[2] assert np.allclose( generate_transformation( 5, np.array([(i.count(0), i.count(1), i.count(2)) for i in it.combinations_with_replacement(range(3), 5)]), (0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5), "left", ), answer, )
def test_generate_transformation_horton(): """Test spherical.generate_transformation using horton reference. Answer obtained from https://theochem.github.io/horton/2.0.1/tech_ref_gaussian_basis.html. """ answer = np.array([[1]]) assert np.allclose( generate_transformation(0, np.array([[0, 0, 0]]), (0, ), "left"), answer) answer = np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]]) assert np.allclose( generate_transformation(1, np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), (0, 1, -1), "left"), answer, ) answer = np.array([ [-0.5, 0, 0, -0.5, 0, 1], [0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 1, 0], [0.5 * 3**0.5, 0, 0, -0.5 * 3**0.5, 0, 0], [0, 1, 0, 0, 0, 0], ]) assert np.allclose( generate_transformation( 2, np.array([[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]]), (0, 1, -1, 2, -2), "left", ), answer, ) answer = np.array([ [0, 0, -3 / 10 * 5**0.5, 0, 0, 0, 0, -3 / 10 * 5**0.5, 0, 1], [ -1 / 4 * 6**0.5, 0, 0, -1 / 20 * 30**0.5, 0, 1 / 5 * 30**0.5, 0, 0, 0, 0 ], [ 0, -1 / 20 * 30**0.5, 0, 0, 0, 0, -1 / 4 * 6**0.5, 0, 1 / 5 * 30**0.5, 0 ], [0, 0, 1 / 2 * 3**0.5, 0, 0, 0, 0, -1 / 2 * 3**0.5, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [1 / 4 * 10**0.5, 0, 0, -3 / 4 * 2**0.5, 0, 0, 0, 0, 0, 0], [0, 3 / 4 * 2**0.5, 0, 0, 0, 0, -1 / 4 * 10**0.5, 0, 0, 0], ]) # shuffle to have correct order assert np.allclose( generate_transformation( 3, np.array([ [3, 0, 0], [2, 1, 0], [2, 0, 1], [1, 2, 0], [1, 1, 1], [1, 0, 2], [0, 3, 0], [0, 2, 1], [0, 1, 2], [0, 0, 3], ]), (0, 1, -1, 2, -2, 3, -3), "left", ), answer, )
def test_generate_transformation(): """Test spherical.generate_transformation.""" assert np.array_equal( generate_transformation(0, np.array([(0, 0, 0)]), (0, ), "right"), np.array([[1.0]])) assert np.array_equal( generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1), "right"), np.array([[0.0, 0.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]), ) assert np.array_equal( generate_transformation(0, np.array([(0, 0, 0)]), (0, ), "right").T, generate_transformation(0, np.array([(0, 0, 0)]), (0, ), "left"), ) assert np.array_equal( generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1), "right").T, generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1), "left"), ) with pytest.raises(TypeError): generate_transformation(0.0, np.array([(0, 0, 0)]), (0, ), "right") with pytest.raises(TypeError): generate_transformation(0, 0, (0, ), "right") with pytest.raises(ValueError): generate_transformation(-1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1), "right") with pytest.raises(ValueError): generate_transformation(0, np.array([(0, 0, 0, 0)]), (0, ), "right") with pytest.raises(ValueError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 1)]), (-1, 0, 1), "right") with pytest.raises(ValueError): generate_transformation( 1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 0, 0)]), (-1, 0, 1), "right") with pytest.raises(ValueError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0)]), (-1, 0, 1), "right") with pytest.raises(ValueError): generate_transformation(1, np.array([(1, 0, 0), (0, 0, 0), (0, 0, 2)]), (-1, 0, 1), "right") with pytest.raises(TypeError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1), 1) with pytest.raises(TypeError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1), None) with pytest.raises(ValueError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1), "up") with pytest.raises(ValueError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1), "") # check angmom_components_sph type with pytest.raises(TypeError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), np.array([-1, 0, 1]), "left") with pytest.raises(TypeError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), {-1, 0, 1}, "left") with pytest.raises(TypeError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), [-1, 0, 1.0], "left") # check angmom_components_sph value with pytest.raises(ValueError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 0, 1, 1), "left") with pytest.raises(ValueError): generate_transformation(1, np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), (-1, 2, 1), "left")
def test_contruct_array_lincomb(): """Test BaseTwoIndexAsymmetric.construct_array_lincomb.""" contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) sph_transform = generate_transformation( 1, contractions.angmom_components_cart, contractions.angmom_components_sph, "left") orb_transform_one = np.random.rand(3, 3) orb_transform_two = np.random.rand(3, 3) Test = disable_abstract( # noqa: N806 BaseTwoIndexAsymmetric, dict_overwrite={ "construct_array_contraction": ( lambda self, cont_one, cont_two, a=2: np.arange(9, dtype=float).reshape(1, 3, 1, 3) * a ) }, ) contractions.norm_cont = np.ones((1, 3)) test = Test([contractions], [contractions]) assert np.allclose( test.construct_array_lincomb(orb_transform_one, orb_transform_two, "cartesian", "cartesian"), orb_transform_one.dot(np.arange(9).reshape(3, 3)).dot( orb_transform_two.T) * 2, ) assert np.allclose( test.construct_array_lincomb(orb_transform_one, orb_transform_two, "spherical", "spherical"), (orb_transform_one.dot(sph_transform).dot(np.arange(9).reshape( 3, 3)).dot(sph_transform.T).dot(orb_transform_two.T) * 2), ) assert np.allclose( test.construct_array_lincomb(orb_transform_one, orb_transform_two, "cartesian", "spherical"), (orb_transform_one.dot(np.arange(9).reshape(3, 3)).dot( sph_transform.T).dot(orb_transform_two.T) * 2), ) assert np.allclose( test.construct_array_lincomb(orb_transform_one, orb_transform_two, "spherical", "cartesian"), (orb_transform_one.dot(sph_transform).dot(np.arange(9).reshape( 3, 3)).dot(orb_transform_two.T) * 2), ) assert np.allclose( test.construct_array_lincomb(orb_transform_one, orb_transform_two, "spherical", "spherical", a=3), (orb_transform_one.dot(sph_transform).dot(np.arange(9).reshape( 3, 3)).dot(sph_transform.T).dot(orb_transform_two.T) * 3), ) with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform_one, orb_transform_two, "spherical", "spherical", bad_keyword=3) with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform_one, orb_transform_two, "bad", "spherical", keyword=3) with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform_one, orb_transform_two, "cartesian", "bad", keyword=3) orb_transform_one = np.random.rand(3, 6) orb_transform_two = np.random.rand(3, 3) test = Test([contractions, contractions], [contractions]) assert np.allclose( test.construct_array_lincomb(orb_transform_one, orb_transform_two, "spherical", "spherical"), orb_transform_one.dot( np.vstack([ sph_transform.dot(np.arange(9).reshape(3, 3)).dot( sph_transform.T) * 2 ] * 2).dot(orb_transform_two.T)), ) assert np.allclose( test.construct_array_lincomb(orb_transform_one, orb_transform_two, ["spherical", "cartesian"], "spherical"), orb_transform_one.dot( np.vstack([ sph_transform.dot(np.arange(9).reshape(3, 3)).dot( sph_transform.T) * 2, (np.arange(9).reshape(3, 3)).dot(sph_transform.T) * 2, ]).dot(orb_transform_two.T)), ) orb_transform_one = np.random.rand(3, 3) orb_transform_two = np.random.rand(3, 6) test = Test([contractions], [contractions, contractions]) assert np.allclose( test.construct_array_lincomb(orb_transform_one, orb_transform_two, "cartesian", ["spherical", "cartesian"]), orb_transform_one.dot( np.hstack([ (np.arange(9).reshape(3, 3)).dot(sph_transform.T) * 2, np.arange(9).reshape(3, 3) * 2, ]).dot(orb_transform_two.T)), ) assert np.allclose( test.construct_array_lincomb(None, orb_transform_two, "cartesian", ["spherical", "cartesian"]), np.hstack([(np.arange(9).reshape(3, 3)).dot(sph_transform.T) * 2, np.arange(9).reshape(3, 3) * 2]).dot(orb_transform_two.T), ) assert np.allclose( test.construct_array_lincomb(orb_transform_one, None, "cartesian", ["spherical", "cartesian"]), orb_transform_one.dot( np.hstack([ (np.arange(9).reshape(3, 3)).dot(sph_transform.T) * 2, np.arange(9).reshape(3, 3) * 2, ])), ) assert np.allclose( test.construct_array_lincomb(None, None, "cartesian", ["spherical", "cartesian"]), np.hstack([(np.arange(9).reshape(3, 3)).dot(sph_transform.T) * 2, np.arange(9).reshape(3, 3) * 2]), )
def test_construct_array_lincomb(): """Test BaseFourIndexSymmetric.construct_array_lincomb.""" contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) sph_transform = generate_transformation( 1, contractions.angmom_components_cart, contractions.angmom_components_sph, "left" ) orb_transform = np.random.rand(3, 3) Test = disable_abstract( # noqa: N806 BaseFourIndexSymmetric, dict_overwrite={ "construct_array_contraction": ( lambda self, cont_one, cont_two, cont_three, cont_four, a=2: np.arange( 81, dtype=float ).reshape(1, 3, 1, 3, 1, 3, 1, 3) * a ) }, ) contractions.norm_cont = np.ones((1, 3)) test = Test([contractions]) assert np.allclose( test.construct_array_lincomb(orb_transform, "cartesian"), np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.einsum("ijkl->lkji", np.arange(81).reshape(3, 3, 3, 3)) * 2, orb_transform, orb_transform, orb_transform, orb_transform, ), ) assert np.allclose( test.construct_array_lincomb(orb_transform, "spherical"), np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.einsum("ijkl->lkji", np.arange(81).reshape(3, 3, 3, 3)) * 2, sph_transform, sph_transform, sph_transform, sph_transform, ), orb_transform, orb_transform, orb_transform, orb_transform, ), ) with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform, "spherical", bad_keyword=3) with pytest.raises(TypeError): test.construct_array_lincomb(orb_transform, "bad", keyword=3) Test = disable_abstract( # noqa: N806 BaseFourIndexSymmetric, dict_overwrite={ "construct_array_contraction": lambda self, cont_one, cont_two, cont_three, cont_four: ( np.arange( cont_one.num_cart * cont_two.num_cart * cont_three.num_cart * cont_four.num_cart, dtype=float, ).reshape( 1, cont_one.num_cart, 1, cont_two.num_cart, 1, cont_three.num_cart, 1, cont_four.num_cart, ) ) }, ) cont_one = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) cont_two = GeneralizedContractionShell(2, np.array([1, 2, 3]), np.ones(1), np.ones(1)) cont_one.norm_cont = np.ones((1, cont_one.num_cart)) cont_two.norm_cont = np.ones((1, cont_two.num_cart)) test = Test([cont_one, cont_two]) sph_transform_one = generate_transformation( 1, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left" ) sph_transform_two = generate_transformation( 2, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left" ) orb_transform = np.random.rand(8, 8) # NOTE: since the test subarray (output of construct_array_contraction) does not satisfy the # symmetries of the two electron integral, only the last permutation is used. If this output # satisfies the symmetries of two electron integrals, then all these permutations should result # in the same array. # FIXME: not a good test sph_array = np.concatenate( [ np.concatenate( [ np.concatenate( [ np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 3 * 3 * 3).reshape(3, 3, 3, 3), sph_transform_one, sph_transform_one, sph_transform_one, sph_transform_one, ), ), np.einsum( "ijkl->jikl", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 3 * 3 * 6).reshape(3, 3, 3, 6), sph_transform_one, sph_transform_one, sph_transform_one, sph_transform_two, ), ), ], axis=3, ), np.concatenate( [ np.einsum( "ijkl->jilk", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 3 * 3 * 6).reshape(3, 3, 3, 6), sph_transform_one, sph_transform_one, sph_transform_one, sph_transform_two, ), ), np.einsum( "ijkl->jilk", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 3 * 6 * 6).reshape(3, 3, 6, 6), sph_transform_one, sph_transform_one, sph_transform_two, sph_transform_two, ), ), ], axis=3, ), ], axis=2, ), np.concatenate( [ np.concatenate( [ np.einsum( "ijkl->klji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 3 * 3 * 6).reshape(3, 3, 3, 6), sph_transform_one, sph_transform_one, sph_transform_one, sph_transform_two, ), ), np.einsum( "ijkl->klij", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 6 * 3 * 6).reshape(3, 6, 3, 6), sph_transform_one, sph_transform_two, sph_transform_one, sph_transform_two, ), ), ], axis=3, ), np.concatenate( [ np.einsum( "ijkl->klji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 6 * 3 * 6).reshape(3, 6, 3, 6), sph_transform_one, sph_transform_two, sph_transform_one, sph_transform_two, ), ), np.einsum( "ijkl->ijlk", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 6 * 6 * 6).reshape(3, 6, 6, 6), sph_transform_one, sph_transform_two, sph_transform_two, sph_transform_two, ), ), ], axis=3, ), ], axis=2, ), ], axis=1, ), np.concatenate( [ np.concatenate( [ np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 3 * 3 * 6).reshape(3, 3, 3, 6), sph_transform_one, sph_transform_one, sph_transform_one, sph_transform_two, ), ), np.einsum( "ijkl->lkij", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 6 * 3 * 6).reshape(3, 6, 3, 6), sph_transform_one, sph_transform_two, sph_transform_one, sph_transform_two, ), ), ], axis=3, ), np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 6 * 3 * 6).reshape(3, 6, 3, 6), sph_transform_one, sph_transform_two, sph_transform_one, sph_transform_two, ), ), np.einsum( "ijkl->jilk", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 6 * 6 * 6).reshape(3, 6, 6, 6), sph_transform_one, sph_transform_two, sph_transform_two, sph_transform_two, ), ), ], axis=3, ), ], axis=2, ), np.concatenate( [ np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 3 * 6 * 6).reshape(3, 3, 6, 6), sph_transform_one, sph_transform_one, sph_transform_two, sph_transform_two, ), ), np.einsum( "ijkl->lkij", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 6 * 6 * 6).reshape(3, 6, 6, 6), sph_transform_one, sph_transform_two, sph_transform_two, sph_transform_two, ), ), ], axis=3, ), np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 6 * 6 * 6).reshape(3, 6, 6, 6), sph_transform_one, sph_transform_two, sph_transform_two, sph_transform_two, ), ), np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(6 * 6 * 6 * 6).reshape(6, 6, 6, 6), sph_transform_two, sph_transform_two, sph_transform_two, sph_transform_two, ), ), ], axis=3, ), ], axis=2, ), ], axis=1, ), ] ) assert np.allclose( test.construct_array_lincomb(orb_transform, "spherical"), np.einsum( "ijkl,ai,bj,ck,dl->abcd", sph_array, orb_transform, orb_transform, orb_transform, orb_transform, ), ) orb_transform = np.random.rand(9, 9) sph_cart_array = np.concatenate( [ np.concatenate( [ np.concatenate( [ np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj,ck,dl->abcd", np.arange(3 * 3 * 3 * 3).reshape(3, 3, 3, 3), sph_transform_one, sph_transform_one, sph_transform_one, sph_transform_one, ), ), np.einsum( "ijkl->jikl", np.einsum( "ijkl,ai,bj,ck->abcl", np.arange(3 * 3 * 3 * 6).reshape(3, 3, 3, 6), sph_transform_one, sph_transform_one, sph_transform_one, ), ), ], axis=3, ), np.concatenate( [ np.einsum( "ijkl->jilk", np.einsum( "ijkl,ai,bj,ck->abcl", np.arange(3 * 3 * 3 * 6).reshape(3, 3, 3, 6), sph_transform_one, sph_transform_one, sph_transform_one, ), ), np.einsum( "ijkl->jilk", np.einsum( "ijkl,ai,bj->abkl", np.arange(3 * 3 * 6 * 6).reshape(3, 3, 6, 6), sph_transform_one, sph_transform_one, ), ), ], axis=3, ), ], axis=2, ), np.concatenate( [ np.concatenate( [ np.einsum( "ijkl->klji", np.einsum( "ijkl,ai,bj,ck->abcl", np.arange(3 * 3 * 3 * 6).reshape(3, 3, 3, 6), sph_transform_one, sph_transform_one, sph_transform_one, ), ), np.einsum( "ijkl->klij", np.einsum( "ijkl,ai,ck->ajcl", np.arange(3 * 6 * 3 * 6).reshape(3, 6, 3, 6), sph_transform_one, sph_transform_one, ), ), ], axis=3, ), np.concatenate( [ np.einsum( "ijkl->klji", np.einsum( "ijkl,ai,ck->ajcl", np.arange(3 * 6 * 3 * 6).reshape(3, 6, 3, 6), sph_transform_one, sph_transform_one, ), ), np.einsum( "ijkl->ijlk", np.einsum( "ijkl,ai->ajkl", np.arange(3 * 6 * 6 * 6).reshape(3, 6, 6, 6), sph_transform_one, ), ), ], axis=3, ), ], axis=2, ), ], axis=1, ), np.concatenate( [ np.concatenate( [ np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj,ck->abcl", np.arange(3 * 3 * 3 * 6).reshape(3, 3, 3, 6), sph_transform_one, sph_transform_one, sph_transform_one, ), ), np.einsum( "ijkl->lkij", np.einsum( "ijkl,ai,ck->ajcl", np.arange(3 * 6 * 3 * 6).reshape(3, 6, 3, 6), sph_transform_one, sph_transform_one, ), ), ], axis=3, ), np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,ck->ajcl", np.arange(3 * 6 * 3 * 6).reshape(3, 6, 3, 6), sph_transform_one, sph_transform_one, ), ), np.einsum( "ijkl->jilk", np.einsum( "ijkl,ai->ajkl", np.arange(3 * 6 * 6 * 6).reshape(3, 6, 6, 6), sph_transform_one, ), ), ], axis=3, ), ], axis=2, ), np.concatenate( [ np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai,bj->abkl", np.arange(3 * 3 * 6 * 6).reshape(3, 3, 6, 6), sph_transform_one, sph_transform_one, ), ), np.einsum( "ijkl->lkij", np.einsum( "ijkl,ai->ajkl", np.arange(3 * 6 * 6 * 6).reshape(3, 6, 6, 6), sph_transform_one, ), ), ], axis=3, ), np.concatenate( [ np.einsum( "ijkl->lkji", np.einsum( "ijkl,ai->ajkl", np.arange(3 * 6 * 6 * 6).reshape(3, 6, 6, 6), sph_transform_one, ), ), np.einsum( "ijkl->lkji", np.arange(6 * 6 * 6 * 6).reshape(6, 6, 6, 6) ), ], axis=3, ), ], axis=2, ), ], axis=1, ), ] ) assert np.allclose( test.construct_array_lincomb(orb_transform, ("spherical", "cartesian")), np.einsum( "ijkl,ai,bj,ck,dl->abcd", sph_cart_array, orb_transform, orb_transform, orb_transform, orb_transform, ), )
def test_construct_array_spherical(): """Test BaseFourIndexSymmetric.construct_array_spherical.""" contractions = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) transform = generate_transformation( 1, contractions.angmom_components_cart, contractions.angmom_components_sph, "left" ) # make symmetric array = np.arange(81, dtype=float).reshape(3, 3, 3, 3) array += np.einsum("ijkl->jikl", array) array += np.einsum("ijkl->ijlk", array) array += np.einsum("ijkl->klij", array) Test = disable_abstract( # noqa: N806 BaseFourIndexSymmetric, dict_overwrite={ "construct_array_contraction": ( lambda self, cont_one, cont_two, cont_three, cont_four, a=2: array.reshape( 1, 3, 1, 3, 1, 3, 1, 3 ) * a ) }, ) contractions.norm_cont = np.ones((1, 3)) test = Test([contractions]) assert np.allclose( test.construct_array_spherical(), np.einsum("ijkl,ai,bj,ck,dl->abcd", array, transform, transform, transform, transform) * 2, ) assert np.allclose( test.construct_array_spherical(a=3), np.einsum("ijkl,ai,bj,ck,dl->abcd", array, transform, transform, transform, transform) * 3, ) with pytest.raises(TypeError): test.construct_array_spherical(bad_keyword=3) cont_one = GeneralizedContractionShell(1, np.array([1, 2, 3]), np.ones(1), np.ones(1)) cont_two = GeneralizedContractionShell(2, np.array([1, 2, 3]), np.ones(1), np.ones(1)) transform_one = generate_transformation( 1, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left" ) transform_two = generate_transformation( 2, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left" ) Test = disable_abstract( # noqa: N806 BaseFourIndexSymmetric, dict_overwrite={ "construct_array_contraction": lambda self, cont_one, cont_two, cont_three, cont_four: ( np.arange( cont_one.num_cart * cont_two.num_cart * cont_three.num_cart * cont_four.num_cart * 2, dtype=float, ).reshape( 1, cont_one.num_cart, 1, cont_two.num_cart, 1, cont_three.num_cart, 1, cont_four.num_cart, 2, ) ) }, ) cont_one.norm_cont = np.ones((1, cont_one.num_cart)) cont_two.norm_cont = np.ones((1, cont_two.num_cart)) test = Test([cont_one, cont_two]) # NOTE: since the test subarray (output of construct_array_contraction) does not satisfy the # symmetries of the two electron integral, only the last permutation is used. If this output # satisfies the symmetries of two electron integrals, then all these permutations should result # in the same array. # FIXME: not a good test assert np.allclose( test.construct_array_spherical()[:3, :3, :3, :3], np.einsum( "ijklm->lkjim", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 3 * 3 * 3 * 2).reshape(3, 3, 3, 3, 2), transform_one, transform_one, transform_one, transform_one, ), ), ) assert np.allclose( test.construct_array_spherical()[:3, :3, :3, 3:], np.einsum( "ijklm->jiklm", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 3 * 3 * 6 * 2).reshape(3, 3, 3, 6, 2), transform_one, transform_one, transform_one, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[:3, :3, 3:, :3], np.einsum( "ijklm->jilkm", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 3 * 3 * 6 * 2).reshape(3, 3, 3, 6, 2), transform_one, transform_one, transform_one, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[:3, :3, 3:, 3:], np.einsum( "ijklm->jilkm", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 3 * 6 * 6 * 2).reshape(3, 3, 6, 6, 2), transform_one, transform_one, transform_two, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[:3, 3:, :3, :3], np.einsum( "ijklm->kljim", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 3 * 3 * 6 * 2).reshape(3, 3, 3, 6, 2), transform_one, transform_one, transform_one, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[:3, 3:, :3, 3:], np.einsum( "ijklm->klijm", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 6 * 3 * 6 * 2).reshape(3, 6, 3, 6, 2), transform_one, transform_two, transform_one, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[:3, 3:, 3:, :3], np.einsum( "ijklm->kljim", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 6 * 3 * 6 * 2).reshape(3, 6, 3, 6, 2), transform_one, transform_two, transform_one, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[:3, 3:, 3:, 3:], np.einsum( "ijklm->ijlkm", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 6 * 6 * 6 * 2).reshape(3, 6, 6, 6, 2), transform_one, transform_two, transform_two, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[3:, :3, :3, :3], np.einsum( "ijklm->lkjim", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 3 * 3 * 6 * 2).reshape(3, 3, 3, 6, 2), transform_one, transform_one, transform_one, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[3:, :3, :3, 3:], np.einsum( "ijklm->lkijm", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 6 * 3 * 6 * 2).reshape(3, 6, 3, 6, 2), transform_one, transform_two, transform_one, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[3:, :3, 3:, :3], np.einsum( "ijklm->lkjim", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 6 * 3 * 6 * 2).reshape(3, 6, 3, 6, 2), transform_one, transform_two, transform_one, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[3:, :3, 3:, 3:], np.einsum( "ijklm->jilkm", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 6 * 6 * 6 * 2).reshape(3, 6, 6, 6, 2), transform_one, transform_two, transform_two, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[3:, 3:, :3, :3], np.einsum( "ijklm->lkjim", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 3 * 6 * 6 * 2).reshape(3, 3, 6, 6, 2), transform_one, transform_one, transform_two, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[3:, 3:, :3, 3:], np.einsum( "ijklm->lkijm", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 6 * 6 * 6 * 2).reshape(3, 6, 6, 6, 2), transform_one, transform_two, transform_two, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[3:, 3:, 3:, :3], np.einsum( "ijklm->lkjim", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(3 * 6 * 6 * 6 * 2).reshape(3, 6, 6, 6, 2), transform_one, transform_two, transform_two, transform_two, ), ), ) assert np.allclose( test.construct_array_spherical()[3:, 3:, 3:, 3:], np.einsum( "ijklm->lkjim", np.einsum( "ijklm,ai,bj,ck,dl->abcdm", np.arange(6 * 6 * 6 * 6 * 2).reshape(6, 6, 6, 6, 2), transform_two, transform_two, transform_two, transform_two, ), ), )
def construct_array_mix(self, coord_types, **kwargs): """Return the array associated with all of the contractions in the given coordinate system. Parameters ---------- coord_types : list/tuple of str Types of the coordinate system for each GeneralizedContractionShell. Each entry must be one of "cartesian" or "spherical". kwargs : dict Other keyword arguments that will be used to construct the array. These keyword arguments are passed entirely to `construct_array_contraction`. See `construct_array_contraction` for details on the keyword arguments. Returns ------- array : np.ndarray(K_cont, ...) Array associated with the spherical contrations of the basis set. Dimension 0 is associated with each spherical contraction in the basis set. `K_cont` is the total number of contractions within the given basis set. Raises ------ TypeError If `coord_types` is not a list/tuple. ValueError If `coord_types` has an entry that is not "cartesian" or "spherical". If `coord_types` has different number of entries as the number of `GeneralizedContractionShell` (`contractions`) in instance. """ if not isinstance(coord_types, (list, tuple)): raise TypeError("`coord_types` must be a list or a tuple.") if not all(i in ["cartesian", "spherical"] for i in coord_types): raise ValueError( "Each entry of `coord_types` must be one of 'cartesian' or 'spherical'." ) if len(coord_types) != len(self.contractions): raise ValueError( "`coord_types` must have the same number of entries as the number of " "`GeneralizedContractionShell` in the instance.") matrices = [] for cont, coord_type in zip(self.contractions, coord_types): # get transformation from cartesian to spherical (applied to left) transform = generate_transformation(cont.angmom, cont.angmom_components_cart, cont.angmom_components_sph, "left") # evaluate the function at the given points matrix_contraction = self.construct_array_contraction( cont, **kwargs) # normalize contractions matrix_contraction *= cont.norm_cont.reshape( *matrix_contraction.shape[:2], *[1 for _ in matrix_contraction.shape[2:]]) # transform # ASSUME array always has shape (M, L, ...) if coord_type == "spherical": matrix_contraction = np.tensordot(transform, matrix_contraction, (1, 1)) matrix_contraction = np.swapaxes(matrix_contraction, 0, 1) matrix_contraction = np.concatenate(matrix_contraction, axis=0) # store matrices.append(matrix_contraction) return np.concatenate(matrices, axis=0)
def construct_array_mix(self, coord_types, **kwargs): """Return the array associated with a set of Gaussians of the given coordinate systems. Parameters ---------- coord_types : list/tuple of str Types of the coordinate system for each `GeneralizedContractionShell`. Each entry must be one of "cartesian" or "spherical". kwargs : dict Other keyword arguments that will be used to construct the array. Returns ------- array : np.ndarray(K_cont, K_cont, K_cont, K_cont, ...) Array associated with the atomic orbitals associated with the given set of contracted Cartesian Gaussians. Dimensions 0, 1, 2 and 3 of the array are associated with two contractions in the given coordinate system. `K_cont` is the total number of contractions within the instance. Raises ------ TypeError If `coord_types` is not a list/tuple. ValueError If `coord_types` has an entry that is not "cartesian" or "spherical". If `coord_types` has different number of entries as the number of `GeneralizedContractionShell` (`contractions`) in instance. """ # pylint: disable=C0103,R0914 if not isinstance(coord_types, (list, tuple)): raise TypeError("`coord_types` must be a list or a tuple.") if not all(i in ["cartesian", "spherical"] for i in coord_types): raise ValueError( "Each entry of `coord_types` must be one of 'cartesian' or 'spherical'." ) if len(coord_types) != len(self.contractions): raise ValueError( "`coord_types` must have the same number of entries as the number of " "`GeneralizedContractionShell` in the instance." ) all_blocks = np.zeros((len(self.contractions),) * 4, dtype=object) pair_i_cont = list( it.combinations_with_replacement( zip(range(len(self.contractions)), self.contractions, coord_types), 2 ) ) for pair_ind, ((i, cont_one, type_one), (j, cont_two, type_two)) in enumerate(pair_i_cont): transform_one = generate_transformation( cont_one.angmom, cont_one.angmom_components_cart, cont_one.angmom_components_sph, "left", ) transform_two = generate_transformation( cont_two.angmom, cont_two.angmom_components_cart, cont_two.angmom_components_sph, "left", ) for (k, cont_three, type_three), (l, cont_four, type_four) in pair_i_cont[pair_ind:]: transform_three = generate_transformation( cont_three.angmom, cont_three.angmom_components_cart, cont_three.angmom_components_sph, "left", ) transform_four = generate_transformation( cont_four.angmom, cont_four.angmom_components_cart, cont_four.angmom_components_sph, "left", ) block = self.construct_array_contraction( cont_one, cont_two, cont_three, cont_four, **kwargs ) # normalize contractions block *= cont_one.norm_cont.reshape(*block.shape[:2], *[1 for _ in block.shape[2:]]) block *= cont_two.norm_cont.reshape( 1, 1, *block.shape[2:4], *[1 for _ in block.shape[4:]] ) block *= cont_three.norm_cont.reshape( 1, 1, 1, 1, *block.shape[4:6], *[1 for _ in block.shape[6:]] ) block *= cont_four.norm_cont.reshape( 1, 1, 1, 1, 1, 1, *block.shape[6:8], *[1 for _ in block.shape[8:]] ) # transform if type_one == "spherical": block = np.tensordot(transform_one, block, (1, 1)) block = np.swapaxes(block, 0, 1) if type_two == "spherical": block = np.tensordot(transform_two, block, (1, 3)) block = np.swapaxes(np.swapaxes(np.swapaxes(block, 0, 1), 1, 2), 2, 3) if type_three == "spherical": block = np.tensordot(transform_three, block, (1, 5)) block = np.swapaxes( np.swapaxes( np.swapaxes(np.swapaxes(np.swapaxes(block, 0, 1), 1, 2), 2, 3), 3, 4 ), 4, 5, ) if type_four == "spherical": block = np.tensordot(transform_four, block, (1, 7)) block = np.swapaxes( np.swapaxes( np.swapaxes( np.swapaxes( np.swapaxes(np.swapaxes(np.swapaxes(block, 0, 1), 1, 2), 2, 3), 3, 4, ), 4, 5, ), 5, 6, ), 6, 7, ) # array has shape (M_1, L_1, M_2, L_2, M_3, L_3, M_4, L_4, ..) block = block.reshape( block.shape[0] * block.shape[1], block.shape[2] * block.shape[3], block.shape[4] * block.shape[5], block.shape[6] * block.shape[7], *block.shape[8:], ) # array now has shape (M_1 L_1, M_2 L_2, M_3, L_3, M_4, L_4, ...) all_blocks[i, j, k, l] = block all_blocks[i, j, l, k] = np.swapaxes(block, 2, 3) all_blocks[j, i, k, l] = np.swapaxes(block, 0, 1) all_blocks[j, i, l, k] = np.swapaxes(np.swapaxes(block, 2, 3), 0, 1) all_blocks[k, l, i, j] = np.swapaxes(np.swapaxes(block, 1, 3), 0, 2) all_blocks[l, k, i, j] = np.swapaxes( np.swapaxes(np.swapaxes(block, 1, 3), 0, 2), 0, 1 ) all_blocks[k, l, j, i] = np.swapaxes( np.swapaxes(np.swapaxes(block, 1, 3), 0, 2), 2, 3 ) all_blocks[l, k, j, i] = np.swapaxes(np.swapaxes(block, 1, 2), 0, 3) # concatenate return np.concatenate( [ np.concatenate( [ np.concatenate( [np.concatenate(blocks_three, axis=3) for blocks_three in blocks_two], axis=2, ) for blocks_two in blocks_one ], axis=1, ) for blocks_one in all_blocks ], axis=0, )
def test_generate_transformation_horton_negative_components(): """Test spherical.generate_transformation using horton reference and ORCA-style conventions. Conventions obtained from `IOData.formats.molden._fix_obasis_orca`. """ # Answer obtained from https://theochem.github.io/horton/2.0.1/tech_ref_gaussian_basis.html. answer = np.array([ [0, 0, -3 / 10 * 5**0.5, 0, 0, 0, 0, -3 / 10 * 5**0.5, 0, 1], [ -1 / 4 * 6**0.5, 0, 0, -1 / 20 * 30**0.5, 0, 1 / 5 * 30**0.5, 0, 0, 0, 0 ], [ 0, -1 / 20 * 30**0.5, 0, 0, 0, 0, -1 / 4 * 6**0.5, 0, 1 / 5 * 30**0.5, 0 ], [0, 0, 1 / 2 * 3**0.5, 0, 0, 0, 0, -1 / 2 * 3**0.5, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [-1 / 4 * 10**0.5, 0, 0, 3 / 4 * 2**0.5, 0, 0, 0, 0, 0, 0], [0, -3 / 4 * 2**0.5, 0, 0, 0, 0, 1 / 4 * 10**0.5, 0, 0, 0], ]) assert np.allclose( generate_transformation( 3, np.array([ [3, 0, 0], [2, 1, 0], [2, 0, 1], [1, 2, 0], [1, 1, 1], [1, 0, 2], [0, 3, 0], [0, 2, 1], [0, 1, 2], [0, 0, 3], ]), ("c0", "c1", "s1", "c2", "s2", "-c3", "-s3"), "left", ), answer, ) # taken from HORTON's gbasis/cartpure.cpp horton_transform = [ [0, 0, 0.375], [0, 3, 0.21957751641341996535], [0, 5, -0.87831006565367986142], [0, 10, 0.375], [0, 12, -0.87831006565367986142], [0, 14, 1.0], [1, 2, -0.89642145700079522998], [1, 7, -0.40089186286863657703], [1, 9, 1.19522860933439364], [2, 4, -0.40089186286863657703], [2, 11, -0.89642145700079522998], [2, 13, 1.19522860933439364], [3, 0, -0.5590169943749474241], [3, 5, 0.9819805060619657157], [3, 10, 0.5590169943749474241], [3, 12, -0.9819805060619657157], [4, 1, -0.42257712736425828875], [4, 6, -0.42257712736425828875], [4, 8, 1.1338934190276816816], [5, 2, 0.790569415042094833], [5, 7, -1.0606601717798212866], [6, 4, 1.0606601717798212866], [6, 11, -0.790569415042094833], [7, 0, 0.73950997288745200532], [7, 3, -1.2990381056766579701], [7, 10, 0.73950997288745200532], [8, 1, 1.1180339887498948482], [8, 6, -1.1180339887498948482], ] answer = np.zeros((9, 15)) for i in horton_transform: # Negative of c3, s3, c4, s4 if i[0] > 4: answer[i[0], i[1]] = -i[2] else: answer[i[0], i[1]] = i[2] assert np.allclose( generate_transformation( 4, np.array([ [4, 0, 0], [3, 1, 0], [3, 0, 1], [2, 2, 0], [2, 1, 1], [2, 0, 2], [1, 3, 0], [1, 2, 1], [1, 1, 2], [1, 0, 3], [0, 4, 0], [0, 3, 1], [0, 2, 2], [0, 1, 3], [0, 0, 4], ]), ("c0", "c1", "s1", "c2", "s2", "-c3", "-s3", "-c4", "-s4"), "left", ), answer, )