def mainCommand(argv): """ Main driver for running program from the command line. """ fieldNames = ('amber', 'charmm', 'parse', 'tyl06', 'peoepb', 'swanson') validForcefields = [] validForcefields.extend(fieldNames) validForcefields.extend((x.upper() for x in fieldNames)) description = 'This module takes a PDB file as input and performs ' +\ 'optimizations before yielding a new PQR-style file in PQR_OUTPUT_PATH.\n' +\ 'If PDB_PATH is an ID it will automatically be obtained from the PDB archive.' usage = 'Usage: %prog [options] PDB_PATH PQR_OUTPUT_PATH' parser = OptionParser(description=description, usage=usage, version='%prog (Version ' + __version__ + ')') group = OptionGroup(parser, "Manditory options", "One of the following options must be used.") group.add_option('--ff', dest='ff', metavar='FIELD_NAME', choices=validForcefields, help='The forcefield to use - currently amber, ' + 'charmm, parse, tyl06, peoepb and swanson ' + 'are supported.') group.add_option( '--userff', dest='userff', metavar='USER_FIELD_FILE', help= 'The user created forcefield file to use. Requires --usernames overrides --ff' ) group.add_option( '--clean', dest='clean', action='store_true', default=False, help='Do no optimization, atom addition, or parameter assignment, ' + 'just return the original PDB file in aligned format. ' + 'Overrides --ff and --userff') parser.add_option_group(group) group = OptionGroup(parser, "General options") group.add_option('--nodebump', dest='debump', action='store_false', default=True, help='Do not perform the debumping operation') group.add_option('--noopt', dest='opt', action='store_false', default=True, help='Do not perform hydrogen optimization') group.add_option('--chain', dest='chain', action='store_true', default=False, help='Keep the chain ID in the output PQR file') group.add_option( '--assign-only', dest='assign_only', action='store_true', default=False, help= 'Only assign charges and radii - do not add atoms, debump, or optimize.' ) group.add_option( '--ffout', dest='ffout', metavar='FIELD_NAME', choices=validForcefields, help= 'Instead of using the standard canonical naming scheme for residue and atom names, ' + 'use the names from the given forcefield - currently amber, ' + 'charmm, parse, tyl06, peoepb and swanson are supported.') group.add_option( '--usernames', dest='usernames', metavar='USER_NAME_FILE', help='The user created names file to use. Required if using --userff') group.add_option( '--apbs-input', dest='input', action='store_true', default=False, help= 'Create a template APBS input file based on the generated PQR file. Also creates a Python ' + 'pickle for using these parameters in other programs.') group.add_option( '--ligand', dest='ligand', metavar='PATH', help= 'Calculate the parameters for the ligand in mol2 format at the given path. ' + 'Pdb2pka must be compiled.') group.add_option( '--whitespace', dest='whitespace', action='store_true', default=False, help= 'Insert whitespaces between atom name and residue name, between x and y, and between y and z.' ) group.add_option('--typemap', dest='typemap', action='store_true', default=False, help='Create Typemap output.') group.add_option( '--neutraln', dest='neutraln', action='store_true', default=False, help='Make the N-terminus of this protein neutral (default is charged). ' 'Requires PARSE force field.') group.add_option( '--neutralc', dest='neutralc', action='store_true', default=False, help='Make the C-terminus of this protein neutral (default is charged). ' 'Requires PARSE force field.') group.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Print information to stdout.') group.add_option( '--drop-water', dest='drop_water', action='store_true', default=False, help= 'Drop waters before processing protein. Currently recognized and deleted are the following water types: %s' % ', '.join(WAT.water_residue_names)) group.add_option( '--include-header', dest='include_header', action='store_true', default=False, help='Include pdb header in pqr file. ' 'WARNING: The resulting PQR file will not work with APBS versions prior to 1.5' ) parser.add_option_group(group) pka_group = OptionGroup(parser, "pH options") pka_group.add_option( '--ph-calc-method', dest='ph_calc_method', metavar='PH_METHOD', choices=('propka', 'pdb2pka'), help= 'Method used to calculate ph values. If a pH calculation method is selected, for each' ' titratable residue pH values will be calculated and the residue potentially modified' ' after comparison with the pH value supplied by --with_ph\n' 'propka - Use PROPKA to calculate pH values. Actual PROPKA results will be output to <output-path>.propka.\n' 'pdb2pka - Use PDB2PKA to calculate pH values. Requires the use of the PARSE force field.' ' Warning: Larger residues can take a very long time to run using this method. EXPERIMENTAL!' ) pka_group.add_option( '--with-ph', dest='ph', action='store', type='float', default=7.0, help= 'pH values to use when applying the results of the selected pH calculation method.' ' Defaults to %default') parser.add_option_group(pka_group) pdb2pka_group = OptionGroup(parser, "PDB2PKA method options") pdb2pka_group.add_option( '--pdb2pka-out', dest='pdb2pka_out', action='store', default='pdb2pka_output', help='Output directory for PDB2PKA results. Defaults to %default') pdb2pka_group.add_option( '--pdb2pka-resume', dest='pdb2pka_resume', action="store_true", default=False, help='Resume run from state saved in output directory.') pdb2pka_group.add_option( '--pdie', dest='pdb2pka_pdie', default=8, type='int', help='Protein dielectric constant. Defaults to %default') pdb2pka_group.add_option( '--sdie', dest='pdb2pka_sdie', default=80, type='int', help='Solvent dielectric constant. Defaults to %default') # pdb2pka_group.add_option('--maps', dest='maps', default=None, type='int', # help='<1 for using provided 3D maps; 2 for genereting new maps>') # pdb2pka_group.add_option('--xdiel', dest='xdiel', default=None, type='str', # help='<xdiel maps>') # pdb2pka_group.add_option('--ydiel', dest='ydiel', default=None, type='str', # help='<ydiel maps>') # pdb2pka_group.add_option('--zdiel', dest='zdiel', default=None, type='str', # help='<zdiel maps>') # pdb2pka_group.add_option('--kappa', dest='kappa', default=None, type='str', # help='<ion-accessibility map>') # pdb2pka_group.add_option('--smooth', dest='sd', default=None, type='float', # help='<st.dev [A] of Gaussian smooting of 3D maps at the boundary, bandthwith=3 st.dev>') # # Cut off energy for calculating non-charged-charged interaction energies # pdb2pka_group.add_option( '--pairene', dest='pdb2pka_pairene', type='float', default=1.0, help= 'Cutoff energy in kT for calculating non charged-charged interaction energies. Default: %default' ) parser.add_option_group(pdb2pka_group) propka_group = OptionGroup(parser, "PROPKA method options") propka_group.add_option( "--propka-reference", dest="propka_reference", default="neutral", choices=('neutral', 'low-pH'), help= "Setting which reference to use for stability calculations. See PROPKA 3.0 documentation." ) propka_group.add_option( '--propka-verbose', dest='propka_verbose', action='store_true', default=False, help='Print extra proPKA information to stdout. ' 'WARNING: This produces an incredible amount of output.') parser.add_option_group(propka_group) extensions.setupExtensionsOptions(parser) (options, args) = parser.parse_args(argv[1:]) commandLine = ' '.join(argv[1:]) if len(args) != 2: parser.error('Incorrect number (%d) of arguments!\nargs: %s' % (len(args), args)) if options.assign_only or options.clean: options.debump = options.optflag = False userfffile = None usernamesfile = None if not options.clean: if not options.usernames is None: try: usernamesfile = open(options.usernames, 'rU') except IOError: parser.error('Unable to open user names file %s' % options.usernames) if not options.userff is None: try: userfffile = open(options.userff, 'rU') except IOError: parser.error('Unable to open user force field file %s' % options.userff) if options.usernames is None: parser.error('--usernames must be specified if using --userff') else: if options.ff is None: parser.error( 'One of the manditory options was not specified.\n' + 'Please specify either --ff, --userff, or --clean') if getFFfile(options.ff) == '': parser.error( 'Unable to find parameter files for forcefield %s!' % options.ff) if options.ph < 0.0 or options.ph > 14.0: parser.error( '%i is not a valid pH! Please choose a pH between 0.0 and 14.0.' % options.pH) ph_calc_options = None if options.ph_calc_method == 'propka': ph_calc_options = utilities.createPropkaOptions( options.ph, verbose=options.propka_verbose, reference=options.propka_reference) if options.ph_calc_method == 'pdb2pka': if options.ff.lower() != 'parse': parser.error('PDB2PKA requires the PARSE force field.') ph_calc_options = { 'output_dir': options.pdb2pka_out, 'clean_output': not options.pdb2pka_resume, 'pdie': options.pdb2pka_pdie, 'sdie': options.pdb2pka_sdie, 'pairene': options.pdb2pka_pairene } if options.ligand is not None: try: options.ligand = open(options.ligand, 'rU') except IOError: parser.error('Unable to find ligand file %s!' % options.ligand) if options.neutraln and (options.ff is None or options.ff.lower() != 'parse'): parser.error('--neutraln option only works with PARSE forcefield!') if options.neutralc and (options.ff is None or options.ff.lower() != 'parse'): parser.error('--neutralc option only works with PARSE forcefield!') text = """ -------------------------- PDB2PQR - a Python-based structural conversion utility -------------------------- Please cite your use of PDB2PQR as: Dolinsky TJ, Nielsen JE, McCammon JA, Baker NA. PDB2PQR: an automated pipeline for the setup, execution, and analysis of Poisson-Boltzmann electrostatics calculations. Nucleic Acids Research 32 W665-W667 (2004). """ sys.stdout.write(text) path = args[0] pdbFile = getPDBFile(path) pdblist, errlist = readPDB(pdbFile) if len(pdblist) == 0 and len(errlist) == 0: parser.error("Unable to find file %s!" % path) if len(errlist) != 0 and options.verbose: print "Warning: %s is a non-standard PDB file.\n" % path print errlist outpath = args[1] options.outname = outpath #In case no extensions were specified or no extensions exist. if not hasattr(options, 'active_extensions') or options.active_extensions is None: options.active_extensions = [] #I see no point in hiding options from extensions. extensionOpts = options #TODO: The ideal would be to pass a file like object for the second # argument and add a third for names then # get rid of the userff and username arguments to this function. # This would also do away with the redundent checks and such in # the Forcefield constructor. try: header, lines, missedligands = runPDB2PQR( pdblist, options.ff, outname=options.outname, ph=options.ph, verbose=options.verbose, selectedExtensions=options.active_extensions, ph_calc_method=options.ph_calc_method, ph_calc_options=ph_calc_options, extensionOptions=extensionOpts, clean=options.clean, neutraln=options.neutraln, neutralc=options.neutralc, ligand=options.ligand, assign_only=options.assign_only, chain=options.chain, drop_water=options.drop_water, debump=options.debump, opt=options.opt, typemap=options.typemap, userff=userfffile, usernames=usernamesfile, ffout=options.ffout, commandLine=commandLine, include_old_header=options.include_header) except PDB2PQRError as er: print er sys.exit(2) # Print the PQR file outfile = open(outpath, "w") outfile.write(header) # Adding whitespaces if --whitespace is in the options for line in lines: if options.whitespace: if line[0:4] == 'ATOM': newline = line[0:6] + ' ' + line[6:16] + ' ' + line[ 16:38] + ' ' + line[38:46] + ' ' + line[46:] outfile.write(newline) elif line[0:6] == 'HETATM': newline = line[0:6] + ' ' + line[6:16] + ' ' + line[ 16:38] + ' ' + line[38:46] + ' ' + line[46:] outfile.write(newline) else: outfile.write(line) outfile.close() if options.input: from src import inputgen from src import psize method = "mg-auto" size = psize.Psize() size.parseInput(outpath) size.runPsize(outpath) async = 0 # No async files here! input = inputgen.Input(outpath, size, method, async, potdx=True) input.printInputFiles() input.dumpPickle() pickleToJSON(outpath)
def __init__(self, form): '''Gleans all information about the user selected options and uploaded files. Also validates the user input. Raises WebOptionsError if there is any problems.''' #options to pass to runPDB2PQR self.runoptions = {} #Additional options to pass to google analytics along with the run options. #These are included in has_key(), __contains__(), and __getitem__() calls. self.otheroptions = {} self.runoptions['debump'] = "DEBUMP" in form self.runoptions['opt'] = "OPT" in form if 'FF' in form: self.ff = form["FF"].value.lower() else: raise WebOptionsError('Force field type missing from form.') if "PDBID" in form and form["PDBID"].value and form["PDBSOURCE"].value == 'ID': self.pdbfile = utilities.getPDBFile(form["PDBID"].value) if self.pdbfile is None: raise WebOptionsError('The pdb ID provided is invalid.') self.pdbfilestring = self.pdbfile.read() self.pdbfile = StringIO(self.pdbfilestring) self.pdbfilename = form["PDBID"].value elif "PDB" in form and form["PDB"].filename and form["PDBSOURCE"].value == 'UPLOAD': self.pdbfilestring = form["PDB"].value self.pdbfile = StringIO(self.pdbfilestring) self.pdbfilename = sanitizeFileName(form["PDB"].filename) else: raise WebOptionsError('You need to specify a pdb ID or upload a pdb file.') if "PKACALCMETHOD" in form: if form["PKACALCMETHOD"].value != 'none': if 'PH' not in form: raise WebOptionsError('Please provide a pH value.') phHelp = 'Please choose a pH between 0.0 and 14.0.' try: ph = float(form["PH"].value) except ValueError: raise WebOptionsError('The pH value provided must be a number! ' + phHelp) if ph < 0.0 or ph > 14.0: text = "The entered pH of %.2f is invalid! " % ph text += phHelp raise WebOptionsError(text) self.runoptions['ph'] = ph #build propka and pdb2pka options if form['PKACALCMETHOD'].value == 'propka': self.runoptions['ph_calc_method'] = 'propka' self.runoptions['ph_calc_options'] = utilities.createPropkaOptions(ph, False) if form['PKACALCMETHOD'].value == 'pdb2pka': self.runoptions['ph_calc_method'] = 'pdb2pka' self.runoptions['ph_calc_options'] = {'output_dir': 'pdb2pka_output', 'clean_output': True, 'pdie': 8, 'sdie': 80, 'pairene': 1.0} self.otheroptions['apbs'] = "INPUT" in form self.otheroptions['whitespace'] = "WHITESPACE" in form if self.ff == 'user': if "USERFF" in form and form["USERFF"].filename: self.userfffilename = sanitizeFileName(form["USERFF"].filename) self.userffstring = form["USERFF"].value self.runoptions['userff'] = StringIO(form["USERFF"].value) else: text = "A force field file must be provided if using a user created force field." raise WebOptionsError(text) if "USERNAMES" in form and form["USERNAMES"].filename: self.usernamesfilename = sanitizeFileName(form["USERNAMES"].filename) self.usernamesstring = form["USERNAMES"].value self.runoptions['usernames'] = StringIO(form["USERNAMES"].value) else: text = "A names file must be provided if using a user created force field." raise WebOptionsError(text) if "FFOUT" in form and form["FFOUT"].value != "internal": self.runoptions['ffout'] = form["FFOUT"].value self.runoptions['chain'] = "CHAIN" in form self.runoptions['typemap'] = "TYPEMAP" in form self.runoptions['neutraln'] = "NEUTRALN" in form self.runoptions['neutralc'] = "NEUTRALC" in form self.runoptions['drop_water'] = "DROPWATER" in form if (self.runoptions['neutraln'] or self.runoptions['neutraln']) and \ self.ff != 'parse': raise WebOptionsError('Neutral N-terminus and C-terminus require the PARSE forcefield.') if "LIGAND" in form and form['LIGAND'].filename: self.ligandfilename=sanitizeFileName(form["LIGAND"].filename) ligandfilestring = form["LIGAND"].value # for Windows and Mac style newline compatibility for pdb2pka ligandfilestring = ligandfilestring.replace('\r\n', '\n') self.ligandfilestring = ligandfilestring.replace('\r', '\n') self.runoptions['ligand'] = StringIO(self.ligandfilestring) if self.pdbfilename[-4:]==".pdb": self.pqrfilename = "%s.pqr" % self.pdbfilename[:-4] else: self.pqrfilename = "%s.pqr" % self.pdbfilename #Always turn on summary and verbose. self.runoptions['verbose'] = True self.runoptions['selectedExtensions'] = ['summary']
def mainCommand(argv): """ Main driver for running program from the command line. """ fieldNames = ('amber', 'charmm', 'parse', 'tyl06', 'peoepb', 'swanson') validForcefields = [] validForcefields.extend(fieldNames) validForcefields.extend((x.upper() for x in fieldNames)) description = 'This module takes a PDB file as input and performs ' +\ 'optimizations before yielding a new PQR-style file in PQR_OUTPUT_PATH.\n' +\ 'If PDB_PATH is an ID it will automatically be obtained from the PDB archive.' usage = 'Usage: %prog [options] PDB_PATH PQR_OUTPUT_PATH' parser = OptionParser(description=description, usage=usage, version='%prog (Version ' + __version__ + ')') group = OptionGroup(parser, "Mandatory options", "One of the following options must be used.") group.add_option('--ff', dest='ff', metavar='FIELD_NAME', choices=validForcefields, help='The forcefield to use - currently AMBER, ' + 'CHARMM, PARSE, TYL06, PEOEPB and SWANSON ' + 'are supported.') group.add_option( '--userff', dest='userff', metavar='USER_FIELD_FILE', help= 'The user created forcefield file to use. Requires --usernames overrides --ff' ) group.add_option( '--clean', dest='clean', action='store_true', default=False, help='Do no optimization, atom addition, or parameter assignment, ' + 'just return the original PDB file in aligned format. ' + 'Overrides --ff and --userff') parser.add_option_group(group) group = OptionGroup(parser, "General options") group.add_option('--nodebump', dest='debump', action='store_false', default=True, help='Do not perform the debumping operation') group.add_option('--noopt', dest='opt', action='store_false', default=True, help='Do not perform hydrogen optimization') group.add_option('--chain', dest='chain', action='store_true', default=False, help='Keep the chain ID in the output PQR file') group.add_option( '--assign-only', dest='assign_only', action='store_true', default=False, help= 'Only assign charges and radii - do not add atoms, debump, or optimize.' ) group.add_option( '--ffout', dest='ffout', metavar='FIELD_NAME', choices=validForcefields, help= 'Instead of using the standard canonical naming scheme for residue and atom names, ' + 'use the names from the given forcefield - currently AMBER, ' + 'CHARMM, PARSE, TYL06, PEOEPB and SWANSON ' + 'are supported.') group.add_option( '--usernames', dest='usernames', metavar='USER_NAME_FILE', help='The user created names file to use. Required if using --userff') group.add_option( '--apbs-input', dest='input', action='store_true', default=False, help= 'Create a template APBS input file based on the generated PQR file. Also creates a Python ' + 'pickle for using these parameters in other programs.') group.add_option( '--ligand', dest='ligand', metavar='PATH', help= 'Calculate the parameters for the ligand in mol2 format at the given path. ' + 'Pdb2pka must be compiled.') group.add_option( '--whitespace', dest='whitespace', action='store_true', default=False, help= 'Insert whitespaces between atom name and residue name, between x and y, and between y and z.' ) group.add_option('--typemap', dest='typemap', action='store_true', default=False, help='Create Typemap output.') group.add_option( '--neutraln', dest='neutraln', action='store_true', default=False, help= 'Make the N-terminus of this protein neutral (default is charged). ' + 'Requires PARSE force field.') group.add_option( '--neutralc', dest='neutralc', action='store_true', default=False, help= 'Make the C-terminus of this protein neutral (default is charged). ' + 'Requires PARSE force field.') group.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Print information to stdout.') parser.add_option_group(group) propkaroup = OptionGroup(parser, "propka options") propkaroup.add_option( '--with-ph', dest='pH', action='store', type='float', help= 'Use propka to calculate pKas and apply them to the molecule given the pH value. ' + 'Actual PropKa results will be output to <output-path>.propka.') propkaroup.add_option( "--reference", dest="reference", default="neutral", help= "setting which reference to use for stability calculations [neutral/low-pH]" ) parser.add_option_group(propkaroup) extensions.setupExtensionsOptions(parser) (options, args) = parser.parse_args() if len(args) != 2: parser.error( 'Incorrect number (%d) of arguments!\nargv: %s, args: %s' % (len(args), argv, args)) # Append Numeric/Numpy path to sys.path if the user specified a non-standard location during configuration sys.argv = argv package_path = PACKAGE_PATH if package_path != "": sys.path.extend(package_path.split(":")) propkaOpts = None if (not options.pH is None): if (options.pH < 0.0 or options.pH > 14.0): parser.error( '%i is not a valid pH! Please choose a pH between 0.0 and 14.0.' % options.pH) #build propka options propkaOpts = utilities.createPropkaOptions(options.pH, options.verbose) if options.assign_only or options.clean: options.debump = options.optflag = False userfffile = None usernamesfile = None if not options.clean: if not options.usernames is None: try: usernamesfile = open(options.usernames, 'rU') except IOError: parser.error('Unable to open user names file %s' % options.usernames) if not options.userff is None: try: userfffile = open(options.userff, 'rU') except IOError: parser.error('Unable to open user force field file %s' % options.userff) if options.usernames is None: parser.error('--usernames must be specified if using --userff') else: if options.ff is None: parser.error( 'One of the manditory options was not specified.\n' + 'Please specify either --ff, --userff, or --clean') if getFFfile(options.ff) == '': parser.error( 'Unable to find parameter files for forcefield %s!' % options.ff) if not options.ligand is None: try: options.ligand = open(options.ligand, 'rU') except IOError: parser.error('Unable to find ligand file %s!' % options.ligand) if options.neutraln and (options.ff != 'parse' or not options.userff is None): parser.error('--neutraln option only works with PARSE forcefield!') if options.neutralc and (options.ff != 'parse' or not options.userff is None): parser.error('--neutralc option only works with PARSE forcefield!') text = "\n--------------------------\n" text += "PDB2PQR - a Python-based structural conversion utility\n" text += "--------------------------\n" text += "Please cite your use of PDB2PQR as:\n" text += " Dolinsky TJ, Nielsen JE, McCammon JA, Baker NA.\n" text += " PDB2PQR: an automated pipeline for the setup, execution,\n" text += " and analysis of Poisson-Boltzmann electrostatics calculations.\n" text += " Nucleic Acids Research 32 W665-W667 (2004).\n\n" sys.stdout.write(text) path = args[0] pdbFile = getPDBFile(path) pdblist, errlist = readPDB(pdbFile) if len(pdblist) == 0 and len(errlist) == 0: parser.error("Unable to find file %s!" % path) if len(errlist) != 0 and options.verbose: print "Warning: %s is a non-standard PDB file.\n" % path print errlist outpath = args[1] options.outname = outpath #In case no extensions were specified or no extensions exist. if not hasattr(options, 'active_extensions') or options.active_extensions is None: options.active_extensions = [] #I see no point in hiding options from extensions. extensionOpts = options #TODO: The ideal would be to pass a file like object for the second # argument and add a third for names then # get rid of the userff and username arguments to this function. # This would also do away with the redundent checks and such in # the Forcefield constructor. header, lines, missedligands = runPDB2PQR( pdblist, options.ff, outname=options.outname, ph=options.pH, verbose=options.verbose, selectedExtensions=options.active_extensions, propkaOptions=propkaOpts, extensionOptions=extensionOpts, clean=options.clean, neutraln=options.neutraln, neutralc=options.neutralc, ligand=options.ligand, assign_only=options.assign_only, chain=options.chain, debump=options.debump, opt=options.opt, typemap=options.typemap, userff=userfffile, usernames=usernamesfile, ffout=options.ffout) # Print the PQR file outfile = open(outpath, "w") outfile.write(header) # Adding whitespaces if --whitespace is in the options for line in lines: if options.whitespace: if line[0:4] == 'ATOM': newline = line[0:16] + ' ' + line[16:38] + ' ' + line[ 38:46] + ' ' + line[46:] outfile.write(newline) elif line[0:6] == 'HETATM': newline = line[0:6] + ' ' + line[6:16] + ' ' + line[ 16:38] + ' ' + line[38:46] + ' ' + line[46:] outfile.write(newline) else: outfile.write(line) outfile.close() if options.input: from src import inputgen from src import psize method = "mg-auto" size = psize.Psize() size.parseInput(outpath) size.runPsize(outpath) async = 0 # No async files here! input = inputgen.Input(outpath, size, method, async) input.printInputFiles() input.dumpPickle()
def __init__(self, form): '''Gleans all information about the user selected options and uploaded files. Also validates the user input. Raises WebOptionsError if there is any problems.''' #options to pass to runPDB2PQR self.runoptions = {} #Additional options to pass to google analytics along with the run options. #These are included in has_key(), __contains__(), and __getitem__() calls. self.otheroptions = {} self.runoptions['debump'] = form.has_key("DEBUMP") self.runoptions['opt'] = form.has_key("OPT") if form.has_key('FF'): self.ff = form["FF"].value.lower() else: raise WebOptionsError('Force field type missing from form.') if form.has_key("PDBID") and form["PDBID"].value and form[ "PDBSOURCE"].value == 'ID': self.pdbfile = utilities.getPDBFile(form["PDBID"].value) if self.pdbfile is None: raise WebOptionsError('The pdb ID provided is invalid.') self.pdbfilestring = self.pdbfile.read() self.pdbfile = StringIO(self.pdbfilestring) self.pdbfilename = form["PDBID"].value elif form.has_key("PDB") and form["PDB"].filename and form[ "PDBSOURCE"].value == 'UPLOAD': self.pdbfilestring = form["PDB"].value self.pdbfile = StringIO(self.pdbfilestring) self.pdbfilename = sanitizeFileName(form["PDB"].filename) else: raise WebOptionsError( 'You need to specify a pdb ID or upload a pdb file.') if form.has_key("PROPKA"): if not form.has_key('PH'): raise WebOptionsError('Please provide a pH value.') phHelp = 'Please choose a pH between 0.0 and 14.0.' try: ph = float(form["PH"].value) except ValueError: raise WebOptionsError( 'The pH value provided must be a number! ' + phHelp) if ph < 0.0 or ph > 14.0: text = "The entered pH of %.2f is invalid! " % ph text += phHelp raise WebOptionsError(text) self.runoptions['ph'] = ph #build propka options self.runoptions['propkaOptions'] = utilities.createPropkaOptions( ph, True) self.otheroptions['apbs'] = form.has_key("INPUT") self.otheroptions['whitespace'] = form.has_key("WHITESPACE") if self.ff == 'user': if form.has_key("USERFF") and form["USERFF"].filename: self.userfffilename = sanitizeFileName(form["USERFF"].filename) self.userffstring = form["USERFF"].value self.runoptions['userff'] = StringIO(form["USERFF"].value) else: text = "A force field file must be provided if using a user created force field." raise WebOptionsError(text) if form.has_key("USERNAMES") and form["USERNAMES"].filename: self.usernamesfilename = sanitizeFileName( form["USERNAMES"].filename) self.usernamesstring = form["USERNAMES"].value self.runoptions['usernames'] = StringIO( form["USERNAMES"].value) else: text = "A names file must be provided if using a user created force field." raise WebOptionsError(text) if form.has_key("FFOUT") and form["FFOUT"].value != "internal": self.runoptions['ffout'] = form["FFOUT"].value self.runoptions['chain'] = form.has_key("CHAIN") self.runoptions['typemap'] = form.has_key("TYPEMAP") self.runoptions['neutraln'] = form.has_key("NEUTRALN") self.runoptions['neutralc'] = form.has_key("NEUTRALC") if (self.runoptions['neutraln'] or self.runoptions['neutraln']) and \ self.ff != 'parse': raise WebOptionsError( 'Neutral N-terminus and C-terminus require the PARSE forcefield.' ) if form.has_key("LIGAND") and form['LIGAND'].filename: self.ligandfilename = sanitizeFileName(form["LIGAND"].filename) ligandfilestring = form["LIGAND"].value # for Windows and Mac style newline compatibility for pdb2pka ligandfilestring = ligandfilestring.replace('\r\n', '\n') self.ligandfilestring = ligandfilestring.replace('\r', '\n') self.runoptions['ligand'] = StringIO(self.ligandfilestring) if self.pdbfilename[-4:] == ".pdb": self.pqrfilename = "%s.pqr" % self.pdbfilename[:-4] else: self.pqrfilename = "%s.pqr" % self.pdbfilename #Always turn on summary and verbose. self.runoptions['verbose'] = True self.runoptions['selectedExtensions'] = ['summary']
def mainCommand(argv): """ Main driver for running program from the command line. """ fieldNames = ('amber','charmm','parse', 'tyl06','peoepb','swanson') validForcefields = [] validForcefields.extend(fieldNames) validForcefields.extend((x.upper() for x in fieldNames)) description = 'This module takes a PDB file as input and performs ' +\ 'optimizations before yielding a new PQR-style file in PQR_OUTPUT_PATH.\n' +\ 'If PDB_PATH is an ID it will automatically be obtained from the PDB archive.' usage = 'Usage: %prog [options] PDB_PATH PQR_OUTPUT_PATH' parser = OptionParser(description=description, usage=usage, version='%prog (Version ' + __version__ + ')') group = OptionGroup(parser,"Mandatory options", "One of the following options must be used.") group.add_option('--ff', dest='ff', metavar='FIELD_NAME', choices=validForcefields, help='The forcefield to use - currently AMBER, ' + 'CHARMM, PARSE, TYL06, PEOEPB and SWANSON ' + 'are supported.') group.add_option('--userff', dest='userff', metavar='USER_FIELD_FILE', help='The user created forcefield file to use. Requires --usernames overrides --ff') group.add_option('--clean', dest='clean', action='store_true', default=False, help='Do no optimization, atom addition, or parameter assignment, ' + 'just return the original PDB file in aligned format. ' + 'Overrides --ff and --userff') parser.add_option_group(group) group = OptionGroup(parser,"General options") group.add_option('--nodebump', dest='debump', action='store_false', default=True, help='Do not perform the debumping operation') group.add_option('--noopt', dest='opt', action='store_false', default=True, help='Do not perform hydrogen optimization') group.add_option('--chain', dest='chain', action='store_true', default=False, help='Keep the chain ID in the output PQR file') group.add_option('--assign-only', dest='assign_only', action='store_true', default=False, help='Only assign charges and radii - do not add atoms, debump, or optimize.') group.add_option('--ffout', dest='ffout', metavar='FIELD_NAME',choices=validForcefields, help='Instead of using the standard canonical naming scheme for residue and atom names, ' + 'use the names from the given forcefield - currently AMBER, ' + 'CHARMM, PARSE, TYL06, PEOEPB and SWANSON ' + 'are supported.') group.add_option('--usernames', dest='usernames', metavar='USER_NAME_FILE', help='The user created names file to use. Required if using --userff') group.add_option('--apbs-input', dest='input', action='store_true', default=False, help='Create a template APBS input file based on the generated PQR file. Also creates a Python ' + 'pickle for using these parameters in other programs.') group.add_option('--ligand', dest='ligand', metavar='PATH', help='Calculate the parameters for the ligand in mol2 format at the given path. ' + 'Pdb2pka must be compiled.') group.add_option('--whitespace', dest='whitespace', action='store_true', default=False, help='Insert whitespaces between atom name and residue name, between x and y, and between y and z.') group.add_option('--typemap', dest='typemap', action='store_true', default=False, help='Create Typemap output.') group.add_option('--neutraln', dest='neutraln', action='store_true', default=False, help='Make the N-terminus of this protein neutral (default is charged). ' + 'Requires PARSE force field.') group.add_option('--neutralc', dest='neutralc', action='store_true', default=False, help='Make the C-terminus of this protein neutral (default is charged). ' + 'Requires PARSE force field.') group.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Print information to stdout.') parser.add_option_group(group) propkaroup = OptionGroup(parser,"propka options") propkaroup.add_option('--with-ph', dest='pH', action='store', type='float', help='Use propka to calculate pKas and apply them to the molecule given the pH value. ' + 'Actual PropKa results will be output to <output-path>.propka.') propkaroup.add_option("--reference", dest="reference", default="neutral", help="setting which reference to use for stability calculations [neutral/low-pH]") parser.add_option_group(propkaroup) extensions.setupExtensionsOptions(parser) (options, args) = parser.parse_args() if len(args) != 2: parser.error('Incorrect number (%d) of arguments!\nargv: %s, args: %s' % (len(args),argv, args)) # Append Numeric/Numpy path to sys.path if the user specified a non-standard location during configuration sys.argv=argv package_path = PACKAGE_PATH if package_path != "": sys.path.extend(package_path.split(":")) propkaOpts = None if (not options.pH is None): if(options.pH < 0.0 or options.pH > 14.0): parser.error('%i is not a valid pH! Please choose a pH between 0.0 and 14.0.' % options.pH) #build propka options propkaOpts = utilities.createPropkaOptions(options.pH, options.verbose) if options.assign_only or options.clean: options.debump = options.optflag = False userfffile = None usernamesfile = None if not options.clean: if not options.usernames is None: try: usernamesfile = open(options.usernames, 'rU') except IOError: parser.error('Unable to open user names file %s' % options.usernames) if not options.userff is None: try: userfffile = open(options.userff, 'rU') except IOError: parser.error('Unable to open user force field file %s' % options.userff) if options.usernames is None: parser.error('--usernames must be specified if using --userff') else: if options.ff is None: parser.error('One of the manditory options was not specified.\n' + 'Please specify either --ff, --userff, or --clean') if getFFfile(options.ff) == '': parser.error('Unable to find parameter files for forcefield %s!' % options.ff) if not options.ligand is None: try: options.ligand = open(options.ligand, 'rU') except IOError: parser.error('Unable to find ligand file %s!' % options.ligand) if options.neutraln and (options.ff != 'parse' or not options.userff is None): parser.error('--neutraln option only works with PARSE forcefield!') if options.neutralc and (options.ff != 'parse' or not options.userff is None): parser.error('--neutralc option only works with PARSE forcefield!') text = "\n--------------------------\n" text += "PDB2PQR - a Python-based structural conversion utility\n" text += "--------------------------\n" text += "Please cite your use of PDB2PQR as:\n" text += " Dolinsky TJ, Nielsen JE, McCammon JA, Baker NA.\n" text += " PDB2PQR: an automated pipeline for the setup, execution,\n" text += " and analysis of Poisson-Boltzmann electrostatics calculations.\n" text += " Nucleic Acids Research 32 W665-W667 (2004).\n\n" sys.stdout.write(text) path = args[0] pdbFile = getPDBFile(path) pdblist, errlist = readPDB(pdbFile) if len(pdblist) == 0 and len(errlist) == 0: parser.error("Unable to find file %s!" % path) if len(errlist) != 0 and options.verbose: print "Warning: %s is a non-standard PDB file.\n" % path print errlist outpath = args[1] options.outname = outpath #In case no extensions were specified or no extensions exist. if not hasattr(options, 'active_extensions' ) or options.active_extensions is None: options.active_extensions = [] #I see no point in hiding options from extensions. extensionOpts = options #TODO: The ideal would be to pass a file like object for the second # argument and add a third for names then # get rid of the userff and username arguments to this function. # This would also do away with the redundent checks and such in # the Forcefield constructor. try: header, lines, missedligands = runPDB2PQR(pdblist, options.ff, outname = options.outname, ph = options.pH, verbose = options.verbose, selectedExtensions = options.active_extensions, propkaOptions = propkaOpts, extensionOptions = extensionOpts, clean = options.clean, neutraln = options.neutraln, neutralc = options.neutralc, ligand = options.ligand, assign_only = options.assign_only, chain = options.chain, debump = options.debump, opt = options.opt, typemap = options.typemap, userff = userfffile, usernames = usernamesfile, ffout = options.ffout) except PDB2PQRError as er: print er sys.exit(1) # Print the PQR file outfile = open(outpath,"w") outfile.write(header) # Adding whitespaces if --whitespace is in the options for line in lines: if options.whitespace: if line[0:4] == 'ATOM': newline = line[0:16] + ' ' + line[16:38] + ' ' + line[38:46] + ' ' + line[46:] outfile.write(newline) elif line[0:6] == 'HETATM': newline = line[0:16] + ' ' + line[16:38] + ' ' + line[38:46] + ' ' + line[46:] outfile.write(newline) else: outfile.write(line) outfile.close() if options.input: from src import inputgen from src import psize method = "mg-auto" size = psize.Psize() size.parseInput(outpath) size.runPsize(outpath) async = 0 # No async files here! input = inputgen.Input(outpath, size, method, async, potdx=True) input.printInputFiles() input.dumpPickle()
def mainCommand(argv): """ Main driver for running program from the command line. """ fieldNames = ('amber','charmm','parse', 'tyl06','peoepb','swanson') validForcefields = [] validForcefields.extend(fieldNames) validForcefields.extend((x.upper() for x in fieldNames)) description = 'This module takes a PDB file as input and performs ' +\ 'optimizations before yielding a new PQR-style file in PQR_OUTPUT_PATH.\n' +\ 'If PDB_PATH is an ID it will automatically be obtained from the PDB archive.' usage = 'Usage: %prog [options] PDB_PATH PQR_OUTPUT_PATH' parser = OptionParser(description=description, usage=usage, version='%prog (Version ' + __version__ + ')') group = OptionGroup(parser,"Manditory options", "One of the following options must be used.") group.add_option('--ff', dest='ff', metavar='FIELD_NAME', choices=validForcefields, help='The forcefield to use - currently amber, ' + 'charmm, parse, tyl06, peoepb and swanson ' + 'are supported.') group.add_option('--userff', dest='userff', metavar='USER_FIELD_FILE', help='The user created forcefield file to use. Requires --usernames overrides --ff') group.add_option('--clean', dest='clean', action='store_true', default=False, help='Do no optimization, atom addition, or parameter assignment, ' + 'just return the original PDB file in aligned format. ' + 'Overrides --ff and --userff') parser.add_option_group(group) group = OptionGroup(parser,"General options") group.add_option('--nodebump', dest='debump', action='store_false', default=True, help='Do not perform the debumping operation') group.add_option('--noopt', dest='opt', action='store_false', default=True, help='Do not perform hydrogen optimization') group.add_option('--chain', dest='chain', action='store_true', default=False, help='Keep the chain ID in the output PQR file') group.add_option('--assign-only', dest='assign_only', action='store_true', default=False, help='Only assign charges and radii - do not add atoms, debump, or optimize.') group.add_option('--ffout', dest='ffout', metavar='FIELD_NAME',choices=validForcefields, help='Instead of using the standard canonical naming scheme for residue and atom names, ' + 'use the names from the given forcefield - currently amber, ' + 'charmm, parse, tyl06, peoepb and swanson are supported.') group.add_option('--usernames', dest='usernames', metavar='USER_NAME_FILE', help='The user created names file to use. Required if using --userff') group.add_option('--apbs-input', dest='input', action='store_true', default=False, help='Create a template APBS input file based on the generated PQR file. Also creates a Python ' + 'pickle for using these parameters in other programs.') group.add_option('--ligand', dest='ligand', metavar='PATH', help='Calculate the parameters for the ligand in mol2 format at the given path. ' + 'Pdb2pka must be compiled.') group.add_option('--whitespace', dest='whitespace', action='store_true', default=False, help='Insert whitespaces between atom name and residue name, between x and y, and between y and z.') group.add_option('--typemap', dest='typemap', action='store_true', default=False, help='Create Typemap output.') group.add_option('--neutraln', dest='neutraln', action='store_true', default=False, help='Make the N-terminus of this protein neutral (default is charged). ' 'Requires PARSE force field.') group.add_option('--neutralc', dest='neutralc', action='store_true', default=False, help='Make the C-terminus of this protein neutral (default is charged). ' 'Requires PARSE force field.') group.add_option('-v', '--verbose', dest='verbose', action='store_true', default=False, help='Print information to stdout.') group.add_option('--drop-water', dest='drop_water', action='store_true', default=False, help='Drop waters before processing protein. Currently recognized and deleted are the following water types: %s' % ', '.join(WAT.water_residue_names)) group.add_option('--include-header', dest='include_header', action='store_true', default=False, help='Include pdb header in pqr file. ' 'WARNING: The resulting PQR file will not work with APBS versions prior to 1.5') parser.add_option_group(group) pka_group = OptionGroup(parser,"pH options") pka_group.add_option('--ph-calc-method', dest='ph_calc_method', metavar='PH_METHOD', choices=('propka', 'propka31', 'pdb2pka'), help='Method used to calculate ph values. If a pH calculation method is selected, for each' ' titratable residue pH values will be calculated and the residue potentially modified' ' after comparison with the pH value supplied by --with_ph\n' 'propka - Use PROPKA to calculate pH values. Actual PROPKA results will be output to <output-path>.propka.\n' 'propka31 - Use PROPKA 3.1 to calculate pH values. Actual PROPKA results will be output to <output-path>.propka.\n' 'pdb2pka - Use PDB2PKA to calculate pH values. Requires the use of the PARSE force field.' ' Warning: Larger residues can take a very long time to run using this method. EXPERIMENTAL!') pka_group.add_option('--with-ph', dest='ph', action='store', type='float', default=7.0, help='pH values to use when applying the results of the selected pH calculation method.' ' Defaults to %default') parser.add_option_group(pka_group) pdb2pka_group = OptionGroup(parser,"PDB2PKA method options") pdb2pka_group.add_option('--pdb2pka-out', dest='pdb2pka_out', action='store', default='pdb2pka_output', help='Output directory for PDB2PKA results. Defaults to %default') pdb2pka_group.add_option('--pdb2pka-resume', dest='pdb2pka_resume', action="store_true", default=False, help='Resume run from state saved in output directory.') pdb2pka_group.add_option('--pdie', dest='pdb2pka_pdie', default=8,type='int', help='Protein dielectric constant. Defaults to %default') pdb2pka_group.add_option('--sdie', dest='pdb2pka_sdie', default=80, type='int', help='Solvent dielectric constant. Defaults to %default') # pdb2pka_group.add_option('--maps', dest='maps', default=None, type='int', # help='<1 for using provided 3D maps; 2 for genereting new maps>') # pdb2pka_group.add_option('--xdiel', dest='xdiel', default=None, type='str', # help='<xdiel maps>') # pdb2pka_group.add_option('--ydiel', dest='ydiel', default=None, type='str', # help='<ydiel maps>') # pdb2pka_group.add_option('--zdiel', dest='zdiel', default=None, type='str', # help='<zdiel maps>') # pdb2pka_group.add_option('--kappa', dest='kappa', default=None, type='str', # help='<ion-accessibility map>') # pdb2pka_group.add_option('--smooth', dest='sd', default=None, type='float', # help='<st.dev [A] of Gaussian smooting of 3D maps at the boundary, bandthwith=3 st.dev>') # # Cut off energy for calculating non-charged-charged interaction energies # pdb2pka_group.add_option('--pairene',dest='pdb2pka_pairene',type='float',default=1.0, help='Cutoff energy in kT for calculating non charged-charged interaction energies. Default: %default') parser.add_option_group(pdb2pka_group) propka_group = OptionGroup(parser,"PROPKA method options") propka_group.add_option("--propka-reference", dest="propka_reference", default="neutral", choices=('neutral','low-pH'), help="Setting which reference to use for stability calculations. See PROPKA 3.0 documentation.") propka_group.add_option('--propka-verbose', dest='propka_verbose', action='store_true', default=False, help='Print extra proPKA information to stdout. ' 'WARNING: This produces an incredible amount of output.') parser.add_option_group(propka_group) extensions.setupExtensionsOptions(parser) (options, args) = parser.parse_args(argv[1:]) commandLine = ' '.join(argv[1:]) if len(args) != 2: parser.error('Incorrect number (%d) of arguments!\nargs: %s' % (len(args), args)) if options.assign_only or options.clean: options.debump = options.optflag = False userfffile = None usernamesfile = None if not options.clean: if not options.usernames is None: try: usernamesfile = open(options.usernames, 'rU') except IOError: parser.error('Unable to open user names file %s' % options.usernames) if not options.userff is None: try: userfffile = open(options.userff, 'rU') except IOError: parser.error('Unable to open user force field file %s' % options.userff) if options.usernames is None: parser.error('--usernames must be specified if using --userff') else: if options.ff is None: parser.error('One of the manditory options was not specified.\n' + 'Please specify either --ff, --userff, or --clean') if getFFfile(options.ff) == '': parser.error('Unable to find parameter files for forcefield %s!' % options.ff) if options.ph < 0.0 or options.ph > 14.0: parser.error('%i is not a valid pH! Please choose a pH between 0.0 and 14.0.' % options.pH) ph_calc_options = None if options.ph_calc_method == 'propka': ph_calc_options = utilities.createPropkaOptions(options.ph, verbose=options.propka_verbose, reference=options.propka_reference) elif options.ph_calc_method == 'propka31': import propka.lib ph_calc_options, _ = propka.lib.loadOptions('--quiet') elif options.ph_calc_method == 'pdb2pka': if options.ff.lower() != 'parse': parser.error('PDB2PKA requires the PARSE force field.') ph_calc_options = {'output_dir': options.pdb2pka_out, 'clean_output': not options.pdb2pka_resume, 'pdie': options.pdb2pka_pdie, 'sdie': options.pdb2pka_sdie, 'pairene': options.pdb2pka_pairene} if options.ligand is not None: try: options.ligand = open(options.ligand, 'rU') except IOError: parser.error('Unable to find ligand file %s!' % options.ligand) if options.neutraln and (options.ff is None or options.ff.lower() != 'parse'): parser.error('--neutraln option only works with PARSE forcefield!') if options.neutralc and (options.ff is None or options.ff.lower() != 'parse'): parser.error('--neutralc option only works with PARSE forcefield!') text = """ -------------------------- PDB2PQR - a Python-based structural conversion utility -------------------------- Please cite your use of PDB2PQR as: Dolinsky TJ, Nielsen JE, McCammon JA, Baker NA. PDB2PQR: an automated pipeline for the setup, execution, and analysis of Poisson-Boltzmann electrostatics calculations. Nucleic Acids Research 32 W665-W667 (2004). """ sys.stdout.write(text) path = args[0] pdbFile = getPDBFile(path) pdblist, errlist = readPDB(pdbFile) if len(pdblist) == 0 and len(errlist) == 0: parser.error("Unable to find file %s!" % path) if len(errlist) != 0 and options.verbose: print("Warning: %s is a non-standard PDB file.\n" % path) print(errlist) outpath = args[1] options.outname = outpath #In case no extensions were specified or no extensions exist. if not hasattr(options, 'active_extensions' ) or options.active_extensions is None: options.active_extensions = [] #I see no point in hiding options from extensions. extensionOpts = options #TODO: The ideal would be to pass a file like object for the second # argument and add a third for names then # get rid of the userff and username arguments to this function. # This would also do away with the redundent checks and such in # the Forcefield constructor. try: header, lines, missedligands, _ = runPDB2PQR(pdblist, options.ff, outname = options.outname, ph = options.ph, verbose = options.verbose, selectedExtensions = options.active_extensions, ph_calc_method = options.ph_calc_method, ph_calc_options = ph_calc_options, extensionOptions = extensionOpts, clean = options.clean, neutraln = options.neutraln, neutralc = options.neutralc, ligand = options.ligand, assign_only = options.assign_only, chain = options.chain, drop_water = options.drop_water, debump = options.debump, opt = options.opt, typemap = options.typemap, userff = userfffile, usernames = usernamesfile, ffout = options.ffout, commandLine = commandLine, include_old_header = options.include_header) except PDB2PQRError as er: print(er) sys.exit(2) # Print the PQR file outfile = open(outpath,"w") outfile.write(header) # Adding whitespaces if --whitespace is in the options for line in lines: if options.whitespace: if line[0:4] == 'ATOM': newline = line[0:6] + ' ' + line[6:16] + ' ' + line[16:38] + ' ' + line[38:46] + ' ' + line[46:] outfile.write(newline) elif line[0:6] == 'HETATM': newline = line[0:6] + ' ' + line[6:16] + ' ' + line[16:38] + ' ' + line[38:46] + ' ' + line[46:] outfile.write(newline) else: outfile.write(line) outfile.close() if options.input: from src import inputgen from src import psize method = "mg-auto" size = psize.Psize() size.parseInput(outpath) size.runPsize(outpath) async = 0 # No async files here! input = inputgen.Input(outpath, size, method, async, potdx=True) input.printInputFiles() input.dumpPickle()