def _create_new_box(md_sys): """ """ # add new orthogonal box md_sys.ts_boxes = [] # delete all previous unneeded boxes #box_diameter = md_sys.get_system_radius(-1) + 100 # diameter with an additional size of 20 should suffice since it # is quite expensive for simulation runs with solvent #box_diameter = md_sys.get_system_radius(-1) + 50 box_diameter = md_sys.get_system_radius(-1) + 200 # very large box which will be altered later anyways pi_2 = math.pi / 2 new_box = mdb.Box(boxtype="lattice", ltc_a=box_diameter, ltc_b=box_diameter, ltc_c=box_diameter, ltc_alpha=pi_2, ltc_beta=pi_2, ltc_gamma=pi_2) md_sys.ts_boxes.append(new_box) md_sys.ts_boxes[0].box_lat2lmp(triclinic=False)
def get_cell_from_cif(cif_file): """Get lattice entities from a cif file.""" def get_number_from_line(input_line): """Get lattice entities from line.""" input_line = input_line.split() number = float(input_line[1].split("(")[0]) return number with open(cif_file) as f_open: line = f_open.readline() while line != "": if "_cell_length_a" in line: cif_a = get_number_from_line(line) elif "_cell_length_b" in line: cif_b = get_number_from_line(line) elif "_cell_length_c" in line: cif_c = get_number_from_line(line) elif "_cell_angle_alpha" in line: cif_alpha = get_number_from_line(line) cif_alpha = np.radians(cif_alpha) elif "_cell_angle_beta" in line: cif_beta = get_number_from_line(line) cif_beta = np.radians(cif_beta) elif "_cell_angle_gamma" in line: cif_gamma = get_number_from_line(line) cif_gamma = np.radians(cif_gamma) else: pass line = f_open.readline() box = mdb.Box(boxtype="lattice", ltc_a=cif_a, ltc_b=cif_b, ltc_c=cif_c, ltc_alpha=cif_alpha, ltc_beta=cif_beta, ltc_gamma=cif_gamma) return box
) args.cell_by_guess = True args.cell_by_coordfile = False # cell coordinates by user if args.cell is not None: a, b, c = args.cell[0:3] alpha, beta, gamma = [math.radians(i) for i in args.cell[3:]] # replace box if given or append if none was given before if sys_topo_ff.ts_boxes == []: sys_topo_ff.ts_boxes.append( mdb.Box(boxtype="lattice", ltc_a=a, ltc_b=b, ltc_c=c, ltc_alpha=alpha, ltc_beta=beta, ltc_gamma=gamma)) else: sys_topo_ff.ts_boxes[0] = mdb.Box(boxtype="lattice", ltc_a=a, ltc_b=b, ltc_c=c, ltc_alpha=alpha, ltc_beta=beta, ltc_gamma=gamma) sys_topo_ff.ts_boxes[0].box_lat2lmp() # guess cell size if none was defined or user wants it that way explicitly elif args.cell_by_guess is True or sys_topo_ff.ts_boxes == []:
M_shft_cut = cgt.translation_matrix(args.shft_cutshape) atm_idxs = list(range(len(sys_cutshape.ts_coords[-1]))) sys_cutshape.mm_atm_coords(-1, M_shft_cut, False, *atm_idxs) del (atm_idxs, M_shft_cut) else: sys_cutshape = None #=============================================================================== # PREPARE BOX WHICH SOLELY DEFINES THE SHAPE #=============================================================================== if args.box is not None: import math if args.boxtype == "lammps": box = mdb.Box(boxtype=args.boxtype, lmp_xlo=args.box[0], lmp_xhi=args.box[1], lmp_ylo=args.box[2], lmp_yhi=args.box[3], lmp_zlo=args.box[4], lmp_zhi=args.box[5], lmp_xy=args.box[6], lmp_xz=args.box[7], lmp_yz=args.box[8]) #box.box_lmp2cart() # change box vectors to lattice elif args.boxtype == "lattice": box = mdb.Box(boxtype=args.boxtype, ltc_a=args.box[0], ltc_b=args.box[1], ltc_c=args.box[2], ltc_alpha=math.radians(args.box[3]), ltc_beta=math.radians(args.box[4]), ltc_gamma=math.radians(args.box[5])) box.box_lat2cart() else: box = mdb.Box(boxtype=args.boxtype, crt_a=[args.box[0], args.box[1], args.box[2]], crt_b=[args.box[3], args.box[4], args.box[5]], crt_c=[args.box[6], args.box[7], args.box[8]]) else: box = None # equalize box variable if sys_cutshape is not None: box = sys_cutshape.ts_boxes[-1] if box.boxtype == "lammps": box.box_lmp2cart()
def read_xyz(self, xyzfile, overwrite_data=False): """ Read the contents of a xyz-file. XYZ-Format: https://en.wikipedia.org/wiki/XYZ_file_format A boxtype may be given in the comment line. The line has to look like the following Boxtype lattice a 52.213276 b 52.213276 c 52.213276 alpha 90.000000 beta 90.000000 gamma 90.000000 """ with open(xyzfile, "r") as xyz_in: for line in xyz_in: if line == "\n" or line == "": #print("Reached EOF.") break num_atms = int( line.split()[0]) # line with number of atoms (mandatory) comment_line = next(xyz_in) # comment line (may be empty) # read box information if there is any if "Boxtype" in comment_line: comment_line = comment_line.split() box = [ None if i == "None" else None if round(float(i), 8) == 0 else float(i) for i in comment_line[3::2] ] if comment_line[1] == "cartesian": current_box = mdb.Box( boxtype=comment_line[1], crt_a=box[0], crt_b=box[1], crt_c=box[2], ) elif comment_line[1] == "lattice": current_box = mdb.Box( boxtype=comment_line[1], ltc_a=box[0], ltc_b=box[1], ltc_c=box[2], ltc_alpha=np.radians(box[3]), ltc_beta=np.radians(box[4]), ltc_gamma=np.radians(box[5]), ) else: current_box = mdb.Box( boxtype=comment_line[1], lmp_xlo=box[0], lmp_xhi=box[1], lmp_ylo=box[2], lmp_yhi=box[3], lmp_zlo=box[4], lmp_zhi=box[5], lmp_xy=box[6], lmp_xz=box[7], lmp_yz=box[8], ) del (box, comment_line) # overwrite given boxes if overwrite_data is True: self.ts_boxes = [] self.ts_boxes.append(current_box) else: pass cframe = [] # parse coordinates section for iid in range(num_atms): catm = next(xyz_in).split() csitnam = catm[0] ccoords = np.array([float(i) for i in catm[1:5]]) # charge of current atom ccharge = None if len(catm) > 4: ccharge = float(catm[4]) # 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 if ccharge is not None: self.atoms[iid].chge = ccharge # 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 if (not hasattr(self.atoms[iid], "chge") and ccharge is not None): self.atoms[iid].chge = ccharge except IndexError: catm = mds.Atom(atm_id=iid, sitnam=csitnam) if ccharge is not None: catm.chge = ccharge self.atoms.append(catm) cframe.append(ccoords) # append current frame self.ts_coords.append(cframe)
def read_pwin(self, pwin): """ Read an input file for pw.x. Cell vector alat (celldm(1)) is converted to angstrom when read. """ # container to supply atoms from "ATOMIC_POSITIONS" with info from "ATOMIC_SPECIES" # which may be compared to lammps "Masses" and "Atoms" input #TODO write frozen atoms atm_types_ptrs = {} with open(pwin) as opened_pwin: line = opened_pwin.readline() while line != '': if line.startswith("&CONTROL"): while line != '': line = opened_pwin.readline() # skip empty lines, end if end of block ('/') is reached if line.startswith("\n"): continue elif line.startswith("/"): break else: pass # split line by '=' and ' ' split_line = re.split(r'\s*=\s*', line) split_line[1] = split_line[1].strip() # convert str float/int if possible if re.match(r"^\d+?\.\d+?$", split_line[1]): split_line[1] = float(split_line[1]) else: try: split_line[1] = int(split_line[1]) except ValueError: pass self.pw_entries["CONTROL"][ split_line[0].strip()] = split_line[1] elif line.startswith("&SYSTEM"): while line != '': line = opened_pwin.readline() if line.startswith("\n"): continue elif line.startswith("/"): break else: pass split_line = re.split(r'\s*=\s*', line) split_line[1] = split_line[1].strip() # convert str float/int if possible if re.match(r"^\d+?\.\d+?$", split_line[1]): split_line[1] = float(split_line[1]) else: try: split_line[1] = int(split_line[1]) except ValueError: pass self.pw_entries["SYSTEM"][ split_line[0].strip()] = split_line[1] elif line.startswith("&ELECTRONS"): while line != '': line = opened_pwin.readline() if line.startswith("\n"): continue elif line.startswith("/"): break else: pass split_line = re.split(r'\s*=\s*', line) split_line[1] = split_line[1].strip() # convert str float/int if possible if re.match(r"^\d+?\.\d+?$", split_line[1]): split_line[1] = float(split_line[1]) else: try: split_line[1] = int(split_line[1]) except ValueError: pass self.pw_entries["ELECTRONS"][ split_line[0].strip()] = split_line[1] elif line.startswith("&IONS"): while line != '': line = opened_pwin.readline() if line.startswith("\n"): continue elif line.startswith("/"): break else: pass split_line = re.split(r'\s*=\s*', line) split_line[1] = split_line[1].strip() # convert str float/int if possible if re.match(r"^\d+?\.\d+?$", split_line[1]): split_line[1] = float(split_line[1]) else: try: split_line[1] = int(split_line[1]) except ValueError: pass self.pw_entries["IONS"][ split_line[0].strip()] = split_line[1] elif line.startswith("&CELL"): while line != '': line = opened_pwin.readline() if line.startswith("\n"): continue elif line.startswith("/"): break else: pass split_line = re.split(r'\s*=\s*', line) split_line[1] = split_line[1].strip() # convert str float/int if possible if re.match(r"^\d+?\.\d+?$", split_line[1]): split_line[1] = float(split_line[1]) else: try: split_line[1] = int(split_line[1]) except ValueError: pass self.pw_entries["CELL"][ split_line[0].strip()] = split_line[1] elif line.startswith("ATOMIC_SPECIES"): # GET ATOM TYPES atmcnt = 0 while line != '': line = opened_pwin.readline() # end of block if line == "\n": break split_line = line.split() # add current atom type to atom types self.atm_types[atmcnt] = mds.Atom( sitnam=split_line[0], weigh=float(split_line[1]), pseudopotential=split_line[2]) # "C": 0, "H": 1, and so on atm_types_ptrs[split_line[0]] = atmcnt atmcnt += 1 elif line.startswith("ATOMIC_POSITIONS"): # GET ATOM COORDINATES self.ts_coords.append([]) while line != '': line = opened_pwin.readline() # end of block if line == "\n": break split_line = line.split() # omit further information if dictionary is empty (should not happen) cur_atm_sitnam = split_line[0] if atm_types_ptrs == {}: self.atoms.append(mds.Atom(sitnam=cur_atm_sitnam)) else: cur_atm_key = atm_types_ptrs[cur_atm_sitnam] #cur_atm_key = self.atm_types[cur_atm_key_idx] catom = mds.Atom(sitnam=cur_atm_sitnam, atm_key=cur_atm_key) # read frozen info if given if len(split_line) == 7: catom.ifrz_x = int(split_line[-3]) catom.ifrz_y = int(split_line[-2]) catom.ifrz_z = int(split_line[-1]) self.atoms.append(catom) # add coordinates from current atom to the current frame self.ts_coords[-1].append( np.array([float(i) for i in split_line[1:4]])) elif line.startswith("K_POINTS"): kpoints_line = line.split() self.pw_entries["K_POINTS"]["option"] = kpoints_line[1] # read upcoming lines while line != '': line = opened_pwin.readline() if line.startswith("\n"): break split_line = line.split() if kpoints_line[1].strip("{}()") == "automatic": self.pw_entries["K_POINTS"]["k_point_grid"] = [ int(i) for i in split_line ] break elif kpoints_line[1] == "gamma": self.pw_entries["K_POINTS"]["k_point_grid"] = [] break else: pass elif line.startswith("CELL_PARAMETERS"): #TODO: calculate from Bohr to Angstrom in place? box_unit = line.split()[1].strip("{}") # get box vectors cbox = mdb.Box(boxtype="cartesian", unit=box_unit) for line_cntr in range(3): line = [ float(i) for i in opened_pwin.readline().split() ] # allot each vector to the box if line_cntr == 0: cbox.crt_a = line # vector a elif line_cntr == 1: cbox.crt_b = line # vector b else: cbox.crt_c = line # vector c self.ts_boxes.append(cbox) else: pass line = opened_pwin.readline() # convert cell to lattice cell and append it to the current cells if ("A" in self.pw_entries["SYSTEM"] and "B" in self.pw_entries["SYSTEM"] and "C" in self.pw_entries["SYSTEM"] and "cosAB" in self.pw_entries["SYSTEM"] and "cosAC" in self.pw_entries["SYSTEM"] and "cosBC" in self.pw_entries["SYSTEM"]): # cbox = mdb.Box( ltc_a=float(self.pw_entries["SYSTEM"]["A"]), ltc_b=float(self.pw_entries["SYSTEM"]["B"]), ltc_c=float(self.pw_entries["SYSTEM"]["C"]), ltc_alpha=math.acos(float(self.pw_entries["SYSTEM"]["cosBC"])), ltc_beta=math.acos(float(self.pw_entries["SYSTEM"]["cosAC"])), ltc_gamma=math.acos(float(self.pw_entries["SYSTEM"]["cosAB"])), boxtype="lattice", unit="angstrom") # delete surplus box entries del self.pw_entries["SYSTEM"]["A"] del self.pw_entries["SYSTEM"]["B"] del self.pw_entries["SYSTEM"]["C"] del self.pw_entries["SYSTEM"]["cosBC"] del self.pw_entries["SYSTEM"]["cosAC"] del self.pw_entries["SYSTEM"]["cosAB"] # add celldm(1) and convert it to bohr #self.pw_entries["SYSTEM"]["celldm(1)"] = cbox.ltc_a * ANGSTROM_BOHR self.pw_entries["SYSTEM"]["ibrav"] = 0 # convert lattice box to cartesian cbox.box_lat2cart() self.ts_boxes.append(cbox) # convert celldm (= alat) to box vector a with angstrom #try: #self.ts_boxes[-1].ltc_a = float(self.pw_entries["SYSTEM"]["celldm(1)"]*BOHR_ANGSTROM) #except KeyError: #pass # final check if len(self.atoms) != self.pw_entries["SYSTEM"]["nat"]: print("***Warning: Number of atoms and SYSTEM entry 'nat' differ!") #time.sleep(5) if os.path.isdir( self.pw_entries["CONTROL"]["pseudo_dir"].strip("'")) is False: print("***Warning: Folder for Pseudopotentials does not exist!")
def read_pwout(self, pwout, read_crystal_sections=False, save_all_scf_steps=True): """ CAVEAT: UNDER CONSTRUCTION! Read the output of pw.x. Currently this only reads the coordinates and cell vectors. Cell vector alat (celldm(1)) is converted to angstrom when read. #TODO READ FROZEN ATOMS """ #print(pwout) with open(pwout) as opened_pwout: line = opened_pwout.readline() while line != '': if line.startswith("CELL_PARAMETERS"): # get alat split_line = line.split() # get box vectors cbox = mdb.Box(boxtype="cartesian") if "alat" in line: #self.pw_entries["SYSTEM"]["celldm(1)"] = float(split_line[2].strip(")")) cbox.unit = "alat" elif "bohr" in line: cbox.unit = "bohr" elif "angstrom" in line: cbox.unit = "angstrom" else: raise Warning( "Keyword for box unknown and not implemented.") cbox.crt_a = [ float(i) for i in opened_pwout.readline().split() ] cbox.crt_b = [ float(i) for i in opened_pwout.readline().split() ] cbox.crt_c = [ float(i) for i in opened_pwout.readline().split() ] if cbox.unit == "alat": cbox.alat2angstrom(float(split_line[2].strip(")"))) self.ts_boxes.append(cbox) elif line.startswith(" atomic species"): line = opened_pwout.readline() atm_types_ptrs = {} atm_type_cntr = 0 while line != '\n': #print(repr(line)) atm_types_ptrs[line.split()[0]] = atm_type_cntr atm_type_cntr += 1 line = opened_pwout.readline() elif line.startswith("ATOMIC_POSITIONS"): #TODO: need a smarter way to do this! # overwrite existing atoms self.atoms = [] # prepare container for coordinates to come self.ts_coords.append([]) atm_cntr = 0 # read the coordinates while line != '': line = opened_pwout.readline() # stop reading when EOF is reached if line.startswith("\n") or line.startswith( "End final coordinates"): break split_line = line.split() cur_atm = mds.Atom( sitnam=split_line[0], atm_id=atm_cntr, atm_key=atm_types_ptrs[split_line[0]]) self.atoms.append(cur_atm) cur_atm_coords = np.array( [float(i) for i in split_line[1:]]) self.ts_coords[-1].append(cur_atm_coords) atm_cntr += 1 elif line.startswith("! total energy"): split_line = line.split() energy = float(split_line[-2]) * RYDBERG_EV self.pw_other_info["ENERGIES"].append(energy) elif line.startswith(" density ="): split_line = line.split() density = float(split_line[-2]) self.pw_other_info["DENSITIES"].append(density) elif line.startswith(" new unit-cell volume"): split_line = line.split() volume = float(split_line[-3]) self.pw_other_info["VOLUMES"].append(volume) else: pass # get alat value if read_crystal_sections is True: if line.startswith(" lattice parameter (alat)"): # not sure why alat was converted here before, seems to be wrong # when the whole box is converted later anyway alat = float(line.split()[-2]) #* BOHR_ANGSTROM #print(alat) # get box with box vectors elif line.startswith( " crystal axes: (cart. coord. in units of alat)" ): # get box vectors cbox = mdb.Box(boxtype="cartesian") cbox.unit = "alat" cbox.crt_a = [ float(i) for i in opened_pwout.readline().split()[3:6] ] cbox.crt_b = [ float(i) for i in opened_pwout.readline().split()[3:6] ] cbox.crt_c = [ float(i) for i in opened_pwout.readline().split()[3:6] ] cbox.alat2angstrom(alat) self.ts_boxes.append(cbox) elif line.startswith(" Cartesian axes"): # overwrite existing atoms self.atoms = [] # prepare container for coordinates to come self.ts_coords.append([]) atm_cntr = 0 # skip next two lines opened_pwout.readline() opened_pwout.readline() # read the coordinates while line != '': line = opened_pwout.readline() # stop reading when end of current entry is reached if line.startswith("\n"): break split_line = line.split() cur_atm = mds.Atom( sitnam=split_line[1], atm_id=atm_cntr, atm_key=atm_types_ptrs[split_line[1]]) self.atoms.append(cur_atm) cur_atm_coords = np.array( [float(i) * alat for i in split_line[6:9]]) self.ts_coords[-1].append(cur_atm_coords) atm_cntr += 1 line = opened_pwout.readline() split_line = None # save only the last frame if save_all_scf_steps is False: self.ts_coords = [self.ts_coords[-1]] for key in self.pw_other_info: try: self.pw_other_info[key] = [self.pw_other_info[key][-1]] except IndexError: pass
def read_file(self, filename, filetype): """Get values of interest from given file of given type.""" if filetype == "pwout": molsys = read_pw_out(filename) molsys.ts_boxes[-1].box_cart2lat() # get box and convert angles to degrees self.box = molsys.ts_boxes[-1] self.box.ltc_alpha = np.degrees(molsys.ts_boxes[-1].ltc_alpha) self.box.ltc_beta = np.degrees(molsys.ts_boxes[-1].ltc_beta) self.box.ltc_gamma = np.degrees(molsys.ts_boxes[-1].ltc_gamma) self.energy = molsys.pw_other_info["ENERGIES"][-1] self.density = molsys.pw_other_info["DENSITIES"][-1] self.volume = molsys.pw_other_info["VOLUMES"][-1] # ab initio is always at 0 K self.temp = 0.0 self.natoms = len(molsys.ts_coords[-1]) elif filetype == "lmplog": molsys = ag_lmplog.LmpLog() molsys.read_lmplog(filename) # box stuff self.box = mdb.Box() self.box.ltc_a = molsys.data[-1]["Cella"][-1] self.box.ltc_b = molsys.data[-1]["Cellb"][-1] self.box.ltc_c = molsys.data[-1]["Cellc"][-1] self.box.ltc_alpha = molsys.data[-1]["CellAlpha"][-1] self.box.ltc_beta = molsys.data[-1]["CellBeta"][-1] self.box.ltc_gamma = molsys.data[-1]["CellGamma"][-1] # other self.energy = molsys.data[-1]["PotEng"][-1] self.density = molsys.data[-1]["Density"][-1] self.volume = molsys.data[-1]["Volume"][-1] self.temp = molsys.data[-1]["Temp"][-1] with open(filename) as fin: line = fin.readline() while line != '': if line.startswith("Loop time of"): self.natoms = int(line.split()[-2]) line = fin.readline() elif filetype == "cif": # box stuff self.box = get_cell_from_cif(filename) cif_others = get_other_stuff_from_cif(filename) self.box.ltc_alpha = np.degrees(self.box.ltc_alpha) self.box.ltc_beta = np.degrees(self.box.ltc_beta) self.box.ltc_gamma = np.degrees(self.box.ltc_gamma) # other self.density = cif_others["density"] self.volume = cif_others["cell_volume"] self.temp = cif_others["cell_measurement_temperature"] else: raise Warning("Only pwout, lmplog and cif are valid keywords") if filetype == "lmplog" or filetype == "pwout": self.nmols = int(self.natoms / self.atoms_p_molecule) else: self.nmols = cif_others["cell_formula_units"]
# Coordinates ------------------------------------------------------------------ if args.xyz: amber_topology.read_xyz(args.xyz, overwrite_data=False) else: amber_topology.read_inpcrd(args.inpcrd) # Box definition --------------------------------------------------------------- if args.box is None: amber_topology.def_boxes_by_coords() else: a, b, c = args.box[0:3] alpha, beta, gamma = [math.radians(i) for i in args.box[3:]] amber_topology.ts_boxes.append( mdb.Box(boxtype="lattice", ltc_a=a, ltc_b=b, ltc_c=c, ltc_alpha=alpha, ltc_beta=beta, ltc_gamma=gamma)) # change indices to start with 1 (everything is newly ordered) amber_topology.change_indices(incr=1, mode="increase") # write title containing box info (if there) amber_topology.write_lmpdat(args.out, frame_id=0, title="{}".format(args.sysname), cgcmm=True)
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()