raddefects 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Alexander Hauck
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,48 @@
1
+ Metadata-Version: 2.1
2
+ Name: raddefects
3
+ Version: 0.1.3
4
+ Summary: Framework to analyze properties of radiation-induced defects in semiconductor materials from first principles.
5
+ Author-email: Alexander Hauck <ash5615@psu.edu>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Alexander Hauck
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://radDefects.readthedocs.io/en/latest/
29
+ Project-URL: Repository, https://github.com/hauck-as/radDefects
30
+ Classifier: Programming Language :: Python :: 3
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Operating System :: OS Independent
33
+ Requires-Python: >=3.6
34
+ Description-Content-Type: text/markdown
35
+ License-File: LICENSE
36
+ Requires-Dist: requests
37
+ Requires-Dist: importlib-metadata; python_version < "3.12"
38
+ Requires-Dist: numpy
39
+ Requires-Dist: pymatgen
40
+ Requires-Dist: mp-api
41
+ Requires-Dist: vise
42
+ Requires-Dist: pydefect
43
+ Requires-Dist: sumo
44
+ Requires-Dist: pymatgen-analysis-defects
45
+ Requires-Dist: niet
46
+
47
+ # radDefects
48
+ Framework to analyze properties of radiation-induced defects in semiconductor materials from first principles.
@@ -0,0 +1,2 @@
1
+ # radDefects
2
+ Framework to analyze properties of radiation-induced defects in semiconductor materials from first principles.
@@ -0,0 +1,82 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ # Templated from both RTD tutorial and doped by SMTG-Bham.
3
+
4
+ # -- Project information
5
+
6
+ project = 'radDefects'
7
+ copyright = '2024, Alexander S. Hauck'
8
+ author = 'Alexander S. Hauck'
9
+
10
+ release = '0.1'
11
+ version = '0.1.3'
12
+
13
+ # -- General configuration
14
+
15
+ extensions = [
16
+ 'sphinx.ext.duration',
17
+ 'sphinx.ext.doctest',
18
+ 'sphinx.ext.autodoc',
19
+ 'sphinx.ext.autosummary',
20
+ 'sphinx.ext.intersphinx',
21
+ 'sphinx.ext.coverage',
22
+ 'sphinx.ext.napoleon',
23
+ 'sphinx.ext.mathjax',
24
+ 'sphinx.ext.viewcode',
25
+ 'sphinx.ext.autosectionlabel',
26
+ 'sphinx_book_theme',
27
+ ]
28
+
29
+ intersphinx_mapping = {
30
+ 'python': ('https://docs.python.org/3/', None),
31
+ 'sphinx': ('https://www.sphinx-doc.org/en/master/', None),
32
+ }
33
+ intersphinx_disabled_domains = ['std']
34
+
35
+ templates_path = ['_templates']
36
+
37
+ # -- Options for HTML output
38
+
39
+ # The theme to use for HTML and HTML Help pages. See the documentation for
40
+ # a list of builtin themes.
41
+ #
42
+ html_theme = 'sphinx_book_theme'
43
+
44
+ # The name of an image file (relative to this directory) to place at the top
45
+ # of the sidebar.
46
+ # html_logo = "rad-defects-logo.png"
47
+ html_title = "radDefects"
48
+
49
+ # If true, SmartyPants will be used to convert quotes and dashes to
50
+ # typographically correct entities.
51
+ html_use_smartypants = True
52
+
53
+ # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
54
+ # html_show_sphinx = True
55
+
56
+ html_theme_options = {
57
+ "repository_url": "https://github.com/hauck-as/radDefects",
58
+ "github_repo": "https://github.com/hauck-as/radDefects",
59
+ "github_button": True,
60
+ "github_user": "hauck-as", # Username
61
+ "description": "Framework to analyze properties of radiation-induced defects in semiconductor materials from first principles.",
62
+ "repository_branch": "main",
63
+ "path_to_docs": "docs",
64
+ "use_repository_button": True,
65
+ "home_page_in_toc": True,
66
+ "launch_buttons": {
67
+ "binderhub_url": "https://mybinder.org",
68
+ "colab_url": "https://colab.research.google.com",
69
+ },
70
+ }
71
+
72
+ # Adding “Edit Source” links on your Sphinx theme
73
+ html_context = {
74
+ "display_github": True, # Integrate GitHub
75
+ "github_user": "hauck-as", # Username
76
+ "github_repo": "radDefects", # Repo name
77
+ "github_version": "main", # Version
78
+ "conf_py_path": "/docs/", # Path in the checkout to the docs root
79
+ }
80
+
81
+ # -- Options for EPUB output
82
+ epub_show_urls = 'footnote'
@@ -0,0 +1,41 @@
1
+ [project]
2
+ name = "raddefects"
3
+ version = "0.1.3"
4
+ authors = [
5
+ { name="Alexander Hauck", email="ash5615@psu.edu" },
6
+ ]
7
+ description = "Framework to analyze properties of radiation-induced defects in semiconductor materials from first principles."
8
+ readme = "README.md"
9
+ license = {file = "LICENSE"}
10
+ requires-python = ">=3.6"
11
+ classifiers = [
12
+ "Programming Language :: Python :: 3",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Operating System :: OS Independent",
15
+ ]
16
+ dependencies = [
17
+ "requests",
18
+ 'importlib-metadata; python_version<"3.12"',
19
+ "numpy",
20
+ "pymatgen",
21
+ "mp-api",
22
+ "vise",
23
+ "pydefect",
24
+ "sumo",
25
+ "pymatgen-analysis-defects",
26
+ "niet"
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://radDefects.readthedocs.io/en/latest/"
31
+ Repository = "https://github.com/hauck-as/radDefects"
32
+
33
+ [project.scripts]
34
+ cli-name = "raddefects.cli.main:main"
35
+
36
+ [tool.setuptools.packages]
37
+ find = {} # Scan the project directory with the default parameters
38
+
39
+ [build-system]
40
+ requires = ["setuptools>=61.0"]
41
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,10 @@
1
+ # Copyright (c) 2024 Alexander Hauck. Distributed under the terms of the MIT License.
2
+
3
+ """
4
+ radDefects is a Python-based framework to analyze properties of radiation-induced defects in semiconductor materials from first principles.
5
+ """
6
+
7
+ __author__ = "Alexander Hauck"
8
+ __copyright__ = "Copyright (C) 2024 Alexander Hauck"
9
+ __license__ = "MIT License"
10
+ __version__ = "0.0.1"
@@ -0,0 +1,104 @@
1
+ """Analysis for charge transition levels within the pydefect format."""
2
+ import logging
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ import os
6
+ import glob
7
+ from pathlib import Path
8
+ import json
9
+ from monty.serialization import dumpfn, loadfn
10
+ from monty.json import MSONable, MontyEncoder, MontyDecoder
11
+
12
+ import re
13
+ import pprint
14
+
15
+ import numpy as np
16
+ import pandas as pd
17
+ import matplotlib as mpl
18
+ import matplotlib.pyplot as plt
19
+ import plotly.graph_objects as go
20
+ import plotly.express as px
21
+ from plotly.subplots import make_subplots
22
+ import plotly.io as pio
23
+
24
+ from pydefect.analyzer.unitcell import Unitcell
25
+ from pydefect.analyzer.band_edge_states import BandEdgeOrbitalInfos, BandEdgeState, PerfectBandEdgeState
26
+ from pydefect.analyzer.defect_energy import DefectEnergyInfo, ChargeEnergies, SingleChargeEnergies, CrossPoints
27
+ from pydefect.analyzer.transition_levels import TransitionLevels, make_transition_levels
28
+
29
+ # Change Plotly default template to simple white and modify for
30
+ pl_paper_theme = pio.templates['simple_white']
31
+ pl_paper_theme.layout.xaxis.ticks = 'inside'
32
+ pl_paper_theme.layout.yaxis.ticks = 'inside'
33
+ pl_paper_theme.layout.xaxis.mirror = 'ticks' # True | "ticks" | False | "all" | "allticks"
34
+ pl_paper_theme.layout.yaxis.mirror = 'ticks' # True | "ticks" | False | "all" | "allticks"
35
+ pl_paper_theme.layout.font.size = 32
36
+ # pl_paper_theme.layout.xaxis.title.standoff = 20
37
+ pl_paper_theme.layout.xaxis.title.font.size = 44
38
+ pl_paper_theme.layout.xaxis.tickfont.size = 36
39
+ pl_paper_theme.layout.yaxis.title.standoff = 24
40
+ pl_paper_theme.layout.yaxis.title.font.size = 28
41
+ #pl_paper_theme.layout.coloraxis.colorbar.title.standoff = 20
42
+ pio.templates.default = pl_paper_theme
43
+
44
+
45
+ def generate_transition_level_diagram(transition_levels, im_write=False, im_name='transition_levels.png'):
46
+ """
47
+ Given a TransitionLevels object from pydefect, plots a charge transition level diagram
48
+ showing the Fermi energy levels and which charges for each defect calculated.
49
+ """
50
+ # add capability to remove defects without transition levels or that are not of interest
51
+ # ex. transition_levels.transition_levels.pop(3)
52
+ defects_list = [defect.name for defect in transition_levels.transition_levels]
53
+
54
+ fig = go.Figure()
55
+
56
+ for i in range(len(defects_list)):
57
+ if len(transition_levels.transition_levels[i].fermi_levels) > 0:
58
+ for j in range(len(transition_levels.transition_levels[i].fermi_levels)):
59
+ defect_fermi_levels = transition_levels.transition_levels[i].fermi_levels
60
+ defect_fermi_levels.sort()
61
+ fig.add_trace(go.Scatter(x=[transition_levels.transition_levels[i].name for j in range(len(defect_fermi_levels))],
62
+ y=[defect_fermi_levels[j] for j in range(len(defect_fermi_levels))],
63
+ text=[f'{transition_levels.transition_levels[i].charges[j][0]:+}/{transition_levels.transition_levels[i].charges[j][1]:+}' for j in range(len(defect_fermi_levels))],
64
+ mode='markers+text',
65
+ marker=dict(symbol='line-ew-open',
66
+ size=28,
67
+ color=px.colors.qualitative.Plotly[i],
68
+ line=dict(width=6)
69
+ )
70
+ ))
71
+ else:
72
+ fig.add_trace(go.Scatter(x=[transition_levels.transition_levels[i].name],
73
+ y=[0.],
74
+ marker=dict(size=0, opacity=0)
75
+ ))
76
+
77
+ fig.update_traces(textposition='top center')
78
+
79
+ # VBM
80
+ fig.add_hline(y=transition_levels.supercell_vbm, line=dict(color='black', width=3, dash='dash'), annotation_text='VBM', annotation_position='bottom left')
81
+ fig.add_hrect(y0=transition_levels.supercell_vbm-0.2, y1=transition_levels.supercell_vbm, line_width=0, fillcolor='red', opacity=0.2)
82
+
83
+ # CBM
84
+ fig.add_hline(y=transition_levels.supercell_cbm, line=dict(color='black', width=3, dash='dash'), annotation_text='CBM', annotation_position='top left')
85
+ fig.add_hrect(y0=transition_levels.supercell_cbm, y1=transition_levels.supercell_cbm+0.2, line_width=0, fillcolor='blue', opacity=0.2)
86
+
87
+ fig.update_layout(xaxis_title=r'Defects',
88
+ yaxis_title=r'$\Huge{E_{F} \; [eV]}$',
89
+ xaxis_type='category',
90
+ yaxis_showticklabels=False,
91
+ showlegend=False,
92
+ margin=dict(l=20, r=20, t=20, b=20),
93
+ autosize=False, width = 850, height = 650
94
+ )
95
+
96
+ fig.show()
97
+
98
+ if im_write == True:
99
+ fig.write_image(im_name, scale=1)
100
+ elif im_write == False:
101
+ pass
102
+
103
+ return
104
+
@@ -0,0 +1,5 @@
1
+ # Copyright (c) 2024 Alexander Hauck. Distributed under the terms of the MIT License.
2
+
3
+ """
4
+ radDefects package containing command line interfaces.
5
+ """
File without changes
@@ -0,0 +1,253 @@
1
+ """Core functions and classes for analyzing rad-induced defects from VASP."""
2
+ import logging
3
+ from typing import TYPE_CHECKING, Optional
4
+ import importlib.resources as ilr
5
+
6
+ import os
7
+ import glob
8
+ from pathlib import Path
9
+ import shutil
10
+ import json
11
+ from monty.serialization import dumpfn, loadfn
12
+ from monty.json import MSONable, MontyEncoder, MontyDecoder
13
+
14
+ import subprocess
15
+ import re
16
+ import pprint
17
+
18
+ import math as m
19
+ from fractions import Fraction
20
+ import random as rand
21
+
22
+ import numpy as np
23
+ import pandas as pd
24
+ import matplotlib as mpl
25
+ import matplotlib.pyplot as plt
26
+
27
+ from pymatgen.io.vasp.sets import VaspInputSet, Poscar
28
+ from pymatgen.io.vasp.outputs import Locpot, Outcar, Vasprun
29
+ from pymatgen.core import Structure, Lattice
30
+ from pymatgen.io.vasp.sets import MPRelaxSet
31
+ from pymatgen.symmetry.analyzer import *
32
+ from pymatgen.analysis.defects.core import DefectComplex, Substitution, Vacancy
33
+ from pymatgen.analysis.defects.finder import DefectSiteFinder
34
+ from mp_api.client import MPRester
35
+
36
+ from pydefect.analyzer.unitcell import Unitcell
37
+ from pydefect.analyzer.band_edge_states import BandEdgeOrbitalInfos, BandEdgeState, PerfectBandEdgeState
38
+ from pydefect.analyzer.calc_results import CalcResults
39
+ from pydefect.analyzer.defect_energy import DefectEnergyInfo
40
+ from pydefect.input_maker.defect_entry import DefectEntry
41
+ from pydefect.corrections.efnv_correction import ExtendedFnvCorrection
42
+
43
+ from doped.analysis import DefectParser, DefectsParser
44
+
45
+ # pydefect file structure
46
+ base_path = os.getcwd()
47
+ cpd_path, defects_path, unitcell_path, band_path, diele_path, dos_path, struc_opt_path = os.path.relpath('cpd'), os.path.relpath('defect'), os.path.relpath('unitcell'), os.path.relpath('unitcell/band'), os.path.relpath('unitcell/dielectric'), os.path.relpath('unitcell/dos'), os.path.relpath('unitcell/structure_opt')
48
+ pydefect_paths = [cpd_path, defects_path, unitcell_path, band_path, diele_path, dos_path, struc_opt_path]
49
+
50
+
51
+ # create pydefect file structure
52
+ def create_pydefect_file_structure():
53
+ os.makedirs([os.path.join(base_path, i) for i in pydefect_paths])
54
+ return
55
+
56
+
57
+ # maybe define class for defective supercells
58
+ # get defect and perfect supercells on definition
59
+ def get_mpid_from_supercell(perfect_poscar_path):
60
+ """
61
+ Given a path for a perfect supercell POSCAR, determine the
62
+ characteristics of the unitcell and fetches from the
63
+ Materials Project.
64
+ """
65
+ # read POSCAR files with pymatgen and determine unitcell from perfect supercell
66
+ perfect_pos = Poscar.from_file(perfect_poscar_path)
67
+ unitcell_strc = perfect_pos.structure.get_primitive_structure()
68
+ unitcell_spg = SpacegroupAnalyzer(unitcell_strc)
69
+
70
+ # query MPD to get material ID matching perfect supercell structure
71
+ # API key is parsed via .pmgrc.yaml
72
+ with MPRester() as mpr:
73
+ docs = mpr.materials.summary.search(
74
+ elements=map(str, unitcell_strc.elements),
75
+ num_elements=len(unitcell_strc.elements),
76
+ num_sites=len(unitcell_strc.sites),
77
+ spacegroup_symbol=unitcell_spg.get_space_group_symbol(),
78
+ fields=['material_id', 'composition', 'symmetry', 'band_gap', 'structure']
79
+ )
80
+ mpid_dict = {doc.material_id: [doc.composition, doc.symmetry, doc.band_gap, doc.structure] for doc in docs}
81
+ if len(mpid_dict.keys()) == 1:
82
+ unitcell_mpid = list(mpid_dict.keys())[0]
83
+ unitcell_info = {
84
+ 'mpid': unitcell_mpid,
85
+ 'composition': mpid_dict[unitcell_mpid][0],
86
+ 'symmetry': mpid_dict[unitcell_mpid][1],
87
+ 'band_gap': mpid_dict[unitcell_mpid][2],
88
+ 'structure': mpid_dict[unitcell_mpid][3]
89
+ }
90
+ else:
91
+ raise UserWarning('Multiple matching structures were found.')
92
+ return unitcell_info
93
+
94
+
95
+ # band edge orbital infos gives fermi level, states below should be occupied and above should be unoccupied
96
+ # interested in occupation of states between VBM & CBM: gap states
97
+ def find_gap_states(pbes_path, beois_path):
98
+ """
99
+ Given a path to the perfect band edge state and band edge orbital
100
+ info JSON files, determine VBM & CBM energies as well as orbital
101
+ energies and occupations from pydefect.
102
+ """
103
+ pbes, beois = PerfectBandEdgeState.from_dict(json.load(open(pbes_path, 'r'))), BandEdgeOrbitalInfos.from_dict(json.load(open(beois_path, 'r')))
104
+ e_vbm, e_cbm = pbes.vbm_info.orbital_info.energy, pbes.cbm_info.orbital_info.energy
105
+
106
+ for s in range(len(beois.orbital_infos)): # spin up/down channels
107
+ for k in range(len(beois.orbital_infos[s])): # kpt idx
108
+ for b in range(len(beois.orbital_infos[s][k])): # band idx
109
+ beois_ens, beois_occs = beois.orbital_infos[s][k][b].energy, beois.orbital_infos[s][k][b].occupation
110
+
111
+ # maybe make a GapState class that incorporates the Orbital Infos plus the s/k/b for the given gap state
112
+ # gap state defined as energy between e_vbm and e_cbm
113
+ # gap state occupancy is of interest
114
+ # use gap state to determine charge localization?
115
+
116
+
117
+ def get_plnr_avg_only(
118
+ defect_locpot: Locpot,
119
+ bulk_locpot: Locpot,
120
+ lattice: Optional[Lattice] = None
121
+ ):
122
+ """Calculates the planar average electrostatic potential.
123
+ Based on FNV correction function from pymatgen.analysis.defects.
124
+
125
+ Args:
126
+ defect_locpot:
127
+ Locpot of defect
128
+ bulk_locpot:
129
+ Locpot of bulk
130
+ lattice:
131
+ Lattice of the defect supercell. If None, then uses the lattice of the
132
+ defect_locpot.
133
+
134
+ Returns:
135
+ Plotting data for the planar average electrostatic potential.
136
+ ```
137
+ plot_plnr_avg(result.metadata[0], title="Lattice Direction 1")
138
+ plot_plnr_avg_only(plnr_avg_data['plot_data'][direction]['pot_plot_data'], ax=axs[direction], title=axis_label_dict[direction])
139
+ ```
140
+ """
141
+
142
+ if isinstance(defect_locpot, Locpot):
143
+ list_axis_grid = [*map(defect_locpot.get_axis_grid, [0, 1, 2])]
144
+ list_defect_plnr_avg_esp = [
145
+ *map(defect_locpot.get_average_along_axis, [0, 1, 2])
146
+ ]
147
+ lattice_ = defect_locpot.structure.lattice.copy()
148
+ if lattice is not None and lattice != lattice_:
149
+ raise ValueError(
150
+ "Lattice of defect_locpot and user provided lattice do not match."
151
+ )
152
+ lattice = lattice_
153
+ elif isinstance(defect_locpot, dict):
154
+ defect_locpot_ = {int(k): v for k, v in defect_locpot.items()}
155
+ list_defect_plnr_avg_esp = [defect_locpot_[i] for i in range(3)]
156
+ list_axis_grid = [
157
+ *map(
158
+ np.linspace,
159
+ [0, 0, 0],
160
+ lattice.abc,
161
+ [len(i) for i in list_defect_plnr_avg_esp],
162
+ )
163
+ ]
164
+ else:
165
+ raise ValueError("defect_locpot must be of type Locpot or dict")
166
+
167
+ # TODO this can be done with regridding later
168
+ if isinstance(bulk_locpot, Locpot):
169
+ list_bulk_plnr_avg_esp = [*map(bulk_locpot.get_average_along_axis, [0, 1, 2])]
170
+ elif isinstance(bulk_locpot, dict):
171
+ bulk_locpot_ = {int(k): v for k, v in bulk_locpot.items()}
172
+ list_bulk_plnr_avg_esp = [bulk_locpot_[i] for i in range(3)]
173
+ else:
174
+ raise ValueError("bulk_locpot must be of type Locpot or dict")
175
+
176
+ plot_data = dict()
177
+
178
+ for x, pureavg, defavg, axis in zip(
179
+ list_axis_grid, list_bulk_plnr_avg_esp, list_defect_plnr_avg_esp, [0, 1, 2]
180
+ ):
181
+ # log plotting data:
182
+ metadata = dict()
183
+ metadata["pot_plot_data"] = {
184
+ "x": x,
185
+ "dft_diff": np.array(defavg) - np.array(pureavg)
186
+ }
187
+
188
+ plot_data[axis] = metadata
189
+
190
+ corr_metadata = {"plot_data": plot_data}
191
+
192
+ return corr_metadata
193
+
194
+
195
+ def plot_plnr_avg_only(plot_data, title=None, ax=None, style_file=None):
196
+ """
197
+ Plots exclusively the planar-averaged electrostatic potential.
198
+
199
+ Original code templated from the original PyCDT and new
200
+ pymatgen.analysis.defects implementations as plot_FNV in doped.
201
+ Functionality for plotting only the planar-averaged electrostatic
202
+ potential is kept.
203
+
204
+ Args:
205
+ plot_data (dict):
206
+ Dictionary of Freysoldt correction metadata to plot
207
+ (i.e. defect_entry.corrections_metadata["plot_data"][axis] where
208
+ axis is one of [0, 1, 2] specifying which axis to plot along (a, b, c)).
209
+ title (str): Title for the plot. Default is no title.
210
+ ax (matplotlib.axes.Axes): Axes object to plot on. If None, makes new figure.
211
+ style_file (str):
212
+ Path to a mplstyle file to use for the plot. If None (default), uses
213
+ the default doped style (from doped/utils/doped.mplstyle).
214
+ """
215
+
216
+ x = plot_data["x"]
217
+ dft_diff = plot_data["dft_diff"]
218
+
219
+ style_file = style_file or f"{ilr.files('doped')}/utils/doped.mplstyle"
220
+ plt.style.use(style_file) # enforce style, as style.context currently doesn't work with jupyter
221
+ with plt.style.context(style_file):
222
+ if ax is None:
223
+ plt.close("all") # close any previous figures
224
+ fig, ax = plt.subplots()
225
+ (line1,) = ax.plot(x, dft_diff, c="red", label=r"$\Delta$(Locpot)")
226
+ leg1 = ax.legend(handles=[line1], loc=9) # middle top legend
227
+ ax.add_artist(leg1) # so isn't overwritten with later legend call
228
+
229
+ ax.set_xlim(round(x[0]), round(x[-1]))
230
+ ymin = min(*dft_diff)
231
+ ymax = max(*dft_diff)
232
+ ax.set_ylim(-0.2 + ymin, 0.2 + ymax)
233
+ ax.set_xlabel(r"Distance along axis ($\AA$)")
234
+ ax.set_ylabel("Potential (V)")
235
+ ax.axhline(y=0, linewidth=0.2, color="black")
236
+ if title is not None:
237
+ ax.set_title(str(title))
238
+ ax.set_xlim(0, max(x))
239
+
240
+ return ax
241
+
242
+
243
+ def plot_plnr_avg_abc(plot_data, title=None, ax=None, style_file=None):
244
+ axis_label_dict = {0: r"$a$-axis", 1: r"$b$-axis", 2: r"$c$-axis"}
245
+ fig, axs = plt.subplots(1, 3, sharey=True, figsize=(12, 3.5), dpi=600)
246
+ for direction in range(3):
247
+ plot_plnr_avg_only(
248
+ plot_data['plot_data'][direction]['pot_plot_data'],
249
+ ax=axs[direction],
250
+ title=axis_label_dict[direction]
251
+ )
252
+ return
253
+
@@ -0,0 +1,162 @@
1
+ """Analysis for sxdefectalign calculations using pydefect, doped, and radDefects tools."""
2
+ import logging
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ import os
6
+ import glob
7
+ from pathlib import Path
8
+ import json
9
+ from monty.serialization import dumpfn, loadfn
10
+ from monty.json import MSONable, MontyEncoder, MontyDecoder
11
+
12
+ import re
13
+ import pprint
14
+
15
+ import numpy as np
16
+ import pandas as pd
17
+
18
+ from pydefect.analyzer.unitcell import Unitcell
19
+ from pydefect.analyzer.band_edge_states import BandEdgeOrbitalInfos, BandEdgeState, PerfectBandEdgeState
20
+ from pydefect.analyzer.defect_energy import DefectEnergyInfo, ChargeEnergies, SingleChargeEnergies, CrossPoints
21
+ from pydefect.analyzer.transition_levels import TransitionLevels, make_transition_levels
22
+
23
+ from raddefects.sxda.io import parse_sxda_vatoms
24
+
25
+
26
+ def sxda_transition_levels(base_path=os.getcwd(), chg_offset=0):
27
+ """
28
+ Using sxdefectalign calculations within the pydefect structure, calculate
29
+ charge transition levels.
30
+ """
31
+ # use unitcell.yaml and perfect_band_edge_state.json files to get CBM/VBM info
32
+ unitcell_yaml = os.path.join(base_path, 'unitcell', 'unitcell.yaml')
33
+ defect_path=os.path.join(base_path, 'defect')
34
+ perfect_band_edge_state_json = os.path.join(defect_path, 'perfect', 'perfect_band_edge_state.json')
35
+ uc_info, pbes = Unitcell.from_yaml(unitcell_yaml), loadfn(perfect_band_edge_state_json)
36
+ cbm, supercell_vbm, supercell_cbm = uc_info.cbm, pbes.vbm_info.energy, pbes.cbm_info.energy
37
+ cbm -= supercell_vbm
38
+ supercell_cbm -= supercell_vbm
39
+ supercell_vbm -= supercell_vbm
40
+
41
+ # gather pydefect defect directories
42
+ defect_paths = glob.glob(os.path.join(defect_path, '*_*/'), recursive=True)
43
+
44
+ # empty dictionaries for sxda charge energies and sxda cross points
45
+ sxda_single_charge_energies = {}
46
+ sxda_charge_energies = {}
47
+ sxda_cross_point_dicts = {}
48
+
49
+ for defect_dir in defect_paths:
50
+ # get defect type and charge from defect directory
51
+ defect = os.path.basename(os.path.dirname(defect_dir))
52
+ defect_type, defect_chg = '_'.join(defect.split('_')[0:2]), int(defect.split('_')[2])
53
+
54
+ # add defect type to single charge energies dictionary
55
+ if defect_type not in sxda_single_charge_energies:
56
+ sxda_single_charge_energies.update({defect_type: []})
57
+
58
+ # get defect.sxda filename
59
+ if 'FP' in defect_type:
60
+ if defect_chg > 0:
61
+ vac_chg, int_chg = chg_offset, defect_chg+chg_offset
62
+ elif defect_chg < 0:
63
+ vac_chg, int_chg = defect_chg-chg_offset, chg_offset
64
+ elif defect_chg == 0:
65
+ if float(chg_offset) == 0.:
66
+ vac_chg, int_chg = 0., 0.
67
+ else:
68
+ vac_chg, int_chg = -1*(chg_offset/2.), chg_offset/2.
69
+ else:
70
+ raise ValueError('Defect charge must be a valid number.')
71
+
72
+ sxda_outfile = os.path.join(defect_dir, f'{defect}_qv{vac_chg:.2f}qi{int_chg:.2f}.sxda')
73
+ else:
74
+ sxda_outfile = os.path.join(defect_dir, f'{defect}.sxda')
75
+
76
+ # compare first line of defect.sxda with defect type and charge
77
+ with open(sxda_outfile) as f:
78
+ sxda_lines = f.readlines()
79
+ title_line, correction_line = sxda_lines[0].strip('\n'), sxda_lines[-1]
80
+
81
+ # check if defect type is correct
82
+ sxda_defect_type, sxda_defect_chg = title_line.split(',')[0], int(title_line.split(',')[1].split(' = ')[1])
83
+ if (sxda_defect_type != defect_type) or (sxda_defect_chg != defect_chg):
84
+ raise ValueError('Defect type/charge does not match between pydefect and sxdefectalign')
85
+
86
+ # ensure correction line contains the correction and extract correction value
87
+ if 'correction' in correction_line:
88
+ sxda_corr = float(re.findall(r'\d[.,]?\d*', correction_line)[0])
89
+ else:
90
+ continue
91
+
92
+ bes = loadfn(os.path.join(defect_dir, 'band_edge_orbital_infos.json'))
93
+ fermi_level = bes.fermi_level - supercell_vbm
94
+
95
+ dei = DefectEnergyInfo.from_yaml(os.path.join(defect_dir, 'defect_energy_info.yaml'))
96
+ formation_en = dei.defect_energy.energy(with_correction=False)
97
+ formation_en_sxda = formation_en + sxda_corr
98
+
99
+ # add charge and formation energies to single charge energies dictionary
100
+ sxda_single_charge_energies[defect_type] += [(int(defect_chg), formation_en_sxda)]
101
+
102
+ for d_type in sxda_single_charge_energies:
103
+ sxda_charge_energies.update({d_type: SingleChargeEnergies(sxda_single_charge_energies[d_type])})
104
+ sxda_energies = ChargeEnergies(sxda_charge_energies, e_min=0., e_max=cbm)
105
+
106
+ sxda_cross_point_dicts = sxda_energies.cross_point_dicts
107
+
108
+ # create TransitionLevels object
109
+ sxda_tls = make_transition_levels(
110
+ cross_point_dicts=sxda_cross_point_dicts,
111
+ cbm=cbm,
112
+ supercell_vbm=supercell_vbm,
113
+ supercell_cbm=supercell_cbm
114
+ )
115
+
116
+ return sxda_tls
117
+
118
+
119
+ def atomic_potential_convergence(base_path=os.getcwd()):
120
+ """
121
+ Calculates the convergence for atomic site potential data from sxdefectalign
122
+ calculations in terms of averages and standard deviations within the sampling
123
+ region.
124
+ """
125
+ # defect directory
126
+ defect_path=os.path.join(base_path, 'defect')
127
+
128
+ # gather pydefect defect directories
129
+ defect_paths = glob.glob(os.path.join(defect_path, '*_*/'), recursive=True)
130
+
131
+ # empty dictionary for alignment averages and standard deviations
132
+ alignment_dict = {}
133
+
134
+ for defect_dir in defect_paths:
135
+ # get defect type and charge from defect directory
136
+ defect = os.path.basename(os.path.dirname(defect_dir))
137
+ defect_type, defect_chg = '_'.join(defect.split('_')[0:2]), int(defect.split('_')[2])
138
+
139
+ # use parse_sxda_vatoms on directory
140
+ vatoms = parse_sxda_vatoms(defect_dir)
141
+
142
+ # use lattice parameters for defect region radius or use pydefect correction.json file
143
+ if os.path.isfile(os.path.join(defect_dir, 'correction.json')):
144
+ correction_json = loadfn(os.path.join(defect_dir, 'correction.json'))
145
+ defect_region_radius = correction_json.defect_region_radius
146
+ else:
147
+ contcar_filepath = os.path.join(filepath, 'CONTCAR')
148
+ contcar = Poscar.from_file(contcar_filepath)
149
+ abc = np.array(contcar.structure.lattice.abc)
150
+ abc /= 2.
151
+ defect_region_radius = np.min(abc)
152
+
153
+ # alignment stats (mean, stdev) from atomic site potential dataframe with r>defect_region_radius
154
+ vatoms_total = pd.concat((vatoms[i] for i in vatoms.keys()))
155
+ vatoms_sample_region = vatoms_total.where(vatoms_total['r']>defect_region_radius)
156
+ alignment_average = vatoms_sample_region.loc[:, 'V_defect-V_ref-V_lr'].mean(skipna=True)
157
+ alignment_stdev = vatoms_sample_region.loc[:, 'V_defect-V_ref-V_lr'].std(skipna=True)
158
+
159
+ alignment_dict.update({defect: (alignment_average, alignment_stdev)})
160
+
161
+ return alignment_dict
162
+
@@ -0,0 +1,59 @@
1
+ """Parsing I/O for sxdefectalign calculations."""
2
+ import logging
3
+ from typing import TYPE_CHECKING, Optional
4
+ from io import StringIO
5
+
6
+ import os
7
+ import glob
8
+ from pathlib import Path
9
+ import json
10
+ from monty.serialization import dumpfn, loadfn
11
+ from monty.json import MSONable, MontyEncoder, MontyDecoder
12
+
13
+ import re
14
+ import pprint
15
+
16
+ import numpy as np
17
+ import pandas as pd
18
+
19
+
20
+ def parse_sxda_vatoms(filepath=os.getcwd()):
21
+ """
22
+ Parses sxdefectalign vAtoms.dat files.
23
+
24
+ potential terms sxdefectalign = pydefect
25
+ V(long-range) = V_{PC,q}
26
+ V(defect)-V(ref) = V_{q/b}
27
+ V(defect)-V(ref)-V(long-range) = dV_{PC,q/b}
28
+
29
+ vAtoms.dat format
30
+ r V(long-range) V(defect)-V(ref) V(defect)-V(ref)-V(long-range) x y z ...
31
+ empty lines between different species (need to include in plotting now)
32
+ with auto_sxda, empty lines are replaced with double empty lines to enable gnuplot index use
33
+ """
34
+ vatoms_filepath, contcar_filepath = os.path.join(filepath, 'vAtoms.dat'), os.path.join(filepath, 'CONTCAR')
35
+ contcar = Poscar.from_file(contcar_filepath)
36
+
37
+ vatoms_dict = {i.symbol:'' for i in contcar.structure.elements}
38
+
39
+ with open(vatoms_filepath, 'r') as va_dat:
40
+ va_dat_text = va_dat.read()
41
+
42
+ # find double line breaks in vatoms data file string
43
+ idx_split = [0]
44
+ idx_split += re.search(r'\n\n\n', va_dat_text).span()
45
+ idx_split.append(len(va_dat_text))
46
+
47
+ # create dataframes for each element's atomic site potentials
48
+ for i in range(int(len(idx_split)/2)):
49
+ atomic_site_type = contcar.structure.elements[i].symbol
50
+ vatoms_str = StringIO(va_dat_text[idx_split[2*i]:idx_split[2*i+1]].strip())
51
+ vatoms_arr = np.genfromtxt(vatoms_str)
52
+ vatoms_df = pd.DataFrame(
53
+ data=vatoms_arr,
54
+ columns=['r', 'V_lr', 'V_defect-V_ref', 'V_defect-V_ref-V_lr', 'x', 'y', 'z']
55
+ )
56
+ vatoms_dict.update({atomic_site_type:vatoms_df})
57
+
58
+ return vatoms_dict
59
+
@@ -0,0 +1,48 @@
1
+ Metadata-Version: 2.1
2
+ Name: raddefects
3
+ Version: 0.1.3
4
+ Summary: Framework to analyze properties of radiation-induced defects in semiconductor materials from first principles.
5
+ Author-email: Alexander Hauck <ash5615@psu.edu>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Alexander Hauck
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://radDefects.readthedocs.io/en/latest/
29
+ Project-URL: Repository, https://github.com/hauck-as/radDefects
30
+ Classifier: Programming Language :: Python :: 3
31
+ Classifier: License :: OSI Approved :: MIT License
32
+ Classifier: Operating System :: OS Independent
33
+ Requires-Python: >=3.6
34
+ Description-Content-Type: text/markdown
35
+ License-File: LICENSE
36
+ Requires-Dist: requests
37
+ Requires-Dist: importlib-metadata; python_version < "3.12"
38
+ Requires-Dist: numpy
39
+ Requires-Dist: pymatgen
40
+ Requires-Dist: mp-api
41
+ Requires-Dist: vise
42
+ Requires-Dist: pydefect
43
+ Requires-Dist: sumo
44
+ Requires-Dist: pymatgen-analysis-defects
45
+ Requires-Dist: niet
46
+
47
+ # radDefects
48
+ Framework to analyze properties of radiation-induced defects in semiconductor materials from first principles.
@@ -0,0 +1,17 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ docs/conf.py
5
+ raddefects/__init__.py
6
+ raddefects/core.py
7
+ raddefects.egg-info/PKG-INFO
8
+ raddefects.egg-info/SOURCES.txt
9
+ raddefects.egg-info/dependency_links.txt
10
+ raddefects.egg-info/entry_points.txt
11
+ raddefects.egg-info/requires.txt
12
+ raddefects.egg-info/top_level.txt
13
+ raddefects/analysis/transition_levels.py
14
+ raddefects/cli/__init__.py
15
+ raddefects/cli/main.py
16
+ raddefects/sxda/analysis.py
17
+ raddefects/sxda/io.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ cli-name = raddefects.cli.main:main
@@ -0,0 +1,12 @@
1
+ requests
2
+ numpy
3
+ pymatgen
4
+ mp-api
5
+ vise
6
+ pydefect
7
+ sumo
8
+ pymatgen-analysis-defects
9
+ niet
10
+
11
+ [:python_version < "3.12"]
12
+ importlib-metadata
@@ -0,0 +1,3 @@
1
+ dist
2
+ docs
3
+ raddefects
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+