{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Exercise 1: Atomistic Structures" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Authors: Jan Janssen, Tilmann Hickel, Jörg Neugebauer ([Max-Planck-Institut für Eisenforschung](https://www.mpie.de))**\n", "\n", "The scope of this first exercise is to become familar with:\n", "* the jupyter notebook environment, \n", "* the pyiron project object and \n", "* the creation of atomistic structures." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reminder\n", "Keyboard Shortcuts used in this tutorial\n", "* `` - auto completion \n", "* ` + ` - documentation\n", "* ` + ` - execute cell\n", "* ` + ` - new cell above\n", "* ` + ` - new cell below" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Update Notice \n", "Since the workshop in 2020, there have been some updates to pyiron commands, and here in the exercises new commands are used. \n", "\n", "The changes include:\n", "- Now pyiron has various modules, like pyiron_atomistics, pyiron_continuum, pyiron_experimental. So we can import `Project` from `pyiron_atomistics` directly.\n", "- using `pr.create` to create instances of various objects, such as structures and jobs. For example:\n", "```python\n", "pr.create.structure.ase.bulk() ## this replaces pr.create_ase_bulk()\n", "```\n", ", or\n", "```python\n", "pr.create.job.Lammps('job_name') ## this replaces pr.pr.create_job(job_type=pr.job_type.Lammps,'job_name')\n", "```\n", "\n", "Similary, one can create pyiron tables via `pr.create.table()`.\n", "\n", "By this approach, the user easily gets the available options via autocompeletion.\n", "\n", "**Please note that in the video tutorials, the old commands are still presented.**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Getting Started \n", "Let's start by creating the first pyiron Project:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Import the Project object\n", "from pyiron_atomistics import ____" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a Project object instance for a project \n", "# named atomistics\n", "pr = ____(\"atomistics\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The Project object instance, or Project for short \n", "# created a new folder in your current directory: \n", "pr.path" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Project Object\n", "The project object is the central object of the workflow management in pyiron. It can be used to:\n", "* create atomistic structure objects\n", "* create different kinds of atomistic simulation jobs\n", "* track the execution of job objects locally and on remote HPC clusters. \n", "\n", "All these features are discussed in the following. For now we focus on the creation of atomistic structures from the project object. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Atomistic Structures\n", "We start by creating a primitive fcc aluminium lattice using the ASE interface:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a primitive aluminium (Al) fcc lattice: \n", "al_fcc = pr.create.structure.ase.bulk(____)\n", "al_fcc" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a cubic aluminium (Al) fcc lattice: \n", "al_fcc_cubic = pr.create.structure.ase.bulk(____, cubic=True)\n", "\n", "# Visualise the cubic aluminium structure using NGLview: \n", "______.plot3d()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Based on the atomistic simulation environment (ASE) pyiron can create atomistic structures with minimal inputs. Still it is also possible to define all details manually: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a cubic aluminium (Al) bcc lattice:\n", "al_bcc_cubic = pr.create.structure.ase.bulk(_____, crystalstructure=_____, a=3.2, cubic=True)\n", "\n", "# Compare the number of atoms (length of the structure object)\n", "# in the bcc lattice (2) and the fcc lattice (4):\n", "____(al_bcc_cubic), ____(al_fcc_cubic)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Replacing atoms\n", "While unary systems are still interesting from an academic perspective, the goal of this workshop is to calculate phase diagrams, so we are interested in alloys. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a copy of the cubic aluminium fcc structure:\n", "al_ni_fcc_cubic = al_fcc_cubic._____" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Replace the first aluminium atom with an nickle (Ni) atom: \n", "al_ni_fcc_cubic[0] = ____\n", "\n", "# Visualise the updated structure: \n", "al_ni_fcc_cubic.plot3d()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Beyond ASE - Atomic Neighbors \n", "https://wiki.fysik.dtu.dk/ase/ase/build/build.html\n", "While the ASE atoms class already provides extensive functionality to build complex structures. pyiron extends the atoms class for example by adding specialized functionality like analysing the neighbour environment: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Repeat the cubic aluminium structure 5 times in each direction: \n", "al_large = al_fcc_cubic.repeat(___)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create the neighbor environment for the cubic aluminium structure, \n", "# by limiting the number of neighbors to 1000: \n", "al_large_neighbors = al_large.get_neighbors(num_neighbors=_____)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Import the matplotlib library for plotting.\n", "import matplotlib.pyplot as plt\n", "\n", "# Visualise the per atom neighbour distances as historgram \n", "# with 100 bins: \n", "plt.hist(al_large_neighbors.distances.flatten(), bins=____);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Special Quasi-random Structures\n", "Rather than replacing individual atoms one by one special quasi-random structures are used to have the most random configuration for a given concentration. More details about this method are available in the literature: \n", "https://doi.org/10.1103/PhysRevLett.65.353" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create an SQS calculation job from the project object \n", "# named \"sqscalculation\" : \n", "job_sqs = create.job.SQSJob( \n", " job_name=________\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# assign the large cubic aluminium fcc structure to the job object: \n", "job_sqs.structure = _____" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Print the input\n", "job_sqs.input" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Set the Aluminium Nickel concentration to 50:50: \n", "job_sqs.input.mole_fractions = {_____: 0.5, _____:0.5}\n", "\n", "# Limit the number of iterations to 1000\n", "job_sqs.input.iterations = ____" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Execute the SQS calculation by calling the run function \n", "# of the job object: \n", "job_sqs.______()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Display the first resulting structure \n", "job_sqs.list_structures()[0].plot3d()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Managing your pyiron project\n", "In contrast to the ASE functions which can be executed nearly instantaneous the calculation of the SQS structure requires multiple iterations and is therefore implemented as pyiron job. The same `create_job()` function is used in the following to create other atomistic simulations. Still before doing so we want to use the projecct object to inspect the calculation in the project: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Display the table of all jobs in the current \n", "# project by calling the job_table function: \n", "___.job_table()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Reload the job once based on it's database ID \n", "# using the job_id property:\n", "job_reload_job_id = pr.load(_____)\n", "\n", "# and once using the job_name property of the job object: \n", "job_reload_job_name = pr.load(____)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Compare the job name of both jobs: \n", "job_reload_job_id._____ == job_reload_job_name._____" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modify SQS-calculation job\n", "By default pyiron is reloading existing calculations, rather than executing the same calculation again. Therefore to change the concentration of the SQS structure we set the `delete_existing_job` parameter for the `run()` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Set the Aluminium Nickel concentration to 80:20. \n", "# The concentrations have to be given as floats ranging from 0 to 1: \n", "job_sqs.input.mole_fractions = {\"Al\": _____, \"Ni\": ____}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Execute the SQS calculation by calling the run function \n", "# with the delete_existing parameter set to true: \n", "job_sqs.run(delete_existing_job=_______)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Display the first resulting structure \n", "job_sqs.list_structures()[0].plot3d()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Publications\n", "Finally using an integrated framework like pyiron also allows us to collect all the publications of the tools we used in a given project, to keep track of the methods in use: " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "# List publications used in the current project\n", "pr.list_publications()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary \n", "At the end of this section you should be able to create pyiron projects, atomistic structures and calculation jobs. \n", "\n", "Additional exercises: \n", "* Create a vacancy using the `del` method. \n", "* Identify the coordinates of the vacancy automatically by calculating the nearest neighbor distance of all atoms.\n", "* Replace the nearest neighbor atoms of the vacancy with a different element and visualise the structure using `plot3d()`. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.12" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }