def add_dummy_entry(lmpdat): """ Add dummy entries to the lammps data file. Parameters ---------- lmpdat : str name of the lammps data file """ md_sys = aglmp.read_lmpdat(lmpdat) if md_sys.bnd_types != {}: ntypes = len(md_sys.bnd_types) if md_sys.bnd_types[ntypes - 1].prm1 > 0: md_sys.bnd_types[ntypes] = mds.Bond( bnd_key=ntypes, prm1=0.0, prm2=0.0, comment=" dummy bond for force field fitting") if md_sys.ang_types != {}: ntypes = len(md_sys.ang_types) if md_sys.ang_types[ntypes - 1].prm1 > 0: md_sys.ang_types[ntypes] = mds.Angle( ang_key=ntypes, prm1=0.0, prm2=0.0, comment=" dummy bond for force field fitting") if md_sys.dih_types != {}: ntypes = len(md_sys.dih_types) if md_sys.dih_types[ntypes - 1].prm_k > 0: md_sys.dih_types[ntypes] = mds.Dihedral( dih_key=ntypes, prm_k=0.0, prm_n=1, prm_d=0, weigh_factor=0, comment=" dummy angle for force field fitting") md_sys.change_indices(incr=1, mode="increase") md_sys.write_lmpdat(lmpdat, frame_id=-1, title="Default Title", cgcmm=True) return True
def relocate_parsed(sect_bad_iwh, container, key, dict_key_old_new, dict_atm_id_old_new): """ Sort the parsed data from the sections: > bonds (inc/without hydrogen) or > angles (inc/without hydrogen) or > dihedrals (inc/without hydrogen) to their respective containers (bonds, angles, dihedrals; see class Universe for more information). 'bad' = b(onds), a(ngles), d(ihedrals) sect_bad_iwh: list; section inclusive hydrogens or section without hydrogens key: "bonds", "angles", "dihedrals" """ #lc = len(container) # number of elements in container # bonds with hydrogens for ientry in sect_bad_iwh: # transform amber-numbered atom-ids to their original ids ientry_0 = true_atm_id(ientry[0]) ientry_0 = dict_atm_id_old_new[ientry_0] ientry_1 = true_atm_id(ientry[1]) ientry_1 = dict_atm_id_old_new[ientry_1] if len(ientry) > 3: # angles or dihedrals ientry_2 = true_atm_id(ientry[2]) ientry_2 = dict_atm_id_old_new[ientry_2] if len(ientry) > 4: # dihedrals ientry_3 = true_atm_id(ientry[3]) ientry_3 = dict_atm_id_old_new[ientry_3] if key == "bonds": container.append( mds.Bond(bnd_id=len(container), atm_id1=ientry_0, atm_id2=ientry_1, bnd_key=dict_key_old_new[ientry[2]])) elif key == "angles": container.append( mds.Angle(ang_id=len(container), atm_id1=ientry_0, atm_id2=ientry_1, atm_id3=ientry_2, ang_key=dict_key_old_new[ientry[3]])) elif key == "dihedrals": # only append non-impropers, which are dihedrals if ientry[3] > 0: container.append( mds.Dihedral(dih_id=len(container), atm_id1=ientry_0, atm_id2=ientry_1, atm_id3=ientry_2, atm_id4=ientry_3, dih_key=dict_key_old_new[ientry[4]])) elif key == "impropers": #print(ientry_0, ientry_1, ientry_2, ientry_3, ientry[4]) # if third int of each subcontainer is < 0, amber assumes it is an improper if ientry[3] < 0: container.append( mds.Improper(imp_id=len(container), atm_id1=ientry_0, atm_id2=ientry_1, atm_id3=ientry_2, atm_id4=ientry_3, imp_key=dict_key_old_new[ientry[4]])) else: raise RuntimeError( "key must be 'bonds', 'angles', 'dihedrals' or 'impropers'!") return container
def read_gau(self, gauin, overwrite=False): """ """ print("***Gau-Info: Reading Gaussian-Input-File!") (chk, nproc, mem, job_type, method, basis_set, geom, charge, multiplicity) = [None for _ in range(9)] cframe = [] with open(gauin, "r") as gau_in: for line in gau_in: if "%chk" in line: if not hasattr(self, "chk"): self.chk = line.split("=")[1].strip("\n") elif "%nproc" in line: if not hasattr(self, "nproc"): self.nproc = int(line.split("=")[1].strip("\n")) elif "%mem" in line: if not hasattr(self, "mem"): mem = line.split("=")[1].strip("\n") self.mem = int(re.findall(r'^\d+', mem)[0]) elif line.startswith("#"): # job settings direction job_settings = line.split() # classify job settings for setting in job_settings: # remove # e.g. #SP if setting.startswith("#"): setting = setting.strip("#") if setting in self.job_types: if not hasattr(self, "job_type"): self.job_type = setting elif "geom" in setting: if not hasattr(self, "geom"): self.geom = setting.split("=")[1] elif "EmpiricalDispersion" in setting: if not hasattr(self, "dispersion"): self.dispersion = setting.split("=")[1] elif "/" in setting: setting = setting.split("/") if not hasattr(self, "method"): self.method = setting[0] if not hasattr(self, "basis_set"): self.basis_set = setting[1] else: pass elif re.findall(r'^-?\d+ \d$', line): line = line.split() if not hasattr(self, "charge"): self.charge = int(line[0]) if not hasattr(self, "multiplicity"): self.multiplicity = int(line[1]) read_coords_section = True while read_coords_section is True: # read info try: line = next(gau_in) except StopIteration: # last line of document reached break # quit reading section when empty line occurs if line == "\n": read_coords_section = False break line = line.split() csitnam = line[0] ccoords = np.array([float(i) for i in line[1:]]) # store info cur_atom = mds.Atom(sitnam=csitnam) self.atoms.append(cur_atom) cframe.append(ccoords) self.ts_coords.append(cframe) elif hasattr(self, "geom") and self.geom == "connectivity": # section with bonds-information if bool(re.search(r'(^\d+ \d+ \d+.\d+)|(^\d+\n$)', line)) is True: line = line.split() # get rest of the bond-entries read_connectivity_section = True while read_connectivity_section is True: # stop reading current entry if line is empty if line == []: break # only process line if it really has bond information if len(line) > 1: # get atm-id 1 (always the same for current line) catm_id1 = int(line[0]) for idx, cur_subentry in enumerate(line[1:]): # get atm-id 2 if idx % 2 == 0: catm_id2 = int(cur_subentry) # decrease indices by 1 since internally # atom-indices start with 0 cbnd = mds.Bond(atm_id1=catm_id1 - 1, atm_id2=catm_id2 - 1) else: cbnd_order = float(cur_subentry) cbnd.bnd_order = cbnd_order self.bonds.append(cbnd) # if there is only one empty line at file bottom try: line = gau_in.next().split() except StopIteration: break else: pass
def read_gau(self, gauin, coordinate_style="cartesian", overwrite=False, debug=False): """ """ self.coordinate_style = coordinate_style print("***Gau-Info: Reading Gaussian-Input-File!") cframe = [] reading = True with open(gauin, "r") as gau_in: line = gau_in.readline() if debug is True: print("Parsing link 0 and route section") # line != "" -> just to be safe this will eventually finish when # loading a wrong file by accident while line != "": # // LINK 0 SECTION if "%oldchk" in line: if not hasattr(self, "oldchk") or overwrite is True: self.oldchk = line.split("=")[1].strip("\n") elif "%chk" in line: if not hasattr(self, "chk") or overwrite is True: self.chk = line.split("=")[1].strip("\n") elif "%nproc" in line: if not hasattr(self, "nproc") or overwrite is True: self.nproc = int(line.split("=")[1].strip("\n")) elif "%mem" in line: if not hasattr(self, "mem") or overwrite is True: self.mem = line.split("=")[1].strip("\n") # TBD elif "%rwf" in line: if not hasattr(self, "rwf") or overwrite is True: self.rwf = line.split("=")[1].strip("\n") #// ROUTE SECTION (may be scattered over several files) elif line.startswith("#"): #pdb.set_trace() # keep reading until empty line is reached, end loop # when it is while line != "\n": if self.job_settings == "" or overwrite is True: self.job_settings += line.rstrip("\n") + " " line = gau_in.readline() # eof reached if line == "": break else: break else: pass line = gau_in.readline() #// TITLE SECTION if debug is True: print("Title section") # skip all empty lines until title line is reached while line == "\n": line = gau_in.readline() else: title_line = line line = gau_in.readline() #// MOLECULE SPECIFICATION SECTION if debug is True: print("Molecule specification section") while line == "\n": line = gau_in.readline() else: charge_mutliplicity_line = re.findall(r'[\w]+', line) if self.gaussian_charges == [] or overwrite is True: self.gaussian_charges = [ int(i) for idx, i in enumerate(charge_mutliplicity_line) if idx % 2 == 0 ] if self.gaussian_multiplicities == [] or overwrite is True: self.gaussian_multiplicities = [ int(i) for idx, i in enumerate(charge_mutliplicity_line[1:]) if idx % 2 == 0 ] line = gau_in.readline() #// COORDINATES SECTION if debug is True: print("Coordinates section") g_atoms = [] g_frame = [] # gaussian coordinates # counter to substitute given atoms or complement their attributes atom_index = 0 while line != "\n": line = line.split() columns_coordinates_section_atomic = len(line) # element parameters section if "Fragment=" in line[0]: fragment_id = re.search(r"Fragment=\d+", line[0]).group(0) fragment_id = int(re.search(r"\d+", fragment_id).group(0)) csitnam = line[0].split("(")[0] else: fragment_id = None csitnam = line[0] # translate atomic number to its element if csitnam.isdigit(): csitnam = int(csitnam) csitnam = mde.atomicnumber_element[csitnam] if "Iso=" in line[0]: print("Iso not implemented yet") if "Spin=" in line[0]: print("Iso not implemented yet") # element freeze section if len(line) > 4 and (line[-4] == "0" or line[-4] == "-1"): cifrz = int(line[-4]) else: cifrz = None # store element info cur_atom = mds.Atom(sitnam=csitnam, atm_id=atom_index, ifrz=cifrz, grp_id=fragment_id) #g_atoms.append(cur_atom) try: if overwrite is True: self.atoms[atom_index] = cur_atom else: if not hasattr(self.atoms[atom_index], "sitnam"): self.atoms[atom_index].sitnam = cur_atom.sitnam # add ifrz to current atom if overwrite option is set or ifrz attribute has not been defined yet if hasattr(cur_atom, "ifrz") and not hasattr( self.atoms[atom_index], "ifrz"): self.atoms[atom_index].ifrz = cur_atom.ifrz if hasattr(cur_atom, "grp_id") and not hasattr( self.atoms[atom_index], "grp_id"): self.atoms[atom_index].grp_id = cur_atom.grp_id except IndexError: # overwrite the whole entry if one index does not fit self.atoms.append(cur_atom) # add coordinates if self.coordinate_style == "cartesian": ccoords = np.array([float(i) for i in line[-3:]]) g_frame.append(ccoords) else: print("Z-Matrix not implemented yet.") line = gau_in.readline() atom_index += 1 if line == "": break # overwrite or append frame (coordinates) to existing one(s) g_frame = np.array(g_frame) if self.ts_coords != [] and overwrite is True: self.ts_coords[-1] = g_frame else: self.ts_coords.append(g_frame) # skip all empty lines until title line is reached while line == "\n": line = gau_in.readline() # first bond line # just to be sure this will end if line == "": break # BOND SECTION if debug is True: print("Bonds Section") if "CONNECTIVITY" in self.job_settings.upper() and bool( re.search(r'(^\d+ \d+ \d+.\d+)|(^\d+\n$)', line)) is True: gau_bonds = [] while line != "\n": line = line.split() # only process line if it really has bond information if len(line) > 1: # get atm-id 1 (always the same for current line) catm_id1 = int(line[0]) catm_id1 -= 1 # decrement atom index by 1 # read other further bond partners (if present) catms_id2 = [ int(i) - 1 for idx, i in enumerate(line[1:]) if idx % 2 == 0 ] # read bond orders (if present) cbnd_orders = [ float(i) for idx, i in enumerate(line[2:]) if idx % 2 == 0 ] # append bond to gaussian given bonds for catm_id2, cbnd_order in zip( catms_id2, cbnd_orders): cbnd = mds.Bond(atm_id1=catm_id1, atm_id2=catm_id2, bnd_order=cbnd_order) gau_bonds.append(cbnd) # if there is only one empty line at file bottom line = gau_in.readline() if line == "": break # complement attributes that do not exist or overwrite existing ones if wanted if len(gau_bonds) == len(self.bonds) and overwrite is False: for idx, gau_bnd in enumerate(gau_bonds): for universe_bnd in self.bonds: if (universe_bnd.atm_id1 == gau_bnd.atm_id1 and universe_bnd.atm_id2 == gau_bnd.atm_id2): # complement attribute or overwrite existing one # if overwriting is active if not hasattr(universe_bnd, "bnd_order"): universe_bnd.bnd_order = gau_bnd.bnd_order break else: self.bonds = gau_bonds # create molecules by bond information self.fetch_molecules_by_bonds()
def read_mae(self, maefile, overwrite_data=False): """ Read Schroedinger Maestro's mae-files. """ atm_id_old_new = {} with open(maefile, "r") as mae_in: for line in mae_in: # find header for atoms-section if "m_atom" in line: cframe = [] num_atms = int(re.findall(r'\d+', line)[0]) # skip lines until coordinates section is reached while ":::" not in line: line = next(mae_in) for iid in range(num_atms): catm = mae_in.next().split() atm_id_old_new[int(catm[0])] = iid csitnam = catm[-1] ccoords = np.array([float(i) for i in catm[2:5]]) # check if an instance of Atom with index iid already exists; # overwrite info if it does or create a new one if it does not try: self.atoms[iid] # overwrite data if overwrite_data is True: self.atoms[iid].atm_id = iid self.atoms[iid].sitnam = csitnam # complement data else: if not hasattr(self.atoms[iid], "atm_id"): self.atoms[iid].atm_id = iid if not hasattr(self.atoms[iid], "sitnam"): self.atoms[iid].sitnam = csitnam except IndexError: catm = mds.Atom(atm_id=iid, sitnam=csitnam) self.atoms.append(catm) cframe.append(ccoords) # append current frame self.ts_coords.append(cframe) elif "m_bond" in line: num_bnds = int(re.findall(r'\d+', line)[0]) # skip lines until coordinates section is reached while ":::" not in line: line = next(mae_in) for iid in range(num_bnds): cbnd = mae_in.next().split() # store section atm_1 = atm_id_old_new[int(cbnd[1])] atm_2 = atm_id_old_new[int(cbnd[2])] bnd_order = int(cbnd[3]) # check if an instance of Bond with index iid already exists; # overwrite info if it does or create a new one if it does not try: self.bonds[iid] # overwrite data if overwrite_data is True: self.bonds[iid].bnd_id = iid self.bonds[iid].bnd_order = bnd_order # complement data else: if not hasattr(self.bonds[iid], "bnd_id"): self.bonds[iid].bnd_id = iid if not hasattr(self.bonds[iid], "atm_id1"): self.bonds[iid].atm_id1 = atm_1 if not hasattr(self.bonds[iid], "atm_id2"): self.bonds[iid].atm_id2 = atm_2 if not hasattr(self.bonds[iid], "bnd_order"): self.bonds[iid].bnd_order = bnd_order except IndexError: cbnd = mds.Bond(bnd_id=iid, atm_id1=atm_1, atm_id2=atm_2, bnd_order=bnd_order) self.bonds.append(cbnd) else: pass
def read_pdb(self, pdb, overwrite_data=False, debug=False): """ Read a pdb file. Work in Progress! """ with open(pdb, "r") as pdb_file: line = pdb_file.readline() atm_idx = 0 bnd_idx = 0 atm_id_old_new = {} all_pdb_coords = [] tmp_bnds = [] while line != '': if line.startswith("HETATM"): atom_line = line.split() atm_id = int(atom_line[1]) sitnam = atom_line[2] coords = np.array([float(i) for i in atom_line[3:6]]) atm_id_old_new[atm_id] = atm_idx cur_atm = mds.Atom( atm_id=atm_idx, sitnam=sitnam) self.atoms.append(cur_atm) all_pdb_coords.append(coords) atm_idx += 1 elif line.startswith("CONECT"): bond_line = line.split() # convert old indices to new ones new_indices = [atm_id_old_new[int(i)] for i in bond_line[1:]] for i, atom_index in enumerate(new_indices): # only covalent bonds are of interest (columns 1-4) if i != 0 and i < 5: id_1 = new_indices[0] id_2 = atom_index # sort by id if id_1 > id_2: id_1, id_2 = atom_index, new_indices[0] if [id_1, id_2] not in tmp_bnds: tmp_bnds.append([id_1, id_2]) cbnd = mds.Bond(bnd_id=bnd_idx, atm_id1=id_1, atm_id2=id_2) bnd_idx += 1 self.bonds.append(cbnd) elif line.startswith("CRYST1"): a = float(line[7:16]) b = float(line[16:25]) c = float(line[25:34]) alpha = float(line[34:41]) beta = float(line[40:47]) gamma = float(line[48:55]) cbox = mdb.Box( boxtype="lattice", ltc_a=a, ltc_b=b, ltc_c=c, ltc_alpha=alpha, ltc_beta=beta, ltc_gamma=gamma) self.ts_boxes.append(cbox) else: pass line = pdb_file.readline() # append coordinates self.ts_coords.append(all_pdb_coords) self.fetch_molecules_by_bonds()
def read_prmtop(self, prmtop): """ Read the contents of the amber prmtop-file. CHARMM-Entries will not be read! Input: > mode str; complement|overwrite|append; complement (missing) data, overwrite given data or append to given data """ # /// parse file with open(prmtop, "r") as prmtop_in: prmtop_version = prmtop_in.readline() # parse sections for line in prmtop_in: if line.startswith("%FLAG TITLE"): # section contains the title of the topology file next(prmtop_in) # line with formatting info prmtop_title = next(prmtop_in) elif line.startswith("%FLAG POINTERS"): # section which contains the information about how many # parameters are present in all of the sections next(prmtop_in) # line with formatting info line = next(prmtop_in).split() (natom, ntypes, nbonh, mbona, ntheth, mtheta, nphih, mphia, nhparm, nparm) = [int(i) for i in line] line = next(prmtop_in).split() (nnb, nres, nbona, ntheta, nphia, numbnd, numang, nptra, natyp, nphb) = [int(i) for i in line] line = next(prmtop_in).split() (ifpert, nbper, ngper, ndper, mbper, mgper, mdper, ifbox, nmxrs, ifcap) = [int(i) for i in line] line = next(prmtop_in).split() numextra = line[0] try: ncopy = line[1] # entry "copy" need not to be given except (IndexError): pass elif line.startswith("%FLAG ATOM_NAME"): # SECTION: ATOM_NAME # section which contains the atom name for every atom in # the prmtop section_atom_name = agphf.parse_section(prmtop_in, natom) elif line.startswith("%FLAG CHARGE"): # SECTION: CHARGE # section which contains the charge for every atom in the prmtop # prmtop-charges must be divided by 18.2223 (reasons unknown) section_charge = agphf.parse_section(prmtop_in, natom) elif line.startswith("%FLAG ATOMIC NUMBER"): pass elif line.startswith("%FLAG MASS"): # SECTION: MASS # section which contains the atomic mass of every atom # in g/mol. section_mass = agphf.parse_section(prmtop_in, natom) elif line.startswith("%FLAG ATOM_TYPE_INDEX"): # SECTION ATOM TYPE INDEX # section which contains the Lennard-Jones atom type index. # The Lennard-Jones potential contains parameters for every # pair of atoms in the system. All atoms with the same # sigma and epsilon parameters are assigned to the same type (regardless # of whether they have the same AMBER ATOM TYPE). section_atom_type_index = agphf.parse_section(prmtop_in, natom, itype="int") elif line.startswith("%FLAG NUMBER_EXCLUDED_ATOMS"): # section which contains the number of atoms that need to be # excluded from the non-bonded calculation loop for atom i # because i is involved in a bond, angle, or torsion with those atoms section_number_excluded_atoms = agphf.parse_section( prmtop_in, natom, itype="int") elif line.startswith("%FLAG NONBONDED_PARM_INDEX"): # section which contains the pointers for each pair of LJ # atom types into the LENNARD JONES ACOEF and # LENNARD JONES BCOEF arrays section_nonbonded_parm_index = agphf.parse_section( prmtop_in, ntypes * ntypes, itype="int") elif line.startswith("%FLAG RESIDUE_LABEL"): # section which contains the residue name for every residue # in the prmtop section_residue_label = agphf.parse_section( prmtop_in, nres) elif line.startswith("%FLAG RESIDUE_POINTER"): section_residue_pointer = agphf.parse_section(prmtop_in, nres, itype="int") elif line.startswith("%FLAG BOND_FORCE_CONSTANT"): # section which lists all of the bond force constants # k in kcal/(mol*Angstrom**2) for each unique bond type section_bond_force_constant = agphf.parse_section( prmtop_in, numbnd) elif line.startswith("%FLAG BOND_EQUIL_VALUE"): # section which lists all of the bond equilibrium distances # in "Angstrom" for each unique bond type section_bond_equil_value = agphf.parse_section( prmtop_in, numbnd) elif line.startswith("%FLAG ANGLE_FORCE_CONSTANT"): # section which contains all of the angle equilibrium angles # in "radians" section_angle_force_constant = agphf.parse_section( prmtop_in, numang) elif line.startswith("%FLAG ANGLE_EQUIL_VALUE"): # section which contains all of the angle equilibrium angles # in "radians" section_angle_equil_value = agphf.parse_section( prmtop_in, numang) elif line.startswith("%FLAG DIHEDRAL_FORCE_CONSTANT"): # section which lists the torsion force constants in kcal/mol # for each unique torsion type section_dihedral_force_constant = agphf.parse_section( prmtop_in, nptra) elif line.startswith("%FLAG DIHEDRAL_PERIODICITY"): # section which lists the periodicity n for each unique # torsion type; only int section_dihedral_periodicity = agphf.parse_section( prmtop_in, nptra) elif line.startswith("%FLAG DIHEDRAL_PHASE"): # section which lists the phase shift for each unique # torsion type in "radians" section_dihedral_phase = agphf.parse_section( prmtop_in, nptra) elif line.startswith("%FLAG SCEE_SCALE_FACTOR"): # section which lists the factor by which 1-4 electrostatic # interactions are divided (i.e., the two atoms on either # end of a torsion) section_scee_scale_factor = agphf.parse_section( prmtop_in, nptra) elif line.startswith("%FLAG SCNB_SCALE_FACTOR"): # section which lists the factor by which 1-4 van der Waals # interactions are divided (i.e., the two atoms on either # end of a torsion) section_scnb_scale_factor = agphf.parse_section( prmtop_in, nptra) elif line.startswith("%FLAG SOLTY"): # section which is unused section_solty = agphf.parse_section(prmtop_in, natyp) elif line.startswith("%FLAG LENNARD_JONES_ACOEF"): # section contains the LJ A-coefficients for all pairs of # distinct LJ types section_lennard_jones_acoef = agphf.parse_section( prmtop_in, ntypes * (ntypes + 1) / 2) elif line.startswith("%FLAG LENNARD_JONES_BCOEF"): # section contains the LJ A-coefficients for all pairs of # distinct LJ types section_lennard_jones_bcoef = agphf.parse_section( prmtop_in, ntypes * (ntypes + 1) / 2) elif line.startswith("%FLAG BONDS_INC_HYDROGEN"): # section which contains a list of every bond in the system # in which at least one atom is Hydrogen section_bonds_inc_hydrogen = agphf.parse_section( prmtop_in, 3 * nbonh, chunksize=3, itype="int") elif line.startswith("%FLAG BONDS_WITHOUT_HYDROGEN"): # section contains a list of every bond in the system in # which neither atom is a Hydrogen section_bonds_without_hydrogen = agphf.parse_section( prmtop_in, 3 * nbona, chunksize=3, itype="int") elif line.startswith("%FLAG ANGLES_INC_HYDROGEN"): # section contains a list of every angle in the system in # which at least one atom is Hydrogen section_angles_inc_hydrogen = agphf.parse_section( prmtop_in, 4 * ntheth, chunksize=4, itype="int") elif line.startswith("%FLAG ANGLES_WITHOUT_HYDROGEN"): # section which contains a list of every angle in the system # in which no atom is Hydrogen section_angles_without_hydrogen = agphf.parse_section( prmtop_in, 4 * ntheta, chunksize=4, itype="int") elif line.startswith("%FLAG DIHEDRALS_INC_HYDROGEN"): # section contains a list of every torsion in the system in # which at least one atom is Hydrogen section_dihedrals_inc_hydrogen = agphf.parse_section( prmtop_in, 5 * nphih, chunksize=5, itype="int") elif line.startswith("%FLAG DIHEDRALS_WITHOUT_HYDROGEN"): section_dihedrals_without_hydrogen = agphf.parse_section( prmtop_in, 5 * nphia, chunksize=5, itype="int") elif line.startswith("%FLAG AMBER_ATOM_TYPE"): section_amber_atom_type = agphf.parse_section( prmtop_in, natom) elif line.startswith("%FLAG TREE_CHAIN_CLASSIFICATION"): agphf.entry_not_read("TREE_CHAIN_CLASSIFICATION") elif line.startswith("%FLAG JOIN_ARRAY"): agphf.entry_not_read("JOIN_ARRAY") elif line.startswith("%FLAG IROTAT"): agphf.entry_not_read("IROTAT") elif line.startswith("%FLAG RADIUS_SET"): agphf.entry_not_read("RADIUS_SET") elif line.startswith("%FLAG RADII"): section_radii = agphf.parse_section(prmtop_in, natom) elif line.startswith("%FLAG SCREEN"): agphf.entry_not_read("SCREEN") else: pass # /// arrange data - force field section /// # /// atom-types # (atoms with same epsilon and sigma (lj) have same type) # 1. get acoef/bcoef-ids for ii-interactions abcoef_ids = agphf.get_AB_ids(ntypes, section_nonbonded_parm_index) # 2. calculate sigma from coefs # dict to translate between internal and amber indices atm_key_old_new = {} for cidx, cid in enumerate(abcoef_ids): #cidx += 1 cur_sig, cur_eps = agphf.sig_eps_from_AB( section_lennard_jones_acoef[cid], section_lennard_jones_bcoef[cid]) # skip duplicates try: if self.atm_types[cidx]: print("***Prmtop-Info: Skipping atom type {}".format(cid)) except KeyError: self.atm_types[cidx] = mds.Atom(sigma=cur_sig, epsilon=cur_eps, energy_unit="kcal/mol") # add old key as key and new key as value atm_key_old_new[cidx + 1] = cidx # ityp: atom type as number (= atom key) # imass: mass of atom type # itypamb: amber force field name of atom type # atypemass: dictionary with atom type masses and amber names assigned # to atom-keys # type-id (key), mass, type-name atypemass = {} for ityp, imass, itypamb in zip(section_atom_type_index, section_mass, section_amber_atom_type): # iterate through names- and mass-list, overwrite duplicates # -> only single atom-types remain atypemass[ityp] = [imass, itypamb] for akey in atypemass: akey_new = atm_key_old_new[akey] # translate old key self.atm_types[akey_new].weigh = atypemass[akey][0] self.atm_types[akey_new].sitnam = atypemass[akey][1] # /// bond-types bnd_key_old_new = {} for cbnd_id, (bnd_fconst, bnd_r0) in enumerate( zip(section_bond_force_constant, section_bond_equil_value)): self.bnd_types[cbnd_id] = mds.Bond(prm1=bnd_fconst, prm2=bnd_r0, energy_unit="kcal/mol") bnd_key_old_new[cbnd_id + 1] = cbnd_id # /// angle-types ang_key_old_new = {} for cang_id, (ang_fconst, ang_r0) in enumerate( zip(section_angle_force_constant, section_angle_equil_value)): self.ang_types[cang_id] = mds.Angle(prm1=ang_fconst, prm2=ang_r0, energy_unit="kcal/mol", angle_unit="rad") ang_key_old_new[cang_id + 1] = cang_id # /// dihedral- and improper-types # assign dihedrals and impropers to "dih" and "imp" dih_imp_dict = agphf.unmask_imp(section_dihedrals_inc_hydrogen, section_dihedrals_without_hydrogen) # dicts where we can look up, which old dihedral-/improper-key points to the new key dih_old_new = {} imp_old_new = {} dih_cntr = 0 # dihedral key-counter, for consecutive numbering imp_cntr = 0 # improper key-counter, for consecutive numbering dih_key_old_new = {} #imp_key_old_new = {} for cdih_id, (dih_fconst, dih_prd, dih_phase) in enumerate( zip(section_dihedral_force_constant, section_dihedral_periodicity, section_dihedral_phase)): cur_key = cdih_id + 1 dih_prd = int(dih_prd) if dih_imp_dict[cur_key] == "dih": self.dih_types[dih_cntr] = mds.Dihedral(prm_k=dih_fconst, prm_n=dih_prd, prm_d=dih_phase, energy_unit="kcal/mol", angle_unit="rad") # pointer new-key -> old-key dih_old_new[cur_key] = dih_cntr dih_key_old_new[dih_cntr + 1] = dih_cntr dih_cntr += 1 # right enumeration for dih-key (starting at 1) elif dih_imp_dict[cur_key] == "imp": self.imp_types[imp_cntr] = mds.Improper(prm_k=dih_fconst, prm_n=dih_prd, prm_d=dih_phase, energy_unit="kcal/mol", angle_unit="rad") # check if prm_k and prm_n fulfill cvff convention (see lammps) agphf.check_cvff_compatibility(dih_phase, dih_prd) # pointer new-key -> old-key imp_old_new[cur_key] = imp_cntr #imp_key_old_new[imp_cntr+1] = imp_cntr imp_cntr += 1 # right enumeration for imp-key (starting at 1) else: raise RuntimeError( "***Undefined dihedral! Something went totally wrong!") # /// arrange data - topology section /// # /// atoms atm_id_old_new = {} for iatmkey, (itype, ichge, isitnam) in enumerate( zip(section_atom_type_index, section_charge, section_atom_name)): # since amber is/was based on fortran, increment atom-ids by 1 self.atoms.append( mds.Atom(atm_id=iatmkey, atm_key=atm_key_old_new[itype], chge=ichge, sitnam=isitnam, grp_id=0)) # save into the corresponding dictionary to translate amber-ids to internal ids #self.atm_idx_id[iatmkey] = iatmkey+1 #self.atm_id_idx[iatmkey+1] = iatmkey atm_id_old_new[iatmkey + 1] = iatmkey # gather residue information for cur_atm_nr in range(nres): cur_res = section_residue_label[cur_atm_nr] # residue name if cur_atm_nr == 0: # first pptr = 0 else: pptr = section_residue_pointer[ cur_atm_nr] # present atom-pointer try: # atom-pointer after present atom-pointer iptr = section_residue_pointer[cur_atm_nr + 1] except (IndexError): iptr = None # None, if no pointer after present pointer for iatm in self.atoms[pptr:iptr]: iatm.res = cur_res # /// bonds self.bonds = agphf.relocate_parsed(section_bonds_inc_hydrogen, self.bonds, "bonds", bnd_key_old_new, atm_id_old_new) self.bonds = agphf.relocate_parsed(section_bonds_without_hydrogen, self.bonds, "bonds", bnd_key_old_new, atm_id_old_new) # /// angles self.angles = agphf.relocate_parsed(section_angles_inc_hydrogen, self.angles, "angles", ang_key_old_new, atm_id_old_new) self.angles = agphf.relocate_parsed(section_angles_without_hydrogen, self.angles, "angles", ang_key_old_new, atm_id_old_new) # /// dihedrals self.dihedrals = agphf.relocate_parsed(section_dihedrals_inc_hydrogen, self.dihedrals, "dihedrals", dih_old_new, atm_id_old_new) self.dihedrals = agphf.relocate_parsed( section_dihedrals_without_hydrogen, self.dihedrals, "dihedrals", dih_old_new, atm_id_old_new) # /// impropers self.impropers = agphf.relocate_parsed(section_dihedrals_inc_hydrogen, self.impropers, "impropers", imp_old_new, atm_id_old_new) self.impropers = agphf.relocate_parsed( section_dihedrals_without_hydrogen, self.impropers, "impropers", imp_old_new, atm_id_old_new) # delete variables not needed (at the moment) del prmtop_version del prmtop_title del numextra # if no ncopy is specified try: del ncopy except UnboundLocalError: pass # delete unneeded variables (at least at the moment there is no need) try: del section_number_excluded_atoms del section_scee_scale_factor del section_scnb_scale_factor del section_solty del section_radii except UnboundLocalError: pass # convert amber charges to normal ones print("***Prmtop-Info: Converting prmtop-charges.") self._convert_prmtop_charges() # convert impropers to match cvff (i.e. cos of prm_d) print("***Prmtop-Info: Converting impropers to cvff-style.") self._amb_imp2cvff() # form molecules by given bonds self.fetch_molecules_by_bonds()