Source code for molsysmt.third_party.openmm.reporters.tqdm
import time
from tqdm.auto import tqdm
[docs]
class TQDMReporter(object):
"""OpenMM reporter that displays progress via tqdm."""
[docs]
def __init__(
self,
reportInterval,
total_n_steps,
potential_energy=True,
temperature=True,
volume=False,
):
from openmm import unit
self._pbar = None
self._report_interval = reportInterval
if self._report_interval == 0:
self._report_interval = 1
self._total_n_steps = total_n_steps
self._with_potential_energy = potential_energy
self._potential_energy = None
self._with_temperature = temperature
self._temperature = None
self._with_volume = volume
self._volume = None
self._needs_positions = False
self._needs_velocities = False
self._needs_forces = False
self._needs_energy = potential_energy or temperature
self._initialized = False
self._dof = 0
self._U = 0.0 * unit.kilojoules_per_mole
self._U2 = 0.0 * unit.kilojoules_per_mole**2
self._T = 0.0 * unit.kelvin
self._T2 = 0.0 * unit.kelvin**2
self._V = 0.0 * unit.nanometers**3
self._V2 = 0.0 * unit.nanometers**6
self._iters = 0
self._start_time = None
self._end_time = None
self._start_md_time = None
self._end_md_time = None
self._md_time_step = None
def _initialize(self, simulation):
import openmm as mm
from openmm import unit
self._start_time = time.time()
self._pbar = tqdm(total=self._total_n_steps, position=0, leave=True)
post_fix_dict = {}
if self._with_potential_energy:
post_fix_dict["potential_energy"] = None
if self._with_temperature:
post_fix_dict["temperature"] = None
if self._with_volume:
post_fix_dict["volume"] = None
self._pbar.set_postfix(post_fix_dict)
if self._with_temperature:
frclist = simulation.system.getForces()
dof = 0
for i in range(simulation.system.getNumParticles()):
if simulation.system.getParticleMass(i) > 0.0 * unit.dalton:
dof += 3
dof -= simulation.system.getNumConstraints()
if any(isinstance(frc, mm.CMMotionRemover) for frc in frclist):
dof -= 3
self._dof = dof
initial_state = simulation.context.getState(
getPositions=self._needs_positions,
getVelocities=self._needs_velocities,
getForces=self._needs_forces,
getEnergy=self._needs_energy,
)
self._start_md_time = initial_state.getTime()
self._md_time_step = simulation.integrator.getStepSize()
self.report(simulation, initial_state)
del initial_state
self._initialized = True
def describeNextReport(self, simulation):
if not self._initialized:
self._initialize(simulation)
steps_left = simulation.currentStep % self._report_interval
steps = self._report_interval - steps_left
return (
steps,
self._needs_positions,
self._needs_velocities,
self._needs_forces,
self._needs_energy,
)
def report(self, simulation, state):
from openmm import unit
post_fix_dict = {}
if self._with_potential_energy:
aux = state.getPotentialEnergy()
self._U += aux
self._U2 += aux**2
post_fix_dict["potential_energy"] = aux.format("%.2f")
if self._with_temperature:
aux = 2 * state.getKineticEnergy() / (self._dof * unit.MOLAR_GAS_CONSTANT_R)
self._T += aux
self._T2 += aux**2
post_fix_dict["temperature"] = aux.format("%.2f")
if self._with_volume:
aux = state.getPeriodicBoxVolume()
self._V += aux
self._V2 += aux**2
post_fix_dict["volume"] = aux.format("%.2f")
self._iters += 1
self._pbar.set_postfix(post_fix_dict)
if simulation.currentStep == 0:
self._pbar.update(0)
else:
self._pbar.update(self._report_interval)
if (self._total_n_steps - simulation.currentStep) < self._report_interval:
self.finalize(state)
def finalize(self, state):
from openmm import unit
self._pbar.close()
self._end_md_time = state.getTime()
self._end_time = time.time()
execution_time = self._end_time - self._start_time
days, remainder = divmod(execution_time, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
days = int(days)
hours = int(hours)
minutes = int(minutes)
seconds = round(seconds, 2)
nanoseconds_md = (self._end_md_time - self._start_md_time).in_units_of(
unit.nanoseconds
)
nanoseconds_per_hour = (nanoseconds_md._value / execution_time) * 3600 * 24
nanoseconds_per_hour = round(nanoseconds_per_hour, 3)
print("")
if self._with_potential_energy:
mean = self._U / self._iters
std = (self._U2 / self._iters - mean**2) ** 0.5
print(f"Potential energy: {mean.format('%.2f')} ± {std.format('%.2f')}")
if self._with_temperature:
mean = self._T / self._iters
std = (self._T2 / self._iters - mean**2) ** 0.5
print(f"Temperature: {mean.format('%.2f')} ± {std.format('%.2f')}")
if self._with_volume:
mean = self._V / self._iters
std = (self._V2 / self._iters - mean**2) ** 0.5
print(f"Volume: {mean.format('%.2f')} ± {std.format('%.2f')}")
print("")
print(
f"Execution time: {days} days, {hours} hours, {minutes} minutes, and {seconds} seconds ({nanoseconds_per_hour} ns/day)."
)
print("")
pass