{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Main Calculation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `crystal17.main` plugin is the core calculation plugin.\n", "It is designed with a more programmatic\n", "input interface , to create the input ``.d12`` and ``.gui`` files,\n", "from a set of AiiDA {py:class}`~aiida.orm.nodes.data.Data` nodes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::{seealso}\n", "See {ref}`main_calculation_immigrant` for a method\n", "to immigrate existing output/input files as a\n", "``crystal17.main`` calculation.\n", ":::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initial Setup" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To run a computation, first ensure AiiDA is running:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[32m ✓ \u001b[0mprofile: On profile test_profile\u001b[0m\r\n", "\u001b[32m ✓ \u001b[0mrepository: /var/folders/dm/b2qnkb_n3r72slmpxlfmcjvm00lbnd/T/tmpvsllm_zf/test_repo\u001b[0m\r\n", "\u001b[32m ✓ \u001b[0mpostgres: Connected as aiida@localhost:61847\u001b[0m\r\n", "\u001b[32m ✓ \u001b[0mrabbitmq: Connected to amqp://127.0.0.1?heartbeat=600\u001b[0m\r\n", "\u001b[32m ✓ \u001b[0mdaemon: Daemon is running as PID 38435 since 2019-08-12 11:39:10\u001b[0m\r\n" ] } ], "source": [ "!verdi status" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::{seealso}\n", "AiiDA documentation: {ref}`aiida:intro:get_started`\n", ":::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If `aiida-crystal17` is installed,\n", "the `crystal17.main` computation should be available:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-\b/\b|\b\\\b-\b/\b\u001b[31m\u001b[1mInputs\u001b[0m\r\n", "\u001b[1m basissets: required BasisSetData Use a node for the basis set of one of the elements in the structure. You h ...\u001b[0m\r\n", "\u001b[1m code: required Code The Code to use for this job.\u001b[0m\r\n", "\u001b[1m parameters: required CryInputParamsData the input parameters to create the .d12 file content.\u001b[0m\r\n", "\u001b[1m structure: required StructureData structure used to construct the input fort.34 (gui) file\u001b[0m\r\n", " kinds: optional KindData additional structure kind specific data (e.g. initial spin)\u001b[0m\r\n", " metadata: optional \u001b[0m\r\n", " symmetry: optional SymmetryData the symmetry of the structure, used to construct the input .gui file (fort. ...\u001b[0m\r\n", " wf_folder: optional RemoteData An optional working directory, of a previously completed calculation, conta ...\u001b[0m\r\n", "\u001b[31m\u001b[1mOutputs\u001b[0m\r\n", "\u001b[1m remote_folder: required RemoteData Input files necessary to run the process will be stored in this folder node ...\u001b[0m\r\n", "\u001b[1m results: required Dict the data extracted from the main output file\u001b[0m\r\n", "\u001b[1m retrieved: required FolderData Files that are retrieved by the daemon will be stored in this node. By defa ...\u001b[0m\r\n", " optimisation: optional TrajectoryData atomic configurations, for each optimisation step\u001b[0m\r\n", " structure: optional StructureData the structure output from the calculation\u001b[0m\r\n", " symmetry: optional SymmetryData the symmetry data from the calculation\u001b[0m\r\n", "\u001b[31m\u001b[1mExit codes\u001b[0m\r\n", " 1: The process has failed with an unspecified error.\u001b[0m\r\n", " 2: The process failed with legacy failure mode.\u001b[0m\r\n", " 10: The process returned an invalid output.\u001b[0m\r\n", " 11: The process did not register a required output.\u001b[0m\r\n", " 200: The retrieved folder data node could not be accessed.\u001b[0m\r\n", " 210: The main (stdout) output file was not found\u001b[0m\r\n", " 211: The temporary retrieved folder was not found\u001b[0m\r\n", " 300: An error was flagged trying to parse the crystal exec stdout file\u001b[0m\r\n", " 301: An error occurred parsing the 'opta'/'optc' geometry files\u001b[0m\r\n", " 302: The crystal exec stdout file denoted that the run was a testgeom\u001b[0m\r\n", " 350: The input file could not be read by crystal\u001b[0m\r\n", " 351: Crystal could not find the required wavefunction file\u001b[0m\r\n", " 400: The calculation stopped prematurely because it ran out of walltime.\u001b[0m\r\n", " 401: The calculation stopped prematurely because it ran out of memory.\u001b[0m\r\n", " 402: The calculation stopped prematurely because it ran out of virtual memory.\u001b[0m\r\n", " 411: Scf convergence did not finalise (usually due to reaching step limit)\u001b[0m\r\n", " 412: Geometry convergence did not finalise (usually due to reaching step limit)\u001b[0m\r\n", " 413: An error encountered usually during geometry optimisation\u001b[0m\r\n", " 414: An error was encountered during an scf computation\u001b[0m\r\n", " 415: An unknown error was encountered, causing the mpi to abort\u001b[0m\r\n", " 499: The main crystal output file flagged an unhandled error\u001b[0m\r\n", " 510: Inconsistency in the input and output symmetry\u001b[0m\r\n", " 520: Primitive symmops were not found in the output file\u001b[0m\r\n" ] } ], "source": [ "!verdi plugin list aiida.calculations crystal17.main" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To use the python interface,\n", "first ensure a profile is loaded in the python kernel,\n", "and import the required modules:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "init_cell": true }, "outputs": [ { "data": { "text/plain": [ "'test_crystal17'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from aiida import load_profile\n", "profile = load_profile()\n", "profile.name" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "init_cell": true }, "outputs": [], "source": [ "import os\n", "from six import StringIO\n", "from aiida.orm import Code\n", "from aiida.plugins import (\n", " DataFactory, WorkflowFactory, CalculationFactory)\n", "from aiida.engine import run_get_node\n", "from aiida_crystal17.common import display_json\n", "from aiida_crystal17.tests import read_resource_text, resource_context\n", "from aiida.tools.visualization import Graph\n", "from jsonextended import edict" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Input Node Creation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::{seealso}\n", "[CRYSTAL17 Manual](http://www.crystal.unito.it/Manuals/crystal17.pdf)\n", ":::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Code" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::{seealso}\n", "AiiDA documentation: {ref}`aiida:how-to:run-codes`\n", ":::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An {py:class}`~aiida.orm.nodes.data.code.Code` node should be set up in advance,\n", "to use the `crystal17.basic` calculation plugin,\n", "and call the ``runcry17`` executable\n", "(or ``mock_runcry17`` used here for test purposes)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['PK', 1],\n", " ['UUID', 'a2241a9c-deac-4960-9812-088666800dee'],\n", " ['Label', 'crystal17.main-mock_crystal17@localhost'],\n", " ['Description', ''],\n", " ['Default plugin', 'crystal17.main'],\n", " ['Type', 'remote'],\n", " ['Remote machine', 'localhost'],\n", " ['Remote absolute path',\n", " '//anaconda/envs/aiida_crystal17/bin/mock_crystal17'],\n", " ['Prepend text', 'No prepend text'],\n", " ['Append text', 'No append text']]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from aiida_crystal17.tests.utils import get_or_create_local_computer, get_or_create_code\n", "computer = get_or_create_local_computer('work_directory', 'localhost')\n", "code = get_or_create_code('crystal17.main', computer, 'mock_crystal17')\n", "code.get_full_text_info()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Input Parameters (Geometry Independent)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The {py:class}`~aiida_crystal17.data.input_params.CryInputParamsData`\n", "supplies (geometry independent) data required to create the `input.d12` file." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "param_dict = {\"scf\":{\"k_points\": (8, 8)}}\n", "params = DataFactory('crystal17.parameters')(data=param_dict)\n", "params" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The input data is validated against the {ref}`cry_main_input_schema`,\n", "which can also be obtained from the `data_schema` attribute.\n", "\n", ":::{note}\n", "The only mandated key is ``scf.k_points`` (known as ``SHRINK`` in CRYSTAL17)\n", ":::" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34m$schema\u001b[0m: http://json-schema.org/draft-04/schema#\n", "\u001b[34madditionalProperties\u001b[0m: False\n", "\u001b[34mdescription\u001b[0m: Allowed Inputs For CRYSTAL17 .d12 file\n", "\u001b[34mproperties\u001b[0m:\n", " \u001b[34mbasis_set\u001b[0m:\n", " \u001b[34madditionalProperties\u001b[0m: False\n", " \u001b[34mdescription\u001b[0m: Basis sets input and control\n", " \u001b[34mproperties\u001b[0m: {...}\n", " \u001b[34mtitle\u001b[0m: Block 2\n", " \u001b[34mtype\u001b[0m: object\n", " \u001b[34mgeometry\u001b[0m:\n", " \u001b[34madditionalProperties\u001b[0m: False\n", " \u001b[34mdescription\u001b[0m: Geometry input, manipulation and optimisation control\n", " \u001b[34mproperties\u001b[0m: {...}\n", " \u001b[34mtitle\u001b[0m: Block 1\n", " \u001b[34mtype\u001b[0m: object\n", " \u001b[34mscf\u001b[0m:\n", " \u001b[34madditionalProperties\u001b[0m: False\n", " \u001b[34mdependencies\u001b[0m: {...}\n", " \u001b[34mdescription\u001b[0m: Single particle Hamiltonian and SCF control\n", " \u001b[34mproperties\u001b[0m: {...}\n", " \u001b[34mrequired\u001b[0m: [k_points]\n", " \u001b[34mtitle\u001b[0m: Block 3\n", " \u001b[34mtype\u001b[0m: object\n", " \u001b[34mtitle\u001b[0m:\n", " \u001b[34mdescription\u001b[0m: the title of the run\n", " \u001b[34mtype\u001b[0m: string\n", "\u001b[34mrequired\u001b[0m: [scf]\n", "\u001b[34mtitle\u001b[0m: CRYSTAL17 Input\n", "\u001b[34mtype\u001b[0m: object\n" ] } ], "source": [ "param_cls = DataFactory('crystal17.parameters')\n", "edict.pprint(params.data_schema, keycolor=\"blue\")" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValidationError", "evalue": "- 'k_points' is a required property [key path: 'scf']", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mparams\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mDataFactory\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'crystal17.parameters'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m\"scf\"\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/Users/cjs14/GitHub/aiida-crystal17/aiida_crystal17/data/input_params.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, data, unflatten, **kwargs)\u001b[0m\n\u001b[1;32m 61\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0munflatten\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0munflatten_dict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 63\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mset_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 64\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 65\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_validate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Users/cjs14/GitHub/aiida-crystal17/aiida_crystal17/data/input_params.py\u001b[0m in \u001b[0;36mset_data\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 80\u001b[0m \u001b[0;31m# first validate the inputs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 81\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_parameters\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0;31m# store all but the symmetry operations as attributes\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Users/cjs14/GitHub/aiida-crystal17/aiida_crystal17/data/input_params.py\u001b[0m in \u001b[0;36mvalidate_parameters\u001b[0;34m(cls, dct)\u001b[0m\n\u001b[1;32m 44\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 45\u001b[0m \"\"\"\n\u001b[0;32m---> 46\u001b[0;31m \u001b[0mvalidate_against_schema\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdct\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcls\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata_schema\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 47\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0munflatten\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/Users/cjs14/GitHub/aiida-crystal17/aiida_crystal17/validation/utils.py\u001b[0m in \u001b[0;36mvalidate_against_schema\u001b[0;34m(data, schema)\u001b[0m\n\u001b[1;32m 109\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 110\u001b[0m raise jsonschema.ValidationError('\\n'.join([\n\u001b[0;32m--> 111\u001b[0;31m \u001b[0;34m\"- {} [key path: '{}']\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merror\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'/'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0merror\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0merror\u001b[0m \u001b[0;32min\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 112\u001b[0m ]))\n\u001b[1;32m 113\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValidationError\u001b[0m: - 'k_points' is a required property [key path: 'scf']" ] } ], "source": [ "params = DataFactory('crystal17.parameters')(data={\"scf\": {}})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also possible to reverse engineer the input data,\n", "from an existing input file, using\n", "{py:class}`~aiida_crystal17.parsers.raw.inputd12_read.extract_data`,\n", "which is also exposed on the command line as `verdi data crystal17.parse stdin`." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'title': 'MgO bulk',\n", " 'geometry': {'optimise': {'type': 'FULLOPTG'}},\n", " 'scf': {'dft': {'xc': 'B3LYP', 'SPIN': True},\n", " 'k_points': (8, 8),\n", " 'fock_mixing': 'ANDERSON',\n", " 'numerical': {'SMEAR': 0.1},\n", " 'post_scf': ['PPAN']}}" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from aiida_crystal17.parsers.raw.inputd12_read import extract_data\n", "param_dict, basis_sets, atom_props = extract_data(\"\"\"\\\n", "MgO bulk\n", "EXTERNAL\n", "OPTGEOM\n", "FULLOPTG\n", "END\n", "END\n", "12 3\n", "1 0 3 2. 0.\n", "1 1 3 8. 0.\n", "1 1 3 2. 0.\n", "8 2\n", "1 0 3 2. 0.\n", "1 1 3 6. 0.\n", "99 0\n", "END\n", "DFT\n", "B3LYP\n", "SPIN\n", "END\n", "SHRINK\n", "8 8\n", "ANDERSON\n", "SMEAR\n", "0.1\n", "ATOMSPIN\n", "2\n", "1 1 2 -1\n", "PPAN\n", "END\n", "\"\"\")\n", "param_dict" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MgO bulk\n", "EXTERNAL\n", "OPTGEOM\n", "FULLOPTG\n", "ENDOPT\n", "END\n", "12 3\n", "1 0 3 2. 0.\n", "1 1 3 8. 0.\n", "1 1 3 2. 0.\n", "8 2\n", "1 0 3 2. 0.\n", "1 1 3 6. 0.\n", "99 0\n", "END\n", "DFT\n", "B3LYP\n", "SPIN\n", "END\n", "SHRINK\n", "8 8\n", "ATOMSPIN\n", "2\n", "1 1\n", "2 -1\n", "SMEAR\n", "0.1\n", "ANDERSON\n", "PPAN\n", "END\n", "\n" ] } ], "source": [ "from aiida_crystal17.parsers.raw.inputd12_write import write_input\n", "print(write_input(param_dict, basis_sets, atom_props))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Atomic Structure" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``structure`` refers to a standard\n", "{py:class}`~aiida.StructureData` node, and is used to create the `main.gui`.\n", "\n", "Structures consist of:\n", "\n", "- A cell with a basis vectors and whether it is periodic, for each dimension\n", "- ``Site`` with a cartesian coordinate and reference to a kind\n", "- ``Kind`` which details the species and composition at one or more sites\n", "\n", "The simplest way to create a structure is *via* {py:mod}`ase`:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from ase.spacegroup import crystal\n", "atoms = crystal(\n", " symbols=[12, 8],\n", " basis=[[0, 0, 0], [0.5, 0.5, 0.5]],\n", " spacegroup=225,\n", " cellpar=[4.21, 4.21, 4.21, 90, 90, 90])\n", "struct_cls = DataFactory('structure')\n", "structure = struct_cls(ase=atoms)\n", "structure" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These structures can be visualised using standard ASE methods." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ipub": { "figure": { "caption": "Structure visualisation, using ASE and Matplotlib." } } }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "from ase.visualize.plot import plot_atoms\n", "atoms = structure.get_ase()\n", "fig, ax = plt.subplots()\n", "plot_atoms(atoms.repeat((2,2,2)),\n", " ax, radii=0.8, show_unit_cell=True,\n", " rotation=('45x,0y,0z'));" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As default, one kind is created per atomic species\n", "(named as the atomic symbol):" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Mg', 'Mg', 'Mg', 'Mg', 'O1', 'O1', 'O1', 'O1']" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "structure.get_site_kindnames()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, we may want to specify more than one kind per species\n", "(for example to setup anti-ferromagnetic spin).\n", "We can achieve this by tagging the atoms:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Mg1', 'Mg1', 'Mg2', 'Mg2', 'O', 'O', 'O', 'O']" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "atoms_afm = atoms.copy()\n", "atoms_afm.set_tags([1, 1, 2, 2, 0, 0, 0, 0])\n", "structure_afm = struct_cls(ase=atoms_afm)\n", "structure_afm.get_site_kindnames()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::{note}\n", "Since we **always** use the ``EXTERNAL`` keyword for geometry,\n", "any manipulation to the geometry is undertaken before calling CRYSTAL\n", "(i.e. we delegate the responsibility for geometry away from CRYSTAL).\n", ":::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Kind Specific Parameters" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also, we may want to add atom specific inputs to the ``.d12``,\n", "such as initial spin and frozen atoms (for optimisation)." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "```json\n", "{\n", " \"Mg1\": {\n", " \"spin_alpha\": true,\n", " \"spin_beta\": false,\n", " \"fixed\": false,\n", " \"ghosts\": false\n", " },\n", " \"Mg2\": {\n", " \"spin_alpha\": false,\n", " \"spin_beta\": true,\n", " \"fixed\": false,\n", " \"ghosts\": false\n", " },\n", " \"O\": {\n", " \"spin_alpha\": false,\n", " \"spin_beta\": false,\n", " \"fixed\": true,\n", " \"ghosts\": false\n", " }\n", "}\n", "```" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "kind_cls = DataFactory(\"crystal17.kinds\")\n", "kind_data = kind_cls(data={\n", " \"kind_names\": [\"Mg1\", \"Mg2\", \"O\"],\n", " \"spin_alpha\": [True, False, False],\n", " \"spin_beta\": [False, True, False],\n", " \"fixed\": [False, False, True],\n", " \"ghosts\": [False, False, False]\n", "})\n", "display_json(kind_data.kind_dict)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'spin_alpha': [1, 2],\n", " 'spin_beta': [3, 4],\n", " 'unfixed': [1, 2, 3, 4],\n", " 'ghosts': []}" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from aiida_crystal17.parsers.raw.inputd12_write import create_atom_properties\n", "atom_props2 = create_atom_properties(structure_afm, kind_data)\n", "atom_props2" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MgO bulk\n", "EXTERNAL\n", "OPTGEOM\n", "FULLOPTG\n", "FRAGMENT\n", "4\n", "1 2 3 4\n", "ENDOPT\n", "END\n", "12 3\n", "1 0 3 2. 0.\n", "1 1 3 8. 0.\n", "1 1 3 2. 0.\n", "8 2\n", "1 0 3 2. 0.\n", "1 1 3 6. 0.\n", "99 0\n", "END\n", "DFT\n", "B3LYP\n", "SPIN\n", "END\n", "SHRINK\n", "8 8\n", "ATOMSPIN\n", "4\n", "1 1\n", "2 1\n", "3 -1\n", "4 -1\n", "SMEAR\n", "0.1\n", "ANDERSON\n", "PPAN\n", "END\n", "\n" ] } ], "source": [ "print(write_input(param_dict, basis_sets, atom_props2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basis Sets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Basis sets are stored as separate\n", "{py:class}`~aiida_crystal17.data.basis_set.BasisSetData` nodes,\n", "in a similar fashion to {py:class}`~aiida.orm.nodes.data.upf.UpfData`.\n", "They are created individually from a text file,\n", "which contains the content of the basis set\n", "and (optionally) a YAML style header section, fenced by ``---``:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---\n", "author: John Smith\n", "year: 1999\n", "class: sto3g\n", "---\n", "12 3\n", "1 0 3 2. 0.\n", "1 1 3 8. 0.\n", "1 1 3 2. 0.\n" ] } ], "source": [ "mg_basis_content = read_resource_text('basis_sets', 'sto3g', 'sto3g_Mg.basis')\n", "print(mg_basis_content)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The attributes of the basis set are stored in the database,\n", "and the md5 hash-sum is used to test equivalence of two basis sets." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "```json\n", "{\n", " \"md5\": \"0731ecc3339d2b8736e61add113d0c6f\",\n", " \"year\": 1999,\n", " \"class\": \"sto3g\",\n", " \"author\": \"John Smith\",\n", " \"element\": \"Mg\",\n", " \"filename\": \"stringio.txt\",\n", " \"basis_type\": \"all-electron\",\n", " \"num_shells\": 3,\n", " \"atomic_number\": 12,\n", " \"orbital_types\": [\n", " \"S\",\n", " \"SP\",\n", " \"SP\"\n", " ]\n", "}\n", "```" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "'12 3\\n1 0 3 2. 0.\\n1 1 3 8. 0.\\n1 1 3 2. 0.'" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "basis_cls = DataFactory('crystal17.basisset')\n", "mg_basis, created = basis_cls.get_or_create(StringIO(mg_basis_content))\n", "display_json(mg_basis.attributes)\n", "mg_basis.content" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A simpler way to create and refer to basis sets, is *via* a **family group**.\n", "All basis sets in a folder can be read and saved to a named family by:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'Mg': ,\n", " 'Ni': ,\n", " 'O': }" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "with resource_context('basis_sets', 'sto3g') as path:\n", " nfiles, nuploaded = basis_cls.upload_basisset_family(\n", " path,\n", " \"sto3g\", \"group of sto3g basis sets\",\n", " extension=\".basis\", stop_if_existing=False)\n", "basis_cls.get_basis_group_map(\"sto3g\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or at the command line:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Usage: verdi data crystal17.basis uploadfamily [OPTIONS]\r\n", "\r\n", " Upload a family of CRYSTAL Basis Set files.\r\n", "\r\n", "Options:\r\n", " --path PATH Path to a folder containing the Basis Set\r\n", " files\r\n", " --ext TEXT the file extension to filter by\r\n", " --name TEXT Name of the BasisSet family [required]\r\n", " -D, --description DESCRIPTION A description for the family\r\n", " --stop-if-existing Abort when encountering a previously uploaded\r\n", " Basis Set file\r\n", " --dry-run do not commit to database or modify\r\n", " configuration files\r\n", " -h, --help Show this message and exit.\r\n" ] } ], "source": [ "!verdi data crystal17.basis uploadfamily --help" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-\b/\b|\b\\\b-\b/\bFamily Num Basis Sets\r\n", "-------- ----------------\r\n", "sto3g 3\r\n", "\r\n" ] } ], "source": [ "!verdi data crystal17.basis listfamilies" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Basis families can be searched by the elements they contain:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "basis_cls.get_basis_groups([\"Ni\", \"O\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Basis sets can also be extracted for a particular structure." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'Mg': ,\n", " 'O': }" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "basis_cls.get_basissets_from_structure(structure, \"sto3g\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::{important}\n", "Unlike `aiida-quantumespresso.pw`,\n", "``crystal17.main`` uses one basis sets per atomic number only **NOT** per kind.\n", "This is because, using multiple basis sets per atomic number is rarely used in CRYSTAL17,\n", "and is limited anyway to only two types per atomic number.\n", ":::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Symmetry" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the ``main.gui`` file,\n", "as well as using the dimensionality (i.e. periodic boundary conditions),\n", "basis vectors and atomic positions, provided by the ``structure``,\n", "we also need to specify the atomic symmetry of the structure.\n", "\n", "{py:class}`~aiida_crystal17.data.symmetry.SymmetryData` is used to store this data, as a validated dictionary.\n", "\n", ":::{note}\n", "The ``operations`` are given as a flattened version of the rotation matrix,\n", "followed by the translation vector.\n", ":::" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[34m$schema\u001b[0m: http://json-schema.org/draft-07/schema\n", "\u001b[34madditionalProperties\u001b[0m: True\n", "\u001b[34mproperties\u001b[0m:\n", " \u001b[34mbasis\u001b[0m:\n", " \u001b[34mdescription\u001b[0m: whether the symmetry operations are fractional or cartesian\n", " \u001b[34menum\u001b[0m: [fractional, cartesian]\n", " \u001b[34mtype\u001b[0m: string\n", " \u001b[34mcomputation\u001b[0m:\n", " \u001b[34mdescription\u001b[0m: details of the computation\n", " \u001b[34mtype\u001b[0m: object\n", " \u001b[34mequivalent_sites\u001b[0m:\n", " \u001b[34mdescription\u001b[0m: mapping table to equivalent atomic sites\n", " \u001b[34mitems\u001b[0m: {...}\n", " \u001b[34mtype\u001b[0m: array\n", " \u001b[34mhall_number\u001b[0m:\n", " \u001b[34mdescription\u001b[0m: Hall number defining the symmetry group\n", " \u001b[34mmaximum\u001b[0m: 530\n", " \u001b[34mminimum\u001b[0m: 1\n", " \u001b[34mtype\u001b[0m: [null, integer]\n", " \u001b[34moperations\u001b[0m:\n", " \u001b[34mdescription\u001b[0m: symmetry operations, should at least include the unity\n", " operation\n", " \u001b[34mitems\u001b[0m: {...}\n", " \u001b[34mminItems\u001b[0m: 1\n", " \u001b[34mtype\u001b[0m: array\n", " \u001b[34muniqueItems\u001b[0m: True\n", "\u001b[34mrequired\u001b[0m: [hall_number, operations, basis]\n", "\u001b[34mtitle\u001b[0m: structure symmetry settings\n", "\u001b[34mtype\u001b[0m: object\n" ] } ], "source": [ "symmetry_cls = DataFactory(\"crystal17.symmetry\")\n", "edict.pprint(symmetry_cls.data_schema, keycolor=\"blue\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The simplest symmetry would be the unitary operator." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'hall_number': 1, 'basis': 'fractional', 'num_symops': 1}" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symmetry = symmetry_cls(data={\n", " \"hall_number\": 1,\n", " \"basis\": \"fractional\",\n", " \"operations\": [\n", " [1,0,0,0,1,0,0,0,1,0,0,0]\n", " ]\n", "})\n", "symmetry.attributes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The full symmetry operations of a periodic structure,\n", "can be computed using the `crystal17.sym3d` workflow.\n", "This uses the `spglib `_ library\n", "to compute symmetries, but with the added constraint that sites\n", "with the same ``Kind`` must be symmetrically equivalent." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-\b/\b|\b\\\b-\b/\b\u001b[31m\u001b[1mInputs\u001b[0m\r\n", "\u001b[1m settings: required Dict \u001b[0m\r\n", " cif: optional CifData \u001b[0m\r\n", " metadata: optional \u001b[0m\r\n", " structure: optional StructureData \u001b[0m\r\n", "\u001b[31m\u001b[1mOutputs\u001b[0m\r\n", "\u001b[1m symmetry: required SymmetryData \u001b[0m\r\n", " structure: optional StructureData \u001b[0m\r\n", "\u001b[31m\u001b[1mExit codes\u001b[0m\r\n", " 1: The process has failed with an unspecified error.\u001b[0m\r\n", " 2: The process failed with legacy failure mode.\u001b[0m\r\n", " 10: The process returned an invalid output.\u001b[0m\r\n", " 11: The process did not register a required output.\u001b[0m\r\n", " 300: One of either a structure or cif input must be supplied\u001b[0m\r\n", " 301: The supplied structure must be 3d (i.e. have all dimensions pbc=true)\"\u001b[0m\r\n", " 302: Idealize can only be used when standardize=true\u001b[0m\r\n", " 303: The kind names supplied are not compatible with the structure\u001b[0m\r\n", " 304: Error creating new structure\u001b[0m\r\n", " 305: Error computing symmetry operations\u001b[0m\r\n" ] } ], "source": [ "!verdi plugin list aiida.workflows crystal17.sym3d" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "sym3d_cls = WorkflowFactory(\"crystal17.sym3d\")\n", "builder = sym3d_cls.get_builder()\n", "builder.settings = {\"symprec\": 0.01}\n", "builder.structure = structure\n", "sym_result = run_get_node(builder)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "ipub": { "figure": { "caption": "`crystal17.sym3d`workflow provenance graph." } } }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "%3\n", "\n", "\n", "\n", "N9\n", "\n", "SymmetryData (9)\n", "hall_number: 523\n", "symmops: 192\n", "\n", "\n", "\n", "N7\n", "\n", "Symmetrise3DStructure (7)\n", "State: finished\n", "Exit Code: 0\n", "\n", "\n", "\n", "N7->N9\n", "\n", "\n", "RETURN\n", "symmetry\n", "\n", "\n", "\n", "N8\n", "\n", "compute_symmetry (8)\n", "State: finished\n", "Exit Code: 0\n", "\n", "\n", "\n", "N7->N8\n", "\n", "\n", "CALL_CALC\n", "CALL\n", "\n", "\n", "\n", "N8->N9\n", "\n", "\n", "CREATE\n", "result\n", "\n", "\n", "\n", "N6\n", "\n", "StructureData (6)\n", "Mg4O4\n", "\n", "\n", "\n", "N6->N7\n", "\n", "\n", "INPUT_WORK\n", "structure\n", "\n", "\n", "\n", "N6->N8\n", "\n", "\n", "INPUT_CALC\n", "structure\n", "\n", "\n", "\n", "N5\n", "\n", "Dict (5)\n", "\n", "\n", "\n", "N5->N7\n", "\n", "\n", "INPUT_WORK\n", "settings\n", "\n", "\n", "\n", "N5->N8\n", "\n", "\n", "INPUT_CALC\n", "settings\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "graph = Graph(graph_attr={'size': \"8,8!\", \"rankdir\": \"LR\"})\n", "graph.recurse_ancestors(sym_result.result[\"symmetry\"],\n", " annotate_links=\"both\")\n", "graph.graphviz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This workflow can also optionally compute the primitive\n", "and/or standardised form of the structure,\n", "before computing the symmetry of the new structure." ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "ipub": { "figure": { "caption": "`crystal17.sym3d`workflow provenance graph, including primitive cell calculation." } } }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "%3\n", "\n", "\n", "\n", "N13\n", "\n", "StructureData (13)\n", "MgO\n", "\n", "\n", "\n", "N14\n", "\n", "compute_symmetry (14)\n", "State: finished\n", "Exit Code: 0\n", "\n", "\n", "\n", "N13->N14\n", "\n", "\n", "INPUT_CALC\n", "structure\n", "\n", "\n", "\n", "N11\n", "\n", "Symmetrise3DStructure (11)\n", "State: finished\n", "Exit Code: 0\n", "\n", "\n", "\n", "N11->N13\n", "\n", "\n", "RETURN\n", "structure\n", "\n", "\n", "\n", "N12\n", "\n", "standard_primitive_structure (12)\n", "State: finished\n", "Exit Code: 0\n", "\n", "\n", "\n", "N11->N12\n", "\n", "\n", "CALL_CALC\n", "CALL\n", "\n", "\n", "\n", "N15\n", "\n", "SymmetryData (15)\n", "hall_number: 523\n", "symmops: 48\n", "\n", "\n", "\n", "N11->N15\n", "\n", "\n", "RETURN\n", "symmetry\n", "\n", "\n", "\n", "N11->N14\n", "\n", "\n", "CALL_CALC\n", "CALL\n", "\n", "\n", "\n", "N12->N13\n", "\n", "\n", "CREATE\n", "result\n", "\n", "\n", "\n", "N6\n", "\n", "StructureData (6)\n", "Mg4O4\n", "\n", "\n", "\n", "N6->N11\n", "\n", "\n", "INPUT_WORK\n", "structure\n", "\n", "\n", "\n", "N6->N12\n", "\n", "\n", "INPUT_CALC\n", "structure\n", "\n", "\n", "\n", "N10\n", "\n", "Dict (10)\n", "\n", "\n", "\n", "N10->N11\n", "\n", "\n", "INPUT_WORK\n", "settings\n", "\n", "\n", "\n", "N10->N12\n", "\n", "\n", "INPUT_CALC\n", "settings\n", "\n", "\n", "\n", "N10->N14\n", "\n", "\n", "INPUT_CALC\n", "settings\n", "\n", "\n", "\n", "N14->N15\n", "\n", "\n", "CREATE\n", "result\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "builder.settings = {\n", " \"symprec\": 0.01,\n", " \"compute_primitive\": True,\n", " \"standardize_cell\": True}\n", "sym_result2 = run_get_node(builder)\n", "graph = Graph(graph_attr={'size': \"9,9!\", \"rankdir\": \"LR\"})\n", "graph.recurse_ancestors(sym_result2.result[\"structure\"],\n", " annotate_links=\"both\")\n", "graph.recurse_ancestors(sym_result2.result[\"symmetry\"],\n", " annotate_links=\"both\")\n", "graph.graphviz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The other option is to ``idealize`` the structure, which\n", "removes distortions of the unit cell's atomic positions,\n", "compared to the ideal symmetry." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setting Up and Running the Calculation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::{seealso}\n", "AiiDA documentation: {ref}`aiida:topics:processes`\n", ":::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "{py:class}`~aiida_crystal17.calculations.cry_main.CryMainCalculation`\n", "provides a helper function to create, populate and validate the input builder." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "```json\n", "{\n", " \"metadata\": {\n", " \"options\": {\n", " \"resources\": {\n", " \"num_machines\": 1,\n", " \"num_mpiprocs_per_machine\": 1\n", " }\n", " }\n", " },\n", " \"basissets\": {\n", " \"Ni\": [\n", " \"uuid: dbf86b0d-0f68-4733-930f-ea48d8f2946d (pk: 3)\"\n", " ],\n", " \"O\": [\n", " \"uuid: 93a07f42-b17c-42ab-a7b8-620b6ccd9a39 (pk: 4)\"\n", " ]\n", " },\n", " \"parameters\": [\n", " \"uuid: c594fdb9-9fc2-4e06-a52d-7b187b1a4cfa (unstored)\"\n", " ],\n", " \"structure\": [\n", " \"uuid: 000fd6e6-4253-44aa-baae-6b45bb7d5fc7 (pk: 20)\"\n", " ],\n", " \"symmetry\": [\n", " \"uuid: 93db2f1e-0949-4e62-a14b-0d68e2d114ad (pk: 22)\"\n", " ],\n", " \"kinds\": [\n", " \"uuid: 7481e639-81c2-4227-b35b-1849d8c2748f (unstored)\"\n", " ],\n", " \"code\": [\n", " \"Remote code 'crystal17.main-mock_crystal17@localhost' on localhost,\",\n", " \"pk: 1, uuid: a2241a9c-deac-4960-9812-088666800dee\"\n", " ]\n", "}\n", "```" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from aiida_crystal17.tests import get_test_structure_and_symm\n", "from aiida_crystal17.data.kinds import KindData\n", "\n", "calc_cls = CalculationFactory('crystal17.main')\n", "structure, symmetry = get_test_structure_and_symm(\"NiO_afm\")\n", "kind_data = KindData(data={\n", " \"kind_names\": [\"Ni1\", \"Ni2\", \"O\"],\n", " \"spin_alpha\": [True, False, False],\n", " \"spin_beta\": [False, True, False]})\n", "\n", "calc_builder = calc_cls.create_builder(\n", " parameters={\n", " \"title\": \"NiO Bulk with AFM spin\",\n", " \"scf.single\": \"UHF\",\n", " \"scf.k_points\": (8, 8),\n", " \"scf.spinlock.SPINLOCK\": (0, 15),\n", " \"scf.numerical.FMIXING\": 30,\n", " \"scf.post_scf\": [\"PPAN\"]\n", " },\n", " unflatten=True,\n", " structure=structure,\n", " symmetry=symmetry,\n", " kinds=kind_data,\n", " bases=\"sto3g\",\n", " code=code,\n", " metadata={\"options\": {\"resources\": {\n", " \"num_machines\": 1, \"num_mpiprocs_per_machine\": 1}}}\n", ")\n", "display_json(calc_builder)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to run the computation,\n", "the builder can be parsed to one of the AiiDA ``run`` (blocking execution) or ``submit`` (non-blocking execution) functions:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "tags": [ "nbreg_compare_output" ] }, "outputs": [], "source": [ "result, calcnode = run_get_node(calc_builder)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The process can be monitored on the command line:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-\b/\b|\b\\\b-\b/\b|\b\u001b[22m PK Created Process label Process State Process status\r\n", "---- --------- --------------------- --------------- ----------------\r\n", " 25 15s ago CryMainCalculation ⏹ Finished [0]\r\n", " 21 15s ago compute_symmetry ⏹ Finished [0]\r\n", " 19 16s ago primitive_structure ⏹ Finished [0]\r\n", " 18 16s ago Symmetrise3DStructure ⏹ Finished [0]\u001b[0m\r\n", "\u001b[22m\r\n", "Total results: 4\r\n", "\u001b[0m\r\n", "\u001b[34m\u001b[1mInfo: \u001b[0m\u001b[22mlast time an entry changed state: 2s ago (at 10:39:42 on 2019-08-12)\u001b[0m\r\n" ] } ], "source": [ "!verdi process list -a -D desc -l 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once the calculation is complete, a ``CalcJobNode`` will be created,\n", "to store the settings and outcome of the computation.\n", "Crucially, if the computation has completed successfully,\n", "the `exit_status` will be **0**.\n", "\n", "This can be assessed on the command line or with the python API." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-\b/\b|\b\\\b-\b/\b|\b\u001b[22mProperty Value\r\n", "------------- ------------------------------------\r\n", "type CalcJobNode\r\n", "pk 25\r\n", "uuid 42166254-7530-4e9e-a7f8-bef09e6a6e6f\r\n", "label\r\n", "description\r\n", "ctime 2019-08-12 10:39:28.969540+00:00\r\n", "mtime 2019-08-12 10:39:42.274641+00:00\r\n", "process state Finished\r\n", "exit status 0\r\n", "computer [1] localhost\r\n", "\r\n", "Inputs PK Type\r\n", "---------- ---- ------------------\r\n", "basissets\r\n", " O 4 BasisSetData\r\n", " Ni 3 BasisSetData\r\n", "code 1 Code\r\n", "kinds 24 KindData\r\n", "parameters 23 CryInputParamsData\r\n", "structure 20 StructureData\r\n", "symmetry 22 SymmetryData\r\n", "\r\n", "Outputs PK Type\r\n", "------------- ---- ----------\r\n", "remote_folder 26 RemoteData\r\n", "results 28 Dict\r\n", "retrieved 27 FolderData\u001b[0m\r\n" ] } ], "source": [ "!verdi process show {calcnode.pk}" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "tags": [ "nbreg_compare_output" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "ProcessState.FINISHED\n", "0\n" ] } ], "source": [ "print(calcnode.is_finished_ok)\n", "print(calcnode.process_state)\n", "print(calcnode.exit_status)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the calculation fails, there are three things that should be checked:\n", "\n", "1. The calculation's exit_message\n", "2. The calculation's log messages and scheduler output\n", "3. The `results` output node (if available)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Exit Message: None\n", "*** 25: None\n", "*** (empty scheduler output file)\n", "*** (empty scheduler errors file)\n", "*** 0 LOG MESSAGES\n" ] } ], "source": [ "print(\"Exit Message:\", calcnode.exit_message)\n", "from aiida.cmdline.utils.common import get_calcjob_report\n", "print(get_calcjob_report(calcnode))" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-\b/\b|\b\\\b-\b/\b|\b\u001b[22m*** 25: None\r\n", "*** (empty scheduler output file)\r\n", "*** (empty scheduler errors file)\r\n", "*** 0 LOG MESSAGES\u001b[0m\r\n" ] } ], "source": [ "!verdi process report {calcnode.pk}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Analysis of Outputs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The {py:class}`~aiida.tools.visualization.graph.Graph` can be used to visualise the calculations provenance graph:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "ipub": { "figure": { "caption": "`crystal17.main` calculation provenance graph (SCF only)." } } }, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\n", "\n", "\n", "%3\n", "\n", "\n", "\n", "N25\n", "\n", "CryMainCalculation (25)\n", "State: finished\n", "Exit Code: 0\n", "\n", "\n", "\n", "N28\n", "\n", "Dict (28)\n", "\n", "\n", "\n", "N25->N28\n", "\n", "\n", "CREATE\n", "results\n", "\n", "\n", "\n", "N27\n", "\n", "FolderData (27)\n", "\n", "\n", "\n", "N25->N27\n", "\n", "\n", "CREATE\n", "retrieved\n", "\n", "\n", "\n", "N26\n", "\n", "RemoteData (26)\n", "@localhost\n", "\n", "\n", "\n", "N25->N26\n", "\n", "\n", "CREATE\n", "remote_folder\n", "\n", "\n", "\n", "N1\n", "\n", "Code (1)\n", "mock_crystal17@localhost\n", "\n", "\n", "\n", "N1->N25\n", "\n", "\n", "INPUT_CALC\n", "code\n", "\n", "\n", "\n", "N24\n", "\n", "KindData (24)\n", "\n", "\n", "\n", "N24->N25\n", "\n", "\n", "INPUT_CALC\n", "kinds\n", "\n", "\n", "\n", "N22\n", "\n", "SymmetryData (22)\n", "hall_number: 400\n", "symmops: 16\n", "\n", "\n", "\n", "N22->N25\n", "\n", "\n", "INPUT_CALC\n", "symmetry\n", "\n", "\n", "\n", "N20\n", "\n", "StructureData (20)\n", "Ni2O2\n", "\n", "\n", "\n", "N20->N25\n", "\n", "\n", "INPUT_CALC\n", "structure\n", "\n", "\n", "\n", "N23\n", "\n", "CryInputParamsData (23)\n", "\n", "\n", "\n", "N23->N25\n", "\n", "\n", "INPUT_CALC\n", "parameters\n", "\n", "\n", "\n", "N4\n", "\n", "BasisSetData (4)\n", "\n", "\n", "\n", "N4->N25\n", "\n", "\n", "INPUT_CALC\n", "basissets__O\n", "\n", "\n", "\n", "N3\n", "\n", "BasisSetData (3)\n", "\n", "\n", "\n", "N3->N25\n", "\n", "\n", "INPUT_CALC\n", "basissets__Ni\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "graph = Graph(graph_attr={'size': \"6,8!\", \"rankdir\": \"LR\"})\n", "graph.add_node(calcnode)\n", "graph.add_incoming(calcnode, annotate_links=\"both\")\n", "graph.add_outgoing(calcnode, annotate_links=\"both\")\n", "graph.graphviz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `retrieved` `FolderData` output node contains the CRYSTAL17 main input and output file." ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "tags": [ "nbreg_compare_output" ] }, "outputs": [ { "data": { "text/plain": [ "['_scheduler-stderr.txt', '_scheduler-stdout.txt', 'fort.34', 'main.out']" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "calcnode.outputs.retrieved.list_object_names()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `results` `Dict` output node contains key values extracted from the CRYSTAL17 standard output file." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/markdown": [ "```json\n", "{\n", " \"units\": {\n", " \"angle\": \"degrees\",\n", " \"energy\": \"eV\",\n", " \"length\": \"angstrom\",\n", " \"conversion\": \"CODATA2014\"\n", " },\n", " \"energy\": -85124.893667339,\n", " \"errors\": [],\n", " \"header\": {\n", " \"crystal_version\": 17,\n", " \"crystal_subversion\": \"1.0.1\"\n", " },\n", " \"volume\": 36.099581472,\n", " \"warnings\": [],\n", " \"calculation\": {\n", " \"n_ao\": 46,\n", " \"spin\": true,\n", " \"type\": \"unrestricted open shell\",\n", " \"n_atoms\": 4,\n", " \"n_shells\": 14,\n", " \"n_symops\": 16,\n", " \"n_core_el\": 40,\n", " \"n_electrons\": 72,\n", " \"n_kpoints_ibz\": 75,\n", " \"n_kpoints_gilat\": 75\n", " },\n", " \"energy_units\": \"eV\",\n", " \"parser_class\": \"CryMainParser\",\n", " \"parser_errors\": [],\n", " \"mulliken_spins\": [\n", " 3.057,\n", " -3.057,\n", " -0.072,\n", " 0.072\n", " ],\n", " \"parser_version\": \"0.11.0\",\n", " \"scf_iterations\": 13,\n", " \"number_of_atoms\": 4,\n", " \"parser_warnings\": [],\n", " \"mulliken_charges\": [\n", " 0.398,\n", " 0.397,\n", " -0.398,\n", " -0.397\n", " ],\n", " \"parser_exceptions\": [],\n", " \"mulliken_electrons\": [\n", " 27.602,\n", " 27.603,\n", " 8.398,\n", " 8.397\n", " ],\n", " \"mulliken_spin_total\": 0.0,\n", " \"number_of_assymetric\": 4,\n", " \"execution_time_seconds\": 187\n", "}\n", "```" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display_json(calcnode.outputs.results.get_dict())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To understand the format of the parsed data,\n", "the raw parser is exposed on the command line as `verdi data crystal17.parse stdout`,\n", "which can be used to parse existing output files." ] } ], "metadata": { "celltoolbar": "Tags", "hide_input": false, "ipub": { "sphinx": { "toggle_input_all": true, "toggle_output_all": true } }, "jupytext": { "formats": "ipynb,md:myst" }, "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.7" }, "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": { "height": "calc(100% - 180px)", "left": "10px", "top": "150px", "width": "256px" }, "toc_section_display": true, "toc_window_display": true } }, "nbformat": 4, "nbformat_minor": 2 }