Exemplo n.º 1
0
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)
Exemplo n.º 2
0
 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']
Exemplo n.º 3
0
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()
Exemplo n.º 4
0
    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']
Exemplo n.º 5
0
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()
Exemplo n.º 6
0
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()