Increasing pyMBE interoperability (part I)#151
Conversation
…ass when the pymbe class is instantiated
… to ParticleInstance class
…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
…ows to the instance dataframe
…type in config class in order to be able to set the position as NDarrays
…presso from pymbe
_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
…ys and lists into the instances dataframe
-get_label_id_map -get_lj_parameters -get_radius_map -propose_unused_type
Add box_l in create methods from hydrogel_builder_with_angles and setup_angular_potential.
jngrad
left a comment
There was a problem hiding this comment.
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.
| ### 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])] |
There was a problem hiding this comment.
I agree, this code looks strange. If the current behavior is intended, the loop is superfluous.
There was a problem hiding this comment.
I agree too, the loop should be removed and central_bead_pos should simply take the first value in list_of_first_residue_positions
There was a problem hiding this comment.
Then, do I modify it in this current pull request as Pablo is suggesting? Or do i set an Issue?
| 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') |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Seems like a great idea to me!
To proceed with the modification:
- 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?
- I will write the methods from the LammpsSimulationEngine with a statement that raises a NotImplementedError, so the implementation follows the open-closed principle
There was a problem hiding this comment.
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 RuntimeErrorI'm not sure how this interact with ABC metaclass options.
| "\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", |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
No, this has been done unintentionally. Now I'm going to delete the outputs.
| @@ -0,0 +1,144 @@ | |||
| from abc import ABC,abstractmethod | |||
There was a problem hiding this comment.
Here and in other new files: missing copyright notices.
|
|
||
|
|
||
| def _get_particle_pos_espresso(self,id): | ||
| """_summary_ |
There was a problem hiding this comment.
Here and elsewhere, there are numerous occurrences of _summary_. Are these todo notes?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
I think that the place holder "_summary" in the docstrings should be replaced by a short description of what each method does.
| def deprecated(new_function): | ||
| """Wrapper function to display a warning deprecation message to all functions that are going to be removed in a future | ||
| """ |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 .
There was a problem hiding this comment.
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.
Co-authored-by: Jean-Noël Grad <jgrad@icp.uni-stuttgart.de>
| 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, |
There was a problem hiding this comment.
This comments should be removed
| @@ -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) | |||
|
|
||
| # 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)) |
There was a problem hiding this comment.
time series should not be comitted to the main repository please remove this file and other similar ones
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
|
@pm-blanco @jngrad 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? |
|
There seems to be an issue with how |
|
@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? |
|
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. |
…0.1 (which is compatible with EspressoSystem5.0.0 version)
Summary
Application of the strategy pattern to delegate the responsability of executing the simulation engine to a particular engine class (e.g
EspressoEngine).Added
EspressoEngineClassEspressoSystemProtocolClass to check that an the working engine corresponds to espresso.system instanceEspressoEngineEspressoEnginecalculate_net_charge,change_volume_and_re-scale_particles,enable_motion_of_rigid_object,etc.)add_instances_to_engineto add particles, bonds and angles to EspressoModified
create_particle,create_residue,create_molecule,etc. to avoid an explicit dependence to EspressoFixed
In commit: 217d15a
DiamondLattice. box_l=(self.mpc+1)*self.bond_l.magnitude / (np.sqrt(3)*0.25)_create_hydrogel_chain. backbone vector=vec_between_nodes / (self.lattice_builder.mpc+1)