Skip to content
Open
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
93f8e93
Add engine factory and unfinished files for the espresso and lammps e…
Apr 8, 2026
d98eec9
Add engine factory to init method to instantiate the wanted engine cl…
Apr 8, 2026
ec47aaa
Add particle_charge,particle_label,particle_position and particle_fix…
Apr 8, 2026
7985bc7
Use attributes inst.particle_label, inst.particle_charge, inst.partic…
Apr 8, 2026
731e325
Add tutorial
Apr 9, 2026
802cac6
Add modifications to decouple the follwoing methods from espresso:
Apr 16, 2026
aa70a25
modify base classes to base engine. Delete engine factory
Apr 16, 2026
dd74d6c
Add espresso engine methods
Apr 16, 2026
08b2453
Add Espresso protocol classes to simulate the structure of the espres…
Apr 16, 2026
4d5163d
Modify manager _get_particle_instances to just add position and fix r…
Apr 16, 2026
10fa793
Modify pydantic validation for particle instances enabling arbitrary …
Apr 16, 2026
764c716
Add modifications to pymbe tutorial according to the decoupling of es…
Apr 16, 2026
43fdd35
Adapt methods:
Apr 30, 2026
ae645c8
Modify method add_instances_to_engine in order that takes into accoun…
Apr 30, 2026
914f74c
Add LammpsEngineProtocol
Apr 30, 2026
7b903b3
Add LammpsSimulation still to be build the code related to LammpsSimu…
Apr 30, 2026
7c57df5
Add position and added to engine in pmb_type particle for _load_datab…
Apr 30, 2026
0fa66d4
Add into Manager class _update_instance method for pymbe type particl…
Apr 30, 2026
6c939ff
Add attributes added_to_engine for both particleinstances and bond in…
Apr 30, 2026
fd4572d
Adapt sample/branched_polyampholyte to changes related in decoupling …
Apr 30, 2026
c1d3ea8
Add modifications to tests.
Apr 30, 2026
e815cea
Add changes to peptide_cpH to account for the decouple of espresso
Apr 30, 2026
edaabda
various small revisions together with Jordi
Apr 30, 2026
16a8263
Add changes to decouple:
May 9, 2026
02559f5
Add pymbe warnings to send a deprecate warning for the use of certain…
May 9, 2026
267cbf8
Add deprecation warnings to the use of handy functions
May 9, 2026
557971b
Add to espresso engine:
May 9, 2026
7d8294b
Add methods that might be useful for any engine:
May 9, 2026
3a04e0a
Add changes in save and load database functions to load and save arra…
May 9, 2026
d3930fe
Add methods to manager:
May 9, 2026
322bf3b
Add changes:
May 9, 2026
6aab5d1
Add comment
May 9, 2026
685a26e
set the simulation engine in order to use the pmb method to determine…
May 9, 2026
5533abb
set simulation engine before executing the tests
May 9, 2026
fc6fa7d
Set simulation engine before executing the tests remove espresso syst…
May 9, 2026
282d215
Add simulation engine in both tests
May 9, 2026
919afbf
Add simulation engine before executing the handy functions as now the…
May 9, 2026
64811b7
Modify method to test column positions from the dataframe as it conta…
May 9, 2026
7df1750
Adapt sample file to current version decoupling espresso
May 11, 2026
2348bb4
Adapt current sample files towards decoupling espresso
May 11, 2026
44aea18
remove espresso_system as an input from methods migrated from handy f…
May 11, 2026
861f03b
Adapt test_handy_functions towards decoupling espresso
May 11, 2026
337cf47
Adapt changes to decoupling espresso from pymbe
May 11, 2026
c8d3f7d
Add modifications to adapt sample script to espresso decoupling
May 14, 2026
1a9b961
Add changes to pymbe_tutorial
May 14, 2026
e7c1445
Merge branch 'main' into CheckThisFeature
May 14, 2026
73404f9
Decouple create_angular_potential,generate_angles_for_entity,
May 14, 2026
850ec76
Add method add_angle, _create_angle_instance and _get_angle_instance.
May 14, 2026
4e28d5e
include in io.py _load_database and _save_database added_to_engine fo…
May 14, 2026
2212e89
Adapt angle tests to decouple it from espresso
May 14, 2026
39ac794
Add as pmb_type "angle" with attributes particle_id1,particle_id2 and…
May 14, 2026
1b03f67
Add added_to_engine in AngleInstance data class
May 14, 2026
61625c4
Adapt test hydrogel_builder_with_angles
May 14, 2026
72562ee
Adapt test_lattice_setup
May 14, 2026
27348fa
Adapt to decouple from espresso method test_io_instances
May 14, 2026
e273215
A commit
May 18, 2026
b1a99a9
Add box_l argument to _create_hydrogel_chain
jorch28 Jun 10, 2026
217d15a
Fix box_l size to match a diamond lattice of monomer chains that cont…
jorch28 Jun 22, 2026
3d63646
Modify test so that the expected result is expressed in terms of magn…
jorch28 Jun 22, 2026
698afb2
Calculate the resulting quantity of the chain length in reduced units…
jorch28 Jun 24, 2026
b5e4523
Delete unused imports.
jorch28 Jun 30, 2026
7316798
use np.prod(box_l) to replace box_l[0]*box_l[1]*box_l[2]
jorch28 Jun 30, 2026
2ca41b2
Add Copyright Notes
jorch28 Jun 30, 2026
06560f8
Clear pymbe_tutorial outputs
jorch28 Jun 30, 2026
858fe3e
Delete data.csv
jorch28 Jul 1, 2026
32289b7
Add DummyEngine with __getattr__ dunder method to raise RuntimeError
jorch28 Jul 1, 2026
0dc430a
Use __getattr__ to setup not ImplementedError for LammpsSimulationEngine
jorch28 Jul 1, 2026
8f18d26
remove unused variable espresso_local_system
jorch28 Jul 1, 2026
cface83
Add LammpsSimulationEngine that Raises a not ImplementedError
jorch28 Jul 1, 2026
807296f
Add a DummyEngine instantiated by default in pyMBE.
jorch28 Jul 1, 2026
d8453bc
added jordi to author list, update changelog
Jul 2, 2026
ea58a8d
Merge branch 'main' into CheckThisFeature
Jul 2, 2026
d20e6b8
Add facade method to lammps engine to comply with the interface contract
jorch28 Jul 2, 2026
bcbbaa4
Delete files from titration simulations
jorch28 Jul 2, 2026
0663dee
Modify EspressoSystemProtocol into version 4.2.2 and EspressoSystem5.…
jorch28 Jul 3, 2026
215a881
Update info from Authors.md
jorch28 Jul 3, 2026
fec7a8e
remove cells created to trial functions
jorch28 Jul 3, 2026
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
17 changes: 17 additions & 0 deletions pyMBE/exceptions/pmb_warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import warnings
from functools import wraps

def deprecated(new_function):
"""Wrapper function to display a warning deprecation message to all functions that are going to be removed in a future
"""
Comment on lines +22 to +24

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit uneasy about pyMBE re-implementing a feature already provided by @warnings.deprecated(). I understand that it's only available in Python 3.13 onward, but Python 3.12 is old. It's no longer receiving bugfixes, only security fixes, and in about 9 months it won't be supported by new packages in the NumPy ecosystem (NEP 29 drop table). Ubuntu 24.04 LTS is the last OS that still imposes Python 3.12, and a couple of HPC clusters are stuck with Python 3.11 and 3.12.

We should discuss in the next meeting to which degree this is an issue for our users. Ubuntu 26.04 LTS is already available and the ICP plans to migrate to it in August. For HPC clusters where EESSI is available, Python 3.13 can be obtained from the 2025 stacks. On HPC clusters that don't provide EESSI, I build Python 3.14 from sources since older Python versions can be tricky to work with in conjunction with Cython and NumPy. Users of conda-like environments can install a new Python version with an extra command line option. I won't oppose this re-implementation, it's not a dealbreaker for me, but I think it's worth considering the maintenance aspects of re-implementing a functionality that is now widely available.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented this function so users now are warned that they have to move their usage of the function setup_langevin_dynamics, relax_espresso_system,setup_electrostatic_interactions , etc. To be employed by the simulation_engine as simulation_engine.setup_langevin_dynamics, simulation_engine.relax_espresso_system,etc. In order that when they start using the new release version not all of their old code breaks due to these changes being implemented.

Respect to upgrading pyMBE to python 3.13 we may find some troubles related to incompatibilities between the versions of the external python libraries, although maybe this is not a major issue, as the differences are between 3 minor versions .

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pyMBE meeting discussion: keep this re-implementation for now, since it will be a couple of months until our community fully migrates to the newer Python version, but replace it with @warnings.deprecated() from Python 3.13 before the next minor release of pyMBE.

def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
warnings.warn(
f"{func.__name__} is deprecated and it will be removed in the future. Please use"+ new_function +"instead.",
DeprecationWarning,
stacklevel=2
)
return func(*args, **kwargs)
return wrapper
return decorator
10 changes: 6 additions & 4 deletions pyMBE/lib/handy_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import re
import numpy as np
import scipy
from pyMBE.exceptions.pmb_warnings import deprecated

def calculate_initial_bond_length(bond_parameters, bond_type, lj_parameters):
"""
Expand Down Expand Up @@ -281,7 +282,7 @@ def define_peptide_AA_residues(sequence,model, pmb):
pmb.define_residue(name = residue_name,
central_bead = central_bead,
side_chains = side_chains)

@deprecated('pmb.simulation_engine.do_reaction')
def do_reaction(algorithm, steps):
"""
Executes reaction steps using an ESPResSo reaction algorithm with
Expand Down Expand Up @@ -311,6 +312,7 @@ def do_reaction(algorithm, steps):
else:
algorithm.reaction(steps=steps)

@deprecated('pmb.simulation_engine.get_number_of_particles')
def get_number_of_particles(espresso_system, ptype):
"""
Returns the number of particles of a given ESPResSo particle type.
Expand Down Expand Up @@ -508,7 +510,7 @@ def protein_sequence_parser(sequence):
clean_sequence.append(residue_ok)
return clean_sequence


@deprecated('pmb.simulation_engine.relax_system')
def relax_espresso_system(espresso_system, seed, gamma=1e-3, Nsteps_steepest_descent=5000, max_displacement=0.01, Nsteps_iter_relax=500):
"""
Relaxes the energy of the given ESPResSo system by performing the following steps:
Expand Down Expand Up @@ -571,7 +573,7 @@ def relax_espresso_system(espresso_system, seed, gamma=1e-3, Nsteps_steepest_des
logging.info(f"*** Minimum particle distance after relaxation: {espresso_system.analysis.min_dist()} ***")
logging.debug("*** Relaxation finished ***")
return espresso_system.analysis.min_dist()

@deprecated('pmb.simulation_engine.setup_langevin_dynamics')
def setup_langevin_dynamics(espresso_system, kT, seed,time_step=1e-2, gamma=1, tune_skin=True, min_skin=1, max_skin=None, tolerance=1e-3, int_steps=200, adjust_max_skin=True):
"""
Sets up Langevin Dynamics for an ESPResSo simulation system.
Expand Down Expand Up @@ -634,7 +636,7 @@ def setup_langevin_dynamics(espresso_system, kT, seed,time_step=1e-2, gamma=1, t
int_steps=int_steps,
adjust_max_skin=adjust_max_skin)
logging.info(f"Optimized skin value: {espresso_system.cell_system.skin}")

@deprecated('pmb.simulation_engine.setup_electrostatic_interactions')
def setup_electrostatic_interactions(units, espresso_system, kT, c_salt=None, solvent_permittivity=78.5, method='p3m', tune_p3m=True, accuracy=1e-3, params=None, verbose=False):
"""
Sets up electrostatic interactions in an ESPResSo system.
Expand Down
2 changes: 1 addition & 1 deletion pyMBE/lib/lattice.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,5 +333,5 @@ def __init__(self,mpc,bond_l):
raise ValueError("mpc must be a non-zero positive integer.")
self.mpc = mpc
self.bond_l = bond_l
self.box_l = (self.mpc+2)*self.bond_l.magnitude / (np.sqrt(3)*0.25)
self.box_l = (self.mpc+1)*self.bond_l.magnitude / (np.sqrt(3)*0.25)

1,072 changes: 250 additions & 822 deletions pyMBE/pyMBE.py

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions pyMBE/simulation_builder/base_engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from abc import ABC,abstractmethod

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and in other new files: missing copyright notices.

import numpy as np

class SimulationEngine(ABC):
"""Base Class for simulation engines contains methods """
def __init__(self):
pass
@abstractmethod
def _check_bond_inputs(self):
return
@abstractmethod
def _create_bond_instance(self):
return
@abstractmethod
def _get_bond_instance(self):
return
@abstractmethod
def add_instances_to_engine(self):
return
def calculate_center_of_mass(self, instance_id, pmb_type):
"""
Calculates the center of mass of a pyMBE object instance in an ESPResSo system.

Args:
instance_id ('int'):
pyMBE instance ID of the object whose center of mass is calculated.

pmb_type ('str'):
Type of the pyMBE object. Must correspond to a particle-aggregating
template type (e.g. '"molecule"', '"residue"', '"peptide"', '"protein"').

Returns:
('numpy.ndarray'):
Array of shape '(3,)' containing the Cartesian coordinates of the
center of mass.

Notes:
- This method assumes equal mass for all particles.
- Periodic boundary conditions are *not* unfolded; positions are taken
directly from ESPResSo particle coordinates.
"""
center_of_mass = np.zeros(3)
axis_list = [0,1,2]
inst = self.db.get_instance(pmb_type=pmb_type,
instance_id=instance_id)
particle_id_list = self.db.get_particle_id_map(object_name=inst.name)["all"]
for pid in particle_id_list:
for axis in axis_list:
center_of_mass[axis] += self.db.get_instance(pmb_type='particle',
instance_id=pid).position[axis]
center_of_mass = center_of_mass / len(particle_id_list)
return center_of_mass
def determine_reservoir_concentrations(self, pH_res, c_salt_res, activity_coefficient_monovalent_pair, max_number_sc_runs=200):
"""
Determines ionic concentrations in the reservoir at fixed pH and salt concentration.

Args:
pH_res ('float'):
Target pH value in the reservoir.

c_salt_res ('pint.Quantity'):
Concentration of monovalent salt (e.g., NaCl) in the reservoir.

activity_coefficient_monovalent_pair ('callable'):
Function returning the activity coefficient of a monovalent ion pair
as a function of ionic strength:
'gamma = activity_coefficient_monovalent_pair(I)'.

max_number_sc_runs ('int', optional):
Maximum number of self-consistent iterations allowed before
convergence is enforced. Defaults to 200.

Returns:
tuple:
(cH_res, cOH_res, cNa_res, cCl_res)
- cH_res ('pint.Quantity'): Concentration of H⁺ ions.
- cOH_res ('pint.Quantity'): Concentration of OH⁻ ions.
- cNa_res ('pint.Quantity'): Concentration of Na⁺ ions.
- cCl_res ('pint.Quantity'): Concentration of Cl⁻ ions.

Notess:
- The algorithm enforces electroneutrality in the reservoir.
- Water autodissociation is included via the equilibrium constant 'Kw'.
- Non-ideal effects enter through activity coefficients depending on
ionic strength.
- The implementation follows the self-consistent scheme described in
Landsgesell (PhD thesis, Sec. 5.3, doi:10.18419/opus-10831), adapted
from the original code (doi:10.18419/darus-2237).
"""
def determine_reservoir_concentrations_selfconsistently(cH_res, c_salt_res):
"""
Iteratively determines reservoir ion concentrations self-consistently.

Args:
cH_res ('pint.Quantity'):
Current estimate of the H⁺ concentration.
c_salt_res ('pint.Quantity'):
Concentration of monovalent salt in the reservoir.

Returns:
'tuple':
(cH_res, cOH_res, cNa_res, cCl_res)
"""
# Initial ideal estimate
cOH_res = self.Kw / cH_res
if cOH_res >= cH_res:
cNa_res = c_salt_res + (cOH_res - cH_res)
cCl_res = c_salt_res
else:
cCl_res = c_salt_res + (cH_res - cOH_res)
cNa_res = c_salt_res
# Self-consistent iteration
for _ in range(max_number_sc_runs):
ionic_strength_res = 0.5 * (cNa_res + cCl_res + cOH_res + cH_res)
cOH_new = self.Kw / (cH_res * activity_coefficient_monovalent_pair(ionic_strength_res))
if cOH_new >= cH_res:
cNa_new = c_salt_res + (cOH_new - cH_res)
cCl_new = c_salt_res
else:
cCl_new = c_salt_res + (cH_res - cOH_new)
cNa_new = c_salt_res
# Update values
cOH_res = cOH_new
cNa_res = cNa_new
cCl_res = cCl_new
return cH_res, cOH_res, cNa_res, cCl_res
# Initial guess for H+ concentration from target pH
cH_res = 10 ** (-pH_res) * self.units.mol / self.units.l
# First self-consistent solve
cH_res, cOH_res, cNa_res, cCl_res = (determine_reservoir_concentrations_selfconsistently(cH_res,
c_salt_res))
ionic_strength_res = 0.5 * (cNa_res + cCl_res + cOH_res + cH_res)
determined_pH = -np.log10(cH_res.to("mol/L").magnitude* np.sqrt(activity_coefficient_monovalent_pair(ionic_strength_res)))
# Outer loop to enforce target pH
while abs(determined_pH - pH_res) > 1e-6:
if determined_pH > pH_res:
cH_res *= 1.005
else:
cH_res /= 1.003
cH_res, cOH_res, cNa_res, cCl_res = (determine_reservoir_concentrations_selfconsistently(cH_res,
c_salt_res))
ionic_strength_res = 0.5 * (cNa_res + cCl_res + cOH_res + cH_res)
determined_pH = -np.log10(cH_res.to("mol/L").magnitude * np.sqrt(activity_coefficient_monovalent_pair(ionic_strength_res)))
return cH_res, cOH_res, cNa_res, cCl_res
25 changes: 25 additions & 0 deletions pyMBE/simulation_builder/engine_protocol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from typing import Protocol,runtime_checkable

class EspressoParticleProtocol(Protocol):
"""Class that emulates the estructure of the Espresso Particle class"""
def add():
return
def by_id():
return
class EspressoBondedInterProtocol(Protocol):
"""Class that emulates the structure of the EspressoBondedInterProtocol"""
def add():
return

@runtime_checkable
class EspressoSystemProtocol(Protocol):
""" Class that emulates the structure of the methods employed by Pymbe from the espressomd.System class
. The decorator @runtime_checkable allows to only check for the structure not the types"""
part: EspressoParticleProtocol
bonded_inter: EspressoBondedInterProtocol

@runtime_checkable
class LammpsProtocol(Protocol):
""" Class that emulates the structure of the methods employed by Pymbe from the Lammps class
. The decorator @runtime_checkable allows to only check for the structure not the types"""

Loading
Loading