def _execute_without_bootstrapping(self, observable_unit, **observables): """Calculates the average reweighted observables at the target state, using the built-in pymbar method to estimate uncertainties. Parameters ---------- observables: dict of str and numpy.ndarray The observables to reweight which have been stripped of their units. """ if len(observables) > 1: raise ValueError('Currently only a single observable can be reweighted at' 'any one time.') reference_reduced_potentials, target_reduced_potentials = self._load_reduced_potentials() values, uncertainties, self.effective_samples = self._reweight_observables(reference_reduced_potentials, target_reduced_potentials, **observables) observable_key = next(iter(observables)) uncertainty = uncertainties[observable_key] if self.effective_samples < self.required_effective_samples: return PropertyEstimatorException(message=f'{self.id}: There was not enough effective samples ' f'to reweight - {self.effective_samples} < ' f'{self.required_effective_samples}') self.value = EstimatedQuantity(values[observable_key] * observable_unit, uncertainty * observable_unit, self.id)
def _execute_with_bootstrapping(self, observable_unit, **observables): """Calculates the average reweighted observables at the target state, using bootstrapping to estimate uncertainties. Parameters ---------- observable_unit: propertyestimator.unit.Unit: The expected unit of the reweighted observable. observables: dict of str and numpy.ndarray The observables to reweight which have been stripped of their units. Returns ------- PropertyEstimatorException, optional None if the method executed normally, otherwise the exception that was raised. """ reference_reduced_potentials, target_reduced_potentials = self._load_reduced_potentials() frame_counts = np.array([len(observable) for observable in self._reference_observables]) # Construct a dummy mbar object to get out the number of effective samples. mbar = self._construct_mbar_object(reference_reduced_potentials) (self.effective_samples, effective_sample_indices) = self._compute_effective_samples(mbar, target_reduced_potentials) if self.effective_samples < self.required_effective_samples: return PropertyEstimatorException(message=f'{self.id}: There was not enough effective samples ' f'to reweight - {self.effective_samples} < ' f'{self.required_effective_samples}') # Transpose the observables ready for bootstrapping. reference_reduced_potentials = np.transpose(reference_reduced_potentials) target_reduced_potentials = np.transpose(target_reduced_potentials) transposed_observables = {} for observable_key in observables: transposed_observables[observable_key] = np.transpose(observables[observable_key]) value, uncertainty = bootstrap(self._bootstrap_function, self.bootstrap_iterations, self.bootstrap_sample_size, frame_counts, reference_reduced_potentials=reference_reduced_potentials, target_reduced_potentials=target_reduced_potentials, **transposed_observables) self.effective_sample_indices = effective_sample_indices self.value = EstimatedQuantity(value * observable_unit, uncertainty * observable_unit, self.id)
def execute(self, directory, available_resources): logging.info('Extracting {}: {}'.format(self.statistics_type, self.id)) if self.statistics_path is None: return PropertyEstimatorException(directory=directory, message='The ExtractAverageStatistic protocol ' 'requires a previously calculated statistics file') self._statistics = statistics.StatisticsArray.from_pandas_csv(self.statistics_path) if self.statistics_type not in self._statistics: return PropertyEstimatorException(directory=directory, message=f'The {self.statistics_path} statistics file contains no ' f'data of type {self.statistics_type}.') values = self._statistics[self.statistics_type] statistics_unit = values[0].units unitless_values = values.to(statistics_unit).magnitude divisor = self.divisor if isinstance(self.divisor, unit.Quantity): statistics_unit /= self.divisor.units divisor = self.divisor.magnitude unitless_values = np.array(unitless_values) / divisor unitless_values, self.equilibration_index, self.statistical_inefficiency = \ timeseries.decorrelate_time_series(unitless_values) final_value, final_uncertainty = bootstrap(self._bootstrap_function, self.bootstrap_iterations, self.bootstrap_sample_size, values=unitless_values) self.uncorrelated_values = unitless_values * statistics_unit self.value = EstimatedQuantity(final_value * statistics_unit, final_uncertainty * statistics_unit, self.id) logging.info('Extracted {}: {}'.format(self.statistics_type, self.id)) return self._get_output_dictionary()
def test_simple_workflow_graph(): dummy_schema = WorkflowSchema() dummy_protocol_a = DummyInputOutputProtocol('protocol_a') dummy_protocol_a.input_value = EstimatedQuantity(1 * unit.kelvin, 0.1 * unit.kelvin, 'dummy_source') dummy_schema.protocols[dummy_protocol_a.id] = dummy_protocol_a.schema dummy_protocol_b = DummyInputOutputProtocol('protocol_b') dummy_protocol_b.input_value = ProtocolPath('output_value', dummy_protocol_a.id) dummy_schema.protocols[dummy_protocol_b.id] = dummy_protocol_b.schema dummy_schema.final_value_source = ProtocolPath('output_value', dummy_protocol_b.id) dummy_schema.validate_interfaces() dummy_property = create_dummy_property(Density) dummy_workflow = Workflow(dummy_property, {}) dummy_workflow.schema = dummy_schema with tempfile.TemporaryDirectory() as temporary_directory: workflow_graph = WorkflowGraph(temporary_directory) workflow_graph.add_workflow(dummy_workflow) dask_local_backend = DaskLocalCluster(1, ComputeResources(1)) dask_local_backend.start() results_futures = workflow_graph.submit(dask_local_backend) assert len(results_futures) == 1 result = results_futures[0].result() assert isinstance(result, CalculationLayerResult) assert result.calculated_property.value == 1 * unit.kelvin
from propertyestimator import unit from propertyestimator.backends import ComputeResources from propertyestimator.properties import ParameterGradient, ParameterGradientKey from propertyestimator.protocols.miscellaneous import AddValues, FilterSubstanceByRole, SubtractValues, MultiplyValue, \ DivideValue, WeightByMoleFraction from propertyestimator.substances import Substance from propertyestimator.utils.exceptions import PropertyEstimatorException from propertyestimator.utils.quantities import EstimatedQuantity @pytest.mark.parametrize("values", [ [random.randint(1, 10) for _ in range(10)], [random.random() for _ in range(10)], [random.random() * unit.kelvin for _ in range(10)], [EstimatedQuantity(random.random() * unit.kelvin, random.random() * unit.kelvin, f'{x}') for x in range(10)], [ParameterGradient(ParameterGradientKey('a', 'b', 'c'), random.random() * unit.kelvin) for x in range(10)] ]) def test_add_values_protocol(values): with tempfile.TemporaryDirectory() as temporary_directory: add_quantities = AddValues('add') add_quantities.values = values result = add_quantities.execute(temporary_directory, ComputeResources()) assert not isinstance(result, PropertyEstimatorException) assert add_quantities.result == reduce(operator.add, values)