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