MayaChemTools

    1 #!/bin/env python
    2 #
    3 # File: PyMOLVisualizeSurfaceAndBuriedResidues.py
    4 # Author: Manish Sud <msud@san.rr.com>
    5 #
    6 # Copyright (C) 2026 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 import os
   33 import sys
   34 import time
   35 import re
   36 
   37 # PyMOL imports...
   38 try:
   39     import pymol
   40 
   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 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python"))
   52 try:
   53     from docopt import docopt
   54     import MiscUtil
   55     import PyMOLUtil
   56 except ImportError as ErrMsg:
   57     sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg)
   58     sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n")
   59     sys.exit(1)
   60 
   61 ScriptName = os.path.basename(sys.argv[0])
   62 Options = {}
   63 OptionsInfo = {}
   64 
   65 
   66 def main():
   67     """Start execution of the script."""
   68 
   69     MiscUtil.PrintInfo(
   70         "\n%s (PyMOL v%s; MayaChemTools v%s; %s): Starting...\n"
   71         % (ScriptName, pymol.cmd.get_version()[0], MiscUtil.GetMayaChemToolsVersion(), time.asctime())
   72     )
   73 
   74     (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime()
   75 
   76     # Retrieve command line arguments and options...
   77     RetrieveOptions()
   78 
   79     # Process and validate command line arguments and options...
   80     ProcessOptions()
   81 
   82     # Perform actions required by the script...
   83     GenerateSurfaceAndBuriedResiduesVisualization()
   84 
   85     MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName)
   86     MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime))
   87 
   88 
   89 def GenerateSurfaceAndBuriedResiduesVisualization():
   90     """Generate visualization for surface and buried residues."""
   91 
   92     Outfile = OptionsInfo["PMLOutfile"]
   93     OutFH = open(Outfile, "w")
   94     if OutFH is None:
   95         MiscUtil.PrintError("Failed to open output fie %s " % Outfile)
   96 
   97     MiscUtil.PrintInfo("\nGenerating file %s..." % Outfile)
   98 
   99     # Setup header...
  100     WritePMLHeader(OutFH, ScriptName)
  101     WritePyMOLParameters(OutFH)
  102 
  103     # Load reffile for alignment..
  104     if OptionsInfo["Align"]:
  105         WriteAlignReference(OutFH)
  106 
  107     # Setup view for each input file...
  108     FirstComplex = True
  109     FirstComplexFirstChainName = None
  110     for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
  111         # Setup PyMOL object names...
  112         PyMOLObjectNames = SetupPyMOLObjectNames(FileIndex)
  113 
  114         # Setup complex view...
  115         WriteComplexView(OutFH, FileIndex, PyMOLObjectNames, FirstComplex)
  116 
  117         SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  118         FirstChain = True
  119         for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  120             if FirstComplex and FirstChain:
  121                 FirstComplexFirstChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
  122 
  123             WriteChainView(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  124 
  125             # Setup ligand views...
  126             FirstLigand = True
  127             for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
  128                 WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNames, ChainID, LigandID)
  129 
  130                 # Set up ligand level group...
  131                 Enable, Action = [False, "close"]
  132                 if FirstLigand:
  133                     FirstLigand = False
  134                     Enable, Action = [True, "open"]
  135                 GenerateAndWritePMLForGroup(
  136                     OutFH,
  137                     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroup"],
  138                     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"],
  139                     Enable,
  140                     Action,
  141                 )
  142 
  143             # Setup Chain level group...
  144             Enable, Action = [False, "close"]
  145             if FirstChain:
  146                 FirstChain = False
  147                 Enable, Action = [True, "open"]
  148             GenerateAndWritePMLForGroup(
  149                 OutFH,
  150                 PyMOLObjectNames["Chains"][ChainID]["ChainGroup"],
  151                 PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"],
  152                 Enable,
  153                 Action,
  154             )
  155 
  156         # Set up complex level group...
  157         Enable, Action = [False, "close"]
  158         if FirstComplex:
  159             FirstComplex = False
  160             Enable, Action = [True, "open"]
  161         GenerateAndWritePMLForGroup(
  162             OutFH, PyMOLObjectNames["PDBGroup"], PyMOLObjectNames["PDBGroupMembers"], Enable, Action
  163         )
  164 
  165         # Delete empty PyMOL objects...
  166         DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNames)
  167 
  168     if OptionsInfo["Align"]:
  169         DeleteAlignReference(OutFH)
  170 
  171     if FirstComplexFirstChainName is not None:
  172         OutFH.write("""\ncmd.orient("%s", animate = -1)\n""" % FirstComplexFirstChainName)
  173     else:
  174         OutFH.write("""\ncmd.orient("visible", animate = -1)\n""")
  175 
  176     OutFH.close()
  177 
  178     # Generate PSE file as needed...
  179     if OptionsInfo["PSEOut"]:
  180         GeneratePyMOLSessionFile()
  181 
  182 
  183 def WritePMLHeader(OutFH, ScriptName):
  184     """Write out PML setting up complex view."""
  185 
  186     HeaderInfo = PyMOLUtil.SetupPMLHeaderInfo(ScriptName)
  187     OutFH.write("%s\n" % HeaderInfo)
  188 
  189 
  190 def WritePyMOLParameters(OutFH):
  191     """Write out PyMOL global parameters."""
  192 
  193     PMLCmds = []
  194     PMLCmds.append("""cmd.set("transparency", %.2f, "", 0)""" % (OptionsInfo["SurfaceTransparency"]))
  195     PMLCmds.append("""cmd.set("label_font_id", %s)""" % (OptionsInfo["LabelFontID"]))
  196 
  197     PML = "\n".join(PMLCmds)
  198 
  199     OutFH.write("""\n""\n"Setting up PyMOL gobal parameters..."\n""\n""")
  200     OutFH.write("%s\n" % PML)
  201 
  202 
  203 def WriteAlignReference(OutFH):
  204     """Setup object for alignment reference."""
  205 
  206     RefFileInfo = OptionsInfo["RefFileInfo"]
  207     RefFile = RefFileInfo["RefFileName"]
  208     RefName = RefFileInfo["PyMOLObjectName"]
  209 
  210     PMLCmds = []
  211     PMLCmds.append("""cmd.load("%s", "%s")""" % (RefFile, RefName))
  212     PMLCmds.append("""cmd.hide("everything", "%s")""" % (RefName))
  213     PMLCmds.append("""cmd.disable("%s")""" % (RefName))
  214     PML = "\n".join(PMLCmds)
  215 
  216     OutFH.write("""\n""\n"Loading %s and setting up view for align reference..."\n""\n""" % RefFile)
  217     OutFH.write("%s\n" % PML)
  218 
  219 
  220 def WriteAlignComplex(OutFH, FileIndex, PyMOLObjectNames):
  221     """Setup alignment of complex to reference."""
  222 
  223     RefFileInfo = OptionsInfo["RefFileInfo"]
  224     RefName = RefFileInfo["PyMOLObjectName"]
  225 
  226     ComplexName = PyMOLObjectNames["Complex"]
  227 
  228     if re.match("^FirstChain$", OptionsInfo["AlignMode"], re.I):
  229         RefFirstChainID = RefFileInfo["ChainsAndLigandsInfo"]["ChainIDs"][0]
  230         RefAlignSelection = "%s and chain %s" % (RefName, RefFirstChainID)
  231 
  232         ComplexFirstChainID = RetrieveFirstChainID(FileIndex)
  233         ComplexAlignSelection = "%s and chain %s" % (ComplexName, ComplexFirstChainID)
  234     else:
  235         RefAlignSelection = RefName
  236         ComplexAlignSelection = ComplexName
  237 
  238     PML = PyMOLUtil.SetupPMLForAlignment(OptionsInfo["AlignMethod"], RefAlignSelection, ComplexAlignSelection)
  239     OutFH.write("""\n""\n"Aligning %s against reference %s ..."\n""\n""" % (ComplexAlignSelection, RefAlignSelection))
  240     OutFH.write("%s\n" % PML)
  241 
  242 
  243 def DeleteAlignReference(OutFH):
  244     """Delete alignment reference object."""
  245 
  246     RefName = OptionsInfo["RefFileInfo"]["PyMOLObjectName"]
  247     OutFH.write("""\n""\n"Deleting alignment reference object %s..."\n""\n""" % RefName)
  248     OutFH.write("""cmd.delete("%s")\n""" % RefName)
  249 
  250 
  251 def WriteComplexView(OutFH, FileIndex, PyMOLObjectNames, FirstComplex):
  252     """Write out PML for viewing polymer complex."""
  253 
  254     # Setup complex...
  255     Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
  256     PML = PyMOLUtil.SetupPMLForPolymerComplexView(PyMOLObjectNames["Complex"], Infile, True)
  257     OutFH.write("""\n""\n"Loading %s and setting up view for complex..."\n""\n""" % Infile)
  258     OutFH.write("%s\n" % PML)
  259 
  260     if OptionsInfo["Align"]:
  261         # No need to align complex on to itself...
  262         if not (re.match("^FirstInputFile$", OptionsInfo["AlignRefFile"], re.I) and FirstComplex):
  263             WriteAlignComplex(OutFH, FileIndex, PyMOLObjectNames)
  264 
  265     if OptionsInfo["SurfaceComplex"]:
  266         # Setup hydrophobic surface...
  267         PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(
  268             PyMOLObjectNames["ComplexHydrophobicSurface"],
  269             PyMOLObjectNames["Complex"],
  270             ColorPalette=OptionsInfo["SurfaceColorPalette"],
  271             Enable=False,
  272         )
  273         OutFH.write("\n%s\n" % PML)
  274 
  275     # Setup complex group...
  276     GenerateAndWritePMLForGroup(
  277         OutFH, PyMOLObjectNames["ComplexGroup"], PyMOLObjectNames["ComplexGroupMembers"], False, "close"
  278     )
  279 
  280 
  281 def WriteChainView(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  282     """Write out PML for viewing chain."""
  283 
  284     OutFH.write("""\n""\n"Setting up views for chain %s..."\n""\n""" % ChainID)
  285 
  286     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  287 
  288     # Setup chain complex group view...
  289     WriteChainComplexViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  290 
  291     # Setup chain view...
  292     WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  293 
  294     # Setup chain solvent view...
  295     PML = PyMOLUtil.SetupPMLForSolventView(PyMOLObjectNames["Chains"][ChainID]["Solvent"], ChainComplexName, False)
  296     OutFH.write("\n%s\n" % PML)
  297 
  298     # Setup chain inorganic view...
  299     PML = PyMOLUtil.SetupPMLForInorganicView(PyMOLObjectNames["Chains"][ChainID]["Inorganic"], ChainComplexName, False)
  300     OutFH.write("\n%s\n" % PML)
  301 
  302 
  303 def WriteChainComplexViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  304     """Write chain complex views."""
  305 
  306     # Setup chain complex...
  307     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  308     PML = PyMOLUtil.SetupPMLForPolymerChainComplexView(ChainComplexName, PyMOLObjectNames["Complex"], ChainID, True)
  309     OutFH.write("%s\n" % PML)
  310 
  311     if OptionsInfo["SurfaceChainComplex"]:
  312         # Setup hydrophobic surface...
  313         PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(
  314             PyMOLObjectNames["Chains"][ChainID]["ChainComplexHydrophobicSurface"],
  315             ChainComplexName,
  316             ColorPalette=OptionsInfo["SurfaceColorPalette"],
  317             Enable=False,
  318         )
  319         OutFH.write("\n%s\n" % PML)
  320 
  321     # Setup chain complex group...
  322     GenerateAndWritePMLForGroup(
  323         OutFH,
  324         PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"],
  325         PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"],
  326         False,
  327         "close",
  328     )
  329 
  330 
  331 def WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  332     """Write individual chain views."""
  333 
  334     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  335 
  336     # Setup a chain view...
  337     ChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
  338     PML = PyMOLUtil.SetupPMLForPolymerChainView(ChainName, ChainComplexName, True)
  339     OutFH.write("\n%s\n" % PML)
  340 
  341     ChainAloneGroupID = "ChainAloneGroup"
  342 
  343     for GroupType in ["Surface_Residues", "Buried_Residues"]:
  344         GroupID = re.sub("_", "", GroupType)
  345 
  346         ResiduesGroupID = "%s%sGroup" % (ChainAloneGroupID, GroupID)
  347         ResiduesGroupMembersID = "%sMembers" % (ResiduesGroupID)
  348 
  349         # Setup a chain view using residues selection...
  350         ResiduesChainNameID = "%sChain" % (ResiduesGroupID)
  351         ResiduesChainName = PyMOLObjectNames["Chains"][ChainID][ResiduesChainNameID]
  352         ChainResiduesSelection = GetChainResiduesSelection(FileIndex, ChainID, GroupType)
  353 
  354         Selection = "%s and chain %s and polymer and (%s)" % (ChainComplexName, ChainID, ChainResiduesSelection)
  355         PML = PyMOLUtil.SetupPMLForSelectionDisplayView(ResiduesChainName, Selection, "cartoon", Enable=False)
  356         OutFH.write("\n%s\n" % PML)
  357 
  358         WriteChainAloneResiduesGroupResiduesTypesView(
  359             GroupType, OutFH, FileIndex, PyMOLObjectNames, ChainID, ResiduesGroupID
  360         )
  361         WriteChainAloneResiduesGroupResiduesSurfacesView(
  362             GroupType, OutFH, FileIndex, PyMOLObjectNames, ChainID, ResiduesGroupID
  363         )
  364 
  365         # Setup residues group...
  366         GenerateAndWritePMLForGroup(
  367             OutFH,
  368             PyMOLObjectNames["Chains"][ChainID][ResiduesGroupID],
  369             PyMOLObjectNames["Chains"][ChainID][ResiduesGroupMembersID],
  370             True,
  371             "open",
  372         )
  373 
  374     # Setup chain group...
  375     GenerateAndWritePMLForGroup(
  376         OutFH,
  377         PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"],
  378         PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"],
  379         True,
  380         "open",
  381     )
  382 
  383 
  384 def WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNames, ChainID, LigandID):
  385     """Write out PML for viewing ligand in a chain."""
  386 
  387     GroupID = "Ligand"
  388     ComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  389 
  390     # Setup main object...
  391     GroupTypeObjectID = "%s" % (GroupID)
  392     GroupTypeObjectName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID]
  393 
  394     OutFH.write("""\n""\n"Setting up views for ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID))
  395     PML = PyMOLUtil.SetupPMLForLigandView(
  396         GroupTypeObjectName, ComplexName, LigandID, Enable=True, IgnoreHydrogens=OptionsInfo["IgnoreHydrogens"]
  397     )
  398     OutFH.write("%s\n" % PML)
  399 
  400     # Setup ball and stick view...
  401     BallAndStickNameID = "%sBallAndStick" % (GroupID)
  402     BallAndStickName = PyMOLObjectNames["Ligands"][ChainID][LigandID][BallAndStickNameID]
  403     PML = PyMOLUtil.SetupPMLForBallAndStickView(BallAndStickName, GroupTypeObjectName, Enable=False)
  404     OutFH.write("\n%s\n" % PML)
  405 
  406     # Setup group....
  407     GroupNameID = "%sGroup" % (GroupID)
  408     GroupMembersID = "%sGroupMembers" % (GroupID)
  409     GroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID]
  410     GroupMembers = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID]
  411 
  412     Action = "close"
  413     Enable = True
  414     GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable, Action)
  415 
  416 
  417 def GetChainResiduesSelection(FileIndex, ChainID, GroupType):
  418     """Get residue selection for surface or buried residues for a chain."""
  419 
  420     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  421     ResiduesSelection = (
  422         SpecifiedChainsAndLigandsInfo["SurfaceResiduesSelection"][ChainID]
  423         if re.match("^Surface_Residues$", GroupType, re.I)
  424         else SpecifiedChainsAndLigandsInfo["BuriedResiduesSelection"][ChainID]
  425     )
  426 
  427     return ResiduesSelection
  428 
  429 
  430 def WriteChainAloneResiduesGroupResiduesTypesView(GroupType, OutFH, FileIndex, PyMOLObjectNames, ChainID, MainGroupID):
  431     """Write out PML for viewing residue types for surface or buried residues in a chain."""
  432 
  433     if not GetChainAloneResidueTypesStatus(FileIndex, ChainID):
  434         return
  435 
  436     NameID = "%sChain" % (MainGroupID)
  437     ChainName = PyMOLObjectNames["Chains"][ChainID][NameID]
  438 
  439     ResiduesGroupID = "%sResiduesGroup" % MainGroupID
  440     ResiduesGroupMembersID = "%sMembers" % ResiduesGroupID
  441 
  442     # Setup residue types objects...
  443     for SubGroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
  444         SubGroupID = re.sub("_", "", SubGroupType)
  445 
  446         ResiduesSubGroupID = "%s%sGroup" % (ResiduesGroupID, SubGroupID)
  447         ResiduesSubGroupMembersID = "%sMembers" % (ResiduesSubGroupID)
  448 
  449         ResiduesObjectID = "%sResidues" % (ResiduesSubGroupID)
  450         ResiduesObjectName = PyMOLObjectNames["Chains"][ChainID][ResiduesObjectID]
  451 
  452         ResiduesSurfaceObjectID = "%sSurface" % (ResiduesSubGroupID)
  453         ResiduesSurfaceObjectName = PyMOLObjectNames["Chains"][ChainID][ResiduesSurfaceObjectID]
  454 
  455         ResiduesColor = OptionsInfo["ResidueTypesParams"][SubGroupType]["Color"]
  456         ResiduesNames = OptionsInfo["ResidueTypesParams"][SubGroupType]["Residues"]
  457 
  458         NegateResidueNames = True if re.match("^Other$", SubGroupType, re.I) else False
  459         WriteResidueTypesResiduesAndSurfaceView(
  460             OutFH,
  461             ChainName,
  462             ResiduesObjectName,
  463             ResiduesSurfaceObjectName,
  464             ResiduesColor,
  465             ResiduesNames,
  466             NegateResidueNames,
  467         )
  468 
  469         # Setup sub groups for residue types..
  470         GenerateAndWritePMLForGroup(
  471             OutFH,
  472             PyMOLObjectNames["Chains"][ChainID][ResiduesSubGroupID],
  473             PyMOLObjectNames["Chains"][ChainID][ResiduesSubGroupMembersID],
  474             True,
  475             "close",
  476         )
  477 
  478     # Setup residues group...
  479     GenerateAndWritePMLForGroup(
  480         OutFH,
  481         PyMOLObjectNames["Chains"][ChainID][ResiduesGroupID],
  482         PyMOLObjectNames["Chains"][ChainID][ResiduesGroupMembersID],
  483         False,
  484         "close",
  485     )
  486 
  487 
  488 def WriteResidueTypesResiduesAndSurfaceView(
  489     OutFH, SelectionObjectName, Name, SurfaceName, ResiduesColor, ResiduesNames, NegateResidueNames
  490 ):
  491     """Write residue types residues and surface view."""
  492 
  493     ResidueNamesSelection = "+".join(ResiduesNames)
  494     if NegateResidueNames:
  495         Selection = "%s and (not resn %s)" % (SelectionObjectName, ResidueNamesSelection)
  496     else:
  497         Selection = "%s and (resn %s)" % (SelectionObjectName, ResidueNamesSelection)
  498 
  499     # Setup residues...
  500     PML = PyMOLUtil.SetupPMLForSelectionDisplayView(Name, Selection, "lines", ResiduesColor, True)
  501     OutFH.write("\n%s\n" % PML)
  502 
  503     # Setup surface...
  504     PML = PyMOLUtil.SetupPMLForSelectionDisplayView(SurfaceName, Selection, "surface", ResiduesColor, True)
  505     OutFH.write("\n%s\n" % PML)
  506 
  507 
  508 def WriteChainAloneResiduesGroupResiduesSurfacesView(
  509     GroupType, OutFH, FileIndex, PyMOLObjectNames, ChainID, MainGroupID
  510 ):
  511     """Write out PML for viewing surfaces for surface and buried residues in chains."""
  512 
  513     if not GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
  514         return
  515 
  516     NameID = "%sChain" % (MainGroupID)
  517     ChainName = PyMOLObjectNames["Chains"][ChainID][NameID]
  518 
  519     SurfacesGroupID = "%sSurfaceGroup" % MainGroupID
  520     SurfacesGroupMembersID = "%sMembers" % SurfacesGroupID
  521 
  522     ProcessingBuriedResidues = True if re.match("^Buried_Residues$", GroupType, re.I) else False
  523 
  524     # Setup a generic color surface...
  525     SurfaceID = "%sSurface" % (SurfacesGroupID)
  526     SurfaceName = PyMOLObjectNames["Chains"][ChainID][SurfaceID]
  527     ColorName = OptionsInfo["SurfaceBuriedResiduesColor"] if ProcessingBuriedResidues else OptionsInfo["SurfaceColor"]
  528     PML = PyMOLUtil.SetupPMLForSurfaceView(SurfaceName, ChainName, Enable=True, DisplayAs=None, Color=ColorName)
  529     OutFH.write("\n%s\n" % PML)
  530 
  531     if GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
  532         # Setup surface colored by hydrophobicity...
  533         HydrophobicSurfaceID = "%sHydrophobicSurface" % (SurfacesGroupID)
  534         HydrophobicSurfaceName = PyMOLObjectNames["Chains"][ChainID][HydrophobicSurfaceID]
  535         PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(
  536             HydrophobicSurfaceName,
  537             ChainName,
  538             ColorPalette=OptionsInfo["SurfaceColorPalette"],
  539             Enable=False,
  540             DisplayAs=None,
  541         )
  542         OutFH.write("\n%s\n" % PML)
  543 
  544         # Setup surface colored by hyrdophobicity and charge...
  545         HydrophobicChargeSurfaceID = "%sHydrophobicChargeSurface" % (SurfacesGroupID)
  546         HydrophobicChargeSurfaceName = PyMOLObjectNames["Chains"][ChainID][HydrophobicChargeSurfaceID]
  547         PML = PyMOLUtil.SetupPMLForHydrophobicAndChargeSurfaceView(
  548             HydrophobicChargeSurfaceName,
  549             ChainName,
  550             OptionsInfo["AtomTypesColorNames"]["HydrophobicAtomsColor"],
  551             OptionsInfo["AtomTypesColorNames"]["NegativelyChargedAtomsColor"],
  552             OptionsInfo["AtomTypesColorNames"]["PositivelyChargedAtomsColor"],
  553             OptionsInfo["AtomTypesColorNames"]["OtherAtomsColor"],
  554             Enable=False,
  555             DisplayAs=None,
  556         )
  557         OutFH.write("\n%s\n" % PML)
  558 
  559         if GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
  560             # Setup electrostatics surface...
  561             ElectrostaticsGroupID = "%sElectrostaticsGroup" % (SurfacesGroupID)
  562             ElectrostaticsGroupMembersID = "%sMembers" % (ElectrostaticsGroupID)
  563             ElectrostaticsGroupName = PyMOLObjectNames["Chains"][ChainID][ElectrostaticsGroupID]
  564             ElectrostaticsGroupMembers = PyMOLObjectNames["Chains"][ChainID][ElectrostaticsGroupMembersID]
  565             WriteSurfaceElectrostaticsView(
  566                 OutFH, ChainName, ElectrostaticsGroupName, ElectrostaticsGroupMembers, DisplayAs=None
  567             )
  568 
  569     # Setup surfaces group...
  570     GenerateAndWritePMLForGroup(
  571         OutFH,
  572         PyMOLObjectNames["Chains"][ChainID][SurfacesGroupID],
  573         PyMOLObjectNames["Chains"][ChainID][SurfacesGroupMembersID],
  574         True,
  575         "close",
  576     )
  577 
  578 
  579 def WriteSurfaceElectrostaticsView(
  580     OutFH, SelectionObjectName, ElectrostaticsGroupName, ElectrostaticsGroupMembers, DisplayAs="lines"
  581 ):
  582     """Write out PML for viewing surface electrostatics."""
  583 
  584     if len(ElectrostaticsGroupMembers) == 5:
  585         Name, ContactPotentialName, MapName, LegendName, VolumeName = ElectrostaticsGroupMembers
  586     else:
  587         Name, ContactPotentialName, MapName, LegendName = ElectrostaticsGroupMembers
  588         VolumeName = None
  589 
  590     PMLCmds = []
  591 
  592     # Setup chain...
  593     PMLCmds.append("""cmd.create("%s", "(%s)")""" % (Name, SelectionObjectName))
  594 
  595     # Setup vacuum electrostatics surface along with associated objects...
  596     PMLCmds.append("""util.protein_vacuum_esp("%s", mode=2, quiet=0, _self=cmd)""" % (Name))
  597     PMLCmds.append("""cmd.set_name("%s_e_chg", "%s")""" % (Name, ContactPotentialName))
  598 
  599     if DisplayAs is not None:
  600         PMLCmds.append("""cmd.show("%s", "(%s)")""" % (DisplayAs, ContactPotentialName))
  601 
  602     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(ContactPotentialName, Enable=True))
  603 
  604     PMLCmds.append("""cmd.set_name("%s_e_map", "%s")""" % (Name, MapName))
  605     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(MapName, Enable=False))
  606 
  607     PMLCmds.append("""cmd.set_name("%s_e_pot", "%s")""" % (Name, LegendName))
  608     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(LegendName, Enable=False))
  609 
  610     if VolumeName is not None:
  611         PMLCmds.append("""cmd.volume("%s", "%s", "%s", "(%s)")""" % (VolumeName, MapName, "esp", Name))
  612         PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(VolumeName, Enable=False))
  613 
  614     # Delete name and take it out from the group membership. It is
  615     # is already part of ContactPotential object.
  616     PMLCmds.append("""cmd.delete("%s")""" % (Name))
  617     ElectrostaticsGroupMembers.pop(0)
  618 
  619     PML = "\n".join(PMLCmds)
  620 
  621     OutFH.write("\n%s\n" % PML)
  622 
  623     # Setup group...
  624     GenerateAndWritePMLForGroup(OutFH, ElectrostaticsGroupName, ElectrostaticsGroupMembers, False, "close")
  625 
  626 
  627 def GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable=False, Action="close"):
  628     """Generate and write PML for group."""
  629 
  630     PML = PyMOLUtil.SetupPMLForGroup(GroupName, GroupMembers, Enable, Action)
  631     OutFH.write("""\n""\n"Setting up group %s..."\n""\n""" % GroupName)
  632     OutFH.write("%s\n" % PML)
  633 
  634 
  635 def GeneratePyMOLSessionFile():
  636     """Generate PME file from PML file."""
  637 
  638     PSEOutfile = OptionsInfo["PSEOutfile"]
  639     PMLOutfile = OptionsInfo["PMLOutfile"]
  640 
  641     MiscUtil.PrintInfo("\nGenerating file %s..." % PSEOutfile)
  642 
  643     PyMOLUtil.ConvertPMLFileToPSEFile(PMLOutfile, PSEOutfile)
  644 
  645     if not os.path.exists(PSEOutfile):
  646         MiscUtil.PrintWarning("Failed to generate PSE file, %s..." % (PSEOutfile))
  647 
  648     if not OptionsInfo["PMLOut"]:
  649         MiscUtil.PrintInfo("Deleting file %s..." % PMLOutfile)
  650         os.remove(PMLOutfile)
  651 
  652 
  653 def DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNames):
  654     """Delete empty PyMOL objects."""
  655 
  656     if OptionsInfo["AllowEmptyObjects"]:
  657         return
  658 
  659     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  660     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  661         OutFH.write("""\n""\n"Checking and deleting empty objects for chain %s..."\n""\n""" % (ChainID))
  662 
  663         # Delete any chain level objects...
  664         WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Solvent"])
  665         WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Inorganic"])
  666 
  667         # Delete any chain alone level objects
  668         ChainAloneGroupID = "ChainAloneGroup"
  669 
  670         for GroupType in ["Surface_Residues", "Buried_Residues"]:
  671             GroupID = re.sub("_", "", GroupType)
  672             ResiduesGroupID = "%s%sGroup" % (ChainAloneGroupID, GroupID)
  673 
  674             # Delete empty chain object...
  675             ResiduesChainNameID = "%sChain" % (ResiduesGroupID)
  676             WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID][ResiduesChainNameID])
  677 
  678             # Delete empty residue type objects...
  679             DeleteEmptyChainAloneResiduesGroupResiduesTypesObjects(
  680                 GroupType, OutFH, FileIndex, PyMOLObjectNames, ChainID, ResiduesGroupID
  681             )
  682 
  683             # Delete empty surface objects...
  684             DeleteEmptyAloneResiduesGroupResiduesSurfacesObjects(
  685                 GroupType, OutFH, FileIndex, PyMOLObjectNames, ChainID, ResiduesGroupID
  686             )
  687 
  688 
  689 def DeleteEmptyChainAloneResiduesGroupResiduesTypesObjects(
  690     GroupType, OutFH, FileIndex, PyMOLObjectNames, ChainID, MainGroupID
  691 ):
  692     """Delete empty residue type objects for surface or buried residues in a chain."""
  693 
  694     if not GetChainAloneResidueTypesStatus(FileIndex, ChainID):
  695         return
  696 
  697     ResiduesGroupID = "%sResiduesGroup" % MainGroupID
  698     for SubGroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
  699         SubGroupID = re.sub("_", "", SubGroupType)
  700 
  701         ResiduesSubGroupID = "%s%sGroup" % (ResiduesGroupID, SubGroupID)
  702         SubGroupName = PyMOLObjectNames["Chains"][ChainID][ResiduesSubGroupID]
  703 
  704         SubGroupObjectNamesList = []
  705 
  706         ResiduesObjectID = "%sResidues" % (ResiduesSubGroupID)
  707         ResiduesObjectName = PyMOLObjectNames["Chains"][ChainID][ResiduesObjectID]
  708         SubGroupObjectNamesList.append(ResiduesObjectName)
  709 
  710         ResiduesSurfaceObjectID = "%sSurface" % (ResiduesSubGroupID)
  711         ResiduesSurfaceObjectName = PyMOLObjectNames["Chains"][ChainID][ResiduesSurfaceObjectID]
  712         SubGroupObjectNamesList.append(ResiduesSurfaceObjectName)
  713 
  714         SubGroupObjectNames = ",".join(SubGroupObjectNamesList)
  715         WritePMLToCheckAndDeleteEmptyObjects(OutFH, SubGroupObjectNames, SubGroupName)
  716 
  717     # Delete residues group object...
  718     DeleteResiduesGroup = (
  719         False if AreGroupTypeResiduesPresent(GroupType, FileIndex, PyMOLObjectNames, ChainID) else True
  720     )
  721     if DeleteResiduesGroup:
  722         OutFH.write("""cmd.delete("%s")\n""" % PyMOLObjectNames["Chains"][ChainID][ResiduesGroupID])
  723 
  724 
  725 def DeleteEmptyAloneResiduesGroupResiduesSurfacesObjects(
  726     GroupType, OutFH, FileIndex, PyMOLObjectNames, ChainID, MainGroupID
  727 ):
  728     """Delete empty surfaces objects for surface or buried residues in a chain."""
  729 
  730     if not GetChainAloneResidueTypesStatus(FileIndex, ChainID):
  731         return
  732 
  733     if AreGroupTypeResiduesPresent(GroupType, FileIndex, PyMOLObjectNames, ChainID):
  734         return
  735 
  736     SurfacesGroupID = "%sSurfaceGroup" % MainGroupID
  737 
  738     # Delete plain surface...
  739     SurfaceID = "%sSurface" % (SurfacesGroupID)
  740     WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID][SurfaceID])
  741 
  742     if GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
  743         HydrophobicSurfaceID = "%sHydrophobicSurface" % (SurfacesGroupID)
  744         WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID][HydrophobicSurfaceID])
  745 
  746         HydrophobicChargeSurfaceID = "%sHydrophobicChargeSurface" % (SurfacesGroupID)
  747         WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID][HydrophobicChargeSurfaceID])
  748 
  749         if GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
  750             ElectrostaticsGroupID = "%sElectrostaticsGroup" % (SurfacesGroupID)
  751             ElectrostaticsGroupMembersID = "%sMembers" % (ElectrostaticsGroupID)
  752 
  753             ElectrostaticsGroupName = PyMOLObjectNames["Chains"][ChainID][ElectrostaticsGroupID]
  754             ElectrostaticsGroupMembers = PyMOLObjectNames["Chains"][ChainID][ElectrostaticsGroupMembersID]
  755             ElectrostaticsGroupMembersNames = ",".join(ElectrostaticsGroupMembers)
  756             WritePMLToCheckAndDeleteEmptyObjects(OutFH, ElectrostaticsGroupMembersNames, ElectrostaticsGroupName)
  757 
  758     # Delete surface group...
  759     OutFH.write("""cmd.delete("%s")\n""" % PyMOLObjectNames["Chains"][ChainID][SurfacesGroupID])
  760 
  761 
  762 def AreGroupTypeResiduesPresent(GroupType, FileIndex, PyMOLObjectNames, ChainID):
  763     """Check presence of surface or buries residue groups in a chain."""
  764 
  765     GroupTypeResiduesPresent = True
  766 
  767     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  768 
  769     if re.match("^Surface_Residues$", GroupType, re.I):
  770         GroupTypeResiduesPresent = SpecifiedChainsAndLigandsInfo["SurfaceResiduesPresent"][ChainID]
  771     elif re.match("^Buried_Residues$", GroupType, re.I):
  772         GroupTypeResiduesPresent = SpecifiedChainsAndLigandsInfo["BuriedResiduesPresent"][ChainID]
  773 
  774     return GroupTypeResiduesPresent
  775 
  776 
  777 def WritePMLToCheckAndDeleteEmptyObjects(OutFH, ObjectName, ParentObjectName=None):
  778     """Write PML to check and delete empty PyMOL objects."""
  779 
  780     if ParentObjectName is None:
  781         PML = """CheckAndDeleteEmptyObjects("%s")""" % (ObjectName)
  782     else:
  783         PML = """CheckAndDeleteEmptyObjects("%s", "%s")""" % (ObjectName, ParentObjectName)
  784 
  785     OutFH.write("%s\n" % PML)
  786 
  787 
  788 def SetupPyMOLObjectNames(FileIndex):
  789     """Setup hierarchy of PyMOL groups and objects for ligand centric views of
  790     chains and ligands present in input file.
  791     """
  792 
  793     PyMOLObjectNames = {}
  794     PyMOLObjectNames["Chains"] = {}
  795     PyMOLObjectNames["Ligands"] = {}
  796 
  797     # Setup groups and objects for complex...
  798     SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames)
  799 
  800     # Setup groups and objects for chain...
  801     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  802     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  803         SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID)
  804 
  805         # Setup groups and objects for ligand...
  806         for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
  807             SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID)
  808 
  809     return PyMOLObjectNames
  810 
  811 
  812 def SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames):
  813     """Setup groups and objects for complex."""
  814 
  815     PDBFileRoot = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
  816 
  817     PDBGroupName = "%s" % PDBFileRoot
  818     PyMOLObjectNames["PDBGroup"] = PDBGroupName
  819     PyMOLObjectNames["PDBGroupMembers"] = []
  820 
  821     ComplexGroupName = "%s.Complex" % PyMOLObjectNames["PDBGroup"]
  822     PyMOLObjectNames["ComplexGroup"] = ComplexGroupName
  823     PyMOLObjectNames["PDBGroupMembers"].append(ComplexGroupName)
  824 
  825     PyMOLObjectNames["Complex"] = "%s.Complex" % ComplexGroupName
  826     if OptionsInfo["SurfaceComplex"]:
  827         PyMOLObjectNames["ComplexHydrophobicSurface"] = "%s.Surface" % ComplexGroupName
  828 
  829     PyMOLObjectNames["ComplexGroupMembers"] = []
  830     PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["Complex"])
  831     if OptionsInfo["SurfaceComplex"]:
  832         PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["ComplexHydrophobicSurface"])
  833 
  834 
  835 def SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID):
  836     """Setup groups and objects for chain."""
  837 
  838     PDBGroupName = PyMOLObjectNames["PDBGroup"]
  839 
  840     PyMOLObjectNames["Chains"][ChainID] = {}
  841     PyMOLObjectNames["Ligands"][ChainID] = {}
  842 
  843     # Set up chain group and chain objects...
  844     ChainGroupName = "%s.Chain%s" % (PDBGroupName, ChainID)
  845     PyMOLObjectNames["Chains"][ChainID]["ChainGroup"] = ChainGroupName
  846     PyMOLObjectNames["PDBGroupMembers"].append(ChainGroupName)
  847     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"] = []
  848 
  849     # Setup chain complex group and objects...
  850     ChainComplexGroupName = "%s.Complex" % (ChainGroupName)
  851     PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"] = ChainComplexGroupName
  852     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainComplexGroupName)
  853 
  854     PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"] = []
  855 
  856     Name = "%s.Complex" % (ChainComplexGroupName)
  857     PyMOLObjectNames["Chains"][ChainID]["ChainComplex"] = Name
  858     PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"].append(Name)
  859 
  860     if OptionsInfo["SurfaceChainComplex"]:
  861         Name = "%s.Surface" % (ChainComplexGroupName)
  862         PyMOLObjectNames["Chains"][ChainID]["ChainComplexHydrophobicSurface"] = Name
  863         PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"].append(Name)
  864 
  865     # Setup up a group for individual chains...
  866     ChainAloneGroupName = "%s.Chain" % (ChainGroupName)
  867     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"] = ChainAloneGroupName
  868     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainAloneGroupName)
  869 
  870     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"] = []
  871 
  872     Name = "%s.Chain" % (ChainAloneGroupName)
  873     PyMOLObjectNames["Chains"][ChainID]["ChainAlone"] = Name
  874     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(Name)
  875 
  876     # Setup groups and their members for surface and buried residues...
  877     ChainAloneGroupID = "ChainAloneGroup"
  878     for GroupType in ["Surface_Residues", "Buried_Residues"]:
  879         GroupID = re.sub("_", "", GroupType)
  880 
  881         ResiduesGroupName = "%s.%s" % (ChainAloneGroupName, GroupType)
  882         ResiduesGroupID = "%s%sGroup" % (ChainAloneGroupID, GroupID)
  883         ResiduesGroupMembersID = "%sMembers" % (ResiduesGroupID)
  884 
  885         PyMOLObjectNames["Chains"][ChainID][ResiduesGroupID] = ResiduesGroupName
  886         PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(ResiduesGroupName)
  887 
  888         PyMOLObjectNames["Chains"][ChainID][ResiduesGroupMembersID] = []
  889 
  890         # Add a chain for surface and buried residues...
  891         Name = "%s.Chain" % (ResiduesGroupName)
  892         NameID = "%sChain" % (ResiduesGroupID)
  893         PyMOLObjectNames["Chains"][ChainID][NameID] = Name
  894         PyMOLObjectNames["Chains"][ChainID][ResiduesGroupMembersID].append(Name)
  895 
  896         SetupPyMOLObjectNamesForChainResiduesTypes(
  897             FileIndex, PyMOLObjectNames, ChainID, ResiduesGroupName, ResiduesGroupID, ResiduesGroupMembersID
  898         )
  899         SetupPyMOLObjectNamesForChainResiduesSurfaces(
  900             FileIndex, PyMOLObjectNames, ChainID, ResiduesGroupName, ResiduesGroupID, ResiduesGroupMembersID
  901         )
  902 
  903     # Setup solvent and inorganic objects for chain...
  904     for NameID in ["Solvent", "Inorganic"]:
  905         Name = "%s.%s" % (ChainGroupName, NameID)
  906         PyMOLObjectNames["Chains"][ChainID][NameID] = Name
  907         PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(Name)
  908 
  909 
  910 def SetupPyMOLObjectNamesForChainResiduesTypes(
  911     FileIndex, PyMOLObjectNames, ChainID, MainGroupName, MainGroupID, MainGroupMembersID
  912 ):
  913     """Setup residue type groups and its objects for residues."""
  914 
  915     if not GetChainAloneResidueTypesStatus(FileIndex, ChainID):
  916         return
  917 
  918     ResiduesGroupName = "%s.Residues" % (MainGroupName)
  919     ResiduesGroupID = "%sResiduesGroup" % MainGroupID
  920     ResiduesGroupMembersID = "%sMembers" % ResiduesGroupID
  921 
  922     # Add residue type group to residues group...
  923     PyMOLObjectNames["Chains"][ChainID][ResiduesGroupID] = ResiduesGroupName
  924     PyMOLObjectNames["Chains"][ChainID][MainGroupMembersID].append(ResiduesGroupName)
  925 
  926     # Initialize residue type group members...
  927     PyMOLObjectNames["Chains"][ChainID][ResiduesGroupMembersID] = []
  928 
  929     # Setup residues sub groups and its members...
  930     for SubGroupType in ["Aromatic", "Hydrophobic", "Polar", "Positively_Charged", "Negatively_Charged", "Other"]:
  931         SubGroupID = re.sub("_", "", SubGroupType)
  932 
  933         ResiduesSubGroupName = "%s.%s" % (ResiduesGroupName, SubGroupType)
  934         ResiduesSubGroupID = "%s%sGroup" % (ResiduesGroupID, SubGroupID)
  935         ResiduesSubGroupMembersID = "%sMembers" % (ResiduesSubGroupID)
  936 
  937         # Add sub group to residues group...
  938         PyMOLObjectNames["Chains"][ChainID][ResiduesSubGroupID] = ResiduesSubGroupName
  939         PyMOLObjectNames["Chains"][ChainID][ResiduesGroupMembersID].append(ResiduesSubGroupName)
  940 
  941         # Initialize sub group members...
  942         PyMOLObjectNames["Chains"][ChainID][ResiduesSubGroupMembersID] = []
  943 
  944         # Add sub group members to subgroup...
  945         for MemberType in ["Residues", "Surface"]:
  946             MemberID = re.sub("_", "", MemberType)
  947 
  948             SubGroupMemberName = "%s.%s" % (ResiduesSubGroupName, MemberType)
  949             SubGroupMemberID = "%s%s" % (ResiduesSubGroupID, MemberID)
  950 
  951             PyMOLObjectNames["Chains"][ChainID][SubGroupMemberID] = SubGroupMemberName
  952             PyMOLObjectNames["Chains"][ChainID][ResiduesSubGroupMembersID].append(SubGroupMemberName)
  953 
  954 
  955 def SetupPyMOLObjectNamesForChainResiduesSurfaces(
  956     FileIndex, PyMOLObjectNames, ChainID, MainGroupName, MainGroupID, MainGroupMembersID
  957 ):
  958     """Setup residue surface groups and its objects for residues."""
  959 
  960     if not GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
  961         return
  962 
  963     SubGroupName = "%s.Surface" % (MainGroupName)
  964     SubGroupID = "%sSurfaceGroup" % MainGroupID
  965     SubGroupMembersID = "%sMembers" % SubGroupID
  966 
  967     # Add surface group to main group...
  968     PyMOLObjectNames["Chains"][ChainID][SubGroupID] = SubGroupName
  969     PyMOLObjectNames["Chains"][ChainID][MainGroupMembersID].append(SubGroupName)
  970 
  971     # Initialize surface group members...
  972     PyMOLObjectNames["Chains"][ChainID][SubGroupMembersID] = []
  973 
  974     # Setup a generic color surface...
  975     SurfaceName = "%s.Surface" % (SubGroupName)
  976     SurfaceID = "%sSurface" % (SubGroupID)
  977     PyMOLObjectNames["Chains"][ChainID][SurfaceID] = SurfaceName
  978     PyMOLObjectNames["Chains"][ChainID][SubGroupMembersID].append(SurfaceName)
  979 
  980     if GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
  981         # Setup hydrophobicity surface...
  982         HydrophobicSurfaceName = "%s.Hydrophobicity" % (SubGroupName)
  983         HydrophobicSurfaceID = "%sHydrophobicSurface" % (SubGroupID)
  984         PyMOLObjectNames["Chains"][ChainID][HydrophobicSurfaceID] = HydrophobicSurfaceName
  985         PyMOLObjectNames["Chains"][ChainID][SubGroupMembersID].append(HydrophobicSurfaceName)
  986 
  987         # Setup hydrophobicity and charge surface...
  988         HydrophobicChargeSurfaceName = "%s.Hydrophobicity_Charge" % (SubGroupName)
  989         HydrophobicChargeSurfaceID = "%sHydrophobicChargeSurface" % (SubGroupID)
  990         PyMOLObjectNames["Chains"][ChainID][HydrophobicChargeSurfaceID] = HydrophobicChargeSurfaceName
  991         PyMOLObjectNames["Chains"][ChainID][SubGroupMembersID].append(HydrophobicChargeSurfaceName)
  992 
  993         if GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
  994             # Setup electrostatics group...
  995             ElectrostaticsGroupName = "%s.Vacuum_Electrostatics" % (SubGroupName)
  996             ElectrostaticsGroupID = "%sElectrostaticsGroup" % (SubGroupID)
  997             ElectrostaticsGroupMembersID = "%sElectrostaticsGroupMembers" % (SubGroupID)
  998 
  999             PyMOLObjectNames["Chains"][ChainID][ElectrostaticsGroupID] = ElectrostaticsGroupName
 1000             PyMOLObjectNames["Chains"][ChainID][SubGroupMembersID].append(ElectrostaticsGroupName)
 1001 
 1002             # Setup electrostatics group members...
 1003             PyMOLObjectNames["Chains"][ChainID][ElectrostaticsGroupMembersID] = []
 1004 
 1005             for MemberType in ["Chain", "Contact_Potential", "Map", "Legend"]:
 1006                 MemberID = re.sub("_", "", MemberType)
 1007 
 1008                 Name = "%s.%s" % (ElectrostaticsGroupName, MemberType)
 1009                 NameID = "%s%s" % (ElectrostaticsGroupID, MemberID)
 1010 
 1011                 PyMOLObjectNames["Chains"][ChainID][NameID] = Name
 1012                 PyMOLObjectNames["Chains"][ChainID][ElectrostaticsGroupMembersID].append(Name)
 1013 
 1014 
 1015 def SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID):
 1016     """Stetup groups and objects for ligand."""
 1017 
 1018     PyMOLObjectNames["Ligands"][ChainID][LigandID] = {}
 1019 
 1020     ChainGroupName = PyMOLObjectNames["Chains"][ChainID]["ChainGroup"]
 1021 
 1022     # Setup a chain level ligand group...
 1023     ChainLigandGroupName = "%s.Ligand%s" % (ChainGroupName, LigandID)
 1024     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroup"] = ChainLigandGroupName
 1025     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainLigandGroupName)
 1026 
 1027     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"] = []
 1028 
 1029     # Set up ligand group and its members...
 1030     GroupName = "%s.Ligand" % (ChainLigandGroupName)
 1031     GroupNameID = "LigandGroup"
 1032     GroupMembersID = "LigandGroupMembers"
 1033 
 1034     PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID] = GroupName
 1035     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"].append(GroupName)
 1036 
 1037     LigandName = "%s.Ligand" % (GroupName)
 1038     LigandNameID = "Ligand"
 1039     PyMOLObjectNames["Ligands"][ChainID][LigandID][LigandNameID] = LigandName
 1040 
 1041     PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID] = []
 1042     PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(LigandName)
 1043 
 1044     # Add ball and stick...
 1045     BallAndStickName = "%s.BallAndStick" % (GroupName)
 1046     BallAndStickID = "LigandBallAndStick"
 1047     PyMOLObjectNames["Ligands"][ChainID][LigandID][BallAndStickID] = BallAndStickName
 1048     PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(BallAndStickName)
 1049 
 1050 
 1051 def RetrieveInfilesInfo():
 1052     """Retrieve information for input files."""
 1053 
 1054     InfilesInfo = {}
 1055 
 1056     InfilesInfo["InfilesNames"] = []
 1057     InfilesInfo["InfilesRoots"] = []
 1058     InfilesInfo["ChainsAndLigandsInfo"] = []
 1059 
 1060     for Infile in OptionsInfo["InfilesNames"]:
 1061         FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
 1062         InfileRoot = FileName
 1063 
 1064         ChainsAndLigandInfo = PyMOLUtil.GetChainsAndLigandsInfo(Infile, InfileRoot)
 1065 
 1066         InfilesInfo["InfilesNames"].append(Infile)
 1067         InfilesInfo["InfilesRoots"].append(InfileRoot)
 1068         InfilesInfo["ChainsAndLigandsInfo"].append(ChainsAndLigandInfo)
 1069 
 1070     OptionsInfo["InfilesInfo"] = InfilesInfo
 1071 
 1072 
 1073 def RetrieveRefFileInfo():
 1074     """Retrieve information for ref file."""
 1075 
 1076     RefFileInfo = {}
 1077     if not OptionsInfo["Align"]:
 1078         OptionsInfo["RefFileInfo"] = RefFileInfo
 1079         return
 1080 
 1081     RefFile = OptionsInfo["RefFileName"]
 1082 
 1083     FileDir, FileName, FileExt = MiscUtil.ParseFileName(RefFile)
 1084     RefFileRoot = FileName
 1085 
 1086     if re.match("^FirstInputFile$", OptionsInfo["AlignRefFile"], re.I):
 1087         ChainsAndLigandInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][0]
 1088     else:
 1089         MiscUtil.PrintInfo("\nRetrieving chain and ligand information for alignment reference file %s..." % RefFile)
 1090         ChainsAndLigandInfo = PyMOLUtil.GetChainsAndLigandsInfo(RefFile, RefFileRoot)
 1091 
 1092     RefFileInfo["RefFileName"] = RefFile
 1093     RefFileInfo["RefFileRoot"] = RefFileRoot
 1094     RefFileInfo["PyMOLObjectName"] = "AlignRef_%s" % RefFileRoot
 1095     RefFileInfo["ChainsAndLigandsInfo"] = ChainsAndLigandInfo
 1096 
 1097     OptionsInfo["RefFileInfo"] = RefFileInfo
 1098 
 1099 
 1100 def ProcessChainAndLigandIDs():
 1101     """Process specified chain and ligand IDs for infiles."""
 1102 
 1103     OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"] = []
 1104 
 1105     for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
 1106         MiscUtil.PrintInfo(
 1107             "\nProcessing specified chain and ligand IDs for input file %s..."
 1108             % OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
 1109         )
 1110 
 1111         ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
 1112         SpecifiedChainsAndLigandsInfo = PyMOLUtil.ProcessChainsAndLigandsOptionsInfo(
 1113             ChainsAndLigandsInfo, "-c, --chainIDs", OptionsInfo["ChainIDs"], "-l, --ligandIDs", OptionsInfo["LigandIDs"]
 1114         )
 1115         ProcessResidueTypesAndSurfaceOptions(FileIndex, SpecifiedChainsAndLigandsInfo)
 1116         OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"].append(SpecifiedChainsAndLigandsInfo)
 1117 
 1118         CheckPresenceOfValidLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo)
 1119 
 1120 
 1121 def RetrieveSurfaceAndBuriedResiduesInfo():
 1122     """Setup surface and buried residues for specified chains."""
 1123 
 1124     for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
 1125         Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
 1126         MolName = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
 1127 
 1128         MiscUtil.PrintInfo("\nRetrieving surface and buried residues from input file %s..." % Infile)
 1129 
 1130         # Load infile...
 1131         pymol.cmd.load(Infile, MolName)
 1132 
 1133         SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
 1134 
 1135         # Initialize surface and buried residues selection...
 1136         SpecifiedChainsAndLigandsInfo["SurfaceResiduesPresent"] = {}
 1137         SpecifiedChainsAndLigandsInfo["SurfaceResiduesSelection"] = {}
 1138         SpecifiedChainsAndLigandsInfo["BuriedResiduesSelection"] = {}
 1139         SpecifiedChainsAndLigandsInfo["BuriedResiduesPresent"] = {}
 1140 
 1141         # Go over all specified chains...
 1142         for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
 1143             SurfaceResiduesInfo, BuriedResiduesInfo = PyMOLUtil.GetSurfaceAndBuriedResiduesInfo(
 1144                 MolName, ChainID, OptionsInfo["CutoffSASA"]
 1145             )
 1146 
 1147             # Retrieve surface and buried residue numbers...
 1148             SurfaceResiduesNums = RetrieveResiduesNumbers(SurfaceResiduesInfo)
 1149             BuriedResiduesNums = RetrieveResiduesNumbers(BuriedResiduesInfo)
 1150 
 1151             # Setup PyMOL selection for surface and buried residue numbers...
 1152             SurfaceResiduesSelection, BuriedResiduesSelection = SetupSurfaceAndBuriedResiduesSelection(
 1153                 SurfaceResiduesNums, BuriedResiduesNums
 1154             )
 1155 
 1156             # Track surface and buried residues...
 1157             SpecifiedChainsAndLigandsInfo["SurfaceResiduesPresent"][ChainID] = (
 1158                 True if len(SurfaceResiduesNums) else False
 1159             )
 1160             SpecifiedChainsAndLigandsInfo["SurfaceResiduesSelection"][ChainID] = SurfaceResiduesSelection
 1161 
 1162             SpecifiedChainsAndLigandsInfo["BuriedResiduesPresent"][ChainID] = True if len(BuriedResiduesNums) else False
 1163             SpecifiedChainsAndLigandsInfo["BuriedResiduesSelection"][ChainID] = BuriedResiduesSelection
 1164 
 1165             # List surface residues...
 1166             SurfaceResiduesCount, SurfaceResiduesDistribution, SurfaceResiduesIDs = FormatResiduesInfo(
 1167                 SurfaceResiduesInfo
 1168             )
 1169             MiscUtil.PrintInfo(
 1170                 "\nInput file: %s; ChainID: %s\nNumber of surface residues: %d"
 1171                 % (Infile, ChainID, SurfaceResiduesCount)
 1172             )
 1173             MiscUtil.PrintInfo("Residue distribution: %s" % (SurfaceResiduesDistribution))
 1174             if OptionsInfo["ResidueIDs"]:
 1175                 MiscUtil.PrintInfo("Residue IDs: %s" % (SurfaceResiduesIDs))
 1176 
 1177             # List buried residues...
 1178             BuriedResiduesCount, BuriedResiduesDistribution, BuriedResiduesIDs = FormatResiduesInfo(BuriedResiduesInfo)
 1179             MiscUtil.PrintInfo(
 1180                 "\nInput file: %s;ChainID: %s\nNumber of buried residues: %d" % (Infile, ChainID, BuriedResiduesCount)
 1181             )
 1182             MiscUtil.PrintInfo("Residue distribution: %s" % (BuriedResiduesDistribution))
 1183             if OptionsInfo["ResidueIDs"]:
 1184                 MiscUtil.PrintInfo("Residue IDs: %s" % (BuriedResiduesIDs))
 1185 
 1186         # Delete loaded object...
 1187         pymol.cmd.delete(MolName)
 1188 
 1189 
 1190 def RetrieveResiduesNumbers(ResiduesInfo):
 1191     """Retrieve residue numbers."""
 1192 
 1193     # Setup residue IDs sorted by residue numbers...
 1194     ResNumMap = {}
 1195     for ResName in ResiduesInfo["ResNames"]:
 1196         for ResNum in ResiduesInfo["ResNum"][ResName]:
 1197             ResNumMap[ResNum] = ResName
 1198 
 1199     ResNumsList = []
 1200     if len(ResNumMap):
 1201         ResNumsList = sorted(ResNumMap, key=int)
 1202 
 1203     return ResNumsList
 1204 
 1205 
 1206 def SetupSurfaceAndBuriedResiduesSelection(SurfaceResiduesNums, BuriedResiduesNums):
 1207     """Setup PyMOL selection for surface and buried residues."""
 1208 
 1209     SurfaceResiduesSelection, BuriedResiduesSelection = [None] * 2
 1210     UseSurfaceResidueNums, UseBuriedResidueNums = [False] * 2
 1211 
 1212     SurfaceResiduesCount = len(SurfaceResiduesNums)
 1213     BuriedResiduesCount = len(BuriedResiduesNums)
 1214 
 1215     # Setup selections using the  residue list containing lower number of residues for
 1216     # ease of read in PML file...
 1217     if SurfaceResiduesCount and BuriedResiduesCount:
 1218         if SurfaceResiduesCount < BuriedResiduesCount:
 1219             UseSurfaceResidueNums = True
 1220         else:
 1221             UseBuriedResidueNums = True
 1222     elif SurfaceResiduesCount:
 1223         UseSurfaceResidueNums = True
 1224     elif BuriedResiduesCount:
 1225         UseBuriedResidueNums = True
 1226 
 1227     if UseSurfaceResidueNums:
 1228         SurfaceResiduesSelection = "resi %s" % ("+".join(SurfaceResiduesNums))
 1229         BuriedResiduesSelection = "not %s" % SurfaceResiduesSelection
 1230     elif UseBuriedResidueNums:
 1231         BuriedResiduesSelection = "resi %s" % ("+".join(BuriedResiduesNums))
 1232         SurfaceResiduesSelection = "not %s" % BuriedResiduesSelection
 1233 
 1234     return SurfaceResiduesSelection, BuriedResiduesSelection
 1235 
 1236 
 1237 def FormatResiduesInfo(SelectionInfo):
 1238     """Format residues info."""
 1239 
 1240     # Setup distribution of residues...
 1241     LineWords = []
 1242     ResiduesCount = 0
 1243     SortedResNames = sorted(
 1244         SelectionInfo["ResNames"], key=lambda ResName: SelectionInfo["ResCount"][ResName], reverse=True
 1245     )
 1246     for ResName in SortedResNames:
 1247         ResCount = SelectionInfo["ResCount"][ResName]
 1248         LineWords.append("%s - %s" % (ResName, ResCount))
 1249         ResiduesCount += ResCount
 1250 
 1251     ResiduesDistribution = "; ".join(LineWords) if len(LineWords) else None
 1252 
 1253     # Setup residue IDs sorted by residue numbers...
 1254     ResNumMap = {}
 1255     for ResName in SelectionInfo["ResNames"]:
 1256         for ResNum in SelectionInfo["ResNum"][ResName]:
 1257             ResNumMap[ResNum] = ResName
 1258 
 1259     ResNumsList = []
 1260     if len(ResNumMap):
 1261         ResNumsList = sorted(ResNumMap, key=int)
 1262 
 1263     LineWords = []
 1264     for ResNum in ResNumsList:
 1265         ResName = ResNumMap[ResNum]
 1266         ResID = "%s_%s" % (ResName, ResNum)
 1267         LineWords.append(ResID)
 1268     ResiduesIDs = ", ".join(LineWords) if len(LineWords) else None
 1269 
 1270     return ResiduesCount, ResiduesDistribution, ResiduesIDs
 1271 
 1272 
 1273 def ProcessResidueTypesAndSurfaceOptions(FileIndex, SpecifiedChainsAndLigandsInfo):
 1274     """Process residue types and surface options for chains."""
 1275 
 1276     SpecifiedChainsAndLigandsInfo["ChainSurfaces"] = {}
 1277     SpecifiedChainsAndLigandsInfo["SurfaceChain"] = {}
 1278     SpecifiedChainsAndLigandsInfo["SurfaceChainElectrostatics"] = {}
 1279 
 1280     SpecifiedChainsAndLigandsInfo["ResidueTypesChain"] = {}
 1281 
 1282     # Load infile...
 1283     Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
 1284     MolName = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
 1285     pymol.cmd.load(Infile, MolName)
 1286 
 1287     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
 1288         AminoAcidsPresent = PyMOLUtil.AreAminoAcidResiduesPresent(MolName, ChainID)
 1289 
 1290         # Process surfaces for chains...
 1291         if re.match("^auto$", OptionsInfo["SurfaceChain"], re.I):
 1292             SurfaceChain = True if AminoAcidsPresent else False
 1293         else:
 1294             SurfaceChain = True if re.match("^yes$", OptionsInfo["SurfaceChain"], re.I) else False
 1295         SpecifiedChainsAndLigandsInfo["SurfaceChain"][ChainID] = SurfaceChain
 1296 
 1297         if re.match("^auto$", OptionsInfo["SurfaceChainElectrostatics"], re.I):
 1298             SurfaceChainElectrostatics = True if AminoAcidsPresent else False
 1299         else:
 1300             SurfaceChainElectrostatics = (
 1301                 True if re.match("^yes$", OptionsInfo["SurfaceChainElectrostatics"], re.I) else False
 1302             )
 1303         SpecifiedChainsAndLigandsInfo["SurfaceChainElectrostatics"][ChainID] = SurfaceChainElectrostatics
 1304 
 1305         # A generic color surface is always created...
 1306         ChainSurfaces = True
 1307         SpecifiedChainsAndLigandsInfo["ChainSurfaces"][ChainID] = ChainSurfaces
 1308 
 1309         # Process residue types for chains...
 1310         if re.match("^auto$", OptionsInfo["ResidueTypesChain"], re.I):
 1311             ResidueTypesChain = True if AminoAcidsPresent else False
 1312         else:
 1313             ResidueTypesChain = True if re.match("^yes$", OptionsInfo["ResidueTypesChain"], re.I) else False
 1314         SpecifiedChainsAndLigandsInfo["ResidueTypesChain"][ChainID] = ResidueTypesChain
 1315 
 1316     # Delete loaded object...
 1317     pymol.cmd.delete(MolName)
 1318 
 1319 
 1320 def GetChainAloneResidueTypesStatus(FileIndex, ChainID):
 1321     """Get status of residue types for chain alone object."""
 1322 
 1323     #  o Need to handle Surface_Residues and Buried residues group based detection...
 1324     Status = (
 1325         True
 1326         if OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["ResidueTypesChain"][ChainID]
 1327         else False
 1328     )
 1329 
 1330     return Status
 1331 
 1332 
 1333 def GetChainAloneContainsSurfacesStatus(FileIndex, ChainID):
 1334     """Get status of surfaces present in chain alone object."""
 1335 
 1336     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["ChainSurfaces"][ChainID]
 1337 
 1338 
 1339 def GetChainAloneSurfaceChainStatus(FileIndex, ChainID):
 1340     """Get status of hydrophobic surfaces for chain alone object."""
 1341 
 1342     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceChain"][ChainID]
 1343 
 1344 
 1345 def GetChainAloneSurfaceChainElectrostaticsStatus(FileIndex, ChainID):
 1346     """Get status of electrostatics surfaces for chain alone object."""
 1347 
 1348     return OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]["SurfaceChainElectrostatics"][ChainID]
 1349 
 1350 
 1351 def CheckPresenceOfValidLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo):
 1352     """Check presence of valid ligand IDs."""
 1353 
 1354     MiscUtil.PrintInfo("\nSpecified chain IDs: %s" % (", ".join(SpecifiedChainsAndLigandsInfo["ChainIDs"])))
 1355 
 1356     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
 1357         if len(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]):
 1358             MiscUtil.PrintInfo(
 1359                 "Chain ID: %s; Specified LigandIDs: %s"
 1360                 % (ChainID, ", ".join(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]))
 1361             )
 1362         else:
 1363             MiscUtil.PrintInfo("Chain IDs: %s; Specified LigandIDs: None" % (ChainID))
 1364             MiscUtil.PrintWarning(
 1365                 "No valid ligand IDs found for chain ID, %s. PyMOL groups and objects related to ligand and binding pockect won't be created."
 1366                 % (ChainID)
 1367             )
 1368 
 1369 
 1370 def RetrieveFirstChainID(FileIndex):
 1371     """Get first chain ID."""
 1372 
 1373     ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
 1374 
 1375     FirstChainID = None
 1376     if len(ChainsAndLigandsInfo["ChainIDs"]):
 1377         FirstChainID = ChainsAndLigandsInfo["ChainIDs"][0]
 1378 
 1379     return FirstChainID
 1380 
 1381 
 1382 def ProcessResidueTypes():
 1383     """Process residue types."""
 1384 
 1385     ResidueTypesNamesInfo, ResidueTypesParamsInfo = PyMOLUtil.ProcessResidueTypesOptionsInfo(
 1386         "-r, --residueTypes", OptionsInfo["ResidueTypes"]
 1387     )
 1388     OptionsInfo["ResidueTypesNames"] = ResidueTypesNamesInfo
 1389     OptionsInfo["ResidueTypesParams"] = ResidueTypesParamsInfo
 1390 
 1391 
 1392 def ProcessSurfaceAtomTypesColors():
 1393     """Process surface atom types colors."""
 1394 
 1395     AtomTypesColorNamesInfo = PyMOLUtil.ProcessSurfaceAtomTypesColorsOptionsInfo(
 1396         "--surfaceAtomTypesColors", OptionsInfo["SurfaceAtomTypesColors"]
 1397     )
 1398     OptionsInfo["AtomTypesColorNames"] = AtomTypesColorNamesInfo
 1399 
 1400 
 1401 def ProcessOptions():
 1402     """Process and validate command line arguments and options."""
 1403 
 1404     MiscUtil.PrintInfo("Processing options...")
 1405 
 1406     # Validate options...
 1407     ValidateOptions()
 1408 
 1409     OptionsInfo["Align"] = True if re.match("^Yes$", Options["--align"], re.I) else False
 1410     OptionsInfo["AlignMethod"] = Options["--alignMethod"].lower()
 1411     OptionsInfo["AlignMode"] = Options["--alignMode"]
 1412 
 1413     OptionsInfo["AllowEmptyObjects"] = True if re.match("^Yes$", Options["--allowEmptyObjects"], re.I) else False
 1414 
 1415     OptionsInfo["CutoffSASA"] = float(Options["--cutoffSASA"])
 1416 
 1417     OptionsInfo["Infiles"] = Options["--infiles"]
 1418     OptionsInfo["InfilesNames"] = Options["--infileNames"]
 1419 
 1420     OptionsInfo["AlignRefFile"] = Options["--alignRefFile"]
 1421     if re.match("^FirstInputFile$", Options["--alignRefFile"], re.I):
 1422         OptionsInfo["RefFileName"] = OptionsInfo["InfilesNames"][0]
 1423     else:
 1424         OptionsInfo["RefFileName"] = Options["--alignRefFile"]
 1425 
 1426     OptionsInfo["IgnoreHydrogens"] = True if re.match("^Yes$", Options["--ignoreHydrogens"], re.I) else False
 1427 
 1428     OptionsInfo["Overwrite"] = Options["--overwrite"]
 1429     OptionsInfo["PMLOut"] = True if re.match("^Yes$", Options["--PMLOut"], re.I) else False
 1430 
 1431     OptionsInfo["Outfile"] = Options["--outfile"]
 1432     FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Outfile"])
 1433     OptionsInfo["PSEOut"] = False
 1434     if re.match("^pml$", FileExt, re.I):
 1435         OptionsInfo["PMLOutfile"] = OptionsInfo["Outfile"]
 1436         OptionsInfo["PMEOutfile"] = re.sub(".pml$", ".pme", OptionsInfo["Outfile"])
 1437     elif re.match("^pse$", FileExt, re.I):
 1438         OptionsInfo["PSEOut"] = True
 1439         OptionsInfo["PSEOutfile"] = OptionsInfo["Outfile"]
 1440         OptionsInfo["PMLOutfile"] = re.sub(".pse$", ".pml", OptionsInfo["Outfile"])
 1441         if os.path.exists(OptionsInfo["PMLOutfile"]) and (not OptionsInfo["Overwrite"]):
 1442             MiscUtil.PrintError(
 1443                 'The intermediate output file to be generated, %s, already exist. Use option "--ov" or "--overwrite" and try again.'
 1444                 % OptionsInfo["PMLOutfile"]
 1445             )
 1446 
 1447     OptionsInfo["LabelFontID"] = int(Options["--labelFontID"])
 1448 
 1449     OptionsInfo["ResidueIDs"] = True if re.match("^Yes$", Options["--residueIDs"], re.I) else False
 1450 
 1451     OptionsInfo["ResidueTypesChain"] = Options["--residueTypesChain"]
 1452     OptionsInfo["ResidueTypes"] = Options["--residueTypes"]
 1453     ProcessResidueTypes()
 1454 
 1455     OptionsInfo["SurfaceChain"] = Options["--surfaceChain"]
 1456     OptionsInfo["SurfaceChainElectrostatics"] = Options["--surfaceChainElectrostatics"]
 1457 
 1458     OptionsInfo["SurfaceChainComplex"] = True if re.match("^Yes$", Options["--surfaceChainComplex"], re.I) else False
 1459     OptionsInfo["SurfaceComplex"] = True if re.match("^Yes$", Options["--surfaceComplex"], re.I) else False
 1460 
 1461     # Retrieve surface colors for generic surfaces..
 1462     SurfaceColors = re.sub(" ", "", Options["--surfaceColors"])
 1463     SurfaceColorsWords = SurfaceColors.split(",")
 1464     if len(SurfaceColorsWords) != 2:
 1465         MiscUtil.PrintError(
 1466             'The number of comma delimited color names, %d, specified using "--surfaceColors" option, "%s",  must be a 2.'
 1467             % (len(SurfaceColorsWords), Options["--surfaceColors"])
 1468         )
 1469     OptionsInfo["SurfaceColors"] = SurfaceColors
 1470     OptionsInfo["SurfaceColor"] = SurfaceColorsWords[0]
 1471     OptionsInfo["SurfaceBuriedResiduesColor"] = SurfaceColorsWords[1]
 1472 
 1473     OptionsInfo["SurfaceColorPalette"] = Options["--surfaceColorPalette"]
 1474     OptionsInfo["SurfaceAtomTypesColors"] = Options["--surfaceAtomTypesColors"]
 1475     ProcessSurfaceAtomTypesColors()
 1476 
 1477     OptionsInfo["SurfaceTransparency"] = float(Options["--surfaceTransparency"])
 1478 
 1479     RetrieveInfilesInfo()
 1480     RetrieveRefFileInfo()
 1481 
 1482     OptionsInfo["ChainIDs"] = Options["--chainIDs"]
 1483     OptionsInfo["LigandIDs"] = Options["--ligandIDs"]
 1484     ProcessChainAndLigandIDs()
 1485 
 1486     RetrieveSurfaceAndBuriedResiduesInfo()
 1487 
 1488 
 1489 def RetrieveOptions():
 1490     """Retrieve command line arguments and options."""
 1491 
 1492     # Get options...
 1493     global Options
 1494     Options = docopt(_docoptUsage_)
 1495 
 1496     # Set current working directory to the specified directory...
 1497     WorkingDir = Options["--workingdir"]
 1498     if WorkingDir:
 1499         os.chdir(WorkingDir)
 1500 
 1501     # Handle examples option...
 1502     if "--examples" in Options and Options["--examples"]:
 1503         MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_))
 1504         sys.exit(0)
 1505 
 1506 
 1507 def ValidateOptions():
 1508     """Validate option values."""
 1509 
 1510     MiscUtil.ValidateOptionTextValue("--align", Options["--align"], "yes no")
 1511     MiscUtil.ValidateOptionTextValue("--alignMethod", Options["--alignMethod"], "align cealign super")
 1512     MiscUtil.ValidateOptionTextValue("--alignMode", Options["--alignMode"], "FirstChain Complex")
 1513 
 1514     MiscUtil.ValidateOptionTextValue("--allowEmptyObjects", Options["--allowEmptyObjects"], "yes no")
 1515 
 1516     MiscUtil.ValidateOptionFloatValue("--cutoffSASA", Options["--cutoffSASA"], {">": 0.0})
 1517 
 1518     # Expand infiles to handle presence of multiple input files...
 1519     InfileNames = MiscUtil.ExpandFileNames(Options["--infiles"], ",")
 1520     if not len(InfileNames):
 1521         MiscUtil.PrintError('No input files specified for "-i, --infiles" option')
 1522 
 1523     # Validate file extensions...
 1524     for Infile in InfileNames:
 1525         MiscUtil.ValidateOptionFilePath("-i, --infiles", Infile)
 1526         MiscUtil.ValidateOptionFileExt("-i, --infiles", Infile, "pdb cif")
 1527         MiscUtil.ValidateOptionsDistinctFileNames("-i, --infiles", Infile, "-o, --outfile", Options["--outfile"])
 1528     Options["--infileNames"] = InfileNames
 1529 
 1530     MiscUtil.ValidateOptionFileExt("-o, --outfile", Options["--outfile"], "pml pse")
 1531     MiscUtil.ValidateOptionsOutputFileOverwrite(
 1532         "-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"]
 1533     )
 1534 
 1535     if re.match("^yes$", Options["--align"], re.I):
 1536         if not re.match("^FirstInputFile$", Options["--alignRefFile"], re.I):
 1537             AlignRefFile = Options["--alignRefFile"]
 1538             MiscUtil.ValidateOptionFilePath("--alignRefFile", AlignRefFile)
 1539             MiscUtil.ValidateOptionFileExt("--alignRefFile", AlignRefFile, "pdb cif")
 1540             MiscUtil.ValidateOptionsDistinctFileNames(
 1541                 "--AlignRefFile", AlignRefFile, "-o, --outfile", Options["--outfile"]
 1542             )
 1543 
 1544     MiscUtil.ValidateOptionTextValue("--ignoreHydrogens", Options["--ignoreHydrogens"], "yes no")
 1545 
 1546     MiscUtil.ValidateOptionTextValue("--PMLOut", Options["--PMLOut"], "yes no")
 1547     MiscUtil.ValidateOptionIntegerValue("--labelFontID", Options["--labelFontID"], {})
 1548 
 1549     MiscUtil.ValidateOptionTextValue("--residueIDs", Options["--residueIDs"], "yes no")
 1550 
 1551     MiscUtil.ValidateOptionTextValue("--residueTypesChain", Options["--residueTypesChain"], "yes no auto")
 1552 
 1553     MiscUtil.ValidateOptionTextValue("--surfaceChain", Options["--surfaceChain"], "yes no auto")
 1554     MiscUtil.ValidateOptionTextValue("--surfaceComplex", Options["--surfaceComplex"], "yes no")
 1555     MiscUtil.ValidateOptionTextValue("--surfaceChainComplex", Options["--surfaceChainComplex"], "yes no")
 1556     MiscUtil.ValidateOptionTextValue(
 1557         "--surfaceChainElectrostatics", Options["--surfaceChainElectrostatics"], "yes no auto"
 1558     )
 1559 
 1560     MiscUtil.ValidateOptionTextValue(
 1561         "--surfaceColorPalette", Options["--surfaceColorPalette"], "RedToWhite WhiteToGreen"
 1562     )
 1563     MiscUtil.ValidateOptionFloatValue("--surfaceTransparency", Options["--surfaceTransparency"], {">=": 0.0, "<=": 1.0})
 1564 
 1565 
 1566 # Setup a usage string for docopt...
 1567 _docoptUsage_ = """
 1568 PyMOLVisualizeSurfaceAndBuriedResidues.py - Visualize surface and buried residues in macromolecules
 1569 
 1570 Usage:
 1571     PyMOLVisualizeSurfaceAndBuriedResidues.py [--align <yes or no>] [--alignMethod <align, cealign, super>]
 1572                                     [--alignMode <FirstChain or Complex>] [--alignRefFile <filename>]
 1573                                     [--allowEmptyObjects <yes or no>] [--chainIDs <First, All or ID1,ID2...>]
 1574                                     [--cutoffSASA <number> ] [--labelFontID <number>]
 1575                                     [--ignoreHydrogens <yes or no>] [--ligandIDs <Largest, All or ID1,ID2...> ] [--PMLOut <yes or no>]
 1576                                     [--residueIDs <yes or no> ] [--residueTypes <Type,Color,ResNames,...>] [--residueTypesChain <yes or no>]
 1577                                     [--surfaceChain <yes or no>] [--surfaceChainElectrostatics <yes or no>]
 1578                                     [--surfaceChainComplex <yes or no>] [--surfaceComplex <yes or no>]
 1579                                     [--surfaceAtomTypesColors <ColorType,ColorSpec,...>]
 1580                                     [--surfaceColors <ColorName1,ColorName2>] [--surfaceColorPalette <RedToWhite or WhiteToGreen>]
 1581                                     [--surfaceTransparency <number>] [--overwrite] [-w <dir>] -i <infile1,infile2,infile3...> -o <outfile>
 1582     PyMOLVisualizeSurfaceAndBuriedResidues.py -h | --help | -e | --examples
 1583 
 1584 Description:
 1585     Generate PyMOL visualization files for viewing surface and buried residues
 1586     in macromolecules including proteins and nucleic acids.
 1587 
 1588     The supported input file format are: PDB (.pdb), CIF (.cif)
 1589 
 1590     The supported output file formats are: PyMOL script file (.pml), PyMOL session
 1591     file (.pse)
 1592 
 1593     A variety of PyMOL groups and objects may be  created for visualization of
 1594     surface and buried residues in macromolecules. These groups and objects
 1595     correspond to complexes, surfaces, chains, ligands, and inorganics. A complete
 1596     hierarchy of all possible PyMOL groups and objects is shown below:
 1597     
 1598         <PDBFileRoot>
 1599             .Complex
 1600                 .Complex
 1601                 .Surface
 1602             .Chain<ID>
 1603                 .Complex
 1604                     .Complex
 1605                     .Surface
 1606                 .Chain
 1607                     .Chain
 1608                     .Surface_Residues
 1609                          .Chain
 1610                         .Residues
 1611                             .Aromatic
 1612                                 .Residues
 1613                                 .Surface
 1614                             .Hydrophobic
 1615                                 .Residues
 1616                                 .Surface
 1617                             .Polar
 1618                                 .Residues
 1619                                 .Surface
 1620                             .Positively_Charged
 1621                                 .Residues
 1622                                 .Surface
 1623                             .Negatively_Charged
 1624                                 .Residues
 1625                                 .Surface
 1626                             .Other
 1627                                 .Residues
 1628                                 .Surface
 1629                         .Surface
 1630                             .Surface
 1631                             .Hydrophobicity
 1632                             .Hydrophobicity_Charge
 1633                             .Vacuum_Electrostatics
 1634                                 .Contact_Potentials
 1635                                 .Map
 1636                                 .Legend
 1637                     .Buried_Residues
 1638                          .Chain
 1639                         .Residues
 1640                             .Aromatic
 1641                                 .Residues
 1642                                 .Surface
 1643                             .Hydrophobic
 1644                                 .Residues
 1645                                 .Surface
 1646                             .Polar
 1647                                 .Residues
 1648                                 .Surface
 1649                             .Positively_Charged
 1650                                 .Residues
 1651                                 .Surface
 1652                             .Negatively_Charged
 1653                                 .Residues
 1654                                 .Surface
 1655                             .Other
 1656                                 .Residues
 1657                                 .Surface
 1658                         .Surface
 1659                             .Surface
 1660                             .Hydrophobicity
 1661                             .Hydrophobicity_Charge
 1662                             .Vacuum_Electrostatics
 1663                                 .Contact_Potentials
 1664                                 .Map
 1665                                 .Legend
 1666                 .Solvent
 1667                 .Inorganic
 1668                 .Ligand<ID>
 1669                     .Ligand
 1670                         .Ligand
 1671                         .BallAndStick
 1672                 .Ligand<ID>
 1673                     .Ligand
 1674                         ... ... ...
 1675             .Chain<ID>
 1676                 ... ... ...
 1677                 .Ligand<ID>
 1678                     ... ... ...
 1679                 .Ligand<ID>
 1680                     ... ... ...
 1681             .Chain<ID>
 1682                 ... ... ...
 1683         <PDBFileRoot>
 1684             .Complex
 1685                 ... ... ...
 1686             .Chain<ID>
 1687                 ... ... ...
 1688                 .Ligand<ID>
 1689                     ... ... ...
 1690                 .Ligand<ID>
 1691                     ... ... ...
 1692             .Chain<ID>
 1693                 ... ... ...
 1694     
 1695     The hydrophobic and electrostatic surfaces are not created for complete complex
 1696     and chain complex in input file(s) by default. A word to the wise: The creation of
 1697     surface objects may slow down loading of PML file and generation of PSE file, based
 1698     on the size of input complexes. The generation of PSE file may also fail.
 1699 
 1700 Options:
 1701     -a, --align <yes or no>  [default: no]
 1702         Align input files to a reference file before visualization.
 1703     --alignMethod <align, cealign, super>  [default: super]
 1704         Alignment methodology to use for aligning input files to a
 1705         reference file.
 1706     --alignMode <FirstChain or Complex>  [default: FirstChain]
 1707         Portion of input and reference files to use for spatial alignment of
 1708         input files against reference file.  Possible values: FirstChain or
 1709         Complex.
 1710         
 1711         The FirstChain mode allows alignment of the first chain in each input
 1712         file to the first chain in the reference file along with moving the rest
 1713         of the complex to coordinate space of the reference file. The complete
 1714         complex in each input file is aligned to the complete complex in reference
 1715         file for the Complex mode.
 1716     --alignRefFile <filename>  [default: FirstInputFile]
 1717         Reference input file name. The default is to use the first input file
 1718         name specified using '-i, --infiles' option.
 1719     --allowEmptyObjects <yes or no>  [default: no]
 1720         Allow creation of empty PyMOL objects corresponding to solvent and
 1721         inorganic atom selections across chains and ligands in input file(s). By
 1722         default, the empty objects are marked for deletion.
 1723     -c, --chainIDs <First, All or ID1,ID2...>  [default: First]
 1724         List of chain IDs to use for visualizing surface and buried residues in
 1725         macromolecules. Possible values: First, All, or a comma delimited
 1726         list of chain IDs. The default is to use the chain ID for the first chain
 1727         in each input file.
 1728     --cutoffSASA <number>  [default: 2.5]
 1729         Solvent Accessible Surface Area (SASA) cutoff value in Angstroms**2
 1730         for identification of surface and buried residues in chains. The residues
 1731         with SASA less than the cutoff value are considered buried residues.
 1732     -e, --examples
 1733         Print examples.
 1734     -h, --help
 1735         Print this help message.
 1736     -i, --infiles <infile1,infile2,infile3...>
 1737         Input file names.
 1738     --ignoreHydrogens <yes or no>  [default: yes]
 1739         Ignore hydrogens for ligand views.
 1740     --labelFontID <number>  [default: 7]
 1741         Font ID for drawing labels. Default: 7 (Sans Bold). Valid values: 5 to 16.
 1742         The specified value must be a valid PyMOL font ID. No validation is
 1743         performed. The complete lists of valid font IDs is available at:
 1744         pymolwiki.org/index.php/Label_font_id. Examples: 5 - Sans;
 1745         7 - Sans Bold; 9 - Serif; 10 - Serif Bold.
 1746     -l, --ligandIDs <Largest, All or ID1,ID2...>  [default: All]
 1747         List of ligand IDs to show in chains during visualizing of surface and buried
 1748         residues in macromolecules. Possible values: Largest, All, or a comma delimited
 1749         list of ligand IDs. The default is to show all ligands present in all or
 1750         specified chains in each input file.
 1751         
 1752         Ligands are identified using organic selection operator available in PyMOL.
 1753         It'll also  identify buffer molecules as ligands. The largest ligand contains
 1754         the highest number of heavy atoms.
 1755     -o, --outfile <outfile>
 1756         Output file name.
 1757     -p, --PMLOut <yes or no>  [default: yes]
 1758         Save PML file during generation of PSE file.
 1759     --residueIDs <yes or no>  [default: no]
 1760         List residue IDs (ResName_ResNum) corresponding to surface and buried
 1761         residues. The count and residue distribution for these residues is always
 1762         listed.
 1763     -r, --residueTypes <Type,Color,ResNames,...>  [default: auto]
 1764         Residue types, colors, and names to generate for residue groups during
 1765         '--residueTypesChain' option. It is only valid for amino acids.
 1766         
 1767         It is a triplet of comma delimited list of amino acid residues type, residues
 1768         color, and a space delimited list three letter residue names. 
 1769         
 1770         The default values for residue type, color, and name triplets  are shown
 1771         below:
 1772             
 1773             Aromatic,brightorange,HIS PHE TRP TYR,
 1774             Hydrophobic,orange,ALA GLY VAL LEU ILE PRO MET,
 1775             Polar,palegreen,ASN GLN SER THR CYS,
 1776             Positively_Charged,marine,ARG LYS,
 1777             Negatively_Charged,red,ASP GLU
 1778             
 1779         The color name must be a valid PyMOL name. No validation is performed.
 1780         An amino acid name may appear across multiple residue types. All other
 1781         residues are grouped under 'Other'.
 1782     --residueTypesChain <yes or no>  [default: auto]
 1783         Chain residue types. The residue groups are generated using residue types,
 1784         colors, and names specified by '--residueTypes' option. It is only valid for
 1785         amino acids.  By default, the residue type groups are automatically created
 1786         for chains containing amino acids and skipped for chains only containing
 1787         nucleic acids.
 1788     --surfaceChain <yes or no>  [default: auto]
 1789         Surfaces around individual chain colored by hydrophobicity alone and
 1790         both hydrophobicity and charge. The hydrophobicity surface is colored
 1791         at residue level using Eisenberg hydrophobicity scale for residues and color
 1792         gradient specified by '--surfaceColorPalette' option. The  hydrophobicity and
 1793         charge surface is colored [ Ref 140 ] at atom level using colors specified for
 1794         groups of atoms by '--surfaceAtomTypesColors' option. This scheme allows
 1795         simultaneous mapping of hyrophobicity and charge values on the surfaces.
 1796         
 1797         This option is only valid for amino acids. By default, both surfaces are
 1798         automatically created for chains containing amino acids and skipped for
 1799         chains containing only nucleic acids.
 1800         
 1801         In addition, generic surfaces colored by '--surfaceColor' are always created
 1802         for chain residues containing amino acids and nucleic acids.
 1803     --surfaceChainElectrostatics <yes or no>  [default: no]
 1804         Vacuum electrostatics contact potential surface around individual
 1805         chain. A word to the wise from PyMOL documentation: The computed protein
 1806         contact potentials are only qualitatively useful, due to short cutoffs,
 1807         truncation, and lack of solvent "screening".
 1808         
 1809         This option is only valid for amino acids. By default, the electrostatics surface
 1810         is automatically created for chains containing amino acids and
 1811         skipped for chains containing only nucleic acids.
 1812     --surfaceChainComplex <yes or no>  [default: no]
 1813         Hydrophobic surface around chain complex. The  surface is colored by
 1814         hydrophobicity. It is only valid for amino acids.
 1815     --surfaceComplex <yes or no>  [default: no]
 1816         Hydrophobic surface around complete complex. The  surface is colored by
 1817         hydrophobicity. It is only valid for amino acids.
 1818     --surfaceAtomTypesColors <ColorType,ColorSpec,...>  [default: auto]
 1819         Atom colors for generating surfaces colored by hyrophobicity and charge
 1820         around chains and pockets in proteins. It's a pairwise comma delimited list
 1821         of atom color type and color specification for goups of atoms.
 1822         
 1823         The default values for color types [ Ref 140 ] along wth color specifications
 1824         are shown below: 
 1825             
 1826             HydrophobicAtomsColor, yellow,
 1827             NegativelyChargedAtomsColor, red,
 1828             PositivelyChargedAtomsColor, blue,
 1829             OtherAtomsColor, gray90
 1830             
 1831         The color names must be valid PyMOL names.
 1832         
 1833         The color values may also be specified as space delimited RGB triplets:
 1834              
 1835             HydrophobicAtomsColor, 0.95 0.78 0.0,
 1836             NegativelyChargedAtomsColor, 1.0 0.4 0.4,
 1837             PositivelyChargedAtomsColor, 0.2 0.5 0.8,
 1838             OtherAtomsColor, 0.95 0.95 0.95
 1839             
 1840     --surfaceColors <ColorName1,ColorName2>  [default: lightblue,salmon]
 1841         Color names for surface and burieds residues in chains. These colors are not
 1842         used for surfaces  colored by hydrophobicity and charge. The color names
 1843         must be valid PyMOL names.
 1844     --surfaceColorPalette <RedToWhite or WhiteToGreen>  [default: RedToWhite]
 1845         Color palette for hydrophobic surfaces around chains and pockets in proteins.
 1846         Possible values: RedToWhite or WhiteToGreen from most hydrophobic amino
 1847         acid to least hydrophobic. The colors values for amino acids are taken from
 1848         color_h script available as part of the Script Library at PyMOL Wiki.
 1849     --surfaceTransparency <number>  [default: 0.25]
 1850         Surface transparency for molecular surfaces.
 1851     --overwrite
 1852         Overwrite existing files.
 1853     -w, --workingdir <dir>
 1854         Location of working directory which defaults to the current directory.
 1855 
 1856 Examples:
 1857     To visualize surface and buried residues in the first chain along with the
 1858     largest ligand in the first chain, solvents, and inorganics, in a PDB file, and
 1859     generate a PML file, type:
 1860 
 1861         % PyMOLVisualizeSurfaceAndBuriedResidues.py -i Sample4.pdb
 1862           -o Sample4.pml
 1863 
 1864     To visualize surface and buries residues in all chain along with all ligands,
 1865     solvents, and inorganics, in a PDB file, and generate a PML file, type:
 1866 
 1867         % PyMOLVisualizeSurfaceAndBuriedResidues.py -c All -l All
 1868           -i Sample4.pdb -o Sample4.pml
 1869 
 1870     To visualize surface and buried residues in the first chain at a specific
 1871     cutoff using specifc colors for surfaces corresponding to surface and
 1872     buried residues, and generate a PML file, type:
 1873 
 1874         % PyMOLVisualizeSurfaceAndBuriedResidues.py  --cutoffSASA 3
 1875            --surfaceColors "blue,red" -i Sample4.pdb -o Sample4.pml
 1876 
 1877     To visualize surface and buried residues in the first chain along with the
 1878     largest ligand in the first chain, solvents, and inorganics, in PDB files, along
 1879     with aligning first chain in each input file to the first chain inand generate a
 1880     PML file, type:
 1881 
 1882         % PyMOLVisualizeSurfaceAndBuriedResidues.py --align yes
 1883           -i "Sample5.pdb,Sample6.pdb,Sample7.pdb"
 1884           -o SampleOut.pml
 1885 
 1886 Author:
 1887     Manish Sud(msud@san.rr.com)
 1888 
 1889 See also:
 1890     DownloadPDBFiles.pl, PyMOLVisualizeCavities.py,
 1891     PyMOLVisualizeCryoEMDensity.py, PyMOLVisualizeElectronDensity.py,
 1892     PyMOLVisualizeInterfaces.py, PyMOLVisualizeMacromolecules.py
 1893 
 1894 Copyright:
 1895     Copyright (C) 2026 Manish Sud. All rights reserved.
 1896 
 1897     The functionality available in this script is implemented using PyMOL, a
 1898     molecular visualization system on an open source foundation originally
 1899     developed by Warren DeLano.
 1900 
 1901     This file is part of MayaChemTools.
 1902 
 1903     MayaChemTools is free software; you can redistribute it and/or modify it under
 1904     the terms of the GNU Lesser General Public License as published by the Free
 1905     Software Foundation; either version 3 of the License, or (at your option) any
 1906     later version.
 1907 
 1908 """
 1909 
 1910 if __name__ == "__main__":
 1911     main()