       1 #!/bin/env python
       2 #
       3 # File: PyMOLCalculateRMSD.py
       4 # Author: Manish Sud <msud@san.rr.com>
       5 #
       6 # Copyright (C) 2018 Manish Sud. All rights reserved.
       7 #
       8 # The functionality available in this script is implemented using PyMOL, a
       9 # molecular visualization system on an open source foundation originally
      10 # developed by Warren DeLano.
      11 #
      12 # This file is part of MayaChemTools.
      13 #
      14 # MayaChemTools is free software; you can redistribute it and/or modify it under
      15 # the terms of the GNU Lesser General Public License as published by the Free
      16 # Software Foundation; either version 3 of the License, or (at your option) any
      17 # later version.
      18 #
      19 # MayaChemTools is distributed in the hope that it will be useful, but without
      20 # any warranty; without even the implied warranty of merchantability of fitness
      21 # for a particular purpose.  See the GNU Lesser General Public License for more
      22 # details.
      23 #
      24 # You should have received a copy of the GNU Lesser General Public License
      25 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
      26 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
      27 # Boston, MA, 02111-1307, USA.
      28 #
      29
      30 from __future__ import print_function
      31
      32 # Add local python path to the global path and import standard library modules...
      33 import os
      34 import sys;  sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python"))
      35 import time
      36 import re
      37
      38 # PyMOL imports...
      39 try:
      40     import pymol
      41     # Finish launching PyMOL in  a command line mode for batch processing (-c)
      42     # along with the following options:  disable loading of pymolrc and plugins (-k);
      43     # suppress start up messages (-q)
      44     pymol.finish_launching(['pymol', '-ckq'])
      45 except ImportError as ErrMsg:
      46     sys.stderr.write("\nFailed to import PyMOL module/package: %s\n" % ErrMsg)
      47     sys.stderr.write("Check/update your PyMOL environment and try again.\n\n")
      48     sys.exit(1)
      49
      50 # MayaChemTools imports...
      51 try:
      52     from docopt import docopt
      53     import MiscUtil
      54     import PyMOLUtil
      55 except ImportError as ErrMsg:
      56     sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg)
      57     sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n")
      58     sys.exit(1)
      59
      60 ScriptName = os.path.basename(sys.argv[0])
      61 Options = {}
      62 OptionsInfo = {}
      63
      64 def main():
      65     """Start execution of the script"""
      66
      67     MiscUtil.PrintInfo("\n%s (PyMOL v%s; %s) Starting...\n" % (ScriptName, pymol.cmd.get_version()[1], time.asctime()))
      68
      69     (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime()
      70
      71     # Retrieve command line arguments and options...
      72     RetrieveOptions()
      73
      74     # Process and validate command line arguments and options...
      75     ProcessOptions()
      76
      77     # Perform actions required by the script...
      78     CalculateRMSDValues()
      79
      80     MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName)
      81     MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime))
      82
      83 def CalculateRMSDValues():
      84     """Calculate RMSD between reference and probe files."""
      85
      86     Outfile = OptionsInfo["Outfile"]
      87     OutDelim = OptionsInfo["OutDelim"]
      88
      89     MiscUtil.PrintInfo("\nGenerating file %s..." % Outfile)
      90     OutFH = open(Outfile, "w")
      91     if OutFH is None:
      92         MiscUtil.PrintError("Couldn't open output file: %s.\n" % (Outfile))
      93
      94     WriteColumnLabels(OutFH, OutDelim)
      95
      96     pymol.cmd.reinitialize()
      97     if re.match("^OneToOne$", OptionsInfo["Mode"], re.I):
      98         CalculateOneToOneRMSDValues(OutFH, OutDelim)
      99     elif re.match("^AllToAll$", OptionsInfo["Mode"], re.I):
     100         CalculateAllToAllRMSDValues(OutFH, OutDelim)
     101     elif re.match("^FirstToAll$", OptionsInfo["Mode"], re.I):
     102         CalculateFirstToAllRMSDValues(OutFH, OutDelim)
     103     else:
     104         MiscUtil.PrintError("RMSD couldn't be calculated: Specified mode, %s, is not supported" % OptionsInfo["Mode"])
     105
     106     OutFH.close()
     107
     108 def CalculateOneToOneRMSDValues(OutFH, OutDelim):
     109     """Calculate pairwise RMSD values."""
     110
     111     RefFilesCount = len(OptionsInfo["RefFilesNames"])
     112     ProbeFilesCount = len(OptionsInfo["ProbeFilesNames"])
     113
     114     FilesCount = ProbeFilesCount if RefFilesCount > ProbeFilesCount else RefFilesCount
     115
     116     if RefFilesCount != ProbeFilesCount:
     117         MiscUtil.PrintWarning("Number of reference files, %d,  is not equal to number of probe files, %d .\n" % (RefFilesCount, ProbeFilesCount))
     118         MiscUtil.PrintWarning("Pairwise RMSD will be calculated only for first %s files.\n" % (FilesCount))
     119
     120     # Process files...
     121     for FileIndex in range(0, FilesCount):
     122         RefFileIndex = FileIndex
     123         ProbeFileIndex = FileIndex
     124
     125         LoadRefFile(RefFileIndex)
     126         LoadProbeFile(ProbeFileIndex)
     127
     128         RMSD = CalculateRMSDValue(RefFileIndex, ProbeFileIndex)
     129
     130         RefID = OptionsInfo["RefFilesInfo"]["FilesRoots"][RefFileIndex]
     131         ProbeID = OptionsInfo["ProbeFilesInfo"]["FilesRoots"][ProbeFileIndex]
     132         Line = "%s%s%s%s%s\n" % (RefID, OutDelim, ProbeID, OutDelim, RMSD)
     133         OutFH.write(Line)
     134
     135         DeleteRefObject(RefFileIndex)
     136         DeleteProbeObject(ProbeFileIndex)
     137
     138 def CalculateAllToAllRMSDValues(OutFH, OutDelim):
     139     """Calculate RMSD values between all pairs of files."""
     140
     141     RefFilesCount = len(OptionsInfo["RefFilesNames"])
     142     ProbeFilesCount = len(OptionsInfo["ProbeFilesNames"])
     143     OutMatrix = OptionsInfo["OutMatrix"]
     144
     145     for RefFileIndex in range(0, RefFilesCount):
     146         LoadRefFile(RefFileIndex)
     147         RefID = OptionsInfo["RefFilesInfo"]["FilesRoots"][RefFileIndex]
     148
     149         LineWords = []
     150         if OutMatrix:
     151             LineWords.append(RefID)
     152
     153         for ProbeFileIndex in range(0, ProbeFilesCount):
     154             LoadProbeFile(ProbeFileIndex)
     155             RMSD = CalculateRMSDValue(RefFileIndex, ProbeFileIndex)
     156             DeleteProbeObject(ProbeFileIndex)
     157
     158             if OutMatrix:
     159                 LineWords.append(RMSD)
     160             else:
     161                 ProbeID = OptionsInfo["ProbeFilesInfo"]["FilesRoots"][ProbeFileIndex]
     162                 Line = "%s%s%s%s%s\n" % (RefID, OutDelim, ProbeID, OutDelim, RMSD)
     163                 OutFH.write(Line)
     164
     165         DeleteRefObject(RefFileIndex)
     166
     167         if OutMatrix:
     168             Line = OutDelim.join(LineWords)
     169             OutFH.write("%s\n" % Line)
     170
     171 def CalculateFirstToAllRMSDValues(OutFH, OutDelim):
     172     """Calculate RMSD values between first reference file and all probe files. """
     173
     174     # Setup reference...
     175     RefFileIndex = 0
     176     RefID = OptionsInfo["RefFilesInfo"]["FilesRoots"][RefFileIndex]
     177     LoadRefFile(RefFileIndex)
     178
     179     # Go over probe files...
     180     for ProbeFileIndex in range(0, len(OptionsInfo["ProbeFilesNames"])):
     181         LoadProbeFile(ProbeFileIndex)
     182
     183         RMSD = CalculateRMSDValue(RefFileIndex, ProbeFileIndex)
     184
     185         ProbeID = OptionsInfo["ProbeFilesInfo"]["FilesRoots"][ProbeFileIndex]
     186         Line = "%s%s%s%s%s\n" % (RefID, OutDelim, ProbeID, OutDelim, RMSD)
     187         OutFH.write(Line)
     188
     189         DeleteProbeObject(ProbeFileIndex)
     190
     191     DeleteRefObject(RefFileIndex)
     192
     193 def WriteColumnLabels(OutFH, OutDelim):
     194     """Write out column labels. """
     195
     196     ColLabels = []
     197
     198     if re.match("^AllToAll$", OptionsInfo["Mode"], re.I) and OptionsInfo["OutMatrix"]:
     199         ColLabels.append("")
     200         ColLabels.extend(OptionsInfo["ProbeFilesInfo"]["FilesRoots"])
     201     else:
     202         ColLabels = ["RefFileID", "ProbeFileID", "RMSD"]
     203
     204     Line = OutDelim.join(ColLabels)
     205     OutFH.write("%s\n" % Line)
     206
     207 def LoadRefFile(RefFileIndex):
     208     """Load reference file. """
     209
     210     RefFile = OptionsInfo["RefFilesNames"][RefFileIndex]
     211     RefName = OptionsInfo["RefFilesInfo"]["PyMOLObjectNames"][RefFileIndex]
     212     LoadFile(RefFile, RefName)
     213
     214 def LoadProbeFile(ProbeFileIndex):
     215     """Load probe file. """
     216
     217     ProbeFile = OptionsInfo["ProbeFilesNames"][ProbeFileIndex]
     218     ProbeName = OptionsInfo["ProbeFilesInfo"]["PyMOLObjectNames"][ProbeFileIndex]
     219     LoadFile(ProbeFile, ProbeName)
     220
     221 def LoadFile(FileName, ObjectName):
     222     """Load a file. """
     223
     224     pymol.cmd.load(FileName, ObjectName)
     225
     226 def DeleteRefObject(RefFileIndex):
     227     """Delete reference object. """
     228
     229     RefName = OptionsInfo["RefFilesInfo"]["PyMOLObjectNames"][RefFileIndex]
     230     DeleteObject(RefName)
     231
     232 def DeleteProbeObject(ProbeFileIndex):
     233     """Delete probe object. """
     234
     235     ProbeName = OptionsInfo["ProbeFilesInfo"]["PyMOLObjectNames"][ProbeFileIndex]
     236     DeleteObject(ProbeName)
     237
     238 def DeleteObject(Name):
     239     """Delete PyMOL object. """
     240
     241     pymol.cmd.delete(Name)
     242
     243 def CalculateRMSDValue(RefFileIndex, ProbeFileIndex):
     244     """Calculate RMSD value between referece and probe objects. """
     245
     246     RefName = OptionsInfo["RefFilesInfo"]["PyMOLObjectNames"][RefFileIndex]
     247     ProbeName = OptionsInfo["ProbeFilesInfo"]["PyMOLObjectNames"][ProbeFileIndex]
     248
     249     if re.match("^FirstChain$", OptionsInfo["AlignMode"], re.I):
     250         RefFirstChainID = OptionsInfo["RefFilesInfo"]["ChainIDs"][RefFileIndex][0]
     251         RefSelection = "(%s and chain %s)" % (RefName, RefFirstChainID)
     252
     253         ProbeFirstChainID = OptionsInfo["ProbeFilesInfo"]["ChainIDs"][ProbeFileIndex][0]
     254         ProbeSelection = "(%s and chain %s)" % (ProbeName, ProbeFirstChainID)
     255     else:
     256         RefSelection = RefName
     257         ProbeSelection = ProbeName
     258
     259     RMSD = CalculateRMSD(RefSelection, ProbeSelection, OptionsInfo["AlignMethod"])
     260
     261     return RMSD
     262
     263 def CalculateRMSD(RefSelectionName, ProbeSelectionName, AlignMethod):
     264     """Calculate RMSD between two selections after aligning the selections."""
     265
     266     if re.match("^super$", AlignMethod, re.I):
     267         Results = pymol.cmd.super(ProbeSelectionName, RefSelectionName)
     268         RMSD = Results[0]
     269     elif re.match("^cealign$", AlignMethod, re.I):
     270         Results = pymol.cmd.super(RefSelectionName, ProbeSelectionName)
     271         RMSD = Results["RMSD"]
     272     elif re.match("^align$", AlignMethod, re.I):
     273         Results = pymol.cmd.super(ProbeSelectionName, RefSelectionName)
     274         RMSD = Results[0]
     275     else:
     276         RMSD = None
     277         MiscUtil.PrintWarning("Failed to calculate RMSD. Unknown alignment method: %s" % AlignMethod)
     278
     279     if RMSD is not None:
     280         RMSD = "%.2f" % RMSD
     281
     282     return RMSD
     283
     284 def RetrieveProbeFilesInfo():
     285     """Retrieve information for probe input files."""
     286
     287     RetrieveInfilesInfo("ProbeFiles")
     288
     289 def RetrieveRefFilesInfo():
     290     """Retrieve information for reference input files."""
     291
     292     RetrieveInfilesInfo("RefFiles")
     293
     294 def RetrieveInfilesInfo(InfilesMode):
     295     """Retrieve information for input files."""
     296
     297     if re.match("^ProbeFiles$", InfilesMode, re.I):
     298         MiscUtil.PrintInfo("Retrieving information for probe files...")
     299         InfilesNames = OptionsInfo["ProbeFilesNames"]
     300         NameSuffix = "_Probe"
     301     elif re.match("^RefFiles$", InfilesMode, re.I):
     302         MiscUtil.PrintInfo("Retrieving information for reference files...")
     303         InfilesNames = OptionsInfo["RefFilesNames"]
     304         NameSuffix = "_Ref"
     305     else:
     306         MiscUtil.PrintError("Internal Error: Unknown infiles mode: %s" % InfilesMode)
     307
     308     InfilesInfo = {}
     309
     310     InfilesInfo["FilesNames"] = []
     311     InfilesInfo["FilesRoots"] = []
     312     InfilesInfo["ChainIDs"] = []
     313     InfilesInfo["PyMOLObjectNames"] = []
     314
     315     for Infile in InfilesNames:
     316         MiscUtil.PrintInfo("\nRetrieving chains information for input file %s..." % Infile)
     317
     318         FileDir, FileName, FileExt = MiscUtil.ParseFileName(Infile)
     319         InfileRoot = FileName
     320
     321         ChainIDs = RetrieveChainIDs(Infile, InfileRoot)
     322         if not len(ChainIDs):
     323             if re.match("^FirstChain$", OptionsInfo["AlignMode"], re.I):
     324                 MiscUtil.PrintError("The align mode, %s, can't be used for calculating RMSD: No non-empty chain IDs found in input file." % (OptionsInfo["AlignMode"]))
     325
     326         InfilesInfo["FilesNames"].append(Infile)
     327         InfilesInfo["FilesRoots"].append(InfileRoot)
     328         InfilesInfo["ChainIDs"].append(ChainIDs)
     329
     330         Name = "%s%s" % (InfileRoot, NameSuffix)
     331         InfilesInfo["PyMOLObjectNames"].append(Name)
     332
     333     if re.match("^ProbeFiles$", InfilesMode, re.I):
     334         OptionsInfo["ProbeFilesInfo"] = InfilesInfo
     335     elif re.match("^RefFiles$", InfilesMode, re.I):
     336         OptionsInfo["RefFilesInfo"] = InfilesInfo
     337
     338 def RetrieveChainIDs(Infile, InfileRoot):
     339     """Retrieve chains IDs for an input file."""
     340
     341     pymol.cmd.reinitialize()
     342
     343     MolName = InfileRoot
     344     pymol.cmd.load(Infile, MolName)
     345
     346     ChainIDs = PyMOLUtil.GetChains(MolName, RemoveEmpty = True)
     347     pymol.cmd.delete(MolName)
     348
     349     if ChainIDs is None:
     350         ChainIDs = []
     351
     352     # Print out chain and ligand IDs...
     353     ChainInfo = ", ".join(ChainIDs) if len(ChainIDs) else "None"
     354     MiscUtil.PrintInfo("Chain IDs: %s" % ChainInfo)
     355
     356     return ChainIDs
     357
     358 def ProcessOptions():
     359     """Process and validate command line arguments and options"""
     360
     361     MiscUtil.PrintInfo("Processing options...")
     362
     363     # Validate options...
     364     ValidateOptions()
     365
     366     OptionsInfo["AlignMethod"] = Options["--alignMethod"].lower()
     367     OptionsInfo["AlignMode"] = Options["--alignMode"]
     368
     369     OptionsInfo["Mode"] = Options["--mode"]
     370
     371     OptionsInfo["ProbeFiles"] = Options["--probefiles"]
     372     OptionsInfo["ProbeFilesNames"] =  Options["--probeFilesNames"]
     373
     374     OptionsInfo["RefFiles"] = Options["--reffiles"]
     375     OptionsInfo["RefFilesNames"] =  Options["--refFilesNames"]
     376
     377     RetrieveProbeFilesInfo()
     378     RetrieveRefFilesInfo()
     379
     380     OptionsInfo["Outfile"] = Options["--outfile"]
     381     OptionsInfo["OutMatrix"] = True if re.match("^Yes$", Options["--outMatrix"], re.I) else False
     382
     383     OptionsInfo["Overwrite"] = Options["--overwrite"]
     384
     385     OptionsInfo["OutDelim"] = " "
     386     if MiscUtil.CheckFileExt(OptionsInfo["Outfile"], "csv"):
     387         OptionsInfo["OutDelim"] = ","
     388     elif MiscUtil.CheckFileExt(OptionsInfo["Outfile"], "tsv txt"):
     389         OptionsInfo["OutDelim"] = "\t"
     390     else:
     391         MiscUtil.PrintError("The file name specified , %s, for option \"--outfile\" is not valid. Supported file formats: csv tsv txt\n" % (OptionsInfo["Outfile"]))
     392
     393 def RetrieveOptions():
     394     """Retrieve command line arguments and options"""
     395
     396     # Get options...
     397     global Options
     398     Options = docopt(_docoptUsage_)
     399
     400     # Set current working directory to the specified directory...
     401     WorkingDir = Options["--workingdir"]
     402     if WorkingDir:
     403         os.chdir(WorkingDir)
     404
     405     # Handle examples option...
     406     if "--examples" in Options and Options["--examples"]:
     407         MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_))
     408         sys.exit(0)
     409
     410 def ValidateOptions():
     411     """Validate option values"""
     412
     413     MiscUtil.ValidateOptionTextValue("-a, --alignMethod", Options["--alignMethod"], "align cealign super")
     414     MiscUtil.ValidateOptionTextValue("--alignMode", Options["--alignMode"], "FirstChain Complex")
     415
     416     MiscUtil.ValidateOptionTextValue("-m, --mode", Options["--mode"], "OneToOne AllToAll FirstToAll")
     417
     418     # Expand reffiles to handle presence of multiple input files...
     419     RefFilesNames = MiscUtil.ExpandFileNames(Options["--reffiles"], ",")
     420
     421     # Validate file extensions...
     422     for RefFile in RefFilesNames:
     423         MiscUtil.ValidateOptionFilePath("-r, --reffiles", RefFile)
     424         MiscUtil.ValidateOptionFileExt("-r, --reffiles", RefFile, "pdb cif")
     425     Options["--refFilesNames"] = RefFilesNames
     426
     427     # Expand probefiles to handle presence of multiple input files...
     428     ProbeFilesNames = MiscUtil.ExpandFileNames(Options["--probefiles"], ",")
     429
     430     # Validate file extensions...
     431     for ProbeFile in ProbeFilesNames:
     432         MiscUtil.ValidateOptionFilePath("-p, --probefiles", ProbeFile)
     433         MiscUtil.ValidateOptionFileExt("-p, --probefiles", ProbeFile, "pdb cif")
     434     Options["--probeFilesNames"] = ProbeFilesNames
     435
     436     MiscUtil.ValidateOptionFileExt("-o, --outfile", Options["--outfile"], "csv tsv txt")
     437     MiscUtil.ValidateOptionsOutputFileOverwrite("-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"])
     438
     439     MiscUtil.ValidateOptionTextValue("--outMatrix", Options["--outMatrix"], "Yes No")
     440
     441 # Setup a usage string for docopt...
     442 _docoptUsage_ = """
     443 PyMOLCalculateRMSD.py - Calculate RMSD between macromolecules
     444
     445 Usage:
     446     PyMOLCalculateRMSD.py [--alignMethod <align, cealign, super>]
     447                           [--alignMode <FirstChain or Complex>] [--mode <OneToOne, AllToAll, FirstToAll>]
     448                           [--outMatrix <yes or no>] [--overwrite]
     449                           [-w <dir>] -p <probefile1,probefile2,probefile3...> -r <reffile1,reffile2,reffile3...> -o <outfile>
     450     PyMOLCalculateRMSD.py -h | --help | -e | --examples
     451
     452 Description:
     453     Calculate Root Mean Square Distance (RMSD) between a set of similar
     454     macromolecules in reference and probe input files. The probe and reference
     455     files are spatially aligned before the the calculation of RMSD values.
     456
     457     The supported input  file format are: PDB (.pdb), mmCIF (.cif)
     458
     459     The supported output file formats are:  CSV (.csv), TSV (.tsv, .txt)
     460
     461 Options:
     462     -a, --alignMethod <align, cealign, super>  [default: super]
     463         Alignment methodology to use for aligning probe input files to
     464         reference files.
     465     --alignMode <FirstChain or Complex>  [default: FirstChain]
     466         Portion of probe and reference files to use for spatial alignment of
     467         probe files against reference files.  Possible values: FirstChain or
     468         Complex.
     469
     470         The FirstChain mode allows alignment of the first chain in probe files
     471         to the first chain in reference files along with moving the rest of the
     472         complex to coordinate space of the reference files. The complete
     473         complex in probe files is aligned to the complete complex in reference
     474         files for the Complex mode.
     475     -e, --examples
     476         Print examples.
     477     -h, --help
     478         Print this help message.
     479     -m, --mode <OneToOne, AllToAll, FirstToAll>  [default: OneToOne]
     480         Specify how reference and probe input files are handled during the calculation
     481         of RMSD between reference and probe files.  Possible values: OneToOne,
     482         AllToAll and AllToFirst. For OneToOne mode, the number of reference input
     483         files must be equal to the number of probe input files. The RMSD is
     484         calculated for each pair of reference and probe file and written to the
     485         output file. For AllToAll mode, the RMSD is calculated for each reference
     486         input file against all probe input files. For FirstToAll mode, however, the RMSD
     487         is only calculated for the first reference input file against all probe files.
     488     -p, --probefiles <probefile1,probefile2,probelfile3...>
     489         A comma delimited list of probe input files. The wildcards are also allowed
     490         in file names.
     491     -r, --reffiles <reffile1,reffile2,reffile3...>
     492         A comma delimited list of reference input files. The wildcards are also allowed
     493         in file names.
     494     -o, --outfile <outfile>
     495         Output file name for writing out RMSD values. Supported text file extensions:
     496         csv, tsv or txt.
     497     --outMatrix <yes or no>  [default: yes]
     498         Output file in a matrix format during 'AllToAll' value for '-m, --mode' option.
     499     --overwrite
     500         Overwrite existing files.
     501     -w, --workingdir <dir>
     502         Location of working directory which defaults to the current directory.
     503
     504 Examples:
     505     To calculate RMSD between pair of macromolecules in reference and probe files
     506     using only first chain in each file and write out a CSV file containing calculated RMSD
     507     values along with IDs, type:
     508
     509         % PyMOLCalculateRMSD.py  -r "Sample3.pdb,Sample4.pdb,Sample5.pdb"
     510           -p "Sample3.pdb,Sample4.pdb,Sample5.pdb" -o SampleOut.csv
     511
     512     To calculate RMSD between all macromolecules in reference and probe files using
     513     complete complex and write out a CSV matrix file, type:
     514
     515         % PyMOLCalculateRMSD.py  -m AllToAll --alignMode Complex
     516            --outMatrix Yes -r "Sample3.pdb,Sample4.pdb,Sample5.pdb"
     517           -p "Sample3.pdb,Sample4.pdb" -o SampleOut.csv
     518
     519     To calculate RMSD between macromolecule in first reference against all probe files
     520     using only first chain in each file and write out a TSV file containing calculated RMSD
     521     values along with IDs, type:
     522
     523         % PyMOLCalculateRMSD.py  -m FirstToAll
     524           -r "Sample3.pdb,Sample4.pdb,Sample5.pdb"
     525           -p "Sample3.pdb,Sample4.pdb,Sample5.pdb" -o SampleOut.tsv
     526
     527     To calculate RMSD between pair of macromolecules in reference and probe files
     528     using only first chain in each file along with a specific alignment method and write
     529     out a CSV file containing calculated RMSD values, type:
     530
     531         % PyMOLCalculateRMSD.py  --alignMethod align
     532           -r "Sample3.pdb,Sample4.pdb,Sample5.pdb"
     533           -p "Sample3.pdb,Sample4.pdb,Sample5.pdb" -o SampleOut.csv
     534
     535 Author:
     536     Manish Sud(msud@san.rr.com)
     537
     538 See also:
     539     PyMOLAlignChains.py, PyMOLSplitChainsAndLigands.py,
     540     PyMOLVisualizeMacromolecules.py
     541
     542 Copyright:
     543     Copyright (C) 2018 Manish Sud. All rights reserved.
     544
     545     The functionality available in this script is implemented using PyMOL, a
     546     molecular visualization system on an open source foundation originally
     547     developed by Warren DeLano.
     548
     549     This file is part of MayaChemTools.
     550
     551     MayaChemTools is free software; you can redistribute it and/or modify it under
     552     the terms of the GNU Lesser General Public License as published by the Free
     553     Software Foundation; either version 3 of the License, or (at your option) any
     554     later version.
     555
     556 """
     557
     558 if __name__ == "__main__":
     559     main()