Beispiel #1
0
 def test_pdf_primitive_vs_supercell(self):
     test_doc, success = res2dict(REAL_PATH + "data/KP_primitive.res",
                                  db=False)
     test_doc["text_id"] = ["primitive", "cell"]
     test_doc["lattice_cart"] = abc2cart(test_doc["lattice_abc"])
     test_doc["cell_volume"] = cart2volume(test_doc["lattice_cart"])
     supercell_doc, success = res2dict(REAL_PATH + "data/KP_supercell.res",
                                       db=False)
     supercell_doc["text_id"] = ["supercell", "cell"]
     supercell_doc["lattice_cart"] = abc2cart(supercell_doc["lattice_abc"])
     supercell_doc["cell_volume"] = cart2volume(
         supercell_doc["lattice_cart"])
     test_doc["pdf"] = PDF(test_doc,
                           dr=0.01,
                           low_mem=True,
                           rmax=10,
                           num_images="auto",
                           debug=DEBUG)
     supercell_doc["pdf"] = PDF(
         supercell_doc,
         dr=0.01,
         low_mem=True,
         rmax=10,
         num_images="auto",
         debug=DEBUG,
     )
     overlap = PDFOverlap(test_doc["pdf"], supercell_doc["pdf"])
     self.assertLessEqual(overlap.similarity_distance, 1e-3)
     self.assertGreaterEqual(overlap.similarity_distance, 0.0)
Beispiel #2
0
 def test_cart2abc(self):
     castep_fname = REAL_PATH + "data/Na3Zn4-swap-ReOs-OQMD_759599.castep"
     self.assertTrue(os.path.isfile(castep_fname))
     test_doc, s = castep2dict(castep_fname, db=True, verbosity=VERBOSITY)
     try:
         self.assertTrue(
             np.allclose(test_doc["lattice_abc"],
                         cart2abc(test_doc["lattice_cart"])),
             msg="Conversion cart2abc failed.",
         )
         self.assertTrue(
             np.allclose(
                 cart2abc(test_doc["lattice_cart"]),
                 cart2abc(abc2cart(test_doc["lattice_abc"])),
             ),
             msg="Conversion abc2cart failed.",
         )
         self.assertAlmostEqual(
             test_doc["cell_volume"],
             cart2volume(test_doc["lattice_cart"]),
             msg="Failed to calculate volume from lattice vectors.",
             places=5,
         )
         self.assertIsInstance(test_doc["lattice_abc"],
                               list,
                               msg="Failed abc numpy cast to list")
         self.assertIsInstance(
             test_doc["lattice_cart"],
             list,
             msg="Failed cartesian numpy cast to list",
         )
         cart_pos = frac2cart(test_doc["lattice_cart"],
                              test_doc["positions_frac"])
         back2frac = cart2frac(test_doc["lattice_cart"], cart_pos)
         np.testing.assert_array_almost_equal(back2frac,
                                              test_doc["positions_frac"])
     except AssertionError:
         print("cart:", test_doc["lattice_cart"],
               abc2cart(test_doc["lattice_abc"]))
         print("abc:", test_doc["lattice_abc"],
               cart2abc(test_doc["lattice_cart"]))
         print(
             "volume:",
             test_doc["cell_volume"],
             cart2volume(test_doc["lattice_cart"]),
         )
         raise AssertionError
Beispiel #3
0
def doc2pwscf(doc, path, template=None, spacing=None):
    """ Write the structural part of QE input file based
    on the provided matador doc. Will calculate the correct
    kpoint_mp_grid if spacing is provided.

    Parameters:
        doc (dict): matador document containing structure
        path (str): desired filename for res file

    Keyword Arguments:
        template (str): filename of template to prepend before structure
            (with prefix keyword to be replaced),
        spacing (float): kpoint_mp_spacing to use when calculating grid.

    """
    if path.endswith('.in'):
        path = path.replace('.in', '')

    if os.path.isfile(path + '.in'):
        print('File already exists, not overwriting...')
        return

    if 'lattice_cart' not in doc:
        doc['lattice_cart'] = abc2cart(doc['lattice_abc'])

    if 'kpoints_mp_spacing' in doc or spacing is not None:
        if 'kpoints_mp_spacing' in doc:
            spacing = doc['kpoints_mp_spacing']
        doc['kpoints_mp_grid'] = calc_mp_grid(doc['lattice_cart'], spacing)

    print(doc['kpoints_mp_grid'])

    file_string = ''
    file_string += 'CELL_PARAMETERS angstrom\n'
    for i in range(3):
        file_string += ' {d[0]: 10.10f} {d[1]: 10.10f} {d[2]: 10.10f}\n'.format(d=doc['lattice_cart'][i])

    file_string += '\n ATOMIC_POSITIONS crystal\n'
    for i in range(len(doc['atom_types'])):
        file_string += ('{:4} {d[0]: 10.10f} {d[1]: 10.10f} {d[2]: 10.10f}\n'
                        .format(doc['atom_types'][i], d=doc['positions_frac'][i]))
    file_string += '\nK_POINTS automatic\n'
    file_string += '{d[0]} {d[1]} {d[2]} 0 0 0'.format(d=doc['kpoints_mp_grid'])

    if template is not None:
        if os.path.isfile(template):
            with open(template, 'r') as f:
                template_string = f.readlines()

    with open(path + '.in', 'w') as f:
        for line in template_string:
            if 'prefix' in line:
                line = '  prefix = \'{}\',\n'.format(path)
            elif 'nat' in line:
                line = '  nat = {},\n'.format(len(doc['atom_types']))
            elif 'nat' in line:
                line = '  ntyp = {},\n'.format(len(set(doc['atom_types'])))
            f.write(line)
        f.write(file_string)
Beispiel #4
0
 def test_pdf_from_projected(self):
     doc, success = res2dict(REAL_PATH + "data/LiPZn-r57des.res")
     doc["lattice_cart"] = abc2cart(doc["lattice_abc"])
     doc["text_id"] = ["unprojected", "test"]
     doc["pdf_unprojected"] = PDF(doc, dr=0.01, **{"debug": False})
     doc["text_id"] = ["projected", "test"]
     doc["pdf_projected"] = PDF(doc, dr=0.01, **{"debug": False})
     np.testing.assert_array_almost_equal(doc["pdf_unprojected"].gr,
                                          doc["pdf_projected"].gr)
Beispiel #5
0
    def test_shift_grid(self):
        from matador.utils.cell_utils import (
            calc_mp_grid,
            shift_to_include_gamma,
            abc2cart,
        )

        lattice_abc = [[5.57068, 10.222092, 10.222039], [90.0, 90.0, 90.0]]
        lattice_cart = abc2cart(lattice_abc)
        spacing = 0.1
        mp_grid = calc_mp_grid(lattice_cart, spacing)
        self.assertEqual(mp_grid, [2, 1, 1])
        self.assertEqual(shift_to_include_gamma(mp_grid), [0.25, 0, 0])

        lattice_abc = [[5.57068, 10.222092, 10.222039], [90.0, 90.0, 90.0]]
        lattice_cart = abc2cart(lattice_abc)
        spacing = 0.05
        mp_grid = calc_mp_grid(lattice_cart, spacing)
        self.assertEqual(mp_grid, [4, 2, 2])
        self.assertEqual(shift_to_include_gamma(mp_grid), [0.125, 0.25, 0.25])
Beispiel #6
0
 def test_identity_overlap(self):
     doc, success = res2dict(REAL_PATH + "data/LiPZn-r57des.res")
     doc["lattice_cart"] = abc2cart(doc["lattice_abc"])
     doc["text_id"] = ["pdf", "test"]
     doc["pdf_smear"] = PDF(
         doc,
         num_images=3,
         dr=0.001,
         gaussian_width=0.1,
         style="smear",
         debug=False,
         low_mem=True,
     )
     overlap = PDFOverlap(doc["pdf_smear"], doc["pdf_smear"])
     self.assertEqual(overlap.similarity_distance, 0.0)
Beispiel #7
0
 def test_overlap_smear_vs_hist(self):
     doc, success = res2dict(REAL_PATH + "data/LiPZn-r57des.res")
     doc["lattice_cart"] = abc2cart(doc["lattice_abc"])
     doc["text_id"] = ["smear", "test"]
     doc["pdf_smear"] = PDF(
         doc,
         num_images=3,
         dr=0.01,
         gaussian_width=0.1,
         projected=False,
         style="smear",
         low_mem=True,
     )
     doc["text_id"] = ["hist", "test"]
     doc["pdf_hist"] = PDF(doc,
                           num_images=3,
                           dr=0.1,
                           projected=False,
                           style="histogram")
     overlap = PDFOverlap(doc["pdf_smear"], doc["pdf_hist"])
     self.assertLessEqual(overlap.similarity_distance, 0.02)
     self.assertGreater(overlap.similarity_distance, 0.0)
Beispiel #8
0
 def test_auto_images_vs_large(self):
     doc, success = res2dict(REAL_PATH + "data/LiPZn-r57des.res")
     doc["lattice_cart"] = abc2cart(doc["lattice_abc"])
     doc["text_id"] = ["pdf", "test"]
     doc["pdf_num_images"] = PDF(doc,
                                 low_mem=True,
                                 num_images=5,
                                 rmax=15,
                                 dr=0.1,
                                 **{
                                     "debug": True,
                                     "projected": False
                                 })
     doc["pdf_auto_images"] = PDF(doc,
                                  low_mem=True,
                                  num_images="auto",
                                  rmax=15,
                                  dr=0.1,
                                  **{
                                      "debug": True,
                                      "projected": False
                                  })
     np.testing.assert_array_almost_equal(doc["pdf_num_images"].gr,
                                          doc["pdf_auto_images"].gr)
Beispiel #9
0
def cif2dict(fname, **kwargs):
    """ Extract available information from  .cif file and store as a
    dictionary. Raw cif data is stored under the `'_cif'` key. Symmetric
    sites are expanded by the symmetry operations and their occupancies
    are tracked.

    Parameters:
        fname (str/list): filename or list of filenames of .cif file(s)
            (with or without extension).

    Returns:
        (dict/str, bool): if successful, a dictionary containing scraped
            data and True, if not, then an error string and False.


    """

    flines, fname = get_flines_extension_agnostic(fname, "cif")

    doc = dict()
    cif_dict = _cif_parse_raw(flines)

    doc['_cif'] = cif_dict
    doc['source'] = [str(Path(fname).resolve())]

    doc['atom_types'] = []
    atom_labels = cif_dict.get("_atom_site_type_symbol", False)
    if not atom_labels:
        atom_labels = cif_dict.get("_atom_site_label", False)
    if not atom_labels:
        raise RuntimeError(f"Unable to find atom types in cif file {fname}.")

    for atom in atom_labels:
        symbol = ''
        for character in atom:
            if not character.isalpha():
                break
            else:
                symbol += character
        doc['atom_types'].append(symbol)

    doc['positions_frac'] = [list(map(lambda x: float(x.split('(')[0]), vector)) for vector in
                             zip(cif_dict['_atom_site_fract_x'],
                                 cif_dict['_atom_site_fract_y'],
                                 cif_dict['_atom_site_fract_z'])]

    if '_atom_site_occupancy' in cif_dict:
        doc['site_occupancy'] = [float(x.split('(')[0]) for x in cif_dict['_atom_site_occupancy']]
    else:
        doc['site_occupancy'] = [1.0 for _ in doc['positions_frac']]

    if '_atom_site_symmetry_multiplicity' in cif_dict:
        doc['site_multiplicity'] = [float(x.split('(')[0]) for x in cif_dict['_atom_site_symmetry_multiplicity']]
    else:
        doc['site_multiplicity'] = [1.0 for _ in doc['positions_frac']]

    doc['lattice_abc'] = [list(map(_cif_parse_float_with_errors,
                                   [cif_dict['_cell_length_a'],
                                    cif_dict['_cell_length_b'],
                                    cif_dict['_cell_length_c']])),
                          list(map(_cif_parse_float_with_errors,
                                   [cif_dict['_cell_angle_alpha'],
                                    cif_dict['_cell_angle_beta'],
                                    cif_dict['_cell_angle_gamma']]))]

    doc['lattice_cart'] = abc2cart(doc['lattice_abc'])
    doc['cell_volume'] = cart2volume(doc['lattice_cart'])
    doc['stoichiometry'] = _cif_disordered_stoichiometry(doc)
    doc['num_atoms'] = len(doc['positions_frac'])

    if '_space_group_symop_operation_xyz' in doc['_cif'] and '_symmetry_equiv_pos_as_xyz' not in doc['_cif']:
        doc["_cif"]["_symmetry_equiv_pos_as_xyz"] = doc["_cif"]["_space_group_symop_operation_xyz"]
    if '_symmetry_equiv_pos_as_xyz' in doc['_cif']:
        _cif_set_unreduced_sites(doc)

    try:
        doc['space_group'] = get_spacegroup_spg(doc, check_occ=False)
    except RuntimeError:
        pass

    return doc, True
Beispiel #10
0
    def make_recipe(self, structure, sg):
        """ Construct PDF with diffpy. """

        # construct a PDFContribution object
        pdf = PDFContribution("Contribution")
        # read experimental data
        try:
            pdf.loadData(self.input_file)
        except:
            print_failure('Failed to parse ' + self.input_file +
                          '. Exiting...')
            exit()

        print('Constructing PDF object for', structure.title)

        pdf.setCalculationRange(self.xmin, self.xmax, self.dx)
        pdf.addStructure("Contribution", structure)

        # create FitRecipe to calculate PDF with chosen fit variable
        fit = FitRecipe()
        fit.addContribution(pdf)
        # configure variables and add to recipe
        if sg != 'xxx' and sg is not None:
            print(sg)
            spacegroup_params = constrainAsSpaceGroup(pdf.Contribution.phase,
                                                      sg)
        else:
            cart_lat = abc2cart([[
                structure.lattice.a, structure.lattice.b, structure.lattice.c
            ],
                                 [
                                     structure.lattice.alpha,
                                     structure.lattice.beta,
                                     structure.lattice.gamma
                                 ]])
            positions_frac = structure.xyz
            atomic_numbers = []
            for atom in structure.element:
                atomic_numbers.append(get_atomic_number(atom))
            cell = (cart_lat, positions_frac, atomic_numbers)
            sg = int(
                spg.get_spacegroup(cell, symprec=1e-2).split(' ')[1].replace(
                    '(', '').replace(')', ''))
            spacegroup_params = constrainAsSpaceGroup(pdf.Contribution.phase,
                                                      sg)
        # print('Space group parameters:')
        # print(', '.join([param.name for param in spacegroup_params]))
        # iterate through spacegroup params and activate them
        for param in spacegroup_params.latpars:
            fit.addVar(param)
        for param in spacegroup_params.xyzpars:
            fit.addVar(param, fixed=True)
        # these next parameters are taken from Martin's PDFht.py,
        # though I have a feeling that was not their origin...
        # set initial ADP parameters
        for param in spacegroup_params.adppars:
            fit.addVar(param, value=0.03, fixed=True)
        # overall scale of PDF and delta2 parameter for correlated motion - from PDFht.py
        fit.addVar(pdf.scale, 1, fixed=True)
        fit.restrain(pdf.scale, lb=0, ub=0.1, scaled=True)
        fit.addVar(pdf.Contribution.delta2, 5, fixed=True)
        fit.restrain(pdf.Contribution.delta2, lb=1, ub=10, scaled=True)
        # fix Qdamp based on information about "our beamline": yep, no idea
        fit.addVar(pdf.qdamp, 0.03, fixed=True)
        fit.restrain(pdf.qdamp, lb=0, ub=0.1, scaled=True)

        return fit
Beispiel #11
0
def random_slice(parent_seeds,
                 standardize=True,
                 supercell=True,
                 shift=True,
                 debug=False):
    """ Simple cut-and-splice crossover of two parents.

    The overall size of the child can vary between 0.5 and 1.5 the size of the
    parent structures. Both parent structures are cut and spliced along the
    same crystallographic axis.

    Parameters:

        parents (list(dict)) : parent structures to crossover,
        standardize (bool)   : use spglib to standardize parents pre-crossover,
        supercell (bool)     : make a random supercell to rescale parents,
        shift (bool)         : randomly shift atoms in parents to unbias.

    Returns:

        dict: newborn structure from parents.

    """
    parents = deepcopy(parent_seeds)
    child = dict()
    # child_size is a number between 0.5 and 2
    child_size = 0.5 + 1.5 * np.random.rand()
    # cut_val is a number between 0.25*child_size and 0.75*child_size
    # the slice position of one parent in fractional coordinates
    # (the other is (child_size-cut_val))
    cut_val = child_size * (0.25 + (np.random.rand() / 2.0))

    parent_densities = []
    for ind, parent in enumerate(parents):
        if "cell_volume" not in parent:
            parents[ind]["cell_volume"] = cart2volume(parent["lattice_cart"])
        parent_densities.append(parent["num_atoms"] / parent["cell_volume"])
    target_density = sum(parent_densities) / len(parent_densities)

    if standardize:
        parents = [standardize_doc_cell(parent) for parent in parents]

    if supercell:
        # check ratio of num atoms in parents and grow the smaller one
        parent_extent_ratio = parents[0]["cell_volume"] / parents[1][
            "cell_volume"]
        if debug:
            print(
                parent_extent_ratio,
                parents[0]["cell_volume"],
                "vs",
                parents[1]["cell_volume"],
            )
        if parent_extent_ratio < 1:
            supercell_factor = int(round(1 / parent_extent_ratio))
            supercell_target = 0
        elif parent_extent_ratio >= 1:
            supercell_factor = int(round(parent_extent_ratio))
            supercell_target = 1
        if debug:
            print(supercell_target, supercell_factor)
        supercell_vector = [1, 1, 1]
        if supercell_factor > 1:
            for ind in range(supercell_factor):
                min_lat_vec_abs = 1e10
                min_lat_vec_ind = -1
                for i in range(3):
                    lat_vec_abs = np.sum(
                        np.asarray(
                            parents[supercell_target]["lattice_cart"][i])**2)
                    if lat_vec_abs < min_lat_vec_abs:
                        min_lat_vec_abs = lat_vec_abs
                        min_lat_vec_ind = i
                supercell_vector[min_lat_vec_ind] += 1
        if debug:
            print("Making supercell of {} with {}".format(
                parents[supercell_target]["source"][0], supercell_vector))
        if supercell_vector != [1, 1, 1]:
            parents[supercell_target] = create_simple_supercell(
                parents[supercell_target], supercell_vector, standardize=False)
    child["positions_frac"] = []
    child["atom_types"] = []
    child["lattice_cart"] = cut_val * np.asarray(
        parents[0]["lattice_cart"]) + (child_size - cut_val) * np.asarray(
            parents[1]["lattice_cart"])
    child["lattice_cart"] = child["lattice_cart"].tolist()

    # choose slice axis
    axis = np.random.randint(low=0, high=3)
    for ind, parent in enumerate(parents):
        if shift:
            # apply same random shift to all atoms in parents
            shift_vec = np.random.rand(3)
            for idx, _ in enumerate(parent["positions_frac"]):
                for k in range(3):
                    parent["positions_frac"][idx][k] += shift_vec[k]
                    if parent["positions_frac"][idx][k] >= 1:
                        parent["positions_frac"][idx][k] -= 1
                    elif parent["positions_frac"][idx][k] < 0:
                        parent["positions_frac"][idx][k] += 1
        # slice parent
        for atom, pos in zip(parent["atom_types"], parent["positions_frac"]):
            if ind == (pos[axis] <= cut_val):
                child["positions_frac"].append(pos)
                child["atom_types"].append(atom)
    # check child is sensible
    child["mutations"] = ["crossover"]
    child["stoichiometry"] = get_stoich(child["atom_types"])
    child["num_atoms"] = len(child["atom_types"])

    if "cell_volume" not in child:
        child["cell_volume"] = cart2volume(child["lattice_cart"])
    number_density = child["num_atoms"] / child["cell_volume"]

    # rescale cell based on number density of parents
    new_scale = np.cbrt(number_density / target_density)
    child["lattice_abc"] = np.asarray(cart2abc(child["lattice_cart"]))
    child["lattice_abc"][0] *= new_scale
    child["lattice_abc"] = child["lattice_abc"].tolist()
    child["lattice_cart"] = abc2cart(child["lattice_abc"])
    child["cell_volume"] = cart2volume(child["lattice_cart"])
    child["positions_abs"] = frac2cart(child["lattice_cart"],
                                       child["positions_frac"])

    return child
Beispiel #12
0
 def lattice_abc(self, new_lattice):
     self._lattice_abc = tuple(tuple(vec) for vec in new_lattice)
     self._lattice_cart = tuple(
         tuple(vec) for vec in cell_utils.abc2cart(self._lattice_abc))
     self._volume = None