"""
A collection of protocols for running analysing the results of molecular simulations.
"""
import logging
from os import path
import numpy as np
from propertyestimator import unit
from propertyestimator.utils import statistics, timeseries
from propertyestimator.utils.exceptions import PropertyEstimatorException
from propertyestimator.utils.quantities import EstimatedQuantity
from propertyestimator.utils.statistics import StatisticsArray, bootstrap
from propertyestimator.workflow.decorators import protocol_input, protocol_output, MergeBehaviour
from propertyestimator.workflow.plugins import register_calculation_protocol
from propertyestimator.workflow.protocols import BaseProtocol
[docs]@register_calculation_protocol()
class AveragePropertyProtocol(BaseProtocol):
"""An abstract base class for protocols which will calculate the
average of a property and its uncertainty via bootstrapping.
"""
@protocol_input(int, merge_behavior=MergeBehaviour.GreatestValue)
def bootstrap_iterations(self):
"""The number of bootstrap iterations to perform."""
pass
@protocol_input(float, merge_behavior=MergeBehaviour.GreatestValue)
def bootstrap_sample_size(self):
"""The relative sample size to use for bootstrapping."""
pass
@protocol_output(EstimatedQuantity)
def value(self):
"""The averaged value."""
pass
@protocol_output(int)
def equilibration_index(self):
"""The index in the data set after which the data is stationary."""
pass
@protocol_output(float)
def statistical_inefficiency(self):
"""The statistical inefficiency in the data set."""
pass
@protocol_output(unit.Quantity)
def uncorrelated_values(self):
"""The uncorrelated values which the average was calculated from."""
pass
[docs] def __init__(self, protocol_id):
super().__init__(protocol_id)
self._bootstrap_iterations = 250
self._bootstrap_sample_size = 1.0
self._value = None
self._equilibration_index = None
self._statistical_inefficiency = None
self._uncorrelated_values = None
def _bootstrap_function(self, **sample_kwargs):
"""The function to perform on the data set being sampled by
bootstrapping.
Parameters
----------
sample_kwargs: dict of str and np.ndarray
A key words dictionary of the bootstrap sample data, where the
sample data is a numpy array of shape=(num_frames, num_dimensions)
with dtype=float.
Returns
-------
float
The result of evaluating the data.
"""
assert len(sample_kwargs) == 1
sample_data = next(iter(sample_kwargs.values()))
return sample_data.mean()
[docs] def execute(self, directory, available_resources):
return self._get_output_dictionary()
[docs]@register_calculation_protocol()
class AverageTrajectoryProperty(AveragePropertyProtocol):
"""An abstract base class for protocols which will calculate the
average of a property from a simulation trajectory.
"""
@protocol_input(str)
def input_coordinate_file(self):
"""The file path to the starting coordinates of a trajectory."""
pass
@protocol_input(str)
def trajectory_path(self):
"""The file path to the trajectory to average over."""
pass
[docs] def __init__(self, protocol_id):
super().__init__(protocol_id)
self._input_coordinate_file = None
self._trajectory_path = None
self.trajectory = None
[docs] def execute(self, directory, available_resources):
import mdtraj
if self._trajectory_path is None:
return PropertyEstimatorException(directory=directory,
message='The AverageTrajectoryProperty protocol '
'requires a previously calculated trajectory')
self.trajectory = mdtraj.load_dcd(filename=self._trajectory_path, top=self._input_coordinate_file)
return self._get_output_dictionary()