Beispiel #1
0
    def __init__(self, infile, moldb=None, atomdb=None, bonddb=None):
        formats = {"pdb": PDBReader, "gro": GROReader}
        try:
            ext = os.path.splitext(infile)[1][1:]
            coords = formats[ext](infile)
        except KeyError as e:
            e.args = ("File extension '{0}' not recognised".format(ext), )
            raise

        self.coords = coords
        self.moldb = MolDatabase() if moldb is None else moldb
        self.atomdb = AtomDatabase() if atomdb is None else atomdb
        self.bonddb = BondDatabase() if bonddb is None else bonddb

        self.moltypes = []
        self.atomtypes = []
        self.lentypes = []
        self.angtypes = []
        self.dihtypes = []
        self.imptypes = []

        self.lenstyles = []
        self.angstyles = []
        self.dihstyles = []
        self.impstyles = []

        self.natoms = Counter()
        self.nlengths = Counter()
        self.nangles = Counter()
        self.ndihedrals = Counter()
        self.nimpropers = Counter()
Beispiel #2
0
    def __init__(self, infile):
        self._suppress_atom_names = False

        formats = {"pdb": PDBReader,
                   "gro": GROReader}
        try:
            ext = os.path.splitext(infile)[1][1:]
            coords = formats[ext](infile)
        except KeyError as e:
            e.args = ("File extension '{0}' not recognised".format(ext),)
            raise

        self.coords = coords
        self.moldb = MolDatabase()
        self.atomdb = AtomDatabase()
        self.bonddb = BondDatabase()

        self.moltypes = []
        self.atomtypes = []
        self.lentypes = []
        self.angtypes = []
        self.dihtypes = []
        self.imptypes = []

        self.lenstyles = []
        self.angstyles = []
        self.dihstyles = []
        self.impstyles = []

        self.natoms = Counter()
        self.nlengths = Counter()
        self.nangles = Counter()
        self.ndihedrals = Counter()
        self.nimpropers = Counter()
Beispiel #3
0
 def test_read_database_atoms(self):
     db = AtomDatabase()
     self.assertTrue("MEOH" in db.atoms)
     self.assertTrue("ETOH" in db.atoms)
     self.assertEqual(db.atoms["MEOH"].type, "MEOH")
     self.assertEqual(db.atoms["MEOH"].mass, 30.026)
     self.assertEqual(db.atoms["MEOH"].charge, 0)
     self.assertEqual(db.atoms["MEOH"].dipole, 0.354)
     self.assertEqual(db.atoms["MEOH"].diameter, 12.7)
     self.assertEqual(db.atoms["MEOH"].rotmass, 30.026)
     self.assertEqual(db.atoms["ETOH"].mass, 44.053)
Beispiel #4
0
class PDB2LMP:
    def __init__(self, infile):
        self._suppress_atom_names = False

        formats = {"pdb": PDBReader,
                   "gro": GROReader}
        try:
            ext = os.path.splitext(infile)[1][1:]
            coords = formats[ext](infile)
        except KeyError as e:
            e.args = ("File extension '{0}' not recognised".format(ext),)
            raise

        self.coords = coords
        self.moldb = MolDatabase()
        self.atomdb = AtomDatabase()
        self.bonddb = BondDatabase()

        self.moltypes = []
        self.atomtypes = []
        self.lentypes = []
        self.angtypes = []
        self.dihtypes = []
        self.imptypes = []

        self.lenstyles = []
        self.angstyles = []
        self.dihstyles = []
        self.impstyles = []

        self.natoms = Counter()
        self.nlengths = Counter()
        self.nangles = Counter()
        self.ndihedrals = Counter()
        self.nimpropers = Counter()

    def collect_types(self):

        def collect_type(values, counter, db_vals, typelist, stylelist):
            for val in values:
                counter.total += 1
                if val.type not in typelist:
                    typelist.append(val.type)
                    counter.types += 1
                    if db_vals[val.type].style not in stylelist:
                        stylelist.append(db_vals[val.type].style)

        atnum = 0

        for mol in self.coords.molecules:
            dbmol = self.moldb.molecules[mol.name]

            if mol.name not in self.moltypes:
                self.moltypes.append(mol.name)

            collect_type(dbmol.lengths, self.nlengths, self.bonddb.length,
                         self.lentypes, self.lenstyles)
            collect_type(dbmol.angles, self.nangles, self.bonddb.angle,
                         self.angtypes, self.angstyles)
            collect_type(dbmol.dihedrals, self.ndihedrals, self.bonddb.dihedral,
                         self.dihtypes, self.dihstyles)
            collect_type(dbmol.impropers, self.nimpropers, self.bonddb.improper,
                         self.imptypes, self.impstyles)

            coordfile_atoms = [self.coords.atoms[x] for x in mol.atoms]
            if len(coordfile_atoms) != len(dbmol.atoms):
                raise ValueError("Number of atoms does not match between coordinate file and force field for molecule {0}.".format(mol.name))

            for coordfile_atom, dbmol_atom in zip(coordfile_atoms, dbmol.atoms.values()):
                if dbmol_atom.type not in self.atomtypes:
                    self.atomtypes.append(dbmol_atom.type)
                    self.natoms.types += 1

                if coordfile_atom.name != dbmol_atom.name:
                    if self._suppress_atom_names:
                            coordfile_atom.name = dbmol_atom.name
                    else:
                        raise NonMatchingAtomException(atnum, coordfile_atom.name, dbmol_atom.name)
                self.natoms.total += 1
                atnum += 1

    def populate_pdb_data(self):
        for mol in self.moldb.molecules.values():
            for atom in mol.atoms.values():
                atom.populate(self.atomdb.atoms[atom.type])
        for atom in self.coords.atoms:
            atom.populate(self.moldb.molecules[atom.resname].atoms[atom.name])

    def write_data(self, filename):
        with open(filename, "w") as data:
            print("LAMMPS 'data.' input file created by PDB2LMP", file=data)
            print(file=data)
            print("{0:8d} atoms".format(self.natoms.total), file=data)
            print("{0:8d} bonds".format(self.nlengths.total), file=data)
            print("{0:8d} angles".format(self.nangles.total), file=data)
            print("{0:8d} dihedrals".format(self.ndihedrals.total), file=data)
            print("{0:8d} impropers".format(self.nimpropers.total), file=data)
            print(file=data)
            print("{0:8d} atom types".format(self.natoms.types), file=data)
            print("{0:8d} bond types".format(self.nlengths.types), file=data)
            print("{0:8d} angle types".format(self.nangles.types), file=data)
            print("{0:8d} dihedral types".format(self.ndihedrals.types), file=data)
            print("{0:8d} improper types".format(self.nimpropers.types), file=data)
            print(file=data)
            cell = [val / 2 for val in self.coords.cell]
            print("{0:8.3f} {1:8.3f} xlo xhi".format(-cell[0], cell[0]), file=data)
            print("{0:8.3f} {1:8.3f} ylo yhi".format(-cell[1], cell[1]), file=data)
            print("{0:8.3f} {1:8.3f} zlo zhi".format(-cell[2], cell[2]), file=data)
            print(file=data)
            print("Atoms", file=data)
            print(file=data)

            atomline = "{0:6d} {1:4d} {2:8.3f} {3:8.3f} {4:8.3f} {5:4d} {6:5.2f} {7:8.3f} {8:8.3f} {9:8.3f} {10:5.2f} {11:5.2f}"
            for i, atom in enumerate(self.coords.atoms, start=1):
                # Write atom line
                # Dipoles are all oriented up - this should equilibrate out quickly
                print(atomline.format(i, self.atomtypes.index(atom.type)+1,
                                      atom.x, atom.y, atom.z, atom.resid, atom.charge,
                                      atom.dipole, 0, 0, atom.diameter, atom.rotmass), file=data)

            def write_bonds(n, types, header):
                if n <= 0:
                    return
                print("\n" + header + "\n", file=data)
                i = 1
                for ii, mol in enumerate(self.coords.molecules):
                    mol_db = self.moldb.molecules[mol.name]
                    atom_list = list(mol_db.atoms.keys())
                    for bond in getattr(mol_db, header.lower()):
                        print("{0:6d} {1:4d}".format(i, types.index(bond.type) + 1), file=data, end="")
                        for atom in bond.atoms:
                            try:
                                atom_num = mol.atoms[atom_list.index(atom)]
                            except ValueError:
                                if atom.startswith("+"):
                                    other_mol = self.coords.molecules[ii + 1]
                                elif atom.startswith("-"):
                                    other_mol = self.coords.molecules[ii - 1]
                                else:
                                    raise

                                other_mol_db = self.moldb.molecules[other_mol.name]
                                try:
                                    if not mol_db.polymer_type.intersection(other_mol_db.polymer_type):
                                        raise PolymerError(mol.name, other_mol.name) from None
                                except AttributeError:
                                    raise PolymerError(mol.name, other_mol.name) from None

                                other_atom_list = list(other_mol_db.atoms.keys())
                                atom_num = other_mol.atoms[other_atom_list.index(atom[1:])]

                            print(" {0:6d}".format(atom_num + 1), file=data, end="")
                        print(file=data)
                        i += 1

            write_bonds(self.nlengths.total, self.lentypes, "Bonds")
            write_bonds(self.nangles.total, self.angtypes, "Angles")
            write_bonds(self.ndihedrals.total, self.dihtypes, "Dihedrals")
            write_bonds(self.nimpropers.total, self.imptypes, "Impropers")

    def write_forcefield(self, filename):
        with open(filename, "w") as ff:
            print("# Forcefield prepared by PDB2LMP", file=ff)
            print(file=ff)
            # TODO change these to "0.0 1.0 1.0 12.0" - ELBA standard
            print("pair_style lj/sf/dipole/sf 12.0", file=ff)
            print("special_bonds lj/coul 0.0 0.0 0.0", file=ff)
            print(file=ff)

            def write_styles(styles, header):
                if styles:
                    print(header, file=ff, end="")
                    for style in styles:
                        print(" " + style, file=ff, end="")
                    print(file=ff)

            write_styles(self.lenstyles, "bond_style hybrid")
            write_styles(self.angstyles, "angle_style hybrid")
            write_styles(self.dihstyles, "dihedral_style hybrid")
            write_styles(self.impstyles, "improper_style hybrid")

            print(file=ff)
            line = "mass {0:4d} {1:8.3f} # {2}"
            for i, atomtype in enumerate(self.atomtypes, start=1):
                print(line.format(i, self.atomdb.atoms[atomtype].mass, atomtype), file=ff)

            print(file=ff)
            line = "set type{0:4d} diameter {1:8.3f} # {2}"
            for i, atomtype in enumerate(self.atomtypes, start=1):
                print(line.format(i, self.atomdb.atoms[atomtype].diameter, atomtype), file=ff)

            print(file=ff)
            line = "pair_coeff {0:4d} {1:4d} {2:6.3f} {3:6.3f} # {4}-{5}"
            for i, atomtype in enumerate(self.atomtypes, start=1):
                for j, atomtype2 in enumerate(self.atomtypes, start=1):
                    if i > j:
                        continue
                    sig, eps = self.atomdb.lj(atomtype, atomtype2)
                    print(line.format(i, j, eps, sig, atomtype, atomtype2), file=ff)

            def write_types(types, db_vals, line_prefix):
                if types:
                    print(file=ff)
                    line = line_prefix + " {0:4d} {1} {2} # {3}"
                    for i, tipe in enumerate(types, start=1):
                        db_type = db_vals[tipe]
                        print(line.format(i, db_type.style, db_type.params, tipe), file=ff)

            write_types(self.lentypes, self.bonddb.length, "bond_coeff")
            write_types(self.angtypes, self.bonddb.angle, "angle_coeff")
            write_types(self.dihtypes, self.bonddb.dihedral, "dihedral_coeff")
            write_types(self.imptypes, self.bonddb.improper, "improper_coeff")
Beispiel #5
0
class PDB2LMP:
    def __init__(self, infile, moldb=None, atomdb=None, bonddb=None):
        formats = {"pdb": PDBReader, "gro": GROReader}
        try:
            ext = os.path.splitext(infile)[1][1:]
            coords = formats[ext](infile)
        except KeyError as e:
            e.args = ("File extension '{0}' not recognised".format(ext), )
            raise

        self.coords = coords
        self.moldb = MolDatabase() if moldb is None else moldb
        self.atomdb = AtomDatabase() if atomdb is None else atomdb
        self.bonddb = BondDatabase() if bonddb is None else bonddb

        self.moltypes = []
        self.atomtypes = []
        self.lentypes = []
        self.angtypes = []
        self.dihtypes = []
        self.imptypes = []

        self.lenstyles = []
        self.angstyles = []
        self.dihstyles = []
        self.impstyles = []

        self.natoms = Counter()
        self.nlengths = Counter()
        self.nangles = Counter()
        self.ndihedrals = Counter()
        self.nimpropers = Counter()

    def collect_types(self, add_water=True, allow_atom_subset=False):
        """
        Collect all bead and bond types used in simulation.

        Args:
            add_water: Add water bead type even if not present in input coordinates?
            allow_atom_subset: Allow converting only a subset of the atoms in coordinate file

        """
        def collect_type(values, counter, db_vals, typelist, stylelist,
                         nextmol_name):
            for val in values:
                try:
                    if re.fullmatch(val.ifnext, nextmol_name) is None:
                        continue
                except AttributeError:
                    pass
                except TypeError:
                    continue
                counter.total += 1
                if val.type not in typelist:
                    typelist.append(val.type)
                    counter.types += 1
                    if db_vals[val.type].style not in stylelist:
                        stylelist.append(db_vals[val.type].style)

        atnum = 0

        for i, mol in enumerate(self.coords.molecules):
            dbmol = self.moldb.molecules[mol.name]
            try:
                nextmol_name = self.coords.molecules[i + 1].name
            except IndexError:
                nextmol_name = None

            if mol.name not in self.moltypes:
                self.moltypes.append(mol.name)

            collect_type(dbmol.lengths, self.nlengths, self.bonddb.length,
                         self.lentypes, self.lenstyles, nextmol_name)
            collect_type(dbmol.angles, self.nangles, self.bonddb.angle,
                         self.angtypes, self.angstyles, nextmol_name)
            collect_type(dbmol.dihedrals, self.ndihedrals,
                         self.bonddb.dihedral, self.dihtypes, self.dihstyles,
                         nextmol_name)
            collect_type(dbmol.impropers, self.nimpropers,
                         self.bonddb.improper, self.imptypes, self.impstyles,
                         nextmol_name)

            coordfile_atoms = [self.coords.atoms[x] for x in mol.atoms]

            if allow_atom_subset:
                if len(coordfile_atoms) < len(dbmol.atoms):
                    raise ValueError(
                        "Number of atoms is greater in coordinate file ({0}) than force field ({1}) for molecule {2}."
                        .format(len(coordfile_atoms), len(dbmol.atoms),
                                mol.name))
            else:
                if len(coordfile_atoms) != len(dbmol.atoms):
                    raise ValueError(
                        "Number of atoms does not match between coordinate file ({0}) and force field ({1}) for molecule {2}."
                        .format(len(coordfile_atoms), len(dbmol.atoms),
                                mol.name))

            # Convert atoms from coordinate file that are present in database
            for coordfile_atom in coordfile_atoms:
                try:
                    dbmol_atom = dbmol.atoms[coordfile_atom.name]
                except KeyError:
                    if allow_atom_subset:
                        continue
                    raise

                if dbmol_atom.type not in self.atomtypes:
                    self.atomtypes.append(dbmol_atom.type)
                    self.natoms.types += 1

                self.natoms.total += 1
                atnum += 1

        if add_water and "WAT" not in self.atomtypes:
            self.atomtypes.append("WAT")
            self.natoms.types += 1

    def populate_pdb_data(self):
        for mol in self.moldb.molecules.values():
            for atom in mol.atoms.values():
                atom.populate(self.atomdb.atoms[atom.type])
        for atom in self.coords.atoms:
            atom.populate(self.moldb.molecules[atom.resname].atoms[atom.name])

    def write_data(self, filename):
        with open(filename, "w") as data:
            print("LAMMPS 'data.' input file created by PDB2LMP", file=data)
            print(file=data)
            print("{0:8d} atoms".format(self.natoms.total), file=data)
            print("{0:8d} bonds".format(self.nlengths.total), file=data)
            print("{0:8d} angles".format(self.nangles.total), file=data)
            print("{0:8d} dihedrals".format(self.ndihedrals.total), file=data)
            print("{0:8d} impropers".format(self.nimpropers.total), file=data)
            print(file=data)
            print("{0:8d} atom types".format(self.natoms.types), file=data)
            print("{0:8d} bond types".format(self.nlengths.types), file=data)
            print("{0:8d} angle types".format(self.nangles.types), file=data)
            print("{0:8d} dihedral types".format(self.ndihedrals.types),
                  file=data)
            print("{0:8d} improper types".format(self.nimpropers.types),
                  file=data)
            print(file=data)
            cell = [val / 2 for val in self.coords.cell]
            if cell == [0, 0, 0]:
                print("WARNING: The simulation box/unit cell size is zero.")
                print(
                    "  If this is not intentional, please check your input files."
                )
            print("{0:8.3f} {1:8.3f} xlo xhi".format(-cell[0], cell[0]),
                  file=data)
            print("{0:8.3f} {1:8.3f} ylo yhi".format(-cell[1], cell[1]),
                  file=data)
            print("{0:8.3f} {1:8.3f} zlo zhi".format(-cell[2], cell[2]),
                  file=data)
            print(file=data)
            print("Atoms", file=data)
            print(file=data)

            atomline = "{0:6d} {1:4d} {2:8.3f} {3:8.3f} {4:8.3f} {5:4d} {6:5.2f} {7:8.3f} {8:8.3f} {9:8.3f} {10:5.2f} {11:5.2f}"
            for i, atom in enumerate(self.coords.atoms, start=1):
                # Write atom line
                # Dipoles are all oriented up - this should equilibrate out quickly
                print(atomline.format(i,
                                      self.atomtypes.index(atom.type) + 1,
                                      atom.x, atom.y, atom.z, atom.resid,
                                      atom.charge, atom.dipole, 0, 0,
                                      atom.diameter, atom.rotmass),
                      file=data)

            def write_bonds(n, types, header):
                if n <= 0:
                    return
                print("\n" + header + "\n", file=data)
                i = 1
                for ii, mol in enumerate(self.coords.molecules):
                    mol_db = self.moldb.molecules[mol.name]
                    try:
                        nextmol_name = self.coords.molecules[ii + 1].name
                    except IndexError:
                        nextmol_name = None

                    atom_list = list(mol_db.atoms.keys())
                    for bond in getattr(mol_db, header.lower()):
                        try:
                            if re.fullmatch(bond.ifnext, nextmol_name) is None:
                                continue
                        except AttributeError:
                            pass
                        except TypeError:
                            continue
                        print("{0:6d} {1:4d}".format(
                            i,
                            types.index(bond.type) + 1),
                              file=data,
                              end="")
                        for atom in bond.atoms:
                            try:
                                atom_num = mol.atoms[atom_list.index(atom)]
                            except ValueError:
                                if atom.startswith("+"):
                                    other_mol = self.coords.molecules[ii + 1]
                                elif atom.startswith("-"):
                                    other_mol = self.coords.molecules[ii - 1]
                                else:
                                    raise

                                other_mol_db = self.moldb.molecules[
                                    other_mol.name]
                                try:
                                    if not mol_db.polymer_type.intersection(
                                            other_mol_db.polymer_type):
                                        raise PolymerError(
                                            mol.name, other_mol.name) from None
                                except AttributeError:
                                    raise PolymerError(
                                        mol.name, other_mol.name) from None

                                other_atom_list = list(
                                    other_mol_db.atoms.keys())
                                atom_num = other_mol.atoms[
                                    other_atom_list.index(atom[1:])]

                            print(" {0:6d}".format(atom_num + 1),
                                  file=data,
                                  end="")
                        print(file=data)
                        i += 1

            write_bonds(self.nlengths.total, self.lentypes, "Bonds")
            write_bonds(self.nangles.total, self.angtypes, "Angles")
            write_bonds(self.ndihedrals.total, self.dihtypes, "Dihedrals")
            write_bonds(self.nimpropers.total, self.imptypes, "Impropers")

    def write_forcefield(self, filename):
        with open(filename, "w") as ff:
            print("# Forcefield prepared by PDB2LMP", file=ff)
            print(file=ff)
            # TODO change these to "0.0 1.0 1.0 12.0" - ELBA standard
            print("pair_style lj/sf/dipole/sf 12.0", file=ff)
            print("special_bonds lj/coul 0.0 0.0 0.0", file=ff)
            print(file=ff)

            def write_styles(styles, header):
                if styles:
                    print(header, file=ff, end="")
                    for style in styles:
                        print(" " + style, file=ff, end="")
                    print(file=ff)

            write_styles(self.lenstyles, "bond_style hybrid")
            write_styles(self.angstyles, "angle_style hybrid")
            write_styles(self.dihstyles, "dihedral_style hybrid")
            write_styles(self.impstyles, "improper_style hybrid")

            print(file=ff)
            line = "mass {0:4d} {1:8.3f} # {2}"
            for i, atomtype in enumerate(self.atomtypes, start=1):
                print(line.format(i, self.atomdb.atoms[atomtype].mass,
                                  atomtype),
                      file=ff)

            print(file=ff)
            line = "set type{0:4d} diameter {1:8.3f} # {2}"
            for i, atomtype in enumerate(self.atomtypes, start=1):
                print(line.format(i, self.atomdb.atoms[atomtype].diameter,
                                  atomtype),
                      file=ff)

            print(file=ff)
            line = "pair_coeff {0:4d} {1:4d} {2:6.3f} {3:6.3f} # {4}-{5}"
            for i, atomtype in enumerate(self.atomtypes, start=1):
                for j, atomtype2 in enumerate(self.atomtypes, start=1):
                    if i > j:
                        continue
                    sig, eps = self.atomdb.lj(atomtype, atomtype2)
                    print(line.format(i, j, eps, sig, atomtype, atomtype2),
                          file=ff)

            def write_types(types, db_vals, line_prefix):
                if types:
                    print(file=ff)
                    line = line_prefix + " {0:4d} {1} {2} # {3}"
                    for i, tipe in enumerate(types, start=1):
                        db_type = db_vals[tipe]
                        print(line.format(i, db_type.style, db_type.params,
                                          tipe),
                              file=ff)

            write_types(self.lentypes, self.bonddb.length, "bond_coeff")
            write_types(self.angtypes, self.bonddb.angle, "angle_coeff")
            write_types(self.dihtypes, self.bonddb.dihedral, "dihedral_coeff")
            write_types(self.imptypes, self.bonddb.improper, "improper_coeff")
Beispiel #6
0
 def test_lj(self):
     db = AtomDatabase()
     self.helper_tuple_compare(db.lj("MEOH", "ETOH"), (3.963, 0.704))
     self.helper_tuple_compare(db.lj("WAT", "WAT"), (3.050, 0.550))
     self.helper_tuple_compare(db.lj("MEOH", "WAT"), (3.388, 0.621))
     self.helper_tuple_compare(db.lj("WAT", "MEOH"), (3.388, 0.621))
Beispiel #7
0
 def test_open_database(self):
     db = AtomDatabase()
Beispiel #8
0
 def test_lj(self):
     db = AtomDatabase()
     self.helper_tuple_compare(db.lj("MEOH", "ETOH"), (3.963, 0.704))
     self.helper_tuple_compare(db.lj("WAT", "WAT"), (3.050, 0.550))
     self.helper_tuple_compare(db.lj("MEOH", "WAT"), (3.388, 0.621))
     self.helper_tuple_compare(db.lj("WAT", "MEOH"), (3.388, 0.621))