def pre_init(original_pdb_list=None, output_dir=None, ff=None, verbose=False, pdie=8.0, sdie=80, maps=None, xdiel=None, ydiel=None, zdiel=None, kappa=None, sd=None, ligand=None): """This function cleans the PDB and prepares the APBS input file Prepares the output folder.""" #prepare the output directory output_dir = os.path.abspath(output_dir) try: os.makedirs(output_dir) except OSError: if not os.path.isdir(output_dir): raise ValueError('Target directory is a file! Aborting.') workspace_dir = os.path.join(output_dir,'workspace') try: os.makedirs(workspace_dir) except OSError: if not os.path.isdir(output_dir): raise ValueError('Target directory is a file! Aborting.') # # remove hydrogen atoms # working_pdb_filename = os.path.join(workspace_dir,'working.pdb') pka_help.dump_protein_no_hydrogens(original_pdb_list, working_pdb_filename) # # Get the PDBfile # pdbfile = getPDBFile(working_pdb_filename) pdblist, errlist = readPDB(pdbfile) if verbose: print "Beginning PDB2PKA...\n" # # Read the definition file # myDefinition = Definition() ligand_titratable_groups=None # # # Choose whether to include the ligand or not # # Add the ligand to the pdb2pqr arrays # Lig=None if ligand is None: myProtein = Protein(pdblist, myDefinition) else: from pdb2pka.ligandclean import ligff myProtein, myDefinition, Lig = ligff.initialize(myDefinition, ligand, pdblist, verbose) # # ======================================================================= # # We have identified the structural elements, now contiue with the setup # # Print something for some reason? # if verbose: print "Created protein object -" print "\tNumber of residues in protein: %s" % myProtein.numResidues() print "\tNumber of atoms in protein : %s" % myProtein.numAtoms() # # Set up all other routines # myRoutines = Routines(myProtein, verbose) #myDefinition) myRoutines.updateResidueTypes() myRoutines.updateSSbridges() myRoutines.updateBonds() myRoutines.setTermini() myRoutines.updateInternalBonds() myRoutines.applyNameScheme(Forcefield(ff, myDefinition, None)) myRoutines.findMissingHeavy() myRoutines.addHydrogens() myRoutines.debumpProtein() #myRoutines.randomizeWaters() myProtein.reSerialize() # # Inject the information on hydrogen conformations in the HYDROGENS.DAT arrays # We get this information from ligand_titratable_groups # from src.hydrogens import hydrogenRoutines myRoutines.updateInternalBonds() myRoutines.calculateDihedralAngles() myhydRoutines = hydrogenRoutines(myRoutines) # # Here we should inject the info!! # myhydRoutines.setOptimizeableHydrogens() myhydRoutines.initializeFullOptimization() myhydRoutines.optimizeHydrogens() myhydRoutines.cleanup() myRoutines.setStates() # # Choose the correct forcefield # myForcefield = Forcefield(ff, myDefinition, None) if Lig: hitlist, misslist = myRoutines.applyForcefield(myForcefield) # # Can we get charges for the ligand? # templist=[] ligsuccess=False for residue in myProtein.getResidues(): if isinstance(residue, LIG): templist = [] Lig.make_up2date(residue) net_charge=0.0 print 'Ligand',residue print 'Atom\tCharge\tRadius' for atom in residue.getAtoms(): if atom.mol2charge: atom.ffcharge=atom.mol2charge else: atom.ffcharge = Lig.ligand_props[atom.name]["charge"] # # Find the net charge # net_charge=net_charge+atom.ffcharge # # Assign radius # atom.radius = Lig.ligand_props[atom.name]["radius"] print '%s\t%6.4f\t%6.4f' %(atom.name,atom.ffcharge,atom.radius) if atom in misslist: misslist.pop(misslist.index(atom)) templist.append(atom) # # Store the charge and radius in the atom instance for later use # This really should be done in a nicer way, but this will do for now # atom.secret_radius=atom.radius atom.secret_charge=atom.ffcharge # # charge = residue.getCharge() if abs(charge - round(charge)) > 0.01: # Ligand parameterization failed myProtein.residues.remove(residue) raise Exception('Non-integer charge on ligand: %8.5f' %charge) else: ligsuccess = 1 # Mark these atoms as hits hitlist = hitlist + templist # # Print the net charge # print 'Net charge for ligand %s is: %5.3f' %(residue.name,net_charge) # # Temporary fix; if ligand was successful, pull all ligands from misslist # Not sure if this is needed at all here ...? (Jens wrote this) # if ligsuccess: templist = misslist[:] for atom in templist: if isinstance(atom.residue, Amino) or isinstance(atom.residue, Nucleic): continue misslist.remove(atom) if verbose: print "Created protein object (after processing myRoutines) -" print "\tNumber of residues in protein: %s" % myProtein.numResidues() print "\tNumber of atoms in protein : %s" % myProtein.numAtoms() # # Create the APBS input file # import src.psize size=src.psize.Psize() method="" async=0 split=0 igen = inputgen_pKa.inputGen(working_pdb_filename) # # For convenience # igen.pdie = pdie print 'Setting protein dielectric constant to ',igen.pdie igen.sdie=sdie igen.maps=maps if maps==1: print "Using dielectric and mobile ion-accessibility function maps in PBE" if xdiel: igen.xdiel = xdiel else: raise PDB2PKAError('X dielectric map is missing') if ydiel: igen.ydiel = ydiel else: raise PDB2PKAError("Y dielectric map is missing\n") if zdiel: igen.zdiel = zdiel else: raise PDB2PKAError("Z dielectric map is missing\n") print 'Setting dielectric function maps: %s, %s, %s'%(igen.xdiel,igen.ydiel,igen.zdiel) if kappa: igen.kappa = kappa else: raise PDB2PKAError("Mobile ion-accessibility map is missing\n") print 'Setting mobile ion-accessibility function map to: ',igen.kappa if sd: xdiel_smooth, ydiel_smooth, zdiel_smooth = smooth(xdiel,ydiel,zdiel) igen.xdiel = xdiel_smooth igen.ydiel = ydiel_smooth igen.zdiel = zdiel_smooth # # Return all we need # return output_dir, myProtein, myRoutines, myForcefield,igen, ligand_titratable_groups, maps, sd
def pre_init(original_pdb_list=None, output_dir=None, ff=None, verbose=False, pdie=8.0, sdie=80, maps=None, xdiel=None, ydiel=None, zdiel=None, kappa=None, sd=None, ligand=None): """This function cleans the PDB and prepares the APBS input file Prepares the output folder.""" #prepare the output directory output_dir = os.path.abspath(output_dir) try: os.makedirs(output_dir) except OSError: if not os.path.isdir(output_dir): raise ValueError('Target directory is a file! Aborting.') workspace_dir = os.path.join(output_dir, 'workspace') try: os.makedirs(workspace_dir) except OSError: if not os.path.isdir(output_dir): raise ValueError('Target directory is a file! Aborting.') # # remove hydrogen atoms # working_pdb_filename = os.path.join(workspace_dir, 'working.pdb') pka_help.dump_protein_no_hydrogens(original_pdb_list, working_pdb_filename) # # Get the PDBfile # pdbfile = getPDBFile(working_pdb_filename) pdblist, errlist = readPDB(pdbfile) if verbose: print "Beginning PDB2PKA...\n" # # Read the definition file # myDefinition = Definition() ligand_titratable_groups = None # # # Choose whether to include the ligand or not # # Add the ligand to the pdb2pqr arrays # Lig = None if ligand is None: myProtein = Protein(pdblist, myDefinition) else: from pdb2pka.ligandclean import ligff myProtein, myDefinition, Lig = ligff.initialize( myDefinition, ligand, pdblist, verbose) # # ======================================================================= # # We have identified the structural elements, now contiue with the setup # # Print something for some reason? # if verbose: print "Created protein object -" print "\tNumber of residues in protein: %s" % myProtein.numResidues() print "\tNumber of atoms in protein : %s" % myProtein.numAtoms() # # Set up all other routines # myRoutines = Routines(myProtein, verbose) #myDefinition) myRoutines.updateResidueTypes() myRoutines.updateSSbridges() myRoutines.updateBonds() myRoutines.setTermini() myRoutines.updateInternalBonds() myRoutines.applyNameScheme(Forcefield(ff, myDefinition, None)) myRoutines.findMissingHeavy() myRoutines.addHydrogens() myRoutines.debumpProtein() #myRoutines.randomizeWaters() myProtein.reSerialize() # # Inject the information on hydrogen conformations in the HYDROGENS.DAT arrays # We get this information from ligand_titratable_groups # from src.hydrogens import hydrogenRoutines myRoutines.updateInternalBonds() myRoutines.calculateDihedralAngles() myhydRoutines = hydrogenRoutines(myRoutines) # # Here we should inject the info!! # myhydRoutines.setOptimizeableHydrogens() myhydRoutines.initializeFullOptimization() myhydRoutines.optimizeHydrogens() myhydRoutines.cleanup() myRoutines.setStates() # # Choose the correct forcefield # myForcefield = Forcefield(ff, myDefinition, None) if Lig: hitlist, misslist = myRoutines.applyForcefield(myForcefield) # # Can we get charges for the ligand? # templist = [] ligsuccess = False for residue in myProtein.getResidues(): if isinstance(residue, LIG): templist = [] Lig.make_up2date(residue) net_charge = 0.0 print 'Ligand', residue print 'Atom\tCharge\tRadius' for atom in residue.getAtoms(): if atom.mol2charge: atom.ffcharge = atom.mol2charge else: atom.ffcharge = Lig.ligand_props[atom.name]["charge"] # # Find the net charge # net_charge = net_charge + atom.ffcharge # # Assign radius # atom.radius = Lig.ligand_props[atom.name]["radius"] print '%s\t%6.4f\t%6.4f' % (atom.name, atom.ffcharge, atom.radius) if atom in misslist: misslist.pop(misslist.index(atom)) templist.append(atom) # # Store the charge and radius in the atom instance for later use # This really should be done in a nicer way, but this will do for now # atom.secret_radius = atom.radius atom.secret_charge = atom.ffcharge # # charge = residue.getCharge() if abs(charge - round(charge)) > 0.01: # Ligand parameterization failed myProtein.residues.remove(residue) raise Exception('Non-integer charge on ligand: %8.5f' % charge) else: ligsuccess = 1 # Mark these atoms as hits hitlist = hitlist + templist # # Print the net charge # print 'Net charge for ligand %s is: %5.3f' % (residue.name, net_charge) # # Temporary fix; if ligand was successful, pull all ligands from misslist # Not sure if this is needed at all here ...? (Jens wrote this) # if ligsuccess: templist = misslist[:] for atom in templist: if isinstance(atom.residue, Amino) or isinstance( atom.residue, Nucleic): continue misslist.remove(atom) if verbose: print "Created protein object (after processing myRoutines) -" print "\tNumber of residues in protein: %s" % myProtein.numResidues() print "\tNumber of atoms in protein : %s" % myProtein.numAtoms() # # Create the APBS input file # import src.psize size = src.psize.Psize() method = "" split = 0 igen = inputgen_pKa.inputGen(working_pdb_filename) # # For convenience # igen.pdie = pdie print 'Setting protein dielectric constant to ', igen.pdie igen.sdie = sdie igen.maps = maps if maps == 1: print "Using dielectric and mobile ion-accessibility function maps in PBE" if xdiel: igen.xdiel = xdiel else: raise PDB2PKAError('X dielectric map is missing') if ydiel: igen.ydiel = ydiel else: raise PDB2PKAError("Y dielectric map is missing\n") if zdiel: igen.zdiel = zdiel else: raise PDB2PKAError("Z dielectric map is missing\n") print 'Setting dielectric function maps: %s, %s, %s' % ( igen.xdiel, igen.ydiel, igen.zdiel) if kappa: igen.kappa = kappa else: raise PDB2PKAError("Mobile ion-accessibility map is missing\n") print 'Setting mobile ion-accessibility function map to: ', igen.kappa if sd: xdiel_smooth, ydiel_smooth, zdiel_smooth = smooth( xdiel, ydiel, zdiel) igen.xdiel = xdiel_smooth igen.ydiel = ydiel_smooth igen.zdiel = zdiel_smooth # # Return all we need # return output_dir, myProtein, myRoutines, myForcefield, igen, ligand_titratable_groups, maps, sd
def handleNonOpal(weboptions): """ Handle non opal run. """ pdblist, errlist = readPDB(weboptions.pdbfile) dummydef = Definition() dummyprot = Protein(pdblist, dummydef) if len(pdblist) == 0 and len(errlist) == 0: text = "Unable to find PDB file - Please make sure this is " text += "a valid PDB file ID!" #print "Content-type: text/html\n" print(text) sys.exit(2) elif dummyprot.numAtoms() > MAXATOMS and weboptions["opt"] == True: text = "<HTML><HEAD>" text += "<TITLE>PDB2PQR Error</title>" text += "<link rel=\"stylesheet\" href=\"%s\" type=\"text/css\">" % STYLESHEET text += "</HEAD><BODY><H2>PDB2PQR Error</H2><P>" text += "Due to server limits, we are currently unable to optimize " text += "proteins of greater than %i atoms on the server (PDB2PQR " % MAXATOMS text += "found %s atoms in the selected PDB file). If you " % dummyprot.numAtoms() text += "want to forgo optimization please try the server again.<P>" text += "Otherwise you may use the standalone version of PDB2PQR that " text += "is available from the <a href=\"http://pdb2pqr.sourceforge.net\">" text += "PDB2PQR SourceForge project page</a>." text += "<script type=\"text/javascript\">" text += "var gaJsHost = ((\"https:\" == document.location.protocol) ? \"https://ssl.\" : \"http://www.\");" text += "document.write(unescape(\"%3Cscript src=\'\" + gaJsHost + \"google-analytics.com/ga.js\' type=\'text/javascript\'%3E%3C/script%3E\"));" text += "</script>" text += "<script type=\"text/javascript\">" text += "try {" text += "var pageTracker = _gat._getTracker(\"UA-11026338-3\");" for key in weboptions: text += "pageTracker._trackPageview(\"/main_cgi/has_%s_%s.html\");" % (key, weboptions[key]) text += "pageTracker._trackPageview();" text += "} catch(err) {}</script>" text += "</BODY></HTML>" #print "Content-type: text/html\n" print(text) sys.exit(2) try: starttime = time.time() name = setID(starttime) #Some job parameters logging. os.makedirs('%s%s%s' % (INSTALLDIR, TMPDIR, name)) apbsInputFile = open('%s%s%s/apbs_input' % (INSTALLDIR, TMPDIR, name),'w') apbsInputFile.write(str(weboptions["apbs"])) apbsInputFile.close() typemapInputFile = open('%s%s%s/typemap' % (INSTALLDIR, TMPDIR, name),'w') typemapInputFile.write(str(weboptions["typemap"])) typemapInputFile.close() statusfile = open('%s%s%s/pdb2pqr_status' % (INSTALLDIR, TMPDIR, name), 'w') statusfile.write('running') statusfile.close() # Recording CGI run information for PDB2PQR Opal pdb2pqrLogFile = open('%s%s%s/pdb2pqr_log' % (INSTALLDIR, TMPDIR, name), 'w') pdb2pqrLogFile.write(str(weboptions.getOptions())+'\n'+ str(weboptions.ff)+'\n'+ str(os.environ["REMOTE_ADDR"])) pdb2pqrLogFile.close() pid = os.fork() if pid: print(redirector(name, weboptions)) sys.exit() else: currentdir = os.getcwd() os.chdir("/") os.setsid() os.umask(0) os.chdir(currentdir) os.close(1) # not sure if these os.close(2) # two lines are necessary pqrpath = '%s%s%s/%s.pqr' % (INSTALLDIR, TMPDIR, name, name) orig_stdout = sys.stdout orig_stderr = sys.stderr sys.stdout = open('%s%s%s/pdb2pqr_stdout.txt' % (INSTALLDIR, TMPDIR, name), 'w') sys.stderr = open('%s%s%s/pdb2pqr_stderr.txt' % (INSTALLDIR, TMPDIR, name), 'w') run_arguements = weboptions.getRunArguments() if weboptions.runoptions.get('ph_calc_method', '') == 'pdb2pka': run_arguements['ph_calc_options']['output_dir']='%s%s%s/pdb2pka_output' % (INSTALLDIR, TMPDIR, name) header, lines, missedligands, _ = runPDB2PQR(pdblist, weboptions.ff, outname = pqrpath, commandLine = weboptions.getCommandLine(), **weboptions.getRunArguments()) sys.stdout.close() sys.stderr.close() sys.stdout = orig_stdout sys.stderr = orig_stderr endtimefile = open('%s%s%s/pdb2pqr_end_time' % (INSTALLDIR, TMPDIR, name), 'w') endtimefile.write(str(time.time())) endtimefile.close() pqrfile = open(pqrpath, "w") pqrfile.write(header) whitespace = weboptions.otheroptions['whitespace'] for line in lines: # Adding whitespaces if --whitespace is in the weboptions if whitespace: if line[0:4] == 'ATOM': newline = line[0:6] + ' ' + line[6:16] + ' ' + line[16:38] + ' ' + line[38:46] + ' ' + line[46:] pqrfile.write("%s\n" % newline.strip()) elif line[0:6] == 'HETATM': newline = line[0:6] + ' ' + line[6:16] + ' ' + line[16:38] + ' ' + line[38:46] + ' ' + line[46:] pqrfile.write("%s\n" % newline.strip()) else: pqrfile.write("%s\n" % line.strip()) pqrfile.close() if weboptions.otheroptions['apbs']: from src import inputgen from src import psize method = "mg-auto" size = psize.Psize() size.parseInput(pqrpath) size.runPsize(pqrpath) async = 0 # No async files here! myinput = inputgen.Input(pqrpath, size, method, async, potdx=True) myinput.printInputFiles() myinput.dumpPickle() endtime = time.time() - starttime #createResults(header, input, name, endtime, missedligands) #logRun(weboptions, endtime, len(lines), weboptions.ff, os.environ["REMOTE_ADDR"]) #printHeader("PDB2PQR Job Submission",have_opal,jobid=name) if 'ligand' in weboptions: outputligandfile = open('%s%s%s/%s.mol2' % (INSTALLDIR,TMPDIR, name, name),'w') outputligandfile.write(weboptions.ligandfilestring) outputligandfile.close() outputpdbfile = open('%s%s%s/%s.pdb' % (INSTALLDIR,TMPDIR,name,name),'w') outputpdbfile.write(weboptions.pdbfilestring) outputpdbfile.close() statusfile = open('%s%s%s/pdb2pqr_status' % (INSTALLDIR, TMPDIR, name), 'w') statusfile.write('complete\n') filelist = glob.glob('%s%s%s/%s*' % (INSTALLDIR, TMPDIR, name, name)) for filename in filelist: statusfile.write(filename+'\n') statusfile.close() #TODO: Better error reporting. #Also, get forked job to properly write error status on failure. except Exception as details: #except StandardError as details: print(traceback.format_exc()) print(sys.exc_info()[0]) #print details createError(name, details)
def handleNonOpal(weboptions): """ Handle non opal run. """ pdblist, errlist = readPDB(weboptions.pdbfile) dummydef = Definition() dummyprot = Protein(pdblist, dummydef) if len(pdblist) == 0 and len(errlist) == 0: text = "Unable to find PDB file - Please make sure this is " text += "a valid PDB file ID!" #print "Content-type: text/html\n" print text sys.exit(2) elif dummyprot.numAtoms() > MAXATOMS and weboptions["opt"] == True: text = "<HTML><HEAD>" text += "<TITLE>PDB2PQR Error</title>" text += "<link rel=\"stylesheet\" href=\"%s\" type=\"text/css\">" % STYLESHEET text += "</HEAD><BODY><H2>PDB2PQR Error</H2><P>" text += "Due to server limits, we are currently unable to optimize " text += "proteins of greater than MAXATOMS atoms on the server (PDB2PQR " text += "found %s atoms in the selected PDB file). If you " % dummyprot.numAtoms( ) text += "want to forgo optimization please try the server again.<P>" text += "Otherwise you may use the standalone version of PDB2PQR that " text += "is available from the <a href=\"http://pdb2pqr.sourceforge.net\">" text += "PDB2PQR SourceForge project page</a>." text += "<script type=\"text/javascript\">" text += "var gaJsHost = ((\"https:\" == document.location.protocol) ? \"https://ssl.\" : \"http://www.\");" text += "document.write(unescape(\"%3Cscript src=\'\" + gaJsHost + \"google-analytics.com/ga.js\' type=\'text/javascript\'%3E%3C/script%3E\"));" text += "</script>" text += "<script type=\"text/javascript\">" text += "try {" text += "var pageTracker = _gat._getTracker(\"UA-11026338-3\");" for key in weboptions: text += "pageTracker._trackPageview(\"/main_cgi/has_%s_%s.html\");" % ( key, weboptions[key]) text += "pageTracker._trackPageview();" text += "} catch(err) {}</script>" text += "</BODY></HTML>" #print "Content-type: text/html\n" print text sys.exit(2) try: starttime = time.time() name = setID(starttime) #Some job parameters logging. os.makedirs('%s%s%s' % (INSTALLDIR, TMPDIR, name)) apbsInputFile = open('%s%s%s/apbs_input' % (INSTALLDIR, TMPDIR, name), 'w') apbsInputFile.write(str(weboptions["apbs"])) apbsInputFile.close() typemapInputFile = open('%s%s%s/typemap' % (INSTALLDIR, TMPDIR, name), 'w') typemapInputFile.write(str(weboptions["typemap"])) typemapInputFile.close() statusfile = open('%s%s%s/pdb2pqr_status' % (INSTALLDIR, TMPDIR, name), 'w') statusfile.write('running') statusfile.close() # Recording CGI run information for PDB2PQR Opal pdb2pqrLogFile = open( '%s%s%s/pdb2pqr_log' % (INSTALLDIR, TMPDIR, name), 'w') pdb2pqrLogFile.write( str(weboptions.getOptions()) + '\n' + str(weboptions.ff) + '\n' + str(os.environ["REMOTE_ADDR"])) pdb2pqrLogFile.close() pid = os.fork() if pid: print redirector(name, weboptions) sys.exit() else: currentdir = os.getcwd() os.chdir("/") os.setsid() os.umask(0) os.chdir(currentdir) os.close(1) # not sure if these os.close(2) # two lines are necessary pqrpath = '%s%s%s/%s.pqr' % (INSTALLDIR, TMPDIR, name, name) orig_stdout = sys.stdout orig_stderr = sys.stderr sys.stdout = open( '%s%s%s/pdb2pqr_stdout.txt' % (INSTALLDIR, TMPDIR, name), 'w') sys.stderr = open( '%s%s%s/pdb2pqr_stderr.txt' % (INSTALLDIR, TMPDIR, name), 'w') header, lines, missedligands = runPDB2PQR( pdblist, weboptions.ff, outname=pqrpath, commandLine=weboptions.getCommandLine(), **weboptions.getRunArguments()) sys.stdout.close() sys.stderr.close() sys.stdout = orig_stdout sys.stderr = orig_stderr endtimefile = open( '%s%s%s/pdb2pqr_end_time' % (INSTALLDIR, TMPDIR, name), 'w') endtimefile.write(str(time.time())) endtimefile.close() pqrfile = open(pqrpath, "w") pqrfile.write(header) whitespace = weboptions.otheroptions['whitespace'] for line in lines: # Adding whitespaces if --whitespace is in the weboptions if whitespace: if line[0:4] == 'ATOM': newline = line[0:16] + ' ' + line[16:38] + ' ' + line[ 38:46] + ' ' + line[46:] pqrfile.write("%s\n" % string.strip(newline)) elif line[0:6] == 'HETATM': newline = line[0:16] + ' ' + line[16:38] + ' ' + line[ 38:46] + ' ' + line[46:] pqrfile.write("%s\n" % string.strip(newline)) else: pqrfile.write("%s\n" % string.strip(line)) pqrfile.close() if weboptions.otheroptions['apbs']: from src import inputgen from src import psize method = "mg-auto" size = psize.Psize() size.parseInput(pqrpath) size.runPsize(pqrpath) async = 0 # No async files here! myinput = inputgen.Input(pqrpath, size, method, async, potdx=True) myinput.printInputFiles() myinput.dumpPickle() endtime = time.time() - starttime #createResults(header, input, name, endtime, missedligands) #logRun(weboptions, endtime, len(lines), weboptions.ff, os.environ["REMOTE_ADDR"]) #printHeader("PDB2PQR Job Submission",have_opal,jobid=name) if 'ligand' in weboptions: outputligandfile = open( '%s%s%s/%s.mol2' % (INSTALLDIR, TMPDIR, name, name), 'w') outputligandfile.write(weboptions.ligandfilestring) outputligandfile.close() outputpdbfile = open( '%s%s%s/%s.pdb' % (INSTALLDIR, TMPDIR, name, name), 'w') outputpdbfile.write(weboptions.pdbfilestring) outputpdbfile.close() statusfile = open( '%s%s%s/pdb2pqr_status' % (INSTALLDIR, TMPDIR, name), 'w') statusfile.write('complete\n') filelist = glob.glob('%s%s%s/%s*' % (INSTALLDIR, TMPDIR, name, name)) for filename in filelist: statusfile.write(filename + '\n') statusfile.close() #TODO: Better error reporting. #Also, get forked job to properly write error status on failure. except StandardError as details: print details createError(name, details)