Skip to content

Commit

Permalink
Merge pull request #165 from alchemistry/prep-051
Browse files Browse the repository at this point in the history
prepare 0.5.1 release
  • Loading branch information
orbeckst authored Sep 17, 2021
2 parents 5f61841 + 15d843a commit 2e96340
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 27 deletions.
4 changes: 3 additions & 1 deletion CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The rules for this file:
* release numbers follow "Semantic Versioning" https://semver.org

------------------------------------------------------------------------------
??/??/2021 xiki-tempula, orbeckst
09/17/2021 xiki-tempula, orbeckst

* 0.5.1

Expand All @@ -24,6 +24,8 @@ Changes (not affecting code)
Fixes
- MBAR estimator now correctly passes max_iterations to pymbar.MBAR. (PR #162)
- docs (PR #157)
- visualisation.df_state.plot_dF_state() now correctly raises ValueError instead
of NameError when incorrect orientation keyword argument is supplied


08/01/2021 xiki-tempula, orbeckst
Expand Down
19 changes: 10 additions & 9 deletions docs/api_principles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The following is an overview over the guiding principles and ideas that underpin
`alchemlyb` is a library that seeks to make doing alchemical free energy calculations easier and less error prone.
It includes functions for parsing data from formats common to existing MD engines, subsampling these data, and fitting these data with an estimator to obtain free energies.
These functions are simple in usage and pure in scope, and can be chained together to build customized analyses of data.
General and robust workflows following best practices are also provided, which can be used as reference implementations and examples.

`alchemlyb` seeks to be as boring and simple as possible to enable more complex work.
Its components allow work at all scales, from use on small systems using a single workstation to larger datasets that require distributed computing using libraries such as dask.
Expand Down Expand Up @@ -57,15 +58,15 @@ The library is structured as follows, following a similar style to
├── postprocessors
│   ├── ...
│   └── units.py
── visualisation
├── convergence.py
├── dF_state.py
├── mbar_matrix.py
├── ti_dhdl.py
└── ...

── visualisation
│   ├── convergence.py
│   ├── dF_state.py
│   ├── mbar_matrix.py
│   ├── ti_dhdl.py
│   └── ...
└── workflows
└── ...

The :mod:`~alchemlyb.parsing` submodule contains parsers for individual MD engines, since the output files needed to perform alchemical free energy calculations vary widely and are not standardized.
Each module at the very least provides an `extract_u_nk` function for extracting reduced potentials (needed for MBAR), as well as an `extract_dHdl` function for extracting derivatives required for thermodynamic integration.
Expand Down
64 changes: 48 additions & 16 deletions src/alchemlyb/tests/test_visualisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,34 @@ def test_plot_ti_dhdl():
dHdl_coul = alchemlyb.concat([extract_dHdl(xvg, T=300) for xvg in bz['Coulomb']])
ti_coul = TI()
ti_coul.fit(dHdl_coul)
assert isinstance(plot_ti_dhdl(ti_coul),
matplotlib.axes.Axes)

ax = plot_ti_dhdl(ti_coul)
assert isinstance(ax, matplotlib.axes.Axes)
plt.close(ax.figure)

fig, ax = plt.subplots(figsize=(8, 6))
assert isinstance(plot_ti_dhdl(ti_coul, ax=ax),
matplotlib.axes.Axes)
assert isinstance(plot_ti_dhdl(ti_coul, labels=['Coul']),
matplotlib.axes.Axes)
assert isinstance(plot_ti_dhdl(ti_coul, labels=['Coul'], colors=['r']),
matplotlib.axes.Axes)
plt.close(fig)

dHdl_vdw = alchemlyb.concat([extract_dHdl(xvg, T=300) for xvg in bz['VDW']])
ti_vdw = TI().fit(dHdl_vdw)
assert isinstance(plot_ti_dhdl([ti_coul, ti_vdw]),
matplotlib.axes.Axes)
ax = plot_ti_dhdl([ti_coul, ti_vdw])
assert isinstance(ax, matplotlib.axes.Axes)
plt.close(ax.figure)

ti_coul.dhdl = pd.DataFrame.from_dict(
{'fep': range(100)},
orient='index',
columns=np.arange(100)/100).T
ti_coul.dhdl.attrs = dHdl_vdw.attrs
assert isinstance(plot_ti_dhdl(ti_coul),
matplotlib.axes.Axes)
ax = plot_ti_dhdl(ti_coul)
assert isinstance(ax, matplotlib.axes.Axes)
plt.close(ax.figure)

def test_plot_dF_state():
'''Just test if the plot runs'''
Expand All @@ -79,26 +87,44 @@ def test_plot_dF_state():
(mbar_coul, mbar_vdw), ]
fig = plot_dF_state(dhdl_data, orientation='portrait')
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

fig = plot_dF_state(dhdl_data, orientation='landscape')
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

fig = plot_dF_state(dhdl_data, labels=['MBAR', 'TI', 'BAR'])
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

with pytest.raises(ValueError):
fig = plot_dF_state(dhdl_data, labels=['MBAR', 'TI',])

fig = plot_dF_state(dhdl_data, colors=['#C45AEC', '#33CC33', '#F87431'])
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

with pytest.raises(ValueError):
fig = plot_dF_state(dhdl_data, colors=['#C45AEC', '#33CC33'])
with pytest.raises(NameError):

with pytest.raises(ValueError):
fig = plot_dF_state(dhdl_data, orientation='xxx')

fig = plot_dF_state(ti_coul, orientation='landscape')
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

fig = plot_dF_state(ti_coul, orientation='portrait')
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

fig = plot_dF_state([ti_coul, bar_coul])
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

fig = plot_dF_state([(ti_coul, ti_vdw)])
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

def test_plot_convergence():
bz = load_benzene().data
Expand All @@ -121,9 +147,9 @@ def test_plot_convergence():
backward.append(estimate.delta_f_.iloc[0,-1])
backward_error.append(estimate.d_delta_f_.iloc[0,-1])

assert isinstance(
plot_convergence(forward, forward_error, backward, backward_error),
matplotlib.axes.Axes)
ax = plot_convergence(forward, forward_error, backward, backward_error)
assert isinstance(ax, matplotlib.axes.Axes)
plt.close(ax.figure)

class Test_Units():
@staticmethod
Expand All @@ -143,33 +169,39 @@ def estimaters():
def test_plot_dF_state_kT(self, estimaters):
fig = plot_dF_state(estimaters, units='kT')
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

def test_plot_dF_state_kJ(self, estimaters):
fig = plot_dF_state(estimaters, units='kJ/mol')
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

def test_plot_dF_state_kcal(self, estimaters):
fig = plot_dF_state(estimaters, units='kcal/mol')
assert isinstance(fig, matplotlib.figure.Figure)
plt.close(fig)

def test_plot_dF_state_unknown(self, estimaters):
with pytest.raises(ValueError):
fig = plot_dF_state(estimaters, units='ddd')

def test_plot_ti_dhdl_kT(self, estimaters):
ti, mbar = estimaters
fig = plot_ti_dhdl(ti, units='kT')
assert isinstance(fig, matplotlib.axes.Axes)
ax = plot_ti_dhdl(ti, units='kT')
assert isinstance(ax, matplotlib.axes.Axes)
plt.close(ax.figure)

def test_plot_ti_dhdl_kJ(self, estimaters):
ti, mbar = estimaters
fig = plot_ti_dhdl(ti, units='kJ/mol')
assert isinstance(fig, matplotlib.axes.Axes)
ax = plot_ti_dhdl(ti, units='kJ/mol')
assert isinstance(ax, matplotlib.axes.Axes)
plt.close(ax.figure)

def test_plot_ti_dhdl_kcal(self, estimaters):
ti, mbar = estimaters
fig = plot_ti_dhdl(ti, units='kcal/mol')
assert isinstance(fig, matplotlib.axes.Axes)
ax = plot_ti_dhdl(ti, units='kcal/mol')
assert isinstance(ax, matplotlib.axes.Axes)
plt.close(ax.figure)

def test_plot_ti_dhdl_unknown(self, estimaters):
ti, mbar = estimaters
Expand Down
2 changes: 1 addition & 1 deletion src/alchemlyb/visualisation/dF_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def plot_dF_state(estimators, labels=None, colors=None, units='kT',
fig, axs = plt.subplots(nrows=len(xs), figsize=(8, 6))
mnb = max([len(i) for i in xs])
else:
raise NameError("Not recognising {}, only supports 'landscape' or 'portrait'.".format(orientation))
raise ValueError("Not recognising {}, only supports 'landscape' or 'portrait'.".format(orientation))

# Sort out the colors
if colors is None:
Expand Down

0 comments on commit 2e96340

Please sign in to comment.