def _build_atoms(self): """It builds the atoms of the molecule.""" from peleffy.utils import Logger logger = Logger() coords = RDKitToolkitWrapper().get_coordinates(self.molecule) for index, (atom_name, atom_type, sigma, epsilon, charge, SGB_radius, vdW_radius, gamma, alpha) \ in enumerate(self.parameters.atom_iterator): atom = Atom(index=index, PDB_name=atom_name, OPLS_type=atom_type, x=coords[index][0], y=coords[index][1], z=coords[index][2], sigma=sigma, epsilon=epsilon, charge=charge, born_radius=SGB_radius, SASA_radius=vdW_radius, nonpolar_gamma=gamma, nonpolar_alpha=alpha) self.add_atom(atom) for atom in self.atoms: if atom.index in self.molecule.graph.core_nodes: atom.set_as_core() else: atom.set_as_branch() # Start from an atom from the core absolute_parent = None for atom in self.atoms: if atom.core: absolute_parent = atom.index break else: logger.error('Error: no core atom found in molecule ' + '{}'.format(self.molecule.name)) # Get parent indexes from the molecular graph parent_idxs = self.molecule.graph.get_parents(absolute_parent) # Assert parent_idxs has right length if len(parent_idxs) != len(self.atoms): logger.error('Error: no core atom found in molecule ' + '{}'.format(self.molecule.name)) for atom in self.atoms: parent_idx = parent_idxs[atom.index] if parent_idx is not None: atom.set_parent(self.atoms[parent_idx])
def get_parents(self, parent): """ It sets the parent of each atom according to the molecular graph. Parameters ---------- parent : int The index of the node to use as the absolute parent Returns ------- parents : dict[int, int] A dictionary containing the index of the parent of each atom according to the molecular graph, keyed by the index of each child """ def recursive_child_visitor(parent, parents, already_visited=set()): """ A recursive function that hierarchically visits all the childs of each atom. Parameters ---------- parent : int The index of the atom whose childs will be visited parents : dict[int, int] A dictionary containing the index of the parent of each atom according to the molecular graph, keyed by the index visited_neighbors : set[int] The updated set that contains the indexes of the atoms that have already been visited Returns ------- parents : dict[int, int] A dictionary containing the index of the parent of each atom according to the molecular graph, keyed by the index of each child visited_neighbors : set[int] The updated set that contains the indexes of the atoms that have already been visited """ if parent in already_visited: return already_visited already_visited.add(parent) childs = self.neighbors(parent) for child in childs: if child in already_visited: continue parents[child] = parent parents, already_visited = recursive_child_visitor( child, parents, already_visited) return parents, already_visited # Initialize the parents dictionary parents = {parent: None} parents, already_visited = recursive_child_visitor(parent, parents) # Assert absolut parent is the only with a None parent value if parents[parent] is not None or \ sum([int(parents[i] is not None) for i in self.nodes]) \ != len(self.nodes) - 1: from peleffy.utils import Logger logger = Logger() logger.error('Error: found descendant without parent') return parents
def _read_and_fix_pdb(self, path): """ It reads the input PDB file returns the corresponding PDB block. It also applies some modifications, in case it requires some fixing prior running the parser. Parameters ---------- path : str The path to a PDB with the molecule structure Returns ------- pdb_block : str The corresponding PDB block, with applied fixes if required """ log = Logger() # Skip PDB fixing if it has been deactivated if not self.fix_pdb: with open(path) as pdb_file: pdb_block = pdb_file.read() return pdb_block # Fix PDB missing_element = False any_fail = False pdb_block = '' with open(path) as pdb_file: for line in pdb_file: if line.startswith('ATOM') or line.startswith('HETATM'): if len(line) < 78 or line[76:78] == ' ': missing_element = True atom_name = line[12:16] # Try to infer element from atom name inferred_element = ''.join([ c for c in atom_name if not c.isdigit() and c != ' ' ]) # Format properly the element identifier if len(inferred_element) == 1: inferred_element = inferred_element.upper() elif len(inferred_element) == 2: inferred_element = inferred_element[0].upper() + \ inferred_element[1].lower() else: # We were expecting an element identifier of 1 or 2 chars any_fail = True break # Remove line breaks, if any line = line.strip() # Fill a short line with white spaces while (len(line) < 79): line += ' ' # Add element to line (right-justified) line = line[:76] + '{:>2s}'.format(inferred_element) \ + line[79:] + '\n' pdb_block += line if missing_element: log.warning("Warning: input PDB has no information about atom " + "elements and they were inferred from atom names. " + "Please, verify that the resulting elements are " + "correct") if any_fail: log.error("Error: PDB could not be fixed") with open(path) as pdb_file: pdb_block = pdb_file.read() return pdb_block