Пример #1
0
def test_replace_pattern_in_structure__replace_hydrogens_in_octane_with_nothing(octane):
    # CH3 CH2 CH2 CH2 CH2 CH2 CH2 CH3 #
    search_pattern = Atoms(elements='H', positions=[(0, 0, 0)])
    replace_pattern = Atoms()

    final_structure = replace_pattern_in_structure(octane, search_pattern, replace_pattern)
    assert list(final_structure.elements) == ["C"] * 8
Пример #2
0
def test_replace_pattern_in_structure__replacement_pattern_across_pbc_gets_coordinates_within_unit_cell():
    structure = Atoms(elements='CNNF', positions=[(9.1, 0., 0), (0.1, 0., 0), (1.1, 0., 0.), (2.1, 0., 0.)], cell=10*np.identity(3))
    search_pattern = Atoms(elements='CN', positions=[(0., 0., 0), (1.0, 0., 0.)])
    replace_pattern = search_pattern
    final_structure = replace_pattern_in_structure(structure, search_pattern, replace_pattern)
    assert Counter(final_structure.elements) == Counter(structure.elements)
    assert_structure_positions_are_unchanged(structure, final_structure)
Пример #3
0
def test_atoms_extend__on_nonbonded_structure_reindexes_new_bonds_to_proper_atoms(
        linear_cnnc):
    linear_cnnc_no_bonds = Atoms(elements='CNNC',
                                 positions=[(0., 0., 0), (1.0, 0., 0.),
                                            (2.0, 0., 0.), (3.0, 0., 0.)])
    linear_cnnc_no_bonds.extend(linear_cnnc)
    assert np.array_equal(linear_cnnc_no_bonds.bonds, [(4, 5), (5, 6), (6, 7)])
Пример #4
0
def test_replace_pattern_in_structure__overlapping_match_patterns_errors():
    structure = Atoms(elements='CNNC', positions=[(0., 0., 0), (1.0, 0., 0.), (2.0, 0., 0.), (3.0, 0., 0.)], cell=100*np.identity(3))
    search_pattern = Atoms(elements='NNC', positions=[(0., 0., 0), (1.0, 0., 0.), (2.0, 0., 0.)])
    replace_pattern = Atoms(elements='FFC', positions=[(0., 0., 0), (1.0, 0., 0.), (2.0, 0., 0.)])

    with pytest.raises(AtomsShouldNotBeDeletedTwice):
        final_structure = replace_pattern_in_structure(structure, search_pattern, replace_pattern)
Пример #5
0
def test_replace_pattern_in_structure__replace_hydrogens_in_octane_with_fluorines_half_the_time(octane):
    search_pattern = Atoms(elements='H', positions=[(0, 0, 0)])
    replace_pattern = Atoms(elements='F', positions=[(0, 0, 0)])
    match_indices = find_pattern_in_structure(octane, search_pattern)
    final_structure = replace_pattern_in_structure(octane, search_pattern, replace_pattern, replace_fraction=0.5)
    assert Counter(final_structure.elements) == {"H":9, "F": 9, "C": 8}
    assert_structure_positions_are_unchanged(octane, final_structure)
Пример #6
0
def check_configs(structure_lmpdat, gas_lmpdat, verbose):
    atoms = Atoms.from_lammps_data(structure_lmpdat, use_comment_for_type_labels=True)
    gas_atoms = Atoms.from_lammps_data(gas_lmpdat, use_comment_for_type_labels=True)
    # check for charges
    num_zero_charges = np.count_nonzero(atoms.charges == 0.0)
    if num_zero_charges > 0:
        print("WARNING: %d/%d atoms in structure have 0 charges" % (num_zero_charges, len(atoms.charges)))

    num_zero_charges = np.count_nonzero(gas_atoms.charges == 0.0)
    if num_zero_charges > 0:
        print("WARNING: %d/%d atoms in gas have 0 charges" % (num_zero_charges, len(gas_atoms.charges)))

    # check for overlapped atom positions
    atoms.extend(gas_atoms)
    s_ss = distance.cdist(atoms.positions, atoms.positions, "sqeuclidean")
    min_dist_sq = s_ss[np.triu_indices_from(s_ss, k=1)].min()
    min_dist_indices = list(zip(*np.where(s_ss == min_dist_sq)))
    min_dist = min_dist_sq ** 0.5
    if verbose:
        print("min distance between atoms: %6.4f" % min_dist)

    if verbose:
        zero_indices = [(i1,i2) for i1, i2 in np.argwhere(s_ss < 0.1) if i1 < i2]
        for i1, i2 in zero_indices:
            print("WARNING: some atoms look like they are overlapped: %d %d (%s-%s) dist=%6.4f" %
                (i1+1, i2+1, atoms.elements[i1], atoms.elements[i2], s_ss[i1,i2] ** 0.5))
Пример #7
0
def test_replace_pattern_in_structure__two_points_on_x_axis_positions_are_unchanged():
    structure = Atoms(elements='CNNC', positions=[(0., 0., 0), (1.0, 0., 0.), (2.0, 0., 0.), (3.0, 0., 0.)], cell=100*np.identity(3))
    search_pattern = Atoms(elements='NN', positions=[(0.0, 0., 0), (1.0, 0., 0.)])
    replace_pattern = Atoms(elements='FF', positions=[(0., 0., 0), (1.0, 0., 0.)])

    final_structure = replace_pattern_in_structure(structure, search_pattern, replace_pattern)
    assert Counter(final_structure.elements) == {"C":2, "F": 2}
    assert_structure_positions_are_unchanged(structure, final_structure)
Пример #8
0
def test_replace_pattern_in_structure__replace_CH3_in_octane_with_CH3(octane):
    search_pattern = Atoms(elements='CHHH', positions=[(0, 0, 0), (-0.538, -0.635,  0.672), (-0.397,  0.993,  0.052), (-0.099, -0.371, -0.998)])
    replace_pattern = Atoms(elements='CHHH', positions=search_pattern.positions)
    final_structure = replace_pattern_in_structure(octane, search_pattern, replace_pattern)
    assert Counter(final_structure.elements) == {"C": 8, "H": 18}
    # note the positions are not EXACTLY the same because the original structure has slightly
    # different coordinates for the two CH3 groups!
    assert_structure_positions_are_unchanged(octane, final_structure, max_delta=0.1)
Пример #9
0
def test_atoms_load__loads_cif_from_file_or_path():
    with Path("tests/uio66/uio66-linker.cif") as path:
        atoms = Atoms.load(path)
        assert len(atoms) == 16

    with Path("tests/uio66/uio66-linker.cif").open() as fd:
        atoms = Atoms.load(fd, filetype="cif")
        assert len(atoms) == 16
Пример #10
0
def test_atoms_load__loads_lmpdat_from_file_or_path():
    with Path("tests/uio66/uio66-linker.lmpdat") as path:
        atoms = Atoms.load(path, atom_format="atomic")
        assert len(atoms) == 16

    with Path("tests/uio66/uio66-linker.lmpdat").open() as fd:
        atoms = Atoms.load(fd, filetype="lmpdat", atom_format="atomic")
        assert len(atoms) == 16
Пример #11
0
def test_replace_pattern_in_structure__special_rotated_pattern_replaced_with_itself_does_not_change_positions():
    search_pattern = Atoms(elements='CCH', positions=[(0., 0., 0.), (4., 0., 0.),(0., 1., 0.)])
    replace_pattern = Atoms(elements='FFHe', positions=search_pattern.positions)
    structure = search_pattern.copy()
    structure.cell = [15] * np.identity(3)
    r = R.from_quat([-0.4480244,  -0.50992783,  0.03212454, -0.7336319 ])
    structure.positions = r.apply(structure.positions)
    structure.positions = structure.positions % 15
    final_structure = replace_pattern_in_structure(structure, search_pattern, replace_pattern, axis1a_idx=0, axis1b_idx=1)
    assert_structure_positions_are_unchanged(structure, final_structure)
Пример #12
0
def test_replace_pattern_in_structure__in_uio66_replacing_linker_with_linker_does_not_change_positions():
    with Path("tests/uio66/uio66.cif") as path:
        structure = Atoms.load_cif(path)
    with Path("tests/uio66/uio66-linker.cif") as path:
        search_pattern = Atoms.load_cif(path)
    with Path("tests/uio66/uio66-linker-fluorinated.cif") as path:
        replace_pattern = Atoms.load_cif(path)

    final_structure = replace_pattern_in_structure(structure, search_pattern, replace_pattern)
    assert Counter(final_structure.elements) == {'C': 192, 'O': 120, 'F': 96, 'Zr': 24}
Пример #13
0
def test_replace_pattern_in_structure__special2_rotated_pattern_replaced_with_itself_does_not_change_positions():
    search_pattern = Atoms(elements='CCH', positions=[(0., 0., 0.), (4., 0., 0.),(0., 1., 0.)])
    replace_pattern = Atoms(elements='FFHe', positions=search_pattern.positions)
    structure = search_pattern.copy()
    structure.cell = 15 * np.identity(3)
    r = R.from_quat([ 0.02814096,  0.99766676,  0.03984918, -0.04776152])
    structure.positions = r.apply(structure.positions)
    structure.positions = structure.positions % 15
    final_structure = replace_pattern_in_structure(structure, search_pattern, replace_pattern, axis1a_idx=0, axis1b_idx=1)
    assert_structure_positions_are_unchanged(structure, final_structure)
Пример #14
0
def test_replace_pattern_in_structure__three_points_on_x_axis_positions_are_unchanged():
    # this test exists to verify that for a search pattern with more than 2 atoms where all atoms lie on the same axis
    # there are no errors, since there is an extra unnecessary quaternion calcuation to orient the replacement pattern
    # into the final position
    structure = Atoms(elements='CNNNC', positions=[(0., 0., 0), (1., 0., 0.), (2., 0., 0.), (3., 0., 0.), (4., 0., 0.)], cell=100*np.identity(3))
    search_pattern = Atoms(elements='NNN', positions=[(0., 0., 0), (1.0, 0., 0.), (2.0, 0., 0.)])
    replace_pattern = Atoms(elements='FFF', positions=[(0., 0., 0), (1.0, 0., 0.), (2.0, 0., 0.)])

    final_structure = replace_pattern_in_structure(structure, search_pattern, replace_pattern)
    assert Counter(final_structure.elements) == {"C":2, "F": 3}
    assert_structure_positions_are_unchanged(structure, final_structure)
Пример #15
0
def test_atoms_replicate__triclinic_222_has_replicates_in_three_dims():
    a = Atoms(elements="H",
              positions=[(1, 1, 1)],
              cell=np.array([[10, 0, 0], [10, 10, 0], [0, 0, 10]]))
    expected = Atoms(elements="HHHHHHHH",
                     cell=np.array([[20, 0, 0], [20, 20, 0], [0, 0, 20]]),
                     positions=[[1, 1, 1], [11, 1, 1], [11, 11, 1],
                                [21, 11, 1], [1, 1, 11], [11, 1, 11],
                                [11, 11, 11], [21, 11, 11]])

    ra = a.replicate((2, 2, 2))
    assert len(ra) == 8
    assert_structure_positions_are_unchanged(ra, expected, verbose=True)
    assert np.array_equal(ra.cell, expected.cell)
Пример #16
0
def test_replace_pattern_in_structure__100_randomly_rotated_patterns_replaced_with_itself_does_not_change_positions():
    search_pattern = Atoms(elements='CCH', positions=[(0., 0., 0.), (4., 0., 0.),(0., 1., 0.)])
    replace_pattern = Atoms(elements='FFHe', positions=search_pattern.positions)
    structure = search_pattern.copy()
    structure.cell = 15 * np.identity(3)
    for _ in range(100):
        r = R.random(1)
        print("quat: ", r.as_quat())
        structure.positions = r.apply(structure.positions)
        dp = np.random.random(3) * 15
        print(dp)
        structure.translate(dp)
        structure.positions = structure.positions % 15
        final_structure = replace_pattern_in_structure(structure, search_pattern, replace_pattern, axis1a_idx=0, axis1b_idx=1)
        assert_structure_positions_are_unchanged(structure, final_structure)
Пример #17
0
def test_atoms_load_lmpdat__atom_type_labels_are_loaded_from_elements_if_no_comments(
):
    with Path("tests/test_atoms_load_save/atomic-masses-no-comments.lmpdat"
              ).open() as f:
        atoms = Atoms.load_lmpdat(f, atom_format="full")
    assert np.array_equal(atoms.atom_type_masses, [12., 14.])
    assert np.array_equal(atoms.atom_type_labels, ["C", "N"])
Пример #18
0
def test_atoms_load_lmpdat__if_masses_are_nonatomic_then_elements_are_type_ids(
):
    with Path(
            "tests/test_atoms_load_save/nonatomic-masses.lmpdat").open() as f:
        atoms = Atoms.load_lmpdat(f, atom_format="full")
    assert np.array_equal(atoms.atom_type_masses, [12., 1000.])
    assert np.array_equal(atoms.atom_type_elements, ["1", "2"])
Пример #19
0
def octane():
    # CH3 CH2 CH2 CH2 CH2 CH2 CH2 CH3 #
    with Path("tests/molecules/octane.xyz") as path:
        structure = Atoms.from_ase_atoms(ase.io.read(path))
        structure.cell = 60 * np.identity(3)
        structure.translate((30., 30., 30.))
        yield structure
Пример #20
0
def test_atoms_del__deletes_impropers_attached_to_atoms():
    atoms = Atoms(elements="HCHH",
                  positions=random_positions(4),
                  impropers=[(0, 1, 2, 3)],
                  improper_types=[0])
    del (atoms[[1]])
    assert len(atoms.impropers) == 0
Пример #21
0
def test_find_pattern_in_structure__cnnc_over_x_pbc_has_positions_across_x_pbc(linear_cnnc):
    linear_cnnc.positions = (linear_cnnc.positions + (-0.5, 0.0, 0.0)) % 15
    linear_cnnc.pop(-1) #don't match final NC
    search_pattern = Atoms(elements='CN', positions=[(0.0, 0., 0), (1.0, 0., 0.)])
    match_indices, match_positions = find_pattern_in_structure(linear_cnnc, search_pattern, return_positions=True)
    assert (linear_cnnc[match_indices[0]].positions == [(14.5, 0., 0.), (0.5, 0., 0.)]).all()
    assert (match_positions[0] == np.array([(14.5, 0., 0.), (15.5, 0., 0.)])).all()
Пример #22
0
def test_find_pattern_in_structure__hkust1_unit_cell_has_48_Cu_metal_nodes(hkust1_cif):
    pattern = Atoms(elements='Cu', positions=[(0, 0, 0)])
    match_indices = find_pattern_in_structure(hkust1_cif, pattern)

    assert len(match_indices) == 48
    for indices in match_indices:
        pattern_found = hkust1_cif[indices]
        assert list(pattern_found.elements) == ['Cu']
Пример #23
0
def test_find_pattern_in_structure__hkust1_xyz_3x3x3_supercell_has_1296_Cu_metal_nodes(hkust1_3x3x3_xyz):
    pattern = Atoms(elements='Cu', positions=[(0, 0, 0)])
    match_indices = find_pattern_in_structure(hkust1_3x3x3_xyz, pattern)

    assert len(match_indices) == 1296
    for indices in match_indices:
        pattern_found = hkust1_3x3x3_xyz[indices]
        assert list(pattern_found.elements) == ['Cu']
Пример #24
0
def test_atoms_load_cif__loads_elements():
    with Path("tests/uio66/uio66-linker.cif").open() as fd:
        atoms = Atoms.load_cif(fd)

    assert atoms.elements == [
        "C", "O", "O", "C", "C", "H", "H", "C", "C", "C", "C", "H", "H", "O",
        "C", "O"
    ]
Пример #25
0
def checkdumpfile(lmpdatpath, dumppath, warns=True, verbose=False):
    atoms = Atoms.from_lammps_data(open(lmpdatpath, "r"),
                                   use_comment_for_type_labels=True)
    dumpatoms = ase.io.read(dumppath, format="lammps-dump-text")
    assert len(dumpatoms.positions) == len(atoms.positions)
    atoms.positions = dumpatoms.positions

    # check for overlapped atom positions
    s_ss = distance.cdist(atoms.positions, atoms.positions, "sqeuclidean")
    min_dist_sq = s_ss[np.triu_indices_from(s_ss, k=1)].min()
    min_dist_indices = list(zip(*np.where(s_ss == min_dist_sq)))
    min_dist = min_dist_sq**0.5
    if verbose:
        print("min distance between atoms: %6.4f" % min_dist)

    if verbose:
        zero_indices = [(i1, i2) for i1, i2 in np.argwhere(s_ss < 0.1)
                        if i1 < i2]
        for i1, i2 in zero_indices:
            print(
                "WARNING: some atoms look like they are overlapped: %d %d (%s-%s) dist=%6.4f"
                % (i1 + 1, i2 + 1, atoms.elements[i1], atoms.elements[i2],
                   s_ss[i1, i2]**0.5))

    # check for bond distances
    dumpatoms.set_pbc(True)
    bonddists = np.array(
        [dumpatoms.get_distance(b1, b2, mic=True) for b1, b2 in atoms.bonds])
    bonds_half_uc = (bonddists > dumpatoms.cell.lengths().min() / 2).any()
    if verbose:
        if bonds_half_uc:
            print(
                "WARNING: some bonds appear to have lengths > 1/2 the smallest UC dimension."
            )
            print(bonddists)
        else:
            print(
                "INFO: all bonds have lengths < 1/2 the smallest UC dimension."
            )
            print("maximum bond length is %.2f Å" % max(bonddists))
            print("min bond length is %.2f Å" % min(bonddists))
    else:
        if len(min_dist_indices) > 0:
            min_dist_indices_s = "(%4d %4d %2s - %-2s)" % (
                min_dist_indices[0][0] + 1, min_dist_indices[0][1] + 1,
                atoms.elements[min_dist_indices[0][0]],
                atoms.elements[min_dist_indices[0][1]])
        else:
            min_dist_indices_s = "(---- ----)"

        print("min_dist: %.2f %s; bonds: %.2f-%.2f" %
              (min_dist, min_dist_indices_s, min(bonddists), max(bonddists)),
              end='')
        if warns:
            if bonds_half_uc:
                print("; WARN: bonds > 1/2 UC", end='')
            if min_dist < 0.92 and min_dist < min(bonddists) - 1e-2:
                print("; WARN: atoms closer than shortest bond", end='')
def updatelmpdatpositions(lmpdatpath, dumppath, outputfile):
    atoms = Atoms.from_lammps_data(open(lmpdatpath, "r"), use_comment_for_type_labels=True)

    # update positions in original atoms file with new positions
    dumpatoms = ase.io.read(dumppath, format="lammps-dump-text")
    assert len(dumpatoms.positions) == len(atoms.positions)
    atoms.positions = dumpatoms.positions

    atoms.to_lammps_data(outputfile)
Пример #27
0
def test__retype_atoms_from_uff_types__BZrZrB_gives_BZrZrB():
    cnnc = Atoms(elements='CNNC',
                 positions=[(0., 0., 0), (1.0, 0., 0.), (2.0, 0., 0.),
                            (3.0, 0., 0.)])
    retype_atoms_from_uff_types(cnnc, ["B", "Zr", "Zr", "B"])
    assert cnnc.atom_types == [0, 1, 1, 0]
    assert cnnc.atom_type_labels == ["B", "Zr"]
    assert cnnc.atom_type_elements == ["B", "Zr"]
    assert cnnc.atom_type_masses == [10.811, 91.224]
Пример #28
0
def test__retype_atoms_from_uff_types__boron_gives_all_boron():
    cnnc = Atoms(elements='CNNC',
                 positions=[(0., 0., 0), (1.0, 0., 0.), (2.0, 0., 0.),
                            (3.0, 0., 0.)])
    retype_atoms_from_uff_types(cnnc, ["B"] * 4)
    assert cnnc.atom_types == [0] * 4
    assert cnnc.atom_type_labels == ["B"]
    assert cnnc.atom_type_elements == ["B"]
    assert cnnc.atom_type_masses == [10.811]
Пример #29
0
def test_find_pattern_in_structure__hkust1_cif_3x3x3_supercell_has_1296_Cu_metal_nodes(hkust1_cif):
    hkust1_3x3x3 = hkust1_cif.replicate(repldims=(3,3,3))
    pattern = Atoms(elements='Cu', positions=[(0, 0, 0)])
    match_indices = find_pattern_in_structure(hkust1_3x3x3, pattern)

    assert len(match_indices) == 1296
    for indices in match_indices:
        pattern_found = hkust1_3x3x3[indices]
        assert list(pattern_found.elements) == ['Cu']
Пример #30
0
def packmol_gaslmpdat(structure_lmpdat, structure_xyz, gas_lmpdat, gas_xyz, num_molecules=1):
    """ packs gas into structure using packmol and converts the result into a LAMMPS lmpdat file.

    The resulting lmpdat file has only the gas molecules in it, according to the geometry and coeffs
    of the gas_lmpdat file. Note that it is redundant to have both an XYZ file input and LAMMPS
    file input but we have it this way because this method is used in large-scale screenings and
    both these files are generated at the beginning of the run.

    Args:
        structure_lmpdat: lmpdat file of structure; this is used to get the unit cell for packmol.
        structure_xyz: Path to xyz file of structure to pack the gas into.
        gas_lmpdat: lmpdat file with geometry and coeffs for gas we are packing.
        gas_xyz: xyz file of gas corresponding to the the gas_lmpdat. Atoms must be in the same order!
        num_molecules (int): number of gas molecules to pack into structure.

    """
    gas_name = Path(gas_lmpdat).stem
    structure_name = Path(structure_xyz).stem

    satoms = Atoms.from_lammps_data(structure_lmpdat, use_comment_for_type_labels=True)

    output_gas_xyz = "%s_%s_packed.xyz" % (structure_name, gas_name)
    packmol_input = packmol_config(structure_xyz, gas_xyz, output_gas_xyz, num_molecules=num_molecules,
        boundary_tolerance=1.5, a2a_tolerance=1.5, supercell=[*np.diag(satoms.cell), 90, 90, 90])

    with open("packmol.input", 'w') as f:
        f.write(packmol_input)
    subprocess.run("/Users/pboone/workspace/_prereqs/packmol/packmol < packmol.input", shell=True, check=True)
    gas_data = np.array(extract_gas_atoms_from_packmol_xyz(output_gas_xyz))

    # update the dummy positions in the template gas lmpdat file with real positions from packmol
    # and save in the current directory. Note that this should NOT overwrite the template, since you
    # should be in a different directory at this point.
    atoms = Atoms.from_lammps_data(open(gas_lmpdat,'r'), use_comment_for_type_labels=True)
    atoms.positions = np.array(gas_data[:, 1:], dtype=float)
    atoms.atom_types = np.tile(atoms.atom_types, num_molecules)
    atoms.charges = np.tile(atoms.charges, num_molecules)
    atoms.atom_groups = np.repeat(np.arange(num_molecules), len(gas_data) / num_molecules)
    atoms.cell = satoms.cell

    atoms.to_lammps_data(open("%s.lmpdat" % gas_name, 'w'))
    Path("tmp").mkdir(exist_ok=True)
    Path("packmol.input").rename("tmp/packmol.input")
    Path(output_gas_xyz).rename(Path("tmp/") / output_gas_xyz)