def _register_driver(cls):
    # Verify that the driver is not already registered.
    if cls in [driver.cls for driver in _REGISTERED_DRIVERS.values()]:
        raise QiskitChemistryError(
            'Could not register class {} is already registered'.format(cls))

    # Verify that it has a minimal valid configuration.
    try:
        driver_name = cls.CONFIGURATION['name']
    except (LookupError, TypeError):
        raise QiskitChemistryError(
            'Could not register driver: invalid configuration')

    # Verify that the driver is valid
    check_driver_valid = getattr(cls, 'check_driver_valid', None)
    if check_driver_valid is not None:
        try:
            check_driver_valid()
        except Exception as e:
            logger.debug(str(e))
            raise QiskitChemistryError(
                'Could not register class {}. Name {} is not valid'.format(
                    cls, driver_name)) from e

    if driver_name in _REGISTERED_DRIVERS:
        raise QiskitChemistryError(
            'Could not register class {}. Name {} {} is already registered'.
            format(cls, driver_name, _REGISTERED_DRIVERS[driver_name].cls))

    # Append the driver to the `registered_classes` dict.
    _REGISTERED_DRIVERS[driver_name] = RegisteredDriver(
        driver_name, cls, copy.deepcopy(cls.CONFIGURATION))
    return driver_name
    def _run_g16(cfg):

        # Run Gaussian 16. We capture stdout and if error log the last 10 lines that
        # should include the error description from Gaussian
        process = None
        try:
            process = Popen(GAUSSIAN_16, stdin=PIPE, stdout=PIPE, universal_newlines=True)
            stdout, stderr = process.communicate(cfg)
            process.wait()
        except:
            if process is not None:
                process.kill()

            raise QiskitChemistryError('{} run has failed'.format(GAUSSIAN_16_DESC))

        if process.returncode != 0:
            errmsg = ""
            if stdout is not None:
                lines = stdout.splitlines()
                start = 0
                if len(lines) > 10:
                    start = len(lines) - 10
                for i in range(start, len(lines)):
                    logger.error(lines[i])
                    errmsg += lines[i] + "\n"
            raise QiskitChemistryError('{} process return code {}\n{}'.format(GAUSSIAN_16_DESC, process.returncode, errmsg))
        else:
            if logger.isEnabledFor(logging.DEBUG):
                alltext = ""
                if stdout is not None:
                    lines = stdout.splitlines()
                    for line in lines:
                        alltext += line + "\n"
                logger.debug("Gaussian output:\n{}".format(alltext))
示例#3
0
    def _run_psi4(input_file, output_file):

        # Run psi4.
        process = None
        try:
            process = subprocess.Popen([PSI4, input_file, output_file],
                                       stdout=subprocess.PIPE,
                                       universal_newlines=True)
            stdout, stderr = process.communicate()
            process.wait()
        except:
            if process is not None:
                process.kill()

            raise QiskitChemistryError('{} run has failed'.format(PSI4))

        if process.returncode != 0:
            errmsg = ""
            if stdout is not None:
                lines = stdout.splitlines()
                for i in range(len(lines)):
                    logger.error(lines[i])
                    errmsg += lines[i] + "\n"
            raise QiskitChemistryError('{} process return code {}\n{}'.format(
                PSI4, process.returncode, errmsg))
def _check_molecule_format(val):
    """If it seems to be zmatrix rather than xyz format we convert before returning"""
    atoms = [x.strip() for x in val.split(';')]
    if atoms is None or len(atoms) < 1:
        raise QiskitChemistryError('Molecule format error: ' + val)

    # An xyz format has 4 parts in each atom, if not then do zmatrix convert
    # Allows dummy atoms, using symbol 'X' in zmatrix format for coord computation to xyz
    parts = [x.strip() for x in atoms[0].split(' ')]
    if len(parts) != 4:
        try:
            zmat = []
            for atom in atoms:
                parts = [x.strip() for x in atom.split(' ')]
                z = [parts[0]]
                for i in range(1, len(parts), 2):
                    z.append(int(parts[i]))
                    z.append(float(parts[i + 1]))
                zmat.append(z)
            xyz = z2xyz(zmat)
            new_val = ""
            for i in range(len(xyz)):
                atm = xyz[i]
                if atm[0].upper() == 'X':
                    continue
                if len(new_val) > 0:
                    new_val += "; "
                new_val += "{} {} {} {}".format(atm[0], atm[1], atm[2], atm[3])
            return new_val
        except Exception as exc:
            raise QiskitChemistryError('Failed to convert atom string: ' +
                                       val) from exc

    return val
    def _augment_config(self, fname, cfg):
        cfgaug = ""
        with io.StringIO() as outf:
            with io.StringIO(cfg) as inf:
                # Add our Route line at the end of any existing ones
                line = ""
                added = False
                while not added:
                    line = inf.readline()
                    if not line:
                        break
                    if line.startswith('#'):
                        outf.write(line)
                        while not added:
                            line = inf.readline()
                            if not line:
                                raise QiskitChemistryError('Unexpected end of Gaussian input')
                            if len(line.strip()) == 0:
                                outf.write('# Window=Full Int=NoRaff Symm=(NoInt,None) output=(matrix,i4labels,mo2el) tran=full\n')
                                added = True
                            outf.write(line)
                    else:
                        outf.write(line)

                # Now add our filename after the title and molecule but before any additional data. We located
                # the end of the # section by looking for a blank line after the first #. Allows comment lines
                # to be inter-mixed with Route lines if that's ever done. From here we need to see two sections
                # more, the title and molecule so we can add the filename.
                added = False
                section_count = 0
                blank = True
                while not added:
                    line = inf.readline()
                    if not line:
                        raise QiskitChemistryError('Unexpected end of Gaussian input')
                    if len(line.strip()) == 0:
                        blank = True
                        if section_count == 2:
                            break
                    else:
                        if blank:
                            section_count += 1
                            blank = False
                    outf.write(line)

                outf.write(line)
                outf.write(fname)
                outf.write('\n\n')

                # Whatever is left in the original config we just append without further inspection
                while True:
                    line = inf.readline()
                    if not line:
                        break
                    outf.write(line)

                cfgaug = outf.getvalue()

        return cfgaug
def compute_integrals(config):
    # Get config from input parameters
    # Molecule is in this format xyz as below or in Z-matrix e.g "H; O 1 1.08; H 2 1.08 1 107.5":
    # atoms=H .0 .0 .0; H .0 .0 0.2
    # units=Angstrom
    # charge=0
    # multiplicity=1
    # where we support symbol for atom as well as number

    if 'atoms' not in config:
        raise QiskitChemistryError('Atoms is missing')
    val = config['atoms']
    if val is None:
        raise QiskitChemistryError('Atoms value is missing')

    charge = int(config.get('charge', '0'))
    multiplicity = int(config.get('multiplicity', '1'))
    units = _check_units(config.get('units', 'Angstrom'))
    mol = _parse_molecule(val, units, charge, multiplicity)
    basis = config.get('basis', 'sto3g')
    calc_type = config.get('calc_type', 'rhf').lower()

    try:
        ehf, enuke, norbs, mohij, mohijkl, orbs, orbs_energy = _calculate_integrals(
            mol, basis, calc_type)
    except Exception as exc:
        raise QiskitChemistryError(
            'Failed electronic structure computation') from exc

    # Create driver level molecule object and populate
    _q_ = QMolecule()
    # Energies and orbits
    _q_.hf_energy = ehf
    _q_.nuclear_repulsion_energy = enuke
    _q_.num_orbitals = norbs
    _q_.num_alpha = mol.nup()
    _q_.num_beta = mol.ndown()
    _q_.mo_coeff = orbs
    _q_.orbital_energies = orbs_energy
    # Molecule geometry
    _q_.molecular_charge = mol.charge
    _q_.multiplicity = mol.multiplicity
    _q_.num_atoms = len(mol)
    _q_.atom_symbol = []
    _q_.atom_xyz = np.empty([len(mol), 3])
    atoms = mol.atoms
    for _n in range(0, _q_.num_atoms):
        atuple = atoms[_n].atuple()
        _q_.atom_symbol.append(QMolecule.symbols[atuple[0]])
        _q_.atom_xyz[_n][0] = atuple[1]
        _q_.atom_xyz[_n][1] = atuple[2]
        _q_.atom_xyz[_n][2] = atuple[3]
    # 1 and 2 electron integrals
    _q_.mo_onee_ints = mohij
    _q_.mo_eri_ints = mohijkl

    return _q_
    def check_driver_valid():
        err_msg = "PySCF is not installed. Use 'pip install pyscf'"
        try:
            spec = importlib.util.find_spec('pyscf')
            if spec is not None:
                return
        except Exception as e:
            logger.debug('PySCF check error {}'.format(str(e)))
            raise QiskitChemistryError(err_msg) from e

        raise QiskitChemistryError(err_msg)
示例#8
0
    def check_driver_valid():
        err_msg = 'PyQuante2 is not installed. See https://github.com/rpmuller/pyquante2'
        try:
            spec = importlib.util.find_spec('pyquante2')
            if spec is not None:
                return
        except Exception as e:
            logger.debug('PyQuante2 check error {}'.format(str(e)))
            raise QiskitChemistryError(err_msg) from e

        raise QiskitChemistryError(err_msg)
    def run_algorithm_from_json(self, params, output=None, backend=None):
        """
        Runs the Aqua Chemistry experiment from json dictionary

        Args:
            params (dictionary): Input data
            output (filename):  Output data
            backend (BaseBackend): backend object

        Returns:
            result dictionary
        """
        ret = run_algorithm(params, None, True, backend)
        if not isinstance(ret, dict):
            raise QiskitChemistryError(
                "Algorithm run result should be a dictionary")

        convert_json_to_dict(ret)
        if logger.isEnabledFor(logging.DEBUG):
            logger.debug('Algorithm returned: {}'.format(
                pprint.pformat(ret, indent=4)))

        print('Output:')
        if isinstance(ret, dict):
            for k, v in ret.items():
                print("'{}': {}".format(k, v))
        else:
            print(ret)

        return ret
示例#10
0
def _check_molecule_format(val):
    """If it seems to be zmatrix rather than xyz format we convert before returning"""
    atoms = [x.strip() for x in val.split(';')]
    if atoms is None or len(atoms) < 1:
        raise QiskitChemistryError('Molecule format error: ' + val)

    # Anx xyz format has 4 parts in each atom, if not then do zmatrix convert
    parts = [x.strip() for x in atoms[0].split(' ')]
    if len(parts) != 4:
        try:
            return gto.mole.from_zmatrix(val)
        except Exception as exc:
            raise QiskitChemistryError('Failed to convert atom string: ' +
                                       val) from exc

    return val
示例#11
0
    def __init__(self,
                 atoms,
                 units=UnitsType.ANGSTROM,
                 charge=0,
                 multiplicity=1,
                 basis=BasisType.BSTO3G):
        """
        Initializer
        Args:
            atoms (str or list): atoms list or string separated by semicolons or line breaks
            units (UnitsType): angstrom or bohr
            charge (int): charge
            multiplicity (int): spin multiplicity
            basis (BasisType): sto3g or 6-31g or 6-31g**
        """
        if not isinstance(atoms, list) and not isinstance(atoms, str):
            raise QiskitChemistryError(
                "Invalid atom input for PYQUANTE Driver '{}'".format(atoms))

        if isinstance(atoms, list):
            atoms = ';'.join(atoms)
        else:
            atoms = atoms.replace('\n', ';')

        units = units.value
        basis = basis.value

        self.validate(locals())
        super().__init__()
        self._atoms = atoms
        self._units = units
        self._charge = charge
        self._multiplicity = multiplicity
        self._basis = basis
示例#12
0
    def init_from_input(cls, section):
        """
        Initialize via section dictionary.

        Args:
            params (dict): section dictionary

        Returns:
            Driver: Driver object
        """
        if 'properties' not in section or len(section['properties']) == 0:
            raise QiskitChemistryError('Missing or empty properties section')

        params = section['properties']
        kwargs = {}
        for k, v in params.items():
            if k == PyQuanteDriver.KEY_UNITS:
                v = UnitsType(v)
            elif k == PyQuanteDriver.KEY_BASIS:
                v = BasisType(v)

            kwargs[k] = v

        logger.debug('init_from_input: {}'.format(kwargs))
        return cls(**kwargs)
    def run(self, section):
        cfg = section['data']
        if cfg is None or not isinstance(cfg, str):
            raise QiskitChemistryError("Gaussian user supplied configuration invalid: '{}'".format(cfg))

        while not cfg.endswith('\n\n'):
            cfg += '\n'

        logger.debug("User supplied configuration raw: '{}'".format(cfg.replace('\r', '\\r').replace('\n', '\\n')))
        logger.debug('User supplied configuration\n{}'.format(cfg))

        # To the Gaussian section of the input file passed here as section['data']
        # add line '# Symm=NoInt output=(matrix,i4labels,mo2el) tran=full'
        # NB: Line above needs to be added in right context, i.e after any lines
        #     beginning with % along with any others that start with #
        # append at end the name of the MatrixElement file to be written

        fd, fname = tempfile.mkstemp(suffix='.mat')
        os.close(fd)

        cfg = self._augment_config(fname, cfg)
        logger.debug('Augmented control information:\n{}'.format(cfg))

        GaussianDriver._run_g16(cfg)

        q_mol = self._parse_matrix_file(fname)
        try:
            os.remove(fname)
        except:
            logger.warning("Failed to remove MatrixElement file " + fname)

        return q_mol
示例#14
0
def _check_units(units):
    if units.lower() in ["angstrom", "ang", "a"]:
        units = 'Angstrom'
    elif units.lower() in ["bohr", "b"]:
        units = 'Bohr'
    else:
        raise QiskitChemistryError('Molecule units format error: ' + units)
    return units
示例#15
0
def _parse_atom(val):
    if val is None or len(val) < 1:
        raise QiskitChemistryError('Molecule atom format error: empty')

    parts = re.split('\s+', val)
    if len(parts) != 4:
        raise QiskitChemistryError('Molecule atom format error: ' + val)

    parts[0] = parts[0].lower().capitalize()
    if not parts[0].isdigit():
        if parts[0] in QMolecule.symbols:
            parts[0] = QMolecule.symbols.index(parts[0])
        else:
            raise QiskitChemistryError('Molecule atom symbol error: ' +
                                       parts[0])

    return int(float(parts[0])), float(parts[1]), float(parts[2]), float(
        parts[3])
示例#16
0
def _calculate_integrals(molecule, basis='sto3g', calc_type='rhf'):
    """Function to calculate the one and two electron terms. Perform a Hartree-Fock calculation in
        the given basis.
    Args:
        molecule : A pyquante2 molecular object.
        basis : The basis set for the electronic structure computation
        calc_type: rhf, uhf, rohf
    Returns:
        ehf : Hartree-Fock energy
        enuke: Nuclear repulsion energy
        norbs : Number of orbitals
        mohij : One electron terms of the Hamiltonian.
        mohijkl : Two electron terms of the Hamiltonian.
        orbs: Molecular orbital coefficients
        orbs_energy: Orbital energies
    """
    bfs = basisset(molecule, basis)
    integrals = onee_integrals(bfs, molecule)
    hij = integrals.T + integrals.V
    hijkl_compressed = twoe_integrals(bfs)

    # convert overlap integrals to molecular basis
    # calculate the Hartree-Fock solution of the molecule

    if calc_type == 'rhf':
        solver = rhf(molecule, bfs)
    elif calc_type == 'rohf':
        solver = rohf(molecule, bfs)
    elif calc_type == 'uhf':
        solver = uhf(molecule, bfs)
    else:
        raise QiskitChemistryError('Invalid calc_type: {}'.format(calc_type))
    logger.debug('Solver name {}'.format(solver.name))
    ehf = solver.converge()
    if hasattr(solver, 'orbs'):
        orbs = solver.orbs
    else:
        orbs = solver.orbsa
    norbs = len(orbs)
    if hasattr(solver, 'orbe'):
        orbs_energy = solver.orbe
    else:
        orbs_energy = solver.orbea
    enuke = molecule.nuclear_repulsion()
    # Get ints in molecular orbital basis
    mohij = simx(hij, orbs)
    mohijkl_compressed = transformintegrals(hijkl_compressed, orbs)
    mohijkl = np.zeros((norbs, norbs, norbs, norbs))
    for i in range(norbs):
        for j in range(norbs):
            for k in range(norbs):
                for l in range(norbs):
                    mohijkl[i, j, k,
                            l] = mohijkl_compressed[ijkl2intindex(i, j, k, l)]

    return ehf[0], enuke, norbs, mohij, mohijkl, orbs, orbs_energy
示例#17
0
def _register_chemistry_operator(cls):
    # Verify that the pluggable is not already registered
    if cls in [input.cls for input in _REGISTERED_CHEMISTRY_OPERATORS.values()]:
        raise QiskitChemistryError('Could not register class {} is already registered'.format(cls))

    # Verify that it has a minimal valid configuration.
    try:
        chemistry_operator_name = cls.CONFIGURATION['name']
    except (LookupError, TypeError):
        raise QiskitChemistryError('Could not register chemistry operator: invalid configuration')

    if chemistry_operator_name in _REGISTERED_CHEMISTRY_OPERATORS:
        raise QiskitChemistryError('Could not register class {}. Name {} {} is already registered'.format(cls,
                                                                                                          chemistry_operator_name, _REGISTERED_CHEMISTRY_OPERATORS[chemistry_operator_name].cls))

    # Append the pluggable to the `registered_classes` dict.
    _REGISTERED_CHEMISTRY_OPERATORS[chemistry_operator_name] = RegisteredChemOp(
        chemistry_operator_name, cls, copy.deepcopy(cls.CONFIGURATION))
    return chemistry_operator_name
    def run(self, input, output=None, backend=None):
        """
        Runs the Aqua Chemistry experiment

        Args:
            input (dictionary/filename): Input data
            output (filename):  Output data
            backend (BaseBackend): backend object

        Returns:
            result dictionary
        """
        if input is None:
            raise QiskitChemistryError("Missing input.")

        self._parser = InputParser(input)
        self._parser.parse()
        driver_return = self._run_driver_from_parser(self._parser, False)
        if driver_return[0] == QiskitChemistry._DRIVER_RUN_TO_HDF5:
            logger.info('No further process.')
            return {'printable': [driver_return[1]]}

        data = run_algorithm(driver_return[1], driver_return[2], True, backend)
        if not isinstance(data, dict):
            raise QiskitChemistryError(
                "Algorithm run result should be a dictionary")

        convert_json_to_dict(data)
        if logger.isEnabledFor(logging.DEBUG):
            logger.debug('Algorithm returned: {}'.format(
                pprint.pformat(data, indent=4)))

        lines, result = self._format_result(data)
        logger.info('Processing complete. Final result available')
        result['printable'] = lines

        if output is not None:
            with open(output, 'w') as f:
                for line in lines:
                    print(line, file=f)

        return result
    def save_input(self, input_file):
        """
        Save the input of a run to a file.

        Params:
            input_file (string): file path
        """
        if self._parser is None:
            raise QiskitChemistryError("Missing input information.")

        self._parser.save_to_file(input_file)
示例#20
0
def _check_molecule_format(val):
    """If it seems to be zmatrix rather than xyz format we convert before returning"""
    atoms = [x.strip() for x in val.split(';')]
    if atoms is None or len(atoms) < 1:
        raise QiskitChemistryError('Molecule format error: ' + val)

    # An xyz format has 4 parts in each atom, if not then do zmatrix convert
    # Allows dummy atoms, using symbol 'X' in zmatrix format for coord computation to xyz
    parts = [x.strip() for x in atoms[0].split(' ')]
    if len(parts) != 4:
        try:
            newval = []
            for entry in gto.mole.from_zmatrix(val):
                if entry[0].upper() != 'X':
                    newval.append(entry)
            return newval
        except Exception as exc:
            raise QiskitChemistryError('Failed to convert atom string: ' +
                                       val) from exc

    return val
    def _run_drive(self, input, save_json_algo_file):
        if input is None:
            raise QiskitChemistryError("Missing input.")

        self._parser = InputParser(input)
        self._parser.parse()
        driver_return = self._run_driver_from_parser(self._parser,
                                                     save_json_algo_file)
        driver_return[1]['input'] = driver_return[2].to_params()
        driver_return[1]['input']['name'] = driver_return[2].configuration[
            'name']
        return driver_return[1]
示例#22
0
def _parse_molecule(val, units, charge, multiplicity):
    val = _check_molecule_format(val)

    parts = [x.strip() for x in val.split(';')]
    if parts is None or len(parts) < 1:
        raise QiskitChemistryError('Molecule format error: ' + val)
    geom = []
    for n in range(len(parts)):
        part = parts[n]
        geom.append(_parse_atom(part))

    if len(geom) < 1:
        raise QiskitChemistryError('Molecule format error: ' + val)

    try:
        return molecule(geom,
                        units=units,
                        charge=charge,
                        multiplicity=multiplicity)
    except Exception as exc:
        raise QiskitChemistryError('Failed to create molecule') from exc
def register_driver(cls):
    """
    Registers a driver class
    Args:
        cls (object): Driver class.
     Returns:
        name: driver name
    """
    _discover_on_demand()
    if not issubclass(cls, BaseDriver):
        raise QiskitChemistryError('Could not register class {} is not subclass of BaseDriver'.format(cls))

    return _register_driver(cls)
def deregister_driver(driver_name):
    """Remove driver from list of available drivers
    Args:
        driver_name (str): name of driver to unregister
    Raises:
        QiskitChemistryError if name is not registered.
    """
    _discover_on_demand()

    if driver_name not in _REGISTERED_DRIVERS:
        raise QiskitChemistryError('Could not deregister {} not registered'.format(driver_name))

    _REGISTERED_DRIVERS.pop(driver_name)
        def deregister_driver(self, driver_name):
            """Remove driver from list of available drivers
            Args:
                driver_name (str): name of driver to unregister
            Raises:
                QiskitChemistryError if name is not registered.
            """
            self._discover_on_demand()

            if driver_name not in self._registration:
                raise QiskitChemistryError('Could not deregister {} not registered'.format(driver_name))

            self._registration.pop(driver_name)
    def run_drive_to_jsonfile(self, input, jsonfile):
        if jsonfile is None:
            raise QiskitChemistryError("Missing json file")

        data = self._run_drive(input, True)
        if data is None:
            logger.info('No data to save. No further process.')
            return

        with open(jsonfile, 'w') as fp:
            json.dump(data, fp, sort_keys=True, indent=4)

        print("Algorithm input file saved: '{}'".format(jsonfile))
    def __init__(self, config):
        """
        Initializer
        Args:
            config (str or list): driver configuration
        """
        if not isinstance(config, list) and not isinstance(config, str):
            raise QiskitChemistryError("Invalid input for Gaussian Driver '{}'".format(config))

        if isinstance(config, list):
            config = '\n'.join(config)

        super().__init__()
        self._config = config
 def get_driver_instance(self, name):
     """Return an instance for the name in configuration.
     Args:
         name (str): the name
     Returns:
         Object: module instance
     Raises:
         QiskitChemistryError: if module is unavailable
     """
     cls = self.get_driver_class(name)
     try:
         return cls()
     except Exception as err:
         raise QiskitChemistryError('{} could not be instantiated: {}'.format(cls, err))
示例#29
0
    def run(self, section):
        properties = section['properties']
        if HDF5Driver.KEY_HDF5_INPUT not in properties:
            raise QiskitChemistryError('Missing hdf5 input property')

        hdf5_file = properties[HDF5Driver.KEY_HDF5_INPUT]
        if self.work_path is not None and not os.path.isabs(hdf5_file):
            hdf5_file = os.path.abspath(os.path.join(self.work_path, hdf5_file))

        if not os.path.isfile(hdf5_file):
            raise LookupError('HDF5 file not found: {}'.format(hdf5_file))

        molecule = QMolecule(hdf5_file)
        molecule.load()
        return molecule
def get_driver_configuration(driver_name):
    """Return the configuration for the named module.
    Args:
        driver_name (str): the module name
    Returns:
        dict: configuration dict
    Raises:
        QiskitChemistryError: if module is unavailable
    """
    _discover_on_demand()

    if driver_name not in _REGISTERED_DRIVERS:
        raise QiskitChemistryError('{} not registered'.format(driver_name))

    return copy.deepcopy(_REGISTERED_DRIVERS[driver_name].configuration)