.. _examples-retis-triple-well: RETIS in a 1D triple-well: the ``zero_left`` shortcut ===================================================== This example shows how a left interface for the [0:math:`^-`] ensemble (set with the ``zero_left`` keyword) can make a RETIS simulation a lot cheaper, **without altering the transition statistics**. The motivation is simple. In RETIS the [0:math:`^-`] ensemble samples the recrossings inside the reactant state. By default, paths in [0:math:`^-`] can wander arbitrarily far to the left of :math:`\lambda_0`. In a multi-state landscape this means they can fall into a *neighbouring* metastable well, where they get trapped and finally rejected at ``maxlength``. ``zero_left`` adds a hard left boundary to [0:math:`^-`] so that paths that would escape into the neighbouring well are rejected on the spot with the cheap ``0-L`` status code. **Verification status:** passing -- see :ref:`example-tutorial-map`. Tutorial quick start -------------------- * **Best starting point:** :file:`examples/tutorials/path_sampling/1D-triple-well/`. * **Edit first:** compare :file:`retis-no-zero-left/retis.rst` and :file:`retis-zero-left/retis.rst`; the key setting is ``zero_left`` in the ``Simulation`` section. * **Run:** execute ``pyretisrun -i retis.rst -p`` in each variant directory. * **Analyse:** run ``pyretisanalyse -i out.rst`` in each completed variant directory, then run ``python compare.py`` from the tutorial directory. * **Expected output:** two comparable RETIS output trees and a short comparison of [0:math:`^-`] path cost. * **Related checks:** represented by the internal RETIS checks and the tutorial smoke runner; see :ref:`example-test-status`. The system ---------- We use the :py:class:`~pyretis.forcefield.potentials.potentials.TripleWell` potential .. math:: V(x) = a x^6 + b x^4 + c x^2 + d x with :math:`(a, b, c, d) = (1, -3, 2, 0)`. This gives three minima - **A** at :math:`x \approx -1.256` (well depth :math:`\approx -0.39`) - **B** at :math:`x = 0` (metastable intermediate, :math:`V = 0`) - **C** at :math:`x \approx +1.256` (well depth :math:`\approx -0.39`) separated by two barriers of height :math:`\approx 0.385` above B at :math:`x \approx \pm 0.65`. From the A side, the same barriers are :math:`\approx 0.776` high, so a particle that drops into A spends many integration steps before escaping. We sample only the **B** :math:`\to` **C** transition. Without a left bound, [0:math:`^-`] paths that wander into A inflate the sampling cost; with a left bound at :math:`x = -0.4` (well inside the B basin) they cannot reach A at all. The two input files ------------------- The example ships two input files that differ in **one** line. **Baseline** (``retis-no-zero-left/retis.rst``) -- uses ``flux = True`` to enable [0:math:`^-`] without a left bound: .. literalinclude:: /_static/examples/retis1d-triple-well/retis-no-zero-left.txt :language: rst :lines: 22-29 **With** ``zero_left`` (``retis-zero-left/retis.rst``): .. literalinclude:: /_static/examples/retis1d-triple-well/retis-zero-left.txt :language: rst :lines: 14-22 Everything else (interfaces, engine, temperature, seeds, output) is identical. The full input files are bundled with the |pyretis| sources under :file:`examples/tutorials/path_sampling/1D-triple-well/`. The triple-well potential itself is specified by: .. literalinclude:: /_static/examples/retis1d-triple-well/retis-no-zero-left.txt :language: rst :lines: 84-90 Running the example ------------------- Each variant runs in roughly one minute on a typical laptop. From the example directory: .. code-block:: bash cd retis-no-zero-left pyretisrun -i retis.rst -p pyretisanalyse -i out.rst cd ../retis-zero-left pyretisrun -i retis.rst -p pyretisanalyse -i out.rst A small helper script then reports the [0:math:`^-`] ensemble cost for both runs: .. literalinclude:: /_static/examples/retis1d-triple-well/compare.py :language: python :lines: 3-11 Run it with ``python compare.py``. What to look for ---------------- In a typical run, the variant with ``zero_left`` shows: - much shorter average accepted paths in [0:math:`^-`]; - zero ``FTX`` / ``BTX`` rejections in [0:math:`^-`] (rejections now appear as the much cheaper ``0-L`` status); - the same B :math:`\to` C crossing probability and rate constant in [0:math:`^+`], [1:math:`^+`], ... That is the take-away: ``zero_left`` is a "free" speed-up whenever the reactant state is bounded on the left by another long-lived basin you are not interested in sampling. Going further ------------- * Try setting ``zero_left`` very close to the A-B barrier (e.g. ``-0.6``) and watch the ``0-L`` rejection rate grow. * Add a tilt to the potential (``d`` parameter of :py:class:`~pyretis.forcefield.potentials.potentials.TripleWell`) to make A deeper and the trapping effect more dramatic. * Run with and without ``swapsimul`` to see how swap acceptance in [0:math:`^-`] :math:`\leftrightarrow` [0:math:`^+`] changes. Tested by --------- * The tutorial is included in :file:`examples/tutorials/path_sampling/1D-triple-well/` and runs every time the tutorial smoke runner (:file:`examples/run-tutorials.sh`) is invoked, including from the top-level ``./test-heavy.sh``. * A dedicated, deterministic regression fixture lives at :file:`examples/tests/test-internal/retis-zero-left/`. It runs the same two input files at a much smaller size, checks that the ``0-L`` rejections appear in [0:math:`^-`] (and may propagate to [0:math:`^+`] through a failed swap-zero) but never in [1:math:`^+`] or beyond, and that ``zero_left`` does not produce ``FTX``/``BTX`` rejections in [0:math:`^-`]. Run it with:: cd examples/tests/test-internal/retis-zero-left ./run.sh