From 3820a02d0f627be6d4108f18d83884b54d6efa7d Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Tue, 22 Sep 2015 14:03:18 +0200 Subject: [PATCH 1/9] Add basic benchmarking --- README.rst | 13 ++- simlammps/bench/__init__.py | 0 simlammps/bench/util.py | 73 ++++++++++++ simlammps/bench/wrapper_bench.py | 113 +++++++++++++++++++ simlammps/io/file_utility.py | 1 + simlammps/testing/md_example_configurator.py | 46 ++++---- 6 files changed, 217 insertions(+), 29 deletions(-) create mode 100644 simlammps/bench/__init__.py create mode 100644 simlammps/bench/util.py create mode 100644 simlammps/bench/wrapper_bench.py diff --git a/README.rst b/README.rst index 0b33146..184fe6f 100644 --- a/README.rst +++ b/README.rst @@ -94,11 +94,18 @@ Directory structure ------------------- - simlammps -- hold the lammps-md wrapper implementation + + - bench - benchmarking + - common - contains general global files + - config - holds configuration related files + - internal - internal library communication with LAMMPS + - io -- file-io related communication with LAMMPS + - testing -- testing related utilities - examples -- holds different examples - doc -- Documentation related files - - source -- Sphinx rst source files - - build -- Documentation build directory, if documentation has been generated - using the ``make`` script in the ``doc`` directory. + - source -- Sphinx rst source files + - build -- Documentation build directory, if documentation has been generated + using the ``make`` script in the ``doc`` directory. .. _simphony-common: https://github.com/simphony/simphony-common diff --git a/simlammps/bench/__init__.py b/simlammps/bench/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/simlammps/bench/util.py b/simlammps/bench/util.py new file mode 100644 index 0000000..9bd0a2a --- /dev/null +++ b/simlammps/bench/util.py @@ -0,0 +1,73 @@ +from __future__ import print_function + +import subprocess +import os +import tempfile +import shutil + +from simlammps import read_data_file + + +def get_particles(y_range): + """ get particles for benchmarking + + Parameters + ---------- + y_range : float + range of particle domain in y + + Returns + ------- + particle_list : iterable of ABCParticles + + """ + particles_list = None + + temp_dir = tempfile.mkdtemp() + script_name = os.path.join(temp_dir, "script") + data_name = os.path.join(temp_dir, "output") + try: + with open(script_name, "w") as script_file: + script_file.write(lammps_script.format(y_range, + data_name)) + cmd = ("lammps -screen none" + " -log none -echo none" + " < {}").format(script_name) + subprocess.check_call(cmd, shell=True) + particles_list = read_data_file(data_name) + finally: + shutil.rmtree(temp_dir) + return particles_list + + +lammps_script = """# create particles" +dimension 2 +atom_style atomic + +# create geometry +lattice hex .7 +region box block 0 {} 0 10 -0.25 0.25 +create_box 1 box +create_atoms 1 box + +mass 1 1.0 + +# LJ potentials +pair_style lj/cut 1.12246 +pair_coeff * * 1.0 1.0 1.12246 + +# define groups +region 1 block INF INF INF 1.25 INF INF +group lower region 1 +region 2 block INF INF 8.75 INF INF INF +group upper region 2 +group boundary union lower upper +group flow subtract all boundary + +# initial velocities +compute mobile flow temp +velocity flow create 1.0 482748 temp mobile +velocity boundary set 0.0 0.0 0.0 + +# write atoms to a lammps data file +write_data {}""" diff --git a/simlammps/bench/wrapper_bench.py b/simlammps/bench/wrapper_bench.py new file mode 100644 index 0000000..1c369a7 --- /dev/null +++ b/simlammps/bench/wrapper_bench.py @@ -0,0 +1,113 @@ +from simphony.engine import lammps +from simphony.bench.util import bench +from simphony.core.cuba import CUBA +from simphony.core.cuds_item import CUDSItem + +from simlammps.bench.util import get_particles +from simlammps.testing.md_example_configurator import MDExampleConfigurator + + +def configure_wrapper(wrapper, particles): + """ Configure wrapper + + Parameters: + ----------- + wrapper : ABCModelingEngine + wrapper to be configured + particles : iterable of ABCParticles + particles to use + + Returns + -------- + steps : int + number of steps which were run + number of particles : int + number of point configured + + """ + material_types = [] + number_particles = 0 + for dataset in particles: + material_types.append(dataset.data[CUBA.MATERIAL_TYPE]) + wrapper.add_dataset(dataset) + number_particles += dataset.count_of(CUDSItem.PARTICLE) + + MDExampleConfigurator.set_configuration(wrapper, material_types) + + return wrapper.CM[CUBA.NUMBER_OF_TIME_STEPS], number_particles + + +def run(wrapper): + wrapper.run() + + +def run_iterate(wrapper): + wrapper.run() + for particles_dataset in wrapper.iter_datasets(): + for particle in particles_dataset.iter_particles(): + pass + + +def run_update_run(wrapper): + wrapper.run() + for particles_dataset in wrapper.iter_datasets(): + for particle in particles_dataset.iter_particles(): + particles_dataset.update_particles([particle]) + wrapper.run() + + +def describe(name, number_particles, number_steps, is_internal): + wrapper_type = "INTERNAL" if is_internal else "FILE-IO" + result = "{}__{}_particles_{}_steps_{}:".format(name, + number_particles, + number_steps, + wrapper_type) + return result + + +if __name__ == '__main__': + + for y_range in [3000, 8000]: + for is_internal in [True, False]: + + lammps_wrapper = lammps.LammpsWrapper( + use_internal_interface=is_internal) + particles = get_particles(y_range) + number_steps, number_particles = configure_wrapper(lammps_wrapper, + particles) + + results = bench(lambda: run(lammps_wrapper), + repeat=1, + adjust_runs=False) + print(describe("run", + number_particles, + number_steps, + is_internal), + results) + + results = bench(lambda: run(lammps_wrapper), + repeat=1, + adjust_runs=False) + print(describe("run", + number_particles, + number_steps, + is_internal), + results) + + results = bench(lambda: run_iterate(lammps_wrapper), + repeat=1, + adjust_runs=False) + print(describe("run_iterate", + number_particles, + number_steps, + is_internal), + results) + + results = bench(lambda: run_update_run(lammps_wrapper), + repeat=1, + adjust_runs=False) + print(describe("run_update_run", + number_particles, + number_steps, + is_internal), + results) diff --git a/simlammps/io/file_utility.py b/simlammps/io/file_utility.py index e869705..dd025d5 100644 --- a/simlammps/io/file_utility.py +++ b/simlammps/io/file_utility.py @@ -42,6 +42,7 @@ def read_data_file(filename): for atom_type, mass in masses.iteritems(): data = DataContainer() data[CUBA.MASS] = mass + data[CUBA.MATERIAL_TYPE] = atom_type data_extension = {} data_extension[CUBAExtension.BOX_ORIGIN] = box_origin diff --git a/simlammps/testing/md_example_configurator.py b/simlammps/testing/md_example_configurator.py index 00d4d71..65dfcb4 100644 --- a/simlammps/testing/md_example_configurator.py +++ b/simlammps/testing/md_example_configurator.py @@ -22,7 +22,7 @@ class MDExampleConfigurator: (0.0, 0.0, 1001.0)] @staticmethod - def set_configuration(wrapper): + def set_configuration(wrapper, material_types=None): """ Configure example engine with example settings The wrapper is configured with required CM, SP, BC parameters @@ -30,6 +30,11 @@ def set_configuration(wrapper): Parameters ---------- wrapper : ABCModelingEngine + wrapper to be configured + material_types : iterable of int + material type that needs to be configured (used for pair + potentials). If None, then 3 (i.e. 1,2,3) material types + are assumed. """ @@ -38,34 +43,23 @@ def set_configuration(wrapper): wrapper.CM[CUBA.TIME_STEP] = 0.003 wrapper.CM_extension[CUBAExtension.THERMODYNAMIC_ENSEMBLE] = "NVE" + if material_types is None: + material_types = set([1, 2, 3]) + else: + material_types = set(material_types) + # SP pair_potential = ("lj:\n" " global_cutoff: 1.12246\n" - " parameters:\n" - " - pair: [1, 1]\n" - " epsilon: 1.0\n" - " sigma: 1.0\n" - " cutoff: 1.2246\n" - " - pair: [1, 2]\n" - " epsilon: 1.0\n" - " sigma: 1.0\n" - " cutoff: 1.2246\n" - " - pair: [1, 3]\n" - " epsilon: 1.0\n" - " sigma: 1.0\n" - " cutoff: 1.2246\n" - " - pair: [2, 2]\n" - " epsilon: 1.0\n" - " sigma: 1.0\n" - " cutoff: 1.2246\n" - " - pair: [2, 3]\n" - " epsilon: 1.0\n" - " sigma: 1.0\n" - " cutoff: 1.2246\n" - " - pair: [3, 3]\n" - " epsilon: 1.0\n" - " sigma: 1.0\n" - " cutoff: 1.0001\n") + " parameters:\n") + while material_types: + m_type = material_types.pop() + for other in ([t for t in material_types] + [m_type]): + pair_potential += " - pair: [{}, {}]\n".format(m_type, + other) + pair_potential += (" epsilon: 1.0\n" + " sigma: 1.0\n" + " cutoff: 1.2246\n") wrapper.SP_extension[CUBAExtension.PAIR_POTENTIALS] = pair_potential # BC From 3fcc28a123ad9db8084d180b695e71cd18b32116 Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Tue, 22 Sep 2015 17:06:02 +0200 Subject: [PATCH 2/9] Benchmark the configuration of the wrapper --- simlammps/bench/wrapper_bench.py | 104 ++++++++++--------- simlammps/testing/md_example_configurator.py | 6 +- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/simlammps/bench/wrapper_bench.py b/simlammps/bench/wrapper_bench.py index 1c369a7..09cc806 100644 --- a/simlammps/bench/wrapper_bench.py +++ b/simlammps/bench/wrapper_bench.py @@ -1,3 +1,8 @@ +from collections import namedtuple + +_Tests = namedtuple( + '_Tests', ['method', 'name']) + from simphony.engine import lammps from simphony.bench.util import bench from simphony.core.cuba import CUBA @@ -7,7 +12,7 @@ from simlammps.testing.md_example_configurator import MDExampleConfigurator -def configure_wrapper(wrapper, particles): +def configure_wrapper(wrapper, particles, number_time_steps): """ Configure wrapper Parameters: @@ -16,25 +21,17 @@ def configure_wrapper(wrapper, particles): wrapper to be configured particles : iterable of ABCParticles particles to use - - Returns - -------- - steps : int - number of steps which were run - number of particles : int - number of point configured - + number_time_steps : int + number of time steps to run """ material_types = [] - number_particles = 0 for dataset in particles: material_types.append(dataset.data[CUBA.MATERIAL_TYPE]) wrapper.add_dataset(dataset) - number_particles += dataset.count_of(CUDSItem.PARTICLE) - - MDExampleConfigurator.set_configuration(wrapper, material_types) - return wrapper.CM[CUBA.NUMBER_OF_TIME_STEPS], number_particles + MDExampleConfigurator.set_configuration(wrapper, + material_types, + number_time_steps) def run(wrapper): @@ -65,49 +62,54 @@ def describe(name, number_particles, number_steps, is_internal): return result +def run_test(func, wrapper): + func(wrapper) + if __name__ == '__main__': - for y_range in [3000, 8000]: - for is_internal in [True, False]: + run_wrapper_tests = [_Tests(method=run, + name="run"), + _Tests(method=run_iterate, + name="run_iterate"), + _Tests(method=run_update_run, + name="run_update_run")] + + for is_internal in [True, False]: + for y_range in [3000, 8000]: + # test different run scenarios + particles = get_particles(y_range) + number_particles = sum(p.count_of( + CUDSItem.PARTICLE) for p in particles) + number_time_steps = 10 + + for test in run_wrapper_tests: + lammps_wrapper = lammps.LammpsWrapper( + use_internal_interface=is_internal) + configure_wrapper(lammps_wrapper, + particles, + number_time_steps=number_time_steps) + + results = bench(lambda: run_test(test.method, lammps_wrapper), + repeat=1, + adjust_runs=False) + + print(describe(test.name, + number_particles, + number_time_steps, + is_internal), results) + + # test configuration lammps_wrapper = lammps.LammpsWrapper( use_internal_interface=is_internal) - particles = get_particles(y_range) - number_steps, number_particles = configure_wrapper(lammps_wrapper, - particles) - results = bench(lambda: run(lammps_wrapper), + results = bench(lambda: configure_wrapper(lammps_wrapper, + particles, + number_time_steps), repeat=1, adjust_runs=False) - print(describe("run", - number_particles, - number_steps, - is_internal), - results) - results = bench(lambda: run(lammps_wrapper), - repeat=1, - adjust_runs=False) - print(describe("run", - number_particles, - number_steps, - is_internal), - results) - - results = bench(lambda: run_iterate(lammps_wrapper), - repeat=1, - adjust_runs=False) - print(describe("run_iterate", - number_particles, - number_steps, - is_internal), - results) - - results = bench(lambda: run_update_run(lammps_wrapper), - repeat=1, - adjust_runs=False) - print(describe("run_update_run", - number_particles, - number_steps, - is_internal), - results) + print(describe("configure_wrapper", + number_particles, + number_time_steps, + is_internal), results) diff --git a/simlammps/testing/md_example_configurator.py b/simlammps/testing/md_example_configurator.py index 65dfcb4..1f2396c 100644 --- a/simlammps/testing/md_example_configurator.py +++ b/simlammps/testing/md_example_configurator.py @@ -22,7 +22,7 @@ class MDExampleConfigurator: (0.0, 0.0, 1001.0)] @staticmethod - def set_configuration(wrapper, material_types=None): + def set_configuration(wrapper, material_types=None, number_time_steps=10): """ Configure example engine with example settings The wrapper is configured with required CM, SP, BC parameters @@ -35,11 +35,13 @@ def set_configuration(wrapper, material_types=None): material type that needs to be configured (used for pair potentials). If None, then 3 (i.e. 1,2,3) material types are assumed. + number_time_steps : int + number of time steps to run """ # CM - wrapper.CM[CUBA.NUMBER_OF_TIME_STEPS] = 10 + wrapper.CM[CUBA.NUMBER_OF_TIME_STEPS] = number_time_steps wrapper.CM[CUBA.TIME_STEP] = 0.003 wrapper.CM_extension[CUBAExtension.THERMODYNAMIC_ENSEMBLE] = "NVE" From b27395d281554a592e791496c8f4b3a06fd1ddc8 Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Wed, 23 Sep 2015 14:06:22 +0200 Subject: [PATCH 3/9] Optimize adding multiple particles --- .../internal/lammps_internal_data_manager.py | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/simlammps/internal/lammps_internal_data_manager.py b/simlammps/internal/lammps_internal_data_manager.py index 9aabc65..5707c78 100644 --- a/simlammps/internal/lammps_internal_data_manager.py +++ b/simlammps/internal/lammps_internal_data_manager.py @@ -1,6 +1,7 @@ import uuid from simphony.core.cuba import CUBA +from simphony.core.cuds_item import CUDSItem from simphony.core.data_container import DataContainer from simphony.cuds.particles import Particle @@ -154,9 +155,7 @@ def _handle_new_particles(self, uname, particles): if CUBA.MATERIAL_TYPE not in self._pc_data[uname]: raise ValueError("Missing the required CUBA.MATERIAL_TYPE") - # add each item - for p in particles.iter_particles(): - self._add_atom(particle=p, uname=uname) + self._add_atoms(particles=particles, uname=uname) # TODO bonds @@ -418,3 +417,32 @@ def _add_atom(self, particle, uname): self._set_particle(particle, uname) return particle.uid + + def _add_atoms(self, particles, uname): + """ Add multiple particles as atoms to lammps + + The particles are assumed to all have a uuid (i.e. not None). + + The number of atoms to be added are randomly added somewhere + in the simulation box by LAMMPS and then their positions (and + other values are corrected/updated) + + Parameters + ---------- + particles : ABCParticles + particle with CUBA.MATERIAL_TYPE + + uname : str + non-changing unique name of particle container + + """ + p_type = self._pc_data[uname][CUBA.MATERIAL_TYPE] + + number_particles = particles.count_of(CUDSItem.PARTICLE) + self._lammps.command( + "create_atoms {} random {} 42 NULL".format(p_type, + number_particles)) + + for particle in particles.iter_particles(): + self._particles[uname].add(particle.uid) + self._set_particle(particle, uname) From 076cd9a3f8f13b4dd5ef4f27bcd7fda9ea6c1a17 Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Wed, 23 Sep 2015 17:18:15 +0200 Subject: [PATCH 4/9] Rework how particles are added in INTERNAL wrapper --- .../internal/lammps_internal_data_manager.py | 72 ++++++------------- 1 file changed, 21 insertions(+), 51 deletions(-) diff --git a/simlammps/internal/lammps_internal_data_manager.py b/simlammps/internal/lammps_internal_data_manager.py index 5707c78..e7f0133 100644 --- a/simlammps/internal/lammps_internal_data_manager.py +++ b/simlammps/internal/lammps_internal_data_manager.py @@ -1,7 +1,6 @@ import uuid from simphony.core.cuba import CUBA -from simphony.core.cuds_item import CUDSItem from simphony.core.data_container import DataContainer from simphony.cuds.particles import Particle @@ -128,7 +127,6 @@ def _handle_delete_particles(self, uname): def _handle_new_particles(self, uname, particles): """Add new particle container to this manager. - Parameters ---------- uname : string @@ -155,7 +153,7 @@ def _handle_new_particles(self, uname, particles): if CUBA.MATERIAL_TYPE not in self._pc_data[uname]: raise ValueError("Missing the required CUBA.MATERIAL_TYPE") - self._add_atoms(particles=particles, uname=uname) + self._add_atoms(particles=particles.iter_particles(), uname=uname) # TODO bonds @@ -225,10 +223,10 @@ def add_particle(self, particle, uname): """ if particle.uid not in self._particles[uname]: - return self._add_atom(particle, uname) + return self._add_atoms([particle], uname)[0] else: raise ValueError( - "particle with same uid ({}) alread exists".format( + "particle with same uid ({}) already exists".format( particle.uid)) def remove_particle(self, deleted_uid, uname): @@ -266,8 +264,7 @@ def remove_particle(self, deleted_uid, uname): # re-add the saved atoms for uname in saved_particles: - for particle in saved_particles[uname]: - self._add_atom(saved_particles[uname][particle], uname) + self._add_atoms(saved_particles[uname].values(), uname) def has_particle(self, uid, uname): """Has particle @@ -380,44 +377,6 @@ def _set_particle(self, particle, uname): data, particle.uid) - def _add_atom(self, particle, uname): - """ Add a atom to lammps - - If particle has uid equal to NONE, we will give - it an uuid - - Parameters - ---------- - particle : Particle - particle with CUBA.MATERIAL_TYPE - - uname : str - non-changing unique name of particle container - - Returns - ------- - uuid : - uid of added particle - - """ - coordinates = ("{0[0]:.16e} " - "{0[1]:.16e} " - "{0[2]:.16e}").format(particle.coordinates) - - p_type = self._pc_data[uname][CUBA.MATERIAL_TYPE] - - self._lammps.command( - "create_atoms {} single {} units box".format(p_type, coordinates)) - - if particle.uid is None: - particle.uid = uuid.uuid4() - - self._particles[uname].add(particle.uid) - - self._set_particle(particle, uname) - - return particle.uid - def _add_atoms(self, particles, uname): """ Add multiple particles as atoms to lammps @@ -429,20 +388,31 @@ def _add_atoms(self, particles, uname): Parameters ---------- - particles : ABCParticles + particles : iterable Particle particle with CUBA.MATERIAL_TYPE uname : str non-changing unique name of particle container + Returns + ------- + uuid : list of UUID4 + uids of added particles + """ p_type = self._pc_data[uname][CUBA.MATERIAL_TYPE] - number_particles = particles.count_of(CUDSItem.PARTICLE) - self._lammps.command( - "create_atoms {} random {} 42 NULL".format(p_type, - number_particles)) + uids = [] + for particle in particles: + if particle.uid is None: + particle.uid = uuid.uuid4() - for particle in particles.iter_particles(): self._particles[uname].add(particle.uid) self._set_particle(particle, uname) + + uids.append(particle.uid) + + self._lammps.command( + "create_atoms {} random {} 42 NULL".format(p_type, + len(uids))) + return uids From bff158c9548dde1de7feaa505d9b4ed23fb03ad2 Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Wed, 23 Sep 2015 17:20:31 +0200 Subject: [PATCH 5/9] Fix docstrs --- simlammps/abc_data_manager.py | 8 ++++---- simlammps/internal/lammps_internal_data_manager.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/simlammps/abc_data_manager.py b/simlammps/abc_data_manager.py index ead58cd..6f2d13f 100644 --- a/simlammps/abc_data_manager.py +++ b/simlammps/abc_data_manager.py @@ -204,8 +204,8 @@ def update_particle(self, particle, uname): Parameters ---------- - uid : - uid of particle + particle : Particle + particle to be udpated uname : string non-changing unique name of particles @@ -217,8 +217,8 @@ def add_particle(self, particle, uname): Parameters ---------- - uid : - uid of particle + particle : Particle + particle to be added uname : string non-changing unique name of particles diff --git a/simlammps/internal/lammps_internal_data_manager.py b/simlammps/internal/lammps_internal_data_manager.py index e7f0133..16959a0 100644 --- a/simlammps/internal/lammps_internal_data_manager.py +++ b/simlammps/internal/lammps_internal_data_manager.py @@ -199,8 +199,8 @@ def update_particle(self, particle, uname): Parameters ---------- - uid : - uid of particle + particle : Particle + particle to be updated uname : string non-changing unique name of particles @@ -216,8 +216,8 @@ def add_particle(self, particle, uname): Parameters ---------- - uid : - uid of particle + particle : Particle + particle to be added uname : string non-changing unique name of particles From 37233059b305276eddd303591839cd483cb7a7bd Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Thu, 24 Sep 2015 15:30:44 +0200 Subject: [PATCH 6/9] Fix method paramters to correctly match ABCParticles --- simlammps/lammps_particles.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/simlammps/lammps_particles.py b/simlammps/lammps_particles.py index bef8148..ddc1848 100644 --- a/simlammps/lammps_particles.py +++ b/simlammps/lammps_particles.py @@ -46,7 +46,7 @@ def data_extension(self, value): # Particle methods ###################################################### - def add_particles(self, particles): + def add_particles(self, iterable): """Adds a set of particles from the provided iterable to the container. @@ -74,15 +74,15 @@ def add_particles(self, particles): in the container. """ uids = [] - for particle in particles: + for particle in iterable: uids.append(self._manager.add_particle(particle, self._uname)) return uids - def update_particles(self, particles): + def update_particles(self, iterable): """Update particle """ - for particle in particles: + for particle in iterable: self._manager.update_particle(particle, self._uname) def get_particle(self, uid): From 231059a6cf67caa41394237ab06d570575066b42 Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Thu, 24 Sep 2015 17:58:34 +0200 Subject: [PATCH 7/9] Rework methods to add/update multiple particles --- simlammps/abc_data_manager.py | 23 ++++-- .../internal/lammps_internal_data_manager.py | 65 +++++++-------- simlammps/io/lammps_fileio_data_manager.py | 80 ++++++++----------- simlammps/lammps_particles.py | 10 +-- 4 files changed, 80 insertions(+), 98 deletions(-) diff --git a/simlammps/abc_data_manager.py b/simlammps/abc_data_manager.py index 6f2d13f..a29eeff 100644 --- a/simlammps/abc_data_manager.py +++ b/simlammps/abc_data_manager.py @@ -199,29 +199,38 @@ def get_particle(self, uid, uname): """ @abc.abstractmethod - def update_particle(self, particle, uname): + def update_particles(self, iterable, uname): """Update particle Parameters ---------- - particle : Particle - particle to be udpated + iterable : iterable of Particle objects + the particles that will be updated. uname : string non-changing unique name of particles + Raises + ------ + ValueError : + If any particle inside the iterable does not exist. + """ @abc.abstractmethod - def add_particle(self, particle, uname): - """Add particle + def add_particles(self, iterable, uname): + """Add particles Parameters ---------- - particle : Particle - particle to be added + iterable : iterable of Particle objects + the particles that will be added. uname : string non-changing unique name of particles + ValueError : + when there is a particle with an uids that already exists + in the container. + """ @abc.abstractmethod diff --git a/simlammps/internal/lammps_internal_data_manager.py b/simlammps/internal/lammps_internal_data_manager.py index 16959a0..3260454 100644 --- a/simlammps/internal/lammps_internal_data_manager.py +++ b/simlammps/internal/lammps_internal_data_manager.py @@ -153,7 +153,9 @@ def _handle_new_particles(self, uname, particles): if CUBA.MATERIAL_TYPE not in self._pc_data[uname]: raise ValueError("Missing the required CUBA.MATERIAL_TYPE") - self._add_atoms(particles=particles.iter_particles(), uname=uname) + self._add_atoms(iterable=particles.iter_particles(), + uname=uname, + safe=True) # TODO bonds @@ -194,40 +196,22 @@ def get_particle(self, uid, uname): else: raise KeyError("uid ({}) was not found".format(uid)) - def update_particle(self, particle, uname): - """Update particle - - Parameters - ---------- - particle : Particle - particle to be updated - uname : string - non-changing unique name of particles + def update_particles(self, iterable, uname): + """Update particles """ - if particle.uid in self._particles[uname]: - self._set_particle(particle, uname) - else: - raise ValueError( - "particle id ({}) was not found".format(particle.uid)) - - def add_particle(self, particle, uname): + for particle in iterable: + if particle.uid in self._particles[uname]: + self._set_particle(particle, uname) + else: + raise ValueError( + "particle id ({}) was not found".format(particle.uid)) + + def add_particles(self, iterable, uname): """Add particle - Parameters - ---------- - particle : Particle - particle to be added - uname : string - non-changing unique name of particles - """ - if particle.uid not in self._particles[uname]: - return self._add_atoms([particle], uname)[0] - else: - raise ValueError( - "particle with same uid ({}) already exists".format( - particle.uid)) + return self._add_atoms(iterable, uname, safe=False) def remove_particle(self, deleted_uid, uname): """Remove particle @@ -264,7 +248,7 @@ def remove_particle(self, deleted_uid, uname): # re-add the saved atoms for uname in saved_particles: - self._add_atoms(saved_particles[uname].values(), uname) + self._add_atoms(saved_particles[uname].values(), uname, safe=True) def has_particle(self, uid, uname): """Has particle @@ -377,23 +361,26 @@ def _set_particle(self, particle, uname): data, particle.uid) - def _add_atoms(self, particles, uname): + def _add_atoms(self, iterable, uname, safe=False): """ Add multiple particles as atoms to lammps - The particles are assumed to all have a uuid (i.e. not None). - The number of atoms to be added are randomly added somewhere in the simulation box by LAMMPS and then their positions (and other values are corrected/updated) Parameters ---------- - particles : iterable Particle + iterable : iterable of Particle objects particle with CUBA.MATERIAL_TYPE uname : str non-changing unique name of particle container + safe : bool + True if uids do not need to be to be checked (e.g.. in the + case that all particles are being added to an empty particle + container). False if uids need to be checked. + Returns ------- uuid : list of UUID4 @@ -403,15 +390,21 @@ def _add_atoms(self, particles, uname): p_type = self._pc_data[uname][CUBA.MATERIAL_TYPE] uids = [] - for particle in particles: + for particle in iterable: if particle.uid is None: particle.uid = uuid.uuid4() + if not safe and particle.uid in self._particles[uname]: + raise ValueError( + "particle with same uid ({}) already exists".format( + particle.uid)) + self._particles[uname].add(particle.uid) self._set_particle(particle, uname) uids.append(particle.uid) + # create atoms in lammps self._lammps.command( "create_atoms {} random {} 42 NULL".format(p_type, len(uids))) diff --git a/simlammps/io/lammps_fileio_data_manager.py b/simlammps/io/lammps_fileio_data_manager.py index 50c97aa..27cfb57 100644 --- a/simlammps/io/lammps_fileio_data_manager.py +++ b/simlammps/io/lammps_fileio_data_manager.py @@ -10,6 +10,27 @@ from simlammps.abc_data_manager import ABCDataManager +# TODO derive supported cuba from atom type +_SUPPORTED_CUBA = [CUBA.VELOCITY] + + +def filter_unsupported_data(iterable): + """Ensure iterators only provide particles with only supported data + + Parameters + ---------- + iterable : iterator of Particles + + """ + for particle in iterable: + data = particle.data + supported_data = {cuba: data[cuba] for cuba in + data if cuba in _SUPPORTED_CUBA} + supported_particle = Particle(coordinates=particle.coordinates, + uid=particle.uid, + data=supported_data) + yield supported_particle + class LammpsFileIoDataManager(ABCDataManager): """ Class managing Lammps data information using file-io @@ -136,61 +157,24 @@ def get_particle(self, uid, uname): """ return self._pc_cache[uname].get_particle(uid) - def _get_supported_particle(self, particle): - """Get particle with only supported data - - Parameters - ---------- - particle : Particle - Particle - - Returns - ------- - particle - particle with only supported data - + def update_particles(self, iterable, uname): + """Update particles """ - # TODO derive supported cuba from atom type - _SUPPORTED_CUBA = [CUBA.VELOCITY] - - data = particle.data - supported_data = {cuba: data[cuba] for cuba - in data if cuba in _SUPPORTED_CUBA} - p = Particle(coordinates=particle.coordinates, - uid=particle.uid, - data=supported_data) - return p + self._pc_cache[uname].update_particles( + filter_unsupported_data(iterable)) - def update_particle(self, particle, uname): - """Update particle - - Parameters - ---------- - uid : - uid of particle - uname : string - name of particle container + def add_particles(self, iterable, uname): + """Add particles """ - self._pc_cache[uname].update_particles([ - self._get_supported_particle(particle)]) + uids = self._pc_cache[uname].add_particles(iterable) - def add_particle(self, particle, uname): - """Add particle + # filter the cached particles of unsupported CUBA + self._pc_cache[uname].update_particles(filter_unsupported_data( + self._pc_cache[uname].iter_particles(uids))) - Parameters - ---------- - uid : - uid of particle - uname : string - name of particle container - - """ - uids = self._pc_cache[uname].add_particles([ - self._get_supported_particle(particle)]) - particle.uid = uids[0] - return particle.uid + return uids def remove_particle(self, uid, uname): """Remove particle diff --git a/simlammps/lammps_particles.py b/simlammps/lammps_particles.py index ddc1848..430ef35 100644 --- a/simlammps/lammps_particles.py +++ b/simlammps/lammps_particles.py @@ -73,17 +73,13 @@ def add_particles(self, iterable): when there is a particle with an uids that already exists in the container. """ - uids = [] - for particle in iterable: - uids.append(self._manager.add_particle(particle, self._uname)) - return uids + return self._manager.add_particles(iterable, self._uname) def update_particles(self, iterable): - """Update particle + """Update particles """ - for particle in iterable: - self._manager.update_particle(particle, self._uname) + self._manager.update_particles(iterable, self._uname) def get_particle(self, uid): """Get particle From 80f4461001ca3987f6b116cf3c11573dc500cc33 Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Mon, 28 Sep 2015 13:12:48 +0200 Subject: [PATCH 8/9] Add multiple types to bench marking --- simlammps/bench/util.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/simlammps/bench/util.py b/simlammps/bench/util.py index 9bd0a2a..9213ba6 100644 --- a/simlammps/bench/util.py +++ b/simlammps/bench/util.py @@ -28,8 +28,8 @@ def get_particles(y_range): data_name = os.path.join(temp_dir, "output") try: with open(script_name, "w") as script_file: - script_file.write(lammps_script.format(y_range, - data_name)) + script_file.write(lammps_script.format(y_range=y_range, + data_name=data_name)) cmd = ("lammps -screen none" " -log none -echo none" " < {}").format(script_name) @@ -46,11 +46,13 @@ def get_particles(y_range): # create geometry lattice hex .7 -region box block 0 {} 0 10 -0.25 0.25 -create_box 1 box +region box block 0 {y_range} 0 10 -0.25 0.25 +create_box 3 box create_atoms 1 box mass 1 1.0 +mass 2 1.0 +mass 3 1.0 # LJ potentials pair_style lj/cut 1.12246 @@ -64,10 +66,13 @@ def get_particles(y_range): group boundary union lower upper group flow subtract all boundary +set group lower type 2 +set group upper type 3 + # initial velocities compute mobile flow temp velocity flow create 1.0 482748 temp mobile velocity boundary set 0.0 0.0 0.0 # write atoms to a lammps data file -write_data {}""" +write_data {data_name}""" From 9fec242d8aac6eeedfb27313f6f1bb5439a54cf4 Mon Sep 17 00:00:00 2001 From: Nathan Franklin Date: Mon, 28 Sep 2015 13:32:34 +0200 Subject: [PATCH 9/9] Add new get_dataset_names method to engine --- simlammps/lammps_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/simlammps/lammps_wrapper.py b/simlammps/lammps_wrapper.py index 40b76e8..cb177a7 100644 --- a/simlammps/lammps_wrapper.py +++ b/simlammps/lammps_wrapper.py @@ -121,6 +121,13 @@ def get_dataset(self, name): raise KeyError( 'Particle container \'{}\` does not exist'.format(name)) + def get_dataset_names(self): + """ Returns the names of all the datasets + + """ + for name in self._data_manager: + yield name + def remove_dataset(self, name): """ Remove a dataset