MayaChemTools

    1 #!/bin/env python
    2 #
    3 # File: PyMOLVisualizeCryoEMDensity.py
    4 # Author: Manish Sud <msud@san.rr.com>
    5 #
    6 # Copyright (C) 2024 Manish Sud. All rights reserved.
    7 #
    8 # The functionality available in this script is implemented using PyMOL, a
    9 # molecular visualization system on an open source foundation originally
   10 # developed by Warren DeLano.
   11 #
   12 # This file is part of MayaChemTools.
   13 #
   14 # MayaChemTools is free software; you can redistribute it and/or modify it under
   15 # the terms of the GNU Lesser General Public License as published by the Free
   16 # Software Foundation; either version 3 of the License, or (at your option) any
   17 # later version.
   18 #
   19 # MayaChemTools is distributed in the hope that it will be useful, but without
   20 # any warranty; without even the implied warranty of merchantability of fitness
   21 # for a particular purpose.  See the GNU Lesser General Public License for more
   22 # details.
   23 #
   24 # You should have received a copy of the GNU Lesser General Public License
   25 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
   26 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
   27 # Boston, MA, 02111-1307, USA.
   28 #
   29 
   30 from __future__ import print_function
   31 
   32 # Add local python path to the global path and import standard library modules...
   33 import os
   34 import sys;  sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python"))
   35 import time
   36 import re
   37 import xml.etree.ElementTree as ElementTree
   38 
   39 # PyMOL imports...
   40 try:
   41     import pymol
   42     # Finish launching PyMOL in  a command line mode for batch processing (-c)
   43     # along with the following options:  disable loading of pymolrc and plugins (-k);
   44     # suppress start up messages (-q)
   45     pymol.finish_launching(['pymol', '-ckq'])
   46 except ImportError as ErrMsg:
   47     sys.stderr.write("\nFailed to import PyMOL module/package: %s\n" % ErrMsg)
   48     sys.stderr.write("Check/update your PyMOL environment and try again.\n\n")
   49     sys.exit(1)
   50 
   51 # MayaChemTools imports...
   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 def main():
   66     """Start execution of the script."""
   67     
   68     MiscUtil.PrintInfo("\n%s (PyMOL v%s; MayaChemTools v%s; %s): Starting...\n" % (ScriptName, pymol.cmd.get_version()[0], MiscUtil.GetMayaChemToolsVersion(), time.asctime()))
   69     
   70     (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime()
   71     
   72     # Retrieve command line arguments and options...
   73     RetrieveOptions()
   74     
   75     # Process and validate command line arguments and options...
   76     ProcessOptions()
   77 
   78     # Perform actions required by the script...
   79     GenerateCryoEMDensityVisualization()
   80     
   81     MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName)
   82     MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime))
   83 
   84 def GenerateCryoEMDensityVisualization():
   85     """Generate cryo-EM density visualization."""
   86     
   87     Outfile = OptionsInfo["PMLOutfile"]
   88     OutFH = open(Outfile, "w")
   89     if OutFH is None:
   90         MiscUtil.PrintError("Failed to open output fie %s " % Outfile)
   91     
   92     MiscUtil.PrintInfo("\nGenerating file %s..." % Outfile)
   93 
   94     # Setup header...
   95     WritePMLHeader(OutFH, ScriptName)
   96     WritePyMOLParameters(OutFH)
   97 
   98     # Load reffile for alignment..
   99     if OptionsInfo["Align"]:
  100         WriteAlignReference(OutFH)
  101 
  102     # Setup view for each input file...
  103     FirstComplex = True
  104     FirstComplexFirstChainName = None
  105     for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
  106         # Setup PyMOL object names...
  107         PyMOLObjectNames = SetupPyMOLObjectNames(FileIndex)
  108 
  109         # Setup complex view...
  110         WriteComplexView(OutFH, FileIndex, PyMOLObjectNames, FirstComplex)
  111         
  112         SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  113         FirstChain = True
  114         for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  115             if FirstComplex and FirstChain:
  116                 FirstComplexFirstChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
  117                 
  118             WriteChainView(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  119             
  120             # Setup ligand views...
  121             FirstLigand = True
  122             for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
  123                 WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNames, ChainID, LigandID)
  124                 
  125                 # Set up ligand level group...
  126                 Enable, Action = [False, "close"]
  127                 if FirstLigand:
  128                     FirstLigand = False
  129                     Enable, Action = [True, "open"]
  130                 GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroup"], PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"], Enable, Action)
  131             
  132             # Setup Chain level group...
  133             Enable, Action = [False, "close"]
  134             if FirstChain:
  135                 FirstChain = False
  136                 Enable, Action = [True, "open"]
  137             GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID]["ChainGroup"], PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"], Enable, Action)
  138     
  139         # Set up complex level group...
  140         Enable, Action = [False, "close"]
  141         if FirstComplex:
  142             FirstComplex = False
  143             Enable, Action = [True, "open"]
  144         GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["PDBGroup"], PyMOLObjectNames["PDBGroupMembers"], Enable, Action)
  145         
  146         # Delete empty PyMOL objects...
  147         DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNames)
  148         
  149     if OptionsInfo["Align"]:
  150         DeleteAlignReference(OutFH)
  151 
  152     if FirstComplexFirstChainName is not None:
  153         OutFH.write("""\ncmd.orient("%s", animate = -1)\n""" % FirstComplexFirstChainName)
  154     else:
  155         OutFH.write("""\ncmd.orient("visible", animate = -1)\n""")
  156     
  157     OutFH.close()
  158 
  159     # Generate PSE file as needed...
  160     if OptionsInfo["PSEOut"]:
  161         GeneratePyMOLSessionFile()
  162 
  163 def WritePMLHeader(OutFH, ScriptName):
  164     """Write out PML setting up complex view."""
  165 
  166     HeaderInfo = PyMOLUtil.SetupPMLHeaderInfo(ScriptName)
  167     OutFH.write("%s\n" % HeaderInfo)
  168 
  169 def WritePyMOLParameters(OutFH):
  170     """Write out PyMOL global parameters."""
  171 
  172     PMLCmds = []
  173     PMLCmds.append("""cmd.set("mesh_width", %.2f)""" % (OptionsInfo["MeshWidth"]))
  174     PMLCmds.append("""cmd.set("transparency", %.2f, "", 0)""" % (OptionsInfo["SurfaceTransparency"]))
  175     PMLCmds.append("""cmd.set("label_font_id", %s)""" % (OptionsInfo["LabelFontID"]))
  176 
  177     if OptionsInfo["VolumeColorRampCreate"]:
  178         ColorRampName = OptionsInfo["VolumeColorRampName"]
  179         ContourLevel = OptionsInfo["VolumeColorRampContourLevel"]
  180         LowerContourLevel = ContourLevel - 0.3
  181         UpperContourLevel = ContourLevel + 0.3
  182         PMLCmds.append("""cmd.volume_ramp_new("%s", "%.2f blue 0.00 %.2f cyan 0.20 %.2f blue 0.00")""" % (ColorRampName, LowerContourLevel, ContourLevel, UpperContourLevel))
  183         
  184     PML = "\n".join(PMLCmds)
  185     
  186     OutFH.write("""\n""\n"Setting up PyMOL gobal parameters..."\n""\n""")
  187     OutFH.write("%s\n" % PML)
  188     
  189 def WriteAlignReference(OutFH):
  190     """Setup object for alignment reference."""
  191 
  192     RefFileInfo = OptionsInfo["RefFileInfo"]
  193     RefFile = RefFileInfo["RefFileName"]
  194     RefName = RefFileInfo["PyMOLObjectName"]
  195     
  196     PMLCmds = []
  197     PMLCmds.append("""cmd.load("%s", "%s")""" % (RefFile, RefName))
  198     PMLCmds.append("""cmd.hide("everything", "%s")""" % (RefName))
  199     PMLCmds.append("""cmd.disable("%s")""" % (RefName))
  200     PML = "\n".join(PMLCmds)
  201     
  202     OutFH.write("""\n""\n"Loading %s and setting up view for align reference..."\n""\n""" % RefFile)
  203     OutFH.write("%s\n" % PML)
  204     
  205 def WriteAlignComplex(OutFH, FileIndex, PyMOLObjectNames):
  206     """Setup alignment of complex to reference."""
  207 
  208     RefFileInfo = OptionsInfo["RefFileInfo"]
  209     RefName = RefFileInfo["PyMOLObjectName"]
  210     
  211     ComplexName = PyMOLObjectNames["Complex"]
  212     
  213     if re.match("^FirstChain$", OptionsInfo["AlignMode"], re.I):
  214         RefFirstChainID = RefFileInfo["ChainsAndLigandsInfo"]["ChainIDs"][0]
  215         RefAlignSelection = "%s and chain %s" % (RefName, RefFirstChainID)
  216         
  217         ComplexFirstChainID = RetrieveFirstChainID(FileIndex)
  218         ComplexAlignSelection = "%s and chain %s" % (ComplexName, ComplexFirstChainID)
  219     else:
  220         RefAlignSelection = RefName
  221         ComplexAlignSelection = ComplexName
  222 
  223     PML = PyMOLUtil.SetupPMLForAlignment(OptionsInfo["AlignMethod"], RefAlignSelection, ComplexAlignSelection)
  224     OutFH.write("""\n""\n"Aligning %s against reference %s ..."\n""\n""" % (ComplexAlignSelection, RefAlignSelection))
  225     OutFH.write("%s\n" % PML)
  226     
  227 def DeleteAlignReference(OutFH):
  228     """Delete alignment reference object."""
  229     
  230     RefName = OptionsInfo["RefFileInfo"]["PyMOLObjectName"]
  231     OutFH.write("""\n""\n"Deleting alignment reference object %s..."\n""\n""" % RefName)
  232     OutFH.write("""cmd.delete("%s")\n""" % RefName)
  233 
  234 def WriteComplexView(OutFH, FileIndex, PyMOLObjectNames, FirstComplex):
  235     """Write out PML for viewing polymer complex along with cryo-EM density."""
  236 
  237     # Setup complex...
  238     Infile = OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex]
  239     PML = PyMOLUtil.SetupPMLForPolymerComplexView(PyMOLObjectNames["Complex"], Infile, True)
  240     OutFH.write("""\n""\n"Loading %s and setting up view for complex..."\n""\n""" % Infile)
  241     OutFH.write("%s\n" % PML)
  242 
  243     if OptionsInfo["Align"]:
  244         # No need to align complex on to itself...
  245         if not (re.match("^FirstInputFile$", OptionsInfo["AlignRefFile"], re.I) and FirstComplex):
  246             WriteAlignComplex(OutFH, FileIndex, PyMOLObjectNames)
  247 
  248     # Setup cryo-EM density maps and meshes...
  249     DensityMapFile = OptionsInfo["DensityMapFilesNames"][FileIndex]
  250     ContourLevel = OptionsInfo["MeshLevels"][FileIndex]
  251     WriteComplexCryoEMDensityMapView(OutFH, PyMOLObjectNames, DensityMapFile, ContourLevel)
  252 
  253     # Setup complex group...
  254     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["ComplexGroup"], PyMOLObjectNames["ComplexGroupMembers"], False, "close")
  255 
  256 def WriteComplexCryoEMDensityMapView(OutFH, PyMOLObjectNames, MapFileName, ContourLevel):
  257     """Write out PML for viewing cryoEM density map."""
  258 
  259     # Load cryo-EM density map and setup mesh views...
  260     Info = """\
  261 ""
  262 "Loading cryo-EM density map %s and setting up mesh view for complex..."
  263 "" """ % MapFileName
  264     OutFH.write("\n%s\n" % Info)
  265 
  266     MapName = PyMOLObjectNames["ComplexCryoEMMap"]
  267     ComplexName = PyMOLObjectNames["Complex"]
  268     
  269     Color = OptionsInfo["MeshColor"]
  270     VolumeColorRamp = OptionsInfo["VolumeColorRampName"]
  271     
  272     VolumeName = PyMOLObjectNames["ComplexCryoEMVolume"]
  273     MeshName = PyMOLObjectNames["ComplexCryoEMMesh"]
  274     SurfaceName = PyMOLObjectNames["ComplexCryoEMSurface"]
  275     
  276     AlignMapToObjectName = ComplexName if OptionsInfo["Align"] else None
  277     EnableMap = True
  278     PML = SetupPMLForCryoEMDensityMap(MapFileName, MapName, AlignMapToObjectName, EnableMap)
  279     OutFH.write("%s\n" % PML)
  280 
  281     EnableMesh = OptionsInfo["MeshComplex"]
  282     
  283     EnableVolume = OptionsInfo["VolumeComplex"]
  284     if EnableVolume and EnableMesh:
  285         EnableVolume = False
  286         
  287     EnableSurface = OptionsInfo["SurfaceComplex"]
  288     if EnableSurface and (EnableVolume or EnableMesh):
  289         EnableSurface = False
  290     
  291     if OptionsInfo["VolumeComplex"]:
  292         PML = SetupPMLForCryoEMDensityVolume(MapName, VolumeName, VolumeColorRamp, Enable = EnableVolume, Selection = ComplexName)
  293         OutFH.write("\n%s\n" % PML)
  294     
  295     if OptionsInfo["MeshComplex"]:
  296         PML = SetupPMLForCryoEMDensityMesh(MapName, MeshName, ContourLevel, Color, Enable = EnableMesh, Selection = ComplexName)
  297         OutFH.write("\n%s\n" % PML)
  298 
  299     if OptionsInfo["SurfaceComplex"]:
  300         PML = SetupPMLForCryoEMDensitySurface(MapName, SurfaceName, ContourLevel, Color, Enable = EnableSurface, Selection = ComplexName)
  301         OutFH.write("\n%s\n" % PML)
  302 
  303     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["ComplexCryoEMGroup"], PyMOLObjectNames["ComplexCryoEMGroupMembers"], True, "close")
  304     
  305 def WriteChainView(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  306     """Write out PML for viewing chain."""
  307     
  308     OutFH.write("""\n""\n"Setting up views for chain %s..."\n""\n""" % ChainID)
  309     
  310     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  311     
  312     # Setup chain complex group view...
  313     WriteChainComplexAndMeshViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  314 
  315     # Setup chain view...
  316     WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  317     
  318     # Setup chain solvent view...
  319     PML = PyMOLUtil.SetupPMLForSolventView(PyMOLObjectNames["Chains"][ChainID]["Solvent"], ChainComplexName, False)
  320     OutFH.write("\n%s\n" % PML)
  321 
  322     # Setup chain inorganic view...
  323     PML = PyMOLUtil.SetupPMLForInorganicView(PyMOLObjectNames["Chains"][ChainID]["Inorganic"], ChainComplexName, False)
  324     OutFH.write("\n%s\n" % PML)
  325 
  326 def WriteChainComplexAndMeshViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  327     """Write chain complex and mesh views."""
  328     
  329     # Setup chain complex...
  330     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  331     PML = PyMOLUtil.SetupPMLForPolymerChainComplexView(ChainComplexName, PyMOLObjectNames["Complex"], ChainID, True)
  332     OutFH.write("%s\n" % PML)
  333 
  334     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  335     
  336     MeshChainComplex = SpecifiedChainsAndLigandsInfo["MeshChainComplex"][ChainID]
  337     VolumeChainComplex = SpecifiedChainsAndLigandsInfo["VolumeChainComplex"][ChainID]
  338     SurfaceChainComplex = SpecifiedChainsAndLigandsInfo["SurfaceChainComplex"][ChainID]
  339     
  340     EnableVolumeChainComplex = SpecifiedChainsAndLigandsInfo["EnableVolumeChainComplex"][ChainID]
  341     EnableMeshChainComplex = SpecifiedChainsAndLigandsInfo["EnableMeshChainComplex"][ChainID]
  342     EnableSurfaceChainComplex = SpecifiedChainsAndLigandsInfo["EnableSurfaceChainComplex"][ChainID]
  343     
  344     if MeshChainComplex or VolumeChainComplex or SurfaceChainComplex:
  345         # Set up cryoEM mesh and group...
  346         MapName = PyMOLObjectNames["ComplexCryoEMMap"]
  347         ContourLevel = OptionsInfo["MeshLevels"][FileIndex]
  348         Color = OptionsInfo["MeshColor"]
  349         
  350         VolumeColorRamp = OptionsInfo["VolumeColorRampName"]
  351         
  352         VolumeName = PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMVolume"]
  353         MeshName = PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMMesh"]
  354         SurfaceName = PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMSurface"]
  355         
  356         if VolumeChainComplex:
  357             PML = SetupPMLForCryoEMDensityVolume(MapName, VolumeName, VolumeColorRamp, Enable = EnableVolumeChainComplex, Selection = ChainComplexName)
  358             OutFH.write("\n%s\n" % PML)
  359             
  360         if MeshChainComplex:
  361             PML = SetupPMLForCryoEMDensityMesh(MapName, MeshName, ContourLevel, Color, Enable = EnableMeshChainComplex, Selection = ChainComplexName)
  362             OutFH.write("\n%s\n" % PML)
  363         
  364         if SurfaceChainComplex:
  365             PML = SetupPMLForCryoEMDensitySurface(MapName, SurfaceName, ContourLevel, Color, Enable = EnableSurfaceChainComplex, Selection = ChainComplexName)
  366             OutFH.write("\n%s\n" % PML)
  367         
  368         GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroup"], PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"], True, "close")
  369         
  370     # Setup chain complex group...
  371     EnableChainComplexGroup = SpecifiedChainsAndLigandsInfo["EnableChainComplexGroup"][ChainID]
  372     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"], PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"], EnableChainComplexGroup, "close")
  373     
  374 def WriteChainAloneViews(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  375     """Write individual chain views."""
  376 
  377     ChainComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  378     
  379     # Setup chain view...
  380     ChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
  381     PML = PyMOLUtil.SetupPMLForPolymerChainView(ChainName, ChainComplexName, Enable = True)
  382     OutFH.write("\n%s\n" % PML)
  383 
  384     # Setup chain putty by B-factor view...
  385     if OptionsInfo["BFactorChainCartoonPutty"]:
  386         BFactorPuttyName = PyMOLObjectNames["Chains"][ChainID]["ChainAloneBFactorPutty"]
  387         PML = PyMOLUtil.SetupPMLForBFactorPuttyView(BFactorPuttyName, ChainName, ColorPalette = OptionsInfo["BFactorColorPalette"], Enable = False)
  388         OutFH.write("\n%s\n" % PML)
  389         
  390     # Setup chain selections view...
  391     SetupChainSelectionsView(OutFH, FileIndex, PyMOLObjectNames, ChainID)
  392     
  393     # Setup chain group...
  394     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  395     EnableChainAloneGroup = SpecifiedChainsAndLigandsInfo["EnableChainAloneGroup"][ChainID]
  396     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"], PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"], EnableChainAloneGroup, "close")
  397     
  398 def SetupChainSelectionsView(OutFH, FileIndex, PyMOLObjectNames, ChainID):
  399     """Setup chain selectons view."""
  400 
  401     if not OptionsInfo["ChainSelections"]:
  402         return
  403     
  404     ChainName = PyMOLObjectNames["Chains"][ChainID]["ChainAlone"]
  405     SelectionsGroupIDPrefix = "ChainAloneSelections"
  406     
  407     for Index in range(0, len(OptionsInfo["ChainSelectionsInfo"]["Names"])):
  408         SelectionName = OptionsInfo["ChainSelectionsInfo"]["Names"][Index]
  409         SpecifiedSelection = OptionsInfo["ChainSelectionsInfo"]["Selections"][Index]
  410         
  411         SelectionNameGroupID = SelectionName
  412         
  413         # Setup selection object...
  414         SelectionObjectID = "%s%sSelection" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  415         SelectionObjectName = PyMOLObjectNames["Chains"][ChainID][SelectionObjectID]
  416         SelectionCmd = "(%s and (%s))" % (ChainName, SpecifiedSelection)
  417         PML = PyMOLUtil.SetupPMLForSelectionDisplayView(SelectionObjectName, SelectionCmd, OptionsInfo["SelectionsChainStyle"], Enable = True)
  418         OutFH.write("\n%s\n" % PML)
  419         
  420         # Set up cryo-EM mesh and group...
  421         CryoEMVolumeID = "%s%sCryoEMVolume" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  422         CryoEMMeshID = "%s%sCryoEMMesh" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  423         CryoEMSurfaceID = "%s%sCryoEMSurface" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  424         CryoEMMeshGroupID = "%s%sCryoEMGroup" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  425         CryoEMMeshGroupMembersID = "%s%sCryoEMGroupMembers" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  426         
  427         CryoEMVolumeName = PyMOLObjectNames["Chains"][ChainID][CryoEMVolumeID]
  428         CryoEMMeshName = PyMOLObjectNames["Chains"][ChainID][CryoEMMeshID]
  429         CryoEMSurfaceName = PyMOLObjectNames["Chains"][ChainID][CryoEMSurfaceID]
  430         CryoEMMeshGroupName = PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupID]
  431         CryoEMMeshGroupMembers = PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID]
  432 
  433         MapName = PyMOLObjectNames["ComplexCryoEMMap"]
  434         ContourLevel = OptionsInfo["MeshLevels"][FileIndex]
  435         Color = OptionsInfo["MeshColor"]
  436         
  437         PML = SetupPMLForCryoEMDensityVolume(MapName, CryoEMVolumeName, OptionsInfo["VolumeColorRampName"], Enable = False, Selection = SelectionObjectName)
  438         OutFH.write("\n%s\n" % PML)
  439         
  440         PML = SetupPMLForCryoEMDensityMesh(MapName, CryoEMMeshName, ContourLevel, Color, Enable = True, Selection = SelectionObjectName)
  441         OutFH.write("\n%s\n" % PML)
  442         
  443         PML = SetupPMLForCryoEMDensitySurface(MapName, CryoEMSurfaceName, ContourLevel, Color, Enable = False, Selection = SelectionObjectName)
  444         OutFH.write("\n%s\n" % PML)
  445         
  446         GenerateAndWritePMLForGroup(OutFH, CryoEMMeshGroupName, CryoEMMeshGroupMembers, True, "close")
  447         
  448         # Setup groups for named selections...
  449         SelectionsNameGroupID = "%s%sGroup" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  450         SelectionsNameGroupMembersID = "%s%sGroupMembers" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  451         GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupID], PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupMembersID], True, "open")
  452     
  453     # Setup a group for selections...
  454     SelectionsGroupID = "%sGroup" % (SelectionsGroupIDPrefix)
  455     SelectionsGroupMembersID = "%sGroupMembers" % (SelectionsGroupIDPrefix)
  456     GenerateAndWritePMLForGroup(OutFH, PyMOLObjectNames["Chains"][ChainID][SelectionsGroupID], PyMOLObjectNames["Chains"][ChainID][SelectionsGroupMembersID], False, "close")
  457         
  458 def WriteChainLigandView(OutFH, FileIndex, PyMOLObjectNames, ChainID, LigandID):
  459     """Write out PML for viewing ligand in a chain."""
  460     
  461     for GroupID in ["Ligand", "Pocket", "PocketSolvent", "PocketInorganic"]:
  462         ComplexName = PyMOLObjectNames["Chains"][ChainID]["ChainComplex"]
  463         LigandName = PyMOLObjectNames["Ligands"][ChainID][LigandID]["Ligand"]
  464         
  465         # Setup main object...
  466         GroupTypeObjectID = "%s" % (GroupID)
  467         GroupTypeObjectName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID]
  468         
  469         if re.match("^Ligand$", GroupID, re.I):
  470             OutFH.write("""\n""\n"Setting up views for ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID))
  471             PML = PyMOLUtil.SetupPMLForLigandView(GroupTypeObjectName, ComplexName, LigandID, Enable = True, IgnoreHydrogens = OptionsInfo["IgnoreHydrogens"])
  472             OutFH.write("%s\n" % PML)
  473         elif re.match("^Pocket$", GroupID, re.I):
  474             OutFH.write("""\n""\n"Setting up views for pocket around ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID))
  475             PML = PyMOLUtil.SetupPMLForLigandPocketView(GroupTypeObjectName, ComplexName, LigandName, OptionsInfo["PocketDistanceCutoff"], Enable = True, IgnoreHydrogens = OptionsInfo["IgnoreHydrogens"])
  476             OutFH.write("%s\n" % PML)
  477             OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (OptionsInfo["PocketLabelColor"], GroupTypeObjectName))
  478         elif re.match("^PocketSolvent$", GroupID, re.I):
  479             OutFH.write("""\n""\n"Setting up views for solvent in pockect around ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID))
  480             PML = PyMOLUtil.SetupPMLForLigandPocketSolventView(GroupTypeObjectName, ComplexName, LigandName, OptionsInfo["PocketDistanceCutoff"], Enable = True)
  481             OutFH.write("%s\n" % PML)
  482         elif re.match("^PocketInorganic$", GroupID, re.I):
  483             OutFH.write("""\n""\n"Setting up views for inorganic in pockect around ligand %s in chain %s..."\n""\n""" % (LigandID, ChainID))
  484             PML = PyMOLUtil.SetupPMLForLigandPocketInorganicView(GroupTypeObjectName, ComplexName, LigandName, OptionsInfo["PocketDistanceCutoff"], Enable = True)
  485             OutFH.write("%s\n" % PML)
  486         
  487         # Set up cryoEM mesh and group...
  488         CryoEMMeshGroupID = "%sCryoEMMeshGroup" % (GroupID)
  489         CryoEMMeshGroupMembersID = "%sCryoEMMeshGroupMembers" % (GroupID)
  490         CryoEMVolumeID = "%sCryoEMVolume" % (GroupID)
  491         CryoEMMeshID = "%sCryoEMMesh" % (GroupID)
  492         CryoEMSurfaceID = "%sCryoEMSurface" % (GroupID)
  493 
  494         CryoEMMapName = PyMOLObjectNames["ComplexCryoEMMap"]
  495         CryoEMVolumeName = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMVolumeID]
  496         CryoEMMeshName = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshID]
  497         CryoEMSurfaceName = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMSurfaceID]
  498         CryoEMMeshGroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupID]
  499         CryoEMMeshGroupMembers = PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID]
  500         
  501         PML = SetupPMLForCryoEMDensityVolume(CryoEMMapName, CryoEMVolumeName, OptionsInfo["VolumeColorRampName"], Enable = False, Selection = GroupTypeObjectName)
  502         OutFH.write("\n%s\n" % PML)
  503 
  504         ContourLevel = OptionsInfo["MeshLevels"][FileIndex]
  505         PML = SetupPMLForCryoEMDensityMesh(CryoEMMapName, CryoEMMeshName, ContourLevel, OptionsInfo["MeshColor"], Enable = True, Selection = GroupTypeObjectName)
  506         OutFH.write("\n%s\n" % PML)
  507         
  508         PML = SetupPMLForCryoEMDensitySurface(CryoEMMapName, CryoEMSurfaceName, ContourLevel, OptionsInfo["MeshColor"], Enable = False, Selection = GroupTypeObjectName)
  509         OutFH.write("\n%s\n" % PML)
  510         
  511         GenerateAndWritePMLForGroup(OutFH, CryoEMMeshGroupName, CryoEMMeshGroupMembers, True, "close")
  512         
  513         # Set up polar contacts...
  514         if re.match("^(Pocket|PocketSolvent|PocketInorganic)$", GroupID, re.I):
  515             PolarContactsID = "%sPolarContacts" % (GroupID)
  516             PolarContactsName = PyMOLObjectNames["Ligands"][ChainID][LigandID][PolarContactsID]
  517             
  518             PolarContactsColor = OptionsInfo["PocketContactsLigandColor"]
  519             if re.match("^PocketSolvent$", GroupID, re.I):
  520                 PolarContactsColor = OptionsInfo["PocketContactsSolventColor"]
  521             elif re.match("^PocketInorganic$", GroupID, re.I):
  522                 PolarContactsColor = OptionsInfo["PocketContactsInorganicColor"]
  523             
  524             PML = PyMOLUtil.SetupPMLForPolarContactsView(PolarContactsName, LigandName, GroupTypeObjectName, Enable = False, Color = PolarContactsColor, Cutoff = OptionsInfo["PocketContactsCutoff"])
  525             OutFH.write("\n%s\n" % PML)
  526             
  527             OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (PolarContactsColor, PolarContactsName))
  528             
  529         # Set up hydrophobic contacts...
  530         if re.match("^Pocket$", GroupID, re.I):
  531             HydrophobicContactsID = "%sHydrophobicContacts" % (GroupID)
  532             HydrophobicContactsName = PyMOLObjectNames["Ligands"][ChainID][LigandID][HydrophobicContactsID]
  533             HydrophobicContactsColor = OptionsInfo["PocketContactsLigandHydrophobicColor"]
  534             
  535             PML = PyMOLUtil.SetupPMLForHydrophobicContactsView(HydrophobicContactsName, LigandName, GroupTypeObjectName, Enable = False, Color = HydrophobicContactsColor, Cutoff = OptionsInfo["PocketContactsCutoff"])
  536             OutFH.write("\n%s\n" % PML)
  537             OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (HydrophobicContactsColor, HydrophobicContactsName))
  538             
  539         # Set up hydrophobic surface...
  540         if re.match("^Pocket$", GroupID, re.I) and OptionsInfo["PocketSurface"]:
  541             HydrophobicSurfaceID = "%sHydrophobicSurface" % (GroupID)
  542             HydrophobicSurfaceName = PyMOLObjectNames["Ligands"][ChainID][LigandID][HydrophobicSurfaceID]
  543             PML = PyMOLUtil.SetupPMLForHydrophobicSurfaceView(HydrophobicSurfaceName, GroupTypeObjectName, ColorPalette = "RedToWhite", Enable = False)
  544             OutFH.write("\n%s\n" % PML)
  545             
  546             OutFH.write("""cmd.set("label_color", "%s", "%s")\n""" % (OptionsInfo["PocketLabelColor"], HydrophobicSurfaceName))
  547         
  548         # Setup group....
  549         GroupNameID = "%sGroup" % (GroupID)
  550         GroupMembersID = "%sGroupMembers" % (GroupID)
  551         GroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID]
  552         GroupMembers = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID]
  553 
  554         Action = "close"
  555         Enable = False
  556         if  re.match("^(Ligand|Pocket)$", GroupID, re.I):
  557             Action = "open"
  558             Enable = True
  559         GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable, Action)
  560 
  561 def GenerateAndWritePMLForGroup(OutFH, GroupName, GroupMembers, Enable = False, Action = "close"):
  562     """Generate and write PML for group."""
  563     
  564     PML = PyMOLUtil.SetupPMLForGroup(GroupName, GroupMembers, Enable, Action)
  565     OutFH.write("""\n""\n"Setting up group %s..."\n""\n""" % GroupName)
  566     OutFH.write("%s\n" % PML)
  567 
  568 def SetupPMLForCryoEMDensityMap(MapFileName, MapName, AlignMapToObjectName = None, Enable = True):
  569     """Setup PML for loading and viewing cryo-EM density map."""
  570 
  571     PMLCmds = []
  572     PMLCmds.append("""cmd.load("%s", "%s")""" % (MapFileName, MapName))
  573     if AlignMapToObjectName is not None:
  574         PMLCmds.append("""cmd.matrix_copy("%s", "%s")""" % (AlignMapToObjectName, MapName))
  575         
  576     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(MapName, Enable))
  577     
  578     PML = "\n".join(PMLCmds)
  579     
  580     return PML
  581     
  582 def SetupPMLForCryoEMDensityMesh(MapName, MeshName, SigmaLevel, Color, Enable = True, Selection = None):
  583     """Setup PML for cryo-EM density mesh."""
  584 
  585     Carve = OptionsInfo["MeshCarveRadius"]
  586     
  587     PMLCmds = []
  588     if Selection is None:
  589         PMLCmds.append("""cmd.isomesh("%s", "%s", %.1f)""" % (MeshName, MapName, SigmaLevel))
  590     else:
  591         PMLCmds.append("""cmd.isomesh("%s", "%s", %.1f, "(%s)", carve = %.1f)""" % (MeshName, MapName, SigmaLevel, Selection, Carve))
  592     PMLCmds.append(PyMOLUtil.SetupPMLForDeepColoring(MeshName, Color))
  593     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(MeshName, Enable))
  594     
  595     PML = "\n".join(PMLCmds)
  596     
  597     return PML
  598 
  599 def SetupPMLForCryoEMDensityVolume(MapName, VolumeName, VolumeColorRamp, Enable = True, Selection = None):
  600     """Setup PML for cryo-EM density volume."""
  601 
  602     Carve = OptionsInfo["VolumeCarveRadius"]
  603     
  604     PMLCmds = []
  605     if Selection is None:
  606         PMLCmds.append("""cmd.volume("%s", "%s", "%s")""" % (VolumeName, MapName, VolumeColorRamp))
  607     else:
  608         PMLCmds.append("""cmd.volume("%s", "%s", "%s", "(%s)", carve = %.1f)""" % (VolumeName, MapName, VolumeColorRamp, Selection, Carve))
  609     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(VolumeName, Enable))
  610     
  611     PML = "\n".join(PMLCmds)
  612     
  613     return PML
  614 
  615 def SetupPMLForCryoEMDensitySurface(MapName, SurfaceName, SigmaLevel, Color, Enable = True, Selection = None):
  616     """Setup PML for cryo-EM density surface."""
  617 
  618     Carve = OptionsInfo["MeshCarveRadius"]
  619     
  620     PMLCmds = []
  621     if Selection is None:
  622         PMLCmds.append("""cmd.isosurface("%s", "%s", %.1f)""" % (SurfaceName, MapName, SigmaLevel))
  623     else:
  624         PMLCmds.append("""cmd.isosurface("%s", "%s", %.1f, "(%s)", carve = %.1f)""" % (SurfaceName, MapName, SigmaLevel, Selection, Carve))
  625     PMLCmds.append(PyMOLUtil.SetupPMLForDeepColoring(SurfaceName, Color))
  626     PMLCmds.append(PyMOLUtil.SetupPMLForEnableDisable(SurfaceName, Enable))
  627     
  628     PML = "\n".join(PMLCmds)
  629     
  630     return PML
  631 
  632 def GeneratePyMOLSessionFile():
  633     """Generate PME file from PML file."""
  634 
  635     PSEOutfile = OptionsInfo["PSEOutfile"]
  636     PMLOutfile = OptionsInfo["PMLOutfile"]
  637     
  638     MiscUtil.PrintInfo("\nGenerating file %s..." % PSEOutfile)
  639     
  640     PyMOLUtil.ConvertPMLFileToPSEFile(PMLOutfile, PSEOutfile)
  641     
  642     if not os.path.exists(PSEOutfile):
  643         MiscUtil.PrintWarning("Failed to generate PSE file, %s..." % (PSEOutfile))
  644     
  645     if not OptionsInfo["PMLOut"]:
  646         MiscUtil.PrintInfo("Deleting file %s..." % PMLOutfile)
  647         os.remove(PMLOutfile)
  648 
  649 def DeleteEmptyPyMOLObjects(OutFH, FileIndex, PyMOLObjectNames):
  650     """Delete empty PyMOL objects."""
  651     
  652     if OptionsInfo["AllowEmptyObjects"]:
  653         return
  654     
  655     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  656     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  657         OutFH.write("""\n""\n"Checking and deleting empty objects for chain %s..."\n""\n""" % (ChainID))
  658         
  659         # Delete any chain level objects...
  660         WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Solvent"])
  661         WritePMLToCheckAndDeleteEmptyObjects(OutFH, PyMOLObjectNames["Chains"][ChainID]["Inorganic"])
  662         
  663         for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
  664             # Delete ligand level objects...
  665             for GroupID in ["Pocket", "PocketSolvent", "PocketInorganic"]:
  666                 GroupNameID = "%sGroup" % (GroupID)
  667                 GroupName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID]
  668 
  669                 GroupTypeObjectID = "%s" % (GroupID)
  670                 GroupTypeObjectName = PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID]
  671                 
  672                 WritePMLToCheckAndDeleteEmptyObjects(OutFH, GroupTypeObjectName, GroupName)
  673 
  674 def WritePMLToCheckAndDeleteEmptyObjects(OutFH, ObjectName, ParentObjectName = None):
  675     """Write PML to check and delete empty PyMOL objects."""
  676     
  677     if ParentObjectName is None:
  678         PML = """CheckAndDeleteEmptyObjects("%s")""" % (ObjectName)
  679     else:
  680         PML = """CheckAndDeleteEmptyObjects("%s", "%s")""" % (ObjectName, ParentObjectName)
  681     
  682     OutFH.write("%s\n" % PML)
  683 
  684 def SetupPyMOLObjectNames(FileIndex):
  685     """Setup hierarchy of PyMOL groups and objects for ligand centric views of
  686     cryo-EM density for chains and ligands present in input file.
  687     """
  688 
  689     PyMOLObjectNames = {}
  690     PyMOLObjectNames["Chains"] = {}
  691     PyMOLObjectNames["Ligands"] = {}
  692 
  693     # Setup groups and objects for complex...
  694     SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames)
  695     
  696     # Setup groups and objects for chain...
  697     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  698     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
  699         SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID)
  700         
  701         # Setup groups and objects for ligand...
  702         for LigandID in SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]:
  703             SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID)
  704 
  705     return PyMOLObjectNames
  706 
  707 def SetupPyMOLObjectNamesForComplex(FileIndex, PyMOLObjectNames):
  708     """Stetup groups and objects for complex."""
  709     
  710     PDBFileRoot = OptionsInfo["InfilesInfo"]["InfilesRoots"][FileIndex]
  711     
  712     PDBGroupName = "%s" % PDBFileRoot
  713     PyMOLObjectNames["PDBGroup"] = PDBGroupName
  714     PyMOLObjectNames["PDBGroupMembers"] = []
  715 
  716     ComplexGroupName = "%s.Complex" % PyMOLObjectNames["PDBGroup"]
  717     PyMOLObjectNames["ComplexGroup"] = ComplexGroupName
  718     PyMOLObjectNames["PDBGroupMembers"].append(ComplexGroupName)
  719     
  720     PyMOLObjectNames["Complex"] = "%s.Complex" % ComplexGroupName
  721 
  722     CryoEMMeshGroupName = "%s.CryoEM" % (ComplexGroupName)
  723     CryoEMMapName = "%s.Map" % (CryoEMMeshGroupName)
  724     CryoEMVolumeName = "%s.Volume" % (CryoEMMeshGroupName)
  725     CryoEMMeshName = "%s.Mesh" % (CryoEMMeshGroupName)
  726     CryoEMSurfaceName = "%s.Surface" % (CryoEMMeshGroupName)
  727     
  728     PyMOLObjectNames["ComplexCryoEMGroup"] = CryoEMMeshGroupName
  729     PyMOLObjectNames["ComplexCryoEMMap"] = CryoEMMapName
  730     PyMOLObjectNames["ComplexCryoEMVolume"] = CryoEMVolumeName
  731     PyMOLObjectNames["ComplexCryoEMMesh"] = CryoEMMeshName
  732     PyMOLObjectNames["ComplexCryoEMSurface"] = CryoEMSurfaceName
  733 
  734     PyMOLObjectNames["ComplexCryoEMGroupMembers"] = []
  735     PyMOLObjectNames["ComplexCryoEMGroupMembers"].append(CryoEMMapName)
  736     if OptionsInfo["VolumeComplex"]:
  737         PyMOLObjectNames["ComplexCryoEMGroupMembers"].append(CryoEMVolumeName)
  738     if OptionsInfo["MeshComplex"]:
  739         PyMOLObjectNames["ComplexCryoEMGroupMembers"].append(CryoEMMeshName)
  740     if OptionsInfo["SurfaceComplex"]:
  741         PyMOLObjectNames["ComplexCryoEMGroupMembers"].append(CryoEMSurfaceName)
  742     
  743     PyMOLObjectNames["ComplexGroupMembers"] = []
  744     PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["Complex"])
  745     PyMOLObjectNames["ComplexGroupMembers"].append(PyMOLObjectNames["ComplexCryoEMGroup"])
  746     
  747 def SetupPyMOLObjectNamesForChain(FileIndex, PyMOLObjectNames, ChainID):
  748     """Setup groups and objects for chain."""
  749     
  750     PDBGroupName = PyMOLObjectNames["PDBGroup"]
  751     
  752     SpecifiedChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"][FileIndex]
  753     MeshChainComplex = SpecifiedChainsAndLigandsInfo["MeshChainComplex"][ChainID]
  754     VolumeChainComplex = SpecifiedChainsAndLigandsInfo["VolumeChainComplex"][ChainID]
  755     SurfaceChainComplex = SpecifiedChainsAndLigandsInfo["SurfaceChainComplex"][ChainID]
  756     
  757     PyMOLObjectNames["Chains"][ChainID] = {}
  758     PyMOLObjectNames["Ligands"][ChainID] = {}
  759     
  760     # Set up chain group and chain objects...
  761     ChainGroupName = "%s.Chain%s" % (PDBGroupName, ChainID)
  762     PyMOLObjectNames["Chains"][ChainID]["ChainGroup"] = ChainGroupName
  763     PyMOLObjectNames["PDBGroupMembers"].append(ChainGroupName)
  764     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"] = []
  765     
  766     # Setup chain complex group and objects...
  767     ChainComplexGroupName = "%s.Complex" % (ChainGroupName)
  768     PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroup"] = ChainComplexGroupName
  769     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainComplexGroupName)
  770     
  771     PyMOLObjectNames["Chains"][ChainID]["ChainComplex"] = "%s.Complex" % (ChainComplexGroupName)
  772     
  773     CryoEMMeshGroupName = "%s.CryoEM" % (ChainComplexGroupName)
  774     CryoEMVolumeName = "%s.Volume" % (CryoEMMeshGroupName)
  775     CryoEMMeshName = "%s.Mesh" % (CryoEMMeshGroupName)
  776     CryoEMSurfaceName = "%s.Surface" % (CryoEMMeshGroupName)
  777     
  778     PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroup"] = CryoEMMeshGroupName
  779     PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMVolume"] = CryoEMVolumeName
  780     PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMMesh"] = CryoEMMeshName
  781     PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMSurface"] = CryoEMSurfaceName
  782     
  783     PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"] = []
  784     if VolumeChainComplex:
  785         PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"].append(CryoEMVolumeName)
  786     if MeshChainComplex:
  787         PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"].append(CryoEMMeshName)
  788     if SurfaceChainComplex:
  789         PyMOLObjectNames["Chains"][ChainID]["ChainComplexCryoEMGroupMembers"].append(CryoEMSurfaceName)
  790     
  791     NameIDs = ["ChainComplex"]
  792     if MeshChainComplex or VolumeChainComplex or SurfaceChainComplex :
  793         NameIDs.append("ChainComplexCryoEMGroup")
  794     
  795     PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"] = []
  796     for NameID in NameIDs:
  797         Name = PyMOLObjectNames["Chains"][ChainID][NameID]
  798         PyMOLObjectNames["Chains"][ChainID]["ChainComplexGroupMembers"].append(Name)
  799 
  800     # Setup up a group for individual chains...
  801     ChainAloneGroupName = "%s.Chain" % (ChainGroupName)
  802     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroup"] = ChainAloneGroupName
  803     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainAloneGroupName)
  804         
  805     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"] = []
  806         
  807     Name = "%s.Chain" % (ChainAloneGroupName)
  808     PyMOLObjectNames["Chains"][ChainID]["ChainAlone"] = Name
  809     PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(Name)
  810         
  811     if OptionsInfo["BFactorChainCartoonPutty"]:
  812         Name = "%s.BFactor" % (ChainAloneGroupName)
  813         PyMOLObjectNames["Chains"][ChainID]["ChainAloneBFactorPutty"] = Name
  814         PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(Name)
  815     
  816     if OptionsInfo["ChainSelections"]:
  817         # Setup selections group and its subgroups..
  818         SelectionsGroupName = "%s.Selections" % (ChainAloneGroupName)
  819         
  820         SelectionsGroupIDPrefix = "ChainAloneSelections"
  821         SelectionsGroupID = "%sGroup" % SelectionsGroupIDPrefix
  822         
  823         # Add selections group to chain alone group...
  824         PyMOLObjectNames["Chains"][ChainID][SelectionsGroupID] = SelectionsGroupName
  825         PyMOLObjectNames["Chains"][ChainID]["ChainAloneGroupMembers"].append(SelectionsGroupName)
  826         
  827         # Initialize selections group members...
  828         SelectionsGroupMembersID = "%sGroupMembers" % SelectionsGroupIDPrefix
  829         PyMOLObjectNames["Chains"][ChainID][SelectionsGroupMembersID] = []
  830         
  831         # Setup selections name sub group and its members...
  832         for SelectionName in OptionsInfo["ChainSelectionsInfo"]["Names"]:
  833             SelectionNameGroupID = SelectionName
  834             
  835             SelectionsNameGroupName = "%s.%s" % (SelectionsGroupName, SelectionName)
  836             SelectionsNameGroupID = "%s%sGroup" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  837 
  838             # Add selections name sub group to selections group...
  839             PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupID] = SelectionsNameGroupName
  840             PyMOLObjectNames["Chains"][ChainID][SelectionsGroupMembersID].append(SelectionsNameGroupName)
  841             
  842             # Initialize selections names sub group members...
  843             SelectionsNameGroupMembersID = "%s%sGroupMembers" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  844             PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupMembersID] = []
  845 
  846             # Add selection object to selections name group...
  847             SelectionObjectName = "%s.Selection" % (SelectionsNameGroupName)
  848             SelectionObjectID = "%s%sSelection" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  849             
  850             PyMOLObjectNames["Chains"][ChainID][SelectionObjectID] = SelectionObjectName
  851             PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupMembersID].append(SelectionObjectName)
  852             
  853             # Setup cryo-EM mesh group and add it to selections name group...
  854             CryoEMMeshGroupName = "%s.CryoEM" % (SelectionsNameGroupName)
  855             CryoEMMeshGroupID = "%s%sCryoEMGroup" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  856             
  857             PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupID] = CryoEMMeshGroupName
  858             PyMOLObjectNames["Chains"][ChainID][SelectionsNameGroupMembersID].append(CryoEMMeshGroupName)
  859             
  860             # Initialize cryo-EM mesh group members...
  861             CryoEMMeshGroupMembersID = "%s%sCryoEMGroupMembers" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  862             PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID] = []
  863 
  864             # Setup members of cryo-EM mesh group...
  865             CryoEMVolumeName = "%s.Volume" % (CryoEMMeshGroupName)
  866             CryoEMVolumeID = "%s%sCryoEMVolume" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  867             CryoEMMeshName = "%s.Mesh" % (CryoEMMeshGroupName)
  868             CryoEMMeshID = "%s%sCryoEMMesh" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  869             CryoEMSurfaceName = "%s.Surface" % (CryoEMMeshGroupName)
  870             CryoEMSurfaceID = "%s%sCryoEMSurface" % (SelectionsGroupIDPrefix, SelectionNameGroupID)
  871     
  872             PyMOLObjectNames["Chains"][ChainID][CryoEMVolumeID] = CryoEMVolumeName
  873             PyMOLObjectNames["Chains"][ChainID][CryoEMMeshID] = CryoEMMeshName
  874             PyMOLObjectNames["Chains"][ChainID][CryoEMSurfaceID] = CryoEMSurfaceName
  875 
  876             PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID].append(CryoEMVolumeName)
  877             PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID].append(CryoEMMeshName)
  878             PyMOLObjectNames["Chains"][ChainID][CryoEMMeshGroupMembersID].append(CryoEMSurfaceName)
  879     
  880     # Setup solvent and inorganic objects for chain...
  881     for NameID in ["Solvent", "Inorganic"]:
  882         Name = "%s.%s" % (ChainGroupName, NameID)
  883         PyMOLObjectNames["Chains"][ChainID][NameID] = Name
  884         PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(Name)
  885 
  886 def SetupPyMOLObjectNamesForLigand(FileIndex, PyMOLObjectNames, ChainID, LigandID):
  887     """Stetup groups and objects for ligand."""
  888 
  889     PyMOLObjectNames["Ligands"][ChainID][LigandID] = {}
  890     
  891     ChainGroupName = PyMOLObjectNames["Chains"][ChainID]["ChainGroup"]
  892     
  893     # Setup a chain level ligand group...
  894     ChainLigandGroupName = "%s.Ligand%s" % (ChainGroupName, LigandID)
  895     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroup"] = ChainLigandGroupName
  896     PyMOLObjectNames["Chains"][ChainID]["ChainGroupMembers"].append(ChainLigandGroupName)
  897     
  898     PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"] = []
  899 
  900     # Set up groups and objects for a specific ligand group...
  901     for GroupType in ["Ligand", "Pocket", "Pocket_Solvent", "Pocket_Inorganic"]:
  902         GroupID = re.sub("_", "", GroupType)
  903         GroupName = "%s.%s" % (ChainLigandGroupName, GroupType)
  904                 
  905         GroupNameID = "%sGroup" % (GroupID)
  906         GroupMembersID = "%sGroupMembers" % (GroupID)
  907         
  908         PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupNameID] = GroupName
  909         PyMOLObjectNames["Ligands"][ChainID][LigandID]["ChainLigandGroupMembers"].append(GroupName)
  910         
  911         GroupTypeObjectName = "%s.%s" % (GroupName, GroupType)
  912         GroupTypeObjectID = "%s" % (GroupID)
  913         PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupTypeObjectID] = GroupTypeObjectName
  914         
  915         CryoEMMeshGroupName = "%s.CryoEM" % (GroupName)
  916         CryoEMVolumeName = "%s.Volume" % (CryoEMMeshGroupName)
  917         CryoEMMeshName = "%s.Mesh" % (CryoEMMeshGroupName)
  918         CryoEMSurfaceName = "%s.Surface" % (CryoEMMeshGroupName)
  919                 
  920         CryoEMMeshGroupID = "%sCryoEMMeshGroup" % (GroupID)
  921         CryoEMMeshGroupMembersID = "%sCryoEMMeshGroupMembers" % (GroupID)
  922         CryoEMVolumeID = "%sCryoEMVolume" % (GroupID)
  923         CryoEMMeshID = "%sCryoEMMesh" % (GroupID)
  924         CryoEMSurfaceID = "%sCryoEMSurface" % (GroupID)
  925         
  926         PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupID] = CryoEMMeshGroupName
  927         PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMVolumeID] = CryoEMVolumeName
  928         PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshID] = CryoEMMeshName
  929         PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMSurfaceID] = CryoEMSurfaceName
  930         PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID] = []
  931         PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID].append(CryoEMVolumeName)
  932         PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID].append(CryoEMMeshName)
  933         PyMOLObjectNames["Ligands"][ChainID][LigandID][CryoEMMeshGroupMembersID].append(CryoEMSurfaceName)
  934                 
  935         PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID] = []
  936         NameIDs = [GroupTypeObjectID, CryoEMMeshGroupID]
  937         
  938         for NameID in NameIDs:
  939             Name = PyMOLObjectNames["Ligands"][ChainID][LigandID][NameID]
  940             PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(Name)
  941         
  942         if re.match("^Ligand$", GroupType, re.I):
  943             # No other object needed for Ligand group...
  944             continue
  945         
  946         PolarContactsName = "%s.Polar_Contacts" % (GroupName)
  947         PolarContactsID = "%sPolarContacts" % (GroupID)
  948         PyMOLObjectNames["Ligands"][ChainID][LigandID][PolarContactsID] = PolarContactsName
  949         PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(PolarContactsName)
  950                 
  951         if not re.match("^Pocket$", GroupType, re.I):
  952             # No other object needed for any other group besides Pocket...
  953             continue
  954         
  955         if not OptionsInfo["PocketSurface"]:
  956             continue
  957 
  958         HydrophobicContactsName = "%s.Hydrophobic_Contacts" % (GroupName)
  959         HydrophobicContactsID = "%sHydrophobicContacts" % (GroupID)
  960         PyMOLObjectNames["Ligands"][ChainID][LigandID][HydrophobicContactsID] = HydrophobicContactsName
  961         PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(HydrophobicContactsName)
  962         
  963         HydrophobicSurfaceName = "%s.Surface" % (GroupName)
  964         HydrophobicSurfaceID = "%sHydrophobicSurface" % (GroupID)
  965         PyMOLObjectNames["Ligands"][ChainID][LigandID][HydrophobicSurfaceID] = HydrophobicSurfaceName
  966         PyMOLObjectNames["Ligands"][ChainID][LigandID][GroupMembersID].append(HydrophobicSurfaceName)
  967 
  968 def ProcessDensityMapFiles():
  969     """Process density map files."""
  970     
  971     DensityMapFiles = OptionsInfo["DensityMapFiles"]
  972     if re.match("^auto$", DensityMapFiles, re.I):
  973         ProcessAutoDensityMapFiles()
  974     else:
  975         ProcessSpecifiedDensityMapFiles()
  976         
  977 def ProcessSpecifiedDensityMapFiles():
  978     """Process specified density map files."""
  979     
  980     OptionsInfo["DensityMapFilesNames"] = []
  981     
  982     MiscUtil.PrintInfo("\nProcessing cryo-EM density file names...")
  983     
  984     DensityMapFiles = re.sub(" ", "", OptionsInfo["DensityMapFiles"])
  985     if not DensityMapFiles:
  986         MiscUtil.PrintError("No valid value specified using \"--densityMapFiles\" option.")
  987     
  988     DensityMapFilesWords = DensityMapFiles.split(",")
  989     DensityMapFilesWordsCount = len(DensityMapFilesWords)
  990     
  991     InfilesNamesCount = len(OptionsInfo["InfilesNames"])
  992     
  993     if DensityMapFilesWordsCount != InfilesNamesCount:
  994         MiscUtil.PrintError("The number of comma delimited cryo-EM density map files, %d, specified using \"--DensityMapFiles\" must be equal to the number of input files, %s, specified using \"-i, --infiles\" option." % (DensityMapFilesWordsCount, InfilesNamesCount))
  995     
  996     for Index in range(0, InfilesNamesCount):
  997         Infile = OptionsInfo["InfilesNames"][Index]
  998         DensityMapFile = DensityMapFilesWords[Index]
  999         
 1000         if not os.path.exists(DensityMapFile):
 1001             MiscUtil.PrintError("The cryo-EM density ED map file, %s, specified using option \"--DensityMapFiles\", corresponding to input file, %s,  doesn't exist.\n" % (DensityMapFile, Infile))
 1002         
 1003         OptionsInfo["DensityMapFilesNames"].append(DensityMapFile)
 1004     
 1005 def ProcessAutoDensityMapFiles():
 1006     """Set up and process name of density map files."""
 1007     
 1008     OptionsInfo["DensityMapFilesNames"] = []
 1009     InfilesNamesCount = len(OptionsInfo["InfilesNames"])
 1010 
 1011     MiscUtil.PrintInfo("\nSetting cryo-EM density file names...")
 1012     
 1013     for Index in range(0, InfilesNamesCount):
 1014         Infile = OptionsInfo["InfilesNames"][Index]
 1015         
 1016         EMDBID = RetrieveEMDBID(Infile)
 1017         if EMDBID is None:
 1018             MiscUtil.PrintError("Failed to retrieve EMDB ID from input file %s to automatically set density map file name. Use option \"-d, --densityMapFiles \" to specify density map file name and try again." % Infile)
 1019         
 1020         DensityMapFile = None
 1021         MapFileRoot = "emd_%s" % EMDBID
 1022         MapFile1 = "%s.map.gz" % MapFileRoot
 1023         MapFile2 = "%s.map" % MapFileRoot
 1024         if os.path.exists(MapFile1):
 1025             DensityMapFile = MapFile1
 1026         elif os.path.exists(MapFile2):
 1027             DensityMapFile = MapFile2
 1028         else:
 1029             MiscUtil.PrintError("Density map files %s or %s don't exist. Use option \"-d, --densityMapFiles \" to specify density map file name and try again" % (MapFile1, MapFile2))
 1030     
 1031         MiscUtil.PrintInfo("Setting density map file name as %s for input file %s..." % (DensityMapFile, Infile))
 1032         OptionsInfo["DensityMapFilesNames"].append(DensityMapFile)
 1033         
 1034 def RetrieveRecommededContourLevel(Infile):
 1035     """Retrieve recommened contour level."""
 1036 
 1037     if Infile in OptionsInfo["InfilesRecommededContourLevels"]:
 1038         RecommendedContourLevel = OptionsInfo["InfilesRecommededContourLevels"][Infile]
 1039         return RecommendedContourLevel
 1040     
 1041     RecommendedContourLevel = None
 1042     EMDBID = RetrieveEMDBID(Infile)
 1043     if EMDBID is None:
 1044         MiscUtil.PrintWarning("Failed to retrieve EMDB ID from input file %s to detect local header file already downloaded from EMDB server..." % Infile)
 1045         OptionsInfo["InfilesRecommededContourLevels"][Infile] = RecommendedContourLevel
 1046         return RecommendedContourLevel
 1047 
 1048     MetadataHeaderFile = "emd-%s.xml" % (EMDBID)
 1049     if not os.path.exists(MetadataHeaderFile):
 1050         MiscUtil.PrintWarning("Failed to find a local header file, %s, for EMDB ID %s..." % (MetadataHeaderFile, EMDBID))
 1051         OptionsInfo["InfilesRecommededContourLevels"][Infile] = RecommendedContourLevel
 1052         return RecommendedContourLevel
 1053 
 1054     MiscUtil.PrintInfo("\nRetrieving recommeded contour level from header file, %s, for input file, %s..." % (MetadataHeaderFile, Infile))
 1055 
 1056     ContourLevel = None
 1057     Source = None
 1058     XMLTree = ElementTree.parse(MetadataHeaderFile)
 1059     XMLRoot = XMLTree.getroot()
 1060 
 1061     MapElement = XMLTree.find("map")
 1062     if MapElement is not None:
 1063         ContourLevelElement = MapElement.find("contourLevel")
 1064         if ContourLevelElement is not None:
 1065             ContourLevel = ContourLevelElement.text
 1066             Source = ContourLevelElement.get("source")
 1067 
 1068     if ContourLevel is not None:
 1069         if Source is None:
 1070             Source = "NA"
 1071         MiscUtil.PrintInfo("Retrieved recommended (Source: %s) contour level %s..." % (Source, ContourLevel))
 1072         RecommendedContourLevel = ContourLevel
 1073     
 1074     OptionsInfo["InfilesRecommededContourLevels"][Infile] = RecommendedContourLevel
 1075     
 1076     return RecommendedContourLevel
 1077 
 1078 def RetrieveEMDBID(Infile):
 1079     """Retrieve EMDB ID from input file."""
 1080 
 1081     if Infile in OptionsInfo["InfilesEMDBIDs"]:
 1082         EMDBID = OptionsInfo["InfilesEMDBIDs"][Infile]
 1083         return EMDBID
 1084     
 1085     EMDBID = None
 1086     FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
 1087 
 1088     if re.match("^pdb$", FileExt, re.I):
 1089         EMDBID = RetriveEMDBIDFromPDBFile(Infile)
 1090     elif re.match("^cif$", FileExt, re.I):
 1091         EMDBID = RetriveEMDBIDFromCIFFile(Infile)
 1092     else:
 1093         EMDBID = None
 1094 
 1095     OptionsInfo["InfilesEMDBIDs"][Infile] = EMDBID
 1096     
 1097     return EMDBID
 1098 
 1099 def RetriveEMDBIDFromPDBFile(Infile):
 1100     """Retrieve EMDB ID from PDB file."""
 1101 
 1102     EMDBID = None
 1103     InfileFH = open(Infile, "r")
 1104     if InfileFH is None:
 1105         MiscUtil.PrintError("Couldn't open input file: %s.\n" % (Infile))
 1106 
 1107     MiscUtil.PrintInfo("\nRetrieving EMDB ID from input file %s..." % Infile)
 1108     
 1109     EMDBID = None
 1110     for Line in InfileFH:
 1111         Line = Line.rstrip()
 1112         if re.match("^REMARK", Line, re.I):
 1113             if re.search("DB: EMDB", Line, re.I):
 1114                 for Word in Line.split(" "):
 1115                     # Retrieve string with EMD-
 1116                     if re.search("EMD-", Word, re.I):
 1117                         Word = Word.strip()
 1118                         EMDBID = re.sub("EMD-", "", Word)
 1119                         break
 1120                 break
 1121     InfileFH.close()
 1122     
 1123     return EMDBID
 1124 
 1125 def RetriveEMDBIDFromCIFFile(Infile):
 1126     """Retrieve EMDB ID from CIF file."""
 1127 
 1128     InfileFH = open(Infile, "r")
 1129     if InfileFH is None:
 1130         MiscUtil.PrintError("Couldn't open input file: %s.\n" % (Infile))
 1131 
 1132     MiscUtil.PrintInfo("\nRetrieving EMDB ID from input file %s..." % Infile)
 1133     
 1134     EMDBID = None
 1135     for Line in InfileFH:
 1136         Line = Line.rstrip()
 1137         if re.match("^EMDB  EMD", Line, re.I):
 1138             for Word in Line.split(" "):
 1139                 # Retrieve string with EMD-
 1140                 if re.search("EMD-", Word, re.I):
 1141                     Word = Word.strip()
 1142                     EMDBID = re.sub("EMD-", "", Word)
 1143                     break
 1144             break
 1145     InfileFH.close()
 1146     
 1147     return EMDBID
 1148 
 1149 def RetrieveInfilesInfo():
 1150     """Retrieve information for input files."""
 1151 
 1152     InfilesInfo = {}
 1153     
 1154     InfilesInfo["InfilesNames"] = []
 1155     InfilesInfo["InfilesRoots"] = []
 1156     InfilesInfo["ChainsAndLigandsInfo"] = []
 1157     
 1158     for Infile in OptionsInfo["InfilesNames"]:
 1159         FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
 1160         InfileRoot = FileName
 1161         
 1162         ChainsAndLigandInfo = PyMOLUtil.GetChainsAndLigandsInfo(Infile, InfileRoot)
 1163         
 1164         InfilesInfo["InfilesNames"].append(Infile)
 1165         InfilesInfo["InfilesRoots"].append(InfileRoot)
 1166         InfilesInfo["ChainsAndLigandsInfo"].append(ChainsAndLigandInfo)
 1167     
 1168     OptionsInfo["InfilesInfo"] = InfilesInfo
 1169 
 1170 def RetrieveRefFileInfo():
 1171     """Retrieve information for ref file."""
 1172 
 1173     RefFileInfo = {}
 1174     if not OptionsInfo["Align"]:
 1175         OptionsInfo["RefFileInfo"] = RefFileInfo
 1176         return
 1177 
 1178     RefFile = OptionsInfo["RefFileName"]
 1179     
 1180     FileDir, FileName, FileExt = MiscUtil.ParseFileName(RefFile)
 1181     RefFileRoot = FileName
 1182     
 1183     if re.match("^FirstInputFile$", OptionsInfo["AlignRefFile"], re.I):
 1184         ChainsAndLigandInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][0]
 1185     else:
 1186         MiscUtil.PrintInfo("\nRetrieving chain and ligand information for alignment reference file %s..." % RefFile)
 1187         ChainsAndLigandInfo = PyMOLUtil.GetChainsAndLigandsInfo(RefFile, RefFileRoot)
 1188 
 1189     RefFileInfo["RefFileName"] = RefFile
 1190     RefFileInfo["RefFileRoot"] = RefFileRoot
 1191     RefFileInfo["PyMOLObjectName"] = "AlignRef_%s" % RefFileRoot
 1192     RefFileInfo["ChainsAndLigandsInfo"] = ChainsAndLigandInfo
 1193     
 1194     OptionsInfo["RefFileInfo"] = RefFileInfo
 1195 
 1196 def ProcessChainAndLigandIDs():
 1197     """Process specified chain and ligand IDs for infiles."""
 1198     
 1199     OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"] = []
 1200     
 1201     for FileIndex in range(0, len(OptionsInfo["InfilesInfo"]["InfilesNames"])):
 1202         MiscUtil.PrintInfo("\nProcessing specified chain and ligand IDs for input file %s..." % OptionsInfo["InfilesInfo"]["InfilesNames"][FileIndex])
 1203         
 1204         ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
 1205         SpecifiedChainsAndLigandsInfo = PyMOLUtil.ProcessChainsAndLigandsOptionsInfo(ChainsAndLigandsInfo, "-c, --chainIDs", OptionsInfo["ChainIDs"], "-l, --ligandIDs", OptionsInfo["LigandIDs"])
 1206         ProcessChainMeshesVolumesAndSurfacesOptions(SpecifiedChainsAndLigandsInfo)
 1207         OptionsInfo["InfilesInfo"]["SpecifiedChainsAndLigandsInfo"].append(SpecifiedChainsAndLigandsInfo)
 1208         
 1209         CheckPresenceOfValidLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo)
 1210         
 1211 def CheckPresenceOfValidLigandIDs(ChainsAndLigandsInfo, SpecifiedChainsAndLigandsInfo):
 1212     """Check presence of valid ligand IDs."""
 1213 
 1214     MiscUtil.PrintInfo("\nSpecified chain IDs: %s" % (", ".join(SpecifiedChainsAndLigandsInfo["ChainIDs"])))
 1215     
 1216     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
 1217         if len (SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]):
 1218             MiscUtil.PrintInfo("Chain ID: %s; Specified LigandIDs: %s" % (ChainID, ", ".join(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID])))
 1219         else:
 1220             MiscUtil.PrintInfo("Chain IDs: %s; Specified LigandIDs: None" % (ChainID))
 1221             MiscUtil.PrintWarning("No valid ligand IDs found for chain ID, %s. PyMOL groups and objects related to ligand and binding pockect won't be created." % (ChainID))
 1222 
 1223 def RetrieveFirstChainID(FileIndex):
 1224     """Get first chain ID."""
 1225     
 1226     ChainsAndLigandsInfo = OptionsInfo["InfilesInfo"]["ChainsAndLigandsInfo"][FileIndex]
 1227     
 1228     FirstChainID = None
 1229     if len(ChainsAndLigandsInfo["ChainIDs"]):
 1230         FirstChainID = ChainsAndLigandsInfo["ChainIDs"][0]
 1231     
 1232     return FirstChainID
 1233 
 1234 def ProcessChainMeshesVolumesAndSurfacesOptions(SpecifiedChainsAndLigandsInfo):
 1235     """Process options to create meshes and surfaces for chains."""
 1236 
 1237     SpecifiedChainsAndLigandsInfo["VolumeChainComplex"] = {}
 1238     SpecifiedChainsAndLigandsInfo["MeshChainComplex"] = {}
 1239     SpecifiedChainsAndLigandsInfo["SurfaceChainComplex"] = {}
 1240 
 1241     SpecifiedChainsAndLigandsInfo["EnableVolumeChainComplex"] = {}
 1242     SpecifiedChainsAndLigandsInfo["EnableMeshChainComplex"] = {}
 1243     SpecifiedChainsAndLigandsInfo["EnableSurfaceChainComplex"] = {}
 1244     
 1245     SpecifiedChainsAndLigandsInfo["EnableChainComplexGroup"] = {}
 1246     SpecifiedChainsAndLigandsInfo["EnableChainAloneGroup"] = {}
 1247     
 1248     for ChainID in SpecifiedChainsAndLigandsInfo["ChainIDs"]:
 1249         LigandsPresent = True if len(SpecifiedChainsAndLigandsInfo["LigandIDs"][ChainID]) else False
 1250 
 1251         # Create and enable mesh  or volume in auto mode...
 1252         if re.match("^auto$", OptionsInfo["MeshChainComplex"], re.I):
 1253             MeshChainComplex = False if LigandsPresent else True
 1254             EnableMeshChainComplex = False if LigandsPresent else True
 1255         else:
 1256             MeshChainComplex = True if re.match("^Yes$", OptionsInfo["MeshChainComplex"], re.I) else False
 1257             EnableMeshChainComplex = True if re.match("^Yes$", OptionsInfo["MeshChainComplex"], re.I) else False
 1258         
 1259         if re.match("^auto$", OptionsInfo["VolumeChainComplex"], re.I):
 1260             VolumeChainComplex = False if LigandsPresent else True
 1261             EnableVolumeChainComplex = False if LigandsPresent else True
 1262         else:
 1263             VolumeChainComplex = True if re.match("^Yes$", OptionsInfo["VolumeChainComplex"], re.I) else False
 1264             EnableVolumeChainComplex = True if re.match("^Yes$", OptionsInfo["VolumeChainComplex"], re.I) else False
 1265         
 1266         if MeshChainComplex and EnableMeshChainComplex:
 1267             EnableVolumeChainComplex = False
 1268         
 1269         # Create and enable surface in auto mode based on the status of mesh and volume...
 1270         if re.match("^auto$", OptionsInfo["SurfaceChainComplex"], re.I):
 1271             SurfaceChainComplex = False if LigandsPresent else True
 1272             EnableSurfaceChainComplex = False if LigandsPresent else True
 1273             
 1274             if MeshChainComplex or VolumeChainComplex:
 1275                 SurfaceChainComplex = False
 1276                 EnableSurfaceChainComplex = False
 1277         else:
 1278             SurfaceChainComplex = True if re.match("^Yes$", OptionsInfo["SurfaceChainComplex"], re.I) else False
 1279             EnableSurfaceChainComplex = True if re.match("^Yes$", OptionsInfo["SurfaceChainComplex"], re.I) else False
 1280         
 1281         if (MeshChainComplex and EnableMeshChainComplex) or (VolumeChainComplex or EnableVolumeChainComplex):
 1282             EnableSurfaceChainComplex = False
 1283             
 1284         if LigandsPresent:
 1285             EnableChainComplexGroup = False
 1286             EnableChainAloneGroup = True
 1287         else:
 1288             EnableChainComplexGroup = True
 1289             EnableChainAloneGroup = False
 1290 
 1291         SpecifiedChainsAndLigandsInfo["VolumeChainComplex"][ChainID] = VolumeChainComplex
 1292         SpecifiedChainsAndLigandsInfo["MeshChainComplex"][ChainID] = MeshChainComplex
 1293         SpecifiedChainsAndLigandsInfo["SurfaceChainComplex"][ChainID] = SurfaceChainComplex
 1294         
 1295         SpecifiedChainsAndLigandsInfo["EnableVolumeChainComplex"][ChainID] = EnableVolumeChainComplex
 1296         SpecifiedChainsAndLigandsInfo["EnableMeshChainComplex"][ChainID] = EnableMeshChainComplex
 1297         SpecifiedChainsAndLigandsInfo["EnableSurfaceChainComplex"][ChainID] = EnableSurfaceChainComplex
 1298         
 1299         SpecifiedChainsAndLigandsInfo["EnableChainComplexGroup"][ChainID] = EnableChainComplexGroup
 1300         SpecifiedChainsAndLigandsInfo["EnableChainAloneGroup"][ChainID] = EnableChainAloneGroup
 1301 
 1302 def ProcessChainSelections():
 1303     """Process custom selections for chains."""
 1304 
 1305     ChainSelectionsInfo = PyMOLUtil.ProcessChainSelectionsOptionsInfo("--selectionsChain", OptionsInfo["SelectionsChain"])
 1306     OptionsInfo["ChainSelectionsInfo"] = ChainSelectionsInfo
 1307     
 1308     ChainSelections = True if len(OptionsInfo["ChainSelectionsInfo"]["Names"]) else False
 1309     OptionsInfo["ChainSelections"] = ChainSelections
 1310     
 1311 def ProcessMeshLevel():
 1312     """Process mesh level."""
 1313     
 1314     MeshLevel = OptionsInfo["MeshLevel"]
 1315     
 1316     if re.match("^auto$", MeshLevel, re.I):
 1317         ProcessAutoMeshLevel()
 1318     else:
 1319         ProcessSpecifiedMeshLevel()
 1320 
 1321 def ProcessAutoMeshLevel():
 1322     """Process auto mesh level."""
 1323     
 1324     OptionsInfo["MeshLevels"] = []
 1325     InfilesNamesCount = len(OptionsInfo["InfilesNames"])
 1326     
 1327     MiscUtil.PrintInfo("\nSetting mesh levels...")
 1328     
 1329     for Index in range(0, InfilesNamesCount):
 1330         Infile = OptionsInfo["InfilesNames"][Index]
 1331         
 1332         RecommededContourLevel = RetrieveRecommededContourLevel(Infile)
 1333         if RecommededContourLevel is None:
 1334             MiscUtil.PrintWarning("Failed to retrieve recommended mesh contour level from header. It's being set to 1.0. Use \"--meshLevel\" option to specify a different contour mesh level.")
 1335             MeshLevel = 1.0
 1336         else:
 1337             MeshLevel = float(RecommededContourLevel)
 1338         OptionsInfo["MeshLevels"].append(MeshLevel)
 1339         
 1340 def ProcessSpecifiedMeshLevel():
 1341     """Process specified mesh level."""
 1342 
 1343     MiscUtil.PrintInfo("\nProcessing mesh levels...")
 1344     
 1345     OptionsInfo["MeshLevels"] = []
 1346     InfilesNamesCount = len(OptionsInfo["InfilesNames"])
 1347     
 1348     MeshLevels = re.sub(" ", "", OptionsInfo["MeshLevel"])
 1349     if not MeshLevels:
 1350         MiscUtil.PrintError("No valid value specified using \"--meshLevel\" option.")
 1351     
 1352     MeshLevelWords = MeshLevels.split(",")
 1353     MeshLevelWordsCount = len(MeshLevelWords)
 1354     
 1355     if MeshLevelWordsCount != InfilesNamesCount:
 1356         MiscUtil.PrintError("The number of comma delimited mesh levels, %d, specified using \"--meshLevel\" must be equal to the number of input files, %s, specified using \"-i, --infiles\" option." % (MeshLevelWordsCount, InfilesNamesCount))
 1357     
 1358     for Index in range(0, InfilesNamesCount):
 1359         Infile = OptionsInfo["InfilesNames"][Index]
 1360         MeshLevel = MeshLevelWords[Index]
 1361         if not MiscUtil.IsFloat(MeshLevel):
 1362             MiscUtil.PrintError("The mesh level, %s, specified using \"--meshLevel\" for input file, %s, must be a float." % (MeshLevel, Infile))
 1363         
 1364         MeshLevel = float(MeshLevel)
 1365         OptionsInfo["MeshLevels"].append(MeshLevel)
 1366     
 1367 def ProcessVolumeColorRamp():
 1368     """Process volume color ramp."""
 1369     
 1370     MiscUtil.PrintInfo("\nProcessing volume color ramp...")
 1371     
 1372     ColorRamp = Options["--volumeColorRamp"]
 1373     ColorRampName = None
 1374     CreateColorRamp = False
 1375     ColorRampContourLevel = None
 1376     if re.match("^auto$", ColorRamp, re.I):
 1377         FirstInfile = OptionsInfo["InfilesNames"][0]
 1378         RecommededContourLevel = RetrieveRecommededContourLevel(FirstInfile)
 1379         if RecommededContourLevel is None:
 1380             ColorRampName = "default"
 1381             MiscUtil.PrintWarning("Failed to retrieve recommended contour level from header file corresponding to input file, %s, to create a new ramp. Using PyMOL default volume color ramp." % (FirstInfile))
 1382         else:
 1383             ColorRampName = "CryoEMAuto"
 1384             CreateColorRamp = True
 1385             ColorRampContourLevel = float(RecommededContourLevel)
 1386             MiscUtil.PrintInfo("\nSetting up a  new volume color ramp, %s, at recommended contour level, %.2f, from input file, %s..." % (ColorRampName, ColorRampContourLevel, FirstInfile))
 1387     else:
 1388         ColorRampName = ColorRamp
 1389         
 1390     OptionsInfo["VolumeColorRamp"] = ColorRamp
 1391     OptionsInfo["VolumeColorRampName"] = ColorRampName
 1392     OptionsInfo["VolumeColorRampCreate"] = CreateColorRamp
 1393     OptionsInfo["VolumeColorRampContourLevel"] = ColorRampContourLevel
 1394 
 1395 def ProcessOptions():
 1396     """Process and validate command line arguments and options."""
 1397     
 1398     MiscUtil.PrintInfo("Processing options...")
 1399     
 1400     # Validate options...
 1401     ValidateOptions()
 1402     
 1403     OptionsInfo["Align"] = True if re.match("^Yes$", Options["--align"], re.I) else False
 1404     OptionsInfo["AlignMethod"] = Options["--alignMethod"].lower()
 1405     OptionsInfo["AlignMode"] = Options["--alignMode"]
 1406     
 1407     OptionsInfo["AllowEmptyObjects"] = True if re.match("^Yes$", Options["--allowEmptyObjects"], re.I) else False
 1408     
 1409     OptionsInfo["BFactorChainCartoonPutty"] = True if re.match("^Yes$", Options["--BFactorChainCartoonPutty"], re.I) else False
 1410     OptionsInfo["BFactorColorPalette"] = Options["--BFactorColorPalette"]
 1411     
 1412     OptionsInfo["Infiles"] = Options["--infiles"]
 1413     OptionsInfo["InfilesNames"] =  Options["--infileNames"]
 1414     
 1415     OptionsInfo["InfilesEMDBIDs"] =  {}
 1416     OptionsInfo["InfilesRecommededContourLevels"] =  {}
 1417 
 1418     OptionsInfo["AlignRefFile"] = Options["--alignRefFile"]
 1419     if re.match("^FirstInputFile$", Options["--alignRefFile"], re.I):
 1420         OptionsInfo["RefFileName"] = OptionsInfo["InfilesNames"][0]
 1421     else:
 1422         OptionsInfo["RefFileName"] = Options["--alignRefFile"]
 1423     
 1424     OptionsInfo["IgnoreHydrogens"] = True if re.match("^Yes$", Options["--ignoreHydrogens"], re.I) else False
 1425     
 1426     OptionsInfo["DensityMapFiles"] = Options["--densityMapFiles"]
 1427     ProcessDensityMapFiles()
 1428 
 1429     OptionsInfo["Overwrite"] = Options["--overwrite"]
 1430     OptionsInfo["PMLOut"] = True if re.match("^Yes$", Options["--PMLOut"], re.I) else False
 1431     
 1432     OptionsInfo["Outfile"] = Options["--outfile"]
 1433     FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Outfile"])
 1434     OptionsInfo["PSEOut"] = False 
 1435     if re.match("^pml$", FileExt, re.I):
 1436         OptionsInfo["PMLOutfile"] = OptionsInfo["Outfile"] 
 1437         OptionsInfo["PMEOutfile"] = re.sub(".pml$", ".pme", OptionsInfo["Outfile"]) 
 1438     elif re.match("^pse$", FileExt, re.I):
 1439         OptionsInfo["PSEOut"] = True 
 1440         OptionsInfo["PSEOutfile"] = OptionsInfo["Outfile"] 
 1441         OptionsInfo["PMLOutfile"] = re.sub(".pse$", ".pml", OptionsInfo["Outfile"]) 
 1442         if os.path.exists(OptionsInfo["PMLOutfile"]) and (not OptionsInfo["Overwrite"]):
 1443             MiscUtil.PrintError("The intermediate output file to be generated, %s, already exist. Use option \"--ov\" or \"--overwrite\" and try again." % OptionsInfo["PMLOutfile"] )
 1444 
 1445     OptionsInfo["LabelFontID"] = int(Options["--labelFontID"])
 1446     
 1447     # Process mesh parameters...
 1448     OptionsInfo["MeshCarveRadius"] = float(Options["--meshCarveRadius"])
 1449     OptionsInfo["MeshComplex"] = True if re.match("^Yes$", Options["--meshComplex"], re.I) else False
 1450     OptionsInfo["MeshChainComplex"] = Options["--meshChainComplex"]
 1451     
 1452     OptionsInfo["MeshWidth"] = float(Options["--meshWidth"])
 1453     OptionsInfo["MeshColor"] = Options["--meshColor"]
 1454     
 1455     OptionsInfo["MeshLevel"] = Options["--meshLevel"]
 1456     ProcessMeshLevel()
 1457     
 1458     OptionsInfo["SurfaceComplex"] = True if re.match("^Yes$", Options["--surfaceComplex"], re.I) else False
 1459     OptionsInfo["SurfaceChainComplex"] = Options["--surfaceChainComplex"]
 1460     OptionsInfo["SurfaceTransparency"] = float(Options["--surfaceTransparency"])
 1461     
 1462     OptionsInfo["PocketContactsLigandColor"] = Options["--pocketContactsLigandColor"]
 1463     OptionsInfo["PocketContactsLigandHydrophobicColor"] = Options["--pocketContactsLigandHydrophobicColor"]
 1464     OptionsInfo["PocketContactsSolventColor"] = Options["--pocketContactsSolventColor"]
 1465     OptionsInfo["PocketContactsInorganicColor"] = Options["--pocketContactsInorganicColor"]
 1466     
 1467     OptionsInfo["PocketContactsCutoff"] = float(Options["--pocketContactsCutoff"])
 1468     OptionsInfo["PocketDistanceCutoff"] = float(Options["--pocketDistanceCutoff"])
 1469     
 1470     OptionsInfo["PocketLabelColor"] = Options["--pocketLabelColor"]
 1471     OptionsInfo["PocketSurface"] = True if re.match("^Yes$", Options["--pocketSurface"], re.I) else False
 1472 
 1473     OptionsInfo["SelectionsChain"] = Options["--selectionsChain"]
 1474     OptionsInfo["SelectionsChainStyle"] = Options["--selectionsChainStyle"]
 1475     ProcessChainSelections()
 1476     
 1477     OptionsInfo["VolumeCarveRadius"] = float(Options["--volumeCarveRadius"])
 1478     OptionsInfo["VolumeComplex"] = True if re.match("^Yes$", Options["--volumeComplex"], re.I) else False
 1479     OptionsInfo["VolumeChainComplex"] = Options["--volumeChainComplex"]
 1480 
 1481     ProcessVolumeColorRamp()
 1482 
 1483     RetrieveInfilesInfo()
 1484     RetrieveRefFileInfo()
 1485     
 1486     OptionsInfo["ChainIDs"] = Options["--chainIDs"]
 1487     OptionsInfo["LigandIDs"] = Options["--ligandIDs"]
 1488     
 1489     ProcessChainAndLigandIDs()
 1490 
 1491 def RetrieveOptions(): 
 1492     """Retrieve command line arguments and options."""
 1493     
 1494     # Get options...
 1495     global Options
 1496     Options = docopt(_docoptUsage_)
 1497     
 1498     # Set current working directory to the specified directory...
 1499     WorkingDir = Options["--workingdir"]
 1500     if WorkingDir:
 1501         os.chdir(WorkingDir)
 1502     
 1503     # Handle examples option...
 1504     if "--examples" in Options and Options["--examples"]:
 1505         MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_))
 1506         sys.exit(0)
 1507 
 1508 def ValidateOptions():
 1509     """Validate option values."""
 1510     
 1511     MiscUtil.ValidateOptionTextValue("--align", Options["--align"], "yes no")
 1512     MiscUtil.ValidateOptionTextValue("--alignMethod", Options["--alignMethod"], "align cealign super")
 1513     MiscUtil.ValidateOptionTextValue("--alignMode", Options["--alignMode"], "FirstChain Complex")
 1514     
 1515     MiscUtil.ValidateOptionTextValue("--allowEmptyObjects", Options["--allowEmptyObjects"], "yes no")
 1516     
 1517     MiscUtil.ValidateOptionTextValue("--BFactorChainCartoonPutty", Options["--BFactorChainCartoonPutty"], "yes no")
 1518 
 1519     # Expand infiles to handle presence of multiple input files...
 1520     InfileNames = MiscUtil.ExpandFileNames(Options["--infiles"], ",")
 1521     if not len(InfileNames):
 1522         MiscUtil.PrintError("No input files specified for \"-i, --infiles\" option")
 1523 
 1524     # Validate file extensions...
 1525     for Infile in InfileNames:
 1526         MiscUtil.ValidateOptionFilePath("-i, --infiles", Infile)
 1527         MiscUtil.ValidateOptionFileExt("-i, --infiles", Infile, "pdb cif")
 1528         MiscUtil.ValidateOptionsDistinctFileNames("-i, --infiles", Infile, "-o, --outfile", Options["--outfile"])
 1529     Options["--infileNames"] = InfileNames
 1530     
 1531     MiscUtil.ValidateOptionFileExt("-o, --outfile", Options["--outfile"], "pml pse")
 1532     MiscUtil.ValidateOptionsOutputFileOverwrite("-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"])
 1533     
 1534     if re.match("^yes$", Options["--align"], re.I):
 1535         if not re.match("^FirstInputFile$", Options["--alignRefFile"], re.I):
 1536             AlignRefFile = Options["--alignRefFile"]
 1537             MiscUtil.ValidateOptionFilePath("--alignRefFile", AlignRefFile)
 1538             MiscUtil.ValidateOptionFileExt("--alignRefFile", AlignRefFile, "pdb cif")
 1539             MiscUtil.ValidateOptionsDistinctFileNames("--AlignRefFile", AlignRefFile, "-o, --outfile", Options["--outfile"])
 1540     
 1541     MiscUtil.ValidateOptionTextValue("--ignoreHydrogens", Options["--ignoreHydrogens"], "yes no")
 1542     
 1543     MiscUtil.ValidateOptionTextValue("--PMLOut", Options["--PMLOut"], "yes no")
 1544     MiscUtil.ValidateOptionIntegerValue("--labelFontID", Options["--labelFontID"], {})
 1545 
 1546     MiscUtil.ValidateOptionFloatValue("--meshCarveRadius", Options["--meshCarveRadius"], {">": 0.0})
 1547     MiscUtil.ValidateOptionTextValue("--meshComplex", Options["--meshComplex"], "yes no")
 1548     MiscUtil.ValidateOptionTextValue("--meshChainComplex", Options["--meshChainComplex"], "yes no auto")
 1549     MiscUtil.ValidateOptionFloatValue("--meshWidth", Options["--meshWidth"], {">": 0.0})
 1550     
 1551     MiscUtil.ValidateOptionTextValue("--PMLOut", Options["--PMLOut"], "yes no")
 1552     
 1553     MiscUtil.ValidateOptionFloatValue("--pocketContactsCutoff", Options["--pocketContactsCutoff"], {">": 0.0})
 1554     MiscUtil.ValidateOptionFloatValue("--pocketDistanceCutoff", Options["--pocketDistanceCutoff"], {">": 0.0})
 1555     if (float(Options["--pocketContactsCutoff"]) > float(Options["--pocketDistanceCutoff"])):
 1556         MiscUtil.PrintError("The value, %s, specified using option \"--pocketContactsCutoff\" must be less than value, %s, specified using \"-pocketDistanceCutoff\" option." % (Options["--pocketContactsCutoff"], Options["--pocketDistanceCutoff"]))
 1557         
 1558     MiscUtil.ValidateOptionTextValue("--pocketSurface", Options["--pocketSurface"], "yes no")
 1559     
 1560     MiscUtil.ValidateOptionTextValue("--surfaceComplex", Options["--surfaceComplex"], "yes no")
 1561     MiscUtil.ValidateOptionTextValue("--surfaceChainComplex", Options["--surfaceChainComplex"], "yes no auto")
 1562     MiscUtil.ValidateOptionFloatValue("--surfaceTransparency", Options["--surfaceTransparency"], {">=": 0.0, "<=": 1.0})
 1563     
 1564     MiscUtil.ValidateOptionFloatValue("--volumeCarveRadius", Options["--volumeCarveRadius"], {">": 0.0})
 1565     MiscUtil.ValidateOptionTextValue("--volumeComplex", Options["--volumeComplex"], "yes no")
 1566     MiscUtil.ValidateOptionTextValue("--volumeChainComplex", Options["--volumeChainComplex"], "yes no auto")
 1567     
 1568 # Setup a usage string for docopt...
 1569 _docoptUsage_ = """
 1570 PyMOLVisualizeCryoEMDensity.py - Visualize cryo-EM density
 1571 
 1572 Usage:
 1573     PyMOLVisualizeCryoEMDensity.py  [--align <yes or no>] [--alignMethod <align, cealign, super>]
 1574                                    [--alignMode <FirstChain or Complex>] [--alignRefFile <filename>]
 1575                                    [--allowEmptyObjects <yes or no>] [--BFactorChainCartoonPutty <yes or no>]
 1576                                    [--BFactorColorPalette <text> ] [--chainIDs <First, All or ID1,ID2...>]
 1577                                    [--densityMapFiles <file1,file2,file3,...>]
 1578                                    [--ignoreHydrogens <yes or no>] [--ligandIDs <Largest, All or ID1,ID2...>] [--labelFontID <number>]
 1579                                    [--meshCarveRadius <number>] [--meshComplex <yes or no>]
 1580                                    [--meshChainComplex <yes, no, or auto>] [--meshColor <text>]
 1581                                    [--meshLevel <number>] [--meshWidth <number>] [--PMLOut <yes or no>]
 1582                                    [--pocketContactsLigandColor <text>] [--pocketContactsLigandHydrophobicColor <text>]
 1583                                    [--pocketContactsSolventColor <text>]  [--pocketContactsCutoff <number>]
 1584                                    [--pocketContactsInorganicColor <text>] [--pocketDistanceCutoff <number>]
 1585                                    [--pocketLabelColor <text>] [--pocketSurface <yes or no>]
 1586                                    [--selectionsChain <ObjectName,SelectionSpec,...>] [--selectionsChainStyle <DisplayStyle>]
 1587                                    [--surfaceComplex <yes or no>] [--surfaceChainComplex <yes, no or auto>]
 1588                                    [--surfaceTransparency <number>] [--volumeCarveRadius <number>]
 1589                                    [--volumeComplex <yes or no>] [--volumeChainComplex <yes, no, or auto>]
 1590                                    [--volumeColorRamp <text>]   [--overwrite] [-w <dir>] -i <infile1,infile2,...> -o <outfile>
 1591     PyMOLVisualizeCryoEMDensity.py -h | --help | -e | --examples
 1592 
 1593 Description:
 1594     Generate PyMOL visualization files for viewing electron microscopy (EM) or
 1595     cryo-EM density around chains, ligands, and ligand binding pockets in
 1596     macromolecules including proteins and nucleic acids.
 1597 
 1598     The supported input file formats are: Macromolecule - PDB (.pdb) or CIF(.cif),
 1599     Cryo-EM Density - Collaborative Computational Project Number 4 (CCP4) ( .map)
 1600 
 1601     The supported output file formats are: PyMOL script file (.pml), PyMOL session
 1602     file (.pse)
 1603 
 1604     The cryo-EM density and header files along with PDB files may be downloaded
 1605     from appropriate servers using DownloadPDBFiles.pl script.
 1606 
 1607     A variety of PyMOL groups and objects may be  created for visualization of
 1608     cryo-EM density present in map files. These groups and objects correspond to
 1609     maps, volumes, meshes, surfaces,chains, ligands, inorganics, ligand binding
 1610     pockets, polar interactions, and pocket hydrophobic surfaces. A complete
 1611     hierarchy of all possible PyMOL groups and objects is shown below:
 1612     
 1613         <PDBFileRoot>
 1614             .Complex
 1615                 .Complex
 1616                 .CryoEM
 1617                     .Map
 1618                     .Volume
 1619                     .Mesh
 1620                     .Surface
 1621             .Chain<ID>
 1622                 .Complex
 1623                     .Complex
 1624                     .CryoEM
 1625                         .Volume
 1626                         .Mesh
 1627                         .Surface
 1628                 .Chain
 1629                     .Chain
 1630                     .BFactor
 1631                     .Selections
 1632                         .<Name1>
 1633                             .Selection
 1634                             .CryoEM
 1635                                 .Volume
 1636                                 .Mesh
 1637                                 .Surface
 1638                         .<Name2>
 1639                             ... ... ..
 1640                 .Solvent
 1641                 .Inorganic
 1642                 .Ligand<ID>
 1643                     .Ligand
 1644                         .Ligand
 1645                         .CryoEM
 1646                             .Volume
 1647                             .Mesh
 1648                             .Surface
 1649                     .Pocket
 1650                         .Pocket
 1651                         .CryoEM
 1652                             .Volume
 1653                             .Mesh
 1654                             .Surface
 1655                         .Polar_Contacts
 1656                         .Hydrophobic_Contacts
 1657                         .Surface
 1658                     .Pocket_Solvent
 1659                         .Pocket_Solvent
 1660                         .CryoEM
 1661                             .Volume
 1662                             .Mesh
 1663                             .Surface
 1664                         .Polar_Contacts
 1665                     .Pocket_Inorganic
 1666                         .Pocket_Inorganic
 1667                         .CryoEM
 1668                             .Volume
 1669                             .Mesh
 1670                             .Surface
 1671                         .Polar_Contacts
 1672                 .Ligand<ID>
 1673                     .Ligand
 1674                         ... ... ...
 1675                     .Pocket
 1676                         ... ... ...
 1677                     .Pocket_Solvent
 1678                         ... ... ...
 1679                     .Pocket_Inorganic
 1680                         ... ... ...
 1681             .Chain<ID>
 1682                 ... ... ...
 1683                 .Ligand<ID>
 1684                     ... ... ...
 1685                 .Ligand<ID>
 1686                     ... ... ...
 1687             .Chain<ID>
 1688                 ... ... ...
 1689         <PDBFileRoot>
 1690             .Complex
 1691                 ... ... ...
 1692             .Chain<ID>
 1693                 ... ... ...
 1694                 .Ligand<ID>
 1695                     ... ... ...
 1696                 .Ligand<ID>
 1697                     ... ... ...
 1698             .Chain<ID>
 1699                 ... ... ...
 1700     
 1701     The meshes, volumes, and surfaces  are not created for complete complex in input
 1702     files by default. A word to the wise: The creation of these mesh, volume, and surface
 1703     objects may slow down loading of PML file and generation of PSE file, based on the
 1704     size of input complex and map files. The generation of PSE file may also fail. In 
 1705     addition, you may want to interactively manipulate the contour level for meshes,
 1706     volumes, and surfaces. The recommended value for contour level is automatically
 1707     retrieved from header files available from EM density server. The recommended
 1708     value may not always work.
 1709 
 1710 Options:
 1711     -a, --align <yes or no>  [default: no]
 1712         Align input files to a reference file before visualization along with
 1713         available cryo-EM density map files.
 1714     --alignMethod <align, cealign, super>  [default: super]
 1715         Alignment methodology to use for aligning input files to a reference
 1716         file.
 1717     --alignMode <FirstChain or Complex>  [default: FirstChain]
 1718         Portion of input and reference files to use for spatial alignment of
 1719         input files against reference file.  Possible values: FirstChain or
 1720         Complex.
 1721         
 1722         The FirstChain mode allows alignment of the first chain in each input
 1723         file to the first chain in the reference file along with moving the rest
 1724         of the complex to coordinate space of the reference file. The complete
 1725         complex in each input file is aligned to the complete complex in reference
 1726         file for the Complex mode.
 1727     --alignRefFile <filename>  [default: FirstInputFile]
 1728         Reference input file name. The default is to use the first input file
 1729         name specified using '-i, --infiles' option.
 1730     --allowEmptyObjects <yes or no>  [default: no]
 1731         Allow creation of empty PyMOL objects corresponding to solvent and
 1732         inorganic atom selections across chains, ligands, and ligand binding pockets
 1733         in input file(s).
 1734     -b, --BFactorChainCartoonPutty <yes or no>  [default: yes]
 1735         A cartoon putty around individual chains colored by B factors. The minimum
 1736         and maximum values for B factors are automatically detected. These values
 1737         indicate spread of cryo-EM density around atoms. The 'blue_white_red' color
 1738         palette is deployed for coloring the cartoon putty.
 1739     --BFactorColorPalette <text>  [default: blue_white_red]
 1740         Color palette for coloring cartoon putty around chains generated using B
 1741         factors. Any valid PyMOL color palette name is allowed. No validation is
 1742         performed. The complete list of valid color palette names is a available
 1743         at: pymolwiki.org/index.php/Spectrum. Examples: blue_white_red,
 1744         blue_white_magenta, blue_red, green_white_red, green_red.
 1745     -c, --chainIDs <First, All or ID1,ID2...>  [default: First]
 1746         List of chain IDs to use for visualizing cryo-EM density. Possible values:
 1747         First, All, or a comma delimited list of chain IDs. The default is to use the
 1748         chain ID for the first chain in each input file.
 1749     -d, --densityMapFiles <file1,file2,file3,...>  [default: auto]
 1750         CryoEM density map file names. The EMDB ID is retrieved from PDB and CIF
 1751         file to set the cryo-EM density file name during automatic detection of
 1752         density files. The format of the file name is as follows:
 1753         
 1754             emd_<EMDBID>.map.gz or emd_<EMDBID>.map
 1755          
 1756         The density files must be present in the working directory.
 1757     -e, --examples
 1758         Print examples.
 1759     -h, --help
 1760         Print this help message.
 1761     -i, --infiles <infile1,infile2,infile3...>
 1762         Input file names.
 1763     --ignoreHydrogens <yes or no>  [default: yes]
 1764         Ignore hydrogens for ligand and pocket views.
 1765     -l, --ligandIDs <Largest, All or ID1,ID2...>  [default: Largest]
 1766         List of ligand IDs present in chains for visualizing cryo-EM density across
 1767         ligands and ligand binding pockets. Possible values: Largest, All, or a comma
 1768         delimited list of ligand IDs. The default is to use the largest ligand present
 1769         in all or specified chains in each input file.
 1770         
 1771         Ligands are identified using organic selection operator available in PyMOL.
 1772         It'll also  identify buffer molecules as ligands. The largest ligand contains
 1773         the highest number of heavy atoms.
 1774     --labelFontID <number>  [default: 7]
 1775         Font ID for drawing labels. Default: 7 (Sans Bold). Valid values: 5 to 16.
 1776         The specified value must be a valid PyMOL font ID. No validation is
 1777         performed. The complete lists of valid font IDs is available at:
 1778         pymolwiki.org/index.php/Label_font_id. Examples: 5 - Sans;
 1779         7 - Sans Bold; 9 - Serif; 10 - Serif Bold.
 1780     --meshCarveRadius <number>  [default: 1.6]
 1781         Radius in Angstroms around atoms for including cryo-EM density.
 1782     --meshComplex <yes or no>  [default: no]
 1783         Create meshes for complete complex in each input file using corresponding
 1784         density map file.
 1785     --meshChainComplex <yes, no, or auto>  [default: auto]
 1786         Create meshes for individual chain complex in each input file using
 1787         corresponding density map file. By default, the meshes are automatically
 1788         created for chain complexes without any ligands. 
 1789     --meshColor <text>  [default: blue]
 1790         Line color for meshes corresponding to density maps.. The specified value
 1791         must be valid color. No validation is performed.
 1792     --meshLevel <number1,number2,...>  [default: auto]
 1793         Comma delimited list of contour levels in sigma units for generating meshes
 1794         for each input file using corresponding density map file. The default is to
 1795         automatically retrieve the recommended contour levels for each input 
 1796         file. The header file emd-<EMDBID>.xml corresponding to an input file
 1797         must be present in the working directory  to automatically retrieve
 1798         recommended value for mesh contour level. Otherwise, the default contour
 1799         level is set to 1.
 1800         
 1801         You may want to interactively manipulate the contour level for meshes and
 1802         surfaces. The default recommended value may not always work.
 1803     --meshWidth <number>  [default: 0.5]
 1804         Line width for mesh lines corresponding to density maps.
 1805     -o, --outfile <outfile>
 1806         Output file name.
 1807     -p, --PMLOut <yes or no>  [default: yes]
 1808         Save PML file during generation of PSE file.
 1809     --pocketContactsLigandColor <text>  [default: orange]
 1810         Color for drawing polar contacts between ligand and pocket residues.
 1811         The specified value must be valid color. No validation is performed.
 1812     --pocketContactsLigandHydrophobicColor <text>  [default: purpleblue]
 1813         Color for drawing hydrophobic contacts between ligand and pocket residues.
 1814         The specified value must be valid color. No validation is performed. The
 1815         hydrophobic contacts are shown between pairs of carbon atoms not
 1816         connected to hydrogen bond donor or acceptors atoms as identified
 1817         by PyMOL.
 1818     --pocketContactsSolventColor <text>  [default: marine]
 1819         Color for drawing polar contacts between solvent and pocket residues.
 1820         The specified value must be valid color. No validation is performed.
 1821     --pocketContactsInorganicColor <text>  [default: deepsalmon]
 1822         Color for drawing polar contacts between inorganic and pocket residues.
 1823         The specified value must be valid color. No validation is performed.
 1824     --pocketContactsCutoff <number>  [default: 4.0]
 1825         Distance in Angstroms for identifying polar and hyrdophobic contacts
 1826         between atoms in pocket residues and ligands.
 1827     --pocketDistanceCutoff <number>  [default: 5.0]
 1828         Distance in Angstroms for identifying pocket residues around ligands.
 1829     --pocketLabelColor <text>  [default: magenta]
 1830         Color for drawing residue or atom level labels for a pocket. The specified
 1831         value must be valid color. No validation is performed.
 1832     --pocketSurface <yes or no>  [default: yes]
 1833         Hydrophobic surface around pocket. The pocket surface is colored by
 1834         hydrophobicity. It is only valid for proteins. The color of amino acids is
 1835         set using the Eisenberg hydrophobicity scale. The color varies from red
 1836         to white, red being the most hydrophobic amino acid.
 1837     --selectionsChain <ObjectName,SelectionSpec,...>  [default: None]
 1838         Custom selections for chains. It is a pairwise list of comma delimited values
 1839         corresponding to PyMOL object names and selection specifications.  The
 1840         selection specification must be a valid PyMOL specification. No validation is
 1841         performed.
 1842         
 1843         The PyMOL objects are created for each chain corresponding to the
 1844         specified selections. The display style for PyMOL objects is set using
 1845         value of '--selectionsChainStyle' option.
 1846         
 1847         The specified selection specification is automatically appended to appropriate
 1848         chain specification before creating PyMOL objects.
 1849         
 1850         For example, the following specification for '--selectionsChain' option will
 1851         generate PyMOL objects for chains containing Cysteines and Serines:
 1852             
 1853             Cysteines,resn CYS,Serines,resn SER
 1854             
 1855     --selectionsChainStyle <DisplayStyle>  [default: sticks]
 1856         Display style for PyMOL objects created for '--selectionsChain' option. It
 1857         must be a valid PyMOL display style. No validation is performed.
 1858     --surfaceComplex <yes or no>  [default: no]
 1859         Create surfaces for complete complex in input file(s) corresponding to density
 1860         map.
 1861     --surfaceChainComplex <yes, no or auto>  [default: auto]
 1862         Create surfaces for individual chain complexes in each input file using corresponding
 1863         density map file. By default, the surfaces are automatically created for chain complexes
 1864         without any ligands.
 1865     --surfaceTransparency <number>  [default: 0.25]
 1866         Surface transparency for molecular and cryo-EM density surfaces.
 1867     --overwrite
 1868         Overwrite existing files.
 1869     --volumeCarveRadius <number>  [default: 1.6]
 1870         Radius in Angstroms around atoms for including cryo-EM density.
 1871     --volumeComplex <yes or no>  [default: no]
 1872         Create volumes for complete complex in each input file using corresponding density
 1873         map file.
 1874     --volumeChainComplex <yes, no, or auto>  [default: auto]
 1875         Create volumes for individual chain complex in each input file using corresponding
 1876         density map file. By default, the volumes are automatically created for chain
 1877         complexes without any ligands.
 1878     --volumeColorRamp <text>  [default: auto]
 1879         Name of a volume color ramp for density map files. The specified value must
 1880         be a valid name. No validation is performed. The following volume color ramps
 1881         are currently available in PyMOL: default, 2fofc, fofc, rainbow, and rainbow2.
 1882         
 1883         The default is to automatically create a new volume color ramp for the first
 1884         input file using recommended contour level with an offset of 0.3 around this value.
 1885         The header file emd-<EMDBID>.xml must be present in the working directory  to
 1886         automatically retrieve recommended contour level and generate a  volume color ramp.
 1887         Otherwise, PyMOL default volume color ramp is employed to color volumes.
 1888         
 1889         The volume color ramp automatically created for the first input file is used for all
 1890         other input files.
 1891     -w, --workingdir <dir>
 1892         Location of working directory which defaults to the current directory.
 1893 
 1894 Examples:
 1895     To download structure and cryo-EM data for 5K12, 5UMD, 5W81, and 5UAK
 1896     before running the following examples, type:
 1897 
 1898         % DownloadPDBFiles.pl --DensityMap yes 5K12,5UMD,5W81,5UAK
 1899 
 1900     To visualize cryo-EM density at recommended contour level for the first
 1901     chain complex in a PDB file using corresponding density map and header
 1902     file, and generate a PML file type:
 1903 
 1904         % PyMOLVisualizeCryoEMDensity.py -i 5K12.pdb -o 5K12.pml
 1905 
 1906     To visualize cryo-EM density at recommended contour level for the first
 1907     chain complex in a PDB file and highlighting densities for all cysteines and
 1908     serines  using corresponding density map and header file, and generate
 1909     a PML file type:
 1910 
 1911         % PyMOLVisualizeCryoEMDensity.py -i 5K12.pdb -o 5K12.pml
 1912           --selectionsChain "Csysteines,resn cys,Serines,resn ser"
 1913 
 1914     To visualize electron density for the largest ligand in  chain K, and ligand
 1915     binding pocket to highlight ligand interactions with pockect residues,
 1916     solvents and inorganics, in a PDB and using corresponding map files, and
 1917     generate a PML file, type:
 1918 
 1919         % PyMOLVisualizeCryoEMDensity.py -c K -i 5UMD.cif -o 5UMD.pml
 1920 
 1921     To visualize cryo-EM density for all  chains along with any solvents in a
 1922     PDB file and using corresponding map files, and generate a PML file, type:
 1923 
 1924         % PyMOLVisualizeCryoEMDensity.py -c all -i 5K12.pdb -o 5K12.pml
 1925 
 1926     To visualize cryo-EM density at a specific contour level for the first chain
 1927     complex along with volume and surface in a PDB file using corresponding
 1928     to a specific density map file, and generate a PML file, type:
 1929 
 1930         % PyMOLVisualizeCryoEMDensity.py -d emd_8194.map.gz --meshLevel 1.0
 1931           --surfaceChainComplex yes --volumeChainComplex yes -i 5K12.pdb
 1932           -o 5K12.pml
 1933 
 1934     To align and visualize cryo-EM density at recommended contour levels for the
 1935     largest ligand in the first chain along with pockets or the first chain complex
 1936     in input files using corresponding maps and header files, type:
 1937 
 1938         % PyMOLVisualizeCryoEMDensity.py -a yes -i "5W81.pdb,5UAK.pdb"
 1939           -o SampleOut.pml
 1940 
 1941     To align and visualize cryo-EM density at recommended contour levels for all
 1942     chains and ligands in input files using specified density files, type:
 1943     in input files using corresponding maps and header files, type:
 1944 
 1945         % PyMOLVisualizeCryoEMDensity.py -a yes -i "5W81.pdb,5UAK.pdb"
 1946           -o SampleOut.pml -c all -l all -d "emd_8782.map.gz,emd_8516.map.gz"
 1947 
 1948 Author:
 1949     Manish Sud(msud@san.rr.com)
 1950 
 1951 See also:
 1952     DownloadPDBFiles.pl, PyMOLVisualizeCavities.py,
 1953     PyMOLVisualizeElectronDensity.py, PyMOLVisualizeInterfaces.py,
 1954     PyMOLVisualizeMacromolecules.py, PyMOLVisualizeSurfaceAndBuriedResidues.py
 1955 
 1956 Copyright:
 1957     Copyright (C) 2024 Manish Sud. All rights reserved.
 1958 
 1959     The functionality available in this script is implemented using PyMOL, a
 1960     molecular visualization system on an open source foundation originally
 1961     developed by Warren DeLano.
 1962 
 1963     This file is part of MayaChemTools.
 1964 
 1965     MayaChemTools is free software; you can redistribute it and/or modify it under
 1966     the terms of the GNU Lesser General Public License as published by the Free
 1967     Software Foundation; either version 3 of the License, or (at your option) any
 1968     later version.
 1969 
 1970 """
 1971 
 1972 if __name__ == "__main__":
 1973     main()