From 0aec3a1f7600e4b2be998f631d7b7d97cbd2072a Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:14:18 -0600 Subject: [PATCH 1/7] Workaround latest dm-haiku and e3nn-jax releases --- .github/workflows/ci.yml | 4 ++-- Dockerfile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36b45ac5..7188b818 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: Install python dependecies run: | python -m pip install --upgrade pip - pip install dill jaxlib "jax-md>=0.2.7" jaxopt pytest matplotlib + pip install dill "dm-haiku<0.0.11" "e3nn-jax!=0.20.4" jaxlib "jax-md>=0.2.7" jaxopt pytest matplotlib - name: Install pysages run: pip install . @@ -60,7 +60,7 @@ jobs: - name: Install python dependecies run: | python -m pip install --upgrade pip - pip install dill jaxlib "jax-md>=0.2.7" jaxopt pytest pylint flake8 + pip install dill "dm-haiku<0.0.11" "e3nn-jax!=0.20.4" jaxlib "jax-md>=0.2.7" jaxopt pytest pylint flake8 pip install -r docs/requirements.txt - name: Install pysages run: pip install . diff --git a/Dockerfile b/Dockerfile index 4b4cd3d5..bab84b57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN python -m pip install ase gsd matplotlib "pyparsing<3" # Install JAX and JAX-MD RUN python -m pip install --upgrade "jax[cuda]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html -RUN python -m pip install --upgrade "jax-md>=0.2.7" jaxopt +RUN python -m pip install --upgrade "dm-haiku<0.0.11" "e3nn-jax!=0.20.4" "jax-md>=0.2.7" jaxopt COPY . /PySAGES RUN pip install /PySAGES/ From 280f626b6e617528a58bc06501c81e688155face Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Tue, 2 Jan 2024 18:14:42 -0600 Subject: [PATCH 2/7] Test on Python 3.11 too --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7188b818..cb2368f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-20.04, macos-latest] - python-version: [3.8, 3.9] + python-version: [3.8, 3.9, 3.11] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} From b126e99484a16cc77965248cc6da5e0c089a2f6a Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Thu, 4 Jan 2024 15:51:11 -0600 Subject: [PATCH 3/7] Add ncalls to spelling whitelist --- docs/source/pysages_wordlist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/pysages_wordlist.txt b/docs/source/pysages_wordlist.txt index 6bf3d923..2a946024 100644 --- a/docs/source/pysages_wordlist.txt +++ b/docs/source/pysages_wordlist.txt @@ -56,6 +56,7 @@ metapotential monocyclic multi nanometer +ncalls nn numpyfying Penrose From 72e50f4f9bdbbb937f8ce4cd0a6bb0f220407a84 Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:25:23 -0600 Subject: [PATCH 4/7] Count how many times each method is called --- pysages/methods/abf.py | 8 ++++++-- pysages/methods/ann.py | 16 ++++++++-------- pysages/methods/cff.py | 18 ++++++++---------- pysages/methods/ffs.py | 5 +++-- pysages/methods/funn.py | 16 ++++++++-------- pysages/methods/harmonic_bias.py | 5 +++-- pysages/methods/metad.py | 11 +++++------ pysages/methods/spectral_abf.py | 16 ++++++++-------- pysages/methods/unbiased.py | 8 ++++++-- 9 files changed, 55 insertions(+), 48 deletions(-) diff --git a/pysages/methods/abf.py b/pysages/methods/abf.py index cc298a86..ba713d15 100644 --- a/pysages/methods/abf.py +++ b/pysages/methods/abf.py @@ -57,6 +57,9 @@ class ABFState(NamedTuple): Wp_: JaxArray (CV shape) Product of W matrix and momenta matrix for the previous step. + + ncalls: int + Counts the number of times the method's update has been called. """ xi: JaxArray @@ -66,6 +69,7 @@ class ABFState(NamedTuple): force: JaxArray Wp: JaxArray Wp_: JaxArray + ncalls: int def __repr__(self): return repr("PySAGES " + type(self).__name__) @@ -174,7 +178,7 @@ def initialize(): force = np.zeros(dims) Wp = np.zeros(dims) Wp_ = np.zeros(dims) - return ABFState(xi, bias, hist, Fsum, force, Wp, Wp_) + return ABFState(xi, bias, hist, Fsum, force, Wp, Wp_, 0) def update(state, data): """ @@ -213,7 +217,7 @@ def update(state, data): force = estimate_force(xi, I_xi, Fsum, hist).reshape(dims) bias = np.reshape(-Jxi.T @ force, state.bias.shape) - return ABFState(xi, bias, hist, Fsum, force, Wp, state.Wp) + return ABFState(xi, bias, hist, Fsum, force, Wp, state.Wp, state.ncalls + 1) return snapshot, initialize, generalize(update, helpers) diff --git a/pysages/methods/ann.py b/pysages/methods/ann.py index a5463a46..98952acd 100644 --- a/pysages/methods/ann.py +++ b/pysages/methods/ann.py @@ -60,8 +60,8 @@ class ANNState(NamedTuple): nn: NNDada Bundle of the neural network parameters, and output scaling coefficients. - nstep: int - Count the number of times the method's update has been called. + ncalls: int + Counts the number of times the method's update has been called. """ xi: JaxArray @@ -70,7 +70,7 @@ class ANNState(NamedTuple): phi: JaxArray prob: JaxArray nn: NNData - nstep: int + ncalls: int def __repr__(self): return repr("PySAGES " + type(self).__name__) @@ -148,13 +148,13 @@ def initialize(): phi = np.zeros(shape) prob = np.ones(shape) nn = NNData(ps, np.array(0.0), np.array(1.0)) - return ANNState(xi, bias, hist, phi, prob, nn, 1) + return ANNState(xi, bias, hist, phi, prob, nn, 0) def update(state, data): - nstep = state.nstep - in_training_regime = nstep > train_freq + ncalls = state.ncalls + 1 + in_training_regime = ncalls > train_freq # We only train every `train_freq` timesteps - in_training_step = in_training_regime & (nstep % train_freq == 1) + in_training_step = in_training_regime & (ncalls % train_freq == 1) hist, phi, prob, nn = learn_free_energy(state, in_training_step) # Compute the collective variable and its jacobian xi, Jxi = cv(data) @@ -163,7 +163,7 @@ def update(state, data): F = estimate_force(xi, I_xi, nn, in_training_regime) bias = np.reshape(-Jxi.T @ F, state.bias.shape) # - return ANNState(xi, bias, hist, phi, prob, nn, nstep + 1) + return ANNState(xi, bias, hist, phi, prob, nn, ncalls) return snapshot, initialize, generalize(update, helpers) diff --git a/pysages/methods/cff.py b/pysages/methods/cff.py index 874aad10..c5b4506e 100644 --- a/pysages/methods/cff.py +++ b/pysages/methods/cff.py @@ -77,8 +77,8 @@ class CFFState(NamedTuple): nn: NNDada Bundle of the neural network parameters, and output scaling coefficients. - nstep: int - Count the number of times the method's update has been called. + ncalls: int + Counts the number of times the method's update has been called. """ xi: JaxArray @@ -93,7 +93,7 @@ class CFFState(NamedTuple): Wp_: JaxArray nn: NNData fnn: NNData - nstep: int + ncalls: int def __repr__(self): return repr("PySAGES " + type(self).__name__) @@ -209,13 +209,13 @@ def initialize(): nn = NNData(ps, np.array(0.0), np.array(1.0)) fnn = NNData(fps, np.zeros(dims), np.array(1.0)) - return CFFState(xi, bias, hist, histp, prob, fe, Fsum, force, Wp, Wp_, nn, fnn, 1) + return CFFState(xi, bias, hist, histp, prob, fe, Fsum, force, Wp, Wp_, nn, fnn, 0) def update(state, data): # During the intial stage, when there are not enough collected samples, use ABF - nstep = state.nstep - in_training_regime = nstep > 1 * train_freq - in_training_step = in_training_regime & (nstep % train_freq == 1) + ncalls = state.ncalls + 1 + in_training_regime = ncalls > train_freq + in_training_step = in_training_regime & (ncalls % train_freq == 1) histp, fe, prob, nn, fnn = learn_free_energy(state, in_training_step) # Compute the collective variable and its jacobian xi, Jxi = cv(data) @@ -232,9 +232,7 @@ def update(state, data): force = estimate_force(PartialCFFState(xi, hist, Fsum, I_xi, fnn, in_training_regime)) bias = (-Jxi.T @ force).reshape(state.bias.shape) # - return CFFState( - xi, bias, hist, histp, prob, fe, Fsum, force, Wp, state.Wp, nn, fnn, nstep + 1 - ) + return CFFState(xi, bias, hist, histp, prob, fe, Fsum, force, Wp, state.Wp, nn, fnn, ncalls) return snapshot, initialize, generalize(update, helpers) diff --git a/pysages/methods/ffs.py b/pysages/methods/ffs.py index 63341da5..6c8ad029 100644 --- a/pysages/methods/ffs.py +++ b/pysages/methods/ffs.py @@ -24,6 +24,7 @@ class FFSState(NamedTuple): xi: JaxArray bias: Optional[JaxArray] + ncalls: int def __repr__(self): return repr("PySAGES " + type(self).__name__) @@ -210,11 +211,11 @@ def _ffs(method, snapshot, helpers): # initialize method def initialize(): xi = cv(helpers.query(snapshot)) - return FFSState(xi, None) + return FFSState(xi, None, 0) def update(state, data): xi = cv(data) - return FFSState(xi, None) + return FFSState(xi, None, state.ncalls + 1) return snapshot, initialize, generalize(update, helpers) diff --git a/pysages/methods/funn.py b/pysages/methods/funn.py index f0a3da5d..9c1c2dde 100644 --- a/pysages/methods/funn.py +++ b/pysages/methods/funn.py @@ -66,8 +66,8 @@ class FUNNState(NamedTuple): nn: NNData Bundle of the neural network parameters, and output scaling coefficients. - nstep: int - Count the number of times the method's update has been called. + ncalls: int + Counts the number of times the method's update has been called. """ xi: JaxArray @@ -78,7 +78,7 @@ class FUNNState(NamedTuple): Wp: JaxArray Wp_: JaxArray nn: NNData - nstep: int + ncalls: int def __repr__(self): return repr("PySAGES " + type(self).__name__) @@ -173,13 +173,13 @@ def initialize(): Wp = np.zeros(dims) Wp_ = np.zeros(dims) nn = NNData(ps, F, F) - return FUNNState(xi, bias, hist, Fsum, F, Wp, Wp_, nn, 1) + return FUNNState(xi, bias, hist, Fsum, F, Wp, Wp_, nn, 0) def update(state, data): # During the intial stage, when there are not enough collected samples, use ABF - nstep = state.nstep - in_training_regime = nstep > 2 * train_freq - in_training_step = in_training_regime & (nstep % train_freq == 1) + ncalls = state.ncalls + 1 + in_training_regime = ncalls > 2 * train_freq + in_training_step = in_training_regime & (ncalls % train_freq == 1) # NN training nn = learn_free_energy_grad(state, in_training_step) # Compute the collective variable and its jacobian @@ -198,7 +198,7 @@ def update(state, data): ) bias = (-Jxi.T @ F).reshape(state.bias.shape) # - return FUNNState(xi, bias, hist, Fsum, F, Wp, state.Wp, nn, state.nstep + 1) + return FUNNState(xi, bias, hist, Fsum, F, Wp, state.Wp, nn, state.ncalls) return snapshot, initialize, generalize(update, helpers) diff --git a/pysages/methods/harmonic_bias.py b/pysages/methods/harmonic_bias.py index 8249886a..1218ab29 100644 --- a/pysages/methods/harmonic_bias.py +++ b/pysages/methods/harmonic_bias.py @@ -34,6 +34,7 @@ class HarmonicBiasState(NamedTuple): xi: JaxArray bias: JaxArray + ncalls: int def __repr__(self): return repr("PySAGES" + type(self).__name__) @@ -118,7 +119,7 @@ def _harmonic_bias(method, snapshot, helpers): def initialize(): xi, _ = cv(helpers.query(snapshot)) bias = np.zeros((natoms, helpers.dimensionality())) - return HarmonicBiasState(xi, bias) + return HarmonicBiasState(xi, bias, 0) def update(state, data): xi, Jxi = cv(data) @@ -126,6 +127,6 @@ def update(state, data): bias = -Jxi.T @ forces.flatten() bias = bias.reshape(state.bias.shape) - return HarmonicBiasState(xi, bias) + return HarmonicBiasState(xi, bias, state.ncalls + 1) return snapshot, initialize, generalize(update, helpers) diff --git a/pysages/methods/metad.py b/pysages/methods/metad.py index b1bea784..9aa04848 100644 --- a/pysages/methods/metad.py +++ b/pysages/methods/metad.py @@ -52,7 +52,7 @@ class MetadynamicsState(NamedTuple): idx: int Index of the next Gaussian to be deposited. - nstep: int + ncalls: int Counts the number of times `method.update` has been called. """ @@ -64,7 +64,7 @@ class MetadynamicsState(NamedTuple): grid_potential: Optional[JaxArray] grid_gradient: Optional[JaxArray] idx: int - nstep: int + ncalls: int def __repr__(self): return repr("PySAGES" + type(self).__name__) @@ -189,8 +189,8 @@ def update(state, data): xi, Jxi = cv(data) # Deposit Gaussian depending on the stride - nstep = state.nstep - in_deposition_step = (nstep > 0) & (nstep % stride == 0) + ncalls = state.ncalls + 1 + in_deposition_step = (ncalls > 1) & (ncalls % stride == 1) partial_state = deposit_gaussian(xi, state, in_deposition_step) # Evaluate gradient of biasing potential (or generalized force) @@ -200,7 +200,7 @@ def update(state, data): bias = -Jxi.T @ generalized_force.flatten() bias = bias.reshape(state.bias.shape) - return MetadynamicsState(xi, bias, *partial_state[1:-1], nstep + 1) + return MetadynamicsState(xi, bias, *partial_state[1:-1], ncalls) return snapshot, initialize, generalize(update, helpers, jit_compile=True) @@ -290,7 +290,6 @@ def build_bias_grad_evaluator(method: Metadynamics): periods = get_periods(method.cvs) evaluate_bias_grad = jit(lambda pstate: grad(sum_of_gaussians)(*pstate[:4], periods)) else: - if restraints: def ob_force(pstate): # out-of-bounds force diff --git a/pysages/methods/spectral_abf.py b/pysages/methods/spectral_abf.py index c309a6cb..68c21c29 100644 --- a/pysages/methods/spectral_abf.py +++ b/pysages/methods/spectral_abf.py @@ -66,8 +66,8 @@ class SpectralABFState(NamedTuple): Object that holds the coefficients of the basis functions approximation to the free energy. - nstep: int - Count the number of times the method's update has been called. + ncalls: int + Counts the number of times the method's update has been called. """ xi: JaxArray @@ -78,7 +78,7 @@ class SpectralABFState(NamedTuple): Wp: JaxArray Wp_: JaxArray fun: Fun - nstep: int + ncalls: int def __repr__(self): return repr("PySAGES " + type(self).__name__) @@ -168,13 +168,13 @@ def initialize(): Wp = np.zeros(dims) Wp_ = np.zeros(dims) fun = fit(Fsum) - return SpectralABFState(xi, bias, hist, Fsum, force, Wp, Wp_, fun, 1) + return SpectralABFState(xi, bias, hist, Fsum, force, Wp, Wp_, fun, 0) def update(state, data): # During the intial stage use ABF - nstep = state.nstep - in_fitting_regime = nstep > fit_threshold - in_fitting_step = in_fitting_regime & (nstep % fit_freq == 1) + ncalls = state.ncalls + 1 + in_fitting_regime = ncalls > fit_threshold + in_fitting_step = in_fitting_regime & (ncalls % fit_freq == 1) # Fit forces fun = fit_forces(state, in_fitting_step) # Compute the collective variable and its jacobian @@ -194,7 +194,7 @@ def update(state, data): ) bias = np.reshape(-Jxi.T @ force, state.bias.shape) # - return SpectralABFState(xi, bias, hist, Fsum, force, Wp, state.Wp, fun, state.nstep + 1) + return SpectralABFState(xi, bias, hist, Fsum, force, Wp, state.Wp, fun, state.ncalls) return snapshot, initialize, generalize(update, helpers) diff --git a/pysages/methods/unbiased.py b/pysages/methods/unbiased.py index 8adb953e..531e3bc0 100644 --- a/pysages/methods/unbiased.py +++ b/pysages/methods/unbiased.py @@ -24,10 +24,14 @@ class UnbiasedState(NamedTuple): bias: Optional[JaxArray] Either None or an array with all entries equal to zero. + + ncalls: int + Counts the number of times the method's update has been called. """ xi: JaxArray bias: Optional[JaxArray] + ncalls: int def __repr__(self): return repr("PySAGES" + type(self).__name__) @@ -62,10 +66,10 @@ def _unbias(method, snapshot, helpers): def initialize(): xi = cv(helpers.query(snapshot)) - return UnbiasedState(xi, None) + return UnbiasedState(xi, None, 0) def update(state, data): xi = cv(data) - return UnbiasedState(xi, None) + return UnbiasedState(xi, None, state.ncalls + 1) return snapshot, initialize, generalize(update, helpers) From 3908e37c768399a2cc46e7efca46bc82f30e9488 Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:07:45 -0600 Subject: [PATCH 5/7] Add options to ASE water example --- examples/ase/abf/water.py | 49 +++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/examples/ase/abf/water.py b/examples/ase/abf/water.py index d25e01c0..252d8e72 100644 --- a/examples/ase/abf/water.py +++ b/examples/ase/abf/water.py @@ -1,22 +1,24 @@ #!/usr/bin/env python3 # %% -import ase.units as units +import argparse +import sys + import numpy as np -from ase import Atoms +from ase import Atoms, units from ase.calculators.tip3p import TIP3P, angleHOH, rOH from ase.constraints import FixBondLengths from ase.io.trajectory import Trajectory from ase.md import Langevin import pysages -from pysages.colvars import Distance +from pysages.colvars import Angle from pysages.grids import Grid from pysages.methods import ABF # %% -def generate_simulation(tag="tip3p"): +def generate_simulation(tag="tip3p", write_output=True): x = angleHOH * np.pi / 180 / 2 pos = [ [0, 0, 0], # rOH is the distance between oxygen and hydrogen atoms in water @@ -37,24 +39,47 @@ def generate_simulation(tag="tip3p"): ) T = 300 * units.kB - logfile = tag + ".log" atoms.calc = TIP3P(rc=4.5) + logfile = tag + ".log" if write_output else None md = Langevin(atoms, 1 * units.fs, temperature_K=T, friction=0.01, logfile=logfile) - traj = Trajectory(tag + ".traj", "w", atoms) - md.attach(traj.write, interval=1) + if write_output: + traj = Trajectory(tag + ".traj", "w", atoms) + md.attach(traj.write, interval=1) return md # %% -def main(): - cvs = [Distance([0, 3])] - grid = Grid(lower=0.1, upper=9.0, shape=64) +def process_args(argv): + print(repr(argv)) + available_args = [ + ("timesteps", "t", int, 100, "Number of simulation steps"), + ("write-output", "o", bool, 1, "Write log and trajectory of the ASE run"), + ] + parser = argparse.ArgumentParser(description="Example script to run pysages with ASE") + + for name, short, T, val, doc in available_args: + parser.add_argument("--" + name, "-" + short, type=T, default=T(val), help=doc) + + return parser.parse_args(argv) + + +# %% +def run_simulation(timesteps, write_output): + cvs = [Angle([1, 0, 2])] + grid = Grid(lower=0.1, upper=9.0, shape=64, periodic=True) method = ABF(cvs, grid) - pysages.run(method, generate_simulation, 100) + context_args = dict(write_output=write_output) + return pysages.run(method, generate_simulation, timesteps, context_args=context_args) + + +# %% +def main(argv=None): + args = process_args([] if argv is None else argv) + run_simulation(args.timesteps, args.write_output) # %% if __name__ == "__main__": - main() + main(sys.argv[1:]) From 934b42f8b4443913ac3a61732422ef4563d0bda1 Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Thu, 4 Jan 2024 15:45:20 -0600 Subject: [PATCH 6/7] Add ASE to CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb2368f5..50001c1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: Install python dependecies run: | python -m pip install --upgrade pip - pip install dill "dm-haiku<0.0.11" "e3nn-jax!=0.20.4" jaxlib "jax-md>=0.2.7" jaxopt pytest matplotlib + pip install ase dill "dm-haiku<0.0.11" "e3nn-jax!=0.20.4" jaxlib "jax-md>=0.2.7" jaxopt pytest matplotlib - name: Install pysages run: pip install . From 6ef2bde2c33f145862aad167792f3be5f70cca8c Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:09:44 -0600 Subject: [PATCH 7/7] Make pickle test self contained --- tests/test_abf_result.pickle | Bin 27785 -> 0 bytes tests/test_pickle.py | 6 +++--- tests/test_simulations/__init__.py | 0 tests/test_simulations/abf.py | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) delete mode 100644 tests/test_abf_result.pickle create mode 100644 tests/test_simulations/__init__.py create mode 120000 tests/test_simulations/abf.py diff --git a/tests/test_abf_result.pickle b/tests/test_abf_result.pickle deleted file mode 100644 index a42d2c90a1e7cad96306d1b7d13dcf258bdaa59e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27785 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 diff --git a/tests/test_pickle.py b/tests/test_pickle.py index 1bcf073f..efd797b6 100644 --- a/tests/test_pickle.py +++ b/tests/test_pickle.py @@ -4,6 +4,7 @@ import dill as pickle import numpy as np +import test_simulations.abf as abf_example import pysages import pysages.colvars @@ -167,10 +168,9 @@ def test_pickle_colvars(): def test_pickle_results(): - with open("tests/test_abf_result.pickle", "rb") as f: - test_result = pickle.load(f) - with tempfile.NamedTemporaryFile() as tmp_pickle: + test_result = abf_example.run_simulation(10, write_output=False) + pickle.dump(test_result, tmp_pickle) tmp_pickle.flush() diff --git a/tests/test_simulations/__init__.py b/tests/test_simulations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_simulations/abf.py b/tests/test_simulations/abf.py new file mode 120000 index 00000000..99070934 --- /dev/null +++ b/tests/test_simulations/abf.py @@ -0,0 +1 @@ +../../examples/ase/abf/water.py \ No newline at end of file