From 1c18bbb8639df49cf4879bbf7c251e9615d1af04 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 14:06:36 +0200 Subject: [PATCH 01/23] merged the extract functions --- src/alchemlyb/parsing/amber.py | 171 ++++++++++++--------------------- 1 file changed, 63 insertions(+), 108 deletions(-) diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index a8e4e723..5dc4f567 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -1,6 +1,6 @@ """Parsers for extracting alchemical data from `Amber `_ output files. -Most of the file parsing parts are inherited from +Most of the file parsing parts are adapted from `alchemical-analysis`_. .. _alchemical-analysis: https://github.com/MobleyLab/alchemical-analysis @@ -21,6 +21,8 @@ k_b = R_kJmol * kJ2kcal +_FP_RE = r'[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?' + def convert_to_pandas(file_datum): """Convert the data structure from numpy to pandas format""" @@ -40,11 +42,6 @@ def convert_to_pandas(file_datum): return df -DVDL_COMPS = ['BOND', 'ANGLE', 'DIHED', '1-4 NB', '1-4 EEL', 'VDWAALS', - 'EELEC', 'RESTRAINT'] -_FP_RE = r'[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?' - - def _pre_gen(it, first): """A generator that returns first first if it exists.""" @@ -148,7 +145,7 @@ def __exit__(self, typ, value, traceback): self.close() -class FEData(object): +class FEData(): """A simple struct container to collect data from individual files.""" __slots__ = ['clambda', 't0', 'dt', 'T', 'ntpr', 'gradients', @@ -240,9 +237,9 @@ def file_validation(outfile): file_datum.have_mbar = have_mbar return file_datum -@_init_attrs -def extract_u_nk(outfile, T): - """Return reduced potentials `u_nk` from Amber outputfile. + +def extract(outfile:str, T:float): + """Return reduced potentials `u_nk` and gradients `dH/dl` from Amber outputfile. Parameters ---------- @@ -252,84 +249,15 @@ def extract_u_nk(outfile, T): Temperature in Kelvin at which the simulations were performed; needed to generated the reduced potential (in units of kT) - Returns + Returns a dictionary with elements: ------- - u_nk : DataFrame - Reduced potential for each alchemical state (k) for each frame (n). - - - .. versionchanged:: 0.5.0 - The :mod:`scipy.constants` is used for parsers instead of - the constants used by the corresponding MD engine. + 'u_nk' : DataFrame + Reduced potential for each alchemical state (k) for each frame (n). + 'dHdl' : Series + dH/dl as a function of time for this lambda window. """ - beta = 1/(k_b * T) - - file_datum = file_validation(outfile) - if not file_validation(outfile): # pragma: no cover - return None - - if not np.isclose(T, file_datum.T, atol=0.01): - msg = f'The temperature read from the input file ({file_datum.T:.2f} K)' - msg += f' is different from the temperature passed as parameter ({T:.2f} K)' - logger.error(msg) - raise ValueError(msg) - - if not file_datum.have_mbar: - raise Exception('ERROR: No MBAR energies found! Cannot parse file.') - with SectionParser(outfile) as secp: - line = secp.skip_lines(5) - high_E_cnt = 0 - for line in secp: - if line.startswith('MBAR Energy analysis'): - mbar = secp.extract_section('^MBAR', '^ ---', file_datum.mbar_lambdas, - extra=line) - - if None in mbar: - continue - - E_ref = mbar[file_datum.mbar_lambda_idx] - - for lmbda, E in enumerate(mbar): - if E > 0.0: - high_E_cnt += 1 - - file_datum.mbar_energies[lmbda].append(beta * (E - E_ref)) - if high_E_cnt: - logger.warning('%i MBAR energ%s > 0.0 kcal/mol', - high_E_cnt, 'ies are' if high_E_cnt > 1 else 'y is') - - time = [file_datum.t0 + (frame_index + 1) * file_datum.dt * file_datum.ntpr - for frame_index in range(len(file_datum.mbar_energies[0]))] - - return pd.DataFrame(file_datum.mbar_energies, - columns=pd.MultiIndex.from_arrays([time, np.repeat(file_datum.clambda, len(time))], - names=['time', 'lambdas']), - index=np.array(file_datum.mbar_lambdas, dtype=np.float64)).T - -@_init_attrs -def extract_dHdl(outfile, T): - """Return gradients ``dH/dl`` from Amber TI outputfile. - - Parameters - ---------- - outfile : str - Path to Amber .out file to extract data from. - T : float - Temperature in Kelvin at which the simulations were performed - - Returns - ------- - dH/dl : Series - dH/dl as a function of time for this lambda window. - - - .. versionchanged:: 0.5.0 - The :mod:`scipy.constants` is used for parsers instead of - the constants used by the corresponding MD engine. - - """ beta = 1/(k_b * T) file_datum = file_validation(outfile) @@ -340,46 +268,73 @@ def extract_dHdl(outfile, T): msg = f'The temperature read from the input file ({file_datum.T:.2f} K)' msg += f' is different from the temperature passed as parameter ({T:.2f} K)' logger.error(msg) - raise ValueError(msg) + raise ValueError(msg) finished = False - comps = [] with SectionParser(outfile) as secp: line = secp.skip_lines(5) + high_E_cnt = 0 nensec = 0 old_nstep = -1 - into_average_section = False for line in secp: - if 'DV/DL, AVERAGES OVER' in line \ - or " A V E R A G E S O V E R" in line: - into_average_section = True - if line.startswith(' NSTEP') and into_average_section: - _ = secp.skip_lines(1) - into_average_section = False + if " A V E R A G E S O V E R" in line: + _ = secp.skip_after('^|=========================================') elif line.startswith(' NSTEP'): nstep, dvdl = secp.extract_section('^ NSTEP', '^ ---', ['NSTEP', 'DV/DL'], extra=line) - if nstep != old_nstep and dvdl is not None \ - and nstep is not None: + if nstep != old_nstep and dvdl is not None and nstep is not None: file_datum.gradients.append(dvdl) nensec += 1 old_nstep = nstep - if line == ' 5. TIMINGS\n': + elif line.startswith('MBAR Energy analysis') and file_datum.have_mbar: + mbar = secp.extract_section('^MBAR', '^ ---', file_datum.mbar_lambdas, + extra=line) + + if None in mbar: + continue + + reference_energy = mbar[file_datum.mbar_lambda_idx] + for lmbda, energy in enumerate(mbar): + if energy > 0.0: + high_E_cnt += 1 + + file_datum.mbar_energies[lmbda].append(beta * (energy - reference_energy)) + elif line == ' 5. TIMINGS\n': finished = True break - if not finished: # pragma: no cover - logger.warning(' WARNING: prematurely terminated run') - if not nensec: # pragma: no cover - logger.warning('WARNING: File %s does not contain any DV/DL data', - outfile) - logger.info(f'Read {nensec} DV/DL data points') - # at this step we get info stored in the FEData object for a given amber out file - file_datum.component_gradients.extend(comps) - # convert file_datum to the pandas format to make it identical to alchemlyb output format - df = convert_to_pandas(file_datum) - df['dHdl'] *= beta - return df + + if high_E_cnt: + logger.warning('%i MBAR energ%s > 0.0 kcal/mol', + high_E_cnt, 'ies are' if high_E_cnt > 1 else 'y is') + + if not finished: + logger.warning('WARNING: file %s is a prematurely terminated run' % outfile) + + if file_datum.have_mbar: + mbar_time = [ + file_datum.t0 + (frame_index + 1) * file_datum.dt * file_datum.ntpr + for frame_index in range(len(file_datum.mbar_energies[0]))] + + mbar_df = pd.DataFrame( + file_datum.mbar_energies, + index=np.array(file_datum.mbar_lambdas, dtype=np.float64), + columns=pd.MultiIndex.from_arrays( + [mbar_time, np.repeat(file_datum.clambda, len(mbar_time))], names=['time', 'lambdas']) + ).T + else: + logger.info('WARNING: No MBAR energies found! "u_nk" entry will be None') + mbar_df = None + + if not nensec: + logger.warning('WARNING: File %s does not contain any dV/dl data' % outfile) + dHdl_df = None + else: + logger.info('Read %s DV/DL data points in file %s' % (nensec, outfile)) + dHdl_df = convert_to_pandas(file_datum) + dHdl_df['dHdl'] *= beta + + return {"u_nk": mbar_df, "dHdl": dHdl_df} def _process_mbar_lambdas(secp): From 4e629191441be2182d946343218a4aa100b3e506 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 14:34:37 +0200 Subject: [PATCH 02/23] amber merged parsers pass all old tests --- src/alchemlyb/parsing/__init__.py | 17 ++++++++ src/alchemlyb/parsing/amber.py | 70 ++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/alchemlyb/parsing/__init__.py b/src/alchemlyb/parsing/__init__.py index 60b0f34e..60165ac9 100644 --- a/src/alchemlyb/parsing/__init__.py +++ b/src/alchemlyb/parsing/__init__.py @@ -14,3 +14,20 @@ def wrapper(outfile, T, *args, **kwargs): dataframe.attrs['energy_unit'] = 'kT' return dataframe return wrapper + + +def _init_attrs_dict(func): + '''Add temperature and energy units to the parsed dataframes. + + The temperature is added to the dataframe as dataframe.attrs['temperature'] + and the energy unit is initiated as dataframe.attrs['energy_unit'] = 'kT'. + ''' + @wraps(func) + def wrapper(outfile, T, *args, **kwargs): + dict_with_df = func(outfile, T, *args, **kwargs) + for k in dict_with_df.keys(): + if dict_with_df[k] is not None: + dict_with_df[k].attrs['temperature'] = T + dict_with_df[k].attrs['energy_unit'] = 'kT' + return dict_with_df + return wrapper diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index 5dc4f567..d8be3a29 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -14,7 +14,7 @@ import numpy as np from .util import anyopen -from . import _init_attrs +from . import _init_attrs_dict from ..postprocessors.units import R_kJmol, kJ2kcal logger = logging.getLogger("alchemlyb.parsers.Amber") @@ -55,7 +55,7 @@ def _pre_gen(it, first): return -class SectionParser(object): +class SectionParser(): """ A simple parser to extract data values from sections. """ @@ -132,7 +132,8 @@ def next(self): return next(self.fileh) # make compatible with python 3.6 - __next__ = next + __next__ = next + # NOTE: could we just define __next__ instead of doing this? def close(self): """Close the filehandle.""" @@ -149,7 +150,7 @@ class FEData(): """A simple struct container to collect data from individual files.""" __slots__ = ['clambda', 't0', 'dt', 'T', 'ntpr', 'gradients', - 'component_gradients', 'mbar_energies', + 'mbar_energies', 'have_mbar', 'mbar_lambdas', 'mbar_lambda_idx'] def __init__(self): @@ -159,7 +160,6 @@ def __init__(self): self.T = -1.0 self.ntpr = -1 self.gradients = [] - self.component_gradients = [] self.mbar_energies = [] self.have_mbar = False self.mbar_lambdas = [] @@ -203,13 +203,12 @@ def file_validation(outfile): mbar_ndata = int(nstlim / mbar_ndata) mbar_lambdas = _process_mbar_lambdas(secp) file_datum.mbar_lambdas = mbar_lambdas - clambda_str = '%6.4f' % clambda + clambda_str = f'{clambda:6.4f}' if clambda_str not in mbar_lambdas: logger.warning('WARNING: lamba %s not contained in set of ' 'MBAR lambas: %s\nNot using MBAR.', clambda_str, ', '.join(mbar_lambdas)) - have_mbar = False else: mbar_nlambda = len(mbar_lambdas) @@ -237,7 +236,7 @@ def file_validation(outfile): file_datum.have_mbar = have_mbar return file_datum - +@_init_attrs_dict def extract(outfile:str, T:float): """Return reduced potentials `u_nk` and gradients `dH/dl` from Amber outputfile. @@ -262,13 +261,13 @@ def extract(outfile:str, T:float): file_datum = file_validation(outfile) if not file_validation(outfile): - return None + return {"u_nk": None, "dHdl": None} if not np.isclose(T, file_datum.T, atol=0.01): msg = f'The temperature read from the input file ({file_datum.T:.2f} K)' msg += f' is different from the temperature passed as parameter ({T:.2f} K)' logger.error(msg) - raise ValueError(msg) + raise ValueError(msg) finished = False with SectionParser(outfile) as secp: @@ -337,6 +336,57 @@ def extract(outfile:str, T:float): return {"u_nk": mbar_df, "dHdl": dHdl_df} +def extract_dHdl(outfile, T): + """Return gradients ``dH/dl`` from Amber TI outputfile. + + Parameters + ---------- + outfile : str + Path to Amber .out file to extract data from. + T : float + Temperature in Kelvin at which the simulations were performed + + Returns + ------- + dH/dl : Series + dH/dl as a function of time for this lambda window. + + + .. versionchanged:: 0.5.0 + The :mod:`scipy.constants` is used for parsers instead of + the constants used by the corresponding MD engine. + + """ + extracted = extract(outfile, T) + return extracted['dHdl'] + + +def extract_u_nk(outfile, T): + """Return reduced potentials `u_nk` from Amber outputfile. + + Parameters + ---------- + outfile : str + Path to Amber .out file to extract data from. + T : float + Temperature in Kelvin at which the simulations were performed; + needed to generated the reduced potential (in units of kT) + + Returns + ------- + u_nk : DataFrame + Reduced potential for each alchemical state (k) for each frame (n). + + + .. versionchanged:: 0.5.0 + The :mod:`scipy.constants` is used for parsers instead of + the constants used by the corresponding MD engine. + + """ + extracted = extract(outfile, T) + return extracted['u_nk'] + + def _process_mbar_lambdas(secp): """ Extract the lambda points used to compute MBAR energies from an AMBER MDOUT file. From bc77e98248d13822215526200e4dc4fbe0fe18b0 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 14:41:35 +0200 Subject: [PATCH 03/23] added extract to gmx parser, tests passed --- src/alchemlyb/parsing/gmx.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/alchemlyb/parsing/gmx.py b/src/alchemlyb/parsing/gmx.py index b1540765..9eee7fcf 100644 --- a/src/alchemlyb/parsing/gmx.py +++ b/src/alchemlyb/parsing/gmx.py @@ -243,6 +243,36 @@ def extract_dHdl(xvg, T, filter=True): return dHdl +def extract(xvg, T, filter=True): + r"""Return reduced potentials `u_nk` and gradients `dH/dl` + from a Hamiltonian differences XVG file. + + Parameters + ---------- + xvg : str + Path to XVG file to extract data from. + T : float + Temperature in Kelvin the simulations sampled. + filter : bool + Filter out the lines that cannot be parsed. + Such as rows with incorrect number of Columns and incorrectly + formatted numbers (e.g. 123.45.67, nan or -). + + Returns a dictionary with elements: + ------- + 'u_nk' : DataFrame + Potential energy for each alchemical state (k) for each frame (n). + 'dHdl' : Series + dH/dl as a function of time for this lambda window. + + dH/dl : Series + dH/dl as a function of time for this lambda window. + + """ + + return {"u_nk": extract_u_nk(xvg, T, filter), "dHdl": extract_dHdl(xvg, T, filter)} + + def _extract_state(xvg, headers=None): """Extract information on state sampled, names of lambdas. From 745690ebccca4866c39168f6bcf6bd842c706f27 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 14:43:28 +0200 Subject: [PATCH 04/23] added extract to gomc --- src/alchemlyb/parsing/gomc.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/alchemlyb/parsing/gomc.py b/src/alchemlyb/parsing/gomc.py index 1944b2a4..c2e807ec 100644 --- a/src/alchemlyb/parsing/gomc.py +++ b/src/alchemlyb/parsing/gomc.py @@ -149,6 +149,36 @@ def extract_dHdl(filename, T): return dHdl +def extract(filename, T): + r"""Return reduced potentials `u_nk` and gradients `dH/dl` + from a Hamiltonian differences free energy file. + + Parameters + ---------- + xvg : str + Path to free energy file to extract data from. + T : float + Temperature in Kelvin the simulations sampled. + filter : bool + Filter out the lines that cannot be parsed. + Such as rows with incorrect number of Columns and incorrectly + formatted numbers (e.g. 123.45.67, nan or -). + + Returns a dictionary with elements: + ------- + 'u_nk' : DataFrame + Potential energy for each alchemical state (k) for each frame (n). + 'dHdl' : Series + dH/dl as a function of time for this lambda window. + + dH/dl : Series + dH/dl as a function of time for this lambda window. + + """ + + return {"u_nk": extract_u_nk(filename, T), "dHdl": extract_dHdl(filename, T)} + + def _extract_state(filename): """Extract information on state sampled, names of lambdas. From fe34171c0ff8f0bd9c7485ee4da74428157a435c Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 14:47:49 +0200 Subject: [PATCH 05/23] added extract to namd parser --- src/alchemlyb/parsing/namd.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/alchemlyb/parsing/namd.py b/src/alchemlyb/parsing/namd.py index 710a0786..57807764 100644 --- a/src/alchemlyb/parsing/namd.py +++ b/src/alchemlyb/parsing/namd.py @@ -306,3 +306,37 @@ def extract_u_nk(fep_files, T): u_nk.set_index(['time','fep-lambda'], inplace=True) return u_nk + +def extract(fep_files, T): + """Return reduced potentials `u_nk` from NAMD fepout file(s). + + Parameters + ---------- + fep_file : str or list of str + Path to fepout file(s) to extract data from. These are sorted by filename, + not including the path, prior to processing, using natural-sort. This way, + filenames including numbers without leading zeros are handled intuitively. + + Windows may be split across files, or more than one window may be present + in a given file. Windows without footer lines (which may be in a different + file than the respective header lines) will raise an error. This means that + while windows may have been interrupted and restarted, they must be + complete. Lambda values are expected to increase or decrease monotonically, + and match between header and footer of each window. + + T : float + Temperature in Kelvin at which the simulation was sampled. + + Returns a dictionary with elements: + ------- + u_nk : DataFrame + Potential energy for each alchemical state (k) for each frame (n). + + Note + ---- + If the number of forward and backward samples in a given window are different, + the extra sample(s) will be discarded. This is typically zero or one sample. + + """ + + return {"u_nk": extract_u_nk(fep_files, T)} # NOTE: maybe we should also have 'dHdl': None From d897c699e2d035edf6013b7389d53a99a5925b3e Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 15:05:58 +0200 Subject: [PATCH 06/23] added test for the new extract function --- src/alchemlyb/tests/parsing/test_amber.py | 29 +++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/alchemlyb/tests/parsing/test_amber.py b/src/alchemlyb/tests/parsing/test_amber.py index afeb5d13..7b1c8a39 100644 --- a/src/alchemlyb/tests/parsing/test_amber.py +++ b/src/alchemlyb/tests/parsing/test_amber.py @@ -2,12 +2,12 @@ """ import pytest -import logging from numpy.testing import assert_allclose from alchemlyb.parsing.amber import extract_dHdl from alchemlyb.parsing.amber import extract_u_nk from alchemlyb.parsing.amber import file_validation +from alchemlyb.parsing.amber import extract from alchemtest.amber import load_simplesolvated from alchemtest.amber import load_invalidfiles from alchemtest.amber import load_bace_example @@ -28,7 +28,7 @@ def fixture_invalid_file(request): @pytest.fixture(name="single_u_nk", scope="module") def fixture_single_u_nk(): """return a single file to check u_unk parsing""" - return load_bace_example().data['solvated']['vdw'][0] + return load_bace_example().data['complex']['vdw'][0] @pytest.fixture(name="single_dHdl", scope="module") @@ -64,6 +64,31 @@ def test_u_nk_time_reading(single_u_nk, first_time=22.0, last_time=1020.0): assert_allclose(u_nk.index.values[-1][0], last_time) +def test_extract_with_both_data( + single_u_nk, + mbar_names=('time', 'lambdas'), + dhdl_names=('time', 'lambdas'), + dhdl_shape=(500, 1)): + """Test that dHdl and u_nk have the correct form when + extracted from files with the extract funcion.""" + df_dict = extract(single_u_nk, T=298.0) + assert df_dict['dHdl'].index.names == dhdl_names + assert df_dict['dHdl'].shape == dhdl_shape + assert df_dict['u_nk'].index.names == mbar_names + + +def test_extract_with_only_dhdl_data( + single_dHdl, + dhdl_names=('time', 'lambdas'), + dhdl_shape=(500, 1)): + """Test that parsing with the extract function a file + with just dHdl gives the correct results""" + df_dict = extract(single_dHdl, T=298.0) + assert df_dict['dHdl'].index.names == dhdl_names + assert df_dict['dHdl'].shape == dhdl_shape + assert df_dict['u_nk'] is None + + def test_wrong_T_should_raise_warning_in_extract_dHdl(single_dHdl, T=300.0): """ Test if calling extract_dHdl with differnt T from what's From bd81563a8883d4d7fd0ad4716563663747584b1e Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 15:08:12 +0200 Subject: [PATCH 07/23] removed reduntant test for T --- src/alchemlyb/tests/parsing/test_amber.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/alchemlyb/tests/parsing/test_amber.py b/src/alchemlyb/tests/parsing/test_amber.py index 7b1c8a39..3fe144c2 100644 --- a/src/alchemlyb/tests/parsing/test_amber.py +++ b/src/alchemlyb/tests/parsing/test_amber.py @@ -89,26 +89,15 @@ def test_extract_with_only_dhdl_data( assert df_dict['u_nk'] is None -def test_wrong_T_should_raise_warning_in_extract_dHdl(single_dHdl, T=300.0): +def test_wrong_T_should_raise_warning(single_dHdl, T=300.0): """ - Test if calling extract_dHdl with differnt T from what's + Test if calling extract with differnt T from what's read from the AMBER file gives a warning """ with pytest.raises( ValueError, match="is different from the temperature passed as parameter"): - _ = extract_dHdl(single_dHdl, T=T) - - -def test_wrong_T_should_raise_warning_in_extract_u_nk(single_u_nk, T=300.0): - """ - Test if calling extract_u_nk with differnt T from what's - read from the AMBER file gives a warning - """ - with pytest.raises( - ValueError, - match="is different from the temperature passed as parameter"): - _ = extract_u_nk(single_u_nk, T=T) + _ = extract(single_dHdl, T=T) @pytest.mark.parametrize("filename", From 3d6a82757806a57cf79b5eef5f1e4e2bd65853ca Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 15:17:21 +0200 Subject: [PATCH 08/23] added test for extract in for gmx --- src/alchemlyb/tests/parsing/test_gmx.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/alchemlyb/tests/parsing/test_gmx.py b/src/alchemlyb/tests/parsing/test_gmx.py index 0c3a0877..a5c6e0bc 100644 --- a/src/alchemlyb/tests/parsing/test_gmx.py +++ b/src/alchemlyb/tests/parsing/test_gmx.py @@ -5,7 +5,7 @@ import bz2 import pytest -from alchemlyb.parsing.gmx import extract_dHdl, extract_u_nk +from alchemlyb.parsing.gmx import extract_dHdl, extract_u_nk, extract from alchemtest.gmx import load_benzene from alchemtest.gmx import load_expanded_ensemble_case_1, load_expanded_ensemble_case_2, load_expanded_ensemble_case_3 from alchemtest.gmx import load_water_particle_with_total_energy @@ -199,6 +199,15 @@ def test_extract_dHdl_unit(): assert dhdl.attrs['temperature'] == 310 assert dhdl.attrs['energy_unit'] == 'kT' +def test_calling_extract(): + '''Test if the extract function is working''' + dataset = load_benzene() + df_dict = extract(dataset['data']['Coulomb'][0], 310) + assert df_dict['dHdl'].attrs['temperature'] == 310 + assert df_dict['dHdl'].attrs['energy_unit'] == 'kT' + assert df_dict['u_nk'].attrs['temperature'] == 310 + assert df_dict['u_nk'].attrs['energy_unit'] == 'kT' + class TestRobustGMX(): '''Test dropping the row that is wrong in different way''' @staticmethod From c7d58c66f050a912d2891b2773b8823d3e6a3cbf Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 15:19:16 +0200 Subject: [PATCH 09/23] cleaned amber tests --- src/alchemlyb/tests/parsing/test_amber.py | 33 +++++++++-------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/alchemlyb/tests/parsing/test_amber.py b/src/alchemlyb/tests/parsing/test_amber.py index 3fe144c2..e1b24a2d 100644 --- a/src/alchemlyb/tests/parsing/test_amber.py +++ b/src/alchemlyb/tests/parsing/test_amber.py @@ -50,42 +50,35 @@ def test_dHdl_invalidfiles(invalid_file): assert extract_dHdl(invalid_file, T=298.0) is None -def test_dHdl_time_reading(single_dHdl, first_time=22.0, last_time=1020.0): +def test_dHdl_time_reading(single_dHdl): """Test if time information is read correctly when extracting dHdl""" dHdl = extract_dHdl(single_dHdl, T=298.0) - assert_allclose(dHdl.index.values[0][0], first_time) - assert_allclose(dHdl.index.values[-1][0], last_time) + assert_allclose(dHdl.index.values[0][0], 22.0) + assert_allclose(dHdl.index.values[-1][0], 1020.0) -def test_u_nk_time_reading(single_u_nk, first_time=22.0, last_time=1020.0): +def test_u_nk_time_reading(single_u_nk): """Test if time information is read correctly when extracting u_nk""" u_nk = extract_u_nk(single_u_nk, T=298.0) - assert_allclose(u_nk.index.values[0][0], first_time) - assert_allclose(u_nk.index.values[-1][0], last_time) + assert_allclose(u_nk.index.values[0][0], 22.0) + assert_allclose(u_nk.index.values[-1][0], 1020.0) -def test_extract_with_both_data( - single_u_nk, - mbar_names=('time', 'lambdas'), - dhdl_names=('time', 'lambdas'), - dhdl_shape=(500, 1)): +def test_extract_with_both_data(single_u_nk): """Test that dHdl and u_nk have the correct form when extracted from files with the extract funcion.""" df_dict = extract(single_u_nk, T=298.0) - assert df_dict['dHdl'].index.names == dhdl_names - assert df_dict['dHdl'].shape == dhdl_shape - assert df_dict['u_nk'].index.names == mbar_names + assert df_dict['dHdl'].index.names == ('time', 'lambdas') + assert df_dict['dHdl'].shape == (500, 1) + assert df_dict['u_nk'].index.names == ('time', 'lambdas') -def test_extract_with_only_dhdl_data( - single_dHdl, - dhdl_names=('time', 'lambdas'), - dhdl_shape=(500, 1)): +def test_extract_with_only_dhdl_data(single_dHdl): """Test that parsing with the extract function a file with just dHdl gives the correct results""" df_dict = extract(single_dHdl, T=298.0) - assert df_dict['dHdl'].index.names == dhdl_names - assert df_dict['dHdl'].shape == dhdl_shape + assert df_dict['dHdl'].index.names == ('time', 'lambdas') + assert df_dict['dHdl'].shape == (500, 1) assert df_dict['u_nk'] is None From 57dafa5a5a331a822254229e20b4fedbd9a5cdc7 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 15:26:12 +0200 Subject: [PATCH 10/23] added extract test for gomc and namd --- src/alchemlyb/tests/parsing/test_gomc.py | 15 ++++++++++++++- src/alchemlyb/tests/parsing/test_namd.py | 11 ++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/alchemlyb/tests/parsing/test_gomc.py b/src/alchemlyb/tests/parsing/test_gomc.py index c03a0b6b..382e01ec 100644 --- a/src/alchemlyb/tests/parsing/test_gomc.py +++ b/src/alchemlyb/tests/parsing/test_gomc.py @@ -2,7 +2,7 @@ """ -from alchemlyb.parsing.gomc import extract_dHdl, extract_u_nk +from alchemlyb.parsing.gomc import extract_dHdl, extract_u_nk, extract from alchemtest.gomc import load_benzene @@ -30,3 +30,16 @@ def test_u_nk(): assert u_nk.index.names == ['time', 'Coulomb-lambda', 'VDW-lambda'] assert u_nk.shape == (1000, 23) +def test_extract(): + """Test that u_nk and dHdl have the correct form when extracted from files. + + """ + dataset = load_benzene() + + for filename in dataset['data']: + df_dict = extract(filename, T=298) + + assert df_dict['u_nk'].index.names == ['time', 'Coulomb-lambda', 'VDW-lambda'] + assert df_dict['u_nk'].shape == (1000, 23) + assert df_dict['dHdl'].index.names == ['time', 'Coulomb-lambda', 'VDW-lambda'] + assert df_dict['dHdl'].shape == (1000, 2) diff --git a/src/alchemlyb/tests/parsing/test_namd.py b/src/alchemlyb/tests/parsing/test_namd.py index d12ff65d..e624aeff 100644 --- a/src/alchemlyb/tests/parsing/test_namd.py +++ b/src/alchemlyb/tests/parsing/test_namd.py @@ -6,7 +6,7 @@ import bz2 import pytest -from alchemlyb.parsing.namd import extract_u_nk +from alchemlyb.parsing.namd import extract_u_nk, extract from alchemtest.namd import load_tyr2ala from alchemtest.namd import load_idws from alchemtest.namd import load_restarted @@ -302,6 +302,15 @@ def test_u_nk_restarted_reversed(): assert u_nk.shape == (30170, 11) +def test_extract(): + filenames = load_restarted_reversed()['data']['both'] + df_dict = extract(filenames, T=300) + + assert df_dict['u_nk'].index.names == ['time', 'fep-lambda'] + assert df_dict['u_nk'].shape == (30170, 11) + # assert df_dict['dHdl'] is None + + def test_u_nk_restarted_reversed_missing_window_header(tmp_path): """Test that u_nk has the correct form when a #NEW line is missing from the restarted_reversed dataset and the parser has to infer lambda_idws for that window.""" From e5921046735f5b5195fb2e3f0177b010f92911a4 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Fri, 23 Sep 2022 15:39:09 +0200 Subject: [PATCH 11/23] added to CHANGES --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index e4d391ea..a882a67e 100644 --- a/CHANGES +++ b/CHANGES @@ -45,6 +45,9 @@ Fixes - substitute the any_none() function with a check "if None in" in the AMBER parser (issue #236, PR #237) - For ABFE workflow, dHdl will only be read when a TI estimator is chosen. Similarly, u_nk will only be read when FEP estimators are chosen. (PR #231) + - All parsers now have a 'extract(file, T)' method that returns a dict with both + "dHdl" and "u_nk" data (or None). THe AMBER parser when using this function will read the + file just once, extracting all data at once. (issue #222, PR #240) 07/22/2022 xiki-tempula, IAlibay, dotsdl, orbeckst, ptmerz From 954effe8eca7a0ec0346154294c9b6f0e2ee545e Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 17:24:01 +0200 Subject: [PATCH 12/23] removed support for python<3.6 --- src/alchemlyb/parsing/amber.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index d8be3a29..3a563156 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -126,15 +126,11 @@ def extract_section(self, start, end, fields, limit=None, extra='', def __iter__(self): return self - def next(self): + def __next__(self): """Read next line of the filehandle and check for EOF.""" self.lineno += 1 return next(self.fileh) - # make compatible with python 3.6 - __next__ = next - # NOTE: could we just define __next__ instead of doing this? - def close(self): """Close the filehandle.""" self.fileh.close() From a102a69476fbe5c424223376fc9cf40d8bb2b9fe Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 17:27:59 +0200 Subject: [PATCH 13/23] emoved type hint to be consistent with the rest --- src/alchemlyb/parsing/amber.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index 3a563156..b9689f12 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -233,7 +233,7 @@ def file_validation(outfile): return file_datum @_init_attrs_dict -def extract(outfile:str, T:float): +def extract(outfile, T): """Return reduced potentials `u_nk` and gradients `dH/dl` from Amber outputfile. Parameters From d4b23558b7f34e52b723ba32c59db86872786690 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 17:45:57 +0200 Subject: [PATCH 14/23] fixed the doscring of extract for sphinx --- docs/parsing/alchemlyb.parsing.amber.rst | 1 + docs/parsing/alchemlyb.parsing.gmx.rst | 1 + docs/parsing/alchemlyb.parsing.gomc.rst | 1 + docs/parsing/alchemlyb.parsing.namd.rst | 1 + src/alchemlyb/parsing/amber.py | 11 +++++------ src/alchemlyb/parsing/gmx.py | 15 ++++++--------- src/alchemlyb/parsing/gomc.py | 15 ++++++--------- src/alchemlyb/parsing/namd.py | 7 ++++--- 8 files changed, 25 insertions(+), 27 deletions(-) diff --git a/docs/parsing/alchemlyb.parsing.amber.rst b/docs/parsing/alchemlyb.parsing.amber.rst index c297b888..53a61686 100644 --- a/docs/parsing/alchemlyb.parsing.amber.rst +++ b/docs/parsing/alchemlyb.parsing.amber.rst @@ -18,3 +18,4 @@ This submodule includes these parsing functions: .. autofunction:: alchemlyb.parsing.amber.extract_dHdl .. autofunction:: alchemlyb.parsing.amber.extract_u_nk +.. autofunction:: alchemlyb.parsing.amber.extract diff --git a/docs/parsing/alchemlyb.parsing.gmx.rst b/docs/parsing/alchemlyb.parsing.gmx.rst index 0c875f56..4f4da027 100644 --- a/docs/parsing/alchemlyb.parsing.gmx.rst +++ b/docs/parsing/alchemlyb.parsing.gmx.rst @@ -37,3 +37,4 @@ This submodule includes these parsing functions: .. autofunction:: alchemlyb.parsing.gmx.extract_dHdl .. autofunction:: alchemlyb.parsing.gmx.extract_u_nk +.. autofunction:: alchemlyb.parsing.gmx.extract diff --git a/docs/parsing/alchemlyb.parsing.gomc.rst b/docs/parsing/alchemlyb.parsing.gomc.rst index 200d4a29..51291c9b 100644 --- a/docs/parsing/alchemlyb.parsing.gomc.rst +++ b/docs/parsing/alchemlyb.parsing.gomc.rst @@ -13,3 +13,4 @@ This submodule includes these parsing functions: .. autofunction:: alchemlyb.parsing.gomc.extract_dHdl .. autofunction:: alchemlyb.parsing.gomc.extract_u_nk +.. autofunction:: alchemlyb.parsing.gomc.extract diff --git a/docs/parsing/alchemlyb.parsing.namd.rst b/docs/parsing/alchemlyb.parsing.namd.rst index 9e71e519..d43a5cda 100644 --- a/docs/parsing/alchemlyb.parsing.namd.rst +++ b/docs/parsing/alchemlyb.parsing.namd.rst @@ -31,3 +31,4 @@ API Reference This submodule includes these parsing functions: .. autofunction:: alchemlyb.parsing.namd.extract_u_nk +.. autofunction:: alchemlyb.parsing.namd.extract diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index b9689f12..56e18515 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -244,13 +244,12 @@ def extract(outfile, T): Temperature in Kelvin at which the simulations were performed; needed to generated the reduced potential (in units of kT) - Returns a dictionary with elements: + Returns ------- - 'u_nk' : DataFrame - Reduced potential for each alchemical state (k) for each frame (n). - 'dHdl' : Series - dH/dl as a function of time for this lambda window. - + Dict + A dictionary with keys of 'u_nk', which is a pandas DataFrame of reduced potentials for each + alchemical state (k) for each frame (n), and 'dHdl', which is a Series of dH/dl + as a function of time for this lambda window. """ beta = 1/(k_b * T) diff --git a/src/alchemlyb/parsing/gmx.py b/src/alchemlyb/parsing/gmx.py index 9eee7fcf..af3d3f50 100644 --- a/src/alchemlyb/parsing/gmx.py +++ b/src/alchemlyb/parsing/gmx.py @@ -258,16 +258,13 @@ def extract(xvg, T, filter=True): Such as rows with incorrect number of Columns and incorrectly formatted numbers (e.g. 123.45.67, nan or -). - Returns a dictionary with elements: + Returns ------- - 'u_nk' : DataFrame - Potential energy for each alchemical state (k) for each frame (n). - 'dHdl' : Series - dH/dl as a function of time for this lambda window. - - dH/dl : Series - dH/dl as a function of time for this lambda window. - + Dict + A dictionary with keys of 'u_nk', which is a pandas DataFrame of + potential energy for each alchemical state (k) for each frame (n), + and 'dHdl', which is a Series of dH/dl + as a function of time for this lambda window. """ return {"u_nk": extract_u_nk(xvg, T, filter), "dHdl": extract_dHdl(xvg, T, filter)} diff --git a/src/alchemlyb/parsing/gomc.py b/src/alchemlyb/parsing/gomc.py index c2e807ec..cfd06462 100644 --- a/src/alchemlyb/parsing/gomc.py +++ b/src/alchemlyb/parsing/gomc.py @@ -164,16 +164,13 @@ def extract(filename, T): Such as rows with incorrect number of Columns and incorrectly formatted numbers (e.g. 123.45.67, nan or -). - Returns a dictionary with elements: + Returns ------- - 'u_nk' : DataFrame - Potential energy for each alchemical state (k) for each frame (n). - 'dHdl' : Series - dH/dl as a function of time for this lambda window. - - dH/dl : Series - dH/dl as a function of time for this lambda window. - + Dict + A dictionary with keys of 'u_nk', which is a pandas DataFrame of + potential energy for each alchemical state (k) for each frame (n), + and 'dHdl', which is a Series of dH/dl + as a function of time for this lambda window. """ return {"u_nk": extract_u_nk(filename, T), "dHdl": extract_dHdl(filename, T)} diff --git a/src/alchemlyb/parsing/namd.py b/src/alchemlyb/parsing/namd.py index 57807764..93b75983 100644 --- a/src/alchemlyb/parsing/namd.py +++ b/src/alchemlyb/parsing/namd.py @@ -327,10 +327,11 @@ def extract(fep_files, T): T : float Temperature in Kelvin at which the simulation was sampled. - Returns a dictionary with elements: + Returns ------- - u_nk : DataFrame - Potential energy for each alchemical state (k) for each frame (n). + Dict + A dictionary with keys of 'u_nk', which is a pandas DataFrame of + potential energy for each alchemical state (k) for each frame (n). Note ---- From b879407dd66e12923bd6ecf4e92ecac0d0bc03f2 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 17:53:23 +0200 Subject: [PATCH 15/23] fix testing extract of gomc parser --- src/alchemlyb/tests/parsing/test_gomc.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/alchemlyb/tests/parsing/test_gomc.py b/src/alchemlyb/tests/parsing/test_gomc.py index 382e01ec..d61b3789 100644 --- a/src/alchemlyb/tests/parsing/test_gomc.py +++ b/src/alchemlyb/tests/parsing/test_gomc.py @@ -36,10 +36,9 @@ def test_extract(): """ dataset = load_benzene() - for filename in dataset['data']: - df_dict = extract(filename, T=298) + df_dict = extract(dataset['data'][0], T=298) - assert df_dict['u_nk'].index.names == ['time', 'Coulomb-lambda', 'VDW-lambda'] - assert df_dict['u_nk'].shape == (1000, 23) - assert df_dict['dHdl'].index.names == ['time', 'Coulomb-lambda', 'VDW-lambda'] - assert df_dict['dHdl'].shape == (1000, 2) + assert df_dict['u_nk'].index.names == ['time', 'Coulomb-lambda', 'VDW-lambda'] + assert df_dict['u_nk'].shape == (1000, 23) + assert df_dict['dHdl'].index.names == ['time', 'Coulomb-lambda', 'VDW-lambda'] + assert df_dict['dHdl'].shape == (1000, 2) From b7d18d57b4870f8fcddbbeef2c7c477a70f6d00d Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 18:15:03 +0200 Subject: [PATCH 16/23] added # pragma: no cover --- src/alchemlyb/parsing/amber.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index 56e18515..2cf55d9a 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -285,7 +285,7 @@ def extract(outfile, T): mbar = secp.extract_section('^MBAR', '^ ---', file_datum.mbar_lambdas, extra=line) - if None in mbar: + if None in mbar: # pragma: no cover continue reference_energy = mbar[file_datum.mbar_lambda_idx] @@ -302,7 +302,7 @@ def extract(outfile, T): logger.warning('%i MBAR energ%s > 0.0 kcal/mol', high_E_cnt, 'ies are' if high_E_cnt > 1 else 'y is') - if not finished: + if not finished: # pragma: no cover logger.warning('WARNING: file %s is a prematurely terminated run' % outfile) if file_datum.have_mbar: @@ -320,7 +320,7 @@ def extract(outfile, T): logger.info('WARNING: No MBAR energies found! "u_nk" entry will be None') mbar_df = None - if not nensec: + if not nensec: # pragma: no cover logger.warning('WARNING: File %s does not contain any dV/dl data' % outfile) dHdl_df = None else: @@ -410,7 +410,7 @@ def _process_mbar_lambdas(secp): if 'total' in line: data = line.split() mbar_lambdas.extend(data[2:]) - else: + else: # pragma: no cover mbar_lambdas.extend(line.split()) return mbar_lambdas From 107b282102661e668c3784107b3aa32ddb54f336 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 19:03:30 +0200 Subject: [PATCH 17/23] commented two lines in units.py that ruined sphinx --- src/alchemlyb/postprocessors/units.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/alchemlyb/postprocessors/units.py b/src/alchemlyb/postprocessors/units.py index a0cdec77..1ccdac08 100644 --- a/src/alchemlyb/postprocessors/units.py +++ b/src/alchemlyb/postprocessors/units.py @@ -1,5 +1,5 @@ -'''Unit conversion and constants -================================''' +# '''Unit conversion and constants +# ================================''' from scipy.constants import R, calorie From df95656ec860284eb5aa512bf952e70a4d9d5305 Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 19:16:25 +0200 Subject: [PATCH 18/23] added description for extract in docs --- docs/api_principles.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api_principles.rst b/docs/api_principles.rst index 8fc6b613..1702a58c 100644 --- a/docs/api_principles.rst +++ b/docs/api_principles.rst @@ -69,7 +69,7 @@ The library is structured as follows, following a similar style to │   ├── abfe.py -* 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. Other helper functions may be exposed for additional processing, such as generating an XVG file from an EDR file in the case of GROMACS. All `extract\_*` functions take similar arguments (a file path, parameters such as temperature), and produce standard outputs (:class:`pandas.DataFrame` for reduced potentials, :class:`pandas.Series` for derivatives). +* 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. Moreover an `extract`` functon is provided, which returns a dict containing both derivatives and reduced potentials. Other helper functions may be exposed for additional processing, such as generating an XVG file from an EDR file in the case of GROMACS. All `extract\_*` functions take similar arguments (a file path, parameters such as temperature), and produce standard outputs (:class:`pandas.DataFrame` for reduced potentials, :class:`pandas.Series` for derivatives). * The :mod:`~alchemlyb.preprocessing` submodule features functions for subsampling timeseries, as may be desired before feeding them to an estimator. So far, these are limited to `slicing`, `statistical_inefficiency`, and `equilibrium_detection` functions, many of which make use of subsampling schemes available from :mod:`pymbar`. These functions are written in such a way that they can be easily composed as parts of complex processing pipelines. * The :mod:`~alchemlyb.estimators` module features classes *a la* **scikit-learn** that can be initialized with parameters that determine their behavior and then "trained" on a `fit` method. MBAR, BAR, and thermodynamic integration (TI) as the major methods are all implemented. Correct error estimates require the use of time series with independent samples. * The :mod:`~alchemlyb.convergence` submodule features convenience functions/classes for doing convergence analysis using a given dataset and a chosen estimator. From 99f3f698ec38790f66b0185a70e0046ee061e52b Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 23:08:17 +0200 Subject: [PATCH 19/23] removed a redundant try/except in the test --- src/alchemlyb/tests/test_import.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/alchemlyb/tests/test_import.py b/src/alchemlyb/tests/test_import.py index 50bc7c8c..50a5d933 100644 --- a/src/alchemlyb/tests/test_import.py +++ b/src/alchemlyb/tests/test_import.py @@ -1,7 +1,4 @@ import alchemlyb def test_name(): - try: - assert alchemlyb.__name__ == 'alchemlyb' - except Exception as e: - raise e + assert alchemlyb.__name__ == 'alchemlyb' From 448c648050228f9388530d6be254ed468dc56aac Mon Sep 17 00:00:00 2001 From: DrDomenicoMarson Date: Sun, 25 Sep 2022 23:09:52 +0200 Subject: [PATCH 20/23] uncommented the docstring of units.py --- src/alchemlyb/postprocessors/units.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/alchemlyb/postprocessors/units.py b/src/alchemlyb/postprocessors/units.py index 1ccdac08..f5e1984d 100644 --- a/src/alchemlyb/postprocessors/units.py +++ b/src/alchemlyb/postprocessors/units.py @@ -1,5 +1,6 @@ -# '''Unit conversion and constants -# ================================''' +""" +Unit conversion and constants +""" from scipy.constants import R, calorie From fcbe55918090a05a757f295778a80c5c1f616007 Mon Sep 17 00:00:00 2001 From: Domenico Marson Date: Mon, 26 Sep 2022 12:03:08 +0200 Subject: [PATCH 21/23] just to force docs rebuilding --- src/alchemlyb/parsing/amber.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index 2cf55d9a..dd48a9fb 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -1,6 +1,6 @@ """Parsers for extracting alchemical data from `Amber `_ output files. -Most of the file parsing parts are adapted from +Some of the file parsing parts are adapted from `alchemical-analysis`_. .. _alchemical-analysis: https://github.com/MobleyLab/alchemical-analysis From eaf8f3de0cfd16d77ade7a20f9b91a3253f44877 Mon Sep 17 00:00:00 2001 From: Domenico Marson Date: Tue, 27 Sep 2022 09:40:15 +0200 Subject: [PATCH 22/23] Added versionadded:: 1.0.0 --- src/alchemlyb/parsing/amber.py | 2 ++ src/alchemlyb/parsing/gmx.py | 2 ++ src/alchemlyb/parsing/gomc.py | 2 ++ src/alchemlyb/parsing/namd.py | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index dd48a9fb..eb9421d9 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -250,6 +250,8 @@ def extract(outfile, T): A dictionary with keys of 'u_nk', which is a pandas DataFrame of reduced potentials for each alchemical state (k) for each frame (n), and 'dHdl', which is a Series of dH/dl as a function of time for this lambda window. + + .. versionadded:: 1.0.0 """ beta = 1/(k_b * T) diff --git a/src/alchemlyb/parsing/gmx.py b/src/alchemlyb/parsing/gmx.py index af3d3f50..8c827aa2 100644 --- a/src/alchemlyb/parsing/gmx.py +++ b/src/alchemlyb/parsing/gmx.py @@ -265,6 +265,8 @@ def extract(xvg, T, filter=True): potential energy for each alchemical state (k) for each frame (n), and 'dHdl', which is a Series of dH/dl as a function of time for this lambda window. + + .. versionadded:: 1.0.0 """ return {"u_nk": extract_u_nk(xvg, T, filter), "dHdl": extract_dHdl(xvg, T, filter)} diff --git a/src/alchemlyb/parsing/gomc.py b/src/alchemlyb/parsing/gomc.py index cfd06462..771be9e3 100644 --- a/src/alchemlyb/parsing/gomc.py +++ b/src/alchemlyb/parsing/gomc.py @@ -171,6 +171,8 @@ def extract(filename, T): potential energy for each alchemical state (k) for each frame (n), and 'dHdl', which is a Series of dH/dl as a function of time for this lambda window. + + .. versionadded:: 1.0.0 """ return {"u_nk": extract_u_nk(filename, T), "dHdl": extract_dHdl(filename, T)} diff --git a/src/alchemlyb/parsing/namd.py b/src/alchemlyb/parsing/namd.py index 93b75983..f6cacc19 100644 --- a/src/alchemlyb/parsing/namd.py +++ b/src/alchemlyb/parsing/namd.py @@ -338,6 +338,8 @@ def extract(fep_files, T): If the number of forward and backward samples in a given window are different, the extra sample(s) will be discarded. This is typically zero or one sample. + .. versionadded:: 1.0.0 + """ return {"u_nk": extract_u_nk(fep_files, T)} # NOTE: maybe we should also have 'dHdl': None From 71020eef97cc729e3ed48b86edaf9912cb21438b Mon Sep 17 00:00:00 2001 From: Domenico Marson Date: Tue, 27 Sep 2022 09:55:21 +0200 Subject: [PATCH 23/23] fixed versionadded --- src/alchemlyb/parsing/amber.py | 1 + src/alchemlyb/parsing/gmx.py | 1 + src/alchemlyb/parsing/gomc.py | 1 + src/alchemlyb/parsing/namd.py | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/alchemlyb/parsing/amber.py b/src/alchemlyb/parsing/amber.py index eb9421d9..a674c83a 100644 --- a/src/alchemlyb/parsing/amber.py +++ b/src/alchemlyb/parsing/amber.py @@ -251,6 +251,7 @@ def extract(outfile, T): alchemical state (k) for each frame (n), and 'dHdl', which is a Series of dH/dl as a function of time for this lambda window. + .. versionadded:: 1.0.0 """ diff --git a/src/alchemlyb/parsing/gmx.py b/src/alchemlyb/parsing/gmx.py index 8c827aa2..00267c66 100644 --- a/src/alchemlyb/parsing/gmx.py +++ b/src/alchemlyb/parsing/gmx.py @@ -266,6 +266,7 @@ def extract(xvg, T, filter=True): and 'dHdl', which is a Series of dH/dl as a function of time for this lambda window. + .. versionadded:: 1.0.0 """ diff --git a/src/alchemlyb/parsing/gomc.py b/src/alchemlyb/parsing/gomc.py index 771be9e3..7cf03af4 100644 --- a/src/alchemlyb/parsing/gomc.py +++ b/src/alchemlyb/parsing/gomc.py @@ -172,6 +172,7 @@ def extract(filename, T): and 'dHdl', which is a Series of dH/dl as a function of time for this lambda window. + .. versionadded:: 1.0.0 """ diff --git a/src/alchemlyb/parsing/namd.py b/src/alchemlyb/parsing/namd.py index f6cacc19..c4181b1d 100644 --- a/src/alchemlyb/parsing/namd.py +++ b/src/alchemlyb/parsing/namd.py @@ -338,8 +338,8 @@ def extract(fep_files, T): If the number of forward and backward samples in a given window are different, the extra sample(s) will be discarded. This is typically zero or one sample. - .. versionadded:: 1.0.0 + .. versionadded:: 1.0.0 """ return {"u_nk": extract_u_nk(fep_files, T)} # NOTE: maybe we should also have 'dHdl': None