diff --git a/examples/Practical_tutorial/Combinations_practical.ipynb b/examples/Practical_tutorial/Combinations_practical.ipynb deleted file mode 100644 index 482fe67b..00000000 --- a/examples/Practical_tutorial/Combinations_practical.ipynb +++ /dev/null @@ -1,399 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# The Combinatorial Explosion\n", - "---\n", - "\n", - "***\"During the past century, science has developed a limited capability to design materials, but we are still too dependent on serendipity\"*** - [Eberhart and Clougherty, Looking for design in materials design (2004)](http://www.nature.com/nmat/journal/v3/n10/abs/nmat1229.html)\n", - "\n", - "This practical explores how materials design can be approached by using the simplest of rules in order to narrow down the combinations to those that might be considered legitimate. It will demonstrate the scale of the problem, even after some chemical rules are applied.\n", - "\n", - "\n", - "#### TASKS\n", - "- Section 1: 1 task\n", - "- Section 2 i: 2 tasks\n", - "- Section 2 ii: 2 tasks\n", - "- Section 2 iii: 2 tasks\n", - "- Section 2 iv: 3 tasks\n", - "- Section 3 & 4: information only\n", - "\n", - "#### NOTES ON USING THE NOTEBOOK\n", - "- This notebook is divided into \"cells\" which either contain Markdown (text, equations and images) or Python code\n", - "- A cell can be \"run\" by selecting it and either\n", - " - pressing the Run button in the toolbar above (triangle/arrow symbol)\n", - " - Using Cell > Run in the menu above\n", - " - Holding the Ctrl key and pressing Enter\n", - "- Running Markdown cells just displays them nicely (like this text!) Running Python code cells runs the code and displays any output below.\n", - "- When you run a cell and it appears to not be doing anything, if there is no number in the square brackets and instead you see ```In [*] ``` it is still running!\n", - "- If the output produces a lot of lines, you can minimise the output box by clicking on the white space to the left of it.\n", - "- You can clear the output of a cell or all cells by going to Cell > Current output/All output > Clear. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. Back to basics: Forget your chemistry\n", - "(From the blog of Anubhav Jain: [www.hackingmaterials.com](http://www.hackingmaterials.com))\n", - "\n", - "1. You have the first 50 elements of the periodic table\n", - "2. You also have a 10 x 10 x 10 grid \n", - "3. You are allowed to arrange 30 of the elements at a time in some combination in the grid to make a 'compound'\n", - "4. How many different arrangements (different compounds) could you make?\n", - "\n", - "\n", - "\n", - "The answer is about $10^{108}$, *over a googol of compounds!*\n", - "\n", - "**TASK: Use the cell below to arrive at the conclusion above. Hints for the formula required are below the cell.**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from math import factorial as factorial\n", - "\n", - "grid_points = 1000.0\n", - "atoms = 30.0\n", - "elements = 50.0\n", - "\n", - "##########\n", - "\n", - "# A. Show that assigning each of the 30 atoms as one of 50 elements is ~ 9e50 (permutations)\n", - "\n", - "element_assignment = 0\n", - "\n", - "print(f\"Number of possible element assignments is: {element_assignment}\")\n", - "\n", - "# B. Show that the number of possible arrangements of 30 atoms on a grid of 10x10x10 is ~2e57 (combinations)\n", - "\n", - "atom_arrangements = 0\n", - "\n", - "print(f\"Number of atom arrangements is: {atom_arrangements}\")\n", - "\n", - "# C. Finally, show that the total number of potential \"materials\" is ~ 2e108\n", - "\n", - "total_materials = 0\n", - "\n", - "print(f'Total number of \"materials\" is: {total_materials}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2. Counting combinations: Remember your chemistry\n", - "\n", - "We will use well-known elemental properties along with the criterion that compounds must not have an overall charge in order to sequentially apply different levels of screening and count the possible combinations:\n", - "\n", - "i. Setting up the search space - Defining which elements we want to include \n", - "\n", - "ii. Element combination counting - Considering combinations of elements and ignore oxidation states\n", - "\n", - "iii. Ion combination counting - Considering combinations of elements in their allowed oxidation states\n", - "\n", - "iv. Charge neutrality - Discarding any combinations that would not make a charge neutral compound\n", - "\n", - "v. Electronegativity - Discarding any combinations which exhibit a cation which is more electronegative than an anion\n", - "\n", - "### i. Setting up and choosing the search-space\n", - "\n", - "The code below imports the element data that we need in order to do our counting. The main variable in the cell below for this practical is the ```max_atomic_number``` which dictates how many elements to consider. \n", - "\n", - "For example, when ```max_atomic_number = 10``` the elements from H to Ne are considered in the search.\n", - "\n", - "- ** TASK 1: Change the variable ```max_atomic_number``` so that it includes elements from H to Ar **\n", - "- ** TASK 2: Get the code to print out the actual list of elements that will be considered ** " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Imports the SMACT toolkit for later on #\n", - "import smact\n", - "\n", - "# Gets element data from file and puts into a list #\n", - "with open(\"Counting/element_data.txt\") as f:\n", - " data = f.readlines()\n", - "\n", - "list_of_elements = []\n", - "\n", - "# Specify the range of elements to include #\n", - "\n", - "### EDIT BELOW ###\n", - "max_atomic_number = 10\n", - "##################\n", - "\n", - "# Populates a list with the elements we are concerned with #\n", - "for line in data:\n", - " if not line.startswith(\"#\"):\n", - " # Grab first three items from table row\n", - " symbol, name, Z = line.split()[:3]\n", - " if int(Z) > 0 and int(Z) < max_atomic_number + 1:\n", - " list_of_elements.append(symbol)\n", - "\n", - "print(\n", - " f\"--- Considering the {len(list_of_elements)} elements \"\n", - " f\"from {list_of_elements[0]} to {list_of_elements[-1]} ---\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ii. Element combination counting\n", - "\n", - "This first procedure simply counts how many binary combinations are possible for a given set of elements. This is a numerical (combinations) problem, as we are not considering element properties in any way for the time being.\n", - "\n", - "- **TASK 1: Increase the number of elements to consider (max_atomic_number in the cell above) to see how this affects the number of combinations**\n", - "- **TASK 2: If you can, add another for statement (e.g. ```for k, ele_c...```) to make the cell count up ternary combinations. It is advisable to change the number of elements to include back to 10 first! Hint: The next exercise is set up for ternary counting so you could come back and do this after looking at that.**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "# Counts up possibilities and prints the output #\n", - "element_count = 0\n", - "for i, ele_a in enumerate(list_of_elements):\n", - " for j, ele_b in enumerate(list_of_elements[i + 1 :]):\n", - " element_count += 1\n", - " print(f\"{ele_a} {ele_b}\")\n", - "\n", - "# Prints the total number of combinations found\n", - "print(f\"Number of combinations = {element_count}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### iii. Ion combination counting\n", - "\n", - "We now consider each known oxidation state of an element (so strictly speaking we are not dealing with 'ions'). The procedure incorporates a library of known oxidation states for each element and is this time already set up to search for ternary combinations. The code prints out the combination of elements including their oxidation states. There is also a timer so that you can see how long it takes to run the program. \n", - "\n", - "- ** TASK 1: Reset the search space to ~10 elements, read through (feel free to ask if you don't understand any parts!) and run the code below. **\n", - "- ** TASK 2: change ```max_atomic_number``` again in the cell above and see how this affects the number of combinations. Hint: It is advisable to increase the search-space gradually and see how long the calculation takes. Big numbers mean you could be waiting a while for the calculation to run....**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Sets up the timer to see how long the program takes to run #\n", - "import time\n", - "\n", - "start_time = time.time()\n", - "\n", - "ion_count = 0\n", - "for i, ele_a in enumerate(list_of_elements):\n", - " for ox_a in smact.Element(ele_a).oxidation_states:\n", - " for j, ele_b in enumerate(list_of_elements[i + 1 :]):\n", - " for ox_b in smact.Element(ele_b).oxidation_states:\n", - " for k, ele_c in enumerate(list_of_elements[i + j + 2 :]):\n", - " for ox_c in smact.Element(ele_c).oxidation_states:\n", - " ion_count += 1\n", - "\n", - " print(\n", - " f\"{ele_a} {ox_a} \\t {ele_b} {ox_b} \\t {ele_c} {ox_c}\"\n", - " )\n", - "\n", - "# Prints the total number of combinations found and the time taken to run.\n", - "print(f\"Number of combinations = {ion_count}\")\n", - "print(f\"--- {time.time() - start_time} seconds to run ---\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "All we seem to have done is make matters worse! \n", - "\n", - "We are introducing many more species by further splitting each element in our search-space into separate ions, one for each allowed oxidation state. When we get to max_atomic_number > 20, we are including the transition metals and their many oxidation states. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### iv. Charge neutrality\n", - "\n", - "The previous step is necessary to incorporate our filter that viable compounds must be charge neutral overall. Scrolling through the output from above, it is easy to see that the vast majority of the combinations are not charge neutral overall. We can discard these combinations to start narrowing our search down to more 'sensible' (or at least not totally unreasonable) ones. In this cell, we will use the `neutral_ratios` function in smact to do this.\n", - "\n", - "- ** TASK 1: Reset the search space to ~10 elements, read through (feel free to ask if you don't understand any parts!) and run the code below. **\n", - "- ** TASK 2: Edit the code so that it also prints out the oxidation state next to each element **\n", - "- ** TASK 3: Increase the number of elements to consider again (```max_atomic_number``` in the cell above) and compare the output of i. and ii. with that of the below cell**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "import time\n", - "\n", - "from smact import neutral_ratios\n", - "\n", - "start_time = time.time()\n", - "\n", - "charge_neutral_count = 0\n", - "for i, ele_a in enumerate(list_of_elements):\n", - " for ox_a in smact.Element(ele_a).oxidation_states:\n", - " for j, ele_b in enumerate(list_of_elements[i + 1 :]):\n", - " for ox_b in smact.Element(ele_b).oxidation_states:\n", - " for k, ele_c in enumerate(list_of_elements[i + j + 2 :]):\n", - " for ox_c in smact.Element(ele_c).oxidation_states:\n", - " # Checks if the combination is charge neutral before printing it out! #\n", - " cn_e, cn_r = neutral_ratios(\n", - " [ox_a, ox_b, ox_c], threshold=1\n", - " )\n", - " if cn_e:\n", - " charge_neutral_count += 1\n", - " print(f\"{ele_a} \\t {ele_b} \\t {ele_c}\")\n", - "\n", - "print(f\"Number of combinations = {charge_neutral_count}\")\n", - "print(f\"--- {time.time() - start_time} seconds to run ---\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This drastically reduces the number of combinations we get out and we can even begin to see some compounds that we recognise and know exist.\n", - "\n", - "### v. Electronegativity\n", - "\n", - "The last step is to incorporate the key chemical property of electronegativity, i.e. the propensity of an element to attract electron density to itself in a bond. This is a logical step as inspection of the output from above reveals that some combinations feature a species in a higher (more positive) oxidation state which is more elecronegative than other species present.\n", - "\n", - "With this in mind, we now incorporate another filter which checks that the species with higher oxidation states have lower electronegativities. The library of values used is of the widely accepted electronegativity scale as developed by Linus Pauling. The scale is based on the dissociation energies of heteronuclear diatomic molecules and their corresponding homonuclear diatomic molecules:\n", - "\n", - "" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "import time\n", - "\n", - "from smact.screening import pauling_test\n", - "\n", - "start_time = time.time()\n", - "\n", - "pauling_count = 0\n", - "for i, ele_a in enumerate(list_of_elements):\n", - " paul_a = smact.Element(ele_a).pauling_eneg\n", - " for ox_a in smact.Element(ele_a).oxidation_states:\n", - " for j, ele_b in enumerate(list_of_elements[i + 1 :]):\n", - " paul_b = smact.Element(ele_b).pauling_eneg\n", - " for ox_b in smact.Element(ele_b).oxidation_states:\n", - " for k, ele_c in enumerate(list_of_elements[i + j + 2 :]):\n", - " paul_c = smact.Element(ele_c).pauling_eneg\n", - " for ox_c in smact.Element(ele_c).oxidation_states:\n", - " # Puts elements, oxidation states and electronegativites into lists for convenience #\n", - " elements = [ele_a, ele_b, ele_c]\n", - " oxidation_states = [ox_a, ox_b, ox_c]\n", - " pauling_electro = [paul_a, paul_b, paul_c]\n", - "\n", - " # Checks if the electronegativity makes sense and if the combination is charge neutral #\n", - " electroneg_makes_sense = pauling_test(\n", - " oxidation_states, pauling_electro, elements\n", - " )\n", - " cn_e, cn_r = smact.neutral_ratios(\n", - " [ox_a, ox_b, ox_c], threshold=1\n", - " )\n", - " if cn_e:\n", - " if electroneg_makes_sense:\n", - " pauling_count += 1\n", - " print(\n", - " f\"{ele_a}{ox_a} \\t {ele_b}{ox_b} \\t {ele_c}{ox_c}\"\n", - " )\n", - "\n", - "print(f\"Number of combinations = {pauling_count}\")\n", - "print(f\"--- {time.time() - start_time} seconds to run ---\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. Speedy calculations \n", - "\n", - "For a given search-space of elements, the number of combinations in the output has decreased each time we've applied a filter. However, the time taken to carry out the calculation has increased. This highlights a fundamental trade-off, however there are some clever coding techniqes that can be used to considerably speed things up. \n", - "\n", - "By employing multi-threading and reworking the above code to reduce the number of times it has to look up element properties from other files, the time taken to carry out the ternary count including checks for charge neutrality and electronegativity for 103 elements was reduced from ~ 1 hour to just 26 seconds (carried out on the same workstation)!\n", - "\n", - "Furthermore, a quaternary count for 103 atoms took only 2 hours. This was reducecd to 40 minutes using a 16-core workstation. The code used to carry out these calculations is available in the examples folder of the [main smact repository.](http://www.github.com/WMD-group/SMACT)\n", - "\n", - "N.B. For the numbers quoted above, the stoichiometry of each site was also allowed to vary between 1 and 8 which significantly increases the number of combinations (see below). " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4. Some technicalities...\n", - "\n", - "**A note on multiplicity:** In this exercise, we have not considered higher multiplicies (stoichiometries) in our combinations at all, i.e. we have considered only AB, ABC (and ABCD for quaternary) type combinations. When extended to AxByCz... where x,y,z > 1, the numbers involved get considerably larger still. This can be adjusted by setting `threshold` in the `charge neutrality` function to > 1 in the cells above. The threshold defines the maximum values of x,y,z... . If this is changed, the sum of the oxidation states printed will not always sum to zero, however some multiples (between 1 and `threshold`) of them always will. \n", - "\n", - "\n", - "** Finally, some wisdom from our friend, Linus: **\n", - "\n", - "" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.8" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/Practical_tutorial/Counting/element_data.txt b/examples/Practical_tutorial/Counting/element_data.txt deleted file mode 100644 index 519a41b6..00000000 --- a/examples/Practical_tutorial/Counting/element_data.txt +++ /dev/null @@ -1,159 +0,0 @@ -############################################################################### -# # -# element_data.txt -- This data file is part of SMACT # -# # -############################################################################### -# # -# This table provides elemental properties which are accessed by the Element # -# class. For efficiency the contents are cached in memory the first time they # -# are accessed by smact.data_loader. # -# # -# Symbol: Standard chemical symbol used as index throughout SMACT # -# # -# Name: Standard chemical name of element # -# # -# Z: Proton number # -# # -# Mass: Relative atomic mass in atomic mass units (i.e. 1/12 * mass of C-12)# -# Values obtained from NIST Standard Reference Database 144 # -# (J. S. Coursey, D. J. Schwab, J. J. Tsai, NIST Physical Measurement # -# Laboratory) in 2016. Where the relative abundance of isotopes is # -# unknown or a range of values is provided, a simple mean was taken. # -# # -# r_cov: Covalent radius in Angstroms # -# Ref: Cordero et al. (2008) DOI:10.1039/B801115J # -# # -# e_affinity: Electron affinity in eV. NIST-recommended values. # -# Note that unspecified negative values (originally reported as '<0') # -# are listed as 'None' in this table. Electron affinities of elements # -# Fr (Z=87) and above are unknown, and also listed as 'None'. # -# Ref: Andersen et al. (1999) DOI: 10.1063/1.556047 # -# # -# p_eig: Highest occupied p-state eigenvalue in eV. Based on approximate # -# Hartree-Fock calculations published by Herman & Skillman (1963); # -# the relevant values were tabulated and converted to eV by Harrison # -# (1980). Harrison's values are used here. # -# # -# s_eig: Highest occupied s-state eigenvalue in eV. The source is the same # -# as for p_states. # -# # -# Abundance: Crustal abundance in mg/kg. # -# Ref: CRC Handbook of Chemistry and Physics, 92nd Ed. (2011) # -# # -# el_neg: Pauling electronegativity # -# Ref: CRC Handbook of Chemistry and Physics, 92nd Ed. (2011) # -# Elements 95 (Am) and above are assigned the value 1.3 as # -# recommended by Pauling (The Nature of the Chemical Bond, 1939) # -# The value of 3.0 for Krypton was computed by Allen and Huheey (1980)# -# from the bond energy of KrF2. DOI: 10.1016/0022-1902(80)80132-1 # -# # -# ion_pot: Ionisation potential in eV. # -# Ref: NIST Atomic Spectra Database, http://physics.nist.gov/asd # -# [Accessed April 2016] # -# # -############################################################################### -# -#Symbol Name Z Mass r_cov e_affinity p_eig s_eig Abundance el_neg ion_pot -H Hydrogen 1 1.0078250322 0.31 0.75420375 None None 1.40e+03 2.20 13.598434005136 -He Helium 2 4.0026020000 0.28 None None -23.40 8.00e-03 None 24.587387936 -Li Lithium 3 6.9675000000 1.28 0.618049 None -5.48 2.00e+01 0.98 5.391714761 -Be Beryllium 4 9.0121831000 0.96 None -4.14 -8.17 2.80e+00 1.57 9.322699 -B Boron 5 10.8135000000 0.84 0.279723 -6.64 -12.54 1.00e+01 2.04 8.2980190 -C Carbon 6 12.0106000000 0.76 1.262118 -8.97 -17.52 2.00e+02 2.55 11.260300 -N Nitrogen 7 14.0068550000 0.71 -0.07 -11.47 -23.04 1.90e+01 3.04 14.53413 -O Oxygen 8 15.9994000000 0.66 1.461112 -14.13 -29.14 4.61e+05 3.44 13.618054 -F Fluorine 9 18.9984031630 0.57 3.4011887 -16.99 -35.80 5.85e+02 3.98 17.42282 -Ne Neon 10 20.1797000000 0.58 None -20.00 -43.20 5.00e-03 None 21.564540 -Na Sodium 11 22.9897692800 1.66 0.547926 None -5.13 2.36e+04 0.93 5.1390767 -Mg Magnesium 12 24.3055000000 1.41 None -2.99 -6.86 2.33e+04 1.31 7.646235 -Al Aluminium 13 26.9815385000 1.21 0.43283 -4.86 -10.11 8.23e+04 1.61 5.985768 -Si Silicon 14 28.0850000000 1.11 1.389521 -6.52 -13.55 2.82e+05 1.90 8.151683 -P Phosphorus 15 30.9737619980 1.07 0.7465 -8.33 -17.10 1.05e+03 2.19 10.486686 -S Sulfur 16 32.0675000000 1.05 2.0771029 -10.27 -20.80 3.50e+00 2.58 10.36001 -Cl Chlorine 17 35.4515000000 1.02 3.612724 -12.31 -24.63 1.45e+02 3.16 12.96763 -Ar Argon 18 39.9480000000 1.06 None -14.50 -28.70 3.50e+00 None 15.7596112 -K Potassium 19 39.0983000000 2.03 0.501459 None -4.19 2.09e+04 0.82 4.34066354 -Ca Calcium 20 40.0780000000 1.76 0.02455 None -5.41 4.15e+04 1.00 6.11315520 -Sc Scandium 21 44.9559080000 1.70 0.188 None -5.85 2.20e+01 1.36 6.56149 -Ti Titanium 22 47.8670000000 1.60 0.084 None None 5.65e+03 1.54 6.82812 -V Vanadium 23 50.9415000000 1.53 0.525 None None 1.20e+02 1.63 6.746187 -Cr Chromium 24 51.9961000000 1.39 0.67584 None None 1.02e+02 1.66 6.76651 -Mn Manganese 25 54.9380440000 1.39 None None None 9.50e+02 1.55 7.434038 -Fe Iron 26 55.8450000000 1.32 0.151 None None 5.63e+04 1.83 7.9024678 -Co Cobalt 27 58.9331940000 1.26 0.6633 None None 2.50e+01 1.88 7.88101 -Ni Nickel 28 58.6934000000 1.24 1.15716 None None 8.40e+01 1.91 7.639877 -Cu Copper 29 63.5460000000 1.32 1.23578 -6.92 -6.92 6.00e+01 1.90 7.726380 -Zn Zinc 30 65.3800000000 1.22 None -3.38 -8.40 7.00e+01 1.65 9.3941968 -Ga Gallium 31 69.7230000000 1.22 0.41 -4.90 -11.37 1.90e+01 1.81 5.9993018 -Ge Germanium 32 72.6300000000 1.20 1.232712 -6.63 -14.38 1.50e+00 2.01 7.899435 -As Arsenic 33 74.9215950000 1.19 0.814 -7.91 -17.33 1.80e+00 2.18 9.7886 -Se Selenium 34 78.9710000000 1.20 2.02067 -9.53 -20.32 5.00e-02 2.55 9.752392 -Br Bromine 35 79.9040000000 1.20 3.3635880 -11.20 -23.35 2.40e+00 2.96 11.81381 -Kr Krypton 36 83.7980000000 1.16 None -13.00 -26.50 1.00e-04 3.0 13.9996049 -Rb Rubidium 37 85.4678000000 2.20 0.485916 None -3.94 9.00e+01 0.82 4.177128 -Sr Strontium 38 87.6200000000 1.95 0.05206 None -5.00 3.70e+02 0.95 5.69486720 -Y Yttrium 39 88.9058400000 1.90 0.307 None -5.53 3.30e+01 1.22 6.21726 -Zr Zirconium 40 91.2240000000 1.75 0.426 None None 1.65e+02 0.33 6.63390 -Nb Niobium 41 92.9063700000 1.64 0.893 None None 2.20e+02 1.6 6.75885 -Mo Molybdenum 42 95.9500000000 1.54 0.7472 None None 1.20e+00 2.16 7.09243 -Tc Technetium 43 98.0000000000 1.47 0.55 None None None 2.10 7.11938 -Ru Ruthenium 44 101.0700000000 1.46 1.04638 None None None 2.2 7.36050 -Rh Rhodium 45 102.9055000000 1.42 1.14289 None None 1.00e-03 2.28 7.45890 -Pd Palladium 46 106.4200000000 1.39 0.56214 None None 1.50e-02 2.20 8.33686 -Ag Silver 47 107.8682000000 1.45 1.30447 -2.05 -6.41 7.50e-02 1.93 7.576234 -Cd Cadmium 48 112.4140000000 1.44 None -3.38 -7.70 1.50e-01 1.69 8.993820 -In Indium 49 114.8180000000 1.42 0.404 -4.69 -10.12 2.50e-01 1.78 5.7863554 -Sn Tin 50 118.7100000000 1.39 1.112066 -5.94 -12.50 2.30e+00 1.96 7.343917 -Sb Antimony 51 121.7600000000 1.39 1.047401 -7.24 -14.80 2.00e-01 2.05 8.608389 -Te Tellurium 52 127.6000000000 1.38 1.970875 -8.59 -17.11 1.00e-03 2.1 9.00966 -I Iodine 53 126.9044700000 1.39 3.059038 -9.97 -19.42 4.50e-01 2.66 10.45126 -Xe Xenon 54 131.2930000000 1.40 None -11.40 -21.80 3.00e-05 2.60 12.1298431 -Cs Caesium 55 132.9054519600 2.44 0.471626 None -3.56 3.00e+00 0.79 3.893905548 -Ba Barium 56 137.3270000000 2.15 0.14462 None -4.45 4.25e+02 0.89 5.211664 -La Lanthanum 57 138.9054700000 2.07 0.47 None -4.86 3.90e+01 1.10 5.5769 -Ce Cerium 58 140.1160000000 2.04 0.5 None None 6.65e+01 1.12 5.5386 -Pr Praseodymium 59 140.9076600000 2.03 0.5 None None 9.20e+00 1.13 5.473 -Nd Neodymium 60 144.2420000000 2.01 0.5 None None 4.15e+01 1.14 5.5250 -Pm Promethium 61 145.0000000000 1.99 0.5 None None None None 5.582 -Sm Samarium 62 150.3600000000 1.98 0.5 None None 7.05e+00 1.17 5.64371 -Eu Europium 63 151.9640000000 1.98 0.5 None None 2.00e+00 None 5.67040385 -Gd Gadolinium 64 157.2500000000 1.96 0.5 None None 6.20e+00 1.20 6.14980 -Tb Terbium 65 158.9253500000 1.94 0.5 None None 1.20e+00 None 5.8638 -Dy Dysprosium 66 162.5000000000 1.92 0.5 None None 5.20e+00 1.22 5.938905 -Ho Holmium 67 164.9303300000 1.92 0.5 None None 1.30e+00 1.23 6.0215 -Er Erbium 68 167.2590000000 1.89 0.5 None None 3.50e+00 1.24 6.1077 -Tm Thulium 69 168.9342200000 1.90 0.5 None None 5.20e-01 1.25 6.18431 -Yb Ytterbium 70 173.0540000000 1.87 0.5 None None 3.20e+00 None 6.254159 -Lu Lutetium 71 174.9668000000 1.87 0.5 None None 8.00e+01 1.0 5.425871 -Hf Hafnium 72 178.4900000000 1.75 0 None None 3.00e+00 1.3 6.825069 -Ta Tantalum 73 180.9478800000 1.70 0.322 None None 2.00e+00 1.5 7.549571 -W Tungsten 74 183.8400000000 1.62 0.815 None None 1.25e+00 1.7 7.86403 -Re Rhenium 75 186.2070000000 1.51 0.15 None None 7.00e-04 1.9 7.83352 -Os Osmium 76 190.2300000000 1.44 1.0778 None None 1.50e-03 2.2 8.43823 -Ir Iridium 77 192.2170000000 1.41 1.56436 None None 1.00e-03 2.2 8.96702 -Pt Platinum 78 195.0840000000 1.36 2.1251 None None 5.00e-03 2.2 8.95883 -Au Gold 79 196.9665690000 1.36 2.30861 -2.38 -6.48 4.00e-03 2.4 9.225553 -Hg Mercury 80 200.5920000000 1.32 None -3.48 -7.68 8.50e-02 1.9 10.437504 -Tl Thallium 81 204.3835000000 1.45 0.377 -4.61 -9.92 8.50e-01 1.8 6.1082871 -Pb Lead 82 207.2000000000 1.46 0.364 -5.77 -12.07 1.40e+01 1.8 7.416796 -Bi Bismuth 83 208.9804000000 1.48 0.942363 -6.97 -14.15 8.50e-03 1.9 7.285516 -Po Polonium 84 209.0000000000 1.40 1.9 -8.19 -16.21 2.00e-10 2.0 8.414 -At Astatine 85 210.0000000000 1.50 2.8 -9.44 -18.24 None 2.2 9.31751 -Rn Radon 86 222.0000000000 1.50 None None -20.31 None None 10.74850 -Fr Francium 87 223.0000000000 2.60 None None -3.40 None 0.7 4.0727409 -Ra Radium 88 226.0000000000 2.21 None None -4.24 9.00e-07 0.9 5.278424 -Ac Actinium 89 227.0000000000 2.15 None None -4.63 5.50e-10 1.1 5.380226 -Th Thorium 90 232.0377000000 2.06 None -10.71 None 9.60e+00 1.3 6.3067 -Pa Protactinium 91 231.0358800000 2.00 None None None 1.40e-06 1.5 5.89 -U Uranium 92 238.0289100000 1.96 None None None 2.70e+00 1.7 6.19405 -Np Neptunium 93 237.0000000000 1.90 None None None None 1.3 6.2655 -Pu Plutonium 94 244.0000000000 1.87 None None None None 1.3 6.0258 -Am Americium 95 242.0591053000 1.80 None None None None 1.3 5.9738 -Cm Curium 96 245.0654423000 1.69 None None None None 1.3 5.9914 -Bk Berkelium 97 248.0726475000 None None None None None 1.3 6.1978 -Cf Californium 98 250.5781189750 None None None None None 1.3 6.2817 -Es Einsteinium 99 252.0829800000 None None None None None 1.3 6.3676 -Fm Fermium 100 257.0951061000 None None None None None 1.3 6.50 -Md Mendelevium 101 259.1010400000 None None None None None 1.3 6.58 -No Nobelium 102 259.1010300000 None None None None None 1.3 6.65 -Lr Lawrencium 103 262.1096100000 None None None None None None 4.96 diff --git a/examples/Practical_tutorial/ELS_practical.ipynb b/examples/Practical_tutorial/ELS_practical.ipynb deleted file mode 100644 index 00565dba..00000000 --- a/examples/Practical_tutorial/ELS_practical.ipynb +++ /dev/null @@ -1,226 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# The ELS matching procedure\n", - "\n", - "This practical is based on the concepts introduced for optimising electrical contacts in photovoltaic cells. The procedure was published in [J. Mater. Chem. C (2016)]((http://pubs.rsc.org/en/content/articlehtml/2016/tc/c5tc04091d).\n", - "\n", - "\n", - "\n", - "In this practical we screen electrical contact materials for CH3NH3PbI3. There are three main steps:\n", - "* Electronic matching of band energies\n", - "* Lattice matching of surface vectors \n", - "* Site matching of under-coordinated surface atoms" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 1. Electronic matching\n", - "## Background\n", - "\n", - "Effective charge extraction requires a low barrier to electron or hole transport accross an the interface. This barrier is exponential in the discontinuity of the band energies across the interface. To a first approximation the offset or discontinuity can be estimated by comparing the ionisation potentials (IPs) or electron affinities (EAs) of the two materials, this is known as [Anderson's rule](https://en.wikipedia.org/wiki/Anderson%27s_rule).\n", - "\n", - "\n", - "\n", - "Here we have collected a database of 173 measured or estimated semiconductor IPs and EAs (`CollatedData.txt`). We use it as the first step in our screening. The screening is performed by the script `scan_energies.py`. We enforce several criteria:\n", - "\n", - "* The IP and EA of the target material are supplied using the flags `-i` and `-e`\n", - "* The IP/EA must be within a certain range from the target material; by default this is set to 0.5 eV, but it can be contolled by the flag `-w`. The window is the full width so the max offset is 0.5*window\n", - "* A selective contact should be a semiconductor, so we apply a criterion based on its band gap. If the gap is too large we consider that it would be an insulator. By default this is set to 4.0 eV and is controlled by the flag `-g`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%%bash\n", - "cd Electronic/\n", - "python scan_energies.py -h" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Now let's do a proper scan\n", - "* IP = 5.7 eV\n", - "* EA = 4.0 eV\n", - "* Window = 0.25 eV\n", - "* Insulating threshold = 4.0 eV" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%%bash\n", - "cd Electronic/\n", - "python scan_energies.py -i 5.7 -e 4.0 -w 0.5 -g 4.0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2. Lattice matching\n", - "## Background\n", - "\n", - "For stable interfaces there should be an integer relation between the lattice constants of the two surfaces in contact, which allows for perfect matching, with minimal strain. Generally a strain value of ~ 3% is considered acceptable, above this the interface will be incoherent.\n", - "\n", - "This section uses the [ASE package](https://wiki.fysik.dtu.dk/ase/) to construct the low index surfaces of the materials identified in the electronic step, as well as those of the target material. The code `LatticeMatch.py` to identify optimal matches.\n", - "\n", - "First we need `.cif` files of the materials obtained from the electronic matching. These are obtained from the [Materials Project website](https://www.materialsproject.org). Most of the `.cif` files are there already, but we should add Cu2O and GaN, just for practice.\n", - "\n", - "## Lattice matching routine\n", - "\n", - "The lattice matching routine involves obtaining reduced cells for each surface and looking for multiples of each side which match. The procedure is described in more detail in [our paper](http://pubs.rsc.org/en/content/articlehtml/2016/tc/c5tc04091d).\n", - "\n", - "\n", - "\n", - "The actual clever stuff of the algorithm comes from a paper from Zur and McGill in [J. Appl. Physics (1984)](http://scitation.aip.org/content/aip/journal/jap/55/2/10.1063/1.333084).\n", - "\n", - "\n", - "\n", - "## The script\n", - "\n", - "The work is done by a python script called `LatticeMatch.py`. As input it reads `.cif` files. It takes a number of flags: \n", - "* `-a` the file containing the crystallographic information of the first material\n", - "* `-b` the file containing the crystallographic information of the second material \n", - "* `-s` the strain threshold above which to cutoff, defaults to 0.05\n", - "* `-l` the maximum number of times to expand either surface to find matching conditions, defaults to 5\n", - "\n", - "We will run the script in a bash loop to iterate over all interfaces of our contact materials with the (100) and (110) surfaces of pseudo-cubic CH3NH3PbI3. Note that I have made all lattice parameters of CH3NH3PbI3 exactly equal, this is to facilitate the removal of duplicate surfaces by the script." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%%bash\n", - "cd Lattice/\n", - "for file in *.cif; do python LatticeMatch.py -a MAPI/CH3NH3PbI3.cif -b $file -s 0.03; done" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3. Site matching\n", - "\n", - "So far the interface matching considered only the magnitude of the lattice vectors. It would be nice to be able to include some measure of how well the dangling bonds can passivate one another. We do this by calculating the site overlap. Basically, we determine the undercoordinated surface atoms on each side and project their positions into a 2D plane. \n", - "\n", - "\n", - "\n", - "We then lay the planes over each other and slide them around until there is the maximum coincidence. We calculate the overlap factor from \n", - "\n", - "$$ ASO = \\frac{2S_C}{S_A + S_B}$$\n", - "\n", - "where $S_C$ is the number of overlapping sites in the interface, and $S_A$ and $S_B$ are the number of sites in each surface.\n", - "\n", - "\n", - "\n", - "## The script\n", - "\n", - "This section can be run in a stand-alone script called `csl.py`. It relies on a library of the 2D projections of lattice sites from different surfaces, which is called `surface_points.py`. Currently this contains a number of common materials types, but sometimes must be expanded as new materials are identified from the electronic and lattice steps.\n", - "\n", - "`csl.py` takes the following input parameters:\n", - "* `-a` The first material to consider\n", - "* `-b` The second material to consider\n", - "* `-x` The first materials miller index to consider, format : 001\n", - "* `-y` The second materials miller index to consider, format : 001\n", - "* `-u` The first materials multiplicity, format : 2,2\n", - "* `-v` The second materials multiplicity, format : 2,2\n", - "\n", - "We can run it for one example from the previous step, let's say GaN (010)x(2,5) with CH3NH3PbI3 (110)x(1,3)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%%bash\n", - "cd Site/\n", - "python csl.py -a CH3NH3PbI3 -b GaN -x 110 -y 010 -u 1,3 -v 2,5" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## All together\n", - "\n", - "The lattice and site examples above give a a feel for what is going on. For a proper screening procedure it would be nice to be able to run them together. That's exactly what happens with the `LatticeSite.py` script. It uses a new class `Pair` to store and pass information about the interface pairings. This includes the materials names, miller indices of matching surfaces, strians, multiplicities etc.\n", - "\n", - "The `LatticeSite.py` script takes the same variables as `LatticeMatch.py`. It just takes a little longer to run, so a bit of patience is required.\n", - "\n", - "This script outputs the standard pair information as well as the site matching factor, which is calculated as\n", - "\n", - "$$ \\frac{100\\times ASO}{1 + |\\epsilon|}$$\n", - "\n", - "where the $ASO$ was defined above, and $\\epsilon$ in the average of the $u$ and $v$ strains. The number is a measure of the mechanical stability of an interface. A perfect interface of a material with itself would have a fator of 100.\n", - "\n", - "Where lattices match but no information on the structure of the surface exists it is flagged up. You can always add new surfaces as required." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%%bash\n", - "cd Site/\n", - "for file in *cif; do python LatticeSite.py -a MAPI/CH3NH3PbI3.cif -b $file -s 0.03; done" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 ('smact_tests')", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - }, - "vscode": { - "interpreter": { - "hash": "9f89bce96645c075fd87ba4308874c26726cf41cb3962e47a97b7697a60dd355" - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/examples/Practical_tutorial/Electronic/CollatedData.txt b/examples/Practical_tutorial/Electronic/CollatedData.txt deleted file mode 100644 index 679591ea..00000000 --- a/examples/Practical_tutorial/Electronic/CollatedData.txt +++ /dev/null @@ -1,174 +0,0 @@ -Species Eg EA IP -SiC 2.36 4.00 6.36 -AlN 6.03 1.90 7.93 -AlP 2.42 2.51 4.93 -AlAs 2.36 1.71 4.07 -AlSb 1.60 3.60 5.20 -BaO 3.99 0.57 4.56 -BaS 3.81 0.84 4.65 -BaSe 3.66 0.95 4.61 -BaTe 3.40 1.43 4.83 -BN 6.20 4.50 10.70 -CaO 6.80 0.70 7.50 -CaS 4.60 1.85 6.45 -CaSe 4.87 2.32 7.19 -CaTe 4.07 3.53 7.60 -CaF2 12.10 -0.30 11.80 -CdO 0.78 5.24 6.02 -CdS 2.42 4.50 6.92 -CdSe 1.74 4.56 6.30 -CdTe 1.44 4.28 5.72 -CsI 6.20 -0.30 5.90 -GaN 3.43 4.10 7.53 -GaP 2.26 4.10 6.36 -GaAs 1.42 4.07 5.49 -GaSb 0.73 4.06 4.79 -InN 0.65 5.80 6.45 -InP 1.34 4.38 5.72 -InAs 0.36 4.90 5.26 -InSb 0.24 4.59 4.83 -KF 10.70 0.00 10.70 -KCl 8.90 0.50 9.40 -KBr 7.40 0.80 8.20 -KI 6.00 1.20 7.20 -LiF 13.60 1.35 14.95 -LiBr 7.60 0.20 7.80 -MgO 7.80 -0.65 7.15 -MgS 4.87 3.15 8.02 -MgSe 4.05 4.50 8.55 -NaF 11.60 1.35 12.95 -NaCl 8.50 0.50 9.00 -NaBr 7.50 0.40 7.90 -PbS 0.40 4.60 5.00 -RbF 10.35 -0.10 10.25 -RbCl 8.20 0.50 8.70 -RbBr 7.40 0.40 7.80 -RbI 6.10 1.20 7.30 -Si3N4 5.30 2.10 7.40 -SnS2 2.10 4.20 6.30 -SnSe2 1.00 4.35 5.35 -SrO 5.20 0.67 5.87 -SrS 4.30 1.35 5.65 -SrSe 4.42 1.77 6.19 -SrTe 3.73 2.40 6.13 -ZnO 3.30 4.20 7.50 -ZnS 3.70 3.80 7.50 -ZnSe 2.82 4.00 6.82 -ZnTe 2.26 3.53 5.79 -HfO2 5.70 2.00 7.70 -ZrO2 5.80 2.60 8.40 -SiO2 9.00 0.90 8.10 -GeO2 5.35 2.93 8.28 -SnO2 3.60 5.30 8.90 -MoO3 2.80 2.20 5.00 -WO3 2.95 3.33 6.28 -Al2O3 8.70 3.72 12.42 -Ga2O3 4.80 3.20 8.00 -In2O3 2.70 4.30 7.00 -La2O3 6.00 2.50 8.50 -Ta2O5 4.50 3.20 7.70 -TiO2 3.05 4.20 7.21 -C 5.48 0.37 5.85 -Si 1.17 3.98 5.15 -Ge 0.74 4.01 4.75 -MnO 3.28 1.80 5.08 -NiO 3.60 1.73 5.33 -Cu2O 2.10 3.56 5.66 -Fe2O3 2.10 4.85 6.95 -SrTiO3 3.20 4.08 7.28 -Zn2TiO4 3.21 3.25 6.46 -Bi2O3 2.77 4.63 7.40 -Sb2O3 3.00 4.17 7.17 -NaNbO3 3.43 3.80 7.23 -KTaO3 3.53 3.80 7.33 -CuI 3.37 2.43 5.80 -CuI 2.18 3.02 5.20 -CuI 4.62 2.28 5.30 -BaTiO3 3.30 4.21 7.51 -CdFe2O4 2.30 4.89 7.19 -CuO 1.70 4.89 6.59 -FeTiO3 2.80 4.56 7.36 -Hg2Nb2O 1.80 5.05 6.85 -Nb2O5 3.40 4.16 7.56 -PbO 2.80 4.46 7.26 -PbFe12O19 2.30 5.20 7.50 -YFeO3 2.60 4.60 7.20 -FeS2 0.95 4.96 5.91 -HfS2 1.13 4.63 5.76 -HgS 2.00 4.74 6.74 -In2S3 2.00 3.69 5.69 -MoS2 1.17 4.43 5.60 -ZrS2 1.82 4.28 6.10 -Ag2O 1.20 4.69 5.89 -AlTiO3 3.60 3.64 7.24 -Ce2O3 2.40 4.00 6.40 -CoO 2.60 4.39 6.99 -CoTiO3 2.25 4.64 6.89 -CuTiO3 2.99 4.32 7.31 -FeO 2.40 4.33 6.73 -Fe3O4 0.10 5.73 5.83 -FeOOH 2.60 5.08 7.68 -HgO 1.90 5.13 7.03 -Hg2Ta2O7 1.80 5.34 7.14 -KNbO3 3.30 3.64 6.94 -LaTi2O7 4.00 3.90 7.90 -LiNbO3 3.50 3.77 7.27 -LiTaO3 4.00 3.55 7.55 -MgTiO3 3.70 3.75 7.45 -MnO2 0.25 5.83 6.08 -MnTiO3 3.10 4.04 7.14 -Nd2O3 4.70 2.87 7.57 -NiTiO3 2.18 4.70 6.88 -PdO 1.00 5.29 6.29 -Pr2O3 3.90 3.24 7.14 -Sm2O3 4.40 3.07 7.47 -SnO 4.20 3.59 7.79 -Tb2O3 3.80 3.44 7.24 -Tl2O3 1.60 4.55 6.15 -Yb2O3 4.90 3.02 7.92 -ZnTiO3 3.06 4.27 7.33 -Ag2S 0.92 4.50 5.42 -AgAsS2 1.95 4.51 6.46 -AgSbS2 1.72 4.51 6.23 -As2S3 2.50 4.58 7.08 -Ce2S3 2.10 3.59 5.69 -CoS 0.00 5.17 5.17 -CoS2 0.00 5.49 5.49 -CoAsS 0.50 4.96 5.46 -CuS 0.00 5.27 5.27 -Cu2S 1.10 4.44 5.54 -CuS2 0.00 5.57 5.57 -Cu3AsS4 1.28 4.75 6.03 -CuFeS2 0.35 4.97 5.32 -Cu5FeS4 1.00 4.55 5.55 -CuInS2 1.50 4.06 5.56 -CuIn5S8 1.26 4.09 5.35 -Dy2S3 2.85 3.36 6.21 -FeS 0.10 4.97 5.07 -Fe3S4 0.00 5.18 5.18 -FeAsS 0.20 5.01 5.21 -Gd2S3 2.55 3.57 6.12 -HgSb4S8 1.68 4.81 6.49 -La2S3 2.91 3.25 6.16 -MnS 3.00 3.31 6.31 -MnS2 0.50 4.99 5.49 -Nd2S3 2.70 3.30 6.00 -NiS 0.40 5.03 5.43 -NiS2 0.30 5.39 5.69 -OsS2 2.00 4.74 6.74 -Pb10Ag3Sb11S28 1.39 4.59 5.98 -Pb2As2S5 1.39 4.71 6.10 -PbCuSbS3 1.23 4.61 5.84 -Pb5Sn3Sb2S14 0.65 4.95 5.60 -PtS2 0.95 5.53 6.48 -Rh2S3 1.50 4.61 6.11 -RuS2 1.38 4.89 6.27 -Sb2S3 1.72 4.72 6.44 -Sm2S3 2.60 3.39 5.99 -SnS 1.01 4.66 5.67 -Tb2S3 2.50 3.51 6.01 -TiS2 0.70 4.76 5.46 -TlAsS2 1.80 4.16 5.96 -WS2 1.35 4.86 6.21 -ZnS2 2.70 4.21 6.91 -Zn3In2S6 2.81 3.59 6.40 diff --git a/examples/Practical_tutorial/Electronic/scan_energies.py b/examples/Practical_tutorial/Electronic/scan_energies.py deleted file mode 100644 index ae7f8f62..00000000 --- a/examples/Practical_tutorial/Electronic/scan_energies.py +++ /dev/null @@ -1,82 +0,0 @@ -from optparse import OptionParser - -parser = OptionParser() -parser.add_option( - "-i", - "--IP", - action="store", - type="float", - dest="IP", - default=5.0, - help="The first material's IP, default 5.0", -) -parser.add_option( - "-e", - "--EA", - action="store", - type="float", - dest="EA", - default=4.0, - help="The first material's EA, default 4.0", -) -parser.add_option( - "-w", - "--window", - action="store", - type="float", - dest="window", - default=1.0, - help="The window around the IP/EA to allow +/- , eq w=1 gives +/- 0.5. Default 1.0", -) -parser.add_option( - "-g", - "--gap", - action="store", - type="float", - dest="gap", - default=4.0, - help="The bandgap above which a layer is considered insulating and disregarded Default 4.0", -) - -(options, args) = parser.parse_args() - - -f = open("CollatedData.txt") -lines = f.readlines() -f.close() - -HTL = [] -ETL = [] -conducting_ETL = [] -conducting_HTL = [] -window = options.window - -for line in lines: - inp = line.split() - if inp[0] != "Species": - Eg = float(inp[1]) - EA = float(inp[2]) - IP = float(inp[3]) - if Eg > 2.0: - if ( - EA >= options.EA - window * 0.5 - and EA <= options.EA + window * 0.5 - ): - ETL.append(inp[0]) - if Eg < options.gap: - conducting_ETL.append(inp[0]) - if IP <= options.IP + window * 0.5 and IP >= options.IP - window * 0.5: - if EA < 3.9: - HTL.append(inp[0]) - if Eg < options.gap: - conducting_HTL.append(inp[0]) - -print("Number of potential electron contacting layers: ", len(conducting_ETL)) -print("Number of potential hole contacting layers: ", len(conducting_HTL)) - -print("Conductive electron contacting layers: ") -print(len(conducting_ETL)) -print(conducting_ETL) -print("Conductive hole contacting layers: ") -print(len(conducting_HTL)) -print(conducting_HTL) diff --git a/examples/Practical_tutorial/Images/ASO.gif b/examples/Practical_tutorial/Images/ASO.gif deleted file mode 100644 index 943185b1..00000000 Binary files a/examples/Practical_tutorial/Images/ASO.gif and /dev/null differ diff --git a/examples/Practical_tutorial/Images/Combinations_vs_Permutations.png b/examples/Practical_tutorial/Images/Combinations_vs_Permutations.png deleted file mode 100644 index 281e56bc..00000000 Binary files a/examples/Practical_tutorial/Images/Combinations_vs_Permutations.png and /dev/null differ diff --git a/examples/Practical_tutorial/Images/ZurMcGill.jpg b/examples/Practical_tutorial/Images/ZurMcGill.jpg deleted file mode 100644 index a29953f6..00000000 Binary files a/examples/Practical_tutorial/Images/ZurMcGill.jpg and /dev/null differ diff --git a/examples/Practical_tutorial/Images/anderson.gif b/examples/Practical_tutorial/Images/anderson.gif deleted file mode 100644 index 0843624f..00000000 Binary files a/examples/Practical_tutorial/Images/anderson.gif and /dev/null differ diff --git a/examples/Practical_tutorial/Images/atomsinbox.png b/examples/Practical_tutorial/Images/atomsinbox.png deleted file mode 100644 index 7c1e70e0..00000000 Binary files a/examples/Practical_tutorial/Images/atomsinbox.png and /dev/null differ diff --git a/examples/Practical_tutorial/Images/binary-graph.tiff b/examples/Practical_tutorial/Images/binary-graph.tiff deleted file mode 100644 index 5a8ec374..00000000 Binary files a/examples/Practical_tutorial/Images/binary-graph.tiff and /dev/null differ diff --git a/examples/Practical_tutorial/Images/forascii.jpg b/examples/Practical_tutorial/Images/forascii.jpg deleted file mode 100644 index 17fcb42d..00000000 Binary files a/examples/Practical_tutorial/Images/forascii.jpg and /dev/null differ diff --git a/examples/Practical_tutorial/Images/lattice_match.gif b/examples/Practical_tutorial/Images/lattice_match.gif deleted file mode 100644 index 99d6f3c2..00000000 Binary files a/examples/Practical_tutorial/Images/lattice_match.gif and /dev/null differ diff --git a/examples/Practical_tutorial/Images/linus-pauling.png b/examples/Practical_tutorial/Images/linus-pauling.png deleted file mode 100644 index fef1d35b..00000000 Binary files a/examples/Practical_tutorial/Images/linus-pauling.png and /dev/null differ diff --git a/examples/Practical_tutorial/Images/pauling-equation.jpg b/examples/Practical_tutorial/Images/pauling-equation.jpg deleted file mode 100644 index 0b1cb9ea..00000000 Binary files a/examples/Practical_tutorial/Images/pauling-equation.jpg and /dev/null differ diff --git a/examples/Practical_tutorial/Images/pauling-equation.png b/examples/Practical_tutorial/Images/pauling-equation.png deleted file mode 100644 index b595fe0d..00000000 Binary files a/examples/Practical_tutorial/Images/pauling-equation.png and /dev/null differ diff --git a/examples/Practical_tutorial/Images/pauling-equation.tiff b/examples/Practical_tutorial/Images/pauling-equation.tiff deleted file mode 100644 index 707cd4a8..00000000 Binary files a/examples/Practical_tutorial/Images/pauling-equation.tiff and /dev/null differ diff --git a/examples/Practical_tutorial/Images/quaternary-graph.tiff b/examples/Practical_tutorial/Images/quaternary-graph.tiff deleted file mode 100644 index 09a77721..00000000 Binary files a/examples/Practical_tutorial/Images/quaternary-graph.tiff and /dev/null differ diff --git a/examples/Practical_tutorial/Images/site_overlap.gif b/examples/Practical_tutorial/Images/site_overlap.gif deleted file mode 100644 index 912afa09..00000000 Binary files a/examples/Practical_tutorial/Images/site_overlap.gif and /dev/null differ diff --git a/examples/Practical_tutorial/Images/ternary-graph.tiff b/examples/Practical_tutorial/Images/ternary-graph.tiff deleted file mode 100644 index c703be5d..00000000 Binary files a/examples/Practical_tutorial/Images/ternary-graph.tiff and /dev/null differ diff --git a/examples/Practical_tutorial/Images/toc.gif b/examples/Practical_tutorial/Images/toc.gif deleted file mode 100644 index 880de944..00000000 Binary files a/examples/Practical_tutorial/Images/toc.gif and /dev/null differ diff --git a/examples/Practical_tutorial/Lattice/LatticeMatch.py b/examples/Practical_tutorial/Lattice/LatticeMatch.py deleted file mode 100644 index 90375c93..00000000 --- a/examples/Practical_tutorial/Lattice/LatticeMatch.py +++ /dev/null @@ -1,380 +0,0 @@ -import glob -import itertools -import math -import re - -# import argparse -from optparse import OptionParser - -import ase.build.surface as surface - -# import smact.core as core -import ase.io as io -import numpy as np - - -# We need a class "pair" which contains the information about a matching interface pair -class Pair: - """Class providing standard nformation on interface matching pairs.""" - - def __init__( - self, - material1, - material2, - surface1, - surface2, - multiplicity1, - multiplicity2, - strains, - ): - """ - Attributes: - Pair.material1 : name of first material - Pair.material2 : name of second material - Pair.surface1 : miller index of surface 1 Format: [1,1,1] - Pair.surface2 : miller index of surface 2 Format: [1,1,1] - Pair.multiplicity1 : multiplicity of u,v in surface1 Format: [1,1] - Pair.multiplicity2 : multiplicity of u,v in surface2 Format: [1,1] - Pair.strains : stains in u,v and gamma Format: [0.1,0.1,0.1] - """ - self.material1 = material1 - self.material2 = material2 - self.surface1 = surface1 - self.surface2 = surface2 - self.multiplicity1 = multiplicity1 - self.multiplicity2 = multiplicity2 - self.strains = strains - - -# parser = argparse.ArgumentParser() -parser = OptionParser() -parser.add_option( - "-a", - "--matera", - action="store", - type="string", - dest="mater1", - default="material.cif", - help="The first material. Default material.cif", -) -parser.add_option( - "-b", - "--materb", - action="store", - type="string", - dest="mater2", - default="material-b.cif", - help="The second material. Default material-b.cif", -) -parser.add_option( - "-s", - "--strain", - action="store", - type="float", - dest="strain", - default="0.04", - help="Maximum strain between the interfaces. Default 0.04", -) -parser.add_option( - "-l", - "--limit", - action="store", - type="int", - dest="limit", - default=5, - help="Maximum number of supercell expansions for each interface. Default 5", -) -parser.add_option("-v", action="store_true", dest="verbose") -# parser.add_option("-v", "--verbose", dest="verbose", type='bool', default=True, help="increase output verbosity") -# parser.add_argument("--print_strains", help="increase output verbosity of strian output") -(options, args) = parser.parse_args() - -# Define some basic algebra - - -def dotproduct(v1, v2): - return sum((a * b) for a, b in zip(v1, v2)) - - -def length(v): - return math.sqrt(dotproduct(v, v)) - - -def angle(v1, v2): - return math.acos(dotproduct(v1, v2) / (length(v1) * length(v2))) - - -# Define the tests as required by Fig 2 of Zur and McGill -def test1(a, b): - if np.dot(a, b) < 0: - return False - else: - return True - - -def test2(a, b): - if np.linalg.norm(a) > np.linalg.norm(b): - return False - else: - return True - - -def test3(a, b): - if np.linalg.norm(b) > np.linalg.norm(b + a): - return False - else: - return True - - -def test4(a, b): - if np.linalg.norm(b) > np.linalg.norm(b - a): - return False - else: - return True - - -# Switching of vectors as prescribed by Fig 2 of Zur and McGill -def cond1(a, b): - if np.dot(a, b) < 0: - b = -b - return a, b - - -def cond2(a, b): - if np.linalg.norm(a) > np.linalg.norm(b): - c = b - b = a - a = c - cond1(a, b) - return a, b - - -def cond3(a, b): - if np.linalg.norm(b) > np.linalg.norm(b + a): - b = b + a - return a, b - - -def cond4(a, b): - if np.linalg.norm(b) > np.linalg.norm(b - a): - b = b - a - return a, b - - -# § -def reduce_vectors(va, vb): - """Reduce the surface vectors to their minimal cell, as outlined in figure 2 of - J. Appl. Phys. 55, 380 (1984) - Args: - va,vb: lists of real numbers/integers. Minimum length 2 - Returns: - a,b: arrays of dimension (2x1). The reduced vectors - - """ - a = np.asarray(va[0:2]) - b = np.asarray(vb[0:2]) - test_truth = 0 # A test that all 4 necessary conditions are met - while test_truth < 4: - a, b = cond1(a, b) - a, b = cond2(a, b) - a, b = cond3(a, b) - a, b = cond4(a, b) - truths = [test1(a, b), test2(a, b), test3(a, b), test4(a, b)] - test_truth = sum(truths) - - return a, b - - -def surface_vectors(lattice, miller): - """Given the xtal as defined with a (3x3) cell uses the ase surface module to cut the required surface. - Args: - lattice : ase Atoms object - miller : miller indices of the surface, a tuple of integers, length 3. - Returns: - vectors[0/1] : the surface vectors (u,v), list of real numbers. - """ - surf = surface(lattice, miller, layers=1) - vectors = surf.cell[0:2] - return vectors[0], vectors[1] - - -def surface_ratios(surface_a, surface_b, threshold=0.05, limit=5): - """Given two surfaces a and b defined by vectors (u,v) tests to see if there is a ratio of r1/r2 which gives a lattice vector with mismatch less than the threshold. - Args: - surfaces_ : the surface vectors and angle. A (3) tuple of real numbers. - threshold : the limit for lattice mismatch. - limit : the maximum number to multiply lattices by to obtain match. - Returns: - exists : a bool of wheter the match was found - multiplicity : a list (1x2) with the integer values to multiply by. - """ - - epitaxy = False - u_satisfied = False - v_satisfied = False - angles_match = False - - super_a = (0, 0) - super_b = (0, 0) - strains = [0, 0, 0] - if options.verbose: - print(" Entering matching ratios routine") - print("------ ------- ------- -------") - print("Surface a: ", surface_a) - print("Surface b: ", surface_b) - print("------ ------- ------- -------") - # Ensure that the vector angles match (up to an arbitrary 180 degree rotation) - if surface_a[2] - surface_b[2] <= 0.2: - angles_match = True - strains[2] = surface_a[2] - surface_b[2] - if options.verbose: - print("Angles are within tolerance") - # Run the test for the first lattice vector set - if angles_match: - for i in range(1, limit + 1): - if u_satisfied: - break - for j in range(1, limit + 1): - r1 = float(i * surface_a[0]) - r2 = float(j * surface_b[0]) - strain = 2 * abs(r1 - r2) / (r1 + r2) - if strain < threshold: - a = (i, j) - u_satisfied = True - strains[0] = strain - break - - # Run the test for the second lattice vector set - if u_satisfied: # Dont bother with v if u not satisfied - for i in range(1, limit + 1): - if v_satisfied: - break - for j in range(1, limit + 1): - r1 = float(i * surface_a[1]) - r2 = float(j * surface_b[1]) - strain = 2 * abs(r1 - r2) / (r1 + r2) - if strain < threshold: - b = (i, j) - v_satisfied = True - strains[1] = strain - break - if angles_match and u_satisfied and v_satisfied: - super_a = (a[0], b[0]) - super_b = (a[1], b[1]) - epitaxy = True - return epitaxy, super_a, super_b, strains - - -material1 = re.sub(r"\.cif$", "", options.mater1) -material2 = re.sub(r"\.cif$", "", options.mater2) - -# Code output header, for God's sake clean this up! -# God's will be done. -""" -print "###-----------------------------------###" -print "### ###" -print " Scanning for srufaces of " -print " ",material1, material2 -print "### ###" -print "###-----------------------------------###" -""" - -# Scan through the various miller indices -indices_a = list(itertools.product([0, 1], repeat=3)) -indices_a = [(1, 0, 0), (1, 1, 0)] # Just consider these two for MAPI -xtalA = io.read(options.mater1) -xtalB = io.read(options.mater2) -# mathced_pairs is a list containing the Pairs class for all unique interfaces -matched_pairs = [] -print(" ") -print( - "-------------------------------------------------------------------------------------------------" -) -print( - "-------------------------------------------------------------------------------------------------" -) -print( - "(miller 1) (miller 2) (mult 1) (mult 2) [Strain in vector u, Strain in vector v, angle mis-match]" -) -# Set the values for material A -for index_a in indices_a: - if index_a != (0, 0, 0): - vec1, vec2 = surface_vectors(xtalA, index_a) - r_vec1, r_vec2 = reduce_vectors(vec1, vec2) - surface_vector_1 = ( - length(r_vec1), - length(r_vec2), - angle(r_vec1, r_vec2), - ) - # Set the values for material B - indices_b = list(itertools.product([0, 1], repeat=3)) - for index_b in indices_b: - if index_b != (0, 0, 0): - vec1, vec2 = surface_vectors(xtalB, index_b) - r_vec1, r_vec2 = reduce_vectors(vec1, vec2) - surface_vector_2 = ( - length(r_vec1), - length(r_vec2), - angle(r_vec1, r_vec2), - ) - epitaxy, a, b, strains = surface_ratios( - surface_vector_1, - surface_vector_2, - threshold=options.strain, - limit=options.limit, - ) - # print index_a, index_b, surface_vector_1, surface_vector_2 - if epitaxy: - if options.verbose: - print("------ ------ ------ ------ ------") - print( - "Surface A multiplicity: ", - a, - "semiconductor multiplicity: ", - b, - ) - print("Strain vector: ", strains) - surface_super_cell_a = np.asarray( - surface_vector_1[0:2] - ) * np.asarray(a) - print("Surface super-cell vector: ", surface_super_cell_a) - surface_super_cell_b = np.asarray( - surface_vector_2[0:2] - ) * np.asarray(b) - print("Surface super-cell vector: ", surface_super_cell_b) - print("------ ------ ------ ------ ------") - else: - new = Pair( - material1, material2, index_a, index_b, a, b, strains - ) - isnew = True - if len(matched_pairs) == 0 and new.strains[2] == 0.0: - matched_pairs.append(new) - for old in matched_pairs: - if ( - new.multiplicity1 == old.multiplicity1 - and new.multiplicity2 == old.multiplicity2 - and new.strains == old.strains - ): - isnew = False - else: - continue - if len(matched_pairs) > 0 and isnew and new.strains[2] == 0.0: - matched_pairs.append(new) - # print("%s ; %s ; %s; %s ; %s; %s" % ('Found',a,index_a,b,index_b,strains)) -print(material1, material2, len(matched_pairs)) -for pair in matched_pairs: - print( - pair.surface1, - pair.surface2, - pair.multiplicity1, - pair.multiplicity2, - pair.strains, - ) - -print( - "#################################################################################################" -) -# print "###-----------------------------------###" -# print "### ###" -# print "###-----------------------------------###" diff --git a/examples/Practical_tutorial/Site/LatticeSite.py b/examples/Practical_tutorial/Site/LatticeSite.py deleted file mode 100644 index 1536e436..00000000 --- a/examples/Practical_tutorial/Site/LatticeSite.py +++ /dev/null @@ -1,361 +0,0 @@ -import glob -import itertools -import math -import re -from optparse import OptionParser - -import ase.build.surface as surface - -# import smact.core as core -import ase.io as io -import numpy as np -import SiteMatch -import surface_points - - -# We need a class "pair" which contains the information about a matching interface pair -class Pair: - """Class providing standard nformation on interface matching pairs.""" - - def __init__( - self, - material1, - material2, - surface1, - surface2, - multiplicity1, - multiplicity2, - strains, - csl, - ): - """ - Attributes: - Pair.material1 : name of first material - Pair.material2 : name of second material - Pair.surface1 : miller index of surface 1 Format: [1,1,1] - Pair.surface2 : miller index of surface 2 Format: [1,1,1] - Pair.multiplicity1 : multiplicity of u,v in surface1 Format: [1,1] - Pair.multiplicity2 : multiplicity of u,v in surface2 Format: [1,1] - Pair.strains : stains in u,v and gamma Format: [0.1,0.1,0.1] - Pair.csl : the site matching, a float - """ - self.material1 = material1 - self.material2 = material2 - self.surface1 = surface1 - self.surface2 = surface2 - self.multiplicity1 = multiplicity1 - self.multiplicity2 = multiplicity2 - self.strains = strains - self.csl = csl - - -# parser = argparse.ArgumentParser() -parser = OptionParser() -parser.add_option( - "-a", - "--matera", - action="store", - type="string", - dest="mater1", - default="material.cif", - help="The first material. Default material.cif", -) -parser.add_option( - "-b", - "--materb", - action="store", - type="string", - dest="mater2", - default="material-b.cif", - help="The second material. Default material-b.cif", -) -parser.add_option( - "-s", - "--strain", - action="store", - type="float", - dest="strain", - default="0.04", - help="Maximum strain between the interfaces. Default 0.04", -) - -parser.add_option("-v", action="store_true", dest="verbose") -(options, args) = parser.parse_args() - -# Define some basic algebra - - -def dotproduct(v1, v2): - return sum((a * b) for a, b in zip(v1, v2)) - - -def length(v): - return math.sqrt(dotproduct(v, v)) - - -def angle(v1, v2): - return math.acos(dotproduct(v1, v2) / (length(v1) * length(v2))) - - -# Define the tests as required by Fig 2 of Zur and McGill -def test1(a, b): - if np.dot(a, b) < 0: - return False - else: - return True - - -def test2(a, b): - if np.linalg.norm(a) > np.linalg.norm(b): - return False - else: - return True - - -def test3(a, b): - if np.linalg.norm(b) > np.linalg.norm(b + a): - return False - else: - return True - - -def test4(a, b): - if np.linalg.norm(b) > np.linalg.norm(b - a): - return False - else: - return True - - -# Switching of vectors as prescribed by Fig 2 of Zur and McGill -def cond1(a, b): - if np.dot(a, b) < 0: - b = -b - return a, b - - -def cond2(a, b): - if np.linalg.norm(a) > np.linalg.norm(b): - c = b - b = a - a = c - cond1(a, b) - return a, b - - -def cond3(a, b): - if np.linalg.norm(b) > np.linalg.norm(b + a): - b = b + a - return a, b - - -def cond4(a, b): - if np.linalg.norm(b) > np.linalg.norm(b - a): - b = b - a - return a, b - - -# § -def reduce_vectors(va, vb): - """Reduce the surface vectors to their minimal cell, as outlined in figure 2 of - J. Appl. Phys. 55, 380 (1984) - Args: - va,vb: lists of real numbers/integers. Minimum length 2 - Returns: - a,b: arrays of dimension (2x1). The reduced vectors - - """ - a = np.asarray(va[0:2]) - b = np.asarray(vb[0:2]) - test_truth = 0 # A test that all 4 necessary conditions are met - while test_truth < 4: - a, b = cond1(a, b) - a, b = cond2(a, b) - a, b = cond3(a, b) - a, b = cond4(a, b) - truths = [test1(a, b), test2(a, b), test3(a, b), test4(a, b)] - test_truth = sum(truths) - - return a, b - - -def surface_vectors(lattice, miller): - """Given the xtal as defined with a (3x3) cell uses the ase surface module to cut the required surface. - Args: - lattice : ase Atoms object - miller : miller indices of the surface, a tuple of integers, length 3. - Returns: - vectors[0/1] : the surface vectors (u,v), list of real numbers. - """ - surf = surface(lattice, miller, layers=1) - vectors = surf.cell[0:2] - return vectors[0], vectors[1] - - -def surface_ratios(surface_a, surface_b, threshold=0.05, limit=5): - """Given two surfaces a and b defined by vectors (u,v) tests to see if there is a ratio of r1/r2 which gives a lattice vector with mismatch less than the threshold. - Args: - surfaces_ : the surface vectors and angle. A (3) tuple of real numbers. - threshold : the limit for lattice mismatch. - limit : the maximum number to multiply lattices by to obtain match. - Returns: - exists : a bool of whether the match was found - multiplicity : a list (1x2) with the integer values to multiply by. - """ - - epitaxy = False - u_satisfied = False - v_satisfied = False - angles_match = False - - super_a = (0, 0) - super_b = (0, 0) - strains = [0, 0, 0] - if options.verbose: - print(" Entering matching ratios routine") - print("------ ------- ------- -------") - print("Surface a: ", surface_a) - print("Surface b: ", surface_b) - print("------ ------- ------- -------") - # Ensure that the vector angles match (up to an arbitrary 180 degree rotation) - if surface_a[2] - surface_b[2] <= 0.2: - angles_match = True - strains[2] = surface_a[2] - surface_b[2] - if options.verbose: - print("Angles are within tolerance") - # Run the test for the first lattice vector set - if angles_match: - for i in range(1, limit + 1): - if u_satisfied: - break - for j in range(1, limit + 1): - r1 = float(i * surface_a[0]) - r2 = float(j * surface_b[0]) - strain = 2 * abs(r1 - r2) / (r1 + r2) - if strain < threshold: - a = (i, j) - u_satisfied = True - strains[0] = strain - break - - # Run the test for the second lattice vector set - if u_satisfied: # Dont bother with v if u not satisfied - for i in range(1, limit + 1): - if v_satisfied: - break - for j in range(1, limit + 1): - r1 = float(i * surface_a[1]) - r2 = float(j * surface_b[1]) - strain = 2 * abs(r1 - r2) / (r1 + r2) - if strain < threshold: - b = (i, j) - v_satisfied = True - strains[1] = strain - break - if angles_match and u_satisfied and v_satisfied: - super_a = (a[0], b[0]) - super_b = (a[1], b[1]) - epitaxy = True - return epitaxy, super_a, super_b, strains - - -material1 = re.sub(r"\.cif$", "", options.mater1) -material2 = re.sub(r"\.cif$", "", options.mater2) - -# Code output header, for God's sake clean this up! -# God's will be done. - -# Scan through the various miller indices -indices_a = list(itertools.product([0, 1], repeat=3)) -# indices_a = [(1,0,0),(1,1,0)] # Just consider these two for MAPI -xtalA = io.read(options.mater1) -xtalB = io.read(options.mater2) -# mathced_pairs is a list containing the Pairs class for all unique interfaces -matched_pairs = [] -# Set the values for material A -for index_a in indices_a: - if index_a != (0, 0, 0): - vec1, vec2 = surface_vectors(xtalA, index_a) - r_vec1, r_vec2 = reduce_vectors(vec1, vec2) - surface_vector_1 = ( - length(r_vec1), - length(r_vec2), - angle(r_vec1, r_vec2), - ) - # Set the values for material B - indices_b = list(itertools.product([0, 1], repeat=3)) - for index_b in indices_b: - if index_b != (0, 0, 0): - vec1, vec2 = surface_vectors(xtalB, index_b) - r_vec1, r_vec2 = reduce_vectors(vec1, vec2) - surface_vector_2 = ( - length(r_vec1), - length(r_vec2), - angle(r_vec1, r_vec2), - ) - epitaxy, a, b, strains = surface_ratios( - surface_vector_1, - surface_vector_2, - threshold=options.strain, - limit=5, - ) - if epitaxy: - if options.verbose: - print("------ ------ ------ ------ ------") - print( - "Surface A multiplicity: ", - a, - "semiconductor multiplicity: ", - b, - ) - print("Strain vector: ", strains) - surface_super_cell_a = np.asarray( - surface_vector_1[0:2] - ) * np.asarray(a) - print("Surface super-cell vector: ", surface_super_cell_a) - surface_super_cell_b = np.asarray( - surface_vector_2[0:2] - ) * np.asarray(b) - print("Surface super-cell vector: ", surface_super_cell_b) - print("------ ------ ------ ------ ------") - else: - new = Pair( - material1, material2, index_a, index_b, a, b, strains, 0.0 - ) - isnew = True - if len(matched_pairs) == 0 and new.strains[2] == 0.0: - matched_pairs.append(new) - for old in matched_pairs: - if ( - new.multiplicity1 == old.multiplicity1 - and new.multiplicity2 == old.multiplicity2 - ): - if ( - new.surface1 == old.surface1 - and new.surface2 == old.surface2 - ): - isnew = False - else: - continue - if len(matched_pairs) > 0 and isnew and new.strains[2] == 0.0: - matched_pairs.append(new) -# print material1, material2, len(matched_pairs) -for pair in matched_pairs: - material_1 = pair.material1 - material_2 = pair.material2 - print("") - print(material_1, material_2) - surface_1 = "".join(map(str, pair.surface1)) - surface_2 = "".join(map(str, pair.surface2)) - multiplicity1 = pair.multiplicity1 - multiplicity2 = pair.multiplicity2 - surfs_1 = getattr(surface_points, material_1)(surface_1) - surfs_2 = getattr(surface_points, material_2)(surface_2) - if len(surfs_1) > 0 and len(surfs_2) > 0: - pair.csl = SiteMatch.find_max_csl( - surfs_1, surfs_2, multiplicity1, multiplicity2 - ) - print( - pair.surface1, - pair.surface2, - (pair.csl * 100) / (1 + np.mean(pair.strains[:2] * 100)), - ) diff --git a/examples/Practical_tutorial/Site/SiteMatch.py b/examples/Practical_tutorial/Site/SiteMatch.py deleted file mode 100755 index 91a2a3ce..00000000 --- a/examples/Practical_tutorial/Site/SiteMatch.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python -# Searches for site overlap between two lattices -# All input between lines 72 - 79 -# Requires the surface_points.py file, which defines the different surfaces -################################################################################ -# Copyright Keith T Butler (2015) # -# # -# This file is part of SMACT: builder.py is free software: you can # -# redistribute it and/or modify it under the terms of the GNU General Public # -# License as published by the Free Software Foundation, either version 3 of # -# the License, or (at your option) any later version. # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# You should have received a copy of the GNU General Public License along with # -# this program. If not, see . # -# # -################################################################################ - -from optparse import OptionParser - -import numpy as np -import surface_points - - -def find_max_csl(surfs_1, surfs_2, multiplicity1, multiplicity2): - """ - Given surface points and multiplicities of the surfaces this returns the maximal overlap fraction of the sites - Attr: - surfs : lists of the surface points on each side of the interface. - multiplicity : lists of the multiplicity of the lattice vectors of u and v for each side of the interface. - Returns: - max_csl : float, the maximum fraction overlap found. - """ - csl_values = [] - for surface_1 in surfs_1: - if len(surface_1) > 0: - surf_1_super = super_surface( - np.asarray(surface_1), np.asarray(multiplicity1) - ) - for surface_2 in surfs_2: - if len(surface_2) > 0: - surf_2_super = super_surface( - np.asarray(surface_2), np.asarray(multiplicity2) - ) - for i in np.arange(0, 1, 0.1): - for j in np.arange(0, 1, 0.1): - t_surf = translate(surf_2_super, [i, j]) - csl_values.append( - csl(surf_1_super, t_surf, multiplicity1) - ) - - return max(csl_values) - - -def super_surface(surface, multiplicity): - """Makes a super cell out of the surface coordinates""" - - surf_super = [] - for site in surface: - for u in range(1, multiplicity[0] + 1): - for v in range(1, multiplicity[1] + 1): - surf_super.append( - [ - (site[0] + (u - 1)) / multiplicity[0], - (site[1] + (v - 1)) / multiplicity[1], - ] - ) - return np.asarray(surf_super) - - -def distance(a, b, mult): - """Calculate separations, don't forget that we need to scale the separations by the multiplicity of the MAPI surface in each direction.""" - d1 = abs(a[0] - b[0]) - if d1 > 1: - d1 = d1 - 1 - d2 = abs(a[1] - b[1]) - if d2 > 1: - d2 = d2 - 1 - - return np.sqrt((d1 * mult[0]) ** 2 + (d2 * mult[1]) ** 2) - - -def csl(surface1, surface2, mult_a, tol=0.15): - """Takes two surfaces and calculates the number of co-inciding sites (within a tolerance)""" - coincidence = 0.0 - for site_a in surface1: - for site_b in surface2: - if distance(site_a, site_b, mult_a) <= tol: - coincidence = coincidence + 1.0 - return coincidence * 2 / (len(surface1) + len(surface2)) - - -def wrapped(site): - """Crude minimum image for this code""" - if site[0] > 1: - site[0] = site[0] - 1 - if site[1] > 1: - site[1] = site[1] - 1 - if site[0] < 0: - site[0] = site[0] + 1 - if site[1] < 0: - site[1] = site[1] + 1 - return site - - -def translate(surface, T): - """Translate the positions of the ions by a given vector""" - for i, site in enumerate(surface): - site = wrapped(site + T) - surface[i] = site - return surface - - -def get_comma_separated_args(option, opt, value, parser): - setattr(parser.values, option.dest, value.split(",")) - - -###### THESE ARE THE INPUT VARIABLES ####### -""" -parser = OptionParser() -parser.add_option("-a", "--matera", - action="store", type="string", dest="mater1", default="perovskite", - help="The first material to consider") -parser.add_option("-b", "--materb", - action="store", type="string", dest="mater2", default="perovskite", - help="The second material to consider") -parser.add_option("-x", "--millera", - action="store", type=int, dest="milla", default="100", - help="The first materials miller index to consider, format : 100") -parser.add_option("-y", "--millerb", - action="store", type=int, dest="millb", default="100", - help="The second materials miller index to consider, format : 100 ") -parser.add_option("-u", "--multa", - type='string',action="callback", dest="multa", - callback=get_comma_separated_args, - help="The first materials multiplicity, format : 2,2") -parser.add_option("-v", "--multb", - type='string',action="callback", dest="multb", - callback=get_comma_separated_args, - help="The second materials multiplicity, format : 3,3") - - -(options, args) = parser.parse_args() -""" diff --git a/examples/Practical_tutorial/Site/csl.py b/examples/Practical_tutorial/Site/csl.py deleted file mode 100755 index 38720db7..00000000 --- a/examples/Practical_tutorial/Site/csl.py +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env python -# Searches for site overlap between two lattices -# All input between lines 72 - 79 -# Requires the surface_points.py file, which defines the different surfaces -################################################################################ -# Copyright Keith T Butler (2015) # -# # -# This file is part of SMACT: builder.py is free software: you can # -# redistribute it and/or modify it under the terms of the GNU General Public # -# License as published by the Free Software Foundation, either version 3 of # -# the License, or (at your option) any later version. # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# You should have received a copy of the GNU General Public License along with # -# this program. If not, see . # -# # -################################################################################ - -from optparse import OptionParser - -import numpy as np -import surface_points - - -def find_max_csl(surfs_1, surfs_2, multiplicity1, multiplicity2): - """ - Given surface points and multiplicities of the surfaces this returns the maximal overlap fraction of the sites - Attr: - surfs : lists of the surface points on each side of the interface. - multiplicity : lists of the multiplicity of the lattice vectors of u and v for each side of the interface. - Returns: - max_csl : float, the maximum fraction overlap found. - """ - csl_values = [] - for surface_1 in surfs_1: - if len(surface_1) > 0: - surf_1_super = super_surface( - np.asarray(surface_1), np.asarray(multiplicity1) - ) - for surface_2 in surfs_2: - if len(surface_2) > 0: - surf_2_super = super_surface( - np.asarray(surface_2), np.asarray(multiplicity2) - ) - for i in np.arange(0, 1, 0.1): - for j in np.arange(0, 1, 0.1): - t_surf = translate(surf_2_super, [i, j]) - csl_values.append( - csl(surf_1_super, t_surf, multiplicity1) - ) - - return max(csl_values) - - -def super_surface(surface, multiplicity): - """Makes a super cell out of the surface coordinates""" - - surf_super = [] - for site in surface: - for u in range(1, multiplicity[0] + 1): - for v in range(1, multiplicity[1] + 1): - surf_super.append( - [ - (site[0] + (u - 1)) / multiplicity[0], - (site[1] + (v - 1)) / multiplicity[1], - ] - ) - return np.asarray(surf_super) - - -def distance(a, b, mult): - """Calculate separations, don't forget that we need to scale the separations by the multiplicity of the MAPI surface in each direction.""" - d1 = abs(a[0] - b[0]) - if d1 > 1: - d1 = d1 - 1 - d2 = abs(a[1] - b[1]) - if d2 > 1: - d2 = d2 - 1 - - return np.sqrt((d1 * mult[0]) ** 2 + (d2 * mult[1]) ** 2) - - -def csl(surface1, surface2, mult_a, tol=0.15): - """Takes two surfaces and calculates the number of co-inciding sites (within a tolerance)""" - coincidence = 0.0 - for site_a in surface1: - for site_b in surface2: - if distance(site_a, site_b, mult_a) <= tol: - coincidence = coincidence + 1.0 - return coincidence * 2 / (len(surface1) + len(surface2)) - - -def wrapped(site): - """Crude minimum image for this code""" - if site[0] > 1: - site[0] = site[0] - 1 - if site[1] > 1: - site[1] = site[1] - 1 - if site[0] < 0: - site[0] = site[0] + 1 - if site[1] < 0: - site[1] = site[1] + 1 - return site - - -def translate(surface, T): - """Translate the positions of the ions by a given vector""" - for i, site in enumerate(surface): - site = wrapped(site + T) - surface[i] = site - return surface - - -def get_comma_separated_args(option, opt, value, parser): - setattr(parser.values, option.dest, value.split(",")) - - -###### THESE ARE THE INPUT VARIABLES ####### -parser = OptionParser() -parser.add_option( - "-a", - "--matera", - action="store", - type="string", - dest="mater1", - default="perovskite", - help="The first material to consider", -) -parser.add_option( - "-b", - "--materb", - action="store", - type="string", - dest="mater2", - default="perovskite", - help="The second material to consider", -) -parser.add_option( - "-x", - "--millera", - action="store", - type=str, - dest="milla", - default="100", - help="The first materials miller index to consider, format : 100", -) -parser.add_option( - "-y", - "--millerb", - action="store", - type=str, - dest="millb", - default="100", - help="The second materials miller index to consider, format : 100 ", -) -parser.add_option( - "-u", - "--multa", - type="string", - action="callback", - dest="multa", - callback=get_comma_separated_args, - help="The first materials multiplicity, format : 2,2", -) -parser.add_option( - "-v", - "--multb", - type="string", - action="callback", - dest="multb", - callback=get_comma_separated_args, - help="The second materials multiplicity, format : 3,3", -) - - -(options, args) = parser.parse_args() -material_1 = options.mater1 -material_2 = options.mater2 -surface_1 = str(options.milla) -surface_2 = str(options.millb) -multiplicity1 = list(map(int, options.multa)) -multiplicity2 = list(map(int, options.multb)) -######## INPUT OVER ########### -print(material_1, surface_1) -print(material_2, surface_2) -surfs_1 = getattr(surface_points, material_1)(surface_1) -surfs_2 = getattr(surface_points, material_2)(surface_2) - -if len(surfs_1) > 0 and len(surfs_2) > 0: - maxi = find_max_csl(surfs_1, surfs_2, multiplicity1, multiplicity2) - print(maxi) diff --git a/examples/Practical_tutorial/Site/surface_points.py b/examples/Practical_tutorial/Site/surface_points.py deleted file mode 100644 index 5f53d5dd..00000000 --- a/examples/Practical_tutorial/Site/surface_points.py +++ /dev/null @@ -1,710 +0,0 @@ -#!/usr/bin/env python -# Defines the positions (on a 2D grid) of the positions of under-coordinated -# atoms at the surface of a material -################################################################################ -# Copyright Keith T Butler (2015) # -# # -# This file is part of SMACT: builder.py is free software: you can # -# redistribute it and/or modify it under the terms of the GNU General Public # -# License as published by the Free Software Foundation, either version 3 of # -# the License, or (at your option) any later version. # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# You should have received a copy of the GNU General Public License along with # -# this program. If not, see . # -# # -################################################################################ - -""" -The general form of the surface_points file. - -Each new species or class of materials is defined as a function, the function contains a dictionary of the known surfaces of that material or class. -The surfaces contain the 2D projection of the under-coordinated surface atoms, there may be several possible terminations, then there are all listed. - -The function has a list called 'exists', this contains all surfaces for which surface points are available. If you add a new surface be sure to include it in this list too. - -Each dictionary item contains a list of the surface cuts and must end with an empty tuple, note the ,() at the end of each item. -""" - - -def anatase(miller): - exists = ["001", "010", "110", "100", "101"] - if miller in exists: - surfaces = {} - surfaces["110"] = ( - [0.0, 0.0], - [0.2, 0], - [0.3, 0.5], - [0.5, 0.5], - [0.7, 0.5], - [0.8, 0.0], - ), () - surfaces["001"] = ([0.5, 0.0], [0.5, 0.5]), () - surfaces["010"] = ( - [0.5, 0.0], - [0.0, 0.0], - [0.0, 0.2], - [0.5, 0.5], - [0.5, 0.75], - [0.8, 0.0], - ), () - surfaces["100"] = ( - [0.5, 0.0], - [0.0, 0.0], - [0.0, 0.2], - [0.5, 0.5], - [0.5, 0.75], - [0.8, 0.0], - ), () - surfaces["101"] = ( - ( - [0.0, 0.17], - [0.5, 0.12], - [0.0, 0.37], - [0.0, 0.62], - [0.5, 0.67], - [0.5, 0.87], - ), - ([0.0, 0.14], [0.0, 0.34], [0.5, 0.68], [0.5, 0.84]), - ( - [0.0, 0.15], - [0.0, 0.36], - [0.5, 0.4], - [0.0, 0.57], - [0.5, 0.65], - [0.5, 0.86], - [0.0, 0.9], - ), - (), - ) - - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def TiO2a(miller): - exists = ["001", "010", "110", "100", "101"] - if miller in exists: - surfaces = {} - surfaces["110"] = ( - [0.0, 0.0], - [0.2, 0], - [0.3, 0.5], - [0.5, 0.5], - [0.7, 0.5], - [0.8, 0.0], - ), () - surfaces["001"] = ([0.5, 0.0], [0.5, 0.5]), () - surfaces["010"] = ( - [0.5, 0.0], - [0.0, 0.0], - [0.0, 0.2], - [0.5, 0.5], - [0.5, 0.75], - [0.8, 0.0], - ), () - surfaces["100"] = ( - [0.5, 0.0], - [0.0, 0.0], - [0.0, 0.2], - [0.5, 0.5], - [0.5, 0.75], - [0.8, 0.0], - ), () - surfaces["101"] = ( - ( - [0.0, 0.17], - [0.5, 0.12], - [0.0, 0.37], - [0.0, 0.62], - [0.5, 0.67], - [0.5, 0.87], - ), - ([0.0, 0.14], [0.0, 0.34], [0.5, 0.68], [0.5, 0.84]), - ( - [0.0, 0.15], - [0.0, 0.36], - [0.5, 0.4], - [0.0, 0.57], - [0.5, 0.65], - [0.5, 0.86], - [0.0, 0.9], - ), - (), - ) - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def WO3(miller): - exists = ["100", "110"] - if miller in exists: - surfaces = {} - surfaces["100"] = ( - ([0.0, 0.25], [0, 0.75], [0.5, 0.25], [0.5, 0.75]), - ( - [0.25, 0.2], - [0.5, 0.25], - [0.5, 0.75], - [0.7, 0.7], - [0.5, 1.0], - [1.0, 1.0], - ), - (), - ) - surfaces["110"] = ( - [0.5, 0.3], - [0.75, 0.3], - [1.0, 0.8], - [0.75, 0.80], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def perovskite(miller): - exists = ["100", "110", "112"] - if miller in exists: - surfaces = {} - surfaces["100"] = ( - ([0, 0], [0.5, 0.5]), - ([0.5, 0], [0, 0.5], [0.5, 0.5]), - (), - ) - surfaces["112"] = ([0.0, 0.0], [0.5, 0.0], [0.5, 0.5]), () - surfaces["110"] = ([0.0, 0.0], [0.0, 0.5], [0.75, 0.5]), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def CH3NH3PbI3(miller): - exists = ["100", "110", "112"] - if miller in exists: - surfaces = {} - surfaces["100"] = ( - ([0, 0], [0.5, 0.5]), - ([0.5, 0], [0, 0.5], [0.5, 0.5]), - (), - ) - surfaces["112"] = ([0.0, 0.0], [0.5, 0.0], [0.5, 0.5]), () - surfaces["110"] = ([0.0, 0.0], [0.0, 0.5], [0.75, 0.5]), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def SrTiO3(miller): - exists = ["100", "110", "112"] - if miller in exists: - surfaces = {} - surfaces["100"] = ( - ([0, 0], [0.5, 0.5]), - ([0.5, 0], [0, 0.5], [0.5, 0.5]), - (), - ) - surfaces["112"] = ([0.0, 0.0], [0.5, 0.0], [0.5, 0.5]), () - surfaces["110"] = ([0.0, 0.0], [0.0, 0.5], [0.75, 0.5]), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def zincblende(miller): - exists = ["100", "110"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0.75, 0.25], [0.0, 0.0]), () - surfaces["110"] = ( - [0.25, 0.9], - [0.25, 0.4], - [0.5, 0.7], - [0.5, 0.2], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def CuIz(miller): - exists = ["100", "110"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0.75, 0.25], [0.0, 0.0]), () - surfaces["001"] = ([0.75, 0.25], [0.0, 0.0]), () - surfaces["110"] = ( - [0.25, 0.9], - [0.25, 0.4], - [0.5, 0.7], - [0.5, 0.2], - ), () - surfaces["011"] = ( - [0.25, 0.9], - [0.25, 0.4], - [0.5, 0.7], - [0.5, 0.2], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def rocksalt(miller): - exists = ["001", "100", "110", "011"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0.0, 0.0], [0.5, 0.5]), () - surfaces["001"] = ([0.0, 0.0], [0.5, 0.5]), () - surfaces["110"] = ([0.0, 0.0], [0.0, 0.5], [0.5, 0.0], [0.5, 0.5]), () - surfaces["011"] = ([0.0, 0.0], [0.0, 0.5], [0.5, 0.0], [0.5, 0.5]), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def ZnTe(miller): - exists = ["001", "100", "110", "011"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0.0, 0.0], [0.5, 0.5]), () - surfaces["001"] = ([0.0, 0.0], [0.5, 0.5]), () - surfaces["110"] = ([0.0, 0.0], [0.0, 0.5], [0.5, 0.0], [0.5, 0.5]), () - surfaces["011"] = ([0.0, 0.0], [0.0, 0.5], [0.5, 0.0], [0.5, 0.5]), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def bixybite(miller): - exists = ["100"] - if miller in exists: - surfaces = {} - surfaces["100"] = ( - ( - [0.2, 0.9], - [0.6, 0.9], - [0.9, 0.6], - [0.4, 0.4], - [0.9, 0.4], - [0.7, 0.1], - ), - ( - [0.2, 0.2], - [0.2, 0.7], - [0.7, 0.2], - [0.7, 0.7], - [0.0, 0.3], - [0.3, 0.5], - [0.8, 0.5], - [0.5, 0.8], - ), - (), - ) - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def rutile(miller): - exists = ["001", "010", "110", "011"] - if miller in exists: - surfaces = {} - surfaces["001"] = ([0.5, 0.5], [0.2, 0.8], [0.8, 0.2]), () - surfaces["010"] = ([0.5, 0.5], [0.7, 0.0]), () - surfaces["110"] = ([0.0, 0.9], [0.0, 0.45]), () - surfaces["011"] = ([0.0, 0.7], [0.3, 0.9], [0.2, 0.4], [0.5, 0.2]), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def MoO3(miller): - exists = ["001", "101"] - if miller in exists: - surfaces = {} - surfaces["001"] = ( - ([0.9, 0.75], [0.7, 0.25], [0.6, 0.25], [0.4, 0.25]), - ( - [0.9, 0.75], - [0.7, 0.25], - [0.6, 0.25], - [0.6, 0.75], - [0.4, 0.25], - [0.4, 0.75], - [0.3, 0.75], - [0.0, 0.25], - ), - (), - ) - surfaces["101"] = ( - [0.25, 1.0], - [0.75, 0.7], - [0.75, 0.66], - [0.25, 0.5], - [0.75, 0.3], - [0.25, 0.1], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def wurtzite(miller): - exists = ["100", "010", "110"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0, 0], [0, 0.37]), () - surfaces["010"] = ([0, 0], [0, 0.37]), () - surfaces["110"] = ( - [0, 0.8], - [0.37, 0.8], - [0.5, 0.17], - [0.87, 0.17], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def GaN(miller): - exists = ["100", "010", "110"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0, 0], [0, 0.37]), () - surfaces["010"] = ([0, 0], [0, 0.37]), () - surfaces["110"] = ( - [0, 0.8], - [0.37, 0.8], - [0.5, 0.17], - [0.87, 0.17], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def SiC(miller): - exists = ["100", "010", "110"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0, 0], [0, 0.37]), () - surfaces["010"] = ([0, 0], [0, 0.37]), () - surfaces["110"] = ( - [0, 0.8], - [0.37, 0.8], - [0.5, 0.17], - [0.87, 0.17], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def Cu2O(miller): - exists = ["100", "110", "001", "011"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0.0, 0.0],), () - surfaces["110"] = ([0.0, 0.0],), () - surfaces["001"] = ([0.0, 0.0],), () - surfaces["011"] = ([0.0, 0.0],), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def In2S3(miller): - exists = ["001", "010"] - if miller in exists: - surfaces = {} - surfaces["001"] = ( - ([0.0, 0.25], [0.5, 0.0]), - ( - [0.0, 0.0], - [0.5, 0.0], - [0.25, 0.75], - [0.75, 0.75], - [0.0, 0.5], - [0.5, 0.0], - ), - ([0.0, 0.0], [0.75, 0.25], [0.0, 0.5], [0.25, 0.75], [0.25, 0.25]), - (), - ) - surfaces["010"] = ( - [0.5, 0.0], - [0.75, 0.2], - [0.25, 0.2], - [0.75, 0.25], - [0.75, 0.3], - [0.25, 0.3], - [0.0, 0.45], - [0.75, 0.5], - [0.25, 0.5], - [0.75, 0.6, 0.25, 0.6], - [0.75, 0.66], - [0.25, 0.66], - [0.5, 0.7], - [0.0, 0.8], - [0.25, 0.84], - [0.75, 0.84], - [0.75, 0.92], - [0.75, 0.92], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def MnTiO3(miller): - exists = ["010"] - if miller in exists: - surfaces = {} - surfaces["010"] = ( - [0.6, 0.1], - [0.9, 0.15], - [0.2, 0.25], - [0.9, 0.36], - [0.52, 0.42], - [0.25, 0.58], - [0.9, 0.64], - [0.6, 0.75], - [0.9, 0.85], - [0.23, 0.9], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def ZnTiO3(miller): - exists = ["011"] - if miller in exists: - surfaces = {} - surfaces["011"] = ( - [0.45, 0.09], - [0.30, 0.45], - [0.82, 0.26], - [0.97, 0.60], - [0.73, 0.82], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def SnS2(miller): - exists = ["100"] - if miller in exists: - surfaces = {} - surfaces["100"] = ([0.0, 0.0],), ([0.67, 0.33],), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def Ce2O3(miller): - exists = ["101"] - if miller in exists: - surfaces = {} - surfaces["101"] = ([0.69, 0.54],), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def LiNbO3(miller): - exists = ["010"] - if miller in exists: - surfaces = {} - surfaces["010"] = ( - [0.60, 0.90], - [0.89, 0.83], - [0.19, 0.73], - [0.89, 0.61], - [0.51, 0.57], - [0.21, 0.40], - [0.89, 0.33], - [0.58, 0.23], - [0.89, 0.11], - [0.28, 0.07], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return [] - - -def Ce2S3(miller): - exists = ["101", "110", "100", "010"] - if miller in exists: - surfaces = {} - surfaces["101"] = ( - [0.25, 0.99], - [0.25, 0.80], - [0.25, 0.64], - [0.25, 0.47], - [0.75, 0.30], - [0.25, 0.22], - [0.75, 0.11], - ), () - surfaces["110"] = ( - [0.93, 0.65], - [0.89, 0.25], - [0.78, 0.88], - [0.70, 0.14], - [0.72, 0.47], - [0.54, 0.56], - [0.43, 0.36], - [0.39, 0.76], - [0.29, 0.46], - [0.20, 0.87], - [0.04, 0.45], - ), () - surfaces["100"] = ( - [0.75, 0.89], - [0.75, 0.70], - [0.25, 0.57], - [0.75, 0.46], - [0.75, 0.28], - [0.25, 0.20], - [0.75, 0.07], - ), () - surfaces["010"] = ( - [0.73, 0.04], - [0.13, 0.07], - [0.85, 0.22], - [0.35, 0.28], - [0.23, 0.46], - [0.63, 0.43], - [0.99, 0.61], - [0.36, 0.70], - [0.86, 0.80], - [0.49, 0.89], - ), () - return surfaces[miller] - else: - print( - "No non-polar surface", - miller, - "is currently in the database, maybe you want to add it.", - ) - return []