def test_change_species(self): from copy import deepcopy from atooms.system import System, Particle system_A = System([Particle(species='A'), Particle(species='B')]) system_C = System([Particle(species='0'), Particle(species='1')]) system_F = System([Particle(species='1'), Particle(species='2')]) from atooms.trajectory.decorators import change_species # DO nothing here self.assertTrue( _equal(system_A, change_species(deepcopy(system_A), 'A'))) self.assertTrue( _equal(system_C, change_species(deepcopy(system_C), 'C'))) self.assertTrue( _equal(system_F, change_species(deepcopy(system_F), 'F'))) # Change self.assertTrue( _equal(system_C, change_species(deepcopy(system_A), 'C'))) self.assertTrue( _equal(system_F, change_species(deepcopy(system_A), 'F'))) self.assertTrue( _equal(system_A, change_species(deepcopy(system_C), 'A'))) self.assertTrue( _equal(system_F, change_species(deepcopy(system_C), 'F'))) self.assertTrue( _equal(system_A, change_species(deepcopy(system_F), 'A'))) self.assertTrue( _equal(system_C, change_species(deepcopy(system_F), 'C')))
def test_view(self): import numpy from atooms.system import Particle, System p = [Particle(), Particle()] s = System(p) pos = s.dump("pos", order='F', view=True) # Modify the dumped array in place preserves the view pos[:, 0] += 1.0 self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # Modify the position array in place preserves the view p[0].position *= 2 self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # Modify the position array in place preserves the view p[0].position[:] = p[0].position[:] + 4 self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) pos[:, 0] = pos[:, 0] + 1.0 self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # Reassining the position will of course destroy the view p[0].position = p[0].position * 2 self.assertFalse((p[0].position == pos[:, 0]).all()) self.assertFalse(numpy.may_share_memory(p[0].position, pos[:, 0]))
def test_interacting_system(self): p = PairPotential('lennard_jones', { 'epsilon': 1.0, 'sigma': 1.0 }, [1, 1], CutOff('CS', 2.5)) i = Interaction(p, 'atomic') s = System() s.interaction = i
def setUp(self): N = 100 L = 10.0 self.ref = System() self.ref.cell = Cell([L, L, L]) self.ref.particle = [] self.ref.thermostat = Thermostat(1.0) self.ref.barostat = Barostat(1.0) self.ref.reservoir = Reservoir(1.0) while len(self.ref.particle) <= N: pos = [(random.random() - 0.5) * L, (random.random() - 0.5) * L, (random.random() - 0.5) * L] self.ref.particle.append(Particle(position=pos))
def setUp(self): import copy particle = [ Particle(position=[0.0, 0.0, 0.0], species='A', mass=1.0), Particle(position=[1.0, 1.0, 1.0], species='B', mass=2.0), ] cell = Cell([2.0, 2.0, 2.0]) self.system = [] self.system.append(System(copy.deepcopy(particle), cell)) self.system.append(System(copy.deepcopy(particle), cell)) self.inpfile = '/tmp/test_trajectory' self.inpdir = '/tmp/test_trajectory.d' from atooms.core.utils import mkdir mkdir(self.inpdir)
def test_ovito(self): try: import ovito except ImportError: self.skipTest('missing ovito') N = 3 L = 5.0 system = System() system.cell = Cell([L, L, L]) system.particle = [] for _ in range(N): pos = (numpy.random.random(len(system.cell.side)) - 0.5) * system.cell.side p = Particle(position=pos) system.particle.append(p) image = system.show('ovito')
def dump_config(filename, pos=None, diam=None, ptypes=None, box=None, compress=None): file_ext = os.path.splitext(filename)[1] cell = Cell(side=box) npart = pos.shape[0] particles = [] for i in range(npart): p = Particle(species=ptypes[i], position=pos[i, :] - box / 2., radius=diam[i] / 2.) particles.append(p) system = System(particle=particles, cell=cell) with Trajectory(filename, "w") as traj: # Step is always 0 for now. traj.write(system, 0) if file_ext == ".xyz": compress = True else: compress = False if compress: subprocess.run(["gzip", "-f", filename])
def read_sample(self, frame): """ returns System instance. """ snap = self.trajectory[frame] ndim = snap.configuration.dimensions # Convert typeid from [0, 0, 1, ...] to ['A', 'A', 'B', ...] when snap.particles.types = ['A', 'B'] distinct_species = snap.particles.types distinct_typeids = list(range(len(distinct_species))) typeid_to_species = {} for i in distinct_typeids: typeid_to_species[i] = distinct_species[i] box = snap.configuration.box[: ndim] # atooms does not handle sheared boxes. cell = Cell(side=box) N = snap.particles.position.shape[0] particles = [] for i in range(N): p = Particle(mass=snap.particles.mass[i], species=typeid_to_species[snap.particles.typeid[i]], position=snap.particles.position[i, :ndim], velocity=snap.particles.velocity[i, :ndim], radius=snap.particles.diameter[i] / 2) particles.append(p) return System(particle=particles, cell=cell)
def test_ram_inplace(self): particle = [Particle(position=[0.0, 0.0, 0.0])] system = System(particle) t = TrajectoryRam() t[0] = system particle[0].position += 1.0 self.assertFalse( (t[0].particle[0].position == particle[0].position).all())
def test_ram(self): particle = [Particle(position=[0.0, 0.0, 0.0])] system = System(particle) t = TrajectoryRam() t[0] = system particle[0].position = numpy.array([1.0, 1.0, 1.0]) self.assertFalse( (t[0].particle[0].position == particle[0].position).all())
def test_write_initial_state(self): p = [ PairPotential('lennard_jones', { 'epsilon': 1.0, 'sigma': 1.0 }, [1, 1], CutOff('CS', 2.5)) ] i = [Interaction(p, 'atomic')] s = System() s.cell = Cell([1.0, 1.0, 1.0]) t = TrajectoryHDF5('/tmp/test_potential.h5', 'w') t.write_interaction(i) t.close() t = TrajectoryHDF5('/tmp/test_potential.h5', 'r') i = t.read_interaction() t.close()
def test_ram_copy(self): particle = [Particle(position=[0.0, 0.0, 0.0])] system = System(particle) t = TrajectoryRam() t[0] = system t[0].particle[0].position = numpy.array([1.0, 1.0, 1.0]) # print system.particle[0].position, t[0].particle[0].position # print id(t[0].particle[0]) # print id(t[0].particle[0]) particle = [Particle(position=[0.0, 0.0, 0.0])] system = System(particle) s = System(particle) t = TrajectoryRamFull() t[0] = system s.update(t[0]) s.particle[0].position = numpy.array([1.0, 1.0, 1.0]) # print system.particle[0].position, t[0].particle[0].position, s.particle[0].position # print id(t[0].particle[0]) # print id(t[0].particle[0]) particle = [Particle(position=[0.0, 0.0, 0.0])] system = System(particle) t = TrajectoryRamFull() t[0] = system system.particle[0].position = numpy.array([1.0, 1.0, 1.0])
def test_dump_cbk(self): """ Make sure that applying callbacks or changing the particle array size creates a new dump. """ import numpy from atooms.system import Particle, System for view in [False, True]: p = [Particle(), Particle()] s = System(p) pos1 = s.dump("pos", view=view) def cbk(system): s = copy.copy(system) s.particle = [system.particle[0]] return s s = cbk(s) pos2 = s.dump('pos', view=view) self.assertEqual(pos1.shape, (2, 3)) self.assertEqual(pos2.shape, (1, 3)) # Grandcanonical s.particle.append(Particle()) self.assertEqual(s.dump('pos', view=view).shape, (2, 3)) # Reassign particle # Expected failure with view = True if not view: s.particle[0] = Particle(position=[1.0, 1.0, 1.0]) self.assertEqual(s.dump('pos', view=view)[0][0], 1.0)
def read_sample(self, frame): cfg, box, pos, typ, vel = self.__read_one(self.__f_frames[frame]) if vel is None: particle = [Particle(species=t, position=numpy.array(p)) for p, t in zip(pos, typ)] else: particle = [Particle(species=t, position=numpy.array(p), velocity=numpy.array(v)) for p, t, v in zip(pos, typ, vel)] cell = Cell(numpy.array(box)) return System(particle, cell)
def test_dump_species(self): """ Make sure that changing species in the dump is reflected in the particle species and viceversa. """ import numpy from atooms.system import Particle, System view = True p = [Particle(), Particle()] s = System(p) spe = s.dump("particle.species", view=True) spe[0] = 'B' self.assertEqual(spe[0], s.particle[0].species) # With this syntax, the numpy scalar preserves the view! # We should upgrade species to property and hide this inside s.particle[0].species[()] = 'C' self.assertEqual(spe[0], s.particle[0].species)
def test_ram_full(self): particle = [Particle(position=[0.0, 0.0, 0.0])] system = System(particle) t = TrajectoryRamFull() t[0] = system system.particle[0].position = numpy.array([2.0, 2.0, 2.0]) t[0] = system particle[0].position += 1.0 self.assertFalse( (t[0].particle[0].position == particle[0].position).all())
def test_write_initial_state(self): p = [ PairPotential("lennard_jones", { "epsilon": 1.0, "sigma": 1.0 }, [1, 1], CutOff("CS", 2.5)) ] i = [Interaction(p, "atomic")] s = System() s.particle = [ Particle(position=[1.0, 1.0, 1.0], velocity=[0.0, 0.0, 0.0]) ] s.cell = Cell([1.0, 1.0, 1.0]) with TrajectoryHDF5('/tmp/test_hdf5.h5', 'w') as t: t.write_interaction(i) t.write(s, 0) with TrajectoryHDF5('/tmp/test_hdf5.h5', 'r') as t: i = t.read_interaction() s = t[0]
def test_view_clear(self): import numpy from atooms.system import Particle, System p = [Particle(), Particle()] s = System(p) # We check that particle positions are views on dump array pos = s.dump("pos", order='F', view=True) self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # We should get the same dump array pos = s.dump("pos", order='F', view=True) self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # We clear the dump array pos1 = s.dump("pos", order='F', view=True, clear=True) pos1 += 1 self.assertFalse((p[0].position == pos[:, 0]).all()) self.assertFalse(numpy.may_share_memory(p[0].position, pos[:, 0]))
def test_callback_copy(self): import copy from atooms.trajectory.decorators import filter_species particle = [Particle(species='A'), Particle(species='B')] system = System(particle) t = TrajectoryRamFull() t[0] = system t.add_callback(copy.deepcopy) t.add_callback(filter_species, 'A') self.assertEqual(t[0].distinct_species(), ['A']) t.callbacks.pop() t.callbacks.pop() self.assertEqual(t[0].distinct_species(), ['A', 'B'])
def test_overlap_random(self): # This test may fail from time to time from atooms.system.particle import collective_overlap N = 1000 L = 5.0 sys = [System(), System()] sys[0].cell = Cell([L, L, L]) sys[1].cell = Cell([L, L, L]) sys[0].particle = [] sys[1].particle = [] for _ in range(N): pos = [(random.random() - 0.5) * L, (random.random() - 0.5) * L, (random.random() - 0.5) * L] sys[0].particle.append(Particle(position=pos)) for _ in range(N): pos = [(random.random() - 0.5) * L, (random.random() - 0.5) * L, (random.random() - 0.5) * L] sys[1].particle.append(Particle(position=pos)) a = 0.3 q_rand = ((a**3 * 4. / 3 * 3.1415) * N / sys[0].cell.volume) self.assertTrue( abs(q_rand - collective_overlap(sys[0].particle, sys[1].particle, a, sys[0].cell.side)) < 0.5)
def read_sample(self, frame): # Read metadata of this frame meta = self._read_comment(frame) # Get number of particles self.trajectory.seek(self._index_header[frame]) npart = int(self.trajectory.readline()) # Read frame now self.trajectory.seek(self._index_frame[frame]) particle = [] for ipart in range(npart): p = Particle() data = self.trajectory.readline().split() i = 0 for key, fmt, ndims in meta['Properties']: ndims = int(ndims) if key in self.alias: key = self.alias[key] if ndims == 1: if fmt == 'R': setattr(p, key, float(data[i])) elif fmt == 'I': setattr(p, key, int(data[i])) elif fmt == 'S': setattr(p, key, data[i]) else: raise ValueError('unknown format key') else: if fmt == 'R': setattr( p, key, numpy.array(data[i:i + ndims], dtype=numpy.float64)) elif fmt == 'I': setattr( p, key, numpy.array(data[i:i + ndims], dtype=numpy.int64)) elif fmt == 'S': setattr(p, key, numpy.array(data[i:i + ndims])) else: raise ValueError('unknown format key') i += ndims particle.append(p) side = meta["Lattice"] # TODO: remove hard coded cell = Cell([side[0], side[4], side[8]]) return System(particle, cell)
def read_sample(self, frame): """ returns System instance. """ L = self.header[0] if self.ndim == 3: cell = Cell(side=[L, L, L]) elif self.ndim == 2: cell = Cell(side=[L, L]) N = self.data.shape[0] pos = self.data[:, :self.ndim] # Lerner group format has positions from [0, 1). pos = pos*L - L/2 if self.velocity_present: # Next is the velocity, if it exists. vel = self.data[:, self.ndim:2*self.ndim] # # In 2D, we add a zero z-coordinate to be consistent with other formats. # if self.ndim == 3: # # First ndim columns are always the position. # elif self.ndim == 2: # new_pos = np.zeros((N, 3)).astype(float) # new_pos[:, :self.ndim] = pos # pos = new_pos # if self.velocity_present: # vel = np.zeros((N, 3)).astype(float) # vel[:, :self.ndim] = self.data[:, self.ndim:2*self.ndim] particles = [] for i in range(N): p = Particle() p.position = pos[i, :] if self.velocity_present: p.velocity = vel[i, :] if self.species_present and self.radius_present: p.species = str( int(self.data[i, -1]) ) p.radius = self.data[i, -2] elif self.radius_present: p.radius = self.data[i, -1] elif self.species_present: p.species = str( int(self.data[i, -1]) ) particles.append(p) return System(particle=particles, cell=cell)
def read_sample(self, frame): meta = self._read_comment(frame) self.trajectory.seek(self._index_frame[frame]) # Read particles particle = [] for _ in range(meta['npart']): data = self.trajectory.readline().strip().split() species = data[0] r = numpy.array(data[1:4], dtype=float) particle.append(Particle(species=species, position=r)) # Read cell try: side = meta['cell'] self._cell = Cell(side) except KeyError: pass return System(particle, self._cell)
def unfold(system): # s = system # particle = system.particle # for i, p in enumerate(particle): # p.position += p.periodic_image * s.cell.side # system.particle = particle # return s from atooms.system import System npart = system.sample.GetNumberOfParticles() pos = system.sample.GetPositions() nsp = system.sample.GetNumberOfTypes() ima = system.sample.GetImages() spe = numpy.ndarray(npart, dtype=int) ii = 0 for i in range(nsp): ni = system.sample.GetNumberThisType(i) spe[ii: ii + ni] = i ii += ni particle = [Particle(species=spe_i, position=pos_i) for spe_i, pos_i in zip(spe, pos)] for p, i in zip(particle, ima): p.position += i * system.cell.side return System(particle=particle, cell=system.cell)
def read_sample(self, frame): system = System() s = self.trajectory["trajectory/realtime/sampleindex"].keys()[frame] system.eigenvalues = self.trajectory["trajectory/normalmodes/eigenvalues/%s" % s][:] system.eigenfreq = numpy.array([copysign(abs(x)**0.5, x) for x in system.eigenvalues]) mode_idx = self.trajectory["trajectory/normalmodes/eigenvectors/index/%s" % s][:] eigv = {} for idx in mode_idx: # Modes are F-indexed omega = system.eigenfreq[idx-1] vect = self.trajectory["trajectory/normalmodes/eigenvectors/vector/%s_mode_%05d" % (s, idx)][:] eigv[omega] = vect system.eigenvectors = eigv # Add positions parent = os.path.splitext(self.trajectory.filename)[0] step = self.steps[frame] with TrajectoryHDF5(parent) as th: # The step should be there parent_frame = th.steps.index(step) system.particle = th[parent_frame].particle system.cell = th[parent_frame].cell return system
def read_init(self): # read particles group = self.trajectory['/initialstate/particle'] n = self.trajectory['/initialstate/particle/number_of_particles'][0] rad = None for entry in group: # TODO: refactor this if entry == 'element': spe = group[entry][:] if entry == 'mass': mas = group[entry][:] if entry == 'position': pos = group[entry][:] if entry == 'velocity': vel = group[entry][:] if entry == 'radius': rad = group[entry][:] if rad is not None: particle = [ Particle(species=spe[i].decode().strip(), mass=mas[i], position=pos[i, :], velocity=vel[i, :], radius=rad[i]) for i in range(n) ] else: particle = [ Particle(species=spe[i].decode().strip(), mass=mas[i], position=pos[i, :], velocity=vel[i, :]) for i in range(n) ] # read cell group = self.trajectory['/initialstate/cell'] for entry in group: if entry == 'sidebox': sidebox = group[entry][:] cell = Cell(sidebox) # read interaction interaction = self.read_interaction() # build system self._system = System(particle, cell, interaction) # read matrix if 'matrix' in self.trajectory['/initialstate']: group = self.trajectory['/initialstate/matrix'] for entry in group: if entry == 'element': spe = group[entry][:] if entry == 'mass': mas = group[entry][:] if entry == 'position': pos = group[entry][:] matrix = [ Particle(species=spe[i].decode().strip(), mass=mas[i], position=pos[i, :]) for i in range(len(spe)) ] self._system.matrix = copy.deepcopy(matrix) return self._system
def read_sample(self, frame, unfolded=False): # TODO: due to unfolded argument this differs from the base class method Can we drop this? # We must increase frame by 1 if we iterate over frames with len(). # This is some convention to be fixed once and for all # TODO: read cell on the fly NPT keys = list(self.trajectory['/trajectory/realtime/stepindex'].keys()) csample = '/' + keys[frame] # read particles group = self.trajectory['/trajectory/particle'] if unfolded: if 'position_unfolded' not in group: raise NotImplementedError( 'cannot unfold like this, use decorator instead') else: # fix for unfolded positions that were not written at the first step # should be fixed once and for all in md.x if frame == 0: pos = self.trajectory['/initialstate/particle/position'][:] else: pos = group['position_unfolded' + csample][:] else: pos = group['position' + csample][:] try: vel = group['velocity' + csample][:] except: vel = numpy.zeros([len(pos), ndim]) # Dynamic properties p = [] for r, v in zip(pos, vel): p.append(Particle(position=r, velocity=v)) # Static properties # TODO: optimize, this takes quite some additional time, almost x2 for pi, r in zip(p, self._system.particle): pi.mass = r.mass pi.species = r.species pi.radius = r.radius # Try update radii. This must be done after setting defaults. try: r = group['radius' + csample][:] for i, pi in enumerate(p): pi.radius = r[i] if 'radius' not in self.fields: self.fields.append('radius') except KeyError: if 'radius' in self.fields: self.fields.remove('radius') # Try update species. This must be done after setting defaults. # TODO: refactor try: spe = group['species' + csample][:] for i, pi in enumerate(p): pi.species = spe[i].decode().strip() if 'species' not in self.fields: self.fields.append('species') except KeyError: if 'species' in self.fields: self.fields.remove('species') # Read cell group = self.trajectory['/trajectory/cell'] side = group['sidebox' + csample][:] # This fixes an issue with some hdf5 trajectories that stored # cell as (1,3) array if len(side.shape) == 2: side = side[0] self._system.cell.side = side # Read also interaction. has_int = True try: group = self.trajectory['/trajectory/interaction'] except: has_int = False if has_int: self._system.interaction.total_energy = group['energy' + csample][0] self._system.interaction.total_virial = group['virial' + csample][0] self._system.interaction.total_stress = group['stress' + csample][:] return System(p, self._system.cell, self._system.interaction)
def __init__(self): self.system = System()
def read_sample(self, frame): # Setup fields again, in case they have changed if self.__cache_fields != self.fields: self._setup_fields() # Read metadata of this frame meta = self._read_comment(frame) # Define read callbacks list before reading lines callbacks_read = [] def _skip(p, data, meta): return data[1:] for key in self.fields: # If the key is associated to a explicit callback, go # for it. Otherwise we throw the field in an particle # attribute named key. If the key is None it means we skip # this column. if key is None: callbacks_read.append(_skip) elif key in self.callback_read: callbacks_read.append(self.callback_read[key]) else: # Trick. We instantiate dynamically a fallback function # to avoid adding `key` to the other callbacks' interface namespace = {} exec( """ from atooms.core.utils import tipify def fallback(p, data, meta): p.__dict__['%s'] = tipify(data[0]) return data[1:] """ % key, namespace) callbacks_read.append(namespace['fallback']) # Read frame now self.trajectory.seek(self._index_frame[frame]) particle = [] for i in range(meta['npart']): p = Particle() # Note: we cannot optimize by shifting an index instead of # cropping lists all the time data = self.trajectory.readline().split() for cbk in callbacks_read: data = cbk(p, data, meta) particle.append(p) # Fix the masses. # We assume masses read from the header are sorted by species name. # The mass metadata must be adjusted to the given frame. if 'mass' in meta: if isinstance(meta['mass'], list) or isinstance( meta['mass'], tuple): species = distinct_species(particle) # We must have as many mass entries as species if len(species) != len(meta['mass']): raise ValueError('mass metadata issue %s, %s' % (species, meta['mass'])) db = {} for key, value in zip(species, meta['mass']): db[key] = value for p in particle: p.mass = float(db[p.species]) else: for p in particle: p.mass = float(meta['mass']) # Add cell info if 'cell' in meta: cell = Cell(meta['cell']) else: cell = None return System(particle, cell)
class Test(unittest.TestCase): def setUp(self): N = 100 L = 10.0 self.ref = System() self.ref.cell = Cell([L, L, L]) self.ref.particle = [] self.ref.thermostat = Thermostat(1.0) self.ref.barostat = Barostat(1.0) self.ref.reservoir = Reservoir(1.0) while len(self.ref.particle) <= N: pos = [(random.random() - 0.5) * L, (random.random() - 0.5) * L, (random.random() - 0.5) * L] self.ref.particle.append(Particle(position=pos)) def test_density(self): system = copy.copy(self.ref) density_old = system.density system.density = density_old * 1.1 self.assertAlmostEqual(system.density, density_old * 1.1) def test_temperature(self): system = copy.copy(self.ref) system.set_temperature(1.0) self.assertAlmostEqual(system.temperature, 1.0) def test_cm(self): system = copy.copy(self.ref) system.set_temperature(1.0) system.fix_momentum() self.assertAlmostEqual(system.cm_velocity[0], 0.0) self.assertAlmostEqual(system.cm_velocity[1], 0.0) self.assertAlmostEqual(system.cm_velocity[2], 0.0) pos_cm = system.cm_position for p in system.particle: p.position -= pos_cm self.assertAlmostEqual(system.cm_position[0], 0.0) self.assertAlmostEqual(system.cm_position[1], 0.0) self.assertAlmostEqual(system.cm_position[2], 0.0) def test_pbc_center(self): system = copy.copy(self.ref) # Move the center of the cell so that positions are within 0 and L system.cell.center = system.cell.side / 2 for p in system.particle: p.position += system.cell.side / 2 # Check that distances are the same for i in range(len(system.particle)): self.assertAlmostEqual( sum(self.ref.particle[0].distance(self.ref.particle[i], self.ref.cell)**2), sum(system.particle[0].distance(system.particle[i], system.cell)**2)) # Move one particle out of the box and fold it back pos = copy.copy(system.particle[0].position) system.particle[0].position += system.cell.side system.particle[0].fold(system.cell) self.assertAlmostEqual(pos[0], system.particle[0].position[0]) self.assertAlmostEqual(pos[1], system.particle[0].position[1]) self.assertAlmostEqual(pos[2], system.particle[0].position[2]) def test_fold(self): system = copy.copy(self.ref) pos = copy.copy(system.particle[0].position) system.particle[0].position += system.cell.side system.particle[0].fold(system.cell) self.assertAlmostEqual(pos[0], system.particle[0].position[0]) self.assertAlmostEqual(pos[1], system.particle[0].position[1]) self.assertAlmostEqual(pos[2], system.particle[0].position[2]) def test_overlaps(self): from atooms.system.particle import overlaps system = copy.copy(self.ref) for p in system.particle: p.radius = 1e-10 pos = copy.copy(system.particle[1].position) system.particle[0].position = pos ov, ipart = overlaps(system.particle, system.cell) self.assertTrue(ov) self.assertEqual(ipart, [(0, 1)]) def test_dump(self): self.assertEqual( self.ref.dump('spe')[-1], self.ref.dump('particle.species')[-1]) self.assertAlmostEqual( self.ref.dump('pos')[-1][-1], self.ref.dump('particle.position')[-1][-1]) self.assertAlmostEqual( self.ref.dump('vel')[-1][-1], self.ref.dump('particle.velocity')[-1][-1]) def test_species(self): system = copy.copy(self.ref) npart = len(system.particle) for p in system.particle[0:10]: p.species = 'B' for p in system.particle[10:30]: p.species = 'C' from atooms.system.particle import composition, distinct_species self.assertEqual(distinct_species(system.particle), ['A', 'B', 'C']) self.assertEqual(system.distinct_species(), ['A', 'B', 'C']) self.assertEqual(composition(system.particle)['A'], npart - 30) self.assertEqual(composition(system.particle)['B'], 10) self.assertEqual(composition(system.particle)['C'], 20) def test_packing(self): import math system = copy.copy(self.ref) self.assertAlmostEqual(system.packing_fraction * 6 / math.pi, system.density) def test_gyration(self): from atooms.system.particle import gyration_radius system = copy.copy(self.ref) # Ignore cell rg1 = gyration_radius(system.particle, method='N1') rg2 = gyration_radius(system.particle, method='N2') self.assertAlmostEqual(rg1, rg2) # With PBC all estimates are different but bounds must be ok rg1 = gyration_radius(system.particle, system.cell, method='min') rg2 = gyration_radius(system.particle, system.cell, method='N1') rg3 = gyration_radius(system.particle, system.cell, method='N2') self.assertLessEqual(rg1, rg2) self.assertLessEqual(rg3, rg2) # Equilateral triangle system.particle = [Particle(), Particle(), Particle()] system.particle[0].position = numpy.array([0.0, 0.0, 0.0]) system.particle[1].position = numpy.array([1.0, 0.0, 0.0]) system.particle[2].position = numpy.array([0.5, 0.5 * 3**0.5, 0]) # Put the triangle across the cell system.particle[0].position -= 1.01 * system.cell.side / 2 system.particle[1].position -= 1.01 * system.cell.side / 2 system.particle[2].position -= 1.01 * system.cell.side / 2 system.particle[0].fold(system.cell) system.particle[1].fold(system.cell) system.particle[2].fold(system.cell) rg1 = gyration_radius(system.particle, system.cell, method='min') rg2 = gyration_radius(system.particle, system.cell, method='N1') rg3 = gyration_radius(system.particle, system.cell, method='N2') self.assertAlmostEqual(rg1, 0.57735026919) self.assertAlmostEqual(rg2, 0.57735026919) self.assertAlmostEqual(rg3, 0.57735026919) def test_interaction(self): from atooms.interaction import Interaction system = copy.copy(self.ref) self.assertAlmostEqual(system.potential_energy(), 0.0) system.interaction = Interaction([]) system.interaction.compute('energy', system.particle, system.cell) system.interaction.compute('forces', system.particle, system.cell) system.interaction.compute('stress', system.particle, system.cell) self.assertAlmostEqual(system.potential_energy(), 0.0) self.assertAlmostEqual(system.potential_energy(normed=True), 0.0) self.assertAlmostEqual(system.total_energy(), system.kinetic_energy()) def test_overlap(self): from atooms.system.particle import self_overlap, collective_overlap sys1 = copy.deepcopy(self.ref) sys2 = copy.deepcopy(self.ref) sys1.particle = sys1.particle[:int(len(sys1.particle) / 2)] sys2.particle = sys2.particle[int(len(sys2.particle) / 2):] self.assertEqual(0, self_overlap(sys1.particle, sys2.particle, 0.001)) self.assertEqual( 0, collective_overlap(sys1.particle, sys2.particle, 0.001, sys1.cell.side)) sys1.particle = sys1.particle sys2.particle = sys1.particle self.assertEqual(1, self_overlap(sys1.particle, sys2.particle, 0.001)) self.assertEqual( 1, collective_overlap(sys1.particle, sys2.particle, 0.001, sys1.cell.side)) def test_overlap_random(self): # This test may fail from time to time from atooms.system.particle import collective_overlap N = 1000 L = 5.0 sys = [System(), System()] sys[0].cell = Cell([L, L, L]) sys[1].cell = Cell([L, L, L]) sys[0].particle = [] sys[1].particle = [] for _ in range(N): pos = [(random.random() - 0.5) * L, (random.random() - 0.5) * L, (random.random() - 0.5) * L] sys[0].particle.append(Particle(position=pos)) for _ in range(N): pos = [(random.random() - 0.5) * L, (random.random() - 0.5) * L, (random.random() - 0.5) * L] sys[1].particle.append(Particle(position=pos)) a = 0.3 q_rand = ((a**3 * 4. / 3 * 3.1415) * N / sys[0].cell.volume) self.assertTrue( abs(q_rand - collective_overlap(sys[0].particle, sys[1].particle, a, sys[0].cell.side)) < 0.5) def test_view(self): import numpy from atooms.system import Particle, System p = [Particle(), Particle()] s = System(p) pos = s.dump("pos", order='F', view=True) # Modify the dumped array in place preserves the view pos[:, 0] += 1.0 self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # Modify the position array in place preserves the view p[0].position *= 2 self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # Modify the position array in place preserves the view p[0].position[:] = p[0].position[:] + 4 self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) pos[:, 0] = pos[:, 0] + 1.0 self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # Reassining the position will of course destroy the view p[0].position = p[0].position * 2 self.assertFalse((p[0].position == pos[:, 0]).all()) self.assertFalse(numpy.may_share_memory(p[0].position, pos[:, 0])) def test_view_clear(self): import numpy from atooms.system import Particle, System p = [Particle(), Particle()] s = System(p) # We check that particle positions are views on dump array pos = s.dump("pos", order='F', view=True) self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # We should get the same dump array pos = s.dump("pos", order='F', view=True) self.assertTrue((p[0].position == pos[:, 0]).all()) self.assertTrue(numpy.may_share_memory(p[0].position, pos[:, 0])) # We clear the dump array pos1 = s.dump("pos", order='F', view=True, clear=True) pos1 += 1 self.assertFalse((p[0].position == pos[:, 0]).all()) self.assertFalse(numpy.may_share_memory(p[0].position, pos[:, 0])) def test_dump_cbk(self): """ Make sure that applying callbacks or changing the particle array size creates a new dump. """ import numpy from atooms.system import Particle, System for view in [False, True]: p = [Particle(), Particle()] s = System(p) pos1 = s.dump("pos", view=view) def cbk(system): s = copy.copy(system) s.particle = [system.particle[0]] return s s = cbk(s) pos2 = s.dump('pos', view=view) self.assertEqual(pos1.shape, (2, 3)) self.assertEqual(pos2.shape, (1, 3)) # Grandcanonical s.particle.append(Particle()) self.assertEqual(s.dump('pos', view=view).shape, (2, 3)) # Reassign particle # Expected failure with view = True if not view: s.particle[0] = Particle(position=[1.0, 1.0, 1.0]) self.assertEqual(s.dump('pos', view=view)[0][0], 1.0) def test_dump_species(self): """ Make sure that changing species in the dump is reflected in the particle species and viceversa. """ import numpy from atooms.system import Particle, System view = True p = [Particle(), Particle()] s = System(p) spe = s.dump("particle.species", view=True) spe[0] = 'B' self.assertEqual(spe[0], s.particle[0].species) # With this syntax, the numpy scalar preserves the view! # We should upgrade species to property and hide this inside s.particle[0].species[()] = 'C' self.assertEqual(spe[0], s.particle[0].species) def test_decimate(self): from atooms.system import Particle, System from atooms.system.particle import composition, decimate p = [Particle(species='A')] * 20 + [Particle(species='B')] * 10 pnew = decimate(p, 12) x = composition(pnew) self.assertEqual(x['A'], 8) self.assertEqual(x['B'], 4) def test_ovito(self): try: import ovito except ImportError: self.skipTest('missing ovito') N = 3 L = 5.0 system = System() system.cell = Cell([L, L, L]) system.particle = [] for _ in range(N): pos = (numpy.random.random(len(system.cell.side)) - 0.5) * system.cell.side p = Particle(position=pos) system.particle.append(p) image = system.show('ovito')