diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..a07e6b0ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +target/ +**/*.rs.bk +Cargo.lock + +.tox/ +build/ +dist/ +*.egg-info +__pycache__/ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/_redirect.html b/_redirect.html new file mode 100644 index 000000000..4f607eaeb --- /dev/null +++ b/_redirect.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/index.html b/index.html new file mode 100644 index 000000000..e22946da0 --- /dev/null +++ b/index.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/latest/.buildinfo b/latest/.buildinfo new file mode 100644 index 000000000..43dee279f --- /dev/null +++ b/latest/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: d612f0f0c6523c4cadb32515af98a626 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/latest/.doctrees/devdoc/explanations/architecture.doctree b/latest/.doctrees/devdoc/explanations/architecture.doctree new file mode 100644 index 000000000..2f3abb85d Binary files /dev/null and b/latest/.doctrees/devdoc/explanations/architecture.doctree differ diff --git a/latest/.doctrees/devdoc/explanations/index.doctree b/latest/.doctrees/devdoc/explanations/index.doctree new file mode 100644 index 000000000..63b2bde61 Binary files /dev/null and b/latest/.doctrees/devdoc/explanations/index.doctree differ diff --git a/latest/.doctrees/devdoc/explanations/interfaces.doctree b/latest/.doctrees/devdoc/explanations/interfaces.doctree new file mode 100644 index 000000000..c388fa00d Binary files /dev/null and b/latest/.doctrees/devdoc/explanations/interfaces.doctree differ diff --git a/latest/.doctrees/devdoc/explanations/radial-integral.doctree b/latest/.doctrees/devdoc/explanations/radial-integral.doctree new file mode 100644 index 000000000..3e196e70f Binary files /dev/null and b/latest/.doctrees/devdoc/explanations/radial-integral.doctree differ diff --git a/latest/.doctrees/devdoc/get-started.doctree b/latest/.doctrees/devdoc/get-started.doctree new file mode 100644 index 000000000..a915babe9 Binary files /dev/null and b/latest/.doctrees/devdoc/get-started.doctree differ diff --git a/latest/.doctrees/devdoc/how-to/index.doctree b/latest/.doctrees/devdoc/how-to/index.doctree new file mode 100644 index 000000000..f891491f3 Binary files /dev/null and b/latest/.doctrees/devdoc/how-to/index.doctree differ diff --git a/latest/.doctrees/devdoc/how-to/new-calculator.doctree b/latest/.doctrees/devdoc/how-to/new-calculator.doctree new file mode 100644 index 000000000..d835e13ed Binary files /dev/null and b/latest/.doctrees/devdoc/how-to/new-calculator.doctree differ diff --git a/latest/.doctrees/devdoc/how-to/profiling.doctree b/latest/.doctrees/devdoc/how-to/profiling.doctree new file mode 100644 index 000000000..d1e648cb8 Binary files /dev/null and b/latest/.doctrees/devdoc/how-to/profiling.doctree differ diff --git a/latest/.doctrees/devdoc/index.doctree b/latest/.doctrees/devdoc/index.doctree new file mode 100644 index 000000000..066696c48 Binary files /dev/null and b/latest/.doctrees/devdoc/index.doctree differ diff --git a/latest/.doctrees/environment.pickle b/latest/.doctrees/environment.pickle new file mode 100644 index 000000000..00c8dff0e Binary files /dev/null and b/latest/.doctrees/environment.pickle differ diff --git a/latest/.doctrees/examples/compute-soap.doctree b/latest/.doctrees/examples/compute-soap.doctree new file mode 100644 index 000000000..056a7363e Binary files /dev/null and b/latest/.doctrees/examples/compute-soap.doctree differ diff --git a/latest/.doctrees/examples/first-calculation.doctree b/latest/.doctrees/examples/first-calculation.doctree new file mode 100644 index 000000000..02ca82465 Binary files /dev/null and b/latest/.doctrees/examples/first-calculation.doctree differ diff --git a/latest/.doctrees/examples/index.doctree b/latest/.doctrees/examples/index.doctree new file mode 100644 index 000000000..aad10614e Binary files /dev/null and b/latest/.doctrees/examples/index.doctree differ diff --git a/latest/.doctrees/examples/keys-selection.doctree b/latest/.doctrees/examples/keys-selection.doctree new file mode 100644 index 000000000..c311ce8fc Binary files /dev/null and b/latest/.doctrees/examples/keys-selection.doctree differ diff --git a/latest/.doctrees/examples/le-basis.doctree b/latest/.doctrees/examples/le-basis.doctree new file mode 100644 index 000000000..cb75d8779 Binary files /dev/null and b/latest/.doctrees/examples/le-basis.doctree differ diff --git a/latest/.doctrees/examples/long-range-descriptor.doctree b/latest/.doctrees/examples/long-range-descriptor.doctree new file mode 100644 index 000000000..0a853fa43 Binary files /dev/null and b/latest/.doctrees/examples/long-range-descriptor.doctree differ diff --git a/latest/.doctrees/examples/profiling.doctree b/latest/.doctrees/examples/profiling.doctree new file mode 100644 index 000000000..29c889a35 Binary files /dev/null and b/latest/.doctrees/examples/profiling.doctree differ diff --git a/latest/.doctrees/examples/property-selection.doctree b/latest/.doctrees/examples/property-selection.doctree new file mode 100644 index 000000000..5f2991ee6 Binary files /dev/null and b/latest/.doctrees/examples/property-selection.doctree differ diff --git a/latest/.doctrees/examples/sample-selection.doctree b/latest/.doctrees/examples/sample-selection.doctree new file mode 100644 index 000000000..cb455f08f Binary files /dev/null and b/latest/.doctrees/examples/sample-selection.doctree differ diff --git a/latest/.doctrees/examples/sg_execution_times.doctree b/latest/.doctrees/examples/sg_execution_times.doctree new file mode 100644 index 000000000..c06c023fd Binary files /dev/null and b/latest/.doctrees/examples/sg_execution_times.doctree differ diff --git a/latest/.doctrees/examples/splined-radial-integral.doctree b/latest/.doctrees/examples/splined-radial-integral.doctree new file mode 100644 index 000000000..891d37e16 Binary files /dev/null and b/latest/.doctrees/examples/splined-radial-integral.doctree differ diff --git a/latest/.doctrees/examples/understanding-hypers.doctree b/latest/.doctrees/examples/understanding-hypers.doctree new file mode 100644 index 000000000..38a1a9ed1 Binary files /dev/null and b/latest/.doctrees/examples/understanding-hypers.doctree differ diff --git a/latest/.doctrees/explanations/concepts.doctree b/latest/.doctrees/explanations/concepts.doctree new file mode 100644 index 000000000..c2fe6a6f0 Binary files /dev/null and b/latest/.doctrees/explanations/concepts.doctree differ diff --git a/latest/.doctrees/explanations/index.doctree b/latest/.doctrees/explanations/index.doctree new file mode 100644 index 000000000..6df25970d Binary files /dev/null and b/latest/.doctrees/explanations/index.doctree differ diff --git a/latest/.doctrees/explanations/rotation_adapted.doctree b/latest/.doctrees/explanations/rotation_adapted.doctree new file mode 100644 index 000000000..f01b4dd40 Binary files /dev/null and b/latest/.doctrees/explanations/rotation_adapted.doctree differ diff --git a/latest/.doctrees/explanations/soap.doctree b/latest/.doctrees/explanations/soap.doctree new file mode 100644 index 000000000..0b0a5b563 Binary files /dev/null and b/latest/.doctrees/explanations/soap.doctree differ diff --git a/latest/.doctrees/get-started/index.doctree b/latest/.doctrees/get-started/index.doctree new file mode 100644 index 000000000..04aacf08e Binary files /dev/null and b/latest/.doctrees/get-started/index.doctree differ diff --git a/latest/.doctrees/get-started/installation.doctree b/latest/.doctrees/get-started/installation.doctree new file mode 100644 index 000000000..bf6cf7e45 Binary files /dev/null and b/latest/.doctrees/get-started/installation.doctree differ diff --git a/latest/.doctrees/get-started/rascaline.doctree b/latest/.doctrees/get-started/rascaline.doctree new file mode 100644 index 000000000..24afe3c92 Binary files /dev/null and b/latest/.doctrees/get-started/rascaline.doctree differ diff --git a/latest/.doctrees/get-started/tutorials.doctree b/latest/.doctrees/get-started/tutorials.doctree new file mode 100644 index 000000000..db377a4f5 Binary files /dev/null and b/latest/.doctrees/get-started/tutorials.doctree differ diff --git a/latest/.doctrees/how-to/computing-soap.doctree b/latest/.doctrees/how-to/computing-soap.doctree new file mode 100644 index 000000000..196bcc4e4 Binary files /dev/null and b/latest/.doctrees/how-to/computing-soap.doctree differ diff --git a/latest/.doctrees/how-to/index.doctree b/latest/.doctrees/how-to/index.doctree new file mode 100644 index 000000000..2f46f9dac Binary files /dev/null and b/latest/.doctrees/how-to/index.doctree differ diff --git a/latest/.doctrees/how-to/keys-selection.doctree b/latest/.doctrees/how-to/keys-selection.doctree new file mode 100644 index 000000000..465841b23 Binary files /dev/null and b/latest/.doctrees/how-to/keys-selection.doctree differ diff --git a/latest/.doctrees/how-to/le-basis.doctree b/latest/.doctrees/how-to/le-basis.doctree new file mode 100644 index 000000000..501736198 Binary files /dev/null and b/latest/.doctrees/how-to/le-basis.doctree differ diff --git a/latest/.doctrees/how-to/long-range.doctree b/latest/.doctrees/how-to/long-range.doctree new file mode 100644 index 000000000..99ab5ea56 Binary files /dev/null and b/latest/.doctrees/how-to/long-range.doctree differ diff --git a/latest/.doctrees/how-to/property-selection.doctree b/latest/.doctrees/how-to/property-selection.doctree new file mode 100644 index 000000000..5fdc5b99e Binary files /dev/null and b/latest/.doctrees/how-to/property-selection.doctree differ diff --git a/latest/.doctrees/how-to/sample-selection.doctree b/latest/.doctrees/how-to/sample-selection.doctree new file mode 100644 index 000000000..e8c419c8a Binary files /dev/null and b/latest/.doctrees/how-to/sample-selection.doctree differ diff --git a/latest/.doctrees/how-to/splined-radial-integral.doctree b/latest/.doctrees/how-to/splined-radial-integral.doctree new file mode 100644 index 000000000..c99bf89d8 Binary files /dev/null and b/latest/.doctrees/how-to/splined-radial-integral.doctree differ diff --git a/latest/.doctrees/index.doctree b/latest/.doctrees/index.doctree new file mode 100644 index 000000000..2c8075b23 Binary files /dev/null and b/latest/.doctrees/index.doctree differ diff --git a/latest/.doctrees/references/api/c/calculators.doctree b/latest/.doctrees/references/api/c/calculators.doctree new file mode 100644 index 000000000..2205c017a Binary files /dev/null and b/latest/.doctrees/references/api/c/calculators.doctree differ diff --git a/latest/.doctrees/references/api/c/index.doctree b/latest/.doctrees/references/api/c/index.doctree new file mode 100644 index 000000000..7ad2af467 Binary files /dev/null and b/latest/.doctrees/references/api/c/index.doctree differ diff --git a/latest/.doctrees/references/api/c/misc.doctree b/latest/.doctrees/references/api/c/misc.doctree new file mode 100644 index 000000000..a14659723 Binary files /dev/null and b/latest/.doctrees/references/api/c/misc.doctree differ diff --git a/latest/.doctrees/references/api/c/systems.doctree b/latest/.doctrees/references/api/c/systems.doctree new file mode 100644 index 000000000..e537c935b Binary files /dev/null and b/latest/.doctrees/references/api/c/systems.doctree differ diff --git a/latest/.doctrees/references/api/cxx/calculators.doctree b/latest/.doctrees/references/api/cxx/calculators.doctree new file mode 100644 index 000000000..7312aea35 Binary files /dev/null and b/latest/.doctrees/references/api/cxx/calculators.doctree differ diff --git a/latest/.doctrees/references/api/cxx/index.doctree b/latest/.doctrees/references/api/cxx/index.doctree new file mode 100644 index 000000000..b5c68d4da Binary files /dev/null and b/latest/.doctrees/references/api/cxx/index.doctree differ diff --git a/latest/.doctrees/references/api/cxx/misc.doctree b/latest/.doctrees/references/api/cxx/misc.doctree new file mode 100644 index 000000000..76b5fbcf2 Binary files /dev/null and b/latest/.doctrees/references/api/cxx/misc.doctree differ diff --git a/latest/.doctrees/references/api/cxx/systems.doctree b/latest/.doctrees/references/api/cxx/systems.doctree new file mode 100644 index 000000000..68780a338 Binary files /dev/null and b/latest/.doctrees/references/api/cxx/systems.doctree differ diff --git a/latest/.doctrees/references/api/index.doctree b/latest/.doctrees/references/api/index.doctree new file mode 100644 index 000000000..1df67a664 Binary files /dev/null and b/latest/.doctrees/references/api/index.doctree differ diff --git a/latest/.doctrees/references/api/python/calculators.doctree b/latest/.doctrees/references/api/python/calculators.doctree new file mode 100644 index 000000000..951fcdafe Binary files /dev/null and b/latest/.doctrees/references/api/python/calculators.doctree differ diff --git a/latest/.doctrees/references/api/python/index.doctree b/latest/.doctrees/references/api/python/index.doctree new file mode 100644 index 000000000..36ce2432e Binary files /dev/null and b/latest/.doctrees/references/api/python/index.doctree differ diff --git a/latest/.doctrees/references/api/python/misc.doctree b/latest/.doctrees/references/api/python/misc.doctree new file mode 100644 index 000000000..acdeff54e Binary files /dev/null and b/latest/.doctrees/references/api/python/misc.doctree differ diff --git a/latest/.doctrees/references/api/python/systems.doctree b/latest/.doctrees/references/api/python/systems.doctree new file mode 100644 index 000000000..5e5edeb2b Binary files /dev/null and b/latest/.doctrees/references/api/python/systems.doctree differ diff --git a/latest/.doctrees/references/api/python/utils/atomic-density.doctree b/latest/.doctrees/references/api/python/utils/atomic-density.doctree new file mode 100644 index 000000000..2700d71c5 Binary files /dev/null and b/latest/.doctrees/references/api/python/utils/atomic-density.doctree differ diff --git a/latest/.doctrees/references/api/python/utils/clebsch-gordan.doctree b/latest/.doctrees/references/api/python/utils/clebsch-gordan.doctree new file mode 100644 index 000000000..6c75b5b59 Binary files /dev/null and b/latest/.doctrees/references/api/python/utils/clebsch-gordan.doctree differ diff --git a/latest/.doctrees/references/api/python/utils/index.doctree b/latest/.doctrees/references/api/python/utils/index.doctree new file mode 100644 index 000000000..1effb49f4 Binary files /dev/null and b/latest/.doctrees/references/api/python/utils/index.doctree differ diff --git a/latest/.doctrees/references/api/python/utils/power-spectrum.doctree b/latest/.doctrees/references/api/python/utils/power-spectrum.doctree new file mode 100644 index 000000000..87aaa2be6 Binary files /dev/null and b/latest/.doctrees/references/api/python/utils/power-spectrum.doctree differ diff --git a/latest/.doctrees/references/api/python/utils/radial-basis.doctree b/latest/.doctrees/references/api/python/utils/radial-basis.doctree new file mode 100644 index 000000000..d32cd32c7 Binary files /dev/null and b/latest/.doctrees/references/api/python/utils/radial-basis.doctree differ diff --git a/latest/.doctrees/references/api/python/utils/splines.doctree b/latest/.doctrees/references/api/python/utils/splines.doctree new file mode 100644 index 000000000..e2d140c0e Binary files /dev/null and b/latest/.doctrees/references/api/python/utils/splines.doctree differ diff --git a/latest/.doctrees/references/api/rust.doctree b/latest/.doctrees/references/api/rust.doctree new file mode 100644 index 000000000..46e3097a8 Binary files /dev/null and b/latest/.doctrees/references/api/rust.doctree differ diff --git a/latest/.doctrees/references/api/torch/calculators.doctree b/latest/.doctrees/references/api/torch/calculators.doctree new file mode 100644 index 000000000..5461460d5 Binary files /dev/null and b/latest/.doctrees/references/api/torch/calculators.doctree differ diff --git a/latest/.doctrees/references/api/torch/cxx/calculators.doctree b/latest/.doctrees/references/api/torch/cxx/calculators.doctree new file mode 100644 index 000000000..066f6aa8d Binary files /dev/null and b/latest/.doctrees/references/api/torch/cxx/calculators.doctree differ diff --git a/latest/.doctrees/references/api/torch/cxx/index.doctree b/latest/.doctrees/references/api/torch/cxx/index.doctree new file mode 100644 index 000000000..5025dfc1e Binary files /dev/null and b/latest/.doctrees/references/api/torch/cxx/index.doctree differ diff --git a/latest/.doctrees/references/api/torch/index.doctree b/latest/.doctrees/references/api/torch/index.doctree new file mode 100644 index 000000000..38d651026 Binary files /dev/null and b/latest/.doctrees/references/api/torch/index.doctree differ diff --git a/latest/.doctrees/references/api/torch/systems.doctree b/latest/.doctrees/references/api/torch/systems.doctree new file mode 100644 index 000000000..a7ffc00d8 Binary files /dev/null and b/latest/.doctrees/references/api/torch/systems.doctree differ diff --git a/latest/.doctrees/references/api/torch/utils/clebsch-gordan.doctree b/latest/.doctrees/references/api/torch/utils/clebsch-gordan.doctree new file mode 100644 index 000000000..e85b3c6d0 Binary files /dev/null and b/latest/.doctrees/references/api/torch/utils/clebsch-gordan.doctree differ diff --git a/latest/.doctrees/references/api/torch/utils/index.doctree b/latest/.doctrees/references/api/torch/utils/index.doctree new file mode 100644 index 000000000..050cdb907 Binary files /dev/null and b/latest/.doctrees/references/api/torch/utils/index.doctree differ diff --git a/latest/.doctrees/references/api/torch/utils/power-spectrum.doctree b/latest/.doctrees/references/api/torch/utils/power-spectrum.doctree new file mode 100644 index 000000000..eac000a0d Binary files /dev/null and b/latest/.doctrees/references/api/torch/utils/power-spectrum.doctree differ diff --git a/latest/.doctrees/references/calculators/atomic-composition.doctree b/latest/.doctrees/references/calculators/atomic-composition.doctree new file mode 100644 index 000000000..717f0860d Binary files /dev/null and b/latest/.doctrees/references/calculators/atomic-composition.doctree differ diff --git a/latest/.doctrees/references/calculators/index.doctree b/latest/.doctrees/references/calculators/index.doctree new file mode 100644 index 000000000..b722c1f7d Binary files /dev/null and b/latest/.doctrees/references/calculators/index.doctree differ diff --git a/latest/.doctrees/references/calculators/lode-spherical-expansion.doctree b/latest/.doctrees/references/calculators/lode-spherical-expansion.doctree new file mode 100644 index 000000000..c79259b22 Binary files /dev/null and b/latest/.doctrees/references/calculators/lode-spherical-expansion.doctree differ diff --git a/latest/.doctrees/references/calculators/neighbor-list.doctree b/latest/.doctrees/references/calculators/neighbor-list.doctree new file mode 100644 index 000000000..af3ac43e9 Binary files /dev/null and b/latest/.doctrees/references/calculators/neighbor-list.doctree differ diff --git a/latest/.doctrees/references/calculators/soap-power-spectrum.doctree b/latest/.doctrees/references/calculators/soap-power-spectrum.doctree new file mode 100644 index 000000000..2b19a783d Binary files /dev/null and b/latest/.doctrees/references/calculators/soap-power-spectrum.doctree differ diff --git a/latest/.doctrees/references/calculators/soap-radial-spectrum.doctree b/latest/.doctrees/references/calculators/soap-radial-spectrum.doctree new file mode 100644 index 000000000..fb4699f60 Binary files /dev/null and b/latest/.doctrees/references/calculators/soap-radial-spectrum.doctree differ diff --git a/latest/.doctrees/references/calculators/sorted-distances.doctree b/latest/.doctrees/references/calculators/sorted-distances.doctree new file mode 100644 index 000000000..0d897969e Binary files /dev/null and b/latest/.doctrees/references/calculators/sorted-distances.doctree differ diff --git a/latest/.doctrees/references/calculators/spherical-expansion-by-pair.doctree b/latest/.doctrees/references/calculators/spherical-expansion-by-pair.doctree new file mode 100644 index 000000000..ffbaab4bf Binary files /dev/null and b/latest/.doctrees/references/calculators/spherical-expansion-by-pair.doctree differ diff --git a/latest/.doctrees/references/calculators/spherical-expansion.doctree b/latest/.doctrees/references/calculators/spherical-expansion.doctree new file mode 100644 index 000000000..f5e7a2302 Binary files /dev/null and b/latest/.doctrees/references/calculators/spherical-expansion.doctree differ diff --git a/latest/.doctrees/references/index.doctree b/latest/.doctrees/references/index.doctree new file mode 100644 index 000000000..fa1351892 Binary files /dev/null and b/latest/.doctrees/references/index.doctree differ diff --git a/latest/_downloads/081634a43959105f7f41a7682e76d405/property-selection.ipynb b/latest/_downloads/081634a43959105f7f41a7682e76d405/property-selection.ipynb new file mode 100644 index 000000000..9503c4a54 --- /dev/null +++ b/latest/_downloads/081634a43959105f7f41a7682e76d405/property-selection.ipynb @@ -0,0 +1,248 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Property Selection\n\n.. start-body\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import chemfiles\nimport numpy as np\nfrom metatensor import Labels, MetatensorError, TensorBlock, TensorMap\nfrom skmatter.feature_selection import FPS\n\nfrom rascaline import SoapPowerSpectrum" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we load the dataset with chemfiles\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "with chemfiles.Trajectory(\"dataset.xyz\") as trajectory:\n frames = [f for f in trajectory]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and define the hyper parameters of the representation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "HYPER_PARAMETERS = {\n \"cutoff\": 5.0,\n \"max_radial\": 6,\n \"max_angular\": 4,\n \"atomic_gaussian_width\": 0.3,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\n \"Gto\": {},\n },\n \"cutoff_function\": {\n \"ShiftedCosine\": {\"width\": 0.5},\n },\n}\n\ncalculator = SoapPowerSpectrum(**HYPER_PARAMETERS)\n\ndescriptor = calculator.compute(frames)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The selections for feature can be a set of ``Labels``, in which case the names\nof the labels must be a subset of the names of the properties produced by the\ncalculator. You can see the default set of names with:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"property names:\", descriptor.property_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use a subset of these names to define a selection. In this case, only\nproperties matching the labels in this selection will be used by rascaline\n(here, only properties with ``l = 0`` will be used)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selection = Labels(\n names=[\"l\"],\n values=np.array([[0]]),\n)\nselected_descriptor = calculator.compute(frames, selected_properties=selection)\n\nselected_descriptor = selected_descriptor.keys_to_samples(\"center_type\")\nselected_descriptor = selected_descriptor.keys_to_properties(\n [\"neighbor_1_type\", \"neighbor_2_type\"]\n)\n\nproperties = selected_descriptor.block().properties" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We expect to get `[0]` as the list of `l` properties\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(f\"we have the following angular components: {np.unique(properties['l'])}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The previous selection method uses the same selection for all blocks. If you\ncan to use different selection for different blocks, you should use a\n``TensorMap`` to create your selection\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selected_descriptor = calculator.compute(frames, selected_properties=selection)\ndescriptor_for_comparison = calculator.compute(\n frames, selected_properties=selected_descriptor\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The descriptor had 180 properties stored in the first block, the\nselected_descriptor had 36. So ``descriptor_for_comparison`` will also have 36\nproperties.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"shape of first block initially:\", descriptor.block(0).values.shape)\nprint(\"shape of first block of reference:\", selected_descriptor.block(0).values.shape)\nprint(\n \"shape of first block after selection:\",\n descriptor_for_comparison.block(0).values.shape,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``TensorMap`` format allows us to select different features within each\nblock, and then construct a general matrix of features. We can select the most\nsignificant features using FPS, which selects features based on the distance\nbetween them. The following code snippet selects the 10 most important\nfeatures in each block, then constructs a TensorMap containing this selection,\nand calculates the final matrix of features for it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def fps_feature_selection(descriptor, n_to_select):\n \"\"\"\n Select ``n_to_select`` features block by block in the ``descriptor``, using\n Farthest Point Sampling to do the selection; and return a ``TensorMap`` with\n the right structure to be used as properties selection with rascaline calculators\n \"\"\"\n blocks = []\n for block in descriptor:\n # create a separate FPS selector for each block\n fps = FPS(n_to_select=n_to_select)\n mask = fps.fit(block.values).get_support()\n selected_properties = Labels(\n names=block.properties.names,\n values=block.properties.values[mask],\n )\n # The only important data here is the properties, so we create empty\n # sets of samples and components.\n blocks.append(\n TensorBlock(\n values=np.empty((1, len(selected_properties))),\n samples=Labels.single(),\n components=[],\n properties=selected_properties,\n )\n )\n\n return TensorMap(descriptor.keys, blocks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can then apply this function to subselect according to the data contained\nin a descriptor\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selection = fps_feature_selection(descriptor, n_to_select=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and use the selection with rascaline, potentially running the calculation on a\ndifferent set of systems\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selected_descriptor = calculator.compute(frames, selected_properties=selection)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that in this case it is no longer possible to have a single feature\nmatrix, because each block will have its own properties.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "try:\n selected_descriptor.keys_to_samples(\"center_type\")\nexcept MetatensorError as err:\n print(err)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ".. end-body\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/08b985c96711d158571cd9dd7ef9d241/understanding-hypers.ipynb b/latest/_downloads/08b985c96711d158571cd9dd7ef9d241/understanding-hypers.ipynb new file mode 100644 index 000000000..9b9c5ce2a --- /dev/null +++ b/latest/_downloads/08b985c96711d158571cd9dd7ef9d241/understanding-hypers.ipynb @@ -0,0 +1,273 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n\n# Changing SOAP hyper parameters\n\nIn the first `tutorial ` we show how to\ncalculate a descriptor using default hyper parameters. Here we will look at how the\nchange of some hyper parameters affects the values of the descriptor. The\ndefinition of every hyper parameter is given in the `userdoc-calculators` and\nbackground on the mathematical foundation of the spherical expansion is given in\nthe `userdoc-explanations` section.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We use the same molecular crystals dataset as in the first\n`tutorial ` which can downloaded from our\n:download:`website <../../static/dataset.xyz>`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# We first import the crucial packages, load the dataset using chemfiles and\n# save the first frame in a variable.\n\nimport time\n\nimport chemfiles\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom rascaline import SphericalExpansion\n\n\nwith chemfiles.Trajectory(\"dataset.xyz\") as trajectory:\n frames = [frame for frame in trajectory]\n\nframe0 = frames[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Increasing ``max_radial`` and ``max_angular``\n\nAs mentioned above changing ``max_radial`` has an effect on the accuracy of\nthe descriptor and on the computation time. We now will increase the number of\nradial channels and angular channels. Note, that here we directly pass the\nparameters into the ``SphericalExpansion`` class without defining a\n``HYPERPARAMETERS`` dictionary like we did in the previous tutorial.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "calculator_ext = SphericalExpansion(\n cutoff=4.5,\n max_radial=12,\n max_angular=8,\n atomic_gaussian_width=0.3,\n center_atom_weight=1.0,\n radial_basis={\"Gto\": {\"spline_accuracy\": 1e-6}},\n cutoff_function={\"ShiftedCosine\": {\"width\": 0.5}},\n radial_scaling={\"Willatt2018\": {\"scale\": 2.0, \"rate\": 1.0, \"exponent\": 4}},\n)\n\ndescriptor_ext = calculator_ext.compute(frame0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Compared to our previous set of hypers we now have 144 blocks instead of 112\nbecause we increased the number of angular channels.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(len(descriptor_ext.blocks()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The increase of the radial channels to 12 is reflected in the shape of the 0th\nblock values.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(descriptor_ext.block(0).values.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the increased number of radial and angular channels can increase the\naccuracy of your representation but will increase the computational time\ntransforming the coordinates into a descriptor. A very simple time measurement\nof the computation shows that the extended calculator takes more time for\nthe computation compared to a calculation using the default hyper parameters\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "start_time = time.time()\ncalculator_ext.compute(frames)\nprint(f\"Extended hypers took {time.time() - start_time:.2f} s.\")\n\n# using smaller max_radial and max_angular, everything else stays the same\ncalculator_small = SphericalExpansion(\n cutoff=4.5,\n max_radial=9,\n max_angular=6,\n atomic_gaussian_width=0.3,\n center_atom_weight=1.0,\n radial_basis={\"Gto\": {\"spline_accuracy\": 1e-6}},\n cutoff_function={\"ShiftedCosine\": {\"width\": 0.5}},\n radial_scaling={\"Willatt2018\": {\"scale\": 2.0, \"rate\": 1.0, \"exponent\": 4}},\n)\n\nstart_time = time.time()\ncalculator_small.compute(frames)\nprint(f\"Smaller hypers took {time.time() - start_time:.2f} s.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reducing the ``cutoff`` and the ``center_atom_weight``\n\nThe cutoff controls how many neighboring atoms are taken into account for a\ndescriptor. By decreasing the cutoff from 6 \u00c5 to 0.1 \u00c5 fewer and fewer atoms\ncontribute to the descriptor which can be seen by the reduced range of the\nfeatures.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for cutoff in [6.0, 4.5, 3.0, 1.0, 0.1]:\n calculator_cutoff = SphericalExpansion(\n cutoff=cutoff,\n max_radial=6,\n max_angular=6,\n atomic_gaussian_width=0.3,\n center_atom_weight=1.0,\n radial_basis={\"Gto\": {\"spline_accuracy\": 1e-6}},\n cutoff_function={\"ShiftedCosine\": {\"width\": 0.5}},\n radial_scaling={\"Willatt2018\": {\"scale\": 2.0, \"rate\": 1.0, \"exponent\": 4}},\n )\n\n descriptor = calculator_cutoff.compute(frame0)\n\n print(f\"Descriptor for cutoff={cutoff} \u00c5: {descriptor.block(0).values[0]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For a ``cutoff`` of 0.1 \u00c5 there is no neighboring atom within the cutoff and\none could expect all features to be 0. This is not the case because the\ncentral atom also contributes to the descriptor. We can vary this contribution\nusing the ``center_atom_weight`` parameter so that the descriptor finally is 0\neverywhere.\n\n..Add a sophisticated and referenced note on how the ``center_atom_weight``\ncould affect ML models.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for center_weight in [1.0, 0.5, 0.0]:\n calculator_cutoff = SphericalExpansion(\n cutoff=0.1,\n max_radial=6,\n max_angular=6,\n atomic_gaussian_width=0.3,\n center_atom_weight=center_weight,\n radial_basis={\"Gto\": {\"spline_accuracy\": 1e-6}},\n cutoff_function={\"ShiftedCosine\": {\"width\": 0.5}},\n radial_scaling={\"Willatt2018\": {\"scale\": 2.0, \"rate\": 1.0, \"exponent\": 4}},\n )\n\n descriptor = calculator_cutoff.compute(frame0)\n\n print(\n f\"Descriptor for center_weight={center_weight}: \"\n f\"{descriptor.block(0).values[0]}\"\n )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Choosing the ``cutoff_function``\n\nIn a naive descriptor approach all atoms within the cutoff are taken in into\naccount equally and atoms without the cutoff are ignored. This behavior is\nimplemented using the ``cutoff_function={\"Step\": {}}`` parameter in each\ncalculator. However, doing so means that small movements of an atom near the\ncutoff result in large changes in the descriptor: there is a discontinuity in\nthe representation as atoms enter or leave the cutoff. A solution is to use\nsome smoothing function to get rid of this discontinuity, such as a shifted\ncosine function:\n\n\\begin{align}f(r) = \\begin{cases}\n 1 &r < r_c - w,\\\\\n 0.5 + 0.5 \\cos[\\pi (r - r_c + w) / w] &r_c - w < r <= r_c, \\\\\n 0 &r_c < r,\n \\end{cases}\\end{align}\n\nwhere $r_\\mathrm{c}$ is the cutoff distance and $w$ the width.\nSuch smoothing function is used as a multiplicative weight for the\ncontribution to the representation coming from each neighbor one by one\n\nThe following functions compute such a shifted cosine weighting.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def shifted_cosine(r, cutoff, width):\n \"\"\"A shifted cosine switching function.\n\n Parameters\n ----------\n r : float\n distance between neighboring atoms in \u00c5\n cutoff : float\n cutoff distance in \u00c5\n width : float\n width of the switching in \u00c5\n\n Returns\n -------\n float\n weighting of the features\n \"\"\"\n if r <= (cutoff - width):\n return 1.0\n elif r >= cutoff:\n return 0.0\n else:\n s = np.pi * (r - cutoff + width) / width\n return 0.5 * (1.0 + np.cos(s))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us plot the weighting for different widths.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "r = np.linspace(1e-3, 4.5, num=100)\n\nplt.plot([0, 4.5, 4.5, 5.0], [1, 1, 0, 0], c=\"k\", label=r\"Step function\")\n\nfor width in [4.5, 2.5, 1.0, 0.5, 0.1]:\n weighting_values = [shifted_cosine(r=r_i, cutoff=4.5, width=width) for r_i in r]\n plt.plot(r, weighting_values, label=f\"Shifted cosine: $width={width}\\\\,\u00c5$\")\n\nplt.legend()\nplt.xlabel(r\"distance $r$ from the central atom in $\u00c5$\")\nplt.ylabel(\"feature weighting\")\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From the plot we conclude that a larger ``width`` of the shifted cosine\nfunction will decrease the feature values already for smaller distances ``r``\nfrom the central atom.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Choosing the ``radial_scaling``\n\nAs mentioned above all atoms within the cutoff are taken equally for a\ndescriptor. This might limit the accuracy of a model, so it is sometimes\nuseful to weigh neighbors that further away from the central atom less than\nneighbors closer to the central atom. This can be achieved by a\n``radial_scaling`` function with a long-range algebraic decay and smooth\nbehavior at $r \\rightarrow 0$. The ``'Willatt2018'`` radial scaling\navailable in rascaline corresponds to the function introduced in this\n[publication](https://doi.org/10.1039/C8CP05921G):\n\n\\begin{align}u(r) = \\begin{cases}\n 1 / (r/r_0)^m & \\text{if c=0,} \\\\\n 1 & \\text{if m=0,} \\\\\n c / (c+(r/r_0)^m) & \\text{else},\n \\end{cases}\\end{align}\n\nwhere $c$ is the ``rate``, $r_0$ is the ``scale`` parameter and\n$m$ the ``exponent`` of the RadialScaling function.\n\nThe following functions compute such a radial scaling.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def radial_scaling(r, rate, scale, exponent):\n \"\"\"Radial scaling function.\n\n Parameters\n ----------\n r : float\n distance between neighboring atoms in \u00c5\n rate : float\n decay rate of the scaling\n scale : float\n scaling of the distance between atoms in \u00c5\n exponent : float\n exponent of the decay\n\n Returns\n -------\n float\n weighting of the features\n \"\"\"\n if rate == 0:\n return 1 / (r / scale) ** exponent\n if exponent == 0:\n return 1\n else:\n return rate / (rate + (r / scale) ** exponent)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the following we show three different radial scaling functions, where the\nfirst one uses the parameters we use for the calculation of features in the\n`first tutorial `.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "r = np.linspace(1e-3, 4.5, num=100)\n\nplt.axvline(4.5, c=\"k\", ls=\"--\", label=\"cutoff\")\n\nradial_scaling_params = {\"scale\": 2.0, \"rate\": 1.0, \"exponent\": 4}\nplt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params)\n\nradial_scaling_params = {\"scale\": 2.0, \"rate\": 3.0, \"exponent\": 6}\nplt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params)\n\nradial_scaling_params = {\"scale\": 2.0, \"rate\": 0.8, \"exponent\": 2}\nplt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params)\n\nplt.legend()\nplt.xlabel(r\"distance $r$ from the central atom in $\u00c5$\")\nplt.ylabel(\"feature weighting\")\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the end the total weight is the product of ``cutoff_function`` and the\n``radial_scaling``\n\n.. math:\n\n rs(r) = sc(r) \\cdot u(r)\n\nThe shape of this function should be a \"S\" like but the optimal shape depends\non each dataset.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def feature_scaling(r, cutoff, width, rate, scale, exponent):\n \"\"\"Features Scaling factor using cosine shifting and radial scaling.\n\n Parameters\n ----------\n r : float\n distance between neighboring atoms\n cutoff : float\n cutoff distance in \u00c5\n width : float\n width of the decay in \u00c5\n rate : float\n decay rate of the scaling\n scale : float\n scaling of the distance between atoms in \u00c5\n exponent : float\n exponent of the decay\n\n Returns\n -------\n float\n weighting of the features\n \"\"\"\n s = radial_scaling(r, rate, scale, exponent)\n s *= np.array([shifted_cosine(ri, cutoff, width) for ri in r])\n return s\n\n\nr = np.linspace(1e-3, 4.5, num=100)\n\nplt.axvline(4.5, c=\"k\", ls=\"--\", label=r\"$r_\\mathrm{cut}$\")\n\nradial_scaling_params = {}\nplt.plot(\n r,\n feature_scaling(r, scale=2.0, rate=4.0, exponent=6, cutoff=4.5, width=0.5),\n label=\"feature weighting function\",\n)\n\nplt.legend()\nplt.xlabel(r\"distance $r$ from the central atom $[\u00c5]$\")\nplt.ylabel(\"feature weighting\")\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally we see how the magnitude of the features further away from the central\natom reduces when we apply both a ``shifted_cosine`` and a ``radial_scaling``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "calculator_step = SphericalExpansion(\n cutoff=4.5,\n max_radial=6,\n max_angular=6,\n atomic_gaussian_width=0.3,\n center_atom_weight=1.0,\n radial_basis={\"Gto\": {\"spline_accuracy\": 1e-6}},\n cutoff_function={\"Step\": {}},\n)\n\ndescriptor_step = calculator_step.compute(frame0)\nprint(f\"Step cutoff: {str(descriptor_step.block(0).values[0]):>97}\")\n\ncalculator_cosine = SphericalExpansion(\n cutoff=4.5,\n max_radial=6,\n max_angular=6,\n atomic_gaussian_width=0.3,\n center_atom_weight=1.0,\n radial_basis={\"Gto\": {\"spline_accuracy\": 1e-6}},\n cutoff_function={\"ShiftedCosine\": {\"width\": 0.5}},\n)\n\ndescriptor_cosine = calculator_cosine.compute(frame0)\nprint(f\"Cosine smoothing: {str(descriptor_cosine.block(0).values[0]):>92}\")\n\ncalculator_rs = SphericalExpansion(\n cutoff=4.5,\n max_radial=6,\n max_angular=6,\n atomic_gaussian_width=0.3,\n center_atom_weight=1.0,\n radial_basis={\"Gto\": {\"spline_accuracy\": 1e-6}},\n cutoff_function={\"ShiftedCosine\": {\"width\": 0.5}},\n radial_scaling={\"Willatt2018\": {\"scale\": 2.0, \"rate\": 1.0, \"exponent\": 4}},\n)\n\ndescriptor_rs = calculator_rs.compute(frame0)\n\nprint(f\"cosine smoothing + radial scaling: {str(descriptor_rs.block(0).values[0]):>50}\")" + ] + } + ], + "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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/157269325187c1e5cc5b17bff969fe70/profiling.py b/latest/_downloads/157269325187c1e5cc5b17bff969fe70/profiling.py new file mode 100644 index 000000000..4ef411047 --- /dev/null +++ b/latest/_downloads/157269325187c1e5cc5b17bff969fe70/profiling.py @@ -0,0 +1,63 @@ +""" +Profiling calculation +===================== + +.. start-body +""" + +import chemfiles + +import rascaline +from rascaline import SoapPowerSpectrum + + +def compute_soap(path): + """Compute SOAP power spectrum. + + This is the same code as the 'compute-soap' example + """ + with chemfiles.Trajectory(path) as trajectory: + frames = [f for f in trajectory] + + HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, + } + + calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + descriptor = calculator.compute(frames, gradients=["positions"]) + descriptor = descriptor.keys_to_samples("center_type") + descriptor = descriptor.keys_to_properties(["neighbor_1_type", "neighbor_2_type"]) + + return descriptor + + +# %% +# +# Run the calculation with profiling enabled. + +with rascaline.Profiler() as profiler: + descriptor = compute_soap("dataset.xyz") +# %% +# +# Display the recorded profiling data as table. + +print(profiler.as_short_table()) + +# %% +# +# You can also save this data as json for future usage +print(profiler.as_json()) + +# %% +# +# .. end-body diff --git a/latest/_downloads/1dcd7388f9219fe5f08cc17fa4fa2d0d/property-selection.py b/latest/_downloads/1dcd7388f9219fe5f08cc17fa4fa2d0d/property-selection.py new file mode 100644 index 000000000..7160afaa7 --- /dev/null +++ b/latest/_downloads/1dcd7388f9219fe5f08cc17fa4fa2d0d/property-selection.py @@ -0,0 +1,166 @@ +""" +Property Selection +================== + +.. start-body +""" + +import chemfiles +import numpy as np +from metatensor import Labels, MetatensorError, TensorBlock, TensorMap +from skmatter.feature_selection import FPS + +from rascaline import SoapPowerSpectrum + + +# %% +# +# First we load the dataset with chemfiles + +with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [f for f in trajectory] + +# %% +# +# and define the hyper parameters of the representation + +HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, +} + +calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + +descriptor = calculator.compute(frames) + +# %% +# +# The selections for feature can be a set of ``Labels``, in which case the names +# of the labels must be a subset of the names of the properties produced by the +# calculator. You can see the default set of names with: + +print("property names:", descriptor.property_names) + +# %% +# +# We can use a subset of these names to define a selection. In this case, only +# properties matching the labels in this selection will be used by rascaline +# (here, only properties with ``l = 0`` will be used) + +selection = Labels( + names=["l"], + values=np.array([[0]]), +) +selected_descriptor = calculator.compute(frames, selected_properties=selection) + +selected_descriptor = selected_descriptor.keys_to_samples("center_type") +selected_descriptor = selected_descriptor.keys_to_properties( + ["neighbor_1_type", "neighbor_2_type"] +) + +properties = selected_descriptor.block().properties + +# %% +# +# We expect to get `[0]` as the list of `l` properties + +print(f"we have the following angular components: {np.unique(properties['l'])}") + +# %% +# +# The previous selection method uses the same selection for all blocks. If you +# can to use different selection for different blocks, you should use a +# ``TensorMap`` to create your selection + +selected_descriptor = calculator.compute(frames, selected_properties=selection) +descriptor_for_comparison = calculator.compute( + frames, selected_properties=selected_descriptor +) + +# %% +# +# The descriptor had 180 properties stored in the first block, the +# selected_descriptor had 36. So ``descriptor_for_comparison`` will also have 36 +# properties. +print("shape of first block initially:", descriptor.block(0).values.shape) +print("shape of first block of reference:", selected_descriptor.block(0).values.shape) +print( + "shape of first block after selection:", + descriptor_for_comparison.block(0).values.shape, +) + +# %% +# +# The ``TensorMap`` format allows us to select different features within each +# block, and then construct a general matrix of features. We can select the most +# significant features using FPS, which selects features based on the distance +# between them. The following code snippet selects the 10 most important +# features in each block, then constructs a TensorMap containing this selection, +# and calculates the final matrix of features for it. + + +def fps_feature_selection(descriptor, n_to_select): + """ + Select ``n_to_select`` features block by block in the ``descriptor``, using + Farthest Point Sampling to do the selection; and return a ``TensorMap`` with + the right structure to be used as properties selection with rascaline calculators + """ + blocks = [] + for block in descriptor: + # create a separate FPS selector for each block + fps = FPS(n_to_select=n_to_select) + mask = fps.fit(block.values).get_support() + selected_properties = Labels( + names=block.properties.names, + values=block.properties.values[mask], + ) + # The only important data here is the properties, so we create empty + # sets of samples and components. + blocks.append( + TensorBlock( + values=np.empty((1, len(selected_properties))), + samples=Labels.single(), + components=[], + properties=selected_properties, + ) + ) + + return TensorMap(descriptor.keys, blocks) + + +# %% +# +# We can then apply this function to subselect according to the data contained +# in a descriptor + +selection = fps_feature_selection(descriptor, n_to_select=10) + +# %% +# +# and use the selection with rascaline, potentially running the calculation on a +# different set of systems + +selected_descriptor = calculator.compute(frames, selected_properties=selection) + +# %% +# +# Note that in this case it is no longer possible to have a single feature +# matrix, because each block will have its own properties. + +try: + selected_descriptor.keys_to_samples("center_type") +except MetatensorError as err: + print(err) + +# %% +# +# .. end-body diff --git a/latest/_downloads/1ea175a310000e5e69ad132e5fc4c813/understanding-hypers.py b/latest/_downloads/1ea175a310000e5e69ad132e5fc4c813/understanding-hypers.py new file mode 100644 index 000000000..24f0a0ccf --- /dev/null +++ b/latest/_downloads/1ea175a310000e5e69ad132e5fc4c813/understanding-hypers.py @@ -0,0 +1,418 @@ +""" +.. _userdoc-tutorials-understanding-hypers: + +Changing SOAP hyper parameters +============================== + +In the first :ref:`tutorial ` we show how to +calculate a descriptor using default hyper parameters. Here we will look at how the +change of some hyper parameters affects the values of the descriptor. The +definition of every hyper parameter is given in the :ref:`userdoc-calculators` and +background on the mathematical foundation of the spherical expansion is given in +the :ref:`userdoc-explanations` section. +""" + +# %% +# +# We use the same molecular crystals dataset as in the first +# :ref:`tutorial ` which can downloaded from our +# :download:`website <../../static/dataset.xyz>`. + +# We first import the crucial packages, load the dataset using chemfiles and +# save the first frame in a variable. + +import time + +import chemfiles +import matplotlib.pyplot as plt +import numpy as np + +from rascaline import SphericalExpansion + + +with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [frame for frame in trajectory] + +frame0 = frames[0] + +# %% +# +# Increasing ``max_radial`` and ``max_angular`` +# --------------------------------------------- +# +# As mentioned above changing ``max_radial`` has an effect on the accuracy of +# the descriptor and on the computation time. We now will increase the number of +# radial channels and angular channels. Note, that here we directly pass the +# parameters into the ``SphericalExpansion`` class without defining a +# ``HYPERPARAMETERS`` dictionary like we did in the previous tutorial. + +calculator_ext = SphericalExpansion( + cutoff=4.5, + max_radial=12, + max_angular=8, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, +) + +descriptor_ext = calculator_ext.compute(frame0) + +# %% +# +# Compared to our previous set of hypers we now have 144 blocks instead of 112 +# because we increased the number of angular channels. + +print(len(descriptor_ext.blocks())) + +# %% +# +# The increase of the radial channels to 12 is reflected in the shape of the 0th +# block values. + +print(descriptor_ext.block(0).values.shape) + +# %% +# +# Note that the increased number of radial and angular channels can increase the +# accuracy of your representation but will increase the computational time +# transforming the coordinates into a descriptor. A very simple time measurement +# of the computation shows that the extended calculator takes more time for +# the computation compared to a calculation using the default hyper parameters + +start_time = time.time() +calculator_ext.compute(frames) +print(f"Extended hypers took {time.time() - start_time:.2f} s.") + +# using smaller max_radial and max_angular, everything else stays the same +calculator_small = SphericalExpansion( + cutoff=4.5, + max_radial=9, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, +) + +start_time = time.time() +calculator_small.compute(frames) +print(f"Smaller hypers took {time.time() - start_time:.2f} s.") + +# %% +# +# Reducing the ``cutoff`` and the ``center_atom_weight`` +# ------------------------------------------------------ +# +# The cutoff controls how many neighboring atoms are taken into account for a +# descriptor. By decreasing the cutoff from 6 Å to 0.1 Å fewer and fewer atoms +# contribute to the descriptor which can be seen by the reduced range of the +# features. + +for cutoff in [6.0, 4.5, 3.0, 1.0, 0.1]: + calculator_cutoff = SphericalExpansion( + cutoff=cutoff, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, + ) + + descriptor = calculator_cutoff.compute(frame0) + + print(f"Descriptor for cutoff={cutoff} Å: {descriptor.block(0).values[0]}") + +# %% +# +# For a ``cutoff`` of 0.1 Å there is no neighboring atom within the cutoff and +# one could expect all features to be 0. This is not the case because the +# central atom also contributes to the descriptor. We can vary this contribution +# using the ``center_atom_weight`` parameter so that the descriptor finally is 0 +# everywhere. +# +# ..Add a sophisticated and referenced note on how the ``center_atom_weight`` +# could affect ML models. + +for center_weight in [1.0, 0.5, 0.0]: + calculator_cutoff = SphericalExpansion( + cutoff=0.1, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=center_weight, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, + ) + + descriptor = calculator_cutoff.compute(frame0) + + print( + f"Descriptor for center_weight={center_weight}: " + f"{descriptor.block(0).values[0]}" + ) + +# %% +# +# Choosing the ``cutoff_function`` +# -------------------------------- +# +# In a naive descriptor approach all atoms within the cutoff are taken in into +# account equally and atoms without the cutoff are ignored. This behavior is +# implemented using the ``cutoff_function={"Step": {}}`` parameter in each +# calculator. However, doing so means that small movements of an atom near the +# cutoff result in large changes in the descriptor: there is a discontinuity in +# the representation as atoms enter or leave the cutoff. A solution is to use +# some smoothing function to get rid of this discontinuity, such as a shifted +# cosine function: +# +# .. math:: +# +# f(r) = \begin{cases} +# 1 &r < r_c - w,\\ +# 0.5 + 0.5 \cos[\pi (r - r_c + w) / w] &r_c - w < r <= r_c, \\ +# 0 &r_c < r, +# \end{cases} +# +# where :math:`r_\mathrm{c}` is the cutoff distance and :math:`w` the width. +# Such smoothing function is used as a multiplicative weight for the +# contribution to the representation coming from each neighbor one by one +# +# The following functions compute such a shifted cosine weighting. + + +def shifted_cosine(r, cutoff, width): + """A shifted cosine switching function. + + Parameters + ---------- + r : float + distance between neighboring atoms in Å + cutoff : float + cutoff distance in Å + width : float + width of the switching in Å + + Returns + ------- + float + weighting of the features + """ + if r <= (cutoff - width): + return 1.0 + elif r >= cutoff: + return 0.0 + else: + s = np.pi * (r - cutoff + width) / width + return 0.5 * (1.0 + np.cos(s)) + + +# %% +# +# Let us plot the weighting for different widths. + +r = np.linspace(1e-3, 4.5, num=100) + +plt.plot([0, 4.5, 4.5, 5.0], [1, 1, 0, 0], c="k", label=r"Step function") + +for width in [4.5, 2.5, 1.0, 0.5, 0.1]: + weighting_values = [shifted_cosine(r=r_i, cutoff=4.5, width=width) for r_i in r] + plt.plot(r, weighting_values, label=f"Shifted cosine: $width={width}\\,Å$") + +plt.legend() +plt.xlabel(r"distance $r$ from the central atom in $Å$") +plt.ylabel("feature weighting") +plt.show() + +# %% +# +# From the plot we conclude that a larger ``width`` of the shifted cosine +# function will decrease the feature values already for smaller distances ``r`` +# from the central atom. + +# %% +# +# Choosing the ``radial_scaling`` +# ------------------------------- +# +# As mentioned above all atoms within the cutoff are taken equally for a +# descriptor. This might limit the accuracy of a model, so it is sometimes +# useful to weigh neighbors that further away from the central atom less than +# neighbors closer to the central atom. This can be achieved by a +# ``radial_scaling`` function with a long-range algebraic decay and smooth +# behavior at :math:`r \rightarrow 0`. The ``'Willatt2018'`` radial scaling +# available in rascaline corresponds to the function introduced in this +# `publication `_: +# +# .. math:: +# +# u(r) = \begin{cases} +# 1 / (r/r_0)^m & \text{if c=0,} \\ +# 1 & \text{if m=0,} \\ +# c / (c+(r/r_0)^m) & \text{else}, +# \end{cases} +# +# where :math:`c` is the ``rate``, :math:`r_0` is the ``scale`` parameter and +# :math:`m` the ``exponent`` of the RadialScaling function. +# +# The following functions compute such a radial scaling. + + +def radial_scaling(r, rate, scale, exponent): + """Radial scaling function. + + Parameters + ---------- + r : float + distance between neighboring atoms in Å + rate : float + decay rate of the scaling + scale : float + scaling of the distance between atoms in Å + exponent : float + exponent of the decay + + Returns + ------- + float + weighting of the features + """ + if rate == 0: + return 1 / (r / scale) ** exponent + if exponent == 0: + return 1 + else: + return rate / (rate + (r / scale) ** exponent) + + +# %% +# +# In the following we show three different radial scaling functions, where the +# first one uses the parameters we use for the calculation of features in the +# :ref:`first tutorial `. + +r = np.linspace(1e-3, 4.5, num=100) + +plt.axvline(4.5, c="k", ls="--", label="cutoff") + +radial_scaling_params = {"scale": 2.0, "rate": 1.0, "exponent": 4} +plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + +radial_scaling_params = {"scale": 2.0, "rate": 3.0, "exponent": 6} +plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + +radial_scaling_params = {"scale": 2.0, "rate": 0.8, "exponent": 2} +plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + +plt.legend() +plt.xlabel(r"distance $r$ from the central atom in $Å$") +plt.ylabel("feature weighting") +plt.show() + +# %% +# +# In the end the total weight is the product of ``cutoff_function`` and the +# ``radial_scaling`` +# +# .. math: +# +# rs(r) = sc(r) \cdot u(r) +# +# The shape of this function should be a "S" like but the optimal shape depends +# on each dataset. + + +def feature_scaling(r, cutoff, width, rate, scale, exponent): + """Features Scaling factor using cosine shifting and radial scaling. + + Parameters + ---------- + r : float + distance between neighboring atoms + cutoff : float + cutoff distance in Å + width : float + width of the decay in Å + rate : float + decay rate of the scaling + scale : float + scaling of the distance between atoms in Å + exponent : float + exponent of the decay + + Returns + ------- + float + weighting of the features + """ + s = radial_scaling(r, rate, scale, exponent) + s *= np.array([shifted_cosine(ri, cutoff, width) for ri in r]) + return s + + +r = np.linspace(1e-3, 4.5, num=100) + +plt.axvline(4.5, c="k", ls="--", label=r"$r_\mathrm{cut}$") + +radial_scaling_params = {} +plt.plot( + r, + feature_scaling(r, scale=2.0, rate=4.0, exponent=6, cutoff=4.5, width=0.5), + label="feature weighting function", +) + +plt.legend() +plt.xlabel(r"distance $r$ from the central atom $[Å]$") +plt.ylabel("feature weighting") +plt.show() + +# %% +# +# Finally we see how the magnitude of the features further away from the central +# atom reduces when we apply both a ``shifted_cosine`` and a ``radial_scaling``. + +calculator_step = SphericalExpansion( + cutoff=4.5, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"Step": {}}, +) + +descriptor_step = calculator_step.compute(frame0) +print(f"Step cutoff: {str(descriptor_step.block(0).values[0]):>97}") + +calculator_cosine = SphericalExpansion( + cutoff=4.5, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, +) + +descriptor_cosine = calculator_cosine.compute(frame0) +print(f"Cosine smoothing: {str(descriptor_cosine.block(0).values[0]):>92}") + +calculator_rs = SphericalExpansion( + cutoff=4.5, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, +) + +descriptor_rs = calculator_rs.compute(frame0) + +print(f"cosine smoothing + radial scaling: {str(descriptor_rs.block(0).values[0]):>50}") diff --git a/latest/_downloads/1fca5afa28681412baa1843c260225ba/sample-selection.py b/latest/_downloads/1fca5afa28681412baa1843c260225ba/sample-selection.py new file mode 100644 index 000000000..471d4370f --- /dev/null +++ b/latest/_downloads/1fca5afa28681412baa1843c260225ba/sample-selection.py @@ -0,0 +1,140 @@ +""" +Sample Selection +================ + +.. start-body +""" + +import chemfiles +import numpy as np +from metatensor import Labels + +from rascaline import SoapPowerSpectrum + + +# %% +# +# First we load the dataset with chemfiles + +with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [f for f in trajectory] + +# %% +# +# and define the hyper parameters of the representation + +HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, +} + +calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + +descriptor = calculator.compute(frames) + +# %% +# +# The selections for sample can be a set of ``Labels``, in which case the names +# of the labels must be a subset of the names of the samples produced by the +# calculator. You can see the default set of names with: + +print("sample names:", descriptor.sample_names) + +# %% +# +# We can use a subset of these names to define a selection. In this case, only +# samples matching the labels in this selection will be used by rascaline (here, +# only atoms from system 0, 2, and 3) + +selection = Labels( + names=["system"], + values=np.array([[0], [2], [3]]), +) + +descriptor_selected = calculator.compute(frames, selected_samples=selection) + +descriptor_selected = descriptor_selected.keys_to_samples("center_type") +descriptor_selected = descriptor_selected.keys_to_properties( + ["neighbor_1_type", "neighbor_2_type"] +) + +samples = descriptor_selected.block().samples + +# %% +# +# The first block should have ``[0, 2, 3]`` as ``samples["system"]`` + +print(f"we have the following systems: {np.unique(samples['system'])}") + +# %% +# +# If we want to select not only based on the system indexes but also atomic +# indexes, we can do the following (here we select atom 0 in the first system +# and atom 1 in the third system): + +selection = Labels( + names=["system", "atom"], + values=np.array([[0, 0], [2, 1]]), +) + +descriptor_selected = calculator.compute(frames, selected_samples=selection) +descriptor_selected = descriptor_selected.keys_to_samples("center_type") +descriptor_selected = descriptor_selected.keys_to_properties( + ["neighbor_1_type", "neighbor_2_type"] +) + +# %% +# +# The values will have 2 rows, since we have two samples: + +print( + "shape of first block of descriptor:", + descriptor_selected.block(0).values.shape, +) + +# %% +# +# The previous selection method uses the same selection for all blocks. If you +# can to use different selection for different blocks, you should use a +# `TensorMap` to create your selection + +descriptor = calculator.compute(frames) +descriptor_selected = calculator.compute(frames, selected_samples=selection) + +# %% +# +# notice how we are passing a TensorMap as the ``selected_samples`` argument: + +print(type(descriptor_selected)) +descriptor_for_comparison = calculator.compute( + frames, selected_samples=descriptor_selected +) + +# %% +# +# The descriptor had 420 samples stored in the first block, +# the ``descriptor_selected`` had 0. So ``descriptor_for_comparison`` +# will also have 0 samples. + +print("shape of first block initially:", descriptor.block(0).values.shape) +print( + "shape of first block of reference:", + descriptor_selected.block(0).values.shape, +) +print( + "shape of first block after selection:", + descriptor_for_comparison.block(0).values.shape, +) + +# %% +# +# .. end-body diff --git a/latest/_downloads/2ec60c786c8a5f204193e244b399a9a4/profiling.zip b/latest/_downloads/2ec60c786c8a5f204193e244b399a9a4/profiling.zip new file mode 100644 index 000000000..e7931057b Binary files /dev/null and b/latest/_downloads/2ec60c786c8a5f204193e244b399a9a4/profiling.zip differ diff --git a/latest/_downloads/33cbf89244c381c85dfb98b83889ff69/first-calculation.ipynb b/latest/_downloads/33cbf89244c381c85dfb98b83889ff69/first-calculation.ipynb new file mode 100644 index 000000000..5c2472137 --- /dev/null +++ b/latest/_downloads/33cbf89244c381c85dfb98b83889ff69/first-calculation.ipynb @@ -0,0 +1,399 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n\n# First descriptor computation\n\nThis is an introduction to the rascaline interface using a molecular crystals\ndataset using the Python interface. If you are interested in another\nprogramming language we recommend you first follow this tutorial and afterward\ntake a look at the how-to guide on `userdoc-how-to-computing-soap`.\n\n## The dataset\n\nThe atomic configurations used in our documentation are a small subset of the\n[ShiftML2 dataset](https://pubs.acs.org/doi/pdf/10.1021/acs.jpcc.2c03854)\ncontaining molecular crystals. There are four crystals - one with each of the\nelements [hydrogen, carbon], [hydrogen, carbon, nitrogen, oxygen], [hydrogen,\ncarbon, nitrogen], or [hydrogen, carbon, oxygen]. Each crystal has 10 structures,\nalso denoted by frames, attributed to it. The first frame of each crystal structure\nis the geometry-optimized frame. The following 9 frames contain atoms that are\nslightly displaced from the geometry-optimized frame. You can obtain the dataset\nfrom our :download:`website <../../static/dataset.xyz>`.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will start by importing all the required packages: the classic numpy;\nchemfiles to load data, and rascaline to compute representations. Afterward\nwe will load the dataset using chemfiles.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import chemfiles\nimport numpy as np\n\nfrom rascaline import SphericalExpansion\n\n\nwith chemfiles.Trajectory(\"dataset.xyz\") as trajectory:\n frames = [f for f in trajectory]\n\nprint(f\"The dataset contains {len(frames)} frames.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will not explain here how to use chemfiles in detail, as we only use a few\nfunctions. Briefly, :class:`chemfiles.Trajectory` loads structure data in a\nformat rascaline can use. If you want to learn more about the possibilities\ntake a look at the [chemfiles documentation](https://chemfiles.org).\n\nLet us now take a look at the first frame of the dataset.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "frame0 = frames[0]\n\nprint(frame0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With ``frame0.atoms`` we get a list of the atoms that make up frame zero.\nThe ``name`` attribute gives us the name of the specified atom.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "elements, counts = np.unique([atom.name for atom in frame0.atoms], return_counts=True)\n\nprint(\n f\"The first frame contains \"\n f\"{counts[0]} {elements[0]}-atoms, \"\n f\"{counts[1]} {elements[1]}-atoms, \"\n f\"{counts[2]} {elements[2]}-atoms and \"\n f\"{counts[3]} {elements[3]}-atoms.\"\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Calculate a descriptor\n\nWe will now calculate an atomic descriptor for this structure using the SOAP\nspherical expansion as introduced by [Bart\u00f3k, Kondor, and Cs\u00e1nyi](http://dx.doi.org/10.1103/PhysRevB.87.184115).\n\nTo do so we define below a set of parameters telling rascaline how the\nspherical expansion should be calculated. These parameters are also called\nhyper parameters since they are parameters of the representation, in\nopposition to parameters of machine learning models. Hyper parameters are a\ncrucial part of calculating descriptors. Poorly selected hyper parameters will\nlead to a poor description of your dataset as discussed in the [literature](https://arxiv.org/abs/1502.02127). The effect of changing some hyper\nparameters is discussed in a `second tutorial\n`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "HYPER_PARAMETERS = {\n \"cutoff\": 4.5,\n \"max_radial\": 9,\n \"max_angular\": 6,\n \"atomic_gaussian_width\": 0.3,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\"Gto\": {\"spline_accuracy\": 1e-6}},\n \"cutoff_function\": {\"ShiftedCosine\": {\"width\": 0.5}},\n \"radial_scaling\": {\"Willatt2018\": {\"scale\": 2.0, \"rate\": 1.0, \"exponent\": 4}},\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After we set the hyper parameters we initialize a\n:class:`rascaline.calculators.SphericalExpansion` object with hyper parameters\ndefined above and run the\n:py:func:`rascaline.calculators.CalculatorBase.compute()` method.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "calculator = SphericalExpansion(**HYPER_PARAMETERS)\ndescriptor0 = calculator.compute(frame0)\nprint(type(descriptor0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The descriptor format is a :class:`metatensor.TensorMap` object. Metatensor is\nlike numpy for storing representations of atomistic ML data. Extensive details\non the metatensor are covered in the [corresponding documentation](https://lab-cosmo.github.io/metatensor/).\n\nWe will now have a look at how the data is stored inside\n:class:`metatensor.TensorMap` objects.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(descriptor0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The :class:`metatensor.TensorMap` is structured in several instances of an\n:class:`metatensor.TensorBlock`. To distinguish the block each block is associated\nwith a unique key. For the current example, we have one block for each angular channel\nlabeled by ``o3_lambda``, the central atom type ``center_type`` and\nneighbor atom type labeled by ``neighbor_type``. Different atomic types are\nrepresented using their atomic number, e.g. 1 for hydrogen, 6 for carbon, etc. To\nsummarize, this descriptor contains 112 blocks covering all combinations of the\nangular channels of the central and neighbor atom types in our dataset.\n\nLet us take a look at the second block (at index 1) in detail. This block contains the\ndescriptor for the $l=1$ angular channel for hydrogen-hydrogen pairs.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "block = descriptor0.block(1)\nprint(descriptor0.keys[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The descriptor values\n\nThe values of the representation are stored as an array. Each entry in this\narray also has associated unique metadata as each block. For the spherical\nexpansion calculator used in this tutorial the values have three dimensions\nwhich we can verify from the ``.shape`` attribute.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(block.values.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The descriptor values\n\nThe first dimension is denoted by the `samples`, the intermediate dimension by\n`components`, and the last dimension by `properties`. The \"sample dimension\"\nhas a length of eight because we have eight hydrogen atoms in the first frame.\nWe can reveal more detailed metadata information about the sample-dimension\nprinting of the :py:attr:`metatensor.TensorBlock.samples` attribute of the\nblock\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(block.samples)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The result is an :class:`metatensor.TensorMap` instance. It contains in total\neight tuples each with two values. The tuple values are named as follows\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(block.samples.names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Meaning that the first entry of each tuple indicates the _structure_, which is\n0 for all because we only computed the representation of a single frame. The\nsecond entry of each tuple refers to the index of the _center_ atom.\n\nWe can do a similar investigation for the second dimension: the\n:py:attr:`metatensor.TensorBlock.components`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(block.components)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, the components are associated with the angular channels of the\nrepresentation. The size of ``o3_mu`` is $2l + 1$, where\n$l$ is the current ``o3_lambda`` of the block. Here, its\ndimension is three because we are looking at the ``o3_lambda=1``\nblock. You may have noticed that the return value of the last call is a\n:class:`list` of :class:`metatensor.Labels` and not a single ``Labels``\ninstance. The reason is that a block can have several component dimensions as\nwe will see below for the gradients.\n\nThe last value represents the number of radial channels. For the\n:py:attr:`metatensor.TensorBlock.properties` dimension we find an object\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(block.properties)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "containing a tuple of only one value ranging from 0 to 8. The name of this entry is\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(block.properties.names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and denoting the radial channels. The range results from our choice of\n``max_radial = 9`` in the hyper parameters above.\n\nAfter looking at the metadata we can investigate the actual data of the\nrepresentation in more details\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(block.values[0, 0, :])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By using ``[0, 0, :]`` we selected the first hydrogen and the first ``m``\nchannel. As you the output shows the values are floating point numbers between\n``-1.0`` and ``1.0``. Values in this range are reasonable and can be directly\nused as input for a machine learning algorithm.\n\nRascaline is also able to process more than one structure within one function\ncall. You can process a whole dataset with\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "descriptor_full = calculator.compute(frames)\n\nblock_full = descriptor_full.block(0)\nprint(block_full.values.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, the 0th block of the :class:`metatensor.TensorMap` contains not eight but\n420 entries in the first dimensions. This reflects the fact that in total we\nhave 420 hydrogen atoms in the whole dataset.\n\nIf you want to use another calculator instead of\n:class:`rascaline.calculators.SphericalExpansion` shown here check out the\n`userdoc-references` section.\n\n## Computing gradients\n\nAdditionally, rascaline is also able to calculate gradients on top of the\nvalues. Gradients are useful for constructing an ML potential and running\nsimulations. For example ``gradients`` of the representation with respect to\natomic positions can be calculated by setting the ``gradients`` parameter of\nthe :py:func:`rascaline.calculators.CalculatorBase.compute()` method to\n``[\"positions\"]``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "descriptor_gradients = calculator.compute(frame0, gradients=[\"positions\"])\n\nblock_gradients = descriptor_gradients.block(0)\ngradient_position = block_gradients.gradient(\"positions\")\n\nprint(gradient_position.values.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The calculated descriptor contains the values and in each block the associated\nposition gradients as an :class:`metatensor.block.Gradient` instance. The\nactual values are stored in the ``data`` attribute. Similar to the features\nthe gradient data also has associated metadata. But, compared to the values\nwere we found three dimensions, and gradients have four. Again the first is\ncalled `samples` and the `properties`. The dimensions between the sample and\nproperty dimensions are denoted by `components`.\n\nLooking at the shape in more detail we find that we have 52 samples, which is\nmuch more compared to features where we only have eight samples. This arises\nfrom the fact that we calculate the position gradient for each pair in the\nstructure. For our selected block these are all hydrogen-hydrogen pairs.\nNaively one would come up with ``8 * 8 = 64`` samples, but rascaline already\nignores pairs that are outside of the cutoff radius. Their position gradient\nis always zero. The :attr:`metatensor.block.Gradient.samples` attribute shows\nthis in detail.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(gradient_position.samples)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that we have a tuple of three with the names\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(gradient_position.samples.names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above output of the Labels instance for example the `(2, 0, 17)` entry\nis missing indicating that this pair is outside of the cutoff.\n\nNow looking at the :attr:`metatensor.block.Gradient.components`\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(gradient_position.components)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we find two of them. Besides the `o3_mu` component that is also present in the\nfeatures position gradients also have a component indicating the direction of the\ngradient vector.\n\nFinally, the :attr:`metatensor.block.Gradient.properties` dimension is the same as for\nthe values\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(gradient_position.properties)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Rascaline can also calculate gradients with respect to the strain (i.e. the virial).\nFor this, you have to add ``\"strain\"`` to the list parsed to the ``gradients``\nparameter of the :py:func:`rascaline.calculators.CalculatorBase.compute()` method.\nStrain gradients/virial are useful when computing the stress and the pressure.\n\nIf you want to know about the effect of changing hypers take a look at the next\ntutorial. If you want to solve an explicit problem our `userdoc-how-to` might\nhelp you.\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/36d886e596f0b08a8c0e4ccbd309a891/long-range-descriptor.py b/latest/_downloads/36d886e596f0b08a8c0e4ccbd309a891/long-range-descriptor.py new file mode 100644 index 000000000..8bac8dae2 --- /dev/null +++ b/latest/_downloads/36d886e596f0b08a8c0e4ccbd309a891/long-range-descriptor.py @@ -0,0 +1,438 @@ +""" +.. _userdoc-tutorials-long-range-descriptor: + +Long-range only LODE descriptor +=============================== + +.. start-body + +We start the example by loading the required packages +""" + +# %% + +import ase +import ase.visualize.plot +import matplotlib.pyplot as plt +import numpy as np +from ase.build import molecule +from metatensor import LabelsEntry, TensorMap + +from rascaline import LodeSphericalExpansion, SphericalExpansion +from rascaline.utils import ( + GaussianDensity, + LodeDensity, + LodeSpliner, + MonomialBasis, + SoapSpliner, +) + + +# %% +# +# **Single water molecule (short range) system** +# +# Our first test system is a single water molecule with a :math:`15\,\mathrm{Å}` vacuum +# layer around it. + + +atoms = molecule("H2O", vacuum=15, pbc=True) + +# %% +# We choose a ``cutoff`` for the projection of the spherical expansion and the neighbor +# search of the real space spherical expansion. + +cutoff = 3 + +# %% +# We can use ase's visualization tools to plot the system and draw a gray circle to +# indicate the ``cutoff`` radius. + +fig, ax = plt.subplots() + +ase.visualize.plot.plot_atoms(atoms) + +cutoff_circle = plt.Circle( + xy=atoms[0].position[:2], + radius=cutoff, + color="gray", + ls="dashed", + fill=False, +) +ax.add_patch(cutoff_circle) + +ax.set_xlabel("Å") +ax.set_ylabel("Å") + +fig.show() + + +# %% +# +# As you can see, for a single water molecule, the ``cutoff`` includes all atoms of the +# system. The combination of the test system and the ``cutoff`` aims to demonstrate that +# the full atomic fingerprint is contained within the ``cutoff``. By later subtracting +# the short-range density from the LODE density, we will observe that the difference +# between them is almost zero, indicating that a single water molecule is a short-range +# system. +# +# To start this construction we choose a high potential exponent to emulate the rapidly +# decaying LODE density and mimic the polar-polar interactions of water. + + +potential_exponent = 3 + + +# %% +# We now define some typical hyperparameters to compute the spherical expansions. + +max_radial = 5 +max_angular = 1 +atomic_gaussian_width = 1.2 +center_atom_weight = 1.0 + + +# %% +# We choose a relatively low spline accuracy (default is ``1e-8``) to achieve quick +# computation of the spline points. You can increase the spline accuracy if required, +# but be aware that the time to compute these points will increase significantly! + + +spline_accuracy = 1e-2 + + +# %% +# As a projection basis, we don't use the usual :py:class:`GtoBasis +# ` which is commonly used for short range descriptors. +# Instead, we select the :py:class:`MonomialBasis ` which +# is the optimal radial basis for the LODE descriptor as discussed in `Huguenin-Dumittan +# et al. `_ + + +basis = MonomialBasis(cutoff=cutoff) + + +# %% +# For the density, we choose a smeared power law as used in LODE, which does not decay +# exponentially like a :py:class:`Gaussian density ` +# and is therefore suited to describe long-range interactions between atoms. + + +density = LodeDensity( + atomic_gaussian_width=atomic_gaussian_width, + potential_exponent=potential_exponent, +) + + +# %% +# To visualize this we plot ``density`` together with a Gaussian density +# (``gaussian_density``) with the same ``atomic_gaussian_width`` in a log-log plot. + +radial_positions = np.geomspace(1e-5, 10, num=1000) +gaussian_density = GaussianDensity(atomic_gaussian_width=atomic_gaussian_width) + +plt.plot(radial_positions, density.compute(radial_positions), label="LodeDensity") +plt.plot( + radial_positions, + gaussian_density.compute(radial_positions), + label="GaussianDensity", +) + + +positions_indicator = np.array([3.0, 8.0]) +plt.plot( + positions_indicator, + 2 * positions_indicator**-potential_exponent, + c="k", + label=f"p={potential_exponent}", +) + +plt.legend() + +plt.xlim(1e-1, 10) +plt.ylim(1e-3, 5e-1) + +plt.xlabel("radial positions / Å") +plt.ylabel("atomic density") + +plt.xscale("log") +plt.yscale("log") + +# %% +# We see that the ``LodeDensity`` decays with a power law of 3, which is the potential +# exponent we picked above, wile the :py:class:`Gaussian density +# ` decays exponentially and is therefore not suited +# for long-range descriptors. +# +# We now have all building blocks to construct the spline points for the real and +# Fourier space spherical expansions. + + +real_space_splines = SoapSpliner( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + basis=basis, + density=density, + accuracy=spline_accuracy, +).compute() + + +# This value gives good convergences for the Fourier space version +k_cutoff = 1.2 * np.pi / atomic_gaussian_width + +fourier_space_splines = LodeSpliner( + k_cutoff=k_cutoff, + max_radial=max_radial, + max_angular=max_angular, + basis=basis, + density=density, + accuracy=spline_accuracy, +).compute() + + +# %% +# .. note:: +# You might want to save the spline points using :py:func:`json.dump` to a file and +# load them with :py:func:`json.load` later without recalculating them. Saving them is +# especially useful if the spline calculations are expensive, i.e., if you increase +# the ``spline_accuracy``. +# +# With the spline points ready, we now compute the real space spherical expansion + + +real_space_calculator = SphericalExpansion( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + atomic_gaussian_width=atomic_gaussian_width, + radial_basis=real_space_splines, + center_atom_weight=center_atom_weight, + cutoff_function={"Step": {}}, + radial_scaling=None, +) + +real_space_expansion = real_space_calculator.compute(atoms) + + +# %% +# where we don't use a smoothing ``cutoff_function`` or a ``radial_scaling`` to ensure +# the correct construction of the long-range only descriptor. Next, we compute the +# Fourier Space / LODE spherical expansion + + +fourier_space_calculator = LodeSphericalExpansion( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + atomic_gaussian_width=atomic_gaussian_width, + center_atom_weight=center_atom_weight, + potential_exponent=potential_exponent, + radial_basis=fourier_space_splines, + k_cutoff=k_cutoff, +) + +fourier_space_expansion = fourier_space_calculator.compute(atoms) + +# %% +# As described in the beginning, we now subtract the real space LODE contributions from +# Fourier space to obtain a descriptor that only contains the contributions from atoms +# outside of the ``cutoff``. + + +subtracted_expansion = fourier_space_expansion - real_space_expansion + + +# %% You can now use the ``subtracted_expansion`` as a long-range descriptor in +# combination with a short-range descriptor like +# :py:class:`rascaline.SphericalExpansion` for your machine learning models. We now +# verify that for our test ``atoms`` the LODE spherical expansion only contains +# short-range contributions. To demonstrate this, we densify the +# :py:class:`metatensor.TensorMap` to have only one block per ``"center_type"`` and +# visualize our result. Since we have to perform the densify operation several times in +# thi show-to, we define a helper function ``densify_tensormap``. + + +def densify_tensormap(tensor: TensorMap) -> TensorMap: + dense_tensor = tensor.components_to_properties("o3_mu") + dense_tensor = dense_tensor.keys_to_samples("neighbor_type") + dense_tensor = dense_tensor.keys_to_properties(["o3_lambda", "o3_sigma"]) + + return dense_tensor + + +# %% +# We apply the function to the Fourier space spherical expansion +# ``fourier_space_expansion`` and ``subtracted_expansion``. + + +fourier_space_expansion = densify_tensormap(fourier_space_expansion) +subtracted_expansion = densify_tensormap(subtracted_expansion) + + +# %% +# Finally, we plot the values of each block for the Fourier Space spherical expansion in +# the upper panel and the difference between the Fourier Space and the real space in the +# lower panel. And since we will do this plot several times we again define a small plot +# function to help us + + +def plot_value_comparison( + key: LabelsEntry, + fourier_space_expansion: TensorMap, + subtracted_expansion: TensorMap, +): + fig, ax = plt.subplots(2, layout="tight") + + values_subtracted = subtracted_expansion[key].values + values_fourier_space = fourier_space_expansion[key].values + + ax[0].set_title(f"center_type={key.values[0]}\n Fourier space sph. expansion") + im = ax[0].matshow(values_fourier_space, vmin=-0.25, vmax=0.5) + ax[0].set_ylabel("sample index") + + ax[1].set_title("Difference between Fourier and real space sph. expansion") + ax[1].matshow(values_subtracted, vmin=-0.25, vmax=0.5) + ax[1].set_ylabel("sample index") + ax[1].set_xlabel("property index") + + fig.colorbar(im, ax=ax[0], orientation="horizontal", fraction=0.1, label="values") + + +# %% +# We first plot the values of the TensorMaps for center_type=1 (hydrogen) + +plot_value_comparison( + fourier_space_expansion.keys[0], fourier_space_expansion, subtracted_expansion +) + +# %% +# and for center_type=8 (oxygen) + +plot_value_comparison( + fourier_space_expansion.keys[1], fourier_space_expansion, subtracted_expansion +) + + +# %% +# The plot shows that the spherical expansion for the Fourier space is non-zero while +# the difference between the two expansions is very small. +# +# .. warning:: +# Small residual values may stems from the contribution of the periodic images. You +# can verify and reduce those contributions by either increasing the cell and/or +# increase the ``potential_exponent``. +# +# **Two water molecule (long range) system** +# +# We now add a second water molecule shifted by :math:`3\,\mathrm{Å}` in each direction +# from our first water molecule to show that such a system has non negliable long range +# effects. + + +atoms_shifted = molecule("H2O", vacuum=10, pbc=True) +atoms_shifted.positions = atoms.positions + 3 + +atoms_long_range = atoms + atoms_shifted + + +fig, ax = plt.subplots() + +ase.visualize.plot.plot_atoms(atoms_long_range, ax=ax) + +cutoff_circle = plt.Circle( + xy=atoms[0].position[1:], + radius=cutoff, + color="gray", + ls="dashed", + fill=False, +) + +cutoff_circle_shifted = plt.Circle( + xy=atoms_shifted[0].position[1:], + radius=cutoff, + color="gray", + ls="dashed", + fill=False, +) + +ax.add_patch(cutoff_circle) +ax.add_patch(cutoff_circle_shifted) + +ax.set_xlabel("Å") +ax.set_ylabel("Å") + +fig.show() + + +# %% +# As you can see, the ``cutoff`` radii of the two molecules are completely disjoint. +# Therefore, a short-range model will not able to describe the intermolecular +# interactions between our two molecules. To verify we now again create a long-range +# only descriptor for this system. We use the already defined +# ``real_space_expansion_long_range`` and ``fourier_space_expansion_long_range`` + + +real_space_expansion_long_range = real_space_calculator.compute(atoms_long_range) +fourier_space_expansion_long_range = fourier_space_calculator.compute(atoms_long_range) + +# %% +# We now firdt verify that the contribution from the short-range descriptors is the same +# as for a single water molecule. Exemplarily, we compare only the first (Hydrogen) +# block of each tensor. + + +print("Single water real space spherical expansion") +print(np.round(real_space_expansion[1].values, 3)) + +print("\nTwo water real space spherical expansion") +print(np.round(real_space_expansion_long_range[1].values, 3)) + +# %% +# Since the values of the block are the same, we can conclude that there is no +# information shared between the two molecules and that the short-range descriptor is +# not able to distinguish the system with only one or two water molecules. Note that the +# different number of `samples` in ``real_space_expansion_long_range`` reflects the fact +# that the second system has more atoms then the first. +# +# As above, we construct a long-range only descriptor and densify the result for +# plotting the values. + + +subtracted_expansion_long_range = ( + fourier_space_expansion_long_range - real_space_expansion_long_range +) + +fourier_space_expansion_long_range = densify_tensormap( + fourier_space_expansion_long_range +) +subtracted_expansion_long_range = densify_tensormap(subtracted_expansion_long_range) + + +# %% +# As above, we plot the values of the spherical expansions for the Fourier and the +# subtracted (long range only) spherical expansion. First for hydrogen +# (``center_species=1``) + +plot_value_comparison( + fourier_space_expansion_long_range.keys[0], + fourier_space_expansion_long_range, + subtracted_expansion_long_range, +) + +# %% +# amd second for oxygen (``center_species=8``) + +plot_value_comparison( + fourier_space_expansion_long_range.keys[1], + fourier_space_expansion_long_range, + subtracted_expansion_long_range, +) + + +# %% +# We clearly see that the values of the subtracted spherical are much larger compared to +# the system with only a single water molecule, thus confirming the presence of +# long-range contributions in the descriptor for a system with two water molecules. +# +# .. end-body diff --git a/latest/_downloads/42f2842f9cfabd51c881bcbd574c2b08/splined-radial-integral.ipynb b/latest/_downloads/42f2842f9cfabd51c881bcbd574c2b08/splined-radial-integral.ipynb new file mode 100644 index 000000000..c5a935c2c --- /dev/null +++ b/latest/_downloads/42f2842f9cfabd51c881bcbd574c2b08/splined-radial-integral.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Splined radial integrals\n\n.. start-body\n\nThis example illustrates how to generate splined radial basis functions/integrals, using\na \"rectangular\" Laplacian eigenstate (LE) basis (https://doi.org/10.1063/5.0124363) as\nthe example, i.e, a LE basis truncated with ``l_max``, ``n_max`` hyper-parameters.\n\nNote that the same basis is also directly available through\n:class:`rascaline.utils.SphericalBesselBasis` with an how-to guide given in\n`userdoc-how-to-le-basis`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import ase\nimport numpy as np\nimport scipy as sp\nfrom scipy.special import spherical_jn as j_l\n\nfrom rascaline import SphericalExpansion\nfrom rascaline.utils import RadialIntegralFromFunction, SphericalBesselBasis" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set some hyper-parameters\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "max_angular = 6\nmax_radial = 8\ncutoff = 5.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "where ``cutoff`` is also the radius of the LE sphere. Now we compute the zeros of the\nspherical bessel functions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "z_ln = SphericalBesselBasis.compute_zeros(max_angular, max_radial)\nz_nl = z_ln.T" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and define the radial basis functions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def R_nl(n, el, r):\n # Un-normalized LE radial basis functions\n return j_l(el, z_nl[n, el] * r / cutoff)\n\n\ndef N_nl(n, el):\n # Normalization factor for LE basis functions, excluding the a**(-1.5) factor\n def function_to_integrate_to_get_normalization_factor(x):\n return j_l(el, x) ** 2 * x**2\n\n integral, _ = sp.integrate.quadrature(\n function_to_integrate_to_get_normalization_factor, 0.0, z_nl[n, el]\n )\n return (1.0 / z_nl[n, el] ** 3 * integral) ** (-0.5)\n\n\ndef laplacian_eigenstate_basis(n, el, r):\n R = np.zeros_like(r)\n for i in range(r.shape[0]):\n R[i] = R_nl(n, el, r[i])\n return N_nl(n, el) * R * cutoff ** (-1.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Quick normalization check:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "normalization_check_integral, _ = sp.integrate.quadrature(\n lambda x: laplacian_eigenstate_basis(1, 1, x) ** 2 * x**2,\n 0.0,\n cutoff,\n)\nprint(f\"Normalization check (needs to be close to 1): {normalization_check_integral}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now the derivatives (by finite differences):\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def laplacian_eigenstate_basis_derivative(n, el, r):\n delta = 1e-6\n all_derivatives_except_at_zero = (\n laplacian_eigenstate_basis(n, el, r[1:] + delta)\n - laplacian_eigenstate_basis(n, el, r[1:] - delta)\n ) / (2.0 * delta)\n derivative_at_zero = (\n laplacian_eigenstate_basis(n, el, np.array([delta / 10.0]))\n - laplacian_eigenstate_basis(n, el, np.array([0.0]))\n ) / (delta / 10.0)\n return np.concatenate([derivative_at_zero, all_derivatives_except_at_zero])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The radial basis functions and their derivatives can be input into a spline generator\nclass. This will output the positions of the spline points, the values of the basis\nfunctions evaluated at the spline points, and the corresponding derivatives.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "spliner = RadialIntegralFromFunction(\n radial_integral=laplacian_eigenstate_basis,\n radial_integral_derivative=laplacian_eigenstate_basis_derivative,\n spline_cutoff=cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n accuracy=1e-5,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The, we feed the splines to the Rust calculator: Note that the\n``atomic_gaussian_width`` will be ignored since we are not uisng a Gaussian basis.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "hypers_spherical_expansion = {\n \"cutoff\": cutoff,\n \"max_radial\": max_radial,\n \"max_angular\": max_angular,\n \"center_atom_weight\": 0.0,\n \"radial_basis\": spliner.compute(),\n \"atomic_gaussian_width\": 1.0, # ignored\n \"cutoff_function\": {\"Step\": {}},\n}\ncalculator = SphericalExpansion(**hypers_spherical_expansion)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create dummy systems to test if the calculator outputs correct radial functions:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def get_dummy_systems(r_array):\n dummy_systems = []\n for r in r_array:\n dummy_systems.append(ase.Atoms(\"CH\", positions=[(0, 0, 0), (0, 0, r)]))\n return dummy_systems\n\n\nr = np.linspace(0.1, 4.9, 20)\nsystems = get_dummy_systems(r)\nspherical_expansion_coefficients = calculator.compute(systems)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Extract ``l = 0`` features and check that the ``n = 2`` predictions are the same:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "block_C_l0 = spherical_expansion_coefficients.block(\n center_type=6, o3_lambda=0, neighbor_type=1\n)\nblock_C_l0_n2 = block_C_l0.values[:, :, 2].flatten()\nspherical_harmonics_0 = 1.0 / np.sqrt(4.0 * np.pi)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "radial function = feature / spherical harmonics function\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "rascaline_output_radial_function = block_C_l0_n2 / spherical_harmonics_0\n\nassert np.allclose(\n rascaline_output_radial_function,\n laplacian_eigenstate_basis(2, 0, r),\n atol=1e-5,\n)\nprint(\"Assertion passed successfully!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ".. end-body\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/491be9e03568f919353d2c473a1b8769/compute-soap.zip b/latest/_downloads/491be9e03568f919353d2c473a1b8769/compute-soap.zip new file mode 100644 index 000000000..3e0151aaa Binary files /dev/null and b/latest/_downloads/491be9e03568f919353d2c473a1b8769/compute-soap.zip differ diff --git a/latest/_downloads/52d185a9d75bdcffe38b2bef27c7b982/long-range-descriptor.ipynb b/latest/_downloads/52d185a9d75bdcffe38b2bef27c7b982/long-range-descriptor.ipynb new file mode 100644 index 000000000..be2a7f792 --- /dev/null +++ b/latest/_downloads/52d185a9d75bdcffe38b2bef27c7b982/long-range-descriptor.ipynb @@ -0,0 +1,482 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n\n# Long-range only LODE descriptor\n\n.. start-body\n\nWe start the example by loading the required packages\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import ase\nimport ase.visualize.plot\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom ase.build import molecule\nfrom metatensor import LabelsEntry, TensorMap\n\nfrom rascaline import LodeSphericalExpansion, SphericalExpansion\nfrom rascaline.utils import (\n GaussianDensity,\n LodeDensity,\n LodeSpliner,\n MonomialBasis,\n SoapSpliner,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Single water molecule (short range) system**\n\nOur first test system is a single water molecule with a $15\\,\\mathrm{\u00c5}$ vacuum\nlayer around it.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "atoms = molecule(\"H2O\", vacuum=15, pbc=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We choose a ``cutoff`` for the projection of the spherical expansion and the neighbor\nsearch of the real space spherical expansion.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cutoff = 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use ase's visualization tools to plot the system and draw a gray circle to\nindicate the ``cutoff`` radius.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n\nase.visualize.plot.plot_atoms(atoms)\n\ncutoff_circle = plt.Circle(\n xy=atoms[0].position[:2],\n radius=cutoff,\n color=\"gray\",\n ls=\"dashed\",\n fill=False,\n)\nax.add_patch(cutoff_circle)\n\nax.set_xlabel(\"\u00c5\")\nax.set_ylabel(\"\u00c5\")\n\nfig.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see, for a single water molecule, the ``cutoff`` includes all atoms of the\nsystem. The combination of the test system and the ``cutoff`` aims to demonstrate that\nthe full atomic fingerprint is contained within the ``cutoff``. By later subtracting\nthe short-range density from the LODE density, we will observe that the difference\nbetween them is almost zero, indicating that a single water molecule is a short-range\nsystem.\n\nTo start this construction we choose a high potential exponent to emulate the rapidly\ndecaying LODE density and mimic the polar-polar interactions of water.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "potential_exponent = 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now define some typical hyperparameters to compute the spherical expansions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "max_radial = 5\nmax_angular = 1\natomic_gaussian_width = 1.2\ncenter_atom_weight = 1.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We choose a relatively low spline accuracy (default is ``1e-8``) to achieve quick\ncomputation of the spline points. You can increase the spline accuracy if required,\nbut be aware that the time to compute these points will increase significantly!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "spline_accuracy = 1e-2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As a projection basis, we don't use the usual :py:class:`GtoBasis\n` which is commonly used for short range descriptors.\nInstead, we select the :py:class:`MonomialBasis ` which\nis the optimal radial basis for the LODE descriptor as discussed in [Huguenin-Dumittan\net al.](https://doi.org/10.1021/acs.jpclett.3c02375)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "basis = MonomialBasis(cutoff=cutoff)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the density, we choose a smeared power law as used in LODE, which does not decay\nexponentially like a :py:class:`Gaussian density `\nand is therefore suited to describe long-range interactions between atoms.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "density = LodeDensity(\n atomic_gaussian_width=atomic_gaussian_width,\n potential_exponent=potential_exponent,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To visualize this we plot ``density`` together with a Gaussian density\n(``gaussian_density``) with the same ``atomic_gaussian_width`` in a log-log plot.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "radial_positions = np.geomspace(1e-5, 10, num=1000)\ngaussian_density = GaussianDensity(atomic_gaussian_width=atomic_gaussian_width)\n\nplt.plot(radial_positions, density.compute(radial_positions), label=\"LodeDensity\")\nplt.plot(\n radial_positions,\n gaussian_density.compute(radial_positions),\n label=\"GaussianDensity\",\n)\n\n\npositions_indicator = np.array([3.0, 8.0])\nplt.plot(\n positions_indicator,\n 2 * positions_indicator**-potential_exponent,\n c=\"k\",\n label=f\"p={potential_exponent}\",\n)\n\nplt.legend()\n\nplt.xlim(1e-1, 10)\nplt.ylim(1e-3, 5e-1)\n\nplt.xlabel(\"radial positions / \u00c5\")\nplt.ylabel(\"atomic density\")\n\nplt.xscale(\"log\")\nplt.yscale(\"log\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that the ``LodeDensity`` decays with a power law of 3, which is the potential\nexponent we picked above, wile the :py:class:`Gaussian density\n` decays exponentially and is therefore not suited\nfor long-range descriptors.\n\nWe now have all building blocks to construct the spline points for the real and\nFourier space spherical expansions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "real_space_splines = SoapSpliner(\n cutoff=cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n basis=basis,\n density=density,\n accuracy=spline_accuracy,\n).compute()\n\n\n# This value gives good convergences for the Fourier space version\nk_cutoff = 1.2 * np.pi / atomic_gaussian_width\n\nfourier_space_splines = LodeSpliner(\n k_cutoff=k_cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n basis=basis,\n density=density,\n accuracy=spline_accuracy,\n).compute()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Note

You might want to save the spline points using :py:func:`json.dump` to a file and\n load them with :py:func:`json.load` later without recalculating them. Saving them is\n especially useful if the spline calculations are expensive, i.e., if you increase\n the ``spline_accuracy``.

\n\nWith the spline points ready, we now compute the real space spherical expansion\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "real_space_calculator = SphericalExpansion(\n cutoff=cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n atomic_gaussian_width=atomic_gaussian_width,\n radial_basis=real_space_splines,\n center_atom_weight=center_atom_weight,\n cutoff_function={\"Step\": {}},\n radial_scaling=None,\n)\n\nreal_space_expansion = real_space_calculator.compute(atoms)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "where we don't use a smoothing ``cutoff_function`` or a ``radial_scaling`` to ensure\nthe correct construction of the long-range only descriptor. Next, we compute the\nFourier Space / LODE spherical expansion\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fourier_space_calculator = LodeSphericalExpansion(\n cutoff=cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n atomic_gaussian_width=atomic_gaussian_width,\n center_atom_weight=center_atom_weight,\n potential_exponent=potential_exponent,\n radial_basis=fourier_space_splines,\n k_cutoff=k_cutoff,\n)\n\nfourier_space_expansion = fourier_space_calculator.compute(atoms)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As described in the beginning, we now subtract the real space LODE contributions from\nFourier space to obtain a descriptor that only contains the contributions from atoms\noutside of the ``cutoff``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "subtracted_expansion = fourier_space_expansion - real_space_expansion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "combination with a short-range descriptor like\n:py:class:`rascaline.SphericalExpansion` for your machine learning models. We now\nverify that for our test ``atoms`` the LODE spherical expansion only contains\nshort-range contributions. To demonstrate this, we densify the\n:py:class:`metatensor.TensorMap` to have only one block per ``\"center_type\"`` and\nvisualize our result. Since we have to perform the densify operation several times in\nthi show-to, we define a helper function ``densify_tensormap``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def densify_tensormap(tensor: TensorMap) -> TensorMap:\n dense_tensor = tensor.components_to_properties(\"o3_mu\")\n dense_tensor = dense_tensor.keys_to_samples(\"neighbor_type\")\n dense_tensor = dense_tensor.keys_to_properties([\"o3_lambda\", \"o3_sigma\"])\n\n return dense_tensor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We apply the function to the Fourier space spherical expansion\n``fourier_space_expansion`` and ``subtracted_expansion``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fourier_space_expansion = densify_tensormap(fourier_space_expansion)\nsubtracted_expansion = densify_tensormap(subtracted_expansion)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we plot the values of each block for the Fourier Space spherical expansion in\nthe upper panel and the difference between the Fourier Space and the real space in the\nlower panel. And since we will do this plot several times we again define a small plot\nfunction to help us\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def plot_value_comparison(\n key: LabelsEntry,\n fourier_space_expansion: TensorMap,\n subtracted_expansion: TensorMap,\n):\n fig, ax = plt.subplots(2, layout=\"tight\")\n\n values_subtracted = subtracted_expansion[key].values\n values_fourier_space = fourier_space_expansion[key].values\n\n ax[0].set_title(f\"center_type={key.values[0]}\\n Fourier space sph. expansion\")\n im = ax[0].matshow(values_fourier_space, vmin=-0.25, vmax=0.5)\n ax[0].set_ylabel(\"sample index\")\n\n ax[1].set_title(\"Difference between Fourier and real space sph. expansion\")\n ax[1].matshow(values_subtracted, vmin=-0.25, vmax=0.5)\n ax[1].set_ylabel(\"sample index\")\n ax[1].set_xlabel(\"property index\")\n\n fig.colorbar(im, ax=ax[0], orientation=\"horizontal\", fraction=0.1, label=\"values\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We first plot the values of the TensorMaps for center_type=1 (hydrogen)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plot_value_comparison(\n fourier_space_expansion.keys[0], fourier_space_expansion, subtracted_expansion\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and for center_type=8 (oxygen)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plot_value_comparison(\n fourier_space_expansion.keys[1], fourier_space_expansion, subtracted_expansion\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The plot shows that the spherical expansion for the Fourier space is non-zero while\nthe difference between the two expansions is very small.\n\n

Warning

Small residual values may stems from the contribution of the periodic images. You\n can verify and reduce those contributions by either increasing the cell and/or\n increase the ``potential_exponent``.

\n\n**Two water molecule (long range) system**\n\nWe now add a second water molecule shifted by $3\\,\\mathrm{\u00c5}$ in each direction\nfrom our first water molecule to show that such a system has non negliable long range\neffects.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "atoms_shifted = molecule(\"H2O\", vacuum=10, pbc=True)\natoms_shifted.positions = atoms.positions + 3\n\natoms_long_range = atoms + atoms_shifted\n\n\nfig, ax = plt.subplots()\n\nase.visualize.plot.plot_atoms(atoms_long_range, ax=ax)\n\ncutoff_circle = plt.Circle(\n xy=atoms[0].position[1:],\n radius=cutoff,\n color=\"gray\",\n ls=\"dashed\",\n fill=False,\n)\n\ncutoff_circle_shifted = plt.Circle(\n xy=atoms_shifted[0].position[1:],\n radius=cutoff,\n color=\"gray\",\n ls=\"dashed\",\n fill=False,\n)\n\nax.add_patch(cutoff_circle)\nax.add_patch(cutoff_circle_shifted)\n\nax.set_xlabel(\"\u00c5\")\nax.set_ylabel(\"\u00c5\")\n\nfig.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see, the ``cutoff`` radii of the two molecules are completely disjoint.\nTherefore, a short-range model will not able to describe the intermolecular\ninteractions between our two molecules. To verify we now again create a long-range\nonly descriptor for this system. We use the already defined\n``real_space_expansion_long_range`` and ``fourier_space_expansion_long_range``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "real_space_expansion_long_range = real_space_calculator.compute(atoms_long_range)\nfourier_space_expansion_long_range = fourier_space_calculator.compute(atoms_long_range)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now firdt verify that the contribution from the short-range descriptors is the same\nas for a single water molecule. Exemplarily, we compare only the first (Hydrogen)\nblock of each tensor.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"Single water real space spherical expansion\")\nprint(np.round(real_space_expansion[1].values, 3))\n\nprint(\"\\nTwo water real space spherical expansion\")\nprint(np.round(real_space_expansion_long_range[1].values, 3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since the values of the block are the same, we can conclude that there is no\ninformation shared between the two molecules and that the short-range descriptor is\nnot able to distinguish the system with only one or two water molecules. Note that the\ndifferent number of `samples` in ``real_space_expansion_long_range`` reflects the fact\nthat the second system has more atoms then the first.\n\nAs above, we construct a long-range only descriptor and densify the result for\nplotting the values.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "subtracted_expansion_long_range = (\n fourier_space_expansion_long_range - real_space_expansion_long_range\n)\n\nfourier_space_expansion_long_range = densify_tensormap(\n fourier_space_expansion_long_range\n)\nsubtracted_expansion_long_range = densify_tensormap(subtracted_expansion_long_range)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As above, we plot the values of the spherical expansions for the Fourier and the\nsubtracted (long range only) spherical expansion. First for hydrogen\n(``center_species=1``)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plot_value_comparison(\n fourier_space_expansion_long_range.keys[0],\n fourier_space_expansion_long_range,\n subtracted_expansion_long_range,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "amd second for oxygen (``center_species=8``)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plot_value_comparison(\n fourier_space_expansion_long_range.keys[1],\n fourier_space_expansion_long_range,\n subtracted_expansion_long_range,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We clearly see that the values of the subtracted spherical are much larger compared to\nthe system with only a single water molecule, thus confirming the presence of\nlong-range contributions in the descriptor for a system with two water molecules.\n\n.. end-body\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/536e92230d631426c3c8630f4db8a141/first-calculation.py b/latest/_downloads/536e92230d631426c3c8630f4db8a141/first-calculation.py new file mode 100644 index 000000000..d55cbb3a6 --- /dev/null +++ b/latest/_downloads/536e92230d631426c3c8630f4db8a141/first-calculation.py @@ -0,0 +1,318 @@ +""" +.. _userdoc-tutorials-get-started: + +First descriptor computation +============================ + +This is an introduction to the rascaline interface using a molecular crystals +dataset using the Python interface. If you are interested in another +programming language we recommend you first follow this tutorial and afterward +take a look at the how-to guide on :ref:`userdoc-how-to-computing-soap`. + +The dataset +----------- + +The atomic configurations used in our documentation are a small subset of the +`ShiftML2 dataset `_ +containing molecular crystals. There are four crystals - one with each of the +elements [hydrogen, carbon], [hydrogen, carbon, nitrogen, oxygen], [hydrogen, +carbon, nitrogen], or [hydrogen, carbon, oxygen]. Each crystal has 10 structures, +also denoted by frames, attributed to it. The first frame of each crystal structure +is the geometry-optimized frame. The following 9 frames contain atoms that are +slightly displaced from the geometry-optimized frame. You can obtain the dataset +from our :download:`website <../../static/dataset.xyz>`. +""" + +# %% +# +# We will start by importing all the required packages: the classic numpy; +# chemfiles to load data, and rascaline to compute representations. Afterward +# we will load the dataset using chemfiles. + +import chemfiles +import numpy as np + +from rascaline import SphericalExpansion + + +with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [f for f in trajectory] + +print(f"The dataset contains {len(frames)} frames.") + +# %% +# +# We will not explain here how to use chemfiles in detail, as we only use a few +# functions. Briefly, :class:`chemfiles.Trajectory` loads structure data in a +# format rascaline can use. If you want to learn more about the possibilities +# take a look at the `chemfiles documentation `_. +# +# Let us now take a look at the first frame of the dataset. + +frame0 = frames[0] + +print(frame0) + +# %% +# +# With ``frame0.atoms`` we get a list of the atoms that make up frame zero. +# The ``name`` attribute gives us the name of the specified atom. + +elements, counts = np.unique([atom.name for atom in frame0.atoms], return_counts=True) + +print( + f"The first frame contains " + f"{counts[0]} {elements[0]}-atoms, " + f"{counts[1]} {elements[1]}-atoms, " + f"{counts[2]} {elements[2]}-atoms and " + f"{counts[3]} {elements[3]}-atoms." +) + +# %% +# +# Calculate a descriptor +# ---------------------- +# +# We will now calculate an atomic descriptor for this structure using the SOAP +# spherical expansion as introduced by `Bartók, Kondor, and Csányi +# `_. +# +# To do so we define below a set of parameters telling rascaline how the +# spherical expansion should be calculated. These parameters are also called +# hyper parameters since they are parameters of the representation, in +# opposition to parameters of machine learning models. Hyper parameters are a +# crucial part of calculating descriptors. Poorly selected hyper parameters will +# lead to a poor description of your dataset as discussed in the `literature +# `_. The effect of changing some hyper +# parameters is discussed in a :ref:`second tutorial +# `. + +HYPER_PARAMETERS = { + "cutoff": 4.5, + "max_radial": 9, + "max_angular": 6, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {"spline_accuracy": 1e-6}}, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + "radial_scaling": {"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, +} + +# %% +# +# After we set the hyper parameters we initialize a +# :class:`rascaline.calculators.SphericalExpansion` object with hyper parameters +# defined above and run the +# :py:func:`rascaline.calculators.CalculatorBase.compute()` method. + +calculator = SphericalExpansion(**HYPER_PARAMETERS) +descriptor0 = calculator.compute(frame0) +print(type(descriptor0)) + +# %% +# +# The descriptor format is a :class:`metatensor.TensorMap` object. Metatensor is +# like numpy for storing representations of atomistic ML data. Extensive details +# on the metatensor are covered in the `corresponding documentation +# `_. +# +# We will now have a look at how the data is stored inside +# :class:`metatensor.TensorMap` objects. + + +print(descriptor0) + +# %% +# +# The :class:`metatensor.TensorMap` is structured in several instances of an +# :class:`metatensor.TensorBlock`. To distinguish the block each block is associated +# with a unique key. For the current example, we have one block for each angular channel +# labeled by ``o3_lambda``, the central atom type ``center_type`` and +# neighbor atom type labeled by ``neighbor_type``. Different atomic types are +# represented using their atomic number, e.g. 1 for hydrogen, 6 for carbon, etc. To +# summarize, this descriptor contains 112 blocks covering all combinations of the +# angular channels of the central and neighbor atom types in our dataset. +# +# Let us take a look at the second block (at index 1) in detail. This block contains the +# descriptor for the :math:`l=1` angular channel for hydrogen-hydrogen pairs. + +block = descriptor0.block(1) +print(descriptor0.keys[1]) + + +# %% +# +# The descriptor values +# --------------------- +# +# The values of the representation are stored as an array. Each entry in this +# array also has associated unique metadata as each block. For the spherical +# expansion calculator used in this tutorial the values have three dimensions +# which we can verify from the ``.shape`` attribute. + + +print(block.values.shape) + +# %% +# +# The descriptor values +# --------------------- +# +# The first dimension is denoted by the `samples`, the intermediate dimension by +# `components`, and the last dimension by `properties`. The "sample dimension" +# has a length of eight because we have eight hydrogen atoms in the first frame. +# We can reveal more detailed metadata information about the sample-dimension +# printing of the :py:attr:`metatensor.TensorBlock.samples` attribute of the +# block + +print(block.samples) + +# %% +# +# The result is an :class:`metatensor.TensorMap` instance. It contains in total +# eight tuples each with two values. The tuple values are named as follows + +print(block.samples.names) + +# %% +# +# Meaning that the first entry of each tuple indicates the _structure_, which is +# 0 for all because we only computed the representation of a single frame. The +# second entry of each tuple refers to the index of the _center_ atom. +# +# We can do a similar investigation for the second dimension: the +# :py:attr:`metatensor.TensorBlock.components`. + +print(block.components) + +# %% +# +# Here, the components are associated with the angular channels of the +# representation. The size of ``o3_mu`` is :math:`2l + 1`, where +# :math:`l` is the current ``o3_lambda`` of the block. Here, its +# dimension is three because we are looking at the ``o3_lambda=1`` +# block. You may have noticed that the return value of the last call is a +# :class:`list` of :class:`metatensor.Labels` and not a single ``Labels`` +# instance. The reason is that a block can have several component dimensions as +# we will see below for the gradients. +# +# The last value represents the number of radial channels. For the +# :py:attr:`metatensor.TensorBlock.properties` dimension we find an object + +print(block.properties) + +# %% +# +# containing a tuple of only one value ranging from 0 to 8. The name of this entry is + +print(block.properties.names) + +# %% +# +# and denoting the radial channels. The range results from our choice of +# ``max_radial = 9`` in the hyper parameters above. +# +# After looking at the metadata we can investigate the actual data of the +# representation in more details + +print(block.values[0, 0, :]) + +# %% +# +# By using ``[0, 0, :]`` we selected the first hydrogen and the first ``m`` +# channel. As you the output shows the values are floating point numbers between +# ``-1.0`` and ``1.0``. Values in this range are reasonable and can be directly +# used as input for a machine learning algorithm. +# +# Rascaline is also able to process more than one structure within one function +# call. You can process a whole dataset with + +descriptor_full = calculator.compute(frames) + +block_full = descriptor_full.block(0) +print(block_full.values.shape) + +# %% +# +# Now, the 0th block of the :class:`metatensor.TensorMap` contains not eight but +# 420 entries in the first dimensions. This reflects the fact that in total we +# have 420 hydrogen atoms in the whole dataset. +# +# If you want to use another calculator instead of +# :class:`rascaline.calculators.SphericalExpansion` shown here check out the +# :ref:`userdoc-references` section. +# +# Computing gradients +# ------------------- +# +# Additionally, rascaline is also able to calculate gradients on top of the +# values. Gradients are useful for constructing an ML potential and running +# simulations. For example ``gradients`` of the representation with respect to +# atomic positions can be calculated by setting the ``gradients`` parameter of +# the :py:func:`rascaline.calculators.CalculatorBase.compute()` method to +# ``["positions"]``. + +descriptor_gradients = calculator.compute(frame0, gradients=["positions"]) + +block_gradients = descriptor_gradients.block(0) +gradient_position = block_gradients.gradient("positions") + +print(gradient_position.values.shape) + +# %% +# +# The calculated descriptor contains the values and in each block the associated +# position gradients as an :class:`metatensor.block.Gradient` instance. The +# actual values are stored in the ``data`` attribute. Similar to the features +# the gradient data also has associated metadata. But, compared to the values +# were we found three dimensions, and gradients have four. Again the first is +# called `samples` and the `properties`. The dimensions between the sample and +# property dimensions are denoted by `components`. +# +# Looking at the shape in more detail we find that we have 52 samples, which is +# much more compared to features where we only have eight samples. This arises +# from the fact that we calculate the position gradient for each pair in the +# structure. For our selected block these are all hydrogen-hydrogen pairs. +# Naively one would come up with ``8 * 8 = 64`` samples, but rascaline already +# ignores pairs that are outside of the cutoff radius. Their position gradient +# is always zero. The :attr:`metatensor.block.Gradient.samples` attribute shows +# this in detail. + +print(gradient_position.samples) + +# %% +# +# Note that we have a tuple of three with the names + +print(gradient_position.samples.names) + +# %% +# +# In the above output of the Labels instance for example the `(2, 0, 17)` entry +# is missing indicating that this pair is outside of the cutoff. +# +# Now looking at the :attr:`metatensor.block.Gradient.components` + +print(gradient_position.components) + +# %% +# +# we find two of them. Besides the `o3_mu` component that is also present in the +# features position gradients also have a component indicating the direction of the +# gradient vector. +# +# Finally, the :attr:`metatensor.block.Gradient.properties` dimension is the same as for +# the values + +print(gradient_position.properties) + +# %% +# +# Rascaline can also calculate gradients with respect to the strain (i.e. the virial). +# For this, you have to add ``"strain"`` to the list parsed to the ``gradients`` +# parameter of the :py:func:`rascaline.calculators.CalculatorBase.compute()` method. +# Strain gradients/virial are useful when computing the stress and the pressure. +# +# If you want to know about the effect of changing hypers take a look at the next +# tutorial. If you want to solve an explicit problem our :ref:`userdoc-how-to` might +# help you. diff --git a/latest/_downloads/5bc1ea0ad98caa228fc23e8e574adf83/long-range-descriptor.zip b/latest/_downloads/5bc1ea0ad98caa228fc23e8e574adf83/long-range-descriptor.zip new file mode 100644 index 000000000..20b87780d Binary files /dev/null and b/latest/_downloads/5bc1ea0ad98caa228fc23e8e574adf83/long-range-descriptor.zip differ diff --git a/latest/_downloads/5fc41c52f18084e21db68b260d315ac3/sample-selection.ipynb b/latest/_downloads/5fc41c52f18084e21db68b260d315ac3/sample-selection.ipynb new file mode 100644 index 000000000..d0ff25d81 --- /dev/null +++ b/latest/_downloads/5fc41c52f18084e21db68b260d315ac3/sample-selection.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Sample Selection\n\n.. start-body\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import chemfiles\nimport numpy as np\nfrom metatensor import Labels\n\nfrom rascaline import SoapPowerSpectrum" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we load the dataset with chemfiles\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "with chemfiles.Trajectory(\"dataset.xyz\") as trajectory:\n frames = [f for f in trajectory]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and define the hyper parameters of the representation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "HYPER_PARAMETERS = {\n \"cutoff\": 5.0,\n \"max_radial\": 6,\n \"max_angular\": 4,\n \"atomic_gaussian_width\": 0.3,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\n \"Gto\": {},\n },\n \"cutoff_function\": {\n \"ShiftedCosine\": {\"width\": 0.5},\n },\n}\n\ncalculator = SoapPowerSpectrum(**HYPER_PARAMETERS)\n\ndescriptor = calculator.compute(frames)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The selections for sample can be a set of ``Labels``, in which case the names\nof the labels must be a subset of the names of the samples produced by the\ncalculator. You can see the default set of names with:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"sample names:\", descriptor.sample_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use a subset of these names to define a selection. In this case, only\nsamples matching the labels in this selection will be used by rascaline (here,\nonly atoms from system 0, 2, and 3)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selection = Labels(\n names=[\"system\"],\n values=np.array([[0], [2], [3]]),\n)\n\ndescriptor_selected = calculator.compute(frames, selected_samples=selection)\n\ndescriptor_selected = descriptor_selected.keys_to_samples(\"center_type\")\ndescriptor_selected = descriptor_selected.keys_to_properties(\n [\"neighbor_1_type\", \"neighbor_2_type\"]\n)\n\nsamples = descriptor_selected.block().samples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first block should have ``[0, 2, 3]`` as ``samples[\"system\"]``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(f\"we have the following systems: {np.unique(samples['system'])}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we want to select not only based on the system indexes but also atomic\nindexes, we can do the following (here we select atom 0 in the first system\nand atom 1 in the third system):\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selection = Labels(\n names=[\"system\", \"atom\"],\n values=np.array([[0, 0], [2, 1]]),\n)\n\ndescriptor_selected = calculator.compute(frames, selected_samples=selection)\ndescriptor_selected = descriptor_selected.keys_to_samples(\"center_type\")\ndescriptor_selected = descriptor_selected.keys_to_properties(\n [\"neighbor_1_type\", \"neighbor_2_type\"]\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The values will have 2 rows, since we have two samples:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\n \"shape of first block of descriptor:\",\n descriptor_selected.block(0).values.shape,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The previous selection method uses the same selection for all blocks. If you\ncan to use different selection for different blocks, you should use a\n`TensorMap` to create your selection\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "descriptor = calculator.compute(frames)\ndescriptor_selected = calculator.compute(frames, selected_samples=selection)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "notice how we are passing a TensorMap as the ``selected_samples`` argument:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(type(descriptor_selected))\ndescriptor_for_comparison = calculator.compute(\n frames, selected_samples=descriptor_selected\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The descriptor had 420 samples stored in the first block,\nthe ``descriptor_selected`` had 0. So ``descriptor_for_comparison``\nwill also have 0 samples.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"shape of first block initially:\", descriptor.block(0).values.shape)\nprint(\n \"shape of first block of reference:\",\n descriptor_selected.block(0).values.shape,\n)\nprint(\n \"shape of first block after selection:\",\n descriptor_for_comparison.block(0).values.shape,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ".. end-body\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/683cb0f50a57b05d570812adf3a45786/sample-selection.zip b/latest/_downloads/683cb0f50a57b05d570812adf3a45786/sample-selection.zip new file mode 100644 index 000000000..fb06ce9f8 Binary files /dev/null and b/latest/_downloads/683cb0f50a57b05d570812adf3a45786/sample-selection.zip differ diff --git a/latest/_downloads/6f3a7c4259176e65715d2c5a1a386b06/understanding-hypers.zip b/latest/_downloads/6f3a7c4259176e65715d2c5a1a386b06/understanding-hypers.zip new file mode 100644 index 000000000..8cff243cf Binary files /dev/null and b/latest/_downloads/6f3a7c4259176e65715d2c5a1a386b06/understanding-hypers.zip differ diff --git a/latest/_downloads/79a7c08af4248e467d582409b4cc073c/compute-soap.ipynb b/latest/_downloads/79a7c08af4248e467d582409b4cc073c/compute-soap.ipynb new file mode 100644 index 000000000..2fa393a67 --- /dev/null +++ b/latest/_downloads/79a7c08af4248e467d582409b4cc073c/compute-soap.ipynb @@ -0,0 +1,140 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Computing SOAP features\n\n.. start-body\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import chemfiles\n\nfrom rascaline import SoapPowerSpectrum" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Read systems using chemfiles. You can obtain the dataset used in this\nexample from our :download:`website <../../static/dataset.xyz>`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "with chemfiles.Trajectory(\"dataset.xyz\") as trajectory:\n systems = [s for s in trajectory]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Rascaline can also handles systems read by [ASE](https://wiki.fysik.dtu.dk/ase/) using\n\n``systems = ase.io.read(\"dataset.xyz\", \":\")``.\n\nWe can now define hyper parameters for the calculation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "HYPER_PARAMETERS = {\n \"cutoff\": 5.0,\n \"max_radial\": 6,\n \"max_angular\": 4,\n \"atomic_gaussian_width\": 0.3,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\n \"Gto\": {},\n },\n \"cutoff_function\": {\n \"ShiftedCosine\": {\"width\": 0.5},\n },\n}\n\ncalculator = SoapPowerSpectrum(**HYPER_PARAMETERS)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And then run the actual calculation, including gradients with respect to positions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "descriptor = calculator.compute(systems, gradients=[\"positions\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The descriptor is a metatensor ``TensorMap``, containing multiple blocks. We\ncan transform it to a single block containing a dense representation, with one\nsample for each atom-centered environment by using ``keys_to_samples`` and\n``keys_to_properties``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"before: \", len(descriptor.keys))\n\ndescriptor = descriptor.keys_to_samples(\"center_type\")\ndescriptor = descriptor.keys_to_properties([\"neighbor_1_type\", \"neighbor_2_type\"])\nprint(\"after: \", len(descriptor.keys))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "you can now use ``descriptor.block().values`` as the input of a machine\nlearning algorithm\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(descriptor.block().values.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ".. end-body\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/887ab8ab59ae3cbe4ee95bca03afef67/le-basis.zip b/latest/_downloads/887ab8ab59ae3cbe4ee95bca03afef67/le-basis.zip new file mode 100644 index 000000000..92f2eaa14 Binary files /dev/null and b/latest/_downloads/887ab8ab59ae3cbe4ee95bca03afef67/le-basis.zip differ diff --git a/latest/_downloads/94fe16a4bed8662f3e4bf7df34cf7786/first-calculation.zip b/latest/_downloads/94fe16a4bed8662f3e4bf7df34cf7786/first-calculation.zip new file mode 100644 index 000000000..c991c372f Binary files /dev/null and b/latest/_downloads/94fe16a4bed8662f3e4bf7df34cf7786/first-calculation.zip differ diff --git a/latest/_downloads/a61b9667afd1dd08cd2729044cdfcc9a/profiling.ipynb b/latest/_downloads/a61b9667afd1dd08cd2729044cdfcc9a/profiling.ipynb new file mode 100644 index 000000000..ad9b6d3d9 --- /dev/null +++ b/latest/_downloads/a61b9667afd1dd08cd2729044cdfcc9a/profiling.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Profiling calculation\n\n.. start-body\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import chemfiles\n\nimport rascaline\nfrom rascaline import SoapPowerSpectrum\n\n\ndef compute_soap(path):\n \"\"\"Compute SOAP power spectrum.\n\n This is the same code as the 'compute-soap' example\n \"\"\"\n with chemfiles.Trajectory(path) as trajectory:\n frames = [f for f in trajectory]\n\n HYPER_PARAMETERS = {\n \"cutoff\": 5.0,\n \"max_radial\": 6,\n \"max_angular\": 4,\n \"atomic_gaussian_width\": 0.3,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\n \"Gto\": {},\n },\n \"cutoff_function\": {\n \"ShiftedCosine\": {\"width\": 0.5},\n },\n }\n\n calculator = SoapPowerSpectrum(**HYPER_PARAMETERS)\n descriptor = calculator.compute(frames, gradients=[\"positions\"])\n descriptor = descriptor.keys_to_samples(\"center_type\")\n descriptor = descriptor.keys_to_properties([\"neighbor_1_type\", \"neighbor_2_type\"])\n\n return descriptor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run the calculation with profiling enabled.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "with rascaline.Profiler() as profiler:\n descriptor = compute_soap(\"dataset.xyz\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Display the recorded profiling data as table.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(profiler.as_short_table())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also save this data as json for future usage\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(profiler.as_json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ".. end-body\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/b1152117d616703477f5224415b7c018/le-basis.py b/latest/_downloads/b1152117d616703477f5224415b7c018/le-basis.py new file mode 100644 index 000000000..21899cdca --- /dev/null +++ b/latest/_downloads/b1152117d616703477f5224415b7c018/le-basis.py @@ -0,0 +1,282 @@ +""" +.. _userdoc-tutorials-le-basis: + +LE basis +======== + +.. start-body + +This example illustrates how to generate a spherical expansion using the Laplacian +eigenstate (LE) basis (https://doi.org/10.1063/5.0124363), using two different basis +truncations approaches. The basis can be truncated in the "traditional" way, using all +values below a limit in the angular and radial direction; or using a "ragged +truncation", where basis functions are selected according to an eigenvalue threshold. + +The main ideas behind the LE basis are: + +1. use a basis of controllable *smoothness* (intended in the same sense as the + smoothness of a low-pass-truncated Fourier expansion) +2. apply a "ragged truncation" strategy in which different angular channels are + truncated at a different number of radial channels, so as to obtain more balanced + smoothness level in the radial and angular direction, for a given number of basis + functions. + +Here we use :class:`rascaline.utils.SphericalBesselBasis` to create a spline of the +radial integral corresponding to the LE basis. An detailed how-to guide how to construct +radial integrals is given in :ref:`userdoc-how-to-splined-radial-integral`. +""" + +import ase.io +import matplotlib.pyplot as plt +import numpy as np +from metatensor import Labels, TensorBlock, TensorMap + +import rascaline + + +# %% +# +# Let's start by using a traditional/square basis truncation. Here we will select all +# basis functions with ``l <= max_angular`` and ``n < max_radial``. The basis functions +# are the solution of a radial Laplacian eigenvalue problem (spherical Bessel +# functions). + +cutoff = 4.4 +max_angular = 6 +max_radial = 8 + +# create a spliner for the SOAP radial integral, using delta functions for the atomic +# density and spherical Bessel functions for the basis +spliner = rascaline.utils.SoapSpliner( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + basis=rascaline.utils.SphericalBesselBasis( + cutoff=cutoff, max_radial=max_radial, max_angular=max_angular + ), + density=rascaline.utils.DeltaDensity(), + accuracy=1e-8, +) + +# %% +# +# We can now plot the radial integral splines for a couple of functions. This gives an +# idea of the smoothness of the different components + +splined_basis = spliner.compute() +grid = [p["position"] for p in splined_basis["TabulatedRadialIntegral"]["points"]] +values = np.array( + [ + np.array(p["values"]["data"]).reshape(p["values"]["dim"]) + for p in splined_basis["TabulatedRadialIntegral"]["points"] + ] +) + +plt.plot(grid, values[:, 1, 1], "b-", label="l=1, n=1") +plt.plot(grid, values[:, 4, 1], "r-", label="l=4, n=1") +plt.plot(grid, values[:, 1, 4], "g-", label="l=1, n=4") +plt.plot(grid, values[:, 4, 4], "y-", label="l=4, n=4") +plt.xlabel("$r$") +plt.ylabel(r"$R_{nl}$") +plt.legend() +plt.show() + +# %% +# +# We can use this spline basis in a :py:class:`SphericalExpansion` calculator to +# evaluate spherical expansion coefficients. + +calculator = rascaline.SphericalExpansion( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + center_atom_weight=1.0, + radial_basis=splined_basis, + atomic_gaussian_width=-1.0, # will not be used due to the delta density above + cutoff_function={"ShiftedCosine": {"width": 0.5}}, +) + +# %% +# +# This calculator defaults to the "traditional" basis function selection, so we have the +# same maximal ``n`` value for all ``l``. + +systems = ase.io.read("dataset.xyz", ":10") + +descriptor = calculator.compute(systems) +descriptor = descriptor.keys_to_properties("neighbor_type") +descriptor = descriptor.keys_to_samples("center_type") + +for key, block in descriptor.items(): + n_max = np.max(block.properties["n"]) + 1 + print(f"l = {key['o3_lambda']}, n_max = {n_max}") + +# %% +# +# **Selecting basis with an eigenvalue threshold** +# +# Now we will calculate the same basis with an eigenvalue threshold. The idea is to +# treat on the same footings the radial and angular dimension, and select all functions +# with a mean Laplacian below a certain threshold. This is similar to the common +# practice in plane-wave electronic-structure methods to use a kinetic energy cutoff +# where :math:`k_x^2 + k_y^2 + k_z^2 < k_\text{max}^2` + +eigenvalue_threshold = 20 + +# %% +# +# Let's start by computing a lot of Laplacian eigenvalues, which are related to the +# squares of the zeros of spherical Bessel functions. + +l_max_large = 49 # just used to get the eigenvalues +n_max_large = 50 # just used to get the eigenvalues + +# compute the zeros of the spherical Bessel functions +zeros_ln = rascaline.utils.SphericalBesselBasis.compute_zeros(l_max_large, n_max_large) + +# %% +# +# We have a 50x50 array containing the position of the zero of the different spherical +# Bessel functions, indexed by ``l`` and ``n``. + +print("zeros_ln.shape =", zeros_ln.shape) +print("zeros_ln =", zeros_ln[:3, :3]) + +# calculate the Laplacian eigenvalues +eigenvalues_ln = zeros_ln**2 / cutoff**2 + +# %% +# +# We can now determine the set of ``l, n`` pairs to include all eigenvalues below the +# threshold. + +max_radial_by_angular = [] +for ell in range(l_max_large + 1): + # for each l, calculate how many radial basis functions we want to include + max_radial = len(np.where(eigenvalues_ln[ell] < eigenvalue_threshold)[0]) + max_radial_by_angular.append(max_radial) + if max_radial_by_angular[-1] == 0: + # all eigenvalues for this `l` are over the threshold + max_radial_by_angular.pop() + max_angular = ell - 1 + break + +# %% +# +# Comparing this eigenvalues threshold with the one based on a square selection, we see +# that the eigenvalues threshold leads to a gradual decrease of ``max_radial`` for high +# ``l`` values + +square_max_angular = 10 +square_max_radial = 4 +plt.fill_between( + [0, square_max_angular], + [square_max_radial, square_max_radial], + label=r"$l_\mathrm{max}$, $n_\mathrm{max}$ threshold " + + f"({(square_max_angular + 1) * square_max_radial} functions)", + color="gray", +) +plt.fill_between( + np.arange(max_angular + 1), + max_radial_by_angular, + label=f"Eigenvalues threshold ({sum(max_radial_by_angular)} functions)", + alpha=0.5, +) +plt.xlabel(r"$\ell$") +plt.ylabel("n radial basis functions") +plt.ylim(-0.5, max_radial_by_angular[0] + 0.5) +plt.legend() +plt.show() + +# %% +# +# **Using a subset of basis functions with rascaline** +# +# We can tweak the default basis selection of rascaline by specifying a larger total +# basis; and then only asking for a subset of properties to be computed. See +# :ref:`userdoc-how-to-property-selection` for more details on properties selection. + +# extract all the atomic types from our dataset +all_atomic_types = list( + np.unique(np.concatenate([system.numbers for system in systems])) +) + +keys = [] +blocks = [] +for center_type in all_atomic_types: + for neighbor_type in all_atomic_types: + for ell in range(max_angular + 1): + max_radial = max_radial_by_angular[ell] + + keys.append([ell, 1, center_type, neighbor_type]) + blocks.append( + TensorBlock( + values=np.zeros((0, max_radial)), + samples=Labels.empty("_"), + components=[], + properties=Labels("n", np.arange(max_radial).reshape(-1, 1)), + ) + ) + +selected_properties = TensorMap( + keys=Labels( + names=["o3_lambda", "o3_sigma", "center_type", "neighbor_type"], + values=np.array(keys), + ), + blocks=blocks, +) + +# %% +# +# With this, we can build a calculator and calculate the spherical expansion +# coefficients + +# the biggest max_radial will be for l=0 +max_radial = max_radial_by_angular[0] + + +# set up a spliner object for the spherical Bessel functions this radial basis will be +# used to compute the spherical expansion +spliner = rascaline.utils.SoapSpliner( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + basis=rascaline.utils.SphericalBesselBasis( + cutoff=cutoff, max_radial=max_radial, max_angular=max_angular + ), + density=rascaline.utils.DeltaDensity(), + accuracy=1e-8, +) + +calculator = rascaline.SphericalExpansion( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + center_atom_weight=1.0, + radial_basis=spliner.compute(), + atomic_gaussian_width=-1.0, # will not be used due to the delta density above + cutoff_function={"ShiftedCosine": {"width": 0.5}}, +) + +# %% +# +# And check that we do get the expected Eigenvalues truncation for the calculated +# features! + +descriptor = calculator.compute( + systems, + # we tell the calculator to only compute the selected properties + # (the desired set of (l,n) expansion coefficients + selected_properties=selected_properties, +) + +descriptor = descriptor.keys_to_properties("neighbor_type") +descriptor = descriptor.keys_to_samples("center_type") + +for key, block in descriptor.items(): + n_max = np.max(block.properties["n"]) + 1 + print(f"l = {key['o3_lambda']}, n_max = {n_max}") + +# %% +# +# .. end-body diff --git a/latest/_downloads/b1679995c5f5a7c97fd29b7a3990fedc/compute-soap.py b/latest/_downloads/b1679995c5f5a7c97fd29b7a3990fedc/compute-soap.py new file mode 100644 index 000000000..bfd246d2c --- /dev/null +++ b/latest/_downloads/b1679995c5f5a7c97fd29b7a3990fedc/compute-soap.py @@ -0,0 +1,75 @@ +""" +Computing SOAP features +======================= + +.. start-body +""" + +import chemfiles + +from rascaline import SoapPowerSpectrum + + +# %% +# +# Read systems using chemfiles. You can obtain the dataset used in this +# example from our :download:`website <../../static/dataset.xyz>`. + +with chemfiles.Trajectory("dataset.xyz") as trajectory: + systems = [s for s in trajectory] + +# %% +# +# Rascaline can also handles systems read by `ASE +# `_ using +# +# ``systems = ase.io.read("dataset.xyz", ":")``. +# +# We can now define hyper parameters for the calculation + +HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, +} + +calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + +# %% +# +# And then run the actual calculation, including gradients with respect to positions + +descriptor = calculator.compute(systems, gradients=["positions"]) + +# %% +# +# The descriptor is a metatensor ``TensorMap``, containing multiple blocks. We +# can transform it to a single block containing a dense representation, with one +# sample for each atom-centered environment by using ``keys_to_samples`` and +# ``keys_to_properties`` + +print("before: ", len(descriptor.keys)) + +descriptor = descriptor.keys_to_samples("center_type") +descriptor = descriptor.keys_to_properties(["neighbor_1_type", "neighbor_2_type"]) +print("after: ", len(descriptor.keys)) + +# %% +# +# you can now use ``descriptor.block().values`` as the input of a machine +# learning algorithm + +print(descriptor.block().values.shape) + + +# %% +# +# .. end-body diff --git a/latest/_downloads/b957f733884c5245e2a56cba651d0969/splined-radial-integral.py b/latest/_downloads/b957f733884c5245e2a56cba651d0969/splined-radial-integral.py new file mode 100644 index 000000000..f3a2d9a16 --- /dev/null +++ b/latest/_downloads/b957f733884c5245e2a56cba651d0969/splined-radial-integral.py @@ -0,0 +1,165 @@ +""" +Splined radial integrals +======================== + +.. start-body + +This example illustrates how to generate splined radial basis functions/integrals, using +a "rectangular" Laplacian eigenstate (LE) basis (https://doi.org/10.1063/5.0124363) as +the example, i.e, a LE basis truncated with ``l_max``, ``n_max`` hyper-parameters. + +Note that the same basis is also directly available through +:class:`rascaline.utils.SphericalBesselBasis` with an how-to guide given in +:ref:`userdoc-how-to-le-basis`. +""" + +# %% + +import ase +import numpy as np +import scipy as sp +from scipy.special import spherical_jn as j_l + +from rascaline import SphericalExpansion +from rascaline.utils import RadialIntegralFromFunction, SphericalBesselBasis + + +# %% +# Set some hyper-parameters + +max_angular = 6 +max_radial = 8 +cutoff = 5.0 + +# %% +# +# where ``cutoff`` is also the radius of the LE sphere. Now we compute the zeros of the +# spherical bessel functions. + +z_ln = SphericalBesselBasis.compute_zeros(max_angular, max_radial) +z_nl = z_ln.T + +# %% +# and define the radial basis functions + + +def R_nl(n, el, r): + # Un-normalized LE radial basis functions + return j_l(el, z_nl[n, el] * r / cutoff) + + +def N_nl(n, el): + # Normalization factor for LE basis functions, excluding the a**(-1.5) factor + def function_to_integrate_to_get_normalization_factor(x): + return j_l(el, x) ** 2 * x**2 + + integral, _ = sp.integrate.quadrature( + function_to_integrate_to_get_normalization_factor, 0.0, z_nl[n, el] + ) + return (1.0 / z_nl[n, el] ** 3 * integral) ** (-0.5) + + +def laplacian_eigenstate_basis(n, el, r): + R = np.zeros_like(r) + for i in range(r.shape[0]): + R[i] = R_nl(n, el, r[i]) + return N_nl(n, el) * R * cutoff ** (-1.5) + + +# %% +# Quick normalization check: + +normalization_check_integral, _ = sp.integrate.quadrature( + lambda x: laplacian_eigenstate_basis(1, 1, x) ** 2 * x**2, + 0.0, + cutoff, +) +print(f"Normalization check (needs to be close to 1): {normalization_check_integral}") + + +# %% +# Now the derivatives (by finite differences): + + +def laplacian_eigenstate_basis_derivative(n, el, r): + delta = 1e-6 + all_derivatives_except_at_zero = ( + laplacian_eigenstate_basis(n, el, r[1:] + delta) + - laplacian_eigenstate_basis(n, el, r[1:] - delta) + ) / (2.0 * delta) + derivative_at_zero = ( + laplacian_eigenstate_basis(n, el, np.array([delta / 10.0])) + - laplacian_eigenstate_basis(n, el, np.array([0.0])) + ) / (delta / 10.0) + return np.concatenate([derivative_at_zero, all_derivatives_except_at_zero]) + + +# %% +# The radial basis functions and their derivatives can be input into a spline generator +# class. This will output the positions of the spline points, the values of the basis +# functions evaluated at the spline points, and the corresponding derivatives. + +spliner = RadialIntegralFromFunction( + radial_integral=laplacian_eigenstate_basis, + radial_integral_derivative=laplacian_eigenstate_basis_derivative, + spline_cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + accuracy=1e-5, +) + +# %% +# The, we feed the splines to the Rust calculator: Note that the +# ``atomic_gaussian_width`` will be ignored since we are not uisng a Gaussian basis. + +hypers_spherical_expansion = { + "cutoff": cutoff, + "max_radial": max_radial, + "max_angular": max_angular, + "center_atom_weight": 0.0, + "radial_basis": spliner.compute(), + "atomic_gaussian_width": 1.0, # ignored + "cutoff_function": {"Step": {}}, +} +calculator = SphericalExpansion(**hypers_spherical_expansion) + +# %% +# +# Create dummy systems to test if the calculator outputs correct radial functions: + + +def get_dummy_systems(r_array): + dummy_systems = [] + for r in r_array: + dummy_systems.append(ase.Atoms("CH", positions=[(0, 0, 0), (0, 0, r)])) + return dummy_systems + + +r = np.linspace(0.1, 4.9, 20) +systems = get_dummy_systems(r) +spherical_expansion_coefficients = calculator.compute(systems) + +# %% +# Extract ``l = 0`` features and check that the ``n = 2`` predictions are the same: + +block_C_l0 = spherical_expansion_coefficients.block( + center_type=6, o3_lambda=0, neighbor_type=1 +) +block_C_l0_n2 = block_C_l0.values[:, :, 2].flatten() +spherical_harmonics_0 = 1.0 / np.sqrt(4.0 * np.pi) + +# %% +# radial function = feature / spherical harmonics function +rascaline_output_radial_function = block_C_l0_n2 / spherical_harmonics_0 + +assert np.allclose( + rascaline_output_radial_function, + laplacian_eigenstate_basis(2, 0, r), + atol=1e-5, +) +print("Assertion passed successfully!") + + +# %% +# +# .. end-body diff --git a/latest/_downloads/baed817b984659f054f6dbda1066cc00/dataset.xyz b/latest/_downloads/baed817b984659f054f6dbda1066cc00/dataset.xyz new file mode 100644 index 000000000..c3442edc7 --- /dev/null +++ b/latest/_downloads/baed817b984659f054f6dbda1066cc00/dataset.xyz @@ -0,0 +1,1460 @@ +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4554.712769935985 energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" name crystal=WETGAE frame=0 pbc="T T T" +O 2.02312000 5.14665000 8.33983000 0.00103696 -0.01740519 -0.00528151 +O 3.24139000 1.50498000 0.95734500 0.00424216 -0.01735464 -0.00118144 +O 3.78983000 5.16709000 7.00368000 0.00266048 0.00637094 0.00200116 +O 1.47589000 1.48008000 2.29292000 -0.00487235 0.00590037 -0.00369057 +C 1.19211000 4.59081000 7.60062000 -0.01251664 -0.00378144 -0.00135354 +C 4.07440000 2.05806000 1.69639000 -0.00081186 -0.00519296 -0.00527930 +C 1.32438000 3.12357000 7.32355000 -0.01118533 -0.01352241 -0.00298926 +C 3.94244000 3.52474000 1.97145000 -0.00626146 0.00961788 0.00582144 +N 2.25042000 2.40973000 7.83079000 -0.00491906 0.00048798 -0.00455194 +N 3.01492000 4.23670000 1.46462000 0.00094263 0.01582550 -0.00162208 +N 0.41467800 2.55219000 6.57338000 -0.00283916 -0.00059027 0.00454750 +N 4.85187000 4.09716000 2.72072000 -0.01353110 -0.00918887 -0.00424976 +H 2.78121000 2.77377000 8.63105000 0.01394746 -0.00669947 -0.00138909 +H 2.48047000 3.87485000 0.66598600 0.00747682 -0.00794810 -0.00622834 +H 2.25505000 1.34633000 7.62757000 -0.00127826 0.02236824 -0.00203658 +H 3.01078000 5.29825000 1.66709000 0.00000215 0.00814022 0.00293038 +H -0.16194500 3.15012000 5.99969000 0.00684453 0.01323727 0.00146462 +H 5.42528000 3.49582000 3.29452000 0.00379395 0.01589929 0.00757051 +H 0.49478100 1.56012000 6.34200000 0.00823941 -0.00174164 0.00918537 +H 4.76962000 5.08990000 2.94978000 0.00902863 -0.01442260 0.00633232 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4554.148814003207 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=10 pbc="T T T" +O 1.92656000 5.16795000 8.36906000 -0.36745744 -1.21622950 -1.36700927 +O 3.27764000 1.51044000 1.01515000 -0.92159650 -0.46687017 -0.99486266 +O 3.76698000 5.13299000 6.97579000 -1.30370357 0.36655292 -0.79114387 +O 1.50207000 1.49556000 2.37677000 -1.52027787 1.09879693 -1.67458006 +C 1.14604000 4.55900000 7.55326000 2.23006690 1.40948904 2.39111052 +C 4.08985000 2.10274000 1.71427000 2.39069400 -2.09158214 2.31800377 +C 1.36874000 3.12640000 7.27091000 -0.86687828 -1.33618689 -0.74383043 +C 3.93391000 3.52197000 2.00293000 0.21302464 1.18447123 0.12637692 +N 2.30584000 2.39665000 7.77803000 -1.42465340 1.74009177 -0.77371179 +N 2.98294000 4.20389000 1.47197000 0.66249101 0.87222104 -0.46929883 +N 0.46041300 2.56040000 6.48784000 1.58079650 -1.49634090 1.09518710 +N 4.83780000 4.11548000 2.75255000 -0.68905565 -1.02492400 -1.09080080 +H 2.76424000 2.82101000 8.56286000 0.84928165 0.10345553 0.87798545 +H 2.56107000 3.78141000 0.62587100 -0.39540327 0.12542407 0.35386761 +H 2.27450000 1.37301000 7.62974000 0.04181195 -1.12155120 -0.13834232 +H 3.03297000 5.29534000 1.51899000 -0.09632175 -0.79619866 0.64661188 +H -0.22770800 3.11119000 6.06124000 -0.64043609 0.94046840 -0.73512467 +H 5.46554000 3.51539000 3.25209000 0.08316593 -0.09030537 0.37348564 +H 0.53241600 1.55776000 6.22384000 0.00028407 0.62538999 0.27057416 +H 4.67216000 5.06885000 2.99095000 0.17416499 1.17382686 0.32550115 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4553.967776665655 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=20 pbc="T T T" +O 2.06789000 5.17952000 8.30616000 0.23840348 0.22239940 0.71644818 +O 3.23007000 1.40283000 1.04010000 -0.06763235 0.02315453 -0.44059195 +O 3.81204000 5.19836000 6.99141000 0.92313402 -0.91092128 0.31702422 +O 1.48425000 1.44214000 2.38186000 -1.70758788 1.30116332 -1.11007893 +C 1.23747000 4.61060000 7.60972000 -1.22082663 -0.11864716 -1.05155034 +C 4.06911000 2.01020000 1.71613000 1.03941988 -0.06776348 1.49959078 +C 1.35438000 3.12995000 7.30768000 -0.98736532 0.46136184 -0.89278472 +C 3.88257000 3.50982000 1.95221000 2.23570276 0.45386861 1.89116465 +N 2.24173000 2.38397000 7.78908000 0.55689580 -1.65735367 -0.93838581 +N 2.93986000 4.24710000 1.49110000 0.48725027 -2.60866184 -0.41585228 +N 0.44838700 2.65431000 6.44118000 0.04663621 0.44261952 0.70955762 +N 4.84237000 4.11686000 2.74628000 -2.44765936 -2.32369105 -2.18124679 +H 2.81179000 2.54729000 8.61888000 0.01162956 0.75288585 0.04292806 +H 2.35794000 3.93865000 0.69615400 0.40003743 -0.12768150 0.11747885 +H 2.30860000 1.25728000 7.40625000 -0.21047719 0.78887101 0.46415765 +H 2.86528000 5.22819000 1.75738000 0.53186354 1.93267768 0.45206987 +H -0.15882300 3.38167000 6.03597000 0.50703440 -0.58116702 0.11901688 +H 5.40139000 3.59485000 3.41026000 -0.23945455 -0.36304234 -0.27803344 +H 0.47176100 1.70218000 6.02326000 0.11987614 0.62440269 0.58014886 +H 4.63041000 5.05044000 2.97853000 -0.21687975 1.75551839 0.39893957 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4554.122663863212 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=30 pbc="T T T" +O 2.16133000 5.20068000 8.25427000 -0.80078036 -0.06588452 0.23027520 +O 3.20668000 1.43403000 1.01369000 -0.33738941 -0.52908161 -0.24162096 +O 3.85544000 5.29320000 7.01478000 -0.23462962 0.05616832 -1.12804066 +O 1.44338000 1.32894000 2.34493000 -0.14894298 0.71589282 0.19256997 +C 1.26752000 4.69557000 7.53938000 0.76420385 -1.12845718 0.89502158 +C 4.04136000 1.92992000 1.77669000 0.10442227 1.28746962 -0.23412363 +C 1.32594000 3.19550000 7.27099000 0.02984953 1.60516027 0.34374004 +C 3.89701000 3.45365000 2.00020000 0.87090977 -1.36755949 0.73980922 +N 2.24612000 2.48301000 7.76849000 0.74835557 0.91850604 1.25200383 +N 3.00617000 4.14572000 1.46970000 -2.22322262 -0.39358961 -1.41212699 +N 0.38593200 2.67319000 6.54895000 2.19999013 -4.10329553 1.03333150 +N 4.75362000 4.06625000 2.75946000 1.58321334 -3.02760767 0.06877958 +H 2.71423000 2.85802000 8.63251000 -0.09217970 -0.40721235 -0.87983664 +H 2.45950000 3.71235000 0.70339700 0.12292598 0.49596066 0.18109874 +H 2.32867000 1.43994000 7.53840000 -0.26832804 -0.37949431 0.19497035 +H 2.94334000 5.18374000 1.68831000 0.09873910 0.39651450 -0.05799895 +H -0.15364900 3.25961000 6.02224000 -1.66220791 1.45145458 -1.80328948 +H 5.34508000 3.40773000 3.25945000 0.09870157 0.53475860 0.26217899 +H 0.51927200 1.61404000 6.37441000 -0.69431098 1.94853624 -0.10719700 +H 4.63788000 4.99143000 3.05059000 -0.15931532 1.99176677 0.47045531 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4553.878332846545 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=49 pbc="T T T" +O 1.95530000 5.22182000 8.21070000 -1.63334985 -1.05225482 -2.33849546 +O 3.29803000 1.50378000 1.01129000 0.36292510 0.61525984 0.64950180 +O 3.73313000 5.13207000 6.77995000 -0.78614050 1.33941105 -0.32467582 +O 1.49937000 1.46085000 2.36878000 1.29535777 0.30004003 1.06109942 +C 1.12896000 4.64239000 7.39802000 2.05847661 -1.09593787 2.82728788 +C 4.13943000 2.04965000 1.76877000 -1.79811128 0.47532396 -1.60758739 +C 1.25711000 3.11195000 7.26438000 0.00224330 0.62654699 -0.08035160 +C 4.04787000 3.54617000 2.03875000 -1.24168342 -0.42746441 0.14378946 +N 2.15938000 2.42732000 7.85262000 0.17133729 -0.23795920 -0.82308726 +N 3.11824000 4.30837000 1.62665000 -1.04224295 -2.97950747 -1.62659299 +N 0.37757000 2.46219000 6.54384000 -0.00639521 0.77194801 0.32180030 +N 4.89243000 4.04662000 2.86788000 0.37486376 2.56778644 0.67410725 +H 2.76062000 2.79273000 8.57612000 0.08311502 0.18232875 0.46966701 +H 2.49198000 3.85500000 0.94258900 0.41770708 0.83866814 0.00983077 +H 2.10449000 1.40409000 7.65520000 0.26079676 -0.39858630 0.31379029 +H 3.02087000 5.29781000 1.94968000 0.05456087 1.23157898 -0.32846203 +H -0.19171100 3.07456000 5.94730000 0.09347400 -0.83991255 0.24352358 +H 5.53147000 3.37799000 3.17420000 1.42214915 -0.73435334 1.23672633 +H 0.40388600 1.42362000 6.55898000 -0.15179639 0.68400600 -0.43559887 +H 4.88600000 5.08086000 3.15639000 0.06270766 -1.86692943 -0.38627431 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4553.918660117589 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=50 pbc="T T T" +O 1.95734000 5.18497000 8.17907000 -0.12563336 -0.19892060 -0.83751629 +O 3.29538000 1.50293000 1.05122000 -0.01987231 0.35695037 -0.15486988 +O 3.73667000 5.12956000 6.76638000 0.84188202 0.19218019 0.70029651 +O 1.49691000 1.47436000 2.37821000 1.51639551 0.35868278 1.09882264 +C 1.15719000 4.61125000 7.40622000 -1.26484392 -0.53653781 0.33200861 +C 4.14150000 2.06717000 1.76753000 -1.66096350 0.46774537 -1.18810677 +C 1.23252000 3.08337000 7.28994000 0.63676969 0.87219018 -0.53783879 +C 4.04621000 3.55977000 1.99675000 0.66497470 0.26940533 2.29178366 +N 2.15464000 2.41336000 7.87549000 -0.05508640 -0.78558514 -0.71416504 +N 3.11598000 4.32609000 1.61421000 -0.71225214 -0.40956953 -0.79545818 +N 0.36513900 2.45908000 6.51799000 1.18599332 0.79830182 1.92618821 +N 4.89272000 4.08107000 2.88437000 1.61173716 -1.67609187 -0.07453011 +H 2.87324000 2.76684000 8.51594000 -0.85149280 0.09700567 0.15498507 +H 2.45967000 3.93860000 0.94520400 0.11175608 0.17423698 -0.29999837 +H 2.00875000 1.37812000 7.75982000 0.67062598 -0.15442766 0.10833395 +H 3.01273000 5.41422000 1.96652000 0.30067200 -0.38484169 -0.61492046 +H -0.17695100 3.07169000 5.95637000 -0.83310427 0.20759601 -0.54115037 +H 5.68878000 3.50958000 3.21562000 -1.24594117 0.34643095 -0.32371012 +H 0.37917600 1.45078000 6.48159000 -0.15625931 -0.48896623 -0.42065459 +H 4.97263000 5.05358000 3.15132000 -0.61535755 0.49421642 -0.10948734 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4554.049247549261 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=70 pbc="T T T" +O 2.05539000 4.98245000 8.29100000 -1.06895157 -0.86277480 -1.34667699 +O 3.20028000 1.73013000 1.08101000 0.10267906 -0.08866089 -0.49197442 +O 3.84105000 4.87653000 6.87368000 0.07016386 1.08661505 0.69299972 +O 1.43242000 1.72841000 2.40406000 0.91681939 -0.80465759 0.07099536 +C 1.24786000 4.37396000 7.53049000 0.61151118 -0.19975518 0.71176877 +C 4.07432000 2.29992000 1.76150000 -0.98129752 -0.43627096 0.43796120 +C 1.35858000 2.88280000 7.24830000 -0.23388091 0.85661444 -0.06525614 +C 3.90793000 3.75078000 2.06340000 1.35422060 -1.36950838 0.10238030 +N 2.28716000 2.14815000 7.73285000 -0.08862593 -0.22452878 0.77294560 +N 2.97860000 4.39014000 1.53082000 -2.33735903 1.45433936 -2.01691730 +N 0.42096500 2.38687000 6.45583000 1.47525272 -0.78124512 0.98253165 +N 4.80560000 4.33786000 2.80249000 -1.32569164 2.41184389 -0.39850762 +H 2.72369000 2.49648000 8.64676000 -0.18828137 -0.42257160 -1.45192253 +H 2.49188000 4.01660000 0.64549600 0.60760310 0.30550311 1.57097489 +H 2.27884000 1.04060000 7.47685000 0.08198220 0.75507129 0.15867615 +H 2.88155000 5.42473000 1.76195000 0.31348741 0.37162519 -0.13754271 +H -0.07909820 3.07895000 5.87639000 0.21543839 -0.79905258 0.26745901 +H 5.37726000 3.77563000 3.36822000 0.76540713 -0.71195903 0.88338991 +H 0.58391200 1.36833000 6.27639000 -0.72496367 0.89921248 -0.49411101 +H 4.64826000 5.37241000 3.01294000 0.43448507 -1.43984348 -0.24917126 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4553.997409862798 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=80 pbc="T T T" +O 2.00493000 4.90163000 8.29247000 0.72512823 0.92113885 0.53687205 +O 3.24267000 1.76257000 0.91952400 -0.23366083 -0.30588620 -0.06551891 +O 3.79259000 5.02393000 6.94426000 -0.31399340 -0.12479158 -0.06180161 +O 1.46709000 1.71027000 2.31358000 -0.76429641 0.21997433 -1.11877440 +C 1.18228000 4.42292000 7.51908000 -0.01050964 -1.52345576 -0.35298418 +C 4.06934000 2.28818000 1.66916000 1.15406537 -0.24131243 1.77467825 +C 1.37477000 2.90450000 7.24939000 -1.94044241 1.82976156 -1.18118022 +C 3.92306000 3.73836000 2.05554000 -0.82933504 -0.44951676 0.02687188 +N 2.28986000 2.27847000 7.80978000 2.39566137 -2.06573227 1.23602185 +N 2.91273000 4.41137000 1.59399000 1.25771168 -1.71795971 -1.80635424 +N 0.49951200 2.21713000 6.52059000 0.37811106 0.49140004 -0.40799859 +N 4.78976000 4.25529000 2.90047000 -0.05675813 -0.86258454 -0.97752314 +H 2.92263000 2.67944000 8.53974000 -0.96002935 -0.07114808 -0.48124675 +H 2.43621000 3.93958000 0.73158100 0.76836904 0.95382785 1.57063036 +H 2.33097000 1.18759000 7.62961000 -0.01411387 0.49512813 0.01364227 +H 3.00264000 5.44501000 1.63791000 -0.40952788 1.00936368 0.38502270 +H -0.04486260 2.74267000 5.81971000 0.35412832 -0.41517711 0.57170021 +H 5.54230000 3.65941000 3.26542000 -1.02927430 0.42162184 -0.18201662 +H 0.81296200 1.24794000 6.27607000 -0.56292761 0.70195744 0.24740903 +H 4.72412000 5.23451000 3.12939000 0.09169582 0.73339689 0.27254876 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4553.773895554868 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=99 pbc="T T T" +O 2.00349000 4.94651000 8.36262000 -2.10015934 -0.57841594 -2.19078558 +O 3.29525000 1.65483000 1.00945000 0.51088128 0.48952622 0.60066626 +O 3.75125000 4.94654000 6.87115000 1.67329451 0.03698784 2.28414234 +O 1.56187000 1.69327000 2.34887000 -1.33045847 0.26916262 -0.25522416 +C 1.14570000 4.41213000 7.57423000 0.32878187 0.55436584 0.10769066 +C 4.10736000 2.23671000 1.76219000 0.69827562 0.18725447 -0.06071352 +C 1.23128000 2.92828000 7.30920000 1.32538311 0.11814939 0.77767129 +C 3.97761000 3.77422000 2.01574000 0.40610729 -2.50636279 -0.68432482 +N 2.14770000 2.16052000 7.82554000 -0.83811792 1.15385968 -0.46463074 +N 3.08774000 4.47143000 1.42284000 1.16669977 -0.00572487 1.68559981 +N 0.34756300 2.43801000 6.50091000 -0.63566926 0.70965018 0.44271260 +N 4.91710000 4.24873000 2.79010000 -1.01893333 2.35736736 -0.98405888 +H 2.61596000 2.43659000 8.69445000 0.23180141 0.57466213 -0.35397457 +H 2.50480000 4.11518000 0.67923600 -0.14269777 -0.30434200 -0.45643920 +H 2.16255000 1.12117000 7.63823000 -0.37379675 -0.29022870 -0.62410444 +H 3.24542000 5.50123000 1.62103000 -0.92494408 0.61737329 -0.17153423 +H -0.27505600 2.97891000 5.92325000 0.23059761 0.77238510 0.35168629 +H 5.39031000 3.53680000 3.32410000 0.55019037 0.05239548 0.05532551 +H 0.31719400 1.49734000 6.27291000 0.32707055 -2.75970901 -0.33277171 +H 5.03386000 5.30237000 2.89795000 -0.08430750 -1.44835383 0.27306967 +20 +Lattice="3.549 0.0 0.0 1.3633044072019755 5.103237985172127 0.0 0.35276448037117664 1.5448560525892414 9.295297809008963" Properties=species:S:1:pos:R:3:forces:R:3 energy=-4553.903503376718 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="6 4 3" crystal=WETGAE frame=100 pbc="T T T" +O 1.99527000 4.93170000 8.34732000 -0.78368767 0.35432835 -0.86289307 +O 3.34021000 1.69072000 1.01270000 -2.34640932 -1.57231186 -2.20191332 +O 3.73761000 4.95928000 6.89728000 1.79604926 -0.26233068 2.26685424 +O 1.56751000 1.70591000 2.33475000 -0.76180758 -0.17302856 -0.16182318 +C 1.16048000 4.41250000 7.58876000 -1.33664969 -0.00929228 -1.13156821 +C 4.11373000 2.23669000 1.73835000 2.93708941 2.20337370 2.27626962 +C 1.23963000 2.93055000 7.32532000 -1.04118879 -0.24656468 -1.23486485 +C 3.98155000 3.74697000 2.01121000 0.73210106 0.10850261 -0.06742512 +N 2.12846000 2.15251000 7.82481000 -0.88446977 0.03324226 -0.83933663 +N 3.08176000 4.45482000 1.43845000 0.05372526 -0.43499260 0.13030865 +N 0.31105700 2.42921000 6.50133000 1.32806734 -2.54503218 1.38763980 +N 4.93561000 4.27300000 2.77449000 -0.83093426 -2.77516134 -0.75975070 +H 2.65463000 2.52539000 8.61741000 0.20883477 -0.18313968 0.00845831 +H 2.55292000 4.01181000 0.65202400 0.29607127 0.46359047 0.70963476 +H 2.00871000 1.04209000 7.57407000 0.92478467 0.81209836 0.17821962 +H 3.11078000 5.53428000 1.59976000 -0.15148271 -0.24540974 0.23410511 +H -0.23810800 3.01654000 5.89468000 -0.03345005 0.26506428 0.18846392 +H 5.38198000 3.45210000 3.27173000 -0.02377396 1.48146964 -0.42777449 +H 0.31177200 1.36250000 6.33988000 -0.01905712 1.97418557 0.04293305 +H 4.95833000 5.22782000 3.07951000 -0.06380707 0.75141518 0.26445904 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14302.429185648707 energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" name crystal=COVSEM frame=0 pbc="T T T" +N -2.10781000 4.14157000 8.23142000 -0.00528285 -0.00008150 0.00338993 +N 5.61516000 0.01149850 4.42090000 0.00510283 0.00011858 -0.00342169 +N 2.94458000 3.53473000 6.81278000 -0.00167876 -0.00476051 -0.00019830 +N 0.56276400 0.61833500 5.83954000 0.00181871 0.00488240 0.00020377 +N 4.14582000 3.60605000 6.10032000 -0.00031166 0.00207279 0.00239113 +N -0.63847600 0.54702200 6.55201000 0.00042463 -0.00208512 -0.00237107 +N -1.32727000 4.55736000 9.27272000 0.00122129 0.00114195 -0.00168966 +N 4.83461000 -0.40428400 3.37961000 -0.00134817 -0.00123926 0.00148556 +N -0.10794100 -1.49487000 10.26550000 0.00766261 -0.00053151 0.00245414 +N 3.61528000 5.64794000 2.38679000 -0.00769953 0.00049470 -0.00254534 +N 0.70221700 -1.11074000 11.30080000 0.00165949 0.00286007 -0.00155214 +N 2.80512000 5.26381000 1.35154000 -0.00166707 -0.00284339 0.00152013 +N 2.44068000 1.88191000 0.69653500 -0.00158319 -0.00194419 -0.00034735 +N 1.06665000 2.27116000 11.95580000 0.00161436 0.00196660 0.00040543 +N 2.38326000 -0.64630300 12.65710000 -0.00382120 -0.00024682 -0.00286528 +N 1.12407000 4.79938000 -0.00474388 0.00401081 0.00026068 0.00291123 +N -0.21034700 4.10380000 6.73503000 0.00215183 -0.00012099 0.00213230 +N 3.71769000 0.04928010 5.91730000 -0.00219621 0.00010134 -0.00215678 +N 0.15372800 3.88200000 5.56163000 0.00432243 0.00185584 0.00153216 +N 3.35361000 0.27107200 7.09070000 -0.00422848 -0.00185488 -0.00169331 +N 0.61380900 3.72061000 4.53098000 0.00142186 0.00172799 -0.00063261 +N 2.89353000 0.43247000 8.12135000 -0.00146498 -0.00172460 0.00072065 +N 2.31844000 3.72566000 9.15348000 0.00270527 -0.00247697 -0.00093396 +N 1.18890000 0.42740900 3.49883000 -0.00287218 0.00240244 0.00105762 +N 1.37156000 2.91150000 8.98770000 0.00395927 -0.00157178 -0.00281550 +N 2.13578000 1.24158000 3.66462000 -0.00322703 0.00214907 0.00272387 +N 0.47774100 2.20840000 9.03724000 0.00406855 0.00021633 0.00138437 +N 3.02960000 1.94468000 3.61508000 -0.00459440 -0.00064379 -0.00134110 +N 0.07374670 1.66892000 0.05168720 -0.00063073 0.00148833 0.00081753 +N 3.43360000 2.48416000 12.60060000 0.00036806 -0.00142823 -0.00069314 +N -0.29771000 2.12702000 1.15506000 0.00346891 0.00238938 0.00207561 +N 3.80504000 2.02606000 11.49730000 -0.00293358 -0.00273951 -0.00281498 +N -0.78275100 2.52123000 2.10840000 -0.00040548 0.00124346 0.00156724 +N 4.29009000 1.63184000 10.54390000 0.00006312 -0.00099095 -0.00101192 +C -1.57035000 3.93650000 6.96195000 -0.00083122 -0.00150032 0.00477367 +C 5.07769000 0.21657400 5.69037000 0.00083368 0.00149927 -0.00475394 +C 3.18943000 3.82709000 8.07560000 -0.00368889 0.00117381 -0.00098713 +C 0.31791300 0.32599200 4.57672000 0.00365211 -0.00131527 0.00109381 +C 0.19604800 -0.67586700 12.51810000 -0.00117277 -0.00103700 -0.00012319 +C 3.31129000 4.82894000 0.13422000 0.00111437 0.00107604 0.00023297 +C 2.08549000 -1.06791000 11.44780000 -0.00289611 0.00075695 -0.00287753 +C 1.42184000 5.22098000 1.20451000 0.00293070 -0.00074386 0.00294882 +H 2.78304000 -1.33714000 10.66360000 0.00178443 -0.00266285 0.00438313 +H 0.72430700 5.49021000 1.98872000 -0.00182488 0.00266529 -0.00437913 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.964668963443 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=10 pbc="T T T" +N -2.08548000 4.14209000 8.18700000 -0.65055081 0.50559664 2.64323803 +N 5.70399000 -0.01543850 4.43366000 -1.22881248 -0.62278803 -1.42040080 +N 2.94259000 3.44419000 6.88590000 -0.49458666 0.35346549 -0.99530489 +N 0.64980200 0.75037600 5.76278000 -0.64616450 -0.66877993 0.85718523 +N 4.11606000 3.53996000 6.10994000 0.29462220 -0.52832570 0.44241743 +N -0.53916800 0.64831200 6.51196000 0.00753174 0.33836438 -0.20059798 +N -1.29690000 4.53335000 9.29525000 -1.87764064 0.07464478 0.13318212 +N 4.86275000 -0.44506600 3.37392000 -0.24007573 0.35136747 1.56653716 +N -0.14676800 -1.44615000 10.25640000 1.19701307 -0.87536293 -1.15176680 +N 3.56990000 5.71345000 2.32653000 1.20946750 -0.58333703 -0.37894101 +N 0.65466400 -1.21441000 11.35420000 0.77291989 0.23903289 -2.04906638 +N 2.75770000 5.20341000 1.35088000 -0.14598621 0.42507946 -0.44134786 +N 2.53794000 2.06285000 0.57862700 0.11536591 -0.84831492 -0.31909601 +N 0.94921200 2.25761000 11.96300000 -0.56121011 -0.00331780 -0.58958995 +N 2.42093000 -0.68689700 12.50430000 0.77294560 1.39753341 2.04948804 +N 0.99924800 4.83809000 0.00606972 1.14730336 0.17032170 0.90573280 +N -0.19702400 4.04936000 6.80174000 1.02902748 -0.73619940 -2.51148442 +N 3.82739000 -0.02579210 5.98865000 1.00818611 -0.15509100 -1.21219287 +N 0.21529500 3.82040000 5.58607000 -0.73012131 1.34984973 1.24356547 +N 3.45432000 0.29575900 7.12508000 1.36381082 -0.47723171 -3.07611925 +N 0.65736600 3.90484000 4.53316000 -0.15352828 -0.58366613 0.71430902 +N 2.87554000 0.60238800 8.01891000 -1.87025129 0.87232388 3.76174504 +N 2.32884000 3.79179000 9.24568000 0.89226536 0.33985870 -0.70762415 +N 1.21401000 0.41788300 3.52625000 2.33652599 0.86208575 -2.36826883 +N 1.40623000 2.96075000 9.11651000 -1.35285278 -1.27029980 -0.38527415 +N 2.07782000 1.34995000 3.67159000 0.72758620 -0.11586419 -0.76892440 +N 0.53013200 2.22142000 9.12696000 0.69667126 0.64392765 0.10595619 +N 2.92483000 2.11219000 3.52322000 -0.78366196 -0.71509578 0.32738834 +N 0.10790600 1.80758000 0.01629400 0.49983582 0.30537249 0.54755241 +N 3.32752000 2.22813000 12.63240000 -1.10641254 0.72182179 0.42997844 +N -0.27738300 2.16763000 1.15970000 -0.30064424 -0.17225671 0.17428223 +N 3.64590000 1.82373000 11.50320000 0.46729337 0.17783498 0.36495164 +N -0.83098000 2.41218000 2.13524000 0.51183825 0.04198884 -0.65710712 +N 4.18779000 1.44537000 10.58840000 0.40408126 -0.45080129 -1.34493378 +C -1.55528000 3.85006000 6.95542000 -0.68949788 0.39842483 0.00792707 +C 5.16762000 0.25429100 5.67864000 -0.21052810 -0.35664183 0.96252846 +C 3.16818000 3.84359000 8.10574000 1.55402103 0.02773408 0.43806713 +C 0.39275600 0.29651600 4.55240000 -1.31973697 0.63018253 1.81931774 +C 0.25037800 -0.53982900 12.46850000 -1.17502500 -0.29902855 0.95615213 +C 3.20819000 4.76696000 0.11144000 1.06882815 -0.04822880 0.71929696 +C 2.06106000 -1.19580000 11.39000000 -0.08643792 -0.98696937 -1.37430092 +C 1.39239000 5.22965000 1.21717000 -0.69359107 -0.34616613 -0.38663581 +H 2.76507000 -1.55783000 10.59840000 -0.92544287 0.32298147 0.77732676 +H 0.80979800 5.46967000 2.07306000 -0.83437954 0.29397068 0.39085088 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.745018672038 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=20 pbc="T T T" +N -2.11057000 4.21143000 8.26244000 -1.13472039 -0.19279674 1.49542559 +N 5.63929000 -0.00618776 4.31012000 0.99778857 0.99383936 0.67976368 +N 2.97113000 3.43265000 6.92143000 -0.68143490 -0.29017162 -0.86266682 +N 0.66377200 0.81042300 5.65926000 -1.90604105 -0.59107091 -0.58658690 +N 4.15231000 3.37582000 6.19801000 0.80486328 1.07941596 1.32338279 +N -0.51449800 0.62727600 6.42148000 -1.15618395 0.04648925 -0.32198799 +N -1.34179000 4.54862000 9.35883000 -0.61117179 0.21523630 -0.76351480 +N 4.85546000 -0.54958200 3.33862000 0.37720500 0.46273326 0.42020516 +N -0.12970700 -1.48063000 10.35540000 0.90753257 -0.03118666 -1.23563104 +N 3.57588000 5.70712000 2.25382000 0.25406613 0.04439051 0.53336507 +N 0.75209000 -1.06736000 11.30350000 -0.99276464 0.40925997 1.70638975 +N 2.72563000 5.21603000 1.32209000 -0.36046095 0.29832253 -0.62392446 +N 2.53002000 1.79341000 0.74930000 1.19296616 0.21992342 -0.28480315 +N 0.84352300 2.24519000 11.91820000 1.32271945 0.45696679 1.61287873 +N 2.47334000 -0.70606400 12.62720000 -0.34611008 0.41376609 1.66025387 +N 0.99510200 4.88675000 0.04470880 -1.58242658 -0.98634202 -2.80617398 +N -0.20379400 4.12541000 6.83937000 -0.33646536 -0.28893852 -2.32030748 +N 3.74074000 0.11044600 5.87151000 0.95687204 -0.14028093 -0.29809113 +N 0.06450750 3.98734000 5.56934000 -0.93824182 0.17094288 4.71315606 +N 3.38275000 0.37977300 7.03568000 0.58913229 -0.17667284 -0.56227455 +N 0.50712400 3.81460000 4.56291000 1.07777559 -0.23719815 -2.82359578 +N 2.96115000 0.58504500 8.06630000 -0.43946272 0.13250283 0.69594620 +N 2.27867000 3.74434000 9.16313000 -0.76916608 -0.09237202 1.15148912 +N 1.33337000 0.46358300 3.41559000 0.10660565 -0.00809116 -1.41948549 +N 1.34807000 2.89239000 9.03702000 -2.06604080 -0.93875090 0.59336433 +N 2.23737000 1.32907000 3.47251000 0.40790655 0.72655262 0.57552087 +N 0.39743900 2.24041000 9.23342000 2.41078974 1.40215625 -0.83513030 +N 3.08396000 2.09856000 3.42024000 -0.47720652 -0.61101238 0.14538303 +N 0.18697300 1.80723000 0.10245600 0.83100111 -0.93604610 -1.97913751 +N 3.29532000 2.39052000 12.58820000 -1.18111851 -0.00584196 0.03977826 +N -0.20414600 2.05047000 1.22026000 -2.14194491 1.21611637 3.71043611 +N 3.68595000 1.74066000 11.59400000 -0.15875276 0.75172372 0.42627194 +N -0.76847300 2.32757000 2.19702000 1.02221405 -0.39835541 -1.48620047 +N 4.24790000 1.21827000 10.75980000 0.27799333 -0.34724599 -0.81101336 +C -1.56603000 3.85587000 7.04927000 0.17511732 -0.10840234 -0.63719135 +C 5.12262000 0.21814200 5.62620000 1.96948045 0.53642982 -0.44617330 +C 3.15339000 3.89068000 8.14000000 1.49845435 -0.57735150 -1.20535373 +C 0.37684700 0.53540900 4.38255000 -1.29720896 -1.36014443 2.16306395 +C 0.29077900 -0.66350400 12.57840000 -0.31042574 -0.41063911 -1.27618248 +C 3.13660000 4.78384000 0.10104400 1.63449142 -0.93331559 -1.61832946 +C 2.12377000 -1.03741000 11.43000000 -0.36173262 -0.05407801 -0.24427486 +C 1.35322000 5.29954000 1.18247000 0.31977221 0.25624900 2.31670793 +H 2.82277000 -1.13272000 10.65120000 0.63235768 -0.46825496 -1.12456967 +H 0.70775000 5.56266000 1.98131000 -0.51802587 0.35154334 0.60982967 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.656772153823 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=30 pbc="T T T" +N -2.11528000 4.14829000 8.31336000 1.56354954 0.57879132 -0.68310097 +N 5.65440000 0.00579884 4.30404000 -0.37892661 0.94798116 1.42375866 +N 3.02241000 3.39366000 6.88266000 -0.06088218 -0.30244298 -0.47599193 +N 0.57713300 0.70172200 5.72959000 -1.43264954 0.27408165 1.83865758 +N 4.21854000 3.51310000 6.14393000 -0.47062758 0.29355879 1.29635021 +N -0.69719300 0.69384100 6.40156000 0.02386354 -0.06567163 0.29703801 +N -1.38029000 4.83787000 9.28558000 0.69480463 -0.87675132 -1.09180867 +N 4.85893000 -0.39871000 3.31933000 -1.02018288 -0.09914842 -0.47933590 +N -0.05193860 -1.49402000 10.38530000 -0.88223291 -0.19085504 0.73653878 +N 3.56841000 5.58708000 2.33449000 0.75035589 -0.46631635 -1.13728120 +N 0.78839700 -1.02869000 11.36270000 0.23222101 -0.13496646 -0.08815284 +N 2.72059000 5.17766000 1.32956000 -0.89130891 1.01888190 2.25830275 +N 2.67914000 1.80488000 0.72063200 -0.45530740 0.73612226 1.86683687 +N 0.91509200 2.15798000 12.04050000 -0.86167951 -0.94823827 -2.10373831 +N 2.54859000 -0.69258200 12.62590000 1.40100954 -0.09842131 0.58649434 +N 0.97837500 4.66314000 0.10129100 -0.16183912 -0.40806235 -1.93759877 +N -0.16831000 4.00709000 6.72357000 -1.58069366 0.83561881 4.09010577 +N 3.63378000 0.13175900 5.66779000 1.87146485 0.43204046 -0.06674892 +N 0.07863120 3.89649000 5.55983000 0.89288756 -0.18736657 -3.09401412 +N 3.39492000 0.34237400 6.87420000 -0.49065801 -0.71469469 -0.96629256 +N 0.41447400 3.82683000 4.47410000 0.30696812 -0.15640535 -0.54023505 +N 3.03535000 0.36196400 7.93401000 -0.73123202 0.47728416 2.30661892 +N 2.32609000 3.66231000 9.18010000 -0.38789668 -0.54568065 0.45091699 +N 1.19473000 0.67005200 3.44073000 -0.80642136 -1.23134758 -0.30411214 +N 1.28663000 2.93589000 9.08532000 1.85561657 1.36927184 -0.65867035 +N 2.20734000 1.36404000 3.63844000 -0.97395445 -0.33981139 0.36714376 +N 0.26485000 2.45314000 9.14647000 -0.61902908 -0.78218615 0.23733082 +N 3.13878000 2.00423000 3.61702000 0.85744234 0.77841177 -0.11298199 +N 0.24251000 1.57665000 0.21454400 0.34449131 0.15893120 -0.15061162 +N 3.31166000 2.51341000 12.56210000 -1.04258233 -0.55250436 0.08858839 +N -0.22811100 2.11831000 1.22985000 0.40435739 0.17945477 0.09241779 +N 3.68156000 1.83839000 11.56990000 -1.05129323 1.73204421 2.27492751 +N -0.77076800 2.58914000 2.11516000 -0.19849328 -0.07031607 -0.00007242 +N 4.23047000 1.33958000 10.73800000 1.37980308 -1.49050450 -2.54592692 +C -1.55110000 3.94205000 7.02133000 0.58975450 -0.21650437 -0.09409723 +C 5.03765000 0.34793700 5.51994000 0.74596445 -0.64274494 -0.55497262 +C 3.26102000 3.68512000 8.14818000 -1.85231528 0.12110102 0.00148637 +C 0.32860200 0.37197400 4.51171000 1.52152229 0.41453639 -2.42501822 +C 0.36477400 -0.64708800 12.62680000 -1.00245255 -0.91048934 -0.82910364 +C 3.16519000 4.71668000 0.15861900 2.38667793 0.43900044 -0.70131981 +C 2.20104000 -1.07138000 11.44700000 -2.55712665 0.31281378 -1.14450600 +C 1.31791000 5.15385000 1.22481000 -0.23251771 0.50777436 3.47340611 +H 2.63394000 -1.21021000 10.49930000 1.60698576 -0.34096839 -0.67948086 +H 0.63469000 5.31687000 2.09541000 0.71255553 0.16470075 -0.82174514 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.890653999046 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=49 pbc="T T T" +N -2.21016000 4.30767000 8.20260000 -1.43441845 -0.56566326 2.23670034 +N 5.57979000 0.00332383 4.44463000 -0.27624344 0.33326022 -1.57674958 +N 2.87059000 3.31254000 6.92961000 0.42307091 -0.48704716 0.00909867 +N 0.51046600 0.72021900 5.78689000 1.01417164 0.37161800 0.85665044 +N 4.05927000 3.43112000 6.19349000 0.23377910 0.49515745 0.03429384 +N -0.63337500 0.56569100 6.50390000 -1.07591411 0.43297634 1.80006532 +N -1.41044000 4.75736000 9.24632000 0.46124151 -0.17114754 -0.35045267 +N 4.78545000 -0.32908500 3.36700000 0.82318496 -1.17267501 -1.66080409 +N -0.06143920 -1.59017000 10.37930000 -0.32126757 -0.37217952 -0.77659657 +N 3.61631000 5.62737000 2.40615000 -1.11443438 -0.34024437 0.06089864 +N 0.82902800 -1.27409000 11.37180000 -0.58111045 0.71070948 0.39379736 +N 2.85080000 5.13118000 1.31430000 -0.14608494 0.23886988 1.51669376 +N 2.58476000 1.78098000 0.78126500 -0.31649509 -0.68005164 -1.36175908 +N 1.15194000 2.11775000 11.90670000 -0.62565739 -0.02837243 0.29955974 +N 2.50995000 -0.75175500 12.69950000 0.12056006 0.28569173 -0.51687401 +N 1.18939000 4.67159000 -0.05508570 -0.29129108 -1.17125576 -1.89349921 +N -0.35264400 4.29768000 6.68206000 -0.47538052 -0.16756239 -0.08844132 +N 3.63407000 -0.10762700 5.95683000 2.37493828 0.91148178 -0.35936463 +N 0.07414610 4.09956000 5.51916000 -0.44170318 0.07294785 0.87256042 +N 3.25536000 0.22486500 7.10362000 0.89860056 -0.09608264 -1.34532459 +N 0.69877100 4.04693000 4.56785000 -0.10303336 -0.32546721 -0.44189550 +N 2.78801000 0.48825300 8.09625000 -0.58074021 0.23804199 1.32447294 +N 2.29377000 3.78482000 9.23676000 -0.58170181 -0.62363650 0.38742668 +N 1.09994000 0.55123700 3.44893000 0.33319954 0.16669902 0.02560865 +N 1.28656000 3.04070000 9.09208000 -1.90338253 -0.38420560 0.32213814 +N 2.07102000 1.36011000 3.57712000 -0.83016807 0.07827364 0.63373579 +N 0.27003400 2.50879000 9.12799000 1.22384511 0.21723405 -0.11267551 +N 2.90646000 2.13876000 3.53518000 -0.09534885 -0.56859432 0.03117936 +N 0.19584200 1.38234000 0.17227100 0.64149024 0.89482103 0.72553446 +N 3.49347000 2.29887000 12.53100000 -0.15671748 0.16076080 0.69966402 +N -0.09928740 2.16378000 1.14011000 0.39933552 -2.05241910 -2.65599071 +N 3.90000000 1.89727000 11.42710000 -0.38661781 0.27973551 0.09578748 +N -0.59458600 2.86908000 1.84637000 -1.08622938 1.51960939 2.38838000 +N 4.42644000 1.61558000 10.45720000 0.03542265 -0.29128645 -0.23551665 +C -1.69736000 4.01761000 6.97839000 0.81110591 -0.52452047 -1.53729858 +C 5.06290000 0.23829800 5.68428000 -2.73546865 -1.07605295 1.06187589 +C 3.11675000 3.67480000 8.16378000 2.26841233 2.16761994 -0.86432261 +C 0.24857100 0.41440600 4.56392000 1.13385649 -0.15309788 -2.24106608 +C 0.32957300 -0.83872900 12.61300000 0.42117807 -0.49063899 -0.24314666 +C 3.37235000 4.62740000 0.11218200 0.60568506 0.85770973 -0.00046487 +C 2.20593000 -1.13135000 11.45870000 0.06700449 -0.27421227 1.21141639 +C 1.44473000 5.00861000 1.14985000 1.73626597 1.10302383 0.45809499 +H 2.91975000 -1.44917000 10.70940000 -0.04463718 0.16427858 -0.06428169 +H 0.70889300 5.25742000 1.86951000 -0.42229752 0.31590270 0.88089594 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.574076757937 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=50 pbc="T T T" +N -2.23124000 4.30636000 8.23264000 0.24394987 -0.04236340 0.41110603 +N 5.58664000 0.01906340 4.46425000 0.43752771 -0.32823577 -4.14269511 +N 2.89820000 3.28867000 6.95133000 0.02622633 -0.11041911 0.02203636 +N 0.48720900 0.67422400 5.79349000 2.29136714 1.51494541 2.52019532 +N 4.05215000 3.42553000 6.21739000 1.09544421 0.36854347 -0.44695955 +N -0.66151500 0.59195500 6.51826000 -1.04099853 -0.41350384 0.66875936 +N -1.42063000 4.78002000 9.24372000 0.88733912 -0.40723240 -0.94292637 +N 4.81124000 -0.33677600 3.35232000 -0.05886901 -0.70277505 -0.52655164 +N -0.06680650 -1.57911000 10.35100000 -0.34304173 -0.16179592 1.19644229 +N 3.62092000 5.63021000 2.40602000 -0.43085416 -0.58912201 -0.40252677 +N 0.83752100 -1.30380000 11.39000000 -1.54888397 0.88220206 -0.67494029 +N 2.85877000 5.12821000 1.31297000 0.24710307 0.05544841 0.81318851 +N 2.56694000 1.75967000 0.76281200 0.77588694 0.43301645 -0.19422987 +N 1.16833000 2.10032000 11.89860000 -0.34850018 0.22290899 0.49952112 +N 2.56712000 -0.74157800 12.69600000 -2.26694680 -0.01970375 -0.03256462 +N 1.17473000 4.68541000 -0.07836060 0.74242661 -1.31600887 -1.75068471 +N -0.36490300 4.28816000 6.70582000 0.25818915 -0.08579771 -0.85096316 +N 3.62491000 -0.13767500 5.96433000 2.49616065 1.22249271 0.10238493 +N 0.06958540 4.11448000 5.52777000 -0.23245755 0.02065542 0.77944535 +N 3.28010000 0.22029900 7.12905000 -0.38844381 0.33556650 0.15213989 +N 0.70981500 4.07822000 4.57570000 -0.63605493 -0.29297052 0.36488170 +N 2.75404000 0.50436100 8.11429000 0.77128981 -0.43163371 -0.96334093 +N 2.27274000 3.78528000 9.24536000 -0.48990108 -0.88356474 -0.31199668 +N 1.08693000 0.53805300 3.43603000 -0.03042782 -0.41133948 0.04154085 +N 1.24158000 3.03794000 9.11292000 2.13658673 1.55189730 -0.46786210 +N 2.05881000 1.31993000 3.53964000 -1.02366416 0.02033439 0.83983542 +N 0.25082300 2.50389000 9.09003000 -1.05982929 -0.90854558 0.10840182 +N 2.86625000 2.11161000 3.54343000 1.02655922 0.36239956 -0.08214315 +N 0.18096600 1.38933000 0.14971800 1.31738698 0.54750099 0.08855548 +N 3.50401000 2.31700000 12.54350000 1.23529166 -0.22901279 -0.64879217 +N -0.11325600 2.14027000 1.11332000 -1.66470702 1.43260326 0.86668802 +N 3.94441000 1.93467000 11.41810000 -1.23151214 0.45578049 1.21845093 +N -0.59574500 2.87533000 1.85924000 0.78350255 -1.33914880 -0.44472011 +N 4.44284000 1.63932000 10.43850000 0.10136060 -0.16433360 -0.07545159 +C -1.69252000 4.00886000 6.99479000 0.23618771 -0.42502135 -1.30973024 +C 5.06632000 0.20761000 5.65705000 -3.50597170 -0.27143650 3.38138633 +C 3.15849000 3.73299000 8.15096000 -1.51605612 0.64132055 1.56670685 +C 0.28016300 0.43009000 4.57486000 -0.70446684 -1.08082492 -2.84080160 +C 0.33863700 -0.79043800 12.58310000 -0.54251819 -1.38974297 0.11293931 +C 3.40380000 4.62972000 0.10758600 -0.96163886 0.70620491 -0.22999855 +C 2.17709000 -1.15795000 11.49730000 3.00430319 -0.62501461 0.09272221 +C 1.46715000 5.01172000 1.11979000 0.30453431 1.85095774 2.06864276 +H 2.97224000 -1.52727000 10.84010000 -0.67505856 0.23710868 -0.38758815 +H 0.75395300 5.34994000 1.88280000 0.28217292 -0.23234545 -0.18852048 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.496197777016 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=70 pbc="T T T" +N -2.19882000 4.15344000 8.17730000 0.28141598 0.99956263 2.06519234 +N 5.56755000 -0.02387750 4.43378000 0.75354406 0.11481570 -0.08556888 +N 2.84287000 3.60406000 6.75666000 0.60161243 -0.25074169 0.35991433 +N 0.44158000 0.63886400 5.91927000 0.49613704 0.77467853 1.13909126 +N 4.04926000 3.75601000 6.04947000 -1.45350632 -0.31203936 -1.06162906 +N -0.79422800 0.55732200 6.59597000 0.89750012 -0.25892089 -0.73024986 +N -1.41154000 4.51181000 9.28506000 0.56314873 0.40843568 0.34489703 +N 4.86403000 -0.59859900 3.40442000 -0.42600403 0.39776560 0.17004196 +N -0.11723200 -1.28432000 10.21890000 -1.55422672 -0.84451483 -1.50875933 +N 3.63632000 5.73282000 2.35089000 0.63650744 0.17825715 -0.35952095 +N 0.63804400 -1.01838000 11.29020000 1.47112867 -0.10790097 1.12604034 +N 2.90614000 5.26744000 1.27291000 1.50106145 -0.50936742 1.30268541 +N 2.45504000 1.54945000 0.81307300 -3.10034418 0.10503419 -0.25300015 +N 1.40113000 2.11238000 11.88350000 0.99828737 0.47446881 0.39685903 +N 2.29490000 -1.01395000 12.76250000 2.20852620 0.28081794 -2.33406802 +N 1.46103000 4.50881000 -0.17112700 -2.32540340 0.30904969 2.12057904 +N -0.36340900 4.39968000 6.63212000 -0.69600791 -0.16533119 0.99788628 +N 3.66556000 0.12658500 5.90463000 -0.77777928 -1.09936772 -0.88551878 +N -0.05284860 4.11646000 5.47336000 0.52744639 -0.30935873 -0.30875452 +N 3.38343000 0.20320300 7.10450000 -0.17264546 0.72413578 -0.75909764 +N 0.37954200 3.87023000 4.45262000 0.30532930 0.01794496 -0.57087232 +N 2.98033000 0.46777300 8.12000000 -0.70754702 -0.02098257 1.98338498 +N 2.25029000 3.75898000 9.08963000 -1.75062301 -1.34142165 0.66031071 +N 1.18039000 0.43702800 3.61975000 0.48037617 0.42488560 -0.43798588 +N 1.24253000 2.94042000 8.93030000 3.63772531 2.34134424 -0.27276474 +N 2.11345000 1.27274000 3.72327000 1.20645416 0.26892042 0.66357087 +N 0.33142700 2.28735000 8.91654000 -1.42206688 -1.02205465 0.15175679 +N 3.06766000 1.91700000 3.76971000 -1.32644241 -0.52826400 -0.48405285 +N 0.02724340 1.76916000 0.05058130 0.16863300 -0.17065594 1.89967500 +N 3.64964000 2.39910000 12.68170000 1.42952822 0.53060884 -0.06860115 +N -0.25972200 2.07088000 1.26436000 0.10140122 0.05357356 -1.70430201 +N 4.10603000 2.12942000 11.52990000 -2.77920825 1.06344941 4.32039948 +N -0.61869200 2.47716000 2.25812000 -0.49584187 -0.07685233 0.51413733 +N 4.49305000 1.75999000 10.56150000 1.68840231 -1.18921235 -3.73989067 +C -1.71020000 4.08594000 6.90173000 2.23294139 0.33479568 0.33130875 +C 5.00477000 0.15828600 5.68102000 0.22769278 0.51544962 0.11272436 +C 3.14536000 3.80525000 8.04243000 -1.89512415 0.01466218 -0.79070678 +C 0.28185300 0.40265800 4.66132000 -1.24513384 -0.96153602 -0.87450932 +C 0.13589800 -0.75602100 12.60830000 1.38127375 0.01311597 -1.48850418 +C 3.53569000 4.82678000 0.13702800 0.93923427 -0.66031071 -1.67309396 +C 2.03916000 -1.13342000 11.44640000 -0.36867562 -0.44869144 0.39631704 +C 1.60974000 4.96556000 1.10855000 -1.85097830 -0.59947327 -1.84148579 +H 2.69730000 -1.34462000 10.55130000 -0.52047870 0.26164060 1.38720272 +H 0.83463900 5.03150000 1.87018000 0.13273012 0.26958839 -0.21103255 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.947035986632 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=80 pbc="T T T" +N -2.17423000 4.27931000 8.16663000 0.70269278 -0.36341772 0.53870268 +N 5.62835000 -0.01034450 4.46394000 0.33877832 -0.76180244 -1.41205500 +N 2.92611000 3.70855000 6.72033000 -0.70038393 -0.92379222 -2.74393786 +N 0.50250300 0.65888600 5.95496000 0.26091503 0.33008131 -0.78217072 +N 4.15248000 3.75845000 6.06399000 -1.43640335 -0.57794800 -2.60572564 +N -0.72186300 0.58339700 6.61550000 -0.27568242 -1.24712902 -1.61429283 +N -1.40847000 4.54879000 9.27677000 -0.68167144 1.09613841 1.16148557 +N 4.95486000 -0.64145600 3.41795000 0.50520634 0.21454313 -0.73522238 +N -0.20139700 -1.35113000 10.23740000 0.42420425 -0.23316100 -1.03229278 +N 3.73600000 5.69366000 2.32727000 -0.18393415 -0.07966717 1.77554214 +N 0.58748100 -0.97699900 11.30670000 -0.43307816 -0.59374485 -0.33347414 +N 2.99369000 5.09206000 1.35201000 0.25455053 0.53100994 0.41912735 +N 2.28308000 1.68939000 0.81053200 1.36075121 0.29003689 -0.51464744 +N 1.30659000 2.17092000 11.92230000 -1.96722816 0.05318121 -0.15036531 +N 2.22311000 -0.84264700 12.74520000 0.91259764 0.18994282 0.29994952 +N 1.31671000 4.76062000 -0.02237460 0.59054126 -0.64351113 -0.63623490 +N -0.22433400 4.18498000 6.68135000 -1.08132372 0.01211668 1.15493440 +N 3.71568000 -0.03331620 6.00182000 0.27172035 -0.11497716 -1.99446129 +N 0.01871730 3.92745000 5.50207000 0.89348406 0.16122771 -1.26283846 +N 3.44700000 0.30458700 7.15177000 -0.68286957 -0.71033924 0.92410590 +N 0.37008200 3.79387000 4.42712000 0.11566210 -0.21126138 -0.12207135 +N 3.02419000 0.37715400 8.20558000 -0.17959978 0.59227932 0.57898158 +N 2.30406000 3.67689000 9.02647000 -0.56228484 -0.01034411 0.01434727 +N 1.14274000 0.55000200 3.56340000 0.67359818 0.03477993 0.07112186 +N 1.31585000 2.90746000 8.81420000 1.02700145 0.66232646 -0.11035843 +N 2.12916000 1.33037000 3.68558000 -1.53565307 -1.04755485 0.41388950 +N 0.39784200 2.23548000 8.80291000 0.00813749 -0.09947495 0.21207076 +N 3.01354000 2.02522000 3.58241000 0.99218357 0.70743904 0.00282347 +N -0.01937530 1.52890000 0.19541300 -0.98923708 0.86366955 0.32676973 +N 3.61422000 2.45762000 12.57860000 0.90866385 0.02909070 1.26849488 +N -0.38546700 2.03659000 1.29335000 -1.58147013 0.37355455 1.48022009 +N 4.08359000 2.04785000 11.51570000 -1.16129017 0.47243095 -0.04617938 +N -0.95494900 2.38865000 2.24727000 1.40988499 -0.67743426 -2.18486176 +N 4.47031000 1.81006000 10.48230000 0.92875960 -0.68139890 -1.15212675 +C -1.61019000 4.03277000 6.91361000 2.23175868 0.92672842 2.06341827 +C 5.05793000 0.09843850 5.69464000 0.33597942 1.71829910 2.14673230 +C 3.15140000 3.94349000 7.93892000 -0.81853640 0.04424946 3.84845293 +C 0.32209600 0.36963900 4.66324000 -0.25406510 0.34183845 0.64479154 +C 0.06845560 -0.63476700 12.58580000 0.22807331 -1.29637593 -1.14493795 +C 3.51129000 4.70625000 0.10692800 0.22514019 0.40121808 0.83071315 +C 1.96284000 -1.09537000 11.47860000 -0.50091774 0.02808082 0.53112306 +C 1.62900000 5.11189000 1.20239000 -1.01810543 0.43571097 -0.40695832 +H 2.63592000 -1.42871000 10.67280000 -0.18460624 0.34212127 0.50602910 +H 0.90671200 5.57578000 1.90395000 0.62804337 -0.57876561 -0.22859370 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.603737166466 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=99 pbc="T T T" +N -2.08409000 4.15305000 8.18619000 -0.43269352 0.05793724 -0.17877652 +N 5.66499000 0.06588720 4.39111000 -1.97800109 -0.55422700 1.24556064 +N 2.96815000 3.49268000 6.79047000 -0.39052537 -0.55752829 -0.79133927 +N 0.51541400 0.88958900 5.75468000 -0.96450307 0.11819001 1.65665947 +N 4.18014000 3.52378000 6.06158000 -0.56603865 0.47035041 0.15540827 +N -0.73123700 0.77727500 6.54301000 0.60235291 -1.03170142 -2.07131670 +N -1.34196000 4.70617000 9.23184000 0.23354564 -0.57301148 -1.81332707 +N 4.91931000 -0.40984300 3.36823000 -0.70903826 -0.06219961 0.31608937 +N -0.12069000 -1.65119000 10.26330000 -0.85850677 0.48242534 0.90314112 +N 3.68687000 5.61463000 2.38534000 0.95072196 0.45289622 0.87710099 +N 0.57520700 -1.10532000 11.30100000 1.46716402 -0.40893961 -0.76435812 +N 2.90747000 5.21029000 1.39231000 -0.29539044 -0.70317100 -1.66593087 +N 2.14045000 1.73408000 0.73506800 0.66096377 0.65856751 1.01427449 +N 1.29417000 2.23935000 11.97270000 -1.20753403 -0.41706944 -1.33645942 +N 2.15416000 -0.62944900 12.79620000 -0.42254486 -0.72659890 -2.20321944 +N 1.31870000 4.68599000 -0.02492560 -0.52894791 -0.17887833 -0.61432396 +N -0.23227500 4.19988000 6.67414000 1.97215440 -0.32491493 -1.55827364 +N 3.69834000 -0.02140740 5.89521000 0.16618737 0.00625009 0.36856558 +N 0.21990100 3.91070000 5.50895000 -2.28754648 0.74039544 3.20533261 +N 3.42593000 0.26084500 7.09500000 -0.11062994 -0.59087550 -2.64436932 +N 0.61152600 3.72512000 4.47360000 0.79671802 -0.15779477 -1.60226007 +N 2.93371000 0.47847500 8.06957000 -1.03012791 0.57832852 2.89653797 +N 2.31617000 3.72277000 9.17775000 0.32323292 -0.30411317 -1.09499684 +N 1.18314000 0.64684000 3.46075000 -0.11683041 -0.57152024 0.41011461 +N 1.37270000 2.88786000 9.02484000 0.77463225 1.00386152 -0.44102338 +N 2.12002000 1.42180000 3.79167000 0.04840529 0.52750295 -0.96697647 +N 0.46619400 2.21194000 8.98496000 -0.50739795 -0.58260169 0.24884062 +N 2.91933000 2.22866000 3.78856000 0.62113739 -0.17579095 0.06238833 +N -0.17980600 1.31321000 -0.02472260 0.26296678 1.26212883 1.78916898 +N 3.59787000 2.57102000 12.64120000 -0.11707055 0.46222881 1.18945917 +N -0.50858100 1.84713000 1.11776000 1.37312850 -1.86988106 -4.54434257 +N 4.08379000 2.08466000 11.62890000 2.28436860 -3.12321157 -4.26315644 +N -1.00911000 2.30510000 1.99196000 -1.44857495 1.50914500 3.20043208 +N 4.66981000 1.53782000 10.74900000 -2.33517874 2.29134143 3.01467502 +C -1.55717000 3.95474000 6.88889000 -0.54777867 -0.11893769 1.16514168 +C 5.02575000 0.23750100 5.70134000 3.47486649 1.26025193 -1.63931481 +C 3.17888000 3.79909000 8.03189000 1.03129005 0.31289194 1.61275017 +C 0.30424100 0.49322900 4.52306000 -0.27991343 0.10354552 0.79879033 +C -0.03431180 -0.81715200 12.50170000 0.21985040 -0.69114853 -0.78121427 +C 3.47481000 4.81471000 0.15539300 0.56805953 0.62932892 1.54051760 +C 1.98939000 -0.97615700 11.48100000 -2.33673683 0.65657233 3.74594304 +C 1.52007000 5.09322000 1.18870000 0.18843667 0.17929074 1.05821978 +H 2.75025000 -1.29975000 10.83410000 0.78113199 -0.18760311 -1.07523020 +H 0.73723900 5.23214000 1.95766000 0.67019918 0.14828632 -0.42490874 +44 +Lattice="6.6604 0.0 0.0 -1.9016531446419103 6.428112286470541 0.0 -1.2514063926874133 -2.2750363427377365 12.652321829591736" Properties=species:S:1:pos:R:3:forces:R:3 energy=-14300.885429413325 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=COVSEM frame=100 pbc="T T T" +N -2.06816000 4.13229000 8.19665000 -0.59892820 0.08295870 -0.85336457 +N 5.66658000 0.08812950 4.43466000 -2.69950406 -1.77635461 -2.03336208 +N 2.94210000 3.48901000 6.78420000 0.83248721 -0.02510235 -0.09207069 +N 0.48913300 0.87356800 5.76157000 -0.15657453 0.32315630 1.59728756 +N 4.18894000 3.55058000 6.05478000 -1.61222567 0.11321544 -0.27254619 +N -0.73779700 0.77847800 6.53305000 1.08693386 -1.04367762 -1.77162892 +N -1.33131000 4.70283000 9.22050000 -0.63873916 -0.69014065 -0.93116615 +N 4.92037000 -0.37283200 3.36212000 -0.70374179 -0.05155010 0.61867427 +N -0.14876000 -1.65190000 10.24910000 0.61171172 0.70676026 0.49881047 +N 3.70127000 5.62885000 2.39683000 0.69553997 0.45462349 1.17801776 +N 0.57507600 -1.10921000 11.28070000 0.94310121 -0.08011095 0.26703632 +N 2.92245000 5.19989000 1.41013000 -0.77040535 -0.55756429 -2.52402626 +N 2.15078000 1.73191000 0.73085000 0.41234890 0.68678793 1.48805681 +N 1.28167000 2.23173000 11.95200000 0.20686325 0.14842002 0.10298142 +N 2.15480000 -0.63546300 12.78030000 -0.17317614 -0.03753096 0.09988941 +N 1.30881000 4.67423000 -0.04515400 -0.14010867 0.19238434 0.00402611 +N -0.21166000 4.15910000 6.66579000 0.35804977 0.05066446 0.22255880 +N 3.69264000 0.00757267 5.88872000 0.77306387 -0.10402221 0.06690987 +N 0.22676400 3.91507000 5.52836000 -0.62934949 -0.25936723 -0.86140183 +N 3.41188000 0.24572100 7.08834000 -0.94407823 0.19326057 -0.06039316 +N 0.62766100 3.70435000 4.47400000 -0.19531128 0.39947693 0.78719980 +N 2.92742000 0.46567200 8.09756000 0.27605215 -0.12039396 0.05860675 +N 2.32521000 3.70969000 9.17320000 0.25805597 -0.66939185 -1.33436140 +N 1.17706000 0.68272700 3.45812000 -2.21431118 -2.24400228 0.26092686 +N 1.37624000 2.86484000 8.98959000 1.64814912 1.88738513 0.02291275 +N 2.11070000 1.39421000 3.79151000 2.53822904 3.26918338 -0.29293298 +N 0.45122800 2.22715000 9.03674000 -1.09159784 -1.08612139 0.06808024 +N 2.90322000 2.23316000 3.82872000 -0.37299816 -1.52676734 -0.00065926 +N -0.15907200 1.33212000 -0.01717700 0.74289455 0.78367739 0.58834039 +N 3.61792000 2.54851000 12.64100000 -0.40990532 0.21484395 0.54004479 +N -0.48172200 1.87585000 1.07338000 -2.78066350 1.62453096 3.16113020 +N 4.06892000 2.03755000 11.59410000 -1.66213592 0.73952640 2.08031042 +N -1.02421000 2.33916000 2.01294000 2.09634896 -1.51046140 -3.04694237 +N 4.64488000 1.55185000 10.76820000 1.16326477 -1.03693619 -2.34323143 +C -1.57683000 3.96327000 6.88394000 1.39904008 0.11869652 1.26019536 +C 5.05818000 0.22955300 5.67080000 0.51612839 1.39435038 0.48379317 +C 3.20710000 3.79133000 8.03502000 -0.18749616 -0.08036189 1.24102007 +C 0.28150100 0.46833100 4.52320000 1.66729869 1.12674482 1.08318519 +C -0.00940967 -0.81595600 12.49660000 -0.48869215 -0.82907278 -1.11524685 +C 3.47841000 4.83438000 0.16741800 0.41465209 -0.34519888 -0.12130259 +C 1.97611000 -0.95847800 11.53420000 -0.36105179 -0.66031071 -0.92384879 +C 1.51751000 5.10552000 1.16503000 1.75789409 -0.29978909 -0.20112969 +H 2.78817000 -1.19530000 10.84180000 -0.44363562 0.10933513 -0.11197977 +H 0.81324600 5.22381000 1.92440000 -1.12347952 0.41424946 1.11160617 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7267.569463858868 energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" name crystal=NIKVUZ frame=0 pbc="T T T" +O 0.31692900 0.99801900 3.05328000 -0.01925052 -0.02874365 -0.01923921 +O 3.00263000 2.44335000 7.78473000 -0.01429163 0.02099393 0.01552293 +O 5.05522000 4.43860000 2.36578000 0.01501169 -0.02246399 0.01679959 +O 2.36993000 5.88516000 8.47163000 -0.00110436 0.00174112 -0.00690254 +O 5.04152000 2.99531000 5.54604000 -0.02724341 -0.00174768 0.01504383 +O 2.35579000 0.44566700 5.29205000 -0.03139831 0.00131992 -0.02009389 +O 0.33051100 6.43622000 10.71060000 0.02392124 -0.00127244 -0.01372851 +O 3.01764000 3.88672000 0.12829400 0.00102084 0.00103716 -0.00617265 +C 0.90230000 1.95266000 3.53503000 0.01686587 -0.00415657 -0.00767073 +C 3.58810000 1.48863000 7.30299000 0.01896585 -0.00126277 0.00400509 +C 4.46970000 5.39324000 1.88406000 -0.01903948 0.00423183 0.00359221 +C 1.78399000 4.93047000 8.95323000 -0.02244455 -0.02038504 0.00527755 +C 0.57899900 2.92419000 4.73145000 -0.00760399 0.00253981 0.01129979 +C 3.26514000 0.51678100 6.10657000 -0.01033712 -0.00270164 -0.01403056 +C 4.79294000 6.36514000 0.68737200 0.00750541 0.00218454 -0.00940448 +C 2.10800000 3.95751000 10.15140000 -0.01334449 0.00102271 -0.01208233 +C 1.84728000 3.71527000 4.42247000 0.01775969 0.03001547 0.01960708 +C 4.53343000 6.60718000 6.41515000 0.01434748 -0.02289094 -0.01621476 +C 3.52447000 0.27466000 0.99625800 -0.01499838 0.02334500 -0.01581660 +C 0.83826900 3.16550000 9.84194000 -0.00901969 -0.00786475 0.00731067 +H 2.60353000 3.64135000 5.23063000 0.01009163 0.00076267 0.01079077 +H 5.28982000 6.68169000 5.60678000 0.00392720 -0.00379150 -0.00408354 +H 2.76804000 0.20024400 11.02570000 -0.00341464 0.00366960 -0.00320783 +H 0.08119390 3.24108000 -0.18683500 0.01689127 -0.01085797 -0.01817266 +H 1.67358000 4.77352000 4.20345000 -0.00208317 0.00896256 -0.00295851 +H 4.35936000 5.54877000 6.63457000 0.00104835 0.00079216 -0.00075635 +H 3.69843000 1.33311000 1.21567000 -0.00061135 -0.00118911 -0.00084740 +H 1.01281000 2.10638000 9.62162000 -0.00861356 0.02988229 0.01109143 +C 2.15391000 2.77824000 3.21726000 -0.00095611 -0.02045307 -0.00340469 +C 4.83964000 0.66269900 7.62030000 0.00264694 0.02055962 0.00728918 +C 3.21793000 6.21920000 2.20169000 0.00222579 -0.02023597 0.00227853 +C 0.53095500 4.10360000 8.63518000 0.02250697 0.02138016 0.01662774 +H 2.10899000 3.24201000 2.22615000 -0.00737058 0.01639459 -0.02369482 +H 4.79503000 7.08104000 8.61135000 -0.00857160 -0.01939291 0.02871002 +H 3.26294000 -0.19886600 3.19291000 0.00655585 0.01465097 0.02047169 +H 0.57735200 3.63880000 7.64322000 -0.00166863 0.00468748 0.01345340 +H 3.10062000 2.22111000 3.30657000 0.00689889 -0.01265008 0.00621081 +H 0.41441400 1.21965000 7.53135000 0.01122945 0.01569098 -0.00815508 +H 2.27114000 5.66197000 2.11229000 -0.00377589 -0.01006463 -0.00527894 +H 4.95553000 4.66213000 8.72594000 0.02772107 -0.01373987 -0.00346634 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.1367300700795 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=10 pbc="T T T" +O 0.48602900 0.98961100 3.03245000 0.17050271 1.62337911 0.74280199 +O 2.97674000 2.43746000 7.87941000 0.41351515 -1.91100842 -1.22005530 +O 5.16566000 4.44612000 2.22285000 0.57083632 -0.93843209 0.47122562 +O 2.50196000 5.83856000 8.36820000 -0.11608377 -0.45210792 0.84774928 +O 4.89164000 3.08979000 5.52886000 -0.58134185 -0.27056284 0.29486851 +O 2.38387000 0.38941900 5.10080000 1.17969412 0.43046026 1.86826126 +O 0.33220700 6.52395000 10.68980000 -1.47998869 -0.40157546 1.52874709 +O 3.07871000 3.70708000 0.19654300 0.62795081 -0.02799458 0.86255369 +C 0.88712500 2.04897000 3.54281000 0.10286264 -1.44353044 -1.07965764 +C 3.45345000 1.42638000 7.33741000 1.04158989 0.71853592 0.69634215 +C 4.49848000 5.35912000 1.79032000 -0.33426912 -0.03536054 0.67906434 +C 1.88273000 5.00596000 9.01816000 -0.60439950 0.13790009 -0.22965196 +C 0.45152100 3.00522000 4.75505000 0.62998712 -0.42196071 -0.06715773 +C 3.21695000 0.47003000 6.03161000 -1.15311920 -0.40840637 -1.59287554 +C 4.78467000 6.36411000 0.69419700 0.52406282 1.36270525 -2.34040836 +C 2.15942000 3.92743000 10.29470000 -0.66453761 0.77462710 -2.21749935 +C 1.75426000 3.73988000 4.61253000 -0.43203429 0.84010796 -1.96209624 +C 4.50777000 6.57984000 6.32457000 0.03446240 0.81783706 0.20225069 +C 3.40616000 0.17319900 1.00874000 1.81020575 -0.20401858 0.47108523 +C 0.85154700 3.27096000 9.89542000 0.18599926 1.26714248 -0.33468564 +H 2.53043000 3.59590000 5.30372000 1.04683494 -0.22512734 1.91405261 +H 5.34111000 6.71927000 5.59763000 -0.37395050 -0.06616785 -0.23061458 +H 2.69794000 -0.03232140 11.06690000 -0.76296458 0.16711399 -0.87785175 +H 0.16209400 3.47972000 -0.14752800 -0.98978730 0.07553953 0.88800761 +H 1.62077000 4.81710000 4.44616000 0.01683527 -0.00642503 0.10725357 +H 4.37480000 5.51112000 6.52852000 -0.12522301 0.05425748 -0.20146547 +H 3.46486000 1.20708000 1.29349000 -0.03648272 0.73723298 -0.22845074 +H 0.88367200 2.23139000 9.75455000 0.09424122 -1.58776933 -0.32997692 +C 2.14229000 2.93848000 3.33564000 -2.45244675 1.75825404 -1.35980504 +C 4.76348000 0.56017600 7.59254000 0.25125643 0.67096022 -0.70189059 +C 3.23965000 6.09668000 2.18317000 -1.94509096 -0.94169224 0.27881094 +C 0.58446300 4.21134000 8.68579000 0.32749221 0.47096131 0.60916119 +H 1.98624000 3.62194000 2.41353000 0.15028509 -1.33078757 1.09846783 +H 4.63270000 6.77796000 8.43033000 0.18202331 0.28744728 0.92719122 +H 3.23388000 -0.33944400 3.17008000 0.48591279 0.27507873 0.44363357 +H 0.79608400 3.77995000 7.71948000 -0.08531743 -0.52618655 -0.53338564 +H 3.10350000 2.50730000 3.25281000 1.28873975 -0.77992358 0.19434352 +H 0.40102200 1.09349000 7.56475000 -1.13209786 -0.33755962 0.30867019 +H 2.22315000 5.55507000 2.20694000 1.21392065 0.27615705 -0.33065004 +H 4.95863000 4.74612000 8.61014000 0.91993043 -0.42910581 0.40363080 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.244106191224 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=20 pbc="T T T" +O 0.33247500 1.23597000 3.01226000 0.07612162 0.09002923 0.81885522 +O 2.86408000 2.29061000 7.72974000 0.93309962 -0.10081655 -0.18690892 +O 5.07118000 4.37668000 2.26985000 1.29345001 -1.80150514 1.14867633 +O 2.58409000 5.79595000 8.56482000 -1.40314356 -1.24458877 0.15026864 +O 4.90254000 3.03697000 5.62321000 0.37484422 0.35425739 -0.56041821 +O 2.40022000 0.40077400 5.16578000 -0.93270881 -0.15278112 -0.59254158 +O 0.26587900 6.56870000 10.75290000 -0.58623209 -0.90810335 0.29352845 +O 3.10630000 3.80093000 0.15024700 -2.11993626 -0.40853595 -2.03366033 +C 0.88850500 2.09660000 3.68917000 0.45587613 -0.03548616 -1.86559760 +C 3.62248000 1.50134000 7.16671000 -1.32421583 -0.45426611 -0.33264676 +C 4.46389000 5.31762000 1.87041000 -1.72484513 1.05961332 -0.87430363 +C 1.89178000 4.81813000 8.93202000 2.79530336 1.48048234 0.18373977 +C 0.45107400 3.06881000 4.79961000 -0.26550343 -0.27953599 1.12449254 +C 3.29866000 0.50060600 5.96625000 0.47674063 0.55816079 0.46884426 +C 4.70662000 6.30133000 0.68793900 1.47008480 1.26550726 -0.28971293 +C 2.20276000 3.79689000 10.09700000 1.05455853 0.77996986 1.77932166 +C 1.72996000 3.90135000 4.61837000 0.04991529 -1.65698343 -0.06469153 +C 4.53391000 6.58705000 6.32517000 0.33074517 -2.21092761 -0.02418904 +C 3.50176000 0.20255400 1.09388000 0.07244957 1.89086640 -0.39192251 +C 0.84507600 3.12245000 9.80734000 0.87900361 -1.04411985 -1.16724484 +H 2.33766000 3.82546000 5.55055000 0.08079846 0.00158552 -0.29452192 +H 5.35862000 6.55754000 5.55888000 -0.59645994 -0.25842004 0.15485857 +H 2.81818000 0.25161200 11.05790000 -0.38737423 0.23648133 0.40912165 +H 0.09178990 3.08009000 -0.22877200 -0.03865499 0.04046382 0.11392610 +H 1.56016000 4.91488000 4.36760000 -0.07419432 1.26335268 -0.25898671 +H 4.27289000 5.54766000 6.75531000 0.43122337 1.23211892 -1.10757468 +H 3.83378000 1.24862000 1.42429000 -0.61650426 -1.13738919 -0.52267956 +H 0.99776100 2.10667000 9.32561000 -0.19650324 0.71974948 0.98163176 +C 2.16606000 2.94741000 3.42232000 0.11275933 -0.89123692 2.31816318 +C 4.86585000 0.64483500 7.43809000 -0.27229885 1.03681792 3.19511504 +C 3.15757000 6.12000000 2.22813000 -0.19055114 -0.75981241 0.64375795 +C 0.62547800 4.14230000 8.61699000 -2.42957936 -0.40940087 -0.10611406 +H 2.08967000 3.39649000 2.48027000 -0.15114847 0.79002801 -1.65772905 +H 4.72308000 7.12495000 8.51283000 0.54272902 0.39855339 -1.38163371 +H 3.16253000 -0.35773500 3.27621000 -0.10817917 -0.26624236 -0.86997904 +H 0.56075000 3.56886000 7.65670000 0.18481912 0.77568640 0.38735829 +H 3.15958000 2.42804000 3.48016000 -0.57053808 0.33692044 0.23669319 +H 0.42300600 1.21716000 7.36453000 0.40708019 -0.12985665 0.04353649 +H 2.20528000 5.52540000 2.03317000 0.86487797 0.46637086 0.30623793 +H 5.04151000 4.78582000 8.71936000 1.10209309 -0.62700979 -0.17507670 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.021054476822 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=30 pbc="T T T" +O 0.34238600 1.21746000 3.05785000 0.57197789 1.45353204 0.78147138 +O 3.06443000 2.34778000 7.71419000 -1.08188936 1.02438921 0.31232064 +O 4.98750000 4.23578000 2.31385000 -0.90468893 1.70732563 -0.62695322 +O 2.54557000 5.75274000 8.44850000 -0.77976931 -1.29375854 0.49958848 +O 4.98087000 3.27672000 5.55075000 -0.18440620 -0.54026591 0.39028318 +O 2.31095000 0.40705700 5.29676000 -0.60403955 -0.02362715 -0.78397049 +O 0.25187200 6.58545000 10.81660000 1.12920794 0.03443437 -0.82711875 +O 2.95900000 3.74247000 0.03138510 2.84632947 -0.42638301 2.94934843 +C 0.87412400 2.20318000 3.59671000 0.40061284 -1.52341976 -0.33663248 +C 3.54707000 1.33863000 7.26809000 1.71108972 -0.65030912 0.10091786 +C 4.39861000 5.26868000 1.92779000 2.12465167 -2.19864287 0.33707060 +C 1.87347000 4.80041000 8.89093000 0.02794152 1.80073381 -0.81952885 +C 0.59800100 3.09649000 4.85968000 -0.63534016 0.87234445 -0.29745298 +C 3.22753000 0.38201200 6.08929000 1.23560019 0.13722183 -0.16414128 +C 4.78068000 6.42258000 0.82057900 -1.17612029 -1.53100966 1.08631166 +C 2.08649000 3.83526000 10.09030000 -2.69426929 0.06104313 -2.98344640 +C 1.84693000 3.94786000 4.57845000 -0.78212444 0.44723208 0.74938915 +C 4.65777000 6.62419000 6.13439000 -0.64533147 2.20266408 2.10665395 +C 3.53087000 0.21429000 1.22820000 -1.47474878 -0.54888425 0.30525062 +C 0.82708100 3.04400000 9.65602000 0.11381348 0.12930643 1.00813983 +H 2.58629000 3.95958000 5.42117000 -0.15113664 -0.07250562 -0.53698004 +H 5.35664000 6.93953000 5.31407000 -0.51401957 -0.38874154 0.31271145 +H 2.74411000 0.39111400 11.30710000 0.03051113 -0.24489295 -0.13134223 +H 0.05348530 3.03090000 -0.36073700 0.32347512 -0.31300404 -0.55923036 +H 1.51114000 5.01463000 4.38703000 0.43972600 -1.06212272 0.03606096 +H 4.65875000 5.58673000 6.37266000 0.14339865 -1.01503553 -0.14961609 +H 3.73999000 1.13829000 1.63802000 0.48113928 2.35085732 0.94795031 +H 1.16273000 2.03671000 9.32084000 -0.57362854 0.38207467 0.32223687 +C 2.14162000 3.03468000 3.37516000 1.11015607 0.50831995 -0.80015302 +C 4.90995000 0.68689400 7.52480000 -1.21794700 -1.94463845 -1.28575727 +C 3.15217000 5.98953000 2.31832000 0.19958497 1.41135566 -0.97139877 +C 0.56104000 4.06707000 8.50651000 0.33235211 -0.07728890 0.89033703 +H 2.24329000 3.58619000 2.43018000 -0.37755313 -0.35758749 -0.08691563 +H 4.83478000 6.97770000 8.47928000 0.45704444 0.42075435 -0.73686274 +H 2.98294000 -0.64900100 3.38246000 0.41715018 0.25790839 -0.31710907 +H 0.62389000 3.54480000 7.57215000 -0.08700716 0.15244019 -0.88350304 +H 3.12449000 2.51588000 3.47442000 -0.41257824 -0.25966599 0.08659115 +H 0.40187500 1.32740000 7.41535000 0.45268385 0.27180314 0.27824838 +H 2.23066000 5.59117000 1.93857000 -0.75547753 -0.94118831 -0.10014190 +H 4.97896000 4.64793000 8.59763000 0.50362255 -0.21277833 -0.10263587 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.280542234361 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=49 pbc="T T T" +O 0.19857200 1.18663000 3.26377000 0.04360766 0.16516818 0.47482568 +O 3.25041000 2.38668000 7.78680000 -0.36565406 0.72378611 0.52300352 +O 5.07164000 4.37686000 2.23693000 0.38479541 -1.19081671 0.52963182 +O 2.47175000 5.67176000 8.40024000 -0.51705913 -1.11645013 0.60766995 +O 4.82379000 3.36598000 5.59790000 1.59582717 -0.57728979 -1.40270647 +O 2.29560000 0.49050000 5.31569000 0.34810166 0.25169454 0.38245828 +O 0.51145500 6.53107000 10.89440000 -0.92884701 -0.13622167 -0.00176638 +O 2.89028000 3.66323000 0.12274300 1.12437941 0.40661791 0.79328303 +C 0.80374600 2.15081000 3.73020000 -0.97563595 -0.82889795 -1.11149818 +C 3.78933000 1.47534000 7.21236000 0.33038419 -1.19769184 0.01805778 +C 4.48442000 5.34519000 1.82914000 0.03003743 0.98903140 -0.37427497 +C 1.88396000 4.67578000 8.85183000 0.32754209 1.85172907 -0.72457287 +C 0.41316200 3.19527000 4.82268000 0.64128455 1.33308614 0.56297903 +C 3.27924000 0.52939000 6.04991000 -0.10976348 -0.28599872 -0.04791554 +C 4.84834000 6.38159000 0.71777400 1.01931385 -0.39632115 -0.46751037 +C 2.06419000 3.78695000 10.08350000 -0.09704886 -0.67540309 0.76154019 +C 1.80000000 4.02450000 4.35981000 -1.33688109 -2.40214055 1.17907192 +C 4.40958000 6.43621000 6.35363000 -0.29617514 -0.46849973 0.93834467 +C 3.58605000 0.27488800 1.02233000 0.12854385 1.08194592 0.68914307 +C 0.77764700 3.06935000 9.82382000 -0.49496050 -0.53442950 -0.52648479 +H 2.57309000 3.92965000 5.20430000 -0.62558025 0.28635147 -1.03262702 +H 5.06827000 6.32165000 5.49611000 0.49660498 -0.09245070 -0.29679067 +H 2.79230000 0.16991900 11.05690000 0.52973981 0.64164965 0.59115318 +H -0.01967140 3.05305000 -0.21475100 0.46382187 0.31812362 -0.52731269 +H 1.57768000 5.00519000 4.04733000 -0.09926824 1.40857887 -0.03980453 +H 4.03609000 5.44560000 6.69532000 0.28142318 0.47813623 -0.40554833 +H 3.91320000 1.31580000 1.37771000 -0.98656314 -0.94965752 -0.89968556 +H 0.96664200 2.02377000 9.54683000 0.05678178 -0.07966100 0.17592002 +C 1.95311000 2.95055000 3.21596000 2.01783262 0.45324538 0.41314080 +C 4.96462000 0.45534100 7.51854000 0.45718894 1.16167069 -0.88952970 +C 3.30633000 6.21025000 2.23917000 -0.58856665 -0.91083901 -0.13492738 +C 0.58333800 3.96812000 8.55421000 -0.12445888 -0.44823224 0.51294485 +H 1.95587000 3.26309000 2.13976000 -0.54300670 -0.05224893 0.78523547 +H 4.97317000 6.94828000 8.56556000 -0.02812303 0.19558587 -0.70424058 +H 3.46697000 -0.25709100 3.23406000 -0.03004910 0.25952510 0.11282566 +H 0.56142300 3.43135000 7.61775000 -0.11125935 -0.09366940 -0.41243786 +H 2.96799000 2.47048000 3.30361000 -0.53797248 -0.18275967 0.13677857 +H 0.61253200 0.92635900 7.23703000 -1.12491934 -0.63332442 0.45778749 +H 2.36219000 5.60103000 2.26779000 0.29926458 0.66392054 -0.35416432 +H 5.09109000 4.60147000 8.67168000 -0.65469028 0.58316734 -0.29200687 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.099396051272 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=50 pbc="T T T" +O 0.17797500 1.17201000 3.26680000 0.86030655 0.98752987 1.10108521 +O 3.23405000 2.36927000 7.78649000 0.69894411 -0.74871553 -0.66766921 +O 5.08235000 4.38603000 2.24777000 -0.39783656 -0.01171765 -0.16566286 +O 2.48532000 5.66584000 8.40323000 -0.70662142 -1.36409878 1.12412744 +O 4.84558000 3.35542000 5.58707000 0.72431576 -0.27609740 -1.03014334 +O 2.32085000 0.49349500 5.32618000 -0.84617576 0.18949185 -0.27552250 +O 0.49459900 6.52944000 10.87550000 2.12244566 -0.04130364 -1.58133643 +O 2.89346000 3.68646000 0.13884900 1.44963424 0.27727496 0.92724779 +C 0.81384600 2.12348000 3.77131000 -1.22594313 -0.99236355 -2.38835943 +C 3.81214000 1.45852000 7.16878000 -1.76683124 0.92607022 2.07624294 +C 4.48894000 5.35983000 1.79797000 0.92602394 -0.65538448 1.34968004 +C 1.88219000 4.69342000 8.90429000 -0.24916766 1.84560470 -2.28602953 +C 0.40026200 3.20589000 4.78505000 1.10055042 0.89667223 1.18403414 +C 3.27359000 0.52227900 6.07322000 1.23385698 -0.27404772 -0.56790527 +C 4.90745000 6.36220000 0.72256400 -3.17429939 0.67736227 0.47579190 +C 2.08311000 3.78868000 10.08800000 -1.06384536 -0.82258846 1.08931470 +C 1.76464000 4.01586000 4.36829000 -3.10032361 1.41752631 -1.61475563 +C 4.41474000 6.42154000 6.36624000 -0.22552020 -0.31552218 -0.24577381 +C 3.58267000 0.26884000 1.00260000 0.85006841 1.07233000 1.13462268 +C 0.78214800 3.05454000 9.84052000 -0.85219214 -0.51578901 -1.36885532 +H 2.49321000 4.01425000 5.14361000 0.99968091 -0.06782416 0.97019035 +H 5.11509000 6.27310000 5.50486000 -0.31366379 0.03212876 0.39743033 +H 2.75940000 0.18348300 11.13470000 -0.14436899 -0.01546020 -0.69643471 +H -0.08633850 3.03957000 -0.26452300 0.91892770 0.21618915 -0.31229596 +H 1.53045000 5.09972000 4.02494000 0.41688689 -1.62309629 0.69397674 +H 3.92657000 5.47962000 6.67602000 0.70826693 0.10011927 -0.04544569 +H 3.76801000 1.35896000 1.22715000 -0.23160806 -0.89411655 -0.17274162 +H 0.97203100 2.01267000 9.51388000 0.00903553 0.17676540 0.41723656 +C 1.96765000 2.98271000 3.24032000 1.39815562 -1.52502927 -0.15492182 +C 4.93479000 0.48184800 7.48938000 -0.68508072 -0.57300634 0.57298062 +C 3.30699000 6.21548000 2.22865000 1.37387412 0.55537371 -0.34897686 +C 0.55590600 3.96222000 8.55926000 -0.39642914 1.01635194 0.50928052 +H 1.82408000 3.23357000 2.15924000 -0.16994889 0.23107841 0.83985085 +H 5.08623000 6.97806000 8.52792000 -0.67796391 0.24951528 -0.52248416 +H 3.44940000 -0.21758800 3.22127000 0.02865613 -0.08540536 -0.10287395 +H 0.56372000 3.47770000 7.56661000 -0.04597194 0.11527130 0.40278645 +H 2.97004000 2.42797000 3.22684000 -0.75806406 0.55294145 0.36023675 +H 0.47664500 0.95647300 7.27440000 1.86563874 0.59051555 -0.76203898 +H 2.41563000 5.64895000 2.20291000 -1.54087241 -0.52732297 -0.14511975 +H 5.02047000 4.66272000 8.63766000 0.88746254 -0.79721682 -0.17075776 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.16723403151 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=70 pbc="T T T" +O 0.25723900 1.11977000 3.22804000 1.19862773 1.35560386 0.34866010 +O 3.19525000 2.11522000 7.96753000 0.41160276 -0.84624261 -0.57079519 +O 4.91025000 4.40268000 2.33458000 -0.12044847 0.83380876 -0.70065647 +O 2.53981000 5.71275000 8.57209000 -1.13315715 -0.93018399 0.75416112 +O 4.65872000 3.26402000 5.46361000 0.40069974 -0.36966344 -0.58115159 +O 2.45240000 0.36590700 5.18063000 -0.28164327 0.42861267 -0.34037344 +O 0.28318100 6.57074000 10.61070000 0.92793684 -0.48975401 -0.05221602 +O 2.92719000 3.85075000 0.28596300 -0.16016430 -0.74223120 -0.21840082 +C 0.82121800 2.13117000 3.69224000 -1.03111521 -2.04343566 -0.86687314 +C 3.76402000 1.26358000 7.29235000 0.58975450 1.19409230 0.48306760 +C 4.41357000 5.39704000 1.80591000 -0.09531028 -0.69101483 0.62870671 +C 1.80681000 4.82923000 9.06876000 2.17525098 0.39830810 -0.74499771 +C 0.24195900 3.18072000 4.68978000 0.71699325 0.62990485 0.38134705 +C 3.40383000 0.44607200 5.92834000 1.00996018 -0.18751055 1.79766905 +C 4.85788000 6.45378000 0.68012000 -1.38753182 0.53404898 0.16475578 +C 2.09354000 3.79361000 10.22870000 0.31409419 1.11806992 0.34296665 +C 1.52372000 4.00655000 4.45276000 -0.11873766 0.20887642 1.25150503 +C 4.70860000 6.57403000 6.12777000 1.08061409 -0.57074376 -1.46884553 +C 3.61425000 0.42035300 0.99623900 -0.62166189 -1.38289869 0.49198573 +C 0.90069100 2.95596000 9.81367000 -0.93182949 0.07555187 -1.14874318 +H 2.07384000 3.98841000 5.41236000 0.16212759 0.18568147 0.14608957 +H 5.44387000 6.77011000 5.24887000 -0.90030263 -0.51592785 0.94390854 +H 2.88884000 0.35265200 10.96180000 0.54296042 0.47230548 0.57751091 +H 0.09271130 2.85409000 -0.27430800 0.00664774 0.41809377 0.20343597 +H 1.38436000 5.04980000 4.16470000 0.12073283 0.01055752 -0.20326113 +H 4.48944000 5.48416000 6.18434000 0.41298087 0.43751588 0.09005186 +H 3.86497000 1.41672000 1.35902000 -0.28131057 0.27681217 -0.24416738 +H 1.01108000 1.91800000 9.42217000 0.46558667 0.60542795 0.26964496 +C 2.11944000 2.97517000 3.46670000 -1.60556137 0.49929641 0.55660784 +C 5.18850000 0.47136100 7.38785000 -2.69183188 -0.98184259 0.39464274 +C 3.16110000 6.26299000 2.13706000 2.53624415 0.90338795 -0.77837577 +C 0.63990200 4.02923000 8.62971000 -2.12392662 0.38372738 1.03294070 +H 2.14592000 3.45807000 2.51176000 0.09486188 -0.22612030 -1.15752607 +H 5.29489000 6.77528000 8.34895000 -0.34645615 0.45728510 -0.82690277 +H 3.31525000 -0.27334800 3.16150000 -0.22182090 0.26603307 0.12563798 +H 0.72190600 3.58978000 7.67385000 0.48581251 -0.57210131 -1.42481796 +H 3.09582000 2.58821000 3.74350000 0.14802818 -0.40471581 0.06281051 +H 0.73036100 1.01630000 7.24355000 0.56035651 0.71435016 -0.24064960 +H 2.20355000 5.82935000 2.01340000 -1.20063319 -0.64454985 -0.22297635 +H 5.01972000 4.61795000 8.52329000 0.89158144 -0.80842168 0.74363503 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.0648920163985 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=80 pbc="T T T" +O 0.47722400 1.06500000 3.12016000 0.00827623 0.61817548 0.13000732 +O 2.97096000 2.01792000 7.84454000 -0.71614993 1.49984275 0.72950424 +O 5.09937000 4.57137000 2.23170000 -1.62484978 1.59643395 -0.18916943 +O 2.70068000 5.59338000 8.60794000 -0.77162405 -0.77961504 -0.00100576 +O 4.69017000 3.25738000 5.30681000 -1.24954585 0.01871290 1.18654868 +O 2.42811000 0.27863500 5.24022000 1.07135812 -0.09741344 0.97191299 +O 0.34062300 6.43637000 10.68510000 -0.91185202 0.66803431 0.32069267 +O 3.04827000 3.69188000 0.19081700 -0.52820743 0.14563808 0.51829326 +C 0.87630900 2.13157000 3.57207000 0.31887798 -0.24818293 0.41622098 +C 3.68754000 1.26344000 7.24200000 -0.12056725 -0.91728219 0.56370923 +C 4.42311000 5.55959000 1.85014000 2.35989218 -1.57444073 -0.43417242 +C 1.94077000 4.72703000 9.06074000 0.10566463 1.77925995 -0.30479657 +C 0.31208100 3.21399000 4.63194000 0.80152598 -0.65440746 -1.35684827 +C 3.35972000 0.31440300 6.06247000 0.29011505 0.14811971 -1.34050634 +C 4.75906000 6.50118000 0.63212200 0.41224760 -1.02409096 0.29984771 +C 2.06176000 3.86416000 10.31800000 0.27482316 -0.06063793 -0.16002855 +C 1.51476000 4.08776000 4.39449000 0.90440096 -0.37976891 0.23764501 +C 4.74819000 6.53713000 6.35261000 0.07062975 -1.01107603 -1.94920473 +C 3.44823000 0.37924700 0.92581400 -0.19768647 -0.06032374 -1.70221428 +C 0.69468800 3.25971000 10.04240000 1.35116099 -3.02601359 0.45730155 +H 2.18683000 4.08219000 5.29369000 -0.20502902 -0.01970493 -0.25811613 +H 5.54319000 6.79512000 5.59325000 -0.62165675 -0.27124264 -0.15459889 +H 2.72803000 0.31878500 10.85080000 0.62681438 -0.03112619 1.24874881 +H -0.10531500 3.44411000 -0.08101020 -0.31801512 0.34850275 0.29273398 +H 1.31605000 5.14146000 4.17779000 0.02927468 -0.09738876 -0.33990601 +H 4.80130000 5.47222000 6.53059000 -0.22552020 -0.49793372 -0.25455567 +H 3.63766000 1.42844000 1.11154000 -0.16343217 0.49127816 0.26156347 +H 0.82225700 2.09897000 10.10480000 -0.31986837 1.65482370 -0.70848290 +C 2.10711000 3.04262000 3.33330000 -1.26056560 1.31652823 -0.78900471 +C 4.97038000 0.48781900 7.55395000 0.81266915 1.46131734 0.80242073 +C 3.15280000 6.33108000 2.13257000 0.00400251 -0.86524821 -0.13438025 +C 0.58712500 4.06908000 8.72593000 0.80362400 -1.26845375 -0.74401555 +H 2.08291000 3.37506000 2.23055000 0.44502556 -0.38997413 1.49146609 +H 4.87327000 6.74506000 8.44626000 0.11405568 0.62360050 0.43621799 +H 3.16173000 -0.12409700 3.13537000 -0.31749730 0.19164334 0.10891707 +H 0.67709300 3.53545000 7.74496000 -0.15515991 0.07699117 0.68992468 +H 3.07176000 2.71257000 3.73069000 0.21144701 -0.40274428 -0.49617097 +H 0.55243700 1.10495000 7.52423000 -0.69544227 -0.60951086 0.33421359 +H 2.31535000 5.60637000 1.99073000 -0.12094726 0.63766444 0.17980753 +H 5.01031000 4.57647000 8.76191000 -0.49227318 1.01000646 -0.36051751 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.022986485084 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=99 pbc="T T T" +O 0.60788800 1.22760000 2.74854000 -0.02092775 -0.02960893 0.28803503 +O 3.05214000 2.20420000 7.67507000 -0.56682540 0.58971336 0.26839335 +O 5.00377000 4.64272000 2.16615000 1.92644018 -3.16662722 1.63530389 +O 2.60688000 5.50655000 8.43690000 -0.11007613 -0.81376958 0.72699999 +O 4.60321000 2.98353000 5.32681000 -1.02290311 -0.28620903 0.44443935 +O 2.66717000 0.04831410 5.24068000 -0.59433621 -0.29733163 -0.68030875 +O 0.12611800 6.88108000 10.56750000 0.78535375 -0.00434837 -0.66113861 +O 2.88100000 3.95220000 0.50655100 -0.37917858 -0.53046486 -0.51595870 +C 0.95304600 2.14010000 3.48040000 -1.05129837 0.01284251 -0.37944392 +C 3.67974000 1.26251000 7.25977000 1.17456734 -2.07309591 -0.15523087 +C 4.42759000 5.59423000 1.81613000 -2.54453853 4.01537409 -2.28780359 +C 2.03394000 4.57945000 9.01177000 -0.49366723 0.47042446 -0.73735639 +C 0.24421600 2.99828000 4.67627000 1.87872565 -0.15042496 -0.37590865 +C 3.53042000 0.15884900 6.08188000 -0.95124646 1.45523925 -0.02817353 +C 4.67377000 6.73394000 0.59720900 0.65158439 -1.49330700 1.48611305 +C 2.13996000 3.78604000 10.38260000 0.64162908 0.54892024 -0.06039573 +C 1.45814000 3.95326000 4.63030000 -1.19123838 0.85214072 -0.48897394 +C 4.81542000 6.39570000 6.43889000 0.37853323 1.07199575 0.19008731 +C 3.45091000 0.54606700 1.01806000 -0.90629330 1.25671409 -0.15943976 +C 0.82399600 3.07344000 10.08270000 0.44340988 0.42476218 -0.02424946 +H 2.03368000 4.00093000 5.58228000 -0.05968867 -0.01811296 -0.45908795 +H 5.57330000 6.58658000 5.65466000 0.25579443 0.47162825 0.00953591 +H 2.77985000 0.60414600 10.97330000 -0.32196845 0.14955490 0.24844930 +H 0.12720000 3.13688000 0.11107300 -0.13617385 0.02484570 -0.58541448 +H 1.03190000 4.96795000 4.33676000 0.84463824 -0.83440011 0.44413647 +H 4.84808000 5.34130000 6.50906000 -0.32908218 -1.35938338 0.50406169 +H 3.71569000 1.59032000 1.33941000 -0.49581359 -0.69172445 -0.05399111 +H 0.95401000 2.06892000 9.72206000 0.17647538 -0.96946016 0.64300719 +C 2.05077000 3.15849000 3.41570000 0.65255113 1.06065205 1.12365436 +C 4.90493000 0.42021100 7.70195000 1.92117971 0.54096011 0.76842560 +C 3.05682000 6.40186000 2.09734000 1.01008873 -0.55531715 0.91247937 +C 0.68441300 3.87441000 8.75736000 -0.02732826 1.15408079 0.55744088 +H 2.03387000 3.79332000 2.51286000 0.16439274 -0.67805647 0.02523882 +H 4.73824000 6.75595000 8.64794000 -0.34839065 0.21763154 -0.34403571 +H 3.01663000 -0.13285200 3.15039000 0.04370130 0.04889971 -0.48456090 +H 0.69723100 3.25848000 7.87019000 -0.16869368 -0.23816334 -0.41045554 +H 3.06508000 2.78863000 3.66976000 -0.11615987 -0.07859862 -0.41672389 +H 0.54780900 0.92805300 7.92329000 -1.15990177 -0.36525503 -0.64922412 +H 2.15989000 5.77150000 1.93745000 0.18900282 0.41968528 -0.23844359 +H 5.25229000 4.62983000 8.71810000 -0.14236250 -0.15240625 -0.07948000 +40 +Lattice="5.3719 0.0 0.0 0.0 6.8819 0.0 0.0 0.0 10.8378" Properties=species:S:1:pos:R:3:forces:R:3 energy=-7266.054606113258 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 3 2" crystal=NIKVUZ frame=100 pbc="T T T" +O 0.61462600 1.21486000 2.72392000 0.24036215 1.09604585 1.41113969 +O 3.04739000 2.22191000 7.66376000 0.30455745 -0.57831823 -0.18602548 +O 4.98666000 4.66634000 2.17215000 0.99144309 -0.90336224 0.50542952 +O 2.60388000 5.50305000 8.45883000 -0.49507774 -0.90706977 0.55483378 +O 4.58456000 2.95362000 5.32999000 0.75083411 0.03130231 -0.43507385 +O 2.66954000 0.04562640 5.23235000 -0.34724805 0.23098328 0.18881770 +O 0.14843500 6.85676000 10.55350000 -1.06836536 -0.61760983 1.59837770 +O 2.91282000 3.95159000 0.51991300 -0.13817006 -0.37500362 -0.92634790 +C 0.94139600 2.13543000 3.49149000 -0.99005984 -0.63557670 -1.50924784 +C 3.68313000 1.25080000 7.26949000 0.34604169 -0.89458449 0.79013086 +C 4.41214000 5.63456000 1.75537000 -1.65204177 1.04421755 -0.13411851 +C 1.99114000 4.58157000 9.00812000 0.71539403 0.90897239 -0.53968998 +C 0.26123000 3.00852000 4.68617000 -0.78806883 -1.19354723 0.17333863 +C 3.51189000 0.20032600 6.10786000 -0.34488881 0.27480773 -1.35689455 +C 4.67081000 6.70705000 0.62428300 1.94899904 0.32120689 -1.05702679 +C 2.19933000 3.79598000 10.37650000 -1.32236978 -0.35303972 0.05581042 +C 1.43094000 3.94559000 4.62924000 0.21512523 -0.93982562 0.16136861 +C 4.81743000 6.41821000 6.39004000 1.28985561 -0.67024546 1.83614818 +C 3.45935000 0.59771000 1.01910000 -1.01838311 0.10921789 -0.06291901 +C 0.82202400 3.06322000 10.09950000 0.77844776 -0.52225276 -1.37754051 +H 2.00526000 3.86622000 5.56413000 0.26728366 0.10656194 0.04174366 +H 5.69011000 6.57946000 5.71224000 -0.40703751 0.46240416 -0.22512014 +H 2.81065000 0.65670000 10.93660000 -0.14513775 -0.03215653 0.61591290 +H 0.04364080 3.10338000 0.03422180 -0.01980361 0.33589509 0.10987764 +H 1.09029000 4.93529000 4.47693000 -0.01708591 1.35163922 -0.28708527 +H 4.88750000 5.30510000 6.55308000 -0.67216864 0.84140894 -0.08666520 +H 3.64742000 1.65092000 1.34901000 -0.14781735 -0.77302788 -0.00471712 +H 0.83067100 2.03728000 9.68247000 0.58134699 -0.09940810 1.12909995 +C 2.03718000 3.17121000 3.42517000 -0.10985450 0.39750746 0.94936956 +C 4.95475000 0.41116500 7.72641000 -1.40377091 0.04049153 -0.99207558 +C 3.04787000 6.37001000 2.10848000 1.29678730 0.58256570 0.05577186 +C 0.67863300 3.85873000 8.76070000 -0.83270318 1.02953656 -0.16085438 +H 2.14001000 3.74373000 2.51948000 -0.28773575 0.02111508 -0.62910781 +H 4.73516000 6.69551000 8.62370000 0.07562231 0.41096204 -0.14187861 +H 2.97182000 -0.17190200 3.17988000 0.10756364 -0.24618004 -0.96292956 +H 0.68392900 3.24076000 7.82809000 -0.02111647 0.35920471 0.62146135 +H 3.01046000 2.76166000 3.63878000 0.82536525 -0.39122009 0.27850755 +H 0.45288100 1.03324000 7.85120000 0.86370554 0.11131334 0.04821857 +H 2.18848000 5.71447000 1.86227000 0.07876986 0.54419455 -0.02961340 +H 5.17853000 4.58032000 8.71401000 0.55138850 -0.47911736 -0.02042865 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3041.9416748830567 energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" name crystal=KIKYIM frame=0 pbc="T T T" +C -0.15926200 -1.07218000 8.45139000 0.00187018 0.00222766 -0.00064316 +C 2.57690000 3.99703000 0.93400300 -0.00187997 -0.00235371 0.00062395 +C -0.39542200 -0.78463800 6.91682000 -0.00211550 -0.00099016 0.00085730 +C 2.81307000 3.70949000 2.46856000 0.00210570 0.00095465 -0.00085518 +C 2.86758000 3.32356000 6.29956000 -0.00027596 -0.00264524 -0.00032559 +C -0.44993900 -0.39872100 3.08582000 0.00027973 0.00267746 0.00035907 +C -0.95162400 3.28853000 5.99477000 0.00140726 -0.00118243 0.00005098 +C 3.36927000 -0.36368800 3.39061000 -0.00143275 0.00120128 -0.00001605 +C 1.16808000 -0.82810200 6.61873000 0.00045791 0.00202148 -0.00043285 +C 1.24957000 3.75295000 2.76666000 -0.00049502 -0.00202118 0.00043587 +C 1.32337000 -1.46144000 8.04303000 0.00287642 0.00303433 0.00153091 +C 1.09427000 4.38629000 1.34236000 -0.00288713 -0.00305356 -0.00156324 +C -0.79822700 2.64585000 7.42052000 0.00157422 -0.00232527 0.00134029 +C 3.21587000 0.27899200 1.96486000 -0.00158246 0.00236467 -0.00133436 +C -2.36753000 2.36564000 7.54617000 0.00046489 -0.00383037 -0.00284336 +C 4.78517000 0.55920000 1.83921000 -0.00045925 0.00390166 0.00290657 +C -2.74670000 3.14257000 8.79562000 -0.00055919 0.00020391 -0.00022644 +C 5.16434000 -0.21771600 0.58976300 0.00056082 -0.00022968 0.00025888 +H -0.28785300 -0.25689500 9.16181000 -0.00100910 0.00118130 -0.00097569 +H 2.70549000 3.18175000 0.22358500 0.00103525 -0.00132652 0.00084052 +H 4.34875000 0.02258880 6.56860000 0.00052965 -0.00212969 0.00192411 +H -1.93111000 2.90226000 2.81679000 -0.00048440 0.00212171 -0.00194707 +H 2.10943000 3.15299000 5.52804000 0.00445114 0.00276623 0.00161850 +H 0.30821400 -0.22814900 3.85735000 -0.00440929 -0.00274195 -0.00161592 +H -0.52963100 2.91628000 5.05883000 -0.00133669 0.00065601 -0.00028461 +H 2.94728000 0.00857171 4.32655000 0.00132211 -0.00063698 0.00034787 +H 1.74342000 0.02208240 6.24193000 -0.00341169 0.00048563 -0.00145272 +H 0.67422100 2.90277000 3.14346000 0.00340296 -0.00052738 0.00145234 +H 2.16496000 -1.28286000 8.72285000 0.00082354 -0.00017913 -0.00117425 +H 0.25268600 4.20771000 0.66254500 -0.00084290 0.00018265 0.00113887 +H -0.08172950 1.87031000 7.70139000 -0.00108365 -0.00114814 0.00096313 +H 2.49938000 1.05454000 1.68400000 0.00105961 0.00118655 -0.00096807 +H 2.68596000 1.33329000 7.43679000 -0.00440060 0.00124890 -0.00253350 +H -0.26831600 1.59154000 1.94859000 0.00444415 -0.00109469 0.00254293 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.9201595288228 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=10 pbc="T T T" +C -0.22726400 -1.13054000 8.39429000 0.30868767 2.58144928 0.94926157 +C 2.55256000 3.96083000 0.96583800 -0.11830160 1.10879338 0.29062105 +C -0.53331200 -0.80080300 6.87072000 2.07188235 -1.58944055 0.14904068 +C 2.74723000 3.71869000 2.49827000 2.20426845 -0.53144702 0.57851878 +C 2.89332000 3.29491000 6.27087000 -0.30873190 -1.10569777 0.05735206 +C -0.44458800 -0.36859000 3.13182000 0.40281216 -1.00152696 -0.95923745 +C -0.93772600 3.34735000 5.95200000 -0.50079228 -0.98230025 -0.28028521 +C 3.38543000 -0.33245300 3.46886000 0.47139120 -0.52355374 -0.26835324 +C 1.11096000 -0.83534200 6.56271000 -0.12629002 2.68144463 0.68208796 +C 1.24219000 3.79516000 2.79409000 -0.20323645 0.98129752 0.89700133 +C 1.27958000 -1.43193000 8.01098000 -0.15458861 0.03669777 -1.36110602 +C 1.06487000 4.41607000 1.40620000 1.98982302 1.15926414 0.93682258 +C -0.70340700 2.67624000 7.35484000 -0.13911828 -1.14923169 0.41832208 +C 3.27014000 0.36326000 2.07983000 -1.08478956 -0.57235328 -2.06107857 +C -2.26657000 2.27026000 7.50985000 0.04268088 1.10300326 0.54116065 +C 4.80506000 0.53842900 1.85082000 0.61327495 1.07547188 0.25627008 +C -2.66321000 3.07892000 8.76736000 -1.62712778 -1.23598585 0.93230772 +C 5.16927000 -0.24557100 0.56797600 0.01433117 -0.41496731 0.07408839 +H -0.44719900 -0.22657400 9.07250000 0.53145731 -1.49565185 -0.58884433 +H 2.68685000 3.08338000 0.34270800 -0.17703896 0.04626803 -0.34303144 +H 4.15996000 -0.04937300 6.53337000 -0.11638716 0.23038216 -0.13232697 +H -1.96288000 2.90232000 2.83019000 -0.55023150 0.39571232 -0.05386255 +H 2.15173000 3.00891000 5.53121000 -0.09173130 0.07697523 -0.38548036 +H 0.35823000 -0.15303500 3.84233000 -0.00061444 -0.24882828 0.19411675 +H -0.58441700 3.06217000 4.96655000 0.24389896 -0.18916223 -0.09896073 +H 3.06442000 -0.09679710 4.47293000 -0.39344100 0.49863306 0.17723797 +H 1.70301000 0.04654000 6.21831000 -0.42443925 -0.49211274 0.09889645 +H 0.63361400 3.01278000 3.19074000 -0.39632938 -0.83268261 0.20991977 +H 2.14363000 -1.22352000 8.61479000 0.33595577 0.25085996 0.66948441 +H 0.23365700 4.23804000 0.81323000 -1.76623474 -0.18819807 -1.39974970 +H 0.10379300 1.93018000 7.63087000 -0.74404640 0.77186060 -0.20580447 +H 2.63332000 1.18299000 1.70623000 -0.09065144 -0.32059651 0.48235129 +H 2.81761000 1.21501000 7.47259000 0.01834580 0.40753271 -0.27450691 +H -0.18416800 1.56953000 1.97754000 -0.23468464 -0.53190468 -0.18223054 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.775258909183 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=20 pbc="T T T" +C -0.18285900 -1.04999000 8.44511000 1.03248304 -1.18347879 -0.05511211 +C 2.54766000 3.96157000 0.94639200 -0.47098445 0.70708422 -0.08370175 +C -0.47412900 -0.82238400 6.86989000 1.33863972 -0.42511648 -0.05475678 +C 2.80197000 3.78144000 2.50631000 -0.52873708 -0.52934386 0.01066077 +C 2.84963000 3.22269000 6.24290000 0.58402094 0.54533098 1.39642783 +C -0.42922200 -0.35738800 3.12953000 -0.12388758 0.15756543 -1.53082968 +C -0.96648000 3.20669000 5.97956000 -0.30431217 1.38561892 1.90859673 +C 3.42423000 -0.28942500 3.42383000 -0.71220072 1.42244226 -0.32942619 +C 1.12439000 -0.81649700 6.54320000 0.07378860 -1.86806586 0.45983512 +C 1.26397000 3.86474000 2.84582000 0.33849653 -0.11754004 -0.93419491 +C 1.38514000 -1.44334000 7.99872000 -1.97038034 -0.32747935 -0.69377105 +C 1.04094000 4.40011000 1.40722000 -0.39415731 0.13161169 -0.95776678 +C -0.73618900 2.58247000 7.44391000 -0.55917894 1.80576803 -0.57385480 +C 3.24426000 0.36479800 1.96006000 0.42783105 -1.37736568 0.39623322 +C -2.39473000 2.30650000 7.56511000 1.77196316 2.30900491 -0.11406596 +C 4.83437000 0.52975000 1.81116000 0.02346733 0.90287373 -0.03918968 +C -2.70400000 3.12737000 8.80259000 -0.74253974 -0.04385490 -0.79474856 +C 5.09760000 -0.24106800 0.54008300 0.83612275 -0.68523499 1.22376283 +H -0.23975200 -0.30377300 9.26171000 -0.32440740 -0.00517836 -0.83160789 +H 2.67341000 3.13489000 0.23841600 -0.04851013 0.08009861 0.31305186 +H 4.28947000 -0.01750780 6.48111000 -0.15351954 -0.10851444 0.10368642 +H -2.09891000 2.94109000 2.94340000 0.89040388 -0.61476619 0.03208773 +H 2.14741000 3.01000000 5.42659000 -0.09315930 0.06577962 0.27821187 +H 0.26038700 -0.22105900 3.93646000 0.86009057 0.25454795 0.32110970 +H -0.51801800 2.84207000 5.10516000 0.54693021 -0.57583969 -1.46208352 +H 3.00451000 0.14241600 4.32533000 -0.08824746 -0.01384354 0.31544350 +H 1.71305000 0.00677065 6.11331000 -0.27264646 -0.12757814 0.06646713 +H 0.82758800 2.99484000 3.25373000 -0.97370248 -0.90432383 0.57904843 +H 2.23305000 -1.24707000 8.65733000 0.07117996 0.20193033 0.06499080 +H 0.11739800 4.16878000 0.76342200 1.12399889 0.36833110 0.71567171 +H 0.08896340 1.90208000 7.75402000 -0.72500481 0.00888476 -0.23810164 +H 2.60952000 1.16666000 1.60738000 -0.34389688 0.20337323 0.16424516 +H 2.69995000 1.31388000 7.51695000 -0.67530025 -1.92348856 -0.09023595 +H -0.08265340 1.51219000 1.78317000 -0.41465158 0.28076961 0.43391994 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.675229861709 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=30 pbc="T T T" +C -0.13019800 -1.10185000 8.41699000 -0.28744316 1.88160529 -0.39126328 +C 2.61712000 4.07537000 0.93859800 -0.89185398 0.13917073 0.24307004 +C -0.41303400 -0.85687100 6.80570000 -0.82720102 -0.05819743 0.76610133 +C 2.88294000 3.75522000 2.44656000 -0.91696337 0.87248843 -0.05579551 +C 2.82109000 3.20863000 6.26114000 -0.04553552 0.45739822 -1.93161324 +C -0.41237200 -0.31894100 3.11043000 -0.32274698 -1.25042517 -0.17284755 +C -0.95001900 3.12756000 6.05525000 -0.54173658 -0.06000029 -3.36224703 +C 3.40956000 -0.29486000 3.43403000 -0.47315806 -1.24311809 -0.11240760 +C 1.14866000 -0.97877900 6.58483000 1.08853309 1.47040361 -1.62638216 +C 1.31797000 3.79780000 2.77504000 -0.09971921 0.27689033 0.33760641 +C 1.28357000 -1.55005000 7.97368000 1.17633626 0.74838128 1.65557446 +C 1.15318000 4.46296000 1.39940000 -1.19286331 -0.17741846 -0.93639063 +C -0.86491100 2.59410000 7.43143000 -0.13230280 -2.09892007 1.33426884 +C 3.21091000 0.37156000 2.02941000 0.13072723 -0.14854189 -0.56349840 +C -2.49344000 2.36116000 7.50615000 0.72117901 -2.05090214 3.27631048 +C 4.79516000 0.65671200 1.88287000 0.27186485 0.49412643 0.09733631 +C -2.75511000 3.18889000 8.82924000 -0.31829692 0.31246051 -1.88581675 +C 5.13636000 -0.11098300 0.61250100 0.39700147 -0.95811645 0.45838244 +H -0.12392000 -0.16360300 9.04075000 -0.42658201 -1.02797847 -0.43818797 +H 2.64893000 3.19690000 0.26680200 0.33096423 0.68943103 -0.02386616 +H 4.21319000 -0.11855100 6.47995000 0.89694991 -0.03957787 0.01830872 +H -1.87868000 2.89970000 2.60815000 0.42167686 -0.14069694 0.81515283 +H 2.16038000 2.96847000 5.35911000 0.50390948 0.50004923 1.29176851 +H 0.32343800 -0.30184300 3.90066000 0.40755739 0.61293557 0.27654426 +H -0.51333100 2.65941000 5.12953000 -0.32432718 0.50169576 0.73816886 +H 2.87497000 -0.03807320 4.35776000 0.54906422 0.27763800 0.00149289 +H 1.87764000 -0.22389900 6.21849000 -0.68968814 -0.01040052 0.06021061 +H 0.65382600 2.95200000 3.03199000 0.38172037 0.18288000 0.29413832 +H 2.19975000 -1.32722000 8.57684000 -0.62688637 -0.20010742 -0.05807968 +H 0.29307600 4.16156000 0.74764300 0.44386342 0.57966549 0.24619907 +H -0.14780900 1.82907000 7.71950000 -0.13619956 -0.28261977 0.22743104 +H 2.45888000 1.14091000 1.74303000 0.49747812 -0.43575159 0.18826851 +H 2.54518000 1.29476000 7.59950000 0.28485149 0.93181921 -0.61271959 +H -0.22800300 1.70658000 2.00811000 -0.25017142 -0.74627298 -0.15522161 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.587473148406 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=49 pbc="T T T" +C -0.12912200 -1.13583000 8.37409000 0.32524712 1.32155217 0.91138922 +C 2.56083000 4.00706000 0.98104800 0.33779205 0.06796300 1.77595351 +C -0.36432000 -0.75606200 6.90598000 -0.34523128 -2.06820053 -0.19940499 +C 2.79286000 3.74455000 2.60356000 0.96973270 -0.34561540 -0.66623454 +C 2.82481000 3.32886000 6.28368000 -0.98194544 0.47258522 -0.71229842 +C -0.43999000 -0.37291000 3.10413000 -0.48905005 0.52283383 1.59308637 +C -1.07083000 3.22526000 5.82138000 0.54363920 0.32291307 2.79825499 +C 3.38654000 -0.28113200 3.48069000 -0.90914722 -0.16057002 -0.54793808 +C 1.14350000 -0.88803300 6.53545000 -0.30146339 -0.18125763 -0.80813372 +C 1.25415000 3.79445000 2.86533000 -0.60294940 -0.38431719 0.09089158 +C 1.34833000 -1.53055000 7.92973000 -1.00520363 0.53737599 -0.49512608 +C 1.08562000 4.42460000 1.45692000 0.57220929 -0.13496852 -0.79563816 +C -0.79645500 2.63173000 7.31869000 -1.62392418 -0.28786482 -0.64414362 +C 3.25919000 0.31730000 1.97267000 -0.85679956 0.94448446 1.23318849 +C -2.39161000 2.35448000 7.48552000 -0.57043523 -0.38229682 0.61644769 +C 4.86582000 0.54473600 1.88521000 -1.13454041 0.00978978 -0.29539507 +C -2.74756000 3.13771000 8.78173000 -0.05160924 -1.24178626 0.79744821 +C 5.23411000 -0.23703100 0.64245500 -0.22194842 0.41304258 -1.89924820 +H -0.32367600 -0.24353500 8.95946000 0.48308817 -0.02958034 0.83693008 +H 2.66789000 3.13749000 0.37745300 0.09042158 -0.56564270 -0.78795056 +H 4.41574000 0.11601000 6.79997000 -0.41997993 0.33011576 -0.85449071 +H -1.90220000 3.04002000 3.12217000 -0.56279906 0.01036710 -0.85374509 +H 2.01406000 3.20814000 5.55388000 -0.07393361 -0.09659172 0.00649877 +H 0.22518600 -0.17288400 3.92807000 0.78712781 -0.02732599 0.17931593 +H -0.79009100 2.66761000 4.94281000 0.42271559 0.34235627 -0.60057885 +H 2.86600000 0.08497650 4.40955000 0.84980102 -0.09646316 -0.78264895 +H 1.65444000 -0.05536350 6.12641000 0.90354736 0.94796574 -0.35017757 +H 0.71038100 2.85649000 3.16240000 0.22199625 0.96458535 0.06808178 +H 2.16816000 -1.35322000 8.58018000 1.00827353 0.14899337 0.68628914 +H 0.22073000 4.29235000 0.80723600 -0.16317403 -0.33416371 -0.22156276 +H -0.09602480 1.92959000 7.68311000 0.83569595 -1.24659423 -0.04596428 +H 2.53837000 1.15799000 1.71099000 0.87298723 -1.04060258 0.05546281 +H 2.57430000 1.33472000 7.34118000 0.50169268 0.48995045 0.09340766 +H -0.28201600 1.57033000 2.05753000 0.58816556 0.77697195 -0.18196931 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.4179734376567 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=50 pbc="T T T" +C -0.15698300 -1.14746000 8.36951000 1.16723456 2.79737567 1.75062815 +C 2.55147000 4.02948000 1.01096000 1.17731328 -2.64149483 0.11509698 +C -0.38303500 -0.73672800 6.90817000 -0.70958334 -1.00156810 -0.68980641 +C 2.76591000 3.71969000 2.63382000 0.88029430 1.16008689 -2.35667316 +C 2.83235000 3.35870000 6.27257000 -1.36022670 0.13375239 0.04371996 +C -0.45973100 -0.37929200 3.12382000 1.61319754 0.44523022 1.93564473 +C -1.08584000 3.24024000 5.80242000 1.28508364 0.44186002 2.15868279 +C 3.42934000 -0.28049700 3.49693000 -1.62994057 -1.16382013 -3.30380586 +C 1.14992000 -0.84168500 6.57770000 0.63330385 0.31115593 -2.62055576 +C 1.25480000 3.77753000 2.88241000 -0.43821162 1.10657709 -0.88490172 +C 1.36741000 -1.50703000 7.93003000 -0.32721402 -0.80545977 0.44363100 +C 1.11826000 4.39455000 1.40811000 -1.48242609 0.25900830 0.10869853 +C -0.82822700 2.61795000 7.32012000 1.20378022 -1.73161227 -0.49338493 +C 3.25166000 0.29632700 1.95115000 1.29014357 -1.21177121 2.02454834 +C -2.37759000 2.36454000 7.51637000 -0.76477978 -0.50737070 -0.68257133 +C 4.86373000 0.52721600 1.86415000 -0.40024671 1.73673905 0.66227504 +C -2.74697000 3.12410000 8.77627000 0.01998596 -0.67272400 0.80076494 +C 5.23809000 -0.22411400 0.62937000 -0.47520311 -0.56003769 -1.13693153 +H -0.24771900 -0.24824900 9.01444000 0.12807796 -0.68415513 0.22768198 +H 2.62862000 3.07106000 0.42289200 0.16965836 1.15303178 0.09893451 +H 4.34001000 0.12764000 6.68441000 0.55705521 -0.75543125 -0.12653221 +H -1.99606000 2.90973000 2.92040000 0.59885621 -0.58022085 0.40537709 +H 1.98700000 3.25352000 5.58632000 -0.10587649 -0.19288416 -0.16785756 +H 0.25480700 -0.14610300 3.94360000 0.07213384 -0.26701575 -0.54731073 +H -0.77271900 2.76291000 4.83859000 -0.07905577 0.68967785 0.72928313 +H 2.83842000 0.07846910 4.29199000 -0.04652848 0.72143098 1.35113014 +H 1.77916000 -0.02735510 6.12454000 -0.51717226 -0.44576038 0.59675819 +H 0.75513200 2.88076000 3.21841000 -0.54741357 -0.09731163 0.35522104 +H 2.25647000 -1.35585000 8.57953000 -0.49302806 0.02959890 -0.13560872 +H 0.26057100 4.22727000 0.69159200 0.63983445 -0.02353742 0.60510913 +H -0.12164400 1.73437000 7.58864000 -0.95631154 1.58844810 -0.43369420 +H 2.62872000 1.09786000 1.69616000 -1.09485286 1.08659448 -0.51189893 +H 2.65375000 1.32490000 7.37750000 0.13942990 0.50459494 0.00609357 +H -0.21047100 1.59001000 2.03969000 -0.14730827 -0.82300498 -0.32774469 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.4344635363423 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=70 pbc="T T T" +C -0.05470280 -1.01795000 8.62276000 -0.43824711 0.33221584 -1.55465867 +C 2.57429000 3.94391000 0.85250400 0.44866059 3.02368931 0.78476753 +C -0.42829900 -0.69388700 7.07021000 1.59332291 -1.05008481 0.06357207 +C 2.83277000 3.54310000 2.32715000 -1.59611513 1.01389911 -0.18881050 +C 2.80288000 3.44183000 6.31752000 -0.07963118 0.88967369 1.49943137 +C -0.44912300 -0.59417800 3.05491000 -1.33226853 -0.32363864 0.41721548 +C -1.03806000 3.48019000 5.98529000 0.06155632 -1.31833829 -1.65919972 +C 3.30141000 -0.57984400 3.33263000 0.27906754 -1.02508340 0.97667982 +C 1.14134000 -0.65959900 6.65506000 -0.49437429 -0.20738107 0.05994373 +C 1.23623000 3.56765000 2.60113000 0.03587758 0.66985465 -0.38866184 +C 1.40338000 -1.38321000 8.07543000 -0.83282659 -0.05001428 -1.20190331 +C 1.15124000 4.39591000 1.24246000 -0.37329333 -0.83752657 1.45465818 +C -0.78987600 2.75786000 7.31934000 -0.25809968 0.72554989 1.10768781 +C 3.23509000 0.20397700 2.04338000 -1.53583305 1.32773310 -2.56818239 +C -2.35231000 2.46890000 7.63390000 0.22791647 -0.23689270 -2.33348695 +C 4.75842000 0.49637600 1.89252000 0.38741434 -0.78321973 0.63049620 +C -2.68487000 3.16604000 8.85754000 0.11059189 1.80464188 2.59416082 +C 5.18026000 -0.21604000 0.64485200 0.20840591 -0.59185766 -1.79394609 +H -0.16745700 -0.08645440 9.24717000 -0.05251530 -1.46913863 -0.20986475 +H 2.66950000 3.29215000 0.05116310 0.40546863 -1.36308063 -1.26190257 +H 4.33416000 0.11445100 6.85890000 -1.04472663 1.27068546 -0.44676671 +H -1.94035000 2.70819000 2.52233000 0.69420814 -0.73703243 0.63013111 +H 2.01244000 3.30224000 5.53451000 0.46737925 0.08245168 0.72358556 +H 0.17875000 -0.54462200 3.92444000 0.66956154 0.30786338 0.28427916 +H -0.71311200 2.98500000 4.99874000 -0.07558015 1.13245781 1.17138432 +H 2.73261000 -0.37942200 4.25569000 0.68324495 0.25284280 0.01605083 +H 1.61566000 0.24055200 6.19760000 -0.10283693 -0.60164328 0.50949752 +H 0.59063000 2.67938000 2.78676000 0.41752864 0.47471100 0.12397037 +H 2.30246000 -1.29008000 8.66967000 0.35558871 0.15960431 0.38043225 +H 0.27077200 4.32572000 0.65369300 -0.73939785 -0.15633490 -1.09035343 +H -0.00712238 2.01894000 7.40453000 0.07439641 -0.43369574 0.40658088 +H 2.47632000 1.03080000 1.70006000 1.24196110 -1.46095738 0.81338391 +H 2.59525000 1.50113000 7.57405000 0.10876898 -1.11974628 -0.33220247 +H -0.33954400 1.53159000 1.98750000 0.48482264 0.29778054 0.38202993 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.8326749293597 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=80 pbc="T T T" +C -0.12759900 -0.95974900 8.43775000 0.05806991 0.57371082 1.77730591 +C 2.71061000 4.01467000 0.89251100 -0.22586216 -1.21149867 -1.35700254 +C -0.34692300 -0.62088000 6.94480000 -0.28568916 0.15680233 -0.32732046 +C 2.83251000 3.61528000 2.40555000 0.73300094 -0.44096270 -0.12558656 +C 2.87476000 3.49462000 6.28087000 -0.32428244 -0.16569629 0.64991317 +C -0.55390100 -0.55209700 3.17401000 0.10755644 0.18425194 -0.59315350 +C -0.91223700 3.42272000 5.98787000 -0.50106224 0.55932292 -1.04503517 +C 3.19547000 -0.72258000 3.36729000 1.88633097 0.70742361 -1.35363439 +C 1.22803000 -0.66971000 6.68869000 0.80208134 -0.30231545 -0.85852220 +C 1.27766000 3.46961000 2.58397000 -0.27326353 1.01632108 -0.42150254 +C 1.35396000 -1.41645000 8.09792000 -1.07400121 -0.13109746 -1.11015092 +C 1.17384000 4.25380000 1.19450000 -0.30773482 -0.02369847 -0.09013876 +C -0.82150300 2.75371000 7.36842000 -0.18898071 -0.31107931 0.89447136 +C 3.20908000 0.07299890 1.97254000 -2.17074641 -0.58735823 0.73332490 +C -2.39932000 2.51329000 7.59238000 -0.08972944 -0.24137722 -0.41500228 +C 4.66511000 0.49922900 1.95266000 0.74795448 0.44825127 0.74888522 +C -2.75889000 3.31110000 8.89198000 0.46983671 -0.52118318 -1.50098432 +C 5.16404000 -0.11992900 0.67159900 0.66761265 -0.34116431 -0.63401347 +H -0.20078000 -0.13093100 9.14829000 0.11715951 -0.09230003 -0.21799921 +H 2.95370000 3.20572000 0.11286900 -0.27400041 1.21904228 1.07128613 +H 4.42616000 0.25815200 6.65833000 0.30004774 -0.64600510 0.05187098 +H -1.89821000 2.76325000 2.62980000 -0.18128951 0.53755596 0.38085186 +H 2.07909000 3.27564000 5.53281000 0.48459330 0.35312456 0.26687999 +H 0.19610100 -0.29471400 3.93665000 -0.26088881 -0.42119555 0.15903507 +H -0.50688900 3.08166000 4.97005000 -0.44386394 0.37483033 1.44991192 +H 2.70329000 -0.45718500 4.28014000 -0.41944977 0.12642526 0.52404739 +H 1.84556000 0.19927900 6.28527000 -0.68790379 -0.93637006 0.63663085 +H 0.80639300 2.53394000 2.85386000 -0.24957030 -0.31101504 -0.01472944 +H 2.12755000 -1.50243000 8.84376000 0.53636297 0.74186096 0.33252797 +H 0.39692500 4.22878000 0.38058500 0.50810912 -0.23902518 0.76264576 +H -0.11301000 1.97206000 7.61161000 0.17781287 -0.27900326 0.12230275 +H 2.40367000 0.76672200 1.76834000 -0.18961166 0.40031511 -0.37148378 +H 2.55523000 1.49357000 7.55008000 0.43347205 0.40791066 -0.35031692 +H -0.50382400 1.57597000 2.08187000 0.11793342 -0.60480060 0.22468151 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.7046453677804 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=99 pbc="T T T" +C -0.12115700 -1.15130000 8.55793000 0.17028416 0.53235205 -0.02797982 +C 2.50014000 3.96166000 0.88406700 0.17166690 -0.13384649 -0.04595430 +C -0.37995500 -0.74279100 7.08698000 0.55059146 -1.22204533 -1.46609445 +C 2.68918000 3.69907000 2.41133000 1.58166039 -2.13741977 0.75109122 +C 2.99529000 3.38650000 6.33372000 0.10701394 -0.50324408 -0.31993882 +C -0.50181000 -0.47424700 3.04516000 -1.35461655 1.31773665 0.04255171 +C -0.81901400 3.39369000 6.05441000 0.15595540 1.61156232 -0.40395630 +C 3.20931000 -0.35732000 3.30236000 1.14633663 -0.65596041 1.83787082 +C 1.16464000 -0.65807800 6.75382000 1.04584763 -0.05400139 -1.58967195 +C 1.12638000 3.72285000 2.71360000 -0.58184065 -0.52715842 0.22519264 +C 1.39696000 -1.39534000 8.07537000 0.01162591 -0.42367564 2.70189004 +C 1.02621000 4.31398000 1.26149000 0.75827489 1.44484685 0.79579242 +C -0.64958900 2.75115000 7.45354000 -0.25317036 -0.43728397 -0.52927187 +C 3.14531000 0.21621400 1.87695000 -0.17878423 2.42602610 -0.03851770 +C -2.21668000 2.36627000 7.49539000 -0.41400880 -0.57125284 1.46104994 +C 4.71571000 0.48647400 1.80558000 0.67969169 0.26040904 -0.41774976 +C -2.70291000 3.05063000 8.75980000 0.22413952 0.53929403 1.84444256 +C 5.15296000 -0.26396600 0.57558000 -0.28946508 -1.08600827 -1.62530230 +H -0.29934400 -0.44881700 9.36289000 0.00916922 0.31799044 0.01083561 +H 2.62132000 3.14002000 0.17632500 0.15037045 0.08398097 0.15744356 +H 4.27508000 -0.05233570 6.72684000 -0.33424855 0.73327862 -0.01873661 +H -1.96639000 2.89979000 2.72097000 -0.95393584 0.45436021 -0.09589341 +H 2.30955000 3.19518000 5.50435000 -0.20415948 0.24398946 0.10341543 +H 0.26875500 -0.28116300 3.80917000 -0.23525183 -0.20623898 -0.07787049 +H -0.26117700 3.05775000 5.15286000 -0.69095826 0.27154346 0.28933652 +H 2.83511000 0.02511320 4.31325000 0.20169430 -0.39093624 -1.46568821 +H 1.66604000 0.26780800 6.34026000 -0.34751339 -0.89177171 0.65644378 +H 0.47998100 2.89186000 3.12745000 0.82697991 0.64792828 -0.49361890 +H 2.22026000 -1.35183000 8.83789000 -0.45682795 0.58616010 -0.70395776 +H 0.26853300 4.21157000 0.55010200 -1.51255428 -0.50890102 -1.08801887 +H 0.15880500 2.05722000 7.70069000 -0.20476728 -0.17529524 0.13009525 +H 2.55796000 1.17170000 1.64429000 0.25923919 -1.68606261 -0.11190264 +H 2.82361000 1.32992000 7.51784000 0.23282522 -0.08901725 -0.85401763 +H -0.28542000 1.50174000 1.85300000 -0.27126167 0.22866517 0.36669433 +34 +Lattice="5.3875 0.0 0.0 -1.9748077529732335 5.548968944659611 0.0 -0.9950502671437214 -2.62412198615541 9.385386234334366" Properties=species:S:1:pos:R:3:forces:R:3 energy=-3040.6249976469003 name energy_unit=eV force_unit=eVperAnstrom length_unit=Angstrom kpts="4 4 3" crystal=KIKYIM frame=100 pbc="T T T" +C -0.13087400 -1.15234000 8.54777000 -0.10922303 1.06605650 1.00337301 +C 2.48216000 3.92872000 0.90896700 0.62526658 0.78238155 -0.23632963 +C -0.37971800 -0.72030600 7.07001000 0.38974222 -1.88953971 -0.96992810 +C 2.66225000 3.67881000 2.43092000 0.76910437 0.16294418 0.26590195 +C 3.03866000 3.38315000 6.32011000 -1.43931898 0.45737714 0.06382404 +C -0.50143100 -0.47293100 3.07921000 -2.18624502 1.10639197 -1.84818094 +C -0.82467200 3.39567000 6.07636000 0.36965470 2.30915917 -0.62186244 +C 3.26148000 -0.34759200 3.28633000 1.03936845 -1.28990189 -1.06531088 +C 1.15300000 -0.66191700 6.74850000 0.52347660 -1.91092615 0.03152512 +C 1.09282000 3.72748000 2.69712000 0.69990056 0.42839875 0.82569435 +C 1.40258000 -1.38986000 8.13018000 -0.70033765 -0.65025770 -0.04899134 +C 1.01359000 4.30672000 1.24589000 -1.64447758 1.63763845 -1.23455632 +C -0.67575000 2.73061000 7.42217000 1.30714885 0.33169699 0.77823693 +C 3.13561000 0.24794400 1.84978000 2.20857247 -1.68560495 1.15650277 +C -2.19230000 2.36562000 7.49832000 -1.64066207 -1.28640519 0.51622609 +C 4.75152000 0.51802900 1.78955000 -0.47709236 -0.75571921 0.65479827 +C -2.71060000 3.03488000 8.77499000 0.61994954 0.43909300 0.84054505 +C 5.16836000 -0.28707200 0.59218200 -0.44422698 -0.53035173 -1.55177903 +H -0.36288100 -0.45525800 9.37306000 0.24271471 -0.03581084 -0.46395505 +H 2.63121000 3.14113000 0.18049300 0.12337181 -0.21674400 0.08225216 +H 4.24516000 -0.04756990 6.68497000 0.17565828 0.32877108 0.24423629 +H -2.00441000 2.97840000 2.77831000 0.18181042 -1.27722635 0.31962206 +H 2.32301000 3.31689000 5.49661000 -0.09853959 -0.30223729 0.05283103 +H 0.25619600 -0.30203700 3.82646000 0.26978740 -0.06240170 0.46021718 +H -0.26464000 3.06290000 5.20776000 -0.31864196 0.03204356 -0.42516996 +H 2.87467000 0.05343320 4.17055000 -0.90391245 0.62203213 1.44284653 +H 1.58836000 0.21548000 6.35662000 0.92940751 1.11661982 -0.28718194 +H 0.58672000 2.90824000 3.22212000 -0.21279581 0.02249777 -0.48103746 +H 2.30148000 -1.34517000 8.77577000 -0.54817976 0.47733713 -0.03704677 +H 0.17081000 4.26630000 0.45970000 1.09060026 -0.49923213 1.19406659 +H 0.20728700 2.10045000 7.58492000 -0.49822991 -0.42670645 0.43975429 +H 2.51140000 1.05963000 1.64625000 -1.19466308 1.09851925 -0.70367494 +H 2.79427000 1.34362000 7.36086000 0.52252015 0.23226163 -0.17542174 +H -0.37328800 1.55513000 1.96008000 0.32849700 0.16784521 -0.22202556 diff --git a/latest/_downloads/bbdfa9e1459a8f3df5a34d118d90df12/keys-selection.py b/latest/_downloads/bbdfa9e1459a8f3df5a34d118d90df12/keys-selection.py new file mode 100644 index 000000000..d66a350d6 --- /dev/null +++ b/latest/_downloads/bbdfa9e1459a8f3df5a34d118d90df12/keys-selection.py @@ -0,0 +1,136 @@ +""" +Keys Selection +============== + +.. start-body +""" + +import chemfiles +import numpy as np +from metatensor import Labels, TensorBlock, TensorMap + +from rascaline import SoapPowerSpectrum + + +# %% +# +# First we load the dataset with chemfiles + +with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [f for f in trajectory] + +# %% +# +# and define the hyper parameters of the representation + +HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, +} + +calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + +# %% +# +# The selections for keys should be a set of ``Labels``, with the names of the +# keys being a subset of the names of the keys produced by the calculator. + +descriptor = calculator.compute(frames) +print("keys names:", descriptor.keys.names) + +# %% +# +# We can use these names to define a selection, and only blocks matching the +# labels in this selection will be used by rascaline. Here, only blocks with +# keys ``[1,1,1]`` and ``[4,4,4]`` will be calculated. + +selection = Labels( + names=["center_type", "neighbor_1_type", "neighbor_2_type"], + values=np.array([[1, 1, 1], [4, 4, 4]], dtype=np.int32), +) +selected_descriptor = calculator.compute(frames, selected_keys=selection) + +# %% +# +# We get a TensorMap with 2 blocks, corresponding to the requested keys + +print(selected_descriptor.keys) + +# %% +# +# The block for ``[1, 1, 1]`` will be exactly the same as the one in the full +# ``TensorMap`` +answer = np.array_equal(descriptor.block(0).values, selected_descriptor.block(0).values) +print(f"Are the blocks 0 in the descriptor and selected_descriptor equal? {answer}") + +# %% +# +# Since there is no block for ``[4, 4, 4]`` in the full ``TensorMap``, an empty +# block with no samples and the default set of properties is generated + +print(selected_descriptor.block(1).values.shape) + +# %% +# +# ``selected_keys`` can be used simultaneously with samples and properties +# selection. Here we define a selection for properties as a ``TensorMap`` to +# select different properties for each block: + +selection = [ + Labels(names=["l", "n_1", "n_2"], values=np.array([[0, 0, 0]])), + Labels(names=["l", "n_1", "n_2"], values=np.array([[1, 1, 1]])), +] +blocks = [] +for entries in selection: + blocks.append( + TensorBlock( + values=np.empty((len(entries), 1)), + samples=Labels.single(), + components=[], + properties=entries, + ) + ) + +keys = Labels( + names=["center_type", "neighbor_1_type", "neighbor_2_type"], + values=np.array([[1, 1, 1], [8, 8, 8]], dtype=np.int32), +) + +selected_properties = TensorMap(keys, blocks) + +# %% +# +# Only one of the key from our ``selected_properties`` will be used in the +# ``selected_keys``, meaning the output will only contain this one key/block. + +selected_keys = Labels( + names=["center_type", "neighbor_1_type", "neighbor_2_type"], + values=np.array([[1, 1, 1]], dtype=np.int32), +) + +descriptor = calculator.compute( + frames, + selected_properties=selected_properties, + selected_keys=selected_keys, +) + +# %% +# +# As expected, we get 1 block with values of the form (420, 1), i.e. with only 1 +# property. + +print(f"list of keys: {descriptor.keys}") +print(descriptor.block(0).values.shape) + +# %% +# +# .. end-body diff --git a/latest/_downloads/bc82bea3a5dd7bdba60b65220891d9e5/examples_python.zip b/latest/_downloads/bc82bea3a5dd7bdba60b65220891d9e5/examples_python.zip new file mode 100644 index 000000000..191000c72 Binary files /dev/null and b/latest/_downloads/bc82bea3a5dd7bdba60b65220891d9e5/examples_python.zip differ diff --git a/latest/_downloads/c7b538745d9e014f991073659387d6c0/splined-radial-integral.zip b/latest/_downloads/c7b538745d9e014f991073659387d6c0/splined-radial-integral.zip new file mode 100644 index 000000000..e0df96cea Binary files /dev/null and b/latest/_downloads/c7b538745d9e014f991073659387d6c0/splined-radial-integral.zip differ diff --git a/latest/_downloads/cd406b7304ffdc24d0054d9b0c7d63d0/keys-selection.zip b/latest/_downloads/cd406b7304ffdc24d0054d9b0c7d63d0/keys-selection.zip new file mode 100644 index 000000000..cd9d20706 Binary files /dev/null and b/latest/_downloads/cd406b7304ffdc24d0054d9b0c7d63d0/keys-selection.zip differ diff --git a/latest/_downloads/da3a0f5fe9cb072a4fc31c517eab269a/property-selection.zip b/latest/_downloads/da3a0f5fe9cb072a4fc31c517eab269a/property-selection.zip new file mode 100644 index 000000000..a002468a9 Binary files /dev/null and b/latest/_downloads/da3a0f5fe9cb072a4fc31c517eab269a/property-selection.zip differ diff --git a/latest/_downloads/fb625db3c50d423b1b7881136ffdeec8/examples_jupyter.zip b/latest/_downloads/fb625db3c50d423b1b7881136ffdeec8/examples_jupyter.zip new file mode 100644 index 000000000..e33ec5a98 Binary files /dev/null and b/latest/_downloads/fb625db3c50d423b1b7881136ffdeec8/examples_jupyter.zip differ diff --git a/latest/_downloads/fc1ab03aab487600310e5f3e33ce7513/keys-selection.ipynb b/latest/_downloads/fc1ab03aab487600310e5f3e33ce7513/keys-selection.ipynb new file mode 100644 index 000000000..bbe022b1d --- /dev/null +++ b/latest/_downloads/fc1ab03aab487600310e5f3e33ce7513/keys-selection.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Keys Selection\n\n.. start-body\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import chemfiles\nimport numpy as np\nfrom metatensor import Labels, TensorBlock, TensorMap\n\nfrom rascaline import SoapPowerSpectrum" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we load the dataset with chemfiles\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "with chemfiles.Trajectory(\"dataset.xyz\") as trajectory:\n frames = [f for f in trajectory]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and define the hyper parameters of the representation\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "HYPER_PARAMETERS = {\n \"cutoff\": 5.0,\n \"max_radial\": 6,\n \"max_angular\": 4,\n \"atomic_gaussian_width\": 0.3,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\n \"Gto\": {},\n },\n \"cutoff_function\": {\n \"ShiftedCosine\": {\"width\": 0.5},\n },\n}\n\ncalculator = SoapPowerSpectrum(**HYPER_PARAMETERS)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The selections for keys should be a set of ``Labels``, with the names of the\nkeys being a subset of the names of the keys produced by the calculator.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "descriptor = calculator.compute(frames)\nprint(\"keys names:\", descriptor.keys.names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use these names to define a selection, and only blocks matching the\nlabels in this selection will be used by rascaline. Here, only blocks with\nkeys ``[1,1,1]`` and ``[4,4,4]`` will be calculated.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selection = Labels(\n names=[\"center_type\", \"neighbor_1_type\", \"neighbor_2_type\"],\n values=np.array([[1, 1, 1], [4, 4, 4]], dtype=np.int32),\n)\nselected_descriptor = calculator.compute(frames, selected_keys=selection)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We get a TensorMap with 2 blocks, corresponding to the requested keys\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(selected_descriptor.keys)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The block for ``[1, 1, 1]`` will be exactly the same as the one in the full\n``TensorMap``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "answer = np.array_equal(descriptor.block(0).values, selected_descriptor.block(0).values)\nprint(f\"Are the blocks 0 in the descriptor and selected_descriptor equal? {answer}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since there is no block for ``[4, 4, 4]`` in the full ``TensorMap``, an empty\nblock with no samples and the default set of properties is generated\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(selected_descriptor.block(1).values.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``selected_keys`` can be used simultaneously with samples and properties\nselection. Here we define a selection for properties as a ``TensorMap`` to\nselect different properties for each block:\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selection = [\n Labels(names=[\"l\", \"n_1\", \"n_2\"], values=np.array([[0, 0, 0]])),\n Labels(names=[\"l\", \"n_1\", \"n_2\"], values=np.array([[1, 1, 1]])),\n]\nblocks = []\nfor entries in selection:\n blocks.append(\n TensorBlock(\n values=np.empty((len(entries), 1)),\n samples=Labels.single(),\n components=[],\n properties=entries,\n )\n )\n\nkeys = Labels(\n names=[\"center_type\", \"neighbor_1_type\", \"neighbor_2_type\"],\n values=np.array([[1, 1, 1], [8, 8, 8]], dtype=np.int32),\n)\n\nselected_properties = TensorMap(keys, blocks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Only one of the key from our ``selected_properties`` will be used in the\n``selected_keys``, meaning the output will only contain this one key/block.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "selected_keys = Labels(\n names=[\"center_type\", \"neighbor_1_type\", \"neighbor_2_type\"],\n values=np.array([[1, 1, 1]], dtype=np.int32),\n)\n\ndescriptor = calculator.compute(\n frames,\n selected_properties=selected_properties,\n selected_keys=selected_keys,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, we get 1 block with values of the form (420, 1), i.e. with only 1\nproperty.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(f\"list of keys: {descriptor.keys}\")\nprint(descriptor.block(0).values.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ".. end-body\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/fcead3d0fa59b2b1de860077be1a661d/le-basis.ipynb b/latest/_downloads/fcead3d0fa59b2b1de860077be1a661d/le-basis.ipynb new file mode 100644 index 000000000..0bdee0658 --- /dev/null +++ b/latest/_downloads/fcead3d0fa59b2b1de860077be1a661d/le-basis.ipynb @@ -0,0 +1,266 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n\n# LE basis\n\n.. start-body\n\nThis example illustrates how to generate a spherical expansion using the Laplacian\neigenstate (LE) basis (https://doi.org/10.1063/5.0124363), using two different basis\ntruncations approaches. The basis can be truncated in the \"traditional\" way, using all\nvalues below a limit in the angular and radial direction; or using a \"ragged\ntruncation\", where basis functions are selected according to an eigenvalue threshold.\n\nThe main ideas behind the LE basis are:\n\n1. use a basis of controllable *smoothness* (intended in the same sense as the\n smoothness of a low-pass-truncated Fourier expansion)\n2. apply a \"ragged truncation\" strategy in which different angular channels are\n truncated at a different number of radial channels, so as to obtain more balanced\n smoothness level in the radial and angular direction, for a given number of basis\n functions.\n\nHere we use :class:`rascaline.utils.SphericalBesselBasis` to create a spline of the\nradial integral corresponding to the LE basis. An detailed how-to guide how to construct\nradial integrals is given in `userdoc-how-to-splined-radial-integral`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import ase.io\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom metatensor import Labels, TensorBlock, TensorMap\n\nimport rascaline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start by using a traditional/square basis truncation. Here we will select all\nbasis functions with ``l <= max_angular`` and ``n < max_radial``. The basis functions\nare the solution of a radial Laplacian eigenvalue problem (spherical Bessel\nfunctions).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cutoff = 4.4\nmax_angular = 6\nmax_radial = 8\n\n# create a spliner for the SOAP radial integral, using delta functions for the atomic\n# density and spherical Bessel functions for the basis\nspliner = rascaline.utils.SoapSpliner(\n cutoff=cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n basis=rascaline.utils.SphericalBesselBasis(\n cutoff=cutoff, max_radial=max_radial, max_angular=max_angular\n ),\n density=rascaline.utils.DeltaDensity(),\n accuracy=1e-8,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now plot the radial integral splines for a couple of functions. This gives an\nidea of the smoothness of the different components\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "splined_basis = spliner.compute()\ngrid = [p[\"position\"] for p in splined_basis[\"TabulatedRadialIntegral\"][\"points\"]]\nvalues = np.array(\n [\n np.array(p[\"values\"][\"data\"]).reshape(p[\"values\"][\"dim\"])\n for p in splined_basis[\"TabulatedRadialIntegral\"][\"points\"]\n ]\n)\n\nplt.plot(grid, values[:, 1, 1], \"b-\", label=\"l=1, n=1\")\nplt.plot(grid, values[:, 4, 1], \"r-\", label=\"l=4, n=1\")\nplt.plot(grid, values[:, 1, 4], \"g-\", label=\"l=1, n=4\")\nplt.plot(grid, values[:, 4, 4], \"y-\", label=\"l=4, n=4\")\nplt.xlabel(\"$r$\")\nplt.ylabel(r\"$R_{nl}$\")\nplt.legend()\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use this spline basis in a :py:class:`SphericalExpansion` calculator to\nevaluate spherical expansion coefficients.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "calculator = rascaline.SphericalExpansion(\n cutoff=cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n center_atom_weight=1.0,\n radial_basis=splined_basis,\n atomic_gaussian_width=-1.0, # will not be used due to the delta density above\n cutoff_function={\"ShiftedCosine\": {\"width\": 0.5}},\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This calculator defaults to the \"traditional\" basis function selection, so we have the\nsame maximal ``n`` value for all ``l``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "systems = ase.io.read(\"dataset.xyz\", \":10\")\n\ndescriptor = calculator.compute(systems)\ndescriptor = descriptor.keys_to_properties(\"neighbor_type\")\ndescriptor = descriptor.keys_to_samples(\"center_type\")\n\nfor key, block in descriptor.items():\n n_max = np.max(block.properties[\"n\"]) + 1\n print(f\"l = {key['o3_lambda']}, n_max = {n_max}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Selecting basis with an eigenvalue threshold**\n\nNow we will calculate the same basis with an eigenvalue threshold. The idea is to\ntreat on the same footings the radial and angular dimension, and select all functions\nwith a mean Laplacian below a certain threshold. This is similar to the common\npractice in plane-wave electronic-structure methods to use a kinetic energy cutoff\nwhere $k_x^2 + k_y^2 + k_z^2 < k_\\text{max}^2$\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "eigenvalue_threshold = 20" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's start by computing a lot of Laplacian eigenvalues, which are related to the\nsquares of the zeros of spherical Bessel functions.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "l_max_large = 49 # just used to get the eigenvalues\nn_max_large = 50 # just used to get the eigenvalues\n\n# compute the zeros of the spherical Bessel functions\nzeros_ln = rascaline.utils.SphericalBesselBasis.compute_zeros(l_max_large, n_max_large)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have a 50x50 array containing the position of the zero of the different spherical\nBessel functions, indexed by ``l`` and ``n``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"zeros_ln.shape =\", zeros_ln.shape)\nprint(\"zeros_ln =\", zeros_ln[:3, :3])\n\n# calculate the Laplacian eigenvalues\neigenvalues_ln = zeros_ln**2 / cutoff**2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now determine the set of ``l, n`` pairs to include all eigenvalues below the\nthreshold.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "max_radial_by_angular = []\nfor ell in range(l_max_large + 1):\n # for each l, calculate how many radial basis functions we want to include\n max_radial = len(np.where(eigenvalues_ln[ell] < eigenvalue_threshold)[0])\n max_radial_by_angular.append(max_radial)\n if max_radial_by_angular[-1] == 0:\n # all eigenvalues for this `l` are over the threshold\n max_radial_by_angular.pop()\n max_angular = ell - 1\n break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Comparing this eigenvalues threshold with the one based on a square selection, we see\nthat the eigenvalues threshold leads to a gradual decrease of ``max_radial`` for high\n``l`` values\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "square_max_angular = 10\nsquare_max_radial = 4\nplt.fill_between(\n [0, square_max_angular],\n [square_max_radial, square_max_radial],\n label=r\"$l_\\mathrm{max}$, $n_\\mathrm{max}$ threshold \"\n + f\"({(square_max_angular + 1) * square_max_radial} functions)\",\n color=\"gray\",\n)\nplt.fill_between(\n np.arange(max_angular + 1),\n max_radial_by_angular,\n label=f\"Eigenvalues threshold ({sum(max_radial_by_angular)} functions)\",\n alpha=0.5,\n)\nplt.xlabel(r\"$\\ell$\")\nplt.ylabel(\"n radial basis functions\")\nplt.ylim(-0.5, max_radial_by_angular[0] + 0.5)\nplt.legend()\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Using a subset of basis functions with rascaline**\n\nWe can tweak the default basis selection of rascaline by specifying a larger total\nbasis; and then only asking for a subset of properties to be computed. See\n`userdoc-how-to-property-selection` for more details on properties selection.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# extract all the atomic types from our dataset\nall_atomic_types = list(\n np.unique(np.concatenate([system.numbers for system in systems]))\n)\n\nkeys = []\nblocks = []\nfor center_type in all_atomic_types:\n for neighbor_type in all_atomic_types:\n for ell in range(max_angular + 1):\n max_radial = max_radial_by_angular[ell]\n\n keys.append([ell, 1, center_type, neighbor_type])\n blocks.append(\n TensorBlock(\n values=np.zeros((0, max_radial)),\n samples=Labels.empty(\"_\"),\n components=[],\n properties=Labels(\"n\", np.arange(max_radial).reshape(-1, 1)),\n )\n )\n\nselected_properties = TensorMap(\n keys=Labels(\n names=[\"o3_lambda\", \"o3_sigma\", \"center_type\", \"neighbor_type\"],\n values=np.array(keys),\n ),\n blocks=blocks,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this, we can build a calculator and calculate the spherical expansion\ncoefficients\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# the biggest max_radial will be for l=0\nmax_radial = max_radial_by_angular[0]\n\n\n# set up a spliner object for the spherical Bessel functions this radial basis will be\n# used to compute the spherical expansion\nspliner = rascaline.utils.SoapSpliner(\n cutoff=cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n basis=rascaline.utils.SphericalBesselBasis(\n cutoff=cutoff, max_radial=max_radial, max_angular=max_angular\n ),\n density=rascaline.utils.DeltaDensity(),\n accuracy=1e-8,\n)\n\ncalculator = rascaline.SphericalExpansion(\n cutoff=cutoff,\n max_radial=max_radial,\n max_angular=max_angular,\n center_atom_weight=1.0,\n radial_basis=spliner.compute(),\n atomic_gaussian_width=-1.0, # will not be used due to the delta density above\n cutoff_function={\"ShiftedCosine\": {\"width\": 0.5}},\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And check that we do get the expected Eigenvalues truncation for the calculated\nfeatures!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "descriptor = calculator.compute(\n systems,\n # we tell the calculator to only compute the selected properties\n # (the desired set of (l,n) expansion coefficients\n selected_properties=selected_properties,\n)\n\ndescriptor = descriptor.keys_to_properties(\"neighbor_type\")\ndescriptor = descriptor.keys_to_samples(\"center_type\")\n\nfor key, block in descriptor.items():\n n_max = np.max(block.properties[\"n\"]) + 1\n print(f\"l = {key['o3_lambda']}, n_max = {n_max}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ".. end-body\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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_images/core-concepts.svg b/latest/_images/core-concepts.svg new file mode 100644 index 000000000..e936c4360 --- /dev/null +++ b/latest/_images/core-concepts.svg @@ -0,0 +1,381 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Systems + + + positions + cell and periodicity + neighbors list + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Calculators + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TensorMap + + + key:   0, 3 + + + key:   1, -2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/latest/_images/long-range-descriptor.svg b/latest/_images/long-range-descriptor.svg new file mode 100644 index 000000000..dd491ebb7 --- /dev/null +++ b/latest/_images/long-range-descriptor.svg @@ -0,0 +1 @@ +All atom contributionsFourier space LODE descriptorInterior partreal space LODE descriptorExterior partresult of this how-to guide \ No newline at end of file diff --git a/latest/_images/moments-descriptor.svg b/latest/_images/moments-descriptor.svg new file mode 100644 index 000000000..99be80f8c --- /dev/null +++ b/latest/_images/moments-descriptor.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/latest/_images/rascaline-python.svg b/latest/_images/rascaline-python.svg new file mode 100644 index 000000000..629c35d52 --- /dev/null +++ b/latest/_images/rascaline-python.svg @@ -0,0 +1 @@ +librascaline.sorascaline-c-apicbindgenrascaline.hpycparserrascalinePython module_rascaline.pycallsgenerates \ No newline at end of file diff --git a/latest/_images/sphx_glr_compute-soap_thumb.png b/latest/_images/sphx_glr_compute-soap_thumb.png new file mode 100644 index 000000000..8a5fed589 Binary files /dev/null and b/latest/_images/sphx_glr_compute-soap_thumb.png differ diff --git a/latest/_images/sphx_glr_first-calculation_thumb.png b/latest/_images/sphx_glr_first-calculation_thumb.png new file mode 100644 index 000000000..8a5fed589 Binary files /dev/null and b/latest/_images/sphx_glr_first-calculation_thumb.png differ diff --git a/latest/_images/sphx_glr_keys-selection_thumb.png b/latest/_images/sphx_glr_keys-selection_thumb.png new file mode 100644 index 000000000..8a5fed589 Binary files /dev/null and b/latest/_images/sphx_glr_keys-selection_thumb.png differ diff --git a/latest/_images/sphx_glr_le-basis_001.png b/latest/_images/sphx_glr_le-basis_001.png new file mode 100644 index 000000000..4995c550c Binary files /dev/null and b/latest/_images/sphx_glr_le-basis_001.png differ diff --git a/latest/_images/sphx_glr_le-basis_002.png b/latest/_images/sphx_glr_le-basis_002.png new file mode 100644 index 000000000..64c40e4c4 Binary files /dev/null and b/latest/_images/sphx_glr_le-basis_002.png differ diff --git a/latest/_images/sphx_glr_le-basis_thumb.png b/latest/_images/sphx_glr_le-basis_thumb.png new file mode 100644 index 000000000..14126bc75 Binary files /dev/null and b/latest/_images/sphx_glr_le-basis_thumb.png differ diff --git a/latest/_images/sphx_glr_long-range-descriptor_001.png b/latest/_images/sphx_glr_long-range-descriptor_001.png new file mode 100644 index 000000000..1837ea7d2 Binary files /dev/null and b/latest/_images/sphx_glr_long-range-descriptor_001.png differ diff --git a/latest/_images/sphx_glr_long-range-descriptor_002.png b/latest/_images/sphx_glr_long-range-descriptor_002.png new file mode 100644 index 000000000..ca4af4b31 Binary files /dev/null and b/latest/_images/sphx_glr_long-range-descriptor_002.png differ diff --git a/latest/_images/sphx_glr_long-range-descriptor_003.png b/latest/_images/sphx_glr_long-range-descriptor_003.png new file mode 100644 index 000000000..8139afe44 Binary files /dev/null and b/latest/_images/sphx_glr_long-range-descriptor_003.png differ diff --git a/latest/_images/sphx_glr_long-range-descriptor_004.png b/latest/_images/sphx_glr_long-range-descriptor_004.png new file mode 100644 index 000000000..d8a3a51fb Binary files /dev/null and b/latest/_images/sphx_glr_long-range-descriptor_004.png differ diff --git a/latest/_images/sphx_glr_long-range-descriptor_005.png b/latest/_images/sphx_glr_long-range-descriptor_005.png new file mode 100644 index 000000000..33e4d72bb Binary files /dev/null and b/latest/_images/sphx_glr_long-range-descriptor_005.png differ diff --git a/latest/_images/sphx_glr_long-range-descriptor_006.png b/latest/_images/sphx_glr_long-range-descriptor_006.png new file mode 100644 index 000000000..39cb3ba03 Binary files /dev/null and b/latest/_images/sphx_glr_long-range-descriptor_006.png differ diff --git a/latest/_images/sphx_glr_long-range-descriptor_007.png b/latest/_images/sphx_glr_long-range-descriptor_007.png new file mode 100644 index 000000000..91267f207 Binary files /dev/null and b/latest/_images/sphx_glr_long-range-descriptor_007.png differ diff --git a/latest/_images/sphx_glr_long-range-descriptor_thumb.png b/latest/_images/sphx_glr_long-range-descriptor_thumb.png new file mode 100644 index 000000000..e0fcb1a58 Binary files /dev/null and b/latest/_images/sphx_glr_long-range-descriptor_thumb.png differ diff --git a/latest/_images/sphx_glr_profiling_thumb.png b/latest/_images/sphx_glr_profiling_thumb.png new file mode 100644 index 000000000..8a5fed589 Binary files /dev/null and b/latest/_images/sphx_glr_profiling_thumb.png differ diff --git a/latest/_images/sphx_glr_property-selection_thumb.png b/latest/_images/sphx_glr_property-selection_thumb.png new file mode 100644 index 000000000..8a5fed589 Binary files /dev/null and b/latest/_images/sphx_glr_property-selection_thumb.png differ diff --git a/latest/_images/sphx_glr_sample-selection_thumb.png b/latest/_images/sphx_glr_sample-selection_thumb.png new file mode 100644 index 000000000..8a5fed589 Binary files /dev/null and b/latest/_images/sphx_glr_sample-selection_thumb.png differ diff --git a/latest/_images/sphx_glr_splined-radial-integral_thumb.png b/latest/_images/sphx_glr_splined-radial-integral_thumb.png new file mode 100644 index 000000000..8a5fed589 Binary files /dev/null and b/latest/_images/sphx_glr_splined-radial-integral_thumb.png differ diff --git a/latest/_images/sphx_glr_understanding-hypers_001.png b/latest/_images/sphx_glr_understanding-hypers_001.png new file mode 100644 index 000000000..8dc1e69f2 Binary files /dev/null and b/latest/_images/sphx_glr_understanding-hypers_001.png differ diff --git a/latest/_images/sphx_glr_understanding-hypers_002.png b/latest/_images/sphx_glr_understanding-hypers_002.png new file mode 100644 index 000000000..1e93231f4 Binary files /dev/null and b/latest/_images/sphx_glr_understanding-hypers_002.png differ diff --git a/latest/_images/sphx_glr_understanding-hypers_003.png b/latest/_images/sphx_glr_understanding-hypers_003.png new file mode 100644 index 000000000..f3c60a16c Binary files /dev/null and b/latest/_images/sphx_glr_understanding-hypers_003.png differ diff --git a/latest/_images/sphx_glr_understanding-hypers_thumb.png b/latest/_images/sphx_glr_understanding-hypers_thumb.png new file mode 100644 index 000000000..77bab4dd8 Binary files /dev/null and b/latest/_images/sphx_glr_understanding-hypers_thumb.png differ diff --git a/latest/_sources/devdoc/explanations/architecture.rst.txt b/latest/_sources/devdoc/explanations/architecture.rst.txt new file mode 100644 index 000000000..fdbe213f6 --- /dev/null +++ b/latest/_sources/devdoc/explanations/architecture.rst.txt @@ -0,0 +1,28 @@ +Code organization +----------------- + +The code is organized in three main products, each in a separate directory: + +- ``rascaline/`` contains the main Rust implementation of all calculators, and + the corresponding unit and regression tests; +- ``rascaline-c-api/`` is a Rust crate containing the implementation of the + rascaline C API; +- ``python/`` contains the Python interface to rascaline, and the corresponding + tests + +Finally, ``docs/`` contains the documentation for everything related to +rascaline. + +The main rascaline crate +^^^^^^^^^^^^^^^^^^^^^^^^ + +Inside the main rascaline crate, the following code organization is used: + +- ``rascaline/benches``: benchmarks of the code on some simple systems; +- ``rascaline/tests``: regression tests for all calculators; +- ``rascaline/src/system/``: definition of everything related to systems: + ``UnitCell``, the ``System`` trait and ``SimpleSystem`` implementation; +- ``rascaline/src/calculator.rs``: convenience wrapper around implementations of + ``CalculatorBase`` that setup everything before a calculation; +- ``rascaline/src/calculators/``: definition of the ``CalculatorBase`` trait and + various implementations of this trait; diff --git a/latest/_sources/devdoc/explanations/index.rst.txt b/latest/_sources/devdoc/explanations/index.rst.txt new file mode 100644 index 000000000..9ccd23922 --- /dev/null +++ b/latest/_sources/devdoc/explanations/index.rst.txt @@ -0,0 +1,15 @@ +.. _devdoc-explanations: + +Explanations +============ + +The explanation section discusses topics that broaden your knowledge of +rascaline. Technical facts and some tidbits of useful information are found here +to give you more clarity and understanding of what rascaline is all about. + +.. toctree:: + :maxdepth: 2 + + architecture + interfaces + radial-integral diff --git a/latest/_sources/devdoc/explanations/interfaces.rst.txt b/latest/_sources/devdoc/explanations/interfaces.rst.txt new file mode 100644 index 000000000..d0d27267d --- /dev/null +++ b/latest/_sources/devdoc/explanations/interfaces.rst.txt @@ -0,0 +1,69 @@ +Python and C interface +====================== + +How is the C interface exported +------------------------------- + +Rascaline exports a C interface, defined in ``rascaline-c-api``. This C +interface is created directly in Rust, without involving any C code. + +This is done by marking functions as ``#[no_mangle] extern pub fn `` in +``rascaline-c-api``, and only using types safe to send to C (mostly pointers and +basic values such as floats or integers). Of these markers, ``pub`` ensures that +the function is exported from the library (it should appear as a ``T`` symbol in +``nm`` output); ``extern`` forces the function to use the C calling convention +(a calling convention describes where in memory/CPU registers the caller should +put data that the function expects); and ``#[no_mangle]`` tells the compiler to +export the function under this exact name, instead of using a mangled named +containing the module path and functions parameters. + +Additionally, the C interfaces expose C-compatible structs declared with +``#[repr(C)] pub struct {}``; where ``#[repr(C)]`` ensures that the +compiler lays out the fields in the exact order they are declared, without +re-organizing them. + +``rascaline-c-api`` is then compiled to a shared library (``librascaline.so`` / +``librascaline.dylib`` / ``librascaline.dll``), which can be used by any +language able to call C code to call the exported functions without ever +realizing it is speaking with Rust code. + +The list of exported functions, together with the types of the function's +parameters, and struct definitions are extracted from the rust source code using +`cbindgen`_, which creates the ``rascaline-c-api/rascaline.h`` header file +containing all of this information in a C compatible syntax. All of the +documentation is also reproduced using `doxygen`_ syntax. + + +How does the Python interface works +----------------------------------- + +The Python interface used the `ctypes`_ module to call exported symbols from the +shared library. For the Python code to be able to call exported function safely, +it needs to know a few things. In particular, it needs to know the name of the +function, the number and types of parameters and the return type of the +function. All this information is available in ``rascaline-c-api/rascaline.h``, +but not in a way that is easily accessible from `ctypes`_. There is a script in +``python/scripts/generate-declaration.py`` which reads the header file using +`pycparser`_, and creates the `python/rascaline/_rascaline.py` file which +declares all functions in the way expected by the `ctypes`_ module. You will +need to manually re-run this script if you modify any of the exported functions +in `rascaline-c-api`. + +The schematic below describes all the relationships between the components +involved in creating the Python interface. + +.. figure:: ../../../static/images/rascaline-python.* + :width: 400px + :align: center + + Schematic representation of all components in the Python interface. The rust + crate ``rascaline-c-api`` is compiled to a shared library + (``librascaline.so`` on Linux), and `cbindgen`_ is used to generate the + corresponding header. This header is then read with `pycparser`_ to create + ctypes' compatible declarations, used to ensure that Python and rust agree + fully on the parameters types, allowing Python to directly call Rust code. + +.. _ctypes: https://docs.python.org/3/library/ctypes.html +.. _pycparser: https://github.com/eliben/pycparser +.. _cbindgen: https://github.com/eqrion/cbindgen/blob/master/docs.md +.. _doxygen: https://doxygen.org diff --git a/latest/_sources/devdoc/explanations/radial-integral.rst.txt b/latest/_sources/devdoc/explanations/radial-integral.rst.txt new file mode 100644 index 000000000..a8e6587f1 --- /dev/null +++ b/latest/_sources/devdoc/explanations/radial-integral.rst.txt @@ -0,0 +1,275 @@ +.. _radial-integral: + +SOAP and LODE radial integrals +=================================== + +On this page, we describe the exact mathematical expression that are implemented in the +radial integral and the splined radial integral classes i.e. +:ref:`python-splined-radial-integral`. Note that this page assumes knowledge of +spherical expansion & friends and currently serves as a reference page for +the developers to support the implementation. + +Preliminaries +------------- + +In this subsection, we briefly provide all the preliminary knowledge that is needed to +understand what the radial integral class is doing. The actual explanation for what is +computed in the radial integral class can be found in the next subsection (1.2). The +spherical expansion coefficients :math:`\langle anlm | \rho_i \rangle` are completely +determined by specifying two ingredients: + +- the atomic density function :math:`g(r)` as implemented in + :ref:`python-atomic-density`, often chosen to be a Gaussian or Delta function, that + defined the type of density under consideration. For a given central atom :math:`i` in + the system, the total density function :math:`\rho_i(\boldsymbol{r})` around is + then defined as :math:`\rho_i(\boldsymbol{r}) = \sum_{j} g(\boldsymbol{r} - + \boldsymbol{r}_{ij})`. + +- the radial basis functions :math:`R_{nl}(r)` as implementated + :ref:`python-radial-basis`, on which the density :math:`\rho_i` is projected. To be + more precise, the actual basis functions are of the form + + .. math:: + + B_{nlm}(\boldsymbol{r}) = R_{nl}(r)Y_{lm}(\hat{r}), + + where :math:`Y_{lm}(\hat{r})` are the real spherical harmonics evaluated at the point + :math:`\hat{r}`, i.e. at the spherical angles :math:`(\theta, \phi)` that determine + the orientation of the unit vector :math:`\hat{r} = \boldsymbol{r}/r`. + +The spherical expansion coefficient :math:`\langle nlm | \rho_i \rangle` (we omit the +atom type index :math:`a` for simplicity) is then defined as + +.. math:: + + \begin{aligned} + \langle nlm | \rho_i \rangle & = \int \mathrm{d}^3\boldsymbol{r} + B_{nlm}(\boldsymbol{r}) \rho_i(\boldsymbol{r}) \\ \label{expansion_coeff_def} & = + \int \mathrm{d}^3\boldsymbol{r} R_{nl}(r)Y_{lm}(\hat{r})\rho_i(\boldsymbol{r}). + \end{aligned} + +In practice, the atom centered density :math:`\rho_i` is a superposition of the neighbor +contributions, namely :math:`\rho_i(\boldsymbol{r}) = \sum_{j} g(\boldsymbol{r} - +\boldsymbol{r}_{ij})`. Due to linearity of integration, evaluating the integral can then +be simplified to + +.. math:: + + \begin{aligned} + \langle nlm | \rho_i \rangle & = \int \mathrm{d}^3\boldsymbol{r} + R_{nl}(r)Y_{lm}(\hat{r})\rho_i(\boldsymbol{r}) \\ & = \int + \mathrm{d}^3\boldsymbol{r} R_{nl}(r)Y_{lm}(\hat{r})\left( \sum_{j} + g(\boldsymbol{r} - \boldsymbol{r}_{ij})\right) \\ & = \sum_{j} \int + \mathrm{d}^3\boldsymbol{r} R_{nl}(r)Y_{lm}(\hat{r}) g(\boldsymbol{r} - + \boldsymbol{r}_{ij}) \\ & = \sum_j \langle nlm | g;\boldsymbol{r}_{ij} \rangle. + \end{aligned} + +Thus, instead of having to compute integrals for arbitrary densities :math:`\rho_i`, we +have reduced our problem to the evaluation of integrals of the form + +.. math:: + + \begin{aligned} + \langle nlm | g;\boldsymbol{r}_{ij} \rangle & = \int \mathrm{d}^3\boldsymbol{r} + R_{nl}(r)Y_{lm}(\hat{r})g(\boldsymbol{r} - \boldsymbol{r}_{ij}), + \end{aligned} + +which are completely specified by + +- the density function :math:`g(\boldsymbol{r})` + +- the radial basis :math:`R_{nl}(r)` + +- the position of the neighbor atom :math:`\boldsymbol{r}_{ij}` relative to the center + atom + +The radial integral class +------------------------- + +In the previous subsection, we have explained how the computation of the spherical +expansion coefficients can be reduced to integrals of the form + +.. math:: + + \begin{aligned} + \langle nlm | g;\boldsymbol{r}_{ij} \rangle & = \int \mathrm{d}^3\boldsymbol{r} + R_{nl}(r)Y_{lm}(\hat{r})g(\boldsymbol{r} - \boldsymbol{r}_{ij}). + \end{aligned} + +If the atomic density is spherically symmetric, i.e. if :math:`g(\boldsymbol{r}) = g(r)` +this integral can always be written in the following form: + +.. math:: + + \begin{aligned} \label{expansion_coeff_spherical_symmetric} + \langle nlm | g;\boldsymbol{r}_{ij} \rangle & = + Y_{lm}(\hat{r}_{ij})I_{nl}(r_{ij}). + \end{aligned} + +The key point is that the dependence on the vectorial position +:math:`\boldsymbol{r}_{ij}` is split into a factor that contains information about the +orientation of this vector, namely :math:`Y_{lm}(\hat{r}_{ij})`, which is just the +spherical harmonic evaluated at :math:`\hat{r}_{ij}`, and a remaining part that captures +the dependence on the distance of atom :math:`j` from the central atom :math:`i`, namely +:math:`I_{nl}(r_{ij})`, which we shall call the radial integral. The radial integral +class computes and outputs this radial part :math:`I_{nl}(r_{ij})`. Since the angular +part is just the usual spherical harmonic, this is the part that also depends on the +choice of atomic density :math:`g(r)`, as well as the radial basis :math:`R_{nl}(r)`. In +the following, for users only interested in a specific type of density, we provide the +explicit expressions of :math:`I_{nl}(r)` for the Delta and Gaussian densities, followed +by the general expression. + +Delta Densities +~~~~~~~~~~~~~~~ + +Here, we consider the especially simple special case where the atomic density function +:math:`g(\boldsymbol{r}) = \delta(\boldsymbol{r})`. Then: + +.. math:: + + \begin{aligned} + \langle nlm | g;\boldsymbol{r}_{ij} \rangle & = \int \mathrm{d}^3\boldsymbol{r} + R_{nl}(r)Y_{lm}(\hat{r})g(\boldsymbol{r} - \boldsymbol{r}_{ij}) \\ & = \int + \mathrm{d}^3\boldsymbol{r} R_{nl}(r)Y_{lm}(\hat{r})\delta(\boldsymbol{r} - + \boldsymbol{r}_{ij}) \\ & = R_{nl}(r) Y_{lm}(\hat{r}_{ij}) = + B_{nlm}(\boldsymbol{r}_{ij}). + \end{aligned} + +Thus, in this particularly simple case, the radial integral is simply the radial basis +function evaluated at the pair distance :math:`r_{ij}`, and we see that the integrals +have indeed the form presented above. + +Gaussian Densities +~~~~~~~~~~~~~~~~~~ + +Here, we consider another popular use case, where the atomic density function is a +Gaussian. In rascaline, we use the convention + +.. math:: + + g(r) = \frac{1}{(\pi \sigma^2)^{3/4}}e^{-\frac{r^2}{2\sigma^2}}. + +The prefactor was chosen such that the “L2-norm” of the Gaussian + +.. math:: + + \begin{aligned} + \|g\|^2 = \int \mathrm{d}^3\boldsymbol{r} |g(r)|^2 = 1, + \end{aligned} + +but does not affect the following calculations in any way. With these conventions, it +can be shown that the integral has the desired form + +.. math:: + + \begin{aligned} + \langle nlm | g;\boldsymbol{r}_{ij} \rangle & = \int \mathrm{d}^3\boldsymbol{r} + R_{nl}(r)Y_{lm}(\hat{r})g(\boldsymbol{r} - \boldsymbol{r}_{ij}) \\ & = + Y_{lm}(\hat{r}_{ij}) \cdot I_{nl}(r_{ij}) + \end{aligned} + +with + +.. math:: + + I_{nl}(r_{ij}) = \frac{1}{(\pi \sigma^2)^{3/4}}4\pi e^{-\frac{r_{ij}^2}{2\sigma^2}} + \int_0^\infty \mathrm{d}r r^2 R_{nl}(r) e^{-\frac{r^2}{2\sigma^2}} + i_l\left(\frac{rr_{ij}}{\sigma^2}\right), + +where :math:`i_l` is a modified spherical Bessel function. The first factor, of course, +is just the normalization factor of the Gaussian density. See the next two subsections +for a derivation of this formula. + +Derivation of the General Case +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We now derive an explicit formula for radial integral that works for any density. Let +:math:`g(r)` be a generic spherically symmetric density function. Our goal will be to +show that + +.. math:: + + \langle nlm | g;\boldsymbol{r}_{ij} \rangle = Y_{lm}(\hat{r}_{ij}) \left[2\pi + \int_0^\infty \mathrm{d}r r^2 R_{nl}(r) \int_{-1}^1 \mathrm{d}(\cos\theta) + P_l(\cos\theta) g(\sqrt{r^2+r_{ij}^2-2rr_{ij}\cos\theta}) \right] + +and thus we have the desired form :math:`\langle nlm | g;\boldsymbol{r}_{ij} \rangle = +Y_{lm}(\hat{r}_{ij}) I_{nl}(r_{ij})` with + +.. math:: + + \begin{aligned} + I_{nl}(r_{ij}) = 2\pi \int_0^\infty \mathrm{d}r r^2 R_{nl}(r) \int_{-1}^1 + \mathrm{d}u P_l(u) g(\sqrt{r^2+r_{ij}^2-2rr_{ij}u}), + \end{aligned} + +where :math:`P_l(x)` is the :math:`l`-th Legendre polynomial. + +Derivation of the explicit radial integral for Gaussian densities +----------------------------------------------------------------- + +Denoting by :math:`\theta(\boldsymbol{r},\boldsymbol{r}_{ij})` the angle between a +generic position vector :math:`\boldsymbol{r}` and the vector +:math:`\boldsymbol{r}_{ij}`, we can write + +.. math:: + + \begin{aligned} + g(\boldsymbol{r}- \boldsymbol{r}_{ij}) & = \frac{1}{(\pi + \sigma^2)^{3/4}}e^{-\frac{(\boldsymbol{r}- \boldsymbol{r}_{ij})^2}{2\sigma^2}} \\ + & = \frac{1}{(\pi + \sigma^2)^{3/4}}e^{-\frac{(r_{ij})^2}{2\sigma^2}}e^{-\frac{(\boldsymbol{r}^2- + 2\boldsymbol{r}\boldsymbol{r}_{ij})}{2\sigma^2}}, + \end{aligned} + +where the first factor no longer depends on the integration variable :math:`r`. + +Analytical Expressions for the GTO Basis +---------------------------------------- + +While the above integrals are hard to compute in general, the GTO basis is one of the +few sets of basis functions for which many of the integrals can be evaluated +analytically. This is also useful to test the correctness of more numerical +implementations. + +The primitive basis functions are defined as + +.. math:: + + \begin{aligned} + R_{nl}(r) = R_n(r) = r^n e^{-\frac{r^2}{2\sigma_n^2}} + \end{aligned} + +In this form, the basis functions are not yet orthonormal, which requires an extra +linear transformation. Since this transformation can also be applied after computing the +integrals, we simply evaluate the radial integral with respect to these primitive basis +functions. + +Real Space Integral for Gaussian Densities +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We now evaluate + +.. math:: + + \begin{aligned} + I_{nl}(r_{ij}) & = \frac{1}{(\pi \sigma^2)^{3/4}}4\pi + e^{-\frac{r_{ij}^2}{2\sigma^2}} \int_0^\infty \mathrm{d}r r^2 R_{nl}(r) + e^{-\frac{r^2}{2\sigma^2}} i_l\left(\frac{rr_{ij}}{\sigma^2}\right) \\ & = + \frac{1}{(\pi \sigma^2)^{3/4}}4\pi e^{-\frac{r_{ij}^2}{2\sigma^2}} \int_0^\infty + \mathrm{d}r r^2 r^n e^{-\frac{r^2}{2\sigma_n^2}} e^{-\frac{r^2}{2\sigma^2}} + i_l\left(\frac{rr_{ij}}{\sigma^2}\right), + \end{aligned} + +the result of which can be conveniently expressed using :math:`a=\frac{1}{2\sigma^2}`, +:math:`b_n = \frac{1}{2\sigma_n^2}`, :math:`n_\mathrm{eff}=\frac{n+l+3}{2}` and +:math:`l_\mathrm{eff}=l+\frac{3}{2}` as + +.. math:: + + \begin{aligned} + I_{nl}(r_{ij}) = \frac{1}{(\pi \sigma^2)^{3/4}} \cdot + \pi^{\frac{3}{2}}\frac{\Gamma\left(n_\mathrm{eff}\right)}{\Gamma\left(l_\mathrm{eff}\right)}\frac{(ar_{ij})^l}{(a+b)^{n_\mathrm{eff}}}M\left(n_\mathrm{eff},l_\mathrm{eff},\frac{a^2r_{ij}^2}{a^2+b^2}\right), + \end{aligned} + +where :math:`M(a,b,z)` is the confluent hypergeometric function (hyp1f1). diff --git a/latest/_sources/devdoc/get-started.rst.txt b/latest/_sources/devdoc/get-started.rst.txt new file mode 100644 index 000000000..4c19e4ef6 --- /dev/null +++ b/latest/_sources/devdoc/get-started.rst.txt @@ -0,0 +1,6 @@ +.. _devdoc-get-started: + +Getting started +=============== + +.. include:: ../../../CONTRIBUTING.rst diff --git a/latest/_sources/devdoc/how-to/index.rst.txt b/latest/_sources/devdoc/how-to/index.rst.txt new file mode 100644 index 000000000..d98198406 --- /dev/null +++ b/latest/_sources/devdoc/how-to/index.rst.txt @@ -0,0 +1,10 @@ +.. _devdoc-how-to: + +How-to guides +============= + +.. toctree:: + :maxdepth: 2 + + new-calculator + profiling diff --git a/latest/_sources/devdoc/how-to/new-calculator.rst.txt b/latest/_sources/devdoc/how-to/new-calculator.rst.txt new file mode 100644 index 000000000..b0d597de5 --- /dev/null +++ b/latest/_sources/devdoc/how-to/new-calculator.rst.txt @@ -0,0 +1,574 @@ +Adding a new calculator +======================= + +Introduction +------------ + +Before adding a new calculator it be might worth taking a look if your desired already +exists in our :ref:`list ` supported ones. + +In this tutorial, we will go over all the steps required to create a new +calculator. For simplicity sake, the calculator we will implement will be very +basic, keeping the focus on how different bits of the code interact with one +another instead of complex math or performance tricks. + +The calculator that we will create computes an atom-centered representation, +where each atomic environment is represented with the moments of the positions +of the neighbors up to a maximal order. Each atomic type in the neighborhood +will be considered separately. The resulting descriptor will represent an +atom-centered environment :math:`\ket{\mathcal{A}_i}` on a basis of atomic types +:math:`\alpha` and moment order :math:`k`: + +.. math:: + + \braket{\alpha k | \mathcal{A}_i} = \frac{1}{N_\text{neighbors}} \sum_{j \in \mathcal{A}_i} r_{ij}^k \ \delta_{\alpha, \alpha_j} + +.. figure:: ../../../static/images/moments-descriptor.* + :width: 40% + :align: center + +Throughout this tutorial, very basic knowledge of the Rust and Python +programming languages is assumed. If you are just starting up, you may find the +official `Rust book `_ useful; as well +as the documentation for the `standard library +`_; and the `API documentation`_ for +rascaline itself. + +We will also assume that you have a local copy of the rascaline git repository, +and can build the code and run the tests. If not, please look at the +:ref:`devdoc-get-started` sections. + +.. _API documentation: ../reference/rust/rascaline/index.html + +The traits we'll use +-------------------- + +Two of the three :ref:`core concepts ` in rascaline are +represented in the code as Rust traits: systems implements the `System`_ trait, +and calculators implement the `CalculatorBase`_ trait. Traits (also called +interfaces in other languages) define contracts that the implementing code must +follow, in the form of a set of function and documented behavior for these +functions. Fulfilling this contract allow to add new systems which work with all +calculators, already implement or not; and new calculators which can use any +system, already implemented or not. + +In this tutorial, our goal is to write a new struct implementing +`CalculatorBase`_. This implementation will take as input a slice of boxed +`System`_ trait objects, and using data from those fill up a `TensorMap`_ +(defined in the metatensor crate). + +.. _System: ../reference/rust/rascaline/systems/trait.System.html +.. _CalculatorBase: ../reference/rust/rascaline/calculators/trait.CalculatorBase.html +.. _Calculator: ../reference/rust/rascaline/struct.Calculator.html +.. _TensorMap: ../reference/rust/metatensor/tensor/struct.TensorMap.html + +Implementation +-------------- + +Let's start by creating a new file in ``rascaline/src/calculators/moments.rs``, +and importing everything we'll need. Everything in here will be explained when +we get to using it. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s1_scaffold.rs + :language: rust + :start-after: [imports] + :end-before: [imports] + +Then, we can define a struct for our new calculator ``GeometricMoments``. It +will contain two fields: ``cutoff`` to store the cutoff radius, and +``max_moment`` to store the maximal moment to compute. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s1_scaffold.rs + :language: rust + :start-after: [struct] + :end-before: [struct] + +We can then write a skeleton implementation for the `CalculatorBase`_ trait, +leaving all function unimplemented with the ``todo!()`` macro. +``CalculatorBase`` is the trait defining all the functions required for a +calculator. Users might be more familiar with the concrete struct `Calculator`_, +which uses a ``Box`` (i.e. a pointer to a +``CalculatorBase``) to provide its functionalities. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s1_scaffold.rs + :language: rust + :start-after: [impl] + :end-before: [impl] + +We'll go over these functions one by one, explaining what they do as we go. Most +of the functions here are used to communicate metadata about the calculator and +the representation, and the ``compute`` function does the main part of the work. + +Calculator metadata +^^^^^^^^^^^^^^^^^^^ + +The first function returning metadata about the calculator itself is ``name``, +which should return a user-facing name for the current instance of the +descriptor. As a quick refresher on Rust, all functions return the last (and in +this case only) expression. Here the expression creates a reference to a str +(``&str``) and then convert it to an heap-allocated ``String`` using the `Into`_ +trait. + +.. _Into: https://doc.rust-lang.org/std/convert/trait.Into.html + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::name] + :end-before: [CalculatorBase::name] + :dedent: 4 + +Then, the ``parameters`` function should return the parameters used to +create the current instance of the calculator in JSON format. To this end, we +use `serde`_ and ``serde_json`` everywhere in rascaline, so it is a good idea to +do the same here. Let's start by adding the corresponding ``#[derive]`` to the +definition of ``GeometricMoments``, and use it to implement the function. + +.. _serde: https://serde.rs/ + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [struct] + :end-before: [struct] + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::parameters] + :end-before: [CalculatorBase::parameters] + :dedent: 4 + +One interesting thing here is that ``serde_json::to_string`` returns a +``Result``, and we use ``expect`` to extract the string +value. This `Result`_ would only contain an error if ``GeometricMoments`` +contained maps with non-string keys, which is not the case here. ``expect`` +allow us to indicate we don't ever expect this function to fail, but if it were +to return an error, then the code would immediately stop and show the given +message (using a `panic`_). + +Finally, the ``cutoffs`` function should return all the radial cutoffs used +in neighbors lists. Here, we only have one --- ``self.cutoffs`` --- and we use +``std::slice::from_ref`` to construct a list with a single element from a +scalar. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::cutoffs] + :end-before: [CalculatorBase::cutoffs] + :dedent: 4 + +.. _Result: https://doc.rust-lang.org/std/result/index.html +.. _panic: https://doc.rust-lang.org/std/macro.panic.html + +Representation metadata +^^^^^^^^^^^^^^^^^^^^^^^ + +The next set of functions in the `CalculatorBase`_ trait is used to communicate +metadata about the representation, and called by the concrete `Calculator`_ +struct when initializing and allocating the corresponding memory. + +Keys +++++ + +First, we have one function defining the set of keys that will be in the final +``TensorMap``. In our case, we will want to have the central atom type and the +neighbor atom type as keys. This allow to only store data if a given neighbor +is actually present around a given atom. + +We could manually create a set of `Labels`_ with a `LabelsBuilder`_ and return +them. But since multiple calculators will create the same kind of keys, there +are already implementation of typical atomic types keys. Here we use +``CenterSingleNeighborsTypesKeys`` to create a set of keys containing the +central atom type and one neighbor type. This key builder requires a ``cutoff`` +(to determine which neighbors it should use) and ``self_pairs`` indicated +whether atoms should be considered to be their own neighbor or not. + +.. _Labels: ../reference/rust/metatensor/labels/struct.Labels.html +.. _LabelsBuilder: ../reference/rust/metatensor/labels/struct.LabelsBuilder.html + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::keys] + :end-before: [CalculatorBase::keys] + :dedent: 4 + +Samples ++++++++ + +Having defined the keys, we need to define the metadata associated with each +block. For each block, the first set of metadata — called the **samples** -- +describes the rows of the data. Three functions are used to define the samples: +first, ``features_names`` defines the name associated with the different columns +in the sample labels. Then, ``samples`` determines the set of samples associated +with each key/block. The return type of the ``samples`` function takes some +unpacking: we are returning a `Result`_ since any call to a `System`_ function +can fail. The non-error case of the result is a ``Vec``: we need +one set of `Labels`_ for each key/block. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::samples] + :end-before: [CalculatorBase::samples] + :dedent: 4 + +Like for ``CalculatorBase::keys``, we could manually write code to detect the +right set of samples for each key. But since a lot of representation are built +on atom-centered neighborhoods, there is already a tool to create the right set +of samples in the form of ``AtomCenteredSamples``. + +Components +++++++++++ + +The next set of metadata associated with a block are the **components**. Each +block can have 0 or more components, that should be used to store metadata and +information about symmetry operations or any kind of tensorial components. + +Here, we dont' have any components (the ``GeometricMoments`` representation is +invariant), so we just return a list (one for each key) of empty vectors. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::components] + :end-before: [CalculatorBase::components] + :dedent: 4 + + +Properties +++++++++++ + +The **properties** define metadata associated with the columns of the data +arrays. Like for the samples, we have one function to define the set of names +associated with each variable in the properties `Labels`_, and one function to +compute the set of properties defined for each key. + +In our case, there is only one variable in the properties labels, the power +:math:`k` used to compute the moment. When building the full list of Labels for +each key in ``CalculatorBase::properties``, we use the fact that the properties +are the same for each key/block and make copies of the ``Labels`` (since +``Labels`` are reference-counted, the copies are actually quite cheap). + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::properties] + :end-before: [CalculatorBase::properties] + :dedent: 4 + + +Gradients ++++++++++ + +Finally, we have metadata related to the gradients. First, the +``supports_gradient`` function should return which if any of the gradients can +be computed by the current calculator. Typically ``parameter`` is either +``"positions"``, ``"cell"```, or ``"strain"``. Here we only support computing +the gradients with respect to positions. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::supports_gradient] + :end-before: [CalculatorBase::supports_gradient] + :dedent: 4 + +If the user request the calculation of some gradients, and the calculator +supports it, the next step is to define the same set of metadata as for the +values above: samples, components and properties. Properties are easy, because +they are the same between the values and the gradients. The components are also +similar, with some additional components added at the beginning depending on the +kind of gradient. For example, if a calculator uses ``[first, second]`` as it's +set of components, the ``"positions"`` gradient would use ``[xyz, first, +second]``, where ``xyz`` contains 3 entries. Similarly, the ``"strain"`` +gradients would use ``[xyz_1, xyz_2, first, second]`` and the ``"cell"`` +gradients would use ``[abc, xyz, first, second]``. + +Finally, the samples needs to be defined. For the ``"cell"`` or ``"strain"`` +gradients, there is always exactly one gradient sample per value sample. For the +``"positions"`` gradient samples, we could have one gradient sample for each +atom in the same system for each value sample. However, this would create a very +large number of gradient samples (number of atoms squared), and a lot of entries +would be filled with zeros. Instead, each calculator which supports positions +gradients must implement the ``positions_gradient_samples`` function, and use it +to return only the sample associated with non-zero gradients. This function get +as input the set of keys, the list of samples associated with each key, and the +list of systems on which we want to run the calculation. + +We are again using the ``AtomCenteredSamples`` here to share code between +multiple calculators all using atom-centered samples. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s2_metadata.rs + :language: rust + :start-after: [CalculatorBase::positions_gradient_samples] + :end-before: [CalculatorBase::positions_gradient_samples] + :dedent: 4 + + +We are now done defining the metadata associated with our ``GeometricMoments`` +calculator! In the next section, we'll go over the actual calculation of the +representation, and how to use the functions provided by `System`_. + +The compute function +^^^^^^^^^^^^^^^^^^^^ + +We are finally approaching the most important function in `CalculatorBase`_, +``compute``. This function takes as input a list of systems and a `TensorMap`_ +in which to write the results of the calculation. The function also returns a +`Result`_, to be able to indicate that an error was reached during the +calculation. + +The `TensorMap`_ is initialized by the concrete `Calculator`_ struct, according +to parameters provided by the user. In particular, the tensor map will only +contain samples and properties requested by the user, meaning that the code in +``compute`` should check for each block whether a particular sample +(respectively property) is present in ``block.samples`` (resp. +``block.property``) before computing it. + +This being said, let's start writing our ``compute`` function. We'll defensively +check that the tensor map keys match what we expect from them, and return a unit +value ``()`` wrapped in ``Ok`` at the end of the function. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s3_compute_1.rs + :language: rust + :start-after: [compute] + :end-before: [compute] + :dedent: 4 + +From here, the easiest way to implement our geometric moments descriptor is to +iterate over the systems, and then iterate over the pairs in the system. Before +we can get the pairs with ``system.pairs()``, we need to compute the neighbors +list for our current cutoff, using ``system.compute_neighbors()``, which +requires a mutable reference to the system to be able to store the list of +computed pairs (hence the iteration using ``systems.iter_mut()``). + +All the functions on the `System`_ trait return `Result`_, but in contrary to +the ``CalculatorBase::parameters`` function above, we want to send the possible +errors back to the user so that they can deal with them as they want. The +question mark ``?`` operator does exactly that: if the value returned by the +called function is ``Err(e)``, ``?`` immediately returns ``Err(e)``; and if the +result is ``Ok(v)``, ``?`` extract the ``v`` and the execution continues. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s3_compute_2.rs + :language: rust + :start-after: [compute] + :end-before: [compute] + :dedent: 4 + +For each pair, we now have to find the corresponding block (using the center and +neighbor atomic types), and check wether the corresponding sample was +requested by the user. + +To find blocks and check for samples, we can use the `Labels::position`_ +function on the keys and the samples `Labels`_. This function returns an +``Option``, which will be ``None`` is the label (key or sample) was not +found, and ``Some(position)`` where ``position`` is an unsigned integer if the +label was found. For the keys, we know the blocks must exists, so we again use +``expect`` to immediately extract the value of the block index and access the +block. For the samples, we keep them as ``Option`` and will deal with +missing samples later. + +One thing to keep in mind is that a given pair can participate to two different +samples. If two atoms ``i`` and ``j`` are closer than the cutoff, the list of +pairs will only contain the ``i-j`` pair, and not the ``j-i`` pair (it is a +so-called half neighbors list). That being said, we can get the list of atomic types +with ``system.types()`` before the loop over pairs, and then construct the two +candidate samples and check for their presence. If neither of the samples was +requested, then we can skip the calculation for this pair. We also use +``system.pairs_containing()`` to get the number of neighbors a given center has. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s3_compute_3.rs + :language: rust + :start-after: [compute] + :end-before: [compute] + :dedent: 4 + + +.. _Labels::position: ../reference/rust/metatensor/labels/struct.Labels.html#method.position + +Now, we can check if the samples are present, and if they are, iterate over the +requested features, compute the moments for the current pair distance, and +accumulate it in the descriptor values array: + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s3_compute_4.rs + :language: rust + :start-after: [compute] + :end-before: [compute] + :dedent: 4 + + +Finally, we can deal with the gradients. We first check if gradient data is +defined in the descriptor we need to fill, by checking if it is defined on the +first block (we know it is either defined on all blocks or none). + +If we need to compute the gradients with respect to atomic positions, we will us +the following expression: + +.. math:: + + \frac{\partial}{\partial \vec{r_{j}}} \braket{\alpha k | \chi_i} + = \frac{\vec{r_{ij}}}{r_{ij}} \cdot \frac{k \ r_{ij}^{k - 1} \ \delta_{\alpha, \alpha_j}}{N_\text{neighbors}} + = \vec{r_{ij}} \frac{k \ r_{ij}^{k - 2} \ \delta_{\alpha, \alpha_j}}{N_\text{neighbors}} + +The code to compute gradients is very similar to the code computing the +representation, checking the existence of a given gradient sample before writing +to it. There are now four possible contributions for a given pair: +:math:`\partial \ket{\chi_i} / \partial r_j`, :math:`\partial \ket{\chi_j} / +\partial r_i`, :math:`\partial \ket{\chi_i} / \partial r_i` and :math:`\partial +\ket{\chi_j} / \partial r_j`, where :math:`\ket{\chi_i}` is the representation +around atom :math:`i`. Another way to say it is that in addition to the +gradients of the descriptor centered on :math:`i` with respect to atom +:math:`j`, we also need to account for the gradient of the descriptor centered +on atom :math:`i` with respect to its own position. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/s3_compute_5.rs + :language: rust + :start-after: [compute] + :end-before: [compute] + :dedent: 4 + +-------------------------------------------------------------------------------- + +.. html_hidden:: + :toggle: Here is the final implementation for the compute function + :before-not-html: Here is the final implementation for the compute function + + .. literalinclude:: ../../../../rascaline/src/tutorials/moments/moments.rs + :language: rust + :start-after: [compute] + :end-before: [compute] + :dedent: 4 + +Registering the new calculator +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now that we are done with the code for this calculator, we need to make it +available to users. The entry point for users is the `Calculator`_ struct, which +needs to be constructed from a calculator name and hyper-parameters in JSON +format. + +When the user calls ``Calculator::new("calculator_name", "{\"hyper_parameters\": +1}")``, rascaline looks for ``"calculator_name"`` in the global calculator +registry, and tries to create an instance using the hyper-parameters. In order +to make our calculator available to all users, we need to add it to this +registry, in ``rascaline/src/calculator.rs``. The registry looks like this: + +.. literalinclude:: ../../../../rascaline/src/calculator.rs + :language: rust + :start-after: [calculator-registration] + :end-before: [calculator-registration] + +``add_calculator!`` is a local macro that takes three or four arguments: the +registry itself (a ``BTreeMap``), the calculator name, the struct implementing +`CalculatorBase`_ and optionally a struct to use as parameters to create the +previous one. In our case, we want to use the three arguments version in +something like ``add_calculator!(map, "geometric_moments", GeometricMoments);``. +You'll need to make sure to bring your new calculator in scope with a `use` item. + +Additionally, you may want to add a convenience class in Python for our new +calculator. For this, you can add a class like this to +``python/rascaline/calculators.py``: + +.. code-block:: python + + class GeometricMoments(CalculatorBase): + """ TODO: documentation """ + + def __init__(self, cutoff, max_moment, gradients): + parameters = { + "cutoff": cutoff, + "max_moment": max_moment, + "gradients": gradients, + } + super().__init__("geometric_moments", parameters) + + + ############################################################################# + + # this allows using the calculator like this + from rascaline import GeometricMoments + calculator = GeometricMoments(cutoff=3.5, max_moment=6, gradients=False) + + # instead of + from rascaline.calculators import CalculatorBase + calculator = CalculatorBase( + "geometric_moments", + {"cutoff": 3.5, "max_moment": 6, "gradients": False}, + ) + +We have now finished our implementation of the geometric moments calculator! In +the next steps, we'll see how to write tests to ensure the calculator works and +how to write some documentation for it. + +Testing the new calculator +-------------------------- + +Before we can release our new calculator in the world, we need to make sure it +currently behaves as intended, and that we have a way to ensure it continues to +behave as intended as the code changes. To achieve both goals, rascaline uses +unit tests and regression tests. Unit tests are written in the same file as the +main part of the code, in a ``tests`` module, and are expected to test high +level properties of the code. For example, unit tests allow to check that the +computed gradient match the derivatives of the computed values; or that the +right values are computed when the users requests a subset of samples & +features. On the other hand, regression tests check the exact values produced by +a given calculator on a specific system; and that these values stay the same as +we modify the code, for example when trying to optimize it. These regression +tests live in the ``rascaline/tests`` folder, with one file per test. + +This tutorial will focus on unit tests and introduce some utilities for tests +that should apply to all calculators. To write regression tests, you should take +inspiration from existing tests such as ``spherical-expansion`` test. Each Rust +file in ``rascaline/tests`` is associated with a Python file in +``rascaline/tests/data`` used to generate the values the regression test is +checking, so you'll need one of these as well. + +Testing properties +^^^^^^^^^^^^^^^^^^ + +If this is the first time you are writing tests in Rust, you should read the +`corresponding chapter +`_ in the official +Rust book for a great introduction to this subject. + +Depending on the representation you are working with, you should write tests +that check the fundamental properties of this representation. For example, for +our geometric moments representation, the first moment (with order 0) should +always be the number of neighbor of the current atomic type over the total +number of neighbors. A test checking this property would look like this: + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/moments.rs + :language: rust + :start-after: [property-test] + :end-before: [property-test] + +The ``rascaline::systems::test_utils::test_systems`` function provides a couple +of very simple systems to be used for testing. + +Testing partial calculations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +One properties that all calculators must respect is that computing only a subset +of samples or feature should give the same values as computing everything. +Rascaline provides a function (``calculators::tests_utils::compute_partial``) to +check this for you, simplifying the tests a bit. Here is how one can use it with +the ``GeometricMoments`` calculator: + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/moments.rs + :language: rust + :start-after: [partial-test] + :end-before: [partial-test] + + +Testing gradients +^^^^^^^^^^^^^^^^^ + +If a calculator can compute gradients, it is a good idea to check if the +gradient does match the finite differences definition of derivatives. Rascaline +provides ``calculators::tests_utils::finite_difference`` to help check this. + +.. literalinclude:: ../../../../rascaline/src/tutorials/moments/moments.rs + :language: rust + :start-after: [finite-differences-test] + :end-before: [finite-differences-test] + +Documenting the new calculator +------------------------------ + +.. warning:: Work in progress + + This section of the documentation is not yet written diff --git a/latest/_sources/devdoc/how-to/profiling.rst.txt b/latest/_sources/devdoc/how-to/profiling.rst.txt new file mode 100644 index 000000000..d366ab2d7 --- /dev/null +++ b/latest/_sources/devdoc/how-to/profiling.rst.txt @@ -0,0 +1,78 @@ +Profiling calculation +===================== + +It can be interesting to know where a calculation is spending its time. To this +end, rascaline includes self-profiling code that can record and display which +part of the calculation takes time, and which function called long-running +functions. All the example should output something similar to the table below. + +.. code-block:: text + + ╔════╦══════════════════════════════╦════════════╦═══════════╦══════════╦═════════════╗ + ║ id ║ span name ║ call count ║ called by ║ total ║ mean ║ + ╠════╬══════════════════════════════╬════════════╬═══════════╬══════════╬═════════════╣ + ║ 2 ║ Full calculation ║ 1 ║ — ║ 660.58ms ║ 660.58ms ║ + ╠════╬══════════════════════════════╬════════════╬═══════════╬══════════╬═════════════╣ + ║ 3 ║ SoapPowerSpectrum::compute ║ 1 ║ 2 ║ 584.02ms ║ 584.02ms ║ + ╠════╬══════════════════════════════╬════════════╬═══════════╬══════════╬═════════════╣ + ║ 1 ║ Calculator::prepare ║ 2 ║ 3, 2 ║ 148.15ms ║ 74.08ms ║ + ╠════╬══════════════════════════════╬════════════╬═══════════╬══════════╬═════════════╣ + ║ 0 ║ NeighborsList ║ 20 ║ 1 ║ 20.82ms ║ 1.04ms ║ + ╠════╬══════════════════════════════╬════════════╬═══════════╬══════════╬═════════════╣ + ║ 5 ║ SphericalExpansion::compute ║ 1 ║ 3 ║ 196.38ms ║ 196.38ms ║ + ╠════╬══════════════════════════════╬════════════╬═══════════╬══════════╬═════════════╣ + ║ 4 ║ GtoRadialIntegral::compute ║ 74448 ║ 5 ║ 117.04ms ║ 1.57µs ║ + ╠════╬══════════════════════════════╬════════════╬═══════════╬══════════╬═════════════╣ + ║ 6 ║ SphericalHarmonics::compute ║ 74448 ║ 5 ║ 9.95ms ║ 133.00ns ⚠️ ║ + ╚════╩══════════════════════════════╩════════════╩═══════════╩══════════╩═════════════╝ + +In this table, the first columns assign a unique numeric identifier to each +section of the code. The second one displays the name of the section. Then come +the number of time this section of the code have been executed, which other +function/section called the current one, and finally the total and mean time +spent in this function. + +The ⚠️ symbol is added when the mean cost of the function is close to the +profiling overhead (30 to 80ns per function call), and thus the measurement +might not be very reliable. + +Some of the most important sections are: + +- ``Calculator::prepare``: building the list of samples/properties that will be in the descriptor +- ``XXX::compute``: building blocks for the overall calculation +- ``NeighborsList``: construction of the list of neighbors + +You can obtain a dataset for profiling from our :download:`website <../../../static/dataset.xyz>`. + +.. tabs:: + + .. group-tab:: Python + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code for this example: profiling.py <../../examples/profiling.py>` + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook for this example: profiling.ipynb <../../examples/profiling.ipynb>` + + .. include:: ../../examples/profiling.rst + :start-after: start-body + :end-before: end-body + + .. group-tab:: Rust + + .. literalinclude:: ../../../../rascaline/examples/profiling.rs + :language: rust + + .. group-tab:: C++ + + .. literalinclude:: ../../../../rascaline-c-api/examples/profiling.cpp + :language: c++ + + .. group-tab:: C + + .. literalinclude:: ../../../../rascaline-c-api/examples/profiling.c + :language: c diff --git a/latest/_sources/devdoc/index.rst.txt b/latest/_sources/devdoc/index.rst.txt new file mode 100644 index 000000000..7d48d384e --- /dev/null +++ b/latest/_sources/devdoc/index.rst.txt @@ -0,0 +1,22 @@ +.. _devdoc: + +Developer documentation +####################### + +This developer documentation is divided into three parts: + +1. :ref:`devdoc-get-started` explains how you can start developing code and + documentation; +2. The :ref:`devdoc-how-to`, take you through a series of steps on key problems + for developing rascaline; +3. In the :ref:`devdoc-explanations` section discusses key topics and concepts + at a fairly high level and provides useful explanations to expand your + knowledge about the architecture of rascaline; + +.. toctree:: + :maxdepth: 2 + :hidden: + + get-started + how-to/index + explanations/index diff --git a/latest/_sources/examples/compute-soap.rst.txt b/latest/_sources/examples/compute-soap.rst.txt new file mode 100644 index 000000000..df1216fee --- /dev/null +++ b/latest/_sources/examples/compute-soap.rst.txt @@ -0,0 +1,204 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/compute-soap.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_compute-soap.py: + + +Computing SOAP features +======================= + +.. start-body + +.. GENERATED FROM PYTHON SOURCE LINES 7-13 + +.. code-block:: Python + + + import chemfiles + + from rascaline import SoapPowerSpectrum + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 14-16 + +Read systems using chemfiles. You can obtain the dataset used in this +example from our :download:`website <../../static/dataset.xyz>`. + +.. GENERATED FROM PYTHON SOURCE LINES 17-21 + +.. code-block:: Python + + + with chemfiles.Trajectory("dataset.xyz") as trajectory: + systems = [s for s in trajectory] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 22-28 + +Rascaline can also handles systems read by `ASE +`_ using + +``systems = ase.io.read("dataset.xyz", ":")``. + +We can now define hyper parameters for the calculation + +.. GENERATED FROM PYTHON SOURCE LINES 29-46 + +.. code-block:: Python + + + HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, + } + + calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 47-48 + +And then run the actual calculation, including gradients with respect to positions + +.. GENERATED FROM PYTHON SOURCE LINES 49-52 + +.. code-block:: Python + + + descriptor = calculator.compute(systems, gradients=["positions"]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 53-57 + +The descriptor is a metatensor ``TensorMap``, containing multiple blocks. We +can transform it to a single block containing a dense representation, with one +sample for each atom-centered environment by using ``keys_to_samples`` and +``keys_to_properties`` + +.. GENERATED FROM PYTHON SOURCE LINES 58-65 + +.. code-block:: Python + + + print("before: ", len(descriptor.keys)) + + descriptor = descriptor.keys_to_samples("center_type") + descriptor = descriptor.keys_to_properties(["neighbor_1_type", "neighbor_2_type"]) + print("after: ", len(descriptor.keys)) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + before: 40 + after: 1 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 66-68 + +you can now use ``descriptor.block().values`` as the input of a machine +learning algorithm + +.. GENERATED FROM PYTHON SOURCE LINES 69-73 + +.. code-block:: Python + + + print(descriptor.block().values.shape) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + (1380, 1800) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 74-75 + +.. end-body + + +.. _sphx_glr_download_examples_compute-soap.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: compute-soap.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: compute-soap.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: compute-soap.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/first-calculation.rst.txt b/latest/_sources/examples/first-calculation.rst.txt new file mode 100644 index 000000000..aa52788a5 --- /dev/null +++ b/latest/_sources/examples/first-calculation.rst.txt @@ -0,0 +1,871 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/first-calculation.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_first-calculation.py: + + +.. _userdoc-tutorials-get-started: + +First descriptor computation +============================ + +This is an introduction to the rascaline interface using a molecular crystals +dataset using the Python interface. If you are interested in another +programming language we recommend you first follow this tutorial and afterward +take a look at the how-to guide on :ref:`userdoc-how-to-computing-soap`. + +The dataset +----------- + +The atomic configurations used in our documentation are a small subset of the +`ShiftML2 dataset `_ +containing molecular crystals. There are four crystals - one with each of the +elements [hydrogen, carbon], [hydrogen, carbon, nitrogen, oxygen], [hydrogen, +carbon, nitrogen], or [hydrogen, carbon, oxygen]. Each crystal has 10 structures, +also denoted by frames, attributed to it. The first frame of each crystal structure +is the geometry-optimized frame. The following 9 frames contain atoms that are +slightly displaced from the geometry-optimized frame. You can obtain the dataset +from our :download:`website <../../static/dataset.xyz>`. + +.. GENERATED FROM PYTHON SOURCE LINES 27-30 + +We will start by importing all the required packages: the classic numpy; +chemfiles to load data, and rascaline to compute representations. Afterward +we will load the dataset using chemfiles. + +.. GENERATED FROM PYTHON SOURCE LINES 31-43 + +.. code-block:: Python + + + import chemfiles + import numpy as np + + from rascaline import SphericalExpansion + + + with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [f for f in trajectory] + + print(f"The dataset contains {len(frames)} frames.") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + The dataset contains 40 frames. + + + + +.. GENERATED FROM PYTHON SOURCE LINES 44-50 + +We will not explain here how to use chemfiles in detail, as we only use a few +functions. Briefly, :class:`chemfiles.Trajectory` loads structure data in a +format rascaline can use. If you want to learn more about the possibilities +take a look at the `chemfiles documentation `_. + +Let us now take a look at the first frame of the dataset. + +.. GENERATED FROM PYTHON SOURCE LINES 51-56 + +.. code-block:: Python + + + frame0 = frames[0] + + print(frame0) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Frame with 20 atoms + + + + +.. GENERATED FROM PYTHON SOURCE LINES 57-59 + +With ``frame0.atoms`` we get a list of the atoms that make up frame zero. +The ``name`` attribute gives us the name of the specified atom. + +.. GENERATED FROM PYTHON SOURCE LINES 60-71 + +.. code-block:: Python + + + elements, counts = np.unique([atom.name for atom in frame0.atoms], return_counts=True) + + print( + f"The first frame contains " + f"{counts[0]} {elements[0]}-atoms, " + f"{counts[1]} {elements[1]}-atoms, " + f"{counts[2]} {elements[2]}-atoms and " + f"{counts[3]} {elements[3]}-atoms." + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + The first frame contains 4 C-atoms, 8 H-atoms, 4 N-atoms and 4 O-atoms. + + + + +.. GENERATED FROM PYTHON SOURCE LINES 72-88 + +Calculate a descriptor +---------------------- + +We will now calculate an atomic descriptor for this structure using the SOAP +spherical expansion as introduced by `Bartók, Kondor, and Csányi +`_. + +To do so we define below a set of parameters telling rascaline how the +spherical expansion should be calculated. These parameters are also called +hyper parameters since they are parameters of the representation, in +opposition to parameters of machine learning models. Hyper parameters are a +crucial part of calculating descriptors. Poorly selected hyper parameters will +lead to a poor description of your dataset as discussed in the `literature +`_. The effect of changing some hyper +parameters is discussed in a :ref:`second tutorial +`. + +.. GENERATED FROM PYTHON SOURCE LINES 89-101 + +.. code-block:: Python + + + HYPER_PARAMETERS = { + "cutoff": 4.5, + "max_radial": 9, + "max_angular": 6, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {"spline_accuracy": 1e-6}}, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + "radial_scaling": {"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, + } + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 102-106 + +After we set the hyper parameters we initialize a +:class:`rascaline.calculators.SphericalExpansion` object with hyper parameters +defined above and run the +:py:func:`rascaline.calculators.CalculatorBase.compute()` method. + +.. GENERATED FROM PYTHON SOURCE LINES 107-112 + +.. code-block:: Python + + + calculator = SphericalExpansion(**HYPER_PARAMETERS) + descriptor0 = calculator.compute(frame0) + print(type(descriptor0)) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 113-120 + +The descriptor format is a :class:`metatensor.TensorMap` object. Metatensor is +like numpy for storing representations of atomistic ML data. Extensive details +on the metatensor are covered in the `corresponding documentation +`_. + +We will now have a look at how the data is stored inside +:class:`metatensor.TensorMap` objects. + +.. GENERATED FROM PYTHON SOURCE LINES 121-125 + +.. code-block:: Python + + + + print(descriptor0) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + TensorMap with 112 blocks + keys: o3_lambda o3_sigma center_type neighbor_type + 0 1 1 1 + 1 1 1 1 + 2 1 1 1 + 3 1 1 1 + 4 1 1 1 + 5 1 1 1 + 6 1 1 1 + 0 1 1 6 + 1 1 1 6 + 2 1 1 6 + 3 1 1 6 + 4 1 1 6 + 5 1 1 6 + 6 1 1 6 + 0 1 1 7 + 1 1 1 7 + 2 1 1 7 + 3 1 1 7 + 4 1 1 7 + 5 1 1 7 + 6 1 1 7 + 0 1 1 8 + 1 1 1 8 + 2 1 1 8 + 3 1 1 8 + 4 1 1 8 + 5 1 1 8 + 6 1 1 8 + 0 1 6 1 + 1 1 6 1 + 2 1 6 1 + 3 1 6 1 + 4 1 6 1 + 5 1 6 1 + 6 1 6 1 + 0 1 6 6 + 1 1 6 6 + 2 1 6 6 + 3 1 6 6 + 4 1 6 6 + 5 1 6 6 + 6 1 6 6 + 0 1 6 7 + 1 1 6 7 + 2 1 6 7 + 3 1 6 7 + 4 1 6 7 + 5 1 6 7 + 6 1 6 7 + 0 1 6 8 + 1 1 6 8 + 2 1 6 8 + 3 1 6 8 + 4 1 6 8 + 5 1 6 8 + 6 1 6 8 + 0 1 7 1 + 1 1 7 1 + 2 1 7 1 + 3 1 7 1 + 4 1 7 1 + 5 1 7 1 + 6 1 7 1 + 0 1 7 6 + 1 1 7 6 + 2 1 7 6 + 3 1 7 6 + 4 1 7 6 + 5 1 7 6 + 6 1 7 6 + 0 1 7 7 + 1 1 7 7 + 2 1 7 7 + 3 1 7 7 + 4 1 7 7 + 5 1 7 7 + 6 1 7 7 + 0 1 7 8 + 1 1 7 8 + 2 1 7 8 + 3 1 7 8 + 4 1 7 8 + 5 1 7 8 + 6 1 7 8 + 0 1 8 1 + 1 1 8 1 + 2 1 8 1 + 3 1 8 1 + 4 1 8 1 + 5 1 8 1 + 6 1 8 1 + 0 1 8 6 + 1 1 8 6 + 2 1 8 6 + 3 1 8 6 + 4 1 8 6 + 5 1 8 6 + 6 1 8 6 + 0 1 8 7 + 1 1 8 7 + 2 1 8 7 + 3 1 8 7 + 4 1 8 7 + 5 1 8 7 + 6 1 8 7 + 0 1 8 8 + 1 1 8 8 + 2 1 8 8 + 3 1 8 8 + 4 1 8 8 + 5 1 8 8 + 6 1 8 8 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 126-137 + +The :class:`metatensor.TensorMap` is structured in several instances of an +:class:`metatensor.TensorBlock`. To distinguish the block each block is associated +with a unique key. For the current example, we have one block for each angular channel +labeled by ``o3_lambda``, the central atom type ``center_type`` and +neighbor atom type labeled by ``neighbor_type``. Different atomic types are +represented using their atomic number, e.g. 1 for hydrogen, 6 for carbon, etc. To +summarize, this descriptor contains 112 blocks covering all combinations of the +angular channels of the central and neighbor atom types in our dataset. + +Let us take a look at the second block (at index 1) in detail. This block contains the +descriptor for the :math:`l=1` angular channel for hydrogen-hydrogen pairs. + +.. GENERATED FROM PYTHON SOURCE LINES 138-143 + +.. code-block:: Python + + + block = descriptor0.block(1) + print(descriptor0.keys[1]) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + LabelsEntry(o3_lambda=1, o3_sigma=1, center_type=1, neighbor_type=1) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 144-151 + +The descriptor values +--------------------- + +The values of the representation are stored as an array. Each entry in this +array also has associated unique metadata as each block. For the spherical +expansion calculator used in this tutorial the values have three dimensions +which we can verify from the ``.shape`` attribute. + +.. GENERATED FROM PYTHON SOURCE LINES 152-156 + +.. code-block:: Python + + + + print(block.values.shape) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + (8, 3, 9) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 157-166 + +The descriptor values +--------------------- + +The first dimension is denoted by the `samples`, the intermediate dimension by +`components`, and the last dimension by `properties`. The "sample dimension" +has a length of eight because we have eight hydrogen atoms in the first frame. +We can reveal more detailed metadata information about the sample-dimension +printing of the :py:attr:`metatensor.TensorBlock.samples` attribute of the +block + +.. GENERATED FROM PYTHON SOURCE LINES 167-170 + +.. code-block:: Python + + + print(block.samples) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Labels( + system atom + 0 12 + 0 13 + ... + 0 18 + 0 19 + ) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 171-173 + +The result is an :class:`metatensor.TensorMap` instance. It contains in total +eight tuples each with two values. The tuple values are named as follows + +.. GENERATED FROM PYTHON SOURCE LINES 174-177 + +.. code-block:: Python + + + print(block.samples.names) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ['system', 'atom'] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 178-184 + +Meaning that the first entry of each tuple indicates the _structure_, which is +0 for all because we only computed the representation of a single frame. The +second entry of each tuple refers to the index of the _center_ atom. + +We can do a similar investigation for the second dimension: the +:py:attr:`metatensor.TensorBlock.components`. + +.. GENERATED FROM PYTHON SOURCE LINES 185-188 + +.. code-block:: Python + + + print(block.components) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + [Labels( + o3_mu + -1 + 0 + 1 + )] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 189-200 + +Here, the components are associated with the angular channels of the +representation. The size of ``o3_mu`` is :math:`2l + 1`, where +:math:`l` is the current ``o3_lambda`` of the block. Here, its +dimension is three because we are looking at the ``o3_lambda=1`` +block. You may have noticed that the return value of the last call is a +:class:`list` of :class:`metatensor.Labels` and not a single ``Labels`` +instance. The reason is that a block can have several component dimensions as +we will see below for the gradients. + +The last value represents the number of radial channels. For the +:py:attr:`metatensor.TensorBlock.properties` dimension we find an object + +.. GENERATED FROM PYTHON SOURCE LINES 201-204 + +.. code-block:: Python + + + print(block.properties) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Labels( + n + 0 + 1 + ... + 7 + 8 + ) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 205-206 + +containing a tuple of only one value ranging from 0 to 8. The name of this entry is + +.. GENERATED FROM PYTHON SOURCE LINES 207-210 + +.. code-block:: Python + + + print(block.properties.names) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ['n'] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 211-216 + +and denoting the radial channels. The range results from our choice of +``max_radial = 9`` in the hyper parameters above. + +After looking at the metadata we can investigate the actual data of the +representation in more details + +.. GENERATED FROM PYTHON SOURCE LINES 217-220 + +.. code-block:: Python + + + print(block.values[0, 0, :]) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + [-0.00102818 0.00860425 -0.02339817 -0.11691264 -0.04411467 -0.02857226 + -0.02109534 -0.00712789 -0.00230597] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 221-228 + +By using ``[0, 0, :]`` we selected the first hydrogen and the first ``m`` +channel. As you the output shows the values are floating point numbers between +``-1.0`` and ``1.0``. Values in this range are reasonable and can be directly +used as input for a machine learning algorithm. + +Rascaline is also able to process more than one structure within one function +call. You can process a whole dataset with + +.. GENERATED FROM PYTHON SOURCE LINES 229-235 + +.. code-block:: Python + + + descriptor_full = calculator.compute(frames) + + block_full = descriptor_full.block(0) + print(block_full.values.shape) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + (420, 1, 9) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 236-253 + +Now, the 0th block of the :class:`metatensor.TensorMap` contains not eight but +420 entries in the first dimensions. This reflects the fact that in total we +have 420 hydrogen atoms in the whole dataset. + +If you want to use another calculator instead of +:class:`rascaline.calculators.SphericalExpansion` shown here check out the +:ref:`userdoc-references` section. + +Computing gradients +------------------- + +Additionally, rascaline is also able to calculate gradients on top of the +values. Gradients are useful for constructing an ML potential and running +simulations. For example ``gradients`` of the representation with respect to +atomic positions can be calculated by setting the ``gradients`` parameter of +the :py:func:`rascaline.calculators.CalculatorBase.compute()` method to +``["positions"]``. + +.. GENERATED FROM PYTHON SOURCE LINES 254-262 + +.. code-block:: Python + + + descriptor_gradients = calculator.compute(frame0, gradients=["positions"]) + + block_gradients = descriptor_gradients.block(0) + gradient_position = block_gradients.gradient("positions") + + print(gradient_position.values.shape) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + (52, 3, 1, 9) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 263-279 + +The calculated descriptor contains the values and in each block the associated +position gradients as an :class:`metatensor.block.Gradient` instance. The +actual values are stored in the ``data`` attribute. Similar to the features +the gradient data also has associated metadata. But, compared to the values +were we found three dimensions, and gradients have four. Again the first is +called `samples` and the `properties`. The dimensions between the sample and +property dimensions are denoted by `components`. + +Looking at the shape in more detail we find that we have 52 samples, which is +much more compared to features where we only have eight samples. This arises +from the fact that we calculate the position gradient for each pair in the +structure. For our selected block these are all hydrogen-hydrogen pairs. +Naively one would come up with ``8 * 8 = 64`` samples, but rascaline already +ignores pairs that are outside of the cutoff radius. Their position gradient +is always zero. The :attr:`metatensor.block.Gradient.samples` attribute shows +this in detail. + +.. GENERATED FROM PYTHON SOURCE LINES 280-283 + +.. code-block:: Python + + + print(gradient_position.samples) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Labels( + sample system atom + 0 0 12 + 0 0 13 + ... + 7 0 18 + 7 0 19 + ) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 284-285 + +Note that we have a tuple of three with the names + +.. GENERATED FROM PYTHON SOURCE LINES 286-289 + +.. code-block:: Python + + + print(gradient_position.samples.names) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ['sample', 'system', 'atom'] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 290-294 + +In the above output of the Labels instance for example the `(2, 0, 17)` entry +is missing indicating that this pair is outside of the cutoff. + +Now looking at the :attr:`metatensor.block.Gradient.components` + +.. GENERATED FROM PYTHON SOURCE LINES 295-298 + +.. code-block:: Python + + + print(gradient_position.components) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + [Labels( + xyz + 0 + 1 + 2 + ), Labels( + o3_mu + 0 + )] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 299-305 + +we find two of them. Besides the `o3_mu` component that is also present in the +features position gradients also have a component indicating the direction of the +gradient vector. + +Finally, the :attr:`metatensor.block.Gradient.properties` dimension is the same as for +the values + +.. GENERATED FROM PYTHON SOURCE LINES 306-309 + +.. code-block:: Python + + + print(gradient_position.properties) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Labels( + n + 0 + 1 + ... + 7 + 8 + ) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 310-318 + +Rascaline can also calculate gradients with respect to the strain (i.e. the virial). +For this, you have to add ``"strain"`` to the list parsed to the ``gradients`` +parameter of the :py:func:`rascaline.calculators.CalculatorBase.compute()` method. +Strain gradients/virial are useful when computing the stress and the pressure. + +If you want to know about the effect of changing hypers take a look at the next +tutorial. If you want to solve an explicit problem our :ref:`userdoc-how-to` might +help you. + + +.. _sphx_glr_download_examples_first-calculation.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: first-calculation.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: first-calculation.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: first-calculation.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/index.rst.txt b/latest/_sources/examples/index.rst.txt new file mode 100644 index 000000000..74bf640c0 --- /dev/null +++ b/latest/_sources/examples/index.rst.txt @@ -0,0 +1,226 @@ +:orphan: + +Rascaline Python Examples +========================= + +This folder consists of introductory examples and examples demonstrating +specific features of rascaline using its Python API. + + + +.. raw:: html + +
+ +.. thumbnail-parent-div-open + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_compute-soap_thumb.png + :alt: + + :ref:`sphx_glr_examples_compute-soap.py` + +.. raw:: html + +
Computing SOAP features
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_profiling_thumb.png + :alt: + + :ref:`sphx_glr_examples_profiling.py` + +.. raw:: html + +
Profiling calculation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_first-calculation_thumb.png + :alt: + + :ref:`sphx_glr_examples_first-calculation.py` + +.. raw:: html + +
First descriptor computation
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_keys-selection_thumb.png + :alt: + + :ref:`sphx_glr_examples_keys-selection.py` + +.. raw:: html + +
Keys Selection
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_sample-selection_thumb.png + :alt: + + :ref:`sphx_glr_examples_sample-selection.py` + +.. raw:: html + +
Sample Selection
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_property-selection_thumb.png + :alt: + + :ref:`sphx_glr_examples_property-selection.py` + +.. raw:: html + +
Property Selection
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_splined-radial-integral_thumb.png + :alt: + + :ref:`sphx_glr_examples_splined-radial-integral.py` + +.. raw:: html + +
Splined radial integrals
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_le-basis_thumb.png + :alt: + + :ref:`sphx_glr_examples_le-basis.py` + +.. raw:: html + +
LE basis
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_long-range-descriptor_thumb.png + :alt: + + :ref:`sphx_glr_examples_long-range-descriptor.py` + +.. raw:: html + +
Long-range only LODE descriptor
+
+ + +.. raw:: html + +
+ +.. only:: html + + .. image:: /examples/images/thumb/sphx_glr_understanding-hypers_thumb.png + :alt: + + :ref:`sphx_glr_examples_understanding-hypers.py` + +.. raw:: html + +
Changing SOAP hyper parameters
+
+ + +.. thumbnail-parent-div-close + +.. raw:: html + +
+ + +.. toctree:: + :hidden: + + /examples/compute-soap + /examples/profiling + /examples/first-calculation + /examples/keys-selection + /examples/sample-selection + /examples/property-selection + /examples/splined-radial-integral + /examples/le-basis + /examples/long-range-descriptor + /examples/understanding-hypers + + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-gallery + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download all examples in Python source code: examples_python.zip ` + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download all examples in Jupyter notebooks: examples_jupyter.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/keys-selection.rst.txt b/latest/_sources/examples/keys-selection.rst.txt new file mode 100644 index 000000000..682c8a575 --- /dev/null +++ b/latest/_sources/examples/keys-selection.rst.txt @@ -0,0 +1,350 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/keys-selection.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_keys-selection.py: + + +Keys Selection +============== + +.. start-body + +.. GENERATED FROM PYTHON SOURCE LINES 7-15 + +.. code-block:: Python + + + import chemfiles + import numpy as np + from metatensor import Labels, TensorBlock, TensorMap + + from rascaline import SoapPowerSpectrum + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 16-17 + +First we load the dataset with chemfiles + +.. GENERATED FROM PYTHON SOURCE LINES 18-22 + +.. code-block:: Python + + + with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [f for f in trajectory] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-24 + +and define the hyper parameters of the representation + +.. GENERATED FROM PYTHON SOURCE LINES 25-42 + +.. code-block:: Python + + + HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, + } + + calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-45 + +The selections for keys should be a set of ``Labels``, with the names of the +keys being a subset of the names of the keys produced by the calculator. + +.. GENERATED FROM PYTHON SOURCE LINES 46-50 + +.. code-block:: Python + + + descriptor = calculator.compute(frames) + print("keys names:", descriptor.keys.names) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + keys names: ['center_type', 'neighbor_1_type', 'neighbor_2_type'] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 51-54 + +We can use these names to define a selection, and only blocks matching the +labels in this selection will be used by rascaline. Here, only blocks with +keys ``[1,1,1]`` and ``[4,4,4]`` will be calculated. + +.. GENERATED FROM PYTHON SOURCE LINES 55-62 + +.. code-block:: Python + + + selection = Labels( + names=["center_type", "neighbor_1_type", "neighbor_2_type"], + values=np.array([[1, 1, 1], [4, 4, 4]], dtype=np.int32), + ) + selected_descriptor = calculator.compute(frames, selected_keys=selection) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 63-64 + +We get a TensorMap with 2 blocks, corresponding to the requested keys + +.. GENERATED FROM PYTHON SOURCE LINES 65-68 + +.. code-block:: Python + + + print(selected_descriptor.keys) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Labels( + center_type neighbor_1_type neighbor_2_type + 1 1 1 + 4 4 4 + ) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 69-71 + +The block for ``[1, 1, 1]`` will be exactly the same as the one in the full +``TensorMap`` + +.. GENERATED FROM PYTHON SOURCE LINES 72-75 + +.. code-block:: Python + + answer = np.array_equal(descriptor.block(0).values, selected_descriptor.block(0).values) + print(f"Are the blocks 0 in the descriptor and selected_descriptor equal? {answer}") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Are the blocks 0 in the descriptor and selected_descriptor equal? True + + + + +.. GENERATED FROM PYTHON SOURCE LINES 76-78 + +Since there is no block for ``[4, 4, 4]`` in the full ``TensorMap``, an empty +block with no samples and the default set of properties is generated + +.. GENERATED FROM PYTHON SOURCE LINES 79-82 + +.. code-block:: Python + + + print(selected_descriptor.block(1).values.shape) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + (0, 180) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 83-86 + +``selected_keys`` can be used simultaneously with samples and properties +selection. Here we define a selection for properties as a ``TensorMap`` to +select different properties for each block: + +.. GENERATED FROM PYTHON SOURCE LINES 87-110 + +.. code-block:: Python + + + selection = [ + Labels(names=["l", "n_1", "n_2"], values=np.array([[0, 0, 0]])), + Labels(names=["l", "n_1", "n_2"], values=np.array([[1, 1, 1]])), + ] + blocks = [] + for entries in selection: + blocks.append( + TensorBlock( + values=np.empty((len(entries), 1)), + samples=Labels.single(), + components=[], + properties=entries, + ) + ) + + keys = Labels( + names=["center_type", "neighbor_1_type", "neighbor_2_type"], + values=np.array([[1, 1, 1], [8, 8, 8]], dtype=np.int32), + ) + + selected_properties = TensorMap(keys, blocks) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 111-113 + +Only one of the key from our ``selected_properties`` will be used in the +``selected_keys``, meaning the output will only contain this one key/block. + +.. GENERATED FROM PYTHON SOURCE LINES 114-126 + +.. code-block:: Python + + + selected_keys = Labels( + names=["center_type", "neighbor_1_type", "neighbor_2_type"], + values=np.array([[1, 1, 1]], dtype=np.int32), + ) + + descriptor = calculator.compute( + frames, + selected_properties=selected_properties, + selected_keys=selected_keys, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 127-129 + +As expected, we get 1 block with values of the form (420, 1), i.e. with only 1 +property. + +.. GENERATED FROM PYTHON SOURCE LINES 130-134 + +.. code-block:: Python + + + print(f"list of keys: {descriptor.keys}") + print(descriptor.block(0).values.shape) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + list of keys: Labels( + center_type neighbor_1_type neighbor_2_type + 1 1 1 + ) + (420, 1) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 135-136 + +.. end-body + + +.. _sphx_glr_download_examples_keys-selection.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: keys-selection.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: keys-selection.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: keys-selection.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/le-basis.rst.txt b/latest/_sources/examples/le-basis.rst.txt new file mode 100644 index 000000000..e889bd210 --- /dev/null +++ b/latest/_sources/examples/le-basis.rst.txt @@ -0,0 +1,533 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/le-basis.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_le-basis.py: + + +.. _userdoc-tutorials-le-basis: + +LE basis +======== + +.. start-body + +This example illustrates how to generate a spherical expansion using the Laplacian +eigenstate (LE) basis (https://doi.org/10.1063/5.0124363), using two different basis +truncations approaches. The basis can be truncated in the "traditional" way, using all +values below a limit in the angular and radial direction; or using a "ragged +truncation", where basis functions are selected according to an eigenvalue threshold. + +The main ideas behind the LE basis are: + +1. use a basis of controllable *smoothness* (intended in the same sense as the + smoothness of a low-pass-truncated Fourier expansion) +2. apply a "ragged truncation" strategy in which different angular channels are + truncated at a different number of radial channels, so as to obtain more balanced + smoothness level in the radial and angular direction, for a given number of basis + functions. + +Here we use :class:`rascaline.utils.SphericalBesselBasis` to create a spline of the +radial integral corresponding to the LE basis. An detailed how-to guide how to construct +radial integrals is given in :ref:`userdoc-how-to-splined-radial-integral`. + +.. GENERATED FROM PYTHON SOURCE LINES 28-37 + +.. code-block:: Python + + + import ase.io + import matplotlib.pyplot as plt + import numpy as np + from metatensor import Labels, TensorBlock, TensorMap + + import rascaline + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 38-42 + +Let's start by using a traditional/square basis truncation. Here we will select all +basis functions with ``l <= max_angular`` and ``n < max_radial``. The basis functions +are the solution of a radial Laplacian eigenvalue problem (spherical Bessel +functions). + +.. GENERATED FROM PYTHON SOURCE LINES 43-61 + +.. code-block:: Python + + + cutoff = 4.4 + max_angular = 6 + max_radial = 8 + + # create a spliner for the SOAP radial integral, using delta functions for the atomic + # density and spherical Bessel functions for the basis + spliner = rascaline.utils.SoapSpliner( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + basis=rascaline.utils.SphericalBesselBasis( + cutoff=cutoff, max_radial=max_radial, max_angular=max_angular + ), + density=rascaline.utils.DeltaDensity(), + accuracy=1e-8, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 62-64 + +We can now plot the radial integral splines for a couple of functions. This gives an +idea of the smoothness of the different components + +.. GENERATED FROM PYTHON SOURCE LINES 65-84 + +.. code-block:: Python + + + splined_basis = spliner.compute() + grid = [p["position"] for p in splined_basis["TabulatedRadialIntegral"]["points"]] + values = np.array( + [ + np.array(p["values"]["data"]).reshape(p["values"]["dim"]) + for p in splined_basis["TabulatedRadialIntegral"]["points"] + ] + ) + + plt.plot(grid, values[:, 1, 1], "b-", label="l=1, n=1") + plt.plot(grid, values[:, 4, 1], "r-", label="l=4, n=1") + plt.plot(grid, values[:, 1, 4], "g-", label="l=1, n=4") + plt.plot(grid, values[:, 4, 4], "y-", label="l=4, n=4") + plt.xlabel("$r$") + plt.ylabel(r"$R_{nl}$") + plt.legend() + plt.show() + + + + +.. image-sg:: /examples/images/sphx_glr_le-basis_001.png + :alt: le basis + :srcset: /examples/images/sphx_glr_le-basis_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 85-87 + +We can use this spline basis in a :py:class:`SphericalExpansion` calculator to +evaluate spherical expansion coefficients. + +.. GENERATED FROM PYTHON SOURCE LINES 88-99 + +.. code-block:: Python + + + calculator = rascaline.SphericalExpansion( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + center_atom_weight=1.0, + radial_basis=splined_basis, + atomic_gaussian_width=-1.0, # will not be used due to the delta density above + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 100-102 + +This calculator defaults to the "traditional" basis function selection, so we have the +same maximal ``n`` value for all ``l``. + +.. GENERATED FROM PYTHON SOURCE LINES 103-114 + +.. code-block:: Python + + + systems = ase.io.read("dataset.xyz", ":10") + + descriptor = calculator.compute(systems) + descriptor = descriptor.keys_to_properties("neighbor_type") + descriptor = descriptor.keys_to_samples("center_type") + + for key, block in descriptor.items(): + n_max = np.max(block.properties["n"]) + 1 + print(f"l = {key['o3_lambda']}, n_max = {n_max}") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + l = 0, n_max = 8 + l = 1, n_max = 8 + l = 2, n_max = 8 + l = 3, n_max = 8 + l = 4, n_max = 8 + l = 5, n_max = 8 + l = 6, n_max = 8 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 115-122 + +**Selecting basis with an eigenvalue threshold** + +Now we will calculate the same basis with an eigenvalue threshold. The idea is to +treat on the same footings the radial and angular dimension, and select all functions +with a mean Laplacian below a certain threshold. This is similar to the common +practice in plane-wave electronic-structure methods to use a kinetic energy cutoff +where :math:`k_x^2 + k_y^2 + k_z^2 < k_\text{max}^2` + +.. GENERATED FROM PYTHON SOURCE LINES 123-126 + +.. code-block:: Python + + + eigenvalue_threshold = 20 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 127-129 + +Let's start by computing a lot of Laplacian eigenvalues, which are related to the +squares of the zeros of spherical Bessel functions. + +.. GENERATED FROM PYTHON SOURCE LINES 130-137 + +.. code-block:: Python + + + l_max_large = 49 # just used to get the eigenvalues + n_max_large = 50 # just used to get the eigenvalues + + # compute the zeros of the spherical Bessel functions + zeros_ln = rascaline.utils.SphericalBesselBasis.compute_zeros(l_max_large, n_max_large) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 138-140 + +We have a 50x50 array containing the position of the zero of the different spherical +Bessel functions, indexed by ``l`` and ``n``. + +.. GENERATED FROM PYTHON SOURCE LINES 141-148 + +.. code-block:: Python + + + print("zeros_ln.shape =", zeros_ln.shape) + print("zeros_ln =", zeros_ln[:3, :3]) + + # calculate the Laplacian eigenvalues + eigenvalues_ln = zeros_ln**2 / cutoff**2 + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + zeros_ln.shape = (50, 50) + zeros_ln = [[ 3.14159265 6.28318531 9.42477796] + [ 4.49340946 7.72525184 10.90412166] + [ 5.7634592 9.09501133 12.32294097]] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 149-151 + +We can now determine the set of ``l, n`` pairs to include all eigenvalues below the +threshold. + +.. GENERATED FROM PYTHON SOURCE LINES 152-164 + +.. code-block:: Python + + + max_radial_by_angular = [] + for ell in range(l_max_large + 1): + # for each l, calculate how many radial basis functions we want to include + max_radial = len(np.where(eigenvalues_ln[ell] < eigenvalue_threshold)[0]) + max_radial_by_angular.append(max_radial) + if max_radial_by_angular[-1] == 0: + # all eigenvalues for this `l` are over the threshold + max_radial_by_angular.pop() + max_angular = ell - 1 + break + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 165-168 + +Comparing this eigenvalues threshold with the one based on a square selection, we see +that the eigenvalues threshold leads to a gradual decrease of ``max_radial`` for high +``l`` values + +.. GENERATED FROM PYTHON SOURCE LINES 169-191 + +.. code-block:: Python + + + square_max_angular = 10 + square_max_radial = 4 + plt.fill_between( + [0, square_max_angular], + [square_max_radial, square_max_radial], + label=r"$l_\mathrm{max}$, $n_\mathrm{max}$ threshold " + + f"({(square_max_angular + 1) * square_max_radial} functions)", + color="gray", + ) + plt.fill_between( + np.arange(max_angular + 1), + max_radial_by_angular, + label=f"Eigenvalues threshold ({sum(max_radial_by_angular)} functions)", + alpha=0.5, + ) + plt.xlabel(r"$\ell$") + plt.ylabel("n radial basis functions") + plt.ylim(-0.5, max_radial_by_angular[0] + 0.5) + plt.legend() + plt.show() + + + + +.. image-sg:: /examples/images/sphx_glr_le-basis_002.png + :alt: le basis + :srcset: /examples/images/sphx_glr_le-basis_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 192-197 + +**Using a subset of basis functions with rascaline** + +We can tweak the default basis selection of rascaline by specifying a larger total +basis; and then only asking for a subset of properties to be computed. See +:ref:`userdoc-how-to-property-selection` for more details on properties selection. + +.. GENERATED FROM PYTHON SOURCE LINES 198-229 + +.. code-block:: Python + + + # extract all the atomic types from our dataset + all_atomic_types = list( + np.unique(np.concatenate([system.numbers for system in systems])) + ) + + keys = [] + blocks = [] + for center_type in all_atomic_types: + for neighbor_type in all_atomic_types: + for ell in range(max_angular + 1): + max_radial = max_radial_by_angular[ell] + + keys.append([ell, 1, center_type, neighbor_type]) + blocks.append( + TensorBlock( + values=np.zeros((0, max_radial)), + samples=Labels.empty("_"), + components=[], + properties=Labels("n", np.arange(max_radial).reshape(-1, 1)), + ) + ) + + selected_properties = TensorMap( + keys=Labels( + names=["o3_lambda", "o3_sigma", "center_type", "neighbor_type"], + values=np.array(keys), + ), + blocks=blocks, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 230-232 + +With this, we can build a calculator and calculate the spherical expansion +coefficients + +.. GENERATED FROM PYTHON SOURCE LINES 233-261 + +.. code-block:: Python + + + # the biggest max_radial will be for l=0 + max_radial = max_radial_by_angular[0] + + + # set up a spliner object for the spherical Bessel functions this radial basis will be + # used to compute the spherical expansion + spliner = rascaline.utils.SoapSpliner( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + basis=rascaline.utils.SphericalBesselBasis( + cutoff=cutoff, max_radial=max_radial, max_angular=max_angular + ), + density=rascaline.utils.DeltaDensity(), + accuracy=1e-8, + ) + + calculator = rascaline.SphericalExpansion( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + center_atom_weight=1.0, + radial_basis=spliner.compute(), + atomic_gaussian_width=-1.0, # will not be used due to the delta density above + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 262-264 + +And check that we do get the expected Eigenvalues truncation for the calculated +features! + +.. GENERATED FROM PYTHON SOURCE LINES 265-280 + +.. code-block:: Python + + + descriptor = calculator.compute( + systems, + # we tell the calculator to only compute the selected properties + # (the desired set of (l,n) expansion coefficients + selected_properties=selected_properties, + ) + + descriptor = descriptor.keys_to_properties("neighbor_type") + descriptor = descriptor.keys_to_samples("center_type") + + for key, block in descriptor.items(): + n_max = np.max(block.properties["n"]) + 1 + print(f"l = {key['o3_lambda']}, n_max = {n_max}") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + l = 0, n_max = 6 + l = 1, n_max = 5 + l = 2, n_max = 5 + l = 3, n_max = 4 + l = 4, n_max = 4 + l = 5, n_max = 4 + l = 6, n_max = 3 + l = 7, n_max = 3 + l = 8, n_max = 2 + l = 9, n_max = 2 + l = 10, n_max = 2 + l = 11, n_max = 1 + l = 12, n_max = 1 + l = 13, n_max = 1 + l = 14, n_max = 1 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 281-282 + +.. end-body + + +.. _sphx_glr_download_examples_le-basis.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: le-basis.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: le-basis.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: le-basis.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/long-range-descriptor.rst.txt b/latest/_sources/examples/long-range-descriptor.rst.txt new file mode 100644 index 000000000..b416b0b9e --- /dev/null +++ b/latest/_sources/examples/long-range-descriptor.rst.txt @@ -0,0 +1,868 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/long-range-descriptor.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_long-range-descriptor.py: + + +.. _userdoc-tutorials-long-range-descriptor: + +Long-range only LODE descriptor +=============================== + +.. start-body + +We start the example by loading the required packages + +.. GENERATED FROM PYTHON SOURCE LINES 13-31 + +.. code-block:: Python + + + import ase + import ase.visualize.plot + import matplotlib.pyplot as plt + import numpy as np + from ase.build import molecule + from metatensor import LabelsEntry, TensorMap + + from rascaline import LodeSphericalExpansion, SphericalExpansion + from rascaline.utils import ( + GaussianDensity, + LodeDensity, + LodeSpliner, + MonomialBasis, + SoapSpliner, + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 32-36 + +**Single water molecule (short range) system** + +Our first test system is a single water molecule with a :math:`15\,\mathrm{Å}` vacuum +layer around it. + +.. GENERATED FROM PYTHON SOURCE LINES 37-41 + +.. code-block:: Python + + + + atoms = molecule("H2O", vacuum=15, pbc=True) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 42-44 + +We choose a ``cutoff`` for the projection of the spherical expansion and the neighbor +search of the real space spherical expansion. + +.. GENERATED FROM PYTHON SOURCE LINES 44-47 + +.. code-block:: Python + + + cutoff = 3 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 48-50 + +We can use ase's visualization tools to plot the system and draw a gray circle to +indicate the ``cutoff`` radius. + +.. GENERATED FROM PYTHON SOURCE LINES 50-70 + +.. code-block:: Python + + + fig, ax = plt.subplots() + + ase.visualize.plot.plot_atoms(atoms) + + cutoff_circle = plt.Circle( + xy=atoms[0].position[:2], + radius=cutoff, + color="gray", + ls="dashed", + fill=False, + ) + ax.add_patch(cutoff_circle) + + ax.set_xlabel("Å") + ax.set_ylabel("Å") + + fig.show() + + + + + +.. image-sg:: /examples/images/sphx_glr_long-range-descriptor_001.png + :alt: long range descriptor + :srcset: /examples/images/sphx_glr_long-range-descriptor_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 71-80 + +As you can see, for a single water molecule, the ``cutoff`` includes all atoms of the +system. The combination of the test system and the ``cutoff`` aims to demonstrate that +the full atomic fingerprint is contained within the ``cutoff``. By later subtracting +the short-range density from the LODE density, we will observe that the difference +between them is almost zero, indicating that a single water molecule is a short-range +system. + +To start this construction we choose a high potential exponent to emulate the rapidly +decaying LODE density and mimic the polar-polar interactions of water. + +.. GENERATED FROM PYTHON SOURCE LINES 81-86 + +.. code-block:: Python + + + + potential_exponent = 3 + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 87-88 + +We now define some typical hyperparameters to compute the spherical expansions. + +.. GENERATED FROM PYTHON SOURCE LINES 88-95 + +.. code-block:: Python + + + max_radial = 5 + max_angular = 1 + atomic_gaussian_width = 1.2 + center_atom_weight = 1.0 + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 96-99 + +We choose a relatively low spline accuracy (default is ``1e-8``) to achieve quick +computation of the spline points. You can increase the spline accuracy if required, +but be aware that the time to compute these points will increase significantly! + +.. GENERATED FROM PYTHON SOURCE LINES 99-104 + +.. code-block:: Python + + + + spline_accuracy = 1e-2 + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 105-110 + +As a projection basis, we don't use the usual :py:class:`GtoBasis +` which is commonly used for short range descriptors. +Instead, we select the :py:class:`MonomialBasis ` which +is the optimal radial basis for the LODE descriptor as discussed in `Huguenin-Dumittan +et al. `_ + +.. GENERATED FROM PYTHON SOURCE LINES 110-115 + +.. code-block:: Python + + + + basis = MonomialBasis(cutoff=cutoff) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 116-119 + +For the density, we choose a smeared power law as used in LODE, which does not decay +exponentially like a :py:class:`Gaussian density ` +and is therefore suited to describe long-range interactions between atoms. + +.. GENERATED FROM PYTHON SOURCE LINES 119-127 + +.. code-block:: Python + + + + density = LodeDensity( + atomic_gaussian_width=atomic_gaussian_width, + potential_exponent=potential_exponent, + ) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 128-130 + +To visualize this we plot ``density`` together with a Gaussian density +(``gaussian_density``) with the same ``atomic_gaussian_width`` in a log-log plot. + +.. GENERATED FROM PYTHON SOURCE LINES 130-161 + +.. code-block:: Python + + + radial_positions = np.geomspace(1e-5, 10, num=1000) + gaussian_density = GaussianDensity(atomic_gaussian_width=atomic_gaussian_width) + + plt.plot(radial_positions, density.compute(radial_positions), label="LodeDensity") + plt.plot( + radial_positions, + gaussian_density.compute(radial_positions), + label="GaussianDensity", + ) + + + positions_indicator = np.array([3.0, 8.0]) + plt.plot( + positions_indicator, + 2 * positions_indicator**-potential_exponent, + c="k", + label=f"p={potential_exponent}", + ) + + plt.legend() + + plt.xlim(1e-1, 10) + plt.ylim(1e-3, 5e-1) + + plt.xlabel("radial positions / Å") + plt.ylabel("atomic density") + + plt.xscale("log") + plt.yscale("log") + + + + +.. image-sg:: /examples/images/sphx_glr_long-range-descriptor_002.png + :alt: long range descriptor + :srcset: /examples/images/sphx_glr_long-range-descriptor_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 162-169 + +We see that the ``LodeDensity`` decays with a power law of 3, which is the potential +exponent we picked above, wile the :py:class:`Gaussian density +` decays exponentially and is therefore not suited +for long-range descriptors. + +We now have all building blocks to construct the spline points for the real and +Fourier space spherical expansions. + +.. GENERATED FROM PYTHON SOURCE LINES 169-194 + +.. code-block:: Python + + + + real_space_splines = SoapSpliner( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + basis=basis, + density=density, + accuracy=spline_accuracy, + ).compute() + + + # This value gives good convergences for the Fourier space version + k_cutoff = 1.2 * np.pi / atomic_gaussian_width + + fourier_space_splines = LodeSpliner( + k_cutoff=k_cutoff, + max_radial=max_radial, + max_angular=max_angular, + basis=basis, + density=density, + accuracy=spline_accuracy, + ).compute() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 195-202 + +.. note:: + You might want to save the spline points using :py:func:`json.dump` to a file and + load them with :py:func:`json.load` later without recalculating them. Saving them is + especially useful if the spline calculations are expensive, i.e., if you increase + the ``spline_accuracy``. + +With the spline points ready, we now compute the real space spherical expansion + +.. GENERATED FROM PYTHON SOURCE LINES 202-218 + +.. code-block:: Python + + + + real_space_calculator = SphericalExpansion( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + atomic_gaussian_width=atomic_gaussian_width, + radial_basis=real_space_splines, + center_atom_weight=center_atom_weight, + cutoff_function={"Step": {}}, + radial_scaling=None, + ) + + real_space_expansion = real_space_calculator.compute(atoms) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 219-222 + +where we don't use a smoothing ``cutoff_function`` or a ``radial_scaling`` to ensure +the correct construction of the long-range only descriptor. Next, we compute the +Fourier Space / LODE spherical expansion + +.. GENERATED FROM PYTHON SOURCE LINES 222-237 + +.. code-block:: Python + + + + fourier_space_calculator = LodeSphericalExpansion( + cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + atomic_gaussian_width=atomic_gaussian_width, + center_atom_weight=center_atom_weight, + potential_exponent=potential_exponent, + radial_basis=fourier_space_splines, + k_cutoff=k_cutoff, + ) + + fourier_space_expansion = fourier_space_calculator.compute(atoms) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 238-241 + +As described in the beginning, we now subtract the real space LODE contributions from +Fourier space to obtain a descriptor that only contains the contributions from atoms +outside of the ``cutoff``. + +.. GENERATED FROM PYTHON SOURCE LINES 241-246 + +.. code-block:: Python + + + + subtracted_expansion = fourier_space_expansion - real_space_expansion + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 247-254 + +combination with a short-range descriptor like +:py:class:`rascaline.SphericalExpansion` for your machine learning models. We now +verify that for our test ``atoms`` the LODE spherical expansion only contains +short-range contributions. To demonstrate this, we densify the +:py:class:`metatensor.TensorMap` to have only one block per ``"center_type"`` and +visualize our result. Since we have to perform the densify operation several times in +thi show-to, we define a helper function ``densify_tensormap``. + +.. GENERATED FROM PYTHON SOURCE LINES 254-264 + +.. code-block:: Python + + + + def densify_tensormap(tensor: TensorMap) -> TensorMap: + dense_tensor = tensor.components_to_properties("o3_mu") + dense_tensor = dense_tensor.keys_to_samples("neighbor_type") + dense_tensor = dense_tensor.keys_to_properties(["o3_lambda", "o3_sigma"]) + + return dense_tensor + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 265-267 + +We apply the function to the Fourier space spherical expansion +``fourier_space_expansion`` and ``subtracted_expansion``. + +.. GENERATED FROM PYTHON SOURCE LINES 267-273 + +.. code-block:: Python + + + + fourier_space_expansion = densify_tensormap(fourier_space_expansion) + subtracted_expansion = densify_tensormap(subtracted_expansion) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 274-278 + +Finally, we plot the values of each block for the Fourier Space spherical expansion in +the upper panel and the difference between the Fourier Space and the real space in the +lower panel. And since we will do this plot several times we again define a small plot +function to help us + +.. GENERATED FROM PYTHON SOURCE LINES 278-302 + +.. code-block:: Python + + + + def plot_value_comparison( + key: LabelsEntry, + fourier_space_expansion: TensorMap, + subtracted_expansion: TensorMap, + ): + fig, ax = plt.subplots(2, layout="tight") + + values_subtracted = subtracted_expansion[key].values + values_fourier_space = fourier_space_expansion[key].values + + ax[0].set_title(f"center_type={key.values[0]}\n Fourier space sph. expansion") + im = ax[0].matshow(values_fourier_space, vmin=-0.25, vmax=0.5) + ax[0].set_ylabel("sample index") + + ax[1].set_title("Difference between Fourier and real space sph. expansion") + ax[1].matshow(values_subtracted, vmin=-0.25, vmax=0.5) + ax[1].set_ylabel("sample index") + ax[1].set_xlabel("property index") + + fig.colorbar(im, ax=ax[0], orientation="horizontal", fraction=0.1, label="values") + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 303-304 + +We first plot the values of the TensorMaps for center_type=1 (hydrogen) + +.. GENERATED FROM PYTHON SOURCE LINES 304-309 + +.. code-block:: Python + + + plot_value_comparison( + fourier_space_expansion.keys[0], fourier_space_expansion, subtracted_expansion + ) + + + + +.. image-sg:: /examples/images/sphx_glr_long-range-descriptor_003.png + :alt: center_type=1 Fourier space sph. expansion, Difference between Fourier and real space sph. expansion + :srcset: /examples/images/sphx_glr_long-range-descriptor_003.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 310-311 + +and for center_type=8 (oxygen) + +.. GENERATED FROM PYTHON SOURCE LINES 311-317 + +.. code-block:: Python + + + plot_value_comparison( + fourier_space_expansion.keys[1], fourier_space_expansion, subtracted_expansion + ) + + + + + +.. image-sg:: /examples/images/sphx_glr_long-range-descriptor_004.png + :alt: center_type=8 Fourier space sph. expansion, Difference between Fourier and real space sph. expansion + :srcset: /examples/images/sphx_glr_long-range-descriptor_004.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 318-331 + +The plot shows that the spherical expansion for the Fourier space is non-zero while +the difference between the two expansions is very small. + +.. warning:: + Small residual values may stems from the contribution of the periodic images. You + can verify and reduce those contributions by either increasing the cell and/or + increase the ``potential_exponent``. + +**Two water molecule (long range) system** + +We now add a second water molecule shifted by :math:`3\,\mathrm{Å}` in each direction +from our first water molecule to show that such a system has non negliable long range +effects. + +.. GENERATED FROM PYTHON SOURCE LINES 331-368 + +.. code-block:: Python + + + + atoms_shifted = molecule("H2O", vacuum=10, pbc=True) + atoms_shifted.positions = atoms.positions + 3 + + atoms_long_range = atoms + atoms_shifted + + + fig, ax = plt.subplots() + + ase.visualize.plot.plot_atoms(atoms_long_range, ax=ax) + + cutoff_circle = plt.Circle( + xy=atoms[0].position[1:], + radius=cutoff, + color="gray", + ls="dashed", + fill=False, + ) + + cutoff_circle_shifted = plt.Circle( + xy=atoms_shifted[0].position[1:], + radius=cutoff, + color="gray", + ls="dashed", + fill=False, + ) + + ax.add_patch(cutoff_circle) + ax.add_patch(cutoff_circle_shifted) + + ax.set_xlabel("Å") + ax.set_ylabel("Å") + + fig.show() + + + + + +.. image-sg:: /examples/images/sphx_glr_long-range-descriptor_005.png + :alt: long range descriptor + :srcset: /examples/images/sphx_glr_long-range-descriptor_005.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 369-374 + +As you can see, the ``cutoff`` radii of the two molecules are completely disjoint. +Therefore, a short-range model will not able to describe the intermolecular +interactions between our two molecules. To verify we now again create a long-range +only descriptor for this system. We use the already defined +``real_space_expansion_long_range`` and ``fourier_space_expansion_long_range`` + +.. GENERATED FROM PYTHON SOURCE LINES 374-379 + +.. code-block:: Python + + + + real_space_expansion_long_range = real_space_calculator.compute(atoms_long_range) + fourier_space_expansion_long_range = fourier_space_calculator.compute(atoms_long_range) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 380-383 + +We now firdt verify that the contribution from the short-range descriptors is the same +as for a single water molecule. Exemplarily, we compare only the first (Hydrogen) +block of each tensor. + +.. GENERATED FROM PYTHON SOURCE LINES 383-391 + +.. code-block:: Python + + + + print("Single water real space spherical expansion") + print(np.round(real_space_expansion[1].values, 3)) + + print("\nTwo water real space spherical expansion") + print(np.round(real_space_expansion_long_range[1].values, 3)) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Single water real space spherical expansion + [[[-0.267 -0.101 -0.06 -0.044 -0.035] + [ 0. 0. 0. 0. 0. ] + [ 0. 0. 0. 0. 0. ]] + + [[ 0.267 0.101 0.06 0.044 0.035] + [ 0. 0. 0. 0. 0. ] + [ 0. 0. 0. 0. 0. ]]] + + Two water real space spherical expansion + [[[-0.267 -0.101 -0.06 -0.044 -0.035] + [ 0. 0. 0. 0. 0. ] + [ 0. 0. 0. 0. 0. ]] + + [[ 0.267 0.101 0.06 0.044 0.035] + [ 0. 0. 0. 0. 0. ] + [ 0. 0. 0. 0. 0. ]] + + [[-0.267 -0.101 -0.06 -0.044 -0.035] + [ 0. 0. 0. 0. 0. ] + [ 0. 0. 0. 0. 0. ]] + + [[ 0.267 0.101 0.06 0.044 0.035] + [ 0. 0. 0. 0. 0. ] + [ 0. 0. 0. 0. 0. ]]] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 392-400 + +Since the values of the block are the same, we can conclude that there is no +information shared between the two molecules and that the short-range descriptor is +not able to distinguish the system with only one or two water molecules. Note that the +different number of `samples` in ``real_space_expansion_long_range`` reflects the fact +that the second system has more atoms then the first. + +As above, we construct a long-range only descriptor and densify the result for +plotting the values. + +.. GENERATED FROM PYTHON SOURCE LINES 400-412 + +.. code-block:: Python + + + + subtracted_expansion_long_range = ( + fourier_space_expansion_long_range - real_space_expansion_long_range + ) + + fourier_space_expansion_long_range = densify_tensormap( + fourier_space_expansion_long_range + ) + subtracted_expansion_long_range = densify_tensormap(subtracted_expansion_long_range) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 413-416 + +As above, we plot the values of the spherical expansions for the Fourier and the +subtracted (long range only) spherical expansion. First for hydrogen +(``center_species=1``) + +.. GENERATED FROM PYTHON SOURCE LINES 416-423 + +.. code-block:: Python + + + plot_value_comparison( + fourier_space_expansion_long_range.keys[0], + fourier_space_expansion_long_range, + subtracted_expansion_long_range, + ) + + + + +.. image-sg:: /examples/images/sphx_glr_long-range-descriptor_006.png + :alt: center_type=1 Fourier space sph. expansion, Difference between Fourier and real space sph. expansion + :srcset: /examples/images/sphx_glr_long-range-descriptor_006.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 424-425 + +amd second for oxygen (``center_species=8``) + +.. GENERATED FROM PYTHON SOURCE LINES 425-433 + +.. code-block:: Python + + + plot_value_comparison( + fourier_space_expansion_long_range.keys[1], + fourier_space_expansion_long_range, + subtracted_expansion_long_range, + ) + + + + + +.. image-sg:: /examples/images/sphx_glr_long-range-descriptor_007.png + :alt: center_type=8 Fourier space sph. expansion, Difference between Fourier and real space sph. expansion + :srcset: /examples/images/sphx_glr_long-range-descriptor_007.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 434-439 + +We clearly see that the values of the subtracted spherical are much larger compared to +the system with only a single water molecule, thus confirming the presence of +long-range contributions in the descriptor for a system with two water molecules. + +.. end-body + + +.. _sphx_glr_download_examples_long-range-descriptor.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: long-range-descriptor.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: long-range-descriptor.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: long-range-descriptor.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/profiling.rst.txt b/latest/_sources/examples/profiling.rst.txt new file mode 100644 index 000000000..a3cf8374d --- /dev/null +++ b/latest/_sources/examples/profiling.rst.txt @@ -0,0 +1,186 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/profiling.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_profiling.py: + + +Profiling calculation +===================== + +.. start-body + +.. GENERATED FROM PYTHON SOURCE LINES 7-44 + +.. code-block:: Python + + + import chemfiles + + import rascaline + from rascaline import SoapPowerSpectrum + + + def compute_soap(path): + """Compute SOAP power spectrum. + + This is the same code as the 'compute-soap' example + """ + with chemfiles.Trajectory(path) as trajectory: + frames = [f for f in trajectory] + + HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, + } + + calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + descriptor = calculator.compute(frames, gradients=["positions"]) + descriptor = descriptor.keys_to_samples("center_type") + descriptor = descriptor.keys_to_properties(["neighbor_1_type", "neighbor_2_type"]) + + return descriptor + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 45-46 + +Run the calculation with profiling enabled. + +.. GENERATED FROM PYTHON SOURCE LINES 47-50 + +.. code-block:: Python + + + with rascaline.Profiler() as profiler: + descriptor = compute_soap("dataset.xyz") + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 51-52 + +Display the recorded profiling data as table. + +.. GENERATED FROM PYTHON SOURCE LINES 53-56 + +.. code-block:: Python + + + print(profiler.as_short_table()) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ╔════╦══════════════════════════════════════════════╦════════════╦═══════════╦══════════╦══════════════╗ + ║ id ║ span name ║ call count ║ called by ║ total ║ mean ║ + ╠════╬══════════════════════════════════════════════╬════════════╬═══════════╬══════════╬══════════════╣ + ║ 4 ║ SoapPowerSpectrum::compute ║ 1 ║ — ║ 420.88ms ║ 420.88ms ║ + ╠════╬══════════════════════════════════════════════╬════════════╬═══════════╬══════════╬══════════════╣ + ║ 5 ║ SphericalExpansion::compute ║ 1 ║ 4 ║ 201.62ms ║ 201.62ms ║ + ╠════╬══════════════════════════════════════════════╬════════════╬═══════════╬══════════╬══════════════╣ + ║ 1 ║ SoapRadialIntegralSpline::with_accuracy ║ 6 ║ 5 ║ 52.55ms ║ 8.76ms ║ + ╠════╬══════════════════════════════════════════════╬════════════╬═══════════╬══════════╬══════════════╣ + ║ 0 ║ GtoRadialIntegral::compute ║ 3846 ║ 1 ║ 49.69ms ║ 12.92µs ║ + ╠════╬══════════════════════════════════════════════╬════════════╬═══════════╬══════════╬══════════════╣ + ║ 3 ║ Calculator::prepare ║ 2 ║ 4 ║ 54.20ms ║ 27.10ms ║ + ╠════╬══════════════════════════════════════════════╬════════════╬═══════════╬══════════╬══════════════╣ + ║ 2 ║ NeighborsList ║ 40 ║ 3 ║ 11.89ms ║ 297.36µs ║ + ╠════╬══════════════════════════════════════════════╬════════════╬═══════════╬══════════╬══════════════╣ + ║ 6 ║ SplinedRadialIntegral::compute ║ 35307 ║ 5 ║ 17.80ms ║ 504.00ns ⚠️ ║ + ╠════╬══════════════════════════════════════════════╬════════════╬═══════════╬══════════╬══════════════╣ + ║ 7 ║ SphericalHarmonics::compute ║ 35307 ║ 5 ║ 21.10ms ║ 597.00ns ⚠️ ║ + ╚════╩══════════════════════════════════════════════╩════════════╩═══════════╩══════════╩══════════════╝ + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 57-58 + +You can also save this data as json for future usage + +.. GENERATED FROM PYTHON SOURCE LINES 59-61 + +.. code-block:: Python + + print(profiler.as_json()) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + {"timings":{"rascaline::calculators::soap::radial_integral::gto::GtoRadialIntegral::compute":{"id":0,"elapsed":"49.692532ms","called":3846},"rascaline::calculators::soap::radial_integral::spline::SoapRadialIntegralSpline::with_accuracy":{"id":1,"elapsed":"52.54813ms","called":6},"rascaline::systems::neighbors::NeighborsList":{"id":2,"elapsed":"11.894447ms","called":40},"rascaline::calculator::Calculator::prepare":{"id":3,"elapsed":"54.2017ms","called":2},"rascaline::calculators::soap::power_spectrum::SoapPowerSpectrum::compute":{"id":4,"elapsed":"420.880076ms","called":1},"rascaline::calculators::soap::spherical_expansion::SphericalExpansion::compute":{"id":5,"elapsed":"201.624284ms","called":1},"rascaline::calculators::soap::radial_integral::spline::SplinedRadialIntegral::compute":{"id":6,"elapsed":"17.798069ms","called":35307},"rascaline::math::spherical_harmonics::SphericalHarmonics::compute":{"id":7,"elapsed":"21.099012ms","called":35307}},"calls":[{"caller":0,"callee":1,"count":3846},{"caller":2,"callee":3,"count":40},{"caller":3,"callee":4,"count":1},{"caller":1,"callee":5,"count":1},{"caller":6,"callee":5,"count":1},{"caller":7,"callee":5,"count":1},{"caller":5,"callee":4,"count":1}]} + + + + +.. GENERATED FROM PYTHON SOURCE LINES 62-63 + +.. end-body + + +.. _sphx_glr_download_examples_profiling.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: profiling.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: profiling.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: profiling.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/property-selection.rst.txt b/latest/_sources/examples/property-selection.rst.txt new file mode 100644 index 000000000..8605b3086 --- /dev/null +++ b/latest/_sources/examples/property-selection.rst.txt @@ -0,0 +1,380 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/property-selection.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_property-selection.py: + + +Property Selection +================== + +.. start-body + +.. GENERATED FROM PYTHON SOURCE LINES 7-16 + +.. code-block:: Python + + + import chemfiles + import numpy as np + from metatensor import Labels, MetatensorError, TensorBlock, TensorMap + from skmatter.feature_selection import FPS + + from rascaline import SoapPowerSpectrum + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 17-18 + +First we load the dataset with chemfiles + +.. GENERATED FROM PYTHON SOURCE LINES 19-23 + +.. code-block:: Python + + + with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [f for f in trajectory] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 24-25 + +and define the hyper parameters of the representation + +.. GENERATED FROM PYTHON SOURCE LINES 26-45 + +.. code-block:: Python + + + HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, + } + + calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + + descriptor = calculator.compute(frames) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 46-49 + +The selections for feature can be a set of ``Labels``, in which case the names +of the labels must be a subset of the names of the properties produced by the +calculator. You can see the default set of names with: + +.. GENERATED FROM PYTHON SOURCE LINES 50-53 + +.. code-block:: Python + + + print("property names:", descriptor.property_names) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + property names: ['l', 'n_1', 'n_2'] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 54-57 + +We can use a subset of these names to define a selection. In this case, only +properties matching the labels in this selection will be used by rascaline +(here, only properties with ``l = 0`` will be used) + +.. GENERATED FROM PYTHON SOURCE LINES 58-72 + +.. code-block:: Python + + + selection = Labels( + names=["l"], + values=np.array([[0]]), + ) + selected_descriptor = calculator.compute(frames, selected_properties=selection) + + selected_descriptor = selected_descriptor.keys_to_samples("center_type") + selected_descriptor = selected_descriptor.keys_to_properties( + ["neighbor_1_type", "neighbor_2_type"] + ) + + properties = selected_descriptor.block().properties + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 73-74 + +We expect to get `[0]` as the list of `l` properties + +.. GENERATED FROM PYTHON SOURCE LINES 75-78 + +.. code-block:: Python + + + print(f"we have the following angular components: {np.unique(properties['l'])}") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + we have the following angular components: [0] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 79-82 + +The previous selection method uses the same selection for all blocks. If you +can to use different selection for different blocks, you should use a +``TensorMap`` to create your selection + +.. GENERATED FROM PYTHON SOURCE LINES 83-89 + +.. code-block:: Python + + + selected_descriptor = calculator.compute(frames, selected_properties=selection) + descriptor_for_comparison = calculator.compute( + frames, selected_properties=selected_descriptor + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 90-93 + +The descriptor had 180 properties stored in the first block, the +selected_descriptor had 36. So ``descriptor_for_comparison`` will also have 36 +properties. + +.. GENERATED FROM PYTHON SOURCE LINES 94-101 + +.. code-block:: Python + + print("shape of first block initially:", descriptor.block(0).values.shape) + print("shape of first block of reference:", selected_descriptor.block(0).values.shape) + print( + "shape of first block after selection:", + descriptor_for_comparison.block(0).values.shape, + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + shape of first block initially: (420, 180) + shape of first block of reference: (420, 36) + shape of first block after selection: (420, 36) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 102-108 + +The ``TensorMap`` format allows us to select different features within each +block, and then construct a general matrix of features. We can select the most +significant features using FPS, which selects features based on the distance +between them. The following code snippet selects the 10 most important +features in each block, then constructs a TensorMap containing this selection, +and calculates the final matrix of features for it. + +.. GENERATED FROM PYTHON SOURCE LINES 109-140 + +.. code-block:: Python + + + + def fps_feature_selection(descriptor, n_to_select): + """ + Select ``n_to_select`` features block by block in the ``descriptor``, using + Farthest Point Sampling to do the selection; and return a ``TensorMap`` with + the right structure to be used as properties selection with rascaline calculators + """ + blocks = [] + for block in descriptor: + # create a separate FPS selector for each block + fps = FPS(n_to_select=n_to_select) + mask = fps.fit(block.values).get_support() + selected_properties = Labels( + names=block.properties.names, + values=block.properties.values[mask], + ) + # The only important data here is the properties, so we create empty + # sets of samples and components. + blocks.append( + TensorBlock( + values=np.empty((1, len(selected_properties))), + samples=Labels.single(), + components=[], + properties=selected_properties, + ) + ) + + return TensorMap(descriptor.keys, blocks) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 141-143 + +We can then apply this function to subselect according to the data contained +in a descriptor + +.. GENERATED FROM PYTHON SOURCE LINES 144-147 + +.. code-block:: Python + + + selection = fps_feature_selection(descriptor, n_to_select=10) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 148-150 + +and use the selection with rascaline, potentially running the calculation on a +different set of systems + +.. GENERATED FROM PYTHON SOURCE LINES 151-154 + +.. code-block:: Python + + + selected_descriptor = calculator.compute(frames, selected_properties=selection) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 155-157 + +Note that in this case it is no longer possible to have a single feature +matrix, because each block will have its own properties. + +.. GENERATED FROM PYTHON SOURCE LINES 158-164 + +.. code-block:: Python + + + try: + selected_descriptor.keys_to_samples("center_type") + except MetatensorError as err: + print(err) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + invalid parameter: can not move keys to samples if the blocks have different property labels + + + + +.. GENERATED FROM PYTHON SOURCE LINES 165-166 + +.. end-body + + +.. _sphx_glr_download_examples_property-selection.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: property-selection.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: property-selection.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: property-selection.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/sample-selection.rst.txt b/latest/_sources/examples/sample-selection.rst.txt new file mode 100644 index 000000000..7af87c59d --- /dev/null +++ b/latest/_sources/examples/sample-selection.rst.txt @@ -0,0 +1,348 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/sample-selection.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_sample-selection.py: + + +Sample Selection +================ + +.. start-body + +.. GENERATED FROM PYTHON SOURCE LINES 7-15 + +.. code-block:: Python + + + import chemfiles + import numpy as np + from metatensor import Labels + + from rascaline import SoapPowerSpectrum + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 16-17 + +First we load the dataset with chemfiles + +.. GENERATED FROM PYTHON SOURCE LINES 18-22 + +.. code-block:: Python + + + with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [f for f in trajectory] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 23-24 + +and define the hyper parameters of the representation + +.. GENERATED FROM PYTHON SOURCE LINES 25-44 + +.. code-block:: Python + + + HYPER_PARAMETERS = { + "cutoff": 5.0, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": { + "Gto": {}, + }, + "cutoff_function": { + "ShiftedCosine": {"width": 0.5}, + }, + } + + calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + + descriptor = calculator.compute(frames) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 45-48 + +The selections for sample can be a set of ``Labels``, in which case the names +of the labels must be a subset of the names of the samples produced by the +calculator. You can see the default set of names with: + +.. GENERATED FROM PYTHON SOURCE LINES 49-52 + +.. code-block:: Python + + + print("sample names:", descriptor.sample_names) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + sample names: ['system', 'atom'] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 53-56 + +We can use a subset of these names to define a selection. In this case, only +samples matching the labels in this selection will be used by rascaline (here, +only atoms from system 0, 2, and 3) + +.. GENERATED FROM PYTHON SOURCE LINES 57-72 + +.. code-block:: Python + + + selection = Labels( + names=["system"], + values=np.array([[0], [2], [3]]), + ) + + descriptor_selected = calculator.compute(frames, selected_samples=selection) + + descriptor_selected = descriptor_selected.keys_to_samples("center_type") + descriptor_selected = descriptor_selected.keys_to_properties( + ["neighbor_1_type", "neighbor_2_type"] + ) + + samples = descriptor_selected.block().samples + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 73-74 + +The first block should have ``[0, 2, 3]`` as ``samples["system"]`` + +.. GENERATED FROM PYTHON SOURCE LINES 75-78 + +.. code-block:: Python + + + print(f"we have the following systems: {np.unique(samples['system'])}") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + we have the following systems: [0 2 3] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 79-82 + +If we want to select not only based on the system indexes but also atomic +indexes, we can do the following (here we select atom 0 in the first system +and atom 1 in the third system): + +.. GENERATED FROM PYTHON SOURCE LINES 83-95 + +.. code-block:: Python + + + selection = Labels( + names=["system", "atom"], + values=np.array([[0, 0], [2, 1]]), + ) + + descriptor_selected = calculator.compute(frames, selected_samples=selection) + descriptor_selected = descriptor_selected.keys_to_samples("center_type") + descriptor_selected = descriptor_selected.keys_to_properties( + ["neighbor_1_type", "neighbor_2_type"] + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 96-97 + +The values will have 2 rows, since we have two samples: + +.. GENERATED FROM PYTHON SOURCE LINES 98-104 + +.. code-block:: Python + + + print( + "shape of first block of descriptor:", + descriptor_selected.block(0).values.shape, + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + shape of first block of descriptor: (2, 1800) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 105-108 + +The previous selection method uses the same selection for all blocks. If you +can to use different selection for different blocks, you should use a +`TensorMap` to create your selection + +.. GENERATED FROM PYTHON SOURCE LINES 109-113 + +.. code-block:: Python + + + descriptor = calculator.compute(frames) + descriptor_selected = calculator.compute(frames, selected_samples=selection) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 114-115 + +notice how we are passing a TensorMap as the ``selected_samples`` argument: + +.. GENERATED FROM PYTHON SOURCE LINES 116-122 + +.. code-block:: Python + + + print(type(descriptor_selected)) + descriptor_for_comparison = calculator.compute( + frames, selected_samples=descriptor_selected + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 123-126 + +The descriptor had 420 samples stored in the first block, +the ``descriptor_selected`` had 0. So ``descriptor_for_comparison`` +will also have 0 samples. + +.. GENERATED FROM PYTHON SOURCE LINES 127-138 + +.. code-block:: Python + + + print("shape of first block initially:", descriptor.block(0).values.shape) + print( + "shape of first block of reference:", + descriptor_selected.block(0).values.shape, + ) + print( + "shape of first block after selection:", + descriptor_for_comparison.block(0).values.shape, + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + shape of first block initially: (420, 180) + shape of first block of reference: (0, 180) + shape of first block after selection: (0, 180) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 139-140 + +.. end-body + + +.. _sphx_glr_download_examples_sample-selection.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: sample-selection.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: sample-selection.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: sample-selection.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/sg_execution_times.rst.txt b/latest/_sources/examples/sg_execution_times.rst.txt new file mode 100644 index 000000000..4c8352eec --- /dev/null +++ b/latest/_sources/examples/sg_execution_times.rst.txt @@ -0,0 +1,64 @@ + +:orphan: + +.. _sphx_glr_examples_sg_execution_times: + + +Computation times +================= +**00:11.931** total execution time for 10 files **from examples**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_long-range-descriptor.py` (``long-range-descriptor.py``) + - 00:04.965 + - 0.0 + * - :ref:`sphx_glr_examples_compute-soap.py` (``compute-soap.py``) + - 00:02.312 + - 0.0 + * - :ref:`sphx_glr_examples_le-basis.py` (``le-basis.py``) + - 00:01.084 + - 0.0 + * - :ref:`sphx_glr_examples_splined-radial-integral.py` (``splined-radial-integral.py``) + - 00:00.930 + - 0.0 + * - :ref:`sphx_glr_examples_profiling.py` (``profiling.py``) + - 00:00.852 + - 0.0 + * - :ref:`sphx_glr_examples_property-selection.py` (``property-selection.py``) + - 00:00.691 + - 0.0 + * - :ref:`sphx_glr_examples_understanding-hypers.py` (``understanding-hypers.py``) + - 00:00.494 + - 0.0 + * - :ref:`sphx_glr_examples_sample-selection.py` (``sample-selection.py``) + - 00:00.333 + - 0.0 + * - :ref:`sphx_glr_examples_keys-selection.py` (``keys-selection.py``) + - 00:00.177 + - 0.0 + * - :ref:`sphx_glr_examples_first-calculation.py` (``first-calculation.py``) + - 00:00.092 + - 0.0 diff --git a/latest/_sources/examples/splined-radial-integral.rst.txt b/latest/_sources/examples/splined-radial-integral.rst.txt new file mode 100644 index 000000000..c489a4d6b --- /dev/null +++ b/latest/_sources/examples/splined-radial-integral.rst.txt @@ -0,0 +1,363 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/splined-radial-integral.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_splined-radial-integral.py: + + +Splined radial integrals +======================== + +.. start-body + +This example illustrates how to generate splined radial basis functions/integrals, using +a "rectangular" Laplacian eigenstate (LE) basis (https://doi.org/10.1063/5.0124363) as +the example, i.e, a LE basis truncated with ``l_max``, ``n_max`` hyper-parameters. + +Note that the same basis is also directly available through +:class:`rascaline.utils.SphericalBesselBasis` with an how-to guide given in +:ref:`userdoc-how-to-le-basis`. + +.. GENERATED FROM PYTHON SOURCE LINES 17-27 + +.. code-block:: Python + + + import ase + import numpy as np + import scipy as sp + from scipy.special import spherical_jn as j_l + + from rascaline import SphericalExpansion + from rascaline.utils import RadialIntegralFromFunction, SphericalBesselBasis + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 28-29 + +Set some hyper-parameters + +.. GENERATED FROM PYTHON SOURCE LINES 29-34 + +.. code-block:: Python + + + max_angular = 6 + max_radial = 8 + cutoff = 5.0 + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 35-37 + +where ``cutoff`` is also the radius of the LE sphere. Now we compute the zeros of the +spherical bessel functions. + +.. GENERATED FROM PYTHON SOURCE LINES 38-42 + +.. code-block:: Python + + + z_ln = SphericalBesselBasis.compute_zeros(max_angular, max_radial) + z_nl = z_ln.T + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 43-44 + +and define the radial basis functions + +.. GENERATED FROM PYTHON SOURCE LINES 44-69 + +.. code-block:: Python + + + + def R_nl(n, el, r): + # Un-normalized LE radial basis functions + return j_l(el, z_nl[n, el] * r / cutoff) + + + def N_nl(n, el): + # Normalization factor for LE basis functions, excluding the a**(-1.5) factor + def function_to_integrate_to_get_normalization_factor(x): + return j_l(el, x) ** 2 * x**2 + + integral, _ = sp.integrate.quadrature( + function_to_integrate_to_get_normalization_factor, 0.0, z_nl[n, el] + ) + return (1.0 / z_nl[n, el] ** 3 * integral) ** (-0.5) + + + def laplacian_eigenstate_basis(n, el, r): + R = np.zeros_like(r) + for i in range(r.shape[0]): + R[i] = R_nl(n, el, r[i]) + return N_nl(n, el) * R * cutoff ** (-1.5) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 70-71 + +Quick normalization check: + +.. GENERATED FROM PYTHON SOURCE LINES 71-80 + +.. code-block:: Python + + + normalization_check_integral, _ = sp.integrate.quadrature( + lambda x: laplacian_eigenstate_basis(1, 1, x) ** 2 * x**2, + 0.0, + cutoff, + ) + print(f"Normalization check (needs to be close to 1): {normalization_check_integral}") + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /home/runner/work/rascaline/rascaline/python/rascaline/examples/splined-radial-integral.py:72: DeprecationWarning: `scipy.integrate.quadrature` is deprecated as of SciPy 1.12.0and will be removed in SciPy 1.15.0. Please use`scipy.integrate.quad` instead. + normalization_check_integral, _ = sp.integrate.quadrature( + /home/runner/work/rascaline/rascaline/python/rascaline/examples/splined-radial-integral.py:56: DeprecationWarning: `scipy.integrate.quadrature` is deprecated as of SciPy 1.12.0and will be removed in SciPy 1.15.0. Please use`scipy.integrate.quad` instead. + integral, _ = sp.integrate.quadrature( + Normalization check (needs to be close to 1): 0.9999999999999999 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 81-82 + +Now the derivatives (by finite differences): + +.. GENERATED FROM PYTHON SOURCE LINES 82-97 + +.. code-block:: Python + + + + def laplacian_eigenstate_basis_derivative(n, el, r): + delta = 1e-6 + all_derivatives_except_at_zero = ( + laplacian_eigenstate_basis(n, el, r[1:] + delta) + - laplacian_eigenstate_basis(n, el, r[1:] - delta) + ) / (2.0 * delta) + derivative_at_zero = ( + laplacian_eigenstate_basis(n, el, np.array([delta / 10.0])) + - laplacian_eigenstate_basis(n, el, np.array([0.0])) + ) / (delta / 10.0) + return np.concatenate([derivative_at_zero, all_derivatives_except_at_zero]) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 98-101 + +The radial basis functions and their derivatives can be input into a spline generator +class. This will output the positions of the spline points, the values of the basis +functions evaluated at the spline points, and the corresponding derivatives. + +.. GENERATED FROM PYTHON SOURCE LINES 101-111 + +.. code-block:: Python + + + spliner = RadialIntegralFromFunction( + radial_integral=laplacian_eigenstate_basis, + radial_integral_derivative=laplacian_eigenstate_basis_derivative, + spline_cutoff=cutoff, + max_radial=max_radial, + max_angular=max_angular, + accuracy=1e-5, + ) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 112-114 + +The, we feed the splines to the Rust calculator: Note that the +``atomic_gaussian_width`` will be ignored since we are not uisng a Gaussian basis. + +.. GENERATED FROM PYTHON SOURCE LINES 114-126 + +.. code-block:: Python + + + hypers_spherical_expansion = { + "cutoff": cutoff, + "max_radial": max_radial, + "max_angular": max_angular, + "center_atom_weight": 0.0, + "radial_basis": spliner.compute(), + "atomic_gaussian_width": 1.0, # ignored + "cutoff_function": {"Step": {}}, + } + calculator = SphericalExpansion(**hypers_spherical_expansion) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 127-128 + +Create dummy systems to test if the calculator outputs correct radial functions: + +.. GENERATED FROM PYTHON SOURCE LINES 129-142 + +.. code-block:: Python + + + + def get_dummy_systems(r_array): + dummy_systems = [] + for r in r_array: + dummy_systems.append(ase.Atoms("CH", positions=[(0, 0, 0), (0, 0, r)])) + return dummy_systems + + + r = np.linspace(0.1, 4.9, 20) + systems = get_dummy_systems(r) + spherical_expansion_coefficients = calculator.compute(systems) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 143-144 + +Extract ``l = 0`` features and check that the ``n = 2`` predictions are the same: + +.. GENERATED FROM PYTHON SOURCE LINES 144-151 + +.. code-block:: Python + + + block_C_l0 = spherical_expansion_coefficients.block( + center_type=6, o3_lambda=0, neighbor_type=1 + ) + block_C_l0_n2 = block_C_l0.values[:, :, 2].flatten() + spherical_harmonics_0 = 1.0 / np.sqrt(4.0 * np.pi) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 152-153 + +radial function = feature / spherical harmonics function + +.. GENERATED FROM PYTHON SOURCE LINES 153-163 + +.. code-block:: Python + + rascaline_output_radial_function = block_C_l0_n2 / spherical_harmonics_0 + + assert np.allclose( + rascaline_output_radial_function, + laplacian_eigenstate_basis(2, 0, r), + atol=1e-5, + ) + print("Assertion passed successfully!") + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Assertion passed successfully! + + + + +.. GENERATED FROM PYTHON SOURCE LINES 164-165 + +.. end-body + + +.. _sphx_glr_download_examples_splined-radial-integral.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: splined-radial-integral.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: splined-radial-integral.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: splined-radial-integral.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/examples/understanding-hypers.rst.txt b/latest/_sources/examples/understanding-hypers.rst.txt new file mode 100644 index 000000000..ce5a1ed0d --- /dev/null +++ b/latest/_sources/examples/understanding-hypers.rst.txt @@ -0,0 +1,688 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/understanding-hypers.py" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code. + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_examples_understanding-hypers.py: + + +.. _userdoc-tutorials-understanding-hypers: + +Changing SOAP hyper parameters +============================== + +In the first :ref:`tutorial ` we show how to +calculate a descriptor using default hyper parameters. Here we will look at how the +change of some hyper parameters affects the values of the descriptor. The +definition of every hyper parameter is given in the :ref:`userdoc-calculators` and +background on the mathematical foundation of the spherical expansion is given in +the :ref:`userdoc-explanations` section. + +.. GENERATED FROM PYTHON SOURCE LINES 16-19 + +We use the same molecular crystals dataset as in the first +:ref:`tutorial ` which can downloaded from our +:download:`website <../../static/dataset.xyz>`. + +.. GENERATED FROM PYTHON SOURCE LINES 20-38 + +.. code-block:: Python + + + # We first import the crucial packages, load the dataset using chemfiles and + # save the first frame in a variable. + + import time + + import chemfiles + import matplotlib.pyplot as plt + import numpy as np + + from rascaline import SphericalExpansion + + + with chemfiles.Trajectory("dataset.xyz") as trajectory: + frames = [frame for frame in trajectory] + + frame0 = frames[0] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 39-47 + +Increasing ``max_radial`` and ``max_angular`` +--------------------------------------------- + +As mentioned above changing ``max_radial`` has an effect on the accuracy of +the descriptor and on the computation time. We now will increase the number of +radial channels and angular channels. Note, that here we directly pass the +parameters into the ``SphericalExpansion`` class without defining a +``HYPERPARAMETERS`` dictionary like we did in the previous tutorial. + +.. GENERATED FROM PYTHON SOURCE LINES 48-62 + +.. code-block:: Python + + + calculator_ext = SphericalExpansion( + cutoff=4.5, + max_radial=12, + max_angular=8, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, + ) + + descriptor_ext = calculator_ext.compute(frame0) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 63-65 + +Compared to our previous set of hypers we now have 144 blocks instead of 112 +because we increased the number of angular channels. + +.. GENERATED FROM PYTHON SOURCE LINES 66-69 + +.. code-block:: Python + + + print(len(descriptor_ext.blocks())) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + 144 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 70-72 + +The increase of the radial channels to 12 is reflected in the shape of the 0th +block values. + +.. GENERATED FROM PYTHON SOURCE LINES 73-76 + +.. code-block:: Python + + + print(descriptor_ext.block(0).values.shape) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + (8, 1, 12) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 77-82 + +Note that the increased number of radial and angular channels can increase the +accuracy of your representation but will increase the computational time +transforming the coordinates into a descriptor. A very simple time measurement +of the computation shows that the extended calculator takes more time for +the computation compared to a calculation using the default hyper parameters + +.. GENERATED FROM PYTHON SOURCE LINES 83-104 + +.. code-block:: Python + + + start_time = time.time() + calculator_ext.compute(frames) + print(f"Extended hypers took {time.time() - start_time:.2f} s.") + + # using smaller max_radial and max_angular, everything else stays the same + calculator_small = SphericalExpansion( + cutoff=4.5, + max_radial=9, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, + ) + + start_time = time.time() + calculator_small.compute(frames) + print(f"Smaller hypers took {time.time() - start_time:.2f} s.") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Extended hypers took 0.08 s. + Smaller hypers took 0.07 s. + + + + +.. GENERATED FROM PYTHON SOURCE LINES 105-112 + +Reducing the ``cutoff`` and the ``center_atom_weight`` +------------------------------------------------------ + +The cutoff controls how many neighboring atoms are taken into account for a +descriptor. By decreasing the cutoff from 6 Å to 0.1 Å fewer and fewer atoms +contribute to the descriptor which can be seen by the reduced range of the +features. + +.. GENERATED FROM PYTHON SOURCE LINES 113-130 + +.. code-block:: Python + + + for cutoff in [6.0, 4.5, 3.0, 1.0, 0.1]: + calculator_cutoff = SphericalExpansion( + cutoff=cutoff, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, + ) + + descriptor = calculator_cutoff.compute(frame0) + + print(f"Descriptor for cutoff={cutoff} Å: {descriptor.block(0).values[0]}") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Descriptor for cutoff=6.0 Å: [[ 0.73193479 -0.29310529 0.20099337 -0.01685146 0.10192235 -0.00619106]] + Descriptor for cutoff=4.5 Å: [[ 0.88696541 -0.27211242 0.12400786 0.03004326 0.13265605 0.00631962]] + Descriptor for cutoff=3.0 Å: [[ 0.99735843 0.02421642 -0.01582201 0.07692315 0.0739584 0.02262702]] + Descriptor for cutoff=1.0 Å: [[0.47066472 0.51914099 0.60560181 0.34760844 0.14044963 0.03946593]] + Descriptor for cutoff=0.1 Å: [[0.00157192 0.00240957 0.00345497 0.00925635 0.00025653 0.02589691]] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 131-139 + +For a ``cutoff`` of 0.1 Å there is no neighboring atom within the cutoff and +one could expect all features to be 0. This is not the case because the +central atom also contributes to the descriptor. We can vary this contribution +using the ``center_atom_weight`` parameter so that the descriptor finally is 0 +everywhere. + +..Add a sophisticated and referenced note on how the ``center_atom_weight`` +could affect ML models. + +.. GENERATED FROM PYTHON SOURCE LINES 140-160 + +.. code-block:: Python + + + for center_weight in [1.0, 0.5, 0.0]: + calculator_cutoff = SphericalExpansion( + cutoff=0.1, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=center_weight, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, + ) + + descriptor = calculator_cutoff.compute(frame0) + + print( + f"Descriptor for center_weight={center_weight}: " + f"{descriptor.block(0).values[0]}" + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Descriptor for center_weight=1.0: [[0.00157192 0.00240957 0.00345497 0.00925635 0.00025653 0.02589691]] + Descriptor for center_weight=0.5: [[0.00078596 0.00120479 0.00172749 0.00462817 0.00012826 0.01294846]] + Descriptor for center_weight=0.0: [[0. 0. 0. 0. 0. 0.]] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 161-186 + +Choosing the ``cutoff_function`` +-------------------------------- + +In a naive descriptor approach all atoms within the cutoff are taken in into +account equally and atoms without the cutoff are ignored. This behavior is +implemented using the ``cutoff_function={"Step": {}}`` parameter in each +calculator. However, doing so means that small movements of an atom near the +cutoff result in large changes in the descriptor: there is a discontinuity in +the representation as atoms enter or leave the cutoff. A solution is to use +some smoothing function to get rid of this discontinuity, such as a shifted +cosine function: + +.. math:: + + f(r) = \begin{cases} + 1 &r < r_c - w,\\ + 0.5 + 0.5 \cos[\pi (r - r_c + w) / w] &r_c - w < r <= r_c, \\ + 0 &r_c < r, + \end{cases} + +where :math:`r_\mathrm{c}` is the cutoff distance and :math:`w` the width. +Such smoothing function is used as a multiplicative weight for the +contribution to the representation coming from each neighbor one by one + +The following functions compute such a shifted cosine weighting. + +.. GENERATED FROM PYTHON SOURCE LINES 187-215 + +.. code-block:: Python + + + + def shifted_cosine(r, cutoff, width): + """A shifted cosine switching function. + + Parameters + ---------- + r : float + distance between neighboring atoms in Å + cutoff : float + cutoff distance in Å + width : float + width of the switching in Å + + Returns + ------- + float + weighting of the features + """ + if r <= (cutoff - width): + return 1.0 + elif r >= cutoff: + return 0.0 + else: + s = np.pi * (r - cutoff + width) / width + return 0.5 * (1.0 + np.cos(s)) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 216-217 + +Let us plot the weighting for different widths. + +.. GENERATED FROM PYTHON SOURCE LINES 218-232 + +.. code-block:: Python + + + r = np.linspace(1e-3, 4.5, num=100) + + plt.plot([0, 4.5, 4.5, 5.0], [1, 1, 0, 0], c="k", label=r"Step function") + + for width in [4.5, 2.5, 1.0, 0.5, 0.1]: + weighting_values = [shifted_cosine(r=r_i, cutoff=4.5, width=width) for r_i in r] + plt.plot(r, weighting_values, label=f"Shifted cosine: $width={width}\\,Å$") + + plt.legend() + plt.xlabel(r"distance $r$ from the central atom in $Å$") + plt.ylabel("feature weighting") + plt.show() + + + + +.. image-sg:: /examples/images/sphx_glr_understanding-hypers_001.png + :alt: understanding hypers + :srcset: /examples/images/sphx_glr_understanding-hypers_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 233-236 + +From the plot we conclude that a larger ``width`` of the shifted cosine +function will decrease the feature values already for smaller distances ``r`` +from the central atom. + +.. GENERATED FROM PYTHON SOURCE LINES 239-263 + +Choosing the ``radial_scaling`` +------------------------------- + +As mentioned above all atoms within the cutoff are taken equally for a +descriptor. This might limit the accuracy of a model, so it is sometimes +useful to weigh neighbors that further away from the central atom less than +neighbors closer to the central atom. This can be achieved by a +``radial_scaling`` function with a long-range algebraic decay and smooth +behavior at :math:`r \rightarrow 0`. The ``'Willatt2018'`` radial scaling +available in rascaline corresponds to the function introduced in this +`publication `_: + +.. math:: + + u(r) = \begin{cases} + 1 / (r/r_0)^m & \text{if c=0,} \\ + 1 & \text{if m=0,} \\ + c / (c+(r/r_0)^m) & \text{else}, + \end{cases} + +where :math:`c` is the ``rate``, :math:`r_0` is the ``scale`` parameter and +:math:`m` the ``exponent`` of the RadialScaling function. + +The following functions compute such a radial scaling. + +.. GENERATED FROM PYTHON SOURCE LINES 264-293 + +.. code-block:: Python + + + + def radial_scaling(r, rate, scale, exponent): + """Radial scaling function. + + Parameters + ---------- + r : float + distance between neighboring atoms in Å + rate : float + decay rate of the scaling + scale : float + scaling of the distance between atoms in Å + exponent : float + exponent of the decay + + Returns + ------- + float + weighting of the features + """ + if rate == 0: + return 1 / (r / scale) ** exponent + if exponent == 0: + return 1 + else: + return rate / (rate + (r / scale) ** exponent) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 294-297 + +In the following we show three different radial scaling functions, where the +first one uses the parameters we use for the calculation of features in the +:ref:`first tutorial `. + +.. GENERATED FROM PYTHON SOURCE LINES 298-317 + +.. code-block:: Python + + + r = np.linspace(1e-3, 4.5, num=100) + + plt.axvline(4.5, c="k", ls="--", label="cutoff") + + radial_scaling_params = {"scale": 2.0, "rate": 1.0, "exponent": 4} + plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + + radial_scaling_params = {"scale": 2.0, "rate": 3.0, "exponent": 6} + plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + + radial_scaling_params = {"scale": 2.0, "rate": 0.8, "exponent": 2} + plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + + plt.legend() + plt.xlabel(r"distance $r$ from the central atom in $Å$") + plt.ylabel("feature weighting") + plt.show() + + + + +.. image-sg:: /examples/images/sphx_glr_understanding-hypers_002.png + :alt: understanding hypers + :srcset: /examples/images/sphx_glr_understanding-hypers_002.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /home/runner/work/rascaline/rascaline/python/rascaline/examples/understanding-hypers.py:304: MatplotlibDeprecationWarning: Passing label as a length 3 sequence when plotting a single dataset is deprecated in Matplotlib 3.9 and will error in 3.11. To keep the current behavior, cast the sequence to string before passing. + plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + /home/runner/work/rascaline/rascaline/python/rascaline/examples/understanding-hypers.py:307: MatplotlibDeprecationWarning: Passing label as a length 3 sequence when plotting a single dataset is deprecated in Matplotlib 3.9 and will error in 3.11. To keep the current behavior, cast the sequence to string before passing. + plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + /home/runner/work/rascaline/rascaline/python/rascaline/examples/understanding-hypers.py:310: MatplotlibDeprecationWarning: Passing label as a length 3 sequence when plotting a single dataset is deprecated in Matplotlib 3.9 and will error in 3.11. To keep the current behavior, cast the sequence to string before passing. + plt.plot(r, radial_scaling(r, **radial_scaling_params), label=radial_scaling_params) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 318-327 + +In the end the total weight is the product of ``cutoff_function`` and the +``radial_scaling`` + +.. math: + + rs(r) = sc(r) \cdot u(r) + +The shape of this function should be a "S" like but the optimal shape depends +on each dataset. + +.. GENERATED FROM PYTHON SOURCE LINES 328-374 + +.. code-block:: Python + + + + def feature_scaling(r, cutoff, width, rate, scale, exponent): + """Features Scaling factor using cosine shifting and radial scaling. + + Parameters + ---------- + r : float + distance between neighboring atoms + cutoff : float + cutoff distance in Å + width : float + width of the decay in Å + rate : float + decay rate of the scaling + scale : float + scaling of the distance between atoms in Å + exponent : float + exponent of the decay + + Returns + ------- + float + weighting of the features + """ + s = radial_scaling(r, rate, scale, exponent) + s *= np.array([shifted_cosine(ri, cutoff, width) for ri in r]) + return s + + + r = np.linspace(1e-3, 4.5, num=100) + + plt.axvline(4.5, c="k", ls="--", label=r"$r_\mathrm{cut}$") + + radial_scaling_params = {} + plt.plot( + r, + feature_scaling(r, scale=2.0, rate=4.0, exponent=6, cutoff=4.5, width=0.5), + label="feature weighting function", + ) + + plt.legend() + plt.xlabel(r"distance $r$ from the central atom $[Å]$") + plt.ylabel("feature weighting") + plt.show() + + + + +.. image-sg:: /examples/images/sphx_glr_understanding-hypers_003.png + :alt: understanding hypers + :srcset: /examples/images/sphx_glr_understanding-hypers_003.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 375-377 + +Finally we see how the magnitude of the features further away from the central +atom reduces when we apply both a ``shifted_cosine`` and a ``radial_scaling``. + +.. GENERATED FROM PYTHON SOURCE LINES 378-419 + +.. code-block:: Python + + + calculator_step = SphericalExpansion( + cutoff=4.5, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"Step": {}}, + ) + + descriptor_step = calculator_step.compute(frame0) + print(f"Step cutoff: {str(descriptor_step.block(0).values[0]):>97}") + + calculator_cosine = SphericalExpansion( + cutoff=4.5, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + ) + + descriptor_cosine = calculator_cosine.compute(frame0) + print(f"Cosine smoothing: {str(descriptor_cosine.block(0).values[0]):>92}") + + calculator_rs = SphericalExpansion( + cutoff=4.5, + max_radial=6, + max_angular=6, + atomic_gaussian_width=0.3, + center_atom_weight=1.0, + radial_basis={"Gto": {"spline_accuracy": 1e-6}}, + cutoff_function={"ShiftedCosine": {"width": 0.5}}, + radial_scaling={"Willatt2018": {"scale": 2.0, "rate": 1.0, "exponent": 4}}, + ) + + descriptor_rs = calculator_rs.compute(frame0) + + print(f"cosine smoothing + radial scaling: {str(descriptor_rs.block(0).values[0]):>50}") + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Step cutoff: [[ 0.87386968 -0.24311082 0.12200976 0.41940912 0.80347292 0.26559202]] + Cosine smoothing: [[ 0.8728401 -0.24114056 0.11656053 0.43711707 0.77838565 0.22482755]] + cosine smoothing + radial scaling: [[ 0.88696541 -0.27211242 0.12400786 0.03004326 0.13265605 0.00631962]] + + + + + +.. _sphx_glr_download_examples_understanding-hypers.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: understanding-hypers.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: understanding-hypers.py ` + + .. container:: sphx-glr-download sphx-glr-download-zip + + :download:`Download zipped: understanding-hypers.zip ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ diff --git a/latest/_sources/explanations/concepts.rst.txt b/latest/_sources/explanations/concepts.rst.txt new file mode 100644 index 000000000..93d25737b --- /dev/null +++ b/latest/_sources/explanations/concepts.rst.txt @@ -0,0 +1,83 @@ +.. _core-concepts: + +Core concepts of rascaline +========================== + +Rascaline is a library computing representations of atomic systems for machine +learning applications. These representations encode fundamental symmetries of +the systems to ensure that the machine learning algorithm is as efficient as +possible. Examples of representations include the `Smooth Overlap of Atomic +Positions `_ (SOAP), `Behler-Parrinello symmetry functions `_, +`Coulomb matrices`_, and many others. This documentation does not describe each +method in details, delegating instead to many other good resources on the +subject. This section in particular explains the three core objects rascaline is +built upon: systems, calculators and descriptors. + +.. figure:: ../../static/images/core-concepts.* + + Schematic representations of the three core concepts in rascaline: systems, + calculators and descriptors. The core operation provided by this library to + compute the representation (associated with a given calculator) of one or + multiple systems, getting the corresponding data in a descriptor. + +.. _SOAP: https://doi.org/10.1103/PhysRevB.87.184115 +.. _BPSF: https://doi.org/10.1063/1.3553717 +.. _Coulomb matrices: https://doi.org/10.1103/PhysRevLett.108.058301 + +Systems: atoms and molecules +---------------------------- + +Systems describe the input data rascaline uses to compute various +representations. They contains information about the atomic positions, different +atomic types, unit cell and periodicity, and are responsible for computing the +neighbors of each atomic center. + +Rascaline uses systems in a generic manner, and while it provides a default +implementation called ``SimpleSystem`` it is able to use data from any source by +going through a few lines of adaptor code. This enables using it directly inside +molecular simulation engines, re-using the neighbors list calculation done by +the engine, when using machine learning force-fields in simulations. + +Both implementation and data related to systems are thus provided by users of +the rascaline library. + +Calculators: computing representations +-------------------------------------- + +Calculators are provided by rascaline, and compute a single representations. +There is a calculator +for the :ref:`sorted distances vector ` representation, +one for the :ref:`spherical expansion ` representation, +one for the :ref:`LODE spherical expansion ` representation, +and hopefully soon many others. + +All calculators are registered globally in rascaline, and can be constructed +with a name and a set of parameters (often called hyper-parameters). These +parameters control the features of the final representation: how many are they, +and what do they represent. All :ref:`available calculators ` +and the corresponding parameters are documented. + +From a user perspective, calculators are black boxes that take systems as input +and returns a descriptor object, described below. + +Descriptors: data storage for atomistic machine learning +-------------------------------------------------------- + +After using a calculator on one or multiple systems, users will get the +numerical representation of their atomic systems in a ``descriptor`` object. +Rascaline uses `metatensor`_ ``TensorMap`` type when returning descriptors. + +.. _metatensor: https://lab-cosmo.github.io/metatensor/ + +A ``TensorMap`` can be seen as a dictionary mapping some keys to a set of data +blocks. Each block contains both data (and gradients) arrays — i.e. +multidimensional arrays containing the descriptor values — and metadata +describing the different dimensions of these arrays. Which keys are present in a +``TensorMap`` will depend on ``Calculator`` being used. Typically, +representation using one-hot encoding of atomic types will have the +corresponding keys (for example ``center_type``, ``neighbor_type``, *etc.*), and +equivariant representations will have keys for the different equivariance +classes (``o3_lambda`` for SO(3) equivariants, *etc.*). + +For more information on ``TensorMap`` and what can be done with one, please see +the `metatensor`_ documentation. diff --git a/latest/_sources/explanations/index.rst.txt b/latest/_sources/explanations/index.rst.txt new file mode 100644 index 000000000..77eb9ffa0 --- /dev/null +++ b/latest/_sources/explanations/index.rst.txt @@ -0,0 +1,16 @@ +.. _userdoc-explanations: + +Explanations +============ + +The explanation section discusses topics that broaden your knowledge of +rascaline. The theory behind the calculators and additional useful information +are found here to give you more clarity and understanding of what rascaline is +all about. + +.. toctree:: + :maxdepth: 1 + + concepts + soap + rotation_adapted \ No newline at end of file diff --git a/latest/_sources/explanations/rotation_adapted.rst.txt b/latest/_sources/explanations/rotation_adapted.rst.txt new file mode 100644 index 000000000..0248cb1ea --- /dev/null +++ b/latest/_sources/explanations/rotation_adapted.rst.txt @@ -0,0 +1,114 @@ +Rotation-Adapted Features +========================= + +Equivariance +------------ + +Descriptors like SOAP are translation, rotation, and permutation invariant. +Indeed, such invariances are extremely useful if one wants to learn an invariant +target (e.g., the energy). Being already encoded in the descriptor, the learning +algorithm does not have to learn such a physical requirement. + +The situation is different if the target is not invariant. For example, one may +want to learn a dipole. The dipole rotates with a rotation of the molecule, and +as such, invariant descriptors do not have the required symmetries for this +task. + +Instead, one would need a rotation equivariant descriptor. Rotation equivariance +means that, if we first rotate the system and compute the descriptor, we obtain +the same result as first computing the descriptor and then applying the +rotation, i.e., the descriptor behaves correctly upon rotation operations. +Denoting a system as :math:`A`, the function computing the descriptor as +:math:`f(\cdot)`, and the rotation operator as :math:`\hat{R}`, rotation +equivariance can be expressed as: + +.. math:: + :name: eq:equivariance + + f(\hat{R} A) = \hat{R} f(A) + +Of course, invariance is a special case of equivariance. + + +Rotation Equivariance of the Spherical Expansion +------------------------------------------------ + +The spherical expansion is a rotation equivariant descriptor. +Let's consider the expansion coefficients of :math:`\rho_i(\mathbf{r})`. +We have: + +.. math:: + + \hat{R} \rho_i(\mathbf{r}) &= \sum_{nlm} c_{nlm}^{i} R_n(r) \hat{R} Y_l^m(\hat{\mathbf{r}}) \nonumber \\ + &= \sum_{nlmm'} c_{nlm}^{i} R_n(r) D_{m,m'}^{l}(\hat{R}) Y_l^{m'}(\hat{\mathbf{r}}) \nonumber \\ + &= \sum_{nlm} \left( \sum_{m'} D_{m',m}^l(\hat{R}) c_{nlm'}^{i}\right) B_{nlm}(\mathbf{r}) \nonumber + +and noting that :math:`Y_l^m(\hat{R} \hat{\mathbf{r}}) = \hat{R} +Y_l^m(\hat{\mathbf{r}})` and :math:`\hat{R}r = r`, equation :ref:`(1) +` is satisfied and we conclude that the expansion coefficients +:math:`c_{nlm}^{i}` are rotation equivariant. Indeed, each :math:`c_{nlm}^{i}` +transforms under rotation as the spherical harmonics +:math:`Y_l^m(\hat{\mathbf{r}})`. + +Using the Dirac notation, the coefficient :math:`c_{nlm}^{i}` can be expressed +as :math:`\braket{nlm\vert\rho_i}`. Equivalently, and to stress the fact that +this coefficient describes something that transforms under rotation as a +spherical harmonics :math:`Y_l^m(\hat{\mathbf{r}})`, it is sometimes written as +:math:`\braket{n\vert\rho_i;lm}`, i.e., the atomic density is "tagged" with a +label that tells how it transforms under rotations. + + +Completeness Relations of Spherical Harmonics +--------------------------------------------- + +Spherical harmonics can be combined together using rules coming from standard +theory of angular momentum: + +.. math:: + :name: eq:cg_coupling + + \ket{lm} \propto \ket{l_1 l_2 l m} = \sum_{m_1 m_2} C_{m_1 m_2 m}^{l_1 l_2 l} \ket{l_1 m_1} \ket{l_2 m_2} + +where :math:`C_{m_1 m_2 m}^{l_1 l_2 l}` is a Clebsch-Gordan (CG) coefficient. + +Thanks to the one-to-one correspondence (under rotation) between +:math:`c_{nlm}^{i}` and :math:`Y_l^m`, :ref:`(2) ` means that +one can take products of two spherical expansion coefficients (which amounts to +considering density correlations), and combine them with CG coefficients to get +new coefficients that transform as a single spherical harmonics. This process is +known as coupling, from the uncoupled basis of angular momentum (formed by the +product of rotation eigenstates) to a coupled basis (a single rotation +eigenstate). + +One can also write the inverse of :ref:`(2) `: + +.. math:: + :name: eq:cg_decoupling + + \ket{l_1 m_1} \ket{l_2 m_2} = \sum_{l m} C_{m_1 m_2 m}^{l_1 l_2 l m} \ket{l_1 l_2 l m} + +that express the product of two rotation eigenstates in terms of one. This +process is known as decoupling. + +Example: :math:`\lambda`-SOAP +----------------------------- + +A straightforward application of :ref:`(2) ` is the construction +of :math:`\lambda`-SOAP features. Indeed, :math:`\lambda`-SOAP was created in +order to have a rotation and inversion equivariant version of the 3-body density +correlations. The :math:`\lambda` represents the degree of a spherical +harmonics, :math:`Y_{\lambda}^{\mu}(\hat{\mathbf{r}})`, and it indicates that +this descriptor can transform under rotations as a spherical harmonics, i.e., it +is rotation equivariant. + +It is then obtained by considering two expansion coefficients of the atomic +density, and combining them with a CG iteration to a coupled basis, as in +:ref:`(2) `. The :math:`\lambda`-SOAP descriptor is then: + +.. math:: + + \braket{n_1 l_1 n_2 l_2\vert\overline{\rho_i^{\otimes 2}, \sigma, \lambda \mu}} = + \frac{\delta_{\sigma, (-1)^{l_1 + l_2 + \lambda}}}{\sqrt{2 \lambda + 1}} + \sum_{m} C_{m (\mu-m) \mu}^{l_1 l_2 \lambda} c_{n_1 l_1 m}^{i} c_{n_2 l_2 (\mu - m)}^{i} + +where we have assumed complex spherical harmonics coefficients. diff --git a/latest/_sources/explanations/soap.rst.txt b/latest/_sources/explanations/soap.rst.txt new file mode 100644 index 000000000..8a6c94a56 --- /dev/null +++ b/latest/_sources/explanations/soap.rst.txt @@ -0,0 +1,8 @@ +.. _theory: + +What is SOAP +============ + +TBD + +.. We can take inspiration from https://lab-cosmo.github.io/librascal/SOAP.html diff --git a/latest/_sources/get-started/index.rst.txt b/latest/_sources/get-started/index.rst.txt new file mode 100644 index 000000000..7c29dfd7e --- /dev/null +++ b/latest/_sources/get-started/index.rst.txt @@ -0,0 +1,13 @@ +.. _userdoc-get-started: + +Getting started +=============== + +The following sections describes how to install and start with using rascaline. + +.. toctree:: + :maxdepth: 2 + + rascaline + installation + tutorials diff --git a/latest/_sources/get-started/installation.rst.txt b/latest/_sources/get-started/installation.rst.txt new file mode 100644 index 000000000..fc6e57cb0 --- /dev/null +++ b/latest/_sources/get-started/installation.rst.txt @@ -0,0 +1,179 @@ +Installation +============ + +You can install rascaline in different ways depending on which language you plan +to use it from. In all cases you will need a Rust compiler, which you can +install using `rustup `_ or your OS package manager. + +.. _install-python-lib: + +Installing the Python module +---------------------------- + +For building and using the Python package, clone the repository using `git +`_ and install rascaline using `pip +`_. + +From source: + +.. code-block:: bash + + # Make sure you are using the latest version of pip + pip install --upgrade pip + + git clone https://github.com/Luthaf/rascaline + cd rascaline + pip install . + + # alternatively, the same thing in a single command + pip install git+https://github.com/Luthaf/rascaline + + +Rascaline is also provided as prebuilt wheel which avoids the intermediate step +of building the package with a Rust compiler from the source code. + +.. code-block:: bash + + pip install --upgrade pip + pip install --extra-index-url https://luthaf.fr/nightly-wheels/ rascaline + + +.. _install-c-lib: + +Installing the C/C++ library +---------------------------- + +This installs a C-compatible shared library that can also be called from C++, as +well as CMake files that can be used with ``find_package(rascaline)``. + +.. code-block:: bash + + git clone https://github.com/Luthaf/rascaline + cd rascaline/rascaline-c-api + mkdir build + cd build + cmake .. + make install + +The build and installation can be configures with a few cmake options, using +``-D