<commit_before># MdpFile.py
#
# HISTORY
# VAV: 9/09/07    Added self.delParameter(), allowing keywords and their valuestrs to be removed from the mdp file
# VAV: 9/02/07    Added self.use_table() and TableMaker object 
# VAV: 8/27/07    File created
#
# TO DO:
# * Have default *.mdp template in case __init__() template file is not provided.

import sys, os, tempfile, string
from TableMaker import *


class MdpFile(object):
    
  def __init__(self, templatefile, debug=False): 
    """A class to store and modify Gromacs mdp files.
    
    INPUT    
        templatefile        an *.mdp file to read in as a template
    
    OUTPUT
        None
    """

    self.debug = debug 
    # process infile name
    self.templatefile = templatefile
    
    # read infile contents and store as lines
    self.lines = []
    self.params = {}    # {keyword:value} dictionary.  NOTE: All values are stored as strings: i.e. {'rlist':'4.0'}
    self.keywords = []  # keep a list of the keyword order, just so we can write oiut *.mdp files in the same order as the template 
    [self.lines, self.params, self.keywords] = self.read(templatefile)

    # settings for user-defined tables    
    self.use_xvg = False
    self.tablemaker = None
    self.tabletype = None
    self.tabletxt = None


  def use_table(self, tabletype, spacing=0.002):   
    """Turn on the xvg table option, and generate a user-defined table 
    defined in self.xvg_lines, generated by the TableMaker object, with the specifications:showParams

    OPTIONS 
        tabletype =  a TableMaker.Dielectric derived class:
                     'Switch_Shift'	(default) GROMACS-style tapered cutoffs
                     'SF3'		ShenFreed 3 table
                     'ReactionField'    rxn field dielectric solvent model

    TableMaker examples:
    # table=TableMaker(spacing=0.002)

    # tabletype=SF3(length_scale=4.0)
    # tabletype=Switch_Shift()
    # tabletype=ReactionField(rc=1.0)

    # settings for eps->Infinity
    # tabletype.krf = 1.0 / ( 2.0 * tabletype.rc )
    # tabletype.crf = 3.0 / ( 2.0 * tabletype.rc ) 

    # table=table.make(tabletype)

    # print table
    """

    self.use_xvg = True
    self.tabletype = tabletype
    self.tablemaker = TableMaker(spacing=spacing)
    self.tabletxt = self.tablemaker.make(self.tabletype)
    
    # set the user-table flags in the the mdp file 
    self.setParameter('coulombtype','user')
    self.setParameter('vdwtype','user')

    # NOTE: the acual 'table.xvg' file will be written by System.prepare()
    
  def read(self, filename):
    """Reads the lines of the template *.mdp"""
    fin = open(filename, 'r')
    lines = fin.readlines()
    fin.close()
    # build an initial dictionary of key:values from the lines
    [params, keywords] = self.buildParameterDict(lines)    
    return [lines, params, keywords]
  
  def write(self, filename):
    """Writes the lines of the template *.mdp"""
    fout = open(filename, 'w')
    for line in self.lines:
      fout.write(line)
    fout.close()
  
  def write_table(self, filename):
    """Writes the lines of self.tabletxt to user-supplied filename in correct directory -- should be 'table.xvg'"""
    fout = open(filename, 'w')
    fout.write(self.tabletxt)
    fout.close()
  

  def buildParameterDict(self, lines):
    """Goes through each line of the file,and parses keywords into a key:value dictionary"""
    params = {}
    keywords = []
    for line in lines:
        fields = line.strip().split()
        if len(fields) >= 3:
          if fields[0][0] != ';':
            params[fields[0]] = fields[2]
            keywords.append(fields[0])                        
    return [params, keywords]

              
  def showParams(self):
    """Prints out a the self.params dictionary."""
    outstr = ''
    for key in self.keywords:
        outstr = outstr + self.keyword2line(key)
    print outstr
    
  def keyword2line(self, keyword):
    """Takes in a parameter keyword and returns a formatted mdp file line.""" 
    return '%-20s = %-20s\n'%(keyword, self.params[keyword])

    
  def setParameter(self, keyword, valuestr):
    """Sets a particular mdp keyword to a value (string) in the parameter dictionary, updates mdp lines."""
    
    # if keyword not already in our ordered list of keywords, append it    
    if self.keywords.count(keyword) == 0:
      self.keywords.append(keyword)
    
    # set keyword in dictionary
    self.params[keyword] = valuestr

    # replace instances of this 'keyword = value' in the mdp lines
    foundone = False
    for i in range(0,len(self.lines)):
        fields = self.lines[i].strip().split()
        if len(fields) > 0:
            if fields[0] == keyword:
                self.lines[i] = self.keyword2line(keyword)
                foundone = True
    # if can't find keyword in previous lines, add it to the lines
    if foundone == False:
        self.lines.append( self.keyword2line(keyword))
        
        
  def setParametersFromDict(self, paramdict):
    """Takes in a set of parameters as a dictionary of {keyword:value} entries (values are strings) and
    sets parameters for each."""
    
    for [key,value] in paramdict.iteritems():
      if self.debug:  print 'DEBUG: key, value of paramdict{}', key, value
      self.setParameter(key, value)
      
  def delParameter(self, keyword):
    """Removes a particular mdp keyword (and its value (string)) from the parameter dictionary, and deletes mdp line."""
  
    # remove keyword from dictionary
    if self.params.has_key(keyword):
        del self.params[keyword]

    # replace instances of this 'keyword = value' in the mdp lines
    i=0
    while i < len(self.lines):
        fields = self.lines[i].strip().split()
        if len(fields) > 0:
            if fields[0] == keyword:
                self.lines.pop(i)
            else:
                i=i+1
        else:
            i=i+1
    
#####################

class ImplicitOptions(object):
  """A data structure object to pass to MdpFile() so params can be set"""

  def __init__(self):
    """Initializes the ImplicitOptions() object.  This provides the parent class for a set of 
    objects all with differnt defaults.  The main default here is:
    
    VVSD
    Still GB
    

    Here is the README_ED, as of August 2007:
    
; Complete description of parameters (from 17 Jan 2007 README_ED from gromacs-3.1.4-ed)
; NOTE not all are enabled on PS3.  Those that are enabled on the PS3 are marked with [PS3]
;
; userint4 - BIT 0 - AGBNP on/off
; userint4 - BIT 1 - GB on/off [PS3]
; userint4 - BIT 2 - SASD for GB on/off
; userint4 - BIT 3 - Andersen on/off
; userint4 - BIT 4 - SASD for AGBNP on/off [PS3]
; userint4 - BIT 5 - Sheffield on/off
; userint4 - BIT 6 - use the velocity Verlet version of the SD algorithm (vvSD) [PS3]
- userint4 - BIT 7 - scale charges via sdelta  => gradually tuning off electrostatics (AGBNP & EdGB)
- userint4 - BIT 8 - turn on/off the GCMC part
; userint4 - BIT 9 - Still SA part on/off [PS3]
; userint4 - BIT 10 - turns on Still GB [PS3]
;
; userint1 - GB frequency (used for GB and AGBNP) [PS3]
; userint2 - BIT 0 - unused
; userint2 - BIT 1 - GB logging on/off
; userint2 - BIT 2 - AGBNP logging on/off
; usetint2 - BIT 3 - do NOT apply the solvation forces, this is helpful for comparisons
; userint3 - Andersen frequency [steps]
; userreal1 - inner/vacuum dielectric [PS3]
; userreal2 - outer/solvent dielectric [PS3]
; userreal3 - Sheffield: A parameter 
;           - Andersen:  target temperature
;           - vvSD: target temperature [PS3]
; userreal4 - Sheffield B parameter 
;           - friction [1/ps] thus 91 would represent water at room temperature [PS3]

userint1    = 1    ; update frequency for GB forces (should be set equal to nstlist)
userreal1   = 1.   ; interior dielectric constant
userreal2   = 80.  ; exterior dielectric constant
userint4    = 1600  ; Still GB on (2^10 = 1024), ACE SA term in the GB/SA (2^9 = 512), VVSD (2^6 = 64)
userint2    = 0    ; no logging, apply solvation forces
userreal3   = 300. ; temperature for VVSD integrator (in K)
userreal4   = 91.0 ; viscosity for VVSD integrator (in 1/ps)
"""

    # implicit solvation models     
    self.use_StillGB = True           # ; userint4 - BIT 10 - turns on Still GB [PS3]
    self.use_GB = False               # ; userint4 - BIT 1 - GB on/off [PS3]
    self.use_AGBNP = False            # ; userint4 - BIT 0 - AGBNP on/off
    self.use_Sheffield = False        # ; userint4 - BIT 5 - Sheffield on/off
    
    # solvent model options
    self.use_SASD = False    # SASD is velocity scaling based on solventg accessibility. Setting this option will modify GB, AGBNP
                                      # ; userint4 - BIT 2 - SASD for GB on/off [PS3]
                                      # ; userint4 - BIT 4 - SASD for AGBNP on/off 
    self.use_ACE_SA = True            # ; userint4 - BIT 9 - Still SA part f GB/SA on/off [PS3]
        
    # integration
    self.use_VVSD = True              # ; userint4 - BIT 6 - use the velocity Verlet version of the SD algorithm (vvSD) [PS3]
    self.use_Andersen = False         # ; userint4 - BIT 3 - Andersen on/off
    
    # Additional Parameters 
    self.GB_frequency = 1             # ; userint1 - GB frequency (used for GB and AGBNP) [PS3]  (should be set equal to nstlist)
    self.scaleCharges = False         # ; userint4 - BIT 7 - scale charges via sdelta  => gradually tuning off electrostatics (AGBNP & EdGB)
    self.use_GCMC = False             # ; userint4 - BIT 8 - turn on/off the GCMC part (Grand Canonical)  [not ready yet!]
    
    ### userint2
    self.GB_logging = False           # ; userint2 - BIT 1 - GB logging on/off
    self.AGBNP_logging = False        # ; userint2 - BIT 2 - AGBNP logging on/off
    self.DontApplySolvationForces = False  # ; usetint2 - BIT 3 - do NOT apply the solvation forces, this is helpful for comparisons
    
    ### userint3
    self.Andersen_frequency = 1       # ; userint2 - BIT 1 - GB logging on/off

    
    # Continuous parameters
    self.innerDielectric = 1.0
    self.outerDielectric = 80.0
    self.Sheffield_A = 1.0            # ; userreal3 - Sheffield A parameter 
    self.Sheffield_B = 1.0            # ; userreal4 - Sheffield B parameter 
    self.targetTemperature = 300.     # ; userreal3 - Andersen:  target temperature
                                      # ;           - vvSD: target temperature [PS3]
    self.viscosity = 91.              # ; userreal4 - friction [1/ps] thus 91 would represent water at room temperature [PS3]


    # user1_groups    
    self.q = {}          # ; A dictionary of key:value (strings) that can be given to MdpFile.setParameter()
   

    ### groups for visualization
    self.user1_grps = None            # show-lines, show-spacefill, show-sticks, ca-trace, or show-balls
    self.user1_residues = None        # This will be used by make_PS3_ndx()
    self.user2_grps = None
    self.user2_residues = None
    ### NOTE: asdfghjk
    # JDC sez:  To include more groups is difficult, as this requires overriding the default behavior of grompp
    # to prevent unnecessary groups from being included in the .tpr file. A modified grompp for the 3.1.4 EdGB
    # version of gromacs is available that allows specification of up to five groups, though this overrides the
    # ACC, FREEZE, and ORFIT capabilities (which we don't use anyway). The modified grompp requires recompilation
    # with this modified kernel/readir.c file.
    #
    # self.user1_grps = show-lines
    # self.user2_grps = show-spacefill
    # self.user3_grps = show-sticks ; requires modified grompp
    # self.user4_grps = ca-trace ; requires modified grompp
    # self.user5_grps = show-balls ; requires modified grompp

    ### Do the setup
    self.setup()                                      # derived classes can change the parms, if desired
    self.buildMdpParams()       # compiles a list of params to set in the mdpfile
    
    
  def setup(self):
    """This is the customizable parrt of derived classes, used to set parameters for a particular type of implicit solvation """
    pass
  

  def buildMdpParams(self, PS3_Visualization=False):
    """compiles a list of params to set in the mdpfile.
    Returns a dictionary of key:value (strings) that can be given to MdpFile.setParameter()"""
    
    params = {}

    # userint 1, 2 and 3
    params['userint1'] = '%d'%self.GB_frequency
    params['userint2'] = '%d'%( self.GB_logging*2 + self.AGBNP_logging*4 + self.DontApplySolvationForces*8  )
    if self.use_Andersen:
      params['userint3'] = '%d'%self.Andersen_frequency
    
    # userint4
    userint4 = 0
    if self.use_StillGB:
        userint4 += (2**10)
        if self.use_ACE_SA:
            userint4 += (2**9)
    elif self.use_GB:
        userint4 += (2**1) 
        if self.use_SASD:
            userint4 += (2**2)
    elif self.use_AGBNP: 
        userint4 += 1
        if self.use_SASD:
            userint4 += (2**4) 
    elif self.use_Sheffield:   
        userint4 += (2**5) 

    if self.use_VVSD:
        userint4 += (2**6)
    if self.use_Andersen:
        userint4 += (2**3)
        
    params['userint4'] = '%d'%userint4
        
    # userreals
    params['userreal1'] = '%3.2f'%self.innerDielectric
    params['userreal2'] = '%3.2f'%self.outerDielectric
    if self.use_Sheffield:
        params['userreal3'] = '%3.2f'%self.Sheffield_A
        params['userreal4'] = '%3.2f'%self.Sheffield_B
    elif self.use_Andersen or self.use_VVSD:
        params['userreal3'] = '%3.2f'%self.targetTemperature
    params['userreal4'] = '%3.2f'%self.viscosity    
  
    if PS3_Visualization: 
        # user1_grps and user2_grps for PS3 Advanced Visualization  
        if self.user1_grps != None:
            params['user1_grps'] = self.user1_grps
        if self.user2_grps != None:
            params['user2_grps'] = self.user2_grps

    self.mdpParams =  params
   
    return
    
    

# Derived Classes

class StillGBOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to StillGB + VVSD, eprot = 1.0, esolv = 80.0"""
    pass   # This is the same as our base class.
  
class GBOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to GB + SASD + VVSD, eprot = 1.0, esolv = 80.0"""
    self.use_GB = True
    self.use_StillGB = False         
  
class AGBNPOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to AGBNP + SASD + VVSD, eprot = 1.0, esolv = 80.0"""
    self.use_GB = False
    self.use_StillGB = False         
    self.use_AGBNP = True      
  
class SheffieldOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to Sheffield + VVSD, eprot = 1.0, esolv = 80.0"""
    self.use_GB = False
    self.use_StillGB = False         
    self.use_AGBNP = False
    self.use_Sheffield = True
      
class SigmoidalDielectricOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to  VVSD, eprot = 1.0, esolv = 80.0"""
    self.use_GB = False
    self.use_StillGB = False         
    self.use_AGBNP = False
    self.use_Sheffield = False
  
<commit_msg># JDC: 1/29/08    Added capability to initialize from contents of an .mdp file.  Added random seed handling.<commit_after># MdpFile.py
#
# HISTORY
# JDC: 1/29/08    Added capability to initialize from contents of an .mdp file.  Added random seed handling.
# VAV: 9/09/07    Added self.delParameter(), allowing keywords and their valuestrs to be removed from the mdp file
# VAV: 9/02/07    Added self.use_table() and TableMaker object 
# VAV: 8/27/07    File created
#
# TO DO:
# * Have default *.mdp template in case __init__() template file is not provided.

import sys, os, tempfile, string
from TableMaker import *


class MdpFile(object):
  """A class to store and manipulate Gromacs mdp files.

  TODO
    Can we make use of the Units class to allow user to specify parameters with units attached and automatically convert to/from gromacs units?
  """

  # Class data
  MAXSEED = 2**30 # maximum random number seed
    
  def __init__(self, mdpfile = None, debug = False): 
    """Constructor to initialize mdp file container.
  
    OPTIONAL ARGUMENTS
      mdpfile        filename (string) or contents (list of strings) of a gromacs .mdp file to be read
    """

    # set debug flag
    self.debug = debug 

    # store filename of .mdp file initialized from, if any
    self.templatefile = None
    if type(mdpfile) == str:
      self.templatefile = mdpfile
          
    # initialize internal storage
    self.lines = []
    self.params = {}    # {keyword:value} dictionary.  NOTE: All values are stored as strings: i.e. {'rlist':'4.0'}
    self.keywords = []  # keep a list of the keyword order, just so we can write oiut *.mdp files in the same order as the template 

    # read .mdp file or process contents, if give
    if mdpfile:
      [self.lines, self.params, self.keywords] = self.read(mdpfile)

    # settings for user-defined tables    
    self.use_xvg = False
    self.tablemaker = None
    self.tabletype = None
    self.tabletxt = None

    return

  def use_table(self, tabletype, spacing=0.002):   
    """Turn on the xvg table option, and generate a user-defined table 
    defined in self.xvg_lines, generated by the TableMaker object, with the specifications:showParams

    OPTIONS 
        tabletype =  a TableMaker.Dielectric derived class:
                     'Switch_Shift'	(default) GROMACS-style tapered cutoffs
                     'SF3'		ShenFreed 3 table
                     'ReactionField'    rxn field dielectric solvent model

    TableMaker examples:
    # table=TableMaker(spacing=0.002)

    # tabletype=SF3(length_scale=4.0)
    # tabletype=Switch_Shift()
    # tabletype=ReactionField(rc=1.0)

    # settings for eps->Infinity
    # tabletype.krf = 1.0 / ( 2.0 * tabletype.rc )
    # tabletype.crf = 3.0 / ( 2.0 * tabletype.rc ) 

    # table=table.make(tabletype)

    # print table
    """

    self.use_xvg = True
    self.tabletype = tabletype
    self.tablemaker = TableMaker(spacing=spacing)
    self.tabletxt = self.tablemaker.make(self.tabletype)
    
    # set the user-table flags in the the mdp file 
    self.setParameter('coulombtype','user')
    self.setParameter('vdwtype','user')

    # NOTE: the acual 'table.xvg' file will be written by System.prepare()
    
  def read(self, mdpfile):
    """Read the contents of a gromacs .mdp file.

    ARGUMENTS
      mdpfile (string or list of strings) - if a string is provided, the contents of the file are read;
                                            if a list is provided, this is interpreted as the contents of an mdp file
    """

    # handle multiple argument types
    if (type(mdpfile) == list):
      lines = mdpfile
    elif (type(mdpfile) == str):
      # if a filename is provided, get its contents
      fin = open(filename, 'r')
      lines = fin.readlines()
      fin.close()
    else:
      raise "Unrecognized argument: " + repr(mdpfile)
      
    # build an initial dictionary of key:values from the lines
    [params, keywords] = self.buildParameterDict(lines)    
    return [lines, params, keywords]

  def write(self, filename):
    """Write contents of .mdp file to disk.

    ARGUMENTS
      filename (string) - the filename to write to
    """

    fout = open(filename, 'w')
    for line in self.lines:
      fout.write(line)
    fout.close()

    return
  
  def write_table(self, filename):
    """Writes the lines of self.tabletxt to user-supplied filename in correct directory -- should be 'table.xvg'

    ARGUMENTS
      filename (string) - the name of the file to be written

    """

    fout = open(filename, 'w')
    fout.write(self.tabletxt)
    fout.close()

    return

  def buildParameterDict(self, lines):
    """Goes through each line of the file,and parses keywords into a key:value dictionary

    ARGUMENTS
      lines (list) - the contents of the .mdp file from which the dictionary is to be built

    RETURNS
      params (dict) - dictionary of key:value processed from contents of file
      keywords (list) - list of keywords found in the file

    TODO
      The processing here is very rudimentary -- may need to be modified to accomodate multiple arguments per line.
      We should store the corresponding original line from the file, or store the complete contents of the line (including comments?)
      
    """

    params = {}
    keywords = []
    for line in lines:
        fields = line.strip().split()
        if len(fields) >= 3:
          if fields[0][0] != ';':
            params[fields[0]] = fields[2]
            keywords.append(fields[0])                        

    return [params, keywords]
              
  def showParams(self):
    """Display dictionary of recognized key:value pairs from mdp file.
    """
    outstr = ''
    for key in self.keywords:
        outstr = outstr + self.keyword2line(key)
    print outstr
    
  def keyword2line(self, keyword):
    """Takes in a parameter keyword and returns a formatted mdp file line.

    ARGUMENTS
      keyword (string) - the keyword specifying the formatted mdp line to retrieve

    RETURNS
      the formatted mdp line corresponding to the keyword, if found

    TODO
      What if keyword isn't found?
      We should store the corresponding original line from the file, or store the complete contents of the line (including comments?)      

    """ 
    return '%-20s = %-20s\n'%(keyword, self.params[keyword])
    
  def setParameter(self, keyword, valuestr):
    """Sets a particular mdp keyword to a value (string) in the parameter dictionary, updates mdp lines.

    ARGUMENTS
      keyword (string) - the keyword to which the parameter is to be assigned
      valuestr (string) - the corresponding parameter value to assign to the keyword

    TODO
      Searching in the parameter file can be facilitated if we store a dictionary of which line a keyword is specified on.
    """
    
    # if keyword not already in our ordered list of keywords, append it    
    if self.keywords.count(keyword) == 0:
      self.keywords.append(keyword)
    
    # set keyword in dictionary
    self.params[keyword] = valuestr

    # replace instances of this 'keyword = value' in the mdp lines
    foundone = False
    for i in range(0,len(self.lines)):
        fields = self.lines[i].strip().split()
        if len(fields) > 0:
            if fields[0] == keyword:
                self.lines[i] = self.keyword2line(keyword)
                foundone = True
    # if can't find keyword in previous lines, add it to the lines
    if foundone == False:
        self.lines.append( self.keyword2line(keyword))

    return
        
  def randomizeSeed(self):
    """Randomize the random seed, adding one if none exists.

    TODO
      Uses range from 1 to 2**30 for now, but should figure out acceptable range for gromacs.
    """

    # choose a new random seed
    import random
    self.setParameter('gen_seed', random.randint(1, self.MAXSEED))

    return
  
  def setParametersFromDict(self, paramdict):
    """Takes in a set of parameters as a dictionary of {keyword:value} entries (values are strings) and sets parameters for each.

    ARGUMENTS
      paramdict (dict) - a dictionary of keyword:value pairs to be used to update parameters
    """
    
    for [key,value] in paramdict.iteritems():
      if self.debug:  print 'DEBUG: key, value of paramdict{}', key, value
      self.setParameter(key, value)

    return
      
  def delParameter(self, keyword):
    """Removes a particular mdp keyword (and its value (string)) from the parameter dictionary, and deletes mdp line.

    ARGUMENTS
      keyword (string) - the keyword to be cleared

    TODO
      Propose new name of clearParameter or removeParameter
    """
  
    # remove keyword from dictionary
    if self.params.has_key(keyword):
        del self.params[keyword]

    # replace instances of this 'keyword = value' in the mdp lines
    i=0
    while i < len(self.lines):
        fields = self.lines[i].strip().split()
        if len(fields) > 0:
            if fields[0] == keyword:
                self.lines.pop(i)
            else:
                i=i+1
        else:
            i=i+1

    return
    
#####################

class ImplicitOptions(object):
  """A data structure object to pass to MdpFile() so params can be set.
  """

  def __init__(self):
    """Initializes the ImplicitOptions() object.  This provides the parent class for a set of 
    objects all with differnt defaults.  The main default here is:
    
    VVSD
    Still GB
    

    Here is the README_ED, as of August 2007:
    
; Complete description of parameters (from 17 Jan 2007 README_ED from gromacs-3.1.4-ed)
; NOTE not all are enabled on PS3.  Those that are enabled on the PS3 are marked with [PS3]
;
; userint4 - BIT 0 - AGBNP on/off
; userint4 - BIT 1 - GB on/off [PS3]
; userint4 - BIT 2 - SASD for GB on/off
; userint4 - BIT 3 - Andersen on/off
; userint4 - BIT 4 - SASD for AGBNP on/off [PS3]
; userint4 - BIT 5 - Sheffield on/off
; userint4 - BIT 6 - use the velocity Verlet version of the SD algorithm (vvSD) [PS3]
- userint4 - BIT 7 - scale charges via sdelta  => gradually tuning off electrostatics (AGBNP & EdGB)
- userint4 - BIT 8 - turn on/off the GCMC part
; userint4 - BIT 9 - Still SA part on/off [PS3]
; userint4 - BIT 10 - turns on Still GB [PS3]
;
; userint1 - GB frequency (used for GB and AGBNP) [PS3]
; userint2 - BIT 0 - unused
; userint2 - BIT 1 - GB logging on/off
; userint2 - BIT 2 - AGBNP logging on/off
; usetint2 - BIT 3 - do NOT apply the solvation forces, this is helpful for comparisons
; userint3 - Andersen frequency [steps]
; userreal1 - inner/vacuum dielectric [PS3]
; userreal2 - outer/solvent dielectric [PS3]
; userreal3 - Sheffield: A parameter 
;           - Andersen:  target temperature
;           - vvSD: target temperature [PS3]
; userreal4 - Sheffield B parameter 
;           - friction [1/ps] thus 91 would represent water at room temperature [PS3]

userint1    = 1    ; update frequency for GB forces (should be set equal to nstlist)
userreal1   = 1.   ; interior dielectric constant
userreal2   = 80.  ; exterior dielectric constant
userint4    = 1600  ; Still GB on (2^10 = 1024), ACE SA term in the GB/SA (2^9 = 512), VVSD (2^6 = 64)
userint2    = 0    ; no logging, apply solvation forces
userreal3   = 300. ; temperature for VVSD integrator (in K)
userreal4   = 91.0 ; viscosity for VVSD integrator (in 1/ps)
"""

    # implicit solvation models     
    self.use_StillGB = True           # ; userint4 - BIT 10 - turns on Still GB [PS3]
    self.use_GB = False               # ; userint4 - BIT 1 - GB on/off [PS3]
    self.use_AGBNP = False            # ; userint4 - BIT 0 - AGBNP on/off
    self.use_Sheffield = False        # ; userint4 - BIT 5 - Sheffield on/off
    
    # solvent model options
    self.use_SASD = False    # SASD is velocity scaling based on solventg accessibility. Setting this option will modify GB, AGBNP
                                      # ; userint4 - BIT 2 - SASD for GB on/off [PS3]
                                      # ; userint4 - BIT 4 - SASD for AGBNP on/off 
    self.use_ACE_SA = True            # ; userint4 - BIT 9 - Still SA part f GB/SA on/off [PS3]
        
    # integration
    self.use_VVSD = True              # ; userint4 - BIT 6 - use the velocity Verlet version of the SD algorithm (vvSD) [PS3]
    self.use_Andersen = False         # ; userint4 - BIT 3 - Andersen on/off
    
    # Additional Parameters 
    self.GB_frequency = 1             # ; userint1 - GB frequency (used for GB and AGBNP) [PS3]  (should be set equal to nstlist)
    self.scaleCharges = False         # ; userint4 - BIT 7 - scale charges via sdelta  => gradually tuning off electrostatics (AGBNP & EdGB)
    self.use_GCMC = False             # ; userint4 - BIT 8 - turn on/off the GCMC part (Grand Canonical)  [not ready yet!]
    
    ### userint2
    self.GB_logging = False           # ; userint2 - BIT 1 - GB logging on/off
    self.AGBNP_logging = False        # ; userint2 - BIT 2 - AGBNP logging on/off
    self.DontApplySolvationForces = False  # ; usetint2 - BIT 3 - do NOT apply the solvation forces, this is helpful for comparisons
    
    ### userint3
    self.Andersen_frequency = 1       # ; userint2 - BIT 1 - GB logging on/off

    
    # Continuous parameters
    self.innerDielectric = 1.0
    self.outerDielectric = 80.0
    self.Sheffield_A = 1.0            # ; userreal3 - Sheffield A parameter 
    self.Sheffield_B = 1.0            # ; userreal4 - Sheffield B parameter 
    self.targetTemperature = 300.     # ; userreal3 - Andersen:  target temperature
                                      # ;           - vvSD: target temperature [PS3]
    self.viscosity = 91.              # ; userreal4 - friction [1/ps] thus 91 would represent water at room temperature [PS3]


    # user1_groups    
    self.q = {}          # ; A dictionary of key:value (strings) that can be given to MdpFile.setParameter()
   

    ### groups for visualization
    self.user1_grps = None            # show-lines, show-spacefill, show-sticks, ca-trace, or show-balls
    self.user1_residues = None        # This will be used by make_PS3_ndx()
    self.user2_grps = None
    self.user2_residues = None
    ### NOTE: asdfghjk
    # JDC sez:  To include more groups is difficult, as this requires overriding the default behavior of grompp
    # to prevent unnecessary groups from being included in the .tpr file. A modified grompp for the 3.1.4 EdGB
    # version of gromacs is available that allows specification of up to five groups, though this overrides the
    # ACC, FREEZE, and ORFIT capabilities (which we don't use anyway). The modified grompp requires recompilation
    # with this modified kernel/readir.c file.
    #
    # self.user1_grps = show-lines
    # self.user2_grps = show-spacefill
    # self.user3_grps = show-sticks ; requires modified grompp
    # self.user4_grps = ca-trace ; requires modified grompp
    # self.user5_grps = show-balls ; requires modified grompp

    ### Do the setup
    self.setup()                                      # derived classes can change the parms, if desired
    self.buildMdpParams()       # compiles a list of params to set in the mdpfile
    
    
  def setup(self):
    """This is the customizable parrt of derived classes, used to set parameters for a particular type of implicit solvation """
    pass
  

  def buildMdpParams(self, PS3_Visualization=False):
    """compiles a list of params to set in the mdpfile.
    Returns a dictionary of key:value (strings) that can be given to MdpFile.setParameter()"""
    
    params = {}

    # userint 1, 2 and 3
    params['userint1'] = '%d'%self.GB_frequency
    params['userint2'] = '%d'%( self.GB_logging*2 + self.AGBNP_logging*4 + self.DontApplySolvationForces*8  )
    if self.use_Andersen:
      params['userint3'] = '%d'%self.Andersen_frequency
    
    # userint4
    userint4 = 0
    if self.use_StillGB:
        userint4 += (2**10)
        if self.use_ACE_SA:
            userint4 += (2**9)
    elif self.use_GB:
        userint4 += (2**1) 
        if self.use_SASD:
            userint4 += (2**2)
    elif self.use_AGBNP: 
        userint4 += 1
        if self.use_SASD:
            userint4 += (2**4) 
    elif self.use_Sheffield:   
        userint4 += (2**5) 

    if self.use_VVSD:
        userint4 += (2**6)
    if self.use_Andersen:
        userint4 += (2**3)
        
    params['userint4'] = '%d'%userint4
        
    # userreals
    params['userreal1'] = '%3.2f'%self.innerDielectric
    params['userreal2'] = '%3.2f'%self.outerDielectric
    if self.use_Sheffield:
        params['userreal3'] = '%3.2f'%self.Sheffield_A
        params['userreal4'] = '%3.2f'%self.Sheffield_B
    elif self.use_Andersen or self.use_VVSD:
        params['userreal3'] = '%3.2f'%self.targetTemperature
    params['userreal4'] = '%3.2f'%self.viscosity    
  
    if PS3_Visualization: 
        # user1_grps and user2_grps for PS3 Advanced Visualization  
        if self.user1_grps != None:
            params['user1_grps'] = self.user1_grps
        if self.user2_grps != None:
            params['user2_grps'] = self.user2_grps

    self.mdpParams =  params
   
    return
    
    

# Derived Classes

class StillGBOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to StillGB + VVSD, eprot = 1.0, esolv = 80.0"""
    pass   # This is the same as our base class.
  
class GBOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to GB + SASD + VVSD, eprot = 1.0, esolv = 80.0"""
    self.use_GB = True
    self.use_StillGB = False         
  
class AGBNPOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to AGBNP + SASD + VVSD, eprot = 1.0, esolv = 80.0"""
    self.use_GB = False
    self.use_StillGB = False         
    self.use_AGBNP = True      
  
class SheffieldOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to Sheffield + VVSD, eprot = 1.0, esolv = 80.0"""
    self.use_GB = False
    self.use_StillGB = False         
    self.use_AGBNP = False
    self.use_Sheffield = True
      
class SigmoidalDielectricOptions(ImplicitOptions):
  def setup(self):
    """Customize the options according to  VVSD, eprot = 1.0, esolv = 80.0"""
    self.use_GB = False
    self.use_StillGB = False         
    self.use_AGBNP = False
    self.use_Sheffield = False
  

{'fraction_non_alphanumeric': 0.09409627070177529, 'fraction_numerical': 0.020910282378172287, 'mean_word_length': 2.4216265796983287, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7185058', 'n_tokens_mistral': 10955, 'n_tokens_neox': 10280, 'n_words': 3476}