MayaChemTools

    1 #!/bin/env python
    2 # File: OpenMMUtil.py
    3 # Author: Manish Sud <msud@san.rr.com>
    4 #
    5 # Copyright (C) 2025 Manish Sud. All rights reserved.
    6 #
    7 # The functionality available in this script is implemented using OpenMM, an
    8 # open source molecuar simulation package.
    9 #
   10 # This file is part of MayaChemTools.
   11 #
   12 # MayaChemTools is free software; you can redistribute it and/or modify it under
   13 # the terms of the GNU Lesser General Public License as published by the Free
   14 # Software Foundation; either version 3 of the License, or (at your option) any
   15 # later version.
   16 #
   17 # MayaChemTools is distributed in the hope that it will be useful, but without
   18 # any warranty; without even the implied warranty of merchantability of fitness
   19 # for a particular purpose.  See the GNU Lesser General Public License for more
   20 # details.
   21 #
   22 # You should have received a copy of the GNU Lesser General Public License
   23 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
   24 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
   25 # Boston, MA, 02111-1307, USA.
   26 #
   27 
   28 from __future__ import print_function
   29 
   30 import os
   31 import sys
   32 import re
   33 import glob
   34 import multiprocessing as mp
   35 
   36 import openmm as mm
   37 import openmm.app
   38 
   39 import openmmforcefields as mmff
   40 import openmmforcefields.generators
   41 import openff as ff
   42 import openff.toolkit
   43 
   44 import pdbfixer
   45 import mdtraj
   46 
   47 import MiscUtil
   48 
   49 __all__ = ["AddWaterBox", "DoAtomListsOverlap", "DoesAtomListOverlapWithSystemConstraints", "DoesSystemContainWater", "FreezeAtoms", "GetAtoms", "GetFormattedTotalSimulationTime", "InitializeBarostat", "InitializeIntegrator", "InitializeReporters", "InitializeSimulation", "InitializeSystem", "InitializeSystemGenerator", "MergeSmallMoleculeWithMacromolecule", "ProcessOptionOpenMMRestartParameters", "ProcessOptionOpenMMAtomsSelectionParameters", "ProcessOptionOpenMMForcefieldParameters", "ProcessOptionOpenMMIntegratorParameters", "ProcessOptionOpenMMPlatformParameters", "ProcessOptionOpenMMOutputParameters", "ProcessOptionOpenMMSimulationParameters", "ProcessOptionOpenMMSystemParameters", "ProcessOptionOpenMMWaterBoxParameters", "ReadPDBFile", "ReadSmallMoleculeFile", "RestraintAtoms", "SetupIntegratorParameters", "SetupSimulationParameters", "SetupSystemGeneratorForcefieldsParameters", "WritePDBFile", "WriteSimulationStatePDBFile"]
   50 
   51 def InitializeSystem(PDBFile, ForcefieldParamsInfo, SystemParamsInfo, WaterBoxAdd = False, WaterBoxParamsInfo = None, SmallMolFile = None, SmallMolID = "LIG"):
   52     """Initialize OpenMM system using specified forcefields, system and water box
   53     parameters along with a small molecule file and ID.
   54     
   55     The ForcefieldParamsInfo parameter is a dictionary of name and value pairs for
   56     system parameters and may be generated by calling the function named
   57     ProcessOptionOpenMMForcefieldParameters().
   58     
   59     The SystemParamsInfo parameter is a dictionary of name and value pairs for
   60     system parameters and may be generated by calling the function named
   61     ProcessOptionOpenMMSystemParameters().
   62     
   63     The WaterBoxParamsInfo parameter is a dictionary of name and value pairs for
   64     system parameters and may be generated by calling the function named
   65     ProcessOptionOpenMMWaterBoxParameters().
   66 
   67     Arguments:
   68         PDBFile (str): PDB file name..
   69         ForcefieldParamsInfo (dict): Parameter name and value pairs.
   70         SystemParamsInfo (dict): Parameter name and value pairs.
   71         WaterBoxAdd (bool): Add water box.
   72         WaterBoxParamsInfo (dict): Parameter name and value pairs.
   73         SmallMolFile (str): Small molecule file name..
   74         SmallMolID (str): Three letter small molecule ID
   75 
   76     Returns:
   77         Object: OpenMM system object.
   78         Object: OpenMM topology object.
   79         Object: OpenMM positions object.
   80 
   81     Examples:
   82 
   83         ... ... ...
   84         OptionsInfo["ForcefieldParams"] =
   85             OpenMMUtil.ProcessOptionOpenMMForcefieldParameters(
   86             "--forcefieldParams", Options["--forcefieldParams"])
   87         ... ... ...
   88         OptionsInfo["SystemParams"] = 
   89             OpenMMUtil.ProcessOptionOpenMMSystemParameters("--systemParams", 
   90             Options["--systemParams"])
   91         ... ... ...
   92         OptionsInfo["WaterBoxParams"] =
   93             OpenMMUtil.ProcessOptionOpenMMWaterBoxParameters(
   94             "--waterBoxParams", Options["--waterBoxParams"])
   95         ... ... ...
   96         System, Topology, Positions  = OpenMMUtil.InitializeSystem(
   97             OptionsInfo["Infile"], OptionsInfo["ForcefieldParams"],
   98             OptionsInfo["SystemParams"], OptionsInfo["WaterBox"],
   99             OptionsInfo["WaterBoxParams"], OptionsInfo["SmallMolFile"],
  100             OptionsInfo["SmallMolID"])
  101 
  102     """
  103 
  104     # Read PDB file file...
  105     MiscUtil.PrintInfo("\nReading PDB file %s..." % PDBFile)
  106     PDBHandle = ReadPDBFile(PDBFile)
  107     
  108     ModellerHandle = mm.app.Modeller(PDBHandle.topology, PDBHandle.positions)
  109     MiscUtil.PrintInfo("Number of residues: %s; Number of atoms: %s" % (ModellerHandle.topology.getNumResidues(), ModellerHandle.topology.getNumAtoms()))
  110 
  111     # Read small molecule file...
  112     SmallMols = None
  113     if SmallMolFile is not None:
  114         MiscUtil.PrintInfo("\nReading small molecule file %s..." % SmallMolFile)
  115         SmallMol = ReadSmallMoleculeFile(SmallMolFile)
  116         if SmallMol is None:
  117             MiscUtil.PrintError("Failed to read small molecule file: %s" % SmallMolFile)
  118         SmallMols = [SmallMol]
  119 
  120         MiscUtil.PrintInfo("\nGenerating macromolecule and small molecule complex...")
  121         MergeSmallMoleculeWithMacromolecule(ModellerHandle, SmallMol, SmallMolID)
  122         MiscUtil.PrintInfo("Number of residues: %s; Number of atoms: %s" % (ModellerHandle.topology.getNumResidues(), ModellerHandle.topology.getNumAtoms()))
  123 
  124     # Initialize system generator...
  125     BiopolymerForcefield = ForcefieldParamsInfo["Biopolymer"]
  126     SmallMoleculeForcefield = ForcefieldParamsInfo["SmallMolecule"]
  127     WaterForcefield = ForcefieldParamsInfo["Water"]
  128     AdditionalForcefiedsList = ForcefieldParamsInfo["AdditionalList"]
  129     SystemGeneratorHandle = InitializeSystemGenerator(BiopolymerForcefield, SmallMoleculeForcefield, WaterForcefield, SystemParamsInfo, SmallMols, AdditionalForcefiedsList)
  130 
  131     if WaterBoxAdd:
  132         AddWaterBox(ModellerHandle, SystemGeneratorHandle, WaterBoxParamsInfo)
  133         MiscUtil.PrintInfo("Number of residues: %s; Number of atoms: %s" % (ModellerHandle.topology.getNumResidues(), ModellerHandle.topology.getNumAtoms()))
  134     else:
  135         MiscUtil.PrintInfo("\nSkipping addition of a water box...")
  136         if DoesSystemContainWater(ModellerHandle.topology):
  137             if ForcefieldParamsInfo["ImplicitWater"]:
  138                 MiscUtil.PrintInfo("Your system contains water molecules during the use of implicit water forcefield. The combination of biopolymer and water forcefields, %s and %s, specified using \"--forcefieldParams\" option may not be valid. You may consider removing water molecules from your system or specify a valid combination of biopolymer and water forcefields for explicit water." % (ForcefieldParamsInfo["Biopolymer"], ForcefieldParamsInfo["Water"]))
  139 
  140     MiscUtil.PrintInfo("\nBuilding system...")
  141     SystemHandle = SystemGeneratorHandle.create_system(ModellerHandle.topology, molecules = SmallMols)
  142 
  143     MiscUtil.PrintInfo("Periodic boundary conditions: %s" % ("Yes" if DoesSystemUsesPeriodicBoundaryConditions(SystemHandle) else "No"))
  144 
  145     return (SystemHandle, ModellerHandle.topology, ModellerHandle.positions)
  146 
  147 def InitializeSystemGenerator(BiopolymerForcefield, SmallMoleculeForcefield, WaterForcefield, SystemParamsInfo, SmallMols, AdditionalForcefieldsList = None):
  148     """Initialize MMFF system generator using specified forcefields and system parameters
  149     along with a list of molecules.
  150     
  151     The SystemParamsInfo parameter is a dictionary of name and value pairs for
  152     system parameters and may be generated by calling the function named
  153     ProcessOptionOpenMMSystemParameters().
  154 
  155     Arguments:
  156         BiopolymerForcefield (str): Biopolymer force field name.
  157         SmallMoleculeForcefield (str): Small molecule force field name.
  158         WaterForcefield (str): Water force field name.
  159         SystemParamsInfo (dict): Parameter name and value pairs.
  160         SmallMols (list): List of OpenFF toolkit molecule objects.
  161         AdditionalForcefieldsList (list): List of any additional forcefield
  162             names
  163 
  164     Returns:
  165         Object: MMFF system generator object.
  166 
  167     Examples:
  168 
  169         OptionsInfo["SystemParams"] = 
  170             OpenMMUtil.ProcessOptionOpenMMSystemParameters("--systemParams", 
  171             Options["--systemParams"])
  172         ... ... ...
  173         SystemGeneratorHandle = OpenMMUtil.InitializeSystemGenerator(
  174             BiopolymerForcefield, SmallMoleculeForcefield, WaterForcefield,
  175             OptionsInfo["SystemParams"], SmallMols, AdditionalForcefiedsList)
  176 
  177     """
  178 
  179     (ForcefieldParams, PeriodicForcefieldParams, NonPeriodicForcefieldParams) = SetupSystemGeneratorForcefieldsParameters(SystemParamsInfo)
  180 
  181     AdditionalForcefieldMsg = ""
  182     if AdditionalForcefieldsList is not None:
  183         AdditionalForcefieldMsg = "; Additional forcefield(s): %s" % ", ".join(AdditionalForcefieldsList)
  184         
  185     MiscUtil.PrintInfo("\nInitializing system generator (Biopolymer forcefield: %s; Small molecule forcefield: %s; Water forcefield: %s%s)..." % (BiopolymerForcefield, SmallMoleculeForcefield,WaterForcefield, AdditionalForcefieldMsg))
  186 
  187     ForcefieldsList = [BiopolymerForcefield, WaterForcefield]
  188     if AdditionalForcefieldsList is not None:
  189         ForcefieldsList.extend(AdditionalForcefieldsList)
  190 
  191     SystemGeneratorHandle = mmff.generators.SystemGenerator(forcefields = ForcefieldsList, small_molecule_forcefield = SmallMoleculeForcefield, molecules = SmallMols, forcefield_kwargs = ForcefieldParams, periodic_forcefield_kwargs = PeriodicForcefieldParams, nonperiodic_forcefield_kwargs = NonPeriodicForcefieldParams)
  192 
  193     return SystemGeneratorHandle
  194 
  195 def InitializeIntegrator(ParamsInfo, ConstraintErrorTolerance):
  196     """Initialize integrator.
  197     
  198     The ParamsInfo parameter is a dictionary of name and value pairs for
  199     integrator parameters and may be generated by calling the function named
  200     ProcessOptionOpenMMIntegratorParameters().
  201 
  202     Arguments:
  203         ParamsInfo (dict): Parameter name and value pairs.
  204         ConstraintErrorTolerance (float): Distance tolerance for
  205             constraints as a fraction of the constrained distance.
  206 
  207     Returns:
  208         Object: OpenMM integrator object.
  209 
  210     Examples:
  211 
  212         OptionsInfo["IntegratorParams"] =
  213             OpenMMUtil.ProcessOptionOpenMMIntegratorParameters(
  214             "--integratorParams", Options["--integratorParams"],
  215             HydrogenMassRepartioningStatus =
  216             OptionsInfo["SystemParams"]["HydrogenMassRepartioning"])
  217         ... ... ...
  218         Integrator = OpenMMUtil.InitializeIntegrator(
  219             OptionsInfo["IntegratorParams"],
  220             OptionsInfo["SystemParams"]["ConstraintErrorTolerance"])
  221 
  222     """
  223 
  224     IntegratorParamsInfo = SetupIntegratorParameters(ParamsInfo)
  225 
  226     IntegratorName = IntegratorParamsInfo["Integrator"]
  227     RandomSeed = IntegratorParamsInfo["RandomSeed"]
  228     StepSize = IntegratorParamsInfo["StepSize"]
  229     Temperature = IntegratorParamsInfo["Temperature"]
  230     FrictionCoefficient = IntegratorParamsInfo["FrictionCoefficient"]
  231     
  232     MiscUtil.PrintInfo("\nIntializing integrator (Name: %s; StepSize: %s; Temperature: %s)..." % (IntegratorName, StepSize, Temperature))
  233 
  234     if re.match("^LangevinMiddle$", IntegratorName, re.I):
  235         Integrator = mm.LangevinMiddleIntegrator(Temperature, FrictionCoefficient, StepSize)
  236     elif re.match("^Langevin$", IntegratorName, re.I):
  237         Integrator = mm.LangevinIntegrator(Temperature, FrictionCoefficient, StepSize)
  238     elif re.match("^NoseHoover$", IntegratorName, re.I):
  239         Integrator = mm.NoseHooverIntegrator(Temperature, FrictionCoefficient, StepSize)
  240     elif re.match("^Brownian$", IntegratorName, re.I):
  241         Integrator = mm.BrownianIntegrator(Temperature, FrictionCoefficient, StepSize)
  242     else:
  243         MiscUtil.PrintError("The parameter value specified, %s, for parameter name, integrator, for option \"--integratorParams\" is not a valid value. Supported values: LangevinMiddle, Langevin, NoseHoover, or Brownian" % IntegratorName)
  244 
  245     Integrator.setConstraintTolerance(ConstraintErrorTolerance)
  246 
  247     if RandomSeed is not None:
  248         if re.match("^(LangevinMiddle|Langevin|Brownian)$", IntegratorName, re.I):
  249             MiscUtil.PrintInfo("Setting random number seed for integrator to %s..." % RandomSeed)
  250             Integrator.setRandomNumberSeed(RandomSeed)
  251         else:
  252             MiscUtil.PrintInfo("Skipping setting of random number seed. Not supported for integrator %s..." % IntegratorName)
  253 
  254     return Integrator
  255 
  256 def InitializeBarostat(ParamsInfo):
  257     """Initialize barostat.
  258     
  259     The ParamsInfo parameter is a dictionary of name and value pairs for
  260     integrator parameters and may be generated by calling the function named
  261     ProcessOptionOpenMMIntegratorParameters().
  262 
  263     Arguments:
  264         ParamsInfo (dict): Parameter name and value pairs.
  265 
  266     Returns:
  267         Object: OpenMM barostat object.
  268 
  269     Examples:
  270 
  271         OptionsInfo["IntegratorParams"] =
  272             OpenMMUtil.ProcessOptionOpenMMIntegratorParameters(
  273             "--integratorParams", Options["--integratorParams"],
  274             HydrogenMassRepartioningStatus =
  275             OptionsInfo["SystemParams"]["HydrogenMassRepartioning"])
  276         ... ... ...
  277         Barostat = OpenMMUtil.InitializeBarostat(
  278             OptionsInfo["IntegratorParams"])
  279 
  280     """
  281     IntegratorParamsInfo = SetupIntegratorParameters(ParamsInfo)
  282 
  283     BarostatName = IntegratorParamsInfo["Barostat"]
  284     if re.match("^MonteCarlo$", BarostatName, re.I):
  285         MiscUtil.PrintInfo("\nInitializing Monte Carlo barostat (Pressure: %s)... " % (IntegratorParamsInfo["Pressure"]))
  286         Barostat = mm.MonteCarloBarostat(IntegratorParamsInfo["Pressure"], IntegratorParamsInfo["Temperature"], IntegratorParamsInfo["BarostatInterval"])
  287     elif re.match("^MonteCarloMembrane$", BarostatName, re.I):
  288         MiscUtil.PrintInfo("\nInitializing Monte Carlo membrane barostat (Pressure: %s; SurfaceTension: %s; XYMode: %s; ZMode: %s)... " % (IntegratorParamsInfo["Pressure"], IntegratorParamsInfo["SurfaceTension"], IntegratorParamsInfo["XYModeSpecified"], IntegratorParamsInfo["ZModeSpecified"]))
  289         Barostat = mm.MonteCarloMembraneBarostat(IntegratorParamsInfo["Pressure"], IntegratorParamsInfo["SurfaceTension"], IntegratorParamsInfo["Temperature"], IntegratorParamsInfo["XYMode"], IntegratorParamsInfo["ZMode"], IntegratorParamsInfo["BarostatInterval"])
  290     else:
  291         MiscUtil.PrintError("The parameter value specified, %s, for parameter name, barostat, for option \"--integratorParams\" is not a valid value. Supported values: MonteCarlo or MonteCarloMembrane" % BarostatName)
  292 
  293     if IntegratorParamsInfo["RandomSeed"] is not None:
  294         RandomSeed = IntegratorParamsInfo["RandomSeed"]
  295         MiscUtil.PrintInfo("Setting random number seed for barostat to %s..." % RandomSeed)
  296         Barostat.setRandomNumberSeed(RandomSeed)
  297 
  298     return Barostat
  299 
  300 def InitializeSimulation(System, Integrator, Topology, Positions, PlatformParamsInfo):
  301     """Initialize simulation.
  302     
  303     The PlatformParamsInfo parameter is a dictionary of name and value pairs for
  304     platform parameters and may be generated by calling the function named
  305     ProcessOptionOpenMMPlatformParameters().
  306 
  307     Arguments:
  308         System (object): OpenMM system object.
  309         Integrator (object): OpenMM integrator object.
  310         Topology (object): OpenMM topology object.
  311         Positons (object): OpenMM Positions object.
  312         PlatformParamsInfo (dict): Parameter name and value pairs.
  313 
  314     Returns:
  315         Object: OpenMM simulation object.
  316 
  317     Examples:
  318 
  319         ParamsDefaultInfoOverride = {"Name": Options["--platform"],
  320              "Threads": 1}
  321         OptionsInfo["PlatformParams"] =
  322             OpenMMUtil.ProcessOptionOpenMMPlatformParameters("--platformParams",
  323             Options["--platformParams"], ParamsDefaultInfoOverride)
  324         ... ... ...
  325         Simulation = OpenMMUtil.InitializeSimulation(System, Integrator, Topology,
  326             Positions, OptionsInfo["PlatformParams"])
  327 
  328     """
  329 
  330     PlatformName, PlatformProperties, PlatformMsg = SetupPlatformParameters(PlatformParamsInfo)
  331     MiscUtil.PrintInfo("\nInitializing simulation (%s)..." % PlatformMsg)
  332 
  333     try:
  334         PlatformHandle = mm.Platform.getPlatformByName(PlatformName)
  335     except Exception as ErrMsg:
  336         MiscUtil.PrintInfo("")
  337         MiscUtil.PrintError("Failed to get platform %s:\n%s\n" % (PlatformName, ErrMsg))
  338         
  339     try:
  340         SimulationHandle = mm.app.Simulation(Topology, System, Integrator, PlatformHandle, PlatformProperties)
  341     except Exception as ErrMsg:
  342         MiscUtil.PrintInfo("")
  343         MiscUtil.PrintError("Failed to initialize simulation: %s\n" % (ErrMsg))
  344 
  345     SimulationHandle.context.setPositions(Positions)
  346 
  347     return (SimulationHandle)
  348 
  349 def InitializeReporters(OutputParamsInfo, TotalSteps, DataOutAppendStatus):
  350     """Initialize reporters for writing data to trajectory, log, and checkpoint
  351     files along with reporting to the stdout.
  352     
  353     The OutputParamsInfo parameter is a dictionary of name and value pairs for
  354     output parameters and may be generated by calling the function named
  355     ProcessOptionOpenMMOutputParameters().
  356 
  357     Arguments:
  358         OutputParamsInfo (dict): Parameter name and value pairs.
  359         TotalSteps (int): Total number of simulation steps.
  360         DataOutAppendStatus (bool): Append data to trajectory and log file.
  361 
  362     Returns:
  363         Object: OpenMM trajectory reporter object.
  364         Object: OpenMM data log file reporter object.
  365         Object: OpenMM stodut reporter object.
  366         Object: OpenMM checkpoint reporter object.
  367 
  368     Examples:
  369 
  370         if OptionsInfo["NVTMode"]:
  371             ParamsDefaultInfoOverride = {"DataOutType": "Step Speed Progress
  372                 PotentialEnergy Temperature Time Volume"}
  373         else:
  374             ParamsDefaultInfoOverride = {"DataOutType": "Step Speed Progress
  375               PotentialEnergy Temperature Time Density"}
  376         OptionsInfo["OutputParams"] =
  377             OpenMMUtil.ProcessOptionOpenMMOutputParameters("--outputParams", 
  378             Options["--outputParams"], OptionsInfo["OutfilePrefix"],
  379             ParamsDefaultInfoOverride)
  380         ProcessOutfileNames()
  381         ... ... ...
  382         (TrajReporter, DataLogReporter, DataStdoutReporter, CheckpointReporter)
  383             = OpenMMUtil.InitializeReporters(OptionsInfo["OutputParams"],
  384             OptionsInfo["SimulationParams"]["Steps"], OptionsInfo["DataOutAppendMode"])
  385 
  386     """
  387 
  388     (TrajReporter, DataLogReporter, DataStdoutReporter, CheckpointReporter) = [None] * 4
  389     if OutputParamsInfo["Traj"]:
  390         if re.match("^DCD$", OutputParamsInfo["TrajFormat"], re.I):
  391             TrajReporter = mm.app.DCDReporter(OutputParamsInfo["TrajFile"], OutputParamsInfo["TrajSteps"], append = DataOutAppendStatus)
  392         elif re.match("^XTC$", OutputParamsInfo["TrajFormat"], re.I):
  393             if not DataOutAppendStatus:
  394                 # Remove existing traj file; otherwise, XTCReporter fails...
  395                 if os.path.isfile(OutputParamsInfo["TrajFile"]):
  396                     os.remove(OutputParamsInfo["TrajFile"])
  397             TrajReporter = mm.app.XTCReporter(OutputParamsInfo["TrajFile"], OutputParamsInfo["TrajSteps"], append = DataOutAppendStatus)
  398         else:
  399             MiscUtil.PrintError("The parameter value specified, %s, for parameter name, trajFormat, for option \"--outputParams\" is not a valid value. Supported format: DCD or XTC")
  400 
  401     if OutputParamsInfo["Checkpoint"]:
  402         CheckpointReporter = mm.app.CheckpointReporter(OutputParamsInfo["CheckpointFile"], OutputParamsInfo["CheckpointSteps"])
  403 
  404     DataOutTypeStatusMap = OutputParamsInfo["DataOutTypeStatusMap"]
  405     if OutputParamsInfo["DataLog"]:
  406         DataLogReporter = mm.app.StateDataReporter(OutputParamsInfo["DataLogFile"], OutputParamsInfo["DataLogSteps"], totalSteps = TotalSteps, step = DataOutTypeStatusMap["Step"], time = DataOutTypeStatusMap["Time"], speed = DataOutTypeStatusMap["Speed"], progress = DataOutTypeStatusMap["Progress"], elapsedTime = DataOutTypeStatusMap["ElapsedTime"], remainingTime = DataOutTypeStatusMap["RemainingTime"], potentialEnergy = DataOutTypeStatusMap["PotentialEnergy"], kineticEnergy = DataOutTypeStatusMap["KineticEnergy"], totalEnergy = DataOutTypeStatusMap["TotalEnergy"], temperature = DataOutTypeStatusMap["Temperature"], volume = DataOutTypeStatusMap["Volume"], density = DataOutTypeStatusMap["Density"], separator = OutputParamsInfo["DataOutDelimiter"], append = DataOutAppendStatus)
  407         
  408     if OutputParamsInfo["DataStdout"]:
  409         DataStdoutReporter = mm.app.StateDataReporter(sys.stdout, OutputParamsInfo["DataStdoutSteps"], totalSteps = TotalSteps, step = DataOutTypeStatusMap["Step"], time = DataOutTypeStatusMap["Time"], speed = DataOutTypeStatusMap["Speed"], progress = DataOutTypeStatusMap["Progress"], elapsedTime = DataOutTypeStatusMap["ElapsedTime"], remainingTime = DataOutTypeStatusMap["RemainingTime"], potentialEnergy = DataOutTypeStatusMap["PotentialEnergy"], kineticEnergy = DataOutTypeStatusMap["KineticEnergy"], totalEnergy = DataOutTypeStatusMap["TotalEnergy"], temperature = DataOutTypeStatusMap["Temperature"], volume = DataOutTypeStatusMap["Volume"], density = DataOutTypeStatusMap["Density"], separator = OutputParamsInfo["DataOutDelimiter"])
  410         
  411     return (TrajReporter, DataLogReporter, DataStdoutReporter, CheckpointReporter)
  412 
  413 def AddWaterBox(ModellerHandle, SystemGeneratorHandle, WaterBoxParamsInfo):
  414     """Add a water box.
  415     
  416     The WaterBoxParamsInfo parameter is a dictionary of name and value pairs for
  417     waterbox parameters and may be generated by calling the function named
  418     ProcessOptionOpenMMWaterBoxParameters().
  419 
  420     Arguments:
  421         ModellerHandle (object): OpenMM modeller object.
  422         SystemGeneratorHandle (object): OpenMM system generator object.
  423         WaterBoxParamsInfo (dict): Parameter name and value pairs.
  424 
  425     Returns:
  426         None.
  427 
  428     Examples:
  429 
  430         OptionsInfo["WaterBoxParams"] =
  431             OpenMMUtil.ProcessOptionOpenMMWaterBoxParameters("--waterBoxParams",
  432             Options["--waterBoxParams"])
  433         ... ... ...
  434         OpenMMUtil.AddWaterBox(ModellerHandle, SystemGeneratorHandle,
  435            OptionsInfo["WaterBoxParams"])
  436 
  437     """
  438 
  439     MiscUtil.PrintInfo("\nRemoving any existing waters...")
  440     ModellerHandle.deleteWater()
  441 
  442     MiscUtil.PrintInfo("\nAdding a water box...")
  443     
  444     Size, Padding, Shape = [None] * 3
  445     if WaterBoxParamsInfo["ModeSize"]:
  446         SizeList = WaterBoxParamsInfo["SizeList"]
  447         Size = mm.Vec3(SizeList[0], SizeList[1], SizeList[2]) * mm.unit.nanometer
  448     elif WaterBoxParamsInfo["ModePadding"]:
  449         Padding = WaterBoxParamsInfo["Padding"] * mm.unit.nanometer
  450         Shape = WaterBoxParamsInfo["Shape"]
  451     else:
  452         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, mode, using \"--waterBoxParams\" option is not a valid value. Supported values: Size Padding \n" % (WaterBoxParamsInfo["Mode"]))
  453 
  454     IonicStrength = WaterBoxParamsInfo["IonicStrength"] * mm.unit.molar
  455 
  456     ModellerHandle.addSolvent(SystemGeneratorHandle.forcefield, model = WaterBoxParamsInfo["Model"], boxSize = Size, boxVectors = None, padding = Padding, numAdded = None, boxShape = Shape, positiveIon = WaterBoxParamsInfo["IonPositive"], negativeIon = WaterBoxParamsInfo["IonNegative"], ionicStrength = IonicStrength, neutralize = True)
  457 
  458 def SetupSystemGeneratorForcefieldsParameters(SystemParamsInfo):
  459     """Setup forcefied parameters for OpenMM API calls.
  460     
  461     The SystemParamsInfo parameter is a dictionary of name and value pairs for
  462     system parameters and may be generated by calling the function named
  463     ProcessOptionOpenMMSystemParameters().
  464 
  465     Arguments:
  466         SystemParamsInfo (dict): Parameter name and value pairs.
  467 
  468     Returns:
  469         dict: Forcefield parameter name and value pairs.
  470         dictionary2: Periodic forcefield parameter name and value pairs.
  471         dictionary3: Non-periodic parameter name and value pairs.
  472 
  473     Examples:
  474 
  475         OptionsInfo["SystemParams"] = 
  476             OpenMMUtil.ProcessOptionOpenMMSystemParameters("--systemParams", 
  477             Options["--systemParams"])
  478         ... ... ...
  479         (ForcefieldParams, PeriodicForcefieldParams, NonPeriodicForcefieldParams)
  480             = SetupSystemGeneratorForcefieldsParameters(OptionsInfo["SystemParams"])
  481 
  482     """
  483 
  484     ForcefieldParams = {"constraints": SystemParamsInfo["Constraints"], "rigidWater": SystemParamsInfo["RigidWater"], "removeCMMotion": SystemParamsInfo["RemoveCMMotion"]}
  485     if SystemParamsInfo["HydrogenMassRepartioning"]:
  486         ForcefieldParams["hydrogenMass"] = SystemParamsInfo["HydrogenMass"] * mm.unit.amu
  487 
  488     NonbondedCutoff = SystemParamsInfo["NonbondedCutoff"] * mm.unit.nanometers
  489     PeriodicForcefieldParams = {"nonbondedMethod": SystemParamsInfo["NonbondedMethodPeriodic"], "nonbondedCutoff": NonbondedCutoff, "ewaldErrorTolerance":  SystemParamsInfo["EwaldErrorTolerance"]}
  490     NonPeriodicForcefieldParams = {"nonbondedMethod": SystemParamsInfo["NonbondedMethodNonPeriodic"], "nonbondedCutoff" : NonbondedCutoff}
  491 
  492     return (ForcefieldParams, PeriodicForcefieldParams, NonPeriodicForcefieldParams)
  493 
  494 def SetupPlatformParameters(ParamsInfo):
  495     """Setup platform parameters for OpenMM calls.
  496     
  497     The ParamsInfo parameter is a dictionary of name and value pairs for
  498     platform parameters and may be generated by calling the function named
  499     ProcessOptionOpenMMPlatformParameters().
  500 
  501     Arguments:
  502         ParamsInfo (dict): Parameter name and value pairs.
  503 
  504     Returns:
  505         str: PlatformName.
  506         dict: Platform properities parameter name and values pairs.
  507         str: Text message describing platform.
  508 
  509     Examples:
  510 
  511         ParamsDefaultInfoOverride = {"Name": Options["--platform"],
  512              "Threads": 1}
  513         OptionsInfo["PlatformParams"] =
  514             OpenMMUtil.ProcessOptionOpenMMPlatformParameters("--platformParams",
  515             Options["--platformParams"], ParamsDefaultInfoOverride)
  516         ... ... ...
  517         PlatformName, PlatformProperties, PlatformMsg =
  518             SetupPlatformParameters(PlatformParamsInfo)
  519 
  520     """
  521 
  522     PlatformName = ParamsInfo["Name"]
  523     ParamNames = None
  524 
  525     if re.match("^CPU$", PlatformName, re.I):
  526         ParamNames = ["Threads"]
  527     elif re.match("^CUDA$", PlatformName, re.I):
  528         ParamNames = ["DeviceIndex", "DeterministicForces", "Precision", "TempDirectory", "UseBlockingSync", "UseCpuPme"]
  529     elif re.match("^OpenCL$", PlatformName, re.I):
  530         ParamNames = ["DeviceIndex", "OpenCLPlatformIndex", "Precision", "UseCpuPme"]
  531     elif re.match("^Reference$", PlatformName, re.I):
  532         ParamNames = None
  533     else:
  534         MiscUtil.PrintError("The parameter value specified, %s, for parameter name, name, for option \"--platformParams\" is not a valid value. Supported values: CPU, CUDA, OpenCL, or Reference")
  535 
  536     PlatformProperties = None
  537     if ParamNames is not None:
  538         FirstValue = True
  539         for ParamName in ParamNames:
  540             ParamValue = ParamsInfo[ParamName]
  541             if ParamValue is not None:
  542                 if FirstValue:
  543                     FirstValue = False
  544                     PlatformProperties = {}
  545                 PlatformProperties[ParamName] = ParamValue
  546 
  547     PlatformMsg = "Platform: %s" % PlatformName
  548     if re.match("^CPU$", PlatformName, re.I):
  549         Threads = ParamsInfo["Threads"]
  550         if Threads is None or Threads == "0":
  551             Threads = "auto"
  552         PlatformMsg = "Platform: %s; Threads: %s" % (PlatformName, Threads)
  553     elif re.match("^(CUDA|OpenCL)$", PlatformName, re.I):
  554         DeviceIndex = "auto" if ParamsInfo["DeviceIndex"] is None else ParamsInfo["DeviceIndex"]
  555         Precision = "auto" if ParamsInfo["Precision"] is None else ParamsInfo["Precision"]
  556         PlatformMsg = "Platform: %s; DeviceIndex: %s; Precision: %s" % (PlatformName, DeviceIndex, Precision)
  557 
  558     return (PlatformName, PlatformProperties, PlatformMsg)
  559 
  560 def SetupIntegratorParameters(ParamsInfo):
  561     """Setup integrator parameters for OpenMM API calls.
  562     
  563     The ParamsInfo parameter is a dictionary of name and value pairs for
  564     integrator parameters and may be generated by calling the function named
  565     ProcessOptionOpenMMIntegratorParameters().
  566 
  567     Arguments:
  568         ParamsInfo (dict): Parameter name and value pairs.
  569 
  570     Returns:
  571         dict: Integrator parameter name and values pairs.
  572 
  573     Examples:
  574 
  575         OptionsInfo["IntegratorParams"] =
  576             OpenMMUtil.ProcessOptionOpenMMIntegratorParameters(
  577             "--integratorParams", Options["--integratorParams"],
  578             HydrogenMassRepartioningStatus =
  579             OptionsInfo["SystemParams"]["HydrogenMassRepartioning"])
  580         ... ... ...
  581         IntegratorParams = SetupIntegratorParameters(
  582             OptionsInfo["IntegratorParams"])
  583 
  584     """
  585 
  586     ParamsInfoWithUnits = {}
  587     
  588     ParamsInfoWithUnits["Integrator"] = ParamsInfo["Integrator"]
  589 
  590     ParamsInfoWithUnits["RandomSeed"] = ParamsInfo["RandomSeed"]
  591 
  592     ParamsInfoWithUnits["FrictionCoefficient"] = ParamsInfo["FrictionCoefficient"]/mm.unit.picosecond
  593     ParamsInfoWithUnits["StepSize"] = ParamsInfo["StepSize"] * mm.unit.femtoseconds
  594     ParamsInfoWithUnits["Temperature"] = ParamsInfo["Temperature"] * mm.unit.kelvin
  595 
  596     ParamsInfoWithUnits["Barostat"] = ParamsInfo["Barostat"]
  597 
  598     ParamsInfoWithUnits["Pressure"] = ParamsInfo["Pressure"] * mm.unit.atmospheres
  599     ParamsInfoWithUnits["BarostatInterval"] = ParamsInfo["BarostatInterval"]
  600 
  601     SurfaceTensionInAngstroms = ParamsInfo["SurfaceTension"]
  602     SurfaceTension = SurfaceTensionInAngstroms  * mm.unit.atmospheres * mm.unit.angstroms
  603 
  604     SurfaceTensionInNanometers = SurfaceTension.value_in_unit(mm.unit.atmospheres * mm.unit.nanometer)
  605     ParamsInfoWithUnits["SurfaceTension"] = SurfaceTensionInNanometers * mm.unit.atmospheres * mm.unit.nanometers
  606 
  607     XYMode = ParamsInfo["XYMode"]
  608     XYModeSpecified = ""
  609     if re.match("^Anisotropic$", XYMode, re.I):
  610         XYMode = mm.MonteCarloMembraneBarostat.XYAnisotropic
  611         XYModeSpecified = "Anisotropic"
  612     elif re.match("^Isotropic$", XYMode, re.I):
  613         XYMode = mm.MonteCarloMembraneBarostat.XYIsotropic
  614         XYModeSpecified = "Isotropic"
  615     else:
  616         MiscUtil.PrintError("The parameter value specified, %s, for parameter name, xymode, for option \"--integratorParams\" is not a valid value. Supported values: Anisotropic or  Isotropic" % XYMode)
  617     ParamsInfoWithUnits["XYMode"] = XYMode
  618     ParamsInfoWithUnits["XYModeSpecified"] = XYModeSpecified
  619 
  620     ZMode = ParamsInfo["ZMode"]
  621     ZModeSpecified = ""
  622     if re.match("^Fixed$", ZMode, re.I):
  623         ZMode = mm.MonteCarloMembraneBarostat.ZFixed
  624         ZModeSpecified = "Fixed"
  625     elif re.match("^Free$", ZMode, re.I):
  626         ZMode = mm.MonteCarloMembraneBarostat.ZFree
  627         ZModeSpecified = "Free"
  628     else:
  629         MiscUtil.PrintError("The parameter value specified, %s, for parameter name, zmode, for option \"--integratorParams\" is not a valid value. Supported values: Fixed or Free" % ZMode)
  630     ParamsInfoWithUnits["ZMode"] = ZMode
  631     ParamsInfoWithUnits["ZModeSpecified"] = ZModeSpecified
  632 
  633     return ParamsInfoWithUnits
  634 
  635 def SetupSimulationParameters(ParamsInfo):
  636     """Setup simulation parameters for OpenMM API calls.
  637     
  638     The ParamsInfo parameter is a dictionary of name and value pairs for
  639     integrator parameters and may be generated by calling the function named
  640     ProcessOptionOpenMSimulationParameters().
  641 
  642     Arguments:
  643         ParamsInfo (dict): Parameter name and value pairs.
  644 
  645     Returns:
  646         dict: Integrator parameter name and values pairs.
  647 
  648     Examples:
  649 
  650         OptionsInfo["SimulationParams"] =
  651             OpenMMUtil.ProcessOptionOpenMMSimulationParameters(
  652             "--simulationParams", Options["--simulationParams"])
  653         ... ... ...
  654         SimulationParams = SetupSimulationParameters(
  655             OptionsInfo["SimulationParams"])
  656 
  657     """
  658 
  659     ParamsInfoWithUnits = {}
  660 
  661     ParamsInfoWithUnits["Steps"] = ParamsInfo["Steps"]
  662 
  663     ParamsInfoWithUnits["Minimization"] = ParamsInfo["Minimization"]
  664     ParamsInfoWithUnits["MinimizationMaxSteps"] = ParamsInfo["MinimizationMaxSteps"]
  665 
  666     MinimizationToleranceInKcal = ParamsInfo["MinimizationTolerance"]
  667     MinimizationTolerance = MinimizationToleranceInKcal * mm.unit.kilocalories_per_mole/mm.unit.angstroms
  668     
  669     MinimizationToleranceInJoules = MinimizationTolerance.value_in_unit(mm.unit.kilojoules_per_mole/mm.unit.nanometer)
  670     MinimizationTolerance = MinimizationToleranceInJoules*mm.unit.kilojoules_per_mole/mm.unit.nanometer
  671 
  672     ParamsInfoWithUnits["MinimizationToleranceInKcal"] = MinimizationToleranceInKcal
  673     ParamsInfoWithUnits["MinimizationToleranceInJoules"] = MinimizationToleranceInJoules
  674     ParamsInfoWithUnits["MinimizationTolerance"] = MinimizationTolerance
  675     
  676     ParamsInfoWithUnits["Equilibration"] = ParamsInfo["Equilibration"]
  677     ParamsInfoWithUnits["EquilibrationSteps"] = ParamsInfo["EquilibrationSteps"]
  678 
  679     return ParamsInfoWithUnits
  680     
  681 def ReimageRealignTrajectory(Topology, TrajFile, ReimageFrames = True, RealignFrames = True, Selection = "protein and backbone and name CA"):
  682     """Reimage and realign a trajectory file using MDTraj. The trajectory frames
  683     are reimaged before realigning to the first frame using the specified atom
  684     selection.
  685     
  686     The trajectory file format must a valid format supported by MDTraj. No
  687     validation is performed.
  688 
  689     Arguments:
  690         Topology (str or object): PDB file name or OpenMM topology object.
  691         TrajFile (str): Trajectory file name.
  692         ReimageFrames (bool): Reimage trajectory frames.
  693         RealignFrames (bool): Realign trajectory frames.
  694         Selection (str): MDTraj atom selection for realigning frames.
  695 
  696     Returns:
  697         None or object: MDTraj trajectory object.
  698         bool: Reimaged status.
  699         bool: Realigned status.
  700 
  701     """
  702 
  703     if isinstance(Topology, str):
  704         MiscUtil.PrintInfo("Reading trajectory file %s (TopologyFile: %s)..." % (TrajFile, Topology))
  705     else:
  706         MiscUtil.PrintInfo("Reading trajectory file %s..." % (TrajFile))
  707         Topology = mdtraj.Topology.from_openmm(Topology)
  708 
  709     try:
  710         Traj = mdtraj.load(TrajFile, top = Topology)
  711     except Exception as ErrMsg:
  712         MiscUtil.PrintInfo("")
  713         MiscUtil.PrintWarning("Failed to read trajectory file: %s" % ErrMsg)
  714         MiscUtil.PrintInfo("")
  715         return (None, False, False)
  716 
  717     ReimagedStatus, RealignedStatus = [False] * 2
  718 
  719     if ReimageFrames:
  720         MiscUtil.PrintInfo("Reimaging frames...")
  721         try:
  722             Traj.image_molecules(inplace = True)
  723             ReimagedStatus = True
  724         except Exception as ErrMsg:
  725             MiscUtil.PrintInfo("")
  726             MiscUtil.PrintWarning("Failed to reimage frames: %s" % ErrMsg)
  727             MiscUtil.PrintInfo("")
  728     else:
  729         MiscUtil.PrintInfo("Skipping reimaging of frames...")
  730 
  731     if RealignFrames:
  732         MiscUtil.PrintInfo("Realigning frames to the first frame using selection \"%s\"..." % Selection)
  733         try:
  734             SelectionAtomIndices = Traj.top.select(Selection)
  735         except Exception as ErrMsg:
  736             MiscUtil.PrintInfo("")
  737             MiscUtil.PrintWarning("Failed to align frames using selection \"%s\": %s" % (Selection, ErrMsg))
  738             MiscUtil.PrintInfo("")
  739             return (Traj, ReimagedStatus, RealignedStatus)
  740 
  741         if SelectionAtomIndices.size == 0:
  742             MiscUtil.PrintInfo("")
  743             MiscUtil.PrintWarning("Failed to align frames using selection \"%s\": No matched atoms found" % (Selection))
  744             MiscUtil.PrintInfo("")
  745             return (Traj, ReimagedStatus, RealignedStatus)
  746             
  747         RealignedStatus = True
  748         Traj.superpose(Traj, frame = 0, atom_indices = SelectionAtomIndices)
  749     else:
  750         MiscUtil.PrintInfo("Skipping realignment of frames to the first frame...")
  751 
  752     return (Traj, ReimagedStatus, RealignedStatus)
  753 
  754 def FreezeAtoms(System, AtomList):
  755     """Freeze atoms during a simulation. The specified atoms are kept completely
  756     fixed by setting their masses to zero. Their positions do not change during
  757     local energy minimization and MD simulation, and they do not contribute
  758     to the kinetic energy of the system.
  759 
  760     Arguments:
  761         System (object): OpenMM system object.
  762         AtomList (list): List of OpenMM atom objects.
  763 
  764     Returns:
  765         None
  766 
  767     """
  768 
  769     if AtomList is None:
  770         return
  771 
  772     for Atom in AtomList:
  773         System.setParticleMass(Atom.index, 0*mm.unit.amu)
  774 
  775 def RestraintAtoms(System, Positions, AtomList, SpringConstantInKcal):
  776     """Restraint atoms during a simulation. The motion of specified atoms is
  777         restricted by adding a harmonic force that binds them to their starting
  778         positions. The atoms are not completely fixed unlike freezing of atoms.
  779         Their motion, however, is restricted and they are not able to move far away
  780         from their starting positions during local energy minimization and MD
  781         simulation.
  782         
  783         The SpringConstantInKcal value must be specified in the units of
  784         kcal/mol/A*82. It is automatically converted into the units of 
  785         kjoules/mol/nm**2 for OpenMM API call.
  786 
  787     Arguments:
  788         System (object): OpenMM system object.
  789         Positions (object): OpenMM positons object object.
  790         AtomList (list): List of OpenMM atom object.
  791         SpringConstantInKcal (float): Spring constant value.
  792 
  793     Returns:
  794         None
  795 
  796     """
  797 
  798     if AtomList is None:
  799         return
  800 
  801     SpringConstant =  SpringConstantInKcal * mm.unit.kilocalories_per_mole/mm.unit.angstroms**2
  802     SpringConstantInKjoules = SpringConstant.value_in_unit(mm.unit.kilojoules_per_mole/mm.unit.nanometer**2)
  803 
  804     MiscUtil.PrintInfo("Restraint spring constant: %.2f kcal/mol/A**2 (%.2f kjoules/mol/nm**2)" % (SpringConstantInKcal, SpringConstantInKjoules))
  805 
  806     if DoesSystemUsesPeriodicBoundaryConditions(System):
  807         # For periodic systems...
  808         RestraintForce = mm.CustomExternalForce('k*periodicdistance(x, y, z, x0, y0, z0)^2')
  809     else:
  810         # For non-periodic systems...
  811         RestraintForce = mm.CustomExternalForce('k*((x-x0)^2+(y-y0)^2+(z-z0)^2)')
  812 
  813     SpringConstant = SpringConstantInKjoules * mm.unit.kilojoules_per_mole/mm.unit.nanometer**2
  814     RestraintForce.addGlobalParameter('k', SpringConstant)
  815 
  816     RestraintForce.addPerParticleParameter('x0')
  817     RestraintForce.addPerParticleParameter('y0')
  818     RestraintForce.addPerParticleParameter('z0')
  819 
  820     for Atom in AtomList:
  821         RestraintForce.addParticle(Atom.index, Positions[Atom.index])
  822 
  823 def GetAtoms(Topology, CAlphaProteinStatus, ResidueNames, Negate):
  824     """Get a list of atoms in the specified residue names. You may set
  825     CAlphaProteinStatus flag to True to only retrieve CAlpha atoms from
  826     the residues. In addition, you may negate residue name match using
  827     Negate flag.
  828     
  829     Arguments:
  830         Topology (object): OpenMM topology object.
  831         CAlphaProteinStatus (bool): Get CAlpha atoms only.
  832         ResidueNames (list): List of residue names.
  833         Negate (bool): Negate residue name match.
  834 
  835     Returns:
  836         None or List of OpenMM atom objects.
  837 
  838     """
  839     AtomList = []
  840     for Chain in Topology.chains():
  841         for Residue in Chain.residues():
  842             if CAlphaProteinStatus:
  843                 if Residue.name in ResidueNames:
  844                     for Atom in Residue.atoms():
  845                         if _MatchName(Atom.name, ["CA"], Negate):
  846                             AtomList.append(Atom)
  847             else:
  848                 if _MatchName(Residue.name, ResidueNames, Negate):
  849                     AtomList.extend(Residue.atoms())
  850 
  851     if len(AtomList) == 0:
  852         AtomList = None
  853 
  854     return AtomList
  855 
  856 def _MatchName(Name, NamesList, Negate = False):
  857     """Match name to the names in a list."""
  858 
  859     Status = True if Name in NamesList else False
  860     if Negate:
  861         Status = not Status
  862 
  863     return Status
  864 
  865 def DoesSystemUsesPeriodicBoundaryConditions(System):
  866     """Check for the use of periodic boundary conditions in a system.
  867     
  868     Arguments:
  869         System (object): OpenMM system object.
  870 
  871     Returns:
  872         bool : True - Uses periodic boundary conditions; Otherwise, false. 
  873 
  874     """
  875 
  876     try:
  877         Status = True if System.usesPeriodicBoundaryConditions() else False
  878     except Exception:
  879         Status = False
  880 
  881     return Status
  882 
  883 def DoesAtomListOverlapWithSystemConstraints(System, AtomList):
  884     """Check for the overlap of specified atoms with the atoms involved
  885     in system constraints.
  886     
  887     Arguments:
  888         System (object): OpenMM system object.
  889         AtomList (list): List of OpenMM atom objects.
  890 
  891     Returns:
  892         bool : True - Overlap with system constraints; Otherwise, false. 
  893 
  894     """
  895 
  896     NumConstraints = System.getNumConstraints()
  897     if NumConstraints == 0:
  898         return False
  899 
  900     if AtomList is None:
  901         return False
  902 
  903     AtomListIndices = [Atom.index for Atom in AtomList]
  904 
  905     for Index in range(NumConstraints):
  906         Particle1Index, Particle2Index, Distance = System.getConstraintParameters(Index)
  907         if Particle1Index in AtomListIndices or Particle2Index in AtomListIndices:
  908             return True
  909 
  910     return False
  911 
  912 def DoAtomListsOverlap(AtomList1, AtomList2):
  913     """Check for the overlap of atoms in the specified atom lists.
  914     
  915     Arguments:
  916         AtomList1 (list): List of OpenMM atom objects.
  917         AtomList2 (list): List of OpenMM atom objects.
  918 
  919     Returns:
  920         bool : True - Overlap between atoms lists; Otherwise, false. 
  921 
  922     """
  923 
  924     if AtomList1 is None or AtomList2 is None:
  925         return False
  926 
  927     AtomList1Indices = [Atom.index for Atom in AtomList1]
  928 
  929     for Atom in AtomList2:
  930         if Atom.index in AtomList1Indices:
  931             return True
  932 
  933     return False
  934 
  935 def DoesSystemContainWater(Topology, WaterResidueNames = ['HOH']):
  936     """Check for the presence of water residues in a system.
  937     
  938     Arguments:
  939         Topology (object): OpenMM modeller topology object.
  940         WaterResidueNames (list): List of water residue names.
  941 
  942     Returns:
  943         bool : True - Contains water; Otherwise, false. 
  944 
  945     """
  946 
  947     Status = False
  948     for Residue in Topology.residues():
  949         if Residue.name in WaterResidueNames:
  950             Status = True
  951             break
  952 
  953     return Status
  954 
  955 def ReadPDBFile(PDBFile):
  956     """Read molecule from a PDB file.
  957     
  958     The supported PDB file formats are pdb and cif.
  959 
  960     Arguments:
  961         PDBFile (str): Name of PDB file.
  962 
  963     Returns:
  964         object: OpenMM PDBFile or PDBFilex object.
  965 
  966     """
  967 
  968     FileDir, FileName, FileExt = MiscUtil.ParseFileName(PDBFile)
  969     if re.match("^pdb$", FileExt, re.I):
  970         PDBHandle = mm.app.PDBFile(PDBFile)
  971     elif re.match("^cif$", FileExt, re.I):
  972         PDBHandle = mm.app.PDBxFile(PDBFile)
  973     else:
  974         MiscUti.PrintError("Failed to read PDB file. Invalid PDB file format %s...\n" % PDBFile)
  975 
  976     return PDBHandle
  977 
  978 def WritePDBFile(PDBFile, Topology, Positions, KeepIDs = True):
  979     """Write a PDB file.
  980     
  981     The supported PDB file formats are pdb and cif.
  982     
  983     Arguments:
  984         PDBFile (str): Name of PDB file.
  985         Topology (object): Topology OpenMM object.
  986         Positions (object): Positions OpenMM object.
  987         KeepIDs (bool): Keep existing residue and chain IDs.
  988 
  989     Returns:
  990         None
  991 
  992     """
  993 
  994     FileDir, FileName, FileExt = MiscUtil.ParseFileName(PDBFile)
  995     if re.match("^pdb$", FileExt, re.I):
  996         mm.app.PDBFile.writeFile(Topology, Positions, PDBFile, KeepIDs)
  997     elif re.match("^cif$", FileExt, re.I):
  998         mm.app.PDBxFile.writeFile(Topology, Positions, PDBFile, KeepIDs)
  999     else:
 1000         MiscUti.PrintError("Failed to write PDB file. Invalid PDB file format %s...\n" % PDBFile)
 1001 
 1002 def WriteSimulationStatePDBFile(Simulation, PDBFile, KeepIDs = True):
 1003     """Write a PDB file for current simulation state.
 1004     
 1005     The supported PDB file formats are pdb and cif.
 1006     
 1007     Arguments:
 1008         Simulation (object): OpenMM simulation object.
 1009         PDBFile (str): Name of PDB fil.
 1010         KeepIDs (bool): Keep existing residue and chain IDs.
 1011 
 1012     Returns:
 1013         None
 1014 
 1015     """
 1016 
 1017     CurrentPositions = Simulation.context.getState(getPositions = True).getPositions()
 1018     WritePDBFile(PDBFile, Simulation.topology, CurrentPositions, KeepIDs)
 1019 
 1020 def ReadSmallMoleculeFile(FileName):
 1021     """Read small molecule file using OpenFF toolkit.
 1022     
 1023     Arguments:
 1024         FileName (str): Small molecule file name.
 1025 
 1026     Returns:
 1027         None or OpenFF tookit molecule object.
 1028 
 1029     """
 1030 
 1031     try:
 1032         SmallMol = ff.toolkit.Molecule.from_file(FileName)
 1033     except Exception as ErrMsg:
 1034         SmallMol = None
 1035         MiscUtil.PrintInfo("")
 1036         MiscUtil.PrintWarning("OpenFF.toolkit.Molecule.from_file() failed: %s" % ErrMsg)
 1037         MiscUtil.PrintInfo("")
 1038 
 1039     return SmallMol
 1040 
 1041 def MergeSmallMoleculeWithMacromolecule(ModellerHandle, SmallMol, SmallMolID = "LIG"):
 1042     """Merge small molecule with macromolecule data contained in a modeller object and
 1043     assign a three letter small molecule residue name to the merged small molecule. 
 1044 
 1045     Arguments:
 1046         ModellerHandle (object): OpenMM modeller object.
 1047         SmallMol (object): OpenFF tookit molecule object.
 1048         SmallMolID (str): Three letter residue name for small molecule.
 1049 
 1050     Returns:
 1051         None
 1052 
 1053     """
 1054 
 1055     SmallMolToplogy = SmallMol.to_topology()
 1056     SmallMolOpenMMTopology = SmallMolToplogy.to_openmm()
 1057     SmallMolOpenMMPositions = SmallMolToplogy.get_positions().to_openmm()
 1058 
 1059     # Set small molecule residue name to LIG...
 1060     for Chain in SmallMolOpenMMTopology.chains():
 1061         for Residue in Chain.residues():
 1062             Residue.name = SmallMolID
 1063 
 1064     ModellerHandle.add(SmallMolOpenMMTopology, SmallMolOpenMMPositions)
 1065 
 1066 def GetFormattedTotalSimulationTime(StepSize, Steps):
 1067     """Get formatted total simulation time with appropriate time units.
 1068     parameter names and values.
 1069     
 1070     Arguments:
 1071         StepSize (object): OpenMM quantity object.
 1072         Steps (int): Number of steps.
 1073 
 1074     Returns:
 1075         str: Total time.
 1076 
 1077     """
 1078 
 1079     TotalTime = StepSize * Steps
 1080     TotalTimeValue = TotalTime.value_in_unit(mm.unit.femtoseconds)
 1081 
 1082     if TotalTimeValue < 1e3:
 1083         TotalTimeUnits = "fs"
 1084         TotalTime = TotalTime.value_in_unit(mm.unit.femtoseconds)
 1085     elif TotalTimeValue < 1e6:
 1086         TotalTimeUnits = "ps"
 1087         TotalTime = TotalTime.value_in_unit(mm.unit.picoseconds)
 1088     elif TotalTimeValue < 1e9:
 1089         TotalTimeUnits = "ns"
 1090         TotalTime = TotalTime.value_in_unit(mm.unit.nanoseconds)
 1091     elif TotalTimeValue < 1e12:
 1092         TotalTimeUnits = "us"
 1093         TotalTime = TotalTime.value_in_unit(mm.unit.microseconds)
 1094     else:
 1095         TotalTimeUnits = "ms"
 1096         TotalTime = TotalTime.value_in_unit(mm.unit.milliseconds)
 1097 
 1098     TotalTime = "%.2f %s" % (TotalTime, TotalTimeUnits)
 1099 
 1100     return TotalTime
 1101 
 1102 def ProcessOptionOpenMMRestartParameters(ParamsOptionName, ParamsOptionValue, OutfilePrefix, ParamsDefaultInfo = None):
 1103     """Process parameters for restart option and return a map containing processed
 1104     parameter names and values.
 1105     
 1106     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 1107     to setup platform.
 1108     
 1109     The supported parameter names along with their default and possible
 1110     values are shown below:
 1111     
 1112         finalStateFile, <OutfilePrefix>_FinalState.<chk>  [ Possible values:
 1113             Valid final state checkpoint or XML filename ]
 1114         dataAppend, yes [ Possible values: yes or no]
 1115             
 1116     A brief description of parameters is provided below:
 1117     
 1118     finalStateFile: Final state checkpoint or XML file
 1119     
 1120     dataAppend: Append data to existing trajectory and data log files during the
 1121     restart of a simulation using a previously saved  final state checkpoint or
 1122     XML file.
 1123 
 1124     Arguments:
 1125         ParamsOptionName (str): Command line OpenMM restart option name.
 1126         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 1127         OutfilePrefix (str): Prefix for output files.
 1128         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 1129 
 1130     Returns:
 1131         dictionary: Processed parameter name and value pairs.
 1132 
 1133     """
 1134 
 1135     ParamsInfo = {"FinalStateFile": "auto", "DataAppend": True}
 1136 
 1137     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 1138 
 1139     if re.match("^auto$", ParamsOptionValue, re.I):
 1140         _ProcessOptionOpenMMRestartParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1141         return ParamsInfo
 1142 
 1143     for Index in range(0, len(ParamsOptionValueWords), 2):
 1144         Name = ParamsOptionValueWords[Index].strip()
 1145         Value = ParamsOptionValueWords[Index + 1].strip()
 1146 
 1147         ParamName = CanonicalParamNamesMap[Name.lower()]
 1148         ParamValue = Value
 1149 
 1150         if re.match("^FinalStateFile$", ParamName, re.I):
 1151             if not re.match("^auto$", Value, re.I):
 1152                 if not os.path.exists(Value):
 1153                     MiscUtil.PrintError("The file name specified, %s, for parameter name, %s, using option \"%s\" doesn't exist.\n." % (Value, Name, ParamsOptionName))
 1154                 if not MiscUtil.CheckFileExt(Value, "chk xml"):
 1155                     MiscUtil.PrintError("The file name specified, %s, for parameter name, %s, using option \"%s\" is not valid file. Supported file formats: chk or xml\n." % (Value, Name, ParamsOptionName))
 1156                 ParamValue = Value
 1157         elif re.match("^DataAppend$", ParamName, re.I):
 1158             if not re.match("^(yes|no|true|false)$", Value, re.I):
 1159                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: yes or no" % (Value, Name, ParamsOptionName))
 1160             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 1161         else:
 1162             ParamValue = Value
 1163 
 1164         # Set value...
 1165         ParamsInfo[ParamName] = ParamValue
 1166 
 1167     # Handle parameters with possible auto values...
 1168     _ProcessOptionOpenMMRestartParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1169 
 1170     return ParamsInfo
 1171 
 1172 def _ProcessOptionOpenMMRestartParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 1173     """Process parameters with possible auto values and perform validation.
 1174     """
 1175 
 1176     FinalStateFileCheckpointMode = False
 1177     FinalStateFileXMLMode = False
 1178 
 1179     ParamName = "FinalStateFile"
 1180     FinalStateFile = ParamsInfo[ParamName]
 1181     if re.match("^auto$", FinalStateFile, re.I):
 1182         FinalStateFile = "%s_FinalState.chk" % OutfilePrefix
 1183         FinalStateFileCheckpointMode = True
 1184     else:
 1185         if MiscUtil.CheckFileExt(FinalStateFile, "chk"):
 1186             FinalStateFileCheckpointMode = True
 1187         elif MiscUtil.CheckFileExt(FinalStateFile, "xml"):
 1188             FinalStateFileXMLMode = True
 1189         else:
 1190             MiscUtil.PrintError("The file name specified, %s, for parameter name, %s, using option \"%s\ is not valid. Supported file formats: chk or xml\n." % (FinalStateFile, ParamName, ParamsOptionName))
 1191 
 1192     ParamsInfo["FinalStateFile"] = FinalStateFile
 1193     ParamsInfo["FinalStateFileCheckpointMode"] = FinalStateFileCheckpointMode
 1194     ParamsInfo["FinalStateFileXMLMode"] = FinalStateFileXMLMode
 1195 
 1196 def ProcessOptionOpenMMSystemParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo = None):
 1197     """Process parameters for system option and return a map containing processed
 1198     parameter names and values.
 1199     
 1200     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 1201     to setup platform.
 1202     
 1203     The supported parameter names along with their default and possible
 1204     values are shown below:
 1205     
 1206         constraints, BondsInvolvingHydrogens [ Possible values: None,
 1207             WaterOnly, BondsInvolvingHydrogens, AllBonds, or
 1208             AnglesInvolvingHydrogens ]
 1209         constraintErrorTolerance, 0.000001
 1210         ewaldErrorTolerance, 0.0005
 1211         
 1212         nonbondedMethodPeriodic, PME [ Possible values: NoCutoff,
 1213             CutoffNonPeriodic, or PME ]
 1214         nonbondedMethodNonPeriodic, NoCutoff [ Possible values:
 1215             NoCutoff or CutoffNonPeriodic]
 1216         nonbondedCutoff, 1.0 [ Units: nm ]
 1217         
 1218         hydrogenMassRepartioning, yes [ Possible values: yes or no ]
 1219         hydrogenMass, 1.5 [ Units: amu]
 1220         
 1221         removeCMMotion, yes [ Possible values: yes or no ]
 1222         rigidWater, auto [ Possible values: yes or no. Default: 'No' for
 1223             'None' value of constraints; Otherwise, yes ]
 1224         
 1225     A brief description of parameters is provided below:
 1226     
 1227     constraints: Type of system constraints to use for simulation. These constraints
 1228     are different from freezing and restraining of any atoms in the system.
 1229     
 1230     constraintErrorTolerance: Distance tolerance for constraints as a fraction
 1231     of the constrained distance.
 1232     
 1233     ewaldErrorTolerance: Ewald error tolerance for a periodic system.
 1234     
 1235     nonbondedMethodPeriodic: Nonbonded method to use during the calculation of
 1236     long range interactions for a periodic system.
 1237     
 1238     nonbondedMethodNonPeriodic: Nonbonded method to use during the calculation
 1239     of long range interactions for a non-periodic system.
 1240     
 1241     nonbondedCutoff: Cutoff distance to use for long range interactions in both
 1242     perioidic non-periodic systems.
 1243     
 1244     hydrogenMassRepartioning: Use hydrogen mass repartioning. It increases the
 1245     mass of the hydrogen atoms attached to the heavy atoms and decreasing the
 1246     mass of the bonded heavy atom to maintain constant system mass. This allows
 1247     the use of larger integration step size (4 fs) during a simulation.
 1248     
 1249     hydrogenMass: Hydrogen mass to use during repartioning.
 1250     
 1251     removeCMMotion: Remove all center of mass motion at every time step.
 1252     
 1253     rigidWater: Keep water rigid during a simulation. This is determined
 1254     automatically based on the value of 'constraints' parameter.
 1255 
 1256     Arguments:
 1257         ParamsOptionName (str): Command line OpenMM system option name.
 1258         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 1259         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 1260 
 1261     Returns:
 1262         dictionary: Processed parameter name and value pairs.
 1263 
 1264     """
 1265 
 1266     ParamsInfo = {"Constraints": "BondsInvolvingHydrogens", "ConstraintErrorTolerance": 0.000001, "EwaldErrorTolerance": 0.0005, "NonbondedMethodPeriodic": "PME", "NonbondedMethodNonPeriodic": "NoCutoff", "NonbondedCutoff": 1.0,  "HydrogenMassRepartioning": True, "HydrogenMass": 1.5, "RemoveCMMotion":  True, "RigidWater": "auto"}
 1267 
 1268     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 1269 
 1270     if re.match("^auto$", ParamsOptionValue, re.I):
 1271         _ProcessOptionOpenMMSystemParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 1272         return ParamsInfo
 1273 
 1274     for Index in range(0, len(ParamsOptionValueWords), 2):
 1275         Name = ParamsOptionValueWords[Index].strip()
 1276         Value = ParamsOptionValueWords[Index + 1].strip()
 1277 
 1278         ParamName = CanonicalParamNamesMap[Name.lower()]
 1279         ParamValue = Value
 1280 
 1281         if re.match("^Constraints$", ParamName, re.I):
 1282             if not re.match("^auto$", Value, re.I):
 1283                 if not re.match("^(None|WaterOnly|BondsInvolvingHydrogens|AllBonds|AnglesInvolvingHydrogens)$", Value, re.I):
 1284                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: None, WaterOnly, BondsInvolvingHydrogens, AllBonds, or AnglesInvolvingHydrogens." % (Value, Name, ParamsOptionName))
 1285             ParamValue = Value
 1286         elif re.match("^(ConstraintErrorTolerance|EwaldErrorTolerance|NonbondedCutoff|HydrogenMass)$", ParamName, re.I):
 1287             if not MiscUtil.IsFloat(Value):
 1288                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be a float.\n" % (Value, ParamName, ParamsOptionName))
 1289             Value = float(Value)
 1290             if Value <= 0:
 1291                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1292             ParamValue = Value
 1293         elif re.match("^NonbondedMethodPeriodic$", ParamName, re.I):
 1294             if not re.match("^(NoCutoff|CutoffPeriodic|PME)$", Value, re.I):
 1295                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: NoCutoff, CutoffPeriodic, or PME" % (Value, Name, ParamsOptionName))
 1296             ParamValue = Value
 1297         elif re.match("^NonbondedMethodNonPeriodic$", ParamName, re.I):
 1298             if not re.match("^(NoCutoff|CutoffNonPeriodic)$", Value, re.I):
 1299                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: NoCutoff or CutoffNonPeriodic" % (Value, Name, ParamsOptionName))
 1300             ParamValue = Value
 1301         elif re.match("^(HydrogenMassRepartioning|removeCMMotion)$", ParamName, re.I):
 1302             if not re.match("^(yes|no|true|false)$", Value, re.I):
 1303                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: yes or no" % (Value, Name, ParamsOptionName))
 1304             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 1305         elif re.match("^RigidWater$", ParamName, re.I):
 1306             if not re.match("^auto$", Value, re.I):
 1307                 if not re.match("^(yes|no|true|false)$", Value, re.I):
 1308                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: yes or no" % (Value, Name, ParamsOptionName))
 1309                 ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 1310         else:
 1311             ParamValue = Value
 1312 
 1313         # Set value...
 1314         ParamsInfo[ParamName] = ParamValue
 1315 
 1316     # Handle parameters with possible auto values...
 1317     _ProcessOptionOpenMMSystemParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 1318 
 1319     return ParamsInfo
 1320 
 1321 def _ProcessOptionOpenMMSystemParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 1322     """Process parameters with possible auto values and perform validation.
 1323     """
 1324 
 1325     for ParamName in ["NonbondedMethodPeriodic", "NonbondedMethodNonPeriodic"]:
 1326         ParamValue = ParamsInfo[ParamName]
 1327         if re.match("^NoCutoff$", ParamValue, re.I):
 1328             ParamValue = mm.app.NoCutoff
 1329         elif re.match("^CutoffNonPeriodic$", ParamValue, re.I):
 1330             ParamValue = mm.app.CutoffNonPeriodic
 1331         elif re.match("^CutoffPeriodic$", ParamValue, re.I):
 1332             ParamValue = mm.app.CutoffPeriodic
 1333         elif re.match("^PME$", ParamValue, re.I):
 1334             ParamValue = mm.app.PME
 1335         else:
 1336             MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: NoCutoff, CutoffNonPeriodic, CutoffPeriodic, or PME" % (ParamValue, ParamName, ParamsOptionName))
 1337         ParamsInfo[ParamName] = ParamValue
 1338 
 1339     ParamName = "Constraints"
 1340     ParamValue = ParamsInfo[ParamName]
 1341     ConstraintsValue = None
 1342     RigidWaterValue = False
 1343     if re.match("^None$", ParamValue, re.I):
 1344         ConstraintsValue = None
 1345         RigidWaterValue = False
 1346     elif re.match("^WaterOnly$", ParamValue, re.I):
 1347         ConstraintsValue = None
 1348         RigidWaterValue = True
 1349     elif re.match("^BondsInvolvingHydrogens$", ParamValue, re.I):
 1350         ConstraintsValue = mm.app.HBonds
 1351         RigidWaterValue = True
 1352     elif re.match("^AllBonds$", ParamValue, re.I):
 1353         ConstraintsValue = mm.app.AllBonds
 1354         RigidWaterValue = True
 1355     elif re.match("^AnglesInvolvingHydrogens$", ParamValue, re.I):
 1356         ConstraintsValue = mm.app.HAngles
 1357         RigidWaterValue = True
 1358     else:
 1359         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: None, WaterOnly, BondsInvolvingHydrogens, AllBonds, or AnglesInvolvingHydrogens." % (ParamValue, ParamName, ParamsOptionName))
 1360 
 1361     ParamsInfo[ParamName] = ConstraintsValue
 1362 
 1363     ParamName = "RigidWater"
 1364     ParamValue = "%s" % ParamsInfo[ParamName]
 1365     if re.match("^auto$", ParamValue, re.I):
 1366         ParamsInfo[ParamName] = RigidWaterValue
 1367 
 1368 def ProcessOptionOpenMMIntegratorParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo = None, HydrogenMassRepartioningStatus = False):
 1369     """Process parameters for integrator option and return a map containing processed
 1370     parameter names and values.
 1371     
 1372     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 1373     to setup platform.
 1374     
 1375     The supported parameter names along with their default and possible
 1376     values are shown below:
 1377     
 1378         integrator, LangevinMiddle [ Possible values: LangevinMiddle,
 1379             Langevin, NoseHoover, Brownian ]
 1380         
 1381         randomSeed, auto [ Possible values: > 0 ]
 1382         
 1383         frictionCoefficient, 1.0 [ Units: 1/ps ]
 1384         stepSize, auto [ Units: fs; Default value: 4 fs during yes value of
 1385             hydrogen mass repartioning with no freezing/restraining of atoms;
 1386             otherwsie, 2 fs ] 
 1387         temperature, 300.0 [ Units: kelvin ]
 1388         
 1389         barostat, MonteCarlo [ Possible values: MonteCarlo or
 1390             MonteCarloMembrane ]
 1391         barostatInterval, 25
 1392         pressure, 1.0 [ Units: atm ]
 1393         
 1394         Parameters used only for MonteCarloMembraneBarostat with default
 1395         values corresponding to Amber forcefields:
 1396         
 1397         surfaceTension, 0.0 [ Units: atm*A. It is automatically converted 
 1398             into OpenMM default units of atm*nm before its usage.  ]
 1399         xymode,  Isotropic [ Possible values: Anisotropic or  Isotropic ]
 1400         zmode,  Free [ Possible values: Free or  Fixed ]
 1401     
 1402     A brief description of parameters is provided below:
 1403         
 1404     integrator: Type of integrator
 1405     
 1406     randomSeed: Random number seed for barostat and integrator. Not supported
 1407         NoseHoover integrator.
 1408     
 1409     frictionCoefficient: Friction coefficient for coupling the system to the heat
 1410     bath.
 1411     
 1412     stepSize: Simulation time step size.
 1413     
 1414     temperature: Simulation temperature.
 1415     
 1416     barostat: Barostat type.
 1417     
 1418     barostatInterval: Barostat interval step size during NPT simulation for
 1419     applying Monte Carlo pressure changes.
 1420     
 1421     pressure: Pressure during NPT simulation. 
 1422     
 1423     surfaceTension: Surface tension acting on the system.
 1424     
 1425     xymode: Behavior along X and Y axes. You may allow the X and Y axes
 1426     to vary independently of each other or always scale them by the same
 1427     amount to keep the ratio of their lengths constant.
 1428     
 1429     zmode: Beahvior along Z axis. You may allow the Z axis to vary
 1430     independently of the other axes or keep it fixed.
 1431 
 1432     Arguments:
 1433         ParamsOptionName (str): Command line OpenMM integrator option name.
 1434         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 1435         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 1436 
 1437     Returns:
 1438         dictionary: Processed parameter name and value pairs.
 1439 
 1440     """
 1441 
 1442     ParamsInfo = {"Integrator": "LangevinMiddle", "RandomSeed":  "auto", "FrictionCoefficient": 1.0, "StepSize": "auto", "Temperature": 300.0, "Barostat": "MonteCarlo", "BarostatInterval": 25, "Pressure": 1.0, "SurfaceTension": 0.0, "XYMode": "Isotropic", "ZMode": "Free"}
 1443 
 1444     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 1445 
 1446     if re.match("^auto$", ParamsOptionValue, re.I):
 1447         _ProcessOptionOpenMMIntegratorParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, HydrogenMassRepartioningStatus)
 1448         return ParamsInfo
 1449 
 1450     for Index in range(0, len(ParamsOptionValueWords), 2):
 1451         Name = ParamsOptionValueWords[Index].strip()
 1452         Value = ParamsOptionValueWords[Index + 1].strip()
 1453 
 1454         ParamName = CanonicalParamNamesMap[Name.lower()]
 1455         ParamValue = Value
 1456 
 1457         if re.match("^Integrator$", ParamName, re.I):
 1458             if not re.match("^(LangevinMiddle|Langevin|NoseHoover|Brownian)$", Value, re.I):
 1459                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: LangevinMiddle,Langevin, NoseHoover, or Brownian." % (Value, Name, ParamsOptionName))
 1460             ParamValue = Value
 1461         elif re.match("^(FrictionCoefficient|Pressure)$", ParamName, re.I):
 1462             if not MiscUtil.IsFloat(Value):
 1463                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be a float.\n" % (Value, ParamName, ParamsOptionName))
 1464             Value = float(Value)
 1465             if Value <= 0:
 1466                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1467             ParamValue = Value
 1468         elif re.match("^StepSize$", ParamName, re.I):
 1469             if not re.match("^auto$", Value, re.I):
 1470                 if not MiscUtil.IsFloat(Value):
 1471                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be a float.\n" % (Value, ParamName, ParamsOptionName))
 1472                 Value = float(Value)
 1473                 if Value <= 0:
 1474                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1475                 ParamValue = Value
 1476         elif re.match("^(Temperature|SurfaceTension)$", ParamName, re.I):
 1477             if not MiscUtil.IsFloat(Value):
 1478                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be a float.\n" % (Value, ParamName, ParamsOptionName))
 1479             Value = float(Value)
 1480             if Value < 0:
 1481                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: >= 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1482             ParamValue = Value
 1483         elif re.match("^BarostatInterval$", ParamName, re.I):
 1484             if not MiscUtil.IsInteger(Value):
 1485                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be an integer.\n" % (Value, ParamName, ParamsOptionName))
 1486             Value = int(Value)
 1487             if Value <= 0:
 1488                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1489             ParamValue = Value
 1490         elif re.match("^Barostat$", ParamName, re.I):
 1491             if not re.match("^(MonteCarlo|MonteCarloMembrane)$", Value, re.I):
 1492                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: MonteCarlo or MonteCarloMembrane" % (Value, Name, ParamsOptionName))
 1493             ParamValue = Value
 1494         elif re.match("^XYMode$", ParamName, re.I):
 1495             if not re.match("^(Anisotropic|Isotropic)$", Value, re.I):
 1496                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: Anisotropic or  Isotropic" % (Value, Name, ParamsOptionName))
 1497             ParamValue = Value
 1498         elif re.match("^ZMode$", ParamName, re.I):
 1499             if not re.match("^(Free|Fixed)$", Value, re.I):
 1500                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: Fixed or Free" % (Value, Name, ParamsOptionName))
 1501             ParamValue = Value
 1502         elif re.match("^RandomSeed$", ParamName, re.I):
 1503             if not re.match("^auto$", Value, re.I):
 1504                 if not MiscUtil.IsInteger(Value):
 1505                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be an integer.\n" % (Value, ParamName, ParamsOptionName))
 1506                 Value = int(Value)
 1507                 if Value <= 0:
 1508                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1509                 ParamValue = Value
 1510         else:
 1511             ParamValue = Value
 1512 
 1513         # Set value...
 1514         ParamsInfo[ParamName] = ParamValue
 1515 
 1516     # Handle parameters with possible auto values...
 1517     _ProcessOptionOpenMMIntegratorParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, HydrogenMassRepartioningStatus)
 1518 
 1519     return ParamsInfo
 1520 
 1521 def _ProcessOptionOpenMMIntegratorParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, HydrogenMassRepartioningStatus):
 1522     """Process parameters with possible auto values and perform validation.
 1523     """
 1524 
 1525     ParamName = "StepSize"
 1526     ParamValue = "%s" % ParamsInfo[ParamName]
 1527     ParamsInfo["StepSizeSpecified"] = ParamValue
 1528     if re.match("^auto$", ParamValue, re.I):
 1529         ParamValue = 4.0 if HydrogenMassRepartioningStatus else 2.0
 1530         ParamsInfo[ParamName] = ParamValue
 1531 
 1532     ParamName = "RandomSeed"
 1533     ParamValue = "%s" % ParamsInfo[ParamName]
 1534     ParamsInfo["RandomSeedSpecified"] = ParamValue
 1535     if re.match("^auto$", ParamValue, re.I):
 1536         ParamsInfo[ParamName] = None
 1537 
 1538 def ProcessOptionOpenMMSimulationParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo = None):
 1539     """Process parameters for simulation option and return a map containing processed
 1540     parameter names and values.
 1541     
 1542     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 1543     to setup platform.
 1544     
 1545     The supported parameter names along with their default and possible
 1546     values are shown below:
 1547     
 1548         steps, 1000000 [ Possible values: > 0 ] 
 1549         
 1550         minimization, yes [ Possible values: yes or no ] 
 1551         minimizationMaxSteps, auto  [ Possible values: >= 0. The value of
 1552             zero implies until the minimization is converged. ]
 1553         minimizationTolerance, 0.25  [ Units: kcal/mol/A. The default value
 1554             0.25, corresponds to OpenMM default of value of 10.04
 1555             kjoules/mol/nm. It is automatically converted into OpenMM
 1556             default units before its usage. ]
 1557         
 1558         equilibration, yes [ Possible values: yes or no ] 
 1559         equilibrationSteps, 1000  [ Possible values: > 0 ]
 1560     
 1561     A brief description of parameters is provided below:
 1562     
 1563     steps: Number of steps for production run.
 1564     
 1565     equilibration: Perform equilibration before the production run.
 1566     
 1567     equilibrationSteps: Number of steps for equilibration.
 1568     
 1569     minimizationMaxSteps: Maximum number of minimization steps. The value
 1570     of zero implies until the minimization is converged.
 1571     
 1572     minimizationTolerance: Energy convergence tolerance during minimization.
 1573 
 1574     minimization: Perform minimization before equilibration and production run.
 1575 
 1576     Arguments:
 1577         ParamsOptionName (str): Command line OpenMM simulation option name.
 1578         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 1579         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 1580 
 1581     Returns:
 1582         dictionary: Processed parameter name and value pairs.
 1583 
 1584     """
 1585 
 1586     ParamsInfo = {"Steps": 1000000, "Minimization": True, "MinimizationMaxSteps": "auto", "MinimizationTolerance": 0.24, "Equilibration": True, "EquilibrationSteps": 1000}
 1587 
 1588     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 1589 
 1590     if re.match("^auto$", ParamsOptionValue, re.I):
 1591         _ProcessOptionOpenMMSimulationParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 1592         return ParamsInfo
 1593 
 1594     for Index in range(0, len(ParamsOptionValueWords), 2):
 1595         Name = ParamsOptionValueWords[Index].strip()
 1596         Value = ParamsOptionValueWords[Index + 1].strip()
 1597 
 1598         ParamName = CanonicalParamNamesMap[Name.lower()]
 1599         ParamValue = Value
 1600 
 1601         if re.match("^(Steps|EquilibrationSteps)$", ParamName, re.I):
 1602             if not MiscUtil.IsInteger(Value):
 1603                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be an integer.\n" % (Value, ParamName, ParamsOptionName))
 1604             Value = int(Value)
 1605             if Value <= 0:
 1606                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1607             ParamValue = Value
 1608         elif re.match("^(Minimization|Equilibration)$", ParamName, re.I):
 1609             if not re.match("^(yes|no|true|false)$", Value, re.I):
 1610                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: yes or no" % (Value, Name, ParamsOptionName))
 1611             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 1612         elif re.match("^MinimizationMaxSteps$", ParamName, re.I):
 1613             if not re.match("^auto$", Value, re.I):
 1614                 if not MiscUtil.IsInteger(Value):
 1615                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be an integer.\n" % (Value, ParamName, ParamsOptionName))
 1616                 Value = int(Value)
 1617                 if Value < 0:
 1618                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: >= 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1619             ParamValue = Value
 1620         elif re.match("^MinimizationTolerance$", ParamName, re.I):
 1621             if not MiscUtil.IsFloat(Value):
 1622                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be a float.\n" % (Value, ParamName, ParamsOptionName))
 1623             Value = float(Value)
 1624             if Value <= 0:
 1625                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1626             ParamValue = Value
 1627         else:
 1628             ParamValue = Value
 1629 
 1630         # Set value...
 1631         ParamsInfo[ParamName] = ParamValue
 1632 
 1633     # Handle parameters with possible auto values...
 1634     _ProcessOptionOpenMMSimulationParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 1635 
 1636     return ParamsInfo
 1637 
 1638 def _ProcessOptionOpenMMSimulationParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 1639     """Process parameters with possible auto values and perform validation.
 1640     """
 1641 
 1642     ParamName = "MinimizationMaxSteps"
 1643     ParamValue = "%s" % ParamsInfo[ParamName]
 1644     if re.match("^auto$", ParamValue, re.I):
 1645         ParamsInfo[ParamName] = 0
 1646 
 1647 def ProcessOptionOpenMMOutputParameters(ParamsOptionName, ParamsOptionValue, OutfilePrefix, ParamsDefaultInfo = None):
 1648     """Process parameters for output option and return a map containing processed
 1649     parameter names and values.
 1650     
 1651     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 1652     to setup platform.
 1653     
 1654     The supported parameter names along with their default and possible
 1655     values are shown below:
 1656     
 1657         checkpoint, no  [ Possible values: yes or no ]
 1658         checkpointFile, auto  [ Default: <OutfilePrefix>.chk ]
 1659         checkpointSteps, 10000
 1660         
 1661         dataOutType, auto [ Possible values: A space delimited list of valid
 1662             parameter names.
 1663             NPT simulation default: Density Step Speed Progress
 1664                   PotentialEnergy Temperature Time.
 1665             NVT simulation default: Step Speed Progress PotentialEnergy
 1666                 Temperature Time Volumne
 1667             Other valid names: ElapsedTime RemainingTime KineticEnergy
 1668                 TotalEnergy  ]
 1669         
 1670         dataLog, yes  [ Possible values: yes or no ]
 1671         dataLogFile, auto  [ Default: <OutfilePrefix>.csv ]
 1672         dataLogSteps, 1000
 1673         
 1674         dataStdout, no  [ Possible values: yes or no ]
 1675         dataStdoutSteps, 1000
 1676         
 1677         minimizationDataSteps, 100
 1678         minimizationDataStdout, no  [ Possible values: yes or no ]
 1679         minimizationDataLog, no  [ Possible values: yes or no ]
 1680         minimizationDataLogFile, auto  [ Default:
 1681             <OutfilePrefix>_MinimizationOut.csv ]
 1682         minimizationDataOutType, auto [ Possible values: A space delimited
 1683             list of valid parameter names.  Default: SystemEnergy
 1684             RestraintEnergy MaxConstraintError.
 1685             Other valid names: RestraintStrength ]
 1686         
 1687         pdbOutFormat, PDB  [ Possible values: PDB or CIF ]
 1688         pdbOutKeepIDs, yes  [ Possible values: yes or no ]
 1689         
 1690         pdbOutMinimized, no  [ Possible values: yes or no ]
 1691         pdbOutEquilibrated, no  [ Possible values: yes or no ]
 1692         pdbOutFinal, no  [ Possible values: yes or no ]
 1693         
 1694         saveFinalStateCheckpoint, yes  [ Possible values: yes or no ]
 1695         saveFinalStateCheckpointFile, auto  [ Default:
 1696             <OutfilePrefix>_FinalState.chk ]
 1697         saveFinalStateXML, no  [ Possible values: yes or no ]
 1698         saveFinalStateXMLFile, auto  [ Default:
 1699             <OutfilePrefix>_FinalState.xml]
 1700         
 1701         traj, yes  [ Possible values: yes or no ]
 1702         trajFile, auto  [ Default: <OutfilePrefix>.<TrajFormat> ]
 1703         trajFormat, DCD  [ Possible values: DCD or XTC ]
 1704         trajSteps, 10000
 1705         
 1706         xmlSystemOut, no  [ Possible values: yes or no ]
 1707         xmlSystemFile, auto  [ Default: <OutfilePrefix>_System.xml ]
 1708         xmlIntegratorOut, no  [ Possible values: yes or no ]
 1709         xmlIntegratorFile, auto  [ Default: <OutfilePrefix>_Integrator.xml ]
 1710             
 1711     A brief description of parameters is provided below:
 1712         
 1713         checkpoint: Write intermediate checkpoint file.
 1714         checkpointFile: Intermediate checkpoint file name.
 1715         checkpointSteps: Frequency of writing intermediate checkpoint file.
 1716         
 1717         dataOutType: Type of data to write to stdout and log file.
 1718         
 1719         dataLog: Write data to log file.
 1720         dataLogFile: Data log file name.
 1721         dataLogSteps: Frequency of writing data to log file.
 1722         
 1723         dataStdout: Write data to stdout.
 1724         dataStdoutSteps: Frequency of writing data to stdout.
 1725         
 1726         minimizationDataSteps: Frequency of writing data to stdout and log file.
 1727         minimizationDataStdout: Write data to stdout.
 1728         minimizationDataLog: Write data to log file.
 1729         minimizationDataLogFile: Data log fie name.
 1730         minimizationDataOutType: Type of data to write to stdout and log file.
 1731         
 1732         pdbOutFormat: Format of output PDB files.
 1733         pdbOutKeepIDs: Keep existing chain and residue IDs.
 1734         
 1735         pdbOutMinimized: Write PDB file after minimization.
 1736         pdbOutEquilibrated: Write PDB file after equilibration.
 1737         pdbOutFinal: Write final PDB file after production run.
 1738         
 1739         saveFinalStateCheckpoint: Save final state checkpoint file.
 1740         saveFinalStateCheckpointFile: Name of final state checkpoint file.
 1741         saveFinalStateXML: Save final state XML file.
 1742         saveFinalStateXMLFile: Name of final state XML file.
 1743         
 1744         traj: Write out trajectory file.
 1745         trajFile: Trajectory file name.
 1746         trajFormat: Trajectory file format.
 1747         trajSteps: Frequency of writing trajectory file.
 1748         
 1749         xmlSystemOut: Write system XML file.
 1750         xmlSystemFile: System XML file name.
 1751         xmlIntegratorOut: Write integrator XML file.
 1752         xmlIntegratorFile: Integrator XML file name.
 1753 
 1754     Arguments:
 1755         ParamsOptionName (str): Command line OpenMM system option name.
 1756         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 1757         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 1758 
 1759     Returns:
 1760         dictionary: Processed parameter name and value pairs.
 1761 
 1762     """
 1763 
 1764     ParamsInfo = {"Checkpoint": False, "CheckpointFile": "auto",  "CheckpointSteps": 10000,
 1765                   "DataOutType": "auto",
 1766                   "DataLog": True, "DataLogFile": "auto", "DataLogSteps": 1000,
 1767                   "DataStdout":  False, "DataStdoutSteps": 1000,
 1768                   "MinimizationDataSteps": 100, "MinimizationDataStdout": False, "MinimizationDataLog": False, "MinimizationDataLogFile": "auto", "MinimizationDataOutType": "auto",
 1769                   "PDBOutFormat": "PDB", "PDBOutKeepIDs": True, "PDBOutMinimized": False, "PDBOutEquilibrated": False, "PDBOutFinal": False, 
 1770                   "SaveFinalStateCheckpoint": True, "SaveFinalStateCheckpointFile": "auto", "SaveFinalStateXML": False, "SaveFinalStateXMLFile": "auto",
 1771                   "Traj": True,  "TrajFile": "auto", "TrajFormat": "DCD", "TrajSteps": 10000,
 1772                   "XmlSystemOut": False, "XmlSystemFile": "auto",  "XmlIntegratorOut": False, "XmlIntegratorFile": "auto"}
 1773 
 1774     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 1775 
 1776     if re.match("^auto$", ParamsOptionValue, re.I):
 1777         _ProcessOptionOpenMMOutputParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1778         return ParamsInfo
 1779 
 1780     for Index in range(0, len(ParamsOptionValueWords), 2):
 1781         Name = ParamsOptionValueWords[Index].strip()
 1782         Value = ParamsOptionValueWords[Index + 1].strip()
 1783 
 1784         ParamName = CanonicalParamNamesMap[Name.lower()]
 1785         ParamValue = Value
 1786 
 1787         if re.match("^(Checkpoint|DataLog|DataStdout|MinimizationDataStdout|MinimizationDataLog|PDBOutKeepIDs|SaveFinalStateCheckpoint|SaveFinalStateXML|Traj|XmlSystemOut|XmlIntegratorOut|PDBOutMinimized|PDBOutEquilibrated|PDBOutFinal)$", ParamName, re.I):
 1788             if not re.match("^(yes|no|true|false)$", Value, re.I):
 1789                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: yes or no" % (Value, Name, ParamsOptionName))
 1790             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 1791         elif re.match("^(CheckpointFile|SaveFinalStateCheckpointFile)$", ParamName, re.I):
 1792             if not re.match("^auto$", Value, re.I):
 1793                 if not MiscUtil.CheckFileExt(Value, "chk"):
 1794                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported file format: chk" % (Value, Name, ParamsOptionName))
 1795                 ParamValue = Value
 1796         elif re.match("^(DataLogFile|MinimizationDataLogFile)$", ParamName, re.I):
 1797             if not re.match("^auto$", Value, re.I):
 1798                 if not MiscUtil.CheckFileExt(Value, "csv"):
 1799                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported file formats: csv" % (Value, Name, ParamsOptionName))
 1800                 ParamValue = Value
 1801         elif re.match("^(SaveFinalStateXMLFile|XmlSystemFile|XmlIntegratorFile)$", ParamName, re.I):
 1802             if not re.match("^auto$", Value, re.I):
 1803                 if not MiscUtil.CheckFileExt(Value, "xml"):
 1804                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported file format: xml" % (Value, Name, ParamsOptionName))
 1805                 ParamValue = Value
 1806         elif re.match("^TrajFile$", ParamName, re.I):
 1807             if not re.match("^auto$", Value, re.I):
 1808                 if not MiscUtil.CheckFileExt(Value, "dcd xtc"):
 1809                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported file formats: dcd xtc" % (Value, Name, ParamsOptionName))
 1810                 ParamValue = Value
 1811         elif re.match("^(CheckpointSteps|DataLogSteps|DataStdoutSteps|MinimizationDataSteps|TrajSteps)$", ParamName, re.I):
 1812             if not MiscUtil.IsInteger(Value):
 1813                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be an integer.\n" % (Value, ParamName, ParamsOptionName))
 1814             Value = int(Value)
 1815             if Value <= 0:
 1816                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 1817             ParamValue = Value
 1818         elif re.match("^DataOutType$", ParamName, re.I):
 1819             if not re.match("^auto$", Value, re.I):
 1820                 ValueTypes = Value.split()
 1821                 if len(ValueTypes) == 0:
 1822                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain a space delimited list of valid values.\n" % (Value, ParamName, ParamsOptionName))
 1823                 ValueTypesSpecified = []
 1824                 for ValueType in ValueTypes:
 1825                     if not re.match("^(Step|Speed|Progress|PotentialEnergy|Temperature|ElapsedTime|RemainingTime|Time|KineticEnergy|TotalEnergy|Volume|Density)$", ValueType, re.I):
 1826                         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: Step, Speed, Progress, PotentialEnergy, Temperature, ElapsedTime, RemainingTime, Time, KineticEnergy, TotalEnergy, Volume, or Density" % (ValueType, Name, ParamsOptionName))
 1827                     if ValueType in ValueTypesSpecified:
 1828                         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It has already been specified." % (ValueType, Name, ParamsOptionName))
 1829                     ValueTypesSpecified.append(ValueType)
 1830                 ParamsInfo["DataOutTypeList"] = ValueTypes
 1831         elif re.match("^MinimizationDataOutType$", ParamName, re.I):
 1832             if not re.match("^auto$", Value, re.I):
 1833                 ValueTypes = Value.split()
 1834                 if len(ValueTypes) == 0:
 1835                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain a space delimited list of valid values.\n" % (Value, ParamName, ParamsOptionName))
 1836                 ValueTypesSpecified = []
 1837                 for ValueType in ValueTypes:
 1838                     if not re.match("^(SystemEnergy|RestraintEnergy|RestraintStrength|MaxConstraintError)$", ValueType, re.I):
 1839                         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: SystemEnergy, RestraintEnergy, RestraintStrength, or MaxConstraintError" % (ValueType, Name, ParamsOptionName))
 1840                     if ValueType in ValueTypesSpecified:
 1841                         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It has already been specified." % (ValueType, Name, ParamsOptionName))
 1842                     ValueTypesSpecified.append(ValueType)
 1843                 ParamsInfo["MinimizationDataOutTypeList"] = ValueTypes
 1844         elif re.match("^PDBOutFormat$", ParamName, re.I):
 1845             if not re.match("^(PDB|CIF)$", Value, re.I):
 1846                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: PDB or CIF" % (Value, Name, ParamsOptionName))
 1847             ParamValue = Value
 1848         elif re.match("^TrajFormat$", ParamName, re.I):
 1849             if not re.match("^(DCD|XTC)$", Value, re.I):
 1850                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: DCD or XTC" % (Value, Name, ParamsOptionName))
 1851             ParamValue = Value
 1852         else:
 1853             ParamValue = Value
 1854 
 1855         # Set value...
 1856         ParamsInfo[ParamName] = ParamValue
 1857 
 1858     # Handle parameters with possible auto values...
 1859     _ProcessOptionOpenMMOutputParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1860 
 1861     return ParamsInfo
 1862 
 1863 def _ProcessOptionOpenMMOutputParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 1864     """Process parameters with possible auto values and perform validation.
 1865     """
 1866 
 1867     # Use comma as a delimiter...
 1868     ParamsInfo["DataOutDelimiter"] = ","
 1869     ParamsInfo["DataOutfileExt"] = "csv"
 1870 
 1871     ParamName = "TrajFormat"
 1872     ParamValue = ParamsInfo[ParamName]
 1873     if re.match("^DCD$", ParamValue, re.I):
 1874         TrajFileExt = "dcd"
 1875     elif re.match("^XTC$", ParamValue, re.I):
 1876         TrajFileExt = "xtc"
 1877     else:
 1878         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: DCD or XTC" % (ParamValue, ParamName, ParamsOptionName))
 1879     ParamsInfo["TrajFileExt"] = TrajFileExt
 1880 
 1881     ParamName = "PDBOutFormat"
 1882     ParamValue = ParamsInfo[ParamName]
 1883     if re.match("^PDB$", ParamValue, re.I):
 1884         PDBOutfileExt = "pdb"
 1885     elif re.match("^CIF$", ParamValue, re.I):
 1886         PDBOutfileExt = "cif"
 1887     else:
 1888         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: PDB or CIF" % (ParamValue, ParamName, ParamsOptionName))
 1889     ParamsInfo["PDBOutfileExt"] = PDBOutfileExt
 1890 
 1891     _ProcessFileNamesOutputPatramaters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1892     _ProcessDataOutTypeOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1893     _ProcessMinimizationDataOutTypeOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1894     
 1895 def _ProcessFileNamesOutputPatramaters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 1896     """Process output parameters corresponding to file names."""
 1897 
 1898     OutfileExt = ParamsInfo["DataOutfileExt"]
 1899     TrajFileExt = ParamsInfo["TrajFileExt"]
 1900     OutfilesSuffixAndExtMap = {"CheckpointFile": ["", "chk"], "DataLogFile": ["", OutfileExt], "MinimizationDataLogFile": ["Minimization", OutfileExt], "SaveFinalStateCheckpointFile": ["FinalState", "chk"], "SaveFinalStateXMLFile": ["FinalState", "xml"], "TrajFile": ["", TrajFileExt], "XmlSystemFile": ["System", "xml"], "XmlIntegratorFile": ["Integrator", "xml"]}
 1901     OutfileNames = []
 1902     for ParamName in OutfilesSuffixAndExtMap:
 1903         ParamValue = ParamsInfo[ParamName]
 1904         if re.match("^auto$", ParamValue, re.I):
 1905             DataOutfileSuffix, DataOutfileExt = OutfilesSuffixAndExtMap[ParamName]
 1906             if len(DataOutfileSuffix):
 1907                 DataOutfileSuffix = "_%s" % DataOutfileSuffix
 1908             ParamValue = "%s%s.%s" % (OutfilePrefix, DataOutfileSuffix, DataOutfileExt)
 1909             ParamsInfo[ParamName] = ParamValue
 1910         else:
 1911             # Check for duplicate output file names...
 1912             if ParamValue not in OutfileNames:
 1913                 OutfileNames.append(ParamValue)
 1914             else:
 1915                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It's a duplicate file name." % (ParamValue, ParamName, ParamsOptionName))
 1916 
 1917             # Validate specified traj file extension...
 1918             if re.match("^TrajFile$", ParamName, re.I):
 1919                 TrajFormat = ParamsInfo["TrajFormat"]
 1920                 if not MiscUtil.CheckFileExt(ParamValue, TrajFileExt):
 1921                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. The file extension must match must match the extenstion, %s, corresponding to trajectory format, %s, speecified using \"--trajFormat\" option." % (ParamValue, ParamName, ParamsOptionName, TrajFileExt, TrajFormat))
 1922 
 1923 def _ProcessDataOutTypeOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 1924     """Process output parameter corresponding to data out type."""
 1925 
 1926     # Setup data out types...
 1927     DataOutTypeStatusMap = {"Step": False, "Speed": False,  "Progress": False,  "PotentialEnergy": False,  "Temperature": False, "ElapsedTime": False, "RemainingTime": False, "Time": False, "KineticEnergy": False, "TotalEnergy": False,  "Volume": False,  "Density": False}
 1928     CanonicalDataOutTypeMap = {}
 1929     ValidDataOutTypes = []
 1930     for DataOutType in DataOutTypeStatusMap:
 1931         ValidDataOutTypes.append(DataOutType)
 1932         CanonicalDataOutTypeMap[DataOutType.lower()] = DataOutType
 1933 
 1934     # Process data out types...
 1935     ParamName = "DataOutType"
 1936     ParamValue = ParamsInfo[ParamName]
 1937     DataOutTypeList = []
 1938     if re.match("^auto$", ParamValue, re.I):
 1939         DataOutTypeList = ["Step", "Speed", "Progress", "PotentialEnergy", "Temperature"]
 1940     else:
 1941         if "DataOutTypeList" in ParamsInfo:
 1942             DataOutTypeList = ParamsInfo["DataOutTypeList"]
 1943         else:
 1944             DataOutTypeList = ParamsInfo["DataOutType"].split()
 1945             ParamsInfo["DataOutTypeList"] = DataOutTypeList
 1946 
 1947     for DataOutType in DataOutTypeList:
 1948         CanonicalDataOutType = DataOutType.lower()
 1949         if CanonicalDataOutType not in CanonicalDataOutTypeMap:
 1950             MiscUtil.PrintError("The parameter value, %s specified for paramaer name, %s, specified using \"%s\" is not a valid name. Supported parameter names: %s" % (DataOutType, ParamName, ParamsOptionName, " ".join(ValidDataOutTypes)))
 1951         
 1952         DataOutType = CanonicalDataOutTypeMap[CanonicalDataOutType]
 1953         DataOutTypeStatusMap[DataOutType] = True
 1954 
 1955     ParamsInfo["DataOutTypeList"] = DataOutTypeList
 1956     ParamsInfo["DataOutTypeStatusMap"] = DataOutTypeStatusMap
 1957 
 1958 def _ProcessMinimizationDataOutTypeOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 1959     """Process output parameter corresponding to minimization data out type."""
 1960 
 1961     # Setup mimimization data out types...
 1962     DataOutTypeOpenMMNameMap = {"SystemEnergy": "system energy", "RestraintEnergy": "restraint energy", "RestraintStrength": "restraint strength", "MaxConstraintError": "max constraint error"}
 1963 
 1964     CanonicalDataOutTypeMap = {}
 1965     ValidDataOutTypes = []
 1966     for DataOutType in DataOutTypeOpenMMNameMap:
 1967         ValidDataOutTypes.append(DataOutType)
 1968         CanonicalDataOutTypeMap[DataOutType.lower()] = DataOutType
 1969 
 1970     # Process minimization data out types...
 1971     ParamName = "MinimizationDataOutType"
 1972     ParamValue = ParamsInfo[ParamName]
 1973     DataOutTypeList = []
 1974     if re.match("^auto$", ParamValue, re.I):
 1975         DataOutTypeList = ["SystemEnergy", "RestraintEnergy", "MaxConstraintError"]
 1976     else:
 1977         if "MinimizationDataOutTypeList" in ParamsInfo:
 1978             DataOutTypeList = ParamsInfo["MinimizationDataOutTypeList"]
 1979         else:
 1980             DataOutTypeList = ParamsInfo["MinimizationDataOutType"].split()
 1981             ParamsInfo["MinimizationDataOutTypeList"] = DataOutTypeList
 1982 
 1983     # Set up a list containing OpenMM names for minimization reporter...
 1984     DataOutTypeOpenMMNameList = []
 1985     for DataOutType in DataOutTypeList:
 1986         CanonicalDataOutType = DataOutType.lower()
 1987         if CanonicalDataOutType not in CanonicalDataOutTypeMap:
 1988             MiscUtil.PrintError("The parameter value, %s specified for paramaer name, %s, specified using \"%s\" is not a valid name. Supported parameter names: %s" % (DataOutType, ParamName, ParamsOptionName, " ".join(ValidDataOutTypes)))
 1989         
 1990         DataOutType = CanonicalDataOutTypeMap[CanonicalDataOutType]
 1991         
 1992         DataOutTypeOpenMMName = DataOutTypeOpenMMNameMap[DataOutType]
 1993         DataOutTypeOpenMMNameList.append(DataOutTypeOpenMMName)
 1994 
 1995     ParamsInfo["MinimizationDataOutTypeList"] = DataOutTypeList
 1996     ParamsInfo["MinimizationDataOutTypeOpenMMNameList"] = DataOutTypeOpenMMNameList
 1997     
 1998 def ProcessOptionOpenMMAtomsSelectionParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo = None):
 1999     """Process parameters for selecting atoms and return a map containing
 2000     processed parameter names and values.
 2001     
 2002     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 2003     to select atoms.
 2004     
 2005     The supported parameter names along with their default and possible
 2006     values are shown below:
 2007     
 2008         selection, none [ Possible values: CAlphaProtein, Ions, Ligand,
 2009             Protein, Residues, or Water ]
 2010         selectionSpec, auto [ Possible values: A space delimited list of
 2011             residue names ]
 2012         negate, no [ Possible values: yes or no ]
 2013     
 2014     A brief description of parameters is provided below:
 2015     
 2016     selection: Atom selection to freeze.
 2017     
 2018     selectionSpec: A space delimited list of residue names for selecting atoms.
 2019     You must specify its value during 'Ligand' and 'Protein' value for 'selection'.
 2020     The default values are automatically set for 'CAlphaProtein', 'Ions', 'Protein',
 2021     and 'Water' values of 'selection' as shown below:
 2022     
 2023         CAlphaProtein: List of stadard protein residues from pdbfixer
 2024             for selecting CAlpha atoms.
 2025         Ions: Li Na K Rb Cs Cl Br F I
 2026         Water: HOH
 2027         Protein: List of standard protein residues from pdbfixer.
 2028     
 2029     negate: Negate atom selection match to select atoms for freezing.
 2030     
 2031     In addition, you may specify an explicit space delimited list of residue
 2032     names using 'selectionSpec' for any 'selection". The specified residue
 2033     names are appended to the appropriate default values during the
 2034     selection of atoms for freezing.
 2035 
 2036     Arguments:
 2037         ParamsOptionName (str): Command line OpenMM selection option name.
 2038         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 2039         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 2040 
 2041     Returns:
 2042         dictionary: Processed parameter name and value pairs.
 2043 
 2044     """
 2045 
 2046     ParamsInfo = {"Selection": None, "SelectionSpec": "auto", "Negate": False}
 2047 
 2048     if ParamsOptionValue is None:
 2049         return ParamsInfo
 2050 
 2051     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 2052 
 2053     if re.match("^auto$", ParamsOptionValue, re.I):
 2054         _ProcessOptionOpenMMAtomsSelectionParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2055         return ParamsInfo
 2056 
 2057     for Index in range(0, len(ParamsOptionValueWords), 2):
 2058         Name = ParamsOptionValueWords[Index].strip()
 2059         Value = ParamsOptionValueWords[Index + 1].strip()
 2060 
 2061         ParamName = CanonicalParamNamesMap[Name.lower()]
 2062         ParamValue = Value
 2063 
 2064         # Set value...
 2065         ParamsInfo[ParamName] = ParamValue
 2066         if re.match("^Selection$", ParamName, re.I):
 2067             if not re.match("^(CAlphaProtein|Ions|Ligand|Protein|Residues|Water)$", Value, re.I):
 2068                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: CAlphaProtein, Ions, Ligand, Protein, Residues, or Water" % (Value, Name, ParamsOptionName))
 2069             ParamValue = Value
 2070         elif re.match("^SelectionSpec$", ParamName, re.I):
 2071             if not re.match("^(auto|none)$", Value, re.I):
 2072                 Values = Value.split()
 2073                 if len(Values) == 0:
 2074                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain space delimited list of residue names.\n" % (Value, ParamName, ParamsOptionName))
 2075                 # Set residues list...
 2076                 ParamsInfo["SelectionSpecList"] = Values
 2077         elif re.match("^Negate$", ParamName, re.I):
 2078             if not re.match("^(yes|no|true|false)$", Value, re.I):
 2079                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: yes or no" % (Value, Name, ParamsOptionName))
 2080             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 2081         else:
 2082             ParamValue = Value
 2083         
 2084         # Set value...
 2085         ParamsInfo[ParamName] = ParamValue
 2086 
 2087     # Handle parameters with possible auto values...
 2088     _ProcessOptionOpenMMAtomsSelectionParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2089 
 2090     return ParamsInfo
 2091 
 2092 def _ProcessOptionOpenMMAtomsSelectionParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 2093     """Process parameters with possible auto values and perform validation.
 2094     """
 2095 
 2096     SelectionParamName = "Selection"
 2097     SelectionParamValue = ParamsInfo[SelectionParamName]
 2098 
 2099     SelectionSpecParamName = "SelectionSpec"
 2100     SelectionSpecParamValue = ParamsInfo[SelectionSpecParamName]
 2101 
 2102     SelectionSpecList = None if re.match("^(auto|none)$", SelectionSpecParamValue, re.I) else ParamsInfo["SelectionSpecList"]
 2103 
 2104     ResidueNames = None
 2105     if re.match("^(CAlphaProtein|Protein)$", SelectionParamValue, re.I):
 2106         ResidueNames = pdbfixer.pdbfixer.proteinResidues
 2107         if SelectionSpecList is not None:
 2108             ResidueNames.extend(SelectionSpecList)
 2109     elif re.match("^Ions$", SelectionParamValue, re.I):
 2110         ResidueNames = ["Li", "Na", "K", "Rb", "Cs",  "Cl", "Br", "F", "I"]
 2111         if SelectionSpecList is not None:
 2112             ResidueNames.extend(SelectionSpecList)
 2113     elif re.match("^Ligand$", SelectionParamValue, re.I):
 2114         if SelectionSpecList is None:
 2115             MiscUtil.PrintError("No value specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain a ligand residue name.\n" % (SelectionSpecParamName, ParamsOptionName))
 2116         elif len(SelectionSpecList) != 1:
 2117             MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain a single ligand residue name.\n" % (SelectionSpecParamValue, SelectionSpecParamName, ParamsOptionName))
 2118         ResidueNames = SelectionSpecList
 2119     elif re.match("^Residues$", SelectionParamValue, re.I):
 2120         if SelectionSpecList is None:
 2121             MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain a space delimited list of residue names.\n" % (SelectionSpecParamValue, SelectionSpecParamName, ParamsOptionName))
 2122         ResidueNames = SelectionSpecList
 2123     elif re.match("^Water$", SelectionParamValue, re.I):
 2124         ResidueNames = ["HOH"]
 2125         if SelectionSpecList is not None:
 2126             ResidueNames.extend(SelectionSpecList)
 2127 
 2128     ParamsInfo["ResidueNames"] = [ResidueName.upper() for ResidueName in ResidueNames]
 2129     ParamsInfo["CAlphaProteinStatus"] = True if re.match("^CAlphaProtein$", SelectionParamValue, re.I) else False
 2130 
 2131 def ProcessOptionOpenMMForcefieldParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo = None):
 2132     """Process parameters for biopolymer, small molecule, and water forcefields and
 2133     return a map containing processed parameter names and values.
 2134     
 2135     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 2136     for forcefields.
 2137     
 2138     The supported parameter names along with their default and possible
 2139     values are shown below:
 2140     
 2141         biopolymer, amber14-all.xml  [ Possible values: Any Valid value ]
 2142         smallMolecule, OpenFF_2.2.0  [ Possible values: Any Valid value ]
 2143         water, auto  [ Possible values: Any Valid value ]
 2144     
 2145     Possible biopolymer forcefield values:
 2146     
 2147         amber14-all.xml, amber99sb.xml, amber99sbildn.xml, amber03.xml,
 2148         amber10.xml
 2149         charmm36.xml, charmm_polar_2019.xml
 2150         amoeba2018.xml
 2151     
 2152     Possible small molecule forcefield values:
 2153     
 2154         openff_2.2.0, openff_2.0.0, openff_1.3.1, openff_1.2.1, openff_1.1.1,
 2155         smirnoff99frosst
 2156         gaff-2.11, gaff-2.1, gaff-1.81, gaff-1.8, gaff-1.4
 2157     
 2158     The default water forcefield valus is dependent on the type of the
 2159     biopolymer forcefield as shown below:
 2160     
 2161         Amber: amber14/tip3pfb.xml
 2162         CHARMM: charmm36/water.xml or None for charmm_polar_2019.xml
 2163         Amoeba: None (Explicit)
 2164         
 2165     Possible water forcefield values:
 2166     
 2167       amber14/tip3p.xml, amber14/tip3pfb.xml, amber14/spce.xml,
 2168       amber14/tip4pew.xml, amber14/tip4pfb.xml,
 2169       implicit/obc2.xml, implicit/GBn.xml, implicit/GBn2.xml
 2170       charmm36/water.xml, charmm36/tip3p-pme-b.xml,
 2171       charmm36/tip3p-pme-f.xml, charmm36/spce.xml,
 2172       charmm36/tip4pew.xml, charmm36/tip4p2005.xml,
 2173       charmm36/tip5p.xml, charmm36/tip5pew.xml,
 2174       implicit/obc2.xml, implicit/GBn.xml, implicit/GBn2.xml
 2175       amoeba2018_gk.xml (Implict water), None (Explicit water for amoeba)
 2176         
 2177     You may specify any valid forcefield name supported by OpenMM. No
 2178     explicit validation is performed.
 2179 
 2180     Arguments:
 2181         ParamsOptionName (str): Command line OpenMM forcefield option name.
 2182         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 2183         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 2184 
 2185     Returns:
 2186         dictionary: Processed parameter name and value pairs.
 2187 
 2188     """
 2189 
 2190     ParamsInfo = {"Biopolymer": "amber14-all.xml", "SmallMolecule": "openff-2.2.1", "Water": "auto", "Additional" : "None"}
 2191 
 2192     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 2193 
 2194     if re.match("^auto$", ParamsOptionValue, re.I):
 2195         _ProcessOptionOpenMMForcefieldParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2196         return ParamsInfo
 2197 
 2198     for Index in range(0, len(ParamsOptionValueWords), 2):
 2199         Name = ParamsOptionValueWords[Index].strip()
 2200         Value = ParamsOptionValueWords[Index + 1].strip()
 2201 
 2202         ParamName = CanonicalParamNamesMap[Name.lower()]
 2203         ParamValue = Value
 2204 
 2205         # Set value...
 2206         ParamsInfo[ParamName] = ParamValue
 2207 
 2208     # Handle parameters with possible auto values...
 2209     _ProcessOptionOpenMMForcefieldParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2210 
 2211     return ParamsInfo
 2212 
 2213 def _ProcessOptionOpenMMForcefieldParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 2214     """Process parameters with possible auto values and perform validation.
 2215     """
 2216     WaterForcefield = ParamsInfo["Water"]
 2217     if re.match("^None$", WaterForcefield, re.I):
 2218         WaterForcefield = None
 2219         ParamsInfo["Water"] = WaterForcefield
 2220     elif re.match("^auto$", WaterForcefield, re.I):
 2221         BiopolymerForcefield = ParamsInfo["Biopolymer"]
 2222         if re.search("amber", BiopolymerForcefield, re.I):
 2223             WaterForcefield = "amber14/tip3pfb.xml"
 2224         elif re.search("charmm", BiopolymerForcefield, re.I):
 2225             if re.search("charmm_polar_2019", BiopolymerForcefield, re.I):
 2226                 WaterForcefield = None
 2227             else:
 2228                 WaterForcefield = "charmm36/water.xml"
 2229         elif re.search("amoeba", BiopolymerForcefield, re.I):
 2230             # Explicit water...
 2231             WaterForcefield = None
 2232         else:
 2233             WaterForcefield = None
 2234         ParamsInfo["Water"] = WaterForcefield
 2235 
 2236     # Set status of implicit water forcefield...
 2237     BiopolymerForcefield = ParamsInfo["Biopolymer"]
 2238     ParamsInfo["ImplicitWater"] = True if _IsImplicitWaterForcefield(BiopolymerForcefield, WaterForcefield) else False
 2239 
 2240     # Process additional forcefields...
 2241     ParamName = "Additional"
 2242     ParamValue = ParamsInfo[ParamName]
 2243     ParamValuesList = None
 2244     if not re.match("^None$", ParamValue, re.I):
 2245         ParamValuesList = ParamValue.split()
 2246         if len(ParamValuesList) == 0:
 2247             MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain a space delimited list of valid values.\n" % (ParamValue, ParamName, ParamsOptionName))
 2248     ParamsInfo["AdditionalList"] = ParamValuesList
 2249 
 2250 def _IsImplicitWaterForcefield(BiopolymerForcefield, WaterForcefield):
 2251     """Check the nature of the water forcefield."""
 2252 
 2253     Status = False
 2254     if WaterForcefield is None:
 2255         if re.search("charmm_polar_2019", BiopolymerForcefield, re.I):
 2256             Status = True
 2257         else:
 2258             Status = False
 2259     else:
 2260         if re.search("amber", BiopolymerForcefield, re.I):
 2261             if re.search("implicit", WaterForcefield, re.I):
 2262                 Status = True
 2263         elif re.search("charmm", BiopolymerForcefield, re.I):
 2264             if re.search("implicit", WaterForcefield, re.I):
 2265                 Status = True
 2266         elif re.search("amoeba", BiopolymerForcefield, re.I):
 2267             Status = True
 2268 
 2269     return Status
 2270 
 2271 def ProcessOptionOpenMMPlatformParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo = None):
 2272     """Process parameters for platform option and return a map containing processed
 2273     parameter names and values.
 2274     
 2275     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 2276     to setup platform.
 2277     
 2278     The supported parameter names along with their default values for
 2279     different platforms are shown below:
 2280     
 2281         CPU:
 2282         
 2283         threads, 1  [ Possible value: >= 0 or auto.  The value of 'auto'
 2284             or zero implies the use of all available CPUs for threading. ]
 2285         
 2286         CUDA:
 2287         
 2288         deviceIndex, auto  [ Possible values: 0, '0 1' etc. ]
 2289         deterministicForces, auto [ Possible values: yes or no ]
 2290         precision, single  [ Possible values: single, double, or mix ]
 2291         tempDirectory, auto [ Possible value: DirName ]
 2292         useBlockingSync, auto [ Possible values: yes or no ]
 2293         useCpuPme, auto [ Possible values: yes or no ]
 2294         
 2295         OpenCL:
 2296         
 2297         deviceIndex, auto  [ Possible values: 0, '0 1' etc. ]
 2298         openCLPlatformIndex, auto  [ Possible value: Number]
 2299         precision, single  [ Possible values: single, double, or mix ]
 2300         useCpuPme, auto [ Possible values: yes or no ]
 2301     
 2302     A brief description of parameters is provided below:
 2303     
 2304         CPU:
 2305         
 2306         threads: Number of threads to use for simulation.
 2307         
 2308         CUDA:
 2309         
 2310         deviceIndex: Space delimited list of device indices to use for
 2311             calculations.
 2312         deterministicForces: Generate reproducible results at the cost of a
 2313             small decrease in performance.
 2314         precision: Number precision to use for calculations.
 2315         tempDirectory: Directory name for storing temporary files.
 2316         useBlockingSync: Control run-time synchronization between CPU and
 2317             GPU.
 2318         useCpuPme: Use CPU-based PME implementation.
 2319         
 2320         OpenCL:
 2321         
 2322         deviceIndex: Space delimited list of device indices to use for
 2323             simulation.
 2324         openCLPlatformIndex: Platform index to use for calculations.
 2325         precision: Number precision to use for calculations.
 2326         useCpuPme: Use CPU-based PME implementation.
 2327 
 2328     Arguments:
 2329         ParamsOptionName (str): Command line OpenMM platform option name.
 2330         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 2331         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 2332 
 2333     Returns:
 2334         dictionary: Processed parameter name and value pairs.
 2335 
 2336     """
 2337 
 2338     ParamsInfo = {"Name": "CPU", "Threads": "auto", "DeviceIndex": "auto", "DeterministicForces": "auto", "Precision": "single", "TempDirectory": "auto", "UseBlockingSync": "auto", "UseCpuPme": "auto", "OpenCLPlatformIndex": "auto"}
 2339 
 2340     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 2341 
 2342     if re.match("^auto$", ParamsOptionValue, re.I):
 2343         _ProcessOptionOpenMMPlatformParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2344         return ParamsInfo
 2345 
 2346     for Index in range(0, len(ParamsOptionValueWords), 2):
 2347         Name = ParamsOptionValueWords[Index].strip()
 2348         Value = ParamsOptionValueWords[Index + 1].strip()
 2349 
 2350         ParamName = CanonicalParamNamesMap[Name.lower()]
 2351         ParamValue = Value
 2352 
 2353         if re.match("^Name$", ParamName, re.I):
 2354             if not re.match("^(CPU|CUDA|OpenCL|Reference)$", Value, re.I):
 2355                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: CPU, GPU, OpenCL, or Reference" % (Value, Name, ParamsOptionName))
 2356             ParamValue = Value
 2357         elif re.match("^Threads$", ParamName, re.I):
 2358             if not re.match("^auto$", Value, re.I):
 2359                 if not MiscUtil.IsInteger(Value):
 2360                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be an integer.\n" % (Value, ParamName, ParamsOptionName))
 2361                 Value = int(Value)
 2362                 if Value < 0:
 2363                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: >=0 \n" % (ParamValue, ParamName, ParamsOptionName))
 2364                 if Value > mp.cpu_count():
 2365                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is greater than number of CPUs, %s, returned by mp.cpu_count().\n" % (ParamValue, ParamName, ParamsOptionName, mp.cpu_count()))
 2366                 ParamValue = "%s" % Value
 2367         elif re.match("^Precision$", ParamName, re.I):
 2368             if not re.match("^(Single|Double|Mix)$", Value, re.I):
 2369                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: single, double or mix" % (Value, Name, ParamsOptionName))
 2370             ParamValue = Value.lower()
 2371         elif re.match("^(DeterministicForces|UseBlockingSync|UseCpuPme)$", ParamName, re.I):
 2372             if not re.match("^auto$", Value, re.I):
 2373                 if not re.match("^(yes|no|true|false)$", Value, re.I):
 2374                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: yes or no" % (Value, Name, ParamsOptionName))
 2375                 ParamValue = "true" if re.match("^(yes|true)$", Value, re.I) else "false"
 2376         elif re.match("^(DeviceIndex|openCLPlatformIndex)$", ParamName, re.I):
 2377             if not re.match("^auto$", Value, re.I):
 2378                 DeviceIndices = Value.split()
 2379                 if len(DeviceIndices) == 0:
 2380                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain space delimited list of device indices.\n" % (Value, ParamName, ParamsOptionName))
 2381                 for DeviceIndex in DeviceIndices:
 2382                     if not MiscUtil.IsInteger(DeviceIndex):
 2383                         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be an integer.\n" % (DeviceIndex, ParamName, ParamsOptionName))
 2384                 ParamValue = ",".join(DeviceIndices)
 2385         elif re.match("^TempDirectory$", ParamName, re.I):
 2386             if not re.match("^auto$", Value, re.I):
 2387                 if not os.path.isdir(Value):
 2388                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. The specified directory doesn't exists." % (Value, Name, ParamsOptionName))
 2389             ParamValue = Value
 2390         else:
 2391             ParamValue = Value
 2392 
 2393         # Set value...
 2394         ParamsInfo[ParamName] = ParamValue
 2395 
 2396     # Handle parameters with possible auto values...
 2397     _ProcessOptionOpenMMPlatformParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2398 
 2399     return ParamsInfo
 2400 
 2401 def _ProcessOptionOpenMMPlatformParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 2402     """Process parameters with possible auto values and perform validation.
 2403     """
 2404 
 2405     ParamValueMap = {"cpu": "CPU", "cuda": "CUDA", "opencl": "OpenCL", "reference": "Reference"}
 2406     ParamName = "Name"
 2407     ParamValue = ParamsInfo[ParamName].lower()
 2408     if ParamValue in ParamValueMap:
 2409         ParamsInfo[ParamName] = ParamValueMap[ParamValue]
 2410 
 2411     ParamsInfo["Precision"] = ParamsInfo["Precision"].lower()
 2412 
 2413     # Set "auto" values to None and treat all other values as strings...
 2414     for ParamName in ParamsInfo:
 2415         ParamValue = "%s" % ParamsInfo[ParamName]
 2416         if re.match("^auto$", ParamValue, re.I):
 2417             ParamsInfo[ParamName] = None
 2418         else:
 2419             ParamsInfo[ParamName] = ParamValue
 2420 
 2421 def ProcessOptionOpenMMWaterBoxParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo = None):
 2422     """Process parameters for adding a water box option and return a map containing
 2423     processed parameter names and values.
 2424     
 2425     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 2426     for adding a water box.
 2427     
 2428     The supported parameter names along with their default and possible
 2429     values are shown below:
 2430     
 2431         model, tip3p [ Possible values: tip3p, spce, tip4pew, tip5p or swm4ndp ]
 2432         mode, Padding [ Possible values: Size or Padding ]
 2433         size, None [ Possible values: xsize ysize zsize ]
 2434         padding, 1.0
 2435         shape, cube [ Possible values: cube, dodecahedron, or octahedron ]
 2436         ionPositive, Na+ [ Possible values: Li+, Na+, K+, Rb+, or Cs+ ]
 2437         ionNegative, Cl- [ Possible values: Cl-, Br-, F-, or I- ]
 2438         ionicStrength, 0.0
 2439     
 2440     A brief description of parameters is provided below:
 2441     
 2442     model: Water model to use for adding water box.
 2443     
 2444     mode: Specify the size of the waterbox explicitly or calculate it automatically
 2445     for a macromolecule along with adding padding around macromolecule.
 2446     Possible values: Size or Padding.
 2447     
 2448     size: A space delimited triplet of values corresponding to water size in
 2449     nanometers. It must be specified during 'Size' value of 'mode' parameter.
 2450     
 2451     padding: Padding around macromolecule in nanometers for filling box with
 2452     water. It must be specified during 'Padding' value of 'mode' parameter.
 2453     
 2454     ionPositive: Type of positive ion to add during the addition of a water box.
 2455     
 2456     ionNegative: Type of negative ion to add during the addition of a water box.
 2457     
 2458     ionicStrength: Total concentration (molar) of both positive and negative ions
 2459     to add excluding he ions added to neutralize the system during the addition
 2460     of a water box.
 2461 
 2462     Arguments:
 2463         ParamsOptionName (str): Command line OpenMM water box option name.
 2464         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 2465         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 2466 
 2467     Returns:
 2468         dictionary: Processed parameter name and value pairs.
 2469 
 2470     """
 2471 
 2472     ParamsInfo = {"Model": "tip3p", "Mode": "Padding", "Size": None, "Padding": 1.0, "Shape": "cube", "IonPositive": "Na+", "IonNegative": "Cl-", "IonicStrength": 0.0}
 2473 
 2474     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 2475 
 2476     if re.match("^auto$", ParamsOptionValue, re.I):
 2477         _ProcessOptionOpenMMWaterBoxParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2478         return ParamsInfo
 2479 
 2480     for Index in range(0, len(ParamsOptionValueWords), 2):
 2481         Name = ParamsOptionValueWords[Index].strip()
 2482         Value = ParamsOptionValueWords[Index + 1].strip()
 2483 
 2484         ParamName = CanonicalParamNamesMap[Name.lower()]
 2485         ParamValue = Value
 2486 
 2487         if re.match("^Model$", ParamName, re.I):
 2488             if not re.match("^(tip3p|spce|tip4pew|tip5p|swm4ndp)$", Value, re.I):
 2489                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: tip3p, spce, tip4pew, tip5p, or swm4ndp" % (Value, Name, ParamsOptionName))
 2490             ParamValue = Value.lower()
 2491         elif re.match("^Mode$", ParamName, re.I):
 2492             if not re.match("^(Padding|Size)$", Value, re.I):
 2493                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: Padding or Size" % (Value, Name, ParamsOptionName))
 2494             ParamValue = Value
 2495         elif re.match("^Size$", ParamName, re.I):
 2496             if Value is not None and not re.match("^None$", Value, re.I):
 2497                 SizeValues = Value.split()
 2498                 if len(SizeValues) != 3:
 2499                     MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. It must contain 3 float values separated by spaces.\n" % (Value, ParamName, ParamsOptionName))
 2500 
 2501                 SizeValueList = []
 2502                 for SizeValue in SizeValues:
 2503                     if not MiscUtil.IsFloat(SizeValue):
 2504                         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be a float.\n" % (SizeValue, ParamName, ParamsOptionName))
 2505                     SizeValue = float(SizeValue)
 2506                     if SizeValue <= 0:
 2507                         MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (SizeValue, ParamName, ParamsOptionName))
 2508                     SizeValueList.append(SizeValue)
 2509 
 2510                 # Set size values...
 2511                 ParamsInfo["SizeList"] = SizeValueList
 2512 
 2513             ParamValue = Value
 2514         elif re.match("^Padding$", ParamName, re.I):
 2515             if not MiscUtil.IsFloat(Value):
 2516                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be a float.\n" % (Value, ParamName, ParamsOptionName))
 2517             Value = float(Value)
 2518             if Value <= 0:
 2519                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: > 0\n" % (ParamValue, ParamName, ParamsOptionName))
 2520             ParamValue = Value
 2521         elif re.match("^Shape$", ParamName, re.I):
 2522             if not re.match("^(cube|dodecahedron|octahedron)$", Value, re.I):
 2523                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: cube, dodecahedron, or octahedron" % (Value, Name, ParamsOptionName))
 2524             ParamValue = Value.lower()
 2525         elif re.match("^IonPositive$", ParamName, re.I):
 2526             ValidValues = "Li+ Na+ K+ Rb+ Cs+"
 2527             EscapedValidValuesPattern = "Li\+|Na\+|K\+|Rb\+|Cs\+"
 2528             if not re.match("^(%s)$" % EscapedValidValuesPattern, Value):
 2529                 MiscUtil.PrintError("The value specified, %s, for parameter name, %s, using  \"%s\" option is not a valid.  Supported value(s): %s" % (ParamValue, ParamName, ParamsOptionName, ValidValues))
 2530             ParamValue = Value
 2531         elif re.match("^IonNegative$", ParamName, re.I):
 2532             ValidValues = "F- Cl- Br- I-"
 2533             ValidValuesPattern = "F-|Cl-|Br-|I-"
 2534             if not re.match("^(%s)$" % ValidValuesPattern, Value):
 2535                 MiscUtil.PrintError("The value specified, %s, for parameter name, %s, using  \"%s\" option is not a valid.  Supported value(s): %s" % (ParamValue, ParamName, ParamsOptionName, ValidValues))
 2536             ParamValue = Value
 2537         elif re.match("^IonicStrength$", ParamName, re.I):
 2538             if not MiscUtil.IsFloat(Value):
 2539                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option must be a float.\n" % (Value, ParamName, ParamsOptionName))
 2540             Value = float(Value)
 2541             if Value < 0:
 2542                 MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: >= 0\n" % (ParamValue, ParamName, ParamsOptionName))
 2543             ParamValue = Value
 2544         else:
 2545             ParamValue = Value
 2546 
 2547         # Set value...
 2548         ParamsInfo[ParamName] = ParamValue
 2549 
 2550     # Handle parameters with possible auto values...
 2551     _ProcessOptionOpenMMWaterBoxParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2552 
 2553     return ParamsInfo
 2554 
 2555 def _ProcessOptionOpenMMWaterBoxParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 2556     """Process parameters with possible auto values and perform validation.
 2557     """
 2558 
 2559     ParamsInfo["ModeSize"] = True if re.match("^Size$", ParamsInfo["Mode"], re.I) else False
 2560     ParamsInfo["ModePadding"] = True if re.match("^Padding$", ParamsInfo["Mode"], re.I) else False
 2561 
 2562     if ParamsInfo["ModeSize"]:
 2563         ParamName = "Size"
 2564         ParamValue = ParamsInfo[ParamName]
 2565         if ParamValue  is None:
 2566             MiscUtil.PrintError("The parameter value, %s, specified for parameter name, %s, using \"%s\" option is not a valid value. Supported values: x y z\n" % (ParamValue, ParamName, ParamsOptionName))
 2567     else:
 2568          ParamsInfo["SizeList"] = None 
 2569 
 2570 def _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo):
 2571     """Validate and canonicalize parameter names."""
 2572 
 2573     # Setup a canonical paramater names...
 2574     ValidParamNames = []
 2575     CanonicalParamNamesMap = {}
 2576     for ParamName in sorted(ParamsInfo):
 2577         ValidParamNames.append(ParamName)
 2578         CanonicalParamNamesMap[ParamName.lower()] = ParamName
 2579 
 2580     # Update default values...
 2581     if ParamsDefaultInfo is not None:
 2582         for ParamName in ParamsDefaultInfo:
 2583             if ParamName not in ParamsInfo:
 2584                 MiscUtil.PrintError("The default parameter name, %s, specified using \"%s\" option is not a valid name. Supported parameter names: %s" % (ParamName, ParamsDefaultInfo, " ".join(ValidParamNames)))
 2585             ParamsInfo[ParamName] = ParamsDefaultInfo[ParamName]
 2586 
 2587     ParamsOptionValue = ParamsOptionValue.strip()
 2588     if not ParamsOptionValue:
 2589         MiscUtil.PrintError("No valid parameter name and value pairs specified using \"%s\" option" % ParamsOptionName)
 2590 
 2591     ParamsOptionValueWords = None
 2592     if not re.match("^auto$", ParamsOptionValue, re.I):
 2593         ParamsOptionValueWords = ParamsOptionValue.split(",")
 2594         if len(ParamsOptionValueWords) % 2:
 2595             MiscUtil.PrintError("The number of comma delimited paramater names and values, %d, specified using \"%s\" option must be an even number." % (len(ParamsOptionValueWords), ParamsOptionName))
 2596 
 2597     if ParamsOptionValueWords is not None:
 2598         for Index in range(0, len(ParamsOptionValueWords), 2):
 2599             Name = ParamsOptionValueWords[Index].strip()
 2600             CanonicalName = Name.lower()
 2601             if  not CanonicalName in CanonicalParamNamesMap:
 2602                 MiscUtil.PrintError("The parameter name, %s, specified using \"%s\" is not a valid name. Supported parameter names: %s" % (Name, ParamsOptionName, " ".join(ValidParamNames)))
 2603         
 2604     return (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords)