MayaChemTools

    1 #!/bin/env python
    2 #
    3 # File: PyMOLVisualizeInterfaces.py
    4 # Author: Manish Sud <msud@san.rr.com>
    5 #
    6 # Copyright (C) 2024 Manish Sud. All rights reserved.
    7 #
    8 # The functionality available in this script is implemented using PyMOL, a
    9 # molecular visualization system on an open source foundation originally
   10 # developed by Warren DeLano.
   11 #
   12 # This file is part of MayaChemTools.
   13 #
   14 # MayaChemTools is free software; you can redistribute it and/or modify it under
   15 # the terms of the GNU Lesser General Public License as published by the Free
   16 # Software Foundation; either version 3 of the License, or (at your option) any
   17 # later version.
   18 #
   19 # MayaChemTools is distributed in the hope that it will be useful, but without
   20 # any warranty; without even the implied warranty of merchantability of fitness
   21 # for a particular purpose.  See the GNU Lesser General Public License for more
   22 # details.
   23 #
   24 # You should have received a copy of the GNU Lesser General Public License
   25 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
   26 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
   27 # Boston, MA, 02111-1307, USA.
   28 #
   29 
   30 from __future__ import print_function
   31 
   32 # Add local python path to the global path and import standard library modules...
   33 import os
   34 import sys;  sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python"))
   35 import time
   36 import re
   37 
   38 # PyMOL imports...
   39 try:
   40     import pymol
   41     # Finish launching PyMOL in  a command line mode for batch processing (-c)
   42     # along with the following options:  disable loading of pymolrc and plugins (-k);
   43     # suppress start up messages (-q)
   44     pymol.finish_launching(['pymol', '-ckq'])
   45 except ImportError as ErrMsg:
   46     sys.stderr.write("\nFailed to import PyMOL module/package: %s\n" % ErrMsg)
   47     sys.stderr.write("Check/update your PyMOL environment and try again.\n\n")
   48     sys.exit(1)
   49 
   50 # MayaChemTools imports...
   51 try:
   52     from docopt import docopt
   53     import MiscUtil
   54     import PyMOLUtil
   55 except ImportError as ErrMsg:
   56     sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg)
   57     sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n")
   58     sys.exit(1)
   59 
   60 ScriptName = os.path.basename(sys.argv[0])
   61 Options = {}
   62 OptionsInfo = {}
   63 
   64 def main():
   65     """Start execution of the script."""
   66     
   67     MiscUtil.PrintInfo("\n%s (PyMOL v%s; MayaChemTools v%s; %s): Starting...\n" % (ScriptName, pymol.cmd.get_version()[0], MiscUtil.GetMayaChemToolsVersion(), time.asctime()))
   68     
   69     (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime()
   70     
   71     # Retrieve command line arguments and options...
   72     RetrieveOptions()
   73     
   74     # Process and validate command line arguments and options...
   75     ProcessOptions()
   76 
   77     # Perform actions required by the script...
   78     GenerateMacromolecularInterfacesVisualization()
   79     
   80     MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName)
   81     MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime))
   82 
   83 def GenerateMacromolecularInterfacesVisualization():
   84     """Generate visualization for macromolecular interfaces."""
   85 
   86     Outfile = OptionsInfo["PMLOutfile"]
   87     OutFH = open(Outfile, "w")
   88     if OutFH is None:
   89         MiscUtil.PrintError("Failed to open output fie %s " % Outfile)
   90     
   91     MiscUtil.PrintInfo("\nGenerating file %s..." % Outfile)
   92 
   93     # Setup header...
   94     WritePMLHeader(OutFH, ScriptName)
   95     WritePyMOLParameters(OutFH)
   96     
   97     WriteComplexesAndChainsViews(OutFH)
   98     WriteInterfaceViews(OutFH)
   99 
  100     OutFH.close()
  101 
  102     # Generate PSE file as needed...
  103     if OptionsInfo["PSEOut"]:
  104         GeneratePyMOLSessionFile()
  105 
  106 def WriteComplexesAndChainsViews(OutFH):
  107     """Write out PML for viewing complexes and chains in input files."""
  108     
  109     # Setup views for input file(s)...
  110     for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
  111         # Setup PyMOL object names...
  112         PyMOLObjectNamesInfo = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex]
  113 
  114         # Setup complex view...
  115         WriteComplexView(OutFH, FileIndex, PyMOLObjectNamesInfo)
  116 
  117         # Setup chain views...
  118         SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  119 
  120         for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  121             WriteChainView(OutFH, FileIndex, PyMOLObjectNamesInfo, ChainID)
  122             
  123             # Setup ligand views...
  124             for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
  125                 WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNamesInfo, ChainID, LigandID)
  126                 
  127                 # Set up ligand level group...
  128                 Enable, Action = [True, "close"]
  129                 GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNamesInfo["Ligands"][ChainID][LigandID]["ChainLigandGroup"], PyMOLObjectNamesInfo["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"], Enable, Action)
  130             
  131             # Setup Chain level group...
  132             Enable, Action = [True, "open"]
  133             GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNamesInfo["Chains"][ChainID]["ChainGroup"], PyMOLObjectNamesInfo["Chains"][ChainID]["ChainGroupMembers"], Enable, Action)
  134     
  135         # Set up complex level group...
  136         Enable, Action = [True, "close"]
  137         GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNamesInfo["PDBGroup"], PyMOLObjectNamesInfo["PDBGroupMembers"], Enable, Action)
  138         
  139         # Delete empty PyMOL objects...
  140         DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNamesInfo)
  141     
  142 def WriteInterfaceViews(OutFH):
  143     """Write out PML for viewing macromolecular interfaces among specified chains."""
  144     
  145     InterfaceChainsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"]
  146     if InterfaceChainsAndResiduesInfo is None:
  147         return
  148 
  149     PyMOLInterfaceObjectNamesInfo = OptionsInfo["InfilesInfo"]["PyMOLInterfaceObjectNamesInfo"]
  150     InterfaceChainPairsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainPairsAndResiduesInfo"]
  151     
  152     FirstInterfaceID = True
  153     for InterfaceID in InterfaceChainsAndResiduesInfo["InterfaceIDs"]:
  154         WriteInterfacePolarContactsView(OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLInterfaceObjectNamesInfo)
  155         WriteInterfaceHydrophobicContactsView(OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLInterfaceObjectNamesInfo)
  156         
  157         for InterfaceChainID in InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID]:
  158             ChainID = InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID][InterfaceChainID]
  159             ResNums = InterfaceChainsAndResiduesInfo["ChainIDsResNums"][InterfaceID][InterfaceChainID]
  160             ComplexName = InterfaceChainsAndResiduesInfo["ChainIDsComplexNames"][InterfaceID][InterfaceChainID]
  161             FileIndex = InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID][InterfaceChainID]
  162 
  163             WriteInterfaceChainView(OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, ResNums, ComplexName, PyMOLInterfaceObjectNamesInfo)
  164 
  165             # Setup interface Chain level group...
  166             Enable, Action = [True, "open"]
  167             GenerateAndWritePMLForGroup(OutFH, PyMOLInterfaceObjectNamesInfo["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroup"], PyMOLInterfaceObjectNamesInfo["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"], Enable, Action)
  168 
  169         if FirstInterfaceID:
  170             FirstInterfaceID = False
  171             Enable, Action = [True, "open"]
  172         else:
  173             Enable, Action = [True, "close"]
  174             
  175         GenerateAndWritePMLForGroup(OutFH, PyMOLInterfaceObjectNamesInfo["InterfaceIDs"][InterfaceID]["InterfaceIDGroup"], PyMOLInterfaceObjectNamesInfo["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"], Enable, Action)
  176 
  177     # Setup interfaces level group...
  178     Enable, Action = [True, "open"]
  179     GenerateAndWritePMLForGroup(OutFH, PyMOLInterfaceObjectNamesInfo["InterfacesGroup"], PyMOLInterfaceObjectNamesInfo["InterfacesGroupMembers"], Enable, Action)
  180 
  181     DeleteEmptyPyMOLInterfaceObjects(OutFH)
  182     
  183     # Setup orientation...
  184     OutFH.write("""\ncmd.orient("visible", animate = -1)\n""")
  185 
  186 def WritePMLHeader(OutFH, ScriptName):
  187     """Write out PML setting up complex view."""
  188 
  189     HeaderInfo = PyMOLUtil.SetupPMLHeaderInfo(ScriptName)
  190     OutFH.write("%s\n" % HeaderInfo)
  191 
  192 def WritePyMOLParameters(OutFH):
  193     """Write out PyMOL global parameters."""
  194 
  195     PMLCmds = []
  196     PMLCmds.append("""cmd.set("transparency", %.2f, "", 0)""" % (OptionsInfo["SurfaceTransparency"]))
  197     PMLCmds.append("""cmd.set("label_font_id", %s)""" % (OptionsInfo["LabelFontID"]))
  198     PML = "\n".join(PMLCmds)
  199     
  200     OutFH.write("""\n""\n"Setting up PyMOL gobal parameters..."\n""\n""")
  201     OutFH.write("%s\n" % PML)
  202     
  203 def WriteComplexView(OutFH, FileIndex, PyMOLObjectNames):
  204     """Write out PML for viewing polymer complex."""
  205 
  206     # Setup complex...
  207     Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
  208     PML = PyMOLUtil.SetupPMLForPolymerComplexView(PyMOLObjectNames["Complex"], Infile, True)
  209     OutFH.write("""\n""\n"Loading %s and setting up view for complex..."\n""\n""" % Infile)
  210     OutFH.write("%s\n" % PML)
  211 
  212     if OptionsInfo["SurfaceComplex"]:
  213         # Setup hydrophobic surface...
  214         PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(PyMOLObjectNames["ComplexHydrophobicSurface"], PyMOLObjectNames["Complex"], ColorPalette = OptionsInfo["SurfaceColorPalette"], Enable = False)
  215         OutFH.write("\n%s\n" % PML)
  216     
  217     # Setup complex group...
  218     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["ComplexGroup"], PyMOLObjectNames["ComplexGroupMembers"], False, "close")
  219 
  220 def WriteChainView(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  221     """Write out PML for viewing chain."""
  222     
  223     OutFH.write("""\n""\n"Setting up views for chain %s..."\n""\n""" % ChainID)
  224     
  225     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  226     
  227     # Setup chain complex group view...
  228     WriteChainComplexViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  229 
  230     # Setup chain view...
  231     WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  232     
  233     # Setup chain solvent view...
  234     PML = PyMOLUtil.SetupPMLForSolventView(PyMOLObjectNames["Chains"][ChainID]["Solvent"], ChainComplexName, False)
  235     OutFH.write("\n%s\n" % PML)
  236 
  237     # Setup chain inorganic view...
  238     PML = PyMOLUtil.SetupPMLForInorganicView(PyMOLObjectNames["Chains"][ChainID]["Inorganic"], ChainComplexName, False)
  239     OutFH.write("\n%s\n" % PML)
  240 
  241 def WriteChainComplexViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  242     """Write chain complex views."""
  243 
  244     # Setup chain complex...
  245     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  246     PML = PyMOLUtil.SetupPMLForPolymerChainComplexView(ChainComplexName, PyMOLObjectNames["Complex"], ChainID, True)
  247     OutFH.write("%s\n" % PML)
  248 
  249     if OptionsInfo["SurfaceChainComplex"]:
  250         # Setup hydrophobic surface...
  251         PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(PyMOLObjectNames["Chains"][ChainID]["ChainComplexHydrophobicSurface"], ChainComplexName, ColorPalette = OptionsInfo["SurfaceColorPalette"], Enable = False)
  252         OutFH.write("\n%s\n" % PML)
  253     
  254     # Setup chain complex group...
  255     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"], PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"], False, "close")
  256     
  257 def WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  258     """Write individual chain views."""
  259 
  260     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  261 
  262     # Setup chain view...
  263     ChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
  264     PML = PyMOLUtil.SetupPMLForPolymerChainView(ChainName, ChainComplexName, True)
  265     OutFH.write("\n%s\n" % PML)
  266 
  267     # Setup a non-interface chain view...
  268     NonInterfaceChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterface"]
  269     
  270     InterfaceResNums = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["InterfaceResNums"][ChainID]
  271     InterfaceResNumsSelection = "+".join(InterfaceResNums)
  272     
  273     Selection = "%s and chain %s and polymer and (not (resi %s))" % (ChainComplexName, ChainID, InterfaceResNumsSelection)
  274     PML = PyMOLUtil.SetupPMLForSelectionDisplayView(NonInterfaceChainName, Selection, "cartoon", Enable = False)
  275     OutFH.write("\n%s\n" % PML)
  276     
  277     if GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
  278         # Setup a generic colored surface...
  279         PML = PyMOLUtil.SetupPMLForSurfaceView(PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurface"], NonInterfaceChainName, Enable = False, Color = OptionsInfo["SurfaceNonInterfaceColor"])
  280         OutFH.write("\n%s\n" % PML)
  281         
  282         if GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
  283             # Setup surface colored by hydrophobicity...
  284             PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(PyMOLObjectNames["Chains"][ChainID]["ChainAloneHydrophobicSurface"], NonInterfaceChainName, ColorPalette = OptionsInfo["SurfaceColorPalette"], Enable = False)
  285             OutFH.write("\n%s\n" % PML)
  286             
  287             # Setup surface colored by hyrdophobicity and charge...
  288             PML = PyMOLUtil.SetupPMLForHydrophobicAndChargeSurfaceView(PyMOLObjectNames["Chains"][ChainID]["ChainAloneHydrophobicChargeSurface"], NonInterfaceChainName, OptionsInfo["AtomTypesColorNames"]["HydrophobicAtomsColor"], OptionsInfo["AtomTypesColorNames"]["NegativelyChargedAtomsColor"], OptionsInfo["AtomTypesColorNames"]["PositivelyChargedAtomsColor"], OptionsInfo["AtomTypesColorNames"]["OtherAtomsColor"], Enable = False, DisplayAs = None)
  289             OutFH.write("\n%s\n" % PML)
  290         
  291         if GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
  292             # Setup electrostatics surface...
  293             SelectionObjectName = NonInterfaceChainName
  294             ElectrostaticsGroupName = PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroup"]
  295             ElectrostaticsGroupMembers = PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroupMembers"]
  296             WriteSurfaceElectrostaticsView("Chain", OutFH, SelectionObjectName, ElectrostaticsGroupName, ElectrostaticsGroupMembers)
  297 
  298         # Setup surface group...
  299         GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroup"], PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"], True, "open")
  300 
  301     # Setup a non-interface group...
  302     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroup"], PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroupMembers"], True, "open")
  303     
  304     # Setup chain group...
  305     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"], PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"], True, "close")
  306     
  307 def WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNames, ChainID, LigandID):
  308     """Write out PML for viewing ligand in a chain."""
  309 
  310     GroupID = "Ligand"
  311     ComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  312     LigandName = PyMOLObjectNames["Ligands"][ChainID][LigandID]["Ligand"]
  313     
  314     # Setup main object...
  315     GroupTypeObjectID = "%s" % (GroupID)
  316     GroupTypeObjectName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID]
  317     
  318     OutFH.write("""\n""\n"Setting up views for ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID))
  319     PML = PyMOLUtil.SetupPMLForLigandView(GroupTypeObjectName, ComplexName, LigandID, Enable = True, IgnoreHydrogens = OptionsInfo["IgnoreHydrogens"])
  320     OutFH.write("%s\n" % PML)
  321     
  322     # Setup ball and stick view...
  323     BallAndStickNameID = "%sBallAndStick" % (GroupID)
  324     BallAndStickName = PyMOLObjectNames["Ligands"][ChainID][LigandID][BallAndStickNameID]
  325     PML = PyMOLUtil.SetupPMLForBallAndStickView(BallAndStickName, GroupTypeObjectName, Enable = False)
  326     OutFH.write("\n%s\n" % PML)
  327             
  328     # Setup group....
  329     GroupNameID = "%sGroup" % (GroupID)
  330     GroupMembersID = "%sGroupMembers" % (GroupID)
  331     GroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID]
  332     GroupMembers = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID]
  333 
  334     Action = "open"
  335     Enable = True
  336     GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable, Action)
  337 
  338 def WriteInterfacePolarContactsView(OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames):
  339     """Write out PML for viewing polar contacts between interface residues."""
  340     
  341     if not OptionsInfo["InterfacePolarContacts"]:
  342         return
  343     
  344     WriteInterfaceContactsView("InterfacePolarConatcts", OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames)
  345     
  346 def WriteInterfaceHydrophobicContactsView(OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames):
  347     """Write out PML for viewing hydrophobic contacts between interface residues."""
  348     
  349     if not OptionsInfo["InterfaceHydrophobicContacts"]:
  350         return
  351 
  352     WriteInterfaceContactsView("InterfaceHydrophobicContacts", OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames)
  353     
  354 def WriteInterfaceContactsView(Mode, OutFH, InterfaceID, InterfaceChainPairsAndResiduesInfo, PyMOLObjectNames):
  355     """Write out PML for viewing polar or hydrophobic contacts between interface residues."""
  356     
  357     InterfacePolarContacts = True if re.match("^InterfacePolarConatcts$", Mode, re.I) else False
  358     
  359     ChainIDs1, ChainIDs2 =  InterfaceChainPairsAndResiduesInfo["ChainIDsPairs"][InterfaceID]
  360     ResNums1, ResNums2 = InterfaceChainPairsAndResiduesInfo["ChainIDsResNumsPairs"][InterfaceID]
  361     
  362     FileIndex1, FileIndex2 = InterfaceChainPairsAndResiduesInfo["InfileIndicesPairs"][InterfaceID]
  363     ComplexName1 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex1]["Complex"]
  364     ComplexName2 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex2]["Complex"]
  365     
  366     Selection1 = SetupSelectionForInterfaceContactsView(ComplexName1, ChainIDs1, ResNums1)
  367     Selection2 = SetupSelectionForInterfaceContactsView(ComplexName2, ChainIDs2, ResNums2)
  368 
  369     if InterfacePolarContacts:
  370         ContactsName = PyMOLObjectNames["InterfaceIDs"][InterfaceID]["PolarContacts"]
  371         ContactsColor = OptionsInfo["InterfacePolarContactsColor"]
  372         ContactsCutoff = OptionsInfo["InterfaceContactsCutoff"]
  373         
  374         PML = PyMOLUtil.SetupPMLForPolarContactsView(ContactsName, Selection1, Selection2, Enable = False, Color = ContactsColor, Cutoff = ContactsCutoff)
  375     else:
  376         ContactsName = PyMOLObjectNames["InterfaceIDs"][InterfaceID]["HydrophobicContacts"]
  377         ContactsColor = OptionsInfo["InterfaceHydrophobicContactsColor"]
  378         ContactsCutoff = OptionsInfo["InterfaceContactsCutoff"]
  379         
  380         PML = PyMOLUtil.SetupPMLForHydrophobicContactsView(ContactsName, Selection1, Selection2, Enable = False, Color = ContactsColor, Cutoff = ContactsCutoff)
  381     
  382     OutFH.write("\n%s\n" % PML)
  383     
  384     OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (ContactsColor, ContactsName))
  385 
  386 def SetupSelectionForInterfaceContactsView(ComplexName, ChainIDs, ResNums):
  387     """Setup a selection for generating polar or hyrophobic contacts for an interface."""
  388 
  389     ChainSelections = []
  390     
  391     for ChainID in ChainIDs:
  392         ChainResNumsSelection = "+".join(ResNums["ResNums"][ChainID])
  393         Selection = "(%s and chain %s and polymer and (resi %s))" % (ComplexName, ChainID, ChainResNumsSelection)
  394         ChainSelections.append(Selection)
  395 
  396     Selection = " or ".join(ChainSelections)
  397     
  398     return Selection
  399 
  400 def WriteInterfaceChainView(OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, ResiduesNums, ComplexName, PyMOLObjectNames):
  401     """Write out PML for viewing interface residues in a chain."""
  402 
  403     OutFH.write("""\n""\n"Setting up interface views for interface in %s..."\n""\n""" % InterfaceChainID)
  404     
  405     ResiduesNumsSelection = "+".join(ResiduesNums)
  406     
  407     # Setup a chain for interface residues...
  408     ChainName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["Chain"]
  409     Selection = "%s and chain %s and polymer and (resi %s)" % (ComplexName, ChainID, ResiduesNumsSelection)
  410 
  411     PML = PyMOLUtil.SetupPMLForSelectionDisplayView(ChainName, Selection, "lines", Enable = True)
  412     OutFH.write("\n%s\n" % PML)
  413 
  414     OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (OptionsInfo["InterfaceLabelColor"], ChainName))
  415 
  416     WriteInterfaceChainResidueTypesView(OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, PyMOLObjectNames)
  417     
  418     if GetInterfaceContainsSurfacesStatus(FileIndex, ChainID):
  419         # Setup generic colored surface...
  420         PML = PyMOLUtil.SetupPMLForSurfaceView(PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurface"], ChainName, Color = OptionsInfo["SurfaceInterfaceColor"], Enable = True, DisplayAs = "lines")
  421         OutFH.write("\n%s\n" % PML)
  422         
  423         if GetInterfaceSurfaceChainStatus(FileIndex, ChainID):
  424             # Setup surface colored by hydrophobicity...
  425             PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainHydrophobicSurface"], ChainName, ColorPalette = OptionsInfo["SurfaceColorPalette"], Enable = False, DisplayAs = "lines")
  426             OutFH.write("\n%s\n" % PML)
  427             
  428             # Setup surface colored by hyrdophobicity and charge...
  429             PML = PyMOLUtil.SetupPMLForHydrophobicAndChargeSurfaceView(PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainHydrophobicChargeSurface"], ChainName, OptionsInfo["AtomTypesColorNames"]["HydrophobicAtomsColor"], OptionsInfo["AtomTypesColorNames"]["NegativelyChargedAtomsColor"], OptionsInfo["AtomTypesColorNames"]["PositivelyChargedAtomsColor"], OptionsInfo["AtomTypesColorNames"]["OtherAtomsColor"], Enable = False, DisplayAs = "lines")
  430             OutFH.write("\n%s\n" % PML)
  431         
  432         if GetInterfaceSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
  433             # Setup electrostatics surface...
  434             SelectionObjectName = ChainName
  435             ElectrostaticsGroupName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainElectrostaticsGroup"]
  436             ElectrostaticsGroupMembers = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainElectrostaticsGroupMembers"]
  437             WriteSurfaceElectrostaticsView("InterfaceResidues", OutFH, SelectionObjectName, ElectrostaticsGroupName, ElectrostaticsGroupMembers)
  438         
  439         # Setup surface group...
  440         GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroup"], PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"], True, "open")
  441         
  442     # Setup chain group...
  443     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroup"], PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"], True, "close")
  444     
  445 def WriteInterfaceChainResidueTypesView(OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, PyMOLObjectNames):
  446     """Write out PML for viewing interface residue types for a chain."""
  447 
  448     if not GetInterfaceResidueTypesStatus(FileIndex, ChainID):
  449         return
  450     
  451     ChainName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["Chain"]
  452     
  453     # Setup residue types objects...
  454     ResiduesGroupIDPrefix = "ChainResidues"
  455     for SubGroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
  456         SubGroupID = re.sub("_", "", SubGroupType)
  457 
  458         ResiduesObjectID = "%s%sResidues" % (ResiduesGroupIDPrefix, SubGroupID)
  459         ResiduesObjectName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesObjectID]
  460 
  461         ResiduesSurfaceObjectID = "%s%sSurface" % (ResiduesGroupIDPrefix, SubGroupID)
  462         ResiduesSurfaceObjectName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSurfaceObjectID]
  463 
  464         ResiduesColor = OptionsInfo["ResidueTypesParams"][SubGroupType]["Color"] 
  465         ResiduesNames = OptionsInfo["ResidueTypesParams"][SubGroupType]["Residues"]
  466 
  467         NegateResidueNames = True if re.match("^Other$", SubGroupType, re.I) else False
  468         WriteResidueTypesResiduesAndSurfaceView(OutFH, ChainName, ResiduesObjectName, ResiduesSurfaceObjectName, ResiduesColor, ResiduesNames, NegateResidueNames)
  469 
  470         # Setup residue type sub groups...
  471         ResiduesSubGroupID = "%s%sGroup" % (ResiduesGroupIDPrefix, SubGroupID)
  472         ResiduesSubGroupMembersID = "%s%sGroupMembers" % (ResiduesGroupIDPrefix, SubGroupID)
  473 
  474         GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupID], PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupMembersID], True, "close")
  475         
  476     # Setup residue types group...
  477     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainResiduesGroup"], PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainResiduesGroupMembers"], False, "close")
  478 
  479 def WriteResidueTypesResiduesAndSurfaceView(OutFH, SelectionObjectName, Name, SurfaceName, ResiduesColor, ResiduesNames, NegateResidueNames):
  480     """Write residue types residues and surface view."""
  481 
  482     ResidueNamesSelection = "+".join(ResiduesNames)
  483     if NegateResidueNames:
  484         Selection = "%s and (not resn %s)" % (SelectionObjectName, ResidueNamesSelection)
  485     else:
  486         Selection = "%s and (resn %s)" % (SelectionObjectName, ResidueNamesSelection)
  487 
  488     # Setup residues...
  489     PML = PyMOLUtil.SetupPMLForSelectionDisplayView(Name, Selection, "lines", ResiduesColor, True)
  490     OutFH.write("\n%s\n" % PML)
  491 
  492     # Setup surface...
  493     PML = PyMOLUtil.SetupPMLForSelectionDisplayView(SurfaceName, Selection, "surface", ResiduesColor, True)
  494     OutFH.write("\n%s\n" % PML)
  495     
  496 def WriteSurfaceElectrostaticsView(Mode, OutFH, SelectionObjectName, ElectrostaticsGroupName, ElectrostaticsGroupMembers):
  497     """Write out PML for viewing surface electrostatics."""
  498 
  499     if len(ElectrostaticsGroupMembers) == 5:
  500         Name, ContactPotentialName, MapName, LegendName, VolumeName = ElectrostaticsGroupMembers
  501     else:
  502         Name, ContactPotentialName, MapName, LegendName = ElectrostaticsGroupMembers
  503         VolumeName = None
  504 
  505     PMLCmds = []
  506 
  507     # Setup chain...
  508     PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, SelectionObjectName))
  509 
  510     # Setup vacuum electrostatics surface along with associated objects...
  511     PMLCmds.append("""util.protein_vacuum_esp("%s", mode=2, quiet=0, _self=cmd)""" % (Name))
  512     
  513     PMLCmds.append("""cmd.set_name("%s_e_chg", "%s")""" % (Name, ContactPotentialName))
  514     if re.match("^Chain$", Mode, re.I):
  515         DisplayStyle = "cartoon"
  516     else:
  517         DisplayStyle = "lines"
  518     PMLCmds.append("""cmd.show("%s", "(%s)")""" % (DisplayStyle, ContactPotentialName))
  519     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(ContactPotentialName, Enable = True))
  520     
  521     PMLCmds.append("""cmd.set_name("%s_e_map", "%s")""" % (Name, MapName))
  522     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(MapName, Enable = False))
  523     
  524     PMLCmds.append("""cmd.set_name("%s_e_pot", "%s")""" % (Name, LegendName))
  525     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(LegendName, Enable = False))
  526 
  527     if VolumeName is not None:
  528         PMLCmds.append("""cmd.volume("%s", "%s", "%s", "(%s)")""" % (VolumeName, MapName, "esp", Name))
  529         PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(VolumeName, Enable = False))
  530     
  531     # Delete name and take it out from the group membership. It is
  532     # is already part of ContactPotential object.
  533     PMLCmds.append("""cmd.delete("%s")""" % (Name))
  534     ElectrostaticsGroupMembers.pop(0)
  535     
  536     PML = "\n".join(PMLCmds)
  537     
  538     OutFH.write("\n%s\n" % PML)
  539     
  540     # Setup group...
  541     GenerateAndWritePMLForGroup(OutFH, ElectrostaticsGroupName, ElectrostaticsGroupMembers, False, "close")
  542 
  543 def GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable = False, Action = "close"):
  544     """Generate and write PML for group."""
  545     
  546     PML = PyMOLUtil.SetupPMLForGroup(GroupName, GroupMembers, Enable, Action)
  547     OutFH.write("""\n""\n"Setting up group %s..."\n""\n""" % GroupName)
  548     OutFH.write("%s\n" % PML)
  549 
  550 def GeneratePyMOLSessionFile():
  551     """Generate PME file from PML file."""
  552 
  553     PSEOutfile = OptionsInfo["PSEOutfile"]
  554     PMLOutfile = OptionsInfo["PMLOutfile"]
  555     
  556     MiscUtil.PrintInfo("\nGenerating file %s..." % PSEOutfile)
  557     
  558     PyMOLUtil.ConvertPMLFileToPSEFile(PMLOutfile, PSEOutfile)
  559     
  560     if not os.path.exists(PSEOutfile):
  561         MiscUtil.PrintWarning("Failed to generate PSE file, %s..." % (PSEOutfile))
  562     
  563     if not OptionsInfo["PMLOut"]:
  564         MiscUtil.PrintInfo("Deleting file %s..." % PMLOutfile)
  565         os.remove(PMLOutfile)
  566 
  567 def DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNames):
  568     """Delete empty PyMOL objects."""
  569     
  570     if OptionsInfo["AllowEmptyObjects"]:
  571         return
  572     
  573     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  574     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  575         OutFH.write("""\n""\n"Checking and deleting empty objects for chain %s..."\n""\n""" % (ChainID))
  576         
  577         # Delete any chain level objects...
  578         WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Solvent"])
  579         WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Inorganic"])
  580 
  581 def DeleteEmptyPyMOLInterfaceObjects(OutFH):
  582     """Delete empty PyMOL interface objects."""
  583     
  584     if OptionsInfo["AllowEmptyObjects"]:
  585         return
  586     
  587     InterfaceChainsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"]
  588     PyMOLInterfaceObjectNamesInfo = OptionsInfo["InfilesInfo"]["PyMOLInterfaceObjectNamesInfo"]
  589     
  590     if InterfaceChainsAndResiduesInfo is None:
  591         return
  592     
  593     for InterfaceID in InterfaceChainsAndResiduesInfo["InterfaceIDs"]:
  594         for InterfaceChainID in InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID]:
  595             ChainID = InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID][InterfaceChainID]
  596             FileIndex = InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID][InterfaceChainID]
  597             
  598             # Delete interface residue type objects...
  599             DeleteEmptyInterfaceChainResidueTypesObjects(OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, PyMOLInterfaceObjectNamesInfo)
  600             
  601 def DeleteEmptyInterfaceChainResidueTypesObjects(OutFH, FileIndex, InterfaceID, InterfaceChainID, ChainID, PyMOLObjectNames):
  602     """Delete empty interface chain residue objects."""
  603     
  604     if not GetInterfaceResidueTypesStatus(FileIndex, ChainID):
  605         return
  606     
  607     ResiduesGroupIDPrefix = "ChainResidues"
  608     for GroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
  609         GroupID = re.sub("_", "", GroupType)
  610         
  611         ResiduesGroupID = "%s%sGroup" % (ResiduesGroupIDPrefix, GroupID)
  612         GroupName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesGroupID]
  613         
  614         GroupObjectNamesList = []
  615         
  616         ResiduesObjectID = "%s%sResidues" % (ResiduesGroupIDPrefix, GroupID)
  617         ResiduesObjectName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesObjectID]
  618         GroupObjectNamesList.append(ResiduesObjectName)
  619         
  620         ResiduesSurfaceObjectID = "%s%sSurface" % (ResiduesGroupIDPrefix, GroupID)
  621         ResiduesSurfaceObjectName = PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSurfaceObjectID]
  622         GroupObjectNamesList.append(ResiduesSurfaceObjectName)
  623         
  624         GroupObjectNames = ",".join(GroupObjectNamesList)
  625         WritePMLToCheckAndDeleteEmptyObjects(OutFH, GroupObjectNames, GroupName)
  626     
  627 def WritePMLToCheckAndDeleteEmptyObjects(OutFH, ObjectName, ParentObjectName = None):
  628     """Write PML to check and delete empty PyMOL objects."""
  629     
  630     if ParentObjectName is None:
  631         PML = """CheckAndDeleteEmptyObjects("%s")""" % (ObjectName)
  632     else:
  633         PML = """CheckAndDeleteEmptyObjects("%s", "%s")""" % (ObjectName, ParentObjectName)
  634     
  635     OutFH.write("%s\n" % PML)
  636     
  637 def RetrieveInfilesInfo():
  638     """Retrieve information for input files."""
  639 
  640     InfilesInfo = {}
  641     
  642     InfilesInfo["InfilesNames"] = []
  643     InfilesInfo["InfilesRoots"] = []
  644     InfilesInfo["ChainsAndLigandsInfo"] = []
  645     InfilesInfo["SpecifiedChainsAndLigandsInfo"] = []
  646     
  647     InfilesInfo["PyMOLObjectNamesInfo"] = []
  648     
  649     InfilesInfo["SingleInfileMode"] = False
  650     InfilesInfo["InterfaceChainsAndResiduesInfo"] = None
  651     InfilesInfo["InterfaceChainPairsAndResiduesInfo"] = None
  652     
  653     InfilesInfo["PyMOLInterfaceObjectNamesInfo"] = None
  654 
  655     InfilesCount = 0
  656     for Infile in OptionsInfo["InfilesNames"]:
  657         InfilesCount += 1
  658         FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
  659         InfileRoot = FileName
  660         
  661         ChainsAndLigandInfo = PyMOLUtil.GetChainsAndLigandsInfo(Infile, InfileRoot)
  662         
  663         InfilesInfo["InfilesNames"].append(Infile)
  664         InfilesInfo["InfilesRoots"].append(InfileRoot)
  665         InfilesInfo["ChainsAndLigandsInfo"].append(ChainsAndLigandInfo)
  666 
  667     if InfilesCount > 2:
  668         MiscUtil.PrintError("Number of input files, %s, specified using \"-i, --infiles\" option is not valid. Number of allowed files: 1 or 2" % (InfilesCount))
  669     
  670     InfilesInfo["SingleInfileMode"] = True if InfilesCount == 1 else False
  671     
  672     OptionsInfo["InfilesInfo"] = InfilesInfo
  673 
  674 def ProcessInterfaceChainIDs():
  675     """Process specified interface chain IDs for input files."""
  676 
  677     ValidateInterfaceChainIDs()
  678 
  679     SetupChainsAndLigandsInfo()
  680     SetupPyMOLObjectNamesInfo()
  681     
  682     SetupInterfaceChainPairsAndResiduesInfo()
  683     ProcessInterfaceChainPairsAndResiduesInfo()
  684 
  685     SetupPyMOLInterfaceObjectNamesInfo()
  686 
  687 def ValidateInterfaceChainIDs():
  688     """Check for the presence of interface IDs in input file(s)."""
  689 
  690     if  re.match("^auto$", OptionsInfo["InterfaceChainIDs"], re.I):
  691         AutoAssignInterfaceChainIDs()
  692         SetupInfilesInterfaceChainIDsLists()
  693         return
  694 
  695     MiscUtil.PrintInfo("\nValidating interface chain IDs...")
  696     
  697     # Check for the presences of interface chain IDs across input files..
  698     SingleInfileMode = OptionsInfo["InfilesInfo"]["SingleInfileMode"]
  699     Infile1ChainIDs = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][0]["ChainIDs"]
  700     Infile2ChainIDs = []
  701     if not SingleInfileMode:
  702         Infile2ChainIDs = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][1]["ChainIDs"]
  703 
  704     InterfaceChainIDsList = OptionsInfo["InterfaceChainIDsList"]
  705 
  706     for Index in range(0, len(InterfaceChainIDsList), 2):
  707         ChainIDs1 = InterfaceChainIDsList[Index]
  708         ChainIDs2 = InterfaceChainIDsList[Index + 1]
  709 
  710         for ChainID in ChainIDs1:
  711             if not ChainID in Infile1ChainIDs:
  712                 MiscUtil.PrintError("The chain ID, %s, specified using \"-c, --chainIDs\" for a chain IDs pairs, \"%s,%s\", must be present in first input file." % (ChainID, "+".join(ChainIDs1), "+".join(ChainIDs2)))
  713         
  714         for ChainID in ChainIDs2:
  715             if  SingleInfileMode:
  716                 if not ChainID in Infile1ChainIDs:
  717                     MiscUtil.PrintError("The chain ID, %s, specified using \"-c, --chainIDs\" for a chain IDs pairs, \"%s,%s\", must be present in first input file." % (ChainID, "+".join(ChainIDs1), "+".join(ChainIDs2)))
  718             else:
  719                 if not ChainID in Infile2ChainIDs:
  720                     MiscUtil.PrintError("The chain ID, %s, specified using \"-c, --chainIDs\" for a chain IDs pairs, \"%s,%s\", must be present in second input file." % (ChainID, "+".join(ChainIDs1), "+".join(ChainIDs2)))
  721 
  722     # Check for any duplicate interface chain IDs specifications...
  723     CanonicalInterfaceIDsMap = {}
  724     
  725     for Index in range(0, len(InterfaceChainIDsList), 2):
  726         ChainIDs1 = InterfaceChainIDsList[Index]
  727         ChainIDs2 = InterfaceChainIDsList[Index + 1]
  728         InterfaceID = "%s,%s" % ("+".join(ChainIDs1), "+".join(ChainIDs2))
  729         
  730         SortedChainIDs1 = sorted(ChainIDs1)
  731         SortedChainIDs2 = sorted(ChainIDs2)
  732         CanonicalInterfaceID = "%s,%s" % ("+".join(SortedChainIDs1), "+".join(SortedChainIDs2))
  733 
  734         if CanonicalInterfaceID in CanonicalInterfaceIDsMap:
  735             MiscUtil.PrintError("The chain ID pair, \"%s\", using \"-c, --chainIDs\", option has been specified multiple times, \"%s\"." % (CanonicalInterfaceIDsMap[CanonicalInterfaceID], OptionsInfo["InterfaceChainIDs"]))
  736         else:
  737             CanonicalInterfaceIDsMap[CanonicalInterfaceID] =  InterfaceID
  738 
  739     SetupInfilesInterfaceChainIDsLists()
  740     
  741 def SetupInfilesInterfaceChainIDsLists():
  742     """Setup interface chain IDs list for infiles."""
  743     
  744     Infie1InterfaceChainIDsList = []
  745     Infie2InterfaceChainIDsList = []
  746     
  747     SingleInfileMode = OptionsInfo["InfilesInfo"]["SingleInfileMode"]
  748     InterfaceChainIDsList = OptionsInfo["InterfaceChainIDsList"]
  749     
  750     for Index in range(0, len(InterfaceChainIDsList), 2):
  751         ChainIDs1 = InterfaceChainIDsList[Index]
  752         ChainIDs2 = InterfaceChainIDsList[Index + 1]
  753 
  754         Infie1InterfaceChainIDsList.extend(ChainIDs1)
  755         if SingleInfileMode:
  756             Infie1InterfaceChainIDsList.extend(ChainIDs2)
  757         else:
  758             Infie2InterfaceChainIDsList.extend(ChainIDs2)
  759 
  760     Infie1InterfaceChainIDsList = sorted(Infie1InterfaceChainIDsList)
  761     Infie2InterfaceChainIDsList = sorted(Infie2InterfaceChainIDsList)
  762     
  763     OptionsInfo["InfilesInterfaceChainIDsList"] = [Infie1InterfaceChainIDsList, Infie2InterfaceChainIDsList]
  764 
  765 def AutoAssignInterfaceChainIDs():
  766     """Handle automatic assignment of interface chain IDs."""
  767     
  768     Infile1ChainIDs = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][0]["ChainIDs"]
  769     Infile2ChainIDs = []
  770     if not OptionsInfo["InfilesInfo"]["SingleInfileMode"]:
  771         Infile2ChainIDs = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][1]["ChainIDs"]
  772     
  773     InterfaceChainIDsList = []
  774     if OptionsInfo["InfilesInfo"]["SingleInfileMode"]:
  775         # Take first two chains from first input file...
  776         if len(Infile1ChainIDs) < 2:
  777             MiscUtil.PrintError("Failed to automatically set interface chain IDs. Number of chains, %s, in input file specified using \"-i, --infiles\" option must be >= 2. " % (len(Infile1ChainIDs)))
  778         InterfaceChainIDsList.append([Infile1ChainIDs[0]])
  779         InterfaceChainIDsList.append([Infile1ChainIDs[1]])
  780     else:
  781         # Take first chain from each input file...
  782         if len(Infile1ChainIDs) < 1:
  783             MiscUtil.PrintError("Failed to automatically set interface chain IDs. Number of chains, %s, in first input file specified using \"-i, --infiles\" option must be >= 1. " % (len(Infile1ChainIDs)))
  784         if len(Infile2ChainIDs) < 1:
  785             MiscUtil.PrintError("Failed to automatically set interface chain IDs. Number of chains, %s, in second input file specified using \"-i, --infiles\" option must be >= 1. " % (len(Infile1ChainIDs)))
  786         InterfaceChainIDsList.append([Infile1ChainIDs[0]])
  787         InterfaceChainIDsList.append([Infile2ChainIDs[1]])
  788     
  789     OptionsInfo["InterfaceChainIDsList"] = []
  790     OptionsInfo["InterfaceChainIDsList"].extend(InterfaceChainIDsList)
  791     
  792     return
  793 
  794 def SetupChainsAndLigandsInfo():
  795     """Setup chains and ligands info for input files to visualize macromolecules."""
  796 
  797     OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"] = []
  798     for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
  799         Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
  800         MiscUtil.PrintInfo("\nSetting up chain and ligand information for input file %s..." % Infile)
  801         
  802         ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
  803         InfilesInterfaceChainIDsList = OptionsInfo["InfilesInterfaceChainIDsList"][FileIndex]
  804         
  805         SpecifiedChainsAndLigandsInfo = {}
  806         SpecifiedChainsAndLigandsInfo["ChainIDs"] = []
  807         SpecifiedChainsAndLigandsInfo["InterfaceResNums"] = {}
  808         SpecifiedChainsAndLigandsInfo["LigandIDs"] = {}
  809 
  810         if len(InfilesInterfaceChainIDsList):
  811             # Add unique interface IDs to the chain IDs list for visualization. Interface chain IDs
  812             # may contain duplicate chain IDs due to the presence # of same chain in multiple
  813             # interfaces.
  814             for ChainID in InfilesInterfaceChainIDsList:
  815                 if not ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  816                     SpecifiedChainsAndLigandsInfo["ChainIDs"].append(ChainID)
  817 
  818             for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  819                 # Initialize interface residue numbers to be assigned later...
  820                 SpecifiedChainsAndLigandsInfo["InterfaceResNums"][ChainID] = []
  821                 
  822                 # Setup ligand IDs...
  823                 SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID] = SetupSpecifiedLigandIDs(FileIndex, ChainID, ChainsAndLigandsInfo)
  824         
  825         ProcessResidueTypesAndSurfaceOptions(FileIndex, SpecifiedChainsAndLigandsInfo)
  826         
  827         OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"].append(SpecifiedChainsAndLigandsInfo)
  828 
  829 def SetupSpecifiedLigandIDs(FileIndex, ChainID, ChainsAndLigandsInfo):
  830     """Setup specified ligand IDs for input file."""
  831 
  832     LigandIDs = []
  833     
  834     if re.match("^All$", OptionsInfo["LigandIDs"], re.I):
  835         LigandIDs = ChainsAndLigandsInfo["LigandIDs"][ChainID]
  836         return LigandIDs
  837     elif re.match("^Largest|Auto$", OptionsInfo["LigandIDs"], re.I):
  838         LargestLigandID = ChainsAndLigandsInfo["LigandIDs"][ChainID][0] if (len(ChainsAndLigandsInfo["LigandIDs"][ChainID])) else None
  839         if LargestLigandID is not None:
  840             LigandIDs.append(LargestLigandID)
  841         return LigandIDs
  842     elif re.match("^None$", OptionsInfo["LigandIDs"], re.I):
  843         return LigandIDs
  844 
  845     Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
  846     ValidLigandIDs = ChainsAndLigandsInfo["LigandIDs"][ChainID]
  847     
  848     SpecifiedLigandIDs = re.sub(" ", "", OptionsInfo["LigandIDs"])
  849     if not SpecifiedLigandIDs:
  850         MiscUtil.PrintError("No valid value specified using \-l, --ligandIDs\" option.")
  851 
  852     LigandIDsWords = SpecifiedLigandIDs.split(",")
  853     for LigandID in LigandIDsWords:
  854         if not LigandID in ValidLigandIDs:
  855             LigandIDsListNames = ",".join(ValidLigandIDs) if len(ValidLigandIDs) else "None"
  856             MiscUtil.PrintWarning("The ligand ID, %s, specified using \"-l, --ligandiIDs\" option is not valid for chain, %s, in input file, %s. It'll be ignored. Valid ligand IDs: %s" % (LigandID, ChainID, Infile, LigandIDsListNames))
  857             continue
  858         
  859         if LigandID in LigandIDs:
  860             MiscUtil.PrintWarning("The ligand ID, %s, has already been specified using \"-l, --ligandIDs\" option for chain, %s, in input file, %s. It'll be ignored." % (LigandID, ChainID, Infile))
  861             continue
  862     
  863         LigandIDs.append(LigandID)
  864     
  865     if not len(LigandIDs):
  866             MiscUtil.PrintWarning("No valid ligand IDs \"%s\" specified using \"-l, --ligandIDs\" option for chain ID, %s, in input file, %s." % (OptionsInfo["LigandIDs"], ChainID, Infile))
  867     
  868     return LigandIDs
  869         
  870 def SetupInterfaceChainPairsAndResiduesInfo():
  871     """Setup chain and residue pairs corresponding to interfaces."""
  872 
  873     MiscUtil.PrintInfo("\nIdentifying interface residues...")
  874     
  875     SingleInfileMode = OptionsInfo["InfilesInfo"]["SingleInfileMode"]
  876     InterfaceChainIDsList = OptionsInfo["InterfaceChainIDsList"]
  877 
  878     if not len(InterfaceChainIDsList):
  879         MiscUtil.PrintError("Failed to identify interface residues: No valid chain ID pairs available for interfaces")
  880 
  881     # Load infiles to identify interface residues...
  882     Infile1 = OptionsInfo["InfilesInfo"]["InfilesNames"][0]
  883     MolName1 = OptionsInfo["InfilesInfo"]["InfilesRoots"][0]
  884     pymol.cmd.load(Infile1, MolName1)
  885     if SingleInfileMode:
  886         MolName2 = MolName1
  887     else:
  888         Infile2 = OptionsInfo["InfilesInfo"]["InfilesNames"][1]
  889         MolName2 = OptionsInfo["InfilesInfo"]["InfilesRoots"][1]
  890         pymol.cmd.load(Infile2, MolName2)
  891 
  892     # Initialize data...
  893     InterfaceChainPairsAndResiduesInfo = {}
  894     InterfaceChainPairsAndResiduesInfo["InterfaceIDs"] = []
  895     InterfaceChainPairsAndResiduesInfo["ChainIDsPairs"] = {}
  896     InterfaceChainPairsAndResiduesInfo["ChainIDsResNumsPairs"] = {}
  897     InterfaceChainPairsAndResiduesInfo["InfileIndicesPairs"] = {}
  898     
  899     Method = OptionsInfo["Method"]
  900     MethodCutoff = OptionsInfo["MethodCutoff"]
  901     MiscUtil.PrintInfo("Methodology: %s; Cutoff: %.2f" % (Method, MethodCutoff))
  902 
  903     for Index in range(0, len(InterfaceChainIDsList), 2):
  904         ChainIDs1 = sorted(InterfaceChainIDsList[Index])
  905         ChainIDs2 = sorted(InterfaceChainIDsList[Index + 1])
  906 
  907         ChainIDs1Prefix = "Chains" if len(ChainIDs1) > 1 else "Chain"
  908         ChainIDs2Prefix = "Chains" if len(ChainIDs2) > 1 else "Chain"
  909         InterfaceID = "%s%s_%s%s" % (ChainIDs1Prefix, "+".join(ChainIDs1), ChainIDs2Prefix, "+".join(ChainIDs2))
  910         
  911         ListInterfaceID = "%s_%s" % ("+".join(ChainIDs1), "+".join(ChainIDs2))
  912 
  913         FileIndex1 = 0
  914         FileIndex2 = 0 if SingleInfileMode else 1
  915 
  916         if InterfaceID in InterfaceChainPairsAndResiduesInfo["InterfaceIDs"]:
  917             MiscUtil.PrintInfo("Ignoring interface ID %s: It has already been defined" % InterfaceID)
  918             continue
  919 
  920         # Identify and list interface chains and residues...
  921         ChainsAndResiduesInfo1, ChainsAndResiduesInfo2 = GetInterfaceChainsAndResiduesInfo(MolName1, ChainIDs1, MolName2, ChainIDs2, Method, MethodCutoff)
  922         ListInterfaceChainsAndResidues(ListInterfaceID, MolName1, ChainIDs1, ChainsAndResiduesInfo1, MolName2, ChainIDs2, ChainsAndResiduesInfo2)
  923 
  924         # Check presence of interface residues...
  925         if (not (len(ChainsAndResiduesInfo1["ChainIDs"]) and len(ChainsAndResiduesInfo2["ChainIDs"]))):
  926             MiscUtil.PrintWarning("Ignoring interface ID %s: Failed to identify any interface residues. PyMOL groups and objects won't be created." % InterfaceID)
  927             continue
  928         
  929         # Collect residue numbers for set of interface residues in each chain...
  930         InterfaceChainIDs1, InterfaceChainResidueNums1 = GetInterfaceChainsAndResidueNumbers(ChainIDs1, ChainsAndResiduesInfo1)
  931         InterfaceChainIDs2, InterfaceChainResidueNums2 = GetInterfaceChainsAndResidueNumbers(ChainIDs2, ChainsAndResiduesInfo2)
  932 
  933         InterfaceChainPairsAndResiduesInfo["InterfaceIDs"].append(InterfaceID)
  934         InterfaceChainPairsAndResiduesInfo["ChainIDsPairs"][InterfaceID] = [InterfaceChainIDs1, InterfaceChainIDs2]
  935         InterfaceChainPairsAndResiduesInfo["ChainIDsResNumsPairs"][InterfaceID] = [InterfaceChainResidueNums1, InterfaceChainResidueNums2]
  936         InterfaceChainPairsAndResiduesInfo["InfileIndicesPairs"][InterfaceID] = [FileIndex1, FileIndex2]
  937 
  938     InterfaceChainPairsAndResiduesInfo["InterfaceIDs"] = sorted(InterfaceChainPairsAndResiduesInfo["InterfaceIDs"])
  939     OptionsInfo["InfilesInfo"]["InterfaceChainPairsAndResiduesInfo"] = InterfaceChainPairsAndResiduesInfo
  940 
  941     # Delete loaded objects...
  942     pymol.cmd.delete(MolName1)
  943     if not SingleInfileMode:
  944         pymol.cmd.delete(MolName2)
  945     
  946 def ProcessInterfaceChainPairsAndResiduesInfo():
  947     """Process chain and residue pairs for visualizing interfaces."""
  948 
  949     InterfaceChainsAndResiduesInfo = {}
  950     InterfaceChainsAndResiduesInfo["InterfaceIDs"] = []
  951     InterfaceChainsAndResiduesInfo["InterfaceChainIDs"] = {}
  952     InterfaceChainsAndResiduesInfo["ChainIDs"] = {}
  953     InterfaceChainsAndResiduesInfo["ChainIDsResNums"] = {}
  954     InterfaceChainsAndResiduesInfo["ChainIDsComplexNames"] = {}
  955     InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"] = {}
  956     
  957     InterfaceChainPairsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainPairsAndResiduesInfo"]
  958     
  959     for InterfaceID in InterfaceChainPairsAndResiduesInfo["InterfaceIDs"]:
  960         # Flatten pairwise interface chain and residues info...
  961         FlattenedInterfaceChainIDs, FlattenedChainIDs, FlattenedResNums, FlattenedComplexNames, FlattenedInfileIndices = FlattenIntferfaceChainPairsAndResiduesInfo(InterfaceChainPairsAndResiduesInfo, InterfaceID)
  962         
  963         if not InterfaceID in InterfaceChainsAndResiduesInfo["InterfaceIDs"]:
  964             InterfaceChainsAndResiduesInfo["InterfaceIDs"].append(InterfaceID)
  965             
  966             InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID] = []
  967             InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID] = {}
  968             InterfaceChainsAndResiduesInfo["ChainIDsResNums"][InterfaceID] = {}
  969             InterfaceChainsAndResiduesInfo["ChainIDsComplexNames"][InterfaceID] = {}
  970             InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID] = {}
  971 
  972         # Track interface information for visualization...
  973         for Index in range(0, len(FlattenedInterfaceChainIDs)):
  974             InterfaceChainID = FlattenedInterfaceChainIDs[Index]
  975             ChainID = FlattenedChainIDs[Index]
  976             ResNums = FlattenedResNums[Index]
  977             ComplexName = FlattenedComplexNames[Index]
  978             FileIndex = FlattenedInfileIndices[Index]
  979 
  980             if not len(ResNums):
  981                 continue
  982 
  983             InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID].append(InterfaceChainID)
  984             InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID][InterfaceChainID] = ChainID
  985             InterfaceChainsAndResiduesInfo["ChainIDsResNums"][InterfaceID][InterfaceChainID] = ResNums
  986             InterfaceChainsAndResiduesInfo["ChainIDsComplexNames"][InterfaceID][InterfaceChainID] = ComplexName
  987             InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID][InterfaceChainID] = FileIndex
  988 
  989             OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["InterfaceResNums"][ChainID].extend(ResNums)
  990 
  991     OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"] = InterfaceChainsAndResiduesInfo
  992 
  993 def FlattenIntferfaceChainPairsAndResiduesInfo(InterfaceChainPairsAndResiduesInfo, InterfaceID):
  994     """Flatten interface chain and residues info."""
  995 
  996     SingleInfileMode = OptionsInfo["InfilesInfo"]["SingleInfileMode"]
  997     
  998     ChainIDs1, ChainIDs2 =  InterfaceChainPairsAndResiduesInfo["ChainIDsPairs"][InterfaceID]
  999     ResNums1, ResNums2 = InterfaceChainPairsAndResiduesInfo["ChainIDsResNumsPairs"][InterfaceID]
 1000     FileIndex1, FileIndex2 = InterfaceChainPairsAndResiduesInfo["InfileIndicesPairs"][InterfaceID]
 1001 
 1002     # Set complex names..
 1003     PDBGroup1 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex1]["PDBGroup"]
 1004     ComplexName1 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex1]["Complex"]
 1005     
 1006     PDBGroup2 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex2]["PDBGroup"]
 1007     ComplexName2 = OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"][FileIndex2]["Complex"]
 1008     
 1009     ChainIDs = []
 1010     InterfaceChainIDs = []
 1011     ResNums = []
 1012     ComplexNames = []
 1013     FileIndices = []
 1014     
 1015     for ChainID in ChainIDs1:
 1016         ChainIDs.append(ChainID)
 1017         InterfaceChainID = ("Chain%s" % ChainID) if SingleInfileMode else ("Chain%s_%s" % (ChainID, PDBGroup1))
 1018         InterfaceChainIDs.append(InterfaceChainID)
 1019         ResNums.append(ResNums1["ResNums"][ChainID])
 1020         ComplexNames.append(ComplexName1)
 1021         FileIndices.append(FileIndex1)
 1022     
 1023     for ChainID in ChainIDs2:
 1024         ChainIDs.append(ChainID)
 1025         InterfaceChainID = ("Chain%s" % ChainID) if SingleInfileMode else ("Chain%s_%s" % (ChainID, PDBGroup2))
 1026         InterfaceChainIDs.append(InterfaceChainID)
 1027         ResNums.append(ResNums2["ResNums"][ChainID])
 1028         ComplexNames.append(ComplexName2)
 1029         FileIndices.append(FileIndex2)
 1030 
 1031     return InterfaceChainIDs, ChainIDs, ResNums, ComplexNames, FileIndices
 1032     
 1033 def GetInterfaceChainsAndResiduesInfo(MolName1, ChainIDs1, MolName2, ChainIDs2, Method, Cutoff):
 1034     """Get interface chains and residues info for chains using a specified methodology."""
 1035 
 1036     InterfaceChainsResiduesInfo1 = None
 1037     InterfaceChainsResiduesInfo2 = None
 1038 
 1039     ChainNames1 = ",".join(ChainIDs1)
 1040     ChainNames2 = ",".join(ChainIDs2)
 1041     
 1042     if re.match("^BySASAChange$", Method, re.I):
 1043         InterfaceChainsResiduesInfo1, InterfaceChainsResiduesInfo2 = PyMOLUtil.GetInterfaceChainsResiduesBySASAChange(MolName1, ChainNames1, MolName2, ChainNames2, Cutoff)
 1044     elif re.match("^ByHeavyAtomsDistance$", Method, re.I):
 1045         InterfaceChainsResiduesInfo1, InterfaceChainsResiduesInfo2 = PyMOLUtil.GetInterfaceChainsResiduesByHeavyAtomsDistance(MolName1, ChainNames1, MolName2, ChainNames2, Cutoff)
 1046     elif re.match("^ByCAlphaAtomsDistance$", Method, re.I):
 1047         InterfaceChainsResiduesInfo1, InterfaceChainsResiduesInfo2 = PyMOLUtil.GetInterfaceChainsResiduesByCAlphaAtomsDistance(MolName1, ChainNames1, MolName2, ChainNames2, Cutoff)
 1048     else:
 1049         MiscUtil.PrintError("Failed to retrieve interface residues information: Method %s is not valid..." % Method)
 1050 
 1051     return InterfaceChainsResiduesInfo1, InterfaceChainsResiduesInfo2
 1052 
 1053 def ListInterfaceChainsAndResidues(InterfaceID, MolName1, ChainIDs1, ChainsAndResiduesInfo1, MolName2, ChainIDs2, ChainsAndResiduesInfo2):
 1054     """List interface chains and residues for an interface."""
 1055     
 1056     ChainNames1, ResiduesInfo1 = PrepareInterfaceChainsAndResiduesInfo(ChainsAndResiduesInfo1)
 1057     ChainNames2, ResiduesInfo2 = PrepareInterfaceChainsAndResiduesInfo(ChainsAndResiduesInfo2)
 1058     
 1059     if len(ChainNames1) and len(ChainNames2):
 1060         MiscUtil.PrintInfo("\nListing interface residues for interface chain IDs: %s" % (InterfaceID))
 1061         
 1062         ListInterfaceChainsAndResiduesInfo(InterfaceID,  MolName1, ChainIDs1, ChainNames1, ResiduesInfo1)
 1063         ListInterfaceChainsAndResiduesInfo(InterfaceID,  MolName2, ChainIDs2, ChainNames2, ResiduesInfo2)
 1064     else:
 1065         MiscUtil.PrintInfo("\nListing interface residues for interface chain IDs: %s" % (InterfaceID))
 1066         MiscUtil.PrintInfo("Interface chain IDs: None; ChainID: None; Number of interface residues: 0")
 1067 
 1068 def PrepareInterfaceChainsAndResiduesInfo(ChainsAndResiduesInfo):
 1069     """Prepare interface chains and residues info for listing."""
 1070 
 1071     ChainNames = []
 1072     ResiduesInfo = []
 1073 
 1074     for ChainID in ChainsAndResiduesInfo["ChainIDs"]:
 1075         ChainNames.append(ChainID)
 1076         
 1077         # Setup distribution of residues...
 1078         LineWords = []
 1079         ResiduesCount = 0
 1080         SortedResNames = sorted(ChainsAndResiduesInfo["ResNames"][ChainID], key = lambda ResName: ChainsAndResiduesInfo["ResCount"][ChainID][ResName], reverse = True)
 1081         for ResName in SortedResNames:
 1082             ResCount = ChainsAndResiduesInfo["ResCount"][ChainID][ResName]
 1083             LineWords.append("%s - %s" % (ResName, ResCount))
 1084             ResiduesCount += ResCount
 1085         
 1086         ResiduesDistribution = "; ".join(LineWords) if len(LineWords) else None
 1087         
 1088         # Setup residue IDs sorted by residue numbers...
 1089         ResNumMap = {}
 1090         for ResName in ChainsAndResiduesInfo["ResNames"][ChainID]:
 1091             for ResNum in ChainsAndResiduesInfo["ResNum"][ChainID][ResName]:
 1092                 ResNumMap[ResNum] = ResName
 1093         
 1094         LineWords = []
 1095         for ResNum in sorted(ResNumMap, key = int):
 1096             ResName = ResNumMap[ResNum]
 1097             ResID = "%s_%s" % (ResName, ResNum)
 1098             LineWords.append(ResID)
 1099         ResiduesIDs = ", ".join(LineWords) if len(LineWords) else None
 1100 
 1101         ResiduesInfo.append([ResiduesCount, ResiduesDistribution, ResiduesIDs])
 1102                 
 1103     return ChainNames, ResiduesInfo
 1104 
 1105 def ListInterfaceChainsAndResiduesInfo(InterfaceID, MolName, InterfaceChainIDs, ChainNames, ResiduesInfo):
 1106     """List interface chains and residues."""
 1107 
 1108     for ChainID in InterfaceChainIDs:
 1109         if not ChainID in ChainNames:
 1110             MiscUtil.PrintWarning("Interface chain IDs: %s; MoleculeID: %s; ChainID: %s; Number of interface residues: 0. PyMOL groups and objects related to chain won't be created." % (InterfaceID, MolName, ChainID))
 1111             continue
 1112         
 1113         for Index in range(0, len(ChainNames)):
 1114             ChainName = ChainNames[Index]
 1115             ChainResiduesInfo = ResiduesInfo[Index]
 1116             if re.match(ChainID, ChainName, re.I):
 1117                 MiscUtil.PrintInfo("\nInterface chain IDs: %s; MoleculeID: %s; ChainID: %s; Number of interface residues: %d" % (InterfaceID, MolName, ChainName, ChainResiduesInfo[0]))
 1118                 MiscUtil.PrintInfo("Residue distribution: %s\nResidue IDs: %s" % (ChainResiduesInfo[1], ChainResiduesInfo[2]))
 1119                 continue
 1120 
 1121 def GetInterfaceChainsAndResidueNumbers(ChainIDs, ChainsAndResiduesInfo):
 1122     """Collect interface residue numbers for chains."""
 1123 
 1124     ChainResidueNums = {}
 1125     ChainResidueNums["ChainIDs"] = []
 1126     ChainResidueNums["ResNums"] = {}
 1127     
 1128     for ChainID in ChainIDs:
 1129         if not ChainID in ChainsAndResiduesInfo["ChainIDs"]:
 1130             continue
 1131         
 1132         ChainResidueNums["ChainIDs"].append(ChainID)
 1133         ChainResidueNums["ResNums"][ChainID] = []
 1134 
 1135         ResNums = []
 1136         for ResName in ChainsAndResiduesInfo["ResNames"][ChainID]:
 1137             ResNums.extend(ChainsAndResiduesInfo["ResNum"][ChainID][ResName])
 1138         
 1139         ChainResidueNums["ResNums"][ChainID] = sorted(ResNums, key = int)
 1140 
 1141     InterfaceChainIDs = ChainResidueNums["ChainIDs"]
 1142     
 1143     return InterfaceChainIDs, ChainResidueNums
 1144 
 1145 def SetupPyMOLObjectNamesInfo():
 1146     """Setup PyMOL object names for displaying macromolecules."""
 1147 
 1148     OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"] = []
 1149     
 1150     for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
 1151         PyMOLObjectNamesInfo = SetupPyMOLObjectNames(FileIndex)
 1152         OptionsInfo["InfilesInfo"]["PyMOLObjectNamesInfo"].append(PyMOLObjectNamesInfo)
 1153     
 1154 def SetupPyMOLObjectNames(FileIndex):
 1155     """Setup hierarchy of PyMOL groups and objects for ligand centric views of
 1156     chains and ligands present in input file.
 1157     """
 1158 
 1159     PyMOLObjectNames = {}
 1160     PyMOLObjectNames["Chains"] = {}
 1161     PyMOLObjectNames["Ligands"] = {}
 1162 
 1163     # Setup groups and objects for complex...
 1164     SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames)
 1165     
 1166     # Setup groups and objects for chain...
 1167     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
 1168     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
 1169         SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID)
 1170         
 1171         # Setup groups and objects for ligand...
 1172         for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
 1173             SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID)
 1174 
 1175     return PyMOLObjectNames
 1176 
 1177 def SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames):
 1178     """Setup groups and objects for complex."""
 1179     
 1180     PDBFileRoot = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
 1181     
 1182     PDBGroupName = "%s" % PDBFileRoot
 1183     PyMOLObjectNames["PDBGroup"] = PDBGroupName
 1184     PyMOLObjectNames["PDBGroupMembers"] = []
 1185 
 1186     ComplexGroupName = "%s.Complex" % PyMOLObjectNames["PDBGroup"]
 1187     PyMOLObjectNames["ComplexGroup"] = ComplexGroupName
 1188     PyMOLObjectNames["PDBGroupMembers"].append(ComplexGroupName)
 1189     
 1190     PyMOLObjectNames["Complex"] = "%s.Complex" % ComplexGroupName
 1191     if OptionsInfo["SurfaceComplex"]:
 1192         PyMOLObjectNames["ComplexHydrophobicSurface"] = "%s.Surface" % ComplexGroupName
 1193 
 1194     PyMOLObjectNames["ComplexGroupMembers"] = []
 1195     PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["Complex"])
 1196     if OptionsInfo["SurfaceComplex"]:
 1197         PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["ComplexHydrophobicSurface"])
 1198 
 1199 def SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID):
 1200     """Setup groups and objects for chain."""
 1201 
 1202     PDBGroupName = PyMOLObjectNames["PDBGroup"]
 1203     
 1204     PyMOLObjectNames["Chains"][ChainID] = {}
 1205     PyMOLObjectNames["Ligands"][ChainID] = {}
 1206     
 1207     # Set up chain group and chain objects...
 1208     ChainGroupName = "%s.Chain%s" % (PDBGroupName, ChainID)
 1209     PyMOLObjectNames["Chains"][ChainID]["ChainGroup"] = ChainGroupName
 1210     PyMOLObjectNames["PDBGroupMembers"].append(ChainGroupName)
 1211     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"] = []
 1212     
 1213     # Setup chain complex group and objects...
 1214     ChainComplexGroupName = "%s.Complex" % (ChainGroupName)
 1215     PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"] = ChainComplexGroupName
 1216     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainComplexGroupName)
 1217 
 1218     PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"] = []
 1219     
 1220     Name = "%s.Complex" % (ChainComplexGroupName)
 1221     PyMOLObjectNames["Chains"][ChainID]["ChainComplex"] = Name
 1222     PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"].append(Name)
 1223     
 1224     if OptionsInfo["SurfaceChainComplex"]:
 1225         Name = "%s.Surface" % (ChainComplexGroupName)
 1226         PyMOLObjectNames["Chains"][ChainID]["ChainComplexHydrophobicSurface"] = Name
 1227         PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"].append(Name)
 1228 
 1229     # Setup up a group for individual chains...
 1230     ChainAloneGroupName = "%s.Chain" % (ChainGroupName)
 1231     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"] = ChainAloneGroupName
 1232     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainAloneGroupName)
 1233         
 1234     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"] = []
 1235         
 1236     Name = "%s.Chain" % (ChainAloneGroupName)
 1237     PyMOLObjectNames["Chains"][ChainID]["ChainAlone"] = Name
 1238     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(Name)
 1239 
 1240     # Setup a group for non-interface residues...
 1241     NonInterfaceGroupName = "%s.NonInterface" % (ChainAloneGroupName)
 1242     PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroup"] = NonInterfaceGroupName
 1243     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(NonInterfaceGroupName)
 1244     
 1245     PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroupMembers"] = []
 1246 
 1247     # Setup a chain for non-interface residues...
 1248     Name = "%s.Chain" % (NonInterfaceGroupName)
 1249     PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterface"] = Name
 1250     PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroupMembers"].append(Name)
 1251 
 1252     if GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
 1253         # Setup a surface group and add it to chain alone non-interface group...
 1254         SurfaceGroupName = "%s.Surface" % (NonInterfaceGroupName)
 1255         PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroup"] = SurfaceGroupName
 1256         PyMOLObjectNames["Chains"][ChainID]["ChainAloneNonInterfaceGroupMembers"].append(SurfaceGroupName)
 1257         
 1258         PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"] = []
 1259 
 1260         # Setup a generic colored surface...
 1261         Name = "%s.Surface" % (SurfaceGroupName)
 1262         PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurface"] = Name
 1263         PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"].append(Name)
 1264         
 1265         if GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
 1266             # Setup hydrophobicity surface...
 1267             Name = "%s.Hydrophobicity" % (SurfaceGroupName)
 1268             PyMOLObjectNames["Chains"][ChainID]["ChainAloneHydrophobicSurface"] = Name
 1269             PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"].append(Name)
 1270             
 1271             # Setup hydrophobicity and charge surface...
 1272             Name = "%s.Hydrophobicity_Charge" % (SurfaceGroupName)
 1273             PyMOLObjectNames["Chains"][ChainID]["ChainAloneHydrophobicChargeSurface"] = Name
 1274             PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"].append(Name)
 1275     
 1276         if GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
 1277             # Setup electrostatics group...
 1278             GroupName = "%s.Vacuum_Electrostatics" % (SurfaceGroupName)
 1279             PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroup"] = GroupName
 1280             PyMOLObjectNames["Chains"][ChainID]["ChainAloneSurfaceGroupMembers"].append(GroupName)
 1281             
 1282             # Setup electrostatics group members...
 1283             PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroupMembers"] = []
 1284             
 1285             for MemberType in ["Chain", "Contact_Potential", "Map", "Legend", "Volume"]:
 1286                 MemberID = re.sub("_", "", MemberType)
 1287                 
 1288                 Name = "%s.%s" % (GroupName, MemberType)
 1289                 NameID = "ChainAloneElectrostaticsSurface%s" % MemberID
 1290                 
 1291                 PyMOLObjectNames["Chains"][ChainID][NameID] = Name
 1292                 PyMOLObjectNames["Chains"][ChainID]["ChainAloneElectrostaticsGroupMembers"].append(Name)
 1293             
 1294     # Setup solvent and inorganic objects for chain...
 1295     for NameID in ["Solvent", "Inorganic"]:
 1296         Name = "%s.%s" % (ChainGroupName, NameID)
 1297         PyMOLObjectNames["Chains"][ChainID][NameID] = Name
 1298         PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(Name)
 1299 
 1300 def SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID):
 1301     """Stetup groups and objects for ligand."""
 1302 
 1303     PyMOLObjectNames["Ligands"][ChainID][LigandID] = {}
 1304     
 1305     ChainGroupName = PyMOLObjectNames["Chains"][ChainID]["ChainGroup"]
 1306     
 1307     # Setup a chain level ligand group...
 1308     ChainLigandGroupName = "%s.Ligand%s" % (ChainGroupName, LigandID)
 1309     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroup"] = ChainLigandGroupName
 1310     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainLigandGroupName)
 1311     
 1312     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"] = []
 1313 
 1314     # Set up ligand group and its members...
 1315     GroupName = "%s.Ligand" % (ChainLigandGroupName)
 1316     GroupNameID = "LigandGroup"
 1317     GroupMembersID = "LigandGroupMembers"
 1318     
 1319     PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID] = GroupName
 1320     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"].append(GroupName)
 1321     
 1322     LigandName = "%s.Ligand" % (GroupName)
 1323     LigandNameID = "Ligand"
 1324     PyMOLObjectNames["Ligands"][ChainID][LigandID][LigandNameID] = LigandName
 1325     
 1326     PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID] = []
 1327     PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(LigandName)
 1328     
 1329     # Add ball and stick...
 1330     BallAndStickName = "%s.BallAndStick" % (GroupName)
 1331     BallAndStickID = "LigandBallAndStick"
 1332     PyMOLObjectNames["Ligands"][ChainID][LigandID][BallAndStickID] = BallAndStickName
 1333     PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(BallAndStickName)
 1334 
 1335 def SetupPyMOLInterfaceObjectNamesInfo():
 1336     """Setup PyMOL object names for displaying macromolecular interfaces."""
 1337 
 1338     InterfaceChainsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"]
 1339     
 1340     PyMOLObjectNames = {}
 1341     PyMOLObjectNames["InterfaceIDs"] = {}
 1342     PyMOLObjectNames["InterfaceChainIDs"] = {}
 1343 
 1344     # Setup top level interfaces group...
 1345     InterfacesGroupName = "Interfaces"
 1346     PyMOLObjectNames["InterfacesGroup"] = InterfacesGroupName
 1347     PyMOLObjectNames["InterfacesGroupMembers"] = []
 1348 
 1349     for InterfaceID in InterfaceChainsAndResiduesInfo["InterfaceIDs"]:
 1350         PyMOLObjectNames["InterfaceIDs"][InterfaceID] = {}
 1351         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID] = {}
 1352         
 1353         # Setup an interface group...
 1354         InterfaceIDGroupName = "%s.%s" % (InterfacesGroupName, InterfaceID)
 1355         PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroup"] = InterfaceIDGroupName
 1356         PyMOLObjectNames["InterfacesGroupMembers"].append(InterfaceIDGroupName)
 1357         PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"] = []
 1358 
 1359         # Setup a polar contact group...
 1360         if OptionsInfo["InterfacePolarContacts"]:
 1361             PolarContactName = "%s.Polar_Contacts" % (InterfaceIDGroupName)
 1362             PyMOLObjectNames["InterfaceIDs"][InterfaceID]["PolarContacts"] = PolarContactName
 1363             PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"].append(PolarContactName)
 1364         
 1365         # Setup a hydrophobic contact group...
 1366         if OptionsInfo["InterfaceHydrophobicContacts"]:
 1367             HydrophobicContactsName = "%s.Hydrophobic_Contacts" % (InterfaceIDGroupName)
 1368             PyMOLObjectNames["InterfaceIDs"][InterfaceID]["HydrophobicContacts"] = HydrophobicContactsName
 1369             PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"].append(HydrophobicContactsName)
 1370         
 1371         for InterfaceChainID in InterfaceChainsAndResiduesInfo["InterfaceChainIDs"][InterfaceID]:
 1372             SetupPyMOLInterfaceObjectNamesForChain(PyMOLObjectNames, InterfaceID, InterfaceChainID)
 1373             
 1374     OptionsInfo["InfilesInfo"]["PyMOLInterfaceObjectNamesInfo"] = PyMOLObjectNames
 1375 
 1376 def SetupPyMOLInterfaceObjectNamesForChain(PyMOLObjectNames, InterfaceID, InterfaceChainID):
 1377     """Setup PyMOL interface object names for a chain."""
 1378     
 1379     InterfaceChainsAndResiduesInfo = OptionsInfo["InfilesInfo"]["InterfaceChainsAndResiduesInfo"]
 1380     FileIndex = InterfaceChainsAndResiduesInfo["ChainIDsInfileIndices"][InterfaceID][InterfaceChainID]
 1381     ChainID = InterfaceChainsAndResiduesInfo["ChainIDs"][InterfaceID][InterfaceChainID]
 1382     
 1383     InterfaceIDGroupName = PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroup"]
 1384     
 1385     PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID] = {}
 1386     
 1387     # Setup a chain group...
 1388     ChainGroupName = "%s.%s" % (InterfaceIDGroupName, InterfaceChainID)
 1389     PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroup"] = ChainGroupName
 1390     PyMOLObjectNames["InterfaceIDs"][InterfaceID]["InterfaceIDGroupMembers"].append(ChainGroupName)
 1391     PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"] = []
 1392     
 1393     # Setup chain...
 1394     Name = "%s.Chain" % (ChainGroupName)
 1395     PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["Chain"] = Name
 1396     PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"].append(Name)
 1397     
 1398     if GetInterfaceResidueTypesStatus(FileIndex, ChainID):
 1399         # Setup residue type group and its subgroups...
 1400         ResiduesGroupName = "%s.Residues" % (ChainGroupName)
 1401         
 1402         ResiduesGroupIDPrefix = "ChainResidues"
 1403         ResiduesGroupID = "%sGroup" % ResiduesGroupIDPrefix
 1404         
 1405         # Add residue group to chain group...
 1406         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesGroupID] = ResiduesGroupName
 1407         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"].append(ResiduesGroupName)
 1408         
 1409         # Initialize residue group members...
 1410         ResiduesGroupMembersID = "%sGroupMembers" % ResiduesGroupIDPrefix
 1411         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesGroupMembersID] = []
 1412         
 1413         # Setup residues sub groups and its members...
 1414         for SubGroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
 1415             SubGroupID = re.sub("_", "", SubGroupType)
 1416 
 1417             ResiduesSubGroupName = "%s.%s" % (ResiduesGroupName, SubGroupType)
 1418             ResiduesSubGroupID = "%s%sGroup" % (ResiduesGroupIDPrefix, SubGroupID)
 1419 
 1420             # Add sub group to residues group...
 1421             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupID] = ResiduesSubGroupName
 1422             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesGroupMembersID].append(ResiduesSubGroupName)
 1423             
 1424             # Initialize sub group members...
 1425             ResiduesSubGroupMembersID = "%s%sGroupMembers" % (ResiduesGroupIDPrefix, SubGroupID)
 1426             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupMembersID] = []
 1427             
 1428             # Add sub group members to subgroup...
 1429             for MemberType in ["Residues", "Surface"]:
 1430                 MemberID = re.sub("_", "", MemberType)
 1431 
 1432                 SubGroupMemberName = "%s.%s" % (ResiduesSubGroupName, MemberType)
 1433                 SubGroupMemberID = "%s%s%s" % (ResiduesGroupIDPrefix, SubGroupID, MemberID)
 1434                 
 1435                 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][SubGroupMemberID] = SubGroupMemberName
 1436                 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][ResiduesSubGroupMembersID].append(SubGroupMemberName)
 1437                 
 1438     if GetInterfaceContainsSurfacesStatus(FileIndex, ChainID):
 1439         # Setup a surface group and add it to chain group...
 1440         SurfaceGroupName = "%s.Surface" % (ChainGroupName)
 1441         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroup"] = SurfaceGroupName
 1442         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainGroupMembers"].append(SurfaceGroupName)
 1443         
 1444         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"] = []
 1445 
 1446         # Setup a generic colored surface...
 1447         Name = "%s.Surface" % (SurfaceGroupName)
 1448         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurface"] = Name
 1449         PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"].append(Name)
 1450         
 1451         if GetInterfaceSurfaceChainStatus(FileIndex, ChainID):
 1452             # Setup hydrophobicity surface...
 1453             Name = "%s.Hydrophobicity" % (SurfaceGroupName)
 1454             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainHydrophobicSurface"] = Name
 1455             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"].append(Name)
 1456             
 1457             # Setup hydrophobicity and charge surface...
 1458             Name = "%s.Hydrophobicity_Charge" % (SurfaceGroupName)
 1459             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainHydrophobicChargeSurface"] = Name
 1460             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"].append(Name)
 1461             
 1462         if GetInterfaceSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
 1463             # Setup electrostatics group...
 1464             GroupName = "%s.Vacuum_Electrostatics" % (SurfaceGroupName)
 1465             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainElectrostaticsGroup"] = GroupName
 1466             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainSurfaceGroupMembers"].append(GroupName)
 1467             
 1468             # Setup electrostatics group members...
 1469             PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainElectrostaticsGroupMembers"] = []
 1470             
 1471             for MemberType in ["Chain", "Contact_Potential", "Map", "Legend", "Volume"]:
 1472                 MemberID = re.sub("_", "", MemberType)
 1473                 
 1474                 Name = "%s.%s" % (GroupName, MemberType)
 1475                 NameID = "ChainElectrostaticsSurface%s" % MemberID
 1476                 
 1477                 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID][NameID] = Name
 1478                 PyMOLObjectNames["InterfaceChainIDs"][InterfaceID][InterfaceChainID]["ChainElectrostaticsGroupMembers"].append(Name)
 1479 
 1480 def ProcessResidueTypesAndSurfaceOptions(FileIndex, SpecifiedChainsAndLigandsInfo):
 1481     """Process residue types and surface options for chains and interfaces."""
 1482 
 1483     SpecifiedChainsAndLigandsInfo["ChainSurfaces"] = {}
 1484     SpecifiedChainsAndLigandsInfo["SurfaceChain"] = {}
 1485     SpecifiedChainsAndLigandsInfo["SurfaceChainElectrostatics"] = {}
 1486 
 1487     SpecifiedChainsAndLigandsInfo["InterfaceSurfaces"] = {}
 1488     SpecifiedChainsAndLigandsInfo["SurfaceInterface"] = {}
 1489     SpecifiedChainsAndLigandsInfo["SurfaceInterfaceElectrostatics"] = {}
 1490     
 1491     SpecifiedChainsAndLigandsInfo["ResidueTypesInterface"] = {}
 1492 
 1493     # Load infile...
 1494     Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
 1495     MolName = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
 1496     pymol.cmd.load(Infile, MolName)
 1497     
 1498     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
 1499         AminoAcidsPresent = PyMOLUtil.AreAminoAcidResiduesPresent(MolName, ChainID)
 1500 
 1501         # Process surfaces for chains...
 1502         if re.match("^auto$", OptionsInfo["SurfaceChain"], re.I):
 1503             SurfaceChain = True if AminoAcidsPresent else False
 1504         else:
 1505             SurfaceChain = True if re.match("^yes$", OptionsInfo["SurfaceChain"], re.I) else False
 1506         SpecifiedChainsAndLigandsInfo["SurfaceChain"][ChainID] = SurfaceChain
 1507 
 1508         if re.match("^auto$", OptionsInfo["SurfaceChainElectrostatics"], re.I):
 1509             SurfaceChainElectrostatics = True if AminoAcidsPresent else False
 1510         else:
 1511             SurfaceChainElectrostatics = True if re.match("^yes$", OptionsInfo["SurfaceChainElectrostatics"], re.I) else False
 1512         SpecifiedChainsAndLigandsInfo["SurfaceChainElectrostatics"][ChainID] = SurfaceChainElectrostatics
 1513 
 1514         # A colored surface is always created by default...
 1515         ChainSurfaces = True
 1516         SpecifiedChainsAndLigandsInfo["ChainSurfaces"][ChainID] = ChainSurfaces
 1517         
 1518         # Process residue types and surfaces for interfaces...
 1519         if re.match("^auto$", OptionsInfo["InterfaceSurface"], re.I):
 1520             InterfaceSurface = True if AminoAcidsPresent else False
 1521         else:
 1522             InterfaceSurface = True if re.match("^yes$", OptionsInfo["InterfaceSurface"], re.I) else False
 1523         SpecifiedChainsAndLigandsInfo["SurfaceInterface"][ChainID] = InterfaceSurface
 1524         
 1525         if re.match("^auto$", OptionsInfo["InterfaceSurfaceElectrostatics"], re.I):
 1526             InterfaceSurfaceElectrostatics = True if AminoAcidsPresent else False
 1527         else:
 1528             InterfaceSurfaceElectrostatics = True if re.match("^yes$", OptionsInfo["InterfaceSurfaceElectrostatics"], re.I) else False
 1529         SpecifiedChainsAndLigandsInfo["SurfaceInterfaceElectrostatics"][ChainID] = InterfaceSurfaceElectrostatics
 1530         
 1531         # A colored surface is always created by default...
 1532         InterfaceSurfaces = True
 1533         SpecifiedChainsAndLigandsInfo["InterfaceSurfaces"][ChainID] = InterfaceSurfaces
 1534         
 1535         if re.match("^auto$", OptionsInfo["InterfaceResidueTypes"], re.I):
 1536             InterfaceResidueTypes = True if AminoAcidsPresent else False
 1537         else:
 1538             InterfaceResidueTypes = True if re.match("^yes$", OptionsInfo["InterfaceResidueTypes"], re.I) else False
 1539         SpecifiedChainsAndLigandsInfo["ResidueTypesInterface"][ChainID] = InterfaceResidueTypes
 1540     
 1541     # Delete loaded object...
 1542     pymol.cmd.delete(MolName)
 1543 
 1544 def GetInterfaceResidueTypesStatus(FileIndex, ChainID):
 1545     """Get status of residue types for an interface."""
 1546 
 1547     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["ResidueTypesInterface"][ChainID]
 1548 
 1549 def GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
 1550     """Get status of surfaces present in chain alone object."""
 1551 
 1552     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["ChainSurfaces"][ChainID]
 1553 
 1554 def GetInterfaceContainsSurfacesStatus(FileIndex, ChainID):
 1555     """Get status of surfaces present in an interface."""
 1556 
 1557     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["InterfaceSurfaces"][ChainID]
 1558 
 1559 def GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
 1560     """Get status of hydrophobic surfaces for chain alone object."""
 1561 
 1562     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceChain"][ChainID]
 1563 
 1564 def GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
 1565     """Get status of electrostatics surfaces for chain alone object."""
 1566 
 1567     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceChainElectrostatics"][ChainID]
 1568 
 1569 def GetInterfaceSurfaceChainStatus(FileIndex, ChainID):
 1570     """Get status of hydrophobic surfaces for an interface."""
 1571 
 1572     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceInterface"][ChainID]
 1573 
 1574 def GetInterfaceSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
 1575     """Get status of hydrophobic surfaces for an interface."""
 1576 
 1577     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceInterfaceElectrostatics"][ChainID]
 1578 
 1579 def CheckPresenceOfValidLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo):
 1580     """Check presence of valid ligand IDs."""
 1581 
 1582     MiscUtil.PrintInfo("\nSpecified chain IDs: %s" % (", ".join(SpecifiedChainsAndLigandsInfo["ChainIDs"])))
 1583     
 1584     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
 1585         if len (SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]):
 1586             MiscUtil.PrintInfo("Chain ID: %s; Specified LigandIDs: %s" % (ChainID, ", ".join(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID])))
 1587         else:
 1588             MiscUtil.PrintInfo("Chain IDs: %s; Specified LigandIDs: None" % (ChainID))
 1589             MiscUtil.PrintWarning("No valid ligand IDs found for chain ID, %s. PyMOL groups and objects related to ligand and binding pockect won't be created." % (ChainID))
 1590 
 1591 def RetrieveFirstChainID(FileIndex):
 1592     """Get first chain ID."""
 1593     
 1594     ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
 1595     
 1596     FirstChainID = None
 1597     if len(ChainsAndLigandsInfo["ChainIDs"]):
 1598         FirstChainID = ChainsAndLigandsInfo["ChainIDs"][0]
 1599     
 1600     return FirstChainID
 1601 
 1602 def ProcessResidueTypes():
 1603     """Process residue types."""
 1604 
 1605     ResidueTypesNamesInfo, ResidueTypesParamsInfo = PyMOLUtil.ProcessResidueTypesOptionsInfo("-r, --residueTypes", OptionsInfo["ResidueTypes"])
 1606     OptionsInfo["ResidueTypesNames"] = ResidueTypesNamesInfo
 1607     OptionsInfo["ResidueTypesParams"] = ResidueTypesParamsInfo
 1608     
 1609 def ProcessSurfaceAtomTypesColors():
 1610     """Process surface atom types colors. """
 1611 
 1612     AtomTypesColorNamesInfo = PyMOLUtil.ProcessSurfaceAtomTypesColorsOptionsInfo("--surfaceAtomTypesColors", OptionsInfo["SurfaceAtomTypesColors"])
 1613     OptionsInfo["AtomTypesColorNames"] = AtomTypesColorNamesInfo
 1614 
 1615 def ProcessOptions():
 1616     """Process and validate command line arguments and options."""
 1617 
 1618     MiscUtil.PrintInfo("Processing options...")
 1619     
 1620     # Validate options...
 1621     ValidateOptions()
 1622     
 1623     OptionsInfo["AllowEmptyObjects"] = True if re.match("^Yes$", Options["--allowEmptyObjects"], re.I) else False
 1624 
 1625     OptionsInfo["Infiles"] = Options["--infiles"]
 1626     OptionsInfo["InfilesNames"] =  Options["--infileNames"]
 1627 
 1628     OptionsInfo["IgnoreHydrogens"] = True if re.match("^Yes$", Options["--ignoreHydrogens"], re.I) else False
 1629     
 1630     OptionsInfo["Overwrite"] = Options["--overwrite"]
 1631     OptionsInfo["PMLOut"] = True if re.match("^Yes$", Options["--PMLOut"], re.I) else False
 1632     
 1633     OptionsInfo["Outfile"] = Options["--outfile"]
 1634     FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Outfile"])
 1635     OptionsInfo["PSEOut"] = False 
 1636     if re.match("^pml$", FileExt, re.I):
 1637         OptionsInfo["PMLOutfile"] = OptionsInfo["Outfile"] 
 1638         OptionsInfo["PMEOutfile"] = re.sub(".pml$", ".pme", OptionsInfo["Outfile"]) 
 1639     elif re.match("^pse$", FileExt, re.I):
 1640         OptionsInfo["PSEOut"] = True 
 1641         OptionsInfo["PSEOutfile"] = OptionsInfo["Outfile"] 
 1642         OptionsInfo["PMLOutfile"] = re.sub(".pse$", ".pml", OptionsInfo["Outfile"]) 
 1643         if os.path.exists(OptionsInfo["PMLOutfile"]) and (not OptionsInfo["Overwrite"]):
 1644             MiscUtil.PrintError("The intermediate output file to be generated, %s, already exist. Use option \"--ov\" or \"--overwrite\" and try again." % OptionsInfo["PMLOutfile"] )
 1645 
 1646     OptionsInfo["InterfaceLabelColor"] = Options["--interfaceLabelColor"]
 1647     
 1648     OptionsInfo["InterfaceContactsCutoff"] = float(Options["--interfaceContactsCutoff"])
 1649     
 1650     OptionsInfo["InterfaceHydrophobicContactsColor"] = Options["--interfaceHydrophobicContactsColor"]
 1651     OptionsInfo["InterfaceHydrophobicContacts"] = True if re.match("^Yes$", Options["--interfaceHydrophobicContacts"], re.I) else False
 1652     
 1653     OptionsInfo["InterfacePolarContactsColor"] = Options["--interfacePolarContactsColor"]
 1654     OptionsInfo["InterfacePolarContacts"] = True if re.match("^Yes$", Options["--interfacePolarContacts"], re.I) else False
 1655     
 1656     OptionsInfo["InterfaceResidueTypes"] = Options["--interfaceResidueTypes"]
 1657     OptionsInfo["InterfaceSurface"] = Options["--interfaceSurface"]
 1658     OptionsInfo["InterfaceSurfaceElectrostatics"] = Options["--interfaceSurfaceElectrostatics"]
 1659     
 1660     OptionsInfo["LabelFontID"] = int(Options["--labelFontID"])
 1661     
 1662     Method = Options["--method"]
 1663     MethodCutoff = Options["--methodCutoff"]
 1664     if re.match("^auto$", MethodCutoff, re.I):
 1665         if re.match("BySASAChange", Method, re.I):
 1666             MethodCutoff = 1.0
 1667         elif re.match("ByHeavyAtomsDistance", Method, re.I):
 1668             MethodCutoff = 5.0
 1669         elif re.match("ByCAlphaAtomsDistance", Method, re.I):
 1670             MethodCutoff = 8.0
 1671         else:
 1672             MiscUtil.PrintError("The method, %s, specified using \"-m, --method\" option  is  not a valid method." % (Method))
 1673     else:
 1674         MethodCutoff = float(Options["--methodCutoff"])
 1675     OptionsInfo["Method"] = Method
 1676     OptionsInfo["MethodCutoff"] = MethodCutoff
 1677     
 1678     OptionsInfo["ResidueTypes"] = Options["--residueTypes"]
 1679     ProcessResidueTypes()
 1680     
 1681     OptionsInfo["SurfaceChain"] = Options["--surfaceChain"]
 1682     OptionsInfo["SurfaceChainElectrostatics"] = Options["--surfaceChainElectrostatics"]
 1683     
 1684     OptionsInfo["SurfaceChainComplex"] = True if re.match("^Yes$", Options["--surfaceChainComplex"], re.I) else False
 1685     OptionsInfo["SurfaceComplex"] = True if re.match("^Yes$", Options["--surfaceComplex"], re.I) else False
 1686 
 1687     # Retrieve surface colors...
 1688     SurfaceColors = re.sub(" ", "", Options["--surfaceColors"])
 1689     SurfaceColorsWords = SurfaceColors.split(",")
 1690     if len(SurfaceColorsWords) != 2:
 1691         MiscUtil.PrintError("The number of comma delinited color names, %d, specified using \"--surfaceColors\" option, \"%s\",  must be a 2." % (len(SurfaceColorsWords), Options["--surfaceColors"]))
 1692     OptionsInfo["SurfaceColors"] = SurfaceColors
 1693     OptionsInfo["SurfaceInterfaceColor"] = SurfaceColorsWords[0]
 1694     OptionsInfo["SurfaceNonInterfaceColor"] = SurfaceColorsWords[1]
 1695     
 1696     OptionsInfo["SurfaceColorPalette"] = Options["--surfaceColorPalette"]
 1697     OptionsInfo["SurfaceAtomTypesColors"] = Options["--surfaceAtomTypesColors"]
 1698     ProcessSurfaceAtomTypesColors()
 1699     
 1700     OptionsInfo["SurfaceTransparency"] = float(Options["--surfaceTransparency"])
 1701     
 1702     RetrieveInfilesInfo()
 1703 
 1704     # Retrieve interface chain IDs...
 1705     InterfaceChainIDs = re.sub(" ", "", Options["--chainIDs"])
 1706     InterfaceChainIDsList = []
 1707     CanonicalInterfaceChainIDsMap = {}
 1708     if not re.match("^auto$", InterfaceChainIDs, re.I):
 1709         InterfaceChainIDsWords = InterfaceChainIDs.split(",")
 1710         if len(InterfaceChainIDsWords) % 2:
 1711             MiscUtil.PrintError("The number of comma delimited chain IDs, %d, specified using \"-c, --chainIDs\" option, \"%s\",  must be a multple of 2." % (len(InterfaceChainIDsWords), Options["--chainIDs"]))
 1712         for ChainID in InterfaceChainIDsWords:
 1713             if not len(ChainID):
 1714                 MiscUtil.PrintError("A chain ID specified, \"%s\" using \"-c, --chainIDs\" option is empty." % (Options["--chainIDs"]))
 1715             ChainIDWords = ChainID.split("+")
 1716             InterfaceChainIDsList.append(ChainIDWords)
 1717     OptionsInfo["InterfaceChainIDs"]  = InterfaceChainIDs
 1718     OptionsInfo["InterfaceChainIDsList"]  = InterfaceChainIDsList
 1719     
 1720     # Process interface chain IDs...
 1721     OptionsInfo["LigandIDs"] = Options["--ligandIDs"]
 1722     ProcessInterfaceChainIDs()
 1723     
 1724 def RetrieveOptions(): 
 1725     """Retrieve command line arguments and options."""
 1726     
 1727     # Get options...
 1728     global Options
 1729     Options = docopt(_docoptUsage_)
 1730 
 1731     # Set current working directory to the specified directory...
 1732     WorkingDir = Options["--workingdir"]
 1733     if WorkingDir:
 1734         os.chdir(WorkingDir)
 1735     
 1736     # Handle examples option...
 1737     if "--examples" in Options and Options["--examples"]:
 1738         MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_))
 1739         sys.exit(0)
 1740 
 1741 def ValidateOptions():
 1742     """Validate option values."""
 1743     
 1744     MiscUtil.ValidateOptionTextValue("--allowEmptyObjects", Options["--allowEmptyObjects"], "yes no")
 1745 
 1746     # Expand infiles to handle presence of multiple input files...
 1747     InfileNames = MiscUtil.ExpandFileNames(Options["--infiles"], ",")
 1748     InfilesCount = len(InfileNames)
 1749     if not InfilesCount:
 1750         MiscUtil.PrintError("No input files specified for \"-i, --infiles\" option")
 1751 
 1752     # Validate file extensions...
 1753     for Infile in InfileNames:
 1754         MiscUtil.ValidateOptionFilePath("-i, --infiles", Infile)
 1755         MiscUtil.ValidateOptionFileExt("-i, --infiles", Infile, "pdb cif")
 1756         MiscUtil.ValidateOptionsDistinctFileNames("-i, --infiles", Infile, "-o, --outfile", Options["--outfile"])
 1757     
 1758     # Validate file count...
 1759     if InfilesCount > 2:
 1760         MiscUtil.PrintError("Number of input files, %s, specified using \"-i, --infiles\" option is not valid. Number of allowed files: 1 or 2" % (InfilesCount))
 1761 
 1762     # Validate distinct file names...
 1763     if InfilesCount == 2:
 1764         Infile1Name, Infile2Name = InfileNames
 1765         Infile1Pattern = r"^" + re.escape(Infile1Name) + r"$";
 1766         if re.match(Infile1Pattern, Infile2Name, re.I):
 1767             MiscUtil.PrintError("The file names specified, \"%s\", for option \"-i, --infiles\" must be different.\n" % (Options["--infiles"]))
 1768         
 1769     Options["--infileNames"] = InfileNames
 1770     
 1771     MiscUtil.ValidateOptionFileExt("-o, --outfile", Options["--outfile"], "pml pse")
 1772     MiscUtil.ValidateOptionsOutputFileOverwrite("-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"])
 1773     
 1774     MiscUtil.ValidateOptionTextValue("--ignoreHydrogens", Options["--ignoreHydrogens"], "yes no")
 1775 
 1776     MiscUtil.ValidateOptionFloatValue("--interfaceContactsCutoff", Options["--interfaceContactsCutoff"], {">": 0.0})
 1777     MiscUtil.ValidateOptionTextValue("--interfaceHydrophobicContacts", Options["--interfaceHydrophobicContacts"], "yes no")
 1778     MiscUtil.ValidateOptionTextValue("--interfacePolarContacts", Options["--interfacePolarContacts"], "yes no")
 1779     
 1780     MiscUtil.ValidateOptionTextValue("--interfaceResidueTypes", Options["--interfaceResidueTypes"], "yes no auto")
 1781     MiscUtil.ValidateOptionTextValue("--interfaceSurface", Options["--interfaceSurface"], "yes no auto")
 1782     MiscUtil.ValidateOptionTextValue("--interfaceSurfaceElectrostatics", Options["--interfaceSurfaceElectrostatics"], "yes no auto")
 1783                        
 1784     MiscUtil.ValidateOptionIntegerValue("--labelFontID", Options["--labelFontID"], {})
 1785     
 1786     MiscUtil.ValidateOptionTextValue("--method", Options["--method"], "BySASAChange ByHeavyAtomsDistance ByCAlphaAtomsDistance")
 1787     if not re.match("^auto$", Options["--methodCutoff"], re.I):
 1788         MiscUtil.ValidateOptionFloatValue("--methodCutoff", Options["--methodCutoff"], {">": 0.0})
 1789     
 1790     MiscUtil.ValidateOptionTextValue("--PMLOut", Options["--PMLOut"], "yes no")
 1791 
 1792     MiscUtil.ValidateOptionTextValue("--surfaceChain", Options["--surfaceChain"], "yes no auto")
 1793     MiscUtil.ValidateOptionTextValue("--surfaceChainElectrostatics", Options["--surfaceChainElectrostatics"], "yes no auto")
 1794     MiscUtil.ValidateOptionTextValue("--surfaceComplex", Options["--surfaceComplex"], "yes no")
 1795     MiscUtil.ValidateOptionTextValue("--surfaceChainComplex", Options["--surfaceChainComplex"], "yes no")
 1796     
 1797     MiscUtil.ValidateOptionTextValue("--surfaceColorPalette", Options["--surfaceColorPalette"], "RedToWhite WhiteToGreen")
 1798     MiscUtil.ValidateOptionFloatValue("--surfaceTransparency", Options["--surfaceTransparency"], {">=": 0.0, "<=": 1.0})
 1799     
 1800 # Setup a usage string for docopt...
 1801 _docoptUsage_ = """
 1802 PyMOLVisualizeInterfaces.py - Visualize macromolecular interfaces
 1803 
 1804 Usage:
 1805     PyMOLVisualizeInterfaces.py [--allowEmptyObjects <yes or no>] [--chainIDs <ChainID1 or ChainID1,ChainID2>]
 1806                                               [--interfaceLabelColor <text>] [ --interfaceContactsCutoff <number>]
 1807                                               [--interfaceHydrophobicContacts <yes or no>] [--interfaceHydrophobicContactsColor <text>]
 1808                                               [--interfacePolarContacts <yes or no>] [--interfacePolarContactsColor <text>]
 1809                                               [--interfaceResidueTypes <yes or no>] [--interfaceSurface <yes or no>]
 1810                                               [--interfaceSurfaceElectrostatics <yes or no>] [--labelFontID <number>]
 1811                                               [--ignoreHydrogens <yes or no>] [--ligandIDs <Largest, All, None or ID1,ID2...>]
 1812                                               [--method <text>] [--methodCutoff <number>]
 1813                                               [--PMLOut <yes or no>] [--residueTypes <Type,Color,ResNames,...>] [--surfaceChain <yes or no>]
 1814                                               [--surfaceChainElectrostatics <yes or no>] [--surfaceChainComplex <yes or no>]
 1815                                               [--surfaceComplex <yes or no>] [--surfaceColors <ColorName1,ColorName2>]
 1816                                               [--surfaceColorPalette <RedToWhite or WhiteToGreen>]
 1817                                               [--surfaceAtomTypesColors <ColorType,ColorSpec,...>] [--surfaceTransparency <number>]
 1818                                               [--overwrite] [-w <dir>] -i <infile1,...> -o <outfile>
 1819     PyMOLVisualizeInterfaces.py -h | --help | -e | --examples
 1820 
 1821 Description:
 1822     Generate PyMOL visualization files for viewing interfaces between macromolecules
 1823     including proteins and nucleic acids. The interfaces may be generated between
 1824     pairs of chains in a single file or across two different files.
 1825 
 1826     The supported input file format are: PDB (.pdb), CIF (.cif)
 1827 
 1828     The supported output file formats are: PyMOL script file (.pml), PyMOL session
 1829     file (.pse)
 1830 
 1831     A variety of PyMOL groups and objects may be  created for visualization of
 1832     macromolecular interfaces. These groups and objects correspond to complexes,
 1833     surfaces, chains, ligands, and interfaces. A complete hierarchy of all possible
 1834     PyMOL groups and objects is shown below:
 1835 
 1836         <PDBFileRoot>
 1837             .Complex
 1838                 .Complex
 1839                 .Surface
 1840             .Chain<ID>
 1841                 .Complex
 1842                     .Complex
 1843                     .Surface
 1844                 .Chain
 1845                     .Chain
 1846                     .NonInterface
 1847                         .Chain
 1848                         .Surface
 1849                             .Surface
 1850                             .Hydrophobicity
 1851                             .Hydrophobicity_Charge
 1852                             .Vacuum_Electrostatics
 1853                                 .Contact_Potentials
 1854                                 .Map
 1855                                 .Legend
 1856                                 .Volume
 1857                 .Solvent
 1858                 .Inorganic
 1859                 .Ligand<ID>
 1860                     .Ligand
 1861                         .Ligand
 1862                         .BallAndStick
 1863                 .Ligand<ID>
 1864                     .Ligand
 1865                         ... ... ...
 1866             .Chain<ID>
 1867                 ... ... ...
 1868                 .Ligand<ID>
 1869                     ... ... ...
 1870                 .Ligand<ID>
 1871                     ... ... ...
 1872             .Chain<ID>
 1873                 ... ... ...
 1874         <PDBFileRoot>
 1875             .Complex
 1876                 ... ... ...
 1877             .Chain<ID>
 1878                 ... ... ...
 1879                 .Ligand<ID>
 1880                     ... ... ...
 1881                 .Ligand<ID>
 1882                     ... ... ...
 1883             .Chain<ID>
 1884                 ... ... ...
 1885         <Interfaces>
 1886             .Chain<IDs1>_Chain<IDs2>
 1887                 .Polar_Contacts
 1888                 .Hydrophobic_Contacts
 1889                 .Chain<ID> or Chain<ID>_<PDBFileRoot>
 1890                     .Chain
 1891                     .Residues
 1892                         .Aromatic
 1893                             .Residues
 1894                             .Surface
 1895                         .Hydrophobic
 1896                             .Residues
 1897                             .Surface
 1898                         .Polar
 1899                             .Residues
 1900                             .Surface
 1901                         .Positively_Charged
 1902                             .Residues
 1903                             .Surface
 1904                         .Negatively_Charged
 1905                             .Residues
 1906                             .Surface
 1907                         .Other
 1908                             .Residues
 1909                             .Surface
 1910                     .Surface
 1911                         .Surface
 1912                         .Hydrophobicity
 1913                         .Hydrophobicity_Charge
 1914                         .Vacuum_Electrostatics
 1915                             .Contact_Potentials
 1916                             .Map
 1917                             .Legend
 1918                             .Volume
 1919                 .Chain<ID> or <PDBFileRoot>_Chain<ID>
 1920                     .Chain
 1921                     .Residues
 1922                         ... ... ...
 1923                     .Surface
 1924                         ... ... ...
 1925             .Chain<IDs>_Chain<IDs>
 1926                 .Polar_Contacts
 1927                 .Hydrophobic_Contacts
 1928                 .Chain<ID> or Chain<ID>_<PDBFileRoot>
 1929                     .Chain
 1930                     .Residues
 1931                         ... ... ...
 1932                     .Surface
 1933                         ... ... ...
 1934                 .Chain<ID> or Chain<ID>_<PDBFileRoot>
 1935                     .Chain
 1936                     .Residues
 1937                         ... ... ...
 1938                     .Surface
 1939                         ... ... ...
 1940     
 1941     The hydrophobic and electrostatic surfaces are not created for complete complex
 1942     and chain complex in input file(s) by default. A word to the wise: The creation of
 1943     surface objects may slow down loading of PML file and generation of PSE file, based
 1944     on the size of input complexes. The generation of PSE file may also fail.
 1945 
 1946 Options:
 1947     --allowEmptyObjects <yes or no>  [default: no]
 1948         Allow creation of empty PyMOL objects corresponding to interface,
 1949         solvent, and inorganic atom selections across chains and ligands in
 1950         input file(s). By default, the empty objects are marked for deletion.
 1951     -c, --chainIDs <ChainID1,ChainD2,...>  [default: Auto]
 1952         Pairwise comma delimited list of chain IDs for the identification of
 1953         macromolecular interfaces. All chain IDs must be present in the
 1954         same file for a single input file. Otherwise, the first and second
 1955         chain ID(s) in a pair belong to the first and second input file.
 1956         
 1957         The default values for interface chain IDs depend on the number
 1958         of input files as shown below:
 1959         
 1960         One input file: First two chains
 1961         Two input files: First chain in each input file
 1962         
 1963         Each chain may contain multiple chain IDs delimited by a plus sign. For
 1964         example, A+B,C+D chain pair specifies interface between chain complexes
 1965         A+B and C+D in first input file or across two input files.
 1966     -e, --examples
 1967         Print examples.
 1968     -h, --help
 1969         Print this help message.
 1970     -i, --infiles <infile or infile1,infile2>
 1971         Name of an input file or a comma delmited list of names for two input
 1972         files.
 1973     --ignoreHydrogens <yes or no>  [default: yes]
 1974         Ignore hydrogens for ligand views.
 1975     --interfaceLabelColor <text>  [default: magenta]
 1976         Color for drawing residue or atom level labels for residues in an interface.
 1977         The specified value must be valid color. No validation is performed.
 1978     --interfaceContactsCutoff <number>  [default: 4.0]
 1979         Distance in Angstroms for identifying polar and hyrdophobic contacts
 1980         between atoms in interface reisudes.
 1981     --interfaceHydrophobicContacts <yes or no>  [default: yes]
 1982         Hydrophobic contacts between residues in an interface. The hydrophobic
 1983         contacts are shown between pairs of carbon atoms not connected to
 1984         hydrogen bond donor or acceptors atoms as identified by PyMOL.
 1985     --interfaceHydrophobicContactsColor <text>  [default: purpleblue]
 1986         Color for drawing hydrophobic contacts between residues in an interface.
 1987         The specified value must be valid color. No validation is performed.
 1988     --interfacePolarContacts <yes or no>  [default: yes]
 1989         Polar contacts between residues in an interface.
 1990     --interfacePolarContactsColor <text>  [default: orange]
 1991         Color for drawing polar contacts between residues in an interface.
 1992         The specified value must be valid color. No validation is performed.
 1993     --interfaceResidueTypes <yes or no>  [default: auto]
 1994         Interface residue types. The residue groups are generated using residue types,
 1995         colors, and names specified by '--residueTypes' option. It is only valid for
 1996         amino acids.  By default, the residue type groups are automatically created
 1997         for interfaces containing amino acids and skipped for chains only containing
 1998         nucleic acids.
 1999     --interfaceSurface <yes or no>  [default: auto]
 2000         Surfaces around interface residues colored by hydrophobicity alone and
 2001         both hydrophobicity and charge. The hydrophobicity surface is colored
 2002         at residue level using Eisenberg hydrophobicity scale for residues and color
 2003         gradient specified by '--surfaceColorPalette' option. The  hydrophobicity and
 2004         charge surface is colored [ Ref 140 ] at atom level using colors specified for
 2005         groups of atoms by '--surfaceAtomTypesColors' option. This scheme allows
 2006         simultaneous mapping of hyrophobicity and charge values on the surfaces.
 2007         
 2008         This option is only valid for amino acids. By default, both surfaces are
 2009         automatically created for pockets containing amino acids and skipped for
 2010         pockets containing only nucleic acids.
 2011         
 2012         In addition, generic surfaces colored by '--surfaceColors' are always created
 2013         for interface residues containing amino acids and nucleic acids.
 2014     --interfaceSurfaceElectrostatics <yes or no>  [default: no]
 2015         Vacuum electrostatics contact potential surface around interface residues.
 2016         A word to the wise from PyMOL documentation: The computed protein
 2017         contact potentials are only qualitatively useful, due to short cutoffs,
 2018         truncation, and lack of solvent "screening".
 2019         
 2020         This option is only valid for amino acids. By default, the electrostatics surface
 2021         is automatically created for chains containing amino acids and skipped for chains
 2022         containing only nucleic acids.
 2023     --labelFontID <number>  [default: 7]
 2024         Font ID for drawing labels. Default: 7 (Sans Bold). Valid values: 5 to 16.
 2025         The specified value must be a valid PyMOL font ID. No validation is
 2026         performed. The complete lists of valid font IDs is available at:
 2027         pymolwiki.org/index.php/Label_font_id. Examples: 5 - Sans;
 2028         7 - Sans Bold; 9 - Serif; 10 - Serif Bold.
 2029     -l, --ligandIDs <Largest, All, None or ID1,ID2...>  [default: All]
 2030         List of ligand IDs to show in chains during visualization of interfaces. Possible
 2031         values: Largest, All, None, or a comma delimited list of ligand IDs. The
 2032         default is to show all ligands present in chains involved in interfaces.
 2033         
 2034         Ligands are identified using organic selection operator available in PyMOL.
 2035         It'll also  identify buffer molecules as ligands. The largest ligand contains
 2036         the highest number of heavy atoms.
 2037     -m, --method <text>  [default: BySASAChange]
 2038         Methodology for the identification of interface residues between a pair
 2039         of chains in an input file. The interface residues may be identified by
 2040         change in solvent accessible surface area (SASA) for a residue between
 2041         a chain and chains complex, distance between heavy atoms
 2042         in two chains, or distance between CAlpha atoms. Possible values:
 2043         BySASAChange, ByHeavyAtomsDistance, or ByCAlphaAtomsDistance. 
 2044     --methodCutoff <number>  [default: auto]
 2045         Cutoff value used by different methodologies during the identification of
 2046         interface residues between a pair of chains. The default values are
 2047         shown below:
 2048         
 2049             BySASAChange: 1.0; Units: Angstrom**2 [ Ref 141 ]
 2050             ByHeavyAtomsDistance: 5.0; Units: Angstrom [ Ref 142 ]
 2051             ByCAlphaAtomsDistance: 8.0; Units: Angstrom [ Ref 143 ]
 2052         
 2053     -o, --outfile <outfile>
 2054         Output file name.
 2055     -p, --PMLOut <yes or no>  [default: yes]
 2056         Save PML file during generation of PSE file.
 2057     -r, --residueTypes <Type,Color,ResNames,...>  [default: auto]
 2058         Residue types, colors, and names to generate for residue groups during
 2059         and '--residueTypesChain' option. It is only valid for amino acids.
 2060         
 2061         It is a triplet of comma delimited list of amino acid residues type, residues
 2062         color, and a space delimited list three letter residue names. 
 2063         
 2064         The default values for residue type, color, and name triplets  are shown
 2065         below:
 2066             
 2067             Aromatic,brightorange,HIS PHE TRP TYR,
 2068             Hydrophobic,orange,ALA GLY VAL LEU ILE PRO MET,
 2069             Polar,palegreen,ASN GLN SER THR CYS,
 2070             Positively_Charged,marine,ARG LYS,
 2071             Negatively_Charged,red,ASP GLU
 2072             
 2073         The color name must be a valid PyMOL name. No validation is performed.
 2074         An amino acid name may appear across multiple residue types. All other
 2075         residues are grouped under 'Other'.
 2076     --surfaceChain <yes or no>  [default: auto]
 2077         Surfaces around non-interface residues in individual  chain colored by
 2078         hydrophobicity alone and both hydrophobicity and charge. The hydrophobicity
 2079         surface is colored at residue level using Eisenberg hydrophobicity scale for residues
 2080         and color gradient specified by '--surfaceColorPalette' option. The  hydrophobicity
 2081         and charge surface is colored [ Ref 140 ] at atom level using colors specified for
 2082         groups of atoms by '--surfaceAtomTypesColors' option. This scheme allows
 2083         simultaneous mapping of hyrophobicity and charge values on the surfaces.
 2084         
 2085         This option is only valid for amino acids. By default, both surfaces are
 2086         automatically created for chains containing amino acids and skipped for
 2087         chains containing only nucleic acids.
 2088         
 2089         In addition, generic surfaces colored by '--surfaceColors' are always created
 2090         for non-interface residues containing amino acids and nucleic acids.
 2091     --surfaceChainElectrostatics <yes or no>  [default: no]
 2092         Vacuum electrostatics contact potential surface and volume around non-interface
 2093         residues in individual chain. A word to the wise from PyMOL documentation: The
 2094         computed protein contact potentials are only qualitatively useful, due to short cutoffs,
 2095         truncation, and lack of solvent "screening".
 2096         
 2097         This option is only valid for amino acids. By default, the electrostatics surface
 2098         and volume are automatically created for chains containing amino acids and
 2099         skipped for chains containing only nucleic acids.
 2100     --surfaceChainComplex <yes or no>  [default: no]
 2101         Hydrophobic surface around chain complex. The  surface is colored by
 2102         hydrophobicity. It is only valid for amino acids.
 2103     --surfaceComplex <yes or no>  [default: no]
 2104         Hydrophobic surface around complete complex. The  surface is colored by
 2105         hydrophobicity. It is only valid for amino acids.
 2106     --surfaceColors <ColorName1,ColorName2>  [default: salmon,lightblue]
 2107         Color names for surfaces around interface residues and non-interface
 2108         residues in chains. These colors are not used for surfaces colored by
 2109         hydrophobicity and charge. The color names must be valid PyMOL names.
 2110     --surfaceColorPalette <RedToWhite or WhiteToGreen>  [default: RedToWhite]
 2111         Color palette for hydrophobic surfaces around chains and interface residues
 2112         in proteins. Possible values: RedToWhite or WhiteToGreen from most
 2113         hydrophobic amino acid to least hydrophobic. The colors values for amino
 2114         acids are taken from color_h script available as part of the Script Library at
 2115         PyMOL Wiki.
 2116     --surfaceAtomTypesColors <ColorType,ColorSpec,...>  [default: auto]
 2117         Atom colors for generating surfaces colored by hyrophobicity and charge
 2118         around chains and interface residues in proteins. It's a pairwise comma
 2119         delimited list of atom color type and color specification for goups of atoms.
 2120         
 2121         The default values for color types [ Ref 140 ] along wth color specifications
 2122         are shown below: 
 2123             
 2124             HydrophobicAtomsColor, yellow,
 2125             NegativelyChargedAtomsColor, red,
 2126             PositivelyChargedAtomsColor, blue,
 2127             OtherAtomsColor, gray90
 2128             
 2129         The color names must be valid PyMOL names.
 2130         
 2131         The color values may also be specified as space delimited RGB triplets:
 2132              
 2133             HydrophobicAtomsColor, 0.95 0.78 0.0,
 2134             NegativelyChargedAtomsColor, 1.0 0.4 0.4,
 2135             PositivelyChargedAtomsColor, 0.2 0.5 0.8,
 2136             OtherAtomsColor, 0.95 0.95 0.95
 2137             
 2138     --surfaceTransparency <number>  [default: 0.25]
 2139         Surface transparency for molecular surfaces.
 2140     --overwrite
 2141         Overwrite existing files.
 2142     -w, --workingdir <dir>
 2143         Location of working directory which defaults to the current directory.
 2144 
 2145 Examples:
 2146     To visualize interface residues between the first two chains in a PDB file,
 2147     using default methodology to identify interfaces, and and generate a PML
 2148     file, type: 
 2149 
 2150         % PyMOLVisualizeInterfaces.py -i Sample8.pdb -o Sample8.pml
 2151 
 2152     To visualize interface residues between a pair of specific chains in a PDB
 2153     file using a specific methodology and cutoff value to identify interfaces, and
 2154     generate a PML file, type: 
 2155 
 2156         % PyMOLVisualizeInterfaces.py -m BySASAChange --methodCutoff 1.0
 2157         -c "A,B" -i Sample8.pdb -o Sample8.pml
 2158 
 2159     To visualize interface residues between multiple pairs of specified chains in
 2160     a PDB file using a specific methodology and cutoff value to identify interfaces,
 2161     and generate a PML file, type: 
 2162 
 2163         % PyMOLVisualizeInterfaces.py -m ByHeavyAtomsDistance
 2164         --methodCutoff 5.0 -c "A,B,B,D" -i Sample8.pdb -o Sample8.pml
 2165 
 2166     To visualize interface residues between a pair of specified chains, each member
 2167     containing multiple chains, a PDB file using a specific methodology and cutoff
 2168     value to identify interfaces, and generate a PML file, type: 
 2169 
 2170         % PyMOLVisualizeInterfaces.py -m ByCAlphaAtomsDistance
 2171         --methodCutoff 8.0 -c "A+C,B+D" -i Sample8.pdb -o Sample8.pml
 2172 
 2173     To visualize interface residues between a pair of specific chains across two PDB
 2174     files using a specific methodology and cutoff value to identify interfaces, and
 2175     generate a PML file, type: 
 2176 
 2177         % PyMOLVisualizeInterfaces.py -m BySASAChange --methodCutoff 1.0 
 2178         -c "A,B" -i Sample8Part1.pdb,Sample8Part2.pdb
 2179         -o Sample8.pml
 2180 
 2181     To visualize interface residues between multiple pairs of specified chains across
 2182     two PDB files using a specific methodology and cutoff value to identify interfaces,
 2183     and generate a PML file, type: 
 2184 
 2185         % PyMOLVisualizeInterfaces.py -m ByHeavyAtomsDistance
 2186         --methodCutoff 5.0  -c "A,B,C,B" -i Sample8Part1.pdb,Sample8Part2.pdb
 2187         -o Sample8.pml
 2188 
 2189     To visualize interface residues between a pair of specified chains, each member
 2190     containing multiple chains, across two PDB files using a specific methodology
 2191     and cutoff value to identify interfaces, and generate a PML file, type:
 2192 
 2193         % PyMOLVisualizeInterfaces.py -m ByCAlphaAtomsDistance
 2194         --methodCutoff 8.0  -c "A+C,B+D" -i "Sample8Part1.pdb,Sample8Part2.pdb"
 2195         -o Sample8.pml
 2196 
 2197 Author:
 2198     Manish Sud(msud@san.rr.com)
 2199 
 2200 See also:
 2201     DownloadPDBFiles.pl,  PyMOLVisualizeCryoEMDensity.py,
 2202     PyMOLVisualizeElectronDensity.py, PyMOLVisualizeMacromolecules.py,
 2203     PyMOLVisualizeSurfaceAndBuriedResidues.py
 2204 
 2205 Copyright:
 2206     Copyright (C) 2024 Manish Sud. All rights reserved.
 2207 
 2208     The functionality available in this script is implemented using PyMOL, a
 2209     molecular visualization system on an open source foundation originally
 2210     developed by Warren DeLano.
 2211 
 2212     This file is part of MayaChemTools.
 2213 
 2214     MayaChemTools is free software; you can redistribute it and/or modify it under
 2215     the terms of the GNU Lesser General Public License as published by the Free
 2216     Software Foundation; either version 3 of the License, or (at your option) any
 2217     later version.
 2218 
 2219 """
 2220 
 2221 if __name__ == "__main__":
 2222     main()