def test_invalid_dimensions(self): space = [1, 1, 1, 1] space3 = [1, 1, 1] with pytest.raises(ValueError): a_test = mb.Lattice(space, dimension=4) with pytest.raises(TypeError): a_test = mb.Lattice(space3, dimension=([1, 2, 3]))
def test_lattice_spacings_dimension(self): with pytest.raises(ValueError): spacing_test = mb.Lattice(dimension=3, lattice_vectors=None, lattice_spacings=([.12], [.13], [.14])) with pytest.raises(ValueError): spacing_test = mb.Lattice(dimension=3, lattice_vectors=None, lattice_spacings=([.12, .13, .14, .15]))
def test_handedness_lattice_vectors(self): shape2 = [1, 1] shape3 = [1, 1, 1] invalid_2d = np.asarray(([1, 2], [2, 1]), dtype=float) invalid_3d = np.asarray(([1, 2, 3], [3, 2, 1], [2, 1, 3]), dtype=float) with pytest.raises(ValueError): a_test_2d = mb.Lattice(shape2, dimension=2, lattice_vectors=invalid_2d) with pytest.raises(ValueError): a_test_3d = mb.Lattice(shape3, dimension=3, lattice_vectors=invalid_3d)
def test_colinear_lattice_vectors(self): shape2 = [1, 1] shape3 = [1, 1, 1] invalid_2d = np.asarray(([1, 0], [3, 0]), dtype=float) invalid_3d = np.asarray(([1, 0, 0], [0, 1, 0], [2, 0, 0]), dtype=float) with pytest.raises(ValueError): a_test_2d = mb.Lattice(shape2, dimension=2, lattice_vectors=invalid_2d) with pytest.raises(ValueError): a_test_3d = mb.Lattice(shape3, dimension=3, lattice_vectors=invalid_3d)
def test_basis_default(self): three_d = mb.Lattice([1, 1, 1], dimension=3, basis_vectors=None) two_d = mb.Lattice([1, 1], dimension=2, basis_vectors=None) one_d = mb.Lattice([1], dimension=1, basis_vectors=None) assert len(three_d.basis_vectors) == 1 assert len(two_d.basis_vectors) == 1 assert len(one_d.basis_vectors) == 1 assert three_d.basis_vectors['default'][0] == (0, 0, 0) assert two_d.basis_vectors['default'][0] == (0, 0) assert one_d.basis_vectors['default'][0] == (0, )
def test_proper_populate(self): values_to_check = [ [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0], [0, 1, 1], [1, 0, 1], [1, 1, 1], ] test_lattice = mb.Lattice( lattice_spacing=[1, 1, 1], angles=[90, 90, 90] ) new_compound = test_lattice.populate(x=2, y=2, z=2) values_to_check = np.asarray(values_to_check, dtype=np.float64) is_true = [] for pos1 in np.split(values_to_check, 8, axis=0): for pos2 in np.split(new_compound.xyz, 8, axis=0): if np.allclose(pos1, pos2): is_true.append(True) assert len(is_true) == len(values_to_check)
def test_incorrect_populate_inputs(self, x, y, z): with pytest.raises(ValueError): test_lattice = mb.Lattice(lattice_spacing=[1, 1, 1]) test_lattice.populate(compound_dict={'id': mb.Compound()}, x=x, y=y, z=z)
def __init__(self, x_length=4, y_length=4, n_sheets=3, vacuum=10.0): super(GrapheneSurface, self).__init__() factor = np.cos(np.pi/6) # Estimate the number of lattice repeat units replicate = [int(x_length/0.2456), (y_length/0.2456)*(1/factor)] if all(x <= 0 for x in [x_length, y_length]): msg = 'Dimension of graphene sheet must be greater than zero' raise ValueError(msg) carbon = mb.Compound() carbon.name = 'C' carbon_locations = [[0, 0, 0], [2/3, 1/3, 0]] basis = {carbon.name: carbon_locations} lattice_spacing = [0.2456, 0.2456, 0.335] angles = [90.0, 90.0, 120.0] graphene_lattice = mb.Lattice(lattice_spacing=lattice_spacing, angles=angles, lattice_points=basis) graphene = graphene_lattice.populate(compound_dict={carbon.name: carbon}, x=replicate[0], y=replicate[1], z=n_sheets) for particle in graphene.particles(): if particle.xyz[0][0] < 0: particle.xyz[0][0] += graphene.periodicity[0] graphene.periodicity[1] *= factor # cos(30)*.246 self.add(graphene) self.periodicity[0] = graphene.periodicity[0] self.periodicity[1] = graphene.periodicity[1] self.periodicity[2] = graphene.periodicity[2] - lattice_spacing[2] + vacuum self.xyz -= np.min(self.xyz, axis=0)
def test_lattice_vectors_invalid_shape(self): space1 = [1, ] space2 = [1, 1, ] space3 = [1, 1, 1] invalid_1d = np.asarray(([1, 0], [0, 1]), dtype=float) invalid_2d = np.asarray(([1, 0, 0], [0, 1, 0], [0, 0, 1]), dtype=float) invalid_3d = np.asarray(([1, 0], [0, 1]), dtype=float) with pytest.raises(ValueError): a_test_1d = mb.Lattice(space1, dimension=1, lattice_vectors=invalid_1d) with pytest.raises(ValueError): a_test_2d = mb.Lattice(space2, dimension=2, lattice_vectors=invalid_2d) with pytest.raises(ValueError): a_test_3d = mb.Lattice(space3, dimension=3, lattice_vectors=invalid_3d)
def test_overdefinied_inputs(self): space = [1, 1, 1] vectors = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] angles = [90, 90, 90] with pytest.raises(ValueError): mb.Lattice(lattice_spacing=space, lattice_vectors=vectors, angles=angles)
def test_lattice_vectors_default(self, spacing, vec_default, dimension): test_lattice = mb.Lattice(spacing, dimension=dimension, lattice_vectors=None) np.testing.assert_array_equal(vec_default, test_lattice.lattice_vectors)
def test_proper_angles(self, vectors, angles): testlattice = mb.Lattice(lattice_spacing=[1, 1, 1], lattice_vectors=vectors) np.testing.assert_allclose(testlattice.angles, np.asarray(angles, dtype=np.float64), rtol=1e-05, atol=1e-08, equal_nan=False)
def test_spacing_success(self, spacing): spacing = np.asarray(spacing, dtype=np.float64) spacing = np.reshape(spacing, (3, )) test_lattice = mb.Lattice(lattice_spacing=spacing) np.testing.assert_allclose(spacing, test_lattice.lattice_spacing, rtol=1e-7, atol=0, equal_nan=True)
def __init__(self, pore_length=4, pore_depth=3, n_sheets=3, pore_width=1, slit_pore_dim=1): super(GraphenePore, self).__init__() factor = np.cos(np.pi/6) # Estimate the number of lattice repeat units replicate = [int(pore_length/0.2456), (pore_depth/0.2456)*(1/factor)] if all(x <= 0 for x in [pore_length, pore_depth]): msg = 'Dimension of graphene sheet must be greater than zero' raise ValueError(msg) carbon = mb.Compound() carbon.name = 'C' carbon_locations = [[0, 0, 0], [2/3, 1/3, 0]] basis = {carbon.name: carbon_locations} lattice_spacing = [0.2456, 0.2456, 0.335] angles = [90.0, 90.0, 120.0] graphene_lattice = mb.Lattice(lattice_spacing=lattice_spacing, angles=angles, lattice_points=basis) graphene = graphene_lattice.populate(compound_dict={carbon.name: carbon}, x=replicate[0], y=replicate[1], z=n_sheets) for particle in graphene.particles(): if particle.xyz[0][0] < 0: particle.xyz[0][0] += graphene.periodicity[0] graphene.periodicity[1] *= factor # cos(30)*.246 bot_sheet = mb.clone(graphene) bot_sheet.name = 'BOT' top_sheet = mb.clone(graphene) if slit_pore_dim == 0: bot_sheet.spin(1.5708, [0, 1, 0]) top_sheet.spin(1.5708, [0, 1, 0]) top_sheet.translate([pore_width + (graphene.periodicity[2] - 0.335), 0, 0]) elif slit_pore_dim == 1: bot_sheet.spin(1.5708, [1, 0, 0]) top_sheet.spin(1.5708, [1, 0, 0]) top_sheet.translate([0, pore_width + (graphene.periodicity[2] - 0.335), 0]) elif slit_pore_dim == 2: top_sheet.translate([0, 0, pore_width + (graphene.periodicity[2] - 0.335)]) top_sheet.name = 'TOP' self.add(top_sheet) self.add(bot_sheet) if slit_pore_dim == 0: self.periodicity[0] = 2 * graphene.periodicity[2] - lattice_spacing[2] + pore_width self.periodicity[1] = graphene.periodicity[0] self.periodicity[2] = graphene.periodicity[1] elif slit_pore_dim == 1: self.periodicity[0] = graphene.periodicity[0] self.periodicity[1] = 2 * graphene.periodicity[2] - lattice_spacing[2] + pore_width self.periodicity[2] = graphene.periodicity[1] elif slit_pore_dim == 2: self.periodicity[0] = graphene.periodicity[0] self.periodicity[1] = graphene.periodicity[1] self.periodicity[2] = 2 * graphene.periodicity[2] - lattice_spacing[2] + pore_width self.xyz -= np.min(self.xyz, axis=0)
def test_set_periodicity(self): lattice = mb.Lattice(lattice_spacing=[1, 1, 1], angles=[90, 90, 90], lattice_points={'A' : [[0, 0, 0]]}) compound_test = lattice.populate(compound_dict={'A' : mb.Compound()}, x=2, y=5, z=9) replication=[2, 5, 9] np.testing.assert_allclose(compound_test.periodicity, np.asarray([x*y for x,y in zip(replication, lattice.lattice_spacing)]))
def test_basis_multi(self): basis_1d = (('test1', [0]), ('test2', [.25]),) basis_2d = (('test1', [0, 0]), ('test2', [.25, .25]),) basis_3d = (('test1', [0, 0, 0]), ('test2', [.25, .25, .25]),) lat_1d = mb.Lattice([1], dimension=1, basis_vectors=basis_1d) lat_2d = mb.Lattice([1, 1], dimension=2, basis_vectors=basis_2d) lat_3d = mb.Lattice([1, 1, 1], dimension=3, basis_vectors=basis_3d) assert len(lat_1d.basis_vectors) == 2 assert len(lat_2d.basis_vectors) == 2 assert len(lat_3d.basis_vectors) == 2 assert lat_1d.basis_vectors['test1'][0] == [0] assert lat_1d.basis_vectors['test2'][0] == [.25] assert lat_2d.basis_vectors['test1'][0] == [0, 0] assert lat_2d.basis_vectors['test2'][0] == [.25, .25] assert lat_3d.basis_vectors['test1'][0] == [0, 0, 0] assert lat_3d.basis_vectors['test2'][0] == [.25, .25, .25]
def test_basis_atoms_default(self, space, correct, dim): test_lattice = mb.Lattice(space, dimension=dim) assert len(test_lattice.basis_atoms.keys()) == 1 for key in test_lattice.basis_atoms.keys(): assert key == correct correct_pos = [0. for x in range(dim)] np.testing.assert_array_equal(test_lattice.basis_atoms[correct][0], correct_pos)
def test_cif_vs_manual_triclinic(self): spacing = [0.641910000, 0.652305930, 0.704466251] angles = [91.77954616, 103.97424201, 118.83663410] points_dict = { "Re": [ [0.94176500, 0.68947700, 0.50807400], [0.05823500, 0.31052300, 0.49192600], [0.51250400, 0.71441700, 0.50209100], [0.48749600, 0.28558300, 0.49790900], ], "S": [ [0.74798600, 0.13254800, 0.67588400], [0.73127300, 0.34781000, 0.26679600], [0.21989400, 0.10784400, 0.70096800], [0.25920200, 0.38690600, 0.24012300], [0.74079800, 0.61309400, 0.75987700], [0.78010600, 0.89215600, 0.29903200], [0.25201400, 0.86745200, 0.32411600], [0.26872700, 0.65219000, 0.73320400], ], } lattice_manual = mb.Lattice( lattice_spacing=spacing, lattice_points=points_dict, angles=angles ) lattice_cif = load_cif(file_or_path=get_fn("ReS2.cif")) assert np.all( np.isclose( lattice_manual.lattice_spacing, lattice_cif.lattice_spacing ) ) assert np.all(np.isclose(lattice_manual.angles, lattice_cif.angles)) # sort dicts first (not necessary once we support py 3.7+ only) # dict sorted by keys dict_manual = OrderedDict( sorted(lattice_manual.lattice_points.items(), key=lambda t: t[0]) ) dict_cif = OrderedDict( sorted(lattice_cif.lattice_points.items(), key=lambda t: t[0]) ) keys_m = dict_manual.keys() keys_c = dict_cif.keys() for k_man, k_cif in zip(keys_m, keys_c): # sort the lists of lists points_man = dict_manual[k_man] points_cif = dict_cif[k_cif] points_man.sort() points_cif.sort() points_man = np.asarray(points_man) points_cif = np.asarray(points_cif) assert np.all(np.isclose(points_man, points_cif))
def test_overdefinied_inputs(self): dim = 3 lat_space = [1., 1., 1.] angles = [90., 90., 90.] lattice_vec = [1, 1, 1] with pytest.raises(ValueError): test_lattice = mb.Lattice(lat_space, dimension=dim, angles=angles, lattice_vectors=lattice_vec)
def graphene(self): carbon = mb.Compound(name='C') angles = [90, 90, 120] carbon_locations = [[0, 0, 0], [2/3, 1/3, 0]] basis = {'C' : carbon_locations} graphene = mb.Lattice(lattice_spacing=[.2456, .2456, 0], angles=angles, lattice_points=basis) carbon_dict = {'C' : carbon} graphene_cell = graphene.populate(compound_dict=carbon_dict, x=3, y=3, z=1) return graphene_cell
def test_lattice_vectors_default(self): # default behavior for 2D and 3D space1 = [1, ] space2 = [1, 1] space3 = [1, 1, 1] one_dim_default = np.asarray(([1.0]), dtype=float) two_dim_default = np.asarray(([1.0, 0.0], [0.0, 1.0]), dtype=float) three_dim_default = np.asarray(([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]), dtype=float) one_d_lattice = mb.Lattice(space1, dimension=1, lattice_vectors=None) two_d_lattice = mb.Lattice(space2, dimension=2, lattice_vectors=None) three_d_lattice = mb.Lattice(space3, dimension=3, lattice_vectors=None) np.testing.assert_array_equal(one_dim_default, one_d_lattice.lattice_vectors) np.testing.assert_array_equal(two_dim_default, two_d_lattice.lattice_vectors) np.testing.assert_array_equal(three_dim_default, three_d_lattice.lattice_vectors)
def GoldLattice(self): lattice_compound = mbuild.Compound(name='Au') lattice_spacing = [0.40788, 0.40788, 0.40788] lattice_vector = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] gold_locations = [[0., 0., 0.], [.5, .5, 0.], [.5, 0., .5], [0, .5, .5]] basis = {lattice_compound.name: gold_locations} gold_lattice = mbuild.Lattice( lattice_spacing=lattice_spacing, lattice_vectors=lattice_vector, lattice_points=basis) return gold_lattice
def cscl_crystal(self): cesium = mb.Compound(name='Cs') chlorine = mb.Compound(name='Cl') spacing = [.4123, .4123, .4123] basis = {'Cs' : [[0.5, 0.5, 0.5]], 'Cl' : [[0, 0, 0]]} cscl_lattice = mb.Lattice(spacing, lattice_points=basis) cscl_dict = {'Cs' : cesium, 'Cl' : chlorine} cscl_compound = cscl_lattice.populate(x=3, y=3, z=1, compound_dict=cscl_dict) return cscl_compound
def test_basis_atoms_overlap_2tags(self): dim = 3 lat_space = [1., 1., 1.] overlap_diff_basis_repeat = { 'test': [[0., 0., 0.]], 'test2': [[.5, .5, .5], [0., 0., 0.]] } with pytest.raises(ValueError): test_lattice = mb.Lattice(lat_space, dimension=dim, basis_atoms=overlap_diff_basis_repeat)
def cscl_crystal(self): cesium = mb.Compound(name="Cs") chlorine = mb.Compound(name="Cl") spacing = [0.4123, 0.4123, 0.4123] basis = {"Cs": [[0.5, 0.5, 0.5]], "Cl": [[0, 0, 0]]} cscl_lattice = mb.Lattice(spacing, lattice_points=basis) cscl_dict = {"Cs": cesium, "Cl": chlorine} cscl_compound = cscl_lattice.populate(x=3, y=3, z=1, compound_dict=cscl_dict) return cscl_compound
def test_cif_vs_manual(self): spacing = [0.760296570, 0.760296570, 0.437540800] points_dict = { "La": [[1 / 3, 2 / 3, 1 / 4], [2 / 3, 1 / 3, 3 / 4]], "Cl": [ [0.69490400, 0.08690400, 1 / 4], [0.60800000, 0.69490400, 3 / 4], [0.30509600, 0.91309600, 3 / 4], [0.39200000, 0.30509600, 1 / 4], [0.91309600, 0.60800000, 1 / 4], [0.08690400, 0.39200000, 3 / 4], ], } lattice_manual = mb.Lattice( lattice_spacing=spacing, lattice_points=points_dict, angles=[90, 90, 120], ) lattice_cif = load_cif(file_or_path=get_fn("LaCl3.cif")) assert np.all( np.isclose( lattice_manual.lattice_spacing, lattice_cif.lattice_spacing ) ) assert np.all(np.isclose(lattice_manual.angles, lattice_cif.angles)) # sort dicts first (not necessary once we support py 3.7+ only) # dict sorted by keys dict_manual = OrderedDict( sorted(lattice_manual.lattice_points.items(), key=lambda t: t[0]) ) dict_cif = OrderedDict( sorted(lattice_cif.lattice_points.items(), key=lambda t: t[0]) ) keys_m = dict_manual.keys() keys_c = dict_cif.keys() for k_man, k_cif in zip(keys_m, keys_c): # sort the lists of lists points_man = dict_manual[k_man] points_cif = dict_cif[k_cif] points_man.sort() points_cif.sort() points_man = np.asarray(points_man) points_cif = np.asarray(points_cif) assert np.all(np.isclose(points_man, points_cif))
def copper_cell(self): copper = mb.Compound(name='Cu') lattice_vector = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] spacing = [.36149, .36149, .36149] copper_locations = [[0., 0., 0.], [.5, .5, 0.], [.5, 0., .5], [0., .5, .5]] basis = {'Cu' : copper_locations} copper_lattice = mb.Lattice(lattice_spacing = spacing, lattice_vectors=lattice_vector, lattice_points=basis) copper_dict = {'Cu': copper} copper_pillar = copper_lattice.populate(x=3, y=3, z=1, compound_dict=copper_dict) return copper_pillar
def test_get_box(self): lattice = mb.Lattice(lattice_spacing=[1, 1, 1], angles=[90, 90, 90], lattice_points={'A': [[0, 0, 0]]}) replication = [5, 4, 3] expected_lengths = [ x * y for x, y in zip(replication, lattice.lattice_spacing) ] mybox = lattice.get_populated_box(x=5, y=4, z=3) assert isinstance(mybox, mb.Box) np.testing.assert_allclose([90, 90, 90], mybox.angles) np.testing.assert_allclose(expected_lengths, mybox.lengths)
def test_get_box_non_rectangular(self): lattice = mb.Lattice(lattice_spacing=[0.5, 0.5, 1], angles=[90, 90, 120], lattice_points={'A': [[0, 0, 0]]}) replication = [2, 2, 1] expected_lengths = [ x * y for x, y in zip(replication, lattice.lattice_spacing) ] mybox = lattice.get_populated_box(x=2, y=2, z=1) assert isinstance(mybox, mb.Box) np.testing.assert_allclose([90, 90, 120], mybox.angles) np.testing.assert_allclose(expected_lengths, mybox.lengths)
def test_box_non_rectangular(self): lattice = mb.Lattice( lattice_spacing=[0.5, 0.5, 1], angles=[90, 90, 120], lattice_points={"A": [[0, 0, 0]]}, ) compound_test = lattice.populate( compound_dict={"A": mb.Compound()}, x=2, y=2, z=1 ) replication = [2, 2, 1] np.testing.assert_allclose( compound_test.box.lengths, np.asarray( [x * y for x, y in zip(replication, lattice.lattice_spacing)] ), ) np.testing.assert_allclose( compound_test.box.angles, np.asarray([90.0, 90.0, 120.0]) )