diff --git a/src/data/npt.py b/src/data/npt.py index 18cfbeacb..64d05b2ed 100755 --- a/src/data/npt.py +++ b/src/data/npt.py @@ -312,7 +312,7 @@ def main(): # Number of threads, multiple timestep integrator, anisotropic box etc. threads = TgtOptions.get('md_threads', 1) mts = TgtOptions.get('mts_integrator', 0) - rpmd_beads = TgtOptions.get('rpmd_beads', 0) + rpmd_beads = TgtOptions.get('rpmd_beads', []) force_cuda = TgtOptions.get('force_cuda', 0) nbarostat = TgtOptions.get('n_mcbarostat', 25) anisotropic = TgtOptions.get('anisotropic_box', 0) @@ -367,7 +367,7 @@ def main(): EngOpts["gas"]["gmx_top"] = os.path.splitext(gas_fnm)[0] + ".top" EngOpts["gas"]["gmx_mdp"] = os.path.splitext(gas_fnm)[0] + ".mdp" if force_cuda: logger.warn("force_cuda option has no effect on Gromacs engine.") - if rpmd_beads > 0: raise RuntimeError("Gromacs cannot handle RPMD.") + if len(rpmd_beads) > 0: raise RuntimeError("Gromacs cannot handle RPMD.") if mts: logger.warn("Gromacs not configured for multiple timestep integrator.") if anisotropic: logger.warn("Gromacs not configured for anisotropic box scaling.") elif engname == "tinker": @@ -376,7 +376,7 @@ def main(): EngOpts["liquid"]["tinker_key"] = os.path.splitext(liquid_fnm)[0] + ".key" EngOpts["gas"]["tinker_key"] = os.path.splitext(gas_fnm)[0] + ".key" if force_cuda: logger.warn("force_cuda option has no effect on Tinker engine.") - if rpmd_beads > 0: raise RuntimeError("TINKER cannot handle RPMD.") + if len(rpmd_beads) > 0: raise RuntimeError("TINKER cannot handle RPMD.") if mts: logger.warn("Tinker not configured for multiple timestep integrator.") EngOpts["liquid"].update(GenOpts) EngOpts["gas"].update(GenOpts) @@ -420,7 +420,7 @@ def main(): Volumes = prop_return['Volumes'] Dips = prop_return['Dips'] EDA = prop_return['Ecomps'] - + #getone = prop_return['One'] # Create a bunch of physical constants. # Energies are in kJ/mol # Lengths are in nanometers. @@ -492,6 +492,10 @@ def main(): # Condensed phase properties and derivatives. # #==============================================# + #---- + # Just get one + #---- + #---- # Density #---- diff --git a/src/forcefield.py b/src/forcefield.py index b49c1b46d..4ab7ae62a 100644 --- a/src/forcefield.py +++ b/src/forcefield.py @@ -223,7 +223,7 @@ def __init__(self, options, verbose=True): ## AMOEBA mutual dipole convergence tolerance. self.set_option(options, 'amoeba_eps') ## Switch for rigid water molecules - self.set_option(options, 'rigid_water') + self.set_option(options, 'rigid_water', forceprint=True) ## Bypass the transformation and use physical parameters directly self.set_option(options, 'use_pvals') @@ -1115,7 +1115,8 @@ def build_qtrans2(tq, qid, qmap): def list_map(self): """ Create the plist, which is like a reversed version of the parameter map. More convenient for printing. """ if len(self.map) == 0: - warn_press_key('The parameter map has no elements (Okay if we are not actually tuning any parameters.)') + #warn_press_key('The parameter map has no elements (Okay if we are not actually tuning any parameters.)') + logger.warning('The parameter map has no elements (Okay if we are not actually tuning any parameters.)\n') else: self.plist = [[] for j in range(max([self.map[i] for i in self.map])+1)] for i in self.map: diff --git a/src/openmmio.py b/src/openmmio.py index d9937d3ec..fdd708df6 100644 --- a/src/openmmio.py +++ b/src/openmmio.py @@ -34,6 +34,26 @@ except: pass +#def H_spring_energy(Sim): # Spring energy in RPMD simulation,only count H atom, it can be used to calculate the HD fractionation ratio. If classical simulation, return 0. +# if isinstance(Sim.integrator,RPMDIntegrator): +# springE=0.0*kilojoule/mole +# hbar=0.0635078*nanometer**2*dalton/picosecond +# kb=0.00831446*nanometer**2*dalton/(picosecond**2*kelvin) +# mass_matrix=[] +# for i in range(Sim.system.getNumParticles()): +# if (Sim.system.getParticleMass(i)<1.02*dalton):#Only count Hydrogen +# mass_matrix.append(Sim.system.getParticleMass(i)) +# else: +# mass_matrix.append(0.0*dalton) +# mass_matrix=np.array(mass_matrix) +# for i in range(Sim.integrator.getNumCopies()): +# j=(i+1)%(Sim.integrator.getNumCopies()) +# beaddif=np.array(Sim.integrator.getState(j,getPositions=True).getPositions())-np.array(Sim.integrator.getState(i,getPositions=True).getPositions())#calculate difference between ith and i+1th bead +# springE=springE+np.sum(((beaddif*beaddif).sum(axis=1))*mass_matrix*(kb**2*Sim.integrator.getTemperature()**2*Sim.integrator.getNumCopies()/(2.0*hbar**2)))#spring energy +# return springE +# else: +# return 0.0*kilojoule/mole + def energy_components(Sim, verbose=False): # Before using EnergyComponents, make sure each Force is set to a different group. EnergyTerms = OrderedDict() @@ -41,7 +61,74 @@ def energy_components(Sim, verbose=False): for i in range(Sim.system.getNumForces()): EnergyTerms[Sim.system.getForce(i).__class__.__name__] = Sim.context.getState(getEnergy=True,groups=2**i).getPotentialEnergy() / kilojoules_per_mole return EnergyTerms - +def centroid_position(Sim): + ##Calculate RPMD centroid position in RPMD simulation(May not be what you actually need!), no difference from simply call getPosition in Classical simulation + if isinstance(Sim.integrator, RPMDIntegrator): + centroid=np.array([[0.0*nanometer,0.0*nanometer,0.0*nanometer]]*Sim.system.getNumParticles()) + for i in range(Sim.integrator.getNumCopies()): + centroid=centroid+np.array(Sim.integrator.getState(i,getPositions=True).getPositions())/Sim.integrator.getNumCopies()#Calculate centroid of ring polymer + return centroid + else: + return Sim.context.getState(getPositions=True).getPositions() +def evaluate_potential(Sim): + # Getting potential energy, taking RPMD into account(average over 4 copies of systems). If running classical simulation, it does nothing more than calling the getPotential energy function + if isinstance(Sim.integrator, RPMDIntegrator): + PE=0.0*kilojoule/mole + nob=Sim.integrator.getNumCopies() + hello=int(nob/4) + for i in range(0,nob,hello): + PE=PE+Sim.integrator.getState(i,getEnergy=True).getPotentialEnergy()/4.0 + return PE + else: + return Sim.context.getState(getEnergy=True).getPotentialEnergy() +def evaluate_kinetic(Sim): + # It gets kinetic energy for classical simulation, or kinetic energy in classical sense(i.e. only dep. on how fast particles move) in RPMD simulation(sample to thermostat T*# of beads). It's NOT a quantum kinetic energy estimator. + if isinstance(Sim.integrator, RPMDIntegrator): + KE=0.0*kilojoule/mole + nob=Sim.integrator.getNumCopies() + hello=int(nob/4) + for i in range(0,nob,hello): + KE=KE+Sim.integrator.getState(i,getEnergy=True).getKineticEnergy()/4.0 + return KE + else: + return Sim.context.getState(getEnergy=True).getKineticEnergy() +def primitive_kinetic(Sim): + # This is primitive quantum kinetic energy estimator for RPMD simulation. Return classical KE in classical simulation. + if isinstance(Sim.integrator,RPMDIntegrator): + priKE=0.0*kilojoule/mole + hbar=0.0635078*nanometer**2*dalton/picosecond + kb=0.00831446*nanometer**2*dalton/(picosecond**2*kelvin) + for i in range(Sim.integrator.getNumCopies()): + priKE=priKE+Sim.integrator.getState(i,getEnergy=True).getKineticEnergy()/(Sim.integrator.getNumCopies()) #First term in primitive KE + mass_matrix=[] + for i in range(Sim.system.getNumParticles()): + mass_matrix.append(Sim.system.getParticleMass(i)) + mass_matrix=np.array(mass_matrix) + for i in range(Sim.integrator.getNumCopies()): + j=(i+1)%(Sim.integrator.getNumCopies()) + beaddif=np.array(Sim.integrator.getState(j,getPositions=True).getPositions())-np.array(Sim.integrator.getState(i,getPositions=True).getPositions())#calculate difference between ith and i+1th bead + priKE=priKE-np.sum(((beaddif*beaddif).sum(axis=1))*mass_matrix*(kb**2*Sim.integrator.getTemperature()**2*Sim.integrator.getNumCopies()/(2.0*hbar**2)))#2nd term in primitive estimator + return priKE + else: + return Sim.context.getState(getEnergy=True).getKineticEnergy() +def centroid_kinetic(Sim): + # This is centroid quantum kinetic energy estimator for RPMD simulation. Return classical KE in classical simulation. + if isinstance(Sim.integrator,RPMDIntegrator): + cenKE=0.0*kilojoule/mole + nob=Sim.integrator.getNumCopies() + hello=int(nob/4) + for i in range(0,nob,hello): + cenKE=cenKE+Sim.integrator.getState(i,getEnergy=True).getKineticEnergy()/(nob*4.0)#First term in centroid KE + centroid=np.array([[0.0*nanometer,0.0*nanometer,0.0*nanometer]]*Sim.system.getNumParticles()) + for i in range(0,nob,hello): + centroid=centroid+np.array(Sim.integrator.getState(i,getPositions=True).getPositions())/4.0#Calculate centroid of ring polymer + for i in range(0,nob,hello):#2nd term of centroid KE + dif=np.array(Sim.integrator.getState(i,getPositions=True).getPositions())-centroid + der=-1.0*np.array(Sim.integrator.getState(i,getForces=True).getForces()) + cenKE=cenKE+np.sum((dif*der).sum(axis=1))*0.5/4.0 + return cenKE + else: + return Sim.context.getState(getEnergy=True).getKineticEnergy() def get_multipoles(simulation,q=None,mass=None,positions=None,rmcom=True): """Return the current multipole moments in Debye and Buckingham units. """ dx = 0.0 @@ -98,6 +185,9 @@ def get_multipoles(simulation,q=None,mass=None,positions=None,rmcom=True): qzz -= tr/3 # This ordering has to do with the way TINKER prints it out. return [dx,dy,dz,qxx,qxy,qyy,qxz,qyz,qzz] +#def get_multipoles_ave(simulation,q=None,mass=None,positions=None,rmcom=True) +# If RPMD simulation, average over all copies of systems, else(in classical simulation) just do the same thing get_multipoles do + def get_dipole(simulation,q=None,mass=None,positions=None): """Return the current dipole moment in Debye. @@ -262,6 +352,16 @@ def CopyNonbondedParameters(src, dest): for i in range(src.getNumExceptions()): dest.setExceptionParameters(i,*src.getExceptionParameters(i)) +def CopyCustomBondParameters(src, dest): + dest.setEnergyFunction(src.getEnergyFunction()) + for i in range(src.getNumGlobalParameters()): + dest.setGlobalParameterName(i,src.GlobalParameterName(i)) + for i in range(src.getNumGlobalParameters()): + dest.setGlobalParameterDefaultValue(i,*src.getGlobalParameterDefaultValue(i)) + for i in range(src.getNumPerBondParameters()): + dest.setPerBondParameterName(i,src.getPerBondParameterName(i)) + for i in range(src.getNumBonds()): + dest.setBondParameters(i,*src.getBondParameters(i)) def do_nothing(src, dest): return @@ -279,6 +379,7 @@ def CopySystemParameters(src,dest): 'HarmonicAngleForce':CopyHarmonicAngleParameters, 'PeriodicTorsionForce':CopyPeriodicTorsionParameters, 'NonbondedForce':CopyNonbondedParameters, + 'CustomBondForce':CopyCustomBondParameters, 'CMMotionRemover':do_nothing} for i in range(src.getNumForces()): nm = src.getForce(i).__class__.__name__ @@ -620,14 +721,13 @@ def prepare(self, pbc=False, mmopts={}, **kwargs): self.AtomLists['ResidueNumber'] = [a.residue.index for a in Atoms] self.AtomMask = [a == 'A' for a in self.AtomLists['ParticleType']] - def create_simulation(self, timestep=1.0, faststep=0.25, temperature=None, pressure=None, anisotropic=False, mts=False, collision=1.0, nbarostat=25, rpmd_beads=0, **kwargs): + def create_simulation(self, timestep=1.0, faststep=0.25, temperature=None, pressure=None, anisotropic=False, mts=False, collision=1.0, nbarostat=25, rpmd_beads=[], **kwargs): """ Create simulation object. Note that this also takes in some options pertinent to system setup, including the type of MD integrator and type of pressure control. """ - # Divisor for the temperature (RPMD sets it to nonzero.) self.tdiv = 1 @@ -635,24 +735,57 @@ def create_simulation(self, timestep=1.0, faststep=0.25, temperature=None, press if temperature: ## If temperature control is turned on, then run Langevin dynamics. if mts: - if rpmd_beads > 0: + if len(rpmd_beads) > 0: raise RuntimeError("No multiple timestep integrator without temperature control.") integrator = MTSVVVRIntegrator(temperature*kelvin, collision/picosecond, timestep*femtosecond, self.system, ninnersteps=int(timestep/faststep)) else: - if rpmd_beads > 0: - logger.info("Creating RPMD integrator with %i beads.\n" % rpmd_beads) - self.tdiv = rpmd_beads - integrator = RPMDIntegrator(rpmd_beads, temperature*kelvin, collision/picosecond, timestep*femtosecond) + if len(rpmd_beads) > 0: + self.tdiv = int(rpmd_beads[0]) + if len(rpmd_beads) == 1: + logger.info("Creating RPMD integrator with %i beads.\n" % int(rpmd_beads[0])) + integrator = RPMDIntegrator(int(rpmd_beads[0]), temperature*kelvin, collision/picosecond, timestep*femtosecond) + elif len(rpmd_beads) == 2: + contract = False + for frc in self.system.getForces(): + if any([isinstance(frc, fc) for fc in [NonbondedForce, AmoebaMultipoleForce, AmoebaVdwForce, CustomNonbondedForce]]): + contract = True + frc.setForceGroup(1) + if contract: + logger.info("Creating RPMD integrator with %i beads (NB forces contracted to %i).\n" % (int(rpmd_beads[0]), int(rpmd_beads[1]))) + integrator = RPMDIntegrator(int(rpmd_beads[0]), temperature*kelvin, collision/picosecond, timestep*femtosecond, {1:int(rpmd_beads[1])}) + else: + logger.info("Creating RPMD integrator with %i beads (no NB forces to contract).\n" % (int(rpmd_beads[0]))) + integrator = RPMDIntegrator(int(rpmd_beads[0]), temperature*kelvin, collision/picosecond, timestep*femtosecond) + elif len(rpmd_beads) == 3: + contract = False + contract_recip = False + for frc in self.system.getForces(): + if any([isinstance(frc, fc) for fc in [NonbondedForce, AmoebaMultipoleForce, AmoebaVdwForce, CustomNonbondedForce]]): + contract = True + frc.setForceGroup(1) + if isinstance(frc, NonbondedForce): + contract_recip = True + frc.setReciprocalSpaceForceGroup(2) + if contract_recip: + logger.info("Creating RPMD integrator with %i beads (NB/Recip forces contracted to %i/%i).\n" % (int(rpmd_beads[0]), int(rpmd_beads[1]), int(rpmd_beads[2]))) + integrator = RPMDIntegrator(int(rpmd_beads[0]), temperature*kelvin, collision/picosecond, timestep*femtosecond, {1:int(rpmd_beads[1]), 2:int(rpmd_beads[2])}) + elif contract: + logger.info("Creating RPMD integrator with %i beads (NB forces contracted to %i, no Recip).\n" % (int(rpmd_beads[0]), int(rpmd_beads[1]))) + integrator = RPMDIntegrator(int(rpmd_beads[0]), temperature*kelvin, collision/picosecond, timestep*femtosecond, {1:int(rpmd_beads[1])}) + else: + logger.info("Creating RPMD integrator with %i beads (no NB forces to contract).\n" % (int(rpmd_beads[0]))) + integrator = RPMDIntegrator(int(rpmd_beads[0]), temperature*kelvin, collision/picosecond, timestep*femtosecond) + else: + raise RuntimeError("Please provide a list of length 1, 2, or 3 to rpmd_beads") else: integrator = LangevinIntegrator(temperature*kelvin, collision/picosecond, timestep*femtosecond) else: ## If no temperature control, default to the Verlet integrator. - if rpmd_beads > 0: + if len(rpmd_beads) > 0: raise RuntimeError("No RPMD integrator without temperature control.") if mts: warn_once("No multiple timestep integrator without temperature control.") integrator = VerletIntegrator(timestep*femtoseconds) - ## Add the barostat. if pressure != None: if anisotropic: @@ -664,22 +797,21 @@ def create_simulation(self, timestep=1.0, faststep=0.25, temperature=None, press elif pressure != None: warn_once("Pressure is ignored because pbc is set to False.") ## Set up for energy component analysis. - if not mts: + if not mts and len(rpmd_beads) == 0: for i, j in enumerate(self.system.getForces()): j.setForceGroup(i) ## If virtual particles are used with AMOEBA... SetAmoebaVirtualExclusions(self.system) - + ## Finally create the simulation object. self.simulation = Simulation(self.mod.topology, self.system, integrator, self.platform) - + #fffff.write(XmlSerializer.serialize(self.simulation.system)) ## Print platform properties. # logger.info("I'm using the platform %s\n" % self.simulation.context.getPlatform().getName()) # printcool_dictionary({i:self.simulation.context.getPlatform().getPropertyValue(self.simulation.context,i) \ # for i in self.simulation.context.getPlatform().getPropertyNames()}, \ # title="Platform %s has properties:" % self.simulation.context.getPlatform().getName()) - def update_simulation(self, **kwargs): """ @@ -714,7 +846,6 @@ def update_simulation(self, **kwargs): UpdateSimulationParameters(self.system, self.simulation) else: self.create_simulation(**self.simkwargs) - def set_positions(self, shot=0, traj=None): """ @@ -735,12 +866,21 @@ def set_positions(self, shot=0, traj=None): #---- # NOTE: Periodic box vectors must be set FIRST if self.pbc: - self.simulation.context.setPeriodicBoxVectors(*self.xyz_omms[shot][1]) + self.simulation.context.setPeriodicBoxVectors(*self.xyz_omms[shot][1]) # self.simulation.context.setPositions(ResetVirtualSites(self.xyz_omms[shot][0], self.system)) # self.simulation.context.setPositions(ResetVirtualSites_fast(self.xyz_omms[shot][0], self.vsinfo)) self.simulation.context.setPositions(self.xyz_omms[shot][0]) self.simulation.context.computeVirtualSites() - + if self.tdiv>1:#RPMDintegrator + integrator=self.simulation.context.getIntegrator() + for i in range(self.tdiv): + integrator.setPositions(i,self.xyz_omms[shot][0]) +# for i in range(self.tdiv): +# temp_position=integrator.getState(i,getPositions=True).getPositions() +# self.simulation.context.setPositions(temp_position) +# self.simulation.context.computeVirtualSites() +# position_with_virtual_site=self.simulation.context.getState(getPositions=True).getPositions() +# integrator.setPositions(i,position_with_virtual_site) def compute_volume(self, box_vectors): """ Compute the total volume of an OpenMM system. """ [a,b,c] = box_vectors @@ -928,7 +1068,6 @@ def interaction_energy(self, fraga, fragb): B = self.B.energy() return (D - A - B) / 4.184 - def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, nequil=0, nsave=1000, minimize=True, anisotropic=False, save_traj=False, verbose=False, **kwargs): """ @@ -990,7 +1129,6 @@ def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, # Determine number of degrees of freedom. self.ndof = 3*(self.system.getNumParticles() - sum([self.system.isVirtualSite(i) for i in range(self.system.getNumParticles())])) \ - self.system.getNumConstraints() - 3*self.pbc - # Initialize statistics. edecomp = OrderedDict() # Stored coordinates, box vectors @@ -1007,6 +1145,7 @@ def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, #========================# # Initialize velocities. self.simulation.context.setVelocitiesToTemperature(temperature*kelvin) + #print(XmlSerializer.serialize(self.simulation.system)) # Equilibrate. if iequil > 0: if verbose: logger.info("Equilibrating...\n") @@ -1014,12 +1153,19 @@ def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, if verbose: logger.info("%6s %9s %9s %13s %10s %13s\n" % ("Iter.", "Time(ps)", "Temp(K)", "Epot(kJ/mol)", "Vol(nm^3)", "Rho(kg/m^3)")) else: if verbose: logger.info("%6s %9s %9s %13s\n" % ("Iter.", "Time(ps)", "Temp(K)", "Epot(kJ/mol)")) - for iteration in range(-1, iequil): + for iteration in range(-1 if self.tdiv == 1 else 0, iequil): if iteration >= 0: self.simulation.step(nsave) state = self.simulation.context.getState(getEnergy=True,getPositions=True,getVelocities=False,getForces=False) - kinetic = state.getKineticEnergy()/self.tdiv - potential = state.getPotentialEnergy() + +##### Energy Data +# kinetic=state.getKineticEnergy()/self.tdiv +# potential=state.getPotentialEnergy() + kinetic=evaluate_kinetic(self.simulation)/self.tdiv + potential=evaluate_potential(self.simulation) + #pri_kinetic=primitive_kinetic(self.simulation) + cen_kinetic=centroid_kinetic(self.simulation) +##### if self.pbc: box_vectors = state.getPeriodicBoxVectors() volume = self.compute_volume(box_vectors) @@ -1044,13 +1190,19 @@ def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, if save_traj: self.simulation.reporters.append(PDBReporter('%s-md.pdb' % self.name, nsteps)) self.simulation.reporters.append(DCDReporter('%s-md.dcd' % self.name, nsave)) - for iteration in range(-1, isteps): + for iteration in range(-1 if self.tdiv == 1 else 0, isteps): # Propagate dynamics. if iteration >= 0: self.simulation.step(nsave) # Compute properties. state = self.simulation.context.getState(getEnergy=True,getPositions=True,getVelocities=False,getForces=False) - kinetic = state.getKineticEnergy()/self.tdiv - potential = state.getPotentialEnergy() +##### Energy Data +# kinetic=state.getKineticEnergy()/self.tdiv +# potential=state.getPotentialEnergy() + kinetic=evaluate_kinetic(self.simulation)/self.tdiv + potential=evaluate_potential(self.simulation) + #pri_kinetic=primitive_kinetic(self.simulation) + cen_kinetic=centroid_kinetic(self.simulation) +##### kinetic_temperature = 2.0 * kinetic / kB / self.ndof if self.pbc: box_vectors = state.getPeriodicBoxVectors() @@ -1077,7 +1229,10 @@ def molecular_dynamics(self, nsteps, timestep, temperature=None, pressure=None, Temps.append(kinetic_temperature / kelvin) Rhos.append(density.value_in_unit(kilogram / meter**3)) Potentials.append(potential / kilojoules_per_mole) - Kinetics.append(kinetic / kilojoules_per_mole) + if self.tdiv>1: + Kinetics.append(cen_kinetic / kilojoules_per_mole)#If RPMD, we use centroid estimator to calculate quantum kinetic energy + else: + Kinetics.append(kinetic / kilojoules_per_mole)#else just classical kinetic energy Volumes.append(volume / nanometer**3) Dips.append(get_dipole(self.simulation,positions=self.xyz_omms[-1][0])) Rhos = np.array(Rhos) diff --git a/src/parser.py b/src/parser.py index 95343c86b..aaf4c6a6a 100644 --- a/src/parser.py +++ b/src/parser.py @@ -77,13 +77,13 @@ }, 'lists' : {"forcefield" : ([], 200, 'The names of force fields, corresponding to directory forcefields/file_name.(itp,xml,prm,frcmod,mol2)', 'All (important)'), "scanindex_num" : ([], -100, 'Numerical index of the parameter to scan over', 'Job types scan_mvals and scan_pvals'), - "scanindex_name" : ([], -100, 'Parameter name to scan over (should convert to a numerical index)', 'Job types scan_mvals and scan_pvals') + "scanindex_name" : ([], -100, 'Parameter name to scan over (should convert to a numerical index)', 'Job types scan_mvals and scan_pvals'), + "rpmd_beads" : ([], -160, 'Number of beads / NB contracted beads / Recip contracted beads in ring polymer MD', 'Condensed phase property targets (advanced usage)', 'liquid_openmm'), }, 'ints' : {"maxstep" : (100, 50, 'Maximum number of steps in an optimization', 'Main Optimizer'), "objective_history" : (2, 20, 'Number of good optimization steps to average over when checking the objective convergence criterion', 'Main Optimizer (jobtype "newton")'), "wq_port" : (0, 0, 'The port number to use for Work Queue', 'Targets that use Work Queue (advanced usage)'), "criteria" : (1, 160, 'The number of convergence criteria that must be met for main optimizer to converge', 'Main Optimizer'), - "rpmd_beads" : (0, -160, 'Number of beads in ring polymer MD (zero to disable)', 'Condensed phase property targets (advanced usage)', 'liquid_openmm'), "zerograd" : (-1, 0, 'Set to a nonnegative number to turn on zero gradient skipping at that optimization step.', 'All'), }, 'bools' : {"backup" : (1, 10, 'Write temp directories to backup before wiping them'),