Skip to content

Increasing pyMBE interoperability (part I)#151

Open
jorch28 wants to merge 77 commits into
pyMBE-dev:mainfrom
jorch28:CheckThisFeature
Open

Increasing pyMBE interoperability (part I)#151
jorch28 wants to merge 77 commits into
pyMBE-dev:mainfrom
jorch28:CheckThisFeature

Conversation

@jorch28

@jorch28 jorch28 commented Jun 24, 2026

Copy link
Copy Markdown

Summary

Application of the strategy pattern to delegate the responsability of executing the simulation engine to a particular engine class (e.g EspressoEngine).

Added

  • EspressoEngine Class
  • EspressoSystemProtocol Class to check that an the working engine corresponds to espresso.system instance
  • reaction methods to EspressoEngine
  • handy functions to EspressoEngine
  • miscellaneous methods as (calculate_net_charge, change_volume_and_re-scale_particles,enable_motion_of_rigid_object,etc.)
  • method add_instances_to_engine to add particles, bonds and angles to Espresso

Modified

  • create_particle,create_residue, create_molecule,etc. to avoid an explicit dependence to Espresso
  • unit_tests and functional_tests accordingly so that they introduce the particles, bonds and angles before choosing espresso as the working engine. Execute pmb methods from the simulation_engine when they depend on espresso.

Fixed

In commit: 217d15a

  • class DiamondLattice. box_l=(self.mpc+1)*self.bond_l.magnitude / (np.sqrt(3)*0.25)
  • method _create_hydrogel_chain. backbone vector=vec_between_nodes / (self.lattice_builder.mpc+1)

jsd94 and others added 30 commits April 8, 2026 21:21
…le_position,inst._particle_fix to _get_instances_df method
- create_espresso_bond_instance
-_create_hydrogel_chain
- create_hydrogel
-_get_espresso_bond_instance
- create_added_salt
- create_counterions
- create_bond
-create_particle
-create_residue
-create_molecule
-create_protein
add methods to enable the decoupling:
-set_simulation_engine
-add_instances_to_engine
- algorithm to add instances to espresso system
…type in config class in order to be able to set the position as NDarrays
_create_hydrogel_chain
_delete_particles_from_engine
calculate_net_charge
center_object_simulation_box
create_counterions
create_hydrogel
create_particle
delete_instances_in_system

Add methods:
change_volume_and_rescale_particles
update_instances_ids_according_to_engine_particle_ids
…t the missing particles from pymbe DB and the particles that have not been transferred yet to espresso.

Add methods _add_bond, _add_particle,_check_particle_exists_in_espresso,_get_last_particle_id_in_espresso,update_instances_ids_according_to_engine_particles_ids
…ase_csv and _save_database_csv

Add added_to_engine for pmb_type bond in _load_database_csv and _save_database_csv.
This methods still have to pass the test due float point accuracy between save/load
…e, particle_id,position and added_to_engine.

Add pymbe type bond and allowed particle_id1,particle_id2 and added_to_engine
The main modification consists on setting as the simulation engine espresso and adding to the simulation engine the instances (particles and bonds ) to the engine. Also removing espresso as an argument from pymbe methods. Adding box_l as argument to pymbe methods
-reaction_montecarlomethods
-determine_reservoir_concentrations
Migrate methods the following methods to the manager:
-propose_unused_types
-get_lj_parameters
-get_radius_map
-_get_label_id_map
- handy functions
- reaction methods
- calculate_center_of_mass
-determine_reservoir_concentrations
-get_label_id_map
-get_lj_parameters
-get_radius_map
-propose_unused_type
@pm-blanco pm-blanco added enhancement New feature or request code quality labels Jun 30, 2026
@pm-blanco pm-blanco added this to the pyMBEv2.0.0 milestone Jun 30, 2026
Add box_l in create methods from hydrogel_builder_with_angles and setup_angular_potential.

@jngrad jngrad left a comment

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.

Overall, I really like how the ESPResSo instance was made a data member of the pyMBE class. This really helps separate the pyMBE molecular building logic from the ESPResSo implementation details, and will make it easier for contributors from other communities to contribute to pyMBE, once LAMMPS is supported.

Comment thread pyMBE/pyMBE.py Outdated
Comment thread pyMBE/pyMBE.py
Comment on lines +1100 to 1103
### This seems like a bug
### the variable central bead pos gets assigned the same value for the lengthh of list_of_first_residue_positions
for item in list_of_first_residue_positions:
central_bead_pos = [np.array(list_of_first_residue_positions[pos_index])]

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 agree, this code looks strange. If the current behavior is intended, the loop is superfluous.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I agree too, the loop should be removed and central_bead_pos should simply take the first value in list_of_first_residue_positions

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.

Then, do I modify it in this current pull request as Pablo is suggesting? Or do i set an Issue?

Comment thread pyMBE/pyMBE.py
Comment on lines +1696 to +1702
if isinstance(self.simulation_engine,EspressoSimulation):
angle_inst=self.simulation_engine._get_angle_instance(angle_template=angle_template)
return angle_inst
elif isinstance(self.simulation_engine,LammpsSimulation):
raise NotImplementedError('It has not yet been implemented for Lammps')
else:
raise RuntimeError('You have not set up any simulation engine yet')

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 elsewhere, what is the intention behind the if/else chain? If the simulation engines share the same API, we could call self.simulation_engine.method() and let the class instance raise a NotImplementedError if the method doesn't exist for that engine, or a RuntimeError if the engine was never set, e.g. using a dummy engine class that throws for any method call. This would satisfy the open–closed principle: adding a new GROMACS simulation engine would only require implementing the corresponding class, and there would be no need to adapt all if/else chains in methods of pyMBE.py.

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.

Seems like a great idea to me!
To proceed with the modification:

  1. By default the instance variable of the simulation_engine=DummySimulationengine() which overrides the methods from the BaseClass and raises a RuntimeError in case that the method is executed?
  2. I will write the methods from the LammpsSimulationEngine with a statement that raises a NotImplementedError, so the implementation follows the open-closed principle

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.

Regarding point 1, here is the general pattern:

class MyClass:
    def test(self):
        return 5
    def __getattr__(self, attr):
        if attr not in self.__dict__:
            raise RuntimeError('You have not set up any simulation engine yet')
        return super().__getattr__(attr)


obj = MyClass()
obj.test() # doesn't raise
obj.method() # raises RuntimeError

I'm not sure how this interact with ABC metaclass options.

Comment on lines -3540 to -3542
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
"\u001b[31mValueError\u001b[39m Traceback (most recent call last)",
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[44]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m mol_ids = \u001b[43mpmb\u001b[49m\u001b[43m.\u001b[49m\u001b[43mcreate_molecule\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m \u001b[49m\u001b[43m=\u001b[49m\u001b[43m \u001b[49m\u001b[43msequence\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 2\u001b[39m \u001b[43m \u001b[49m\u001b[43mnumber_of_molecules\u001b[49m\u001b[43m=\u001b[49m\u001b[43m \u001b[49m\u001b[43mN_peptide\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 3\u001b[39m \u001b[43m \u001b[49m\u001b[43mespresso_system\u001b[49m\u001b[43m \u001b[49m\u001b[43m=\u001b[49m\u001b[43m \u001b[49m\u001b[43mespresso_system\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 4\u001b[39m \u001b[43m \u001b[49m\u001b[43mlist_of_first_residue_positions\u001b[49m\u001b[43m \u001b[49m\u001b[43m=\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43m[\u001b[49m\u001b[43mBox_L\u001b[49m\u001b[43m.\u001b[49m\u001b[43mto\u001b[49m\u001b[43m(\u001b[49m\u001b[33;43m'\u001b[39;49m\u001b[33;43mreduced_length\u001b[39;49m\u001b[33;43m'\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m.\u001b[49m\u001b[43mmagnitude\u001b[49m\u001b[43m/\u001b[49m\u001b[32;43m2\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m*\u001b[49m\u001b[32;43m3\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 5\u001b[39m pmb.get_instances_df(pmb_type=\u001b[33m\"\u001b[39m\u001b[33mpeptide\u001b[39m\u001b[33m\"\u001b[39m)\n",

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 elsewhere in this notebook: that's a lot of text formatted for specific interpreters (ANSI escape code). Do we really need to ship this notebook with all outputs? There are ways to execute notebooks in CI to regenerate output cells, and to export the final notebook as a HTML page for the GitHub Pages.

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.

No, this has been done unintentionally. Now I'm going to delete the outputs.

@@ -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.



def _get_particle_pos_espresso(self,id):
"""_summary_

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 elsewhere, there are numerous occurrences of _summary_. Are these todo notes?

@jorch28 jorch28 Jun 30, 2026

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.

Nope. The extension AutoDocstring from VSCode generates the word summary automatically. I almost always keep it, because it is the header of the section as it happens as well with the words: Args, Return and sometimes Notes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think that the place holder "_summary" in the docstrings should be replaced by a short description of what each method does.

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

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.

Comment thread pyMBE/pyMBE.py
bond_inst = self._get_espresso_bond_instance(bond_template=bond_tpl,
espresso_system=espresso_system)
espresso_system.part.by_id(particle_id1).add_bond((bond_inst, particle_id2))
# bond_inst = self._get_espresso_bond_instance(bond_template=bond_tpl,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This comments should be removed

Comment thread pyMBE/pyMBE.py
@@ -1686,10 +1646,10 @@ def create_angular_potential(self, particle_id1, particle_id2, particle_id3, esp
central_name=particle_inst_2.name,
side_name2=particle_inst_3.name,
use_default_angle=use_default_angle)
angle_inst = self._get_espresso_angle_instance(angle_template=angle_tpl, espresso_system=espresso_system)
# angle_inst = self._get_espresso_angle_instance(angle_template=angle_tpl, espresso_system=espresso_system)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

remove this comment

Comment thread pyMBE/pyMBE.py

# ESPResSo angle bonds are added to the central particle
espresso_system.part.by_id(particle_id2).add_bond((angle_inst, particle_id1, particle_id3))
# espresso_system.part.by_id(particle_id2).add_bond((angle_inst, particle_id1, particle_id3))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

remove this comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

time series should not be comitted to the main repository please remove this file and other similar ones

jorch28 added 6 commits July 1, 2026 17:47
Add methods descriptions,remove unused import
Modify default value for fix=False. As fix=[False,False,False] is considered as a dangerous default value for pylint.
Modify if/else chain ,that raised different exceptions depending on the instantiated simulation Engine, in class pymbe_library  methods implemented by espresso by simulation_engine.method
@jorch28

jorch28 commented Jul 2, 2026

Copy link
Copy Markdown
Author

@pm-blanco @jngrad
For version ESPREesSo 5.0-dev testsuite is failing due to an error importing espressomd. In the workflow execution logs it is shown that the module espresso is not loaded. I think this happens because in the push_pull.yaml the value for the key upload artifact in jobs.ubuntu.strategy.matrix.espresso.upload_artifact=False.

For ESPREsSO 4.2.2, all tests are passing, but they last longer than 300s and the last test 26/26 is not being executed. Did this happened before?

@jngrad

jngrad commented Jul 2, 2026

Copy link
Copy Markdown
Member

There seems to be an issue with how module save handles the dev.eessi.io stack. In addition, the runner is executing actions with the wrong Node.js version. Let's drop the development stack in favor of the stable repository, and upgrade all software and operating systems. I'll open a separate PR, since it's orthogonal to this work.

@pm-blanco

Copy link
Copy Markdown
Collaborator

@jorch28 we have already updated the runner pipeline in the main pyMBE-dev repo, can you merge it here and see if now the tests pass?

@jorch28

jorch28 commented Jul 2, 2026

Copy link
Copy Markdown
Author

Now, for version 5.0.1 seems that there is no error related to import espressomd anymore. Thank you for your very fast answer! I'm going to add the method _check_bond_input to the LammpsSimulationEngine that is missing and therefore is not complying with the contract setup by the interface.
The actual problem was related to the differences between the methods and attributes from espressosystem in version 4.2.2 and version 5.0.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code quality enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants