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