def compute_the_fixed_phase_overlaps(
        paths_overlaps: List, path_hdf5: str, project_name: str,
        enumerate_from: int, nHOMO: int) -> Tuple:
    """
    First track the unavoided crossings between Molecular orbitals and
    finally correct the phase for the whole trajectory.
    """
    number_of_frames = len(paths_overlaps)
    # Pasth to the overlap matrices after the tracking
    # and phase correction
    roots = [join(project_name, 'overlaps_{}'.format(i))
             for i in range(enumerate_from, number_of_frames + enumerate_from)]
    paths_corrected_overlaps = [join(r, 'mtx_sji_t0_corrected') for r in roots]
    # Paths inside the HDF5 to the array containing the tracking of the
    # unavoided crossings
    path_swaps = join(project_name, 'swaps')

    # Compute the corrected overlaps if not avaialable in the HDF5
    if not is_data_in_hdf5(path_hdf5, paths_corrected_overlaps[0]):

        # Compute the dimension of the coupling matrix
        mtx_0 = retrieve_hdf5_data(path_hdf5, paths_overlaps[0])
        _, dim = mtx_0.shape

        # Read all the Overlaps
        overlaps = np.stack([retrieve_hdf5_data(path_hdf5, ps)
                             for ps in paths_overlaps])

        # Number of couplings to compute
        nCouplings = overlaps.shape[0]

        # Compute the unavoided crossing using the Overlap matrix
        # and correct the swaps between Molecular Orbitals
        logger.debug("Computing the Unavoided crossings, "
                     "Tracking the crossings between MOs")
        overlaps, swaps = track_unavoided_crossings(overlaps, nHOMO)

        # Compute all the phases taking into account the unavoided crossings
        logger.debug("Computing the phases of the MOs")
        mtx_phases = compute_phases(overlaps, nCouplings, dim)

        # Fixed the phases of the whole set of overlap matrices
        fixed_phase_overlaps = correct_phases(overlaps, mtx_phases)

        # Store corrected overlaps in the HDF5
        store_arrays_in_hdf5(path_hdf5, paths_corrected_overlaps,
                             fixed_phase_overlaps)

        # Store the Swaps tracking the crossing
        store_arrays_in_hdf5(path_hdf5, path_swaps, swaps, dtype=np.int32)
    else:
        # Read the corrected overlaps and the swaps from the HDF5
        fixed_phase_overlaps = np.stack(
            retrieve_hdf5_data(path_hdf5, paths_corrected_overlaps))
        swaps = retrieve_hdf5_data(path_hdf5, path_swaps)

    return fixed_phase_overlaps, swaps
def compute_excited_states_tddft(config: dict, path_MOs: list, dict_input: dict):
    """
    Compute the excited states properties (energy and coefficients) for a given
    `mo_index_range` using the `tddft` method and `xc_dft` exchange functional.
    """
    logger.info("Reading energies and mo coefficients")
    # type of calculation
    energy, c_ao = retrieve_hdf5_data(config.path_hdf5, path_MOs)

    # Number of virtual orbitals
    nocc = config.active_space[0]
    nvirt = config.active_space[1]
    dict_input.update({"energy": energy, "c_ao": c_ao, "nocc": nocc, "nvirt": nvirt})

    # Pass the molecule in Angstrom to the libint calculator
    copy_dict = DictConfig(dict_input.copy())
    copy_dict["mol"] = change_mol_units(dict_input["mol"], factor=1/angs2au)

    # compute the multipoles if they are not stored
    multipoles = get_multipole_matrix(config, copy_dict, 'dipole')

    # read data from the HDF5 or calculate it on the fly
    dict_input["overlap"] = multipoles[0]

    # retrieve or compute the omega xia values
    omega, xia = get_omega_xia(config, dict_input)

    # add arrays to the dictionary
    dict_input.update({"multipoles": multipoles[1:], "omega": omega, "xia": xia})

    return compute_oscillator_strengths(
        config, dict_input)
def get_omega_xia(config: dict, dict_input: dict):
    """
    Search for the multipole_matrices, Omega and xia values in the HDF5,
    if they are not available compute and store them.
    """
    tddft = config.tddft.lower()

    def compute_omega_xia():
        if tddft == 'sing_orb':
            return compute_sing_orb(dict_input)
        else:
            return compute_std_aproximation(config, dict_input)

    # search data in HDF5
    root = join(config.project_name, 'omega_xia', tddft, 'point_{}'.format(dict_input.i + config.enumerate_from))
    paths_omega_xia = [join(root, x) for x in ("omega", "xia")]

    if is_data_in_hdf5(config.path_hdf5, paths_omega_xia):
        return tuple(retrieve_hdf5_data(config.path_hdf5, paths_omega_xia))
    else:
        omega, xia = compute_omega_xia()
        store_arrays_in_hdf5(config.path_hdf5, paths_omega_xia[0], omega, dtype=omega.dtype)
        store_arrays_in_hdf5(config.path_hdf5, paths_omega_xia[1], xia, dtype=xia.dtype)

        return omega, xia
def lazy_couplings(config: dict, paths_overlaps: list) -> list:
    """
    Compute the Nonadibatic coupling using a 3 point approximation. See:
    The Journal of Chemical Physics 137, 22A514 (2012); doi: 10.1063/1.4738960

    or a 2Point approximation using an smoothing function:
    J. Phys. Chem. Lett. 2014, 5, 2351−2356; doi: 10.1021/jz5009449

    Notice that the states can cross frequently due to unavoided crossing and
    such crossing must be track. see:
    J. Chem. Phys. 137, 014512 (2012); doi: 10.1063/1.4732536
    """
    if config.tracking:
        fixed_phase_overlaps, swaps = compute_the_fixed_phase_overlaps(
            paths_overlaps, config.path_hdf5, config.project_name,
            config.enumerate_from, config.nHOMO)
    else:
        # Do not track the crossings
        mtx_0 = retrieve_hdf5_data(config.path_hdf5, paths_overlaps[0])
        _, dim = mtx_0.shape
        overlaps = np.stack(
            retrieve_hdf5_data(config.path_hdf5, paths_overlaps))
        nOverlaps, nOrbitals, _ = overlaps.shape
        swaps = np.tile(np.arange(nOrbitals), (nOverlaps + 1, 1))
        mtx_phases = compute_phases(overlaps, nOverlaps, dim)
        fixed_phase_overlaps = correct_phases(overlaps, mtx_phases)

    # Write the overlaps in text format
    logger.debug("Writing down the overlaps in ascii format")
    write_overlaps_in_ascii(fixed_phase_overlaps)

    # Compute the couplings using either the levine method
    # or the 3Points approximation
    coupling_algorithms = {'levine': (calculate_couplings_levine, 1),
                           '3points': (calculate_couplings_3points, 2)}
    # Choose an algorithm to compute the couplings
    fun_coupling, step = coupling_algorithms[config["algorithm"]]
    config["fun_coupling"] = fun_coupling

    # Number of couplings to compute
    nCouplings = fixed_phase_overlaps.shape[0] - step + 1
    couplings = [calculate_couplings(config, i, fixed_phase_overlaps)
                 for i in range(nCouplings)]

    return swaps, couplings
def search_multipole_in_hdf5(path_hdf5: str, path_multipole_hdf5: str, multipole: str):
    """
    Search if the multipole is already store in the HDFt
    """
    if is_data_in_hdf5(path_hdf5, path_multipole_hdf5):
        print("retrieving multipole: {} from the hdf5".format(multipole))
        return retrieve_hdf5_data(path_hdf5, path_multipole_hdf5)
    else:
        print("computing multipole: {}".format(multipole))
        return None
def check_properties(path_test_hdf5):
    """
    Check that the tensor stored in the HDF5 are correct.
    """
    dipole_matrices = retrieve_hdf5_data(
        path_test_hdf5, 'Cd/multipole/point_0/dipole')

    # The diagonals of each component of the matrix must be zero
    # for a single atom
    diagonals = np.sum([np.diag(dipole_matrices[n + 1]) for n in range(3)])
    assert abs(diagonals) < 1e-16
def read_overlap_data(config: dict, mo_paths: list) -> Tuple:
    """
    Read the Molecular orbital coefficients and the transformation matrix
    """
    mos = retrieve_hdf5_data(config.path_hdf5, mo_paths)

    # Extract a subset of molecular orbitals to compute the coupling
    lowest, highest = compute_range_orbitals(mos[0], config.nHOMO, config.mo_index_range)
    css0, css1 = tuple(map(lambda xs: xs[:, lowest: highest], mos))

    return css0, css1
def read_overlap_data(config: dict, mo_paths: list) -> tuple:
    """
    Read the Molecular orbital coefficients and the transformation matrix
    """
    mos = retrieve_hdf5_data(config.path_hdf5, mo_paths)

    # Extract a subset of molecular orbitals to compute the coupling
    lowest, highest = compute_range_orbitals(config)
    css0, css1 = tuple(map(lambda xs: xs[:, lowest: highest], mos))

    return css0, css1
Exemple #9
0
def read_swaps(path_hdf5: str, project_name: str) -> Matrix:
    """
    Read the crossing tracking for the Molecular orbital
    """
    path_swaps = join(project_name, 'swaps')
    if search_data_in_hdf5(path_hdf5, path_swaps):
        return retrieve_hdf5_data(path_hdf5, path_swaps)
    else:
        msg = """There is not a tracking file called: {}
        This file is automatically created when running the worflow_coupling
        simulations""".format(path_swaps)
        raise RuntimeError(msg)
def read_swaps(path_hdf5: str, project_name: str) -> Matrix:
    """
    Read the crossing tracking for the Molecular orbital
    """
    path_swaps = join(project_name, 'swaps')
    if is_data_in_hdf5(path_hdf5, path_swaps):
        return retrieve_hdf5_data(path_hdf5, path_swaps)
    else:
        msg = """There is not a tracking file called: {}
        This file is automatically created when running the worflow_coupling
        simulations""".format(path_swaps)
        raise RuntimeError(msg)
def check_properties(path_test_hdf5):
    """
    Test if the coupling coupling by the Levine method is correct
    """
    # Paths to all the arrays to test
    path_swaps = join(project_name, 'swaps')
    name_Sji = 'overlaps_{}/mtx_sji_t0'
    name_Sji_fixed = 'overlaps_{}/mtx_sji_t0_corrected'
    path_overlaps = [join(project_name, name_Sji.format(i)) for i in range(4)]
    path_fixed_overlaps = [
        join(project_name, name_Sji_fixed.format(i)) for i in range(4)
    ]
    path_couplings = [
        join(project_name, 'coupling_{}'.format(i)) for i in range(4)
    ]

    # Define partial func
    fun_original = partial(stack_retrieve, path_original_hdf5)
    fun_test = partial(stack_retrieve, path_test_hdf5)

    # Read data from the HDF5
    swaps_original = retrieve_hdf5_data(path_original_hdf5, path_swaps)
    swaps_test = retrieve_hdf5_data(path_test_hdf5, path_swaps)

    overlaps_original = fun_original(path_overlaps)
    overlaps_test = fun_test(path_overlaps)

    fixed_overlaps_original = fun_original(path_fixed_overlaps)
    fixed_overlaps_test = fun_test(path_fixed_overlaps)

    css_original = fun_original(path_couplings)
    css_test = fun_test(path_couplings)

    # Test data
    b1 = np.allclose(swaps_original, swaps_test)
    b2 = np.allclose(overlaps_original, overlaps_test)
    b3 = np.allclose(fixed_overlaps_original, fixed_overlaps_test)
    b4 = np.allclose(css_original, css_test)

    assert all((b1, b2, b3, b4))
Exemple #12
0
def lazy_couplings(paths_overlaps: List,
                   path_hdf5: str,
                   project_name: str,
                   enumerate_from: int,
                   nHOMO: int,
                   dt: float,
                   tracking: bool,
                   algorithm='levine') -> List:
    """
    Compute the Nonadibatic coupling using a 3 point approximation. See:
    The Journal of Chemical Physics 137, 22A514 (2012); doi: 10.1063/1.4738960

    or a 2Point approximation using an smoothing function:
    J. Phys. Chem. Lett. 2014, 5, 2351−2356; doi: 10.1021/jz5009449

    Notice that the states can cross frequently due to unavoided crossing and
    such crossing must be track. see:
    J. Chem. Phys. 137, 014512 (2012); doi: 10.1063/1.4732536
    """
    if tracking:
        fixed_phase_overlaps, swaps = compute_the_fixed_phase_overlaps(
            paths_overlaps, path_hdf5, project_name, enumerate_from, nHOMO)
    else:
        # Do not track the crossings
        fixed_phase_overlaps = np.stack(
            retrieve_hdf5_data(path_hdf5, paths_overlaps))
        nOverlaps, nOrbitals, _ = fixed_phase_overlaps.shape
        swaps = np.tile(np.arange(nOrbitals), (nOverlaps + 1, 1))

    # Compute the couplings using either the levine method
    # or the 3Points approximation
    coupling_algorithms = {
        'levine': (calculate_couplings_levine, 1),
        '3points': (calculate_couplings_3points, 2)
    }
    # Choose an algorithm to compute the couplings
    fun_coupling, step = coupling_algorithms[algorithm]

    # Number of couplings to compute
    nCouplings = fixed_phase_overlaps.shape[0] - step + 1

    # time in atomic units
    dt_au = dt * femtosec2au

    couplings = [
        calculate_couplings(fun_coupling, algorithm, i, project_name,
                            fixed_phase_overlaps, path_hdf5, enumerate_from,
                            dt_au) for i in range(nCouplings)
    ]

    return swaps, couplings
def test_cube():
    """
    Test the density compute to create a cube file.
    """
    if not os.path.exists(scratch_path):
        os.makedirs(scratch_path)

    # Overlap matrix in cartesian coordinates
    basisname = "DZVP-MOLOPT-SR-GTH"

    # Read coordinates
    molecule = change_mol_units(readXYZ(path_xyz))

    # String representation of the molecule
    geometries = split_file_geometries(path_xyz)

    try:
        shutil.copy(path_original_hdf5, path_test_hdf5)
        # Contracted Gauss functions
        dictCGFs = create_dict_CGFs(path_test_hdf5, basisname, molecule)

        dict_global_norms = compute_normalization_sphericals(dictCGFs)

        # Compute the transformation matrix and store it in the HDF5
        with h5py.File(path_test_hdf5, 'r') as f5:
            transf_mtx = calc_transf_matrix(
                f5, molecule, basisname, dict_global_norms, 'cp2k')

        path_transf_mtx = join(project_name, 'trans_mtx')
        store_arrays_in_hdf5(
            path_test_hdf5, path_transf_mtx, transf_mtx)

        # voxel size and Number of steps
        grid_data = GridCube(0.300939, 80)

        rs = workflow_compute_cubes(
            'cp2k', project_name, package_args, path_time_coeffs=None,
            grid_data=grid_data, guess_args=None, geometries=geometries,
            dictCGFs=dictCGFs, calc_new_wf_guess_on_points=[],
            path_hdf5=path_test_hdf5, enumerate_from=0, package_config=None,
            traj_folders=None, work_dir=scratch_path, basisname=basisname,
            hdf5_trans_mtx=path_transf_mtx, nHOMO=6, orbitals_range=(6, 6),
            ignore_warnings=False)

        xs = retrieve_hdf5_data(path_test_hdf5, rs)[0]
        np.save("grid_density", xs)

    finally:
        # Remove intermediate results
        shutil.rmtree(scratch_path)
    def write_data(i):
        j = i + config.enumerate_from
        path_coupling = path_couplings[i]
        css = retrieve_hdf5_data(config.path_hdf5, path_coupling)

        # Extract the energy values at time t
        # The first coupling is compute at time t + dt
        # Then I'm shifting the energies dt to get the correct value
        energies_t0 = retrieve_hdf5_data(config.path_hdf5, mo_paths_hdf5[i][0])
        energies_t1 = retrieve_hdf5_data(config.path_hdf5, mo_paths_hdf5[i + 1][0])

        # Return the average between time t and t + dt
        energies = np.average((energies_t0, energies_t1), axis=0)

        # Print Energies in the range given by the user
        if all(x is not None for x in [nHOMO, mo_index_range]):
            lowest = nHOMO - mo_index_range[0]
            highest = nHOMO + mo_index_range[1]
            energies = energies[lowest: highest]

        # Swap the energies of the states that are crossing
        energies = energies[swaps[i + 1]]

        # FileNames
        path_dir_results = config.path_hamiltonians
        file_ham_im = join(path_dir_results, 'Ham_{}_im'.format(j))
        file_ham_re = join(path_dir_results, 'Ham_{}_re'.format(j))

        # convert to Rydbergs
        ham_im = 2.0 * css
        ham_re = np.diag(2.0 * energies)

        write_pyxaid_format(ham_im, file_ham_im)
        write_pyxaid_format(ham_re, file_ham_re)

        return (file_ham_im, file_ham_re)
    def write_data(i):
        j = i + config.enumerate_from
        path_coupling = path_couplings[i]
        css = retrieve_hdf5_data(config.path_hdf5, path_coupling)

        # Extract the energy values at time t
        # The first coupling is compute at time t + dt
        # Then I'm shifting the energies dt to get the correct value
        energies_t0 = retrieve_hdf5_data(config.path_hdf5, mo_paths_hdf5[i][0])
        energies_t1 = retrieve_hdf5_data(
            config.path_hdf5, mo_paths_hdf5[i + 1][0])

        # Return the average between time t and t + dt
        energies = np.average((energies_t0, energies_t1), axis=0)

        # Print Energies in the range given by the user
        if all(x is not None for x in [nHOMO, mo_index_range]):
            lowest, highest = compute_range_orbitals(config)
            energies = energies[lowest: highest]

        # Swap the energies of the states that are crossing
        energies = energies[swaps[i + 1]]

        # FileNames
        path_dir_results = config.path_hamiltonians
        file_ham_im = join(path_dir_results, f'Ham_{i}_im')
        file_ham_re = join(path_dir_results, f'Ham_{j}_re')

        # convert to Rydbergs
        ham_im = 2.0 * css
        ham_re = np.diag(2.0 * energies)

        write_pyxaid_format(ham_im, file_ham_im)
        write_pyxaid_format(ham_re, file_ham_re)

        return (file_ham_im, file_ham_re)
def check_couplings(config: dict, tmp_hdf5: str) -> None:
    """
    Check that the couplings have meaningful values
    """
    def create_paths(keyword: str) -> list:
        return ['{}/{}_{}'.format(config.project_name, keyword, x)
                for x in range(len(config.geometries) - 1)]
    overlaps = create_paths('overlaps')
    couplings = create_paths('coupling')

    # Check that couplings and overlaps exists
    assert is_data_in_hdf5(tmp_hdf5, overlaps)
    assert is_data_in_hdf5(tmp_hdf5, couplings)

    # All the elements are different of inifinity or nan
    tensor_couplings = np.stack(retrieve_hdf5_data(tmp_hdf5, couplings))
    assert np.isfinite(tensor_couplings).all()
def compute_photoexcitation(path_hdf5: str, time_dependent_coeffs: Matrix,
                            paths_fragment_overlaps: List,
                            map_index_pyxaid_hdf5: Matrix, swaps: Matrix,
                            n_points: int, pyxaid_iconds: List,
                            dt_au: float) -> List:
    """
    :param i: Electron transfer rate at time i * dt
    :param path_hdf5: Path to the HDF5 file that contains the
    numerical results.
    :param geometries: list of 3 contiguous molecular geometries
    :param time_depend_paths: mean value of the time dependent coefficients
    computed with PYXAID.
    param fragment_overlaps: Tensor containing 3 overlap matrices corresponding
    with the `geometries`.
    :param map_index_pyxaid_hdf5: map from PYXAID excitation to the indices i,j
    of the molecular orbitals stored in the HDF5.
    :param swaps: Matrix containing the crossing between the MOs during the
    molecular dynamics.
    :param n_points: Number of frames to compute the ETR.
    :param pyxaid_iconds: List of initial conditions
    :param dt_au: Delta time in atomic units
    :returns: promise to path to the Coupling inside the HDF5.
    """
    msg = "Computing the photo-excitation rate for the molecular fragments"
    logger.info(msg)

    results = []

    for paths_overlaps in paths_fragment_overlaps:
        overlaps = np.stack(retrieve_hdf5_data(path_hdf5, paths_overlaps))
        # Track the crossing between MOs
        for k, mtx in enumerate(np.rollaxis(overlaps, 0)):
            overlaps[k] = mtx[:, swaps[k]][swaps[k]]

        etr = np.stack(
            np.array([
                photo_excitation_rate(overlaps[i:i + 3], time_dependent_coeffs[
                    j, i:i + 3], map_index_pyxaid_hdf5, dt_au)
                for i in range(n_points)
            ]) for j in range(len(pyxaid_iconds)))

        etr = np.mean(etr, axis=0)

        results.append(etr)

    return np.stack(results)
Exemple #18
0
def write_overlap_densities(path_hdf5: str, paths_fragment_overlaps: List, dt: int=1):
    """
    Write the diagonal of the overlap matrices
    """
    logger.info("writing densities in human readable format")
    for k, paths_overlaps in enumerate(paths_fragment_overlaps):
        overlaps = np.stack(retrieve_hdf5_data(path_hdf5, paths_overlaps))
        # time frame
        frames = overlaps.shape[0]
        ts = np.arange(1, frames + 1).reshape(frames, 1) * dt
        # Diagonal of the 3D-tensor
        densities = np.diagonal(overlaps, axis1=1, axis2=2)
        data = np.hstack((ts, densities))

        # Save data in human readable format
        file_name = 'densities_fragment_{}.txt'.format(k)
        np.savetxt(file_name, data, fmt='{:^3}'.format('%e'))
def compute_excited_states_tddft(config: dict, path_MOs: list,
                                 dict_input: dict):
    """
    Compute the excited states properties (energy and coefficients) for a given
    `mo_index_range` using the `tddft` method and `xc_dft` exchange functional.
    """
    logger.info("Reading energies and mo coefficients")
    # type of calculation
    energy, c_ao = retrieve_hdf5_data(config.path_hdf5, path_MOs)

    # Number of virtual orbitals
    nocc = config.active_space[0]
    nvirt = config.active_space[1]
    dict_input.update({
        "energy": energy,
        "c_ao": c_ao,
        "nocc": nocc,
        "nvirt": nvirt
    })

    # Pass the molecule in Angstrom to the libint calculator
    copy_dict = DictConfig(dict_input.copy())
    copy_dict["mol"] = change_mol_units(dict_input["mol"], factor=1 / angs2au)

    # compute the multipoles if they are not stored
    multipoles = get_multipole_matrix(config, copy_dict, 'dipole')

    # read data from the HDF5 or calculate it on the fly
    dict_input["overlap"] = multipoles[0]

    # retrieve or compute the omega xia values
    omega, xia = get_omega_xia(config, dict_input)

    # add arrays to the dictionary
    dict_input.update({
        "multipoles": multipoles[1:],
        "omega": omega,
        "xia": xia
    })

    return compute_oscillator_strengths(config, dict_input)
def stack_retrieve(path_hdf5, path_prop):
    """
    Retrieve a list of Numpy arrays and create a tensor out of it
    """
    return np.stack(retrieve_hdf5_data(path_hdf5, path_prop))
Exemple #21
0
def calcOscillatorStrenghts(i: int,
                            project_name: str,
                            mo_paths_hdf5: str,
                            dictCGFs: Dict,
                            atoms: List,
                            path_hdf5: str,
                            hdf5_trans_mtx: str = None,
                            initial_states: Vector = None,
                            final_states: Matrix = None):
    """
    Use the Molecular orbital Energies and Coefficients to compute the
    oscillator_strength.

    :param i: time frame
    :param project_name: Folder name where the computations
    are going to be stored.
    :param mo_paths_hdf5: Path to the MO coefficients and energies in the
    HDF5 file.
    :paramter dictCGFS: Dictionary from Atomic Label to basis set.
    :type     dictCGFS: Dict String [CGF],
              CGF = ([Primitives], AngularMomentum),
              Primitive = (Coefficient, Exponent)
    :param atoms: Molecular geometry.
    :type atoms: [namedtuple("AtomXYZ", ("symbol", "xyz"))]
    :param path_hdf5: Path to the HDF5 file that contains the
    numerical results.
    :param hdf5_trans_mtx: path to the transformation matrix in the HDF5 file.
    :param initial_states: List of the initial Electronic states.
    :type initial_states: [Int]
    :param final_states: List containing the sets of possible electronic
    states.
    :type final_states: [[Int]]
    """
    # Energy and coefficients at time t
    es, coeffs = retrieve_hdf5_data(path_hdf5, mo_paths_hdf5[i])

    # If the MO orbitals are given in Spherical Coordinates transform then to
    # Cartesian Coordinates.
    if hdf5_trans_mtx is not None:
        trans_mtx = retrieve_hdf5_data(path_hdf5, hdf5_trans_mtx)

    logger.info("Computing the oscillator strength at time: {}".format(i))
    # Overlap matrix

    # Origin of the dipole
    rc = compute_center_of_mass(atoms)

    # Dipole matrix element in spherical coordinates
    path_dipole_matrices = join(project_name, 'point_{}'.format(i),
                                'dipole_matrices')

    if search_data_in_hdf5(path_hdf5, path_dipole_matrices):
        mtx_integrals_spher = retrieve_hdf5_data(path_hdf5,
                                                 path_dipole_matrices)
    else:
        # Compute the Dipole matrices and store them in the HDF5
        mtx_integrals_spher = calcDipoleCGFS(atoms, dictCGFs, rc, trans_mtx)
        store_arrays_in_hdf5(path_hdf5, path_dipole_matrices,
                             mtx_integrals_spher)

    oscillators = [
        compute_oscillator_strength(rc, atoms, dictCGFs, es, coeffs,
                                    mtx_integrals_spher, initialS, fs)
        for initialS, fs in zip(initial_states, final_states)
    ]

    return oscillators
Exemple #22
0
def compute_the_fixed_phase_overlaps(paths_overlaps: List, path_hdf5: str,
                                     project_name: str, enumerate_from: int,
                                     nHOMO: int) -> Tuple:
    """
    First track the unavoided crossings between Molecular orbitals and
    finally correct the phase for the whole trajectory.
    """
    number_of_frames = len(paths_overlaps)
    # Pasth to the overlap matrices after the tracking
    # and phase correction
    roots = [
        join(project_name, 'overlaps_{}'.format(i))
        for i in range(enumerate_from, number_of_frames + enumerate_from)
    ]
    paths_corrected_overlaps = [join(r, 'mtx_sji_t0_corrected') for r in roots]
    # Paths inside the HDF5 to the array containing the tracking of the
    # unavoided crossings
    path_swaps = join(project_name, 'swaps')

    # Compute the corrected overlaps if not avaialable in the HDF5
    if not search_data_in_hdf5(path_hdf5, paths_corrected_overlaps[0]):

        # Compute the dimension of the coupling matrix
        mtx_0 = retrieve_hdf5_data(path_hdf5, paths_overlaps[0])
        _, dim = mtx_0.shape

        # Read all the Overlaps
        overlaps = np.stack(
            [retrieve_hdf5_data(path_hdf5, ps) for ps in paths_overlaps])

        # Number of couplings to compute
        nCouplings = overlaps.shape[0]

        # Compute the unavoided crossing using the Overlap matrix
        # and correct the swaps between Molecular Orbitals
        logger.debug("Computing the Unavoided crossings, "
                     "Tracking the crossings between MOs")
        overlaps, swaps = track_unavoided_crossings(overlaps, nHOMO)

        # Compute all the phases taking into account the unavoided crossings
        logger.debug("Computing the phases of the MOs")
        mtx_phases = compute_phases(overlaps, nCouplings, dim)

        # Fixed the phases of the whole set of overlap matrices
        fixed_phase_overlaps = correct_phases(overlaps, mtx_phases)

        # Store corrected overlaps in the HDF5
        store_arrays_in_hdf5(path_hdf5, paths_corrected_overlaps,
                             fixed_phase_overlaps)

        # Store the Swaps tracking the crossing
        store_arrays_in_hdf5(path_hdf5, path_swaps, swaps, dtype=np.int32)
    else:
        # Read the corrected overlaps and the swaps from the HDF5
        fixed_phase_overlaps = np.stack(
            retrieve_hdf5_data(path_hdf5, paths_corrected_overlaps))
        swaps = retrieve_hdf5_data(path_hdf5, path_swaps)

    # Write the overlaps in text format
    logger.debug("Writing down the overlaps in ascii format")
    write_overlaps_in_ascii(fixed_phase_overlaps)

    return fixed_phase_overlaps, swaps
Exemple #23
0
def compute_matrix_multipole(mol: List, config: Dict,
                             multipole: str) -> Matrix:
    """
    Compute the some `multipole` matrix: overlap, dipole, etc. for a given geometry `mol`.
    Compute the Multipole matrix in cartesian coordinates and
    expand it to a matrix and finally convert it to spherical coordinates.

    :returns: Matrix with entries <ψi | x y z | ψj>
    """
    path_hdf5 = config['path_hdf5']
    runner = config['runner']

    # Compute the number of cartesian basis functions
    dictCGFs = config['dictCGFs']
    n_cart_funcs = np.sum(np.stack(len(dictCGFs[at.symbol]) for at in mol))

    # Compute the transformation matrix from cartesian to spherical
    transf_mtx = retrieve_hdf5_data(path_hdf5, config['hdf5_trans_mtx'])
    transf_mtx = sparse.csr_matrix(transf_mtx)
    transpose = transf_mtx.transpose()

    if multipole == 'overlap':
        rs = calcMtxOverlapP(mol, dictCGFs, runner)
        mtx_overlap = triang2mtx(
            rs, n_cart_funcs)  # there are 1452 Cartesian basis CGFs
        matrix_multipole = transf_mtx.dot(
            sparse.csr_matrix.dot(mtx_overlap, transpose))

    else:
        rc = compute_center_of_mass(mol)
        exponents = {
            'dipole': [{
                'e': 1,
                'f': 0,
                'g': 0
            }, {
                'e': 0,
                'f': 1,
                'g': 0
            }, {
                'e': 0,
                'f': 0,
                'g': 1
            }],
            'quadrupole': [{
                'e': 2,
                'f': 0,
                'g': 0
            }, {
                'e': 0,
                'f': 2,
                'g': 0
            }, {
                'e': 0,
                'f': 0,
                'g': 2
            }]
        }
        mtx_integrals_triang = tuple(
            calcMtxMultipoleP(mol, dictCGFs, runner, rc, **kw)
            for kw in exponents[multipole])
        mtx_integrals_cart = tuple(
            triang2mtx(xs, n_cart_funcs) for xs in mtx_integrals_triang)
        matrix_multipole = np.stack(
            transf_mtx.dot(sparse.csr_matrix.dot(x, transpose))
            for x in mtx_integrals_cart)

    return matrix_multipole