Download model/utils/pdb_reres.py from OneScience-Group/Chainsaw: direct link, hf CLI and curl.
- Browser
- Download file 5.82 kB
-
https://huggingface.co/OneScience-Group/Chainsaw/resolve/main/model/utils/pdb_reres.py
- Command line
-
hf download hf://OneScience-Group/Chainsaw/model/utils/pdb_reres.py
-
curl -L -o pdb_reres.py https://huggingface.co/OneScience-Group/Chainsaw/resolve/main/model/utils/pdb_reres.py
5.82 kB
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| # | |
| # Copyright 2018 João Pedro Rodrigues | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """ | |
| Renumbers the residues of the PDB file starting from a given number (default 1). | |
| Usage: | |
| python pdb_reres.py -<number> <pdb file> | |
| Example: | |
| python pdb_reres.py -10 1CTF.pdb # renumbers from 10 | |
| python pdb_reres.py --1 1CTF.pdb # renumbers from -1 | |
| This program is part of the `pdb-tools` suite of utilities and should not be | |
| distributed isolatedly. The `pdb-tools` were created to quickly manipulate PDB | |
| files using the terminal, and can be used sequentially, with one tool streaming | |
| data to another. They are based on old FORTRAN77 code that was taking too much | |
| effort to maintain and compile. RIP. | |
| """ | |
| import os | |
| import sys | |
| import logging | |
| LOG = logging.getLogger(__name__) | |
| __author__ = "Joao Rodrigues" | |
| __email__ = "j.p.g.l.m.rodrigues@gmail.com" | |
| def check_input(args): | |
| """Checks whether to read from stdin/file and validates user input/options. | |
| """ | |
| # Defaults | |
| option = 1 | |
| fh = sys.stdin # file handle | |
| if not len(args): | |
| # Reading from pipe with default option | |
| if sys.stdin.isatty(): | |
| sys.stderr.write(__doc__) | |
| sys.exit(1) | |
| elif len(args) == 1: | |
| # One of two options: option & Pipe OR file & default option | |
| if args[0].startswith('-'): | |
| option = args[0][1:] | |
| if sys.stdin.isatty(): # ensure the PDB data is streamed in | |
| emsg = 'ERROR!! No data to process!\n' | |
| sys.stderr.write(emsg) | |
| sys.stderr.write(__doc__) | |
| sys.exit(1) | |
| else: | |
| if not os.path.isfile(args[0]): | |
| emsg = 'ERROR!! File not found or not readable: \'{}\'\n' | |
| sys.stderr.write(emsg.format(args[0])) | |
| sys.stderr.write(__doc__) | |
| sys.exit(1) | |
| fh = open(args[0], 'r') | |
| elif len(args) == 2: | |
| # Two options: option & File | |
| if not args[0].startswith('-'): | |
| emsg = 'ERROR! First argument is not an option: \'{}\'\n' | |
| sys.stderr.write(emsg.format(args[0])) | |
| sys.stderr.write(__doc__) | |
| sys.exit(1) | |
| if not os.path.isfile(args[1]): | |
| emsg = 'ERROR!! File not found or not readable: \'{}\'\n' | |
| sys.stderr.write(emsg.format(args[1])) | |
| sys.stderr.write(__doc__) | |
| sys.exit(1) | |
| option = args[0][1:] | |
| fh = open(args[1], 'r') | |
| else: # Whatever ... | |
| sys.stderr.write(__doc__) | |
| sys.exit(1) | |
| # Validate option | |
| try: | |
| option = int(option) | |
| except ValueError: | |
| emsg = 'ERROR!! You provided an invalid residue number: \'{}\'' | |
| sys.stderr.write(emsg.format(option)) | |
| sys.exit(1) | |
| return (fh, option) | |
| def pad_line(line): | |
| """Helper function to pad line to 80 characters in case it is shorter""" | |
| size_of_line = len(line) | |
| if size_of_line < 80: | |
| padding = 80 - size_of_line + 1 | |
| line = line.strip('\n') + ' ' * padding + '\n' | |
| return line[:81] # 80 + newline character | |
| def run(fhandle, starting_resid): | |
| """ | |
| Reset the residue number column to start from a specific number. | |
| This function is a generator. | |
| Parameters | |
| ---------- | |
| fhandle : a line-by-line iterator of the original PDB file. | |
| starting_resid : int | |
| The starting residue number. | |
| Yields | |
| ------ | |
| str (line-by-line) | |
| The modified (or not) PDB line. | |
| """ | |
| _pad_line = pad_line | |
| prev_resid = None # tracks chain and resid | |
| resid = starting_resid - 1 # account for first residue | |
| records = ('ATOM', 'HETATM', 'TER', 'ANISOU') | |
| for line in fhandle: | |
| line = _pad_line(line) | |
| if line.startswith('MODEL'): | |
| resid = starting_resid - 1 # account for first residue | |
| prev_resid = None # tracks chain and resid | |
| yield line | |
| elif line.startswith(records): | |
| line_resuid = line[17:27] | |
| if line_resuid != prev_resid: | |
| prev_resid = line_resuid | |
| resid += 1 | |
| if resid > 9999: | |
| emsg = 'Cannot set residue number above 9999.\n' | |
| sys.stderr.write(emsg) | |
| sys.exit(1) | |
| yield line[:22] + str(resid).rjust(4) + line[26:] | |
| else: | |
| yield line | |
| renumber_residues = run | |
| def main(): | |
| # Check Input | |
| pdbfh, starting_resid = check_input(sys.argv[1:]) | |
| # Do the job | |
| new_pdb = run(pdbfh, starting_resid) | |
| # Output results | |
| try: | |
| _buffer = [] | |
| _buffer_size = 5000 # write N lines at a time | |
| for lineno, line in enumerate(new_pdb): | |
| if not (lineno % _buffer_size): | |
| sys.stdout.write(''.join(_buffer)) | |
| _buffer = [] | |
| _buffer.append(line) | |
| sys.stdout.write(''.join(_buffer)) | |
| sys.stdout.flush() | |
| except IOError: | |
| # This is here to catch Broken Pipes | |
| # for example to use 'head' or 'tail' without | |
| # the error message showing up | |
| pass | |
| # last line of the script | |
| # Close file handle even if it is sys.stdin, no problem here. | |
| pdbfh.close() | |
| sys.exit(0) | |
| if __name__ == '__main__': | |
| main() | |