Skip to content

Commit

Permalink
Blackfy the code (#280)
Browse files Browse the repository at this point in the history
* black (we now use black for code formatting, see also 
   https://github.com/alchemistry/alchemlyb/wiki/Developer-Guide#style-guide )
* ci
* change log
  • Loading branch information
xiki-tempula authored Dec 6, 2022
1 parent 380302d commit 0095be2
Show file tree
Hide file tree
Showing 43 changed files with 2,901 additions and 2,035 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:
- name: Run tests
run: |
pytest -v -n 2 --cov=alchemlyb --cov-report=xml --color=yes src/alchemlyb/tests
pytest -v -n 2 --black --cov=alchemlyb --cov-report=xml --color=yes src/alchemlyb/tests
env:
MPLBACKEND: agg

Expand Down
5 changes: 4 additions & 1 deletion CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ The rules for this file:
* release numbers follow "Semantic Versioning" https://semver.org

------------------------------------------------------------------------------
??/??/2022 DrDomenicoMarson
??/??/2022 DrDomenicoMarson, xiki-tempula

* 1.0.1

Enhancements
- Blackfy the codebase (PR #280).

Fixes
- Remove most of the iloc in the tests (issue #202, PR #254).
- AMBER parser now raises ValueError when the initial simulation time
Expand Down
1 change: 1 addition & 0 deletions devtools/conda-envs/test_env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
- pytest-black
- codecov
35 changes: 20 additions & 15 deletions src/alchemlyb/__init__.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
import pandas as pd
from functools import wraps

import pandas as pd

from ._version import get_versions
__version__ = get_versions()['version']

__version__ = get_versions()["version"]
del get_versions


def pass_attrs(func):
'''Pass the attrs from the first positional argument to the output
"""Pass the attrs from the first positional argument to the output
dataframe.
.. versionadded:: 0.5.0
'''
"""

@wraps(func)
def wrapper(input_dataframe, *args,**kwargs):
dataframe = func(input_dataframe, *args,**kwargs)
def wrapper(input_dataframe, *args, **kwargs):
dataframe = func(input_dataframe, *args, **kwargs)
dataframe.attrs = input_dataframe.attrs
return dataframe

return wrapper


def concat(objs, *args, **kwargs):
'''Concatenate pandas objects while persevering the attrs.
"""Concatenate pandas objects while persevering the attrs.
Concatenate pandas objects along a particular axis with optional set
logic along the other axes. If all pandas objects have the same attrs
Expand All @@ -46,16 +51,16 @@ def concat(objs, *args, **kwargs):
See Also
--------
pandas.concat
.. versionadded:: 0.5.0'''
.. versionadded:: 0.5.0"""
# Sanity check
try:
attrs = objs[0].attrs
except IndexError: # except empty list as input
raise ValueError('No objects to concatenate')
except IndexError: # except empty list as input
raise ValueError("No objects to concatenate")

for obj in objs:
if attrs != obj.attrs:
raise ValueError('All pandas objects should have the same attrs.')
raise ValueError("All pandas objects should have the same attrs.")
return pd.concat(objs, *args, **kwargs)
130 changes: 77 additions & 53 deletions src/alchemlyb/convergence/convergence.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
import logging
from warnings import warn

import pandas as pd
import numpy as np
import pandas as pd

from ..estimators import BAR, TI, FEP_ESTIMATORS, TI_ESTIMATORS
from ..estimators import AutoMBAR as MBAR
from .. import concat
from ..estimators import AutoMBAR as MBAR
from ..estimators import BAR, TI, FEP_ESTIMATORS, TI_ESTIMATORS
from ..postprocessors.units import to_kT

estimators_dispatch = {"BAR": BAR, "TI": TI, "MBAR": MBAR}


def forward_backward_convergence(df_list, estimator='MBAR', num=10, **kwargs):
'''Forward and backward convergence of the free energy estimate.
def forward_backward_convergence(df_list, estimator="MBAR", num=10, **kwargs):
"""Forward and backward convergence of the free energy estimate.
Generate the free energy estimate as a function of time in both directions,
with the specified number of equally spaced points in the time
Expand Down Expand Up @@ -69,16 +71,17 @@ def forward_backward_convergence(df_list, estimator='MBAR', num=10, **kwargs):
The default for using ``estimator='MBAR'`` was changed from
:class:`~alchemlyb.estimators.MBAR` to :class:`~alchemlyb.estimators.AutoMBAR`.
'''
logger = logging.getLogger('alchemlyb.convergence.'
'forward_backward_convergence')
logger.info('Start convergence analysis.')
logger.info('Check data availability.')
"""
logger = logging.getLogger("alchemlyb.convergence." "forward_backward_convergence")
logger.info("Start convergence analysis.")
logger.info("Check data availability.")
if estimator.upper() != estimator:
warn("Using lower-case strings for the 'estimator' kwarg in "
"convergence.forward_backward_convergence() is deprecated in "
"1.0.0 and only upper case will be accepted in 2.0.0",
DeprecationWarning)
warn(
"Using lower-case strings for the 'estimator' kwarg in "
"convergence.forward_backward_convergence() is deprecated in "
"1.0.0 and only upper case will be accepted in 2.0.0",
DeprecationWarning,
)
estimator = estimator.upper()

if estimator not in (FEP_ESTIMATORS + TI_ESTIMATORS):
Expand All @@ -87,62 +90,78 @@ def forward_backward_convergence(df_list, estimator='MBAR', num=10, **kwargs):
raise ValueError(msg)
else:
# select estimator class by name
estimator_fit = globals()[estimator](**kwargs).fit
logger.info(f'Use {estimator} estimator for convergence analysis.')
estimator_fit = estimators_dispatch[estimator](**kwargs).fit
logger.info(f"Use {estimator} estimator for convergence analysis.")

logger.info('Begin forward analysis')
logger.info("Begin forward analysis")
forward_list = []
forward_error_list = []
for i in range(1, num + 1):
logger.info('Forward analysis: {:.2f}%'.format(100 * i / num))
logger.info("Forward analysis: {:.2f}%".format(100 * i / num))
sample = []
for data in df_list:
sample.append(data[:len(data) // num * i])
sample.append(data[: len(data) // num * i])
sample = concat(sample)
result = estimator_fit(sample)
forward_list.append(result.delta_f_.iloc[0, -1])
if estimator.lower() == 'bar':
error = np.sqrt(sum(
[result.d_delta_f_.iloc[i, i + 1] ** 2
for i in range(len(result.d_delta_f_) - 1)]))
if estimator.lower() == "bar":
error = np.sqrt(
sum(
[
result.d_delta_f_.iloc[i, i + 1] ** 2
for i in range(len(result.d_delta_f_) - 1)
]
)
)
forward_error_list.append(error)
else:
forward_error_list.append(result.d_delta_f_.iloc[0, -1])
logger.info('{:.2f} +/- {:.2f} kT'.format(forward_list[-1],
forward_error_list[-1]))
logger.info(
"{:.2f} +/- {:.2f} kT".format(forward_list[-1], forward_error_list[-1])
)

logger.info('Begin backward analysis')
logger.info("Begin backward analysis")
backward_list = []
backward_error_list = []
for i in range(1, num + 1):
logger.info('Backward analysis: {:.2f}%'.format(100 * i / num))
logger.info("Backward analysis: {:.2f}%".format(100 * i / num))
sample = []
for data in df_list:
sample.append(data[-len(data) // num * i:])
sample.append(data[-len(data) // num * i :])
sample = concat(sample)
result = estimator_fit(sample)
backward_list.append(result.delta_f_.iloc[0, -1])
if estimator.lower() == 'bar':
error = np.sqrt(sum(
[result.d_delta_f_.iloc[i, i + 1] ** 2
for i in range(len(result.d_delta_f_) - 1)]))
if estimator.lower() == "bar":
error = np.sqrt(
sum(
[
result.d_delta_f_.iloc[i, i + 1] ** 2
for i in range(len(result.d_delta_f_) - 1)
]
)
)
backward_error_list.append(error)
else:
backward_error_list.append(result.d_delta_f_.iloc[0, -1])
logger.info('{:.2f} +/- {:.2f} kT'.format(backward_list[-1],
backward_error_list[-1]))
logger.info(
"{:.2f} +/- {:.2f} kT".format(backward_list[-1], backward_error_list[-1])
)

convergence = pd.DataFrame(
{'Forward': forward_list,
'Forward_Error': forward_error_list,
'Backward': backward_list,
'Backward_Error': backward_error_list,
'data_fraction': [i / num for i in range(1, num + 1)]})
{
"Forward": forward_list,
"Forward_Error": forward_error_list,
"Backward": backward_list,
"Backward_Error": backward_error_list,
"data_fraction": [i / num for i in range(1, num + 1)],
}
)
convergence.attrs = df_list[0].attrs
return convergence


def _cummean(vals, out_length):
'''The cumulative mean of an array.
"""The cumulative mean of an array.
This function computes the cumulative mean and shapes the result to the
desired length.
Expand All @@ -167,18 +186,19 @@ def _cummean(vals, out_length):
.. versionadded:: 1.0.0
'''
"""
in_length = len(vals)
if in_length < out_length:
out_length = in_length
block = in_length // out_length
reshape = vals[: block*out_length].reshape(block, out_length)
reshape = vals[: block * out_length].reshape(block, out_length)
mean = np.mean(reshape, axis=0)
result = np.cumsum(mean) / np.arange(1, out_length+1)
result = np.cumsum(mean) / np.arange(1, out_length + 1)
return result


def fwdrev_cumavg_Rc(series, precision=0.01, tol=2):
'''Generate the convergence criteria :math:`R_c` for a single simulation.
"""Generate the convergence criteria :math:`R_c` for a single simulation.
The input will be :class:`pandas.Series` generated by
:func:`~alchemlyb.preprocessing.subsampling.decorrelate_u_nk` or
Expand Down Expand Up @@ -241,7 +261,7 @@ def fwdrev_cumavg_Rc(series, precision=0.01, tol=2):
.. _`equation 16`:
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8397498/#FD16
'''
"""
series = to_kT(series)
array = series.to_numpy()
out_length = int(1 / precision)
Expand All @@ -250,9 +270,12 @@ def fwdrev_cumavg_Rc(series, precision=0.01, tol=2):
length = len(g_forward)

convergence = pd.DataFrame(
{'Forward': g_forward,
'Backward': g_backward,
'data_fraction': [i / length for i in range(1, length + 1)]})
{
"Forward": g_forward,
"Backward": g_backward,
"data_fraction": [i / length for i in range(1, length + 1)],
}
)
convergence.attrs = series.attrs

# Final value
Expand All @@ -270,8 +293,9 @@ def fwdrev_cumavg_Rc(series, precision=0.01, tol=2):
# the same as this branch will be triggered.
return 1.0, convergence


def A_c(series_list, precision=0.01, tol=2):
'''Generate the ensemble convergence criteria :math:`A_c` for a set of simulations.
"""Generate the ensemble convergence criteria :math:`A_c` for a set of simulations.
The input is a :class:`list` of :class:`pandas.Series` generated by
:func:`~alchemlyb.preprocessing.subsampling.decorrelate_u_nk` or
Expand Down Expand Up @@ -317,11 +341,11 @@ def A_c(series_list, precision=0.01, tol=2):
.. _`equation 18`:
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8397498/#FD18
'''
logger = logging.getLogger('alchemlyb.convergence.A_c')
"""
logger = logging.getLogger("alchemlyb.convergence.A_c")
n_R_c = len(series_list)
R_c_list = [fwdrev_cumavg_Rc(series, precision, tol)[0] for series in series_list]
logger.info(f'R_c list: {R_c_list}')
logger.info(f"R_c list: {R_c_list}")
# Integrate the R_c_list <= R_c over the range of 0 to 1
array_01 = np.hstack((R_c_list, [0, 1]))
sorted_array = np.sort(np.unique(array_01))
Expand All @@ -330,6 +354,6 @@ def A_c(series_list, precision=0.01, tol=2):
if i == 0:
continue
else:
d_R_c = sorted_array[-i] - sorted_array[-i-1]
d_R_c = sorted_array[-i] - sorted_array[-i - 1]
result += d_R_c * sum(R_c_list <= element) / n_R_c
return result
2 changes: 1 addition & 1 deletion src/alchemlyb/estimators/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .mbar_ import MBAR, AutoMBAR
from .bar_ import BAR
from .mbar_ import MBAR, AutoMBAR
from .ti_ import TI

FEP_ESTIMATORS = [MBAR.__name__, AutoMBAR.__name__, BAR.__name__]
Expand Down
Loading

0 comments on commit 0095be2

Please sign in to comment.