MayaChemTools

    1 #
    2 # File: OpenMMUtil.py
    3 # Author: Manish Sud <msud@san.rr.com>
    4 #
    5 # Copyright (C) 2026 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 shutil
   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__ = [
   51     "AddWaterBox",
   52     "DoAtomListsOverlap",
   53     "DoesAtomListOverlapWithSystemConstraints",
   54     "DoesSystemContainWater",
   55     "FixColumNamesLineInDataLogFile",
   56     "FreezeAtoms",
   57     "GenerateReimagedRealignedTrajectoryFiles",
   58     "GetAtoms",
   59     "GetFormattedTotalSimulationTime",
   60     "InitializeBarostat",
   61     "InitializeIntegrator",
   62     "InitializeReporters",
   63     "InitializeSimulation",
   64     "InitializeSystem",
   65     "InitializeSystemGenerator",
   66     "MapDataOutTypePlotToDataLogColumnNames",
   67     "MergeSmallMoleculeWithMacromolecule",
   68     "PerformAnnealing",
   69     "ProcessOptionOpenMMRestartParameters",
   70     "ProcessOptionOpenMMAtomsSelectionParameters",
   71     "ProcessOptionOpenMMAnnealingParameters",
   72     "ProcessOptionOpenMMForcefieldParameters",
   73     "ProcessOptionOpenMMIntegratorParameters",
   74     "ProcessOptionOpenMMMDProtocolParameters",
   75     "ProcessOptionOpenMMPlatformParameters",
   76     "ProcessOptionOpenMMOutputParameters",
   77     "ProcessOptionOpenMMSimulationParameters",
   78     "ProcessOptionOpenMMSystemParameters",
   79     "ProcessOptionOpenMMWaterBoxParameters",
   80     "ReadPDBFile",
   81     "ReadSmallMoleculeFile",
   82     "RestraintAtoms",
   83     "SetupAnnealingParameters",
   84     "SetupIntegratorParameters",
   85     "SetupMDProtocolParameters",
   86     "SetupSimulationParameters",
   87     "SetupSystemGeneratorForcefieldsParameters",
   88     "ValidateAndFreezeRestraintAtoms",
   89     "WritePDBFile",
   90     "WriteSimulationStatePDBFile",
   91 ]
   92 
   93 
   94 def InitializeSystem(
   95     PDBFile,
   96     ForcefieldParamsInfo,
   97     SystemParamsInfo,
   98     WaterBoxAdd=False,
   99     WaterBoxParamsInfo=None,
  100     SmallMolFile=None,
  101     SmallMolID="LIG",
  102 ):
  103     """Initialize OpenMM system using specified forcefields, system and water box
  104     parameters along with a small molecule file and ID.
  105 
  106     The ForcefieldParamsInfo parameter is a dictionary of name and value pairs for
  107     system parameters and may be generated by calling the function named
  108     ProcessOptionOpenMMForcefieldParameters().
  109 
  110     The SystemParamsInfo parameter is a dictionary of name and value pairs for
  111     system parameters and may be generated by calling the function named
  112     ProcessOptionOpenMMSystemParameters().
  113 
  114     The WaterBoxParamsInfo parameter is a dictionary of name and value pairs for
  115     system parameters and may be generated by calling the function named
  116     ProcessOptionOpenMMWaterBoxParameters().
  117 
  118     Arguments:
  119         PDBFile (str): PDB file name..
  120         ForcefieldParamsInfo (dict): Parameter name and value pairs.
  121         SystemParamsInfo (dict): Parameter name and value pairs.
  122         WaterBoxAdd (bool): Add water box.
  123         WaterBoxParamsInfo (dict): Parameter name and value pairs.
  124         SmallMolFile (str): Small molecule file name.
  125         SmallMolID (str): Three letter small molecule ID.
  126 
  127     Returns:
  128         Object: OpenMM system object.
  129         Object: OpenMM topology object.
  130         Object: OpenMM positions object.
  131 
  132     Examples:
  133 
  134         ... ... ...
  135         OptionsInfo["ForcefieldParams"] =
  136             OpenMMUtil.ProcessOptionOpenMMForcefieldParameters(
  137             "--forcefieldParams", Options["--forcefieldParams"])
  138         ... ... ...
  139         OptionsInfo["SystemParams"] =
  140             OpenMMUtil.ProcessOptionOpenMMSystemParameters("--systemParams",
  141             Options["--systemParams"])
  142         ... ... ...
  143         OptionsInfo["WaterBoxParams"] =
  144             OpenMMUtil.ProcessOptionOpenMMWaterBoxParameters(
  145             "--waterBoxParams", Options["--waterBoxParams"])
  146         ... ... ...
  147         System, Topology, Positions  = OpenMMUtil.InitializeSystem(
  148             OptionsInfo["Infile"], OptionsInfo["ForcefieldParams"],
  149             OptionsInfo["SystemParams"], OptionsInfo["WaterBox"],
  150             OptionsInfo["WaterBoxParams"], OptionsInfo["SmallMolFile"],
  151             OptionsInfo["SmallMolID"])
  152 
  153     """
  154 
  155     # Read PDB file...
  156     MiscUtil.PrintInfo("\nReading PDB file %s..." % PDBFile)
  157     PDBHandle = ReadPDBFile(PDBFile)
  158 
  159     ModellerHandle = mm.app.Modeller(PDBHandle.topology, PDBHandle.positions)
  160     MiscUtil.PrintInfo(
  161         "Number of residues: %s; Number of atoms: %s"
  162         % (ModellerHandle.topology.getNumResidues(), ModellerHandle.topology.getNumAtoms())
  163     )
  164 
  165     # Read small molecule file...
  166     SmallMols = None
  167     if SmallMolFile is not None:
  168         MiscUtil.PrintInfo("\nReading small molecule file %s..." % SmallMolFile)
  169         SmallMol = ReadSmallMoleculeFile(SmallMolFile)
  170         if SmallMol is None:
  171             MiscUtil.PrintError("Failed to read small molecule file: %s" % SmallMolFile)
  172         SmallMols = [SmallMol]
  173 
  174         MiscUtil.PrintInfo("\nGenerating macromolecule and small molecule complex...")
  175         MergeSmallMoleculeWithMacromolecule(ModellerHandle, SmallMol, SmallMolID)
  176         MiscUtil.PrintInfo(
  177             "Number of residues: %s; Number of atoms: %s"
  178             % (ModellerHandle.topology.getNumResidues(), ModellerHandle.topology.getNumAtoms())
  179         )
  180 
  181     # Initialize system generator...
  182     BiopolymerForcefield = ForcefieldParamsInfo["Biopolymer"]
  183     SmallMoleculeForcefield = ForcefieldParamsInfo["SmallMolecule"]
  184     WaterForcefield = ForcefieldParamsInfo["Water"]
  185     AdditionalForcefiedsList = ForcefieldParamsInfo["AdditionalList"]
  186     SystemGeneratorHandle = InitializeSystemGenerator(
  187         BiopolymerForcefield,
  188         SmallMoleculeForcefield,
  189         WaterForcefield,
  190         SystemParamsInfo,
  191         SmallMols,
  192         AdditionalForcefiedsList,
  193     )
  194 
  195     if WaterBoxAdd:
  196         AddWaterBox(ModellerHandle, SystemGeneratorHandle, WaterBoxParamsInfo)
  197         MiscUtil.PrintInfo(
  198             "Number of residues: %s; Number of atoms: %s"
  199             % (ModellerHandle.topology.getNumResidues(), ModellerHandle.topology.getNumAtoms())
  200         )
  201     else:
  202         MiscUtil.PrintInfo("\nSkipping addition of a water box...")
  203         if DoesSystemContainWater(ModellerHandle.topology):
  204             if ForcefieldParamsInfo["ImplicitWater"]:
  205                 MiscUtil.PrintInfo(
  206                     '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.'
  207                     % (ForcefieldParamsInfo["Biopolymer"], ForcefieldParamsInfo["Water"])
  208                 )
  209 
  210     MiscUtil.PrintInfo("\nBuilding system...")
  211     SystemHandle = SystemGeneratorHandle.create_system(ModellerHandle.topology, molecules=SmallMols)
  212 
  213     MiscUtil.PrintInfo(
  214         "Periodic boundary conditions: %s" % ("Yes" if DoesSystemUsesPeriodicBoundaryConditions(SystemHandle) else "No")
  215     )
  216 
  217     return (SystemHandle, ModellerHandle.topology, ModellerHandle.positions)
  218 
  219 
  220 def InitializeSystemGenerator(
  221     BiopolymerForcefield,
  222     SmallMoleculeForcefield,
  223     WaterForcefield,
  224     SystemParamsInfo,
  225     SmallMols,
  226     AdditionalForcefieldsList=None,
  227 ):
  228     """Initialize MMFF system generator using specified forcefields and system parameters
  229     along with a list of molecules.
  230 
  231     The SystemParamsInfo parameter is a dictionary of name and value pairs for
  232     system parameters and may be generated by calling the function named
  233     ProcessOptionOpenMMSystemParameters().
  234 
  235     Arguments:
  236         BiopolymerForcefield (str): Biopolymer force field name.
  237         SmallMoleculeForcefield (str): Small molecule force field name.
  238         WaterForcefield (str): Water force field name.
  239         SystemParamsInfo (dict): Parameter name and value pairs.
  240         SmallMols (list): List of OpenFF toolkit molecule objects.
  241         AdditionalForcefieldsList (list): List of any additional forcefield
  242             names
  243 
  244     Returns:
  245         Object: MMFF system generator object.
  246 
  247     Examples:
  248 
  249         OptionsInfo["SystemParams"] =
  250             OpenMMUtil.ProcessOptionOpenMMSystemParameters("--systemParams",
  251             Options["--systemParams"])
  252         ... ... ...
  253         SystemGeneratorHandle = OpenMMUtil.InitializeSystemGenerator(
  254             BiopolymerForcefield, SmallMoleculeForcefield, WaterForcefield,
  255             OptionsInfo["SystemParams"], SmallMols, AdditionalForcefiedsList)
  256 
  257     """
  258 
  259     (ForcefieldParams, PeriodicForcefieldParams, NonPeriodicForcefieldParams) = (
  260         SetupSystemGeneratorForcefieldsParameters(SystemParamsInfo)
  261     )
  262 
  263     AdditionalForcefieldMsg = ""
  264     if AdditionalForcefieldsList is not None:
  265         AdditionalForcefieldMsg = "; Additional forcefield(s): %s" % ", ".join(AdditionalForcefieldsList)
  266 
  267     MiscUtil.PrintInfo(
  268         "\nInitializing system generator (Biopolymer forcefield: %s; Small molecule forcefield: %s; Water forcefield: %s%s)..."
  269         % (BiopolymerForcefield, SmallMoleculeForcefield, WaterForcefield, AdditionalForcefieldMsg)
  270     )
  271 
  272     ForcefieldsList = [BiopolymerForcefield, WaterForcefield]
  273     if AdditionalForcefieldsList is not None:
  274         ForcefieldsList.extend(AdditionalForcefieldsList)
  275 
  276     SystemGeneratorHandle = mmff.generators.SystemGenerator(
  277         forcefields=ForcefieldsList,
  278         small_molecule_forcefield=SmallMoleculeForcefield,
  279         molecules=SmallMols,
  280         forcefield_kwargs=ForcefieldParams,
  281         periodic_forcefield_kwargs=PeriodicForcefieldParams,
  282         nonperiodic_forcefield_kwargs=NonPeriodicForcefieldParams,
  283     )
  284 
  285     return SystemGeneratorHandle
  286 
  287 
  288 def InitializeIntegrator(ParamsInfo, ConstraintErrorTolerance):
  289     """Initialize integrator.
  290 
  291     The ParamsInfo parameter is a dictionary of name and value pairs for
  292     integrator parameters and may be generated by calling the function named
  293     ProcessOptionOpenMMIntegratorParameters().
  294 
  295     Arguments:
  296         ParamsInfo (dict): Parameter name and value pairs.
  297         ConstraintErrorTolerance (float): Distance tolerance for
  298             constraints as a fraction of the constrained distance.
  299 
  300     Returns:
  301         Object: OpenMM integrator object.
  302 
  303     Examples:
  304 
  305         OptionsInfo["IntegratorParams"] =
  306             OpenMMUtil.ProcessOptionOpenMMIntegratorParameters(
  307             "--integratorParams", Options["--integratorParams"],
  308             HydrogenMassRepartioningStatus =
  309             OptionsInfo["SystemParams"]["HydrogenMassRepartioning"])
  310         ... ... ...
  311         Integrator = OpenMMUtil.InitializeIntegrator(
  312             OptionsInfo["IntegratorParams"],
  313             OptionsInfo["SystemParams"]["ConstraintErrorTolerance"])
  314 
  315     """
  316 
  317     IntegratorParamsInfo = SetupIntegratorParameters(ParamsInfo)
  318 
  319     IntegratorName = IntegratorParamsInfo["Integrator"]
  320     RandomSeed = IntegratorParamsInfo["RandomSeed"]
  321     StepSize = IntegratorParamsInfo["StepSize"]
  322     Temperature = IntegratorParamsInfo["Temperature"]
  323     FrictionCoefficient = IntegratorParamsInfo["FrictionCoefficient"]
  324 
  325     MiscUtil.PrintInfo(
  326         "\nIntializing integrator (Name: %s; StepSize: %s; Temperature: %s)..."
  327         % (IntegratorName, StepSize, Temperature)
  328     )
  329 
  330     if re.match("^LangevinMiddle$", IntegratorName, re.I):
  331         Integrator = mm.LangevinMiddleIntegrator(Temperature, FrictionCoefficient, StepSize)
  332     elif re.match("^Langevin$", IntegratorName, re.I):
  333         Integrator = mm.LangevinIntegrator(Temperature, FrictionCoefficient, StepSize)
  334     elif re.match("^NoseHoover$", IntegratorName, re.I):
  335         Integrator = mm.NoseHooverIntegrator(Temperature, FrictionCoefficient, StepSize)
  336     elif re.match("^Brownian$", IntegratorName, re.I):
  337         Integrator = mm.BrownianIntegrator(Temperature, FrictionCoefficient, StepSize)
  338     else:
  339         MiscUtil.PrintError(
  340             'The parameter value specified, %s, for parameter name, integrator, for option "--integratorParams" is not a valid value. Supported values: LangevinMiddle, Langevin, NoseHoover, or Brownian'
  341             % IntegratorName
  342         )
  343 
  344     Integrator.setConstraintTolerance(ConstraintErrorTolerance)
  345 
  346     if RandomSeed is not None:
  347         if re.match("^(LangevinMiddle|Langevin|Brownian)$", IntegratorName, re.I):
  348             MiscUtil.PrintInfo("Setting random number seed for integrator to %s..." % RandomSeed)
  349             Integrator.setRandomNumberSeed(RandomSeed)
  350         else:
  351             MiscUtil.PrintInfo(
  352                 "Skipping setting of random number seed. Not supported for integrator %s..." % IntegratorName
  353             )
  354 
  355     return Integrator
  356 
  357 
  358 def InitializeBarostat(ParamsInfo):
  359     """Initialize barostat.
  360 
  361     The ParamsInfo parameter is a dictionary of name and value pairs for
  362     integrator parameters and may be generated by calling the function named
  363     ProcessOptionOpenMMIntegratorParameters().
  364 
  365     Arguments:
  366         ParamsInfo (dict): Parameter name and value pairs.
  367 
  368     Returns:
  369         Object: OpenMM barostat object.
  370 
  371     Examples:
  372 
  373         OptionsInfo["IntegratorParams"] =
  374             OpenMMUtil.ProcessOptionOpenMMIntegratorParameters(
  375             "--integratorParams", Options["--integratorParams"],
  376             HydrogenMassRepartioningStatus =
  377             OptionsInfo["SystemParams"]["HydrogenMassRepartioning"])
  378         ... ... ...
  379         Barostat = OpenMMUtil.InitializeBarostat(
  380             OptionsInfo["IntegratorParams"])
  381 
  382     """
  383     IntegratorParamsInfo = SetupIntegratorParameters(ParamsInfo)
  384 
  385     BarostatName = IntegratorParamsInfo["Barostat"]
  386     if re.match("^MonteCarlo$", BarostatName, re.I):
  387         MiscUtil.PrintInfo(
  388             "\nInitializing Monte Carlo barostat (Pressure: %s)... " % (IntegratorParamsInfo["Pressure"])
  389         )
  390         Barostat = mm.MonteCarloBarostat(
  391             IntegratorParamsInfo["Pressure"],
  392             IntegratorParamsInfo["Temperature"],
  393             IntegratorParamsInfo["BarostatInterval"],
  394         )
  395     elif re.match("^MonteCarloMembrane$", BarostatName, re.I):
  396         MiscUtil.PrintInfo(
  397             "\nInitializing Monte Carlo membrane barostat (Pressure: %s; SurfaceTension: %s; XYMode: %s; ZMode: %s)... "
  398             % (
  399                 IntegratorParamsInfo["Pressure"],
  400                 IntegratorParamsInfo["SurfaceTension"],
  401                 IntegratorParamsInfo["XYModeSpecified"],
  402                 IntegratorParamsInfo["ZModeSpecified"],
  403             )
  404         )
  405         Barostat = mm.MonteCarloMembraneBarostat(
  406             IntegratorParamsInfo["Pressure"],
  407             IntegratorParamsInfo["SurfaceTension"],
  408             IntegratorParamsInfo["Temperature"],
  409             IntegratorParamsInfo["XYMode"],
  410             IntegratorParamsInfo["ZMode"],
  411             IntegratorParamsInfo["BarostatInterval"],
  412         )
  413     else:
  414         MiscUtil.PrintError(
  415             'The parameter value specified, %s, for parameter name, barostat, for option "--integratorParams" is not a valid value. Supported values: MonteCarlo or MonteCarloMembrane'
  416             % BarostatName
  417         )
  418 
  419     if IntegratorParamsInfo["RandomSeed"] is not None:
  420         RandomSeed = IntegratorParamsInfo["RandomSeed"]
  421         MiscUtil.PrintInfo("Setting random number seed for barostat to %s..." % RandomSeed)
  422         Barostat.setRandomNumberSeed(RandomSeed)
  423 
  424     return Barostat
  425 
  426 
  427 def InitializeSimulation(System, Integrator, Topology, Positions, PlatformParamsInfo):
  428     """Initialize simulation.
  429 
  430     The PlatformParamsInfo parameter is a dictionary of name and value pairs for
  431     platform parameters and may be generated by calling the function named
  432     ProcessOptionOpenMMPlatformParameters().
  433 
  434     Arguments:
  435         System (object): OpenMM system object.
  436         Integrator (object): OpenMM integrator object.
  437         Topology (object): OpenMM topology object.
  438         Positons (object): OpenMM Positions object.
  439         PlatformParamsInfo (dict): Parameter name and value pairs.
  440 
  441     Returns:
  442         Object: OpenMM simulation object.
  443 
  444     Examples:
  445 
  446         ParamsDefaultInfoOverride = {"Name": Options["--platform"],
  447              "Threads": 1}
  448         OptionsInfo["PlatformParams"] =
  449             OpenMMUtil.ProcessOptionOpenMMPlatformParameters("--platformParams",
  450             Options["--platformParams"], ParamsDefaultInfoOverride)
  451         ... ... ...
  452         Simulation = OpenMMUtil.InitializeSimulation(System, Integrator, Topology,
  453             Positions, OptionsInfo["PlatformParams"])
  454 
  455     """
  456 
  457     PlatformName, PlatformProperties, PlatformMsg = SetupPlatformParameters(PlatformParamsInfo)
  458     MiscUtil.PrintInfo("\nInitializing simulation (%s)..." % PlatformMsg)
  459 
  460     try:
  461         PlatformHandle = mm.Platform.getPlatformByName(PlatformName)
  462     except Exception as ErrMsg:
  463         MiscUtil.PrintInfo("")
  464         MiscUtil.PrintError("Failed to get platform %s:\n%s\n" % (PlatformName, ErrMsg))
  465 
  466     try:
  467         SimulationHandle = mm.app.Simulation(Topology, System, Integrator, PlatformHandle, PlatformProperties)
  468     except Exception as ErrMsg:
  469         MiscUtil.PrintInfo("")
  470         MiscUtil.PrintError("Failed to initialize simulation: %s\n" % (ErrMsg))
  471 
  472     SimulationHandle.context.setPositions(Positions)
  473 
  474     return SimulationHandle
  475 
  476 
  477 def InitializeReporters(OutputParamsInfo, TotalSteps, DataOutAppendStatus):
  478     """Initialize reporters for writing data to trajectory, log, and checkpoint
  479     files along with reporting to the stdout.
  480 
  481     The OutputParamsInfo parameter is a dictionary of name and value pairs for
  482     output parameters and may be generated by calling the function named
  483     ProcessOptionOpenMMOutputParameters().
  484 
  485     Arguments:
  486         OutputParamsInfo (dict): Parameter name and value pairs.
  487         TotalSteps (int): Total number of simulation steps.
  488         DataOutAppendStatus (bool): Append data to trajectory and log file.
  489 
  490     Returns:
  491         Object: OpenMM trajectory reporter object.
  492         Object: OpenMM data log file reporter object.
  493         Object: OpenMM stodut reporter object.
  494         Object: OpenMM checkpoint reporter object.
  495 
  496     Examples:
  497 
  498         if OptionsInfo["NVTMode"]:
  499             ParamsDefaultInfoOverride = {"DataOutType": "Step Speed Progress
  500                 PotentialEnergy Temperature Time Volume"}
  501         else:
  502             ParamsDefaultInfoOverride = {"DataOutType": "Step Speed Progress
  503               PotentialEnergy Temperature Time Density"}
  504         OptionsInfo["OutputParams"] =
  505             OpenMMUtil.ProcessOptionOpenMMOutputParameters("--outputParams",
  506             Options["--outputParams"], OptionsInfo["OutfilePrefix"],
  507             ParamsDefaultInfoOverride)
  508         ProcessOutfileNames()
  509         ... ... ...
  510         (TrajReporter, DataLogReporter, DataStdoutReporter, CheckpointReporter)
  511             = OpenMMUtil.InitializeReporters(OptionsInfo["OutputParams"],
  512             OptionsInfo["SimulationParams"]["Steps"], OptionsInfo["DataOutAppendMode"])
  513 
  514     """
  515 
  516     (TrajReporter, DataLogReporter, DataStdoutReporter, CheckpointReporter) = [None] * 4
  517     if OutputParamsInfo["Traj"]:
  518         if re.match("^DCD$", OutputParamsInfo["TrajFormat"], re.I):
  519             TrajReporter = mm.app.DCDReporter(
  520                 OutputParamsInfo["TrajFile"], OutputParamsInfo["TrajSteps"], append=DataOutAppendStatus
  521             )
  522         elif re.match("^XTC$", OutputParamsInfo["TrajFormat"], re.I):
  523             if not DataOutAppendStatus:
  524                 # Remove existing traj file; otherwise, XTCReporter fails...
  525                 if os.path.isfile(OutputParamsInfo["TrajFile"]):
  526                     os.remove(OutputParamsInfo["TrajFile"])
  527             TrajReporter = mm.app.XTCReporter(
  528                 OutputParamsInfo["TrajFile"], OutputParamsInfo["TrajSteps"], append=DataOutAppendStatus
  529             )
  530         else:
  531             MiscUtil.PrintError(
  532                 'The parameter value specified, %s, for parameter name, trajFormat, for option "--outputParams" is not a valid value. Supported format: DCD or XTC'
  533             )
  534 
  535     if OutputParamsInfo["Checkpoint"]:
  536         CheckpointReporter = mm.app.CheckpointReporter(
  537             OutputParamsInfo["CheckpointFile"], OutputParamsInfo["CheckpointSteps"]
  538         )
  539 
  540     DataOutTypeStatusMap = OutputParamsInfo["DataOutTypeStatusMap"]
  541     if OutputParamsInfo["DataLog"]:
  542         DataLogReporter = mm.app.StateDataReporter(
  543             OutputParamsInfo["DataLogFile"],
  544             OutputParamsInfo["DataLogSteps"],
  545             totalSteps=TotalSteps,
  546             step=DataOutTypeStatusMap["Step"],
  547             time=DataOutTypeStatusMap["Time"],
  548             speed=DataOutTypeStatusMap["Speed"],
  549             progress=DataOutTypeStatusMap["Progress"],
  550             elapsedTime=DataOutTypeStatusMap["ElapsedTime"],
  551             remainingTime=DataOutTypeStatusMap["RemainingTime"],
  552             potentialEnergy=DataOutTypeStatusMap["PotentialEnergy"],
  553             kineticEnergy=DataOutTypeStatusMap["KineticEnergy"],
  554             totalEnergy=DataOutTypeStatusMap["TotalEnergy"],
  555             temperature=DataOutTypeStatusMap["Temperature"],
  556             volume=DataOutTypeStatusMap["Volume"],
  557             density=DataOutTypeStatusMap["Density"],
  558             separator=OutputParamsInfo["DataOutDelimiter"],
  559             append=DataOutAppendStatus,
  560         )
  561 
  562     if OutputParamsInfo["DataStdout"]:
  563         DataStdoutReporter = mm.app.StateDataReporter(
  564             sys.stdout,
  565             OutputParamsInfo["DataStdoutSteps"],
  566             totalSteps=TotalSteps,
  567             step=DataOutTypeStatusMap["Step"],
  568             time=DataOutTypeStatusMap["Time"],
  569             speed=DataOutTypeStatusMap["Speed"],
  570             progress=DataOutTypeStatusMap["Progress"],
  571             elapsedTime=DataOutTypeStatusMap["ElapsedTime"],
  572             remainingTime=DataOutTypeStatusMap["RemainingTime"],
  573             potentialEnergy=DataOutTypeStatusMap["PotentialEnergy"],
  574             kineticEnergy=DataOutTypeStatusMap["KineticEnergy"],
  575             totalEnergy=DataOutTypeStatusMap["TotalEnergy"],
  576             temperature=DataOutTypeStatusMap["Temperature"],
  577             volume=DataOutTypeStatusMap["Volume"],
  578             density=DataOutTypeStatusMap["Density"],
  579             separator=OutputParamsInfo["DataOutDelimiter"],
  580         )
  581 
  582     return (TrajReporter, DataLogReporter, DataStdoutReporter, CheckpointReporter)
  583 
  584 
  585 def PerformAnnealing(
  586     Simulation, Integrator, Barostat, TemperatureStart, TemperatureEnd, TemperatureChange, SimulationSteps
  587 ):
  588     """Perform annealing by heating or cooling the system from start to end
  589     temperature.
  590 
  591     The temperature is increased or decreased from start to end temperature by
  592     temperature to perform annealing following by performing simulations for a
  593     specified number of steps after each temperature step.
  594 
  595     Arguments:
  596         System (object): OpenMM system object.
  597         Integrator (object): OpenMM integrator object.
  598         Barostat (object): OpenMM integrator object.
  599         TemperatureStart (float): Start temperature.
  600         TemperatureEnd (float): End temperature.
  601         TemperatureChange (int): Temperature step size to heat or cool the
  602             system from start to end temperature.
  603         SimulationSteps (fint): Number of simulations steps to perform after
  604             each temperature step.
  605 
  606     Returns:
  607         int: Total number of simulation steps.
  608 
  609     Examples:
  610 
  611         ... ... ...
  612         TotalInitialSimulationSteps  = OpenMMUtil.PerformAnnealing(Simulation,
  613             Integrator, Barostat, InitialStart, InitialEnd, InitialChange, InitialSteps)
  614 
  615     """
  616 
  617     if TemperatureStart < TemperatureEnd:
  618         TemperatureRange = np.arange(TemperatureStart, TemperatureEnd, TemperatureChange)
  619     else:
  620         TemperatureRange = np.arange(TemperatureStart, TemperatureEnd, -TemperatureChange)
  621 
  622     TemperatureRange = TemperatureRange.tolist()
  623     TemperatureRange.append(TemperatureEnd)
  624 
  625     TotalSimulationSteps = 0
  626     for Temperature in TemperatureRange:
  627         Temperature = Temperature * mm.unit.kelvin
  628 
  629         Integrator.setTemperature(Temperature)
  630         if Barostat is not None:
  631             try:
  632                 Simulation.context.setParameter(Barostat.Temperature(), Temperature)
  633             except Exception as ErrMsg:
  634                 MiscUtil.PrintInfo("")
  635                 MiscUtil.PrintError("Failed to set barostat temperature:\n%s\n" % (ErrMsg))
  636 
  637         Simulation.step(SimulationSteps)
  638         TotalSimulationSteps += SimulationSteps
  639 
  640     return TotalSimulationSteps
  641 
  642 
  643 def AddWaterBox(ModellerHandle, SystemGeneratorHandle, WaterBoxParamsInfo):
  644     """Add a water box.
  645 
  646     The WaterBoxParamsInfo parameter is a dictionary of name and value pairs for
  647     waterbox parameters and may be generated by calling the function named
  648     ProcessOptionOpenMMWaterBoxParameters().
  649 
  650     Arguments:
  651         ModellerHandle (object): OpenMM modeller object.
  652         SystemGeneratorHandle (object): OpenMM system generator object.
  653         WaterBoxParamsInfo (dict): Parameter name and value pairs.
  654 
  655     Returns:
  656         None.
  657 
  658     Examples:
  659 
  660         OptionsInfo["WaterBoxParams"] =
  661             OpenMMUtil.ProcessOptionOpenMMWaterBoxParameters("--waterBoxParams",
  662             Options["--waterBoxParams"])
  663         ... ... ...
  664         OpenMMUtil.AddWaterBox(ModellerHandle, SystemGeneratorHandle,
  665            OptionsInfo["WaterBoxParams"])
  666 
  667     """
  668 
  669     MiscUtil.PrintInfo("\nRemoving any existing waters...")
  670     ModellerHandle.deleteWater()
  671 
  672     MiscUtil.PrintInfo("\nAdding a water box...")
  673 
  674     Size, Padding, Shape = [None] * 3
  675     if WaterBoxParamsInfo["ModeSize"]:
  676         SizeList = WaterBoxParamsInfo["SizeList"]
  677         Size = mm.Vec3(SizeList[0], SizeList[1], SizeList[2]) * mm.unit.nanometer
  678     elif WaterBoxParamsInfo["ModePadding"]:
  679         Padding = WaterBoxParamsInfo["Padding"] * mm.unit.nanometer
  680         Shape = WaterBoxParamsInfo["Shape"]
  681     else:
  682         MiscUtil.PrintError(
  683             'The parameter value, %s, specified for parameter name, mode, using "--waterBoxParams" option is not a valid value. Supported values: Size Padding \n'
  684             % (WaterBoxParamsInfo["Mode"])
  685         )
  686 
  687     IonicStrength = WaterBoxParamsInfo["IonicStrength"] * mm.unit.molar
  688 
  689     ModellerHandle.addSolvent(
  690         SystemGeneratorHandle.forcefield,
  691         model=WaterBoxParamsInfo["Model"],
  692         boxSize=Size,
  693         boxVectors=None,
  694         padding=Padding,
  695         numAdded=None,
  696         boxShape=Shape,
  697         positiveIon=WaterBoxParamsInfo["IonPositive"],
  698         negativeIon=WaterBoxParamsInfo["IonNegative"],
  699         ionicStrength=IonicStrength,
  700         neutralize=True,
  701     )
  702 
  703 
  704 def SetupSystemGeneratorForcefieldsParameters(SystemParamsInfo):
  705     """Setup forcefied parameters for OpenMM API calls.
  706 
  707     The SystemParamsInfo parameter is a dictionary of name and value pairs for
  708     system parameters and may be generated by calling the function named
  709     ProcessOptionOpenMMSystemParameters().
  710 
  711     Arguments:
  712         SystemParamsInfo (dict): Parameter name and value pairs.
  713 
  714     Returns:
  715         dict: Forcefield parameter name and value pairs.
  716         dictionary2: Periodic forcefield parameter name and value pairs.
  717         dictionary3: Non-periodic parameter name and value pairs.
  718 
  719     Examples:
  720 
  721         OptionsInfo["SystemParams"] =
  722             OpenMMUtil.ProcessOptionOpenMMSystemParameters("--systemParams",
  723             Options["--systemParams"])
  724         ... ... ...
  725         (ForcefieldParams, PeriodicForcefieldParams, NonPeriodicForcefieldParams)
  726             = SetupSystemGeneratorForcefieldsParameters(OptionsInfo["SystemParams"])
  727 
  728     """
  729 
  730     ForcefieldParams = {
  731         "constraints": SystemParamsInfo["Constraints"],
  732         "rigidWater": SystemParamsInfo["RigidWater"],
  733         "removeCMMotion": SystemParamsInfo["RemoveCMMotion"],
  734     }
  735     if SystemParamsInfo["HydrogenMassRepartioning"]:
  736         ForcefieldParams["hydrogenMass"] = SystemParamsInfo["HydrogenMass"] * mm.unit.amu
  737 
  738     NonbondedCutoff = SystemParamsInfo["NonbondedCutoff"] * mm.unit.nanometers
  739     PeriodicForcefieldParams = {
  740         "nonbondedMethod": SystemParamsInfo["NonbondedMethodPeriodic"],
  741         "nonbondedCutoff": NonbondedCutoff,
  742         "ewaldErrorTolerance": SystemParamsInfo["EwaldErrorTolerance"],
  743     }
  744     NonPeriodicForcefieldParams = {
  745         "nonbondedMethod": SystemParamsInfo["NonbondedMethodNonPeriodic"],
  746         "nonbondedCutoff": NonbondedCutoff,
  747     }
  748 
  749     return (ForcefieldParams, PeriodicForcefieldParams, NonPeriodicForcefieldParams)
  750 
  751 
  752 def SetupPlatformParameters(ParamsInfo):
  753     """Setup platform parameters for OpenMM calls.
  754 
  755     The ParamsInfo parameter is a dictionary of name and value pairs for
  756     platform parameters and may be generated by calling the function named
  757     ProcessOptionOpenMMPlatformParameters().
  758 
  759     Arguments:
  760         ParamsInfo (dict): Parameter name and value pairs.
  761 
  762     Returns:
  763         str: PlatformName.
  764         dict: Platform properities parameter name and values pairs.
  765         str: Text message describing platform.
  766 
  767     Examples:
  768 
  769         ParamsDefaultInfoOverride = {"Name": Options["--platform"],
  770              "Threads": 1}
  771         OptionsInfo["PlatformParams"] =
  772             OpenMMUtil.ProcessOptionOpenMMPlatformParameters("--platformParams",
  773             Options["--platformParams"], ParamsDefaultInfoOverride)
  774         ... ... ...
  775         PlatformName, PlatformProperties, PlatformMsg =
  776             SetupPlatformParameters(PlatformParamsInfo)
  777 
  778     """
  779 
  780     PlatformName = ParamsInfo["Name"]
  781     ParamNames = None
  782 
  783     if re.match("^CPU$", PlatformName, re.I):
  784         ParamNames = ["Threads"]
  785     elif re.match("^CUDA$", PlatformName, re.I):
  786         ParamNames = [
  787             "DeviceIndex",
  788             "DeterministicForces",
  789             "Precision",
  790             "TempDirectory",
  791             "UseBlockingSync",
  792             "UseCpuPme",
  793         ]
  794     elif re.match("^OpenCL$", PlatformName, re.I):
  795         ParamNames = ["DeviceIndex", "OpenCLPlatformIndex", "Precision", "UseCpuPme"]
  796     elif re.match("^Reference$", PlatformName, re.I):
  797         ParamNames = None
  798     else:
  799         MiscUtil.PrintError(
  800             'The parameter value specified, %s, for parameter name, name, for option "--platformParams" is not a valid value. Supported values: CPU, CUDA, OpenCL, or Reference'
  801         )
  802 
  803     PlatformProperties = None
  804     if ParamNames is not None:
  805         FirstValue = True
  806         for ParamName in ParamNames:
  807             ParamValue = ParamsInfo[ParamName]
  808             if ParamValue is not None:
  809                 if FirstValue:
  810                     FirstValue = False
  811                     PlatformProperties = {}
  812                 PlatformProperties[ParamName] = ParamValue
  813 
  814     PlatformMsg = "Platform: %s" % PlatformName
  815     if re.match("^CPU$", PlatformName, re.I):
  816         Threads = ParamsInfo["Threads"]
  817         if Threads is None or Threads == "0":
  818             Threads = "auto"
  819         PlatformMsg = "Platform: %s; Threads: %s" % (PlatformName, Threads)
  820     elif re.match("^(CUDA|OpenCL)$", PlatformName, re.I):
  821         DeviceIndex = "auto" if ParamsInfo["DeviceIndex"] is None else ParamsInfo["DeviceIndex"]
  822         Precision = "auto" if ParamsInfo["Precision"] is None else ParamsInfo["Precision"]
  823         PlatformMsg = "Platform: %s; DeviceIndex: %s; Precision: %s" % (PlatformName, DeviceIndex, Precision)
  824 
  825     return (PlatformName, PlatformProperties, PlatformMsg)
  826 
  827 
  828 def SetupAnnealingParameters(ParamsInfo):
  829     """Setup annealing parameters for OpenMM API calls.
  830 
  831     The ParamsInfo parameter is a dictionary of name and value pairs for
  832     annealing parameters and may be generated by calling the function named
  833     ProcessOptionOpenMMAnnealingParameters().
  834 
  835     Arguments:
  836         ParamsInfo (dict): Parameter name and value pairs.
  837 
  838     Returns:
  839         dict: Annealing parameter name and values pairs.
  840 
  841     Examples:
  842 
  843         OptionsInfo["AnnealingParams"] =
  844             OpenMMUtil.ProcessOptionOpenMMAnnealingParameters(
  845             "--annealingParams", Options["--annealingParams"],
  846         ... ... ...
  847         AnnealingParams = SetupAnnealingParams(
  848             OptionsInfo["AnnealingParams"])
  849 
  850     """
  851 
  852     ParamsInfoWithUnits = {}
  853 
  854     ParamsInfoWithUnits["InitialStart"] = ParamsInfo["InitialStart"] * mm.unit.kelvin
  855     ParamsInfoWithUnits["InitialEnd"] = ParamsInfo["InitialEnd"] * mm.unit.kelvin
  856     ParamsInfoWithUnits["InitialChange"] = ParamsInfo["InitialChange"] * mm.unit.kelvin
  857     ParamsInfoWithUnits["InitialSteps"] = ParamsInfo["InitialSteps"]
  858 
  859     ParamsInfoWithUnits["InitialEquilibrationSteps"] = ParamsInfo["InitialEquilibrationSteps"]
  860 
  861     ParamsInfoWithUnits["Cycles"] = ParamsInfo["Cycles"]
  862     ParamsInfoWithUnits["CycleStart"] = ParamsInfo["CycleStart"] * mm.unit.kelvin
  863     ParamsInfoWithUnits["CycleEnd"] = ParamsInfo["CycleEnd"] * mm.unit.kelvin
  864     ParamsInfoWithUnits["CycleChange"] = ParamsInfo["CycleChange"] * mm.unit.kelvin
  865     ParamsInfoWithUnits["CycleSteps"] = ParamsInfo["CycleSteps"]
  866 
  867     ParamsInfoWithUnits["CycleEquilibrationSteps"] = ParamsInfo["CycleEquilibrationSteps"]
  868 
  869     ParamsInfoWithUnits["FinalEquilibrationSteps"] = ParamsInfo["FinalEquilibrationSteps"]
  870 
  871     return ParamsInfoWithUnits
  872 
  873 
  874 def SetupMDProtocolParameters(ParamsInfo):
  875     """Setup MD protocol parameters for OpenMM API calls.
  876 
  877     The ParamsInfo parameter is a dictionary of name and value pairs for
  878     annealing parameters and may be generated by calling the function named
  879     ProcessOptionOpenMMMDProtocolParameters().
  880 
  881     Arguments:
  882         ParamsInfo (dict): Parameter name and value pairs.
  883 
  884     Returns:
  885         dict: MD protocol parameter name and values pairs.
  886 
  887     Examples:
  888 
  889         OptionsInfo["ProtocolParams"] =
  890             OpenMMUtil.ProcessOptionOpenMMMDProtocolParameters(
  891             "--protocolParams", Options["--protocolParams"],
  892         ... ... ...
  893         ProtocolParams = SetupMDProtocolParameters(
  894             OptionsInfo["ProtocolParams"])
  895 
  896     """
  897 
  898     ParamsInfoWithUnits = {}
  899 
  900     ParamsInfoWithUnits["Phase1"] = ParamsInfo["Phase1"]
  901     ParamsInfoWithUnits["Phase1InitialStart"] = ParamsInfo["Phase1InitialStart"] * mm.unit.kelvin
  902     ParamsInfoWithUnits["Phase1InitialEnd"] = ParamsInfo["Phase1InitialEnd"] * mm.unit.kelvin
  903     ParamsInfoWithUnits["Phase1InitialChange"] = ParamsInfo["Phase1InitialChange"] * mm.unit.kelvin
  904     ParamsInfoWithUnits["Phase1InitialSteps"] = ParamsInfo["Phase1InitialSteps"]
  905 
  906     ParamsInfoWithUnits["Phase1InitialEquilibrationSteps"] = ParamsInfo["Phase1InitialEquilibrationSteps"]
  907 
  908     ParamsInfoWithUnits["Phase2"] = ParamsInfo["Phase2"]
  909     ParamsInfoWithUnits["Phase2Cycles"] = ParamsInfo["Phase2Cycles"]
  910     ParamsInfoWithUnits["Phase2CycleStart"] = ParamsInfo["Phase2CycleStart"] * mm.unit.kelvin
  911     ParamsInfoWithUnits["Phase2CycleEnd"] = ParamsInfo["Phase2CycleEnd"] * mm.unit.kelvin
  912     ParamsInfoWithUnits["Phase2CycleChange"] = ParamsInfo["Phase2CycleChange"] * mm.unit.kelvin
  913     ParamsInfoWithUnits["Phase2CycleSteps"] = ParamsInfo["Phase2CycleSteps"]
  914 
  915     ParamsInfoWithUnits["Phase2CycleEquilibrationSteps"] = ParamsInfo["Phase2CycleEquilibrationSteps"]
  916 
  917     ParamsInfoWithUnits["Phase3"] = ParamsInfo["Phase3"]
  918     ParamsInfoWithUnits["Phase3Steps"] = ParamsInfo["Phase3Steps"]
  919 
  920     ParamsInfoWithUnits["Phase4"] = ParamsInfo["Phase4"]
  921     ParamsInfoWithUnits["Phase4Steps"] = ParamsInfo["Phase4Steps"]
  922 
  923     ParamsInfoWithUnits["Phase5"] = ParamsInfo["Phase5"]
  924     ParamsInfoWithUnits["Phase5Steps"] = ParamsInfo["Phase5Steps"]
  925     if ParamsInfo["Phase5StepSize"] is None:
  926         ParamsInfoWithUnits["Phase5StepSize"] = None
  927     else:
  928         ParamsInfoWithUnits["Phase5StepSize"] = ParamsInfo["Phase5StepSize"] * mm.unit.femtoseconds
  929 
  930     return ParamsInfoWithUnits
  931 
  932 
  933 def SetupIntegratorParameters(ParamsInfo):
  934     """Setup integrator parameters for OpenMM API calls.
  935 
  936     The ParamsInfo parameter is a dictionary of name and value pairs for
  937     integrator parameters and may be generated by calling the function named
  938     ProcessOptionOpenMMIntegratorParameters().
  939 
  940     Arguments:
  941         ParamsInfo (dict): Parameter name and value pairs.
  942 
  943     Returns:
  944         dict: Integrator parameter name and values pairs.
  945 
  946     Examples:
  947 
  948         OptionsInfo["IntegratorParams"] =
  949             OpenMMUtil.ProcessOptionOpenMMIntegratorParameters(
  950             "--integratorParams", Options["--integratorParams"],
  951             HydrogenMassRepartioningStatus =
  952             OptionsInfo["SystemParams"]["HydrogenMassRepartioning"])
  953         ... ... ...
  954         IntegratorParams = SetupIntegratorParameters(
  955             OptionsInfo["IntegratorParams"])
  956 
  957     """
  958 
  959     ParamsInfoWithUnits = {}
  960 
  961     ParamsInfoWithUnits["Integrator"] = ParamsInfo["Integrator"]
  962 
  963     ParamsInfoWithUnits["RandomSeed"] = ParamsInfo["RandomSeed"]
  964 
  965     ParamsInfoWithUnits["FrictionCoefficient"] = ParamsInfo["FrictionCoefficient"] / mm.unit.picosecond
  966     ParamsInfoWithUnits["StepSize"] = ParamsInfo["StepSize"] * mm.unit.femtoseconds
  967     ParamsInfoWithUnits["Temperature"] = ParamsInfo["Temperature"] * mm.unit.kelvin
  968 
  969     ParamsInfoWithUnits["Barostat"] = ParamsInfo["Barostat"]
  970 
  971     ParamsInfoWithUnits["Pressure"] = ParamsInfo["Pressure"] * mm.unit.atmospheres
  972     ParamsInfoWithUnits["BarostatInterval"] = ParamsInfo["BarostatInterval"]
  973 
  974     SurfaceTensionInAngstroms = ParamsInfo["SurfaceTension"]
  975     SurfaceTension = SurfaceTensionInAngstroms * mm.unit.atmospheres * mm.unit.angstroms
  976 
  977     SurfaceTensionInNanometers = SurfaceTension.value_in_unit(mm.unit.atmospheres * mm.unit.nanometer)
  978     ParamsInfoWithUnits["SurfaceTension"] = SurfaceTensionInNanometers * mm.unit.atmospheres * mm.unit.nanometers
  979 
  980     XYMode = ParamsInfo["XYMode"]
  981     XYModeSpecified = ""
  982     if re.match("^Anisotropic$", XYMode, re.I):
  983         XYMode = mm.MonteCarloMembraneBarostat.XYAnisotropic
  984         XYModeSpecified = "Anisotropic"
  985     elif re.match("^Isotropic$", XYMode, re.I):
  986         XYMode = mm.MonteCarloMembraneBarostat.XYIsotropic
  987         XYModeSpecified = "Isotropic"
  988     else:
  989         MiscUtil.PrintError(
  990             'The parameter value specified, %s, for parameter name, xymode, for option "--integratorParams" is not a valid value. Supported values: Anisotropic or  Isotropic'
  991             % XYMode
  992         )
  993     ParamsInfoWithUnits["XYMode"] = XYMode
  994     ParamsInfoWithUnits["XYModeSpecified"] = XYModeSpecified
  995 
  996     ZMode = ParamsInfo["ZMode"]
  997     ZModeSpecified = ""
  998     if re.match("^Fixed$", ZMode, re.I):
  999         ZMode = mm.MonteCarloMembraneBarostat.ZFixed
 1000         ZModeSpecified = "Fixed"
 1001     elif re.match("^Free$", ZMode, re.I):
 1002         ZMode = mm.MonteCarloMembraneBarostat.ZFree
 1003         ZModeSpecified = "Free"
 1004     else:
 1005         MiscUtil.PrintError(
 1006             'The parameter value specified, %s, for parameter name, zmode, for option "--integratorParams" is not a valid value. Supported values: Fixed or Free'
 1007             % ZMode
 1008         )
 1009     ParamsInfoWithUnits["ZMode"] = ZMode
 1010     ParamsInfoWithUnits["ZModeSpecified"] = ZModeSpecified
 1011 
 1012     return ParamsInfoWithUnits
 1013 
 1014 
 1015 def SetupSimulationParameters(ParamsInfo):
 1016     """Setup simulation parameters for OpenMM API calls.
 1017 
 1018     The ParamsInfo parameter is a dictionary of name and value pairs for
 1019     integrator parameters and may be generated by calling the function named
 1020     ProcessOptionOpenMSimulationParameters().
 1021 
 1022     Arguments:
 1023         ParamsInfo (dict): Parameter name and value pairs.
 1024 
 1025     Returns:
 1026         dict: Integrator parameter name and values pairs.
 1027 
 1028     Examples:
 1029 
 1030         OptionsInfo["SimulationParams"] =
 1031             OpenMMUtil.ProcessOptionOpenMMSimulationParameters(
 1032             "--simulationParams", Options["--simulationParams"])
 1033         ... ... ...
 1034         SimulationParams = SetupSimulationParameters(
 1035             OptionsInfo["SimulationParams"])
 1036 
 1037     """
 1038 
 1039     ParamsInfoWithUnits = {}
 1040 
 1041     ParamsInfoWithUnits["Steps"] = ParamsInfo["Steps"]
 1042 
 1043     ParamsInfoWithUnits["Minimization"] = ParamsInfo["Minimization"]
 1044     ParamsInfoWithUnits["MinimizationMaxSteps"] = ParamsInfo["MinimizationMaxSteps"]
 1045 
 1046     MinimizationToleranceInKcal = ParamsInfo["MinimizationTolerance"]
 1047     MinimizationTolerance = MinimizationToleranceInKcal * mm.unit.kilocalories_per_mole / mm.unit.angstroms
 1048 
 1049     MinimizationToleranceInJoules = MinimizationTolerance.value_in_unit(mm.unit.kilojoules_per_mole / mm.unit.nanometer)
 1050     MinimizationTolerance = MinimizationToleranceInJoules * mm.unit.kilojoules_per_mole / mm.unit.nanometer
 1051 
 1052     ParamsInfoWithUnits["MinimizationToleranceInKcal"] = MinimizationToleranceInKcal
 1053     ParamsInfoWithUnits["MinimizationToleranceInJoules"] = MinimizationToleranceInJoules
 1054     ParamsInfoWithUnits["MinimizationTolerance"] = MinimizationTolerance
 1055 
 1056     ParamsInfoWithUnits["Equilibration"] = ParamsInfo["Equilibration"]
 1057     ParamsInfoWithUnits["EquilibrationSteps"] = ParamsInfo["EquilibrationSteps"]
 1058 
 1059     return ParamsInfoWithUnits
 1060 
 1061 
 1062 def GenerateReimagedRealignedTrajectoryFiles(
 1063     System, Topology, TrajTopologyFile, ReimagedPDBOutfile, ReimagedTrajOutfile, OutputParamsInfo, RealignFrames=True
 1064 ):
 1065     """Reimage and realign a trajectory file using MDTraj. The trajectory frames
 1066     are reimaged before realigning to the first frame using the specified atom
 1067     selection.
 1068 
 1069     The trajectory file format must a valid format supported by MDTraj. No
 1070     validation is performed.
 1071 
 1072     The OutputParamsInfo is a dictionary of name and value pairs for output
 1073     parameters and may be generated by calling the function named
 1074     ProcessOptionOpenMMOutputParameters().
 1075 
 1076     Arguments:
 1077         System (object): OpenMM system object.
 1078         Topology (object): OpenMM topology object.
 1079         TrajTopologyFile (str): Trajectory PDB topology file name.
 1080         ReimagedPDBOutfile (str): Trajectory PDB out file name.
 1081         ReimagedTrajOutfile (str): Trajectory out file name.
 1082         OutputParamsInfo (dict): Parameter name and value pairs.
 1083         RealignFrames (bool): Realign trajectory frames.
 1084 
 1085     Returns:
 1086         None
 1087 
 1088     """
 1089 
 1090     if not OutputParamsInfo["Traj"] or not os.path.exists(OutputParamsInfo["TrajFile"]):
 1091         return
 1092 
 1093     ReimageFrames = True if DoesSystemUsesPeriodicBoundaryConditions(System) else False
 1094     if not ReimageFrames:
 1095         MiscUtil.PrintInfo(
 1096             "\nSkipping reimaging and realigning of trajectory for a system not using periodic boundary conditions..."
 1097         )
 1098         return
 1099 
 1100     MiscUtil.PrintInfo("\nReimaging and realigning trajectory for a system using periodic boundary conditions...")
 1101 
 1102     # Reimage and realign trajectory file...
 1103     TrajFile = OutputParamsInfo["TrajFile"]
 1104     Traj, ReimagedStatus, RealignedStatus = ReimageRealignTrajectory(Topology, TrajFile, ReimageFrames, RealignFrames)
 1105 
 1106     PDBOutFormat = OutputParamsInfo["PDBOutFormat"]
 1107 
 1108     if (Traj is None) or (not ReimagedStatus and not RealignedStatus):
 1109         MiscUtil.PrintInfo("Skipping writing first frame to PDB file %s..." % ReimagedPDBOutfile)
 1110         MiscUtil.PrintInfo("Skippig writing trajectory file %s..." % ReimagedTrajOutfile)
 1111         return
 1112 
 1113     # Write out first frame...
 1114     MiscUtil.PrintInfo("Writing first frame to PDB file %s..." % ReimagedPDBOutfile)
 1115     if re.match("^CIF$", PDBOutFormat, re.I):
 1116         # MDTraj doesn't appear to support CIF format. Write it out as a temporary
 1117         #  PDB file and convert it using OpenMM...
 1118         FileDir, FileRoot, FileExt = MiscUtil.ParseFileName(ReimagedPDBOutfile)
 1119         TmpReimagedPDBOutfile = "%s_PID%s.pdb" % (FileRoot, os.getpid())
 1120         Traj[0].save(TmpReimagedPDBOutfile)
 1121 
 1122         PDBHandle = ReadPDBFile(TmpReimagedPDBOutfile)
 1123         WritePDBFile(ReimagedPDBOutfile, PDBHandle.topology, PDBHandle.positions, OutputParamsInfo["PDBOutKeepIDs"])
 1124 
 1125         os.remove(TmpReimagedPDBOutfile)
 1126     else:
 1127         Traj[0].save(ReimagedPDBOutfile)
 1128 
 1129     # Write out reimaged and realinged trajectory...
 1130     MiscUtil.PrintInfo("Writing trajectory file %s..." % ReimagedTrajOutfile)
 1131     Traj.save(ReimagedTrajOutfile)
 1132 
 1133 
 1134 def ReimageRealignTrajectory(
 1135     Topology, TrajFile, ReimageFrames=True, RealignFrames=True, Selection="protein and backbone and name CA"
 1136 ):
 1137     """Reimage and realign a trajectory file using MDTraj. The trajectory frames
 1138     are reimaged before realigning to the first frame using the specified atom
 1139     selection.
 1140 
 1141     The trajectory file format must a valid format supported by MDTraj. No
 1142     validation is performed.
 1143 
 1144     Arguments:
 1145         Topology (str or object): PDB file name or OpenMM topology object.
 1146         TrajFile (str): Trajectory file name.
 1147         ReimageFrames (bool): Reimage trajectory frames.
 1148         RealignFrames (bool): Realign trajectory frames.
 1149         Selection (str): MDTraj atom selection for realigning frames.
 1150 
 1151     Returns:
 1152         None or object: MDTraj trajectory object.
 1153         bool: Reimaged status.
 1154         bool: Realigned status.
 1155 
 1156     """
 1157 
 1158     if isinstance(Topology, str):
 1159         MiscUtil.PrintInfo("Reading trajectory file %s (TopologyFile: %s)..." % (TrajFile, Topology))
 1160     else:
 1161         MiscUtil.PrintInfo("Reading trajectory file %s..." % (TrajFile))
 1162         Topology = mdtraj.Topology.from_openmm(Topology)
 1163 
 1164     try:
 1165         Traj = mdtraj.load(TrajFile, top=Topology)
 1166     except Exception as ErrMsg:
 1167         MiscUtil.PrintInfo("")
 1168         MiscUtil.PrintWarning("Failed to read trajectory file: %s" % ErrMsg)
 1169         MiscUtil.PrintInfo("")
 1170         return (None, False, False)
 1171 
 1172     ReimagedStatus, RealignedStatus = [False] * 2
 1173 
 1174     if ReimageFrames:
 1175         MiscUtil.PrintInfo("Reimaging frames...")
 1176         try:
 1177             Traj.image_molecules(inplace=True)
 1178             ReimagedStatus = True
 1179         except Exception as ErrMsg:
 1180             MiscUtil.PrintInfo("")
 1181             MiscUtil.PrintWarning("Failed to reimage frames: %s" % ErrMsg)
 1182             MiscUtil.PrintInfo("")
 1183     else:
 1184         MiscUtil.PrintInfo("Skipping reimaging of frames...")
 1185 
 1186     if RealignFrames:
 1187         MiscUtil.PrintInfo('Realigning frames to the first frame using selection "%s"...' % Selection)
 1188         try:
 1189             SelectionAtomIndices = Traj.top.select(Selection)
 1190         except Exception as ErrMsg:
 1191             MiscUtil.PrintInfo("")
 1192             MiscUtil.PrintWarning('Failed to align frames using selection "%s": %s' % (Selection, ErrMsg))
 1193             MiscUtil.PrintInfo("")
 1194             return (Traj, ReimagedStatus, RealignedStatus)
 1195 
 1196         if SelectionAtomIndices.size == 0:
 1197             MiscUtil.PrintInfo("")
 1198             MiscUtil.PrintWarning('Failed to align frames using selection "%s": No matched atoms found' % (Selection))
 1199             MiscUtil.PrintInfo("")
 1200             return (Traj, ReimagedStatus, RealignedStatus)
 1201 
 1202         RealignedStatus = True
 1203         Traj.superpose(Traj, frame=0, atom_indices=SelectionAtomIndices)
 1204     else:
 1205         MiscUtil.PrintInfo("Skipping realignment of frames to the first frame...")
 1206 
 1207     return (Traj, ReimagedStatus, RealignedStatus)
 1208 
 1209 
 1210 def ValidateAndFreezeRestraintAtoms(
 1211     FreezeAtomsStatus,
 1212     FreezeAtomsParamsInfo,
 1213     RestraintAtomsStatus,
 1214     RestraintAtomsParamsInfo,
 1215     RestraintSpringConstantInKcal,
 1216     SystemParamsInfo,
 1217     System,
 1218     Topology,
 1219     Positions,
 1220 ):
 1221     """Handle freezing and restraining of atoms along with validation of atoms
 1222     to be frozen/restrained.
 1223 
 1224     The FreezeAtomsParamsInfo and RestraintAtomsParamsInfo parameters are dictionaries
 1225     of name and value pairs for system parameters and may be generated by calling the
 1226     function named ProcessOptionOpenMMAtomsSelectionParameters().
 1227 
 1228     The SystemParamsInfo parameter is a dictionary of name and value pairs for
 1229     system parameters and may be generated by calling the function named
 1230     ProcessOptionOpenMMSystemParameters().
 1231 
 1232     Arguments:
 1233         FreezeAtomsStatus (bool): Freeze atoms.
 1234         FreezeAtomsParamsInfo (dict): Parameter name and value pairs.
 1235         RestraintAtomsStatus (bool): Restraint atoms.
 1236         RestraintAtomsParamsInfo (dict): Parameter name and value pairs.
 1237         RestraintSpringConstantInKcal (float): Restraint spring constant.
 1238         SystemParamsInfo (dict): Parameter name and value pairs.
 1239         Topology (object): OpenMM topology object.
 1240         Positions (object): OpenMM positions object.
 1241 
 1242     Returns:
 1243         None or List: OpenMM atom objects.
 1244         None or List: OpenMM atom objects.
 1245 
 1246     """
 1247 
 1248     # Get atoms for freezing...
 1249     FreezeAtomList = None
 1250     if FreezeAtomsStatus:
 1251         FreezeAtomList = GetAtoms(
 1252             Topology,
 1253             FreezeAtomsParamsInfo["CAlphaProteinStatus"],
 1254             FreezeAtomsParamsInfo["ResidueNames"],
 1255             FreezeAtomsParamsInfo["Negate"],
 1256         )
 1257         if FreezeAtomList is None:
 1258             MiscUtil.PrintError(
 1259                 'The freeze atoms parameters specified, "selection, %s, selectionSpec, %s, negate, %s", using "--freezeAtomsParams" option didn\'t match any atoms in the system. You must specify a valid set of parameters for freezing atoms or disable freezing using "No" value for "--freezeAtoms" option..'
 1260                 % (
 1261                     FreezeAtomsParamsInfo["Selection"],
 1262                     FreezeAtomsParamsInfo["SelectionSpec"],
 1263                     FreezeAtomsParamsInfo["Negate"],
 1264                 )
 1265             )
 1266 
 1267     # Get atoms for restraining...
 1268     RestraintAtomList = None
 1269     if RestraintAtomsStatus:
 1270         RestraintAtomList = GetAtoms(
 1271             Topology,
 1272             RestraintAtomsParamsInfo["CAlphaProteinStatus"],
 1273             RestraintAtomsParamsInfo["ResidueNames"],
 1274             RestraintAtomsParamsInfo["Negate"],
 1275         )
 1276         if RestraintAtomList is None:
 1277             MiscUtil.PrintError(
 1278                 'The restraint atoms parameters specified, "selection, %s, selectionSpec, %s, negate, %s", using "--restraintAtomsParams" option didn\'t match any atoms in the system. You must specify a valid set of parameters for restraining atoms or disable restraining using "No" value for "--restraintAtoms" option.'
 1279                 % (
 1280                     RestraintAtomsParamsInfo["Selection"],
 1281                     RestraintAtomsParamsInfo["SelectionSpec"],
 1282                     RestraintAtomsParamsInfo["Negate"],
 1283                 )
 1284             )
 1285 
 1286     # Check for atoms to freeze or restraint...
 1287     if FreezeAtomList is None and RestraintAtomList is None:
 1288         return (FreezeAtomList, RestraintAtomList)
 1289 
 1290     #   Check for overlap between freeze and restraint atoms...
 1291     if DoAtomListsOverlap(FreezeAtomList, RestraintAtomList):
 1292         MiscUtil.PrintError(
 1293             'The atoms specified using "--freezeAtomsParams" and "--restraintAtomsParams" options appear to overlap. You must specify unique sets of atoms to freeze and restraint.'
 1294         )
 1295 
 1296     #  Check overlap of freeze atoms with system constraints...
 1297     if DoesAtomListOverlapWithSystemConstraints(System, FreezeAtomList):
 1298         MiscUtil.PrintError(
 1299             'The atoms specified using "--freezeAtomsParams" appear to overlap with atoms being constrained corresponding to the value specified, %s, for paramater name "constraints" using "--systemParams" option.\n\nYou must specify a unique set of atoms to freeze or turn off system constaints by specifying value, None, for "constraints" parameter using option "--systemsParams".\n\nIn addtion, you may want specify, no, value for "rigidWater" option.\n\nThe atoms are frozen by setting their particle mass to zero. OpenMM doesn\'t allow to both constraint atoms and set their mass to zero.'
 1300             % (SystemParamsInfo["Constraints"])
 1301         )
 1302 
 1303     #  Check overlap of restraint atoms with system constraints...
 1304     if DoesAtomListOverlapWithSystemConstraints(System, RestraintAtomList):
 1305         MiscUtil.PrintInfo("")
 1306         MiscUtil.PrintWarning(
 1307             'The atoms specified using "--restraintAtomsParams" appear to overlap with atoms being constrained corresponding to the value specified, %s, for paramater name "constraints" using "--systemParams" option. You may want to specify a unique set of atoms to restraints or turn off system constaints by specifying value, None, for "constraints" parameter using option "--systemsParams".'
 1308             % (SystemParamsInfo["Constraints"])
 1309         )
 1310 
 1311     # Freeze atoms...
 1312     if FreezeAtomList is None:
 1313         MiscUtil.PrintInfo("\nSkipping freezing of atoms...")
 1314     else:
 1315         MiscUtil.PrintInfo("\nFreezing atoms (Selection: %s)..." % FreezeAtomsParamsInfo["Selection"])
 1316         FreezeAtoms(System, FreezeAtomList)
 1317 
 1318     # Restraint atoms...
 1319     if RestraintAtomList is None:
 1320         MiscUtil.PrintInfo("\nSkipping restraining of atoms...")
 1321     else:
 1322         MiscUtil.PrintInfo("\nRestraining atoms (Selection: %s)..." % RestraintAtomsParamsInfo["Selection"])
 1323         RestraintAtoms(System, Positions, RestraintAtomList, RestraintSpringConstantInKcal)
 1324 
 1325     return (FreezeAtomList, RestraintAtomList)
 1326 
 1327 
 1328 def FreezeAtoms(System, AtomList):
 1329     """Freeze atoms during a simulation. The specified atoms are kept completely
 1330     fixed by setting their masses to zero. Their positions do not change during
 1331     local energy minimization and MD simulation, and they do not contribute
 1332     to the kinetic energy of the system.
 1333 
 1334     Arguments:
 1335         System (object): OpenMM system object.
 1336         AtomList (list): List of OpenMM atom objects.
 1337 
 1338     Returns:
 1339         None
 1340 
 1341     """
 1342 
 1343     if AtomList is None:
 1344         return
 1345 
 1346     for Atom in AtomList:
 1347         System.setParticleMass(Atom.index, 0 * mm.unit.amu)
 1348 
 1349 
 1350 def RestraintAtoms(System, Positions, AtomList, SpringConstantInKcal):
 1351     """Restraint atoms during a simulation. The motion of specified atoms is
 1352         restricted by adding a harmonic force that binds them to their starting
 1353         positions. The atoms are not completely fixed unlike freezing of atoms.
 1354         Their motion, however, is restricted and they are not able to move far away
 1355         from their starting positions during local energy minimization and MD
 1356         simulation.
 1357 
 1358         The SpringConstantInKcal value must be specified in the units of
 1359         kcal/mol/A*82. It is automatically converted into the units of
 1360         kjoules/mol/nm**2 for OpenMM API call.
 1361 
 1362     Arguments:
 1363         System (object): OpenMM system object.
 1364         Positions (object): OpenMM positons object object.
 1365         AtomList (list): List of OpenMM atom object.
 1366         SpringConstantInKcal (float): Spring constant value.
 1367 
 1368     Returns:
 1369         None
 1370 
 1371     """
 1372 
 1373     if AtomList is None:
 1374         return
 1375 
 1376     SpringConstant = SpringConstantInKcal * mm.unit.kilocalories_per_mole / mm.unit.angstroms**2
 1377     SpringConstantInKjoules = SpringConstant.value_in_unit(mm.unit.kilojoules_per_mole / mm.unit.nanometer**2)
 1378 
 1379     MiscUtil.PrintInfo(
 1380         "Restraint spring constant: %.2f kcal/mol/A**2 (%.2f kjoules/mol/nm**2)"
 1381         % (SpringConstantInKcal, SpringConstantInKjoules)
 1382     )
 1383 
 1384     if DoesSystemUsesPeriodicBoundaryConditions(System):
 1385         # For periodic systems...
 1386         RestraintForce = mm.CustomExternalForce("k*periodicdistance(x, y, z, x0, y0, z0)^2")
 1387     else:
 1388         # For non-periodic systems...
 1389         RestraintForce = mm.CustomExternalForce("k*((x-x0)^2+(y-y0)^2+(z-z0)^2)")
 1390 
 1391     SpringConstant = SpringConstantInKjoules * mm.unit.kilojoules_per_mole / mm.unit.nanometer**2
 1392     RestraintForce.addGlobalParameter("k", SpringConstant)
 1393 
 1394     RestraintForce.addPerParticleParameter("x0")
 1395     RestraintForce.addPerParticleParameter("y0")
 1396     RestraintForce.addPerParticleParameter("z0")
 1397 
 1398     for Atom in AtomList:
 1399         RestraintForce.addParticle(Atom.index, Positions[Atom.index])
 1400 
 1401 
 1402 def GetAtoms(Topology, CAlphaProteinStatus, ResidueNames, Negate):
 1403     """Get a list of atoms in the specified residue names. You may set
 1404     CAlphaProteinStatus flag to True to only retrieve CAlpha atoms from
 1405     the residues. In addition, you may negate residue name match using
 1406     Negate flag.
 1407 
 1408     Arguments:
 1409         Topology (object): OpenMM topology object.
 1410         CAlphaProteinStatus (bool): Get CAlpha atoms only.
 1411         ResidueNames (list): List of residue names.
 1412         Negate (bool): Negate residue name match.
 1413 
 1414     Returns:
 1415         None or List of OpenMM atom objects.
 1416 
 1417     """
 1418     AtomList = []
 1419     for Chain in Topology.chains():
 1420         for Residue in Chain.residues():
 1421             if CAlphaProteinStatus:
 1422                 if Residue.name in ResidueNames:
 1423                     for Atom in Residue.atoms():
 1424                         if _MatchName(Atom.name, ["CA"], Negate):
 1425                             AtomList.append(Atom)
 1426             else:
 1427                 if _MatchName(Residue.name, ResidueNames, Negate):
 1428                     AtomList.extend(Residue.atoms())
 1429 
 1430     if len(AtomList) == 0:
 1431         AtomList = None
 1432 
 1433     return AtomList
 1434 
 1435 
 1436 def _MatchName(Name, NamesList, Negate=False):
 1437     """Match name to the names in a list."""
 1438 
 1439     Status = True if Name in NamesList else False
 1440     if Negate:
 1441         Status = not Status
 1442 
 1443     return Status
 1444 
 1445 
 1446 def DoesSystemUsesPeriodicBoundaryConditions(System):
 1447     """Check for the use of periodic boundary conditions in a system.
 1448 
 1449     Arguments:
 1450         System (object): OpenMM system object.
 1451 
 1452     Returns:
 1453         bool : True - Uses periodic boundary conditions; Otherwise, false.
 1454 
 1455     """
 1456 
 1457     try:
 1458         Status = True if System.usesPeriodicBoundaryConditions() else False
 1459     except Exception:
 1460         Status = False
 1461 
 1462     return Status
 1463 
 1464 
 1465 def DoesAtomListOverlapWithSystemConstraints(System, AtomList):
 1466     """Check for the overlap of specified atoms with the atoms involved
 1467     in system constraints.
 1468 
 1469     Arguments:
 1470         System (object): OpenMM system object.
 1471         AtomList (list): List of OpenMM atom objects.
 1472 
 1473     Returns:
 1474         bool : True - Overlap with system constraints; Otherwise, false.
 1475 
 1476     """
 1477 
 1478     NumConstraints = System.getNumConstraints()
 1479     if NumConstraints == 0:
 1480         return False
 1481 
 1482     if AtomList is None:
 1483         return False
 1484 
 1485     AtomListIndices = [Atom.index for Atom in AtomList]
 1486 
 1487     for Index in range(NumConstraints):
 1488         Particle1Index, Particle2Index, Distance = System.getConstraintParameters(Index)
 1489         if Particle1Index in AtomListIndices or Particle2Index in AtomListIndices:
 1490             return True
 1491 
 1492     return False
 1493 
 1494 
 1495 def DoAtomListsOverlap(AtomList1, AtomList2):
 1496     """Check for the overlap of atoms in the specified atom lists.
 1497 
 1498     Arguments:
 1499         AtomList1 (list): List of OpenMM atom objects.
 1500         AtomList2 (list): List of OpenMM atom objects.
 1501 
 1502     Returns:
 1503         bool : True - Overlap between atoms lists; Otherwise, false.
 1504 
 1505     """
 1506 
 1507     if AtomList1 is None or AtomList2 is None:
 1508         return False
 1509 
 1510     AtomList1Indices = [Atom.index for Atom in AtomList1]
 1511 
 1512     for Atom in AtomList2:
 1513         if Atom.index in AtomList1Indices:
 1514             return True
 1515 
 1516     return False
 1517 
 1518 
 1519 def DoesSystemContainWater(Topology, WaterResidueNames=["HOH"]):
 1520     """Check for the presence of water residues in a system.
 1521 
 1522     Arguments:
 1523         Topology (object): OpenMM modeller topology object.
 1524         WaterResidueNames (list): List of water residue names.
 1525 
 1526     Returns:
 1527         bool : True - Contains water; Otherwise, false.
 1528 
 1529     """
 1530 
 1531     Status = False
 1532     for Residue in Topology.residues():
 1533         if Residue.name in WaterResidueNames:
 1534             Status = True
 1535             break
 1536 
 1537     return Status
 1538 
 1539 
 1540 def FixColumNamesLineInDataLogFile(DataLogFile):
 1541     """Fix column name line in data log file by removing the # character
 1542     written by OpenMM at the start of the first line.
 1543 
 1544     Arguments:
 1545         DataLogFile (str): Data log file name.
 1546 
 1547     Returns:
 1548         None
 1549 
 1550     """
 1551 
 1552     # Remove the "#" character written out by OpenMM at the start of the first
 1553     # line corresponding to column names...
 1554     #
 1555 
 1556     FileDir, FileRoot, FileExt = MiscUtil.ParseFileName(DataLogFile)
 1557     TmpDataLogFile = "Tmp%s_PID%s.%s" % (FileRoot, os.getpid(), FileExt)
 1558 
 1559     DataLogFH = open(DataLogFile, "r")
 1560     TmpDataLogFH = open(TmpDataLogFile, "w")
 1561 
 1562     FirstLine = True
 1563     for Line in DataLogFH:
 1564         if FirstLine:
 1565             FirstLine = False
 1566             if re.match(r"^\#", Line, re.I):
 1567                 Line = re.sub(r"^\#", "", Line)
 1568         TmpDataLogFH.write(Line)
 1569 
 1570     DataLogFH.close()
 1571     TmpDataLogFH.close()
 1572 
 1573     shutil.move(TmpDataLogFile, DataLogFile)
 1574 
 1575 
 1576 def MapDataOutTypePlotToDataLogColumnNames(DataOutTypePlotList, DataLogColNames):
 1577     """Map data out type to be plotted to column names in data log file.
 1578 
 1579     Arguments:
 1580         DataOutTypePlotList (list): List of data out types.
 1581         DataLogColNames (list): List of data log file column names.
 1582 
 1583     Returns:
 1584         dict: Data out type and column name value pairs.
 1585 
 1586     """
 1587 
 1588     DataOutTypePlotColNames = {}
 1589     for DataType in DataOutTypePlotList:
 1590         DataTypeColName = None
 1591         for ColName in DataLogColNames:
 1592             MatchDataType = DataType
 1593             if re.search("Energy", MatchDataType, re.I):
 1594                 MatchDataType = re.sub("Energy", " Energy", MatchDataType)
 1595 
 1596             if re.search(MatchDataType, ColName, re.I):
 1597                 DataTypeColName = ColName
 1598                 break
 1599 
 1600         DataOutTypePlotColNames[DataType] = DataTypeColName
 1601 
 1602     return DataOutTypePlotColNames
 1603 
 1604 
 1605 def ReadPDBFile(PDBFile):
 1606     """Read molecule from a PDB file.
 1607 
 1608     The supported PDB file formats are pdb and cif.
 1609 
 1610     Arguments:
 1611         PDBFile (str): Name of PDB file.
 1612 
 1613     Returns:
 1614         object: OpenMM PDBFile or PDBFilex object.
 1615 
 1616     """
 1617 
 1618     FileDir, FileName, FileExt = MiscUtil.ParseFileName(PDBFile)
 1619     if re.match("^pdb$", FileExt, re.I):
 1620         PDBHandle = mm.app.PDBFile(PDBFile)
 1621     elif re.match("^cif$", FileExt, re.I):
 1622         PDBHandle = mm.app.PDBxFile(PDBFile)
 1623     else:
 1624         MiscUtil.PrintError("Failed to read PDB file. Invalid PDB file format %s...\n" % PDBFile)
 1625 
 1626     return PDBHandle
 1627 
 1628 
 1629 def WritePDBFile(PDBFile, Topology, Positions, KeepIDs=True):
 1630     """Write a PDB file.
 1631 
 1632     The supported PDB file formats are pdb and cif.
 1633 
 1634     Arguments:
 1635         PDBFile (str): Name of PDB file.
 1636         Topology (object): Topology OpenMM object.
 1637         Positions (object): Positions OpenMM object.
 1638         KeepIDs (bool): Keep existing residue and chain IDs.
 1639 
 1640     Returns:
 1641         None
 1642 
 1643     """
 1644 
 1645     FileDir, FileName, FileExt = MiscUtil.ParseFileName(PDBFile)
 1646     if re.match("^pdb$", FileExt, re.I):
 1647         mm.app.PDBFile.writeFile(Topology, Positions, PDBFile, KeepIDs)
 1648     elif re.match("^cif$", FileExt, re.I):
 1649         mm.app.PDBxFile.writeFile(Topology, Positions, PDBFile, KeepIDs)
 1650     else:
 1651         MiscUtil.PrintError("Failed to write PDB file. Invalid PDB file format %s...\n" % PDBFile)
 1652 
 1653 
 1654 def WriteSimulationStatePDBFile(Simulation, PDBFile, KeepIDs=True):
 1655     """Write a PDB file for current simulation state.
 1656 
 1657     The supported PDB file formats are pdb and cif.
 1658 
 1659     Arguments:
 1660         Simulation (object): OpenMM simulation object.
 1661         PDBFile (str): Name of PDB fil.
 1662         KeepIDs (bool): Keep existing residue and chain IDs.
 1663 
 1664     Returns:
 1665         None
 1666 
 1667     """
 1668 
 1669     CurrentPositions = Simulation.context.getState(getPositions=True).getPositions()
 1670     WritePDBFile(PDBFile, Simulation.topology, CurrentPositions, KeepIDs)
 1671 
 1672 
 1673 def ReadSmallMoleculeFile(FileName):
 1674     """Read small molecule file using OpenFF toolkit.
 1675 
 1676     Arguments:
 1677         FileName (str): Small molecule file name.
 1678 
 1679     Returns:
 1680         None or OpenFF tookit molecule object.
 1681 
 1682     """
 1683 
 1684     try:
 1685         SmallMol = ff.toolkit.Molecule.from_file(FileName)
 1686     except Exception as ErrMsg:
 1687         SmallMol = None
 1688         MiscUtil.PrintInfo("")
 1689         MiscUtil.PrintWarning("OpenFF.toolkit.Molecule.from_file() failed: %s" % ErrMsg)
 1690         MiscUtil.PrintInfo("")
 1691 
 1692     return SmallMol
 1693 
 1694 
 1695 def MergeSmallMoleculeWithMacromolecule(ModellerHandle, SmallMol, SmallMolID="LIG"):
 1696     """Merge small molecule with macromolecule data contained in a modeller object and
 1697     assign a three letter small molecule residue name to the merged small molecule.
 1698 
 1699     Arguments:
 1700         ModellerHandle (object): OpenMM modeller object.
 1701         SmallMol (object): OpenFF tookit molecule object.
 1702         SmallMolID (str): Three letter residue name for small molecule.
 1703 
 1704     Returns:
 1705         None
 1706 
 1707     """
 1708 
 1709     SmallMolToplogy = SmallMol.to_topology()
 1710     SmallMolOpenMMTopology = SmallMolToplogy.to_openmm()
 1711     SmallMolOpenMMPositions = SmallMolToplogy.get_positions().to_openmm()
 1712 
 1713     # Set small molecule residue name to LIG...
 1714     for Chain in SmallMolOpenMMTopology.chains():
 1715         for Residue in Chain.residues():
 1716             Residue.name = SmallMolID
 1717 
 1718     ModellerHandle.add(SmallMolOpenMMTopology, SmallMolOpenMMPositions)
 1719 
 1720 
 1721 def GetFormattedTotalSimulationTime(StepSize, Steps):
 1722     """Get formatted total simulation time with appropriate time units.
 1723     parameter names and values.
 1724 
 1725     Arguments:
 1726         StepSize (object): OpenMM quantity object.
 1727         Steps (int): Number of steps.
 1728 
 1729     Returns:
 1730         str: Total time.
 1731 
 1732     """
 1733 
 1734     TotalTime = StepSize * Steps
 1735     TotalTimeValue = TotalTime.value_in_unit(mm.unit.femtoseconds)
 1736 
 1737     if TotalTimeValue < 1e3:
 1738         TotalTimeUnits = "fs"
 1739         TotalTime = TotalTime.value_in_unit(mm.unit.femtoseconds)
 1740     elif TotalTimeValue < 1e6:
 1741         TotalTimeUnits = "ps"
 1742         TotalTime = TotalTime.value_in_unit(mm.unit.picoseconds)
 1743     elif TotalTimeValue < 1e9:
 1744         TotalTimeUnits = "ns"
 1745         TotalTime = TotalTime.value_in_unit(mm.unit.nanoseconds)
 1746     elif TotalTimeValue < 1e12:
 1747         TotalTimeUnits = "us"
 1748         TotalTime = TotalTime.value_in_unit(mm.unit.microseconds)
 1749     else:
 1750         TotalTimeUnits = "ms"
 1751         TotalTime = TotalTime.value_in_unit(mm.unit.milliseconds)
 1752 
 1753     TotalTime = "%.2f %s" % (TotalTime, TotalTimeUnits)
 1754 
 1755     return TotalTime
 1756 
 1757 
 1758 def ProcessOptionOpenMMRestartParameters(ParamsOptionName, ParamsOptionValue, OutfilePrefix, ParamsDefaultInfo=None):
 1759     """Process parameters for restart option and return a map containing processed
 1760     parameter names and values.
 1761 
 1762     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 1763     to setup platform.
 1764 
 1765     The supported parameter names along with their default and possible
 1766     values are shown below:
 1767 
 1768         finalStateFile, <OutfilePrefix>_FinalState.<chk>  [ Possible values:
 1769             Valid final state checkpoint or XML filename ]
 1770         dataAppend, yes [ Possible values: yes or no]
 1771 
 1772     A brief description of parameters is provided below:
 1773 
 1774     finalStateFile: Final state checkpoint or XML file
 1775 
 1776     dataAppend: Append data to existing trajectory and data log files during the
 1777     restart of a simulation using a previously saved  final state checkpoint or
 1778     XML file.
 1779 
 1780     Arguments:
 1781         ParamsOptionName (str): Command line OpenMM restart option name.
 1782         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 1783         OutfilePrefix (str): Prefix for output files.
 1784         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 1785 
 1786     Returns:
 1787         dictionary: Processed parameter name and value pairs.
 1788 
 1789     """
 1790 
 1791     ParamsInfo = {"FinalStateFile": "auto", "DataAppend": True}
 1792 
 1793     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 1794         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 1795     )
 1796 
 1797     if re.match("^auto$", ParamsOptionValue, re.I):
 1798         _ProcessOptionOpenMMRestartParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1799         return ParamsInfo
 1800 
 1801     for Index in range(0, len(ParamsOptionValueWords), 2):
 1802         Name = ParamsOptionValueWords[Index].strip()
 1803         Value = ParamsOptionValueWords[Index + 1].strip()
 1804 
 1805         ParamName = CanonicalParamNamesMap[Name.lower()]
 1806         ParamValue = Value
 1807 
 1808         if re.match("^FinalStateFile$", ParamName, re.I):
 1809             if not re.match("^auto$", Value, re.I):
 1810                 if not os.path.exists(Value):
 1811                     MiscUtil.PrintError(
 1812                         'The file name specified, %s, for parameter name, %s, using option "%s" doesn\'t exist.\n.'
 1813                         % (Value, Name, ParamsOptionName)
 1814                     )
 1815                 if not MiscUtil.CheckFileExt(Value, "chk xml"):
 1816                     MiscUtil.PrintError(
 1817                         'The file name specified, %s, for parameter name, %s, using option "%s" is not valid file. Supported file formats: chk or xml\n.'
 1818                         % (Value, Name, ParamsOptionName)
 1819                     )
 1820                 ParamValue = Value
 1821         elif re.match("^DataAppend$", ParamName, re.I):
 1822             if not re.match("^(yes|no|true|false)$", Value, re.I):
 1823                 MiscUtil.PrintError(
 1824                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: yes or no'
 1825                     % (Value, Name, ParamsOptionName)
 1826                 )
 1827             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 1828         else:
 1829             ParamValue = Value
 1830 
 1831         # Set value...
 1832         ParamsInfo[ParamName] = ParamValue
 1833 
 1834     # Handle parameters with possible auto values...
 1835     _ProcessOptionOpenMMRestartParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 1836 
 1837     return ParamsInfo
 1838 
 1839 
 1840 def _ProcessOptionOpenMMRestartParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 1841     """Process parameters with possible auto values and perform validation."""
 1842 
 1843     FinalStateFileCheckpointMode = False
 1844     FinalStateFileXMLMode = False
 1845 
 1846     ParamName = "FinalStateFile"
 1847     FinalStateFile = ParamsInfo[ParamName]
 1848     if re.match("^auto$", FinalStateFile, re.I):
 1849         FinalStateFile = "%s_FinalState.chk" % OutfilePrefix
 1850         FinalStateFileCheckpointMode = True
 1851     else:
 1852         if MiscUtil.CheckFileExt(FinalStateFile, "chk"):
 1853             FinalStateFileCheckpointMode = True
 1854         elif MiscUtil.CheckFileExt(FinalStateFile, "xml"):
 1855             FinalStateFileXMLMode = True
 1856         else:
 1857             MiscUtil.PrintError(
 1858                 'The file name specified, %s, for parameter name, %s, using option "%s" is not valid. Supported file formats: chk or xml\n.'
 1859                 % (FinalStateFile, ParamName, ParamsOptionName)
 1860             )
 1861 
 1862     ParamsInfo["FinalStateFile"] = FinalStateFile
 1863     ParamsInfo["FinalStateFileCheckpointMode"] = FinalStateFileCheckpointMode
 1864     ParamsInfo["FinalStateFileXMLMode"] = FinalStateFileXMLMode
 1865 
 1866 
 1867 def ProcessOptionOpenMMSystemParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
 1868     """Process parameters for system option and return a map containing processed
 1869     parameter names and values.
 1870 
 1871     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 1872     to setup platform.
 1873 
 1874     The supported parameter names along with their default and possible
 1875     values are shown below:
 1876 
 1877         constraints, BondsInvolvingHydrogens [ Possible values: None,
 1878             WaterOnly, BondsInvolvingHydrogens, AllBonds, or
 1879             AnglesInvolvingHydrogens ]
 1880         constraintErrorTolerance, 0.000001
 1881         ewaldErrorTolerance, 0.0005
 1882 
 1883         nonbondedMethodPeriodic, PME [ Possible values: NoCutoff,
 1884             CutoffNonPeriodic, or PME ]
 1885         nonbondedMethodNonPeriodic, NoCutoff [ Possible values:
 1886             NoCutoff or CutoffNonPeriodic]
 1887         nonbondedCutoff, 1.0 [ Units: nm ]
 1888 
 1889         hydrogenMassRepartioning, yes [ Possible values: yes or no ]
 1890         hydrogenMass, 1.5 [ Units: amu]
 1891 
 1892         removeCMMotion, yes [ Possible values: yes or no ]
 1893         rigidWater, auto [ Possible values: yes or no. Default: 'No' for
 1894             'None' value of constraints; Otherwise, yes ]
 1895 
 1896     A brief description of parameters is provided below:
 1897 
 1898     constraints: Type of system constraints to use for simulation. These constraints
 1899     are different from freezing and restraining of any atoms in the system.
 1900 
 1901     constraintErrorTolerance: Distance tolerance for constraints as a fraction
 1902     of the constrained distance.
 1903 
 1904     ewaldErrorTolerance: Ewald error tolerance for a periodic system.
 1905 
 1906     nonbondedMethodPeriodic: Nonbonded method to use during the calculation of
 1907     long range interactions for a periodic system.
 1908 
 1909     nonbondedMethodNonPeriodic: Nonbonded method to use during the calculation
 1910     of long range interactions for a non-periodic system.
 1911 
 1912     nonbondedCutoff: Cutoff distance to use for long range interactions in both
 1913     perioidic non-periodic systems.
 1914 
 1915     hydrogenMassRepartioning: Use hydrogen mass repartioning. It increases the
 1916     mass of the hydrogen atoms attached to the heavy atoms and decreasing the
 1917     mass of the bonded heavy atom to maintain constant system mass. This allows
 1918     the use of larger integration step size (4 fs) during a simulation.
 1919 
 1920     hydrogenMass: Hydrogen mass to use during repartioning.
 1921 
 1922     removeCMMotion: Remove all center of mass motion at every time step.
 1923 
 1924     rigidWater: Keep water rigid during a simulation. This is determined
 1925     automatically based on the value of 'constraints' parameter.
 1926 
 1927     Arguments:
 1928         ParamsOptionName (str): Command line OpenMM system option name.
 1929         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 1930         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 1931 
 1932     Returns:
 1933         dictionary: Processed parameter name and value pairs.
 1934 
 1935     """
 1936 
 1937     ParamsInfo = {
 1938         "Constraints": "BondsInvolvingHydrogens",
 1939         "ConstraintErrorTolerance": 0.000001,
 1940         "EwaldErrorTolerance": 0.0005,
 1941         "NonbondedMethodPeriodic": "PME",
 1942         "NonbondedMethodNonPeriodic": "NoCutoff",
 1943         "NonbondedCutoff": 1.0,
 1944         "HydrogenMassRepartioning": True,
 1945         "HydrogenMass": 1.5,
 1946         "RemoveCMMotion": True,
 1947         "RigidWater": "auto",
 1948     }
 1949 
 1950     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 1951         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 1952     )
 1953 
 1954     if re.match("^auto$", ParamsOptionValue, re.I):
 1955         _ProcessOptionOpenMMSystemParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 1956         return ParamsInfo
 1957 
 1958     for Index in range(0, len(ParamsOptionValueWords), 2):
 1959         Name = ParamsOptionValueWords[Index].strip()
 1960         Value = ParamsOptionValueWords[Index + 1].strip()
 1961 
 1962         ParamName = CanonicalParamNamesMap[Name.lower()]
 1963         ParamValue = Value
 1964 
 1965         if re.match("^Constraints$", ParamName, re.I):
 1966             if not re.match("^auto$", Value, re.I):
 1967                 if not re.match(
 1968                     "^(None|WaterOnly|BondsInvolvingHydrogens|AllBonds|AnglesInvolvingHydrogens)$", Value, re.I
 1969                 ):
 1970                     MiscUtil.PrintError(
 1971                         '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.'
 1972                         % (Value, Name, ParamsOptionName)
 1973                     )
 1974             ParamValue = Value
 1975         elif re.match("^(ConstraintErrorTolerance|EwaldErrorTolerance|NonbondedCutoff|HydrogenMass)$", ParamName, re.I):
 1976             if not MiscUtil.IsFloat(Value):
 1977                 MiscUtil.PrintError(
 1978                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 1979                     % (Value, ParamName, ParamsOptionName)
 1980                 )
 1981             Value = float(Value)
 1982             if Value <= 0:
 1983                 MiscUtil.PrintError(
 1984                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 1985                     % (ParamValue, ParamName, ParamsOptionName)
 1986                 )
 1987             ParamValue = Value
 1988         elif re.match("^NonbondedMethodPeriodic$", ParamName, re.I):
 1989             if not re.match("^(NoCutoff|CutoffPeriodic|PME)$", Value, re.I):
 1990                 MiscUtil.PrintError(
 1991                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: NoCutoff, CutoffPeriodic, or PME'
 1992                     % (Value, Name, ParamsOptionName)
 1993                 )
 1994             ParamValue = Value
 1995         elif re.match("^NonbondedMethodNonPeriodic$", ParamName, re.I):
 1996             if not re.match("^(NoCutoff|CutoffNonPeriodic)$", Value, re.I):
 1997                 MiscUtil.PrintError(
 1998                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: NoCutoff or CutoffNonPeriodic'
 1999                     % (Value, Name, ParamsOptionName)
 2000                 )
 2001             ParamValue = Value
 2002         elif re.match("^(HydrogenMassRepartioning|removeCMMotion)$", ParamName, re.I):
 2003             if not re.match("^(yes|no|true|false)$", Value, re.I):
 2004                 MiscUtil.PrintError(
 2005                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: yes or no'
 2006                     % (Value, Name, ParamsOptionName)
 2007                 )
 2008             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 2009         elif re.match("^RigidWater$", ParamName, re.I):
 2010             if not re.match("^auto$", Value, re.I):
 2011                 if not re.match("^(yes|no|true|false)$", Value, re.I):
 2012                     MiscUtil.PrintError(
 2013                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: yes or no'
 2014                         % (Value, Name, ParamsOptionName)
 2015                     )
 2016                 ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 2017         else:
 2018             ParamValue = Value
 2019 
 2020         # Set value...
 2021         ParamsInfo[ParamName] = ParamValue
 2022 
 2023     # Handle parameters with possible auto values...
 2024     _ProcessOptionOpenMMSystemParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2025 
 2026     return ParamsInfo
 2027 
 2028 
 2029 def _ProcessOptionOpenMMSystemParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 2030     """Process parameters with possible auto values and perform validation."""
 2031 
 2032     for ParamName in ["NonbondedMethodPeriodic", "NonbondedMethodNonPeriodic"]:
 2033         ParamValue = ParamsInfo[ParamName]
 2034         if re.match("^NoCutoff$", ParamValue, re.I):
 2035             ParamValue = mm.app.NoCutoff
 2036         elif re.match("^CutoffNonPeriodic$", ParamValue, re.I):
 2037             ParamValue = mm.app.CutoffNonPeriodic
 2038         elif re.match("^CutoffPeriodic$", ParamValue, re.I):
 2039             ParamValue = mm.app.CutoffPeriodic
 2040         elif re.match("^PME$", ParamValue, re.I):
 2041             ParamValue = mm.app.PME
 2042         else:
 2043             MiscUtil.PrintError(
 2044                 'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: NoCutoff, CutoffNonPeriodic, CutoffPeriodic, or PME'
 2045                 % (ParamValue, ParamName, ParamsOptionName)
 2046             )
 2047         ParamsInfo[ParamName] = ParamValue
 2048 
 2049     ParamName = "Constraints"
 2050     ParamValue = ParamsInfo[ParamName]
 2051     ConstraintsValue = None
 2052     RigidWaterValue = False
 2053     if re.match("^None$", ParamValue, re.I):
 2054         ConstraintsValue = None
 2055         RigidWaterValue = False
 2056     elif re.match("^WaterOnly$", ParamValue, re.I):
 2057         ConstraintsValue = None
 2058         RigidWaterValue = True
 2059     elif re.match("^BondsInvolvingHydrogens$", ParamValue, re.I):
 2060         ConstraintsValue = mm.app.HBonds
 2061         RigidWaterValue = True
 2062     elif re.match("^AllBonds$", ParamValue, re.I):
 2063         ConstraintsValue = mm.app.AllBonds
 2064         RigidWaterValue = True
 2065     elif re.match("^AnglesInvolvingHydrogens$", ParamValue, re.I):
 2066         ConstraintsValue = mm.app.HAngles
 2067         RigidWaterValue = True
 2068     else:
 2069         MiscUtil.PrintError(
 2070             '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.'
 2071             % (ParamValue, ParamName, ParamsOptionName)
 2072         )
 2073 
 2074     ParamsInfo[ParamName] = ConstraintsValue
 2075 
 2076     ParamName = "RigidWater"
 2077     ParamValue = "%s" % ParamsInfo[ParamName]
 2078     if re.match("^auto$", ParamValue, re.I):
 2079         ParamsInfo[ParamName] = RigidWaterValue
 2080 
 2081 
 2082 def ProcessOptionOpenMMIntegratorParameters(
 2083     ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None, HydrogenMassRepartioningStatus=False
 2084 ):
 2085     """Process parameters for integrator option and return a map containing processed
 2086     parameter names and values.
 2087 
 2088     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 2089     to setup platform.
 2090 
 2091     The supported parameter names along with their default and possible
 2092     values are shown below:
 2093 
 2094         integrator, LangevinMiddle [ Possible values: LangevinMiddle,
 2095             Langevin, NoseHoover, Brownian ]
 2096 
 2097         randomSeed, auto [ Possible values: > 0 ]
 2098 
 2099         frictionCoefficient, 1.0 [ Units: 1/ps ]
 2100         stepSize, auto [ Units: fs; Default value: 4 fs during yes value of
 2101             hydrogen mass repartioning with no freezing/restraining of atoms;
 2102             otherwsie, 2 fs ]
 2103         temperature, 300.0 [ Units: kelvin ]
 2104 
 2105         barostat, MonteCarlo [ Possible values: MonteCarlo or
 2106             MonteCarloMembrane ]
 2107         barostatInterval, 25
 2108         pressure, 1.0 [ Units: atm ]
 2109 
 2110         Parameters used only for MonteCarloMembraneBarostat with default
 2111         values corresponding to Amber forcefields:
 2112 
 2113         surfaceTension, 0.0 [ Units: atm*A. It is automatically converted
 2114             into OpenMM default units of atm*nm before its usage.  ]
 2115         xymode,  Isotropic [ Possible values: Anisotropic or  Isotropic ]
 2116         zmode,  Free [ Possible values: Free or  Fixed ]
 2117 
 2118     A brief description of parameters is provided below:
 2119 
 2120     integrator: Type of integrator
 2121 
 2122     randomSeed: Random number seed for barostat and integrator. Not supported
 2123         NoseHoover integrator.
 2124 
 2125     frictionCoefficient: Friction coefficient for coupling the system to the heat
 2126     bath.
 2127 
 2128     stepSize: Simulation time step size.
 2129 
 2130     temperature: Simulation temperature.
 2131 
 2132     barostat: Barostat type.
 2133 
 2134     barostatInterval: Barostat interval step size, in terms of time step size,
 2135     for applying Monte Carlo pressure changes during NPT simulation.
 2136 
 2137     pressure: Pressure during NPT simulation.
 2138 
 2139     surfaceTension: Surface tension acting on the system.
 2140 
 2141     xymode: Behavior along X and Y axes. You may allow the X and Y axes
 2142     to vary independently of each other or always scale them by the same
 2143     amount to keep the ratio of their lengths constant.
 2144 
 2145     zmode: Beahvior along Z axis. You may allow the Z axis to vary
 2146     independently of the other axes or keep it fixed.
 2147 
 2148     Arguments:
 2149         ParamsOptionName (str): Command line OpenMM integrator option name.
 2150         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 2151         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 2152 
 2153     Returns:
 2154         dictionary: Processed parameter name and value pairs.
 2155 
 2156     """
 2157 
 2158     ParamsInfo = {
 2159         "Integrator": "LangevinMiddle",
 2160         "RandomSeed": "auto",
 2161         "FrictionCoefficient": 1.0,
 2162         "StepSize": "auto",
 2163         "Temperature": 300.0,
 2164         "Barostat": "MonteCarlo",
 2165         "BarostatInterval": 25,
 2166         "Pressure": 1.0,
 2167         "SurfaceTension": 0.0,
 2168         "XYMode": "Isotropic",
 2169         "ZMode": "Free",
 2170     }
 2171 
 2172     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 2173         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 2174     )
 2175 
 2176     if re.match("^auto$", ParamsOptionValue, re.I):
 2177         _ProcessOptionOpenMMIntegratorParameters(
 2178             ParamsInfo, ParamsOptionName, ParamsOptionValue, HydrogenMassRepartioningStatus
 2179         )
 2180         return ParamsInfo
 2181 
 2182     for Index in range(0, len(ParamsOptionValueWords), 2):
 2183         Name = ParamsOptionValueWords[Index].strip()
 2184         Value = ParamsOptionValueWords[Index + 1].strip()
 2185 
 2186         ParamName = CanonicalParamNamesMap[Name.lower()]
 2187         ParamValue = Value
 2188 
 2189         if re.match("^Integrator$", ParamName, re.I):
 2190             if not re.match("^(LangevinMiddle|Langevin|NoseHoover|Brownian)$", Value, re.I):
 2191                 MiscUtil.PrintError(
 2192                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: LangevinMiddle,Langevin, NoseHoover, or Brownian.'
 2193                     % (Value, Name, ParamsOptionName)
 2194                 )
 2195             ParamValue = Value
 2196         elif re.match("^(FrictionCoefficient|Pressure)$", ParamName, re.I):
 2197             if not MiscUtil.IsFloat(Value):
 2198                 MiscUtil.PrintError(
 2199                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 2200                     % (Value, ParamName, ParamsOptionName)
 2201                 )
 2202             Value = float(Value)
 2203             if Value <= 0:
 2204                 MiscUtil.PrintError(
 2205                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 2206                     % (ParamValue, ParamName, ParamsOptionName)
 2207                 )
 2208             ParamValue = Value
 2209         elif re.match("^StepSize$", ParamName, re.I):
 2210             if not re.match("^auto$", Value, re.I):
 2211                 if not MiscUtil.IsFloat(Value):
 2212                     MiscUtil.PrintError(
 2213                         'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 2214                         % (Value, ParamName, ParamsOptionName)
 2215                     )
 2216                 Value = float(Value)
 2217                 if Value <= 0:
 2218                     MiscUtil.PrintError(
 2219                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 2220                         % (ParamValue, ParamName, ParamsOptionName)
 2221                     )
 2222                 ParamValue = Value
 2223         elif re.match("^(Temperature|SurfaceTension)$", ParamName, re.I):
 2224             if not MiscUtil.IsFloat(Value):
 2225                 MiscUtil.PrintError(
 2226                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 2227                     % (Value, ParamName, ParamsOptionName)
 2228                 )
 2229             Value = float(Value)
 2230             if Value < 0:
 2231                 MiscUtil.PrintError(
 2232                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: >= 0\n'
 2233                     % (ParamValue, ParamName, ParamsOptionName)
 2234                 )
 2235             ParamValue = Value
 2236         elif re.match("^BarostatInterval$", ParamName, re.I):
 2237             if not MiscUtil.IsInteger(Value):
 2238                 MiscUtil.PrintError(
 2239                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be an integer.\n'
 2240                     % (Value, ParamName, ParamsOptionName)
 2241                 )
 2242             Value = int(Value)
 2243             if Value <= 0:
 2244                 MiscUtil.PrintError(
 2245                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 2246                     % (ParamValue, ParamName, ParamsOptionName)
 2247                 )
 2248             ParamValue = Value
 2249         elif re.match("^Barostat$", ParamName, re.I):
 2250             if not re.match("^(MonteCarlo|MonteCarloMembrane)$", Value, re.I):
 2251                 MiscUtil.PrintError(
 2252                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: MonteCarlo or MonteCarloMembrane'
 2253                     % (Value, Name, ParamsOptionName)
 2254                 )
 2255             ParamValue = Value
 2256         elif re.match("^XYMode$", ParamName, re.I):
 2257             if not re.match("^(Anisotropic|Isotropic)$", Value, re.I):
 2258                 MiscUtil.PrintError(
 2259                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: Anisotropic or  Isotropic'
 2260                     % (Value, Name, ParamsOptionName)
 2261                 )
 2262             ParamValue = Value
 2263         elif re.match("^ZMode$", ParamName, re.I):
 2264             if not re.match("^(Free|Fixed)$", Value, re.I):
 2265                 MiscUtil.PrintError(
 2266                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: Fixed or Free'
 2267                     % (Value, Name, ParamsOptionName)
 2268                 )
 2269             ParamValue = Value
 2270         elif re.match("^RandomSeed$", ParamName, re.I):
 2271             if not re.match("^auto$", Value, re.I):
 2272                 if not MiscUtil.IsInteger(Value):
 2273                     MiscUtil.PrintError(
 2274                         'The parameter value, %s, specified for parameter name, %s, using "%s" option must be an integer.\n'
 2275                         % (Value, ParamName, ParamsOptionName)
 2276                     )
 2277                 Value = int(Value)
 2278                 if Value <= 0:
 2279                     MiscUtil.PrintError(
 2280                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 2281                         % (ParamValue, ParamName, ParamsOptionName)
 2282                     )
 2283                 ParamValue = Value
 2284         else:
 2285             ParamValue = Value
 2286 
 2287         # Set value...
 2288         ParamsInfo[ParamName] = ParamValue
 2289 
 2290     # Handle parameters with possible auto values...
 2291     _ProcessOptionOpenMMIntegratorParameters(
 2292         ParamsInfo, ParamsOptionName, ParamsOptionValue, HydrogenMassRepartioningStatus
 2293     )
 2294 
 2295     return ParamsInfo
 2296 
 2297 
 2298 def _ProcessOptionOpenMMIntegratorParameters(
 2299     ParamsInfo, ParamsOptionName, ParamsOptionValue, HydrogenMassRepartioningStatus
 2300 ):
 2301     """Process parameters with possible auto values and perform validation."""
 2302 
 2303     ParamName = "StepSize"
 2304     ParamValue = "%s" % ParamsInfo[ParamName]
 2305     ParamsInfo["StepSizeSpecified"] = ParamValue
 2306     if re.match("^auto$", ParamValue, re.I):
 2307         ParamValue = 4.0 if HydrogenMassRepartioningStatus else 2.0
 2308         ParamsInfo[ParamName] = ParamValue
 2309 
 2310     ParamName = "RandomSeed"
 2311     ParamValue = "%s" % ParamsInfo[ParamName]
 2312     ParamsInfo["RandomSeedSpecified"] = ParamValue
 2313     if re.match("^auto$", ParamValue, re.I):
 2314         ParamsInfo[ParamName] = None
 2315 
 2316 
 2317 def ProcessOptionOpenMMSimulationParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
 2318     """Process parameters for simulation option and return a map containing processed
 2319     parameter names and values.
 2320 
 2321     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 2322     to setup platform.
 2323 
 2324     The supported parameter names along with their default and possible
 2325     values are shown below:
 2326 
 2327         steps, 1000000 [ Possible values: > 0 ]
 2328 
 2329         minimization, yes [ Possible values: yes or no ]
 2330         minimizationMaxSteps, auto  [ Possible values: >= 0. The value of
 2331             zero implies until the minimization is converged. ]
 2332         minimizationTolerance, 0.24  [ Units: kcal/mol/A. The default value
 2333             0.24, corresponds to OpenMM default of value of 10.04
 2334             kjoules/mol/nm. It is automatically converted into OpenMM
 2335             default units before its usage. ]
 2336 
 2337         equilibration, yes [ Possible values: yes or no ]
 2338         equilibrationSteps, 1000  [ Possible values: > 0 ]
 2339 
 2340     A brief description of parameters is provided below:
 2341 
 2342     steps: Number of steps for production run.
 2343 
 2344     equilibration: Perform equilibration before the production run.
 2345 
 2346     equilibrationSteps: Number of steps for equilibration.
 2347 
 2348     minimizationMaxSteps: Maximum number of minimization steps. The value
 2349     of zero implies until the minimization is converged.
 2350 
 2351     minimizationTolerance: Energy convergence tolerance during minimization.
 2352 
 2353     minimization: Perform minimization before equilibration and production run.
 2354 
 2355     Arguments:
 2356         ParamsOptionName (str): Command line OpenMM simulation option name.
 2357         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 2358         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 2359 
 2360     Returns:
 2361         dictionary: Processed parameter name and value pairs.
 2362 
 2363     """
 2364 
 2365     ParamsInfo = {
 2366         "Steps": 1000000,
 2367         "Minimization": True,
 2368         "MinimizationMaxSteps": "auto",
 2369         "MinimizationTolerance": 0.24,
 2370         "Equilibration": True,
 2371         "EquilibrationSteps": 1000,
 2372     }
 2373 
 2374     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 2375         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 2376     )
 2377 
 2378     if re.match("^auto$", ParamsOptionValue, re.I):
 2379         _ProcessOptionOpenMMSimulationParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2380         return ParamsInfo
 2381 
 2382     for Index in range(0, len(ParamsOptionValueWords), 2):
 2383         Name = ParamsOptionValueWords[Index].strip()
 2384         Value = ParamsOptionValueWords[Index + 1].strip()
 2385 
 2386         ParamName = CanonicalParamNamesMap[Name.lower()]
 2387         ParamValue = Value
 2388 
 2389         if re.match("^(Steps|EquilibrationSteps)$", ParamName, re.I):
 2390             if not MiscUtil.IsInteger(Value):
 2391                 MiscUtil.PrintError(
 2392                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be an integer.\n'
 2393                     % (Value, ParamName, ParamsOptionName)
 2394                 )
 2395             Value = int(Value)
 2396             if Value <= 0:
 2397                 MiscUtil.PrintError(
 2398                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 2399                     % (ParamValue, ParamName, ParamsOptionName)
 2400                 )
 2401             ParamValue = Value
 2402         elif re.match("^(Minimization|Equilibration)$", ParamName, re.I):
 2403             if not re.match("^(yes|no|true|false)$", Value, re.I):
 2404                 MiscUtil.PrintError(
 2405                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: yes or no'
 2406                     % (Value, Name, ParamsOptionName)
 2407                 )
 2408             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 2409         elif re.match("^MinimizationMaxSteps$", ParamName, re.I):
 2410             if not re.match("^auto$", Value, re.I):
 2411                 if not MiscUtil.IsInteger(Value):
 2412                     MiscUtil.PrintError(
 2413                         'The parameter value, %s, specified for parameter name, %s, using "%s" option must be an integer.\n'
 2414                         % (Value, ParamName, ParamsOptionName)
 2415                     )
 2416                 Value = int(Value)
 2417                 if Value < 0:
 2418                     MiscUtil.PrintError(
 2419                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: >= 0\n'
 2420                         % (ParamValue, ParamName, ParamsOptionName)
 2421                     )
 2422             ParamValue = Value
 2423         elif re.match("^MinimizationTolerance$", ParamName, re.I):
 2424             if not MiscUtil.IsFloat(Value):
 2425                 MiscUtil.PrintError(
 2426                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 2427                     % (Value, ParamName, ParamsOptionName)
 2428                 )
 2429             Value = float(Value)
 2430             if Value <= 0:
 2431                 MiscUtil.PrintError(
 2432                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 2433                     % (ParamValue, ParamName, ParamsOptionName)
 2434                 )
 2435             ParamValue = Value
 2436         else:
 2437             ParamValue = Value
 2438 
 2439         # Set value...
 2440         ParamsInfo[ParamName] = ParamValue
 2441 
 2442     # Handle parameters with possible auto values...
 2443     _ProcessOptionOpenMMSimulationParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 2444 
 2445     return ParamsInfo
 2446 
 2447 
 2448 def _ProcessOptionOpenMMSimulationParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 2449     """Process parameters with possible auto values and perform validation."""
 2450 
 2451     ParamName = "MinimizationMaxSteps"
 2452     ParamValue = "%s" % ParamsInfo[ParamName]
 2453     if re.match("^auto$", ParamValue, re.I):
 2454         ParamsInfo[ParamName] = 0
 2455 
 2456 
 2457 def ProcessOptionOpenMMOutputParameters(ParamsOptionName, ParamsOptionValue, OutfilePrefix, ParamsDefaultInfo=None):
 2458     """Process parameters for output option and return a map containing processed
 2459     parameter names and values.
 2460 
 2461     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 2462     to setup platform.
 2463 
 2464     The supported parameter names along with their default and possible
 2465     values are shown below:
 2466 
 2467         checkpoint, no  [ Possible values: yes or no ]
 2468         checkpointFile, auto  [ Default: <OutfilePrefix>.chk ]
 2469         checkpointSteps, 10000
 2470 
 2471         dataOutType, auto [ Possible values: A space delimited list of valid
 2472             parameter names.
 2473             NPT simulation default: Density Step Speed Progress
 2474                   PotentialEnergy Temperature Time.
 2475             NVT simulation default: Step Speed Progress PotentialEnergy
 2476                 Temperature Time Volumne
 2477             Other valid names: ElapsedTime RemainingTime KineticEnergy
 2478                 TotalEnergy  ]
 2479 
 2480         dataLog, yes  [ Possible values: yes or no ]
 2481         dataLogFile, auto  [ Default: <OutfilePrefix>.csv ]
 2482         dataLogSteps, 1000
 2483 
 2484         dataStdout, no  [ Possible values: yes or no ]
 2485         dataStdoutSteps, 1000
 2486 
 2487         dataOutTypePlot, yes  [ Possible values: yes or no ]
 2488         dataOutTypePlotX, auto  [ Default: Time; Possible values: Step or
 2489             Time ]
 2490         dataOutTypePlotY, auto  [ Possible values: A space delimited list
 2491             of valid parameter names specified for dataOutType.
 2492             NPT simulation default: Density PotentialEnergy Temperature
 2493             NVT simulation default: PotentialEnergy Temperature Volume
 2494             Other valid names: KineticEnergy TotalEnergy]
 2495 
 2496         minimizationDataSteps, 100
 2497         minimizationDataStdout, no  [ Possible values: yes or no ]
 2498         minimizationDataLog, no  [ Possible values: yes or no ]
 2499         minimizationDataLogFile, auto  [ Default:
 2500             <OutfilePrefix>_MinimizationOut.csv ]
 2501         minimizationDataOutType, auto [ Possible values: A space delimited
 2502             list of valid parameter names.  Default: SystemEnergy
 2503             RestraintEnergy MaxConstraintError.
 2504             Other valid names: RestraintStrength ]
 2505 
 2506         pdbOutFormat, PDB  [ Possible values: PDB or CIF ]
 2507         pdbOutKeepIDs, yes  [ Possible values: yes or no ]
 2508 
 2509         pdbOutMinimized, no  [ Possible values: yes or no ]
 2510         pdbOutEquilibrated, no  [ Possible values: yes or no ]
 2511         pdbOutFinal, no  [ Possible values: yes or no ]
 2512 
 2513         pdbOutPhase1HeatedNVT, no  [ Possible values: yes or no ]
 2514         pdbOutPhase2AnnealedNVT, no  [ Possible values: yes or no ]
 2515         pdbOutPhase3EquilibratedNVT, no  [ Possible values: yes or no ]
 2516         pdbOutPhase4EquilibratedNPT, no  [ Possible values: yes or no ]
 2517         pdbOutPhase5ProductionNPT, no  [ Possible values: yes or no ]
 2518 
 2519         saveFinalStateCheckpoint, yes  [ Possible values: yes or no ]
 2520         saveFinalStateCheckpointFile, auto  [ Default:
 2521             <OutfilePrefix>_FinalState.chk ]
 2522         saveFinalStateXML, no  [ Possible values: yes or no ]
 2523         saveFinalStateXMLFile, auto  [ Default:
 2524             <OutfilePrefix>_FinalState.xml]
 2525 
 2526         traj, yes  [ Possible values: yes or no ]
 2527         trajFile, auto  [ Default: <OutfilePrefix>.<TrajFormat> ]
 2528         trajFormat, DCD  [ Possible values: DCD or XTC ]
 2529         trajSteps, 10000
 2530 
 2531         xmlSystemOut, no  [ Possible values: yes or no ]
 2532         xmlSystemFile, auto  [ Default: <OutfilePrefix>_System.xml ]
 2533         xmlIntegratorOut, no  [ Possible values: yes or no ]
 2534         xmlIntegratorFile, auto  [ Default: <OutfilePrefix>_Integrator.xml ]
 2535 
 2536     A brief description of parameters is provided below:
 2537 
 2538         checkpoint: Write intermediate checkpoint file.
 2539         checkpointFile: Intermediate checkpoint file name.
 2540         checkpointSteps: Frequency of writing intermediate checkpoint file.
 2541 
 2542         dataOutType: Type of data to write to stdout and log file.
 2543 
 2544         dataLog: Write data to log file.
 2545         dataLogFile: Data log file name.
 2546         dataLogSteps: Frequency of writing data to log file.
 2547 
 2548         dataStdout: Write data to stdout.
 2549         dataStdoutSteps: Frequency of writing data to stdout.
 2550 
 2551         dataOutTypePlot: Generate plots using data written to log file.
 2552         dataOutTypePlotX: Data out type to plot on X axis.
 2553         dataOutTypePlotY: Data out types to plot on Y axis. An individual plot
 2554             is generated for each pair of X and Y vaues to be plotted.
 2555 
 2556         minimizationDataSteps: Frequency of writing data to stdout and log file.
 2557         minimizationDataStdout: Write data to stdout.
 2558         minimizationDataLog: Write data to log file.
 2559         minimizationDataLogFile: Data log fie name.
 2560         minimizationDataOutType: Type of data to write to stdout and log file.
 2561 
 2562         pdbOutFormat: Format of output PDB files.
 2563         pdbOutKeepIDs: Keep existing chain and residue IDs.
 2564 
 2565         pdbOutMinimized: Write PDB file after minimization.
 2566         pdbOutEquilibrated: Write PDB file after equilibration.
 2567         pdbOutFinal: Write final PDB file after production run.
 2568 
 2569         pdbOutPhase1HeatedNVT: Write out PDB file after initial heatin
 2570         pdbOutPhase2AnnealedNVT: Write out PDB file after heating and cooling.
 2571         pdbOutPhase3EquilibratedNVT: Write out PDB file after equilibration.
 2572         pdbOutPhase4EquilibratedNPT: Write out PDB file after equilibration.
 2573         pdbOutPhase5ProductionNPT: Write out PDB file after production run.
 2574 
 2575         saveFinalStateCheckpoint: Save final state checkpoint file.
 2576         saveFinalStateCheckpointFile: Name of final state checkpoint file.
 2577         saveFinalStateXML: Save final state XML file.
 2578         saveFinalStateXMLFile: Name of final state XML file.
 2579 
 2580         traj: Write out trajectory file.
 2581         trajFile: Trajectory file name.
 2582         trajFormat: Trajectory file format.
 2583         trajSteps: Frequency of writing trajectory file.
 2584 
 2585         xmlSystemOut: Write system XML file.
 2586         xmlSystemFile: System XML file name.
 2587         xmlIntegratorOut: Write integrator XML file.
 2588         xmlIntegratorFile: Integrator XML file name.
 2589 
 2590     Arguments:
 2591         ParamsOptionName (str): Command line OpenMM system option name.
 2592         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 2593         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 2594 
 2595     Returns:
 2596         dictionary: Processed parameter name and value pairs.
 2597 
 2598     """
 2599 
 2600     ParamsInfo = {
 2601         "Checkpoint": False,
 2602         "CheckpointFile": "auto",
 2603         "CheckpointSteps": 10000,
 2604         "DataOutType": "auto",
 2605         "DataLog": True,
 2606         "DataLogFile": "auto",
 2607         "DataLogSteps": 1000,
 2608         "DataStdout": False,
 2609         "DataStdoutSteps": 1000,
 2610         "DataOutTypePlot": True,
 2611         "DataOutTypePlotX": "auto",
 2612         "DataOutTypePlotY": "auto",
 2613         "MinimizationDataSteps": 100,
 2614         "MinimizationDataStdout": False,
 2615         "MinimizationDataLog": False,
 2616         "MinimizationDataLogFile": "auto",
 2617         "MinimizationDataOutType": "auto",
 2618         "PDBOutFormat": "PDB",
 2619         "PDBOutKeepIDs": True,
 2620         "PDBOutMinimized": False,
 2621         "PDBOutEquilibrated": False,
 2622         "PDBOutFinal": False,
 2623         "PDBOutPhase1HeatedNVT": False,
 2624         "PDBOutPhase2AnnealedNVT": False,
 2625         "PDBOutPhase3EquilibratedNVT": False,
 2626         "PDBOutPhase4EquilibratedNPT": False,
 2627         "PDBOutPhase5ProductionNPT": False,
 2628         "SaveFinalStateCheckpoint": True,
 2629         "SaveFinalStateCheckpointFile": "auto",
 2630         "SaveFinalStateXML": False,
 2631         "SaveFinalStateXMLFile": "auto",
 2632         "Traj": True,
 2633         "TrajFile": "auto",
 2634         "TrajFormat": "DCD",
 2635         "TrajSteps": 10000,
 2636         "XmlSystemOut": False,
 2637         "XmlSystemFile": "auto",
 2638         "XmlIntegratorOut": False,
 2639         "XmlIntegratorFile": "auto",
 2640     }
 2641 
 2642     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 2643         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 2644     )
 2645 
 2646     if re.match("^auto$", ParamsOptionValue, re.I):
 2647         _ProcessOptionOpenMMOutputParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 2648         return ParamsInfo
 2649 
 2650     for Index in range(0, len(ParamsOptionValueWords), 2):
 2651         Name = ParamsOptionValueWords[Index].strip()
 2652         Value = ParamsOptionValueWords[Index + 1].strip()
 2653 
 2654         ParamName = CanonicalParamNamesMap[Name.lower()]
 2655         ParamValue = Value
 2656 
 2657         if re.match(
 2658             "^(Checkpoint|DataLog|DataStdout|DataOutTypePlot|MinimizationDataStdout|MinimizationDataLog|PDBOutKeepIDs|SaveFinalStateCheckpoint|SaveFinalStateXML|Traj|XmlSystemOut|XmlIntegratorOut|PDBOutMinimized|PDBOutEquilibrated|PDBOutFinal|PDBOutPhase1HeatedNVT|PDBOutPhase2AnnealedNVT|PDBOutPhase3EquilibratedNVT|PDBOutPhase4EquilibratedNPT|PDBOutPhase5ProductionNPT)$",
 2659             ParamName,
 2660             re.I,
 2661         ):
 2662             if not re.match("^(yes|no|true|false)$", Value, re.I):
 2663                 MiscUtil.PrintError(
 2664                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: yes or no'
 2665                     % (Value, Name, ParamsOptionName)
 2666                 )
 2667             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 2668         elif re.match("^(CheckpointFile|SaveFinalStateCheckpointFile)$", ParamName, re.I):
 2669             if not re.match("^auto$", Value, re.I):
 2670                 if not MiscUtil.CheckFileExt(Value, "chk"):
 2671                     MiscUtil.PrintError(
 2672                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported file format: chk'
 2673                         % (Value, Name, ParamsOptionName)
 2674                     )
 2675                 ParamValue = Value
 2676         elif re.match("^(DataLogFile|MinimizationDataLogFile)$", ParamName, re.I):
 2677             if not re.match("^auto$", Value, re.I):
 2678                 if not MiscUtil.CheckFileExt(Value, "csv"):
 2679                     MiscUtil.PrintError(
 2680                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported file formats: csv'
 2681                         % (Value, Name, ParamsOptionName)
 2682                     )
 2683                 ParamValue = Value
 2684         elif re.match("^(SaveFinalStateXMLFile|XmlSystemFile|XmlIntegratorFile)$", ParamName, re.I):
 2685             if not re.match("^auto$", Value, re.I):
 2686                 if not MiscUtil.CheckFileExt(Value, "xml"):
 2687                     MiscUtil.PrintError(
 2688                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported file format: xml'
 2689                         % (Value, Name, ParamsOptionName)
 2690                     )
 2691                 ParamValue = Value
 2692         elif re.match("^TrajFile$", ParamName, re.I):
 2693             if not re.match("^auto$", Value, re.I):
 2694                 if not MiscUtil.CheckFileExt(Value, "dcd xtc"):
 2695                     MiscUtil.PrintError(
 2696                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported file formats: dcd xtc'
 2697                         % (Value, Name, ParamsOptionName)
 2698                     )
 2699                 ParamValue = Value
 2700         elif re.match(
 2701             "^(CheckpointSteps|DataLogSteps|DataStdoutSteps|MinimizationDataSteps|TrajSteps)$", ParamName, re.I
 2702         ):
 2703             if not MiscUtil.IsInteger(Value):
 2704                 MiscUtil.PrintError(
 2705                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be an integer.\n'
 2706                     % (Value, ParamName, ParamsOptionName)
 2707                 )
 2708             Value = int(Value)
 2709             if Value <= 0:
 2710                 MiscUtil.PrintError(
 2711                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 2712                     % (ParamValue, ParamName, ParamsOptionName)
 2713                 )
 2714             ParamValue = Value
 2715         elif re.match("^DataOutType$", ParamName, re.I):
 2716             if not re.match("^auto$", Value, re.I):
 2717                 ValueTypes = Value.split()
 2718                 if len(ValueTypes) == 0:
 2719                     MiscUtil.PrintError(
 2720                         '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'
 2721                         % (Value, ParamName, ParamsOptionName)
 2722                     )
 2723                 ValueTypesSpecified = []
 2724                 for ValueType in ValueTypes:
 2725                     if not re.match(
 2726                         "^(Step|Speed|Progress|PotentialEnergy|Temperature|ElapsedTime|RemainingTime|Time|KineticEnergy|TotalEnergy|Volume|Density)$",
 2727                         ValueType,
 2728                         re.I,
 2729                     ):
 2730                         MiscUtil.PrintError(
 2731                             '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'
 2732                             % (ValueType, Name, ParamsOptionName)
 2733                         )
 2734                     if ValueType in ValueTypesSpecified:
 2735                         MiscUtil.PrintError(
 2736                             'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. It has already been specified.'
 2737                             % (ValueType, Name, ParamsOptionName)
 2738                         )
 2739                     ValueTypesSpecified.append(ValueType)
 2740                 ParamsInfo["DataOutTypeList"] = ValueTypes
 2741         elif re.match("^DataOutTypePlotX$", ParamName, re.I):
 2742             if not re.match("^auto$", Value, re.I):
 2743                 if not re.match("^(Step|Time)$", Value, re.I):
 2744                     MiscUtil.PrintError(
 2745                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: Step or Time'
 2746                         % (Value, Name, ParamsOptionName)
 2747                     )
 2748                 ParamValue = Value
 2749         elif re.match("^DataOutTypePlotY$", ParamName, re.I):
 2750             if not re.match("^auto$", Value, re.I):
 2751                 ValueTypes = Value.split()
 2752                 if len(ValueTypes) == 0:
 2753                     MiscUtil.PrintError(
 2754                         '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'
 2755                         % (Value, ParamName, ParamsOptionName)
 2756                     )
 2757                 ValueTypesSpecified = []
 2758                 for ValueType in ValueTypes:
 2759                     if not re.match(
 2760                         "^(PotentialEnergy|Temperature|KineticEnergy|TotalEnergy|Volume|Density)$", ValueType, re.I
 2761                     ):
 2762                         MiscUtil.PrintError(
 2763                             'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: PotentialEnergy, Temperature, KineticEnergy, TotalEnergy, Volume, or Density'
 2764                             % (ValueType, Name, ParamsOptionName)
 2765                         )
 2766                     if ValueType in ValueTypesSpecified:
 2767                         MiscUtil.PrintError(
 2768                             'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. It has already been specified.'
 2769                             % (ValueType, Name, ParamsOptionName)
 2770                         )
 2771                     ValueTypesSpecified.append(ValueType)
 2772                 ParamsInfo["DataOutTypePlotXList"] = ValueTypes
 2773         elif re.match("^MinimizationDataOutType$", ParamName, re.I):
 2774             if not re.match("^auto$", Value, re.I):
 2775                 ValueTypes = Value.split()
 2776                 if len(ValueTypes) == 0:
 2777                     MiscUtil.PrintError(
 2778                         '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'
 2779                         % (Value, ParamName, ParamsOptionName)
 2780                     )
 2781                 ValueTypesSpecified = []
 2782                 for ValueType in ValueTypes:
 2783                     if not re.match(
 2784                         "^(SystemEnergy|RestraintEnergy|RestraintStrength|MaxConstraintError)$", ValueType, re.I
 2785                     ):
 2786                         MiscUtil.PrintError(
 2787                             'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: SystemEnergy, RestraintEnergy, RestraintStrength, or MaxConstraintError'
 2788                             % (ValueType, Name, ParamsOptionName)
 2789                         )
 2790                     if ValueType in ValueTypesSpecified:
 2791                         MiscUtil.PrintError(
 2792                             'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. It has already been specified.'
 2793                             % (ValueType, Name, ParamsOptionName)
 2794                         )
 2795                     ValueTypesSpecified.append(ValueType)
 2796                 ParamsInfo["MinimizationDataOutTypeList"] = ValueTypes
 2797         elif re.match("^PDBOutFormat$", ParamName, re.I):
 2798             if not re.match("^(PDB|CIF)$", Value, re.I):
 2799                 MiscUtil.PrintError(
 2800                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: PDB or CIF'
 2801                     % (Value, Name, ParamsOptionName)
 2802                 )
 2803             ParamValue = Value
 2804         elif re.match("^TrajFormat$", ParamName, re.I):
 2805             if not re.match("^(DCD|XTC)$", Value, re.I):
 2806                 MiscUtil.PrintError(
 2807                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: DCD or XTC'
 2808                     % (Value, Name, ParamsOptionName)
 2809                 )
 2810             ParamValue = Value
 2811         else:
 2812             ParamValue = Value
 2813 
 2814         # Set value...
 2815         ParamsInfo[ParamName] = ParamValue
 2816 
 2817     # Handle parameters with possible auto values...
 2818     _ProcessOptionOpenMMOutputParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 2819 
 2820     return ParamsInfo
 2821 
 2822 
 2823 def _ProcessOptionOpenMMOutputParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 2824     """Process parameters with possible auto values and perform validation."""
 2825 
 2826     # Use comma as a delimiter...
 2827     ParamsInfo["DataOutDelimiter"] = ","
 2828     ParamsInfo["DataOutfileExt"] = "csv"
 2829 
 2830     ParamName = "TrajFormat"
 2831     ParamValue = ParamsInfo[ParamName]
 2832     if re.match("^DCD$", ParamValue, re.I):
 2833         TrajFileExt = "dcd"
 2834     elif re.match("^XTC$", ParamValue, re.I):
 2835         TrajFileExt = "xtc"
 2836     else:
 2837         MiscUtil.PrintError(
 2838             'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: DCD or XTC'
 2839             % (ParamValue, ParamName, ParamsOptionName)
 2840         )
 2841     ParamsInfo["TrajFileExt"] = TrajFileExt
 2842 
 2843     ParamName = "PDBOutFormat"
 2844     ParamValue = ParamsInfo[ParamName]
 2845     if re.match("^PDB$", ParamValue, re.I):
 2846         PDBOutfileExt = "pdb"
 2847     elif re.match("^CIF$", ParamValue, re.I):
 2848         PDBOutfileExt = "cif"
 2849     else:
 2850         MiscUtil.PrintError(
 2851             'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: PDB or CIF'
 2852             % (ParamValue, ParamName, ParamsOptionName)
 2853         )
 2854     ParamsInfo["PDBOutfileExt"] = PDBOutfileExt
 2855 
 2856     _ProcessFileNamesOutputPatramaters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 2857     _ProcessDataOutTypeOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 2858     _ProcessMinimizationDataOutTypeOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 2859     _ProcessDataOutTypePlotOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix)
 2860 
 2861 
 2862 def _ProcessFileNamesOutputPatramaters(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 2863     """Process output parameters corresponding to file names."""
 2864 
 2865     OutfileExt = ParamsInfo["DataOutfileExt"]
 2866     TrajFileExt = ParamsInfo["TrajFileExt"]
 2867     OutfilesSuffixAndExtMap = {
 2868         "CheckpointFile": ["", "chk"],
 2869         "DataLogFile": ["", OutfileExt],
 2870         "MinimizationDataLogFile": ["Minimization", OutfileExt],
 2871         "SaveFinalStateCheckpointFile": ["FinalState", "chk"],
 2872         "SaveFinalStateXMLFile": ["FinalState", "xml"],
 2873         "TrajFile": ["", TrajFileExt],
 2874         "XmlSystemFile": ["System", "xml"],
 2875         "XmlIntegratorFile": ["Integrator", "xml"],
 2876     }
 2877     OutfileNames = []
 2878     for ParamName in OutfilesSuffixAndExtMap:
 2879         ParamValue = ParamsInfo[ParamName]
 2880         if re.match("^auto$", ParamValue, re.I):
 2881             DataOutfileSuffix, DataOutfileExt = OutfilesSuffixAndExtMap[ParamName]
 2882             if len(DataOutfileSuffix):
 2883                 DataOutfileSuffix = "_%s" % DataOutfileSuffix
 2884             ParamValue = "%s%s.%s" % (OutfilePrefix, DataOutfileSuffix, DataOutfileExt)
 2885             ParamsInfo[ParamName] = ParamValue
 2886         else:
 2887             # Check for duplicate output file names...
 2888             if ParamValue not in OutfileNames:
 2889                 OutfileNames.append(ParamValue)
 2890             else:
 2891                 MiscUtil.PrintError(
 2892                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. It\'s a duplicate file name.'
 2893                     % (ParamValue, ParamName, ParamsOptionName)
 2894                 )
 2895 
 2896             # Validate specified traj file extension...
 2897             if re.match("^TrajFile$", ParamName, re.I):
 2898                 TrajFormat = ParamsInfo["TrajFormat"]
 2899                 if not MiscUtil.CheckFileExt(ParamValue, TrajFileExt):
 2900                     MiscUtil.PrintError(
 2901                         '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.'
 2902                         % (ParamValue, ParamName, ParamsOptionName, TrajFileExt, TrajFormat)
 2903                     )
 2904 
 2905 
 2906 def _ProcessDataOutTypeOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 2907     """Process output parameter corresponding to data out type."""
 2908 
 2909     # Setup data out types...
 2910     DataOutTypeStatusMap = {
 2911         "Step": False,
 2912         "Speed": False,
 2913         "Progress": False,
 2914         "PotentialEnergy": False,
 2915         "Temperature": False,
 2916         "ElapsedTime": False,
 2917         "RemainingTime": False,
 2918         "Time": False,
 2919         "KineticEnergy": False,
 2920         "TotalEnergy": False,
 2921         "Volume": False,
 2922         "Density": False,
 2923     }
 2924     CanonicalDataOutTypeMap = {}
 2925     ValidDataOutTypes = []
 2926     for DataOutType in DataOutTypeStatusMap:
 2927         ValidDataOutTypes.append(DataOutType)
 2928         CanonicalDataOutTypeMap[DataOutType.lower()] = DataOutType
 2929 
 2930     # Process data out types...
 2931     ParamName = "DataOutType"
 2932     ParamValue = ParamsInfo[ParamName]
 2933     DataOutTypeList = []
 2934     if re.match("^auto$", ParamValue, re.I):
 2935         DataOutTypeList = ["Step", "Speed", "Progress", "PotentialEnergy", "Temperature", "Time"]
 2936     else:
 2937         if "DataOutTypeList" in ParamsInfo:
 2938             DataOutTypeList = ParamsInfo["DataOutTypeList"]
 2939         else:
 2940             DataOutTypeList = ParamsInfo["DataOutType"].split()
 2941             ParamsInfo["DataOutTypeList"] = DataOutTypeList
 2942 
 2943     for DataOutType in DataOutTypeList:
 2944         CanonicalDataOutType = DataOutType.lower()
 2945         if CanonicalDataOutType not in CanonicalDataOutTypeMap:
 2946             MiscUtil.PrintError(
 2947                 'The parameter value, %s specified for paramaer name, %s, using "%s" is not a valid name. Supported parameter names: %s'
 2948                 % (DataOutType, ParamName, ParamsOptionName, " ".join(ValidDataOutTypes))
 2949             )
 2950 
 2951         DataOutType = CanonicalDataOutTypeMap[CanonicalDataOutType]
 2952         DataOutTypeStatusMap[DataOutType] = True
 2953 
 2954     ParamsInfo["DataOutTypeList"] = DataOutTypeList
 2955     ParamsInfo["DataOutTypeStatusMap"] = DataOutTypeStatusMap
 2956 
 2957 
 2958 def _ProcessDataOutTypePlotOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 2959     """Process output parameter corresponding to plot data out type."""
 2960 
 2961     # Setup specified data out types...
 2962     DataOutTypes = ParamsInfo["DataOutTypeList"]
 2963     CanonicalDataOutTypeMap = {}
 2964     for DataOutType in DataOutTypes:
 2965         CanonicalDataOutTypeMap[DataOutType.lower()] = DataOutType
 2966 
 2967     # Process data out type plot X value...
 2968     ParamName = "DataOutTypePlotX"
 2969     ParamValue = ParamsInfo[ParamName]
 2970     if re.match("^auto$", ParamValue, re.I):
 2971         ParamValue = "Time"
 2972     if ParamValue.lower() not in CanonicalDataOutTypeMap:
 2973         MiscUtil.PrintError(
 2974             'The specified or auto assigned parameter value, %s for paramaer name, %s, using "%s" is not a valid. It must be present in the list of values specified for parameter name, dataOutType, using "--dataOutType"option.'
 2975             % (ParamValue, ParamName, ParamsOptionName)
 2976         )
 2977 
 2978     ParamsInfo[ParamName] = CanonicalDataOutTypeMap[ParamValue.lower()]
 2979 
 2980     # Process data out type plot Y values...
 2981     ParamName = "DataOutTypePlotY"
 2982     ParamValue = ParamsInfo[ParamName]
 2983     DataOutTypePlotYList = []
 2984     if re.match("^auto$", ParamValue, re.I):
 2985         DataOutTypePlotYList = ["PotentialEnergy", "Temperature"]
 2986     else:
 2987         if "DataOutTypePlotYList" in ParamsInfo:
 2988             DataOutTypePlotYList = ParamsInfo["DataOutTypePlotYList"]
 2989         else:
 2990             DataOutTypePlotYList = ParamsInfo["DataOutTypePlotY"].split()
 2991             ParamsInfo["DataOutTypePlotYList"] = DataOutTypePlotYList
 2992 
 2993     CanonicalDataOutTypePlotYList = []
 2994     for DataOutTypePlotY in DataOutTypePlotYList:
 2995         CanonicalDataOutTypePlotY = DataOutTypePlotY.lower()
 2996         if CanonicalDataOutTypePlotY not in CanonicalDataOutTypeMap:
 2997             MiscUtil.PrintError(
 2998                 'The specified or auto assigned parameter value, %s for paramaer name, %s, using "%s" is not a valid. It must be present in the list of values specified for parameter name, dataOutType, using "--dataOutType"option.'
 2999                 % (DataOutTypePlotY, ParamName, ParamsOptionName)
 3000             )
 3001         CanonicalDataOutTypePlotYList.append(CanonicalDataOutTypeMap[CanonicalDataOutTypePlotY])
 3002 
 3003     ParamsInfo["DataOutTypePlotYList"] = CanonicalDataOutTypePlotYList
 3004 
 3005 
 3006 def _ProcessMinimizationDataOutTypeOutputParameter(ParamsInfo, ParamsOptionName, ParamsOptionValue, OutfilePrefix):
 3007     """Process output parameter corresponding to minimization data out type."""
 3008 
 3009     # Setup mimimization data out types...
 3010     DataOutTypeOpenMMNameMap = {
 3011         "SystemEnergy": "system energy",
 3012         "RestraintEnergy": "restraint energy",
 3013         "RestraintStrength": "restraint strength",
 3014         "MaxConstraintError": "max constraint error",
 3015     }
 3016 
 3017     CanonicalDataOutTypeMap = {}
 3018     ValidDataOutTypes = []
 3019     for DataOutType in DataOutTypeOpenMMNameMap:
 3020         ValidDataOutTypes.append(DataOutType)
 3021         CanonicalDataOutTypeMap[DataOutType.lower()] = DataOutType
 3022 
 3023     # Process minimization data out types...
 3024     ParamName = "MinimizationDataOutType"
 3025     ParamValue = ParamsInfo[ParamName]
 3026     DataOutTypeList = []
 3027     if re.match("^auto$", ParamValue, re.I):
 3028         DataOutTypeList = ["SystemEnergy", "RestraintEnergy", "MaxConstraintError"]
 3029     else:
 3030         if "MinimizationDataOutTypeList" in ParamsInfo:
 3031             DataOutTypeList = ParamsInfo["MinimizationDataOutTypeList"]
 3032         else:
 3033             DataOutTypeList = ParamsInfo["MinimizationDataOutType"].split()
 3034             ParamsInfo["MinimizationDataOutTypeList"] = DataOutTypeList
 3035 
 3036     # Set up a list containing OpenMM names for minimization reporter...
 3037     DataOutTypeOpenMMNameList = []
 3038     for DataOutType in DataOutTypeList:
 3039         CanonicalDataOutType = DataOutType.lower()
 3040         if CanonicalDataOutType not in CanonicalDataOutTypeMap:
 3041             MiscUtil.PrintError(
 3042                 'The parameter value, %s specified for paramaer name, %s, specified using "%s" is not a valid name. Supported parameter names: %s'
 3043                 % (DataOutType, ParamName, ParamsOptionName, " ".join(ValidDataOutTypes))
 3044             )
 3045 
 3046         DataOutType = CanonicalDataOutTypeMap[CanonicalDataOutType]
 3047 
 3048         DataOutTypeOpenMMName = DataOutTypeOpenMMNameMap[DataOutType]
 3049         DataOutTypeOpenMMNameList.append(DataOutTypeOpenMMName)
 3050 
 3051     ParamsInfo["MinimizationDataOutTypeList"] = DataOutTypeList
 3052     ParamsInfo["MinimizationDataOutTypeOpenMMNameList"] = DataOutTypeOpenMMNameList
 3053 
 3054 
 3055 def ProcessOptionOpenMMAtomsSelectionParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
 3056     """Process parameters for selecting atoms and return a map containing
 3057     processed parameter names and values.
 3058 
 3059     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 3060     to select atoms.
 3061 
 3062     The supported parameter names along with their default and possible
 3063     values are shown below:
 3064 
 3065         selection, none [ Possible values: CAlphaProtein, Ions, Ligand,
 3066             Protein, Residues, or Water ]
 3067         selectionSpec, auto [ Possible values: A space delimited list of
 3068             residue names ]
 3069         negate, no [ Possible values: yes or no ]
 3070 
 3071     A brief description of parameters is provided below:
 3072 
 3073     selection: Atom selection to freeze.
 3074 
 3075     selectionSpec: A space delimited list of residue names for selecting atoms.
 3076     You must specify its value during 'Ligand' and 'Protein' value for 'selection'.
 3077     The default values are automatically set for 'CAlphaProtein', 'Ions', 'Protein',
 3078     and 'Water' values of 'selection' as shown below:
 3079 
 3080         CAlphaProtein: List of stadard protein residues from pdbfixer
 3081             for selecting CAlpha atoms.
 3082         Ions: Li Na K Rb Cs Cl Br F I
 3083         Water: HOH
 3084         Protein: List of standard protein residues from pdbfixer.
 3085 
 3086     negate: Negate atom selection match to select atoms for freezing.
 3087 
 3088     In addition, you may specify an explicit space delimited list of residue
 3089     names using 'selectionSpec' for any 'selection". The specified residue
 3090     names are appended to the appropriate default values during the
 3091     selection of atoms for freezing.
 3092 
 3093     Arguments:
 3094         ParamsOptionName (str): Command line OpenMM selection option name.
 3095         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 3096         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 3097 
 3098     Returns:
 3099         dictionary: Processed parameter name and value pairs.
 3100 
 3101     """
 3102 
 3103     ParamsInfo = {"Selection": None, "SelectionSpec": "auto", "Negate": False}
 3104 
 3105     if ParamsOptionValue is None:
 3106         return ParamsInfo
 3107 
 3108     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 3109         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 3110     )
 3111 
 3112     if re.match("^auto$", ParamsOptionValue, re.I):
 3113         _ProcessOptionOpenMMAtomsSelectionParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3114         return ParamsInfo
 3115 
 3116     for Index in range(0, len(ParamsOptionValueWords), 2):
 3117         Name = ParamsOptionValueWords[Index].strip()
 3118         Value = ParamsOptionValueWords[Index + 1].strip()
 3119 
 3120         ParamName = CanonicalParamNamesMap[Name.lower()]
 3121         ParamValue = Value
 3122 
 3123         # Set value...
 3124         ParamsInfo[ParamName] = ParamValue
 3125         if re.match("^Selection$", ParamName, re.I):
 3126             if not re.match("^(CAlphaProtein|Ions|Ligand|Protein|Residues|Water)$", Value, re.I):
 3127                 MiscUtil.PrintError(
 3128                     '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'
 3129                     % (Value, Name, ParamsOptionName)
 3130                 )
 3131             ParamValue = Value
 3132         elif re.match("^SelectionSpec$", ParamName, re.I):
 3133             if not re.match("^(auto|none)$", Value, re.I):
 3134                 Values = Value.split()
 3135                 if len(Values) == 0:
 3136                     MiscUtil.PrintError(
 3137                         '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'
 3138                         % (Value, ParamName, ParamsOptionName)
 3139                     )
 3140                 # Set residues list...
 3141                 ParamsInfo["SelectionSpecList"] = Values
 3142         elif re.match("^Negate$", ParamName, re.I):
 3143             if not re.match("^(yes|no|true|false)$", Value, re.I):
 3144                 MiscUtil.PrintError(
 3145                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: yes or no'
 3146                     % (Value, Name, ParamsOptionName)
 3147                 )
 3148             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 3149         else:
 3150             ParamValue = Value
 3151 
 3152         # Set value...
 3153         ParamsInfo[ParamName] = ParamValue
 3154 
 3155     # Handle parameters with possible auto values...
 3156     _ProcessOptionOpenMMAtomsSelectionParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3157 
 3158     return ParamsInfo
 3159 
 3160 
 3161 def _ProcessOptionOpenMMAtomsSelectionParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 3162     """Process parameters with possible auto values and perform validation."""
 3163 
 3164     SelectionParamName = "Selection"
 3165     SelectionParamValue = ParamsInfo[SelectionParamName]
 3166 
 3167     SelectionSpecParamName = "SelectionSpec"
 3168     SelectionSpecParamValue = ParamsInfo[SelectionSpecParamName]
 3169 
 3170     SelectionSpecList = (
 3171         None if re.match("^(auto|none)$", SelectionSpecParamValue, re.I) else ParamsInfo["SelectionSpecList"]
 3172     )
 3173 
 3174     ResidueNames = None
 3175     if re.match("^(CAlphaProtein|Protein)$", SelectionParamValue, re.I):
 3176         ResidueNames = pdbfixer.pdbfixer.proteinResidues
 3177         if SelectionSpecList is not None:
 3178             ResidueNames.extend(SelectionSpecList)
 3179     elif re.match("^Ions$", SelectionParamValue, re.I):
 3180         ResidueNames = ["Li", "Na", "K", "Rb", "Cs", "Cl", "Br", "F", "I"]
 3181         if SelectionSpecList is not None:
 3182             ResidueNames.extend(SelectionSpecList)
 3183     elif re.match("^Ligand$", SelectionParamValue, re.I):
 3184         if SelectionSpecList is None:
 3185             MiscUtil.PrintError(
 3186                 'No value specified for parameter name, %s, using "%s" option is not a valid value. It must contain a ligand residue name.\n'
 3187                 % (SelectionSpecParamName, ParamsOptionName)
 3188             )
 3189         elif len(SelectionSpecList) != 1:
 3190             MiscUtil.PrintError(
 3191                 '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'
 3192                 % (SelectionSpecParamValue, SelectionSpecParamName, ParamsOptionName)
 3193             )
 3194         ResidueNames = SelectionSpecList
 3195     elif re.match("^Residues$", SelectionParamValue, re.I):
 3196         if SelectionSpecList is None:
 3197             MiscUtil.PrintError(
 3198                 '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'
 3199                 % (SelectionSpecParamValue, SelectionSpecParamName, ParamsOptionName)
 3200             )
 3201         ResidueNames = SelectionSpecList
 3202     elif re.match("^Water$", SelectionParamValue, re.I):
 3203         ResidueNames = ["HOH"]
 3204         if SelectionSpecList is not None:
 3205             ResidueNames.extend(SelectionSpecList)
 3206 
 3207     ParamsInfo["ResidueNames"] = [ResidueName.upper() for ResidueName in ResidueNames]
 3208     ParamsInfo["CAlphaProteinStatus"] = True if re.match("^CAlphaProtein$", SelectionParamValue, re.I) else False
 3209 
 3210 
 3211 def ProcessOptionOpenMMForcefieldParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
 3212     """Process parameters for biopolymer, small molecule, and water forcefields and
 3213     return a map containing processed parameter names and values.
 3214 
 3215     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 3216     for forcefields.
 3217 
 3218     The supported parameter names along with their default and possible
 3219     values are shown below:
 3220 
 3221         biopolymer, amber14-all.xml  [ Possible values: Any Valid value ]
 3222         smallMolecule, OpenFF_2.2.0  [ Possible values: Any Valid value ]
 3223         water, auto  [ Possible values: Any Valid value ]
 3224 
 3225     Possible biopolymer forcefield values:
 3226 
 3227         amber14-all.xml, amber99sb.xml, amber99sbildn.xml, amber03.xml,
 3228         amber10.xml
 3229         charmm36.xml, charmm_polar_2019.xml
 3230         amoeba2018.xml
 3231 
 3232     Possible small molecule forcefield values:
 3233 
 3234         openff_2.2.0, openff_2.0.0, openff_1.3.1, openff_1.2.1, openff_1.1.1,
 3235         smirnoff99frosst
 3236         gaff-2.11, gaff-2.1, gaff-1.81, gaff-1.8, gaff-1.4
 3237 
 3238     The default water forcefield valus is dependent on the type of the
 3239     biopolymer forcefield as shown below:
 3240 
 3241         Amber: amber14/tip3pfb.xml
 3242         CHARMM: charmm36/water.xml or None for charmm_polar_2019.xml
 3243         Amoeba: None (Explicit)
 3244 
 3245     Possible water forcefield values:
 3246 
 3247       amber14/tip3p.xml, amber14/tip3pfb.xml, amber14/spce.xml,
 3248       amber14/tip4pew.xml, amber14/tip4pfb.xml,
 3249       implicit/obc2.xml, implicit/GBn.xml, implicit/GBn2.xml
 3250       charmm36/water.xml, charmm36/tip3p-pme-b.xml,
 3251       charmm36/tip3p-pme-f.xml, charmm36/spce.xml,
 3252       charmm36/tip4pew.xml, charmm36/tip4p2005.xml,
 3253       charmm36/tip5p.xml, charmm36/tip5pew.xml,
 3254       implicit/obc2.xml, implicit/GBn.xml, implicit/GBn2.xml
 3255       amoeba2018_gk.xml (Implict water), None (Explicit water for amoeba)
 3256 
 3257     You may specify any valid forcefield name supported by OpenMM. No
 3258     explicit validation is performed.
 3259 
 3260     Arguments:
 3261         ParamsOptionName (str): Command line OpenMM forcefield option name.
 3262         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 3263         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 3264 
 3265     Returns:
 3266         dictionary: Processed parameter name and value pairs.
 3267 
 3268     """
 3269 
 3270     ParamsInfo = {
 3271         "Biopolymer": "amber14-all.xml",
 3272         "SmallMolecule": "openff-2.2.1",
 3273         "Water": "auto",
 3274         "Additional": "None",
 3275     }
 3276 
 3277     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 3278         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 3279     )
 3280 
 3281     if re.match("^auto$", ParamsOptionValue, re.I):
 3282         _ProcessOptionOpenMMForcefieldParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3283         return ParamsInfo
 3284 
 3285     for Index in range(0, len(ParamsOptionValueWords), 2):
 3286         Name = ParamsOptionValueWords[Index].strip()
 3287         Value = ParamsOptionValueWords[Index + 1].strip()
 3288 
 3289         ParamName = CanonicalParamNamesMap[Name.lower()]
 3290         ParamValue = Value
 3291 
 3292         # Set value...
 3293         ParamsInfo[ParamName] = ParamValue
 3294 
 3295     # Handle parameters with possible auto values...
 3296     _ProcessOptionOpenMMForcefieldParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3297 
 3298     return ParamsInfo
 3299 
 3300 
 3301 def _ProcessOptionOpenMMForcefieldParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 3302     """Process parameters with possible auto values and perform validation."""
 3303     WaterForcefield = ParamsInfo["Water"]
 3304     if re.match("^None$", WaterForcefield, re.I):
 3305         WaterForcefield = None
 3306         ParamsInfo["Water"] = WaterForcefield
 3307     elif re.match("^auto$", WaterForcefield, re.I):
 3308         BiopolymerForcefield = ParamsInfo["Biopolymer"]
 3309         if re.search("amber", BiopolymerForcefield, re.I):
 3310             WaterForcefield = "amber14/tip3pfb.xml"
 3311         elif re.search("charmm", BiopolymerForcefield, re.I):
 3312             if re.search("charmm_polar_2019", BiopolymerForcefield, re.I):
 3313                 WaterForcefield = None
 3314             else:
 3315                 WaterForcefield = "charmm36/water.xml"
 3316         elif re.search("amoeba", BiopolymerForcefield, re.I):
 3317             # Explicit water...
 3318             WaterForcefield = None
 3319         else:
 3320             WaterForcefield = None
 3321         ParamsInfo["Water"] = WaterForcefield
 3322 
 3323     # Set status of implicit water forcefield...
 3324     BiopolymerForcefield = ParamsInfo["Biopolymer"]
 3325     ParamsInfo["ImplicitWater"] = True if _IsImplicitWaterForcefield(BiopolymerForcefield, WaterForcefield) else False
 3326 
 3327     # Process additional forcefields...
 3328     ParamName = "Additional"
 3329     ParamValue = ParamsInfo[ParamName]
 3330     ParamValuesList = None
 3331     if not re.match("^None$", ParamValue, re.I):
 3332         ParamValuesList = ParamValue.split()
 3333         if len(ParamValuesList) == 0:
 3334             MiscUtil.PrintError(
 3335                 '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'
 3336                 % (ParamValue, ParamName, ParamsOptionName)
 3337             )
 3338     ParamsInfo["AdditionalList"] = ParamValuesList
 3339 
 3340 
 3341 def _IsImplicitWaterForcefield(BiopolymerForcefield, WaterForcefield):
 3342     """Check the nature of the water forcefield."""
 3343 
 3344     Status = False
 3345     if WaterForcefield is None:
 3346         if re.search("charmm_polar_2019", BiopolymerForcefield, re.I):
 3347             Status = True
 3348         else:
 3349             Status = False
 3350     else:
 3351         if re.search("amber", BiopolymerForcefield, re.I):
 3352             if re.search("implicit", WaterForcefield, re.I):
 3353                 Status = True
 3354         elif re.search("charmm", BiopolymerForcefield, re.I):
 3355             if re.search("implicit", WaterForcefield, re.I):
 3356                 Status = True
 3357         elif re.search("amoeba", BiopolymerForcefield, re.I):
 3358             Status = True
 3359 
 3360     return Status
 3361 
 3362 
 3363 def ProcessOptionOpenMMAnnealingParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
 3364     """Process parameters for annealing option and return a map containing processed
 3365     parameter names and values.
 3366 
 3367     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 3368     to setup platform.
 3369 
 3370     The supported parameter names along with their default values for
 3371     different platforms are shown below:
 3372 
 3373         Initial heating parameters:
 3374 
 3375         initialStart, 0.0  [ Units: kelvin ]
 3376         initialEnd, 300.0  [ Units: kelvin ]
 3377         initialChange, 5.0  [ Units: kelvin ]
 3378         initialSteps, 5000
 3379 
 3380         initialEquilibrationSteps, 100000
 3381 
 3382         Heating and cooling cycle parameters:
 3383 
 3384         cycles, 1
 3385 
 3386         cycleStart, auto  [ Units: kelvin. The default value is set to
 3387             initialEnd ]
 3388         cycleEnd, 315.0  [ Units: kelvin ]
 3389         cycleChange, 1.0  [ Units: kelvin ]
 3390         cycleSteps, 1000
 3391 
 3392         cycleEquilibrationSteps, 100000
 3393 
 3394         Final equilibration parameters:
 3395 
 3396         finalEquilibrationSteps, 200000
 3397 
 3398     A brief description of parameters is provided below:
 3399 
 3400         Initial heating parameters:
 3401 
 3402         initialStart: Start temperature for initial heating.
 3403         initialEnd: End temperature for initial heating.
 3404         initialChange: Temperature change for increasing temperature
 3405             during initial heating.
 3406         initialSteps: Number of simulation steps after each
 3407             heating step during initial heating
 3408 
 3409         initialEquilibrationSteps: Number of equilibration steps
 3410             after the completion of initial heating.
 3411 
 3412         Heating and cooling cycles parameters:
 3413 
 3414         cycles: Number of annealing cycles to perform. Each cycle
 3415             consists of a heating and a cooling phase. The heating phase
 3416             consists of the following steps: Heat system from start to
 3417             end temperature using change size and perform simulation for a
 3418             number of steps after each increase in temperature; Perform
 3419             equilibration after the completion of heating. The cooling
 3420             phase is reverse of the heating phase and cools the system
 3421             from end to start temperature.
 3422 
 3423         cycleStart: Start temperature for annealing cycle.
 3424         cycleEnd: End temperature for annealing cycle.
 3425         cycleChange: Temperature change for increasing or decreasing
 3426             temperature during annealing cycle.
 3427         cycleSteps: Number of simulation steps after each heating and
 3428             cooling step during annealing cycle.
 3429 
 3430         cycleEquilibrationSteps: Number of equilibration steps
 3431             after the completion of heating and cooling phase during a
 3432             annealing cycle.
 3433 
 3434         Final equilibration parameters:
 3435 
 3436         finalEquilibrationSteps: Number of final equilibration
 3437             steps after the completion of annealing cycles.
 3438 
 3439     Arguments:
 3440         ParamsOptionName (str): Command line OpenMM annealing option name.
 3441         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 3442         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 3443 
 3444     Returns:
 3445         dictionary: Processed parameter name and value pairs.
 3446 
 3447     """
 3448 
 3449     ParamsInfo = {
 3450         "InitialStart": 0.0,
 3451         "InitialEnd": 300.0,
 3452         "InitialChange": 5.0,
 3453         "InitialSteps": 5000,
 3454         "InitialEquilibrationSteps": 100000,
 3455         "Cycles": 1,
 3456         "CycleStart": "auto",
 3457         "CycleEnd": 315.0,
 3458         "CycleChange": 1.0,
 3459         "CycleSteps": 1000,
 3460         "CycleEquilibrationSteps": 100000,
 3461         "FinalEquilibrationSteps": 200000,
 3462     }
 3463 
 3464     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 3465         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 3466     )
 3467 
 3468     if re.match("^auto$", ParamsOptionValue, re.I):
 3469         _ProcessOptionOpenMMAnnealingParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3470         return ParamsInfo
 3471 
 3472     for Index in range(0, len(ParamsOptionValueWords), 2):
 3473         Name = ParamsOptionValueWords[Index].strip()
 3474         Value = ParamsOptionValueWords[Index + 1].strip()
 3475 
 3476         ParamName = CanonicalParamNamesMap[Name.lower()]
 3477         ParamValue = Value
 3478 
 3479         if re.match("^(InitialStart|InitialEnd|CycleEnd)$", ParamName, re.I):
 3480             if not MiscUtil.IsFloat(Value):
 3481                 MiscUtil.PrintError(
 3482                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 3483                     % (Value, ParamName, ParamsOptionName)
 3484                 )
 3485             Value = float(Value)
 3486             if Value < 0:
 3487                 MiscUtil.PrintError(
 3488                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 3489                     % (ParamValue, ParamName, ParamsOptionName)
 3490                 )
 3491             ParamValue = Value
 3492         elif re.match("^(InitialChange|CycleChange)$", ParamName, re.I):
 3493             if not MiscUtil.IsFloat(Value):
 3494                 MiscUtil.PrintError(
 3495                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 3496                     % (Value, ParamName, ParamsOptionName)
 3497                 )
 3498             Value = float(Value)
 3499             if Value <= 0:
 3500                 MiscUtil.PrintError(
 3501                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 3502                     % (ParamValue, ParamName, ParamsOptionName)
 3503                 )
 3504             ParamValue = Value
 3505         elif re.match("^CycleStart$", ParamName, re.I):
 3506             if not re.match("^auto$", Value, re.I):
 3507                 if not MiscUtil.IsFloat(Value):
 3508                     MiscUtil.PrintError(
 3509                         'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 3510                         % (Value, ParamName, ParamsOptionName)
 3511                     )
 3512                 Value = float(Value)
 3513                 if Value < 0:
 3514                     MiscUtil.PrintError(
 3515                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 3516                         % (ParamValue, ParamName, ParamsOptionName)
 3517                     )
 3518                 ParamValue = Value
 3519         elif re.match(
 3520             "^(InitialSteps|InitialEquilibrationSteps|Cycles|CycleSteps|CycleEquilibrationSteps|FinalEquilibrationSteps)$",
 3521             ParamName,
 3522             re.I,
 3523         ):
 3524             if not MiscUtil.IsInteger(Value):
 3525                 MiscUtil.PrintError(
 3526                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a integer.\n'
 3527                     % (Value, ParamName, ParamsOptionName)
 3528                 )
 3529             Value = int(Value)
 3530             if Value <= 0:
 3531                 MiscUtil.PrintError(
 3532                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 3533                     % (ParamValue, ParamName, ParamsOptionName)
 3534                 )
 3535             ParamValue = Value
 3536         else:
 3537             ParamValue = Value
 3538 
 3539         # Set value...
 3540         ParamsInfo[ParamName] = ParamValue
 3541 
 3542     # Handle parameters with possible auto values...
 3543     _ProcessOptionOpenMMAnnealingParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3544 
 3545     return ParamsInfo
 3546 
 3547 
 3548 def _ProcessOptionOpenMMAnnealingParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 3549     """Process parameters with possible auto values and perform validation."""
 3550 
 3551     ParamName = "CycleStart"
 3552     ParamValue = "%s" % ParamsInfo[ParamName]
 3553     if re.match("^auto$", ParamValue, re.I):
 3554         ParamsInfo[ParamName] = ParamsInfo["InitialEnd"]
 3555 
 3556     if ParamsInfo["InitialStart"] >= ParamsInfo["InitialEnd"]:
 3557         MiscUtil.PrintError(
 3558             'The parameter value, %s, specified for parameter name, initialStart, must be less than value, %s, specified for parameter name, initialEnd, using "%s" option.\n'
 3559             % (ParamsInfo["InitialStart"], ParamsInfo["InitialEnd"], ParamsOptionName)
 3560         )
 3561 
 3562     if ParamsInfo["CycleStart"] >= ParamsInfo["CycleEnd"]:
 3563         MiscUtil.PrintError(
 3564             'The parameter value, %s, specified for parameter name, cycleStart, must be less than value, %s, specified for parameter name, cycleEnd, using "%s" option.\n'
 3565             % (ParamsInfo["CycleStart"], ParamsInfo["CycleEnd"], ParamsOptionName)
 3566         )
 3567 
 3568     if ParamsInfo["CycleStart"] != ParamsInfo["InitialEnd"]:
 3569         MiscUtil.PrintError(
 3570             'The parameter value, %s, specified for parameter name, cycleStart, must be equal to value, %s, specified for parameter name, initialEndEnd, using "%s" option.\n'
 3571             % (ParamsInfo["CycleStart"], ParamsInfo["InitialEnd"], ParamsOptionName)
 3572         )
 3573 
 3574     if ParamsInfo["InitialChange"] >= (ParamsInfo["InitialEnd"] - ParamsInfo["InitialStart"]):
 3575         MiscUtil.PrintError(
 3576             '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'
 3577             % (ParamsInfo["InitialChange"], (ParamsInfo["InitialEnd"] - ParamsInfo["InitialStart"]), ParamsOptionName)
 3578         )
 3579 
 3580     if ParamsInfo["CycleChange"] >= (ParamsInfo["CycleEnd"] - ParamsInfo["CycleStart"]):
 3581         MiscUtil.PrintError(
 3582             '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'
 3583             % (ParamsInfo["CycleChange"], (ParamsInfo["CycleEnd"] - ParamsInfo["CycleStart"]), ParamsOptionName)
 3584         )
 3585 
 3586 
 3587 def ProcessOptionOpenMMMDProtocolParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
 3588     """Process parameters for MD protocol option and return a map containing
 3589     processed parameter names and values.
 3590 
 3591     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 3592     to setup platform.
 3593 
 3594     The supported parameter names along with their default values for
 3595     different platforms are shown below:
 3596 
 3597         Phase1 - Initial heating parameters (NVT simulation):
 3598 
 3599         phase1, yes [ Possible values: yes or no ]
 3600         phase1InitialStart, 0.0  [ Units: kelvin ]
 3601         phase1InitialEnd, 300.0  [ Units: kelvin ]
 3602         phase1InitialChange, 5.0  [ Units: kelvin ]
 3603         phase1InitialSteps, 5000
 3604 
 3605         phase1InitialEquilibrationSteps, 100000
 3606 
 3607         Phase2 - Heating and cooling cycles parameters (NVT simulation):
 3608 
 3609         phase2, yes [ Possible values: yes or no ]
 3610         phase2Cycles, 1
 3611         phase2CycleStart, auto  [ Units: kelvin. The default value is set to
 3612             initialEnd ]
 3613         phase2CycleEnd, 315.0  [ Units: kelvin ]
 3614         phase2CycleChange, 1.0  [ Units: kelvin ]
 3615         phase2CycleSteps, 1000
 3616 
 3617         phase2CycleEquilibrationSteps, 100000
 3618 
 3619         Phase3 - NVT equilibration parameters:
 3620 
 3621         phase3, yes [ Possible values: yes or no ]
 3622         phase3Steps, 200000
 3623 
 3624         Phase4 - NPT equilibration parameters:
 3625 
 3626         phase4, yes [ Possible values: yes or no ]
 3627         phase4Steps, 200000
 3628 
 3629         Phase5 - NPT production parameters:
 3630 
 3631         phase5, yes [ Possible values: yes or no ]
 3632         phase5Steps, 1000000
 3633         phase5StepSize, auto [ Units: fs; Default value: Same as stepSize
 3634             parameter in integratorParams option. ]
 3635 
 3636     A brief description of parameters is provided below:
 3637 
 3638         Phase1 - Initial heating parameters (NVT simulation):
 3639 
 3640         phase1: Execute phase1.
 3641         phase1InitialStart: Start temperature for initial heating.
 3642         phase1InitialEnd: End temperature for initial heating.
 3643         phas1InitialChange: Temperature change for increasing temperature
 3644             during initial heating.
 3645         phase1InitialSteps: Number of simulation steps after each
 3646             heating step during initial heating
 3647 
 3648         phase1InitialEquilibrationSteps: Number of equilibration steps
 3649             after the completion of initial heating.
 3650 
 3651         Phase2 - Heating and cooling cycles parameters (NVT simulation):
 3652 
 3653         phase2: Execute phase2.
 3654         phase2Cycles: Number of annealing cycles to perform. Each cycle
 3655             consists of a heating and a cooling phase. The heating phase
 3656             consists of the following steps: Heat system from start to
 3657             end temperature using change size and perform simulation for a
 3658             number of steps after each increase in temperature; Perform
 3659             equilibration after the completion of heating. The cooling
 3660             phase is reverse of the heating phase and cools the system
 3661             from end to start temperature.
 3662 
 3663         phase2CycleStart: Start temperature for annealing cycle.
 3664         phase2CycleEnd: End temperature for annealing cycle.
 3665         phase2CycleChange: Temperature change for increasing or decreasing
 3666             temperature during annealing cycle.
 3667         phase2CycleSteps: Number of simulation steps after each heating and
 3668             cooling step during annealing cycle.
 3669 
 3670         phase2CycleEquilibrationSteps: Number of equilibration steps
 3671             after the completion of heating and cooling phase during a
 3672             annealing cycle.
 3673 
 3674         Phase3 - NVT equilibration parameters:
 3675 
 3676         phase3: Execute phase3.
 3677         phase3Steps: Number of NVT equilibration steps.
 3678 
 3679         Phase4 - NPT equilibration parameters:
 3680 
 3681         phase4: Execute phase4.
 3682         phase4Steps: Number of NPT equilibration steps.
 3683 
 3684         Phase5 - NPT production parameters:
 3685 
 3686         phase5: Execute phase5
 3687         phase5Steps: Number of NPT production steps.
 3688         phase5StepSize: Simulation time step size for NPT production.
 3689 
 3690     Arguments:
 3691         ParamsOptionName (str): Command line OpenMM MD protocol option name.
 3692         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 3693         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 3694 
 3695     Returns:
 3696         dictionary: Processed parameter name and value pairs.
 3697 
 3698     """
 3699 
 3700     ParamsInfo = {
 3701         "Phase1": True,
 3702         "Phase1InitialStart": 0.0,
 3703         "Phase1InitialEnd": 300.0,
 3704         "Phase1InitialChange": 5.0,
 3705         "Phase1InitialSteps": 5000,
 3706         "Phase1InitialEquilibrationSteps": 100000,
 3707         "Phase2": True,
 3708         "Phase2Cycles": 1,
 3709         "Phase2CycleStart": "auto",
 3710         "Phase2CycleEnd": 315.0,
 3711         "Phase2CycleChange": 1.0,
 3712         "Phase2CycleSteps": 1000,
 3713         "Phase2CycleEquilibrationSteps": 100000,
 3714         "Phase3": True,
 3715         "Phase3Steps": 200000,
 3716         "Phase4": True,
 3717         "Phase4Steps": 200000,
 3718         "Phase5": True,
 3719         "Phase5Steps": 1000000,
 3720         "Phase5StepSize": "auto",
 3721     }
 3722 
 3723     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 3724         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 3725     )
 3726 
 3727     if re.match("^auto$", ParamsOptionValue, re.I):
 3728         _ProcessOptionOpenMMMDProtocolParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3729         return ParamsInfo
 3730 
 3731     for Index in range(0, len(ParamsOptionValueWords), 2):
 3732         Name = ParamsOptionValueWords[Index].strip()
 3733         Value = ParamsOptionValueWords[Index + 1].strip()
 3734 
 3735         ParamName = CanonicalParamNamesMap[Name.lower()]
 3736         ParamValue = Value
 3737 
 3738         if re.match("^(Phase1|Phase2|Phase3|Phase4|Phase5)$", ParamName, re.I):
 3739             if not re.match("^(yes|no|true|false)$", Value, re.I):
 3740                 MiscUtil.PrintError(
 3741                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: yes or no'
 3742                     % (Value, Name, ParamsOptionName)
 3743                 )
 3744             ParamValue = True if re.match("^(yes|true)$", Value, re.I) else False
 3745         elif re.match("^(Phase1InitialStart|Phase1InitialEnd|Phase2CycleEnd)$", ParamName, re.I):
 3746             if not MiscUtil.IsFloat(Value):
 3747                 MiscUtil.PrintError(
 3748                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 3749                     % (Value, ParamName, ParamsOptionName)
 3750                 )
 3751             Value = float(Value)
 3752             if Value < 0:
 3753                 MiscUtil.PrintError(
 3754                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 3755                     % (ParamValue, ParamName, ParamsOptionName)
 3756                 )
 3757             ParamValue = Value
 3758         elif re.match("^(Phase1InitialChange|Phase2CycleChange)$", ParamName, re.I):
 3759             if not MiscUtil.IsFloat(Value):
 3760                 MiscUtil.PrintError(
 3761                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 3762                     % (Value, ParamName, ParamsOptionName)
 3763                 )
 3764             Value = float(Value)
 3765             if Value <= 0:
 3766                 MiscUtil.PrintError(
 3767                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 3768                     % (ParamValue, ParamName, ParamsOptionName)
 3769                 )
 3770             ParamValue = Value
 3771         elif re.match("^Phase2CycleStart$", ParamName, re.I):
 3772             if not re.match("^auto$", Value, re.I):
 3773                 if not MiscUtil.IsFloat(Value):
 3774                     MiscUtil.PrintError(
 3775                         'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 3776                         % (Value, ParamName, ParamsOptionName)
 3777                     )
 3778                 Value = float(Value)
 3779                 if Value < 0:
 3780                     MiscUtil.PrintError(
 3781                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 3782                         % (ParamValue, ParamName, ParamsOptionName)
 3783                     )
 3784                 ParamValue = Value
 3785         elif re.match(
 3786             "^(Phase1InitialSteps|Phase1InitialEquilibrationSteps|Phase2Cycles|Phase2CycleSteps|Phase2CycleEquilibrationSteps|Phase3Steps|Phase4Steps|Phase5Steps|Phase5StepSize)$",
 3787             ParamName,
 3788             re.I,
 3789         ):
 3790             if not MiscUtil.IsInteger(Value):
 3791                 MiscUtil.PrintError(
 3792                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a integer.\n'
 3793                     % (Value, ParamName, ParamsOptionName)
 3794                 )
 3795             Value = int(Value)
 3796             if Value <= 0:
 3797                 MiscUtil.PrintError(
 3798                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 3799                     % (ParamValue, ParamName, ParamsOptionName)
 3800                 )
 3801             ParamValue = Value
 3802         else:
 3803             ParamValue = Value
 3804 
 3805         # Set value...
 3806         ParamsInfo[ParamName] = ParamValue
 3807 
 3808     # Handle parameters with possible auto values...
 3809     _ProcessOptionOpenMMMDProtocolParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3810 
 3811     return ParamsInfo
 3812 
 3813 
 3814 def _ProcessOptionOpenMMMDProtocolParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 3815     """Process parameters with possible auto values and perform validation."""
 3816 
 3817     ParamName = "Phase2CycleStart"
 3818     ParamValue = "%s" % ParamsInfo[ParamName]
 3819     if re.match("^auto$", ParamValue, re.I):
 3820         ParamsInfo[ParamName] = ParamsInfo["Phase1InitialEnd"]
 3821 
 3822     ParamName = "Phase5StepSize"
 3823     ParamValue = "%s" % ParamsInfo[ParamName]
 3824     if re.match("^auto$", ParamValue, re.I):
 3825         # Set Phase5StepSize to None to use StepSize specifieid using --integratiorParams option...
 3826         ParamsInfo[ParamName] = None
 3827 
 3828     if ParamsInfo["Phase1InitialStart"] >= ParamsInfo["Phase1InitialEnd"]:
 3829         MiscUtil.PrintError(
 3830             'The parameter value, %s, specified for parameter name, phase1InitialStart, must be less than value, %s, specified for parameter name, phase1InitialEnd, using "%s" option.\n'
 3831             % (ParamsInfo["Phase1InitialStart"], ParamsInfo["Phase1InitialEnd"], ParamsOptionName)
 3832         )
 3833 
 3834     if ParamsInfo["Phase2CycleStart"] >= ParamsInfo["Phase2CycleEnd"]:
 3835         MiscUtil.PrintError(
 3836             'The parameter value, %s, specified for parameter name, phase2CycleStart, must be less than value, %s, specified for parameter name, phase2CycleEnd, using "%s" option.\n'
 3837             % (ParamsInfo["Phase2CycleStart"], ParamsInfo["Phase2CycleEnd"], ParamsOptionName)
 3838         )
 3839 
 3840     if ParamsInfo["Phase2CycleStart"] != ParamsInfo["Phase1InitialEnd"]:
 3841         MiscUtil.PrintError(
 3842             'The parameter value, %s, specified for parameter name, phase2CycleStart, must be equal to value, %s, specified for parameter name, phase1InitialEndEnd, using "%s" option.\n'
 3843             % (ParamsInfo["Phase2CycleStart"], ParamsInfo["Phase1InitialEnd"], ParamsOptionName)
 3844         )
 3845 
 3846     if ParamsInfo["Phase1InitialChange"] >= (ParamsInfo["Phase1InitialEnd"] - ParamsInfo["Phase1InitialStart"]):
 3847         MiscUtil.PrintError(
 3848             'The parameter value, %s, specified for parameter name, phase2InitialChange, must be less than value, %s, corresponding to the difference between values specified for parameter names, phase1InitialStart and phase1InitialEnd, using "%s" option.\n'
 3849             % (
 3850                 ParamsInfo["Phase1InitialChange"],
 3851                 (ParamsInfo["Phase1InitialEnd"] - ParamsInfo["Phase1InitialStart"]),
 3852                 ParamsOptionName,
 3853             )
 3854         )
 3855 
 3856     if ParamsInfo["Phase2CycleChange"] >= (ParamsInfo["Phase2CycleEnd"] - ParamsInfo["Phase2CycleStart"]):
 3857         MiscUtil.PrintError(
 3858             'The parameter value, %s, specified for parameter name, phase2CycleChange, must be less than value, %s, corresponding to the difference between values specified for parameter names, phase2CycleStart and Phase2CycleEnd, using "%s" option.\n'
 3859             % (
 3860                 ParamsInfo["Phase2CycleChange"],
 3861                 (ParamsInfo["Phase2CycleEnd"] - ParamsInfo["Phase2CycleStart"]),
 3862                 ParamsOptionName,
 3863             )
 3864         )
 3865 
 3866 
 3867 def ProcessOptionOpenMMPlatformParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
 3868     """Process parameters for platform option and return a map containing processed
 3869     parameter names and values.
 3870 
 3871     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 3872     to setup platform.
 3873 
 3874     The supported parameter names along with their default values for
 3875     different platforms are shown below:
 3876 
 3877         CPU:
 3878 
 3879         threads, 1  [ Possible value: >= 0 or auto.  The value of 'auto'
 3880             or zero implies the use of all available CPUs for threading. ]
 3881 
 3882         CUDA:
 3883 
 3884         deviceIndex, auto  [ Possible values: 0, '0 1' etc. ]
 3885         deterministicForces, auto [ Possible values: yes or no ]
 3886         precision, single  [ Possible values: single, double, or mix ]
 3887         tempDirectory, auto [ Possible value: DirName ]
 3888         useBlockingSync, auto [ Possible values: yes or no ]
 3889         useCpuPme, auto [ Possible values: yes or no ]
 3890 
 3891         OpenCL:
 3892 
 3893         deviceIndex, auto  [ Possible values: 0, '0 1' etc. ]
 3894         openCLPlatformIndex, auto  [ Possible value: Number]
 3895         precision, single  [ Possible values: single, double, or mix ]
 3896         useCpuPme, auto [ Possible values: yes or no ]
 3897 
 3898     A brief description of parameters is provided below:
 3899 
 3900         CPU:
 3901 
 3902         threads: Number of threads to use for simulation.
 3903 
 3904         CUDA:
 3905 
 3906         deviceIndex: Space delimited list of device indices to use for
 3907             calculations.
 3908         deterministicForces: Generate reproducible results at the cost of a
 3909             small decrease in performance.
 3910         precision: Number precision to use for calculations.
 3911         tempDirectory: Directory name for storing temporary files.
 3912         useBlockingSync: Control run-time synchronization between CPU and
 3913             GPU.
 3914         useCpuPme: Use CPU-based PME implementation.
 3915 
 3916         OpenCL:
 3917 
 3918         deviceIndex: Space delimited list of device indices to use for
 3919             simulation.
 3920         openCLPlatformIndex: Platform index to use for calculations.
 3921         precision: Number precision to use for calculations.
 3922         useCpuPme: Use CPU-based PME implementation.
 3923 
 3924     Arguments:
 3925         ParamsOptionName (str): Command line OpenMM platform option name.
 3926         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 3927         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 3928 
 3929     Returns:
 3930         dictionary: Processed parameter name and value pairs.
 3931 
 3932     """
 3933 
 3934     ParamsInfo = {
 3935         "Name": "CPU",
 3936         "Threads": "auto",
 3937         "DeviceIndex": "auto",
 3938         "DeterministicForces": "auto",
 3939         "Precision": "single",
 3940         "TempDirectory": "auto",
 3941         "UseBlockingSync": "auto",
 3942         "UseCpuPme": "auto",
 3943         "OpenCLPlatformIndex": "auto",
 3944     }
 3945 
 3946     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 3947         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 3948     )
 3949 
 3950     if re.match("^auto$", ParamsOptionValue, re.I):
 3951         _ProcessOptionOpenMMPlatformParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 3952         return ParamsInfo
 3953 
 3954     for Index in range(0, len(ParamsOptionValueWords), 2):
 3955         Name = ParamsOptionValueWords[Index].strip()
 3956         Value = ParamsOptionValueWords[Index + 1].strip()
 3957 
 3958         ParamName = CanonicalParamNamesMap[Name.lower()]
 3959         ParamValue = Value
 3960 
 3961         if re.match("^Name$", ParamName, re.I):
 3962             if not re.match("^(CPU|CUDA|OpenCL|Reference)$", Value, re.I):
 3963                 MiscUtil.PrintError(
 3964                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: CPU, GPU, OpenCL, or Reference'
 3965                     % (Value, Name, ParamsOptionName)
 3966                 )
 3967             ParamValue = Value
 3968         elif re.match("^Threads$", ParamName, re.I):
 3969             if not re.match("^auto$", Value, re.I):
 3970                 if not MiscUtil.IsInteger(Value):
 3971                     MiscUtil.PrintError(
 3972                         'The parameter value, %s, specified for parameter name, %s, using "%s" option must be an integer.\n'
 3973                         % (Value, ParamName, ParamsOptionName)
 3974                     )
 3975                 Value = int(Value)
 3976                 if Value < 0:
 3977                     MiscUtil.PrintError(
 3978                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: >=0 \n'
 3979                         % (ParamValue, ParamName, ParamsOptionName)
 3980                     )
 3981                 if Value > mp.cpu_count():
 3982                     MiscUtil.PrintError(
 3983                         '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'
 3984                         % (ParamValue, ParamName, ParamsOptionName, mp.cpu_count())
 3985                     )
 3986                 ParamValue = "%s" % Value
 3987         elif re.match("^Precision$", ParamName, re.I):
 3988             if not re.match("^(Single|Double|Mix)$", Value, re.I):
 3989                 MiscUtil.PrintError(
 3990                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: single, double or mix'
 3991                     % (Value, Name, ParamsOptionName)
 3992                 )
 3993             ParamValue = Value.lower()
 3994         elif re.match("^(DeterministicForces|UseBlockingSync|UseCpuPme)$", ParamName, re.I):
 3995             if not re.match("^auto$", Value, re.I):
 3996                 if not re.match("^(yes|no|true|false)$", Value, re.I):
 3997                     MiscUtil.PrintError(
 3998                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: yes or no'
 3999                         % (Value, Name, ParamsOptionName)
 4000                     )
 4001                 ParamValue = "true" if re.match("^(yes|true)$", Value, re.I) else "false"
 4002         elif re.match("^(DeviceIndex|openCLPlatformIndex)$", ParamName, re.I):
 4003             if not re.match("^auto$", Value, re.I):
 4004                 DeviceIndices = Value.split()
 4005                 if len(DeviceIndices) == 0:
 4006                     MiscUtil.PrintError(
 4007                         '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'
 4008                         % (Value, ParamName, ParamsOptionName)
 4009                     )
 4010                 for DeviceIndex in DeviceIndices:
 4011                     if not MiscUtil.IsInteger(DeviceIndex):
 4012                         MiscUtil.PrintError(
 4013                             'The parameter value, %s, specified for parameter name, %s, using "%s" option must be an integer.\n'
 4014                             % (DeviceIndex, ParamName, ParamsOptionName)
 4015                         )
 4016                 ParamValue = ",".join(DeviceIndices)
 4017         elif re.match("^TempDirectory$", ParamName, re.I):
 4018             if not re.match("^auto$", Value, re.I):
 4019                 if not os.path.isdir(Value):
 4020                     MiscUtil.PrintError(
 4021                         'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. The specified directory doesn\'t exists.'
 4022                         % (Value, Name, ParamsOptionName)
 4023                     )
 4024             ParamValue = Value
 4025         else:
 4026             ParamValue = Value
 4027 
 4028         # Set value...
 4029         ParamsInfo[ParamName] = ParamValue
 4030 
 4031     # Handle parameters with possible auto values...
 4032     _ProcessOptionOpenMMPlatformParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 4033 
 4034     return ParamsInfo
 4035 
 4036 
 4037 def _ProcessOptionOpenMMPlatformParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 4038     """Process parameters with possible auto values and perform validation."""
 4039 
 4040     ParamValueMap = {"cpu": "CPU", "cuda": "CUDA", "opencl": "OpenCL", "reference": "Reference"}
 4041     ParamName = "Name"
 4042     ParamValue = ParamsInfo[ParamName].lower()
 4043     if ParamValue in ParamValueMap:
 4044         ParamsInfo[ParamName] = ParamValueMap[ParamValue]
 4045 
 4046     ParamsInfo["Precision"] = ParamsInfo["Precision"].lower()
 4047 
 4048     # Set "auto" values to None and treat all other values as strings...
 4049     for ParamName in ParamsInfo:
 4050         ParamValue = "%s" % ParamsInfo[ParamName]
 4051         if re.match("^auto$", ParamValue, re.I):
 4052             ParamsInfo[ParamName] = None
 4053         else:
 4054             ParamsInfo[ParamName] = ParamValue
 4055 
 4056 
 4057 def ProcessOptionOpenMMWaterBoxParameters(ParamsOptionName, ParamsOptionValue, ParamsDefaultInfo=None):
 4058     """Process parameters for adding a water box option and return a map containing
 4059     processed parameter names and values.
 4060 
 4061     ParamsOptionValue is a comma delimited list of parameter name and value pairs
 4062     for adding a water box.
 4063 
 4064     The supported parameter names along with their default and possible
 4065     values are shown below:
 4066 
 4067         model, tip3p [ Possible values: tip3p, spce, tip4pew, tip5p or swm4ndp ]
 4068         mode, Padding [ Possible values: Size or Padding ]
 4069         size, None [ Possible values: xsize ysize zsize ]
 4070         padding, 1.0
 4071         shape, cube [ Possible values: cube, dodecahedron, or octahedron ]
 4072         ionPositive, Na+ [ Possible values: Li+, Na+, K+, Rb+, or Cs+ ]
 4073         ionNegative, Cl- [ Possible values: Cl-, Br-, F-, or I- ]
 4074         ionicStrength, 0.0
 4075 
 4076     A brief description of parameters is provided below:
 4077 
 4078     model: Water model to use for adding water box.
 4079 
 4080     mode: Specify the size of the waterbox explicitly or calculate it automatically
 4081     for a macromolecule along with adding padding around macromolecule.
 4082     Possible values: Size or Padding.
 4083 
 4084     size: A space delimited triplet of values corresponding to water size in
 4085     nanometers. It must be specified during 'Size' value of 'mode' parameter.
 4086 
 4087     padding: Padding around macromolecule in nanometers for filling box with
 4088     water. It must be specified during 'Padding' value of 'mode' parameter.
 4089 
 4090     ionPositive: Type of positive ion to add during the addition of a water box.
 4091 
 4092     ionNegative: Type of negative ion to add during the addition of a water box.
 4093 
 4094     ionicStrength: Total concentration (molar) of both positive and negative ions
 4095     to add excluding he ions added to neutralize the system during the addition
 4096     of a water box.
 4097 
 4098     Arguments:
 4099         ParamsOptionName (str): Command line OpenMM water box option name.
 4100         ParamsOptionValues (str): Space delimited list of parameter name and value pairs.
 4101         ParamsDefaultInfo (dict): Default values to override for selected parameters.
 4102 
 4103     Returns:
 4104         dictionary: Processed parameter name and value pairs.
 4105 
 4106     """
 4107 
 4108     ParamsInfo = {
 4109         "Model": "tip3p",
 4110         "Mode": "Padding",
 4111         "Size": None,
 4112         "Padding": 1.0,
 4113         "Shape": "cube",
 4114         "IonPositive": "Na+",
 4115         "IonNegative": "Cl-",
 4116         "IonicStrength": 0.0,
 4117     }
 4118 
 4119     (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords) = (
 4120         _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo)
 4121     )
 4122 
 4123     if re.match("^auto$", ParamsOptionValue, re.I):
 4124         _ProcessOptionOpenMMWaterBoxParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 4125         return ParamsInfo
 4126 
 4127     for Index in range(0, len(ParamsOptionValueWords), 2):
 4128         Name = ParamsOptionValueWords[Index].strip()
 4129         Value = ParamsOptionValueWords[Index + 1].strip()
 4130 
 4131         ParamName = CanonicalParamNamesMap[Name.lower()]
 4132         ParamValue = Value
 4133 
 4134         if re.match("^Model$", ParamName, re.I):
 4135             if not re.match("^(tip3p|spce|tip4pew|tip5p|swm4ndp)$", Value, re.I):
 4136                 MiscUtil.PrintError(
 4137                     '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'
 4138                     % (Value, Name, ParamsOptionName)
 4139                 )
 4140             ParamValue = Value.lower()
 4141         elif re.match("^Mode$", ParamName, re.I):
 4142             if not re.match("^(Padding|Size)$", Value, re.I):
 4143                 MiscUtil.PrintError(
 4144                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: Padding or Size'
 4145                     % (Value, Name, ParamsOptionName)
 4146                 )
 4147             ParamValue = Value
 4148         elif re.match("^Size$", ParamName, re.I):
 4149             if Value is not None and not re.match("^None$", Value, re.I):
 4150                 SizeValues = Value.split()
 4151                 if len(SizeValues) != 3:
 4152                     MiscUtil.PrintError(
 4153                         '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'
 4154                         % (Value, ParamName, ParamsOptionName)
 4155                     )
 4156 
 4157                 SizeValueList = []
 4158                 for SizeValue in SizeValues:
 4159                     if not MiscUtil.IsFloat(SizeValue):
 4160                         MiscUtil.PrintError(
 4161                             'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 4162                             % (SizeValue, ParamName, ParamsOptionName)
 4163                         )
 4164                     SizeValue = float(SizeValue)
 4165                     if SizeValue <= 0:
 4166                         MiscUtil.PrintError(
 4167                             'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 4168                             % (SizeValue, ParamName, ParamsOptionName)
 4169                         )
 4170                     SizeValueList.append(SizeValue)
 4171 
 4172                 # Set size values...
 4173                 ParamsInfo["SizeList"] = SizeValueList
 4174 
 4175             ParamValue = Value
 4176         elif re.match("^Padding$", ParamName, re.I):
 4177             if not MiscUtil.IsFloat(Value):
 4178                 MiscUtil.PrintError(
 4179                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 4180                     % (Value, ParamName, ParamsOptionName)
 4181                 )
 4182             Value = float(Value)
 4183             if Value <= 0:
 4184                 MiscUtil.PrintError(
 4185                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: > 0\n'
 4186                     % (ParamValue, ParamName, ParamsOptionName)
 4187                 )
 4188             ParamValue = Value
 4189         elif re.match("^Shape$", ParamName, re.I):
 4190             if not re.match("^(cube|dodecahedron|octahedron)$", Value, re.I):
 4191                 MiscUtil.PrintError(
 4192                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: cube, dodecahedron, or octahedron'
 4193                     % (Value, Name, ParamsOptionName)
 4194                 )
 4195             ParamValue = Value.lower()
 4196         elif re.match("^IonPositive$", ParamName, re.I):
 4197             ValidValues = "Li+ Na+ K+ Rb+ Cs+"
 4198             EscapedValidValuesPattern = r"Li\+|Na\+|K\+|Rb\+|Cs\+"
 4199             if not re.match("^(%s)$" % EscapedValidValuesPattern, Value):
 4200                 MiscUtil.PrintError(
 4201                     'The value specified, %s, for parameter name, %s, using  "%s" option is not a valid.  Supported value(s): %s'
 4202                     % (ParamValue, ParamName, ParamsOptionName, ValidValues)
 4203                 )
 4204             ParamValue = Value
 4205         elif re.match("^IonNegative$", ParamName, re.I):
 4206             ValidValues = "F- Cl- Br- I-"
 4207             ValidValuesPattern = "F-|Cl-|Br-|I-"
 4208             if not re.match("^(%s)$" % ValidValuesPattern, Value):
 4209                 MiscUtil.PrintError(
 4210                     'The value specified, %s, for parameter name, %s, using  "%s" option is not a valid.  Supported value(s): %s'
 4211                     % (ParamValue, ParamName, ParamsOptionName, ValidValues)
 4212                 )
 4213             ParamValue = Value
 4214         elif re.match("^IonicStrength$", ParamName, re.I):
 4215             if not MiscUtil.IsFloat(Value):
 4216                 MiscUtil.PrintError(
 4217                     'The parameter value, %s, specified for parameter name, %s, using "%s" option must be a float.\n'
 4218                     % (Value, ParamName, ParamsOptionName)
 4219                 )
 4220             Value = float(Value)
 4221             if Value < 0:
 4222                 MiscUtil.PrintError(
 4223                     'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: >= 0\n'
 4224                     % (ParamValue, ParamName, ParamsOptionName)
 4225                 )
 4226             ParamValue = Value
 4227         else:
 4228             ParamValue = Value
 4229 
 4230         # Set value...
 4231         ParamsInfo[ParamName] = ParamValue
 4232 
 4233     # Handle parameters with possible auto values...
 4234     _ProcessOptionOpenMMWaterBoxParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue)
 4235 
 4236     return ParamsInfo
 4237 
 4238 
 4239 def _ProcessOptionOpenMMWaterBoxParameters(ParamsInfo, ParamsOptionName, ParamsOptionValue):
 4240     """Process parameters with possible auto values and perform validation."""
 4241 
 4242     ParamsInfo["ModeSize"] = True if re.match("^Size$", ParamsInfo["Mode"], re.I) else False
 4243     ParamsInfo["ModePadding"] = True if re.match("^Padding$", ParamsInfo["Mode"], re.I) else False
 4244 
 4245     if ParamsInfo["ModeSize"]:
 4246         ParamName = "Size"
 4247         ParamValue = ParamsInfo[ParamName]
 4248         if ParamValue is None:
 4249             MiscUtil.PrintError(
 4250                 'The parameter value, %s, specified for parameter name, %s, using "%s" option is not a valid value. Supported values: x y z\n'
 4251                 % (ParamValue, ParamName, ParamsOptionName)
 4252             )
 4253     else:
 4254         ParamsInfo["SizeList"] = None
 4255 
 4256 
 4257 def _ValidateAndCanonicalizeParameterNames(ParamsOptionName, ParamsOptionValue, ParamsInfo, ParamsDefaultInfo):
 4258     """Validate and canonicalize parameter names."""
 4259 
 4260     # Setup a canonical paramater names...
 4261     ValidParamNames = []
 4262     CanonicalParamNamesMap = {}
 4263     for ParamName in sorted(ParamsInfo):
 4264         ValidParamNames.append(ParamName)
 4265         CanonicalParamNamesMap[ParamName.lower()] = ParamName
 4266 
 4267     # Update default values...
 4268     if ParamsDefaultInfo is not None:
 4269         for ParamName in ParamsDefaultInfo:
 4270             if ParamName not in ParamsInfo:
 4271                 MiscUtil.PrintError(
 4272                     'The default parameter name, %s, specified using "%s" option is not a valid name. Supported parameter names: %s'
 4273                     % (ParamName, ParamsDefaultInfo, " ".join(ValidParamNames))
 4274                 )
 4275             ParamsInfo[ParamName] = ParamsDefaultInfo[ParamName]
 4276 
 4277     ParamsOptionValue = ParamsOptionValue.strip()
 4278     if not ParamsOptionValue:
 4279         MiscUtil.PrintError('No valid parameter name and value pairs specified using "%s" option' % ParamsOptionName)
 4280 
 4281     ParamsOptionValueWords = None
 4282     if not re.match("^auto$", ParamsOptionValue, re.I):
 4283         ParamsOptionValueWords = ParamsOptionValue.split(",")
 4284         if len(ParamsOptionValueWords) % 2:
 4285             MiscUtil.PrintError(
 4286                 'The number of comma delimited paramater names and values, %d, specified using "%s" option must be an even number.'
 4287                 % (len(ParamsOptionValueWords), ParamsOptionName)
 4288             )
 4289 
 4290     if ParamsOptionValueWords is not None:
 4291         for Index in range(0, len(ParamsOptionValueWords), 2):
 4292             Name = ParamsOptionValueWords[Index].strip()
 4293             CanonicalName = Name.lower()
 4294             if CanonicalName not in CanonicalParamNamesMap:
 4295                 MiscUtil.PrintError(
 4296                     'The parameter name, %s, specified using "%s" is not a valid name. Supported parameter names: %s'
 4297                     % (Name, ParamsOptionName, " ".join(ValidParamNames))
 4298                 )
 4299 
 4300     return (ValidParamNames, CanonicalParamNamesMap, ParamsOptionValue, ParamsOptionValueWords)