├── DefAP_manual_1.pdf ├── ARCHIVE ├── DefAP2 │ ├── DefAP2_manual.pdf │ └── DefAP2_manual_addendum.pdf └── DefAP1 │ └── DefAP_manual_1.1.pdf ├── manual_v2_additions+changes.pdf ├── manual_v3_additions+changes.pdf ├── work_in_progress ├── __pycache__ │ ├── defap_misc.cpython-312.pyc │ ├── defap_defects.cpython-312.pyc │ ├── defap_input.cpython-312.pyc │ ├── defap_output.cpython-312.pyc │ ├── defap_tasks.cpython-312.pyc │ ├── defap_chem_pots.cpython-312.pyc │ └── thermodynamics.cpython-312.pyc ├── README ├── __init__.py ├── PuO2_example │ ├── PuO2.input │ └── PuO2_defects.csv ├── defap.py ├── defap_misc.py ├── thermodynamics.py ├── defap_chem_pots.py ├── defap_defects.py ├── defap_input.py └── defap_output.py ├── LICENSE ├── EXAMPLES ├── PuO2 │ ├── PuO2.defects │ ├── PuO2.input │ ├── PuO2.entropy │ └── PuO2.dos ├── Li2TiO3 │ ├── Li2TiO3.input │ └── Li2TiO3.defects ├── Si │ ├── Si.input │ └── Si.defects └── YBa2Cu3O7 │ ├── YBa2Cu3O7.input │ └── YBa2Cu3O7.defects ├── README.md └── .gitignore /DefAP_manual_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/DefAP_manual_1.pdf -------------------------------------------------------------------------------- /ARCHIVE/DefAP2/DefAP2_manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/ARCHIVE/DefAP2/DefAP2_manual.pdf -------------------------------------------------------------------------------- /manual_v2_additions+changes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/manual_v2_additions+changes.pdf -------------------------------------------------------------------------------- /manual_v3_additions+changes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/manual_v3_additions+changes.pdf -------------------------------------------------------------------------------- /ARCHIVE/DefAP1/DefAP_manual_1.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/ARCHIVE/DefAP1/DefAP_manual_1.1.pdf -------------------------------------------------------------------------------- /ARCHIVE/DefAP2/DefAP2_manual_addendum.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/ARCHIVE/DefAP2/DefAP2_manual_addendum.pdf -------------------------------------------------------------------------------- /work_in_progress/__pycache__/defap_misc.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/work_in_progress/__pycache__/defap_misc.cpython-312.pyc -------------------------------------------------------------------------------- /work_in_progress/__pycache__/defap_defects.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/work_in_progress/__pycache__/defap_defects.cpython-312.pyc -------------------------------------------------------------------------------- /work_in_progress/__pycache__/defap_input.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/work_in_progress/__pycache__/defap_input.cpython-312.pyc -------------------------------------------------------------------------------- /work_in_progress/__pycache__/defap_output.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/work_in_progress/__pycache__/defap_output.cpython-312.pyc -------------------------------------------------------------------------------- /work_in_progress/__pycache__/defap_tasks.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/work_in_progress/__pycache__/defap_tasks.cpython-312.pyc -------------------------------------------------------------------------------- /work_in_progress/__pycache__/defap_chem_pots.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/work_in_progress/__pycache__/defap_chem_pots.cpython-312.pyc -------------------------------------------------------------------------------- /work_in_progress/__pycache__/thermodynamics.cpython-312.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DefAP/defap/HEAD/work_in_progress/__pycache__/thermodynamics.cpython-312.pyc -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 DefAP 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. 22 | -------------------------------------------------------------------------------- /work_in_progress/README: -------------------------------------------------------------------------------- 1 | Required packages: 2 | 3 | numpy 4 | scipy 5 | pandas 6 | shapely 7 | pyromat 8 | decimal 9 | bisect 10 | matplotlib 11 | 12 | In PuO2_example folder, run using: 13 | python3 ../defap.py PuO2 14 | 15 | 16 | 17 | brouwer task produces "brouwer_output" directory 18 | brouwer diagram can be viewed in this directory by running: python3 plot_brouwer.py 19 | 20 | 21 | 22 | defect_phase task produces the "defect_phases_output" directory 23 | python3 plot_defect_phases_main.py plots the phase diagram that considers all defects, all dopants and all secondary phases 24 | python3 plot_defect_phases_{dopant}.py plots the phase diagram with defects and secondary phases associated with {dopant} only 25 | 26 | 27 | 28 | formation_energy task produces the "form_eng_output" directory if the host material has a bandgap 29 | python3 plot_formation_energies.py creates png files for each defect GROUP showing formation energies as a function of Fermi level for all charge states 30 | python3 plot_min_formation_energies.py creates png files for each defect GROUP showing the minimum formation energy as a function of the Fermi level 31 | 32 | if material has no bandgap, then a simple "form_engs.out" file is created that tabulates: 33 | {defect name} {formation energy} 34 | -------------------------------------------------------------------------------- /EXAMPLES/PuO2/PuO2.defects: -------------------------------------------------------------------------------- 1 | V_O V_O 2 1 2 -1157.59226632 0 0 1 2 | V_O V_O 2 1 1 -1148.01365139 0 0 1 3 | V_O V_O 2 1 0 -1138.73519286 0 0 1 4 | O_i O_i 1 3 -2 -1133.49066664 0 0 -1 5 | O_i O_i 1 3 -1 -1142.24481974 0 0 -1 6 | O_i O_i 1 3 0 -1150.57192243 0 0 -1 7 | V_{Pu} V_{Pu} 1 2 -4 -1083.77749370 0 1 0 8 | V_{Pu} V_{Pu} 1 2 -3 -1092.28217816 0 1 0 9 | V_{Pu} V_{Pu} 1 2 -2 -1100.50897741 0 1 0 10 | V_{Pu} V_{Pu} 1 2 -1 -1108.54946813 0 1 0 11 | V_{Pu} V_{Pu} 1 2 0 -1116.43194053 0 1 0 12 | Pu_i Pu_i 1 3 4 -1198.35420144 0 -1 0 13 | Pu_i Pu_i 1 3 3 -1190.06329067 0 -1 0 14 | Pu_i Pu_i 1 3 2 -1179.22286978 0 -1 0 15 | Pu_i Pu_i 1 3 1 -1170.91935973 0 -1 0 16 | Pu_i Pu_i 1 3 0 -1160.41800505 0 -1 0 17 | -------------------------------------------------------------------------------- /EXAMPLES/PuO2/PuO2.input: -------------------------------------------------------------------------------- 1 | Input file for the Defect Analysis Package 2 | 3 | #List of tasks to perform 4 | tasks : energy form_plots brouwer autodisplay 5 | 6 | #Independent variable for brouwer task 7 | loop = 0 8 | 9 | #Request for stoichiometry to be calculated and plotted 10 | Stoichiometry : 1 11 | 12 | #Range for defect diagram 13 | min_value = -40 14 | max_value = 0 15 | iterator = 0.5 16 | 17 | #Define the host properties 18 | Host : Pu-O_2 19 | Host_energy : -35.8748 eV 20 | Host_supercell : -1147.9941 eV 21 | E_VBM : 7.933220192 eV 22 | 23 | #Selection of method to calculate chemical potentials 24 | chem_pot_method : volatile 25 | #Request for oxygen to be treated as a real gas when calculating chemical potential temperature dependence 26 | real_gas = 1 27 | 28 | #Method selection for carrier concentrations 29 | Electron_method : Fermi-Dirac 30 | Hole_method : Fermi-Dirac 31 | 32 | #Limits of intergration for DOS file 33 | Valence_band_limits : -5.2 0 34 | Conduction_band_limits : 3.04 4.9 35 | 36 | #Constituents listed as required for 'volatile' chemical potential method 37 | Constituents 38 | O -1 39 | Pu-O_2 -35.8748 -16.56520623 -10.943 40 | 41 | #Fixed temperature (if temperature not the variable) 42 | Temperature = 1000 43 | 44 | #Define electronic properties. 45 | Bandgap : 3.04 eV 46 | 47 | #Entrop contribution selection 48 | entropy : 1 49 | entropy_units : 256 50 | 51 | #Method to calculate defect concentrations 52 | Defect_conc_method : Boltzmann 53 | 54 | #Plotting preferences 55 | min_y_range : -20 56 | 57 | -------------------------------------------------------------------------------- /EXAMPLES/Li2TiO3/Li2TiO3.input: -------------------------------------------------------------------------------- 1 | Input file for the Defect Analysis Package 2 | 3 | #List of tasks to perform 4 | tasks : energy form_plots brouwer group autodisplay 5 | 6 | #Independent variable for brouwer task 7 | loop = 0 8 | 9 | #Range for defect diagram 10 | min_value = -40 11 | max_value = 0 12 | iterator = 2 13 | 14 | #Define the host properties 15 | Host : Li_2-Ti-O_3 16 | Host_energy : -3326.97680 eV 17 | Host_supercell : -212926.4738576 18 | E_VBM : 6.32 eV 19 | 20 | #Selection of method to calculate chemical potentials 21 | chem_pot_method : volatile-rich-poor 22 | #Request for oxygen to be treated as a real gas when calculating chemical potential temperature dependence 23 | real_gas = 1 24 | 25 | #Method selection for carrier concentrations 26 | Electron_method : Boltzmann 27 | Hole_method : Boltzmann 28 | 29 | Valenceband : 147.2702 30 | Conductionband : 17.76023 31 | 32 | #Constituents listed as required for 'volatile-rich-poor' chemical potential method 33 | Constituents 34 | O 0 -20 35 | Li_2-O 1 -843.5319278 -201.0166555 -5.8158768 1 36 | Ti-O_2 1 -2482.17894 -1601.1944250 -9.218336 0 37 | 38 | #Fixed temperature (if temperature not the variable) 39 | Temperature = 1000 40 | 41 | #Define electronic properties. 42 | Bandgap : 3.27 eV 43 | 44 | #Corrections 45 | Coulombic_correction : 2 46 | Screened_Madelung : 0.00034559 47 | 48 | #Dopants 49 | Dopant_table : 2 50 | H H -17.8701 2 0.01 2.3 51 | He He -78.498 1 0.01 1.5 52 | 53 | #Method to calculate defect concentrations 54 | Defect_conc_method : Boltzmann 55 | 56 | #Plotting preferences 57 | min_y_range : -5 58 | 59 | -------------------------------------------------------------------------------- /EXAMPLES/Si/Si.input: -------------------------------------------------------------------------------- 1 | Input file for the Defect Analysis Package 2 | 3 | #List of tasks to perform 4 | tasks : energy form_plots brouwer autodisplay 5 | 6 | #Independent variable for brouwer task 7 | loop = 1 8 | 9 | #Range for defect diagram 10 | min_value = 100 11 | max_value = 500 12 | iterator = 20 13 | Charge_convergence : 0.00000000000000001 14 | 15 | #Define the host properties 16 | Host : Si 17 | Host_energy : -5.425776852 eV 18 | Host_supercell : -1171.9678 eV 19 | E_VBM : 5.56951365 eV 20 | 21 | #Selection of method to calculate chemical potentials 22 | chem_pot_method : defined 23 | 24 | #Method selection for carrier concentrations 25 | Electron_method : Effective_masses [[4.2,1.06],[50,1.06],[100,1.06],[150,1.07],[200,1.08],[250,1.08],[300,1.09],[350,1.10],[400,1.11],[450,1.12],[500,1.13]] 26 | Hole_method : Effective_masses [[4.2,0.59],[50,0.69],[100,0.83],[150,0.95],[200,1.03],[250,1.10],[300,1.15],[350,1.19],[400,1.23],[450,1.29],[500,1.29]] 27 | fu_unit_cell = 8 28 | Volume_unit_cell : 163.79786 29 | 30 | #Constituents listed as required for 'defined' chemical potential method 31 | Constituents 1 32 | Si -5.425776852 33 | 34 | #Fixed temperature (if temperature not the variable) 35 | Temperature = 273 36 | 37 | #Corrections 38 | Coulombic_correction : 1 39 | Length : 16.41 40 | Dielectric_constant : 11.9 41 | 42 | #Define electronic properties. 43 | Bandgap : 1.11 eV 44 | 45 | #Dopants 46 | Dopant_table : 1 47 | P P -5 2 4.9e-8 5 48 | 49 | #Method to calculate defect concentrations 50 | Defect_conc_method : Boltzmann 51 | 52 | #Plotting preferences 53 | min_y_range : -30 54 | 55 | -------------------------------------------------------------------------------- /EXAMPLES/PuO2/PuO2.entropy: -------------------------------------------------------------------------------- 1 | T host V_O V_O V_O O_i O_i O_i V_{Pu} V_{Pu} V_{Pu} V_{Pu} V_{Pu} Pu_i Pu_i Pu_i Pu_i Pu_i 2 | 400 0.215191 0.215238 0.215238 0.215238 0.215585 0.215585 0.215585 0.214865 0.214865 0.214865 0.214865 0.214865 0.215408 0.215408 0.215408 0.215408 0.215408 3 | 600 0.287153 0.287114 0.287114 0.287114 0.287616 0.287616 0.287616 0.286701 0.286701 0.286701 0.286701 0.286701 0.287421 0.287421 0.287421 0.287421 0.287421 4 | 800 0.34104 0.340934 0.340934 0.340934 0.341562 0.341562 0.341562 0.340505 0.340505 0.340505 0.340505 0.340505 0.341361 0.341361 0.341361 0.341361 0.341361 5 | 1000 0.383786 0.383625 0.383625 0.383625 0.384358 0.384358 0.384358 0.383188 0.383188 0.383188 0.383188 0.383188 0.384154 0.384154 0.384154 0.384154 0.384154 6 | 1200 0.419112 0.418906 0.418906 0.418906 0.419727 0.419727 0.419727 0.418465 0.418465 0.418465 0.418465 0.418465 0.419521 0.419521 0.419521 0.419521 0.419521 7 | 1400 0.449176 0.448931 0.448931 0.448931 0.449829 0.449829 0.449829 0.448487 0.448487 0.448487 0.448487 0.448487 0.449621 0.449621 0.449621 0.449621 0.449621 8 | 1600 0.475326 0.475047 0.475047 0.475047 0.476012 0.476012 0.476012 0.474602 0.474602 0.474602 0.474602 0.474602 0.475804 0.475804 0.475804 0.475804 0.475804 9 | 1800 0.498455 0.498147 0.498147 0.498147 0.499171 0.499171 0.499171 0.4977 0.4977 0.4977 0.4977 0.4977 0.498962 0.498962 0.498962 0.498962 0.498962 10 | 2000 0.519186 0.51885 0.51885 0.51885 0.519927 0.519927 0.519927 0.518403 0.518403 0.518403 0.518403 0.518403 0.519718 0.519718 0.519718 0.519718 0.519718 11 | -------------------------------------------------------------------------------- /work_in_progress/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "4" 2 | 3 | ##################################################### 4 | # # 5 | # Defect Analysis Package 4 # 6 | # # 7 | # by Samuel T. Murphy # 8 | # & William D. Neilson # 9 | # & Reece T. Bedford # 10 | # # 11 | ##################################################### 12 | # # 13 | # Script for exploring a material's defect # 14 | # chemistry, connecting the results of DFT # 15 | # calculations with bespoke, user-customised # 16 | # thermodynamics and processing operations that can # 17 | # be tailored to any defect-containing system of # 18 | # interest # 19 | # # 20 | # William D. Neilson, Reece T. Bedford and # 21 | # Samuel T. Murphy # 22 | # DefAP: A Python code for the analysis of point # 23 | # defects in crystalline solids, Computational # 24 | # Materials Science 210 (2022) 111434. # 25 | # # 26 | ##################################################### 27 | # # 28 | # Last updated : 30/04/2025 # 29 | # # 30 | ##################################################### 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## The Defect Analysis Package (DefAP) 2 | 3 | *Our newest update - defap_3.0 - is the reccomended and default version available in home directory. Legacy versions kept in archive. 4 | 5 | DefAP is a program developed to facilitate the exploration of a material's defect chemistry. A large number of features are provided and rapid exploration is supported through the use of autoplotting with carefully considered automatic data labelling and simplification options enabling production of publication quality plots. 6 | 7 | ## Installation 8 | 9 | DefAP is a Python (Python 3.6.9 tested) code that runs in a command-line interface using Linux (tested on Ubuntu 18.04.5 LTS) or MacOS (tested on MacOS 10.13.4). The following modules are required: 10 | - numpy 11 | - scipy 12 | - PYroMat 13 | 14 | A gnuplot installation is also required (tested with gnuplot v5.2) and, if using a Linux system and want to automatically view plots, a GV installation (tested with gv 3.7.4). 15 | 16 | ## Usage 17 | 18 | To operate DefAP, please consult the operating manual included in the software. 19 | 20 | DefAP_manual_1.pdf contains core operating instructions to perform most tasks. Additionally functionality recorded in v2 & v3 addendums. 21 | 22 | Additional information and description available at mmmg.co.uk/defap. 23 | 24 | ## Authors 25 | - William Neilson 26 | - Reece Bedford 27 | - Samuel Murphy 28 | 29 | For work produced using DefAP, please cite: 30 | 31 | William D. Neilson and Samuel T. Murphy, DefAP: A Python code for the analysis of point defects in crystalline solids, Computational Materials Science 210 (2022) 111434, https://doi.org/10.1016/j.commatsci.2022.111434 32 | 33 | ## Contact 34 | Questions, remarks and contributions should be addressed to wdneilson@lanl.gov and samuel.murphy@lancaster.ac.uk 35 | -------------------------------------------------------------------------------- /EXAMPLES/YBa2Cu3O7/YBa2Cu3O7.input: -------------------------------------------------------------------------------- 1 | Input file for the Defect Analysis Package 2 | 3 | #List of tasks to perform 4 | tasks : energy form_plots brouwer group stability autodisplay 5 | 6 | #Independent variable for brouwer task 7 | loop = 0 8 | 9 | #Request for stoichiometry to be calculated and plotted 10 | Stoichiometry : 1 11 | 12 | #Range for defect diagram 13 | min_value = -20 14 | max_value = 0 15 | iterator = 0.1 16 | 17 | #Define the host properties 18 | Host : Y-Ba_2-Cu_3-O_7 19 | Host_energy : -11259.08217828 eV 20 | Host_supercell : -180146.7988847 eV 21 | 22 | #Selection of method to calculate chemical potentials 23 | chem_pot_method : volatile-rich-poor 24 | #Request for oxygen to be treated as a real gas when calculating chemical potential temperature dependence 25 | real_gas = 1 26 | 27 | #Method selection for carrier concentrations 28 | Electron_method : Off 29 | Hole_method : Off 30 | 31 | #Constituents listed as required for 'volatile-rich-poor' chemical potential method 32 | Constituents 33 | O 2 -4.0 34 | Y_2-O_3 0.5 -3475.90880604 -1072.4301564025 -18.8278903456496 1 35 | Ba-O 2 -1470.908217608 -1028.2631771885 -5.39339793750324 1 36 | Cu_2-O 1.5 -3800.773619044 -1680.9293809865 -1.53288075866715 0 37 | 38 | #Fixed temperature (if temperature not the variable) 39 | Temperature = 700 40 | 41 | #Phase entry for stability task 42 | Stability_check : 10 43 | Y-Cu-O_2 -3638.343216 44 | Y-Cu_2-O_4 -6196.709592 45 | Ba-Cu_3-O_4 -7830.560771 46 | Y_2-Ba-O_4 -4946.912003 47 | Y_4-Ba_3-O_9 -11364.46251 48 | Ba-Cu -2709.325232 49 | Cu-Y -2753.812613 50 | Cu_5-Y -9478.189405 51 | Cu_2-Ba-O_2 -5272.176675 52 | Ba_2-Cu_3-O_6 -9740.77808 53 | 54 | #Method to calculate defect concentrations 55 | Defect_conc_method : Boltzmann 56 | 57 | #Plotting preferences 58 | min_y_range : -10 59 | x_variable = 1 60 | -------------------------------------------------------------------------------- /EXAMPLES/Si/Si.defects: -------------------------------------------------------------------------------- 1 | I_H I_H 0.5 1 0 -1173.760676 0 -1 0 2 | I_H I_H 0.5 1 -1 -1167.483616 0 -1 0 3 | I_H I_H 0.5 1 1 -1179.457968 0 -1 0 4 | I_H I_H 0.5 1 -2 -1161.164195 0 -1 0 5 | I_H I_H 0.5 1 2 -1185.057011 0 -1 0 6 | I_T I_T 0.5 2 0 -1173.71877 0 -1 0 7 | I_T I_T 0.5 2 -1 -1167.392007 0 -1 0 8 | I_T I_T 0.5 2 1 -1179.997435 0 -1 0 9 | I_T I_T 0.5 2 -2 -1161.028421 0 -1 0 10 | I_T I_T 0.5 2 2 -1186.201162 0 -1 0 11 | V_B V_B 1 3 0 -1162.613056 0 1 0 12 | V_B V_B 1 3 -1 -1156.904184 0 1 0 13 | V_B V_B 1 3 1 -1168.197932 0 1 0 14 | V_B V_B 1 3 -2 -1151.061439 0 1 0 15 | V_B V_B 1 3 2 -1173.702969 0 1 0 16 | V_L V_L 1 3 0 -1162.664813 0 1 0 17 | V_L V_L 1 3 -1 -1156.761042 0 1 0 18 | V_L V_L 1 3 1 -1168.455869 0 1 0 19 | V_L V_L 1 3 -2 -1150.783808 0 1 0 20 | V_L V_L 1 3 2 -1174.115446 0 1 0 21 | I_{110} I_{110} 1 3 0 -1173.815045 0 -1 0 22 | I_{110} I_{110} 1 3 -1 -1167.661133 0 -1 0 23 | I_{110} I_{110} 1 3 1 -1179.467984 0 -1 0 24 | I_{110} I_{110} 1 3 -2 -1161.384024 0 -1 0 25 | I_{110} I_{110} 1 3 2 -1185.041169 0 -1 0 26 | P_I_H P_I_H 0.5 1 0 -1174.185256 0 0 -1 27 | P_I_H P_I_H 0.5 1 -1 -1167.902067 0 0 -1 28 | P_I_H P_I_H 0.5 1 1 -1180.414438 0 0 -1 29 | P_I_H P_I_H 0.5 1 -2 -1161.55871 0 0 -1 30 | P_I_H P_I_H 0.5 1 2 -1186.029366 0 0 -1 31 | P_I_H P_I_H 0.5 1 3 -1191.561626 0 0 -1 32 | P_I_H P_I_H 0.5 1 -3 -1155.163421 0 0 -1 33 | P_I_T P_I_T 0.5 2 0 -1173.028445 0 0 -1 34 | P_I_T P_I_T 0.5 2 -1 -1166.809734 0 0 -1 35 | P_I_T P_I_T 0.5 2 1 -1179.151408 0 0 -1 36 | P_I_T P_I_T 0.5 2 -2 -1160.541576 0 0 -1 37 | P_I_T P_I_T 0.5 2 2 -1185.144134 0 0 -1 38 | P_I_T P_I_T 0.5 2 3 -1190.978616 0 0 -1 39 | P_I_T P_I_T 0.5 2 -3 -1154.231797 0 0 -1 40 | P_V_L P_V_L 1 3 0 -1171.720794 0 1 -1 41 | P_V_L P_V_L 1 3 -1 -1165.47509 0 1 -1 42 | P_V_L P_V_L 1 3 1 -1177.899353 0 1 -1 43 | P_V_L P_V_L 1 3 -2 -1159.15957 0 1 -1 44 | P_V_L P_V_L 1 3 2 -1183.482573 0 1 -1 45 | P_V_L P_V_L 1 3 3 -1188.983992 0 1 -1 46 | P_V_L P_V_L 1 3 -3 -1152.807077 0 1 -1 47 | P_I_{110} P_I_{110} 1 3 0 -1174.286262550 0 0 -1 48 | P_I_{110} P_I_{110} 1 3 -1 -1168.387960800 0 0 -1 49 | P_I_{110} P_I_{110} 1 3 1 -1180.154349800 0 0 -1 50 | P_I_{110} P_I_{110} 1 3 -2 -1162.132885840 0 0 -1 51 | P_I_{110} P_I_{110} 1 3 2 -1185.774137820 0 0 -1 52 | P_I_{110} P_I_{110} 1 3 -3 -1155.809444 0 0 -1 53 | P_I_{110} P_I_{110} 1 3 3 -1191.317498 0 0 -1 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /work_in_progress/PuO2_example/PuO2.input: -------------------------------------------------------------------------------- 1 | Input file for the Defect Analysis Package 2 | 3 | #List of tasks to perform 4 | tasks : formation_energy 5 | #tasks : brouwer group 6 | #tasks : defect_phases group 7 | 8 | # define independent variable to loop over, plotted on x-axis 9 | loop = 0 10 | min_value = -50 11 | max_value = 0 12 | iterator = 0.25 13 | 14 | # secondary loop for defect_phase task 15 | loop_y = 3 16 | min_value_y = -50 17 | max_value_y = 0 18 | iterator_y = 0.25 19 | 20 | # Define type of host lattice 21 | Host : Pu-O_2 22 | Host_energy_pfu : -36.606574 23 | Host_energy_supercell : -1171.4104 24 | 25 | # number of functional units in unit cell used to calculate density of states 26 | fu_unit_cell : 4 27 | 28 | # energy of valence band maximum 29 | E_VBM : 7.853 eV 30 | 31 | # Width of material band gap 32 | Bandgap : 2.232 33 | 34 | # method for calculation chemical potentials 35 | chem_pot_method : volatile 36 | 37 | # volatile chem pot method definition 38 | # Using MgO as a reference due to using DFT+U for Pu 39 | Constituents : 2 40 | O -20 41 | Mg-O -12.476 -1.731 -6.235 42 | 43 | #Al_2-O_3 -39.3451187 -4.111623 -17.455104167 44 | 45 | 46 | # method for calculation electron and hole concentrations 47 | Electron_method : Fermi-Dirac 48 | Hole_method : Fermi-Dirac 49 | 50 | # valence and condunction band limits for fermi-dirac method 51 | Valence_band_limits : -20 0 52 | Conduction_band_limits : 2.2 10 53 | 54 | # temperature of system 55 | Temperature = 800 56 | 57 | # how stoichiometry is calculated in a material containing a volatile element 58 | Stoichiometry : 1 59 | 60 | # specifiy whether volatile species is an ideal or real gas 61 | real_gas = 1 62 | 63 | # method for calculation defect concentrations 64 | Defect_conc_method : Boltzmann 65 | 66 | # Dopants 67 | # | Name | Reference | chem pot | fitting option | conc / log10(PP) | chem pot range (if fitting conc) | 68 | Dopants : 3 69 | Cl Cl -1.494 4 -4.7 70 | N N -8.272 0 -0.09691 71 | H H -3.175 0 -20 72 | 73 | ## fitting options ## 74 | # 0 = ignore dopant 75 | # 1 = fit concentration 76 | # 2 = loop over fitted dopant concentration 77 | # 3 = fixed partial pressure 78 | # 4 = loop over dopant partial pressure 79 | # 5 = fixed chemical potential 80 | 81 | secondary_phases : 2 82 | Pu-Cl_3 -31.3689 83 | Pu-O-Cl -32.5187 84 | #Cl_2 -2.988 true 85 | 86 | #secondary_phases : 1 87 | #Pu-N -27.967142 88 | #N_2 -16.544000 true 89 | #N_2-O -21.099600 true 90 | 91 | #secondary_phases : 2 92 | #Pu-H_2 -24.86122835 93 | #Pu-H_3 -28.50907221 94 | 95 | # Add tabulated correction energies in defecrs file to defect formation energies 96 | tab_correction : 1 97 | 98 | # brouwer axis 99 | #y_axis_max = 0 100 | y_axis_min = -15 101 | -------------------------------------------------------------------------------- /EXAMPLES/YBa2Cu3O7/YBa2Cu3O7.defects: -------------------------------------------------------------------------------- 1 | VO1 VO 1 1 0 -179708.0764651 0 0 0 0 1 2 | VO2 VO 2 2 0 -179707.4883567 0 0 0 0 1 3 | VO3 VO 2 3 0 -179707.3747857 0 0 0 0 1 4 | VO4 VO 2 4 0 -179708.2047789 0 0 0 0 1 5 | VCu1 VCu 1 5 0 -178463.7173744 0 0 0 1 0 6 | VCu2 VCu 2 6 0 -178464.1100308 0 0 0 1 0 7 | VY VY 1 7 0 -179063.4962678 0 1 0 0 0 8 | VBa VBa 2 8 0 -179111.3677412 0 0 1 0 0 9 | BaCu1 BaCu 1 5 0 -179495.6906767 0 0 -1 1 0 10 | BaCu2 BaCu 2 6 0 -179494.7583488 0 0 -1 1 0 11 | BaY BaY 1 7 0 -180098.2859778 0 1 -1 0 0 12 | YBa YBa 2 8 0 -180193.7735001 0 -1 1 0 0 13 | YCu1 YCu 1 5 0 -179543.2737403 0 -1 0 1 0 14 | YCu2 YCu 2 6 0 -179544.4701953 0 -1 0 1 0 15 | CuY CuY 1 7 0 -180745.7490491 0 1 0 -1 0 16 | CuBa CuBa 2 8 0 -180793.7701668 0 0 1 -1 0 17 | Oi1 Oi 1 9 0 -180582.3691329 0 0 0 0 -1 18 | Oi2 Oi 1 10 0 -180584.2526162 0 0 0 0 -1 19 | Oi3 Oi 2 11 0 -180582.2390010 0 0 0 0 -1 20 | Oi4 Oi 2 12 0 -180584.2397007 0 0 0 0 -1 21 | Oi6 Oi 1 13 0 -180584.3996242 0 0 0 0 -1 22 | Oi7 Oi 1 14 0 -180584.4052446 0 0 0 0 -1 23 | Oi8 Oi 1 15 0 -180584.4000015 0 0 0 0 -1 24 | Cui1 Cui 1 9 0 -181826.2097593 0 0 0 -1 0 25 | Cui2 Cui 1 10 0 -181825.1305439 0 0 0 -1 0 26 | Cui3 Cui 2 11 0 -181826.4006527 0 0 0 -1 0 27 | Cui4 Cui 2 12 0 -181825.9167257 0 0 0 -1 0 28 | Cui6 Cui 1 13 0 -181824.8214898 0 0 0 -1 0 29 | Cui7 Cui 1 14 0 -181825.2402183 0 0 0 -1 0 30 | Cui8 Cui 1 15 0 -181824.4568622 0 0 0 -1 0 31 | Yi1 Yi 1 9 0 -181219.5412616 0 -1 0 0 0 32 | Yi2 Yi 1 10 0 -181221.1681145 0 -1 0 0 0 33 | Yi3 Yi 2 11 0 -181220.8352723 0 -1 0 0 0 34 | Yi4 Yi 2 12 0 -181220.5439342 0 -1 0 0 0 35 | Yi6 Yi 1 14 0 -181220.8623155 0 -1 0 0 0 36 | Yi7 Yi 1 15 0 -181217.5786669 0 -1 0 0 0 37 | Yi8 Yi 1 16 0 -181216.2153392 0 -1 0 0 0 38 | Bai1 Bai 1 9 0 -181173.2156863 0 0 -1 0 0 39 | Bai2 Bai 1 10 0 -181174.5132686 0 0 -1 0 0 40 | Bai3 Bai 2 11 0 -181172.3278923 0 0 -1 0 0 41 | Bai4 Bai 2 12 0 -181174.5105867 0 0 -1 0 0 42 | Bai6 Bai 1 14 0 -181172.0016571 0 0 -1 0 0 43 | Bai7 Bai 1 15 0 -181171.1754351 0 0 -1 0 0 44 | Bai8 Bai 1 16 0 -181169.5158727 0 0 -1 0 0 45 | VO1_VO1 VO2 0.5 1 0 -179269.3987167 0 0 0 0 2 46 | VO1_VO1b VO2 0.5 1 0 -179269.7459703 0 0 0 0 2 47 | VO1_VO1c VO2 0.5 1 0 -179269.4664417 0 0 0 0 2 48 | VO1_VO1d VO2 0.5 1 0 -179269.4828949 0 0 0 0 2 49 | VO1_VO1e VO2 0.5 1 0 -179269.8498097 0 0 0 0 2 50 | VO4_VO4 VO2 0.5 4 0 -179269.2939937 0 0 0 0 2 51 | VO4_VO4b VO2 0.5 4 0 -179269.3932768 0 0 0 0 2 52 | VO4_VO4c VO2 0.5 4 0 -179269.4149566 0 0 0 0 2 53 | VO4_VO4d VO2 0.5 4 0 -179269.3449089 0 0 0 0 2 54 | VO1_VO4 VO2 0.5 1 0 -179269.0216352 0 0 0 0 2 55 | VO1_VO4b VO2 0.5 1 0 -179269.4265212 0 0 0 0 2 56 | VO1_VO4c VO2 0.5 1 0 -179269.7626806 0 0 0 0 2 57 | VO1_VO4d VO2 0.5 1 0 -179269.4584703 0 0 0 0 2 58 | VO1_VO4e VO2 0.5 1 0 -179269.4963445 0 0 0 0 2 59 | -------------------------------------------------------------------------------- /work_in_progress/defap.py: -------------------------------------------------------------------------------- 1 | import time 2 | import sys 3 | 4 | import defap_input 5 | from defap_tasks import Tasks 6 | import defap_misc 7 | from defap_output import write_output_file 8 | 9 | def main_wrapper(func): 10 | def wrapper(): 11 | start_time = time.time() 12 | 13 | print("+-------------------------------------------+") 14 | print("| ____ __ _ ____ |") 15 | print(r"| | _ \ ___ / _| / \ | _ \ _ __ _ _ |") 16 | print(r"| | | | |/ _ \ |_ / _ \ | |_) | '_ \| | | | |") 17 | print(r"| | |_| | __/ _/ ___ \| __/| |_) | |_| | |") 18 | print(r"| |____/ \___|_|/_/ \_\_| (_) .__/ \__, | |") 19 | print("| |_| |___/ |") 20 | print("| |") 21 | print("| Defect Analysis Package : 4.0 |") 22 | print("| https://github.com/DefAP |") 23 | print("+-------------------------------------------+") 24 | print("| |") 25 | print("| William D. Neilson |") 26 | print("| Reece T. Bedford |") 27 | print("| Samuel T. Murphy |") 28 | print("| |") 29 | print("+-------------------------------------------+\n") 30 | 31 | print( 32 | "For assistance, please contact the developers at:\n" 33 | "wneilson@lanl.gov\nr.t.bedford@lancaster.ac.uk\nsamuel.murphy@lancaster.ac.uk\n") 34 | 35 | func() 36 | 37 | end_time = time.time() 38 | 39 | print("\n>>> Tasks complete") 40 | 41 | execute_time = end_time - start_time 42 | 43 | time_format = time.strftime("%H hrs %M minutes %S seconds", time.gmtime(execute_time)) 44 | 45 | print(f">>> DefAP executed in {time_format}.") 46 | 47 | return wrapper 48 | 49 | 50 | @main_wrapper 51 | def main(): 52 | seedname = sys.argv[1] 53 | 54 | # initialise class to read input data 55 | data = defap_input.ReadInputData(seedname=seedname) 56 | 57 | # read external files for input data 58 | data.read_input_file() 59 | data.read_defects_file(data.host["elements"], data.dopants) 60 | data.read_dos_data() 61 | data.read_entropy_data() 62 | data.read_gibbs_data() 63 | 64 | # uncomment to see all input parameters defap has read 65 | #data.print_input_data(data.input_data) 66 | #data.print_input_data(data.defects_data) 67 | #data.print_input_data(data.dos_data) 68 | #data.print_input_data(data.entropy_data) 69 | #data.print_input_data(data.gibbs_data) 70 | #exit() 71 | 72 | # check errors on input data 73 | defap_misc.check_input_errors(data_input=data) 74 | 75 | 76 | # initialise writing of the output file 77 | write_output_file(input_data=data, 78 | seedname=seedname) 79 | 80 | 81 | # calculate screened madelung 82 | if "madelung" in data.tasks: 83 | Tasks(data=data, seedname=seedname).madelung() 84 | 85 | # run formation_energy task 86 | if "formation_energy" in data.tasks: 87 | Tasks(data=data, seedname=seedname).formation_energies() 88 | 89 | # run brouwer tasks 90 | if "brouwer" in data.tasks: 91 | Tasks(data=data, seedname=seedname).brouwer() 92 | 93 | # run defect_phases task 94 | if "defect_phases" in data.tasks: 95 | Tasks(data=data, seedname=seedname).defect_phases() 96 | 97 | 98 | if __name__ == "__main__": 99 | main() 100 | -------------------------------------------------------------------------------- /EXAMPLES/Li2TiO3/Li2TiO3.defects: -------------------------------------------------------------------------------- 1 | Ti_vac1 V_{Ti}-4 0.083333333 1 -4 -211284.4573 0 0 1 0 0 0 2 | Ti_vac1 V_{Ti}-3 0.083333333 1 -3 -211291.38 0 0 1 0 0 0 3 | Ti_vac1 V_{Ti}-2 0.083333333 1 -2 -211297.8956 0 0 1 0 0 0 4 | Ti_vac1 V_{Ti}-1 0.083333333 1 -1 -211304.6057 0 0 1 0 0 0 5 | Ti_vac1 V_{Ti}-0 0.083333333 1 0 -211310.8051 0 0 1 0 0 0 6 | Ti_vac2 V_{Ti}-4 0.083333333 1 -4 -211284.5062 0 0 1 0 0 0 7 | Ti_vac2 V_{Ti}-3 0.083333333 1 -3 -211291.4018 0 0 1 0 0 0 8 | Ti_vac2 V_{Ti}-2 0.083333333 1 -2 -211298.0501 0 0 1 0 0 0 9 | Ti_vac2 V_{Ti}-1 0.083333333 1 -1 -211304.616 0 0 1 0 0 0 10 | Ti_vac2 V_{Ti}-0 0.083333333 1 0 -211310.8789 0 0 1 0 0 0 11 | O_vac1 V_{O}+2 0.166666667 1 2 -212503.156 0 0 0 1 0 0 12 | O_vac1 V_{O}+1 0.166666667 1 1 -212494.0748 0 0 0 1 0 0 13 | O_vac1 V_{O}0 0.166666667 1 0 -212484.404 0 0 0 1 0 0 14 | O_vac2 V_{O}+2 0.166666667 1 2 -212503.1716 0 0 0 1 0 0 15 | O_vac2 V_{O}+1 0.166666667 1 1 -212494.0837 0 0 0 1 0 0 16 | O_vac2 V_{O}0 0.166666667 1 0 -212484.6626 0 0 0 1 0 0 17 | O_vac3 V_{O}+2 0.166666667 1 2 -212503.012 0 0 0 1 0 0 18 | O_vac3 V_{O}+1 0.166666667 1 1 -212493.7422 0 0 0 1 0 0 19 | O_vac3 V_{O}0 0.166666667 1 0 -212484.1968 0 0 0 1 0 0 20 | Li_vac1 V_{Li}-1 0.166666667 1 -1 -212714.411 0 1 0 0 0 0 21 | Li_vac1 V_{Li}0 0.166666667 1 0 -212720.6927 0 1 0 0 0 0 22 | Li_vac2 V_{Li}-1 0.083333333 1 -1 -212714.3679 0 1 0 0 0 0 23 | Li_vac2 V_{Li}0 0.083333333 1 0 -212720.6944 0 1 0 0 0 0 24 | Li_vac3 V_{Li}-1 0.083333333 1 -1 -212714.5116 0 1 0 0 0 0 25 | Li_vac3 V_{Li}0 0.083333333 1 0 -212720.8133 0 1 0 0 0 0 26 | Tili1 Ti_{Li}+3 0.166666667 1 3 -214353.8189 0 1 -1 0 0 0 27 | Tili1 Ti_{Li}+2 0.166666667 1 2 -214344.8647 0 1 -1 0 0 0 28 | Tili1 Ti_{Li}+1 0.166666667 1 1 -214335.6208 0 1 -1 0 0 0 29 | Tili1 Ti_{Li}+0 0.166666667 1 0 -214326.2273 0 1 -1 0 0 0 30 | Tili2 Ti_{Li}+3 0.083333333 1 3 -214353.8539 0 1 -1 0 0 0 31 | Tili2 Ti_{Li}+2 0.083333333 1 2 -214344.7885 0 1 -1 0 0 0 32 | Tili2 Ti_{Li}+1 0.083333333 1 1 -214335.4842 0 1 -1 0 0 0 33 | Tili2 Ti_{Li}+0 0.083333333 1 0 -214326.2294 0 1 -1 0 0 0 34 | Tili3 Ti_{Li}+3 0.083333333 1 3 -214353.6776 0 1 -1 0 0 0 35 | Tili3 Ti_{Li}+2 0.083333333 1 2 -214344.8371 0 1 -1 0 0 0 36 | Tili3 Ti_{Li}+1 0.083333333 1 1 -214335.5472 0 1 -1 0 0 0 37 | Tili3 Ti_{Li}+0 0.083333333 1 0 -214326.2588 0 1 -1 0 0 0 38 | LiTi1 Li_{Ti}-3 0.083333333 1 -3 -211497.2495 0 -1 1 0 0 0 39 | LiTi1 Li_{Ti}-2 0.083333333 1 -2 -211503.8854 0 -1 1 0 0 0 40 | LiTi1 Li_{Ti}-1 0.083333333 1 -1 -211510.1788 0 -1 1 0 0 0 41 | LiTi1 Li_{Ti}-0 0.083333333 1 0 -211516.3896 0 -1 1 0 0 0 42 | LiTi2 Li_{Ti}-3 0.083333333 1 -3 -211497.3277 0 -1 1 0 0 0 43 | LiTi2 Li_{Ti}-2 0.083333333 1 -2 -211503.7999 0 -1 1 0 0 0 44 | LiTi2 Li_{Ti}-1 0.083333333 1 -1 -211510.1551 0 -1 1 0 0 0 45 | LiTi2 Li_{Ti}-0 0.083333333 1 0 -211516.4011 0 -1 1 0 0 0 46 | Li_int1 Li_i+1 0.166666667 1 1 -213136.3969 0 -1 0 0 0 0 47 | Li_int1 Li_i0 0.166666667 1 0 -213126.8861 0 -1 0 0 0 0 48 | O_int1 O_i-2 0.166666667 1 -2 -213343.0164 0 0 0 -1 0 0 49 | O_int1 O_i-1 0.166666667 1 -1 -213351.3371 0 0 0 -1 0 0 50 | O_int1 O_i-0 0.166666667 1 0 -213360.4494 0 0 0 -1 0 0 51 | Ti_int1 Ti_i+4 0.166666667 1 4 -214561.2406 0 0 -1 0 0 0 52 | Ti_int1 Ti_i+3 0.166666667 1 3 -214552.2154 0 0 -1 0 0 0 53 | Ti_int1 Ti_i+2 0.166666667 1 2 -214543.0511 0 0 -1 0 0 0 54 | Ti_int1 Ti_i+1 0.166666667 1 1 -214533.6421 0 0 -1 0 0 0 55 | Ti_int1 Ti_i+0 0.166666667 1 0 -214524.1209 0 0 -1 0 0 0 56 | Li_int2 Li_i+1 0.166666667 1 1 -213136.6774 0 -1 0 0 0 0 57 | Li_int2 Li_i0 0.166666667 1 0 -213127.016 0 -1 0 0 0 0 58 | O_int2 O_i-2 0.166666667 1 -2 -213341.4404 0 0 0 -1 0 0 59 | O_int2 O_i-1 0.166666667 1 -1 -213351.0275 0 0 0 -1 0 0 60 | O_int2 O_i-0 0.166666667 1 0 -213360.577 0 0 0 -1 0 0 61 | H_Li1 H_{Li}0 0.166666667 1 0 -212739.1127 0 1 0 0 -1 0 62 | H_Li2 H_{Li}0 0.083333333 1 0 -212739.0904 0 1 0 0 -1 0 63 | H_Li3 H_{Li}0 0.083333333 1 0 -212739.1058 0 1 0 0 -1 0 64 | H_O1 H_{O}+2 0.166666667 1 2 -212517.3114 0 0 0 1 -1 0 65 | H_O1 H_{O}+1 0.166666667 1 1 -212511.1777 0 0 0 1 -1 0 66 | H_O1 H_{O}+0 0.166666667 1 0 -212501.7337 0 0 0 1 -1 0 67 | H_O1 H_{O}-1 0.166666667 1 -1 -212492.1868 0 0 0 1 -1 0 68 | H_O2 H_{O}+2 0.166666667 1 2 -212517.3161 0 0 0 1 -1 0 69 | H_O2 H_{O}+1 0.166666667 1 1 -212511.1603 0 0 0 1 -1 0 70 | H_O2 H_{O}+0 0.166666667 1 0 -212501.7214 0 0 0 1 -1 0 71 | H_O2 H_{O}-1 0.166666667 1 -1 -212492.1713 0 0 0 1 -1 0 72 | H_O3 H_{O}+2 0.166666667 1 2 -212517.211 0 0 0 1 -1 0 73 | H_O3 H_{O}+1 0.166666667 1 1 -212511.0545 0 0 0 1 -1 0 74 | H_O3 H_{O}+0 0.166666667 1 0 -212501.6061 0 0 0 1 -1 0 75 | H_O3 H_{O}-1 0.166666667 1 -1 -212492.0526 0 0 0 1 -1 0 76 | H_int1 H_i+1 0.166666667 1 1 -212950.4896 0 0 0 0 -1 0 77 | H_int2 H_i+1 0.166666667 1 1 -212950.4127 0 0 0 0 -1 0 78 | H_int3 H_i+1 0.166666667 1 1 -212950.3532 0 0 0 0 -1 0 79 | H_int4 H_i+1 0.166666667 1 1 -212950.3235 0 0 0 0 -1 0 80 | H_int5 H_i+1 0.166666667 1 1 -212950.4152 0 0 0 0 -1 0 81 | H_int6 H_i+1 0.166666667 1 1 -212950.4961 0 0 0 0 -1 0 82 | H_int7 H_i+1 0.166666667 1 1 -212950.2269 0 0 0 0 -1 0 83 | H_int1 H_i+0 0.166666667 1 0 -212940.9979 0 0 0 0 -1 0 84 | H_int2 H_i+0 0.166666667 1 0 -212940.9142 0 0 0 0 -1 0 85 | H_int3 H_i+0 0.166666667 1 0 -212940.8314 0 0 0 0 -1 0 86 | H_int4 H_i+0 0.166666667 1 0 -212940.8205 0 0 0 0 -1 0 87 | H_int5 H_i+0 0.166666667 1 0 -212940.907 0 0 0 0 -1 0 88 | H_int4 H_i-1 0.166666667 1 -1 -212930.9467 0 0 0 0 -1 0 89 | H_int5 H_i-1 0.166666667 1 -1 -212930.9628 0 0 0 0 -1 0 90 | H_int6 H_i-1 0.166666667 1 -1 -212930.2654 0 0 0 0 -1 0 91 | H_int7 H_i+0 0.166666667 1 0 -212940.7178 0 0 0 0 -1 0 92 | H_int6 H_i+0 0.166666667 1 0 -212940.9841 0 0 0 0 -1 0 93 | He_int1 He_i+0 0.166666667 1 0 -213002.779 0 0 0 0 0 -1 94 | He_int2 He_i+0 0.166666667 1 0 -213002.792 0 0 0 0 0 -1 95 | He_int3 He_i+0 0.166666667 1 0 -213003.3753 0 0 0 0 0 -1 96 | HeLi1 He_{Li}-1 0.166666667 1 -1 -212792.1436 0 1 0 0 0 -1 97 | HeLi2 He_{Li}-1 0.083333333 1 -1 -212792.1216 0 1 0 0 0 -1 98 | HeLi3 He_{Li}-1 0.083333333 1 -1 -212792.1865 0 1 0 0 0 -1 99 | HeLi1 He_{Li}0 0.166666667 1 0 -212798.4514 0 1 0 0 0 -1 100 | HeLi2 He_{Li}0 0.083333333 1 0 -212798.4211 0 1 0 0 0 -1 101 | HeLi3 He_{Li}0 0.083333333 1 0 -212798.4495 0 1 0 0 0 -1 102 | HeO1 He_{O}+2 0.166666667 1 2 -212581.4247 0 0 0 1 0 -1 103 | HeO2 He_{O}+2 0.166666667 1 2 -212581.4668 0 0 0 1 0 -1 104 | HeO3 He_{O}+2 0.166666667 1 2 -212581.2145 0 0 0 1 0 -1 105 | HeO1 He_{O}+1 0.166666667 1 1 -212572.0952 0 0 0 1 0 -1 106 | HeO2 He_{O}+1 0.166666667 1 1 -212572.0731 0 0 0 1 0 -1 107 | HeO3 He_{O}+1 0.166666667 1 1 -212571.8774 0 0 0 1 0 -1 108 | HeO1 He_{O}0 0.166666667 1 0 -212562.709 0 0 0 1 0 -1 109 | HeO2 He_{O}0 0.166666667 1 0 -212562.7244 0 0 0 1 0 -1 110 | HeO3 He_{O}0 0.166666667 1 0 -212562.4698 0 0 0 1 0 -1 111 | HeTi1 He_{Ti}-4 0.083333333 1 -4 -211361.8451 0 0 1 0 0 -1 112 | HeTi1 He_{Ti}-3 0.083333333 1 -3 -211368.7759 0 0 1 0 0 -1 113 | HeTi1 He_{Ti}-2 0.083333333 1 -2 -211375.538 0 0 1 0 0 -1 114 | HeTi1 He_{Ti}-1 0.083333333 1 -1 -211382.2244 0 0 1 0 0 -1 115 | HeTi1 He_{Ti}-0 0.083333333 1 0 -211388.457 0 0 1 0 0 -1 116 | HeTi2 He_{Ti}-4 0.083333333 1 -4 -211361.8426 0 0 1 0 0 -1 117 | HeTi2 He_{Ti}-3 0.083333333 1 -3 -211368.7743 0 0 1 0 0 -1 118 | HeTi2 He_{Ti}-2 0.083333333 1 -2 -211375.5895 0 0 1 0 0 -1 119 | HeTi2 He_{Ti}-1 0.083333333 1 -1 -211382.1875 0 0 1 0 0 -1 120 | HeTi2 He_{Ti}-0 0.083333333 1 0 -211388.4453 0 0 1 0 0 -1 121 | -------------------------------------------------------------------------------- /work_in_progress/PuO2_example/PuO2_defects.csv: -------------------------------------------------------------------------------- 1 | Defect_name,Defect_group,multiplicity,defect_site,Charge,energy,corrections,Pu,O,Cl,N,H 2 | V_{O}^{2+},V_{O},2,1,2,-1181.28239,0.247052964,0,1,0,0,0 3 | V_{O}^{1+},V_{O},2,1,1,-1171.818572,0.040669459,0,1,0,0,0 4 | V_{O}^{0},V_{O},2,1,0,-1162.327537,0,0,1,0,0,0 5 | O_{i}^{2-},O_i,1,3,-2,-1157.260222,0.214177024,0,-1,0,0,0 6 | O_{i}^{1-},O_i,1,3,-1,-1165.804939,0.036312893,0,-1,0,0,0 7 | O_{i}^{0},O_i,1,3,0,-1174.762041,0,0,-1,0,0,0 8 | V_{Pu}^{4-},V_{Pu},1,2,-4,-1109.365243,2.739655659,1,0,0,0,0 9 | V_{Pu}^{3-},V_{Pu},1,2,-3,-1117.066942,1.879992516,1,0,0,0,0 10 | V_{Pu}^{2-},V_{Pu},1,2,-2,-1124.944007,1.157021098,1,0,0,0,0 11 | V_{Pu}^{1-},V_{Pu},1,2,-1,-1132.746933,0.527530387,1,0,0,0,0 12 | V_{Pu}^{0},V_{Pu},1,2,0,-1140.387845,0,1,0,0,0,0 13 | Pu_{i}^{4+},Pu_{i},1,3,4,-1224.042665,2.329878257,-1,0,0,0,0 14 | Pu_{i}^{3+},Pu_{i},1,3,3,-1215.264937,1.516545197,-1,0,0,0,0 15 | Pu_{i}^{2+},Pu_{i},1,3,2,-1205.550005,0.852411545,-1,0,0,0,0 16 | Pu_{i}^{1+},Pu_{i},1,3,1,-1195.808846,0.347502489,-1,0,0,0,0 17 | Pu_{i}^{0},Pu_{i},1,3,0,-1185.976793,0,-1,0,0,0,0 18 | SD 001,SD,24,1,0,-1129.637666,0,1,2,0,0,0 19 | SD 011,SD,24,1,0,-1130.195058,0,1,2,0,0,0 20 | SD 111,SD,24,1,0,-1130.117713,0,1,2,0,0,0 21 | VO_VPu 2-,VO_Vpu,8,1,-2,-1119.822171,1.123395768,1,1,0,0,0 22 | VO_VPu 1-,VO_Vpu,8,1,-1,-1127.491779,0.5169621,1,1,0,0,0 23 | VO_VPu 0,VO_Vpu,8,1,0,-1135.253221,0,1,1,0,0,0 24 | VO_VO 4+,VO_VO,12,1,4,-1190.409038,0.930085988,0,2,0,0,0 25 | VO_VO 3+,VO_VO,12,1,3,-1181.144432,0.463176617,0,2,0,0,0 26 | VO_VO 2+,VO_VO,12,1,2,-1171.929837,0.137642691,0,2,0,0,0 27 | VO_VO 1+,VO_VO,12,1,1,-1162.558136,-0.010757068,0,2,0,0,0 28 | VO_VO 0,VO_VO,12,1,0,-1153.150215,0,0,2,0,0,0 29 | Cl_{O}^{2+},Cl_{O},2,1,2,-1181.84479,0.405716824,0,1,-1,0,0 30 | Cl_{O}^{1+},Cl_{O},2,1,1,-1173.951966,0.175164206,0,1,-1,0,0 31 | Cl_{O}^{0},Cl_{O},2,1,0,-1164.277202,0,0,1,-1,0,0 32 | Cl_{O}^{1-},Cl_{O},2,1,-1,-1154.579544,-0.00645937,0,1,-1,0,0 33 | Cl_{i}^{0},Cl_i,1,3,0,-1169.2663,0,0,0,-1,0,0 34 | Cl_{i}^{1-},Cl_i,1,3,-1,-1160.865309,-0.089537353,0,0,-1,0,0 35 | Cl_{Pu}^{5-},Cl_{Pu},1,2,-5,-1098.511391,2.629146946,1,0,-1,0,0 36 | Cl_{Pu}^{4-},Cl_{Pu},1,2,-4,-1108.444088,1.698763283,1,0,-1,0,0 37 | Cl_{Pu}^{3-},Cl_{Pu},1,2,-3,-1117.844805,1.398125628,1,0,-1,0,0 38 | Cl_{Pu}^{2-},Cl_{Pu},1,2,-2,-1126.347534,0.740367794,1,0,-1,0,0 39 | Cl_{Pu}^{1-},Cl_{Pu},1,2,-1,-1135.269989,0.267143876,1,0,-1,0,0 40 | Cl_{Pu}^{0},Cl_{Pu},1,2,0,-1143.271648,0,1,0,-1,0,0 41 | ClO:VO3+,ClO:VO,12,4,3,-1184.368574,0.840234362,0,2,-1,0,0 42 | ClO:VO2+,ClO:VO,12,4,2,-1174.871346,0.381336488,0,2,-1,0,0 43 | ClO:VO1+,ClO:VO,12,4,1,-1165.257661,0.1126063,0,2,-1,0,0 44 | ClO:VO0,ClO:VO,12,4,0,-1155.728048,0,0,2,-1,0,0 45 | ClO:VO1-,ClO:VO,12,4,-1,-1146.215477,0.045861938,0,2,-1,0,0 46 | ClO:Vpu4-,ClO:Vpu,8,4,-4,-1104.001839,2.316587264,1,1,-1,0,0 47 | ClO:Vpu3-,ClO:Vpu,8,4,-3,-1113.629979,1.534889162,1,1,-1,0,0 48 | ClO:Vpu2-,ClO:Vpu,8,4,-2,-1121.539613,0.919579913,1,1,-1,0,0 49 | ClO:Vpu1-,ClO:Vpu,8,4,-1,-1129.473913,0.41610266,1,1,-1,0,0 50 | ClO:Vpu0,ClO:Vpu,8,4,0,-1137.364345,0,1,1,-1,0,0 51 | SD_Cl (001) -1,SD_Cl (001),24,5,-1,-1124.533389,0.395832428,1,2,-1,0,0 52 | SD_Cl (001) 0,SD_Cl (001),24,5,0,-1132.432673,0,1,2,-1,0,0 53 | SD_Cl (001) 1,SD_Cl (001),24,5,1,-1140.241744,-0.31536522,1,2,-1,0,0 54 | SD_Cl (011) -1,SD_Cl (011),24,5,-1,-1124.260072,0.389795467,1,2,-1,0,0 55 | SD_Cl (011) 0,SD_Cl (011),24,5,0,-1132.186231,0,1,2,-1,0,0 56 | SD_Cl (011) 1,SD_Cl (011),24,5,1,-1140.025103,-0.32742134,1,2,-1,0,0 57 | SD_Cl (111) -1,SD_Cl (111),24,5,-1,-1124.230783,0.394857015,1,2,-1,0,0 58 | SD_Cl (111) 0,SD_Cl (111),24,5,0,-1132.090517,0,1,2,-1,0,0 59 | SD_Cl (111) 1,SD_Cl (111),24,5,1,-1139.950943,-0.308841363,1,2,-1,0,0 60 | N_{O}^{2+},N_{O},2,1,2,-1186.220332,0.262336824,0,1,0,-1,0 61 | N_{O}^{1+},N_{O},2,1,1,-1178.128279,0.06471308,0,1,0,-1,0 62 | N_{O}^{0},N_{O},2,1,0,-1169.793435,0,0,1,0,-1,0 63 | N_{O}^{1-},N_{O},2,1,-1,-1161.248095,0.087806207,0,1,0,-1,0 64 | N_{O}^{2-},N_{O},2,1,-2,-1151.533084,0.382343495,0,1,0,-1,0 65 | N_{O}^{3-},N_{O},2,1,-3,-1141.779008,0.853681777,0,1,0,-1,0 66 | N_{i}^{3+},N_i,1,3,3,-1201.395794,0.854181085,0,0,0,-1,0 67 | N_{i}^{2+},N_i,1,3,2,-1193.187214,0.418968286,0,0,0,-1,0 68 | N_{i}^{1+},N_i,1,3,1,-1184.718309,0.130591264,0,0,0,-1,0 69 | N_{i}^{0},N_i,1,3,0,-1175.130284,0,0,0,0,-1,0 70 | N_{i}^{1-},N_i,1,3,-1,-1166.058012,0.03464105,0,0,0,-1,0 71 | N_{i}^{2-},N_i,1,3,-2,-1156.263837,0.273796574,0,0,0,-1,0 72 | N_{i}^{3-},N_i,1,3,-3,-1146.321962,0.314574037,0,0,0,-1,0 73 | N_{Pu}^{3-},N_{Pu},1,2,-4,-1114.199449,2.28424929,1,0,0,-1,0 74 | N_{Pu}^{3-},N_{Pu},1,2,-3,-1123.459147,1.219038858,1,0,0,-1,0 75 | N_{Pu}^{2-},N_{Pu},1,2,-2,-1132.832935,0.923932305,1,0,0,-1,0 76 | N_{Pu}^{1-},N_{Pu},1,2,-1,-1141.854442,0.377589897,1,0,0,-1,0 77 | N_{Pu}^{0},N_{Pu},1,2,0,-1149.759759,0,1,0,0,-1,0 78 | N_{Pu}^{1+},N_{Pu},1,2,1,-1157.677498,-0.289719497,1,0,0,-1,0 79 | NO:VO2+,NO:VO,12,6,2,-1179.819968,0.211715363,0,2,0,-1,0 80 | NO:VO1+,NO:VO,12,6,1,-1171.381483,0.03341072,0,2,0,-1,0 81 | NO:VO0,NO:VO,12,6,0,-1161.904889,0,0,2,0,-1,0 82 | NO:VO1-,NO:VO,12,6,-1,-1152.406722,0.125584697,0,2,0,-1,0 83 | NO:VPu5-,NO:Vpu,8,5,-5,-1098.984596,3.846965348,1,1,0,-1,0 84 | NO:VPu4-,NO:Vpu,8,5,-4,-1107.752696,2.729585649,1,1,0,-1,0 85 | NO:VPu3-,NO:Vpu,8,5,-3,-1116.079276,1.813310722,1,1,0,-1,0 86 | NO:VPu2-,NO:Vpu,8,5,-2,-1124.095774,1.06330632,1,1,0,-1,0 87 | NO:VPu1-,NO:Vpu,8,5,-1,-1131.89781,0.488966584,1,1,0,-1,0 88 | NO:VPu0,NO:Vpu,8,5,0,-1139.597791,0,1,1,0,-1,0 89 | SD_N (001) -3,SD_N (001),24,4,-3,-1109.617524,1.952811129,1,2,0,-1,0 90 | SD_N (001) -2,SD_N (001),24,4,-2,-1118.195056,1.146628129,1,2,0,-1,0 91 | SD_N (001) -1,SD_N (001),24,4,-1,-1126.418702,0.50458246,1,2,0,-1,0 92 | SD_N (001) 0,SD_N (001),24,4,0,-1134.14782,0,1,2,0,-1,0 93 | SD_N (011) -3,SD_N (011),24,4,-3,-1109.467559,1.94073315,1,2,0,-1,0 94 | SD_N (011) -2,SD_N (011),24,4,-2,-1118.212835,1.118768205,1,2,0,-1,0 95 | SD_N (011) -1,SD_N (011),24,4,-1,-1126.539699,0.483136873,1,2,0,-1,0 96 | SD_N (011) 0,SD_N (011),24,4,0,-1134.472337,0,1,2,0,-1,0 97 | SD_N (111) -3,SD_N (111),8,4,-3,-1109.42348,1.887736722,1,2,0,-1,0 98 | SD_N (111) -2,SD_N (111),8,4,-2,-1118.245331,1.118768205,1,2,0,-1,0 99 | SD_N (111) -1,SD_N (111),8,4,-1,-1126.519141,0.483136873,1,2,0,-1,0 100 | SD_N (111) 0,SD_N (111),8,4,0,-1134.492518,0,1,2,0,-1,0 101 | H_{O}^{2+},H_{O},2,1,2,-1183.322252,0.195398894,0,1,0,0,-1 102 | H_{O}^{1+},H_{O},2,1,1,-1175.495344,0.052986941,0,1,0,0,-1 103 | H_{O}^{0},H_{O},2,1,0,-1165.909425,0,0,1,0,0,-1 104 | H_{O}^{1-},H_{O},2,1,-1,-1156.32827,0.122838039,0,1,0,0,-1 105 | H_{i}^{1+},H_i,1,3,1,-1183.20499,0.105690135,0,0,0,0,-1 106 | H_{i}^{0},H_i,1,3,0,-1173.604463,0,0,0,0,0,-1 107 | H_{i}^{1-},H_i,1,3,-1,-1163.906179,0.063352928,0,0,0,0,-1 108 | H_{Pu}^{4-},H_{Pu},1,3,-4,-1113.610999,2.328308641,1,0,0,0,-1 109 | H_{Pu}^{3-},H_{Pu},1,3,-3,-1122.890728,1.703547398,1,0,0,0,-1 110 | H_{Pu}^{2-},H_{Pu},1,3,-2,-1130.60016,1.029093608,1,0,0,0,-1 111 | H_{Pu}^{1-},H_{Pu},1,3,-1,-1138.481405,0.467464347,1,0,0,0,-1 112 | H_{Pu}^{0},H_{Pu},1,3,0,-1146.289842,0,1,0,0,0,-1 113 | H_{Pu}^{1+},H_{Pu},1,3,1,-1153.954138,-0.367722841,1,0,0,0,-1 114 | HO:VO1-,HO:VO,12,4,-1,-1147.423778,0.158527139,0,2,0,0,-1 115 | HO:VO0,HO:VO,12,4,0,-1156.872361,0,0,2,0,0,-1 116 | HO:VO1+,HO:VO,12,4,1,-1166.345867,-0.014792012,0,2,0,0,-1 117 | HO:VO2+,HO:VO,12,4,2,-1175.513748,0.167428539,0,2,0,0,-1 118 | HO:VO3+,HO:VO,12,4,3,-1184.902763,0.494448409,0,2,0,0,-1 119 | HO:Vpu4-,HO:Vpu,8,4,-4,-1104.288233,2.783605777,1,1,0,0,-1 120 | HO:Vpu3-,HO:Vpu,8,4,-3,-1113.761918,1.906994695,1,1,0,0,-1 121 | HO:Vpu2-,HO:Vpu,8,4,-2,-1121.543254,1.129429679,1,1,0,0,-1 122 | HO:Vpu1-,HO:Vpu,8,4,-1,-1129.320598,0.508463452,1,1,0,0,-1 123 | HO:Vpu0,HO:Vpu,8,4,0,-1137.024856,0,1,1,0,0,-1 124 | SD_HO (001) -1,SD_HO (001),24,5,-1,-1123.805851,0.512611031,1,2,0,0,-1 125 | SD_HO (001) 0,SD_HO (001),24,5,0,-1131.552819,0,1,2,0,0,-1 126 | SD_HO (001) 1,SD_HO (001),24,5,1,-1139.19066,-0.430843408,1,2,0,0,-1 127 | SD_HO (011) -1,SD_HO (011),24,5,-1,-1124.146359,0.495886677,1,2,0,0,-1 128 | SD_HO (011) 0,SD_HO (011),24,5,0,-1131.859447,0,1,2,0,0,-1 129 | SD_HO (011) 1,SD_HO (011),24,5,1,-1139.547612,-0.421418424,1,2,0,0,-1 130 | SD_HO (111) -1,SD_HO (111),24,5,-1,-1124.088259,0.50578449,1,2,0,0,-1 131 | SD_HO (111) 0,SD_HO (111),24,5,0,-1131.871803,0,1,2,0,0,-1 132 | SD_HO (111) 1,SD_HO (111),24,5,1,-1139.488051,-0.399097121,1,2,0,0,-1 133 | SD_Hi (001) -1,SD_Hi 0(01),24,5,-1,-1125.09039,0.486783532,1,2,0,0,-1 134 | SD_Hi (001) 0,SD_Hi (001),24,5,0,-1134.079065,0,1,2,0,0,-1 135 | SD_Hi (001) 1,SD_Hi (001),24,5,1,-1142.946401,-0.333930372,1,2,0,0,-1 136 | SD_Hi (011) -1,SD_Hi (011),24,5,-1,-1125.308997,0.481950738,1,2,0,0,-1 137 | SD_Hi (011) 0,SD_Hi (011),24,5,0,-1134.347075,0,1,2,0,0,-1 138 | SD_Hi (011) 1,SD_Hi (011),24,5,1,-1143.299458,-0.331021367,1,2,0,0,-1 139 | SD_Hi (111) -1,SD_Hi (111),24,5,-1,-1125.146838,0.476804016,1,2,0,0,-1 140 | SD_Hi (111) 0,SD_Hi (111),24,5,0,-1134.373638,0,1,2,0,0,-1 141 | SD_Hi (111) 1,SD_Hi (111),24,5,1,-1143.383468,-0.341648507,1,2,0,0,-1 -------------------------------------------------------------------------------- /work_in_progress/defap_misc.py: -------------------------------------------------------------------------------- 1 | from bisect import bisect_left 2 | 3 | 4 | def format_constituents(constituents_lst, chemical_potential_method): 5 | 6 | """ 7 | Function that formats the constituents into dictionaries that are more readable and can access 8 | variables with less loops. Formats based on the chemical potential method 9 | :param constituents_lst: 10 | :param chemical_potential_method: 11 | :return: all_constituents_dic 12 | """ 13 | 14 | all_constituents_dic = {"volatile": None, 15 | "compound": None, 16 | "constituent_compounds": None 17 | } 18 | 19 | total_rich_poor_fraction = 0 20 | 21 | # loop through list of constituents 22 | for constituent_index, constituent in enumerate(constituents_lst): 23 | individual_constituents_dic = {} 24 | 25 | if chemical_potential_method == "defined": 26 | 27 | # simple assign defined species with its dft energy 28 | individual_constituents_dic["elements"] = break_formula(constituent[0]) 29 | individual_constituents_dic["dft_energy_pfu"] = float(constituent[1]) 30 | 31 | if all_constituents_dic["constituent_compounds"] is None: 32 | all_constituents_dic["constituent_compounds"] = {} 33 | 34 | all_constituents_dic["constituent_compounds"][constituent[0]] = individual_constituents_dic 35 | 36 | elif chemical_potential_method == "rich-poor": 37 | 38 | # assign dft energy and rich-poor fraction for this specie to a dict 39 | individual_constituents_dic["elements"] = break_formula(constituent[0]) 40 | individual_constituents_dic["dft_energy_pfu"] = float(constituent[1]) 41 | individual_constituents_dic["fraction"] = float(constituent[2]) 42 | 43 | # check total rich-poor fraction is not exceeded 44 | total_rich_poor_fraction += individual_constituents_dic["fraction"] 45 | if total_rich_poor_fraction > len(constituents_lst) - 1: 46 | raise Exception("ERROR Sum of constituent rich-poor fractions too large for the number of constituents provided.\n" 47 | f"Max sum of fractions: {len(constituents_lst) - 1}\n" 48 | f"Total sum of fractions specified: {total_rich_poor_fraction}") 49 | 50 | # add specie to the dict for all constituents 51 | if all_constituents_dic["constituent_compounds"] is None: 52 | all_constituents_dic["constituent_compounds"] = {} 53 | all_constituents_dic["constituent_compounds"][constituent[0]] = individual_constituents_dic 54 | else: 55 | all_constituents_dic["constituent_compounds"][constituent[0]] = individual_constituents_dic 56 | 57 | all_constituents_dic["total_fraction"] = total_rich_poor_fraction 58 | 59 | elif chemical_potential_method == "volatile" or chemical_potential_method == "volatile-reference": 60 | # first constituent is always the volatile specie 61 | if constituent_index == 0: 62 | individual_constituents_dic["volatile_element"] = constituent[0] 63 | individual_constituents_dic["log_pp"] = float(constituent[1]) 64 | all_constituents_dic["volatile"] = individual_constituents_dic 65 | 66 | else: 67 | individual_constituents_dic["formula"] = constituent[0] 68 | individual_constituents_dic["elements"] = break_formula(constituent[0]) 69 | individual_constituents_dic["compound_energy_pfu"] = float(constituent[1]) 70 | individual_constituents_dic["metal_energy_pfu"] = float(constituent[2]) 71 | individual_constituents_dic["std_formation_energy"] = float(constituent[3]) 72 | all_constituents_dic["compound"] = individual_constituents_dic 73 | 74 | elif chemical_potential_method == "volatile-rich-poor": 75 | if constituent_index == 0: 76 | individual_constituents_dic["volatile_element"] = constituent[0] 77 | individual_constituents_dic["coefficient"] = float(constituent[1]) 78 | individual_constituents_dic["log_pp"] = float(constituent[2]) 79 | all_constituents_dic["volatile"] = individual_constituents_dic 80 | 81 | else: 82 | individual_constituents_dic["elements"] = break_formula(constituent[0]) 83 | individual_constituents_dic["coefficient"] = float(constituent[1]) 84 | individual_constituents_dic["compound_energy_pfu"] = float(constituent[2]) 85 | individual_constituents_dic["metal_energy_pfu"] = float(constituent[3]) 86 | individual_constituents_dic["std_formation_energy"] = float(constituent[4]) 87 | individual_constituents_dic["fraction"] = float(constituent[5]) 88 | 89 | total_rich_poor_fraction += individual_constituents_dic["fraction"] 90 | if total_rich_poor_fraction > len(constituents_lst) - 2: # -2 to account for the volatile in the list 91 | raise Exception( 92 | "ERROR Sum of constituent rich-poor fractions too large for the number of constituents provided.\n" 93 | f"Max sum of fractions: {len(constituents_lst) - 2}\n" 94 | f"Total sum of fractions specified: {total_rich_poor_fraction}") 95 | 96 | if all_constituents_dic["constituent_compounds"] is None: 97 | all_constituents_dic["constituent_compounds"] = {} 98 | all_constituents_dic["constituent_compounds"][constituent[0]] = individual_constituents_dic 99 | else: 100 | all_constituents_dic["constituent_compounds"][constituent[0]] = individual_constituents_dic 101 | 102 | all_constituents_dic["total_fraction"] = total_rich_poor_fraction 103 | 104 | else: 105 | raise Exception("ERROR Invalid method for calculating chemical potentials.\n" 106 | f"Your input: {chemical_potential_method}") 107 | 108 | return all_constituents_dic 109 | 110 | 111 | def format_dopants(dopants_lst): 112 | 113 | """ 114 | Function that formats the list of dopants provided 115 | :param dopants_lst: 116 | :return: all_dopants_dict 117 | """ 118 | 119 | dopants_dict = {} 120 | dopants_to_fit = 0 121 | dopants_to_loop_conc = 0 122 | dopants_to_loop_press = 0 123 | 124 | 125 | for dopant_index, dopant in enumerate(dopants_lst): 126 | 127 | individual_dopant_dict = {"reference": dopant[1], 128 | "reference_elements": break_formula(dopant[1]), 129 | "chemical_potential": float(dopant[2]), 130 | "fitting_option": int(dopant[3]), 131 | } 132 | 133 | # fitting concentration 134 | if int(dopant[3]) == 1 or int(dopant[3]) == 2: 135 | individual_dopant_dict["concentration_pfu"] = float(dopant[4]) 136 | individual_dopant_dict["chem_pot_range"] = float(dopant[5]) 137 | dopants_to_fit += 1 138 | 139 | if int(dopant[3]) == 2: 140 | dopants_to_loop_conc += 1 141 | 142 | # calc chem pot from partial pressure 143 | elif int(dopant[3]) == 3 or int(dopant[3]) == 4: 144 | individual_dopant_dict["log_PP_atm"] = float(dopant[4]) 145 | 146 | # count number of dopant partial pressures being looped over for defect phase task 147 | if int(dopant[3]) == 4: 148 | dopants_to_loop_press += 1 149 | 150 | elif int(dopant[3]) == 0 or int(dopant[3]) == 5: 151 | pass 152 | 153 | else: 154 | raise Exception(f"ERROR Invalid fitting option for {dopant[0]} dopant!") 155 | 156 | 157 | if (dopants_to_loop_conc + dopants_to_loop_press) > 2: 158 | raise ValueError("ERROR Can't loop over more than 2 dopants at once!") 159 | 160 | dopants_dict[dopant[0]] = individual_dopant_dict 161 | 162 | return dopants_dict, dopants_to_fit 163 | 164 | 165 | def format_secondary_phases(phases_lst): 166 | 167 | phases_dict = {} 168 | 169 | for phase in phases_lst: 170 | num_phases_vals = len(phase) 171 | 172 | phases_dict[phase[0]] = {"elements": break_formula(phase[0]), 173 | "energy": float(phase[1]), 174 | "add_temperature_contribution": False, 175 | "use_gibbs_energy": False, 176 | } 177 | 178 | if num_phases_vals > 2: 179 | 180 | if phase[2].lower() == "true" or phase[2].lower() == "t": 181 | phases_dict[phase[0]]["add_temperature_contribution"] = True 182 | 183 | elif phase[2].lower() == "gibbs_true": 184 | phases_dict[phase[0]]["use_gibbs_energy"] = True 185 | 186 | return phases_dict 187 | 188 | 189 | def break_formula(formula): 190 | """ 191 | Function that takes a chemical formula and breaks it down into a dictionary containing constituent elements 192 | and stoichiometries 193 | """ 194 | 195 | # break formula into a dictionary of {"Element" : stoichiometry} 196 | constituent_formula_breakdown = {} 197 | 198 | # Split the constituent species by the hyphen 199 | split_formula = formula.split('-') 200 | 201 | # loop through species in the formula 202 | for species in split_formula: 203 | # split species into element and its stoichiometry 204 | split_stoichiometry = species.split("_") 205 | 206 | if len(split_stoichiometry) == 2: 207 | element, stoichiometry = split_stoichiometry[0], int(split_stoichiometry[1]) 208 | else: 209 | # stoichiometry is 1 if no "_value" provided 210 | element, stoichiometry = split_stoichiometry[0], 1 211 | 212 | # add species and stoich to dictionary 213 | constituent_formula_breakdown[element] = stoichiometry 214 | 215 | return constituent_formula_breakdown 216 | 217 | 218 | def check_input_errors(data_input): 219 | 220 | # check entropy data has been provided if needed 221 | if data_input.entropy_data is None and data_input.entropy == 1: 222 | print("\n>>> WARNING <<<\nInclusion of vibrational entropy specified in the input file (entropy : 1)\n" 223 | "However, no entropy data has been provided!\n" 224 | "Switching vibrational entropy off (entropy = 0)") 225 | 226 | # if not, switch off 227 | data_input.entropy = 0 228 | 229 | # check that functional units have been provided for entropy inclusion 230 | if data_input.entropy == 1 and data_input.entropy_units is None: 231 | raise ValueError("\n ERROR\nInclusion of vibrational entropy specified in the input file (entropy : 1)\n" 232 | "However, the number of functional units used to calculate entropy contribution has not been" 233 | " specified! (entropy_units)\n" 234 | "Please specify 'entropy_units : (int)' tag\n") 235 | 236 | # check gibbs data has been provided if needed 237 | if data_input.gibbs_data is None and data_input.include_gibbs == 1: 238 | print("\n>>> WARNING <<<\nInclusion of Gibbs temperature dependant energy contributions specified in the" 239 | " input file (gibbs : 1)\n" 240 | "However, no Gibbs energy data has been provided!\n" 241 | "Switching Gibbs energy contributions off (gibbs = 0)") 242 | 243 | # switch off it no data 244 | data_input.include_gibbs = 0 245 | 246 | # check dos data has been provided for fermi-dirac statistics 247 | if data_input.dos_data is None: 248 | if data_input.electron_method == "fermi-dirac" or data_input.hole_method == "fermi-dirac": 249 | raise ValueError("\n ERROR\nFermi-Dirac method for calculating charge carrier concentrations requires " 250 | "material density of states.\n" 251 | "No density of state data has been provided!\n" 252 | "Please provide a 'filename.dos' file\n") 253 | 254 | # check that defect data has been provided 255 | if data_input.defects_data is None: 256 | raise ValueError("\n ERROR\n" 257 | "Using the Defect Analysis Package with no defects provided!?!?! Madness!\n" 258 | "Jokes aside... Have you provide a 'filename.defects' or 'filename_defects.csv' file?\n") 259 | 260 | 261 | def take_closest(myList, myNumber): 262 | """ 263 | For bisecting DOS energy list to determine index of VBM and CBM 264 | """ 265 | 266 | pos = bisect_left(myList, myNumber) 267 | if pos == 0: 268 | return myList[0] 269 | if pos == len(myList): 270 | return myList[-1] 271 | 272 | before = myList[pos - 1] 273 | after = myList[pos] 274 | 275 | if after - myNumber < myNumber - before: 276 | return after 277 | else: 278 | return before 279 | 280 | 281 | -------------------------------------------------------------------------------- /work_in_progress/thermodynamics.py: -------------------------------------------------------------------------------- 1 | import math 2 | from defap_misc import break_formula 3 | import pyromat as pm 4 | from scipy import interpolate 5 | 6 | def calc_pressure_contribution(volatile_PP: float, 7 | temperature: float 8 | ): 9 | std_pressure_atm = 1 10 | boltzmann = 0.000086173324 11 | 12 | # Change partial pressure from a log to atm 13 | partial_pressure_atm = 10 ** volatile_PP 14 | pressure_cont = (1 / 2) * boltzmann * temperature * math.log(partial_pressure_atm / std_pressure_atm) 15 | 16 | return pressure_cont 17 | 18 | 19 | def calc_temperature_contribution(gas_species: str, 20 | temperature: float, 21 | real_gas: int 22 | ): 23 | 24 | std_temp = 298.15 25 | 26 | # ideal gas 27 | if real_gas == 0: 28 | 29 | volatile_entropy, volatile_Cp = gas_thermo_values(gas_species, temperature, real_gas) 30 | 31 | temp_cont = -(volatile_entropy - volatile_Cp) * (temperature - std_temp) + volatile_Cp * temperature * math.log(temperature / std_temp) 32 | return temp_cont 33 | 34 | # real gas relations 35 | elif real_gas == 1 or real_gas == 2: 36 | 37 | shomate_coefficients = gas_thermo_values(gas_species, temperature, real_gas) 38 | 39 | gibbs_std = calc_volatile_gibbs_free_energy(std_temp, real_gas, **shomate_coefficients) 40 | gibbs = calc_volatile_gibbs_free_energy(temperature, real_gas, **shomate_coefficients) 41 | 42 | temp_cont = gibbs - gibbs_std 43 | return temp_cont 44 | 45 | # pyromat library 46 | elif real_gas == 3: 47 | 48 | # min temperature for many species is 300 K, so this is set as std temp 49 | std_temp = 300 50 | 51 | # define units 52 | pm.config['unit_energy'] = "eV" 53 | pm.config["unit_temperature"] = "K" 54 | pm.config["unit_matter"] = "n" 55 | 56 | molecular_vol_species_list = ["H", "N", "O", "Cl", "F"] 57 | 58 | # ensure constituent volatile species is defined properly for pyromat 59 | if gas_species in molecular_vol_species_list: 60 | gas_species += "_2" 61 | 62 | elif gas_species == "D" or gas_species == "T": 63 | gas_species = "H_2" 64 | 65 | # break formula of gas molecule 66 | gas_array = break_formula(gas_species) 67 | 68 | # create string input for pyromat libray 69 | pyromat_input = "ig." 70 | for element, stoic in gas_array.items(): 71 | if stoic == 1: 72 | str = element 73 | else: 74 | str = f"{element}{stoic}" 75 | 76 | pyromat_input += str 77 | 78 | # eg: gas_array = {'N': 1, 'O': 2} 79 | # pyromat_input = "ig.NO2" 80 | pyromat_species_thermo_data = pm.get(pyromat_input) 81 | 82 | # G = H - TS 83 | pyromat_species_Gibbs = pyromat_species_thermo_data.h(T=temperature) - ( 84 | temperature * pyromat_species_thermo_data.s(T=temperature)) 85 | 86 | pyromat_species_Gibbs_std = pyromat_species_thermo_data.h(T=std_temp) - ( 87 | std_temp * pyromat_species_thermo_data.s(T=std_temp)) 88 | 89 | temp_cont = (pyromat_species_Gibbs - pyromat_species_Gibbs_std) 90 | 91 | return temp_cont[0] 92 | 93 | 94 | def gas_thermo_values(volatile_species: str, 95 | temperature: float, 96 | real_gas: int 97 | ): 98 | 99 | 100 | # units pre converted from J/mol --> eV 101 | 102 | # ideal gas 103 | if real_gas == 0: 104 | ideal_gas_entropies = {"H": 0.00135436, 105 | "N": 0.00198589, 106 | "O": 0.00212622, 107 | "F": 0.00210186, 108 | "Cl": 0.00231205 109 | } 110 | 111 | ideal_gas_heat_capacities = {"H": 0.000298891, 112 | "N": 0.00030187, 113 | "O": 0.000304546, 114 | "F": 0.000324774, 115 | "Cl": 0.000351828 116 | } 117 | 118 | return ideal_gas_entropies[volatile_species], ideal_gas_heat_capacities[volatile_species] 119 | 120 | # real gas relations 121 | elif real_gas == 1: 122 | 123 | if volatile_species == "H" or volatile_species == "D" or volatile_species == "T": 124 | if 100 <= temperature <= 1000: 125 | coefficients = {"aaa": 0.000342734, 126 | "bbb": -0.000117783, 127 | "ccc": 0.000118502, 128 | "ddd": -2.87411E-05, 129 | "eee": -1.64347E-06, 130 | "fff": -0.000103452, 131 | "ggg": 0.001790133 132 | } 133 | 134 | elif 1000 < temperature <= 2500: 135 | coefficients = {"aaa": 0.000192408, 136 | "bbb": 0.000127049, 137 | "ccc": -2.96419E-05, 138 | "ddd": 2.78031E-06, 139 | "eee": 2.0502E-05, 140 | "fff": -1.18933E-05, 141 | "ggg": 0.00161994 142 | } 143 | 144 | elif 2500 < temperature <= 6000: 145 | coefficients = {"aaa": 0.000449985, 146 | "bbb": -4.44981E-05, 147 | "ccc": 1.31888E-05, 148 | "ddd": -1.00413E-06, 149 | "eee": -0.000212835, 150 | "fff": -0.000399213, 151 | "ggg": 0.001679987 152 | } 153 | else: 154 | raise ValueError(f" Cannot use real gas parameters at temperature of {temperature} K\n" 155 | f"The temperature range for hydrogen is between 100 and 6000 K.") 156 | 157 | elif volatile_species == "N": 158 | if 100 <= temperature <= 500: 159 | coefficients = {"aaa": 0.000300447, 160 | "bbb": 1.92166E-05, 161 | "ccc": -9.99967E-05, 162 | "ddd": 0.000172427, 163 | "eee": 1.21271E-09, 164 | "fff": -8.98851E-05, 165 | "ggg": 0.002346829 166 | } 167 | 168 | elif 500 < temperature <= 2000: 169 | coefficients = {"aaa": 0.00020218, 170 | "bbb": 0.000206131, 171 | "ccc": -8.91245E-05, 172 | "ddd": 1.41979E-05, 173 | "eee": 5.46863E-06, 174 | "fff": -5.11538E-05, 175 | "ggg": 0.00220144 176 | } 177 | 178 | elif 2000 < temperature <= 6000: 179 | coefficients = {"aaa": 0.000368155, 180 | "bbb": 1.16994E-05, 181 | "ccc": -2.03262E-06, 182 | "ddd": 1.51973E-07, 183 | "eee": -4.72001E-05, 184 | "fff": -0.000196635, 185 | "ggg": 0.002331947 186 | } 187 | else: 188 | raise ValueError(f" Cannot use real gas parameters at temperature of {temperature} K\n" 189 | f"The temperature range for nitrogen is between 100 and 6000 K.") 190 | 191 | elif volatile_species == "F": 192 | if 298 <= temperature <= 6000: 193 | coefficients = {"aaa": 0.000325931, 194 | "bbb": 8.72101E-05, 195 | "ccc": -2.8803E-05, 196 | "ddd": 2.26067E-06, 197 | "eee": -2.18885E-06, 198 | "fff": -0.000108135, 199 | "ggg": 0.002459396 200 | } 201 | 202 | else: 203 | raise ValueError(f" Cannot use real gas parameters at temperature of {temperature} K\n" 204 | f"The temperature range for fluorine is between 298 and 6000 K.") 205 | 206 | elif volatile_species == "Cl": 207 | if 298 <= temperature <= 1000: 208 | coefficients = {"aaa": 0.000342572, 209 | "bbb": 0.000126759, 210 | "ccc": -0.000125056, 211 | "ddd": 4.54543E-05, 212 | "eee": -1.65317E-06, 213 | "fff": -0.000112304, 214 | "ggg": 0.002684858 215 | } 216 | 217 | elif 1000 < temperature <= 3000: 218 | coefficients = {"aaa": 0.000442354, 219 | "bbb": -5.19246E-05, 220 | "ccc": 1.97416E-05, 221 | "ddd": -1.71688E-06, 222 | "eee": -2.17509E-05, 223 | "fff": -0.00017921, 224 | "ggg": 0.002796914 225 | } 226 | 227 | elif 3000 < temperature <= 6000: 228 | coefficients = {"aaa": -0.000441071, 229 | "bbb": 0.000432076, 230 | "ccc": -7.38702E-05, 231 | "ddd": 4.01998E-06, 232 | "eee": 0.001048366, 233 | "fff": 0.00137611, 234 | "ggg": 0.002744529 235 | } 236 | else: 237 | raise ValueError(f" Cannot use real gas parameters at temperature of {temperature} K\n" 238 | f"The temperature range for nitrogen is between 100 and 6000 K.") 239 | 240 | elif volatile_species == "Br": 241 | if 332.5 <= temperature <= 3400: 242 | coefficients = {"aaa": 0.000399308, 243 | "bbb": -2.04885E-05, 244 | "ccc": 1.5817E-05, 245 | "ddd": -2.05626E-06, 246 | "eee": -1.92584E-06, 247 | "fff": 0.000195639, 248 | "ggg": 0.003021051, 249 | "hhh": 0.000320361 250 | } 251 | 252 | elif 3400 < temperature <= 6000: 253 | coefficients = {"aaa": 0.000362677, 254 | "bbb": 9.58931E-05, 255 | "ccc": -2.44762E-05, 256 | "ddd": 1.59958E-06, 257 | "eee": -0.000446456, 258 | "fff": -7.73982E-05, 259 | "ggg": 0.002835987, 260 | "hhh": 0.000320361 261 | } 262 | 263 | else: 264 | raise ValueError(f" Cannot use real gas parameters at temperature of {temperature} K\n" 265 | f"The temperature range for bromine is between 332.5 and 6000 K.") 266 | 267 | elif volatile_species == "I": 268 | if 457.666 <= temperature <= 2000: 269 | coefficients = {"aaa": 0.000391746, 270 | "bbb": 2.33666E-06, 271 | "ccc": -9.458E-06, 272 | "ddd": 1.07261E-05, 273 | "eee": -8.68798E-07, 274 | "fff": 0.000527218, 275 | "ggg": 0.003170646, 276 | "hhh": 0.000646951 277 | } 278 | 279 | elif 2000 < temperature <= 6000: 280 | coefficients = {"aaa": 0.000795296, 281 | "bbb": -4.19317E-05, 282 | "ccc": -1.91547E-05, 283 | "ddd": 2.27024E-06, 284 | "eee": -0.000853954, 285 | "fff": -0.00055834, 286 | "ggg": 0.002914718, 287 | "hhh": 0.000646951 288 | } 289 | 290 | else: 291 | raise ValueError(f" Cannot use real gas parameters at temperature of {temperature} K\n" 292 | f"The temperature range for iodine is between 457.666 and 6000 K.") 293 | 294 | 295 | elif volatile_species == "O": 296 | if 100 <= temperature <= 700: 297 | coefficients = {"aaa": 0.000324659, 298 | "bbb": -0.000209741, 299 | "ccc": 0.000599791, 300 | "ddd": -0.00037839, 301 | "eee": -7.64321e-08, 302 | "fff": -9.22852e-05, 303 | "ggg": 0.002558046 304 | } 305 | 306 | elif 700 < temperature <= 2000: 307 | coefficients = {"aaa": 0.000311288, 308 | "bbb": 9.09326E-05, 309 | "ccc": -4.13373E-05, 310 | "ddd": 8.17093E-06, 311 | "eee": -7.68674E-06, 312 | "fff": -0.000117381, 313 | "ggg": 0.002447884 314 | } 315 | 316 | elif 2000 < temperature <= 6000: 317 | coefficients = {"aaa": 0.000216745, 318 | "bbb": 0.000111121, 319 | "ccc": -2.09426E-05, 320 | "ddd": 1.51796E-06, 321 | "eee": 9.58327E-05, 322 | "fff": 5.53252E-05, 323 | "ggg": 0.002462936 324 | } 325 | 326 | else: 327 | raise ValueError(f" Cannot use real gas parameters at temperature of {temperature} K\n" 328 | f"The temperature range for oxygen is between 100 and 6000 K.") 329 | 330 | else: 331 | raise Exception(f"{volatile_species} is not available for real_gas method 1.\n" 332 | f"Please consult the manual for help.") 333 | 334 | return coefficients 335 | 336 | # johnston et al for oxygen 337 | elif real_gas == 2: 338 | 339 | coefficients = {"aaa": 3.074E-4, 340 | "bbb": 6.36066E-8, 341 | "ccc": -1.22974E-11, 342 | "ddd": 9.927E-16, 343 | "eee": -2.2766, 344 | "fff": -0.1022061, 345 | "ggg": 0.0024661578656} 346 | 347 | return coefficients 348 | 349 | 350 | def calc_volatile_gibbs_free_energy(temperature: float, 351 | real_gas: int, 352 | aaa, bbb, ccc, 353 | ddd, eee, fff, ggg): 354 | 355 | if real_gas == 1: 356 | t = temperature / 1000 357 | enthalpy = 1000 * (aaa * t + 358 | (1 / 2) * bbb * (t ** 2) + 359 | (1 / 3) * ccc * (t ** 3) + 360 | (1 / 4) * ddd * (t ** 4) - 361 | (eee / t) + 362 | fff) 363 | 364 | entropy = (aaa * math.log(t) + 365 | bbb * t + 366 | (1 / 2) * ccc * (t ** 2) + 367 | (1 / 3) * ddd * (t ** 3) - 368 | eee / (2 * (t ** 2)) + 369 | ggg) 370 | 371 | return enthalpy - (temperature * entropy) 372 | 373 | elif real_gas == 2: 374 | 375 | Gibbs = (aaa * (temperature - (temperature * math.log(temperature / 1000))) - 376 | (1 / 2) * bbb * (temperature ** 2) - 377 | (1 / 6) * ccc * (temperature ** 3) - 378 | (1 / 12) * ddd * (temperature ** 4) - 379 | (eee / (2 * temperature)) + 380 | fff - 381 | ggg * temperature) 382 | 383 | return Gibbs 384 | 385 | 386 | def calc_entropies(entropy_data, temperature): 387 | entropies = {} 388 | 389 | if not entropy_data: 390 | return None 391 | 392 | else: 393 | # separate temperature from the constituents in the dict keys 394 | temperature_key, *constituent_keys = entropy_data.keys() 395 | 396 | temperatures_lst = entropy_data[temperature_key] 397 | 398 | # check the desired temperature falls between the provided temperatures for the gibbs data 399 | if temperature < temperatures_lst[0] or temperature > temperatures_lst[-1]: 400 | raise Exception("\n ERROR\nTemperature is outside of range of entropy data provided\n") 401 | 402 | # loop through the constituents 403 | for constituent in constituent_keys: 404 | # acquire the list of energies for this constituent 405 | constituent_entropies = entropy_data[constituent] 406 | 407 | # interpolate the entropy at the desired temperature 408 | tck = interpolate.splrep(temperatures_lst, constituent_entropies) 409 | entropy_at_temp = interpolate.splev(temperature, tck) 410 | 411 | # add constituent and interpolated entropy to the dictionary 412 | entropies[constituent] = float(entropy_at_temp) 413 | 414 | return entropies 415 | 416 | 417 | def calc_gibbs_function(gibbs_data, temperature): 418 | 419 | gibbs_energies = {} 420 | 421 | if not gibbs_data: 422 | return None 423 | else: 424 | 425 | # separate temperature from the constituents in the dict keys 426 | temperature_key, *constituent_keys = gibbs_data.keys() 427 | 428 | temperatures_lst = gibbs_data[temperature_key] 429 | 430 | # check the desired temperature falls between the provided temperatures for the gibbs data 431 | if not (temperatures_lst[0] <= temperature <= temperatures_lst[-1]): 432 | raise Exception("\n ERROR\nTemperature is outside of range of Gibbs data provided\n") 433 | 434 | 435 | for constituent in constituent_keys: 436 | constituent_gibbs_engergies = gibbs_data[constituent] 437 | 438 | # interpolate the entropy at the desired temperature 439 | tck = interpolate.splrep(temperatures_lst, constituent_gibbs_engergies) 440 | gibbs_at_temp = interpolate.splev(temperature, tck) 441 | 442 | # add constituent and interpolated entropy to the dictionary 443 | gibbs_energies[constituent] = float(gibbs_at_temp) 444 | 445 | return gibbs_energies 446 | 447 | -------------------------------------------------------------------------------- /work_in_progress/defap_chem_pots.py: -------------------------------------------------------------------------------- 1 | from thermodynamics import calc_pressure_contribution 2 | from thermodynamics import calc_temperature_contribution 3 | 4 | 5 | class ChemicalPotentials: 6 | """ 7 | Class for calculating chemical potentials 8 | """ 9 | 10 | def __init__(self, data, entropy_vals, gibbs_vals): 11 | 12 | self.data = data 13 | self.data_copy = None 14 | self.entropy_vals = entropy_vals 15 | self.gibbs_vals = gibbs_vals 16 | 17 | # ensures chemical potentials are returned in defap_tasks when chemical_potentials.chem_pots is called 18 | self.chem_pots = self.call_chemical_pot_method() 19 | 20 | self.phase_chem_pots = None 21 | 22 | self.fitting_dopants = [] 23 | self.looping_dopants = [] 24 | 25 | def call_chemical_pot_method(self): 26 | 27 | # auto call chemical potential function depending on method specified 28 | if self.data.chem_pot_method == "defined": 29 | return self.calc_chemical_defined() 30 | 31 | elif self.data.chem_pot_method == "rich-poor": 32 | return self.calc_chemical_rich_poor() 33 | 34 | elif self.data.chem_pot_method == "volatile": 35 | return self.calc_chemical_volatile() 36 | 37 | elif self.data.chem_pot_method == "volatile-rich-poor": 38 | return self.calc_chemical_volatile_rich_poor() 39 | 40 | else: 41 | raise ValueError("\nERROR. Invalid chemical potential method!\n") 42 | 43 | 44 | def calc_chemical_defined(self): 45 | 46 | chemical_potentials = {} 47 | total_potential = 0 48 | 49 | # loop through host elements 50 | for host_element, stoic in self.data.host["elements"].items(): 51 | 52 | for constituent_element in self.data.constituents["constituent_compounds"].keys(): 53 | 54 | # assign chemical potential of this host element to what has been defined in the consitutuents tab 55 | if host_element == constituent_element: 56 | chem_pot = self.data.constituents["constituent_compounds"][constituent_element]["dft_energy_pfu"] 57 | chemical_potentials[host_element] = chem_pot 58 | 59 | # sum total chemical potential 60 | total_potential += stoic * chem_pot 61 | 62 | # check that host energy is not larger then chemical potential sum 63 | if abs(self.data.host_energy_pfu - total_potential) > 0.001: 64 | raise ValueError( 65 | f" Error : The chemical potentials for the constituents do not add up to that for the host system\n" 66 | f"Host: {self.data.host_energy_pfu}\n" 67 | f"Sum of constituents: {total_potential}") 68 | 69 | return chemical_potentials 70 | 71 | 72 | def calc_chemical_rich_poor(self): 73 | chemical_potentials = {} 74 | 75 | # energy of the host from input file 76 | host_energy = self.data.host_energy_pfu 77 | 78 | # loop through elements in the host and get the respective stoichiometries 79 | for host_element, stoic in self.data.host["elements"].items(): 80 | 81 | # total up rich chemical potentials of other constituents in the host 82 | other_chem_pot_total = 0 83 | # loop through the constituents 84 | for constituent_element, constituent_vals in self.data.constituents["constituent_compounds"].items(): 85 | 86 | # get the rich chemical potential and rich poor fraction of the current constituent element in the host 87 | if host_element == constituent_element: 88 | chem_pot_rich = constituent_vals["dft_energy_pfu"] 89 | rp_fraction = constituent_vals["fraction"] 90 | 91 | else: 92 | # sum the rich chemical potentials of the other elements in the host to determine the poor chemical potential limit of the current element 93 | other_chem_pot_rich = constituent_vals["dft_energy_pfu"] 94 | other_chem_pot_total += other_chem_pot_rich * self.data.host["elements"][constituent_element] 95 | 96 | # calculate poor chemical potential limit of current element 97 | chem_pot_poor = (host_energy - other_chem_pot_total) / stoic 98 | 99 | # determine final chemical potential by summing the fractions of the rich and poor chemical potentials 100 | final_chem_pot = rp_fraction*chem_pot_rich + (1 - rp_fraction)*chem_pot_poor 101 | 102 | chemical_potentials[host_element] = final_chem_pot 103 | 104 | return chemical_potentials 105 | 106 | def calc_chemical_volatile(self): 107 | 108 | # energy of the host from input file 109 | host_energy = self.data.host_energy_pfu 110 | 111 | # unpack dictionary to get values of the compound provided 112 | compound_formula, compound_elements, compound_energy, compound_metal_energy, compound_std_form_eng = \ 113 | self.data.constituents["compound"].values() 114 | 115 | # unpack elements to get element stoichiometries from compound provided 116 | # assume format of compound is: M_{a}-V_{b} 117 | metal_compound_stoic, volatile_compound_stoic = compound_elements.values() 118 | 119 | # calculate volatile standard chemical potential 120 | nu_volatile_std = (compound_energy - (metal_compound_stoic * compound_metal_energy) - compound_std_form_eng) / volatile_compound_stoic 121 | 122 | # calculate temperature contribution to volatile chem pot 123 | temp_cont = 0.5 * calc_temperature_contribution( 124 | gas_species=self.data.constituents["volatile"]["volatile_element"], 125 | temperature=self.data.temperature, 126 | real_gas=self.data.real_gas 127 | ) 128 | 129 | # calculate pressure contribution to volatile chem pot 130 | pressure_cont = calc_pressure_contribution(volatile_PP=self.data.constituents["volatile"]["log_pp"], 131 | temperature=self.data.temperature 132 | ) 133 | 134 | # calculate volatile chemical potential at desired conditions 135 | nu_volatile = nu_volatile_std + temp_cont + pressure_cont 136 | 137 | # now calculate chemical potential of metal species in host 138 | 139 | # add entropy contribution to host energy if specified 140 | if self.entropy_vals: 141 | # host should be first key in the dict 142 | host_entropy_key = list(self.entropy_vals.keys())[0] 143 | 144 | if host_entropy_key == "host" or host_entropy_key == self.data.host["formula"]: 145 | host_entropy = self.entropy_vals[host_entropy_key] 146 | host_energy -= (host_entropy * self.data.temperature / self.data.entropy_units) 147 | else: 148 | raise Exception("ERROR! The host material is not the first defined compound in the entropy file." 149 | f"\nFirst compound found: {host_entropy_key}") 150 | 151 | # get host elements and stoichiometries (incase a reference compound was used to calculate nu_volatile) 152 | # assume format of host is: M_{a}-V_{b} 153 | metal_host_element, volatile_element = self.data.host["elements"].keys() 154 | metal_host_stoic, volatile_host_stoic = self.data.host["elements"].values() 155 | 156 | # calculate chemical potential of metal in host 157 | nu_metal = (host_energy - (volatile_host_stoic * nu_volatile)) / metal_host_stoic 158 | 159 | chemical_potentials = {metal_host_element: nu_metal, 160 | volatile_element: nu_volatile 161 | } 162 | 163 | return chemical_potentials 164 | 165 | def calc_chemical_volatile_rich_poor(self): 166 | chemical_potentials = {} 167 | rich_poor_fraction_total = 0 168 | nu_volatile_std = 0 169 | 170 | # energy of the host from input file 171 | host_energy = self.data.host_energy_pfu 172 | 173 | # change energy of host if using gibbs function. 174 | # host should be first key 175 | if self.gibbs_vals: 176 | # assigns first key in dict as host_gibbs_key and leaves the rest in a list 177 | host_gibbs_key, *constituents_gibbs_keys = self.gibbs_vals.keys() 178 | 179 | if host_gibbs_key == "host" or host_gibbs_key == self.data.host["formula"]: 180 | host_energy = self.gibbs_vals[host_gibbs_key] 181 | else: 182 | raise Exception("ERROR! The host material is not the first defined compound in the gibbs energies file." 183 | f"\nFirst compound found: {host_gibbs_key}") 184 | 185 | # loop through the constituent compounds that make up the host 186 | for compound in self.data.constituents["constituent_compounds"]: 187 | # unpack compound dictionary to get values 188 | compound_elements, compound_coefficient, compound_energy, compound_metal_energy, compound_std_form_eng, compound_rich_poor_frac = \ 189 | self.data.constituents["constituent_compounds"][compound].values() 190 | 191 | # unpack elements to get element stoichiometries from compound provided 192 | # assume format of compound is: M_{a}-V_{b} 193 | metal_compound_stoic, volatile_compound_stoic = compound_elements.values() 194 | 195 | # accumulate the total rich-poor fraction 196 | rich_poor_fraction_total += compound_rich_poor_frac 197 | 198 | # calculate the contribution to the std volatile chem pot from this compound 199 | volatile_chem_pot_contribution = compound_rich_poor_frac * ((compound_energy - ( 200 | metal_compound_stoic * compound_metal_energy) - compound_std_form_eng) / volatile_compound_stoic) 201 | 202 | # accumulate std volatile chem pot 203 | nu_volatile_std += volatile_chem_pot_contribution 204 | 205 | # get final std volatile chem pot by dividing by total rich poor fraction 206 | nu_volatile_std /= rich_poor_fraction_total 207 | 208 | # calculate temperature contribution to the volatile chem pot 209 | temp_cont = 0.5 * calc_temperature_contribution(gas_species=self.data.constituents["volatile"]["volatile_element"], 210 | temperature=self.data.temperature, 211 | real_gas=self.data.real_gas 212 | ) 213 | 214 | # calculate pressure contribution to the volatile chem pot 215 | pressure_cont = calc_pressure_contribution(volatile_PP=self.data.constituents["volatile"]["log_pp"], 216 | temperature=self.data.temperature 217 | ) 218 | 219 | # determine volatile chem pot at desired conditions 220 | nu_volatile = nu_volatile_std + temp_cont + pressure_cont 221 | 222 | # now loop over elements in the host and determine the final chemical potentials 223 | for host_element, element_stoichiometry in self.data.host["elements"].items(): 224 | 225 | # only do non-volatile elements 226 | if host_element is not self.data.constituents["volatile"]["volatile_element"]: 227 | 228 | other_constituents_chem_pot_contribution = 0 229 | 230 | # loop over constituent compounds again to check if this element is in this compound 231 | for compound in self.data.constituents["constituent_compounds"]: 232 | # unpack compound dictionary to get values 233 | compound_elements, compound_coefficient, compound_energy, compound_metal_energy, compound_std_form_eng, compound_rich_poor_frac = \ 234 | self.data.constituents["constituent_compounds"][compound].values() 235 | 236 | # change energies of constituents to gibbs energies at desired temperature if requested 237 | if self.gibbs_vals: 238 | compound_energy = self.gibbs_vals[compound] 239 | 240 | if host_element not in compound_elements: 241 | # sum up "rich" energies of constituents that DO NOT contain target host element 242 | other_constituents_chem_pot_contribution += compound_coefficient * compound_energy 243 | else: 244 | # hold values for after the inner loop has finished 245 | target_compound_energy = compound_energy 246 | target_compound_coefficient = compound_coefficient 247 | target_rich_poor_frac = compound_rich_poor_frac 248 | 249 | # unpack elements to get element stoichiometries from compound provided 250 | # assume format of compound is: M_{a}-V_{b} 251 | target_metal_compound_stoic, target_volatile_compound_stoic = compound_elements.values() 252 | 253 | # calc chemical potential for element 254 | chemical_potential = target_rich_poor_frac * ((target_compound_energy - (target_volatile_compound_stoic * nu_volatile)) / target_metal_compound_stoic) + (1 - target_rich_poor_frac) * (((host_energy - other_constituents_chem_pot_contribution - (self.data.constituents["volatile"]["coefficient"] * nu_volatile)) / target_compound_coefficient - (target_volatile_compound_stoic * nu_volatile)) / target_metal_compound_stoic) 255 | 256 | # add to the dictionary 257 | chemical_potentials[host_element] = chemical_potential 258 | 259 | else: 260 | chemical_potentials[self.data.constituents["volatile"]["volatile_element"]] = nu_volatile 261 | 262 | return chemical_potentials 263 | 264 | def calc_secondary_phase_chem_pots(self): 265 | 266 | phase_chem_pots = {} 267 | 268 | # loop through secondary phases provided 269 | for phase, phase_vals in self.data.secondary_phases.items(): 270 | chem_pot_sum = 0 271 | 272 | # sum total chemical potentials of the consituents in the secondary phase 273 | for phase_element, element_stoic in phase_vals["elements"].items(): 274 | chem_pot_sum += (self.chem_pots[phase_element] * element_stoic) 275 | 276 | 277 | # add temperature contribution to gaseous secondary phases using pyromat if requested 278 | if phase_vals["add_temperature_contribution"]: 279 | temp_cont = calc_temperature_contribution( 280 | gas_species=phase, 281 | temperature=self.data.temperature, 282 | real_gas=3 283 | ) 284 | 285 | phase_eng = phase_vals["energy"] + temp_cont 286 | 287 | elif phase_vals["use_gibbs_energy"]: 288 | phase_eng = self.gibbs_vals[phase] 289 | 290 | else: 291 | phase_eng = phase_vals["energy"] 292 | 293 | # secondary phase "stable" if sum of chemical potentials exceeds the chemical potential of the secondary phase 294 | if chem_pot_sum > phase_eng: 295 | is_stable = True 296 | else: 297 | is_stable = False 298 | 299 | phase_chem_pots[phase] = {"energy": phase_eng, 300 | "chem_pot_sum": chem_pot_sum, 301 | "difference": chem_pot_sum - phase_eng, 302 | "is_stable": is_stable 303 | } 304 | 305 | self.phase_chem_pots = phase_chem_pots 306 | 307 | def add_dopants(self): 308 | 309 | # loop through dopants, add them to the chemical_potentials dict and determine if they need 310 | # chemical potentials fitting to a concentration 311 | 312 | delete_dopants = None 313 | 314 | for dopant, dopant_vals in self.data.dopants.items(): 315 | 316 | reference = dopant_vals["reference"] 317 | ref_elements = dopant_vals["reference_elements"] 318 | dopant_chem_pot = dopant_vals["chemical_potential"] 319 | fitting_option = dopant_vals["fitting_option"] 320 | 321 | # delete dopant 322 | if fitting_option == 0: 323 | 324 | if delete_dopants: 325 | delete_dopants.append(dopant) 326 | else: 327 | delete_dopants = [dopant] 328 | 329 | for defect in list(self.data.defects_data.keys()): 330 | 331 | if self.data.defects_data[defect]["added/removed"][dopant] != 0: 332 | del self.data.defects_data[defect] 333 | 334 | else: 335 | del self.data.defects_data[defect]["added/removed"][dopant] 336 | 337 | # 1 = fixed concentration | 2 = loop over concentration 338 | # regardless, chemical potential needs fitting 339 | elif fitting_option == 1 or fitting_option == 2: 340 | self.chem_pots[dopant] = dopant_chem_pot 341 | self.fitting_dopants.append(dopant) 342 | 343 | 344 | # 3 = fixed partial pressure | 4 - loop over partial pressure 345 | # no need to fit as chemical potential is calculated directly from partial pressure 346 | # only volatile elements available 347 | elif fitting_option == 3 or fitting_option == 4: 348 | 349 | valid_gas_dopants = ["H", "D", "T", "N", "O", "F", "Cl"] 350 | 351 | dopant_log_pp = dopant_vals["log_PP_atm"] 352 | 353 | # determine whether X or X2 has been provided as a dopant reference 354 | # e.g. Cl or Cl_2 355 | if reference in valid_gas_dopants: 356 | volatile_element = reference 357 | dopant_stoic = ref_elements[volatile_element] 358 | 359 | elif reference[:-2] in valid_gas_dopants: 360 | volatile_element = reference[:-2] 361 | dopant_stoic = ref_elements[volatile_element] 362 | 363 | else: 364 | raise Exception( 365 | f"\n Error. Partial pressure dopant fitting option can only be used for diatomic gas molecules!\n") 366 | 367 | dopant_chem_pot /= dopant_stoic 368 | 369 | # calculate temperature and pressure contributions to the volatile dopant chemical potential 370 | temperature_contribution = 0.5 * calc_temperature_contribution(gas_species=volatile_element, 371 | temperature=self.data.temperature, 372 | real_gas=self.data.real_gas 373 | ) 374 | 375 | pressure_contribution = calc_pressure_contribution(volatile_PP=dopant_log_pp, 376 | temperature=self.data.temperature 377 | ) 378 | 379 | 380 | # calculate dopant chemical potential under desired conditions 381 | dopant_chem_pot += (temperature_contribution + pressure_contribution) 382 | 383 | self.chem_pots[dopant] = dopant_chem_pot 384 | 385 | # dopant chem pot directly specified 386 | elif fitting_option == 5: 387 | self.chem_pots[dopant] = dopant_chem_pot 388 | 389 | # remove dopants from dopant dict if not being used 390 | # prevent errors on next loop step 391 | if delete_dopants: 392 | for dopant in delete_dopants: 393 | del self.data.dopants[dopant] 394 | 395 | # for whether a dopant is being fitted or not 396 | if self.fitting_dopants == []: 397 | self.fitting_dopants = None 398 | 399 | elif len(self.fitting_dopants) == 1: 400 | self.fitting_dopants = self.fitting_dopants[0] 401 | 402 | 403 | -------------------------------------------------------------------------------- /EXAMPLES/PuO2/PuO2.dos: -------------------------------------------------------------------------------- 1 | -5.4323 0 2 | -5.421 0 3 | -5.4096 0 4 | -5.3983 0 5 | -5.3869 0 6 | -5.3756 0 7 | -5.3643 0 8 | -5.3529 0 9 | -5.3416 0 10 | -5.3302 0 11 | -5.3189 0 12 | -5.3076 0 13 | -5.2962 0 14 | -5.2849 0 15 | -5.2735 0 16 | -5.2622 0 17 | -5.2509 0 18 | -5.2395 0 19 | -5.2282 0 20 | -5.2168 0 21 | -5.2055 0 22 | -5.1942 0 23 | -5.1828 0.0001 24 | -5.1715 0.0306 25 | -5.1601 1.1386 26 | -5.1488 4.6333 27 | -5.1375 2.335 28 | -5.1261 0.7788 29 | -5.1148 6.6026 30 | -5.1034 8.5545 31 | -5.0921 10.0838 32 | -5.0808 18.8063 33 | -5.0694 7.3466 34 | -5.0581 6.6872 35 | -5.0467 7.7683 36 | -5.0354 19.1336 37 | -5.0241 11.7232 38 | -5.0127 13.6692 39 | -5.0014 8.5596 40 | -4.99 2.9645 41 | -4.9787 5.1051 42 | -4.9674 22.7022 43 | -4.956 38.5608 44 | -4.9447 22.2426 45 | -4.9333 5.9117 46 | -4.922 18.1357 47 | -4.9107 30.8999 48 | -4.8993 11.6025 49 | -4.888 11.4018 50 | -4.8766 17.2403 51 | -4.8653 7.5681 52 | -4.854 3.1842 53 | -4.8426 9.2063 54 | -4.8313 7.4504 55 | -4.8199 12.1218 56 | -4.8086 17.5138 57 | -4.7973 8.3561 58 | -4.7859 14.5605 59 | -4.7746 10.5113 60 | -4.7632 17.736 61 | -4.7519 16.0345 62 | -4.7406 12.9926 63 | -4.7292 19.1591 64 | -4.7179 28.1256 65 | -4.7065 31.901 66 | -4.6952 35.5072 67 | -4.6839 24.7395 68 | -4.6725 27.7413 69 | -4.6612 16.8033 70 | -4.6498 15.9161 71 | -4.6385 15.5817 72 | -4.6272 3.9338 73 | -4.6158 21.6667 74 | -4.6045 53.8655 75 | -4.5931 40.1134 76 | -4.5818 24.1731 77 | -4.5705 23.379 78 | -4.5591 29.1947 79 | -4.5478 22.2936 80 | -4.5364 18.5409 81 | -4.5251 18.4367 82 | -4.5138 8.5709 83 | -4.5024 2.2868 84 | -4.4911 3.2509 85 | -4.4797 14.0013 86 | -4.4684 16.6437 87 | -4.457 7.2218 88 | -4.4457 11.9276 89 | -4.4344 22.1465 90 | -4.423 22.9397 91 | -4.4117 24.929 92 | -4.4003 35.2114 93 | -4.389 33.3485 94 | -4.3777 23.8464 95 | -4.3663 9.2434 96 | -4.355 13.6276 97 | -4.3436 12.0157 98 | -4.3323 7.9637 99 | -4.321 19.3039 100 | -4.3096 25.2137 101 | -4.2983 20.4702 102 | -4.2869 21.4356 103 | -4.2756 26.4676 104 | -4.2643 14.3691 105 | -4.2529 11.7607 106 | -4.2416 11.5561 107 | -4.2302 13.3912 108 | -4.2189 13.448 109 | -4.2076 18.4349 110 | -4.1962 8.7157 111 | -4.1849 10.4696 112 | -4.1735 13.4792 113 | -4.1622 13.7217 114 | -4.1509 8.038 115 | -4.1395 8.4405 116 | -4.1282 1.4449 117 | -4.1168 1.0027 118 | -4.1055 6.0875 119 | -4.0942 9.7347 120 | -4.0828 2.4613 121 | -4.0715 2.7777 122 | -4.0601 10.6909 123 | -4.0488 5.4768 124 | -4.0375 1.5473 125 | -4.0261 8.1447 126 | -4.0148 7.5857 127 | -4.0034 2.095 128 | -3.9921 1.4183 129 | -3.9808 7.9973 130 | -3.9694 7.6934 131 | -3.9581 11.8132 132 | -3.9467 17.089 133 | -3.9354 3.8174 134 | -3.9241 2.6924 135 | -3.9127 9.8253 136 | -3.9014 11.1582 137 | -3.89 19.8624 138 | -3.8787 15.89 139 | -3.8674 8.5445 140 | -3.856 3.5037 141 | -3.8447 1.5435 142 | -3.8333 6.0944 143 | -3.822 5.5267 144 | -3.8107 9.3959 145 | -3.7993 5.5413 146 | -3.788 8.5663 147 | -3.7766 14.7651 148 | -3.7653 5.5434 149 | -3.754 9.3356 150 | -3.7426 9.6655 151 | -3.7313 6.7724 152 | -3.7199 6.3561 153 | -3.7086 6.6583 154 | -3.6973 10.756 155 | -3.6859 12.5715 156 | -3.6746 7.5145 157 | -3.6632 5.4626 158 | -3.6519 9.614 159 | -3.6406 4.2209 160 | -3.6292 0.3639 161 | -3.6179 1.1964 162 | -3.6065 7.2743 163 | -3.5952 12.7122 164 | -3.5839 9.7672 165 | -3.5725 3.1244 166 | -3.5612 13.0383 167 | -3.5498 34.1073 168 | -3.5385 28.4988 169 | -3.5272 6.4256 170 | -3.5158 1.7737 171 | -3.5045 0.5346 172 | -3.4931 0.0212 173 | -3.4818 0.2878 174 | -3.4705 8.3604 175 | -3.4591 37.9469 176 | -3.4478 44.2514 177 | -3.4364 20.1784 178 | -3.4251 12.5777 179 | -3.4138 11.3298 180 | -3.4024 14.7722 181 | -3.3911 19.0888 182 | -3.3797 24.6514 183 | -3.3684 22.0371 184 | -3.3571 18.0659 185 | -3.3457 31.0273 186 | -3.3344 15.7022 187 | -3.323 4.8827 188 | -3.3117 8.7914 189 | -3.3004 6.2951 190 | -3.289 5.8518 191 | -3.2777 12.7295 192 | -3.2663 25.089 193 | -3.255 41.8758 194 | -3.2436 39.7217 195 | -3.2323 14.1166 196 | -3.221 3.5198 197 | -3.2096 13.3676 198 | -3.1983 16.1414 199 | -3.1869 11.64 200 | -3.1756 5.7716 201 | -3.1643 0.4685 202 | -3.1529 1.1692 203 | -3.1416 4.6614 204 | -3.1302 3.2643 205 | -3.1189 7.7797 206 | -3.1076 10.3486 207 | -3.0962 19.2472 208 | -3.0849 23.0214 209 | -3.0735 17.6799 210 | -3.0622 4.0752 211 | -3.0509 7.1041 212 | -3.0395 21.8277 213 | -3.0282 24.5007 214 | -3.0168 15.1604 215 | -3.0055 13.2001 216 | -2.9942 7.7467 217 | -2.9828 1.0762 218 | -2.9715 1.8014 219 | -2.9601 10.565 220 | -2.9488 8.681 221 | -2.9375 0.9693 222 | -2.9261 0.0125 223 | -2.9148 0 224 | -2.9034 0 225 | -2.8921 0 226 | -2.8808 0.0005 227 | -2.8694 0.1458 228 | -2.8581 4.0029 229 | -2.8467 13.5817 230 | -2.8354 6.625 231 | -2.8241 1.244 232 | -2.8127 7.1079 233 | -2.8014 8.2185 234 | -2.79 7.7874 235 | -2.7787 12.9244 236 | -2.7674 12.991 237 | -2.756 9.3573 238 | -2.7447 11.2231 239 | -2.7333 12.0774 240 | -2.722 12.9251 241 | -2.7107 4.6632 242 | -2.6993 5.8194 243 | -2.688 4.8457 244 | -2.6766 4.7132 245 | -2.6653 2.9083 246 | -2.654 3.3324 247 | -2.6426 13.9225 248 | -2.6313 13.3558 249 | -2.6199 14.4192 250 | -2.6086 17.0407 251 | -2.5973 16.5132 252 | -2.5859 25.2035 253 | -2.5746 19.3594 254 | -2.5632 4.5886 255 | -2.5519 8.4677 256 | -2.5406 15.8154 257 | -2.5292 19.4105 258 | -2.5179 21.0859 259 | -2.5065 11.7826 260 | -2.4952 6.6708 261 | -2.4839 2.9101 262 | -2.4725 8.8867 263 | -2.4612 13.3243 264 | -2.4498 28.5682 265 | -2.4385 19.3414 266 | -2.4272 20.1274 267 | -2.4158 9.6379 268 | -2.4045 3.9068 269 | -2.3931 6.1442 270 | -2.3818 1.4569 271 | -2.3705 0.5728 272 | -2.3591 6.4078 273 | -2.3478 13.1031 274 | -2.3364 15.0514 275 | -2.3251 16.4132 276 | -2.3138 16.5072 277 | -2.3024 13.9878 278 | -2.2911 17.3394 279 | -2.2797 23.8852 280 | -2.2684 21.4429 281 | -2.2571 7.8878 282 | -2.2457 10.596 283 | -2.2344 23.8595 284 | -2.223 17.1126 285 | -2.2117 6.0795 286 | -2.2004 15.1918 287 | -2.189 20.1058 288 | -2.1777 18.4588 289 | -2.1663 13.7572 290 | -2.155 6.7257 291 | -2.1437 15.5675 292 | -2.1323 13.5495 293 | -2.121 9.6499 294 | -2.1096 8.4572 295 | -2.0983 12.8713 296 | -2.087 20.6032 297 | -2.0756 16.153 298 | -2.0643 13.423 299 | -2.0529 19.0508 300 | -2.0416 15.2257 301 | -2.0302 17.3996 302 | -2.0189 18.3013 303 | -2.0076 3.6778 304 | -1.9962 0.0842 305 | -1.9849 0.0002 306 | -1.9735 0 307 | -1.9622 0.0048 308 | -1.9509 0.5607 309 | -1.9395 7.3093 310 | -1.9282 16.2573 311 | -1.9168 8.2001 312 | -1.9055 0.9486 313 | -1.8942 4.2503 314 | -1.8828 9.4118 315 | -1.8715 2.6976 316 | -1.8601 1.2067 317 | -1.8488 1.3205 318 | -1.8375 0.1876 319 | -1.8261 0.0038 320 | -1.8148 0.1054 321 | -1.8034 1.0927 322 | -1.7921 1.355 323 | -1.7808 0.4918 324 | -1.7694 2.5817 325 | -1.7581 8.6213 326 | -1.7467 12.3781 327 | -1.7354 12.7764 328 | -1.7241 11.7631 329 | -1.7127 3.897 330 | -1.7014 5.8369 331 | -1.69 16.4352 332 | -1.6787 22.502 333 | -1.6674 32.7351 334 | -1.656 12.5867 335 | -1.6447 0.8829 336 | -1.6333 0.0092 337 | -1.622 0.0412 338 | -1.6107 1.3269 339 | -1.5993 4.7179 340 | -1.588 2.0773 341 | -1.5766 0.2982 342 | -1.5653 2.7132 343 | -1.554 4.4445 344 | -1.5426 0.8952 345 | -1.5313 0.0194 346 | -1.5199 0.0021 347 | -1.5086 0.33 348 | -1.4973 5.3302 349 | -1.4859 14.3398 350 | -1.4746 22.4321 351 | -1.4632 18.1439 352 | -1.4519 2.7624 353 | -1.4406 0.9122 354 | -1.4292 8.3845 355 | -1.4179 18.3053 356 | -1.4065 22.0544 357 | -1.3952 31.7126 358 | -1.3839 19.2295 359 | -1.3725 16.9811 360 | -1.3612 23.0102 361 | -1.3498 28.6587 362 | -1.3385 17.0034 363 | -1.3272 8.3372 364 | -1.3158 1.2145 365 | -1.3045 3.8329 366 | -1.2931 13.8658 367 | -1.2818 6.6445 368 | -1.2705 2.7547 369 | -1.2591 20.5459 370 | -1.2478 46.9771 371 | -1.2364 47.5558 372 | -1.2251 21.2326 373 | -1.2138 6.7922 374 | -1.2024 3.2612 375 | -1.1911 13.9678 376 | -1.1797 11.2648 377 | -1.1684 3.2046 378 | -1.1571 8.4304 379 | -1.1457 24.7145 380 | -1.1344 29.1269 381 | -1.123 16.7697 382 | -1.1117 14.752 383 | -1.1004 23.4938 384 | -1.089 22.3438 385 | -1.0777 25.9817 386 | -1.0663 10.0969 387 | -1.055 4.3265 388 | -1.0437 5.5176 389 | -1.0323 5.5681 390 | -1.021 23.9498 391 | -1.0096 40.7864 392 | -0.998299 36.4697 393 | -0.986999 40.2203 394 | -0.975599 19.6956 395 | -0.964299 5.1318 396 | -0.952899 5.7022 397 | -0.941599 19.9561 398 | -0.930299 16.4776 399 | -0.918899 13.5436 400 | -0.907599 19.7018 401 | -0.896199 10.7407 402 | -0.884899 3.1046 403 | -0.873599 8.6122 404 | -0.862199 13.4022 405 | -0.850899 16.1636 406 | -0.839499 22.9274 407 | -0.828199 24.202 408 | -0.816799 30.0664 409 | -0.805499 35.4888 410 | -0.794199 27.1182 411 | -0.782799 22.1888 412 | -0.771499 15.8552 413 | -0.760099 10.0377 414 | -0.748799 5.343 415 | -0.737499 9.7093 416 | -0.726099 4.5491 417 | -0.714799 5.6183 418 | -0.703399 9.5735 419 | -0.692099 2.5866 420 | -0.680799 0.0786 421 | -0.669399 0.0899 422 | -0.658099 1.9636 423 | -0.646699 6.2584 424 | -0.635399 10.0034 425 | -0.624099 5.9943 426 | -0.612699 0.5809 427 | -0.601399 3.8064 428 | -0.589999 19.1844 429 | -0.578699 17.0812 430 | -0.567399 5.8533 431 | -0.555999 13.5259 432 | -0.544699 14.1013 433 | -0.533299 3.2523 434 | -0.521999 0.2621 435 | -0.510699 0.2189 436 | -0.499299 3.702 437 | -0.487999 10.2697 438 | -0.476599 7.1636 439 | -0.465299 6.1603 440 | -0.453999 15.1764 441 | -0.442599 9.0264 442 | -0.431299 9.3084 443 | -0.419899 19.9078 444 | -0.408599 17.6511 445 | -0.397299 39.915 446 | -0.385899 67.2891 447 | -0.374599 54.7314 448 | -0.363199 52.5922 449 | -0.351899 32.9039 450 | -0.340599 12.9726 451 | -0.329199 9.01 452 | -0.317899 2.0905 453 | -0.306499 12.0952 454 | -0.295199 26.9929 455 | -0.283899 12.0731 456 | -0.272499 6.6341 457 | -0.261199 12.8682 458 | -0.249799 12.0666 459 | -0.238499 4.3982 460 | -0.227199 0.2501 461 | -0.215799 1.3372 462 | -0.204499 9.9852 463 | -0.193099 23.9712 464 | -0.181799 31.5349 465 | -0.170499 13.2666 466 | -0.159099 10.0399 467 | -0.147799 16.1813 468 | -0.136399 6.895 469 | -0.125099 7.0529 470 | -0.113799 9.6759 471 | -0.102399 9.4506 472 | -0.0910987 11.5713 473 | -0.0796987 5.3416 474 | -0.0683987 4.8559 475 | -0.0570987 1.7176 476 | -0.0456987 3.4521 477 | -0.0343987 3.9411 478 | -0.0229987 0.5531 479 | -0.0116987 0.0081 480 | -0.00039869 0 481 | 0.0110013 0 482 | 0.0223013 0 483 | 0.0337013 0 484 | 0.0450013 0 485 | 0.0563013 0 486 | 0.0677013 0 487 | 0.0790013 0 488 | 0.0904013 0 489 | 0.101701 0 490 | 0.113001 0 491 | 0.124401 0 492 | 0.135701 0 493 | 0.147101 0 494 | 0.158401 0 495 | 0.169701 0 496 | 0.181101 0 497 | 0.192401 0 498 | 0.203801 0 499 | 0.215101 0 500 | 0.226401 0 501 | 0.237801 0 502 | 0.249101 0 503 | 0.260501 0 504 | 0.271801 0 505 | 0.283101 0 506 | 0.294501 0 507 | 0.305801 0 508 | 0.317201 0 509 | 0.328501 0 510 | 0.339801 0 511 | 0.351201 0 512 | 0.362501 0 513 | 0.373901 0 514 | 0.385201 0 515 | 0.396601 0 516 | 0.407901 0 517 | 0.419201 0 518 | 0.430601 0 519 | 0.441901 0 520 | 0.453301 0 521 | 0.464601 0 522 | 0.475901 0 523 | 0.487301 0 524 | 0.498601 0 525 | 0.510001 0 526 | 0.521301 0 527 | 0.532601 0 528 | 0.544001 0 529 | 0.555301 0 530 | 0.566701 0 531 | 0.578001 0 532 | 0.589301 0 533 | 0.600701 0 534 | 0.612001 0 535 | 0.623401 0 536 | 0.634701 0 537 | 0.646001 0 538 | 0.657401 0 539 | 0.668701 0 540 | 0.680101 0 541 | 0.691401 0 542 | 0.702701 0 543 | 0.714101 0 544 | 0.725401 0 545 | 0.736801 0 546 | 0.748101 0 547 | 0.759401 0 548 | 0.770801 0 549 | 0.782101 0 550 | 0.793501 0 551 | 0.804801 0 552 | 0.816101 0 553 | 0.827501 0 554 | 0.838801 0 555 | 0.850201 0 556 | 0.861501 0 557 | 0.872801 0 558 | 0.884201 0 559 | 0.895501 0 560 | 0.906901 0 561 | 0.918201 0 562 | 0.929501 0 563 | 0.940901 0 564 | 0.952201 0 565 | 0.963601 0 566 | 0.974901 0 567 | 0.986201 0 568 | 0.997601 0 569 | 1.0089 0 570 | 1.0203 0 571 | 1.0316 0 572 | 1.0429 0 573 | 1.0543 0 574 | 1.0656 0 575 | 1.077 0 576 | 1.0883 0 577 | 1.0996 0 578 | 1.111 0 579 | 1.1223 0 580 | 1.1337 0 581 | 1.145 0 582 | 1.1563 0 583 | 1.1677 0 584 | 1.179 0 585 | 1.1904 0 586 | 1.2017 0 587 | 1.213 0 588 | 1.2244 0 589 | 1.2357 0 590 | 1.2471 0 591 | 1.2584 0 592 | 1.2697 0 593 | 1.2811 0 594 | 1.2924 0 595 | 1.3038 0 596 | 1.3151 0 597 | 1.3264 0 598 | 1.3378 0 599 | 1.3491 0 600 | 1.3605 0 601 | 1.3718 0 602 | 1.3831 0 603 | 1.3945 0 604 | 1.4058 0 605 | 1.4172 0 606 | 1.4285 0 607 | 1.4398 0 608 | 1.4512 0 609 | 1.4625 0 610 | 1.4739 0 611 | 1.4852 0 612 | 1.4965 0 613 | 1.5079 0 614 | 1.5192 0 615 | 1.5306 0 616 | 1.5419 0 617 | 1.5532 0 618 | 1.5646 0 619 | 1.5759 0 620 | 1.5873 0 621 | 1.5986 0 622 | 1.61 0 623 | 1.6213 0 624 | 1.6326 0 625 | 1.644 0 626 | 1.6553 0 627 | 1.6667 0 628 | 1.678 0 629 | 1.6893 0 630 | 1.7007 0 631 | 1.712 0 632 | 1.7234 0 633 | 1.7347 0 634 | 1.746 0 635 | 1.7574 0 636 | 1.7687 0 637 | 1.7801 0 638 | 1.7914 0 639 | 1.8027 0 640 | 1.8141 0 641 | 1.8254 0 642 | 1.8368 0 643 | 1.8481 0 644 | 1.8594 0 645 | 1.8708 0 646 | 1.8821 0 647 | 1.8935 0 648 | 1.9048 0 649 | 1.9161 0 650 | 1.9275 0 651 | 1.9388 0 652 | 1.9502 0 653 | 1.9615 0 654 | 1.9728 0 655 | 1.9842 0 656 | 1.9955 0 657 | 2.0069 0 658 | 2.0182 0 659 | 2.0295 0 660 | 2.0409 0 661 | 2.0522 0 662 | 2.0636 0 663 | 2.0749 0 664 | 2.0862 0 665 | 2.0976 0 666 | 2.1089 0 667 | 2.1203 0 668 | 2.1316 0 669 | 2.1429 0 670 | 2.1543 0 671 | 2.1656 0 672 | 2.177 0 673 | 2.1883 0 674 | 2.1996 0 675 | 2.211 0 676 | 2.2223 0 677 | 2.2337 0 678 | 2.245 0 679 | 2.2563 0 680 | 2.2677 0 681 | 2.279 0 682 | 2.2904 0 683 | 2.3017 0 684 | 2.313 0 685 | 2.3244 0 686 | 2.3357 0 687 | 2.3471 0 688 | 2.3584 0 689 | 2.3697 0 690 | 2.3811 0 691 | 2.3924 0 692 | 2.4038 0 693 | 2.4151 0 694 | 2.4264 0 695 | 2.4378 0 696 | 2.4491 0 697 | 2.4605 0 698 | 2.4718 0 699 | 2.4831 0 700 | 2.4945 0 701 | 2.5058 0 702 | 2.5172 0 703 | 2.5285 0 704 | 2.5398 0 705 | 2.5512 0 706 | 2.5625 0 707 | 2.5739 0 708 | 2.5852 0 709 | 2.5965 0 710 | 2.6079 0 711 | 2.6192 0 712 | 2.6306 0 713 | 2.6419 0 714 | 2.6532 0 715 | 2.6646 0 716 | 2.6759 0 717 | 2.6873 0 718 | 2.6986 0 719 | 2.7099 0 720 | 2.7213 0 721 | 2.7326 0 722 | 2.744 0 723 | 2.7553 0 724 | 2.7666 0 725 | 2.778 0 726 | 2.7893 0 727 | 2.8007 0 728 | 2.812 0 729 | 2.8234 0 730 | 2.8347 0 731 | 2.846 0 732 | 2.8574 0 733 | 2.8687 0 734 | 2.8801 0 735 | 2.8914 0 736 | 2.9027 0 737 | 2.9141 0 738 | 2.9254 0 739 | 2.9368 0 740 | 2.9481 0 741 | 2.9594 0.0006 742 | 2.9708 0.0732 743 | 2.9821 0.951 744 | 2.9935 1.4531 745 | 3.0048 0.2724 746 | 3.0161 0.0055 747 | 3.0275 0 748 | 3.0388 0 749 | 3.0502 0.0021 750 | 3.0615 0.3253 751 | 3.0728 5.0448 752 | 3.0842 9.2141 753 | 3.0955 3.466 754 | 3.1069 6.3639 755 | 3.1182 12.4622 756 | 3.1295 16.0728 757 | 3.1409 9.5364 758 | 3.1522 2.2706 759 | 3.1636 12.1023 760 | 3.1749 15.9258 761 | 3.1862 15.8067 762 | 3.1976 31.8653 763 | 3.2089 40.8119 764 | 3.2203 18.6925 765 | 3.2316 7.0944 766 | 3.2429 2.2415 767 | 3.2543 1.5731 768 | 3.2656 6.3053 769 | 3.277 11.2669 770 | 3.2883 12.9381 771 | 3.2996 10.5514 772 | 3.311 8.7043 773 | 3.3223 28.0802 774 | 3.3337 24.2305 775 | 3.345 20.782 776 | 3.3563 10.5656 777 | 3.3677 19.3735 778 | 3.379 29.5036 779 | 3.3904 19.1146 780 | 3.4017 9.0478 781 | 3.413 21.1988 782 | 3.4244 35.5748 783 | 3.4357 28.182 784 | 3.4471 35.4452 785 | 3.4584 29.5417 786 | 3.4697 25.1727 787 | 3.4811 23.0274 788 | 3.4924 16.1216 789 | 3.5038 24.614 790 | 3.5151 34.246 791 | 3.5264 55.5949 792 | 3.5378 48.4647 793 | 3.5491 23.7592 794 | 3.5605 19.2367 795 | 3.5718 19.7774 796 | 3.5831 16.6736 797 | 3.5945 20.4059 798 | 3.6058 33.5161 799 | 3.6172 27.1679 800 | 3.6285 9.9702 801 | 3.6398 1.5331 802 | 3.6512 11.4028 803 | 3.6625 30.1774 804 | 3.6739 16.3714 805 | 3.6852 5.9071 806 | 3.6965 8.6814 807 | 3.7079 6.2829 808 | 3.7192 1.1712 809 | 3.7306 1.5927 810 | 3.7419 0.5077 811 | 3.7532 0.0181 812 | 3.7646 0.0001 813 | 3.7759 0.0079 814 | 3.7873 0.3319 815 | 3.7986 1.5117 816 | 3.8099 0.8484 817 | 3.8213 0.0554 818 | 3.8326 0.0004 819 | 3.844 0 820 | 3.8553 0 821 | 3.8666 0 822 | 3.878 0 823 | 3.8893 0 824 | 3.9007 0 825 | 3.912 0 826 | 3.9233 0 827 | 3.9347 0 828 | 3.946 0 829 | 3.9574 0 830 | 3.9687 0 831 | 3.98 0 832 | 3.9914 0 833 | 4.0027 0 834 | 4.0141 0 835 | 4.0254 0 836 | 4.0368 0 837 | 4.0481 0 838 | 4.0594 0 839 | 4.0708 0 840 | 4.0821 0 841 | 4.0935 0 842 | 4.1048 0 843 | 4.1161 0 844 | 4.1275 0 845 | 4.1388 0 846 | 4.1502 0 847 | 4.1615 0 848 | 4.1728 0 849 | 4.1842 0 850 | 4.1955 0 851 | 4.2069 0 852 | 4.2182 0 853 | 4.2295 0 854 | 4.2409 0 855 | 4.2522 0 856 | 4.2636 0 857 | 4.2749 0 858 | 4.2862 0 859 | 4.2976 0 860 | 4.3089 0 861 | 4.3203 0 862 | 4.3316 0 863 | 4.3429 0.0063 864 | 4.3543 0.6385 865 | 4.3656 6.58 866 | 4.377 8.0822 867 | 4.3883 1.2082 868 | 4.3996 0.019 869 | 4.411 0.036 870 | 4.4223 1.6828 871 | 4.4337 10.9835 872 | 4.445 14.9265 873 | 4.4563 11.3398 874 | 4.4677 6.0989 875 | 4.479 4.3104 876 | 4.4904 5.7597 877 | 4.5017 13.6181 878 | 4.513 15.0851 879 | 4.5244 8.7797 880 | 4.5357 5.9432 881 | 4.5471 18.9728 882 | 4.5584 24.3878 883 | 4.5697 13.1953 884 | 4.5811 1.9164 885 | 4.5924 0.0391 886 | 4.6038 0.2341 887 | 4.6151 4.755 888 | 4.6264 11.0661 889 | 4.6378 4.8784 890 | 4.6491 9.3383 891 | 4.6605 7.1566 892 | 4.6718 1.1403 893 | 4.6831 1.7779 894 | 4.6945 15.3485 895 | 4.7058 32.6358 896 | 4.7172 15.3461 897 | 4.7285 3.9717 898 | 4.7398 13.0787 899 | 4.7512 10.3227 900 | 4.7625 4.0577 901 | 4.7739 20.5664 902 | 4.7852 20.2478 903 | 4.7965 3.1046 904 | 4.8079 0.0914 905 | 4.8192 0.0005 906 | 4.8306 0 907 | 4.8419 0 908 | 4.8532 0 909 | 4.8646 0 910 | 4.8759 0 911 | 4.8873 0 912 | 4.8986 0 913 | 4.9099 0 914 | 4.9213 0 915 | 4.9326 0 916 | 4.944 0 917 | 4.9553 0 918 | 4.9666 0 919 | 4.978 0 920 | 4.9893 0 921 | 5.0007 0 922 | 5.012 0 923 | 5.0233 0 924 | 5.0347 0 925 | 5.046 0 926 | 5.0574 0 927 | 5.0687 0 928 | 5.08 0 929 | 5.0914 0 930 | 5.1027 0 931 | 5.1141 0 932 | 5.1254 0 933 | 5.1367 0 934 | 5.1481 0 935 | 5.1594 0 936 | 5.1708 0 937 | 5.1821 0 938 | 5.1935 0 939 | 5.2048 0 940 | 5.2161 0 941 | 5.2275 0 942 | 5.2388 0 943 | 5.2502 0 944 | 5.2615 0 945 | 5.2728 0 946 | 5.2842 0 947 | 5.2955 0 948 | 5.3069 0 949 | 5.3182 0 950 | 5.3295 0 951 | 5.3409 0 952 | 5.3522 0 953 | 5.3636 0 954 | 5.3749 0 955 | 5.3862 0 956 | 5.3976 0 957 | 5.4089 0 958 | 5.4203 0 959 | 5.4316 0 960 | 5.4429 0 961 | 5.4543 0 962 | 5.4656 0 963 | 5.477 0 964 | 5.4883 0 965 | 5.4996 0 966 | 5.511 0 967 | 5.5223 0 968 | 5.5337 0 969 | 5.545 0 970 | 5.5563 0 971 | 5.5677 0 972 | 5.579 0 973 | 5.5904 0 974 | 5.6017 0 975 | 5.613 0 976 | 5.6244 0 977 | 5.6357 0 978 | 5.6471 0 979 | 5.6584 0 980 | 5.6697 0 981 | 5.6811 0 982 | 5.6924 0 983 | 5.7038 0 984 | 5.7151 0 985 | 5.7264 0 986 | 5.7378 0 987 | 5.7491 0 988 | 5.7605 0 989 | 5.7718 0 990 | 5.7831 0 991 | 5.7945 0 992 | 5.8058 0 993 | 5.8172 0 994 | 5.8285 0 995 | 5.8398 0 996 | 5.8512 0 997 | 5.8625 0 998 | 5.8739 0 999 | 5.8852 0 1000 | 5.8965 0 1001 | 5.9079 0 1002 | 5.9192 0 1003 | 5.9306 0 1004 | 5.9419 0 1005 | 5.9532 0 1006 | 5.9646 0 1007 | 5.9759 0 1008 | 5.9873 0 1009 | 5.9986 0 1010 | 6.0099 0 1011 | 6.0213 0 1012 | 6.0326 0 1013 | 6.044 0 1014 | 6.0553 0 1015 | 6.0666 0 1016 | 6.078 0 1017 | 6.0893 0 1018 | 6.1007 0 1019 | 6.112 0 1020 | 6.1233 0 1021 | 6.1347 0 1022 | 6.146 0 1023 | 6.1574 0 1024 | 6.1687 0 1025 | 6.18 0 1026 | 6.1914 0 1027 | 6.2027 0 1028 | 6.2141 0 1029 | 6.2254 0 1030 | 6.2367 0 1031 | 6.2481 0 1032 | 6.2594 0 1033 | 6.2708 0 1034 | 6.2821 0 1035 | 6.2934 0 1036 | 6.3048 0 1037 | 6.3161 0 1038 | 6.3275 0 1039 | 6.3388 0 1040 | 6.3501 0 1041 | 6.3615 0 1042 | 6.3728 0 1043 | 6.3842 0 1044 | 6.3955 0 1045 | 6.4069 0 1046 | 6.4182 0 1047 | 6.4295 0 1048 | 6.4409 0 1049 | 6.4522 0 1050 | 6.4636 0 1051 | 6.4749 0 1052 | 6.4862 0 1053 | 6.4976 0 1054 | 6.5089 0 1055 | 6.5203 0 1056 | 6.5316 0 1057 | 6.5429 0 1058 | 6.5543 0 1059 | 6.5656 0 1060 | 6.577 0 1061 | 6.5883 0 1062 | 6.5996 0 1063 | 6.611 0 1064 | 6.6223 0 1065 | 6.6337 0 1066 | 6.645 0 1067 | 6.6563 0 1068 | 6.6677 0 1069 | 6.679 0 1070 | 6.6904 0 1071 | 6.7017 0 1072 | 6.713 0 1073 | 6.7244 0 1074 | 6.7357 0 1075 | 6.7471 0 1076 | 6.7584 0 1077 | 6.7697 0 1078 | 6.7811 0 1079 | 6.7924 0 1080 | 6.8038 0 1081 | 6.8151 0 1082 | 6.8264 0 1083 | 6.8378 0 1084 | 6.8491 0 1085 | 6.8605 0 1086 | 6.8718 0 1087 | 6.8831 0 1088 | 6.8945 0 1089 | 6.9058 0 1090 | 6.9172 0 1091 | 6.9285 0 1092 | 6.9398 0 1093 | 6.9512 0 1094 | 6.9625 0 1095 | 6.9739 0 1096 | 6.9852 0 1097 | 6.9965 0 1098 | 7.0079 0 1099 | 7.0192 0 1100 | 7.0306 0 1101 | 7.0419 0 1102 | 7.0532 0 1103 | 7.0646 0 1104 | 7.0759 0 1105 | 7.0873 0 1106 | 7.0986 0 1107 | 7.1099 0 1108 | 7.1213 0 1109 | 7.1326 0 1110 | 7.144 0 1111 | 7.1553 0 1112 | 7.1666 0 1113 | 7.178 0 1114 | 7.1893 0 1115 | 7.2007 0 1116 | 7.212 0 1117 | 7.2233 0 1118 | 7.2347 0 1119 | 7.246 0 1120 | 7.2574 0 1121 | 7.2687 0 1122 | 7.28 0 1123 | 7.2914 0 1124 | 7.3027 0 1125 | 7.3141 0 1126 | 7.3254 0 1127 | 7.3367 0 1128 | 7.3481 0 1129 | 7.3594 0 1130 | -------------------------------------------------------------------------------- /work_in_progress/defap_defects.py: -------------------------------------------------------------------------------- 1 | import decimal 2 | import math 3 | from scipy import optimize, interpolate 4 | from decimal import * 5 | decimal.getcontext().prec=50 6 | from defap_misc import take_closest 7 | import numpy as np 8 | 9 | 10 | class Defects: 11 | def __init__(self, data, chemical_potentials, entropy_vals): 12 | self.data = data 13 | self.chemical_potentials = chemical_potentials 14 | self.entropy_vals = entropy_vals 15 | 16 | self.formation_energies_vbm = {} 17 | self.formation_energies = {} 18 | self.concentrations = {} 19 | self.fermi_level = None 20 | self.defect_chg_sum = 0 21 | self.temp = 0 22 | 23 | self.boltzmann = 0.000086173324 24 | 25 | def calc_form_eng_vbm(self): 26 | 27 | # calculate formation energies at valence band maximum 28 | for defect_name, defect_vals in self.data.defects_data.items(): 29 | 30 | # pull vals from defects_dict for each defect 31 | defect_group, multiplicity, site_num, defect_charge, defect_energy, tab_correction, atoms_added_removed = defect_vals.values() 32 | 33 | # add chemical potential contributions of each element in the defect to the formation energy 34 | chem_pot_contributions = 0 35 | for element in self.chemical_potentials: 36 | chem_pot_contributions += atoms_added_removed[element] * self.chemical_potentials[element] 37 | 38 | 39 | # calculate defect form eng at valence band maximum 40 | defect_form_eng_vbm = defect_energy - self.data.host_energy_supercell + (defect_charge * self.data.e_vbm) + chem_pot_contributions 41 | 42 | # simple cubic point charge 43 | if self.data.coulombic_correction == 1: 44 | defect_form_eng_vbm += 14.39942 * 2.8383 * defect_charge**2 / (2*self.data.length * self.data.dielectric_constant) 45 | 46 | # anisotropic charge correction 47 | elif self.data.coulombic_correction == 2: 48 | defect_form_eng_vbm += (14.39942 * ((defect_charge ** 2 * self.data.screened_madelung) / 2)) 49 | 50 | # add tabulated corrections in defects_dict to the formation energies 51 | if self.data.tab_correction: 52 | defect_form_eng_vbm += tab_correction 53 | 54 | # add entropy contributions to defect formation energies if provided 55 | if self.entropy_vals: 56 | host_name = list(self.entropy_vals.keys())[0] 57 | 58 | dS = self.entropy_vals[defect_name] - self.entropy_vals[host_name] 59 | 60 | defect_form_eng_vbm -= (self.data.temperature * dS) 61 | 62 | # add defect name and vbm form energy to the dict 63 | self.formation_energies_vbm[defect_name] = defect_form_eng_vbm 64 | 65 | 66 | return self.formation_energies_vbm 67 | 68 | def calc_form_eng_at_fermi(self, fermi_level): 69 | 70 | # add fermi level contribution to the formation energy 71 | for defect in self.formation_energies_vbm: 72 | self.formation_energies[defect] = self.formation_energies_vbm[defect] + (fermi_level * self.data.defects_data[defect]["defect_charge"]) 73 | 74 | return self.formation_energies 75 | 76 | def calc_charge_carriers_conc(self, method, limits, energies, states, valband, condband, fermi_level, e_or_p): 77 | 78 | # calculate concentration of electrons or holes depending on the method specified 79 | if method == "off": 80 | # set to min concentration 81 | conc = 10e-200 82 | 83 | elif method == "boltzmann": 84 | if e_or_p == -1: 85 | conc = valband * math.exp(-((fermi_level) / (self.data.temperature * self.boltzmann))) 86 | elif e_or_p == 1: 87 | conc = condband * math.exp(-((self.data.bandgap - fermi_level) / (self.data.temperature * self.boltzmann))) 88 | else: 89 | raise ValueError("Invalid e_or_p value ???") 90 | 91 | elif method == "fermi-dirac": 92 | # divide DOS by number of formula units used to calculate DOS 93 | states_per_fu = states / self.data.fu_unit_cell 94 | 95 | # determine the VBM and CBM energy in the DOS file closest to the values in the limits provided 96 | closest_band_min = take_closest(energies, float(limits[0])) 97 | closest_band_max = take_closest(energies, float(limits[1])) 98 | 99 | # get the list index of the found VBM and CBM energies 100 | band_min_index = np.where(energies == closest_band_min)[0][0] 101 | band_max_index = np.where(energies == closest_band_max)[0][0] 102 | 103 | # numerically integrate the DOS between the limits provided to calculate electron/hole concentrations 104 | # e_or_p = 1 -> electrons | e_or_p = -1 -> holes 105 | if e_or_p == 1: 106 | conc = np.trapezoid(self.electron_intergrand(energies, states_per_fu,band_positions=[band_min_index, band_max_index],fermi_level=fermi_level), 107 | energies[band_min_index:band_max_index], 108 | dx=energies[1] - energies[0] 109 | ) 110 | else: 111 | conc = np.trapezoid(self.hole_intergrand(energies, states_per_fu, band_positions=[band_min_index, band_max_index],fermi_level=fermi_level), 112 | energies[band_min_index:band_max_index], 113 | dx=energies[1] - energies[0] 114 | ) 115 | 116 | elif method == "fixed": 117 | pass 118 | 119 | elif method == "effective_masses": 120 | vol_cell_cm3 = self.data.volume_unit_cell * 1e-30 121 | if e_or_p == 1: 122 | N_c = self.effective_masses(temperature=self.data.temperature, effect_mass=self.data.electron_effective_masses) 123 | conc = ((N_c * vol_cell_cm3) / self.data.fu_unit_cell) * math.exp(-((self.data.bandgap - fermi_level) / (self.data.temperature * self.boltzmann))) 124 | else: 125 | N_v = self.effective_masses(temperature=self.data.temperature, effect_mass=self.data.hole_effective_masses) 126 | conc = ((N_v * vol_cell_cm3) / self.data.fu_unit_cell) * math.exp(-((fermi_level) / (self.data.temperature * self.boltzmann))) 127 | 128 | return conc 129 | 130 | def electron_intergrand(self, energies, states, band_positions, fermi_level): 131 | # function to be integrated to calculate electron concentrations 132 | return states[band_positions[0]:band_positions[1]] * (1 / (1 + np.exp( 133 | (energies[band_positions[0]:band_positions[1]] - fermi_level) / (self.boltzmann * self.data.temperature)))) 134 | 135 | def hole_intergrand(self, energies, states, band_positions, fermi_level): 136 | # function to be integrated to calculate hole concentrations 137 | return states[band_positions[0]:band_positions[1]] * (1 / (1 + np.exp( 138 | (fermi_level - energies[band_positions[0]:band_positions[1]]) / (self.boltzmann * self.data.temperature)))) 139 | 140 | def effective_masses(self, temperature, effect_mass,): 141 | 142 | boltzmann_SI = 1.380649E-23 143 | planck_SI = 6.62607015E-34 144 | 145 | em = np.array(effect_mass) 146 | 147 | x, y = em[:,0], em[:,1] 148 | 149 | tck = interpolate.splrep(x, y) 150 | 151 | mass_eff = interpolate.splev(temperature, tck) 152 | 153 | return (2 * ((2* math.pi * mass_eff * 9.11e-31 * boltzmann_SI * temperature) / (planck_SI**2)) ** (3/2)) 154 | 155 | 156 | def calc_defect_concentrations(self): 157 | 158 | # calculate defect concentrations and determine total ionic chg contribution of these defects 159 | concentrations = {} 160 | defect_chg_sum = 0 161 | 162 | for defect, defect_vals in self.data.defects_data.items(): 163 | 164 | defect_multiplicity = defect_vals["multiplicity"] 165 | defect_charge = defect_vals["defect_charge"] 166 | 167 | if self.data.defect_conc_method == "boltzmann": 168 | #print(defect, self.formation_energies[defect]) 169 | concentration = defect_multiplicity * math.exp(-self.formation_energies[defect] / (self.boltzmann * self.data.temperature)) 170 | 171 | elif self.data.defect_conc_method == "kasamatsu": 172 | pass 173 | 174 | # cant remember why we do this??? 175 | # think python struggles with logs and precision when smaller than this 176 | if concentration < 1e-200: 177 | concentration = -200 178 | else: 179 | concentration = math.log10(concentration) 180 | 181 | # determine chg contribution of defects 182 | defect_chg_sum += (defect_charge * 10 ** concentration) 183 | 184 | concentrations[defect] = concentration 185 | 186 | return concentrations, defect_chg_sum 187 | 188 | def calc_concentrations(self, fermi_level): 189 | 190 | # calculate concentration of holes 191 | hole_conc = self.calc_charge_carriers_conc(method=self.data.hole_method, 192 | limits=self.data.valenceband_limits, 193 | energies=self.data.dos_data["energies"], 194 | states=self.data.dos_data["states"], 195 | valband=self.data.valenceband, 196 | condband=self.data.conductionband, 197 | fermi_level=fermi_level, 198 | e_or_p=-1 199 | ) 200 | 201 | 202 | # concentration of electrons 203 | elec_conc = self.calc_charge_carriers_conc(method=self.data.electron_method, 204 | limits=self.data.conductionband_limits, 205 | energies=self.data.dos_data["energies"], 206 | states=self.data.dos_data["states"], 207 | valband=self.data.valenceband, 208 | condband=self.data.conductionband, 209 | fermi_level=fermi_level, 210 | e_or_p=1 211 | ) 212 | 213 | 214 | # calculate formation energies at current fermi level 215 | self.calc_form_eng_at_fermi(fermi_level=fermi_level) 216 | 217 | # then calculate defect concentrations at this fermi level 218 | self.concentrations, self.defect_chg_sum = self.calc_defect_concentrations() 219 | 220 | # determine total charge 221 | # used to optimise fermi level 222 | total_charge = self.defect_chg_sum - elec_conc + hole_conc + (self.data.art_dopant_conc * self.data.art_dopant_chg) 223 | 224 | # add electron/holes to concentrations dict 225 | self.concentrations["electrons"] = math.log10(elec_conc) 226 | self.concentrations["holes"] = math.log10(hole_conc) 227 | 228 | return total_charge 229 | 230 | def optimise_fermi_level(self): 231 | 232 | # optimise the position of the fermi level by finding the point where total charge = 0 233 | # uses brentq scipy formula 234 | try: 235 | self.fermi_level = optimize.brentq(f=self.calc_concentrations, a=0, b=self.data.bandgap, maxiter=500) 236 | except ValueError: 237 | raise ValueError("\n ERROR. Unable to determine the Fermi Level.\n" 238 | "Your initial conditions likely result in the root Fermi level for charge neutrality to be" 239 | f" outside the bandgap." 240 | ) 241 | 242 | return self.concentrations 243 | 244 | def calc_single_dopant_concentration(self, dopant_chemical_potential, dopant): 245 | 246 | # calculate the concentration of a single dopant at the provided chemical potential 247 | self.chemical_potentials[dopant] = dopant_chemical_potential 248 | target_dopant_conc = self.data.dopants[dopant]["concentration_pfu"] 249 | 250 | # calculate formation energies at vbm 251 | self.calc_form_eng_vbm() 252 | 253 | # now optimise fermi level with this dopant chemical potential 254 | # this also calculates defect concentrations 255 | self.optimise_fermi_level() 256 | 257 | 258 | # calculate total dopant concentration 259 | dopant_conc_sum = 0 260 | for defect, defect_vals in self.data.defects_data.items(): 261 | # -1 in defects dict indicates that an element is added into the lattice 262 | if defect_vals["added/removed"][dopant] < 0: 263 | dopant_conc_sum += 10 ** (self.concentrations[defect]) 264 | 265 | # calculate difference in calculated and desired dopant concentration 266 | target_conc_diff = dopant_conc_sum - target_dopant_conc 267 | 268 | 269 | return target_conc_diff 270 | 271 | def optimise_single_dopant(self, fitting_dopant): 272 | 273 | # optimise the chemical potential of a single dopant by fitting to a desired concentration 274 | 275 | # initial guess chemical potential of dopant 276 | dopant_chem_pot = self.data.dopants[fitting_dopant]["chemical_potential"] 277 | 278 | # +/- guessed bounds of chemical potential 279 | dopant_chem_pot_range = self.data.dopants[fitting_dopant]["chem_pot_range"] 280 | 281 | 282 | chem_pots_reattempts = np.arange(-50, 10, 1) 283 | attempt_num = 0 284 | while attempt_num < len(chem_pots_reattempts): 285 | 286 | # optimise dopant chemical potential by fitting to desired dopant chemical potential 287 | try: 288 | dopant_chem_pot = optimize.brentq(self.calc_single_dopant_concentration, dopant_chem_pot - dopant_chem_pot_range, dopant_chem_pot + dopant_chem_pot_range, args=(fitting_dopant)) 289 | break 290 | except: 291 | 292 | dopant_chem_pot = chem_pots_reattempts[attempt_num] 293 | dopant_chem_pot_range = 1 294 | 295 | attempt_num += 1 296 | 297 | else: 298 | raise ValueError("\n ERROR. Unable to determine dopant chemical potential.\n" 299 | f"Your target dopant concentration may be unobtainable for the chemical potential range: {dopant_chem_pot - dopant_chem_pot_range} - {dopant_chem_pot + dopant_chem_pot_range} eV") 300 | 301 | self.chemical_potentials[fitting_dopant] = dopant_chem_pot 302 | 303 | 304 | def calc_multi_dopant_conc(self, dopant_chemical_potentials, fitting_dopants): 305 | 306 | # calculate the concentration of multiple fitted dopants 307 | 308 | # assign chemical potentials to the dopants into the chemical potentials dict 309 | target_dopant_conc = [] 310 | for index, dopant_element in enumerate(fitting_dopants): 311 | self.chemical_potentials[dopant_element] = dopant_chemical_potentials[index] 312 | target_dopant_conc.append(self.data.dopants[dopant_element]["concentration_pfu"]) 313 | 314 | # calculate formation energies at vbm 315 | self.calc_form_eng_vbm() 316 | 317 | # now optimise fermi level with these dopant chemical potentials 318 | # this also calculates defect concentrations 319 | self.optimise_fermi_level() 320 | 321 | # determine difference in calculated and desired dopant concentrations 322 | dopant_conc_diffs = [] 323 | for index, dopant_element in enumerate(fitting_dopants): 324 | dopant_conc_sum = 0 325 | for defect, defect_vals in self.data.defects_data.items(): 326 | if defect_vals["added/removed"][dopant_element] < 0: 327 | dopant_conc_sum += 10 ** (self.concentrations[defect]) 328 | 329 | # calculate absolute log difference in targe and desired concentration and add to list 330 | dopant_conc_diffs.append(np.abs(np.log(target_dopant_conc[index]) - np.log(dopant_conc_sum))) 331 | 332 | # convert list to numpy array 333 | target_dopant_concs_diff = np.array(dopant_conc_diffs) 334 | 335 | # calculate sum of the differences 336 | # this will be minimised using optimiser 337 | return np.sum(target_dopant_concs_diff) 338 | 339 | 340 | def optimise_multi_dopant(self): 341 | 342 | # optimise chemical potentials of multiple dopants 343 | 344 | # initial guesses 345 | x0 = [] 346 | 347 | # chemical potential bounds of each dopant 348 | bnds = [] 349 | 350 | # list of dopants to be fitted 351 | dopant_elements = [] 352 | 353 | # loop through dopants, determine dopants to be fitted 354 | for dopant, dopant_vals in self.data.dopants.items(): 355 | if dopant_vals["fitting_option"] == 1 or dopant_vals["fitting_option"] == 2: 356 | # add initial guess of dopant chemical potential to list 357 | x0.append(dopant_vals["chemical_potential"]) 358 | 359 | # +/- guessed bounds of chemical potential 360 | element_bnds = (dopant_vals["chemical_potential"] - self.data.dopants[dopant]["chem_pot_range"], 361 | dopant_vals["chemical_potential"] + self.data.dopants[dopant]["chem_pot_range"] 362 | ) 363 | 364 | bnds.append(element_bnds) 365 | dopant_elements.append(dopant) 366 | 367 | # the function itself is a constraint as it needs to sum of differences in target and calculated concentrations needs to be zero 368 | constraints = {"type": "eq", "fun": self.calc_multi_dopant_conc, "args": [dopant_elements]} 369 | 370 | attempt_num = 1 371 | while attempt_num < 100: 372 | 373 | # optimise chemical potentials using SLSQP 374 | sol = optimize.minimize(self.calc_multi_dopant_conc, np.array(x0), method="SLSQP", bounds=tuple(bnds), 375 | args=dopant_elements, constraints=(constraints), options={"disp":False}) 376 | 377 | # check that individual dopants meet the target concentration 378 | # sometimes slsqp minimiser doesn't quite meet the criteria 379 | 380 | dopant_log_diffs = [] 381 | for index, dopant in enumerate(dopant_elements): 382 | 383 | # calculate total dopant concetration 384 | dopant_conc_sum = 0 385 | for defect, defect_vals in self.data.defects_data.items(): 386 | if defect_vals["added/removed"][dopant] < 0: 387 | dopant_conc_sum += 10 ** (self.concentrations[defect]) 388 | 389 | # calc log difference between calculated and target concentration 390 | log_diff = np.log10(self.data.dopants[dopant]["concentration_pfu"]) - np.log10(dopant_conc_sum) 391 | 392 | # shift chemical potential bounds depending on if difference +ve or -ve 393 | if log_diff > 0: 394 | bnds[index] = (self.chemical_potentials[dopant], bnds[index][1]) 395 | else: 396 | bnds[index] = (bnds[index][0], self.chemical_potentials[dopant]) 397 | 398 | # re adjust initial guessed chem pot 399 | x0[index] = np.average(bnds[index]) 400 | 401 | # add log difference between target and calculated dopant concentration to list 402 | dopant_log_diffs.append(abs(log_diff)) 403 | 404 | # break loop if all dopant concentrations satisfactory 405 | if (np.array(dopant_log_diffs) < 5e-3).all(): 406 | break 407 | 408 | attempt_num+=1 409 | 410 | else: 411 | raise ValueError(f"\n ERROR. Unable to determine dopant chemical potential.\n{self.chemical_potentials}\n{dopant_log_diffs}") 412 | 413 | 414 | def calc_stoichiometry(self): 415 | 416 | # initial values for the volatile numerator / metal denominator 417 | # use decimal module to get increase precision for very small +-x 418 | volatile_numerator = Decimal(0) 419 | metal_denominator = Decimal(0) 420 | denominator_stoic_sum = Decimal(0) 421 | volatile_element = self.data.constituents["volatile"]["volatile_element"] 422 | 423 | # get perfect stoichiometric ratios of volatile and metal 424 | for host_element, element_stoic in self.data.host["elements"].items(): 425 | if host_element == volatile_element: 426 | volatile_stoic = Decimal(element_stoic) 427 | volatile_numerator += volatile_stoic 428 | 429 | else: 430 | metal_denominator += Decimal(element_stoic) 431 | denominator_stoic_sum += Decimal(element_stoic) 432 | 433 | # loop through defects 434 | for defect_name, defect_vals in self.data.defects_data.items(): 435 | 436 | # get concentration and which elements are added/removed in this defect 437 | defect_concentration = Decimal(self.concentrations[defect_name]) 438 | defect_elements_added_removed = defect_vals["added/removed"] 439 | 440 | # +- stoic for numerator if defect is a volatile is added/removed 441 | for element, val in defect_elements_added_removed.items(): 442 | if element == volatile_element: 443 | #volatile_numerator += np.longdouble(-val * np.power(10, defect_concentration)) 444 | volatile_numerator += Decimal(-val * np.power(10, defect_concentration)) 445 | 446 | # if not volatile and element is in the host, then consider it a metal 447 | elif element in self.data.host["elements"] and element is not volatile_element: 448 | #metal_denominator += np.longdouble(-val * np.power(10, defect_concentration)) 449 | metal_denominator += Decimal(-val * np.power(10, defect_concentration)) 450 | 451 | # for dopants to be consider metal elements 452 | elif self.data.stoichiometry == 2: 453 | #metal_denominator += np.longdouble(-val * np.power(10, defect_concentration)) 454 | metal_denominator += Decimal(-val * np.power(10, defect_concentration)) 455 | 456 | # calculate stoichiometry and log10(stoich) (for plotting) 457 | stoichiometry = ((volatile_numerator / (metal_denominator / denominator_stoic_sum)) - volatile_stoic) 458 | log_stoic = np.log10(np.abs(stoichiometry)) 459 | 460 | return log_stoic, stoichiometry 461 | 462 | -------------------------------------------------------------------------------- /work_in_progress/defap_input.py: -------------------------------------------------------------------------------- 1 | import os 2 | import csv 3 | import numpy as np 4 | import defap_misc 5 | 6 | 7 | class ReadInputData: 8 | 9 | def __init__(self, seedname: str): 10 | 11 | self.seedname = seedname 12 | 13 | # list of tasks 14 | self.tasks = None 15 | 16 | # loop properties for brouwer/defect phase task 17 | self.loop = None 18 | self.min_value = None 19 | self.max_value = None 20 | self.iterator = None 21 | 22 | # second loop variable for defect phase task 23 | self.loop_y = None 24 | self.min_value_y = None 25 | self.max_value_y = None 26 | self.iterator_y = None 27 | 28 | # plot as function of loop or stoichiometry | 1 = loop, 2 = stoich 29 | self.x_variable = 1 30 | 31 | # method to calculate stoichiometry | 0 = dont calc, 1 = consider defects leaving due to dopant 32 | # 2 = dopants considered as a metal species 33 | self.stoichiometry = 0 34 | 35 | # temperature of system 36 | self.temperature = 1000 37 | 38 | # properties of host species 39 | self.host = None 40 | self.host_energy_pfu = None 41 | self.host_energy_supercell = None 42 | 43 | # properties of bandstructure of system 44 | self.e_vbm = 0 45 | self.bandgap = 0 46 | self.charged_system = False 47 | 48 | # method to calculate chemical potentials 49 | self.chem_pot_method = None 50 | 51 | # constituents of host system 52 | self.constituents = None 53 | 54 | # dopants incorporated 55 | self.dopants = None 56 | self.dopants_to_fit = 0 57 | 58 | # any artificial dopant charges added and its concentration 59 | self.art_dopant_conc = 0 60 | self.art_dopant_chg = 0 61 | 62 | # dict for secondary phases 63 | self.secondary_phases = None 64 | 65 | # For calculating volatile chemical potentials | 0 = ideal gas, 1 = real gas (Shomate), 66 | # | 2 = Johnson et al (Discontinued), 3 = pyromat library 67 | self.real_gas = 0 68 | 69 | # method for calculating electron/hole concentrations | boltzmann, fermi-dirac 70 | self.electron_method = "off" 71 | self.hole_method = "off" 72 | self.conductionband = None 73 | self.valenceband = None 74 | self.conductionband_limits = None 75 | self.valenceband_limits = None 76 | self.electron_fixed_conc = None 77 | self.hole_fixed_conc = None 78 | self.electron_effective_masses = None 79 | self.hole_effective_masses = None 80 | 81 | # functional units of unit cell 82 | self.fu_unit_cell = None 83 | 84 | # volume and length of cell 85 | self.volume_unit_cell = None 86 | self.length = None 87 | 88 | # method for calculting defect concentrations | boltzmann or kasamatsu 89 | self.defect_conc_method = "boltzmann" 90 | 91 | # concentration units | 0 = per formula unit, 1 = cm-3 92 | self.conc_units = 0 93 | 94 | # limits of y-axis on brouwer plot 95 | self.y_axis_min = -20 96 | self.y_axis_max = 0 97 | 98 | # convergence of multi-dopant fitting 99 | self.tolerance = 1e-10 100 | self.max_iteration = 100 101 | self.slsqp_dial = 10 102 | 103 | # convergence critera for total charge and dopant concentration 104 | self.dopant_convergence = 1e-3 105 | self.charge_convergence = 1e-10 106 | 107 | # brouwer colour scheme | 0 = default, 1 = user defined 108 | self.colour_scheme = 0 109 | 110 | # include entropy contributions to formation energies 111 | self.entropy = 0 112 | self.entropy_units = None 113 | 114 | # use gibbs temperature dependant energies for calculating chemical potentials 115 | self.include_gibbs = 0 116 | 117 | # whether to add charge corrections | 0 = dont add, 1 = cubic point charge, 2 = anisotropic point charge 118 | self.coulombic_correction = 0 119 | 120 | # add tabulated corrections in defects file 121 | self.tab_correction = False 122 | 123 | # values for calculating madelung constant for anisotropic point charge 124 | self.dielectric_constant = None 125 | self.screened_madelung = None 126 | self.dielectric_array = None 127 | self.lattice_array = None 128 | self.cutoff = 20 129 | self.gamma = 0.3 130 | 131 | # defect phases simplify polygon shapes parameters 132 | self.simplify_shape = False 133 | self.shape_tolerance = None 134 | 135 | # external file input data 136 | self.input_data = None 137 | self.defects_data = None 138 | self.dos_data = None 139 | self.entropy_data = None 140 | self.gibbs_data = None 141 | 142 | 143 | def read_input_file(self): 144 | 145 | """ 146 | Function that reads .input file and appends variables to a dictionary 147 | :param seed: 148 | :return: self.input_data 149 | """ 150 | 151 | # dictionary of variables with default values 152 | # only here so can be easily looped through to view all input variables 153 | self.input_data = { 154 | "tasks": None, 155 | "loop": None, "min_value": None, "max_value": None, "iterator": None, 156 | "loop_y": None, "min_value_y": None, "max_value_y": None, "iterator_y": None, 157 | "x_variable": 0, # plot as function of loop 158 | "temperature": 1000, # kelvin 159 | "host": None, "host_energy_pfu": None, "host_energy_supercell": None, 160 | "e_vbm": 0, "bandgap": 0, 161 | "chem_pot_method": None, 162 | "constituents": None, 163 | "dopants": None, 164 | "dopants_to_fit": 0, 165 | "art_dopant_conc": None, "art_dopant_chg": None, 166 | "secondary_phases": None, 167 | "real_gas": 0, # ideal gas relations 168 | "electron_method": "off", "hole_method": "off", 169 | "conductionband": None, "valenceband": None, 170 | "conduction_band_limits": None, "valence_band_limits": None, 171 | "fu_unit_cell": None, 172 | "volume_unit_cell": None, 173 | "stoichiometry": 0, # dont calculate 174 | "defect_conc_method": "boltzmann", 175 | "tab_correction": False, # dont add 176 | "concentration_units": 0, # per formula unit 177 | "y_axis_min": -15, "y_axis_max": 0, 178 | "tolerance": 1e-10, "max_iteration": 100, "SLSQP_dial": 10, # for multi dopants 179 | "dopant_convergence": 1e-3, 180 | "charge_convergence": 1e-10, 181 | "colour_scheme": 0, # defap default colours 182 | "entropy": 0, "entropy_units": None, 183 | "include_gibbs": 0, # dont include 184 | "coulombic_correction": 0, # no correction added 185 | "dielectric_constant": None, 186 | "screened_madelung": None, 187 | "length": None, 188 | "dielectric_array": None, 189 | "lattice_array": None, 190 | "cutoff": 30, "gamma": 0.5, # for calculatinf madelung constant 191 | "simplify_shape": False, "shape_tolerance": None 192 | } 193 | 194 | input_file = f"{self.seedname}.input" 195 | 196 | if not os.path.isfile(input_file): 197 | raise Exception("ERROR Input file not detected.\n" 198 | f"Please provide a [name.input] file.") 199 | 200 | #print(f">>> Reading in parameters from {input_file}\n") 201 | 202 | with open(input_file, "r") as f: 203 | # strip and split *.input file lines and append into a list. Skips empty lines 204 | lines = [s.strip().split() for s in f.readlines() if s.strip().split() != []] 205 | 206 | # loop through lines in .input file and add variables to dictionary. Certain cases require 207 | # additional processing lines to be added to the dict 208 | for line_index, line in enumerate(lines): 209 | 210 | variable = line[0].lower() 211 | 212 | 213 | 214 | if variable == "tasks": 215 | self.input_data[variable] = [s.lower() for s in line[2:]] 216 | self.tasks = [s.lower() for s in line[2:]] 217 | 218 | elif variable == "loop": 219 | self.input_data[variable] = int(line[2]) 220 | self.loop = int(line[2]) 221 | 222 | elif variable == "min_value": 223 | self.input_data[variable] = float(line[2]) 224 | self.min_value = float(line[2]) 225 | 226 | elif variable == "max_value": 227 | self.input_data[variable] = float(line[2]) 228 | self.max_value = float(line[2]) 229 | 230 | elif variable == "iterator": 231 | self.input_data[variable] = float(line[2]) 232 | self.iterator = float(line[2]) 233 | 234 | elif variable == "loop_y": 235 | self.input_data[variable] = float(line[2]) 236 | self.loop_y = float(line[2]) 237 | 238 | elif variable == "min_value_y": 239 | self.input_data[variable] = float(line[2]) 240 | self.min_value_y = float(line[2]) 241 | 242 | elif variable == "max_value_y": 243 | self.input_data[variable] = float(line[2]) 244 | self.max_value_y = float(line[2]) 245 | 246 | elif variable == "iterator_y": 247 | self.input_data[variable] = float(line[2]) 248 | self.iterator_y = float(line[2]) 249 | 250 | elif variable == "x_variable": 251 | self.input_data[variable] = int(line[2]) 252 | self.x_variable = int(line[2]) 253 | 254 | elif variable == "temperature": 255 | self.input_data[variable] = float(line[2]) 256 | self.temperature = float(line[2]) 257 | 258 | elif variable == "host": 259 | host_breakdown = defap_misc.break_formula(line[2]) 260 | self.input_data["host"] = {"formula": line[2], "elements": host_breakdown} 261 | self.host = {"formula": line[2], "elements": host_breakdown} 262 | 263 | elif variable == "host_energy_pfu": 264 | self.input_data["host_energy_pfu"] = float(line[2]) 265 | self.host_energy_pfu = float(line[2]) 266 | 267 | elif variable == "host_energy_supercell": 268 | self.input_data["host_energy_supercell"] = float(line[2]) 269 | self.host_energy_supercell = float(line[2]) 270 | 271 | elif variable == "e_vbm": 272 | self.input_data[variable] = float(line[2]) 273 | self.e_vbm = float(line[2]) 274 | 275 | elif variable == "bandgap": 276 | self.input_data[variable] = float(line[2]) 277 | self.bandgap = float(line[2]) 278 | 279 | elif variable == "chem_pot_method": 280 | self.input_data[variable] = line[2].lower() 281 | self.chem_pot_method = line[2].lower() 282 | 283 | elif variable == "art_dopant_conc": 284 | self.input_data[variable] = float(line[2]) 285 | self.art_dopant_conc = float(line[2]) 286 | 287 | elif variable == "art_dopant_chg": 288 | self.input_data[variable] = int(line[2]) 289 | self.art_dopant_chg = int(line[2]) 290 | 291 | elif variable == "secondary_phases": 292 | phases_lst = [] 293 | for i in range(int(line[2])): 294 | phases_lst.append(lines[line_index + i + 1]) 295 | 296 | self.input_data["secondary_phases"] = phases_lst 297 | self.secondary_phases = phases_lst 298 | 299 | elif variable == "real_gas": 300 | self.input_data[variable] = int(line[2]) 301 | self.real_gas = int(line[2]) 302 | 303 | elif variable == "electron_method": 304 | self.input_data[variable] = line[2].lower() 305 | self.electron_method = line[2].lower() 306 | 307 | if line[2].lower() == "effective_masses": 308 | self.electron_effective_masses = eval(line[3]) 309 | 310 | elif variable == "hole_method": 311 | self.input_data[variable] = line[2].lower() 312 | self.hole_method = line[2].lower() 313 | 314 | if line[2].lower() == "effective_masses": 315 | self.hole_effective_masses = eval(line[3]) 316 | 317 | elif variable == "conductionband": 318 | self.input_data[variable] = float(line[2]) 319 | self.conductionband = float(line[2]) 320 | 321 | elif variable == "valenceband": 322 | self.input_data[variable] = float(line[2]) 323 | self.valenceband = float(line[2]) 324 | 325 | elif variable == "fu_unit_cell": 326 | self.input_data[variable] = int(line[2]) 327 | self.fu_unit_cell = int(line[2]) 328 | 329 | elif variable == "volume_unit_cell": 330 | self.input_data[variable] = float(line[2]) 331 | self.volume_unit_cell = float(line[2]) 332 | 333 | elif variable == "stoichiometry": 334 | self.input_data[variable] = int(line[2]) 335 | self.stoichiometry = int(line[2]) 336 | 337 | elif variable == "defect_conc_method": 338 | self.input_data[variable] = line[2].lower() 339 | self.defect_conc_method = line[2].lower() 340 | 341 | elif variable == "concentration_units": 342 | self.input_data[variable] = int(line[2]) 343 | self.conc_units = int(line[2]) 344 | 345 | elif variable == "y_axis_min": 346 | self.input_data[variable] = float(line[2]) 347 | self.y_axis_min = float(line[2]) 348 | 349 | elif variable == "y_axis_max": 350 | self.input_data[variable] = float(line[2]) 351 | self.y_axis_max = float(line[2]) 352 | 353 | elif variable == "tolerance": 354 | self.input_data[variable] = float(line[2]) 355 | self.tolerance = float(line[2]) 356 | 357 | elif variable == "max_iteration": 358 | self.input_data[variable] = float(line[2]) 359 | self.max_iteration = float(line[2]) 360 | 361 | elif variable == "slsqp_dial": 362 | self.input_data[variable] = float(line[2]) 363 | self.slsqp_dial = float(line[2]) 364 | 365 | elif variable == "dopant_fit_convergence": 366 | self.input_data[variable] = float(line[2]) 367 | self.dopant_convergence = float(line[2]) 368 | 369 | elif variable == "charge_convergence": 370 | self.input_data[variable] = float(line[2]) 371 | self.charge_convergence = float(line[2]) 372 | 373 | elif variable == "colour_scheme": 374 | self.input_data[variable] = int(line[2]) 375 | self.colour_scheme = int(line[2]) 376 | 377 | elif variable == "entropy": 378 | self.input_data[variable] = int(line[2]) 379 | self.entropy = int(line[2]) 380 | 381 | elif variable == "entropy_units": 382 | self.input_data[variable] = int(line[2]) 383 | self.entropy_units = int(line[2]) 384 | 385 | elif variable == "gibbs": 386 | self.input_data["include_gibbs"] = int(line[2]) 387 | self.include_gibbs = int(line[2]) 388 | 389 | elif variable == "coulombic_correction": 390 | self.input_data[variable] = int(line[2]) 391 | self.coulombic_correction = int(line[2]) 392 | 393 | elif variable == "tab_correction": 394 | if line[2] == "1" or line[1].lower() == "t" or line[1].lower() == "true": 395 | self.tab_correction = True 396 | self.input_data[variable] = True 397 | else: 398 | self.tab_correction = False 399 | self.input_data[variable] = False 400 | 401 | elif variable == "dielectric_constant": 402 | self.input_data[variable] = float(line[2]) 403 | self.dielectric_constant = float(line[2]) 404 | 405 | elif variable == "screened_madelung": 406 | self.input_data[variable] = float(line[2]) 407 | self.screened_madelung = float(line[2]) 408 | 409 | elif variable == "length": 410 | self.input_data[variable] = float(line[2]) 411 | self.length = float(line[2]) 412 | 413 | elif variable == "cutoff": 414 | self.input_data[variable] = float(line[2]) 415 | self.cutoff = float(line[2]) 416 | 417 | elif variable == "gamma": 418 | self.input_data[variable] = float(line[2]) 419 | self.gamma = float(line[2]) 420 | 421 | elif variable == "constituents": 422 | constituents_lst = [] 423 | for i in range(int(line[2])): 424 | constituents_lst.append(lines[line_index + i + 1]) 425 | 426 | self.input_data["constituents"] = constituents_lst 427 | 428 | elif variable == "dopants": 429 | dopants_lst = [] 430 | for i in range(int(line[2])): 431 | dopants_lst.append(lines[line_index + i + 1]) 432 | 433 | self.input_data["dopants"] = dopants_lst 434 | 435 | elif variable == "dopant_table": 436 | dopants_lst = [] 437 | for i in range(int(line[2])): 438 | dopants_lst.append(lines[line_index + i + 1]) 439 | 440 | self.input_data["dopants"] = dopants_lst 441 | 442 | elif variable == "conduction_band_limits": 443 | self.input_data[variable] = line[2:] 444 | self.conductionband_limits = line[2:] 445 | 446 | elif variable == "valence_band_limits": 447 | self.input_data[variable] = line[2:] 448 | self.valenceband_limits = line[2:] 449 | 450 | elif variable == "lattice_array": 451 | lattice_array_lst = [] 452 | for i in range(3): 453 | row = list(map(float, lines[line_index + i + 1])) 454 | lattice_array_lst.append(row) 455 | 456 | self.input_data["lattice_array"] = lattice_array_lst 457 | self.lattice_array = np.array(lattice_array_lst) 458 | 459 | elif variable == "dielectric_array": 460 | dielectric_array_lst = [] 461 | for i in range(3): 462 | row = list(map(float, lines[line_index + i + 1])) 463 | dielectric_array_lst.append(row) 464 | 465 | self.input_data["dielectric_array"] = dielectric_array_lst 466 | self.dielectric_array = np.array(dielectric_array_lst) 467 | 468 | elif variable == "simplify_shape" and line[2] in ['t', 'true', '1']: 469 | self.input_data[variable] = True 470 | self.simplify_shape = True 471 | 472 | elif variable == "shape_tolerance": 473 | self.input_data[variable] = float(line[2]) 474 | self.shape_tolerance = float(line[2]) 475 | 476 | 477 | #case _: # underscore used to define default case 478 | # if variable in list(self.input_data.keys()):# 479 | 480 | # convert input values to float types if possible. If string, ensure all lower case 481 | #try: 482 | # input_value = float(line[2]) 483 | #except: 484 | # input_value = line[2].lower() 485 | #finally: 486 | # self.input_data[variable] = input_value 487 | 488 | # format constituents based on chem_pot_method 489 | self.input_data["constituents"] = defap_misc.format_constituents(self.input_data["constituents"],self.input_data["chem_pot_method"]) 490 | self.constituents = self.input_data["constituents"] 491 | 492 | # format dopants if provided 493 | if self.input_data["dopants"]: 494 | self.input_data["dopants"], self.input_data["dopants_to_fit"] = defap_misc.format_dopants(self.input_data["dopants"]) 495 | self.dopants, self.dopants_to_fit = self.input_data["dopants"], self.input_data["dopants_to_fit"] 496 | 497 | if self.secondary_phases: 498 | self.secondary_phases = defap_misc.format_secondary_phases(self.secondary_phases) 499 | self.input_data["secondary_phases"] = self.secondary_phases 500 | 501 | if self.bandgap > 0: 502 | self.charged_system = True 503 | 504 | 505 | if self.simplify_shape and self.shape_tolerance is None and "defect_phases" in self.tasks: 506 | self.shape_tolerance = 2 * min(self.iterator, self.iterator_y) 507 | self.input_data["shape_tolerance"] = 2 * min(self.iterator, self.iterator_y) 508 | 509 | 510 | return self.input_data 511 | 512 | 513 | def read_defects_file(self, host_compound_elements, dopants): 514 | self.defects_data = {} 515 | 516 | number_species = len(host_compound_elements) 517 | if dopants: 518 | number_species += len(dopants) 519 | 520 | # old .defects format 521 | if os.path.exists(f"./{self.seedname}.defects"): 522 | defectfile = f"{self.seedname}.defects" 523 | #print("\n>>> Reading in parameters from ", defectfile) 524 | 525 | with open(defectfile, "r") as f: 526 | # strip and split lines. Skip empty lines 527 | lines = [s.strip().split() for s in f.readlines() if s.strip().split() != []] 528 | 529 | # loop through rows and and indicies 530 | for row_index, defect_row in enumerate(lines): 531 | 532 | atoms_added_removed = {} 533 | 534 | # check that the required number of values for each defect has been specified 535 | if len(defect_row) != 7 + number_species: 536 | raise Exception("ERROR! Insufficient number of values defined for the defect:\n" 537 | f"{defect_row[0]}\n" 538 | f"Number of values provided: {len(defect_row)}\n" 539 | f"Number of values needed: {7 + number_species}\n" 540 | f"Did you specify all the species added/removed for each defect?") 541 | 542 | # assign defect values into dict 543 | individual_defect_dict = {"group": defect_row[1], 544 | "multiplicity": float(defect_row[2]), 545 | "defect_site": int(defect_row[3]), 546 | "defect_charge": int(defect_row[4]), 547 | "defect_energy": float(defect_row[5]), 548 | "tab_correction": float(defect_row[6]), 549 | } 550 | 551 | # loop through host elements and add whether an element is added/removed for each defect 552 | for element_index, host_element in enumerate(host_compound_elements.keys()): 553 | atoms_added_removed[host_element] = int(defect_row[7 + element_index]) 554 | 555 | # loop through dopants and add whether it is added/removed for each defect 556 | if dopants: 557 | for dopant_index, dopant in enumerate(dopants): 558 | atoms_added_removed[dopant] = int( 559 | defect_row[7 + len(host_compound_elements) + dopant_index]) 560 | 561 | individual_defect_dict["added/removed"] = atoms_added_removed 562 | 563 | # check if defect name is unique to add to the dict 564 | # if not, add a suffix to the name for the defect index 565 | if defect_row[0] in self.defects_data: 566 | defect_index = 2 567 | new_defect_name = defect_row[0] + f'_{defect_index}' 568 | while new_defect_name in self.defects_data: 569 | defect_index += 1 570 | new_defect_name = defect_row[0] + f'_{defect_index}' 571 | 572 | defect_row[0] = new_defect_name 573 | 574 | # add defect name and assign values to it in the dict 575 | self.defects_data[defect_row[0]] = individual_defect_dict 576 | 577 | return self.defects_data 578 | 579 | elif os.path.exists(f"./{self.seedname}_defects.csv"): 580 | defectfile = f"{self.seedname}_defects.csv" 581 | #print("\n>>> Reading in parameters from ", defectfile) 582 | 583 | with open(defectfile, "r") as csv_file: 584 | csv_reader = csv.reader(csv_file, delimiter=',') 585 | 586 | for row_index, defect_row in enumerate(csv_reader): 587 | 588 | atoms_added_removed = {} 589 | 590 | if row_index == 0: 591 | continue 592 | 593 | elif len(defect_row) == 0: 594 | continue 595 | 596 | elif len(defect_row) != 7 + number_species: 597 | raise Exception("ERROR! Insufficient number of values defined for the defect:\n" 598 | f"{defect_row[0]}\n" 599 | f"Number of values provided: {len(defect_row)}\n" 600 | f"Number of values needed: {7 + number_species}\n" 601 | f"Did you specify all the species added/removed for each defect?") 602 | 603 | else: 604 | individual_defect_dict = {"group": defect_row[1], 605 | "multiplicity": float(defect_row[2]), 606 | "defect_site": int(defect_row[3]), 607 | "defect_charge": int(defect_row[4]), 608 | "defect_energy": float(defect_row[5]), 609 | "tab_correction": float(defect_row[6]) 610 | } 611 | 612 | # loop through host elements and add whether an element is added/removed for each defect 613 | for element_index, host_element in enumerate(host_compound_elements.keys()): 614 | atoms_added_removed[host_element] = int(defect_row[7 + element_index]) 615 | 616 | # loop through dopants and add whether it is added/removed for each defect 617 | if dopants: 618 | for dopant_index, dopant in enumerate(dopants.keys()): 619 | atoms_added_removed[dopant] = int(defect_row[7 + len(host_compound_elements) + dopant_index]) 620 | 621 | individual_defect_dict["added/removed"] = atoms_added_removed 622 | 623 | # check if defect name is unique to add to the dict 624 | # if not, add a suffix to the name for the defect index 625 | if defect_row[0] in self.defects_data: 626 | defect_index = 2 627 | new_defect_name = defect_row[0] + f'_{defect_index}' 628 | while new_defect_name in self.defects_data: 629 | defect_index += 1 630 | new_defect_name = defect_row[0] + f'_{defect_index}' 631 | 632 | defect_row[0] = new_defect_name 633 | 634 | # add defect name and assign values to it in the dict 635 | self.defects_data[defect_row[0]] = individual_defect_dict 636 | 637 | return self.defects_data 638 | 639 | else: 640 | raise Exception("ERROR! No defects file is present.\nPlease provide a .defects or _defects.csv file") 641 | 642 | 643 | def read_dos_data(self): 644 | 645 | if os.path.exists(f"{self.seedname}.dos"): 646 | 647 | try: 648 | energy = np.loadtxt(f"{self.seedname}.dos", delimiter=' ', usecols=0) 649 | states = np.loadtxt(f"{self.seedname}.dos", delimiter=' ', usecols=1) 650 | 651 | except: 652 | try: 653 | energy = np.loadtxt(f"{self.seedname}.dos", delimiter='\t', usecols=0) 654 | states = np.loadtxt(f"{self.seedname}.dos", delimiter='\t', usecols=1) 655 | 656 | except: 657 | raise Exception("\n Error. Unable to read dos file.\n" 658 | "Ensure file format is in the format: 'energy' 'states'") 659 | 660 | self.dos_data = {"energies": energy, "states": states} 661 | 662 | else: 663 | self.dos_data = {"energies": None, "states": None} 664 | 665 | return self.dos_data 666 | 667 | 668 | def read_entropy_data(self): 669 | 670 | heading_names = [] 671 | 672 | # old .entropy txt file format 673 | if os.path.exists(f"./{self.seedname}.entropy") and self.entropy == 1: 674 | entropy_file = f"{self.seedname}.entropy" 675 | self.entropy_data = {} 676 | 677 | with open(entropy_file, "r") as f: 678 | # strip and split *.entropy file lines and append into a list. Skips empty lines 679 | lines = [s.strip().split() for s in f.readlines() if s.strip().split() != []] 680 | 681 | # loop through line rows 682 | for row_index, row in enumerate(lines): 683 | # loop through values in the row 684 | for value_index, row_value in enumerate(row): 685 | # index 0 is a header row containing defect names 686 | if row_index == 0: 687 | # initialise dict with key being defect name and value being an empty list 688 | self.entropy_data[row_value] = [] 689 | 690 | # store header names in separate list 691 | heading_names.append(row_value) 692 | else: 693 | # add entropy values to list for this defect 694 | self.entropy_data[heading_names[value_index]].append(float(row_value)) 695 | 696 | return self.entropy_data 697 | 698 | # csv format 699 | elif os.path.exists(f"./{self.seedname}_entropy.csv") and self.entropy == 1: 700 | entropy_file = f"{self.seedname}_entropy.csv" 701 | self.entropy_data = {} 702 | 703 | with open(entropy_file) as csv_file: 704 | csv_reader = csv.reader(csv_file, delimiter=',') 705 | 706 | # as before, loop though rows and row values and store defect names and entropy values in the dict 707 | for row_index, row in enumerate(csv_reader): 708 | for value_index, row_value in enumerate(row): 709 | if row_index == 0: 710 | self.entropy_data[row_value] = [] 711 | heading_names.append(row_value) 712 | else: 713 | self.entropy_data[heading_names[value_index]].append(float(row_value)) 714 | 715 | return self.entropy_data 716 | 717 | else: 718 | return None 719 | #raise Exception("ERROR! No entropy file is present.\nPlease provide a .entropy or _entropy.csv file") 720 | 721 | 722 | def read_gibbs_data(self): 723 | 724 | self.gibbs_data = {} 725 | heading_names = [] 726 | 727 | # old text .gibbs format 728 | if os.path.exists(f"./{self.seedname}.gibbs"): 729 | gibbs_file = f"{self.seedname}.gibbs" 730 | 731 | with open(gibbs_file, "r") as f: 732 | # strip and split *.gibbs file lines and append into a list. Skips empty lines 733 | lines = [s.strip().split() for s in f.readlines() if s.strip().split() != []] 734 | 735 | # loop through line rows 736 | for row_index, row in enumerate(lines): 737 | # loop through row values 738 | for value_index, row_value in enumerate(row): 739 | # defect name / constituent names are index 0 740 | if row_index == 0: 741 | # initialise dict with key being defect/constituent name and value being an empty list 742 | self.gibbs_data[row_value] = [] 743 | heading_names.append(row_value) 744 | else: 745 | # add gibbs energy temperature dependant values to list for this defect 746 | self.gibbs_data[heading_names[value_index]].append(float(row_value)) 747 | 748 | return self.gibbs_data 749 | 750 | # csv format 751 | elif os.path.exists(f"./{self.seedname}_gibbs.csv"): 752 | gibbs_file = f"{self.seedname}_gibbs.csv" 753 | with open(gibbs_file) as csv_file: 754 | csv_reader = csv.reader(csv_file, delimiter=',') 755 | 756 | # as before, loop though rows and row values and store names and gibbs energy values in the dict 757 | for row_index, row in enumerate(csv_reader): 758 | for value_index, row_value in enumerate(row): 759 | if row_index == 0: 760 | self.gibbs_data[row_value] = [] 761 | heading_names.append(row_value) 762 | else: 763 | self.gibbs_data[heading_names[value_index]].append(float(row_value)) 764 | 765 | return self.gibbs_data 766 | 767 | else: 768 | return None 769 | #raise Exception("ERROR! No Gibbs energy file is present.\nPlease provide a .gibbs or _gibbs.csv file") 770 | 771 | 772 | 773 | @staticmethod 774 | def print_input_data(input_val): 775 | """ 776 | A method just to easily and quickly print the parameters from input files 777 | :param input_val: 778 | """ 779 | 780 | if isinstance(input_val, dict): 781 | 782 | for key, val in input_val.items(): 783 | print(key, val) 784 | 785 | elif isinstance(input_val, list) or isinstance(input_val, tuple): 786 | for val in input_val: 787 | print(val) 788 | 789 | else: 790 | print(input_val) 791 | 792 | print("\n") 793 | 794 | 795 | 796 | 797 | 798 | 799 | -------------------------------------------------------------------------------- /work_in_progress/defap_output.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | import pandas as pd 4 | from datetime import datetime 5 | import matplotlib.pyplot as plt 6 | plt.close("all") 7 | 8 | def write_output_file(input_data, seedname): 9 | 10 | defects_data = input_data.defects_data 11 | 12 | with open(f"{seedname}.output", "w") as f: 13 | 14 | f.write("Defect Analysis Pacakge") 15 | f.write(", v: 4.0\n") 16 | 17 | f.write(f"\nDefAP executed on: {datetime.now().strftime('%d/%m/%Y %H:%M:%S')}\n\n") 18 | 19 | f.write(f">>> Tasks:\n\n") 20 | 21 | f.write(f" Number of tasks : {len(input_data.tasks)}\n") 22 | for task_num, task in enumerate(input_data.tasks, start=1): 23 | f.write(f" Task {task_num} : {task}\n") 24 | 25 | f.write("\n\n") 26 | 27 | f.write(">>> Host Material:\n\n") 28 | 29 | f.write(f" {'{:22s}'.format('Host')} : {input_data.host['formula']}\n") 30 | f.write(f" {'{:22s}'.format('Host energy pfu')} : {input_data.host_energy_pfu}\n") 31 | f.write(f" {'{:22s}'.format('Host energy supercell')} : {input_data.host_energy_supercell}\n") 32 | 33 | f.write("\n\n") 34 | 35 | f.write(">>> Electronic Properties:\n\n") 36 | 37 | f.write(f" {'{:15s}'.format('Bandgap')} : {input_data.bandgap}\n") 38 | f.write(f" {'{:15s}'.format('Energy of VBM')} : {input_data.e_vbm}\n") 39 | 40 | f.write("\n") 41 | 42 | if input_data.electron_method == "off": 43 | f.write(" Not calculating concentration of electrons\n") 44 | 45 | elif input_data.electron_method == "boltzmann": 46 | f.write(" Calculating concentration of electrons with Boltzmann statistics\n") 47 | 48 | elif input_data.electron_method == "fermi-dirac": 49 | f.write(" Calculating concentration of electrons with Fermi-Dirac statistics\n") 50 | f.write(f" Conduction band integral limits : {input_data.conductionband_limits[0]} - {input_data.conductionband_limits[1]}\n") 51 | f.write(f" Number of functional units per unit cell : {input_data.fu_unit_cell}\n") 52 | 53 | elif input_data.electron_method == "fixed": 54 | f.write(f" Fixed electron concentration of : {input_data.electron_fixed_conc}\n") 55 | 56 | elif input_data.electron_method == "effective_masses": 57 | f.write(f" Calculating electron concentration from effective masses\n") 58 | f.write(f" Electron effective masses : {input_data.electron_effective_masses}\n") 59 | f.write(f" Number of functional units per unit cell : {input_data.fu_unit_cell}\n") 60 | f.write(f" Volume of unit cell: {input_data.volume_unit_cell}\n") 61 | 62 | f.write("\n") 63 | 64 | if input_data.hole_method == "off": 65 | f.write(" Not calculating concentration of holes\n") 66 | 67 | elif input_data.hole_method == "boltzmann": 68 | f.write(" Calculating concentration of holes with Boltzmann statistics\n") 69 | 70 | elif input_data.hole_method == "fermi-dirac": 71 | f.write(" Calculating concentration of holes with Fermi-Dirac statistics\n") 72 | f.write(f" Valence band integral limits : {input_data.valenceband_limits[0]} - {input_data.valenceband_limits[1]}\n") 73 | f.write(f" Number of functional units per unit cell : {input_data.fu_unit_cell}\n") 74 | 75 | elif input_data.hole_method == "fixed": 76 | f.write(f" Fixed hole concentration of : {input_data.hole_fixed_conc}\n") 77 | 78 | elif input_data.hole_method == "effective_masses": 79 | f.write(f" Calculating hole concentration from effective masses\n") 80 | f.write(f" Hole effective masses : {input_data.hole_effective_masses}\n") 81 | f.write(f" Number of functional units per unit cell : {input_data.fu_unit_cell}\n") 82 | f.write(f" Volume of unit cell: {input_data.volume_unit_cell}\n") 83 | 84 | f.write("\n\n") 85 | 86 | f.write(">>> Calculation of Chemical Potentials:\n\n") 87 | 88 | if input_data.chem_pot_method == "defined": 89 | f.write(" Chemical potentials are defined\n") 90 | 91 | elif input_data.chem_pot_method == "rich-poor": 92 | f.write(" Rich-poor chemical potential method selected\n") 93 | 94 | elif input_data.chem_pot_method == "volatile": 95 | f.write(" Volatile chemical potential method selected\n") 96 | 97 | if input_data.real_gas == 0: 98 | f.write(" Assuming ideal gas relations\n") 99 | 100 | elif input_data.real_gas == 1 or input_data.real_gas == 2: 101 | f.write(" Calculating real gas relations using Shomate Equations\n") 102 | 103 | elif input_data.real_gas == 3: 104 | f.write(" Calculating real gas relations using PYroMat library (NASA equations)\n") 105 | 106 | f.write("\n") 107 | f.write(f" +{25*'-'}+{25*'-'}+\n") 108 | f.write(" |{:^25s}|{:^25s}|\n".format("Volatile", "Partial Pressure")) 109 | f.write(f" +{25*'-'}+{25*'-'}+\n") 110 | f.write(" | {:23s}| {:23s}|\n".format(input_data.constituents["volatile"]["volatile_element"], 111 | str(input_data.constituents["volatile"]["log_pp"]))) 112 | f.write(f" +{25 * '-'}+{25 * '-'}+\n") 113 | 114 | f.write("\n") 115 | 116 | f.write(f" +{25*'-'}+{25*'-'}+{25*'-'}+{25*'-'}+\n") 117 | f.write(" |{:^25s}|{:^25s}|{:^25s}|{:^25s}|\n".format("Constituent", "Compound Energy", "Metal Energy", "Std Formation Energy")) 118 | f.write(f" +{25 * '-'}+{25 * '-'}+{25 * '-'}+{25 * '-'}+\n") 119 | f.write(" | {:23s}| {:23s}| {:23s}| {:23s}|\n".format(input_data.constituents["compound"]["formula"], 120 | str(input_data.constituents["compound"]["compound_energy_pfu"]), 121 | str(input_data.constituents["compound"]["metal_energy_pfu"]), 122 | str(input_data.constituents["compound"]["std_formation_energy"]))) 123 | f.write(f" +{25 * '-'}+{25 * '-'}+{25 * '-'}+{25 * '-'}+\n") 124 | 125 | 126 | 127 | elif input_data.chem_pot_method == "volatile-reference": 128 | f.write(" Volatile chemical potential calculated using a reference material\n") 129 | 130 | elif input_data.chem_pot_method == "volatile-rich-poor": 131 | f.write(" Volatile-rich-poor chemical potential method selected\n") 132 | 133 | 134 | f.write("\n\n") 135 | 136 | f.write(">>> Dopants\n\n") 137 | 138 | dopants_fitting = 0 139 | if input_data.dopants: 140 | dopant_num = 1 141 | 142 | for dopant_element, dopant_vals in input_data.dopants.items(): 143 | if dopant_vals["fitting_option"] == 1 or dopant_vals["fitting_option"] == 2: 144 | f.write(f" Dopant {dopant_num} :\n") 145 | f.write(f" +{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+\n") 146 | f.write(" |{:^28s}|{:^28s}|{:^28s}|{:^28s}|{:^28s}|{:^28s}|\n".format("Dopant", "Reference", "Chemical Potential", "Fitting Option", "Target Concentration pfu", "Chemical Potential Range")) 147 | f.write(f" +{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+\n") 148 | f.write(" | {:26s}| {:26s}| {:26s}| {:26s}| {:26s}| {:26s}|\n".format(dopant_element, 149 | dopant_vals["reference"], 150 | str(dopant_vals["chemical_potential"]), 151 | str(dopant_vals["fitting_option"]), 152 | str(dopant_vals["concentration_pfu"]), 153 | str(dopant_vals["chem_pot_range"]))) 154 | f.write(f" +{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+\n") 155 | 156 | dopant_num += 1 157 | dopants_fitting += 1 158 | 159 | elif dopant_vals["fitting_option"] == 3 or dopant_vals["fitting_option"] == 4: 160 | f.write(f" Dopant {dopant_num} :\n") 161 | f.write(f" +{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+\n") 162 | f.write(" |{:^28s}|{:^28s}|{:^28s}|{:^28s}|{:^28s}|\n".format("Dopant", "Reference", 163 | "Chemical Potential", 164 | "Fitting Option", 165 | "log_{10}(P) /atm")) 166 | 167 | f.write(f" +{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+\n") 168 | f.write(" | {:26s}| {:26s}| {:26s}| {:26s}| {:26s}|\n".format(dopant_element,dopant_vals["reference"], 169 | str(dopant_vals["chemical_potential"]), 170 | str(dopant_vals["fitting_option"]), 171 | str(dopant_vals["log_PP_atm"]))) 172 | f.write(f" +{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+{28 * '-'}+\n") 173 | 174 | dopant_num += 1 175 | 176 | f.write("\n") 177 | 178 | f.write(f" Fitting chemical potential of {dopants_fitting} dopants\n") 179 | 180 | if dopants_fitting == 0: 181 | f.write(" No dopant chemical potentials being fitted\n") 182 | elif dopants_fitting == 1: 183 | f.write(" Using Linear bisection\n") 184 | else: 185 | f.write(" Using SLSQP\n") 186 | 187 | if input_data.art_dopant_conc: 188 | f.write(f" Artificial dopant concentration : {input_data.art_dopant_conc}\n") 189 | 190 | if input_data.art_dopant_chg: 191 | f.write(f" Artificial dopant charge : {input_data.art_dopant_chg}\n") 192 | 193 | f.write("\n\n") 194 | 195 | f.write(">>> Vibrational Entropy\n\n") 196 | 197 | if input_data.entropy_data: 198 | f.write(" Adding entropy contributions to defect formation energies\n") 199 | f.write(f" Number of functional units in the supercell for the entropy calculation : {input_data.entropy_units}\n") 200 | 201 | else: 202 | f.write(" No vibrational entropy contributions\n") 203 | 204 | f.write("\n\n") 205 | 206 | if input_data.gibbs_data: 207 | f.write(">>> Gibbs Temperature Dependant Energies\n\n") 208 | f.write(" Using supplied Gibbs temperature dependent energies\n") 209 | f.write("\n\n") 210 | 211 | f.write(">>> Defect Concentrations\n\n") 212 | 213 | f.write(f" Defect concentration method : {input_data.defect_conc_method.capitalize()}\n") 214 | 215 | if input_data.conc_units == 0: 216 | f.write(f" Defect concentration units : per formula unit\n") 217 | elif input_data.conc_units == 1: 218 | f.write(f" Defect concentration units : per cm3\n") 219 | 220 | f.write("\n\n") 221 | 222 | f.write(">>> Defect Energy Corrections\n\n") 223 | 224 | if input_data.coulombic_correction == 0 and not input_data.tab_correction: 225 | f.write(" No energy corrections being applies\n") 226 | 227 | elif input_data.coulombic_correction == 1: 228 | f.write(" Adding simple point charge for a cubic system\n") 229 | f.write(f" Supercell length : {input_data.length}\n") 230 | f.write(f" Dielectric constant : {input_data.dielectric_constant}\n") 231 | f.write(" Madelung constant : 2.8373\n") 232 | 233 | elif input_data.coulombic_correction == 2: 234 | f.write(" Adding anisotropic point charge\n") 235 | 236 | if "madelung" not in input_data.tasks: 237 | f.write(f" Screened Madelung potential : {input_data.screened_madelung}\n") 238 | else: 239 | f.write(" Screened Madelung to be calculated\n") 240 | 241 | if input_data.tab_correction: 242 | f.write(" Adding tabulated corrections from defects file\n") 243 | 244 | f.write("\n\n") 245 | 246 | f.write(">>> Summary of defects:\n\n") 247 | f.write(f" +{20*'-'}+{20*'-'}+{20*'-'}+{20*'-'}+{20*'-'}+{20*'-'}+{20*'-'}+\n") 248 | f.write(" |{:^20s}|{:^20s}|{:^20s}|{:^20s}|{:^20s}|{:^20s}|{:^20s}|\n".format("Defect", "Group", "Multiplicity", 249 | "Site", "Charge", "Energy", 250 | "Correction")) 251 | 252 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 253 | 254 | for defect_name, defect_vals in defects_data.items(): 255 | group, multiplicity, site, charge, energy, correction, added_removed = defect_vals.values() 256 | 257 | if charge >= 0: 258 | charge = f" {charge}" 259 | 260 | if correction >= 0: 261 | correction = f" {correction}" 262 | 263 | f.write(" | {:18s}| {:18s}| {:18s}| {:18s}| {:18s}| {:18s}| {:18s}|\n".format(defect_name, group, 264 | str(multiplicity), str(site), 265 | str(charge), str(energy), 266 | str(correction))) 267 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+\n\n") 268 | 269 | f.write(f" Number of defects : {len(defects_data)}\n") 270 | 271 | f.write("\n\n") 272 | 273 | 274 | def write_defect_phases_output(f, concentrations, formation_energies, chemical_pots, fermi_level, 275 | secondary_phases, loop_type_a, loop_type_b, loop_a_val, loop_b_val, 276 | progress_a, progress_b, total_a, total_b): 277 | 278 | elements = chemical_pots.keys() 279 | 280 | if secondary_phases: 281 | phases_names = secondary_phases.keys() 282 | 283 | f.write(f" Loop step a: {progress_a} of {total_a} \n") 284 | f.write(f" Loop step b: {progress_b} of {total_b} \n\n") 285 | 286 | if loop_type_a == 0: 287 | f.write(f" Volatile partial pressure : 10^( {loop_a_val:10.8f} ) atm \n") 288 | 289 | elif loop_type_a == 1: 290 | f.write(f" Temperature : {loop_a_val:10.8f} K \n") 291 | 292 | elif loop_type_a == 2: 293 | f.write(f" Dopant Concentration : 10^( {loop_a_val:10.8f} ) \n") 294 | 295 | elif loop_type_a == 3: 296 | f.write(f" Dopant Partial Pressure : 10^( {loop_a_val:10.8f} ) atm \n") 297 | 298 | if loop_type_b == 0: 299 | f.write(f" Volatile partial pressure : 10^( {loop_b_val:10.8f} ) atm \n\n") 300 | 301 | elif loop_type_b == 1: 302 | f.write(f" Temperature : {loop_b_val:10.2f} K \n\n") 303 | 304 | elif loop_type_b == 2: 305 | f.write(f" Dopant Concentration : 10^( {loop_b_val:10.8f} ) \n\n") 306 | 307 | elif loop_type_b == 3: 308 | f.write(f" Dopant Partial Pressure : 10^( {loop_b_val:10.8f} ) atm \n\n") 309 | 310 | f.write(" Calculated chemical potentials: \n\n") 311 | 312 | for element in elements: 313 | f.write(f" {'{:2s} :'.format(element)} {'{:12.8f}'.format(chemical_pots[element])}\n") 314 | 315 | f.write("\n") 316 | 317 | f.write(f" Fermi level : {fermi_level:10.8f}\n\n") 318 | 319 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 320 | f.write(" |{:^20s}|{:^20s}|{:^20s}|\n".format("Defect", "Formation Energy", "log_{10}[D]", )) 321 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 322 | for defect_name in concentrations.keys(): 323 | 324 | if defect_name != "electrons" and defect_name != "holes" and defect_name != "log_stoic": 325 | f.write(" | {:18s}| {:<18.8f}| {:<18.8f}|\n".format(defect_name, 326 | formation_energies[defect_name], 327 | concentrations[defect_name] 328 | ) 329 | ) 330 | else: 331 | f.write(" | {:18s}| {:<18s}| {:<18.8f}|\n".format(defect_name, '-', 332 | concentrations[defect_name] 333 | ) 334 | ) 335 | 336 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+\n\n") 337 | 338 | if secondary_phases: 339 | f.write(" Secondary phase stability check:\n") 340 | 341 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 342 | f.write(" |{:^20s}|{:^20s}|{:^20s}|{:^20s}|{:^20s}|\n".format("Phase", "Energy", "Chem Pot Sum", 343 | "Difference", "Stable?")) 344 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 345 | 346 | for phase in secondary_phases: 347 | 348 | 349 | phase_eng = secondary_phases[phase]["energy"] 350 | phase_chem_pot = secondary_phases[phase]["chem_pot_sum"] 351 | phase_difference = secondary_phases[phase]["difference"] 352 | 353 | phase_stability = secondary_phases[phase]["is_stable"] 354 | if phase_stability: 355 | phase_stability = "True" 356 | else: 357 | phase_stability = "False" 358 | 359 | f.write(" | {:<18s}| {:<18.8f}| {:<18.8f}| {:<18.8f}| {:<18s}|\n".format(phase, 360 | phase_eng, 361 | phase_chem_pot, 362 | phase_difference, 363 | phase_stability 364 | ) 365 | ) 366 | 367 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+\n\n") 368 | 369 | f.write(f"{110 * '-'}\n\n") 370 | 371 | 372 | 373 | def write_brouwer_output(f, concentrations, formation_energies, chemical_pots, fermi_level, secondary_phases, loop_type, loop_val, loop_prog, total_step, grouped_defects): 374 | 375 | 376 | elements = chemical_pots.keys() 377 | 378 | f.write(f" Loop step : {loop_prog} of {total_step}\n\n") 379 | 380 | if loop_type == 0: 381 | f.write(f" Volatile partial pressure : 10^( {loop_val:10.8f} ) atm\n\n") 382 | 383 | f.write(" Calculated chemical potentials:\n\n") 384 | 385 | for element in elements: 386 | f.write(f" {'{:2s} :'.format(element)} {'{:12.8f}'.format(chemical_pots[element])}\n") 387 | 388 | f.write("\n") 389 | 390 | f.write(f" Fermi level : {fermi_level:10.8f}\n\n") 391 | 392 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 393 | f.write(" |{:^20s}|{:^20s}|{:^20s}|\n".format("Defect", "Formation Energy", "log_{10}[D]",)) 394 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 395 | for defect_name in concentrations.keys(): 396 | 397 | if defect_name != "electrons" and defect_name != "holes" and defect_name != "pm_stoic" and defect_name != "log_stoic" and not grouped_defects: 398 | f.write(" | {:18s}| {:<18.8f}| {:<18.8f}|\n".format(defect_name, formation_energies[defect_name], concentrations[defect_name])) 399 | else: 400 | f.write(" | {:18s}| {:<18s}| {:<18.8f}|\n".format(defect_name, '-', concentrations[defect_name])) 401 | 402 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+\n\n") 403 | 404 | if secondary_phases: 405 | f.write(" Secondary phase stability check:\n") 406 | 407 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 408 | f.write(" |{:^20s}|{:^20s}|{:^20s}|{:^20s}|{:^20s}|\n".format("Phase", "Energy", "Chem Pot Sum", "Difference", "Stable?")) 409 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+\n") 410 | 411 | for phase in secondary_phases: 412 | 413 | phase_eng = secondary_phases[phase]["energy"] 414 | phase_chem_pot = secondary_phases[phase]["chem_pot_sum"] 415 | phase_difference = secondary_phases[phase]["difference"] 416 | 417 | phase_stability = secondary_phases[phase]["is_stable"] 418 | if phase_stability: 419 | phase_stability = "True" 420 | else: 421 | phase_stability = "False" 422 | 423 | f.write(" | {:<18s}| {:<18.8f}| {:<18.8f}| {:<18.8f}| {:<18s}|\n".format(phase, phase_eng, phase_chem_pot, phase_difference, phase_stability)) 424 | 425 | f.write(f" +{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+{20 * '-'}+\n\n") 426 | 427 | f.write(f"{110*'-'}\n\n") 428 | 429 | 430 | def defect_phases_plot(min_val_x, max_val_x, min_val_y, max_val_y, phase_type, loop_a_type, loop_b_type, looping_dopants, art_dopant_chg): 431 | 432 | phases_dataframe = pd.read_csv(f"defect_phases_{phase_type}_data.csv") 433 | legend_labels = [] 434 | 435 | colours = ["forestgreen", "indianred", "#008cf9", "#d163e6", "#00bbad", "#ff9287", "peru", "#878500", "#00c6f8", 436 | "#00a76c", "#bdbdbd", "#5954d6", "#ebac23", "silver"] 437 | 438 | text_colours = ["#274e13", "darkred", "b", "purple", "#008080", "maroon", "#b24502", "#004225", "steelblue", 439 | "darkgreen", "dimgrey", "darkslateblue", "darkgoldenrod", "grey"] 440 | 441 | looping_num = 0 442 | 443 | with open(f"plot_defect_phases_{phase_type}.py", "w") as f: 444 | 445 | f.write('import pandas as pd\n') 446 | f.write('import numpy as np\n') 447 | f.write('import matplotlib.pyplot as plt\n') 448 | f.write('from matplotlib.patches import Polygon\n') 449 | f.write('plt.close("all")\n\n') 450 | 451 | f.write('plt.rcParams["axes.facecolor"] = "black"\n\n') 452 | 453 | f.write("\nplt.rc('font', size=14) # controls default text sizes\n") 454 | f.write("plt.rc('axes', titlesize=14) # fontsize of the axes title\n") 455 | f.write("plt.rc('axes', labelsize=14) # fontsize of the x and y labels\n") 456 | f.write("plt.rc('xtick', labelsize=12) # fontsize of the tick labels\n") 457 | f.write("plt.rc('ytick', labelsize=12) # fontsize of the tick labels\n") 458 | f.write("plt.rc('legend', fontsize=12) # legend fontsize\n\n") 459 | 460 | f.write(f'phases_dataframe = pd.read_csv("defect_phases_{phase_type}_data.csv")\n\n') 461 | 462 | f.write('fig, ax = plt.subplots(1, 1, figsize=(12,7))\n') 463 | f.write(f"plt.axis({min_val_x, max_val_x, min_val_y, max_val_y})\n") 464 | 465 | if loop_a_type == 0: 466 | f.write(r"plt.xlabel(r'$\mathrm{log}_{10}\mathrm{P}_{\mathrm{O}_{2}}$ /atm')"+"\n") 467 | elif loop_a_type == 1: 468 | f.write("plt.xlabel('Temperature /K')\n") 469 | elif loop_a_type == 2: 470 | f.write(f"plt.xlabel('[{looping_dopants[0]}] /pfu')\n") 471 | looping_num+=1 472 | elif loop_a_type == 3: 473 | string = r"plt.xlabel(r'$\mathrm{log}_{10}\mathrm{P}_{\mathrm{" + f"{looping_dopants[0]}" + r"}_{2}}$ /atm')"+"\n" 474 | f.write(string) 475 | looping_num+=1 476 | elif loop_a_type == 4: 477 | string = r"plt.xlabel(r'$\mu_\mathrm{" + f"{looping_dopants[0]}" +"}$ /eV')" +"\n" 478 | f.write(string) 479 | elif loop_a_type == 5: 480 | string = r"plt.xlabel(r'[$\lambda^{" + f"{art_dopant_chg}" + r"}$] /pfu')" +"\n" 481 | f.write(string) 482 | elif loop_a_type == 6: 483 | string = r"plt.xlabel(r'$s$')" +"\n" 484 | f.write(string) 485 | 486 | if loop_b_type == 0: 487 | f.write(r"plt.ylabel(r'$\mathrm{log}_{10}\mathrm{P}_{\mathrm{O}_{2}}$ /atm')" +"\n") 488 | elif loop_b_type == 1: 489 | f.write("plt.ylabel('Temperature /K')\n") 490 | elif loop_b_type == 2: 491 | f.write(f"plt.ylabel('[{looping_dopants[1]}] /pfu')\n") 492 | elif loop_b_type == 3: 493 | string = r"plt.ylabel(r'$\mathrm{log}_{10}\mathrm{P}_{\mathrm{" + f"{looping_dopants[1]}" + r"}_{2}}$ /atm')" +"\n" 494 | f.write(string) 495 | elif loop_b_type == 4: 496 | string = r"plt.ylabel(r'$\mu_\mathrm{" + f"{looping_dopants[1]}" +"}$ /eV')" +"\n" 497 | f.write(string) 498 | elif loop_b_type == 5: 499 | string = r"plt.ylabel(r'[$\lambda^{" + f"{art_dopant_chg}" + r"}$] /pfu')" +"\n" 500 | f.write(string) 501 | elif loop_b_type == 6: 502 | string = r"plt.ylabel(r'$s$')" +"\n" 503 | f.write(string) 504 | 505 | f.write("\n") 506 | 507 | colour_index = 0 508 | 509 | for phase_index, phase in enumerate(phases_dataframe): 510 | if phase == "index": 511 | continue 512 | 513 | else: 514 | 515 | phase_coords_lst = np.array([np.fromstring(val[1:-1], dtype=float, count=2, sep=' ') for val in phases_dataframe[phase] if 'nan' not in val]) 516 | 517 | f.write(f"phase_{phase_index}_coords_lst = np.array([np.fromstring(val[1:-1], dtype=float, count=2, sep=' ') for val in phases_dataframe['{phase}'] if 'nan' not in val])\n") 518 | f.write(f"phase_{phase_index}_polygon = Polygon(phase_{phase_index}_coords_lst, color='{colours[colour_index]}', ec='black')\n") 519 | f.write(f"ax.add_patch(phase_{phase_index}_polygon)\n") 520 | 521 | 522 | cx = phase_coords_lst[:,0].mean(0) 523 | cy = phase_coords_lst[:, 1].mean(0) 524 | 525 | f.write(f"plt.text(x={cx}, y={cy}, s='{phase}', ha='center', va='center', c='{text_colours[colour_index]}')\n") 526 | 527 | f.write("\n\n") 528 | 529 | if colour_index < (len(colours)-1): 530 | colour_index+=1 531 | else: 532 | colour_index = len(colours)-1 533 | 534 | legend_labels.append(phase) 535 | 536 | f.write("\n") 537 | for location in ['left', 'right', 'top', 'bottom']: 538 | f.write(f'ax.spines["{location}"].set_linewidth(2)\n') 539 | f.write('ax.tick_params(width=2, pad=15, direction="in", length=10)\n') 540 | 541 | f.write('plt.tight_layout()\n') 542 | f.write('plt.show()\n') 543 | 544 | 545 | def brouwer_plot(axes, defects_data, grouped_defects, loop_type, looping_dopants, art_dopant_chg, x_variable): 546 | 547 | concentrations_dataframe = pd.read_csv("brouwer_data.csv") 548 | legend_labels = [] 549 | 550 | if x_variable == 2: 551 | x_axis_var = "pm_stoic" 552 | else: 553 | x_axis_var = "loop_step" 554 | 555 | with open("plot_brouwer.py", "w") as f: 556 | 557 | colours = ["#006e00", "#b80058", "#008cf9", "#d163e6", "#00bbad", "#ff9287", "#b24502", "#878500", "#00c6f8", 558 | "#00a76c", "#bdbdbd", "#000000"] 559 | 560 | linestyles = [(0, ()), (0, (5, 2)), (0, (5, 2, 1, 2)), (0, (1, 1)), (0, (3, 5, 1, 5, 1, 5)), (0, (5, 1)), (0, (1, 1)), (0, (3, 1, 1, 1))] 561 | 562 | group_colours = {} 563 | 564 | f.write('import pandas as pd\n') 565 | f.write('import matplotlib.pyplot as plt\n') 566 | f.write('plt.close("all")\n\n') 567 | f.write('concentrations_dataframe = pd.read_csv("brouwer_data.csv")\n\n') 568 | 569 | f.write("\nplt.rc('font', size=20) # controls default text sizes\n") 570 | f.write("plt.rc('axes', titlesize=20) # fontsize of the axes title\n") 571 | f.write("plt.rc('axes', labelsize=20) # fontsize of the x and y labels\n") 572 | f.write("plt.rc('xtick', labelsize=16) # fontsize of the tick labels\n") 573 | f.write("plt.rc('ytick', labelsize=16) # fontsize of the tick labels\n") 574 | f.write("plt.rc('legend', fontsize=10) # legend fontsize\n") 575 | f.write("plt.rc('lines', linewidth=2)\n") 576 | f.write("plt.rcParams['figure.figsize'] = (12,8)\n\n") 577 | 578 | f.write("fig, ax = plt.subplots()\n") 579 | f.write(f"plt.axis({axes})\n") 580 | 581 | if x_variable == 2: 582 | f.write(r"plt.xlabel(r'$\pm x$')" + "\n") 583 | elif loop_type == 0: 584 | f.write(r"plt.xlabel(r'$\mathrm{log}_{10}\mathrm{P}_{\mathrm{O}_{2}}$ /atm')"+"\n") 585 | elif loop_type == 1: 586 | f.write("plt.xlabel('Temperature /K')\n") 587 | elif loop_type == 2: 588 | f.write(f"plt.xlabel('[{looping_dopants[0]}] /pfu')\n") 589 | elif loop_type == 3: 590 | string = r"plt.xlabel(r'$\mathrm{log}_{10}\mathrm{P}_{\mathrm{" + f"{looping_dopants[0]}" + r"}_{2}}$ /atm')" +"\n" 591 | f.write(string) 592 | elif loop_type == 4: 593 | string = r"plt.xlabel(r'$\mu_\mathrm{" + f"{looping_dopants[0]}" +"}$ /eV')" +"\n" 594 | f.write(string) 595 | elif loop_type == 5: 596 | string = r"plt.xlabel(r'[$\lambda^{" + f"{art_dopant_chg}" + r"}$] /pfu')" +"\n" 597 | f.write(string) 598 | elif loop_type == 6: 599 | string = r"plt.xlabel(r'$s$')" +"\n" 600 | f.write(string) 601 | 602 | f.write("plt.ylabel('[D] /pfu')\n\n") 603 | 604 | colour_index = 0 605 | line_index = 0 606 | for defect in concentrations_dataframe: 607 | 608 | if defect == "loop_step": 609 | continue 610 | 611 | elif defect != "electrons" and defect != "holes" and defect != "pm_stoic" and defect != "log_stoic": 612 | 613 | if max(concentrations_dataframe[defect]) > axes[2]: 614 | if not grouped_defects: 615 | defect_group = defects_data[defect]["group"] 616 | else: 617 | defect_group = defect 618 | 619 | if defect_group not in group_colours: 620 | #print(colour_index) 621 | 622 | if colour_index < len(colours): 623 | group_colours[defect_group] = colours[colour_index] 624 | colour_index+=1 625 | else: 626 | group_colours[defect_group] = colours[-1] 627 | 628 | #colour_index += 1 if colour_index < len(colours) - 1 else len(colours) - 1 629 | 630 | line_index = 0 631 | else: 632 | line_index += 1 if line_index < 7 else 0 633 | 634 | f.write(f'plt.plot(concentrations_dataframe["{x_axis_var}"], concentrations_dataframe["{defect}"], "{group_colours[defect_group]}", linestyle={linestyles[line_index]}, label="{defect}")\n') 635 | legend_labels.append(defect) 636 | 637 | elif defect == "electrons" and max(concentrations_dataframe[defect]) > axes[2]: 638 | f.write(f'plt.plot(concentrations_dataframe["{x_axis_var}"], concentrations_dataframe["{defect}"], "#5954d6", linestyle="solid", label="electrons")\n') 639 | legend_labels.append(defect) 640 | 641 | elif defect == "holes" and max(concentrations_dataframe[defect]) > axes[2]: 642 | f.write( 643 | f'plt.plot(concentrations_dataframe["{x_axis_var}"], concentrations_dataframe["{defect}"], "#ebac23", linestyle="solid", label="holes")\n') 644 | legend_labels.append(defect) 645 | 646 | elif defect == "log_stoic" and x_variable != 2 and max(concentrations_dataframe[defect]) > axes[2]: 647 | f.write(f'plt.plot(concentrations_dataframe["{x_axis_var}"], concentrations_dataframe["{defect}"], "#000000", linestyle=(0, (6, 4)), linewidth=3, label="stoic")\n') 648 | legend_labels.append(defect) 649 | 650 | 651 | f.write("\n") 652 | for location in ['left', 'right', 'top', 'bottom']: 653 | f.write(f'ax.spines["{location}"].set_linewidth(2)\n') 654 | f.write('ax.tick_params(width=2, pad=15, direction="in", length=10)\n') 655 | 656 | f.write(f'plt.legend(loc="lower center", bbox_to_anchor=(0.5, -0.35), ncol={int(np.round(len(legend_labels)/3))}, edgecolor="white")\n') 657 | f.write('plt.subplots_adjust(bottom=0.2)\n') 658 | f.write('plt.tight_layout()\n') 659 | f.write('plt.show()\n') 660 | 661 | 662 | def plot_formation_energies(defects_data, bandgap): 663 | 664 | form_eng_dataframe = pd.read_csv("all_form_eng_data.csv") 665 | min_form_eng_dataframe = pd.read_csv("all_min_form_eng_data.csv") 666 | 667 | colours = ["#006e00", "#b80058", "#008cf9", "#d163e6", "#00bbad", "#ff9287", "#b24502", "#878500", "#00c6f8", 668 | "#00a76c", "#bdbdbd", "#5954d6", "#ebac23", "#000000"] 669 | 670 | linestyles = [(0, ()), (0, (5, 2)), (0, (5, 2, 1, 2)), (0, (1, 1)), (0, (3, 5, 1, 5, 1, 5)), (0, (5, 1)), 671 | (0, (1, 1)), (0, (3, 1, 1, 1))] 672 | 673 | group_colours = {} 674 | for index, group_name in enumerate(min_form_eng_dataframe): 675 | if group_name == "fermi_energy": 676 | continue 677 | 678 | if index < len(colours): 679 | group_colours[group_name] = colours[index-1] 680 | else: 681 | group_colours[group_name] = colours[-1] 682 | 683 | 684 | with open("plot_formation_energies.py", "w") as f: 685 | f.write('import pandas as pd\n') 686 | f.write('import matplotlib.pyplot as plt\n') 687 | f.write('plt.close("all")\n\n') 688 | 689 | f.write('form_eng_dataframe = pd.read_csv("all_form_eng_data.csv")\n') 690 | f.write('min_form_eng_dataframe = pd.read_csv("all_min_form_eng_data.csv")\n\n') 691 | 692 | # plots all defect formation energies on one plot 693 | f.write("# Plot all defect formation energies\n") 694 | f.write("plt.figure(figsize=(12, 7))\n") 695 | f.write("plt.xlabel('Fermi Level /eV')\n") 696 | f.write("plt.ylabel('Formation Energy /eV')\n") 697 | f.write(f"plt.xlim(0, {bandgap})\n\n") 698 | 699 | group_line_index = {} 700 | 701 | for defect in form_eng_dataframe: 702 | if defect == "fermi_energy": 703 | continue 704 | 705 | defect_group = defects_data[defect]["group"] 706 | if defect_group not in group_line_index: 707 | group_line_index[defect_group] = 0 708 | 709 | 710 | f.write(f'plt.plot(form_eng_dataframe["fermi_energy"], form_eng_dataframe["{defect}"], "{group_colours[defect_group]}", linestyle={linestyles[group_line_index[defect_group]]}, label="{defect}")\n') 711 | 712 | if group_line_index[defect_group] < len(linestyles) - 1: 713 | group_line_index[defect_group] += 1 714 | else: 715 | group_line_index[defect_group] = 0 716 | 717 | f.write('\nplt.tight_layout()\n') 718 | f.write(f'plt.legend(loc="lower center", ncol={math.ceil(len(group_colours) / 4)}, fancybox=True)\n') 719 | f.write('plt.savefig("all_form_eng_plot.png", dpi=200)\n') 720 | f.write('plt.close()\n\n\n') 721 | 722 | # Plots all defect formation energies in a group 723 | # loop through defect groups. Min form eng dataframe is grouped by these, so loop through them 724 | for defect_group in min_form_eng_dataframe: 725 | 726 | if defect_group == "fermi_energy": 727 | continue 728 | 729 | f.write(f"# Plot {defect_group} defect formation energies\n") 730 | 731 | f.write("plt.figure(figsize=(12, 7))\n") 732 | f.write("plt.xlabel('Fermi Level /eV')\n") 733 | f.write("plt.ylabel('Formation Energy /eV')\n") 734 | f.write(f"plt.xlim(0, {bandgap})\n\n") 735 | 736 | # loop through defects to see which defects are in the current group iteration 737 | line_index = 0 738 | for defect in form_eng_dataframe: 739 | 740 | if defect == "fermi_energy": 741 | continue 742 | 743 | if defects_data[defect]["group"] == defect_group: 744 | f.write( 745 | f'plt.plot(form_eng_dataframe["fermi_energy"], form_eng_dataframe["{defect}"], "{group_colours[defect_group]}", linestyle={linestyles[line_index]}, label="{defect}")\n') 746 | 747 | if line_index < len(linestyles) - 1: 748 | line_index += 1 749 | else: 750 | line_index = 0 751 | 752 | f.write('\nplt.tight_layout()\n') 753 | f.write(f'plt.legend(loc="lower center", ncol={math.ceil(len(group_colours) / 2)}, fancybox=True)\n') 754 | f.write(f'plt.savefig("{defect_group}_form_eng_plot.png", dpi=200)\n') 755 | f.write('plt.close()\n\n\n') 756 | 757 | with open("plot_min_formation_energies.py", "w") as f: 758 | f.write('import pandas as pd\n') 759 | f.write('import matplotlib.pyplot as plt\n') 760 | f.write('plt.close("all")\n\n') 761 | 762 | f.write('form_eng_dataframe = pd.read_csv("all_form_eng_data.csv")\n') 763 | f.write('min_form_eng_dataframe = pd.read_csv("all_min_form_eng_data.csv")\n\n') 764 | 765 | # Plots all the minimum defect formation energies 766 | f.write("# Plot all minimum defect formation energies\n") 767 | f.write("plt.figure(figsize=(12, 7))\n") 768 | f.write("plt.xlabel('Fermi Level /eV')\n") 769 | f.write("plt.ylabel('Formation Energy /eV')\n") 770 | f.write(f"plt.xlim(0, {bandgap})\n\n") 771 | 772 | for defect_group in min_form_eng_dataframe: 773 | if defect_group == "fermi_energy": 774 | continue 775 | 776 | f.write(f'plt.plot(min_form_eng_dataframe["fermi_energy"], min_form_eng_dataframe["{defect_group}"], "{group_colours[defect_group]}", linestyle="solid", label="{defect_group}")\n') 777 | 778 | f.write('\nplt.tight_layout()\n') 779 | f.write(f'plt.legend(loc="lower center", ncol={math.ceil(len(group_colours)/2)}, fancybox=True)\n') 780 | f.write('plt.savefig("all_min_form_eng_plot.png", dpi=200)\n') 781 | f.write('plt.close()\n\n\n') 782 | 783 | # plot all min formation energies for each defect group 784 | for defect_group in min_form_eng_dataframe: 785 | if defect_group == "fermi_energy": 786 | continue 787 | 788 | # Plots individual minimum defect formation energies 789 | f.write(f"# Plot {defect_group} minimum defect formation energies\n") 790 | f.write("plt.figure(figsize=(12, 7))\n") 791 | f.write("plt.xlabel('Fermi Level /eV')\n") 792 | f.write("plt.ylabel('Formation Energy /eV')\n") 793 | f.write(f"plt.xlim(0, {bandgap})\n\n") 794 | 795 | f.write(f'plt.plot(min_form_eng_dataframe["fermi_energy"], min_form_eng_dataframe["{defect_group}"], "{group_colours[defect_group]}", linestyle="solid", label="{defect_group}")\n') 796 | 797 | f.write('\nplt.tight_layout()\n') 798 | f.write(f'plt.legend(loc="lower center", ncol={math.ceil(len(group_colours) / 2)}, fancybox=True)\n') 799 | f.write(f'plt.savefig("{defect_group}_min_form_eng_plot.png", dpi=200)\n') 800 | f.write('plt.close()\n\n\n') 801 | 802 | --------------------------------------------------------------------------------