######################################################################## # # # This is a module that contains functions responsible for parsing the # # input file for MMPBSA.py. It must be included with MMPBSA.py to # # ensure proper functioning. # # # # Last updated: 05/17/2010 # # # ######################################################################## ########################## GPL LICENSE INFO ############################ # Copyright (C) 2009 Dwight McGee, Billy Miller III, and Jason Swails # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. def InputParse(filename, INPUT, warnings): import utils, sys # read all lines of the input file into memory try: file = open(filename,'r') except IOError: print >> sys.stderr, "Error: Input file '{0}' does not exist!".format(filename) return -1 lines = file.readlines() # load input file into memory file.close() # this lets us know if we are in any of the namelists (i.e. defined, but not terminated) ingbblock = 0 inpbblock = 0 inalablock = 0 ingenblock = 0 innmodeblock = 0 indecompblock = 0 # if we have defined a block -- +1 gb, +10 pb, +100 ala, +1000 nmode, +0 general, +10000 decomp blockdefined = 0 block='none' # name of the block for x in range(len(lines)): lines[x] = lines[x].strip() # first strip whitespace # skip forward until first block is defined if ingbblock == 0 and inpbblock == 0 and inalablock == 0 and ingenblock == 0 and innmodeblock == 0 \ and indecompblock == 0 and not (lines[x].startswith('&')): continue # skip over any comment or blank lines elif str(Check(lines[x])).startswith('#') or Check(lines[x]) == -1: continue if '/' in lines[x] or '&end' in lines[x]: # terminate all namelists. We are no longer in any namelist. ingbblock = 0 inpbblock = 0 inalablock = 0 ingenblock = 0 innmodeblock = 0 indecompblock = 0 block='none' continue elif lines[x].startswith('&'): # we are defining a namelist block = GetBlock(lines[x]) if block.startswith('gb'): # this is the GB namelist block='gb' ingbblock = 1 blockdefined += 1 continue # skip to the next line elif block.startswith('pb'): # this is the PB namelist block='pb' inpbblock = 1 blockdefined += 10 continue # skip to the next line elif block.startswith('ala'): # alanine scanning namelist block='ala' inalablock = 1 blockdefined += 100 continue # skip to next line elif block.startswith('gen'): block='general' ingenblock = 1 blockdefined += 0 continue # skip to next line elif block.startswith('nmo'): block='nmode' innmodeblock = 1 blockdefined = blockdefined + 1000 continue # skip to next line elif block.startswith('dec'): block='decomp' indecompblock = 1 blockdefined = blockdefined + 10000 continue # skip to next line else: # if it's none of the above, what is it? print >> sys.stderr, "Error: Unknown namelist, '&{0}'. Check input!".format(block.strip()) return -1 # return error code elif ingbblock == 1 or inpbblock == 1 or inalablock == 1 or ingenblock == 1 or innmodeblock == 1 or \ indecompblock == 1: # if we're in a block... entry = [] # this will be a 2-element array with [INPUT index, value] words = lines[x].split(',') # split along commas for y in words: # go through each word and strip whitespace and commas (that's what Check does) ychk = Check(y) # strip whitespace and ', " if ychk != -1: # if it's not blank... if '=' in ychk: # each field must have an = entry = InputEntry(ychk.split('='),block) # send InputEntry [variable, value] and namelist we're in if entry == -1: print >> sys.stderr, 'Warning: Input error! "{0}" is an invalid option.'.format(ychk) return -1 # fatal error else: INPUT[entry[0]] = entry[1] else: # if there's no =, we don't know what to do. Input error. (therefore, no variable can have commas in it! print >> sys.stderr, 'Warning: Input error! "{0}" is not recognized. Initialize variables with "="'.format(ychk) return -1 # Check to see if any blocks were defined twice if utils.digit(blockdefined,0) > 1: print >> sys.stderr, "Warning: You defined &gb more than once!" warnings.append("Warning: You defined &gb more than once!") blockdefined = blockdefined - (utils.digit(blockdefined,0) - 1) * 1 if utils.digit(blockdefined,1) > 1: print >> sys.stderr, "Warning: You defined &pb more than once!" warnings.append("Warning: You defined &pb more than once!") blockdefined = blockdefined - (utils.digit(blockdefined,1) - 1) * 10 if utils.digit(blockdefined,2) > 1: print >> sys.stderr, "Warning: You defined &alanine scanning more than once!" warnings.append("Warning: You defined &alanine scanning more than once!") blockdefined = blockdefined - (utils.digit(blockdefined,2) - 1) * 100 if utils.digit(blockdefined,3) > 1: print >> sys.stderr, "Warning: You defined &nmode more than once!" warnings.append("Warning: You defined &nmode more than once!") blockdefined = blockdefined - (utils.digit(blockdefined,2) - 1) * 1000 if utils.digit(blockdefined,4) > 1: print >> sys.stderr, "Warning: You defined &nmode more than once!" warnings.append("Warning: You defined &nmode more than once!") blockdefined = blockdefined - (utils.digit(blockdefined,2) - 1) * 10000 # Check to see if the namelists were not ended if ingenblock == 1 or ingbblock == 1 or inpbblock == 1 or inalablock == 1 or innmodeblock == 1 or indecompblock == 1: print >> sys.stderr, 'Warning: You did not end a namelist in your input file!' return -1 # fatal error # Check to see if any calculation input blocks were defined -- general # adds 0 to blockdefined. Alanine scanning also requires either GB or PB # to be specified, so give default to blockdefined = 100 also. if blockdefined == 0 or blockdefined == 100 or blockdefined == 10000: print >> sys.stderr, 'Warning: No calculation namelist flags specified! Assuming GB with default values.' warnings.append('Warning: No calculation namelist flags specified! Assuming GB with default values.') blockdefined += 1 return blockdefined def InputEntry(entry,block): # This will return the number of the input array that is being initial- # ized and the value # that was specified in the input file # get rid of white space and carriage returns in the input entries entry[0] = Check(entry[0]) entry[1] = Check(entry[1]) if block == 'general': if Compare(entry[0],"startframe",4): # 4 chars to match return [5,entry[1]] elif Compare(entry[0],"endframe",4): # 4 chars to match return [6,entry[1]] elif Compare(entry[0],"interval",4): # 4 chars to match return [7,entry[1]] elif Compare(entry[0],"verbose",4): # 4 chars to match return [29,entry[1]] elif Compare(entry[0],"strip_mdcrd",8): # 8 chars to match return [30,entry[1]] elif Compare(entry[0],"receptor_mask",4): # 4 chars to match return [35,entry[1]] elif Compare(entry[0],"ligand_mask",4): # 4 chars to match return [36,entry[1]] elif Compare(entry[0],"entropy",4): # 4 chars to match return [39,entry[1]] elif Compare(entry[0],"keep_files",4): # 4 chars to match return [51,entry[1]] elif Compare(entry[0],"strip_mask",8): # 8 chars to match return [52,entry[1]] else: return -1 if block == 'gb': if Compare(entry[0],"igb",3): # 3 chars to match return [9,entry[1]] elif Compare(entry[0],"gbsa",4): # 4 chars to match return [10,entry[1]] elif Compare(entry[0],"saltcon",4): # 4 chars to match return [11,entry[1]] elif Compare(entry[0],"surften",5): # 5 chars to match return [14,entry[1]] elif Compare(entry[0],"surfoff",5): # 5 chars to match return [15,entry[1]] else: return -1 elif block == 'pb': if Compare(entry[0],"indi",4): # 4 chars to match return [16,entry[1]] elif Compare(entry[0],"exdi",4): # 4 chars to match return [17,entry[1]] elif Compare(entry[0],"scale",4): # 4 chars to match return [18,entry[1]] elif Compare(entry[0],"linit",4): # 4 chars to match return [19,entry[1]] elif Compare(entry[0],"prbrad",4): # 4 chars to match return [20,entry[1]] elif Compare(entry[0],"istrng",4): # 4 chars to match return [21,entry[1]] elif Compare(entry[0],"inp",3): # 3 chars to match return [22,entry[1]] elif Compare(entry[0],"fillratio",4): # 4 chars to match return [25,entry[1]] elif Compare(entry[0],"radiopt",4): # 4 chars to match return [28,entry[1]] elif Compare(entry[0],"cavity_surften",8): # 8 chars to match return [23,entry[1]] elif Compare(entry[0],"cavity_offset",8): # 8 chars to match return [24,entry[1]] elif Compare(entry[0],"sander_apbs",4): # 4 chars to match return [37,entry[1]] else: return -1 elif block == 'ala': if Compare(entry[0],"mutant_only",4): # 4 chars to match return [38,entry[1]] else: return -1 elif block == 'nmode': if Compare(entry[0],"dielc",4): # 4 chars to match return [40,entry[1]] elif Compare(entry[0],"drms",4): # 4 chars to match return [41,entry[1]] elif Compare(entry[0],"maxcyc",4): # 4 chars to match return [42,entry[1]] elif Compare(entry[0],"nmstartframe",4): # 4 chars to match return [43,entry[1]] elif Compare(entry[0],"nmendframe",4): # 4 chars to match return [44,entry[1]] elif Compare(entry[0],"nminterval",4): # 4 chars to match return [45,entry[1]] elif Compare(entry[0],"ala_entropy",4): # 4 chars to match return [50,entry[1]] elif Compare(entry[0],"nmode_igb",8): # 8 chars to match return [58,entry[1]] elif Compare(entry[0],"nmode_istrng",8): # 8 chars to match return [59,entry[1]] else: return -1 elif block == 'decomp': if Compare(entry[0],"idecomp",4): # 4 chars to match return [54, entry[1]] elif Compare(entry[0],"print_res",4): # 4 chars to match return [55, entry[1]] elif Compare(entry[0],"dec_verbose",4): # 4 chars to match return [56, entry[1]] else: return -1 else: return -1 def GetBlock(line): return line.strip().strip('&') def Check(word): # Strips all whitespace (hard tabs, newlines, and spaces) from the both # ends of the word. It also strips quotes, but no whitespace past the # quotes (single and double are equivalent) firstchar = -1 for x in range(len(word)): if word[x] == ' ' or word[x] == '\t' or word[x] == '\n': continue elif firstchar == -1: firstchar = x if firstchar == -1: return -1 lastchar = len(word) - 1 while word[lastchar] == '\n' or word[lastchar] == ' ' or word[lastchar] == '\t' and lastchar > 0: lastchar = lastchar - 1 if word[firstchar] == '\'' or word[firstchar] == '"': firstchar = firstchar + 1 if word[lastchar] == '\'' or word[lastchar] == '"': lastchar = lastchar - 1 return word[firstchar:lastchar+1] def Compare(entry, input, tomatch): # makes sure that each entry has at least tomatch characters and they are all equal # if entry is bigger than input or entry doesn't have enough characters, return false if len(entry) > len(input) or len(entry) < tomatch: return False # otherwise compare the entry with the corresponding part of the input variable return input[:len(entry)] == entry