Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
305 changes: 305 additions & 0 deletions cookbook/exploring_rbfe_settings.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
{
"cells": [
{
"metadata": {},
"cell_type": "markdown",
"source": [
"# Exploring HybridTopologyProtocol settings\n",
"\n",
"\n",
"The `RelativeHybridTopologyProtocol` exposes a number of simulation settings that can affect the convergence properties, accuracy and precision of an alchemical transformation. In this notebook, we will explore changes to common settings, advising when you might want to consider changing them and how to change them in practice. For a detailed explanation of the protocol and its limitations see the [protocol documentation](https://docs.openfree.energy/en/latest/guide/protocols/relativehybridtopology.html#relative-hybrid-topology-protocol) and references therein.\n",
"\n",
"## Inspecting the default settings\n",
"\n",
"The default settings for the `RelativeHybridTopologyProtocol` are designed to be a good starting point for most alchemical transformations with the goal of obtaining reliable estimates with sufficient precision for decision-making at a reasonable computational cost. However, depending on the specific system and transformation being studied, you may want to adjust these settings to improve convergence or precision of the estimation.\n",
"\n",
"The default settings can be inspected by:"
],
"id": "a3f965b58be21979"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-10-22T10:46:22.362791Z",
"start_time": "2026-10-22T10:46:22.275865Z"
}
},
"cell_type": "code",
"source": [
"from openfe.protocols.openmm_rfe import RelativeHybridTopologyProtocol\n",
"\n",
"settings = RelativeHybridTopologyProtocol.default_settings()"
],
"id": "5690f07a5cd27245",
"outputs": [],
"execution_count": 24
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"For a complete explanation of each setting and how to customize the object see [Choose and Configure a Protocol](https://docs.openfree.energy/en/latest/cookbook/choose_protocol.html).\n",
"\n",
"The main parameters that determine the amount of sampling performed and the associated cost for the hybrid topology protocol are:\n",
"\n",
"- **Lambda windows**: the number of discrete alchemical states simulated during the transformation.\n",
"- **Production length**: the length of the production simulation performed at each lambda window.\n",
"- **Equilibration length**: the length of the equilibration simulation performed at each lambda window.\n",
"- **Protocol repeats**: the number of independent executions of the protocol.\n",
"\n",
"The appropriate changes to these settings are transformation dependent with no single setting guaranteeing sufficient convergence or accuracy in general. These settings provide a good starting point to investigate the affect of additional sampling on the transformation under study however, but will also increase the computational cost of the simulation. The following example retrieves them from the default settings:"
],
"id": "94c914fc75cd8fcb"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-10-22T13:12:34.530752Z",
"start_time": "2026-10-22T13:12:34.485473Z"
}
},
"cell_type": "code",
"source": [
"n_repeats = settings.protocol_repeats\n",
"n_windows = settings.lambda_settings.lambda_windows\n",
"production_length = settings.simulation_settings.production_length\n",
"equilibration_length = settings.simulation_settings.equilibration_length\n",
"\n",
"print(f\"Lambda windows: {n_windows}\")\n",
"print(f\"Production length per state: {production_length.m} ns\")\n",
"print(f\"Equilibration length per state: {equilibration_length.m} ns\")\n",
"print(f\"Independent repeats: {n_repeats}\")"
],
"id": "3c2f7354aadac1e8",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Lambda windows: 11\n",
"Production length per state: 5.0 ns\n",
"Equilibration length per state: 1.0 ns\n",
"Independent repeats: 3\n"
]
}
],
"execution_count": 35
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"## Estimating the computational cost of a protocol\n",
"\n",
"A useful first approximation of the computational cost of a protocol execution is the total simulation time in nanoseconds across all lambda windows and repeats. This can be calculated as:\n",
"\n",
"$$T_{total} = N_{repeats} \\times N_{\\lambda windows} \\times (T_{production} + T_{equilibration})$$\n",
"\n",
"So for the default settings the total simulation time is:"
],
"id": "704d5dc6e6f895f5"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-10-22T11:20:41.651615Z",
"start_time": "2026-10-22T11:20:41.533380Z"
}
},
"cell_type": "code",
"source": [
"total_sim_time = n_repeats * n_windows * (production_length + equilibration_length)\n",
"print(f\"Total simulation time: {total_sim_time.m} ns\")"
],
"id": "fd81e13e2c34684d",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total simulation time: 198.0 ns\n"
]
}
],
"execution_count": 29
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"The `RelativeHybridTopologyProtocol` simulates the complex and solvent legs of a transformation independently, so if both use the same settings the total cost of the protocol is double the above estimate. It is useful to consider this estimate when deciding how to adjust the settings for a given transformation.\n",
"\n",
"# Increasing simulation length\n",
"\n",
"This section describes how to increase the amount of production simulation performed at each lambda window and estimate the increase in computational cost.\n",
"\n",
"## When to increase simulation length\n",
"\n",
"Consider increasing the simulation length **before** running the simulation when:\n",
"\n",
"- The transformation involves large structural changes due to for example changes in formal charge, you may also need to consider increasing the number of lambda windows see the next section for more information.\n",
"\n",
"Consider increasing the simulation length **after** running the simulation when:\n",
"\n",
"- Free-energy estimates differ substantially between independent repeats of the protocol.\n",
"- Forward and reverse free-energy estimates disagree by more than 1kbT at over 50% of the simulation length and their uncertainties do not overlap.\n",
"- A large number of samples are discarded during analysis due to the automated equilibration and decorrelation methods.\n",
"- Replica exchange or MBAR analysis indicates that alchemical overlap or replica mixing is poor between lambda windows, you may also need to consider increasing the number of lambda windows see the next section for more information.\n",
"\n",
"This information is available through the automated analysis performed by the `RelativeHybridTopologyProtocol` see the list of available [analysis metrics](https://docs.openfree.energy/en/latest/guide/protocols/relativehybridtopology.html#analysis) for more information, it is recommended to review the analysis metrics before deciding to increase the simulation length.\n",
"\n",
"## When not to increase simulation length\n",
"\n",
"Increasing the simulation length is not always the best solution. For example poor overlap between neighboring lambda windows may require changes to the number of lambda windows or the spacing between them.\n",
"\n",
"## Changing the production length\n",
"\n",
"The following example shows how to change the production length for a `RelativeHybridTopologyProtocol` object. In this example, we will double the production length from `5 ns` to `10 ns` per lambda window. Note the use of units from the `openff.units` package to specify the value is in nanoseconds. We will then calculate the new total simulation time and compare it to the default settings.\n"
],
"id": "3ab10c2ecebbd3df"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-10-22T11:21:00.199353Z",
"start_time": "2026-10-22T11:21:00.150806Z"
}
},
"cell_type": "code",
"source": [
"from openff.units import unit\n",
"\n",
"long_settings = RelativeHybridTopologyProtocol.default_settings()\n",
"\n",
"# Increase the production length to 10 ns\n",
"long_settings.simulation_settings.production_length = 10 * unit.nanoseconds\n",
"\n",
"# Create a new protocol object with the updated settings\n",
"protocol = RelativeHybridTopologyProtocol(settings=long_settings)\n",
"\n",
"print(f\"Updated production length: {protocol.settings.simulation_settings.production_length.m} ns\")\n",
"\n",
"# Calculate the new total simulation time\n",
"new_total_sim_time = n_repeats * n_windows * (protocol.settings.simulation_settings.production_length + protocol.settings.simulation_settings.equilibration_length)\n",
"print(f\"New total simulation time: {new_total_sim_time.m} ns\")\n",
"\n",
"# Print the percentage increase in total simulation time\n",
"percentage_increase = ((new_total_sim_time - total_sim_time) / total_sim_time) * 100\n",
"print(f\"Percentage increase in total simulation time: {percentage_increase.m:.2f}%\")"
],
"id": "2cf9b3c7030df36f",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Updated production length: 10 ns\n",
"New total simulation time: 363.0 ns\n",
"Percentage increase in total simulation time: 83.33%\n"
]
}
],
"execution_count": 31
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"# Increasing the number of lambda windows\n",
"\n",
"Increasing the number of lambda windows introduces additional intermediate alchemical states along the transformation which can make the pathway easier to traverse and improve the overlap between neighboring states. This section describes how to increase the number of lambda windows and estimate the increase in computational cost.\n",
"\n",
"## When to increase the number of lambda windows\n",
"\n",
"Consider increasing the number of lambda windows **before** running the simulation when:\n",
"\n",
"- The transformation involves a change in net formal charge or substantial redistribution of charge, you may also need to consider increasing the simulation length see the previous section for more information.\n",
"\n",
"Consider increasing the number of lambda windows **after** running the simulation when:\n",
"\n",
"- Neighboring lambda windows have poor phase-space overlap or replica mixing statistics.\n",
"\n",
"## When not to increase the number of lambda windows\n",
"\n",
"Increasing the number of lambda windows is not always the best solution, slow changes in ligand conformation or binding site rearrangements may require longer simulation lengths to achieve convergence. In these cases, increasing the number of lambda windows may not improve convergence and will increase the computational cost of the protocol.\n",
"\n",
"## Changing the number of lambda windows\n",
"\n",
"The following example shows how to change the number of lambda windows for a `RelativeHybridTopologyProtocol` object. In this example, we will double the number of lambda windows from `11` to `22`. We will then calculate the new total simulation time and compare it to the default settings. Note the `lambda_windows` setting only accepts integer values and generates a uniform spacing of lambda values between `0` and `1`.\n"
],
"id": "3d6bb208a91ce6d0"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-10-22T13:14:05.953017Z",
"start_time": "2026-10-22T13:14:05.920141Z"
}
},
"cell_type": "code",
"source": [
"more_window_settings = RelativeHybridTopologyProtocol.default_settings()\n",
"\n",
"# Increase the number of lambda windows to 22\n",
"more_window_settings.lambda_settings.lambda_windows = 22\n",
"# The number of replicas should be increased to match the number of lambda windows\n",
"more_window_settings.simulation_settings.n_replicas = 22\n",
"\n",
"# Create a new protocol object with the updated settings\n",
"protocol = RelativeHybridTopologyProtocol(settings=more_window_settings)\n",
"\n",
"print(f\"Updated number of lambda windows: {protocol.settings.lambda_settings.lambda_windows}\")\n",
"\n",
"# Calculate the new total simulation time\n",
"new_total_sim_time = n_repeats * protocol.settings.lambda_settings.lambda_windows * (protocol.settings.simulation_settings.production_length + protocol.settings.simulation_settings.equilibration_length)\n",
"print(f\"New total simulation time: {new_total_sim_time.m} ns\")\n",
"\n",
"# Print the percentage increase in total simulation time\n",
"percentage_increase = ((new_total_sim_time - total_sim_time) / total_sim_time) * 100\n",
"print(f\"Percentage increase in total simulation time: {percentage_increase.m:.2f}%\")"
],
"id": "a8a0a2b5ba644eb4",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Updated number of lambda windows: 22\n",
"New total simulation time: 396.0 ns\n",
"Percentage increase in total simulation time: 100.00%\n"
]
}
],
"execution_count": 37
},
{
"metadata": {},
"cell_type": "code",
"outputs": [],
"execution_count": null,
"source": "",
"id": "2be1cfe17af0153"
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading