def _example():
    """Example of using OpenBabel interoperability"""
    from BigDFT.Systems import System
    from BigDFT.Fragments import Fragment
    from BigDFT.IO import XYZReader
    from os.path import join

    # Read in a system.
    sys = System()
    sys["FRA:1"] = Fragment()
    with XYZReader("CH4") as ifile:
        for at in ifile:
            sys["FRA:1"] += Fragment([at])

    # We can compute the smiles representation.
    print(compute_smiles(sys))

    # The energy.
    print(system_energy(sys, forcefield="UFF"))

    # Extract the forces.
    compute_system_forces(sys, forcefield="UFF")
    for frag in sys.values():
        for at in frag:
            print(at["force"])

    # Optimize the geometry.
    sys2 = optimize_system(sys, forcefield="UFF")
    print(system_energy(sys2, forcefield="UFF"))
Esempio n. 2
0
    def fragment_mask_matrix(self, sys, mat, fragments, log):
        """
        Sometimes we don't want to store an entire matrix, just the parts
        related to some fragments of interest. This routine will mask out a
        matrix, keeping entries only related to the list of fragments
        provided.

        Args:
          sys (BigDFT.Systems.System): the system associated with the matrix.
          mat (scipy.sparse.csr_matrix): the matrix to mask.
          fragments (list): a list of fragment ids to keep.
          log (BigDFT.Logfiles.Logfile): the logfile associated with this
            matrix's calculation.
        Returns:
          (scipy.sparse.csr_matrix): the masked matrix.
        """
        from BigDFT.Systems import System
        from copy import deepcopy
        from scipy.sparse import dok_matrix

        subsys = System()
        for fragid in fragments:
            subsys[fragid] = deepcopy(sys[fragid])

        frag_indices = self.get_frag_indices(subsys, log)
        frag_indices = sum(frag_indices.values(), [])

        imat = dok_matrix(mat.shape)
        for i in frag_indices:
            imat[i, i] = 1

        return imat.dot(mat).dot(imat)
def _example():
    """Example of using PSI4 interoperability"""
    from BigDFT.IO import XYZReader
    from BigDFT.Systems import System
    from BigDFT.Fragments import Fragment
    from os.path import join
    from copy import deepcopy

    # Create a system.
    reader = XYZReader(join("Database", "XYZs", "He.xyz"))
    fsys = System()
    fsys["FRA:1"] = Fragment(xyzfile=reader)
    fsys["FRA:2"] = deepcopy(fsys["FRA:1"])
    fsys["FRA:2"].translate([-2, 0, 0])

    # Create a calculator.
    code = PSI4Calculator()
    log = code.run(sys=fsys, action="energy", basis="jun-cc-pvdz",
                   psi4_options={"scf_type": "direct"}, method="scf",
                   name="test")
    print(log)

    # The raw logfile is also available.
    print(log.log[4])

    # Geometry optimization.
    log = code.run(sys=fsys, action="optimize", basis="jun-cc-pvdz",
                   method="scf", name="test-opt")
    print(log)

    # SAPT
    log = code.run(sys=fsys, action="energy", basis="jun-cc-pvdz",
                   method="sapt0", name="test-sapt")
    print(log)
 def __init__(self, system=None, filename=None):
     from simtk.openmm.app.pdbfile import PDBFile
     from simtk.openmm import app
     from BigDFT.IO import read_pdb, write_pdb
     from tempfile import NamedTemporaryFile as tmp
     if filename is not None:
         pdb = PDBFile(open(filename))
         sys = read_pdb(open(filename))
     elif system is not None:
         sys = system
         ofile = tmp('w+')
         write_pdb(system=system, ofile=ofile)
         ofilename = ofile.name
         pdb = PDBFile(open(ofilename))
         ofile.close()
     System.__init__(self, **sys.dict())
     self.pdb = pdb
     self.modeller = app.Modeller(pdb.topology, pdb.positions)
Esempio n. 5
0
    def compute_fragment_dos(self,
                             frag,
                             log,
                             ks_coeff,
                             eigvals,
                             frag_indices=None,
                             smat=None,
                             assume_pure=False,
                             **kwargs):
        """
        Compute the partial density of states projected onto a given
        fragment.

        Args:
            sys (BigDFT.Fragments.Fragment): the fragment to project on to.
            log (BigDFT.Logfiles.Logfile): the log of the calculation.
            ks_coeff (scipy.sparse.csc_matrix): the matrix of eigenvectors.
            eigvals (list): a list of eigenvalues.
            frag_indices (list): list of indices associated with this
              fragment.
            smat (scipy.sparse.csc_matrix): the overlap matrix.
            assume_pure (bool): an optimization can be performed if we assume
              the target is pure.
            kwargs (dict): any extra options to pass to the DoS constructor.
        Returns:
          (BigDFT.DoS.DoS): a density of states object built using the partial
          density of states.
        """
        from BigDFT.Systems import System
        from BigDFT.DoS import DoS
        # Subsystem with just this fragment.
        subsys = System()
        subsys["FRAG:0"] = frag

        # Optional Argments
        if smat is None:
            smat = self.get_matrix_s(log)
        if frag_indices is None:
            frag_indices = self.get_frag_indices(subsys, log)["FRAG:0"]

        subsmat = smat[frag_indices, :]
        subkmat = ks_coeff[frag_indices, :].T

        vals = []
        for n in range(len(eigvals)):
            work = subkmat[n, :].dot(subsmat)
            if assume_pure:
                sumval = work[:, frag_indices].dot(ks_coeff[frag_indices, n])
            else:
                sumval = work[:, :].dot(ks_coeff[:, n])
            vals.append(sumval[0, 0])

        # Construct the dos object
        dos = DoS(energies=eigvals, norm=[vals], units='AU', **kwargs)
        return dos
 def __init__(self, name):
     import os
     from BigDFT.Fragments import Fragment
     from BigDFT.Systems import System
     from BigDFT.IO import XYZReader
     # import the positions of the molecules from the XYZ directory
     dirXYZ = os.path.join(os.path.dirname(__file__), 'XYZs')
     filename = os.path.abspath(os.path.join(dirXYZ, name + '.xyz'))
     if not os.path.isfile(filename):
         raise ValueError('Molecule not available')
     ff = XYZReader(filename)
     frag = Fragment(xyzfile=ff)
     system = System({'molecule:0': frag})
     self.update(system.get_posinp())
     # temporary change of the keys 'values' into 'positions'
     if 'values' in self:
         self['positions'] = self.pop('values')
     if 'positions' in self:
         for at in self['positions']:
             if 'r' in at:
                 at.pop('r')
    def _create_system(self):
        """
        Create a BigDFT system from the atoms of this calculator.
        """
        from BigDFT.Systems import System
        from BigDFT.UnitCells import UnitCell
        from ase.units import Bohr

        sys = System()
        sys["FRAG:0"] = ase_to_bigdft(self.atoms)

        if self.atoms.cell is not None:
            if any(self.atoms.get_pbc()):
                if not self.atoms.cell.orthorhombic:
                    raise ValueError("Only orthorhombic cells are supported.")
                vec = [
                    float(self.atoms.cell[i, i])
                    if self.atoms.get_pbc()[i] else float("inf")
                    for i in range(3)
                ]
                sys.cell = UnitCell(vec, units="angstroem")

        return sys
def _example():
    """Visualization Example"""
    from BigDFT.Systems import System
    from BigDFT.Fragments import Fragment
    from BigDFT.IO import XYZReader

    # Read in a system.
    sys = System()
    with XYZReader("SiO") as ifile:
        for i, at in enumerate(ifile):
            sys["FRA:" + str(i)] = Fragment([at])

    # Display the system.
    viz = InlineVisualizer(400, 300)
    viz.display_system(sys)

    # Change the colors
    colordict = get_distinct_colors(list(sys))
    viz.display_system(sys, colordict=colordict)
Esempio n. 9
0
    def create_layered_qmmm_system(self,
                                   system,
                                   target,
                                   pairwise_bo,
                                   cutoffs,
                                   criteria="bondorder",
                                   link_atoms=False):
        """
        Creates a multilayered system suitable for QM/MM calculations.
        For each layer, a suitable QM region is built around it.

        Args:
          system (BigDFT.Systems.System): a System class, already broken up
            into fragments.
          pairwise_bo (dict): pairwise bond order values between all fragments
            in the system.
          target (str): the name of the fragment to treat as the target of
            the qm/mm run.
          cutoffs (list): a list of cutoff value for fragment interactions.
            The number of layers is equal to the number of cutoffs.
          criteria (str): how to determine which atoms are included in the
            QM region. Valid choices are "bondorder" and "distance".
          link_atoms (bool): whether to generate link atoms.

        Returns:
          (list): a list of Systems, one for each QM layer.
          (System): the MM region.

        """
        from copy import deepcopy
        from BigDFT.Systems import System

        # First, we will build the layers using only keys.
        qm_list = []
        qm, mm = self.create_qmmm_system(system,
                                         target,
                                         pairwise_bo[target],
                                         cutoffs[0],
                                         criteria,
                                         link_atoms=False)
        qm_list.append(list(qm.keys()))
        mm_keys = list(mm.keys())

        # To avoid duplicates
        used_list = deepcopy(list(qm.keys()))

        for k in range(1, len(cutoffs)):
            qm_list.append([])
            for subtarget in qm_list[k - 1]:
                qm, mm = self.create_qmmm_system(system,
                                                 subtarget,
                                                 pairwise_bo[subtarget],
                                                 cutoffs[k],
                                                 criteria,
                                                 link_atoms=False)
                qm_list[k] += qm.keys()

            # Remove duplicates
            qm_list[k] = [x for x in qm_list[k] if x not in used_list]
            qm_list[k] = list(set(qm_list[k]))
            used_list = list(set(used_list + qm_list[k]))

            mm_keys = [x for x in mm_keys if x not in qm_list[k]]

        # Next, we will convert those keys into systems.
        qmsys = []
        for j in range(0, len(cutoffs)):
            qmsys.append(System())
            for k in qm_list[j]:
                qmsys[j][k] = deepcopy(system[k])
        mmsys = System()
        for k in mm_keys:
            mmsys[k] = deepcopy(system[k])

        # Add the link atoms.
        if link_atoms:
            # One big system to add the link atoms.
            mergesys = System()
            for k in range(0, len(cutoffs)):
                for fragid, frag in qmsys[k].items():
                    mergesys[fragid] = frag
            linksub, remove = self.generate_link_atoms(system, mergesys)

            # Insert the link atoms into the correct layers.
            for fragid, frag in linksub.items():
                for at in frag:
                    if at.is_link:
                        for k in range(0, len(cutoffs)):
                            if fragid in qmsys[k]:
                                qmsys[k][fragid] += [at]
                                break

        return qmsys, mmsys
Esempio n. 10
0
def _example():
    """
    Postprocessing Example
    """
    from BigDFT.Systems import System, FragmentView
    from BigDFT.Fragments import Fragment
    from BigDFT.IO import XYZReader
    from BigDFT.Calculators import SystemCalculator
    from BigDFT.Inputfiles import Inputfile
    from scipy.linalg import eigh
    from copy import deepcopy

    # Create a system
    sys = System()
    sys["FRA:0"] = Fragment()
    with XYZReader("CH2") as ifile:
        for at in ifile:
            sys["FRA:0"].append(at)
    sys["FRA:1"] = Fragment()
    with XYZReader("CH3") as ifile:
        for at in ifile:
            sys["FRA:1"].append(at)
    sys["FRA:1"].translate([0, 0, -3])
    sys["FRA:2"] = deepcopy(sys["FRA:0"])
    sys["FRA:2"].translate([0, 0, 3])
    sys["FRA:2"].rotate(y=150, units="degrees")
    sys["FRA:3"] = deepcopy(sys["FRA:0"])
    sys["FRA:3"].translate([3, 0, 1.5])

    print(list(sys))

    # Run a calculation. `write_support_function_matrices` and `linear` are
    # key. You also should be sure to set the atom multipoles.
    inp = Inputfile()
    inp.set_xc("PBE")
    inp.set_hgrid(0.4)
    inp.write_support_function_matrices()
    inp["import"] = "linear"

    code = SystemCalculator()
    code.update_global_options(verbose=False)
    log = code.run(input=inp, posinp=sys.get_posinp(), run_dir="work")
    sys.set_atom_multipoles(log)

    # Create the post processing tool.
    from BigDFT.PostProcessing import BigDFTool
    btool = BigDFTool()

    # Purity
    purity = btool.run_compute_purity(sys, log)
    print(purity)

    # Charges
    charges = {
        fragid: sum(at.nel for at in frag)
        for fragid, frag in sys.items()
    }

    # Bond Orders
    bo = btool.fragment_bond_order(sys, sys.keys(), sys.keys(), log)

    # Population values.
    population = btool.fragment_population(sys, log)
    print(population)

    # These three things define a fragment view.
    view = FragmentView(purity, bo, charges)

    # Auto Fragmentation
    mapping = btool.auto_fragment(sys, view, 0.10)
    print(mapping)

    # This defines a new view.
    new_view = view.refragment(mapping)
    print(new_view.purities)

    # Eigenvalues.
    H = btool.get_matrix_h(log)
    S = btool.get_matrix_s(log)
    w = eigh(H.todense(), b=S.todense(), eigvals_only=True)
    print(w)
Esempio n. 11
0
def _example():
    """Test the XYZ Module"""
    from BigDFT.Systems import System
    from BigDFT.Fragments import Fragment
    from BigDFT.UnitCells import UnitCell
    file = "Si4"

    safe_print("First let's try reading an XYZ file.")
    atom_list = []
    with XYZReader(file) as reader:
        safe_print(reader.closed)
        for at in reader:
            atom_list.append(at)
    safe_print(reader.closed)
    safe_print(atom_list)
    safe_print()

    safe_print("Now let's try writing an XYZ file.")
    safe_print()
    with XYZWriter("test.xyz", len(atom_list),
                   units=reader.units) as writer:
        safe_print(writer.closed)
        for at in atom_list:
            writer.write(at)
    safe_print(writer.closed)
    safe_print()
    with open("test.xyz") as ifile:
        for line in ifile:
            safe_print(line, end='')
    safe_print()

    safe_print("Print with various boundary conditions")
    with XYZWriter("test.xyz", len(atom_list), reader.units,
                   cell=UnitCell()) as writer:
        for at in atom_list:
            writer.write(at)
    with XYZReader("test.xyz") as ifile:
        print(ifile.cell.get_boundary_condition())

    with XYZWriter("test.xyz", len(atom_list), reader.units,
                   cell=UnitCell([5, 5, 5])) as writer:
        for at in atom_list:
            writer.write(at)
    with XYZReader("test.xyz") as ifile:
        print(ifile.cell.get_boundary_condition())

    with XYZWriter("test.xyz", len(atom_list), reader.units,
                   cell=UnitCell([5, float("inf"), 5])) as writer:
        for at in atom_list:
            writer.write(at)
    with XYZReader("test.xyz") as ifile:
        print(ifile.cell.get_boundary_condition())

    with XYZWriter("test.xyz", len(atom_list), reader.units,
                   cell=UnitCell([float("inf"), float("inf"), 5])) as writer:
        for at in atom_list:
            writer.write(at)
    with XYZReader("test.xyz") as ifile:
        print(ifile.cell.get_boundary_condition())
    safe_print()

    safe_print("Now let's demonstrate the pdb and mol2 writer")
    sys = System()
    sys["FRAG:0"] = Fragment(atom_list)
    with open("test.pdb", "w") as ofile:
        write_pdb(sys, ofile)
    with open("test.pdb") as ifile:
        for line in ifile:
            safe_print(line, end='')
    safe_print()

    with open("test.mol2", "w") as ofile:
        write_mol2(sys, ofile)
    with open("test.mol2") as ifile:
        for line in ifile:
            safe_print(line, end='')
    safe_print()
def _example():
    """Example of using ASE interoperability"""
    from BigDFT.IO import XYZReader
    from BigDFT.Inputfiles import Inputfile
    from BigDFT.Calculators import SystemCalculator
    from BigDFT.Fragments import Fragment
    from BigDFT.Systems import System
    from ase.calculators.lj import LennardJones
    from BigDFT.UnitCells import UnitCell
    from ase.units import Hartree
    from ase.optimize import BFGS
    from os.path import join
    from copy import deepcopy

    # Create a system.
    sys = System()
    reader = XYZReader("Ar")
    sys["FRA:1"] = Fragment(xyzfile=reader)
    sys["FRA:2"] = deepcopy(sys["FRA:1"])
    sys["FRA:2"].translate([-2, 0, 0])

    # Skip straight to the potential energy.
    print(ase_potential_energy(sys, LennardJones()))

    # Advanced used.
    asys = bigdft_to_ase(sys)
    asys.set_calculator(LennardJones())
    dyn = BFGS(asys)
    dyn.run(fmax=0.05)
    print(asys.get_potential_energy() / Hartree)

    # Unit cells
    sys.cell = UnitCell([5, 5, 5], units="bohr")
    print(ase_potential_energy(sys, LennardJones()))
    sys.cell = UnitCell([5, float("inf"), 5], units="bohr")
    print(ase_potential_energy(sys, LennardJones()))
    sys.cell = UnitCell([float("inf"), float("inf"), 5], units="bohr")
    print(ase_potential_energy(sys, LennardJones()))

    # We can also use BigDFT with ase.
    inp = Inputfile()
    inp.set_xc("PBE")
    inp.set_hgrid(0.4)
    code = SystemCalculator(verbose=False)
    sys.cell = UnitCell()
    print(
        ase_potential_energy(
            sys, BigASECalculator(inp,
                                  code,
                                  directory="work",
                                  label="ase-free")))
    sys.cell = UnitCell([5, 5, 5], units="bohr")
    print(
        ase_potential_energy(
            sys,
            BigASECalculator(inp, code, directory="work",
                             label="ase-periodic")))
    sys.cell = UnitCell([5, float("inf"), 5], units="bohr")
    print(
        ase_potential_energy(
            sys,
            BigASECalculator(inp, code, directory="work",
                             label="ase-surface")))
    sys.cell = UnitCell([float("inf"), float("inf"), 5], units="bohr")
    print(
        ase_potential_energy(
            sys, BigASECalculator(inp,
                                  code,
                                  directory="work",
                                  label="ase-wire")))
Esempio n. 13
0
def read_mol2(ifile, disable_warnings=False):
    """
    Read a system from a mol2 file.

    Args:
      ifile (TextIOBase): the file to read from.
      disable_warnings (bool): whether to print warnings about possible file
        issues.

    Returns:
      (BigDFT.Systems.System): the system file.
    """
    from BigDFT.Systems import System
    from BigDFT.Fragments import Fragment
    from BigDFT.Atoms import Atom
    from BigDFT.UnitCells import UnitCell
    from warnings import warn

    sys = System()

    # Just go ahead and read the whole file into a string.
    lines = [x for x in ifile]

    # First pass, read in the number of atoms.
    for start, line in enumerate(lines):
        if ("@<TRIPOS>MOLECULE" in line):
            break
    start += 1

    split = lines[start+1].split()
    natoms = int(split[0])
    nbonds = int(split[1])

    # Second pass read in the atoms.
    for start, line in enumerate(lines):
        if ("@<TRIPOS>ATOM" in line):
            break
    start += 1

    lookup = []
    for i in range(0, natoms):
        split = lines[start + i].split()
        pos = [float(x) for x in split[2:5]]
        name = split[5]
        sym = name.split(".")[0]
        fragid = split[7] + ":" + split[6]
        charge = [float(split[8])]

        # Add fragment
        if fragid not in sys:
            sys[fragid] = Fragment()
        at = Atom({sym: pos, "units": "angstroem", "q0":
                   charge, "name": name})
        sys[fragid] += [at]

        # Lookup table for connectivity
        lookup.append((fragid, len(sys[fragid]) - 1))

    # Third pass reads the connectivity.
    for start, line in enumerate(lines):
        if ("@<TRIPOS>BOND" in line):
            break
    start += 1

    if start < len(lines):
        sys.conmat = {}
        for fragid, frag in sys.items():
            sys.conmat[fragid] = []
            for i in range(0, len(frag)):
                sys.conmat[fragid].append({})

    bowarn = False
    for i in range(0, nbonds):
        split = lines[start + i].split()
        frag1, at1 = lookup[int(split[1])-1]
        frag2, at2 = lookup[int(split[2])-1]
        bo = split[3]
        try:
            bo = float(split[3])
        except ValueError:
            bowarn = True
            bo = 1
        sys.conmat[frag1][at1][(frag2, at2)] = bo

        # Since mol2 doesn't include the symmetric bonds.
        if frag1 != frag2 or at1 != at2:
            sys.conmat[frag2][at2][(frag1, at1)] = bo

    # Fourth path reads the unit cell.
    for start, line in enumerate(lines):
        if ("@<TRIPOS>CRYSIN" in line):
            break
    start += 1

    if start < len(lines):
        split = lines[start].split()
        a = float(split[0])
        b = float(split[1])
        c = float(split[2])
        alpha = float(split[3])
        beta = float(split[4])
        gamma = float(split[5])

        sys.cell = UnitCell([a, b, c], units="angstroem")

        if not disable_warnings:
            if (alpha != 90 or beta != 90 or gamma != 90):
                warn("Cell angles must be 90 degrees", UserWarning)

    if not disable_warnings:
        if sum([len(x) for x in sys.values()]) == 0:
            warn("Warning: zero atoms found", UserWarning)
        if bowarn:
            warn("Unsupported bond type had to be set to 1 (i.e. aromatic)",
                 UserWarning)

    return sys
def read_polaris_pdb(pdbfile, chain_as_letter=False, slefile=None):
    """
    Read coordinates in the PDB format of POLARIS

    Args:
       pdbfile (str): path of the input file
       chain_as_letter (bool): If True, the fifth column
           is assumed to contain a letter
       slefile (str): path of the file ``.sle`` of Polaris from which
           to extract the system's attributes.

    Warning:
       Assumes Free Boundary conditions for the molecule.
       Only accepts atoms that have one letter in the symbol.
       Switch representation if there is a single letter in the fifth column

    Returns:
       System: A system class
    """
    from BigDFT.Fragments import Fragment
    from BigDFT.Systems import System, GetFragId
    from BigDFT.Atoms import Atom
    sys = System()
    units = 'angstroem'
    with open(pdbfile) as ifile:
        for line in ifile:
            if 'ATOM' not in line:
                continue
            atomline = line.split()
            if chain_as_letter:
                iat, name, frag, lett, ifrag, x, y, z, sn = atomline[1:10]
                chain = lett
                segname = sn
            else:
                iat, name, frag, ifrag, x, y, z, chlett = atomline[1:9]
                chain = chlett[2]
                segname = chlett
            atdict = {
                str(name[:1]): map(float, [x, y, z]),
                'frag': [chain + '-' + frag, int(ifrag)],
                'name': name,
                'iat': int(iat),
                'segname': segname
            }
            fragid = GetFragId(atdict, iat)
            if fragid not in sys:
                sys[fragid] = Fragment()
            sys[fragid].append(Atom(atdict, units=units))
    if slefile is None:
        return sys
    attributes = read_polaris_sle(slefile)
    from BigDFT import Systems as S, Fragments as F, Atoms as A
    system = S.System()
    for name, frag in sys.items():
        refrag = F.Fragment()
        for at in frag:
            atdict = at.dict()
            att = attributes[atdict['iat'] - 1]
            assert att['name'] == atdict['name']
            atdict.update(att)
            refrag.append(A.Atom(atdict))
        system[name] = refrag
    return system
    def pre_processing(self):
        """
        Process local run dictionary to create the input directory and identify
        the command to be passed

        Returns:
            :py:class:`dict`: dictionary containing the command to be passed to
            :meth:`process_run`
        """
        from psi4 import set_options, energy, optimize, frequency
        from psi4.core import set_output_file
        from BigDFT.Systems import System
        from os.path import join

        # Check Arguments
        try:
            self.sys = self.run_options["sys"]
        except KeyError:
            raise ValueError("sys= must be provided as an argument")

        try:
            action = self.run_options["action"]
        except KeyError:
            raise ValueError("You must specify a valid action=(energy,"
                             " optimize, frequency")

        try:
            method = self.run_options["method"]
        except KeyError:
            raise ValueError("You must specify an ab initio method=")

        try:
            basis = self.run_options["basis"]
        except KeyError:
            raise ValueError("You must specify a basis=")

        # Run directory
        self._ensure_run_directory()

        # Check skip
        if self.run_options["skip"]:
            try:
                log = PSI4Logfile(self.sys, self._get_logname(True),
                                  action, method)
                return {"command": None}
            except ValueError:  # invalid logfile, so we can't skip.
                pass
            except IOError:  # no logfile, so we can't skip.
                pass

        # Convert system
        if "sapt" in method:
            keys = list(self.sys)
            if len(keys) != 2:
                raise ValueError("For SAPT method, your system must be"
                                 " composed of exactly two fragments.")
            sysA = System()
            sysA[keys[0]] = self.sys[keys[0]]
            sysB = System()
            sysB[keys[1]] = self.sys[keys[1]]
            mol = bigdft_to_psi4(sysA=sysA, sysB=sysB)
        else:
            mol = bigdft_to_psi4(sysA=self.sys)

        # Set extra options.
        if "psi4_options" in self.run_options:
            set_options(self.run_options["psi4_options"])
        set_output_file(self._get_logname(True), False)

        # Instead of a command, we return a closure.
        if action == "energy":
            def cmd(method, mol):
                energy(method, molecule=mol)
        elif action == "optimize":
            def cmd(method, mol):
                optimize(method, molecule=mol)
        elif action == "frequency":
            def cmd(method, mol):
                frequency(method, molecule=mol)

        return {"command": cmd(join(method, basis), mol)}
Esempio n. 16
0
    def create_qmmm_system(self,
                           system,
                           target,
                           bond_order,
                           cutoff,
                           criteria="bondorder",
                           link_atoms=False):
        """
        Creates a system suitable for QM/MM calculations.

        Args:
          system (System): a System class, already broken up into fragments.
          target (str): the name of the fragment to treat as the target of
            the qm/mm run.
          bond_order (dict): bond order values between the target fragment and
            all other fragments in the system.
          cutoff (float): a cutoff value for fragment interactions.
          criteria (str): how to determine which atoms are included in the
            QM region. Valid choices are "bondorder" and "distance".
          link_atoms (bool): whether to generate link atoms.

        Returns:
          (System): the QM region.
          (System): the MM region.
        """
        from BigDFT.Systems import System
        from BigDFT.Fragments import pairwise_distance
        from copy import deepcopy

        qmsys = System()
        mmsys = deepcopy(system)

        if criteria == "bondorder":
            # Order the fragments by their spillage value
            sort_spill = sorted(bond_order.keys(),
                                key=lambda x: bond_order[x],
                                reverse=True)

            # Iterate until we reach the cutoff
            cumsum = sum(bond_order.values())
            for key in sort_spill:
                qmsys[key] = deepcopy(system[key])
                del mmsys[key]

                # check cutoff
                cumsum -= bond_order[key]
                if cumsum < cutoff:
                    break

        elif criteria == "distance":
            interaction = {
                x: pairwise_distance(system[target], system[x])
                for x in system.keys()
            }
            for fragid, frag in system.items():
                if interaction[fragid] < cutoff:
                    qmsys[fragid] = deepcopy(frag)
                    del mmsys[fragid]

        else:
            raise ValueError("Criteria must be either distance or bondorder")

        # Double check that the target is in qmsys.
        # (this can happen if the target is not a pure fragment)
        if target not in qmsys:
            qmsys[target] = system[target]

        if link_atoms:
            qmsys, remove = self.generate_link_atoms(system, qmsys)

        return qmsys, mmsys
Esempio n. 17
0
    def generate_link_atoms(self, fullsys, subsys, distcut=6.0):
        """
        This routine adds link atoms to a subsystem based on the bond
        order of a full system. Link atom positions are automatically adjusted
        based on the length of some standard bonds.

        Args:
          fullsys (BigDFT.Systems.System): the full system that the subsystem
            is embedded into.
          subsys (BigDFT.Systems.System): the embedded system which needs
            link atoms.
          distcut (float): this cutoff is the largest distance value we expect
            allow a bond to be.

        Returns:
          (BigDFT.Systems.System): the subsystem with link atoms added.
          (BigDFT.Systems.System): a system which has the atoms that were
            removed and replaced with link atoms.
        """
        from BigDFT.Systems import System
        from BigDFT.Fragments import Fragment
        from copy import deepcopy
        from numpy.linalg import norm
        from numpy import array
        from warnings import warn

        # Bond lengths for link atoms.
        bond_lengths = {
            "C": 2.0598,
            "N": 1.90862,
            "O": 1.81414,
            "F": 1.73855,
            "P": 2.68341,
            "S": 2.53223,
            "Cl": 2.39995,
            "Br": 2.66451,
            "I": 3.04246
        }

        if fullsys.conmat is None:
            raise ValueError("Generating link atoms requires connectivity"
                             " information")

        linksys = deepcopy(subsys)
        removesys = System()

        # Loop over atoms and look for bonds running out of the QM system.
        for fragid in subsys:
            linklist = []
            for i in range(0, len(fullsys[fragid])):
                for ft, bv in fullsys.conmat[fragid][i].items():
                    if ft[0] in subsys.keys():
                        continue
                    if bv == 1:
                        newat = deepcopy(fullsys[ft[0]][ft[1]])
                        # Change the symbol to hydrogen
                        newat.sym = "H"
                        newat.is_link = True
                        # If possible we adjust the position for a reasonable
                        # bond length
                        conat = fullsys[fragid][i]
                        if conat.sym in bond_lengths:
                            pos1 = array(conat.get_position("bohr"))
                            pos2 = array(newat.get_position("bohr"))
                            vec = pos2 - pos1
                            vec *= bond_lengths[conat.sym] / norm(vec)
                            newpos = [x + y for x, y in zip(pos1, vec)]
                            newat.set_position(newpos, units="bohr")
                        else:
                            warn(conat.sym + "bondlength unknown", UserWarning)
                        linklist.append(newat)
                    elif bv > 1:
                        print("Not yet implemented double/triple bonds.", bv)
                        raise NotImplementedError
                    if ft[0] not in removesys:
                        removesys[ft[0]] = Fragment()
                    removesys[ft[0]] += [fullsys[ft[0]][ft[1]]]

            # Add those atoms to the fragment
            for link in linklist:
                linksys[fragid] += [link]

        return linksys, removesys
Esempio n. 18
0
def read_pdb(ifile, include_chain=False, disable_warnings=False):
    """
    Read a system from a PDB file.

    Args:
      ifile (TextIOBase): the file to read from.
      disable_warnings (bool): whether to print warnings about possible file
        issues.
      include_chain (bool): include the chain id if True

    Warning:
       This will read in the connectivity information from the pdb as well.
       However, a pdb file does not provide any information about the bond
       order. Thus, the bond order of each bond will be set to one.

    Returns:
      (BigDFT.Systems.System): the system file.
    """
    from BigDFT.Fragments import Fragment
    from BigDFT.Systems import System
    from warnings import warn
    from BigDFT.UnitCells import UnitCell

    # First pass read in the atoms.
    sys = System()
    lookup = {}
    sys.conmat = {}
    found = False

    for line in ifile:
        try:  # See if there is an atom on this line
            if line[:4] == "ATOM" or line[:6] == "HETATM":
                at, atid, fragid = _process_atom(line,
                                                 include_chain=include_chain)

                # We can ignore lone pairs
                if at.sym == "Lp":
                    continue

                # Add to the system
                if fragid not in sys:
                    sys[fragid] = Fragment()
                sys[fragid] += [at]

                # Build the lookup table
                lookup[atid] = (fragid, len(sys[fragid]) - 1)

            elif line[:6] == "CONECT":
                found = True
                split = _split_line(line, len(lookup))
                (fragid, atnum) = lookup[int(split[1])]

                for at2 in split[2:]:
                    fragid2, atnum2 = lookup[int(at2)]

                    if fragid not in sys.conmat:
                        sys.conmat[fragid] = []
                        for i in range(0, len(sys[fragid])):
                            sys.conmat[fragid].append({})

                    sys.conmat[fragid][atnum][(fragid2, atnum2)] = 1.0

            elif line[:6] == "CRYST1":
                a = float(line[7:15])
                b = float(line[16:24])
                c = float(line[25:33])
                alpha = float(line[34:40])
                beta = float(line[41:47])
                gamma = float(line[48:54])

                sys.cell = UnitCell([a, b, c], units="angstroem")

                if not disable_warnings:
                    if (alpha != 90 or beta != 90 or gamma != 90):
                        warn("Cell angles must be 90 degrees", UserWarning)

        except IndexError:  # For shorter lines
            continue

    if not found:
        sys.conmat = None
    else:
        # for any connectivity not specified we give default values.
        for fragid in sys:
            if fragid not in sys.conmat:
                sys.conmat[fragid] = []
                for i in range(0, len(sys[fragid])):
                    sys.conmat[fragid].append({})

    if not disable_warnings:
        if sum([len(x) for x in sys.values()]) == 0:
            warn("Warning: zero atoms found", UserWarning)

    return sys