Exemplo n.º 1
0
    def __init__(self, *args):
        """ Constructor.

        Args:
            One or more strings. Each string specifies path to one par file.

        Attributes:
            lgr         : logging.Logger
            fnames      : a list of paths to the par files
            bondpars    : ParType, bonds
            anglepars   : ParType, angles
            dihedralpars: ParType, dihedrals
            improperpars: ParType, impropers
            nonbonding  : ParType, nonbonding
            cmappars    : ParType, cmaps
            nbfix       : ParType, nbfix

        """

        self.lgr = logging.getLogger("mainapp.charmmpar.CharmmPar")
        self.lgr.debug(">> entering CharmmPar")

        self.fnames = args
        self.bondpars = ParType(sym=True, mult=False, name="bond")
        self.anglepars = ParType(sym=True, mult=False, name="angle")
        self.dihedralpars = ParType(sym=True, mult=True, name="dihedral")
        self.improperpars = ParType(sym=True, mult=False, name="improper")
        self.nonbonding = ParType(sym=False, mult=False, name="nonbonding")
        self.nbfix = ParType(sym=True, mult=False, name="nbfix")
        self.cmappars = ParType(sym=False, mult=False, name="cmap")

        for p in args:
            self._parse_charmmpar(p)
            self.lgr.debug(self.__repr__())

        self.lgr.debug("<< leaving CharmmPar")
Exemplo n.º 2
0
    def __init__(self, *args):
        """ Constructor.

        Args:
            One or more strings. Each string specifies path to one par file.

        Attributes:
            lgr         : logging.Logger
            fnames      : a list of paths to the par files
            bondpars    : ParType, bonds
            anglepars   : ParType, angles
            dihedralpars: ParType, dihedrals
            improperpars: ParType, impropers
            nonbonding  : ParType, nonbonding
            cmappars    : ParType, cmaps
            nbfix       : ParType, nbfix

        """

        self.lgr = logging.getLogger('mainapp.charmmpar.CharmmPar')
        self.lgr.debug(">> entering CharmmPar")

        self.fnames = args
        self.bondpars = ParType(sym=True, mult=False, name='bond')
        self.anglepars = ParType(sym=True, mult=False, name='angle')
        self.dihedralpars = ParType(sym=True, mult=True, name='dihedral')
        self.improperpars = ParType(sym=True, mult=False, name='improper')
        self.nonbonding = ParType(sym=False, mult=False, name='nonbonding')
        self.nbfix = ParType(sym=True, mult=False, name='nbfix')
        self.cmappars = ParType(sym=False, mult=False, name='cmap')

        for p in args:
            self._parse_charmmpar(p)
            self.lgr.debug(self.__repr__())

        self.lgr.debug("<< leaving CharmmPar")
Exemplo n.º 3
0
class CharmmPar(object):
    """ A class for reading CHARMM PAR/PRM files. """

    def __init__(self, *args):
        """ Constructor.

        Args:
            One or more strings. Each string specifies path to one par file.

        Attributes:
            lgr         : logging.Logger
            fnames      : a list of paths to the par files
            bondpars    : ParType, bonds
            anglepars   : ParType, angles
            dihedralpars: ParType, dihedrals
            improperpars: ParType, impropers
            nonbonding  : ParType, nonbonding
            cmappars    : ParType, cmaps
            nbfix       : ParType, nbfix

        """

        self.lgr = logging.getLogger("mainapp.charmmpar.CharmmPar")
        self.lgr.debug(">> entering CharmmPar")

        self.fnames = args
        self.bondpars = ParType(sym=True, mult=False, name="bond")
        self.anglepars = ParType(sym=True, mult=False, name="angle")
        self.dihedralpars = ParType(sym=True, mult=True, name="dihedral")
        self.improperpars = ParType(sym=True, mult=False, name="improper")
        self.nonbonding = ParType(sym=False, mult=False, name="nonbonding")
        self.nbfix = ParType(sym=True, mult=False, name="nbfix")
        self.cmappars = ParType(sym=False, mult=False, name="cmap")

        for p in args:
            self._parse_charmmpar(p)
            self.lgr.debug(self.__repr__())

        self.lgr.debug("<< leaving CharmmPar")

    def __repr__(self):
        return "%3d bonding, %3d angle, %3d dih, %3d imp, %3d nonbonding and %2d cmaps" % (
            len(self.bondpars),
            len(self.anglepars),
            len(self.dihedralpars),
            len(self.improperpars),
            len(self.nonbonding),
            len(self.cmappars),
        )

    def _parse_charmmpar(self, fname):
        """ A method for parsing CHARMM PAR/PRM files. """

        self.lgr.debug("parsing parameter file: %s" % fname)
        t1 = time.time()

        # sections of the par file (doesn't include CMAP, which will be parsed separately)
        main_parts = {
            "BOND": {"nfields": (4,), "nheader": 2, "cont": self.bondpars},
            "ANGL": {"nfields": (5, 7), "nheader": 3, "cont": self.anglepars},
            "TETH": {"nfields": (5, 7), "nheader": 3, "cont": self.anglepars},
            "DIHE": {"nfields": (7, 10, 13), "nheader": 4, "cont": self.dihedralpars},
            "IMPR": {"nfields": (7, 10, 13), "nheader": 4, "cont": self.improperpars},
            "IMPH": {"nfields": (7, 10, 13), "nheader": 4, "cont": self.improperpars},
            "NONB": {"nfields": (4, 7), "nheader": 1, "cont": self.nonbonding},
            "NBON": {"nfields": (4, 7), "nheader": 1, "cont": self.nonbonding},
            "NBFI": {"nfields": (4,), "nheader": 2, "cont": self.nbfix},
        }

        # check if the file exists
        if not os.path.exists(fname):
            raise IOError("the '%s' CHARMM PAR file doesn't exist" % fname)

        # cache all of lines
        with open(fname) as f:
            _lines = f.readlines()

        # check if this is a stream file
        is_stream_file = False
        stream_i = None
        stream_j = len(_lines)
        for m, line in enumerate(_lines):
            if line.startswith("read para"):
                is_stream_file = True
                stream_i = m + 1
                continue
            if is_stream_file:
                if line.strip().lower() == "end":
                    stream_j = m

        if is_stream_file:
            _lines = _lines[stream_i:stream_j]

        # helper function to parse a line -------------------------------------
        def _parse_par_line(line, _curr_par):

            f = line.split()

            # check the number of fields
            if not len(f) in main_parts[_curr_par]["nfields"]:
                return False, "section %s - number of fields didn't match: %d \n  %s" % (_curr_par, len(f), line)

            if _curr_par in ("BOND",):
                if len(f) == 4:
                    at1, at2, kb, b0 = f
                    main_parts[_curr_par]["cont"].add_parameter((at1, at2), (float(kb), float(b0)))

            elif _curr_par in ("ANGL", "TETH"):
                if len(f) == 5:
                    at1, at2, at3, ktetha, tetha0 = f
                    main_parts[_curr_par]["cont"].add_parameter(
                        (at1, at2, at3), (float(ktetha), float(tetha0), None, None)
                    )
                elif len(f) == 7:
                    at1, at2, at3, ktetha, tetha0, kub, s0 = f
                    main_parts[_curr_par]["cont"].add_parameter(
                        (at1, at2, at3), (float(ktetha), float(tetha0), float(kub), float(s0))
                    )
                else:
                    raise ValueError(line)

            elif _curr_par in ("DIHE",):
                key = (f[0], f[1], f[2], f[3])
                nsets = int((len(f) - 4) / 3)
                for i in range(nsets):
                    kchi = float(f[4 + i * 3 + 0])
                    n = int(f[4 + i * 3 + 1])
                    delta = float(f[4 + i * 3 + 2])
                    main_parts[_curr_par]["cont"].add_parameter(key, (kchi, n, delta))

            elif _curr_par in ("IMPR", "IMPH"):
                key = (f[0], f[1], f[2], f[3])
                nsets = int((len(f) - 4) / 3)
                for i in range(nsets):
                    kpsi = float(f[4 + i * 3 + 0])
                    psi0 = float(f[4 + i * 3 + 2])
                    main_parts[_curr_par]["cont"].add_parameter(key, (kpsi, psi0))

            elif _curr_par in ("NONB", "NBON"):
                if len(f) == 4:
                    at, tmp, epsilon, rmin2 = f
                    main_parts[_curr_par]["cont"].add_parameter(at, (float(epsilon), float(rmin2), None, None))
                elif len(f) == 7:
                    at, tmp, epsilon, rmin2, tmp, epsilon14, rmin2_14 = f
                    main_parts[_curr_par]["cont"].add_parameter(
                        at, (float(epsilon), float(rmin2), float(epsilon14), float(rmin2_14))
                    )
                else:
                    raise ValueError(line)

            elif _curr_par in ("NBFI",):
                if len(f) == 4:
                    at1, at2, epsilon, rmin = f
                    main_parts[_curr_par]["cont"].add_parameter((at1, at2), (float(epsilon), float(rmin)))
                else:
                    raise NotImplementedError

            else:
                raise NotImplementedError

            return True, "OK"

        def _parse_cmap_lines(lines, cmappars):
            # assuming the cmap grid is 24x24

            n = 0  # should be zero for modulus
            p = []
            key = None
            for i, line in enumerate(lines):
                if n % (24 * 24) == 0:

                    if len(p) > 0:
                        if len(p) != 24 * 24:
                            print("warning - not enough item for the cmap", key)
                        cmappars.add_parameter(key, p)

                    key = tuple(line.split()[:8])

                    p = []
                    n = 1

                else:
                    p += list(map(float, line.split()))
                    n = len(p)

            # last one
            if len(p) > 0:
                if len(p) != 24 * 24:
                    print("warning - not enough item for the cmap", key)
                cmappars.add_parameter(key, p)

        # go over the lines in the file
        _main_sections = tuple(main_parts.keys())
        _curr_par = None

        cm_lines = []  # for caching CMAP lines

        for ln, line in enumerate(_lines):
            if "!" in line:
                line = line[0 : line.index("!")]
            line = line.strip()

            if line == "":
                continue

            elif line == "END" or line == "end":
                break

            elif line.startswith("*"):
                pass

            elif line.startswith("cutnb"):
                pass

            elif line.startswith(("HBOND", "ATOM")):
                _curr_par = None

            elif line.startswith("CMAP"):
                _curr_par = "CMAP"

            elif line.startswith(_main_sections):
                _curr_par = line[:4]

            elif _curr_par is not None:
                # parsing normal line that has parameter data

                if _curr_par == "CMAP":
                    cm_lines.append(line)
                else:
                    result, msg = _parse_par_line(line, _curr_par)

                    if result is False:
                        self.lgr.error(msg)
                        return False

        if len(cm_lines) > 0:
            _parse_cmap_lines(cm_lines, self.cmappars)

        t2 = time.time()
        self.lgr.debug("parsing took %4.1f seconds" % (t2 - t1))

    def add_params_to_system(self, system, panic_on_missing_param=True):
        self.lgr.debug("adding parameters to the system...")
        assert isinstance(system, PSFSystem)

        added_atomtypes = []
        added_bondtypes = []
        added_angletypes = []
        added_dihedraltypes = []
        added_impropertypes = []
        added_cmaptypes = []

        system.forcefield = "charmm"

        for mi, mol in enumerate(system.molecules):

            for atom in mol.atoms:
                at = atom.get_atomtype()
                if not at:
                    raise ValueError("atom type for atom %s was not found" % atom)

                if at in added_atomtypes:
                    continue

                added_atomtypes.append(at)
                p = self.nonbonding.get_parameter(at)

                if len(p) != 1:
                    msg = "for atom type %s, %d parameters found (expecting 1, found: %s)" % (at, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 4
                lje, ljl, lje14, ljl14 = p[0]

                newat = blocks.AtomType("charmm")
                newat.atype = at
                newat.mass = atom.mass
                newat.charge = atom.charge
                newat.charmm["param"]["lje"] = lje
                newat.charmm["param"]["ljl"] = ljl
                newat.charmm["param"]["lje14"] = lje14
                newat.charmm["param"]["ljl14"] = ljl14
                system.atomtypes.append(newat)

            for bond in mol.bonds:
                at1 = bond.atom1.get_atomtype()
                at2 = bond.atom2.get_atomtype()

                if (at1, at2) in added_bondtypes or (at2, at1) in added_bondtypes:
                    continue

                added_bondtypes.append((at1, at2))
                p = self.bondpars.get_parameter((at1, at2))

                if len(p) != 1:
                    msg = "for bond %s-%s, %d parameters found (expecting 1, found %s)" % (at1, at2, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 2
                kb, b0 = p[0]

                newbt = blocks.BondType("charmm")
                newbt.atype1 = at1
                newbt.atype2 = at2
                newbt.charmm["param"]["kb"] = kb
                newbt.charmm["param"]["b0"] = b0
                system.bondtypes.append(newbt)

            for angle in mol.angles:
                at1 = angle.atom1.get_atomtype()
                at2 = angle.atom2.get_atomtype()
                at3 = angle.atom3.get_atomtype()

                if (at1, at2, at3) in added_angletypes or (at3, at2, at1) in added_angletypes:
                    continue

                added_angletypes.append((at1, at2, at3))
                p = self.anglepars.get_parameter((at1, at2, at3))

                if len(p) != 1:
                    msg = "for angle %s-%s-%s, %d parameters found (expecting 1, found %s)" % (at1, at2, at3, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 4
                ktetha, tetha0, kub, s0 = p[0]
                kub = kub if kub else 0
                s0 = s0 if s0 else 0

                newagt = blocks.AngleType("charmm")
                newagt.atype1 = at1
                newagt.atype2 = at2
                newagt.atype3 = at3
                newagt.charmm["param"]["ktetha"] = ktetha
                newagt.charmm["param"]["tetha0"] = tetha0
                newagt.charmm["param"]["kub"] = kub
                newagt.charmm["param"]["s0"] = s0

                system.angletypes.append(newagt)

            for dihedral in mol.dihedrals:
                at1 = dihedral.atom1.get_atomtype()
                at2 = dihedral.atom2.get_atomtype()
                at3 = dihedral.atom3.get_atomtype()
                at4 = dihedral.atom4.get_atomtype()

                if (at1, at2, at3, at4) in added_dihedraltypes or (at4, at3, at2, at1) in added_dihedraltypes:
                    continue

                added_dihedraltypes.append((at1, at2, at3, at4))
                p = self.dihedralpars.get_charmm_dihedral_wildcard((at1, at2, at3, at4))

                if len(p) == 0:
                    msg = "for dihedral %s-%s-%s-%s no parameter was found" % (at1, at2, at3, at4)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                newdih = blocks.DihedralType("charmm")
                newdih.atype1 = at1
                newdih.atype2 = at2
                newdih.atype3 = at3
                newdih.atype4 = at4

                for dp in p:
                    kchi, n, delta = dp

                    m = {"kchi": kchi, "n": n, "delta": delta}
                    newdih.charmm["param"].append(m)

                system.dihedraltypes.append(newdih)

            for improper in mol.impropers:
                at1 = improper.atom1.get_atomtype()
                at2 = improper.atom2.get_atomtype()
                at3 = improper.atom3.get_atomtype()
                at4 = improper.atom4.get_atomtype()

                if (at1, at2, at3, at4) in added_impropertypes or (at4, at3, at2, at1) in added_impropertypes:
                    continue

                added_impropertypes.append((at1, at2, at3, at4))
                p = self.improperpars.get_charmm_improper_wildcard((at1, at2, at3, at4))

                if len(p) != 1:
                    msg = "for improper %s-%s-%s-%s, %d parameters found (expecting 1, found %s)" % (
                        at1,
                        at2,
                        at3,
                        at4,
                        len(p),
                        p,
                    )
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 2
                kpsi, psi0 = p[0]

                newimp = blocks.ImproperType("charmm")
                newimp.atype1 = at1
                newimp.atype2 = at2
                newimp.atype3 = at3
                newimp.atype4 = at4

                # newimp.charmm['param']['kpsi'] = kpsi
                # newimp.charmm['param']['psi0'] = psi0

                m = {}
                m["kpsi"] = kpsi
                m["psi0"] = psi0

                newimp.charmm["param"].append(m)

                system.impropertypes.append(newimp)

            for cmap in mol.cmaps:
                at1 = cmap.atom1.get_atomtype()
                at2 = cmap.atom2.get_atomtype()
                at3 = cmap.atom3.get_atomtype()
                at4 = cmap.atom4.get_atomtype()
                at5 = cmap.atom5.get_atomtype()
                at6 = cmap.atom6.get_atomtype()
                at7 = cmap.atom7.get_atomtype()
                at8 = cmap.atom8.get_atomtype()

                if ((at1, at2, at3, at4, at5, at6, at7, at8)) in added_cmaptypes:
                    continue

                added_cmaptypes.append((at1, at2, at3, at4, at5, at6, at7, at8))
                p = self.cmappars.get_parameter((at1, at2, at3, at4, at5, at6, at7, at8))

                if len(p) != 1:
                    msg = "for cmap: %s-%s-%s-%s-%s-%s-%s-%s, %d parameters found (expecting 1, found %s)" % (
                        at1,
                        at2,
                        at3,
                        at4,
                        at5,
                        at6,
                        at7,
                        at8,
                        len(p),
                        p,
                    )
                    if not panic_on_missing_param:
                        self.lgr.error(msg, len(p))
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 24 * 24, "%d != %d" % (len(p[0]), 24 * 24)
                newcmt = blocks.CMapType("charmm")
                newcmt.atype1 = at1
                newcmt.atype2 = at2
                newcmt.atype3 = at3
                newcmt.atype4 = at4
                newcmt.atype5 = at5
                newcmt.atype6 = at6
                newcmt.atype7 = at7
                newcmt.atype8 = at8
                newcmt.charmm["param"] = p[0]

                system.cmaptypes.append(newcmt)

            for nbkey in list(self.nbfix._data.keys()):
                if mi != 0:
                    continue  # just for the first molecule

                at1, at2 = nbkey
                p = self.nbfix.get_parameter((at1, at2))
                if len(p) == 0:
                    continue  #

                print("adding pair param to the mol for %s-%s" % (at1, at2))

                if len(p) != 1:
                    msg = "for pair %s-%s, %d parameters found (expecting 1, found %s)" % (at1, at2, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 2
                eps, rmin = p[0]
                newnb = blocks.InteractionType("charmm")
                newnb.atype1 = at1
                newnb.atype2 = at2
                newnb.charmm["param"]["lje"] = eps
                newnb.charmm["param"]["ljl"] = rmin

                system.interactiontypes.append(newnb)
Exemplo n.º 4
0
class CharmmPar(object):
    """ A class for reading CHARMM PAR/PRM files. """
    def __init__(self, *args):
        """ Constructor.

        Args:
            One or more strings. Each string specifies path to one par file.

        Attributes:
            lgr         : logging.Logger
            fnames      : a list of paths to the par files
            bondpars    : ParType, bonds
            anglepars   : ParType, angles
            dihedralpars: ParType, dihedrals
            improperpars: ParType, impropers
            nonbonding  : ParType, nonbonding
            cmappars    : ParType, cmaps
            nbfix       : ParType, nbfix

        """

        self.lgr = logging.getLogger('mainapp.charmmpar.CharmmPar')
        self.lgr.debug(">> entering CharmmPar")

        self.fnames = args
        self.bondpars = ParType(sym=True, mult=False, name='bond')
        self.anglepars = ParType(sym=True, mult=False, name='angle')
        self.dihedralpars = ParType(sym=True, mult=True, name='dihedral')
        self.improperpars = ParType(sym=True, mult=False, name='improper')
        self.nonbonding = ParType(sym=False, mult=False, name='nonbonding')
        self.nbfix = ParType(sym=True, mult=False, name='nbfix')
        self.cmappars = ParType(sym=False, mult=False, name='cmap')

        for p in args:
            self._parse_charmmpar(p)
            self.lgr.debug(self.__repr__())

        self.lgr.debug("<< leaving CharmmPar")

    def __repr__(self):
        return "%3d bonding, %3d angle, %3d dih, %3d imp, %3d nonbonding and %2d cmaps" % (
            len(self.bondpars), len(self.anglepars), len(self.dihedralpars),
            len(self.improperpars), len(self.nonbonding), len(self.cmappars))

    def _parse_charmmpar(self, fname):
        """ A method for parsing CHARMM PAR/PRM files. """

        self.lgr.debug("parsing parameter file: %s" % fname)
        t1 = time.time()

        # sections of the par file (doesn't include CMAP, which will be parsed separately)
        main_parts = {
            'BOND': {
                'nfields': (4, ),
                'nheader': 2,
                'cont': self.bondpars
            },
            'ANGL': {
                'nfields': (5, 7),
                'nheader': 3,
                'cont': self.anglepars
            },
            'TETH': {
                'nfields': (5, 7),
                'nheader': 3,
                'cont': self.anglepars
            },
            'DIHE': {
                'nfields': (7, 10, 13),
                'nheader': 4,
                'cont': self.dihedralpars
            },
            'IMPR': {
                'nfields': (7, 10, 13),
                'nheader': 4,
                'cont': self.improperpars
            },
            'IMPH': {
                'nfields': (7, 10, 13),
                'nheader': 4,
                'cont': self.improperpars
            },
            'NONB': {
                'nfields': (4, 7),
                'nheader': 1,
                'cont': self.nonbonding
            },
            'NBON': {
                'nfields': (4, 7),
                'nheader': 1,
                'cont': self.nonbonding
            },
            'NBFI': {
                'nfields': (4, ),
                'nheader': 2,
                'cont': self.nbfix
            },
        }

        # check if the file exists
        if not os.path.exists(fname):
            raise IOError("the '%s' CHARMM PAR file doesn't exist" % fname)

        # cache all of lines
        with open(fname) as f:
            _lines = f.readlines()

        # check if this is a stream file
        is_stream_file = False
        stream_i = None
        stream_j = len(_lines)
        for m, line in enumerate(_lines):
            if line.startswith('read para'):
                is_stream_file = True
                stream_i = m + 1
                continue
            if is_stream_file:
                if line.strip().lower() == 'end':
                    stream_j = m

        if is_stream_file:
            _lines = _lines[stream_i:stream_j]

        # helper function to parse a line -------------------------------------
        def _parse_par_line(line, _curr_par):

            f = line.split()

            # check the number of fields
            if not len(f) in main_parts[_curr_par]['nfields']:
                return False, "section %s - number of fields didn't match: %d \n  %s" % (
                    _curr_par, len(f), line)

            if _curr_par in ('BOND', ):
                if len(f) == 4:
                    at1, at2, kb, b0 = f
                    main_parts[_curr_par]['cont'].add_parameter(
                        (at1, at2), (float(kb), float(b0)))

            elif _curr_par in ('ANGL', 'TETH'):
                if len(f) == 5:
                    at1, at2, at3, ktetha, tetha0 = f
                    main_parts[_curr_par]['cont'].add_parameter(
                        (at1, at2, at3),
                        (float(ktetha), float(tetha0), None, None))
                elif len(f) == 7:
                    at1, at2, at3, ktetha, tetha0, kub, s0 = f
                    main_parts[_curr_par]['cont'].add_parameter(
                        (at1, at2, at3),
                        (float(ktetha), float(tetha0), float(kub), float(s0)))
                else:
                    raise ValueError(line)

            elif _curr_par in ('DIHE', ):
                key = (f[0], f[1], f[2], f[3])
                nsets = int((len(f) - 4) / 3)
                for i in range(nsets):
                    kchi = float(f[4 + i * 3 + 0])
                    n = int(f[4 + i * 3 + 1])
                    delta = float(f[4 + i * 3 + 2])
                    main_parts[_curr_par]['cont'].add_parameter(
                        key, (kchi, n, delta))

            elif _curr_par in ('IMPR', 'IMPH'):
                key = (f[0], f[1], f[2], f[3])
                nsets = int((len(f) - 4) / 3)
                for i in range(nsets):
                    kpsi = float(f[4 + i * 3 + 0])
                    psi0 = float(f[4 + i * 3 + 2])
                    main_parts[_curr_par]['cont'].add_parameter(
                        key, (kpsi, psi0))

            elif _curr_par in ('NONB', 'NBON'):
                if len(f) == 4:
                    at, tmp, epsilon, rmin2 = f
                    main_parts[_curr_par]['cont'].add_parameter(
                        at, (float(epsilon), float(rmin2), None, None))
                elif len(f) == 7:
                    at, tmp, epsilon, rmin2, tmp, epsilon14, rmin2_14 = f
                    main_parts[_curr_par]['cont'].add_parameter(
                        at, (float(epsilon), float(rmin2), float(epsilon14),
                             float(rmin2_14)))
                else:
                    raise ValueError(line)

            elif _curr_par in ('NBFI', ):
                if len(f) == 4:
                    at1, at2, epsilon, rmin = f
                    main_parts[_curr_par]['cont'].add_parameter(
                        (at1, at2), (float(epsilon), float(rmin)))
                else:
                    raise NotImplementedError

            else:
                raise NotImplementedError

            return True, "OK"

        def _parse_cmap_lines(lines, cmappars):
            # assuming the cmap grid is 24x24

            n = 0  # should be zero for modulus
            p = []
            key = None
            for i, line in enumerate(lines):
                if n % (24 * 24) == 0:

                    if len(p) > 0:
                        if len(p) != 24 * 24:
                            print('warning - not enough item for the cmap',
                                  key)
                        cmappars.add_parameter(key, p)

                    key = tuple(line.split()[:8])

                    p = []
                    n = 1

                else:
                    p += list(map(float, line.split()))
                    n = len(p)

            # last one
            if len(p) > 0:
                if len(p) != 24 * 24:
                    print('warning - not enough item for the cmap', key)
                cmappars.add_parameter(key, p)

        # go over the lines in the file
        _main_sections = tuple(main_parts.keys())
        _curr_par = None

        cm_lines = []  # for caching CMAP lines

        for ln, line in enumerate(_lines):
            if '!' in line:
                line = line[0:line.index('!')]
            line = line.strip()

            if line == '':
                continue

            elif line == 'END' or line == 'end':
                break

            elif line.startswith('*'):
                pass

            elif line.startswith('cutnb'):
                pass

            elif line.startswith(('HBOND', 'ATOM')):
                _curr_par = None

            elif line.startswith('CMAP'):
                _curr_par = 'CMAP'

            elif line.startswith(_main_sections):
                _curr_par = line[:4]

            elif _curr_par is not None:
                # parsing normal line that has parameter data

                if _curr_par == 'CMAP':
                    cm_lines.append(line)
                else:
                    result, msg = _parse_par_line(line, _curr_par)

                    if result is False:
                        self.lgr.error(msg)
                        return False

        if len(cm_lines) > 0:
            _parse_cmap_lines(cm_lines, self.cmappars)

        t2 = time.time()
        self.lgr.debug("parsing took %4.1f seconds" % (t2 - t1))

    def add_params_to_system(self, system, panic_on_missing_param=True):
        self.lgr.debug("adding parameters to the system...")
        assert isinstance(system, PSFSystem)

        added_atomtypes = []
        added_bondtypes = []
        added_angletypes = []
        added_dihedraltypes = []
        added_impropertypes = []
        added_cmaptypes = []

        system.forcefield = 'charmm'

        for mi, mol in enumerate(system.molecules):

            for atom in mol.atoms:
                at = atom.get_atomtype()
                if not at:
                    raise ValueError('atom type for atom %s was not found' %
                                     atom)

                if at in added_atomtypes:
                    continue

                added_atomtypes.append(at)
                p = self.nonbonding.get_parameter(at)

                if len(p) != 1:
                    msg = "for atom type %s, %d parameters found (expecting 1, found: %s)" % (
                        at, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 4
                lje, ljl, lje14, ljl14 = p[0]

                newat = blocks.AtomType('charmm')
                newat.atype = at
                newat.mass = atom.mass
                newat.charge = atom.charge
                newat.charmm['param']['lje'] = lje
                newat.charmm['param']['ljl'] = ljl
                newat.charmm['param']['lje14'] = lje14
                newat.charmm['param']['ljl14'] = ljl14
                system.atomtypes.append(newat)

            for bond in mol.bonds:
                at1 = bond.atom1.get_atomtype()
                at2 = bond.atom2.get_atomtype()

                if (at1, at2) in added_bondtypes or (at2,
                                                     at1) in added_bondtypes:
                    continue

                added_bondtypes.append((at1, at2))
                p = self.bondpars.get_parameter((at1, at2))

                if len(p) != 1:
                    msg = "for bond %s-%s, %d parameters found (expecting 1, found %s)" % (
                        at1, at2, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 2
                kb, b0 = p[0]

                newbt = blocks.BondType('charmm')
                newbt.atype1 = at1
                newbt.atype2 = at2
                newbt.charmm['param']['kb'] = kb
                newbt.charmm['param']['b0'] = b0
                system.bondtypes.append(newbt)

            for angle in mol.angles:
                at1 = angle.atom1.get_atomtype()
                at2 = angle.atom2.get_atomtype()
                at3 = angle.atom3.get_atomtype()

                if (at1, at2,
                        at3) in added_angletypes or (at3, at2,
                                                     at1) in added_angletypes:
                    continue

                added_angletypes.append((at1, at2, at3))
                p = self.anglepars.get_parameter((at1, at2, at3))

                if len(p) != 1:
                    msg = "for angle %s-%s-%s, %d parameters found (expecting 1, found %s)" % (
                        at1, at2, at3, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 4
                ktetha, tetha0, kub, s0 = p[0]
                kub = kub if kub else 0
                s0 = s0 if s0 else 0

                newagt = blocks.AngleType('charmm')
                newagt.atype1 = at1
                newagt.atype2 = at2
                newagt.atype3 = at3
                newagt.charmm['param']['ktetha'] = ktetha
                newagt.charmm['param']['tetha0'] = tetha0
                newagt.charmm['param']['kub'] = kub
                newagt.charmm['param']['s0'] = s0

                system.angletypes.append(newagt)

            for dihedral in mol.dihedrals:
                at1 = dihedral.atom1.get_atomtype()
                at2 = dihedral.atom2.get_atomtype()
                at3 = dihedral.atom3.get_atomtype()
                at4 = dihedral.atom4.get_atomtype()

                if (at1, at2, at3, at4) in added_dihedraltypes or (
                        at4, at3, at2, at1) in added_dihedraltypes:
                    continue

                added_dihedraltypes.append((at1, at2, at3, at4))
                p = self.dihedralpars.get_charmm_dihedral_wildcard(
                    (at1, at2, at3, at4))

                if len(p) == 0:
                    msg = "for dihedral %s-%s-%s-%s no parameter was found" % (
                        at1, at2, at3, at4)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                newdih = blocks.DihedralType('charmm')
                newdih.atype1 = at1
                newdih.atype2 = at2
                newdih.atype3 = at3
                newdih.atype4 = at4

                for dp in p:
                    kchi, n, delta = dp

                    m = {'kchi': kchi, 'n': n, 'delta': delta}
                    newdih.charmm['param'].append(m)

                system.dihedraltypes.append(newdih)

            for improper in mol.impropers:
                at1 = improper.atom1.get_atomtype()
                at2 = improper.atom2.get_atomtype()
                at3 = improper.atom3.get_atomtype()
                at4 = improper.atom4.get_atomtype()

                if (at1, at2, at3, at4) in added_impropertypes or (
                        at4, at3, at2, at1) in added_impropertypes:
                    continue

                added_impropertypes.append((at1, at2, at3, at4))
                p = self.improperpars.get_charmm_improper_wildcard(
                    (at1, at2, at3, at4))

                if len(p) != 1:
                    msg = "for improper %s-%s-%s-%s, %d parameters found (expecting 1, found %s)" % (
                        at1, at2, at3, at4, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 2
                kpsi, psi0 = p[0]

                newimp = blocks.ImproperType('charmm')
                newimp.atype1 = at1
                newimp.atype2 = at2
                newimp.atype3 = at3
                newimp.atype4 = at4

                # newimp.charmm['param']['kpsi'] = kpsi
                # newimp.charmm['param']['psi0'] = psi0

                m = {}
                m['kpsi'] = kpsi
                m['psi0'] = psi0

                newimp.charmm['param'].append(m)

                system.impropertypes.append(newimp)

            for cmap in mol.cmaps:
                at1 = cmap.atom1.get_atomtype()
                at2 = cmap.atom2.get_atomtype()
                at3 = cmap.atom3.get_atomtype()
                at4 = cmap.atom4.get_atomtype()
                at5 = cmap.atom5.get_atomtype()
                at6 = cmap.atom6.get_atomtype()
                at7 = cmap.atom7.get_atomtype()
                at8 = cmap.atom8.get_atomtype()

                if ((at1, at2, at3, at4, at5, at6, at7,
                     at8)) in added_cmaptypes:
                    continue

                added_cmaptypes.append(
                    (at1, at2, at3, at4, at5, at6, at7, at8))
                p = self.cmappars.get_parameter(
                    (at1, at2, at3, at4, at5, at6, at7, at8))

                if len(p) != 1:
                    msg = "for cmap: %s-%s-%s-%s-%s-%s-%s-%s, %d parameters found (expecting 1, found %s)" % (
                        at1, at2, at3, at4, at5, at6, at7, at8, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg, len(p))
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 24 * 24, '%d != %d' % (len(p[0]), 24 * 24)
                newcmt = blocks.CMapType('charmm')
                newcmt.atype1 = at1
                newcmt.atype2 = at2
                newcmt.atype3 = at3
                newcmt.atype4 = at4
                newcmt.atype5 = at5
                newcmt.atype6 = at6
                newcmt.atype7 = at7
                newcmt.atype8 = at8
                newcmt.charmm['param'] = p[0]

                system.cmaptypes.append(newcmt)

            for nbkey in list(self.nbfix._data.keys()):
                if mi != 0:
                    continue  # just for the first molecule

                at1, at2 = nbkey
                p = self.nbfix.get_parameter((at1, at2))
                if len(p) == 0:
                    continue  #

                print('adding pair param to the mol for %s-%s' % (at1, at2))

                if len(p) != 1:
                    msg = "for pair %s-%s, %d parameters found (expecting 1, found %s)" % (
                        at1, at2, len(p), p)
                    if not panic_on_missing_param:
                        self.lgr.error(msg)
                        continue
                    else:
                        raise ValueError(msg)

                assert len(p[0]) == 2
                eps, rmin = p[0]
                newnb = blocks.InteractionType('charmm')
                newnb.atype1 = at1
                newnb.atype2 = at2
                newnb.charmm['param']['lje'] = eps
                newnb.charmm['param']['ljl'] = rmin

                system.interactiontypes.append(newnb)