def test_get_pattern(self): s = self.get_structure("CsCl") c = XRDCalculator() xrd = c.get_pattern(s, two_theta_range=(0, 90)) self.assertTrue(xrd.to_json()) # Test MSONAble property # Check the first two peaks self.assertAlmostEqual(xrd.x[0], 21.107738329639844) self.assertAlmostEqual(xrd.y[0], 36.483184003748946) self.assertEqual(xrd.hkls[0], [{'hkl': (1, 0, 0), 'multiplicity': 6}]) self.assertAlmostEqual(xrd.d_hkls[0], 4.2089999999999996) self.assertAlmostEqual(xrd.x[1], 30.024695921112777) self.assertAlmostEqual(xrd.y[1], 100) self.assertEqual(xrd.hkls[1], [{"hkl": (1, 1, 0), "multiplicity": 12}]) self.assertAlmostEqual(xrd.d_hkls[1], 2.976212442014178) s = self.get_structure("LiFePO4") xrd = c.get_pattern(s, two_theta_range=(0, 90)) self.assertAlmostEqual(xrd.x[1], 17.03504233621785) self.assertAlmostEqual(xrd.y[1], 50.400928948337075) s = self.get_structure("Li10GeP2S12") xrd = c.get_pattern(s, two_theta_range=(0, 90)) self.assertAlmostEqual(xrd.x[1], 14.058274883353876) self.assertAlmostEqual(xrd.y[1], 4.4111123641667671) # Test a hexagonal structure. s = self.get_structure("Graphite") xrd = c.get_pattern(s, two_theta_range=(0, 90)) self.assertAlmostEqual(xrd.x[0], 26.21057350859598) self.assertAlmostEqual(xrd.y[0], 100) self.assertAlmostEqual(len(xrd.hkls[0][0]["hkl"]), 4) # Add test case with different lengths of coefficients. # Also test d_hkl. coords = [[0.25, 0.25, 0.173], [0.75, 0.75, 0.827], [0.75, 0.25, 0], [0.25, 0.75, 0], [0.25, 0.25, 0.676], [0.75, 0.75, 0.324]] sp = ["Si", "Si", "Ru", "Ru", "Pr", "Pr"] s = Structure(Lattice.tetragonal(4.192, 6.88), sp, coords) xrd = c.get_pattern(s) self.assertAlmostEqual(xrd.x[0], 12.86727341476735) self.assertAlmostEqual(xrd.y[0], 31.448239816769796) self.assertAlmostEqual(xrd.d_hkls[0], 6.88) self.assertEqual(len(xrd), 42) xrd = c.get_pattern(s, two_theta_range=[0, 60]) self.assertEqual(len(xrd), 18) # Test with and without Debye-Waller factor tungsten = Structure(Lattice.cubic(3.1653), ["W"] * 2, [[0, 0, 0], [0.5, 0.5, 0.5]]) xrd = c.get_pattern(tungsten, scaled=False) self.assertAlmostEqual(xrd.x[0], 40.294828554672264) self.assertAlmostEqual(xrd.y[0], 2414237.5633093244) self.assertAlmostEqual(xrd.d_hkls[0], 2.2382050944897789) c = XRDCalculator(debye_waller_factors={"W": 0.1526}) xrd = c.get_pattern(tungsten, scaled=False) self.assertAlmostEqual(xrd.x[0], 40.294828554672264) self.assertAlmostEqual(xrd.y[0], 2377745.2296686019) self.assertAlmostEqual(xrd.d_hkls[0], 2.2382050944897789) c.get_plot(tungsten).show()
def from_structure( # type: ignore[override] cls, material_id: Union[MPID, int], spectrum_id: str, structure: Structure, wavelength: float, min_two_theta=0, max_two_theta=180, symprec=0.1, **kwargs, ) -> "XRDDoc": calc = XRDCalculator(wavelength=wavelength, symprec=symprec) pattern = calc.get_pattern( structure, two_theta_range=(min_two_theta, max_two_theta) ) return super().from_structure( material_id=material_id, spectrum_id=spectrum_id, structure=structure, spectrum=pattern, wavelength=wavelength, min_two_theta=min_two_theta, max_two_theta=max_two_theta, **kwargs, )
def pattern_from_mpid_or_struct(rad_source, mp_time, struct_time, mpid, struct): if (struct_time is None) or (mp_time is None): raise PreventUpdate if struct_time > mp_time: if struct is None: raise PreventUpdate sga = SpacegroupAnalyzer(self.from_data(struct)) struct = ( sga.get_conventional_standard_structure() ) # always get conventional structure elif mp_time >= struct_time: if mpid is None: raise PreventUpdate mpid = mpid["mpid"] with MPRester() as mpr: struct = mpr.get_structure_by_material_id( mpid, conventional_unit_cell=True ) xrdc = XRDCalculator(wavelength=rad_source) data = xrdc.get_pattern(struct, two_theta_range=None) return data.as_dict()
def get_xrd_from_struct(self, structure): doc = {} for xs in self.__settings: xrdcalc = XRDCalculator(wavelength="".join([xs['target'], xs['edge']]), symprec=xs.get('symprec', 0)) pattern = jsanitize(xrdcalc.get_pattern(structure, two_theta_range=xs['two_theta']).as_dict()) d = { 'wavelength': { 'element': xs['target'], 'in_angstroms': WAVELENGTHS["".join([xs['target'], xs['edge']])] }, 'pattern': pattern } doc[xs['target']] = d return doc
def pattern_from_struct(struct, xrdcalculator_kwargs): if struct is None: raise PreventUpdate struct = self.from_data(struct) xrdcalculator_kwargs = self.from_data(xrdcalculator_kwargs) sga = SpacegroupAnalyzer(struct) struct = ( sga.get_conventional_standard_structure() ) # always get conventional structure xrdc = XRDCalculator(**xrdcalculator_kwargs) data = xrdc.get_pattern(struct, two_theta_range=None) return data.as_dict()
def get_xrd(): struct = readstructure() xrd = XRDCalculator() # xrd_data=xrd.get_xrd_pattern(struct) xrd_data = xrd.get_pattern(struct) jxrd_data = jsanitize(xrd_data.as_dict()) fname = 'XRD.json' proc_str = "Saving data to " + fname + " File ..." procs(proc_str, 1, sp='-->>') json_store(jxrd_data, fname) data = np.vstack((xrd_data.x, xrd_data.y)).T margin = 10. ds = xrd_data.x[0] - margin de = xrd_data.x[-1] + margin tmp_data = [ds] + xrd_data.x.tolist() + [de] tmp_data1 = np.diff(tmp_data).tolist() tmp_data2 = np.array([0] + np.cumsum(tmp_data1).tolist()) tmp_data3 = tmp_data2 / tmp_data2[-1] x_data = np.linspace(ds, de, 10000) y_data = np.zeros((len(x_data))) for i in range(1, len(tmp_data3) - 1): index = int(tmp_data3[i] * 10000) y_data[index] = xrd_data.y[i - 1] data = np.vstack((x_data, y_data)) data = (smear(data, sigma=0.1)).T head_line = "#%(key1)+12s %(key2)+12s" % { 'key1': '2theta', 'key2': 'Intensity' } fname = 'XRD.dat' proc_str = "Saving data to " + fname + " File ..." procs(proc_str, 2, sp='-->>') write_col_data(fname, data, head_line) check_matplotlib() fname = 'XRD.png' proc_str = "Saving plot to " + fname + " File ..." procs(proc_str, 3, sp='-->>') plt = xrd.get_plot(struct) plt.savefig(fname, format='png')
def pattern_from_struct(struct, rad_source): if struct is None or not rad_source: raise PreventUpdate struct = self.from_data(struct) rad_source = self.reconstruct_kwarg_from_state( callback_context.inputs, "rad_source") sga = SpacegroupAnalyzer(struct) struct = (sga.get_conventional_standard_structure() ) # always get conventional structure xrdc = XRDCalculator(wavelength=WAVELENGTHS[rad_source], symprec=0, debye_waller_factors=None) data = xrdc.get_pattern(struct, two_theta_range=None) return data.as_dict()
def xrd(structure: Structure, two_theta_range: Tuple[int, int] = (0, 120), sigma: float = 0.05, nsample: int = 5000, fig_name: str = "XRD.png", peak_raw_fname: str = "", plot_dat_fname: str = ""): ''' Calculate XRD pattern of given structure, raw pattern data is returned @in - structure, Structure - two_theta_range, (int, int), range of 2Theta in XRD pattern - sigma, float, gaussian smearing width - nsample, int, how many points in final plot - fig_name, str, name of the figure file to be written, default is XRD.png - peak_raw_fname, str, name of the raw data file containing 2Theta and intensity. - plot_dat_fname, str, name of the plot data file. That plot data was used to plot the XRD pattern. @out - x, np.1darray, theta - y, np.1darray, intensity - plot_x, np.1darray, theta of final data in plotting - plot_y, np.1darray, intensity of final data in plotting ''' def _smearing(x, y, sigma=sigma, nsample=nsample) -> Tuple[NDArray, NDArray]: ''' Apply smearing to discret delta functions to get a continuous array @in - x: x coordinates of peak - y: peak heights @out - res_x - res_y ''' def _smearing_helper(x, x0, sigma=sigma): return np.exp(-(x - x0)**2 / (2 * sigma**2)) assert x.shape == y.shape npeaks = x.shape[0] res_x = np.linspace(two_theta_range[0], two_theta_range[1], num=nsample) smear_res = np.empty((npeaks, nsample)) for ipeak in range(npeaks): smear_res[ipeak] = _smearing_helper(res_x, x[ipeak]) * y[ipeak] pass res_y = np.sum(smear_res, axis=(0)) return (res_x, res_y) c = XRDCalculator() p = c.get_pattern(structure, two_theta_range=two_theta_range) (x, y) = _smearing(p.x, p.y, sigma=sigma) plt.figure() plt.plot(x, y) plt.vlines(p.x, ymin=-5, ymax=-1) plt.ylim(-5, 110) plt.xlabel(r"$2\theta$ ($^\circ$)") plt.ylabel(r"Intensities (scaled)") if "" != fig_name: plt.savefig(fig_name, dpi=800, linewidth=0.01) if "" != peak_raw_fname: with open(peak_raw_fname, 'w') as f: to_be_written = "# {:^10} {:^12} {:^9}\n".format( "2Theta", "Intensity", "Miller") for (_x, _y, hkls) in zip(p.x, p.y, p.hkls): label = ",".join([str(hkl['hkl']) for hkl in hkls]) to_be_written += " {:11.7f} {:11.7f} {}\n".format( _x, _y, label) print(to_be_written, file=f) if "" != plot_dat_fname: with open(plot_dat_fname, 'w') as f: to_be_written = "# {:^10} {:^12}\n".format("2Theta", "Intensity") for (_x, _y) in np.vstack([x, y]).T: to_be_written += " {:11.7f} {:11.7f}\n".format(_x, _y) print(to_be_written, file=f) return (p.x, p.y, x, y)
def set_from_pymatgen(self, structure, k0, k0p, file=None, name='', version=4, int_min=0.1, comments='', thermal_expansion=0., two_theta_range=(0., 30.)): """ set parameters from pymatgen outputs Parameters ---------- structure = pymatgen structure object k0 = bulk modulus k0p = pressure derivative of bulk modulus file = file name (optional) name = name (optional) version = version (optional) comments = comments (optional) thermal_expansion = 0 (optional) Returns ------- """ lattice = structure.lattice self.k0 = k0 self.k0p = k0p self.a0 = float(lattice.a) self.b0 = float(lattice.b) self.c0 = float(lattice.c) self.alpha0 = float(lattice.alpha) self.beta0 = float(lattice.beta) self.gamma0 = float(lattice.gamma) self.symmetry = str(SpacegroupAnalyzer(structure).get_crystal_system()) self.file = file self.name = name self.version = version self.comments = comments self.thermal_expansion = thermal_expansion self.v0 = cal_UnitCellVolume(self.symmetry, self.a0, self.b0, self.c0, self.alpha0, self.beta0, self.gamma0) c = XRDCalculator(wavelength=0.3344) pattern = c.get_pattern(structure, two_theta_range=two_theta_range) h = [] k = [] l = [] for i in range(pattern.hkls.__len__()): h.append(pattern.hkls[i][0]['hkl'][0]) k.append(pattern.hkls[i][0]['hkl'][1]) l.append(pattern.hkls[i][0]['hkl'][-1]) d_lines = np.transpose([pattern.x, pattern.d_hkls, pattern.y, h, k, l]) DiffLines = [] for line in d_lines: if float(line[2]) >= int_min: d_line = DiffractionLine() d_line.dsp0 = float(line[1]) #d_line.dsp = float(line[1]) d_line.intensity = float(line[2]) d_line.h = float(line[3]) d_line.k = float(line[4]) d_line.l = float(line[5]) DiffLines.append(d_line) self.DiffLines = DiffLines
def list_get_pattern_xrd(list_struc): ls = [] for structure in list_struc: i = XRDCalculator() ls.append(i.get_pattern(structure)) return ls
#%% import os from pymatgen.analysis.diffraction.xrd import XRDCalculator from pymatgen import Structure os.chdir('/home/jinho93/arsnide/ZnAs/15700/opti/dos') calc = XRDCalculator(symprec=1e-1) s = Structure.from_file('POSCAR') pat = calc.get_pattern(s, two_theta_range=(0, 90)) calc.show_plot(s) # %% import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import interp1d from scipy.ndimage import gaussian_filter1d f = interp1d(pat.x, pat.y, kind='linear') xnew = np.linspace(20, 70, 1000) plt.plot(xnew, f(xnew)) ynew = gaussian_filter1d(f(xnew), 10) plt.plot(xnew, ynew) plt.xlim(20, 70) np.savetxt('/home/jinho93/xrd.dat', np.transpose([pat.x, pat.y])) # %%
class XRDPowderPattern(BaseFeaturizer): """ 1D array representing powder diffraction of a structure as calculated by pymatgen. The powder is smeared / normalized according to gaussian_kde. NOTE comprhys: placed in distribution as the rdf and ssf are related by a fourier transform. """ def __init__(self, two_theta_range=(0, 127), bw_method=0.05, pattern_length=None, **kwargs): """ Initialize the featurizer. Args: two_theta_range ([float of length 2]): Tuple for range of two_thetas to calculate in degrees. Defaults to (0, 90). Set to None if you want all diffracted beams within the limiting sphere of radius 2 / wavelength. bw_method (float): how much to smear the XRD pattern pattern_length (float): length of final array; defaults to one value per degree (i.e. two_theta_range + 1) **kwargs: any other arguments to pass into pymatgen's XRDCalculator, such as the type of radiation. """ self.two_theta_range = two_theta_range self.bw_method = bw_method self.pattern_length = pattern_length or two_theta_range[1] - \ two_theta_range[0] + 1 self.xrd_calc = XRDCalculator(**kwargs) def featurize(self, strc): pattern = self.xrd_calc.get_pattern( strc, two_theta_range=self.two_theta_range) x, y = pattern.x, pattern.y hist = [] for x1, y1 in zip(x, y): num = int(y1) hist += [x1] * num kernel = gaussian_kde(hist, bw_method=self.bw_method) x = np.linspace(self.two_theta_range[0], self.two_theta_range[1], self.pattern_length) y = kernel(x) return y def feature_labels(self): return ['xrd_{}'.format(x) for x in range(self.pattern_length)] def citations(self): return ["@article{Ong2013, author = {Ong, Shyue Ping and Richards, " "William Davidson and Jain, Anubhav and Hautier, " "Geoffroy and Kocher, Michael and Cholia, Shreyas and Gunter, " "Dan and Chevrier, Vincent L. and Persson, " "Kristin A. and Ceder, Gerbrand}, " "doi = {10.1016/j.commatsci.2012.10.028}, issn = {09270256}, " "journal = {Computational Materials Science}, month = {feb}, " "pages = {314--319}, " "publisher = {Elsevier B.V.}, title = {{Python Materials " "Genomics (pymatgen): A robust, open-source python " "library for materials analysis}}, url = " "{http://linkinghub.elsevier.com/retrieve/pii/S0927025612006295}, " "volume = {68}, year = {2013} } "] def implementors(self): return ['Anubhav Jain', 'Matthew Horton']
for line in cif_data: if '_symmetry_space_group_name_H-M' in line: a = line.replace('_symmetry_space_group_name_H-M', '') if 'P 1' in a: print('Got it') # ## Get diffraction pattern # In[64]: c = XRDCalculator(wavelength=wl_xray) # In[65]: pattern = c.get_pattern(material, two_theta_range=xrange) # ## Extract twotheta, d-sp, int, hkl # In[66]: h = [] k = [] l = [] for i in range(pattern.hkls.__len__()): h.append(pattern.hkls[i][0]['hkl'][0]) k.append(pattern.hkls[i][0]['hkl'][1]) l.append(pattern.hkls[i][0]['hkl'][2]) # In[67]:
def calculate_pattern(filecontent, extension="cif", wavelength="CuKa", return_jcamp=False): """Use pymatgen to calculate a PXRD pattern based on a pymatgen structure""" m = hashlib.md5() m.update(filecontent.encode("utf-8")) input_hash = m.hexdigest() response = None try: response = pattern_cache.get(input_hash) except KeyError: pass logger.debug("Response from cache for key {} is {}".format( input_hash, response)) if response is not None: logger.info("Returning from cache") return response structure = Structure.from_str(filecontent, fmt=extension) calculator = XRDCalculator(wavelength=wavelength) pattern = calculator.get_pattern(structure) two_theta = list(pattern.x) intensity = list(pattern.y) hkls = pattern.hkls output_dict = { "x": two_theta, "y": intensity, "hkls": hkls, "apiVersion": __version__, } if return_jcamp: jcamp = from_dict( { "x": { "data": output_dict["x"], "unit": "°", "type": "INDEPENDENT", "name": "2 theta", }, "y": { "data": output_dict["y"], "type": "DEPENDENT", "unit": "", "name": "intensity", }, }, data_type="Predicted PXRD pattern", origin=f"Pymatgen version {pymatgen.__version__}\ converted to JCAMP with pytojcamp version\ {pytojcamp.__version__}", meta={"wavelength": wavelength}, ) output_dict["jcamp"] = jcamp logger.debug("Trying to set cache") pattern_cache.set(input_hash, output_dict) return output_dict
def process_item(self, item): """ Finds all predicted structures for given item Args: item (dict): structure prediction request and relevant oxidation state-labeled structure templates Returns: (dict, dict): A tuple containing updated request doc and a list of crystal docs to update """ request = item["request"] templates = item["templates"] self.logger.info( f"Labeling oxidation states for {len(templates)} structure templates" ) oxi_labeled_templates = [] for template in templates: struct = Structure.from_dict(template["structure"]) try: oxi_labeled_templates.append({ "structure": self.auto_oxi.apply_transformation(struct), "id": template[self.structure_templates.key], }) except: continue # if auto-oxidation fails, try next structure self.logger.info( f"Successfully labeled oxidation states for {len(oxi_labeled_templates)} structures" ) self.logger.info("Substituting original species into structures") predicted_structs = Substitutor( threshold=request["threshold"]).pred_from_structures( request["original_species"], oxi_labeled_templates, remove_duplicates=True, remove_existing=True, ) predicted_structs.sort(key=lambda s: s.other_parameters["proba"], reverse=True) structure_prediction_id = request[self.requests.key] crystal_docs = [] summaries = [] self.logger.info( f"Found {len(predicted_structs)} predicted structures. Generating crystal docs (XRDs, CIFs, etc." ) for number_id, struct in enumerate(predicted_structs): crystal = {} summary = {} xrd_dict = {} final_structure = struct.final_structure sga = SpacegroupAnalyzer(final_structure, symprec=0.1) for rad_source in ["CuKa", "AgKa", "MoKa", "FeKa"]: xrdc = XRDCalculator(wavelength=rad_source) pattern = xrdc.get_pattern(final_structure, two_theta_range=None) xrd_dict[rad_source] = pattern transformed_structure = struct.to_snl( f"{request['name']} <{request['email']}>", remarks=["Created by MP Structure Predictor"], ) crystal[self.requests.key] = structure_prediction_id crystal[self.crystals.key] = number_id crystal["probability"] = struct.other_parameters["proba"] crystal["transformed_structure"] = transformed_structure crystal["xrd"] = xrd_dict crystal["space_group_info"] = { "symbol": sga.get_space_group_symbol(), "number": sga.get_space_group_number(), "hall": sga.get_hall(), "crystal_system": sga.get_crystal_system(), } summary[self.crystals.key] = number_id summary["probability"] = struct.other_parameters["proba"] summary[ "pretty_formula"] = final_structure.composition.reduced_formula summary["nsites"] = len(final_structure) summary["space_group"] = sga.get_space_group_symbol() summary["cif"] = str(CifWriter(final_structure)) crystal_docs.append(jsanitize(crystal, strict=True)) summaries.append(jsanitize(summary, strict=True)) self.logger.info( f"Successfully generated {len(crystal_docs)} crystal docs for request {request['original_species']}" ) request.update({ "state": "COMPLETE", "completed_at": datetime.utcnow(), "num_crystals": len(crystal_docs), "crystals": summaries, }) return request, crystal_docs