diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8a4060e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/.tox/ +/build/ +/dist/ +*.egg-info +__pycache__/ + diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/index.html b/index.html new file mode 100644 index 00000000..3c1a5aac --- /dev/null +++ b/index.html @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/latest/.buildinfo b/latest/.buildinfo new file mode 100644 index 00000000..01604e2d --- /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: 5f1d35288f995fa2749255ee0d36f006 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/latest/.doctrees/environment.pickle b/latest/.doctrees/environment.pickle new file mode 100644 index 00000000..bf3fc87b Binary files /dev/null and b/latest/.doctrees/environment.pickle differ diff --git a/latest/.doctrees/examples/batch-cp2k/reference-trajectory.doctree b/latest/.doctrees/examples/batch-cp2k/reference-trajectory.doctree new file mode 100644 index 00000000..38a5d713 Binary files /dev/null and b/latest/.doctrees/examples/batch-cp2k/reference-trajectory.doctree differ diff --git a/latest/.doctrees/examples/batch-cp2k/sg_execution_times.doctree b/latest/.doctrees/examples/batch-cp2k/sg_execution_times.doctree new file mode 100644 index 00000000..f290c63b Binary files /dev/null and b/latest/.doctrees/examples/batch-cp2k/sg_execution_times.doctree differ diff --git a/latest/.doctrees/examples/dos-align/dos-align.doctree b/latest/.doctrees/examples/dos-align/dos-align.doctree new file mode 100644 index 00000000..55d1f707 Binary files /dev/null and b/latest/.doctrees/examples/dos-align/dos-align.doctree differ diff --git a/latest/.doctrees/examples/dos-align/sg_execution_times.doctree b/latest/.doctrees/examples/dos-align/sg_execution_times.doctree new file mode 100644 index 00000000..dafe860d Binary files /dev/null and b/latest/.doctrees/examples/dos-align/sg_execution_times.doctree differ diff --git a/latest/.doctrees/examples/gaas-map/gaas-map.doctree b/latest/.doctrees/examples/gaas-map/gaas-map.doctree new file mode 100644 index 00000000..5c3bc228 Binary files /dev/null and b/latest/.doctrees/examples/gaas-map/gaas-map.doctree differ diff --git a/latest/.doctrees/examples/gaas-map/sg_execution_times.doctree b/latest/.doctrees/examples/gaas-map/sg_execution_times.doctree new file mode 100644 index 00000000..329b127c Binary files /dev/null and b/latest/.doctrees/examples/gaas-map/sg_execution_times.doctree differ diff --git a/latest/.doctrees/examples/lode-linear/lode-linear.doctree b/latest/.doctrees/examples/lode-linear/lode-linear.doctree new file mode 100644 index 00000000..9a078914 Binary files /dev/null and b/latest/.doctrees/examples/lode-linear/lode-linear.doctree differ diff --git a/latest/.doctrees/examples/lode-linear/sg_execution_times.doctree b/latest/.doctrees/examples/lode-linear/sg_execution_times.doctree new file mode 100644 index 00000000..bd26f8b6 Binary files /dev/null and b/latest/.doctrees/examples/lode-linear/sg_execution_times.doctree differ diff --git a/latest/.doctrees/examples/lpr/lpr.doctree b/latest/.doctrees/examples/lpr/lpr.doctree new file mode 100644 index 00000000..c6097149 Binary files /dev/null and b/latest/.doctrees/examples/lpr/lpr.doctree differ diff --git a/latest/.doctrees/examples/lpr/sg_execution_times.doctree b/latest/.doctrees/examples/lpr/sg_execution_times.doctree new file mode 100644 index 00000000..a6b776b1 Binary files /dev/null and b/latest/.doctrees/examples/lpr/sg_execution_times.doctree differ diff --git a/latest/.doctrees/examples/path-integrals/path-integrals.doctree b/latest/.doctrees/examples/path-integrals/path-integrals.doctree new file mode 100644 index 00000000..42dbf02c Binary files /dev/null and b/latest/.doctrees/examples/path-integrals/path-integrals.doctree differ diff --git a/latest/.doctrees/examples/path-integrals/sg_execution_times.doctree b/latest/.doctrees/examples/path-integrals/sg_execution_times.doctree new file mode 100644 index 00000000..c1db948a Binary files /dev/null and b/latest/.doctrees/examples/path-integrals/sg_execution_times.doctree differ diff --git a/latest/.doctrees/examples/roy-gch/roy-gch.doctree b/latest/.doctrees/examples/roy-gch/roy-gch.doctree new file mode 100644 index 00000000..f7732761 Binary files /dev/null and b/latest/.doctrees/examples/roy-gch/roy-gch.doctree differ diff --git a/latest/.doctrees/examples/roy-gch/sg_execution_times.doctree b/latest/.doctrees/examples/roy-gch/sg_execution_times.doctree new file mode 100644 index 00000000..5634dddc Binary files /dev/null and b/latest/.doctrees/examples/roy-gch/sg_execution_times.doctree differ diff --git a/latest/.doctrees/examples/sample-selection/sample-selection.doctree b/latest/.doctrees/examples/sample-selection/sample-selection.doctree new file mode 100644 index 00000000..4ec14719 Binary files /dev/null and b/latest/.doctrees/examples/sample-selection/sample-selection.doctree differ diff --git a/latest/.doctrees/examples/sample-selection/sg_execution_times.doctree b/latest/.doctrees/examples/sample-selection/sg_execution_times.doctree new file mode 100644 index 00000000..8e0115ac Binary files /dev/null and b/latest/.doctrees/examples/sample-selection/sg_execution_times.doctree differ diff --git a/latest/.doctrees/index.doctree b/latest/.doctrees/index.doctree new file mode 100644 index 00000000..45ba0a4a Binary files /dev/null and b/latest/.doctrees/index.doctree differ diff --git a/latest/_downloads/3237a57d8246eaec10a69b4e251f623d/environment.yml b/latest/_downloads/3237a57d8246eaec10a69b4e251f623d/environment.yml new file mode 100644 index 00000000..fafbc008 --- /dev/null +++ b/latest/_downloads/3237a57d8246eaec10a69b4e251f623d/environment.yml @@ -0,0 +1,8 @@ +channels: + - conda-forge +dependencies: + - python=3.11 + - pip + - pip: + - ase + - matplotlib diff --git a/latest/_downloads/328f2a3eeccb4e902f81e5646c33e2e8/environment.yml b/latest/_downloads/328f2a3eeccb4e902f81e5646c33e2e8/environment.yml new file mode 100644 index 00000000..48eabd61 --- /dev/null +++ b/latest/_downloads/328f2a3eeccb4e902f81e5646c33e2e8/environment.yml @@ -0,0 +1,14 @@ +channels: + - conda-forge +dependencies: + - python=3.11 + - pip + - rust >=1.65 + - pip: + - ase + - chemiscope + - matplotlib + - metatensor + - rascaline @ git+https://github.com/Luthaf/rascaline@ca957642f512e141c7570e987aadc05c7ac71983 + - skmatter + - equisolve @ git+https://github.com/lab-cosmo/equisolve.git@c858bedef4b2799eb445e4c92535ee387224089a diff --git a/latest/_downloads/372c6744f93b866ccf802a12006619bb/roy-gch.py b/latest/_downloads/372c6744f93b866ccf802a12006619bb/roy-gch.py new file mode 100644 index 00000000..13ba591b --- /dev/null +++ b/latest/_downloads/372c6744f93b866ccf802a12006619bb/roy-gch.py @@ -0,0 +1,294 @@ +""" +Generalized Convex Hull construction for the polymorphs of ROY +============================================================== + +:Authors: Michele Ceriotti `@ceriottm `_ + +This notebook analyzes the structures of 264 polymorphs of ROY, from +`Beran et Al, Chemical Science +(2022) `__, comparing the +conventional density-energy convex hull with a Generalized Convex Hull +(GCH) analysis (see `Anelli et al., Phys. Rev. Materials +(2018) `__). +It uses features computed with `rascaline `__ +and uses the directional convex hull function from +`scikit-matter `__ +to make the figure. +""" + +import chemiscope +import matplotlib.tri +import numpy as np +from matplotlib import pyplot as plt +from metatensor import mean_over_samples +from rascaline import SoapPowerSpectrum +from sklearn.decomposition import PCA +from skmatter.datasets import load_roy_dataset +from skmatter.sample_selection import DirectionalConvexHull + + +# %% +# Loads the structures (that also contain properties in the ``info`` field) + +roy_data = load_roy_dataset() + +structures = roy_data["structures"] + +density = np.array([s.info["density"] for s in structures]) +energy = np.array([s.info["energy"] for s in structures]) +structype = np.array([s.info["type"] for s in structures]) +iknown = np.where(structype == "known")[0] +iothers = np.where(structype != "known")[0] + + +# %% +# Energy-density hull +# ------------------- +# +# The Directional Convex Hull routines can be used to compute a +# conventional density-energy hull + +dch_builder = DirectionalConvexHull(low_dim_idx=[0]) +dch_builder.fit(density.reshape(-1, 1), energy) + +# %% +# We can get the indices of the selection, and compute the distance from +# the hull + +sel = dch_builder.selected_idx_ +dch_dist = dch_builder.score_samples(density.reshape(-1, 1), energy) + + +# %% +# +# Hull energies +# ^^^^^^^^^^^^^ +# +# Structures on the hull are stable with respect to synthesis at constant +# molar volume. Any other structure would lower the energy by decomposing +# into a mixture of the two nearest structures along the hull. Given that +# the lattice energy is an imperfect proxy for the free energy, and that +# synthesis can be performed in other ways than by fixing the density, +# structures that are not exactly on the hull might also be stable. One +# can compute a “hull energy” as an indication of how close these +# structures are to being stable. + +fig, ax = plt.subplots(1, 1, figsize=(6, 4)) +ax.scatter(density, energy, c=dch_dist, marker=".") +ssel = sel[np.argsort(density[sel])] +ax.plot(density[ssel], energy[ssel], "k--") +ax.set_xlabel("density / g/cm$^3$") +ax.set_ylabel("energy / kJ/mol") + +print( + f"Mean hull energy for 'known' stable structures {dch_dist[iknown].mean()} kJ/mol" +) +print(f"Mean hull energy for 'other' structures {dch_dist[iothers].mean()} kJ/mol") + + +# %% +# Interactive visualization +# ^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# You can also visualize the hull with ``chemiscope``. +# This runs only in a notebook, and +# requires having the ``chemiscope`` package installed. +# + +cs = chemiscope.show( + structures, + dict( + energy=energy, + density=density, + hull_energy=dch_dist, + structure_type=structype, + ), + settings={ + "map": { + "x": {"property": "density"}, + "y": {"property": "energy"}, + "color": {"property": "hull_energy"}, + "symbol": "structure_type", + "size": {"factor": 35}, + }, + "structure": [{"unitCell": True, "supercell": {"0": 2, "1": 2, "2": 2}}], + }, +) + + +if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) +else: + cs.save("roy_ch.json.gz") + +# %% +# Generalized Convex Hull +# ----------------------- +# +# A GCH is a similar construction, in which generic structural descriptors +# are used in lieu of composition, density or other thermodynamic +# constraints. The idea is that configurations that are found close to the +# GCH are locally stable with respect to structurally-similar +# configurations. In other terms, one can hope to find a thermodynamic +# constraint (i.e. synthesis conditions) that act differently on these +# structures in comparison with the others, and may potentially stabilize +# them. +# + + +# %% +# Compute structural descriptors +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# A first step is to computes suitable ML descriptors. Here we have used +# ``rascaline`` to evaluate average SOAP features for the structures. +# If you don't want to install these dependencies for this example you +# can also use the pre-computed features, but you can use this as a stub +# to apply this analysis to other chemical systems + +hypers = { + "cutoff": 4, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.7, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + "radial_basis": {"Gto": {"accuracy": 1e-6}}, + "center_atom_weight": 1.0, +} +calculator = SoapPowerSpectrum(**hypers) +rho2i = calculator.compute(structures) +rho2i = rho2i.keys_to_samples(["species_center"]).keys_to_properties( + ["species_neighbor_1", "species_neighbor_2"] +) +rho2i_structure = mean_over_samples(rho2i, sample_names=["center", "species_center"]) +np.savez("roy_features.npz", feats=rho2i_structure.block(0).values) + + +# features = roy_data["features"] +features = rho2i_structure.block(0).values + + +# %% +# PCA projection +# ^^^^^^^^^^^^^^ +# +# Computes PCA projection to generate low-dimensional descriptors that +# reflect structural diversity. Any other dimensionality reduction scheme +# could be used in a similar fashion. + +pca = PCA(n_components=4) +pca_features = pca.fit_transform(features) + +fig, ax = plt.subplots(1, 1, figsize=(6, 4)) +scatter = ax.scatter(pca_features[:, 0], pca_features[:, 1], c=energy) +ax.set_xlabel("PCA[1]") +ax.set_ylabel("PCA[2]") +cbar = fig.colorbar(scatter, ax=ax) +cbar.set_label("energy / kJ/mol") + + +# %% +# Builds the Generalized Convex Hull +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Builds a convex hull on the first two PCA features + +dch_builder = DirectionalConvexHull(low_dim_idx=[0, 1]) +dch_builder.fit(pca_features, energy) +sel = dch_builder.selected_idx_ +dch_dist = dch_builder.score_samples(pca_features, energy) + + +# %% +# Generates a 3D Plot +# + +triang = matplotlib.tri.Triangulation(pca_features[sel, 0], pca_features[sel, 1]) +fig = plt.figure(figsize=(7, 5), tight_layout=True) +ax = fig.add_subplot(projection="3d") +ax.plot_trisurf(triang, energy[sel], color="gray") +ax.scatter(pca_features[:, 0], pca_features[:, 1], energy, c=dch_dist) +ax.set_xlabel("PCA[1]") +ax.set_ylabel("PCA[2]") +ax.set_zlabel("energy / kJ/mol\n \n", labelpad=11) +ax.view_init(25, 110) + + +# %% +# The GCH construction improves the separation between the hull energies +# of “known” and hypothetical polymorphs (compare with the density-energy +# values above) + +print( + f"Mean hull energy for 'known' stable structures {dch_dist[iknown].mean()} kJ/mol" +) +print(f"Mean hull energy for 'other' structures {dch_dist[iothers].mean()} kJ/mol") + + +# %% +# Visualize in ``chemiscope``. This runs only in a notebook, and +# requires having the ``chemiscope`` package installed. + +for i, f in enumerate(structures): + for j in range(len(pca_features[i])): + f.info["pca_" + str(j + 1)] = pca_features[i, j] +structure_properties = chemiscope.extract_properties(structures) +structure_properties.update({"per_atom_energy": energy, "hull_energy": dch_dist}) + +# shows chemiscope if not run in terminal + +cs = chemiscope.show( + frames=structures, + properties=structure_properties, + meta={ + "name": "GCH for ROY polymorphs", + "description": """ +Demonstration of the Generalized Convex Hull construction for +polymorphs of the ROY molecule. Molecules that are closest to +the hull built on PCA-based structural descriptors and having the +internal energy predicted by electronic-structure calculations as +the z axis are the most thermodynamically stable. Indeed most of the +known polymorphs of ROY are on (or very close) to this hull. +""", + "authors": ["Michele Ceriotti "], + "references": [ + 'A. Anelli, E. A. Engel, C. J. Pickard, and M. Ceriotti, \ + "Generalized convex hull construction for materials discovery," \ + Physical Review Materials 2(10), 103804 (2018).', + 'G. J. O. Beran, I. J. Sugden, C. Greenwell, D. H. Bowskill, \ + C. C. Pantelides, and C. S. Adjiman, "How many more polymorphs of \ + ROY remain undiscovered," Chem. Sci. 13(5), 1288–1297 (2022).', + ], + }, + settings={ + "map": { + "x": {"property": "pca_1"}, + "y": {"property": "pca_2"}, + "z": {"property": "energy"}, + "symbol": "type", + "color": {"property": "hull_energy"}, + "size": { + "factor": 35, + "mode": "linear", + "property": "", + "reverse": True, + }, + }, + "structure": [ + { + "bonds": True, + "unitCell": True, + "keepOrientation": True, + } + ], + }, +) + +if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) +else: + cs.save("roy_gch.json.gz") diff --git a/latest/_downloads/4cc6d7251cc20e13dd91e533c7271a6a/charge-charge.xyz b/latest/_downloads/4cc6d7251cc20e13dd91e533c7271a6a/charge-charge.xyz new file mode 100644 index 00000000..a988fbef --- /dev/null +++ b/latest/_downloads/4cc6d7251cc20e13dd91e533c7271a6a/charge-charge.xyz @@ -0,0 +1,2834 @@ +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13961.0350892859 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=5.690705127008064 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.69902091 -0.75330680 0.65287932 +C -23.86700000 -15.59000000 -25.01000000 0.54022160 0.53450759 2.35559299 +C -22.00600000 -15.99600000 -27.05600000 -0.00837973 1.27218157 0.31933751 +N -22.00900000 -14.81000000 -26.46800000 -0.50291940 -0.34870639 -0.02343831 +N -22.97400000 -16.87300000 -26.85700000 -0.57339954 -1.76724206 -1.26909466 +N -21.03500000 -16.32600000 -27.87900000 1.83030176 -0.47050530 -1.21950425 +H -23.65000000 -13.61700000 -25.89000000 0.06849366 0.32652106 0.12670392 +H -22.47300000 -13.98600000 -24.61600000 -0.10233027 0.49301737 0.10937452 +H -23.24100000 -16.45200000 -24.76000000 -0.01467466 -0.39767784 -1.07630033 +H -24.75600000 -15.73900000 -25.63000000 -0.11033169 -0.31861290 0.30138773 +H -21.30800000 -14.13600000 -26.74300000 0.10855604 0.19049848 0.00342126 +H -23.91000000 -16.51500000 -26.79400000 -0.22091234 -0.23467575 0.19009341 +H -22.88300000 -17.78900000 -27.27300000 0.01703936 -0.08269867 -0.25912284 +H -20.27200000 -15.69400000 -28.06100000 0.31374409 -0.01402229 0.04784428 +H -20.98400000 -17.25100000 -28.27500000 0.03445105 -0.04352040 -0.18461387 +H -24.16288000 -15.59000000 -23.95054000 -0.77852330 1.71978297 -0.03157711 +C -22.52196163 -10.66596984 -22.58440081 0.67844879 0.45513050 0.69215040 +C -23.75496163 -11.32196984 -23.10140081 -1.41995788 0.36313342 0.41516871 +O -23.59396163 -12.32196984 -23.84240081 0.39560261 -1.34439497 -0.95728857 +O -24.85896163 -10.80696984 -22.79340081 -0.21273266 0.08620314 0.02113320 +H -22.77396163 -9.97896984 -21.77140081 0.06436973 0.13775077 0.08472735 +H -22.12296163 -10.08296984 -23.41640081 0.46007946 0.12838107 -0.09540760 +H -21.78879163 -11.39985984 -22.21854081 0.13187423 0.06825543 -0.20346705 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.96607249 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=5.938169769300996 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.71626918 -0.62875277 0.74237584 +C -23.86700000 -15.59000000 -25.01000000 0.52146335 0.54145183 2.37445557 +C -22.00600000 -15.99600000 -27.05600000 0.00393734 1.11123760 0.32053830 +N -22.00900000 -14.81000000 -26.46800000 -0.49389956 -0.15183579 0.05331357 +N -22.97400000 -16.87300000 -26.85700000 -0.58367599 -1.76230288 -1.24239030 +N -21.03500000 -16.32600000 -27.87900000 1.82846171 -0.44531577 -1.21831345 +H -23.65000000 -13.61700000 -25.89000000 0.03729579 0.33371354 0.09958739 +H -22.47300000 -13.98600000 -24.61600000 -0.07541075 0.46959704 0.14304573 +H -23.24100000 -16.45200000 -24.76000000 -0.01656850 -0.38322802 -1.08039145 +H -24.75600000 -15.73900000 -25.63000000 -0.09568127 -0.31448025 0.29896098 +H -21.30800000 -14.13600000 -26.74300000 0.10666562 0.19232739 -0.00310737 +H -23.91000000 -16.51500000 -26.79400000 -0.24997072 -0.23959417 0.15674722 +H -22.88300000 -17.78900000 -27.27300000 0.01486768 -0.08399832 -0.26191257 +H -20.27200000 -15.69400000 -28.06100000 0.31981202 -0.00432644 0.03592510 +H -20.98400000 -17.25100000 -28.27500000 0.02957950 -0.03933131 -0.18534281 +H -24.16288000 -15.59000000 -23.95054000 -0.77958345 1.71121348 -0.02134425 +C -22.53898081 -10.46498492 -22.43670041 0.66644017 0.46625930 0.69552265 +C -23.77198081 -11.12098492 -22.95370041 -1.21986379 0.20100662 0.28916554 +O -23.61098081 -12.12098492 -23.69470041 0.36676191 -1.43014162 -1.03444633 +O -24.87598081 -10.60598492 -22.64570041 -0.30788599 0.11486968 0.04462620 +H -22.79098081 -9.77798492 -21.62370041 0.06685115 0.14662875 0.09341913 +H -22.13998081 -9.88198492 -23.26870041 0.45616763 0.12659108 -0.09362564 +H -21.80581081 -11.19887492 -22.07084041 0.12050533 0.06841100 -0.20680905 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.8603277197 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=6.1858383159671995 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.70547678 -0.58427283 0.76671805 +C -23.86700000 -15.59000000 -25.01000000 0.50693550 0.54781072 2.38910848 +C -22.00600000 -15.99600000 -27.05600000 0.02060908 0.97210181 0.32119482 +N -22.00900000 -14.81000000 -26.46800000 -0.48832579 0.00467286 0.11241690 +N -22.97400000 -16.87300000 -26.85700000 -0.59347735 -1.75953655 -1.21571875 +N -21.03500000 -16.32600000 -27.87900000 1.83002452 -0.42569276 -1.22144544 +H -23.65000000 -13.61700000 -25.89000000 0.01697074 0.32672377 0.06652661 +H -22.47300000 -13.98600000 -24.61600000 -0.04178485 0.42205364 0.14926218 +H -23.24100000 -16.45200000 -24.76000000 -0.01743056 -0.37181913 -1.08460068 +H -24.75600000 -15.73900000 -25.63000000 -0.08491410 -0.31186775 0.29600139 +H -21.30800000 -14.13600000 -26.74300000 0.10464933 0.19244052 -0.00945134 +H -23.91000000 -16.51500000 -26.79400000 -0.27822575 -0.24340234 0.12529564 +H -22.88300000 -17.78900000 -27.27300000 0.01291253 -0.08520727 -0.26480484 +H -20.27200000 -15.69400000 -28.06100000 0.32532711 0.00475613 0.02483899 +H -20.98400000 -17.25100000 -28.27500000 0.02564346 -0.03771626 -0.18724774 +H -24.16288000 -15.59000000 -23.95054000 -0.78078009 1.70101486 -0.01218748 +C -22.55600000 -10.26400000 -22.28900000 0.65505122 0.47353723 0.69573435 +C -23.78900000 -10.92000000 -22.80600000 -1.06277215 0.08294978 0.19952989 +O -23.62800000 -11.92000000 -23.54700000 0.30723446 -1.39073858 -1.01161090 +O -24.89300000 -10.40500000 -22.49800000 -0.38491795 0.13597450 0.06185559 +H -22.80800000 -9.57700000 -21.47600000 0.06827835 0.15314491 0.10013787 +H -22.15700000 -9.68100000 -23.12100000 0.45285394 0.12505242 -0.09226530 +H -21.82283000 -10.99789000 -21.92314000 0.11161512 0.06802031 -0.20928827 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.7507448301 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=6.433687211666039 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.68476151 -0.57599922 0.76274801 +C -23.86700000 -15.59000000 -25.01000000 0.49548813 0.55399478 2.40090980 +C -22.00600000 -15.99600000 -27.05600000 0.03752905 0.85183262 0.32181887 +N -22.00900000 -14.81000000 -26.46800000 -0.48521588 0.13398972 0.16123563 +N -22.97400000 -16.87300000 -26.85700000 -0.60253400 -1.75854863 -1.19052420 +N -21.03500000 -16.32600000 -27.87900000 1.83456967 -0.41031061 -1.22799791 +H -23.65000000 -13.61700000 -25.89000000 0.00228684 0.31623853 0.03643256 +H -22.47300000 -13.98600000 -24.61600000 -0.01218289 0.37379521 0.14584601 +H -23.24100000 -16.45200000 -24.76000000 -0.01777484 -0.36280174 -1.08865745 +H -24.75600000 -15.73900000 -25.63000000 -0.07682597 -0.31032845 0.29286134 +H -21.30800000 -14.13600000 -26.74300000 0.10226063 0.19134244 -0.01534518 +H -23.91000000 -16.51500000 -26.79400000 -0.30474037 -0.24637973 0.09631972 +H -22.88300000 -17.78900000 -27.27300000 0.01111682 -0.08590484 -0.26726353 +H -20.27200000 -15.69400000 -28.06100000 0.32974542 0.01252088 0.01483242 +H -20.98400000 -17.25100000 -28.27500000 0.02262799 -0.03694988 -0.18907464 +H -24.16288000 -15.59000000 -23.95054000 -0.78186517 1.69074235 -0.00420570 +C -22.57301919 -10.06301508 -22.14129959 0.64497964 0.47721485 0.69335910 +C -23.80601919 -10.71901508 -22.65829959 -0.93707216 0.00010578 0.13817158 +O -23.64501919 -11.71901508 -23.39929959 0.24524802 -1.31252213 -0.95695555 +O -24.91001919 -10.20401508 -22.35029959 -0.44663559 0.14899386 0.07242799 +H -22.82501919 -9.37601508 -21.32829959 0.06851378 0.15778750 0.10536343 +H -22.17401919 -9.48001508 -22.97329959 0.45024377 0.12384684 -0.09123206 +H -21.83984919 -10.79690508 -21.77543959 0.10499860 0.06733986 -0.21107026 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.6493933514 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=6.681696379133143 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.66195394 -0.58328058 0.74742585 +C -23.86700000 -15.59000000 -25.01000000 0.48640282 0.55997206 2.41067572 +C -22.00600000 -15.99600000 -27.05600000 0.05305687 0.74839629 0.32225233 +N -22.00900000 -14.81000000 -26.46800000 -0.48364856 0.24241464 0.20269700 +N -22.97400000 -16.87300000 -26.85700000 -0.61033992 -1.75857087 -1.16740477 +N -21.03500000 -16.32600000 -27.87900000 1.84059345 -0.39801217 -1.23603199 +H -23.65000000 -13.61700000 -25.89000000 -0.00921016 0.30621217 0.01130738 +H -22.47300000 -13.98600000 -24.61600000 0.01163295 0.33201812 0.14013720 +H -23.24100000 -16.45200000 -24.76000000 -0.01784286 -0.35569530 -1.09244773 +H -24.75600000 -15.73900000 -25.63000000 -0.07067116 -0.30952773 0.28969258 +H -21.30800000 -14.13600000 -26.74300000 0.09981870 0.18971171 -0.02069580 +H -23.91000000 -16.51500000 -26.79400000 -0.32916115 -0.24869515 0.07029520 +H -22.88300000 -17.78900000 -27.27300000 0.00946701 -0.08631773 -0.26930136 +H -20.27200000 -15.69400000 -28.06100000 0.33331702 0.01902783 0.00595183 +H -20.98400000 -17.25100000 -28.27500000 0.02038113 -0.03658373 -0.19064609 +H -24.16288000 -15.59000000 -23.95054000 -0.78278831 1.68110543 0.00266012 +C -22.59003837 -9.86203016 -21.99359919 0.63656811 0.47819749 0.68947325 +C -23.82303837 -10.51803016 -22.51059919 -0.83607798 -0.05719009 0.09676844 +O -23.66203837 -11.51803016 -23.25159919 0.18986082 -1.22938460 -0.89722547 +O -24.92703837 -10.00303016 -22.20259919 -0.49557835 0.15572437 0.07793578 +H -22.84203837 -9.17503016 -21.18059919 0.06784851 0.16096417 0.10933931 +H -22.19103837 -9.27903016 -22.82559919 0.44822726 0.12284057 -0.09041154 +H -21.85686837 -10.59592016 -21.62773919 0.10009773 0.06667311 -0.21244724 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.5595813796 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=6.929848617797843 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.64008304 -0.59620009 0.72920693 +C -23.86700000 -15.59000000 -25.01000000 0.47932023 0.56581458 2.41903695 +C -22.00600000 -15.99600000 -27.05600000 0.06668602 0.65841712 0.32269886 +N -22.00900000 -14.81000000 -26.46800000 -0.48235712 0.33513921 0.23830875 +N -22.97400000 -16.87300000 -26.85700000 -0.61660321 -1.75910056 -1.14626097 +N -21.03500000 -16.32600000 -27.87900000 1.84742471 -0.38787908 -1.24481239 +H -23.65000000 -13.61700000 -25.89000000 -0.01864106 0.29776901 -0.00906174 +H -22.47300000 -13.98600000 -24.61600000 0.02998949 0.29732975 0.13412940 +H -23.24100000 -16.45200000 -24.76000000 -0.01776794 -0.35001365 -1.09589830 +H -24.75600000 -15.73900000 -25.63000000 -0.06596081 -0.30931833 0.28642907 +H -21.30800000 -14.13600000 -26.74300000 0.09732741 0.18757829 -0.02535566 +H -23.91000000 -16.51500000 -26.79400000 -0.35184487 -0.25049123 0.04696045 +H -22.88300000 -17.78900000 -27.27300000 0.00794878 -0.08650499 -0.27095000 +H -20.27200000 -15.69400000 -28.06100000 0.33618957 0.02449654 -0.00196501 +H -20.98400000 -17.25100000 -28.27500000 0.01860219 -0.03637924 -0.19202150 +H -24.16288000 -15.59000000 -23.95054000 -0.78355704 1.67240161 0.00850732 +C -22.60705756 -9.66104525 -21.84589878 0.62949184 0.47750625 0.68479653 +C -23.84005756 -10.31704525 -22.36289878 -0.75317229 -0.09732489 0.06855334 +O -23.67905756 -11.31704525 -23.10389878 0.14236631 -1.15285980 -0.84167504 +O -24.94405756 -9.80204525 -22.05489878 -0.53502529 0.15838894 0.08023232 +H -22.85905756 -8.97404525 -21.03289878 0.06663558 0.16316133 0.11241672 +H -22.20805756 -9.07804525 -22.67789878 0.44665845 0.12197991 -0.08975935 +H -21.87388756 -10.39493525 -21.48003878 0.09637208 0.06608934 -0.21351668 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.481386365 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=7.17812909420908 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.62017865 -0.61009750 0.71230305 +C -23.86700000 -15.59000000 -25.01000000 0.47399619 0.57157018 2.42629536 +C -22.00600000 -15.99600000 -27.05600000 0.07823437 0.57906109 0.32309125 +N -22.00900000 -14.81000000 -26.46800000 -0.48028528 0.41602952 0.26923682 +N -22.97400000 -16.87300000 -26.85700000 -0.62115639 -1.75981053 -1.12676156 +N -21.03500000 -16.32600000 -27.87900000 1.85464139 -0.37919095 -1.25387685 +H -23.65000000 -13.61700000 -25.89000000 -0.02673980 0.29105364 -0.02547279 +H -22.47300000 -13.98600000 -24.61600000 0.04356398 0.26868861 0.12800013 +H -23.24100000 -16.45200000 -24.76000000 -0.01761369 -0.34546262 -1.09905935 +H -24.75600000 -15.73900000 -25.63000000 -0.06237400 -0.30959899 0.28305932 +H -21.30800000 -14.13600000 -26.74300000 0.09474106 0.18486830 -0.02925328 +H -23.91000000 -16.51500000 -26.79400000 -0.37321448 -0.25191997 0.02595313 +H -22.88300000 -17.78900000 -27.27300000 0.00654285 -0.08654616 -0.27225052 +H -20.27200000 -15.69400000 -28.06100000 0.33852216 0.02913080 -0.00909490 +H -20.98400000 -17.25100000 -28.27500000 0.01706885 -0.03630397 -0.19335016 +H -24.16288000 -15.59000000 -23.95054000 -0.78425421 1.66472578 0.01353677 +C -22.62407675 -9.46006033 -21.69819838 0.62353674 0.47574605 0.67979094 +C -23.85707675 -10.11606033 -22.21519837 -0.68421115 -0.12574346 0.04908345 +O -23.69607675 -11.11606033 -22.95619837 0.10254849 -1.08616333 -0.79300852 +O -24.96107675 -9.60106033 -21.90719838 -0.56734209 0.15844511 0.08051510 +H -22.87607675 -8.77306033 -20.88519838 0.06509633 0.16465624 0.11480690 +H -22.22507675 -8.87706033 -22.53019838 0.44539130 0.12122287 -0.08921919 +H -21.89090675 -10.19395033 -21.33233837 0.09348603 0.06563930 -0.21432509 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.4138280991 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=7.426524940834331 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.60222955 -0.62327841 0.69662702 +C -23.86700000 -15.59000000 -25.01000000 0.46981137 0.57696393 2.43272206 +C -22.00600000 -15.99600000 -27.05600000 0.08825387 0.50999638 0.32350356 +N -22.00900000 -14.81000000 -26.46800000 -0.47873745 0.48591354 0.29656668 +N -22.97400000 -16.87300000 -26.85700000 -0.62490013 -1.76071942 -1.10914518 +N -21.03500000 -16.32600000 -27.87900000 1.86185284 -0.37204672 -1.26264824 +H -23.65000000 -13.61700000 -25.89000000 -0.03379493 0.28589148 -0.03846988 +H -22.47300000 -13.98600000 -24.61600000 0.05380654 0.24584240 0.12287815 +H -23.24100000 -16.45200000 -24.76000000 -0.01748063 -0.34180168 -1.10196073 +H -24.75600000 -15.73900000 -25.63000000 -0.05949445 -0.31010511 0.27988215 +H -21.30800000 -14.13600000 -26.74300000 0.09233792 0.18226022 -0.03278756 +H -23.91000000 -16.51500000 -26.79400000 -0.39262716 -0.25301586 0.00723835 +H -22.88300000 -17.78900000 -27.27300000 0.00525947 -0.08653037 -0.27338994 +H -20.27200000 -15.69400000 -28.06100000 0.34046252 0.03311969 -0.01544643 +H -20.98400000 -17.25100000 -28.27500000 0.01582744 -0.03623806 -0.19451013 +H -24.16288000 -15.59000000 -23.95054000 -0.78480075 1.65803809 0.01791924 +C -22.64109593 -9.25907541 -21.55049797 0.61865057 0.47309260 0.67466794 +C -23.87409593 -9.91507541 -22.06749797 -0.62707783 -0.14472566 0.03663413 +O -23.71309593 -10.91507541 -22.80849797 0.06937417 -1.03056292 -0.75229081 +O -24.97809593 -9.40007541 -21.75949797 -0.59353357 0.15648274 0.07909394 +H -22.89309593 -8.57207541 -20.73749797 0.06337223 0.16555420 0.11664152 +H -22.24209593 -8.67607541 -22.38249797 0.44440124 0.12051808 -0.08875259 +H -21.90792593 -9.99296541 -21.18463797 0.09126629 0.06535088 -0.21497325 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.3555221732 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=7.675024962343216 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.58598204 -0.63537898 0.68129553 +C -23.86700000 -15.59000000 -25.01000000 0.46623023 0.58163875 2.43816496 +C -22.00600000 -15.99600000 -27.05600000 0.09755859 0.45064052 0.32445514 +N -22.00900000 -14.81000000 -26.46800000 -0.47897342 0.54555830 0.32110623 +N -22.97400000 -16.87300000 -26.85700000 -0.62869232 -1.76184832 -1.09366922 +N -21.03500000 -16.32600000 -27.87900000 1.86875150 -0.36653748 -1.27090824 +H -23.65000000 -13.61700000 -25.89000000 -0.03986340 0.28191972 -0.04859707 +H -22.47300000 -13.98600000 -24.61600000 0.06198432 0.22825553 0.11952419 +H -23.24100000 -16.45200000 -24.76000000 -0.01742389 -0.33887194 -1.10465863 +H -24.75600000 -15.73900000 -25.63000000 -0.05703351 -0.31062899 0.27713125 +H -21.30800000 -14.13600000 -26.74300000 0.09034559 0.18029627 -0.03637560 +H -23.91000000 -16.51500000 -26.79400000 -0.40965322 -0.25377779 -0.00928174 +H -22.88300000 -17.78900000 -27.27300000 0.00412883 -0.08646444 -0.27446931 +H -20.27200000 -15.69400000 -28.06100000 0.34208903 0.03667262 -0.02101609 +H -20.98400000 -17.25100000 -28.27500000 0.01490253 -0.03603347 -0.19533711 +H -24.16288000 -15.59000000 -23.95054000 -0.78517651 1.65227676 0.02186449 +C -22.65811512 -9.05809049 -21.40279756 0.61463604 0.46999669 0.66962347 +C -23.89111512 -9.71409049 -21.91979756 -0.57867033 -0.15631088 0.02986932 +O -23.73011512 -10.71409049 -22.66079756 0.04105244 -0.98548362 -0.71918575 +O -24.99511512 -9.19909049 -21.61179756 -0.61481587 0.15295411 0.07627671 +H -22.91011512 -8.37109049 -20.58979756 0.06150334 0.16607312 0.11807822 +H -22.25911512 -8.47509049 -22.23479756 0.44359667 0.11987176 -0.08837101 +H -21.92494512 -9.79198049 -21.03693756 0.08950541 0.06518177 -0.21551974 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.3049514433 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=7.923619347117433 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.57138678 -0.64639787 0.66621438 +C -23.86700000 -15.59000000 -25.01000000 0.46307460 0.58567496 2.44289863 +C -22.00600000 -15.99600000 -27.05600000 0.10647737 0.40001414 0.32584042 +N -22.00900000 -14.81000000 -26.46800000 -0.48105578 0.59579812 0.34296525 +N -22.97400000 -16.87300000 -26.85700000 -0.63248693 -1.76288834 -1.08027952 +N -21.03500000 -16.32600000 -27.87900000 1.87477776 -0.36233754 -1.27807537 +H -23.65000000 -13.61700000 -25.89000000 -0.04506127 0.27891177 -0.05644408 +H -22.47300000 -13.98600000 -24.61600000 0.06882184 0.21494426 0.11789997 +H -23.24100000 -16.45200000 -24.76000000 -0.01745173 -0.33652491 -1.10715766 +H -24.75600000 -15.73900000 -25.63000000 -0.05488625 -0.31110280 0.27482686 +H -21.30800000 -14.13600000 -26.74300000 0.08893635 0.17918301 -0.04005838 +H -23.91000000 -16.51500000 -26.79400000 -0.42438994 -0.25420285 -0.02367633 +H -22.88300000 -17.78900000 -27.27300000 0.00315301 -0.08648275 -0.27561592 +H -20.27200000 -15.69400000 -28.06100000 0.34360080 0.03998675 -0.02588091 +H -20.98400000 -17.25100000 -28.27500000 0.01420917 -0.03582350 -0.19596792 +H -24.16288000 -15.59000000 -23.95054000 -0.78538152 1.64736049 0.02548846 +C -22.67513431 -8.85710557 -21.25509716 0.61130087 0.46672057 0.66491409 +C -23.90813431 -9.51310557 -21.77209716 -0.53739031 -0.16288203 0.02684169 +O -23.74713431 -10.51310557 -22.51309716 0.01655816 -0.94912746 -0.69244703 +O -25.01213431 -8.99810557 -21.46409716 -0.63205298 0.14846400 0.07256879 +H -22.92713431 -8.17010557 -20.44209716 0.05966563 0.16633241 0.11920264 +H -22.27613431 -8.27410557 -22.08709716 0.44292695 0.11925481 -0.08803883 +H -21.94196431 -9.59099557 -20.88923716 0.08804098 0.06512478 -0.21601923 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.2606417846 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=8.172299487318071 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.55843067 -0.65628138 0.65167889 +C -23.86700000 -15.59000000 -25.01000000 0.46030499 0.58909421 2.44698443 +C -22.00600000 -15.99600000 -27.05600000 0.11512831 0.35646699 0.32772534 +N -22.00900000 -14.81000000 -26.46800000 -0.48454006 0.63830213 0.36238061 +N -22.97400000 -16.87300000 -26.85700000 -0.63622293 -1.76378992 -1.06871782 +N -21.03500000 -16.32600000 -27.87900000 1.87994711 -0.35916174 -1.28427551 +H -23.65000000 -13.61700000 -25.89000000 -0.04952912 0.27662451 -0.06255188 +H -22.47300000 -13.98600000 -24.61600000 0.07471526 0.20504050 0.11777345 +H -23.24100000 -16.45200000 -24.76000000 -0.01753986 -0.33463643 -1.10947963 +H -24.75600000 -15.73900000 -25.63000000 -0.05297433 -0.31154512 0.27285380 +H -21.30800000 -14.13600000 -26.74300000 0.08803113 0.17874660 -0.04381618 +H -23.91000000 -16.51500000 -26.79400000 -0.43722125 -0.25435837 -0.03627358 +H -22.88300000 -17.78900000 -27.27300000 0.00232740 -0.08657439 -0.27681572 +H -20.27200000 -15.69400000 -28.06100000 0.34502789 0.04312722 -0.03015474 +H -20.98400000 -17.25100000 -28.27500000 0.01367386 -0.03560975 -0.19643988 +H -24.16288000 -15.59000000 -23.95054000 -0.78545573 1.64317687 0.02880207 +C -22.69215350 -8.65612066 -21.10739675 0.60842442 0.46342708 0.66053496 +C -23.92515350 -9.31212066 -21.62439675 -0.50128231 -0.16607654 0.02628681 +O -23.76415350 -10.31212066 -22.36539675 -0.00515640 -0.91956843 -0.67069845 +O -25.02915350 -8.79712066 -21.31639675 -0.64628308 0.14338771 0.06833935 +H -22.94415350 -7.96912066 -20.29439675 0.05793303 0.16643937 0.12011776 +H -22.29315350 -8.07312066 -21.93939675 0.44235020 0.11866386 -0.08775864 +H -21.95898350 -9.39001066 -20.74153675 0.08677214 0.06510503 -0.21649541 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.2213962842 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=8.421057793623207 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.54693588 -0.66506306 0.63792631 +C -23.86700000 -15.59000000 -25.01000000 0.45785906 0.59203519 2.45053631 +C -22.00600000 -15.99600000 -27.05600000 0.12348087 0.31877257 0.32995114 +N -22.00900000 -14.81000000 -26.46800000 -0.48893428 0.67435420 0.37955969 +N -22.97400000 -16.87300000 -26.85700000 -0.63975809 -1.76448675 -1.05871776 +N -21.03500000 -16.32600000 -27.87900000 1.88424257 -0.35671815 -1.28951341 +H -23.65000000 -13.61700000 -25.89000000 -0.05334176 0.27478396 -0.06737561 +H -22.47300000 -13.98600000 -24.61600000 0.07986155 0.19760934 0.11863866 +H -23.24100000 -16.45200000 -24.76000000 -0.01767196 -0.33311125 -1.11162741 +H -24.75600000 -15.73900000 -25.63000000 -0.05129175 -0.31196296 0.27113235 +H -21.30800000 -14.13600000 -26.74300000 0.08755411 0.17886153 -0.04757566 +H -23.91000000 -16.51500000 -26.79400000 -0.44849779 -0.25431021 -0.04731553 +H -22.88300000 -17.78900000 -27.27300000 0.00163138 -0.08676074 -0.27806563 +H -20.27200000 -15.69400000 -28.06100000 0.34641564 0.04613908 -0.03392833 +H -20.98400000 -17.25100000 -28.27500000 0.01323905 -0.03544127 -0.19682850 +H -24.16288000 -15.59000000 -23.95054000 -0.78545213 1.63959371 0.03188073 +C -22.70917268 -8.45513574 -20.95969634 0.60587659 0.46026295 0.65651729 +C -23.94217268 -9.11113574 -21.47669634 -0.46922584 -0.16708173 0.02730668 +O -23.78117268 -10.11113574 -22.21769634 -0.02461664 -0.89517586 -0.65280536 +O -25.04617268 -8.59613574 -21.16869634 -0.65816630 0.13802219 0.06388094 +H -22.96117268 -7.76813574 -20.14669634 0.05630500 0.16645034 0.12087478 +H -22.31017268 -7.87213574 -21.79169634 0.44181528 0.11809898 -0.08750787 +H -21.97600268 -9.18902574 -20.59383634 0.08561133 0.06512794 -0.21694382 +23 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-13960.1863991973 label=CC chargeA=1 energyA=-7738.76386157005 chargeB=-1 energyB=-6220.47808514827 distance=8.66988752780838 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 -0.53673052 -0.67296236 0.62511120 +C -23.86700000 -15.59000000 -25.01000000 0.45573037 0.59458549 2.45372114 +C -22.00600000 -15.99600000 -27.05600000 0.13150622 0.28573323 0.33249909 +N -22.00900000 -14.81000000 -26.46800000 -0.49382060 0.70531780 0.39474295 +N -22.97400000 -16.87300000 -26.85700000 -0.64301524 -1.76496214 -1.04997970 +N -21.03500000 -16.32600000 -27.87900000 1.88783692 -0.35480473 -1.29400868 +H -23.65000000 -13.61700000 -25.89000000 -0.05666182 0.27334560 -0.07121152 +H -22.47300000 -13.98600000 -24.61600000 0.08436408 0.19184761 0.12004352 +H -23.24100000 -16.45200000 -24.76000000 -0.01782941 -0.33184931 -1.11361488 +H -24.75600000 -15.73900000 -25.63000000 -0.04979994 -0.31235824 0.26958918 +H -21.30800000 -14.13600000 -26.74300000 0.08738034 0.17932953 -0.05124162 +H -23.91000000 -16.51500000 -26.79400000 -0.45855222 -0.25407636 -0.05707936 +H -22.88300000 -17.78900000 -27.27300000 0.00104698 -0.08699287 -0.27932095 +H -20.27200000 -15.69400000 -28.06100000 0.34775153 0.04902795 -0.03729019 +H -20.98400000 -17.25100000 -28.27500000 0.01286436 -0.03529542 -0.19714973 +H -24.16288000 -15.59000000 -23.95054000 -0.78538928 1.63653120 0.03470286 +C -22.72619187 -8.25415082 -20.81199594 0.60353015 0.45725253 0.65280571 +C -23.95919187 -8.91015082 -21.32899594 -0.44028562 -0.16657505 0.02939262 +O -23.79819187 -9.91015082 -22.06999594 -0.04229297 -0.87479017 -0.63794649 +O -25.06319187 -8.39515082 -21.02099594 -0.66827740 0.13253483 0.05933952 +H -22.97819187 -7.56715082 -19.99899594 0.05479071 0.16641521 0.12152328 +H -22.32719187 -7.67115082 -21.64399594 0.44131444 0.11756688 -0.08727917 +H -21.99302187 -8.98804082 -20.44613594 0.08453894 0.06517880 -0.21734877 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.2536467192 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.757384076215318 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.46704201 -0.03983473 -0.24562320 +C -22.00600000 -15.99600000 -27.05600000 1.66391618 0.22064471 -1.54156675 +N -21.03500000 -16.32600000 -27.87900000 -0.63664611 0.78933999 -0.41746617 +N -22.00900000 -14.81000000 -26.46800000 -0.92009781 0.71643666 0.85550961 +N -22.97400000 -16.87300000 -26.85700000 -1.49956884 -1.23795130 0.81955374 +H -20.27200000 -15.69400000 -28.06100000 0.86940879 -0.29312383 0.34150156 +H -20.98400000 -17.25100000 -28.27500000 0.52504776 -0.23739517 0.03455365 +H -21.30800000 -14.13600000 -26.74300000 0.21333428 -0.00007333 0.03900492 +H -23.91000000 -16.51500000 -26.79400000 -0.42832907 -0.05632656 0.18398620 +H -22.88300000 -17.78900000 -27.27300000 0.00720252 -0.06895854 -0.06978714 +H -23.65000000 -13.61700000 -25.89000000 -0.27183123 0.16800967 -0.05271055 +H -22.47300000 -13.98600000 -24.61600000 -0.04260650 0.04239585 0.25431125 +H -23.61928000 -15.24549000 -25.14423000 0.23811495 0.13020756 -0.04203499 +C -16.70261563 -18.18981609 -27.33383433 0.87620755 -0.80061141 -0.07577325 +C -17.78861563 -17.17981609 -27.26383433 0.21318894 0.85632542 0.25474292 +O -18.97661563 -17.54281609 -27.25883433 -2.27086765 -2.08638034 -0.28552868 +O -17.47461563 -15.99081609 -27.17283433 1.06630481 2.45378448 -0.04069842 +H -16.76661563 -18.73181609 -28.28083433 0.00556479 -0.23604465 -0.16393823 +H -16.85661563 -18.90781609 -26.52683433 0.08395533 -0.32973933 0.13463769 +H -15.69915563 -17.74717609 -27.24931433 -0.15934070 0.00929485 0.01732586 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.1677077876 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.006824184225634 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.43459402 -0.03173257 -0.22774235 +C -22.00600000 -15.99600000 -27.05600000 1.49835516 0.25958179 -1.29451915 +N -21.03500000 -16.32600000 -27.87900000 -0.18717521 0.52843518 -0.38081269 +N -22.00900000 -14.81000000 -26.46800000 -0.91183757 0.61930150 0.77731645 +N -22.97400000 -16.87300000 -26.85700000 -1.41850674 -1.15378383 0.75038878 +H -20.27200000 -15.69400000 -28.06100000 0.89823352 -0.29221301 0.29907890 +H -20.98400000 -17.25100000 -28.27500000 0.52133713 -0.25459785 -0.00899593 +H -21.30800000 -14.13600000 -26.74300000 0.21577552 0.01551702 0.03570694 +H -23.91000000 -16.51500000 -26.79400000 -0.43871202 -0.05582822 0.20362604 +H -22.88300000 -17.78900000 -27.27300000 0.00061863 -0.08455770 -0.07419726 +H -23.65000000 -13.61700000 -25.89000000 -0.26262378 0.16254165 -0.05603738 +H -22.47300000 -13.98600000 -24.61600000 -0.03637901 0.03977624 0.24647374 +H -23.61928000 -15.24549000 -25.14423000 0.23946776 0.13125252 -0.04208502 +C -16.47380781 -18.28640804 -27.36241716 0.87627377 -0.81692989 -0.07414438 +C -17.55980781 -17.27640804 -27.29241716 0.05112542 0.94756008 0.24418272 +O -18.74780781 -17.63940804 -27.28741716 -2.57880759 -1.90639979 -0.36739250 +O -17.24580781 -16.08740804 -27.20141716 1.16233982 2.45323382 -0.01960352 +H -16.53780781 -18.82840804 -28.30941716 0.00616419 -0.23738196 -0.16645320 +H -16.62780781 -19.00440804 -26.55541716 0.08651762 -0.33337084 0.13703914 +H -15.47034781 -17.84376804 -27.27789716 -0.15676063 0.00959585 0.01817065 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.0140684553 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.256317487073673 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.41158763 -0.02468405 -0.21547798 +C -22.00600000 -15.99600000 -27.05600000 1.35062895 0.28656367 -1.09642632 +N -21.03500000 -16.32600000 -27.87900000 0.10613625 0.37195257 -0.40298376 +N -22.00900000 -14.81000000 -26.46800000 -0.89997220 0.56344393 0.72730295 +N -22.97400000 -16.87300000 -26.85700000 -1.35266404 -1.10133591 0.70012725 +H -20.27200000 -15.69400000 -28.06100000 0.88088158 -0.26483479 0.24977420 +H -20.98400000 -17.25100000 -28.27500000 0.48237148 -0.25272983 -0.05354677 +H -21.30800000 -14.13600000 -26.74300000 0.21253444 0.03101796 0.03137098 +H -23.91000000 -16.51500000 -26.79400000 -0.46009605 -0.05154162 0.21301411 +H -22.88300000 -17.78900000 -27.27300000 -0.00807123 -0.09671485 -0.07872654 +H -23.65000000 -13.61700000 -25.89000000 -0.25621082 0.15799530 -0.05757257 +H -22.47300000 -13.98600000 -24.61600000 -0.03152778 0.03933612 0.24259566 +H -23.61928000 -15.24549000 -25.14423000 0.24017265 0.13179811 -0.04285599 +C -16.24500000 -18.38300000 -27.39100000 0.87427010 -0.82974543 -0.07750313 +C -17.33100000 -17.37300000 -27.32100000 -0.05515903 0.98217868 0.24061288 +O -18.51900000 -17.73600000 -27.31600000 -2.65661035 -1.83634477 -0.36663795 +O -17.01700000 -16.18400000 -27.23000000 1.22001474 2.45621565 -0.00269790 +H -16.30900000 -18.92500000 -28.33800000 0.00717407 -0.23836723 -0.16838877 +H -16.39900000 -19.10100000 -26.58400000 0.08827673 -0.33523638 0.13920060 +H -15.24154000 -17.94036000 -27.30648000 -0.15373712 0.01103285 0.01881904 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.8432321992 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.505856757751566 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.39916149 -0.01775610 -0.21100499 +C -22.00600000 -15.99600000 -27.05600000 1.21187915 0.28761816 -0.90582456 +N -21.03500000 -16.32600000 -27.87900000 0.34247310 0.26248459 -0.47747201 +N -22.00900000 -14.81000000 -26.46800000 -0.88620730 0.55585509 0.70173161 +N -22.97400000 -16.87300000 -26.85700000 -1.29678044 -1.07783474 0.66445600 +H -20.27200000 -15.69400000 -28.06100000 0.83115590 -0.23044869 0.20069474 +H -20.98400000 -17.25100000 -28.27500000 0.43044640 -0.23523314 -0.08845599 +H -21.30800000 -14.13600000 -26.74300000 0.20135023 0.04548187 0.02640477 +H -23.91000000 -16.51500000 -26.79400000 -0.50312557 -0.04176843 0.21021251 +H -22.88300000 -17.78900000 -27.27300000 -0.01922541 -0.10311262 -0.08309552 +H -23.65000000 -13.61700000 -25.89000000 -0.25273296 0.15369223 -0.05628033 +H -22.47300000 -13.98600000 -24.61600000 -0.02768290 0.04167217 0.24354047 +H -23.61928000 -15.24549000 -25.14423000 0.23987710 0.13146855 -0.04487909 +C -16.01619219 -18.47959196 -27.41958284 0.86839836 -0.83356499 -0.08342671 +C -17.10219219 -17.46959196 -27.34958284 -0.10983998 0.92858483 0.23620820 +O -18.29019219 -17.83259196 -27.34458284 -2.61015343 -1.77460085 -0.33681106 +O -16.78819219 -16.28059196 -27.25858284 1.23294218 2.46681259 0.01294300 +H -16.08019219 -19.02159196 -28.36658284 0.00825872 -0.23771487 -0.16954308 +H -16.17019219 -19.19759196 -26.61258284 0.08918367 -0.33456246 0.14121553 +H -15.01273219 -18.03695196 -27.33506284 -0.14937828 0.01292680 0.01938652 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.6802966608 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.755436022115563 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.39585643 -0.01166427 -0.21145672 +C -22.00600000 -15.99600000 -27.05600000 1.08143934 0.27259669 -0.73119528 +N -21.03500000 -16.32600000 -27.87900000 0.54949599 0.17811848 -0.58285530 +N -22.00900000 -14.81000000 -26.46800000 -0.86892282 0.58540200 0.69671693 +N -22.97400000 -16.87300000 -26.85700000 -1.25394322 -1.07622043 0.64104568 +H -20.27200000 -15.69400000 -28.06100000 0.76691508 -0.19973567 0.15755589 +H -20.98400000 -17.25100000 -28.27500000 0.37995502 -0.21128882 -0.11200805 +H -21.30800000 -14.13600000 -26.74300000 0.18458223 0.05677178 0.02271150 +H -23.91000000 -16.51500000 -26.79400000 -0.55527662 -0.03120370 0.19863231 +H -22.88300000 -17.78900000 -27.27300000 -0.03142416 -0.10372944 -0.08477388 +H -23.65000000 -13.61700000 -25.89000000 -0.25157037 0.15013553 -0.05349515 +H -22.47300000 -13.98600000 -24.61600000 -0.02566511 0.04540745 0.24755385 +H -23.61928000 -15.24549000 -25.14423000 0.23889101 0.13049322 -0.04735936 +C -15.78738437 -18.57618391 -27.44816567 0.86382406 -0.82897871 -0.08976581 +C -16.87338437 -17.56618391 -27.37816567 -0.14106434 0.81436523 0.22889266 +O -18.06138437 -17.92918391 -27.37316567 -2.50953910 -1.70118986 -0.30090879 +O -16.55938437 -16.37718391 -27.28716567 1.22186878 2.48367929 0.02804914 +H -15.85138437 -19.11818391 -28.39516567 0.00888631 -0.23532718 -0.17000482 +H -15.94138437 -19.29418391 -26.64116567 0.08908399 -0.33153462 0.14289505 +H -14.78392437 -18.13354391 -27.36364567 -0.14339249 0.01390302 0.01977016 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.5339723581 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.005050284242796 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.39689196 -0.00686499 -0.21320060 +C -22.00600000 -15.99600000 -27.05600000 0.96523630 0.25576767 -0.58668993 +N -21.03500000 -16.32600000 -27.87900000 0.72567633 0.11171094 -0.68853059 +N -22.00900000 -14.81000000 -26.46800000 -0.85011706 0.62809883 0.70282425 +N -22.97400000 -16.87300000 -26.85700000 -1.22368477 -1.08502279 0.62644191 +H -20.27200000 -15.69400000 -28.06100000 0.70342904 -0.17413269 0.12248202 +H -20.98400000 -17.25100000 -28.27500000 0.33607645 -0.18855338 -0.12800625 +H -21.30800000 -14.13600000 -26.74300000 0.16738239 0.06537495 0.02022106 +H -23.91000000 -16.51500000 -26.79400000 -0.60243318 -0.02280613 0.18450814 +H -22.88300000 -17.78900000 -27.27300000 -0.04277174 -0.10200798 -0.08437340 +H -23.65000000 -13.61700000 -25.89000000 -0.25150594 0.14750779 -0.05068322 +H -22.47300000 -13.98600000 -24.61600000 -0.02508880 0.04909797 0.25223791 +H -23.61928000 -15.24549000 -25.14423000 0.23781440 0.12943566 -0.04954432 +C -15.55857656 -18.67277587 -27.47674851 0.86192402 -0.82106256 -0.09545328 +C -16.64457656 -17.66277587 -27.40674851 -0.16282297 0.68844292 0.22099805 +O -17.83257656 -18.02577587 -27.40174851 -2.40075290 -1.62967567 -0.26849785 +O -16.33057656 -16.47377587 -27.31574851 1.20426760 2.50088031 0.04123542 +H -15.62257656 -19.21477587 -28.42374851 0.00911333 -0.23247144 -0.17018306 +H -15.71257656 -19.39077587 -26.66974851 0.08842270 -0.32780174 0.14422008 +H -14.55511656 -18.23013587 -27.39222851 -0.13705716 0.01408233 0.01999365 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.4055809716 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.254695358424409 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.39953935 -0.00299888 -0.21528385 +C -22.00600000 -15.99600000 -27.05600000 0.86458025 0.23955575 -0.46770449 +N -21.03500000 -16.32600000 -27.87900000 0.87395583 0.05815390 -0.78518880 +N -22.00900000 -14.81000000 -26.46800000 -0.83193864 0.67290016 0.71364403 +N -22.97400000 -16.87300000 -26.85700000 -1.20127527 -1.09772419 0.61723851 +H -20.27200000 -15.69400000 -28.06100000 0.64634932 -0.15310071 0.09442263 +H -20.98400000 -17.25100000 -28.27500000 0.29927973 -0.16844914 -0.13883028 +H -21.30800000 -14.13600000 -26.74300000 0.15156478 0.07225845 0.01835971 +H -23.91000000 -16.51500000 -26.79400000 -0.64372570 -0.01601356 0.17038524 +H -22.88300000 -17.78900000 -27.27300000 -0.05284621 -0.09958786 -0.08318201 +H -23.65000000 -13.61700000 -25.89000000 -0.25191530 0.14548234 -0.04810467 +H -22.47300000 -13.98600000 -24.61600000 -0.02518228 0.05250554 0.25688219 +H -23.61928000 -15.24549000 -25.14423000 0.23673788 0.12846061 -0.05142423 +C -15.32976875 -18.76936783 -27.50533135 0.86193304 -0.81204704 -0.10022343 +C -16.41576875 -17.75936783 -27.43533135 -0.17827399 0.56582351 0.21310211 +O -17.60376875 -18.12236783 -27.43033135 -2.29888822 -1.56195371 -0.24156360 +O -16.10176875 -16.57036783 -27.34433135 1.18448726 2.51650990 0.05224500 +H -15.39376875 -19.31136783 -28.45233135 0.00903563 -0.22953644 -0.17023660 +H -15.48376875 -19.48736783 -26.69833135 0.08749948 -0.32401895 0.14530842 +H -14.32630875 -18.32672783 -27.42081135 -0.13091695 0.01378031 0.02015411 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.2940038267 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.504367695780043 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.40220503 0.00038620 -0.21770373 +C -22.00600000 -15.99600000 -27.05600000 0.77965074 0.22295095 -0.36584244 +N -21.03500000 -16.32600000 -27.87900000 0.99772235 0.01382563 -0.87045310 +N -22.00900000 -14.81000000 -26.46800000 -0.81618073 0.71430208 0.72495303 +N -22.97400000 -16.87300000 -26.85700000 -1.18237162 -1.11049799 0.61065966 +H -20.27200000 -15.69400000 -28.06100000 0.59745735 -0.13525144 0.07154627 +H -20.98400000 -17.25100000 -28.27500000 0.26852095 -0.15060917 -0.14615601 +H -21.30800000 -14.13600000 -26.74300000 0.13776989 0.07835927 0.01640100 +H -23.91000000 -16.51500000 -26.79400000 -0.68142259 -0.00959743 0.15735459 +H -22.88300000 -17.78900000 -27.27300000 -0.06167584 -0.09725480 -0.08236416 +H -23.65000000 -13.61700000 -25.89000000 -0.25242442 0.14368223 -0.04564938 +H -22.47300000 -13.98600000 -24.61600000 -0.02519567 0.05573715 0.26132899 +H -23.61928000 -15.24549000 -25.14423000 0.23566621 0.12761077 -0.05315764 +C -15.10096094 -18.86595979 -27.53391418 0.86251015 -0.80275378 -0.10412090 +C -16.18696094 -17.85595979 -27.46391418 -0.18670198 0.45092710 0.20550798 +O -17.37496094 -18.21895979 -27.45891418 -2.20848540 -1.49759882 -0.21985699 +O -15.87296094 -16.66695979 -27.37291418 1.16291050 2.52960146 0.06125702 +H -15.16496094 -19.40795979 -28.48091418 0.00879190 -0.22668912 -0.17024868 +H -15.25496094 -19.58395979 -26.72691418 0.08649815 -0.32042983 0.14625022 +H -14.09750094 -18.42331979 -27.44939418 -0.12524497 0.01329954 0.02029427 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.197751642 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.754064280802951 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.40400951 0.00343135 -0.22054431 +C -22.00600000 -15.99600000 -27.05600000 0.71177254 0.20638074 -0.27691827 +N -21.03500000 -16.32600000 -27.87900000 1.10090951 -0.02364758 -0.94100700 +N -22.00900000 -14.81000000 -26.46800000 -0.80415099 0.74896781 0.73424430 +N -22.97400000 -16.87300000 -26.85700000 -1.16653463 -1.12206883 0.60551292 +H -20.27200000 -15.69400000 -28.06100000 0.55688604 -0.11860021 0.05224756 +H -20.98400000 -17.25100000 -28.27500000 0.24200218 -0.13489310 -0.15207903 +H -21.30800000 -14.13600000 -26.74300000 0.12652209 0.08460412 0.01365610 +H -23.91000000 -16.51500000 -26.79400000 -0.71513904 -0.00302406 0.14611771 +H -22.88300000 -17.78900000 -27.27300000 -0.06925562 -0.09568847 -0.08291832 +H -23.65000000 -13.61700000 -25.89000000 -0.25288266 0.14195932 -0.04323936 +H -22.47300000 -13.98600000 -24.61600000 -0.02476313 0.05876782 0.26535824 +H -23.61928000 -15.24549000 -25.14423000 0.23473242 0.12696447 -0.05478713 +C -14.87215312 -18.96255174 -27.56249702 0.86142660 -0.79509014 -0.10736012 +C -15.95815312 -17.95255174 -27.49249702 -0.18405997 0.35280421 0.19895104 +O -17.14615312 -18.31555174 -27.48749702 -2.13392745 -1.44075963 -0.20268495 +O -15.64415312 -16.76355174 -27.40149702 1.13882622 2.53854930 0.06817521 +H -14.93615312 -19.50455174 -28.50949702 0.00865789 -0.22438435 -0.17030191 +H -15.02615312 -19.68055174 -26.75549702 0.08574245 -0.31758612 0.14710002 +H -13.86869312 -18.51991174 -27.47797702 -0.12077395 0.01331335 0.02047731 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.1146266445 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=7.003782507908067 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.40518715 0.00610771 -0.22358198 +C -22.00600000 -15.99600000 -27.05600000 0.65800758 0.19074523 -0.19981885 +N -21.03500000 -16.32600000 -27.87900000 1.18781631 -0.05570305 -0.99875100 +N -22.00900000 -14.81000000 -26.46800000 -0.79513011 0.77778003 0.74180506 +N -22.97400000 -16.87300000 -26.85700000 -1.15393191 -1.13274083 0.60161844 +H -20.27200000 -15.69400000 -28.06100000 0.52329199 -0.10308997 0.03588731 +H -20.98400000 -17.25100000 -28.27500000 0.21903688 -0.12120639 -0.15717378 +H -21.30800000 -14.13600000 -26.74300000 0.11741457 0.09083881 0.01036549 +H -23.91000000 -16.51500000 -26.79400000 -0.74455621 0.00338389 0.13650909 +H -22.88300000 -17.78900000 -27.27300000 -0.07572741 -0.09473217 -0.08449395 +H -23.65000000 -13.61700000 -25.89000000 -0.25328384 0.14034423 -0.04091483 +H -22.47300000 -13.98600000 -24.61600000 -0.02404759 0.06154357 0.26895157 +H -23.61928000 -15.24549000 -25.14423000 0.23397468 0.12649261 -0.05627295 +C -14.64334531 -19.05914370 -27.59107986 0.85886853 -0.78934905 -0.11002960 +C -15.72934531 -18.04914370 -27.52107986 -0.17363782 0.27207620 0.19346736 +O -16.91734531 -18.41214370 -27.51607986 -2.07384912 -1.39217323 -0.18911137 +O -15.41534531 -16.86014370 -27.43007986 1.11415688 2.54394316 0.07337092 +H -14.70734531 -19.60114370 -28.53807986 0.00862741 -0.22259695 -0.17040025 +H -14.79734531 -19.77714370 -26.78407986 0.08523012 -0.31545791 0.14787677 +H -13.63988531 -18.61650370 -27.50655986 -0.11744807 0.01379411 0.02069656 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.0423757153 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=7.253520146110052 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.40594325 0.00843692 -0.22659869 +C -22.00600000 -15.99600000 -27.05600000 0.61499923 0.17645209 -0.13329925 +N -21.03500000 -16.32600000 -27.87900000 1.26124616 -0.08320451 -1.04635254 +N -22.00900000 -14.81000000 -26.46800000 -0.78830588 0.80187238 0.74814004 +N -22.97400000 -16.87300000 -26.85700000 -1.14395319 -1.14249604 0.59872877 +H -20.27200000 -15.69400000 -28.06100000 0.49564480 -0.08902593 0.02210883 +H -20.98400000 -17.25100000 -28.27500000 0.19932915 -0.10947395 -0.16155152 +H -21.30800000 -14.13600000 -26.74300000 0.10997363 0.09685930 0.00684815 +H -23.91000000 -16.51500000 -26.79400000 -0.77006938 0.00939249 0.12828739 +H -22.88300000 -17.78900000 -27.27300000 -0.08125841 -0.09416850 -0.08662819 +H -23.65000000 -13.61700000 -25.89000000 -0.25365325 0.13887875 -0.03874626 +H -22.47300000 -13.98600000 -24.61600000 -0.02321979 0.06407154 0.27214809 +H -23.61928000 -15.24549000 -25.14423000 0.23333309 0.12615880 -0.05760007 +C -14.41453750 -19.15573566 -27.61966269 0.85560410 -0.78500721 -0.11219418 +C -15.50053750 -18.14573566 -27.54966269 -0.15977293 0.20569993 0.18869983 +O -16.68853750 -18.50873566 -27.54466269 -2.02499867 -1.35087255 -0.17835032 +O -15.18653750 -16.95673566 -27.45866269 1.09063827 2.54677632 0.07734492 +H -14.47853750 -19.69773566 -28.56666269 0.00863049 -0.22111645 -0.17050005 +H -14.56853750 -19.87373566 -26.81266269 0.08487203 -0.31378060 0.14858018 +H -13.41107750 -18.71309566 -27.53514269 -0.11498270 0.01454722 0.02093488 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12891.9790977749 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=7.503275268555756 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.40638588 0.01046042 -0.22951060 +C -22.00600000 -15.99600000 -27.05600000 0.58032544 0.16343747 -0.07557086 +N -21.03500000 -16.32600000 -27.87900000 1.32345992 -0.10696109 -1.08600098 +N -22.00900000 -14.81000000 -26.46800000 -0.78316506 0.82206752 0.75347464 +N -22.97400000 -16.87300000 -26.85700000 -1.13586690 -1.15121262 0.59652640 +H -20.27200000 -15.69400000 -28.06100000 0.47301248 -0.07638548 0.01047380 +H -20.98400000 -17.25100000 -28.27500000 0.18247461 -0.09949056 -0.16529332 +H -21.30800000 -14.13600000 -26.74300000 0.10388532 0.10253966 0.00325707 +H -23.91000000 -16.51500000 -26.79400000 -0.79233772 0.01496042 0.12122890 +H -22.88300000 -17.78900000 -27.27300000 -0.08598903 -0.09388519 -0.08906118 +H -23.65000000 -13.61700000 -25.89000000 -0.25397198 0.13754339 -0.03674904 +H -22.47300000 -13.98600000 -24.61600000 -0.02232651 0.06636538 0.27498928 +H -23.61928000 -15.24549000 -25.14423000 0.23278647 0.12592457 -0.05879412 +C -14.18572968 -19.25232762 -27.64824553 0.85210772 -0.78165919 -0.11394346 +C -15.27172968 -18.24232762 -27.57824553 -0.14520282 0.15082281 0.18456141 +O -16.45972968 -18.60532762 -27.57324553 -1.98470925 -1.31552534 -0.16980311 +O -14.95772968 -17.05332762 -27.48724553 1.06904064 2.54781462 0.08042895 +H -14.24972968 -19.79432762 -28.59524553 0.00862223 -0.21982524 -0.17059389 +H -14.33972968 -19.97032762 -26.84124553 0.08459992 -0.31239507 0.14921124 +H -13.18226968 -18.80968762 -27.56372553 -0.11313136 0.01540350 0.02116887 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12891.9232148018 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=7.753046163349467 pbc="T T T" +C -23.00700000 -14.39400000 -25.47600000 0.40654714 0.01223187 -0.23226766 +C -22.00600000 -15.99600000 -27.05600000 0.55221727 0.15157930 -0.02509914 +N -21.03500000 -16.32600000 -27.87900000 1.37621044 -0.12759814 -1.11925263 +N -22.00900000 -14.81000000 -26.46800000 -0.77940039 0.83891969 0.75790966 +N -22.97400000 -16.87300000 -26.85700000 -1.12913732 -1.15882431 0.59476385 +H -20.27200000 -15.69400000 -28.06100000 0.45438155 -0.06488567 0.00052484 +H -20.98400000 -17.25100000 -28.27500000 0.16795737 -0.09100135 -0.16852461 +H -21.30800000 -14.13600000 -26.74300000 0.09892791 0.10788269 -0.00032066 +H -23.91000000 -16.51500000 -26.79400000 -0.81193389 0.02012717 0.11517325 +H -22.88300000 -17.78900000 -27.27300000 -0.09003959 -0.09382681 -0.09166970 +H -23.65000000 -13.61700000 -25.89000000 -0.25423753 0.13631859 -0.03490068 +H -22.47300000 -13.98600000 -24.61600000 -0.02138898 0.06844753 0.27753199 +H -23.61928000 -15.24549000 -25.14423000 0.23230863 0.12576843 -0.05985997 +C -13.95692187 -19.34891957 -27.67682837 0.84864266 -0.77905687 -0.11534825 +C -15.04292187 -18.33891957 -27.60682837 -0.13077907 0.10486906 0.18094197 +O -16.23092187 -18.70191957 -27.60182837 -1.95098282 -1.28502217 -0.16294364 +O -14.72892187 -17.14991957 -27.51582837 1.04946204 2.54761573 0.08281733 +H -14.02092187 -19.89091957 -28.62382837 0.00859288 -0.21864627 -0.17066608 +H -14.11092187 -20.06691957 -26.86982837 0.08438080 -0.31120311 0.14978517 +H -12.95346187 -18.90627957 -27.59230837 -0.11172908 0.01630464 0.02140497 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.7854046654 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.169831093811181 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 0.06990787 -0.17685370 -0.19036263 +C 12.50200000 35.31700000 5.75900000 1.40153631 -1.42415412 0.49266099 +N 13.33700000 34.30300000 5.87400000 -1.77378893 2.39057157 -1.89035931 +N 12.22000000 36.09300000 6.79800000 -0.25583760 0.77562824 0.99548626 +N 11.93800000 35.55500000 4.59100000 -1.15466944 0.81960625 -1.55275017 +H 13.73100000 34.01500000 6.77000000 1.15708786 -1.28425261 1.45116420 +H 13.57300000 33.74600000 5.07200000 0.06603431 -0.26617592 -0.12233835 +H 11.60800000 36.88200000 6.64200000 -0.09461352 -0.01015467 0.01063562 +H 11.31200000 36.33700000 4.47600000 -0.09418678 0.04881645 -0.25688032 +H 12.19300000 35.00900000 3.78400000 -0.06203831 0.01366501 -0.12933965 +H 12.75000000 36.88800000 8.67500000 -0.15758637 0.11788689 -0.06214826 +H 13.83900000 35.65300000 8.06400000 0.15699889 -0.18360150 0.07973422 +H 12.25752000 35.16852000 8.72794600 0.04646349 0.02598078 -0.07165629 +C 13.40355816 31.21451667 8.58561965 0.20503098 -0.34846444 -0.05087109 +C 14.31455816 32.43651667 8.49761965 0.75751356 -0.11434983 2.56531413 +O 14.41755816 33.00851667 7.38861965 0.38171586 -0.25719196 -1.43453057 +O 14.90855816 32.84051667 9.52061965 -0.28958907 -0.29080009 0.40282403 +H 13.60955816 30.55151667 7.74161965 -0.03634911 -0.14276449 -0.22895696 +H 12.36755816 31.54351667 8.49061965 -0.33471873 0.03289626 0.00997757 +H 13.52358816 30.63377667 9.51207965 0.01108872 0.27371190 -0.01760341 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.8928427033 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.41568261761627 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 0.06074110 -0.19442319 -0.14713490 +C 12.50200000 35.31700000 5.75900000 1.17847026 -1.10377940 0.72902239 +N 13.33700000 34.30300000 5.87400000 -0.76842058 1.24633289 -0.67847781 +N 12.22000000 36.09300000 6.79800000 -0.20204879 0.67677610 0.91548796 +N 11.93800000 35.55500000 4.59100000 -1.00467213 0.69524642 -1.46523217 +H 13.73100000 34.01500000 6.77000000 1.00583324 -1.36000377 1.13805591 +H 13.57300000 33.74600000 5.07200000 0.10037594 -0.32066066 -0.09165506 +H 11.60800000 36.88200000 6.64200000 -0.10229299 -0.00487636 0.00392576 +H 11.31200000 36.33700000 4.47600000 -0.07831889 0.04403933 -0.23509207 +H 12.19300000 35.00900000 3.78400000 -0.07122643 0.00317275 -0.15550044 +H 12.75000000 36.88800000 8.67500000 -0.15090405 0.11559264 -0.06939287 +H 13.83900000 35.65300000 8.06400000 0.16814267 -0.17581282 0.08284082 +H 12.25752000 35.16852000 8.72794600 0.04771037 0.02579786 -0.08258382 +C 13.46977908 31.00525834 8.70530982 0.18028299 -0.38470245 -0.03477122 +C 14.38077908 32.22725834 8.61730982 0.70160868 0.11206593 2.13237768 +O 14.48377908 32.79925834 7.50830982 -0.49478014 0.78137643 -2.40075389 +O 14.97477908 32.63125834 9.64030982 -0.20822175 -0.29923480 0.57983147 +H 13.67577908 30.34225834 7.86130982 -0.03530167 -0.14412599 -0.22732823 +H 12.43377908 31.33425834 8.61030982 -0.33303101 0.03091557 0.01436199 +H 13.58980908 30.42451834 9.63176982 0.00605319 0.25630352 -0.00798147 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.7226339314 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.6619754095544765 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 0.04831058 -0.20660842 -0.12353301 +C 12.50200000 35.31700000 5.75900000 0.99753844 -0.86262700 0.85385801 +N 13.33700000 34.30300000 5.87400000 -0.24744139 0.60854695 -0.10178887 +N 12.22000000 36.09300000 6.79800000 -0.16079261 0.60643679 0.86471234 +N 11.93800000 35.55500000 4.59100000 -0.89813542 0.61010616 -1.39475844 +H 13.73100000 34.01500000 6.77000000 0.75855209 -1.16640088 0.82801878 +H 13.57300000 33.74600000 5.07200000 0.11756340 -0.35443868 -0.08696340 +H 11.60800000 36.88200000 6.64200000 -0.10884580 0.00034048 0.00022271 +H 11.31200000 36.33700000 4.47600000 -0.07324854 0.04540823 -0.22279593 +H 12.19300000 35.00900000 3.78400000 -0.07814894 -0.00484925 -0.17480180 +H 12.75000000 36.88800000 8.67500000 -0.14383282 0.11186488 -0.07265111 +H 13.83900000 35.65300000 8.06400000 0.17621416 -0.15728766 0.08517367 +H 12.25752000 35.16852000 8.72794600 0.04465929 0.02640740 -0.08717925 +C 13.53600000 30.79600000 8.82500000 0.15911221 -0.40897513 -0.02023662 +C 14.44700000 32.01800000 8.73700000 0.66340735 0.25780530 1.81621061 +O 14.55000000 32.59000000 7.62800000 -0.74693881 1.07046139 -2.67447860 +O 15.04100000 32.42200000 9.76000000 -0.14318544 -0.30327619 0.71979599 +H 13.74200000 30.13300000 7.98100000 -0.03421153 -0.14472515 -0.22633218 +H 12.50000000 31.12500000 8.73000000 -0.33250326 0.02926547 0.01720684 +H 13.65603000 30.21526000 9.75146000 0.00192705 0.24254528 0.00032025 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.4738142045 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.908643036894216 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 0.03388287 -0.21565397 -0.11420084 +C 12.50200000 35.31700000 5.75900000 0.85505530 -0.67261095 0.91105836 +N 13.33700000 34.30300000 5.87400000 0.04675998 0.23215382 0.19300604 +N 12.22000000 36.09300000 6.79800000 -0.12922847 0.55628259 0.83824206 +N 11.93800000 35.55500000 4.59100000 -0.82125812 0.54971716 -1.33978547 +H 13.73100000 34.01500000 6.77000000 0.53912770 -0.92620950 0.56757542 +H 13.57300000 33.74600000 5.07200000 0.12493700 -0.37421211 -0.09633163 +H 11.60800000 36.88200000 6.64200000 -0.11548088 0.00574833 -0.00175461 +H 11.31200000 36.33700000 4.47600000 -0.07537974 0.05007156 -0.21523871 +H 12.19300000 35.00900000 3.78400000 -0.08342180 -0.01182594 -0.18974212 +H 12.75000000 36.88800000 8.67500000 -0.13735327 0.10777393 -0.07310087 +H 13.83900000 35.65300000 8.06400000 0.18264087 -0.13507132 0.08546422 +H 12.25752000 35.16852000 8.72794600 0.03907927 0.02807481 -0.08721817 +C 13.60222092 30.58674166 8.94469018 0.14188322 -0.42478482 -0.00549583 +C 14.51322092 31.80874166 8.85669018 0.62969373 0.34935027 1.55919906 +O 14.61622092 32.38074166 7.74769018 -0.77800875 1.06699784 -2.66555079 +O 15.10722092 32.21274166 9.87969018 -0.08654672 -0.30113701 0.83256988 +H 13.80822092 29.92374166 8.10069018 -0.03263262 -0.14410327 -0.22543553 +H 12.56622092 30.91574166 8.84969018 -0.33201714 0.02837143 0.01915216 +H 13.72225092 30.00600166 9.87115018 -0.00173241 0.23106715 0.00758736 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.2236393787 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.155631685807265 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 0.01668301 -0.22393470 -0.11742629 +C 12.50200000 35.31700000 5.75900000 0.74579141 -0.50511208 0.92253707 +N 13.33700000 34.30300000 5.87400000 0.23618893 -0.02064479 0.36418774 +N 12.22000000 36.09300000 6.79800000 -0.10242486 0.51744745 0.83690392 +N 11.93800000 35.55500000 4.59100000 -0.76036900 0.50189584 -1.29600466 +H 13.73100000 34.01500000 6.77000000 0.36514194 -0.70734887 0.35925323 +H 13.57300000 33.74600000 5.07200000 0.12579504 -0.38522412 -0.11450360 +H 11.60800000 36.88200000 6.64200000 -0.12661511 0.01429431 -0.00449645 +H 11.31200000 36.33700000 4.47600000 -0.08784592 0.06191251 -0.20863132 +H 12.19300000 35.00900000 3.78400000 -0.08704686 -0.02204468 -0.20385405 +H 12.75000000 36.88800000 8.67500000 -0.13224187 0.10444248 -0.07143746 +H 13.83900000 35.65300000 8.06400000 0.18820004 -0.11258797 0.08338766 +H 12.25752000 35.16852000 8.72794600 0.03250063 0.03106753 -0.08328690 +C 13.66844184 30.37748333 9.06438035 0.12960861 -0.43187420 0.01186273 +C 14.57944184 31.59948333 8.97638035 0.57947305 0.38982992 1.31532504 +O 14.68244184 32.17148333 7.86738035 -0.72927298 0.96602282 -2.52910929 +O 15.17344184 32.00348333 9.99938035 -0.02882387 -0.28631835 0.92392022 +H 13.87444184 29.71448333 8.22038035 -0.02953631 -0.14122651 -0.22374509 +H 12.63244184 30.70648333 8.96938035 -0.33003436 0.02857311 0.02095541 +H 13.78847184 29.79674333 9.99084035 -0.00517153 0.22083030 0.01416210 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.9993584234 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.402897354813886 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 -0.00110551 -0.23405947 -0.12964229 +C 12.50200000 35.31700000 5.75900000 0.65678054 -0.34464517 0.90136182 +N 13.33700000 34.30300000 5.87400000 0.36946528 -0.20847160 0.48022556 +N 12.22000000 36.09300000 6.79800000 -0.06868728 0.47195187 0.85156904 +N 11.93800000 35.55500000 4.59100000 -0.69884535 0.45481154 -1.24585979 +H 13.73100000 34.01500000 6.77000000 0.23170432 -0.52518459 0.19760647 +H 13.57300000 33.74600000 5.07200000 0.12182941 -0.39053286 -0.14101929 +H 11.60800000 36.88200000 6.64200000 -0.14886182 0.03315851 -0.01272847 +H 11.31200000 36.33700000 4.47600000 -0.11535635 0.09021345 -0.20007080 +H 12.19300000 35.00900000 3.78400000 -0.08664618 -0.04163778 -0.22321209 +H 12.75000000 36.88800000 8.67500000 -0.12927856 0.10307108 -0.06884708 +H 13.83900000 35.65300000 8.06400000 0.19300536 -0.09151808 0.07965748 +H 12.25752000 35.16852000 8.72794600 0.02568620 0.03536330 -0.07658480 +C 13.73466276 30.16822499 9.18407053 0.12302743 -0.42925553 0.03199809 +C 14.64566276 31.39022499 9.09607053 0.50381350 0.37970005 1.06697445 +O 14.74866276 31.96222499 7.98707053 -0.65063382 0.84575121 -2.32923071 +O 15.23966276 31.79422499 10.11907053 0.03274916 -0.25419942 0.99591658 +H 13.94066276 29.50522499 8.34007053 -0.02438421 -0.13602586 -0.22115788 +H 12.69866276 30.49722499 9.08907053 -0.32603593 0.02988371 0.02313221 +H 13.85469276 29.58748499 10.11053053 -0.00822620 0.21162563 0.01991150 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.8071395579 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.650403657431074 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 -0.01510686 -0.24491575 -0.14383599 +C 12.50200000 35.31700000 5.75900000 0.57584340 -0.20455484 0.86756718 +N 13.33700000 34.30300000 5.87400000 0.46427009 -0.34516843 0.56204377 +N 12.22000000 36.09300000 6.79800000 -0.02821288 0.41834707 0.86723767 +N 11.93800000 35.55500000 4.59100000 -0.63793821 0.40838198 -1.18608153 +H 13.73100000 34.01500000 6.77000000 0.13396526 -0.38235923 0.07992456 +H 13.57300000 33.74600000 5.07200000 0.11619291 -0.39175091 -0.17160657 +H 11.60800000 36.88200000 6.64200000 -0.17699770 0.06019238 -0.02519916 +H 11.31200000 36.33700000 4.47600000 -0.14859979 0.12888783 -0.19093385 +H 12.19300000 35.00900000 3.78400000 -0.08158943 -0.06624299 -0.24700627 +H 12.75000000 36.88800000 8.67500000 -0.12799610 0.10325799 -0.06640284 +H 13.83900000 35.65300000 8.06400000 0.19713997 -0.07325430 0.07588030 +H 12.25752000 35.16852000 8.72794600 0.01870899 0.04001729 -0.06973249 +C 13.80088368 29.95896666 9.30376071 0.11974623 -0.42069828 0.04913041 +C 14.71188368 31.18096666 9.21576071 0.42471610 0.34219486 0.84932484 +O 14.81488368 31.75296666 8.10676071 -0.57184392 0.73723429 -2.12913014 +O 15.30588368 31.58496666 10.23876071 0.08883936 -0.21430102 1.04770599 +H 14.00688368 29.29596666 8.45976071 -0.01897360 -0.13103354 -0.21881227 +H 12.76488368 30.28796666 9.20876071 -0.32193338 0.03140562 0.02530873 +H 13.92091368 29.37822666 10.23022071 -0.01023044 0.20435999 0.02461767 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.6447062465 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.898120314460774 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 -0.02320110 -0.25204725 -0.15930411 +C 12.50200000 35.31700000 5.75900000 0.48229462 -0.10616813 0.84040354 +N 13.33700000 34.30300000 5.87400000 0.54583311 -0.44801227 0.61790001 +N 12.22000000 36.09300000 6.79800000 0.01094197 0.37604280 0.88600319 +N 11.93800000 35.55500000 4.59100000 -0.59235042 0.36809692 -1.13306466 +H 13.73100000 34.01500000 6.77000000 0.06360007 -0.27200055 -0.00608961 +H 13.57300000 33.74600000 5.07200000 0.11263493 -0.38788191 -0.20048945 +H 11.60800000 36.88200000 6.64200000 -0.19986427 0.09009064 -0.03822269 +H 11.31200000 36.33700000 4.47600000 -0.17331740 0.16719115 -0.18419056 +H 12.19300000 35.00900000 3.78400000 -0.07144319 -0.08649894 -0.27156542 +H 12.75000000 36.88800000 8.67500000 -0.12696300 0.10340387 -0.06441010 +H 13.83900000 35.65300000 8.06400000 0.20060338 -0.05754684 0.07407749 +H 12.25752000 35.16852000 8.72794600 0.01065406 0.04315474 -0.06422181 +C 13.86710460 29.74970832 9.42345089 0.11777134 -0.40952196 0.06077980 +C 14.77810460 30.97170832 9.33545089 0.35562779 0.29539817 0.67729419 +O 14.88110460 31.54370832 8.22645089 -0.50419221 0.64590046 -1.95551209 +O 15.37210460 31.37570832 10.35845089 0.13528377 -0.17414187 1.08239147 +H 14.07310460 29.08670832 8.57945089 -0.01435867 -0.12742858 -0.21727410 +H 12.83110460 30.07870832 9.32845089 -0.31860576 0.03271467 0.02716351 +H 13.98713460 29.16896832 10.34991089 -0.01094903 0.19925490 0.02833139 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.5086361853 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.146021878892945 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 -0.02097832 -0.24773868 -0.18148748 +C 12.50200000 35.31700000 5.75900000 0.32401811 -0.08982086 0.84512506 +N 13.33700000 34.30300000 5.87400000 0.65173958 -0.53645624 0.65058430 +N 12.22000000 36.09300000 6.79800000 0.04390051 0.37707711 0.92091203 +N 11.93800000 35.55500000 4.59100000 -0.58353856 0.33964815 -1.11024945 +H 13.73100000 34.01500000 6.77000000 0.01296828 -0.18347559 -0.07807125 +H 13.57300000 33.74600000 5.07200000 0.11798761 -0.37379482 -0.22207755 +H 11.60800000 36.88200000 6.64200000 -0.20315932 0.12206693 -0.04973922 +H 11.31200000 36.33700000 4.47600000 -0.17068191 0.19778710 -0.18400926 +H 12.19300000 35.00900000 3.78400000 -0.05162477 -0.09043743 -0.29539248 +H 12.75000000 36.88800000 8.67500000 -0.12365439 0.10054478 -0.06321870 +H 13.83900000 35.65300000 8.06400000 0.20300063 -0.04265622 0.07818092 +H 12.25752000 35.16852000 8.72794600 -0.00158513 0.04069981 -0.06123205 +C 13.93332552 29.54044998 9.54314106 0.11639007 -0.39702832 0.06679567 +C 14.84432552 30.76244998 9.45514106 0.30064041 0.24798095 0.54666103 +O 14.94732552 31.33444998 8.34614106 -0.45011430 0.56734370 -1.81131217 +O 15.43832552 31.16644998 10.47814106 0.17176443 -0.13613153 1.10515943 +H 14.13932552 28.87744998 8.69914106 -0.01064396 -0.12536323 -0.21650453 +H 12.89732552 29.86944998 9.44814106 -0.31600325 0.03373764 0.02868921 +H 14.05335552 28.95970998 10.46960106 -0.01042572 0.19601675 0.03118650 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.3948027872 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.39408684611913 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 -0.01766446 -0.24085947 -0.20374689 +C 12.50200000 35.31700000 5.75900000 0.17577043 -0.09422127 0.85492474 +N 13.33700000 34.30300000 5.87400000 0.74776549 -0.61181756 0.67345688 +N 12.22000000 36.09300000 6.79800000 0.06963267 0.39182226 0.95802618 +N 11.93800000 35.55500000 4.59100000 -0.58566394 0.32001467 -1.10159433 +H 13.73100000 34.01500000 6.77000000 -0.02387524 -0.11507083 -0.13452792 +H 13.57300000 33.74600000 5.07200000 0.12523081 -0.35912616 -0.23945246 +H 11.60800000 36.88200000 6.64200000 -0.20105148 0.14879688 -0.05829534 +H 11.31200000 36.33700000 4.47600000 -0.16228509 0.22053214 -0.18543049 +H 12.19300000 35.00900000 3.78400000 -0.03327904 -0.08969005 -0.31472613 +H 12.75000000 36.88800000 8.67500000 -0.12027037 0.09744811 -0.06215271 +H 13.83900000 35.65300000 8.06400000 0.20496836 -0.03010153 0.08284091 +H 12.25752000 35.16852000 8.72794600 -0.01335833 0.03710148 -0.05867742 +C 13.99954644 29.33119165 9.66283124 0.11509613 -0.38558817 0.06947516 +C 14.91054644 30.55319165 9.57483124 0.25623692 0.20480479 0.45033307 +O 15.01354644 31.12519165 8.46583124 -0.40653383 0.50541677 -1.69564060 +O 15.50454644 30.95719165 10.59783124 0.20043383 -0.10394727 1.11809603 +H 14.20554644 28.66819165 8.81883124 -0.00789997 -0.12410955 -0.21604063 +H 12.96354644 29.66019165 9.56783124 -0.31387186 0.03452290 0.02976592 +H 14.11957644 28.75045165 10.58929124 -0.00938103 0.19407186 0.03336602 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.29873128 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.642296918599837 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 -0.01511531 -0.23429258 -0.22418866 +C 12.50200000 35.31700000 5.75900000 0.05232253 -0.10101692 0.86230120 +N 13.33700000 34.30300000 5.87400000 0.82835895 -0.67601277 0.69175862 +N 12.22000000 36.09300000 6.79800000 0.09032688 0.40886258 0.99335003 +N 11.93800000 35.55500000 4.59100000 -0.58995029 0.30563416 -1.09876551 +H 13.73100000 34.01500000 6.77000000 -0.05151677 -0.06211267 -0.17837238 +H 13.57300000 33.74600000 5.07200000 0.13180595 -0.34605157 -0.25420255 +H 11.60800000 36.88200000 6.64200000 -0.19856134 0.17049287 -0.06492345 +H 11.31200000 36.33700000 4.47600000 -0.15474007 0.23821547 -0.18671049 +H 12.19300000 35.00900000 3.78400000 -0.01817799 -0.08836067 -0.33019172 +H 12.75000000 36.88800000 8.67500000 -0.11753242 0.09491711 -0.06118806 +H 13.83900000 35.65300000 8.06400000 0.20653406 -0.01980753 0.08675605 +H 12.25752000 35.16852000 8.72794600 -0.02360296 0.03378243 -0.05622836 +C 14.06576736 29.12193331 9.78252142 0.11408843 -0.37511540 0.07031475 +C 14.97676736 30.34393331 9.69452142 0.21712748 0.16356892 0.37823636 +O 15.07976736 30.91593331 8.58552142 -0.36984120 0.45838873 -1.60204618 +O 15.57076736 30.74793331 10.71752142 0.22425524 -0.07600218 1.12419560 +H 14.27176736 28.45893331 8.93852142 -0.00572715 -0.12327635 -0.21580468 +H 13.02976736 29.45093331 9.68752142 -0.31202231 0.03526631 0.03053077 +H 14.18579736 28.54119331 10.70898142 -0.00803171 0.19292006 0.03517866 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.2168235929 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.89063640189919 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 -0.01335346 -0.22864111 -0.24214162 +C 12.50200000 35.31700000 5.75900000 -0.04754046 -0.10608141 0.86640891 +N 13.33700000 34.30300000 5.87400000 0.89365510 -0.72965672 0.70723282 +N 12.22000000 36.09300000 6.79800000 0.10740139 0.42389479 1.02454679 +N 11.93800000 35.55500000 4.59100000 -0.59354545 0.29462263 -1.09728289 +H 13.73100000 34.01500000 6.77000000 -0.07240448 -0.02094746 -0.21204151 +H 13.57300000 33.74600000 5.07200000 0.13741327 -0.33518642 -0.26741047 +H 11.60800000 36.88200000 6.64200000 -0.19697119 0.18839070 -0.07013859 +H 11.31200000 36.33700000 4.47600000 -0.14927784 0.25261478 -0.18762504 +H 12.19300000 35.00900000 3.78400000 -0.00589482 -0.08770571 -0.34294042 +H 12.75000000 36.88800000 8.67500000 -0.11541889 0.09306068 -0.06027720 +H 13.83900000 35.65300000 8.06400000 0.20791333 -0.01149586 0.08984473 +H 12.25752000 35.16852000 8.72794600 -0.03227005 0.03092612 -0.05387919 +C 14.13198828 28.91267498 9.90221159 0.11332216 -0.36591438 0.07016476 +C 15.04298828 30.13467497 9.81421159 0.18352516 0.12689287 0.32344314 +O 15.14598828 30.70667497 8.70521159 -0.33925155 0.42221297 -1.52584073 +O 15.63698828 30.53867497 10.83721159 0.24369936 -0.05251778 1.12581849 +H 14.33798828 28.24967498 9.05821159 -0.00403013 -0.12266965 -0.21561322 +H 13.09598828 29.24167497 9.80721159 -0.31032183 0.03591167 0.03110253 +H 14.25201828 28.33193497 10.82867159 -0.00664962 0.19228930 0.03662870 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.1462454998 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=7.139091798074071 pbc="T T T" +C 12.78700000 35.93500000 8.14300000 -0.01212884 -0.22402504 -0.25760757 +C 12.50200000 35.31700000 5.75900000 -0.12805809 -0.10875171 0.86762839 +N 13.33700000 34.30300000 5.87400000 0.94578127 -0.77382602 0.72086420 +N 12.22000000 36.09300000 6.79800000 0.12221456 0.43552016 1.05118074 +N 11.93800000 35.55500000 4.59100000 -0.59547688 0.28575250 -1.09507374 +H 13.73100000 34.01500000 6.77000000 -0.08837701 0.01149879 -0.23790529 +H 13.57300000 33.74600000 5.07200000 0.14210402 -0.32656632 -0.27980034 +H 11.60800000 36.88200000 6.64200000 -0.19663265 0.20359134 -0.07451880 +H 11.31200000 36.33700000 4.47600000 -0.14606530 0.26507165 -0.18806708 +H 12.19300000 35.00900000 3.78400000 0.00421805 -0.08812489 -0.35378877 +H 12.75000000 36.88800000 8.67500000 -0.11389326 0.09185342 -0.05948652 +H 13.83900000 35.65300000 8.06400000 0.20909560 -0.00480072 0.09218596 +H 12.25752000 35.16852000 8.72794600 -0.03955012 0.02854896 -0.05172631 +C 14.19820920 28.70341664 10.02190177 0.11280996 -0.35778359 0.06945968 +C 15.10920920 29.92541664 9.93390177 0.15360337 0.09354648 0.28126945 +O 15.21220920 30.49741664 8.82490177 -0.31296488 0.39452982 -1.46281826 +O 15.70320920 30.32941664 10.95690177 0.25997992 -0.03240543 1.12437065 +H 14.40420920 28.04041664 9.17790177 -0.00264994 -0.12214997 -0.21547680 +H 13.16220920 29.03241664 9.92690177 -0.30873082 0.03654846 0.03151866 +H 14.31823920 28.12267664 10.94836177 -0.00527896 0.19197213 0.03779176 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8843.17939441773 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=3.6724529766326075 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.40746773 0.29747564 0.47079174 +N 7.96000000 -6.55600000 21.83900000 -0.57387493 -0.81380253 2.83617368 +H 8.24600000 -6.67200000 20.86300000 0.90699854 0.67531803 -2.75174464 +H 7.55700000 -5.63000000 21.88900000 -0.09993156 0.63338325 -0.13775987 +H 7.23800000 -7.23200000 22.05200000 -0.47010459 -0.29670214 0.37623674 +H 9.98100000 -6.18400000 22.28300000 -0.12104733 0.10119776 -0.17680947 +H 9.39500000 -7.74000000 22.88700000 -0.20260583 -0.04307181 -0.07106855 +H 8.91513100 -6.21360700 23.70924000 -0.00497881 -0.17568191 -0.08543737 +C 7.98350924 -5.26600874 17.56955611 -0.26752230 -0.68147795 -0.56611454 +C 8.54350924 -5.05900874 18.96355611 0.54464488 2.19622657 0.64249524 +O 8.74450924 -6.08900874 19.65755611 0.07009357 -3.37059713 -0.32617580 +O 8.83650924 -3.96200874 19.46955611 -0.41922618 1.42451488 -0.79628583 +H 7.05450924 -5.82900874 17.69255611 -0.21970298 -0.25066759 -0.02057564 +H 8.66750924 -5.94800874 17.05855611 0.12963246 -0.27327296 -0.10745433 +H 7.75328024 -4.48120174 16.83397611 0.32015733 0.57715791 0.71372864 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8843.07650806844 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=3.9205187003526993 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.54812534 0.27540558 0.51544675 +N 7.96000000 -6.55600000 21.83900000 -0.06067138 -0.54472055 1.47589351 +H 8.24600000 -6.67200000 20.86300000 0.71357011 0.67446814 -2.48421272 +H 7.55700000 -5.63000000 21.88900000 -0.13732947 0.67735084 -0.16143501 +H 7.23800000 -7.23200000 22.05200000 -0.46440763 -0.32070373 0.24175500 +H 9.98100000 -6.18400000 22.28300000 -0.11658090 0.09966175 -0.16086919 +H 9.39500000 -7.74000000 22.88700000 -0.20533470 -0.03823069 -0.07816330 +H 8.91513100 -6.21360700 23.70924000 -0.03626796 -0.17498244 -0.11527447 +C 7.96475462 -5.18650437 17.33327806 -0.26812990 -0.69031791 -0.59508119 +C 8.52475462 -4.97950437 18.72727806 0.59762984 1.95215844 0.93232784 +O 8.72575462 -6.00950437 19.42127806 -0.39722459 -3.60342175 0.69265250 +O 8.81775462 -3.88250437 19.23327806 -0.40216503 1.62861663 -0.82973478 +H 7.03575462 -5.74950437 17.45627806 -0.21791878 -0.24585297 -0.01791503 +H 8.64875462 -5.86850437 16.82227806 0.12939239 -0.27141376 -0.11302176 +H 7.73452562 -4.40169737 16.59769806 0.31731266 0.58198241 0.69763185 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8842.78849688106 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=4.168815535073765 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.64774412 0.25668288 0.54941939 +N 7.96000000 -6.55600000 21.83900000 0.18202216 -0.37980439 0.75844397 +H 8.24600000 -6.67200000 20.86300000 0.51292151 0.53902424 -2.11029287 +H 7.55700000 -5.63000000 21.88900000 -0.17907264 0.71311489 -0.16113871 +H 7.23800000 -7.23200000 22.05200000 -0.47528399 -0.34206048 0.16039896 +H 9.98100000 -6.18400000 22.28300000 -0.10860071 0.09824887 -0.14349252 +H 9.39500000 -7.74000000 22.88700000 -0.20752633 -0.03556506 -0.08285730 +H 8.91513100 -6.21360700 23.70924000 -0.05754685 -0.17336874 -0.13577409 +C 7.94600000 -5.10700000 17.09700000 -0.27418356 -0.69440530 -0.61993680 +C 8.50600000 -4.90000000 18.49100000 0.64604293 1.74010010 1.14954230 +O 8.70700000 -5.93000000 19.18500000 -0.52588423 -3.59185276 0.94253094 +O 8.79900000 -3.80300000 18.99700000 -0.38590898 1.79491832 -0.85688799 +H 7.01700000 -5.67000000 17.22000000 -0.21740770 -0.24239732 -0.01562195 +H 8.63000000 -5.78900000 16.58600000 0.12945317 -0.26916200 -0.11701609 +H 7.71577100 -4.32219300 16.36142000 0.31323110 0.58652673 0.68268277 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8842.4565332665 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=4.417304501123408 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.72003425 0.24211448 0.57661482 +N 7.96000000 -6.55600000 21.83900000 0.30455446 -0.28001401 0.36785462 +H 8.24600000 -6.67200000 20.86300000 0.35992237 0.38534256 -1.75969783 +H 7.55700000 -5.63000000 21.88900000 -0.22032949 0.74306367 -0.14609954 +H 7.23800000 -7.23200000 22.05200000 -0.49477121 -0.36258151 0.11254981 +H 9.98100000 -6.18400000 22.28300000 -0.09980091 0.09686244 -0.12695898 +H 9.39500000 -7.74000000 22.88700000 -0.20932759 -0.03426544 -0.08612859 +H 8.91513100 -6.21360700 23.70924000 -0.07205299 -0.17152876 -0.14993600 +C 7.92724538 -5.02749563 16.86072194 -0.28329447 -0.69308950 -0.64266724 +C 8.48724538 -4.82049563 18.25472194 0.68765089 1.53754768 1.31630832 +O 8.68824538 -5.85049563 18.94872194 -0.54475303 -3.48465745 0.87958791 +O 8.78024538 -3.72349563 18.76072194 -0.36940292 1.93626686 -0.87793532 +H 6.99824538 -5.59049563 16.98372194 -0.21687147 -0.23941790 -0.01302497 +H 8.61124538 -5.70949563 16.34972194 0.12982837 -0.26639370 -0.11911015 +H 7.69701638 -4.24268863 16.12514194 0.30861374 0.59075057 0.66864312 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8842.13744870909 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=4.665954893108933 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.77549461 0.23142476 0.59885428 +N 7.96000000 -6.55600000 21.83900000 0.37855809 -0.21657085 0.14426968 +H 8.24600000 -6.67200000 20.86300000 0.25290152 0.24767983 -1.47168891 +H 7.55700000 -5.63000000 21.88900000 -0.26059053 0.77137473 -0.12133384 +H 7.23800000 -7.23200000 22.05200000 -0.52241703 -0.38716676 0.08604644 +H 9.98100000 -6.18400000 22.28300000 -0.09167839 0.09512682 -0.11153279 +H 9.39500000 -7.74000000 22.88700000 -0.21128831 -0.03423650 -0.08854748 +H 8.91513100 -6.21360700 23.70924000 -0.08267146 -0.16960697 -0.15964246 +C 7.90849076 -4.94799126 16.62444389 -0.29396286 -0.68311190 -0.66481105 +C 8.46849076 -4.74099126 18.01844389 0.71623630 1.31116537 1.44129558 +O 8.66949076 -5.77099126 18.71244389 -0.53109846 -3.32605451 0.70878563 +O 8.76149076 -3.64399126 18.52444389 -0.34837868 2.06410203 -0.88924900 +H 6.97949076 -5.51099126 16.74744389 -0.21519048 -0.23591940 -0.00887228 +H 8.59249076 -5.62999126 16.11344389 0.13072098 -0.26252610 -0.11830781 +H 7.67826176 -4.16318426 15.88886389 0.30336471 0.59431946 0.65473402 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8841.85170585896 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=4.914742227116861 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.82437430 0.22607920 0.61297675 +N 7.96000000 -6.55600000 21.83900000 0.45851501 -0.16368776 -0.00439814 +H 8.24600000 -6.67200000 20.86300000 0.17563529 0.12726944 -1.23604553 +H 7.55700000 -5.63000000 21.88900000 -0.30517729 0.80712766 -0.08420595 +H 7.23800000 -7.23200000 22.05200000 -0.57436453 -0.43533799 0.07856918 +H 9.98100000 -6.18400000 22.28300000 -0.08482225 0.09219269 -0.09498728 +H 9.39500000 -7.74000000 22.88700000 -0.21515732 -0.03708693 -0.09064185 +H 8.91513100 -6.21360700 23.70924000 -0.09344173 -0.16669544 -0.16531000 +C 7.88973614 -4.86848689 16.38816583 -0.30408848 -0.65071799 -0.68528607 +C 8.44973614 -4.66148689 17.78216583 0.70486499 0.97606763 1.48930070 +O 8.65073614 -5.69148689 18.47616583 -0.49807056 -3.06806079 0.51992508 +O 8.74273614 -3.56448689 18.28816583 -0.30633267 2.18237148 -0.86557739 +H 6.96073614 -5.43148689 16.51116583 -0.21075819 -0.22988312 -0.00022253 +H 8.57373614 -5.55048689 15.87716583 0.13321911 -0.25552192 -0.11173140 +H 7.65950714 -4.08367989 15.65258583 0.29560433 0.59588383 0.63763443 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8841.6098275333 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=5.1636466922846544 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.87825891 0.22390718 0.61768678 +N 7.96000000 -6.55600000 21.83900000 0.59321339 -0.09997745 -0.14573967 +H 8.24600000 -6.67200000 20.86300000 0.12104425 0.02693960 -1.01973371 +H 7.55700000 -5.63000000 21.88900000 -0.35800741 0.86582123 -0.03085598 +H 7.23800000 -7.23200000 22.05200000 -0.68388969 -0.54112307 0.11439831 +H 9.98100000 -6.18400000 22.28300000 -0.08015467 0.08976506 -0.07752276 +H 9.39500000 -7.74000000 22.88700000 -0.22378701 -0.04508525 -0.09188898 +H 8.91513100 -6.21360700 23.70924000 -0.11026215 -0.16122666 -0.16624893 +C 7.87098152 -4.78898252 16.15188778 -0.31050779 -0.63940539 -0.66950481 +C 8.43098152 -4.58198252 17.54588778 0.66183417 0.77842571 1.34225243 +O 8.63198152 -5.61198252 18.23988778 -0.44566668 -2.77309147 0.37421893 +O 8.72398152 -3.48498252 18.05188778 -0.26063067 2.16045573 -0.77151558 +H 6.94198152 -5.35198252 16.27488778 -0.21187272 -0.22679236 0.00197496 +H 8.55498152 -5.47098252 15.64088778 0.13771604 -0.25258775 -0.11013374 +H 7.64075252 -4.00417552 15.41630778 0.29271205 0.59397489 0.63261274 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8841.41457610454 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=5.412652146732347 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.92201804 0.21935019 0.62739256 +N 7.96000000 -6.55600000 21.83900000 0.68941340 -0.06309745 -0.22989421 +H 8.24600000 -6.67200000 20.86300000 0.09139508 -0.04888169 -0.87626260 +H 7.55700000 -5.63000000 21.88900000 -0.40332886 0.92228456 0.01436725 +H 7.23800000 -7.23200000 22.05200000 -0.76923102 -0.62306613 0.14501826 +H 9.98100000 -6.18400000 22.28300000 -0.07663673 0.08857951 -0.06528276 +H 9.39500000 -7.74000000 22.88700000 -0.23009505 -0.05074169 -0.09301661 +H 8.91513100 -6.21360700 23.70924000 -0.12277075 -0.15677957 -0.16712058 +C 7.85222690 -4.70947815 15.91560972 -0.31510743 -0.63508705 -0.64976259 +C 8.41222690 -4.50247815 17.30960972 0.62143319 0.64943159 1.18822378 +O 8.61322690 -5.53247815 18.00360972 -0.40221967 -2.53377437 0.26705063 +O 8.70522690 -3.40547815 17.81560972 -0.22385026 2.11606646 -0.68332862 +H 6.92322690 -5.27247815 16.03860972 -0.21388217 -0.22503540 0.00216490 +H 8.53622690 -5.39147815 15.40460972 0.14162848 -0.25128073 -0.11018508 +H 7.62199790 -3.92467115 15.18002972 0.29123374 0.59203178 0.63063567 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8841.25689226691 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=5.661745248606425 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.95542590 0.21370102 0.64013150 +N 7.96000000 -6.55600000 21.83900000 0.75220813 -0.04497492 -0.27078171 +H 8.24600000 -6.67200000 20.86300000 0.07718661 -0.10680136 -0.78896074 +H 7.55700000 -5.63000000 21.88900000 -0.44048916 0.97127065 0.05025132 +H 7.23800000 -7.23200000 22.05200000 -0.83010789 -0.68105479 0.16633331 +H 9.98100000 -6.18400000 22.28300000 -0.07377726 0.08811779 -0.05723168 +H 9.39500000 -7.74000000 22.88700000 -0.23421691 -0.05417766 -0.09400649 +H 8.91513100 -6.21360700 23.70924000 -0.13114381 -0.15368544 -0.16822250 +C 7.83347228 -4.62997378 15.67933167 -0.31813130 -0.62876149 -0.63338286 +C 8.39347228 -4.42297378 17.07333167 0.58105721 0.53509716 1.05383528 +O 8.59447228 -5.45297378 17.76733167 -0.36604656 -2.33300249 0.18893382 +O 8.68647228 -3.32597378 17.57933167 -0.19134877 2.07724439 -0.60846830 +H 6.90447228 -5.19297378 15.80233167 -0.21511829 -0.22335202 0.00291625 +H 8.51747228 -5.31197378 15.16833167 0.14492105 -0.24997186 -0.10968661 +H 7.60324328 -3.84516678 14.94375167 0.28958106 0.59035103 0.62833941 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8841.12862125546 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=5.910914934526397 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.98039135 0.20784383 0.65378493 +N 7.96000000 -6.55600000 21.83900000 0.79252864 -0.03760861 -0.28410172 +H 8.24600000 -6.67200000 20.86300000 0.07220453 -0.15129169 -0.73974234 +H 7.55700000 -5.63000000 21.88900000 -0.47041804 1.01227401 0.07797136 +H 7.23800000 -7.23200000 22.05200000 -0.87357192 -0.72203922 0.18096794 +H 9.98100000 -6.18400000 22.28300000 -0.07134261 0.08815780 -0.05214669 +H 9.39500000 -7.74000000 22.88700000 -0.23679433 -0.05608811 -0.09474408 +H 8.91513100 -6.21360700 23.70924000 -0.13655288 -0.15170370 -0.16939514 +C 7.81471766 -4.55046941 15.44305361 -0.31991754 -0.62066830 -0.62068308 +C 8.37471766 -4.34346941 16.83705361 0.54176178 0.43202167 0.94036629 +O 8.57571766 -5.37346941 17.53105361 -0.33544519 -2.16463188 0.13284808 +O 8.66771766 -3.24646941 17.34305361 -0.16267374 2.04497903 -0.54668903 +H 6.88571766 -5.11346941 15.56605361 -0.21561421 -0.22163280 0.00434242 +H 8.49871766 -5.23246941 14.93205361 0.14765766 -0.24852546 -0.10857215 +H 7.58448866 -3.76566241 14.70747361 0.28778648 0.58891342 0.62579320 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8841.0230520496 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=6.160151893959503 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 0.99880688 0.20228146 0.66702899 +N 7.96000000 -6.55600000 21.83900000 0.81818717 -0.03614648 -0.28081085 +H 8.24600000 -6.67200000 20.86300000 0.07257315 -0.18551308 -0.71544014 +H 7.55700000 -5.63000000 21.88900000 -0.49434497 1.04597750 0.09905022 +H 7.23800000 -7.23200000 22.05200000 -0.90496499 -0.75132394 0.19113609 +H 9.98100000 -6.18400000 22.28300000 -0.06926411 0.08845546 -0.04905032 +H 9.39500000 -7.74000000 22.88700000 -0.23833029 -0.05701763 -0.09523325 +H 8.91513100 -6.21360700 23.70924000 -0.13992636 -0.15052965 -0.17053214 +C 7.79596304 -4.47096504 15.20677556 -0.32087668 -0.61165770 -0.61125505 +C 8.35596304 -4.26396504 16.60077556 0.50465262 0.33998271 0.84611657 +O 8.55696304 -5.29396504 17.29477556 -0.30923199 -2.02371960 0.09305910 +O 8.64896304 -3.16696504 17.10677556 -0.13761568 2.01837523 -0.49657092 +H 6.86696304 -5.03396504 15.32977556 -0.21556359 -0.21990432 0.00631511 +H 8.47996304 -5.15296504 14.69577556 0.14992580 -0.24696666 -0.10701752 +H 7.56573404 -3.68615804 14.47119556 0.28597303 0.58770670 0.62320408 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8840.93510219809 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=6.409448296386224 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 1.01236474 0.19722218 0.67922393 +N 7.96000000 -6.55600000 21.83900000 0.83444611 -0.03786511 -0.26808493 +H 8.24600000 -6.67200000 20.86300000 0.07585743 -0.21216835 -0.70676198 +H 7.55700000 -5.63000000 21.88900000 -0.51346972 1.07363216 0.11505371 +H 7.23800000 -7.23200000 22.05200000 -0.92801907 -0.77246748 0.19825712 +H 9.98100000 -6.18400000 22.28300000 -0.06746238 0.08885868 -0.04721492 +H 9.39500000 -7.74000000 22.88700000 -0.23918014 -0.05736288 -0.09549417 +H 8.91513100 -6.21360700 23.70924000 -0.14195225 -0.14989289 -0.17154052 +C 7.77720842 -4.39146067 14.97049750 -0.32123871 -0.60258101 -0.60435810 +C 8.33720842 -4.18446067 16.36449750 0.47034456 0.25943928 0.76786903 +O 8.53820842 -5.21446067 17.05849750 -0.28669362 -1.90584957 0.06486696 +O 8.63020842 -3.08746067 16.87049750 -0.11600802 1.99597804 -0.45604424 +H 6.84820842 -4.95446067 15.09349750 -0.21514474 -0.21821635 0.00864446 +H 8.46120842 -5.07346067 14.45949750 0.15185670 -0.24540766 -0.10520761 +H 7.54697942 -3.60665367 14.23491750 0.28429911 0.58668098 0.62079125 +15 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-8840.86093540257 label=CC chargeA=1 energyA=-2617.69985845671 chargeB=-1 energyB=-6220.46984312555 distance=6.658797447914187 pbc="T T T" +C 9.12400000 -6.69000000 22.74000000 1.02242634 0.19276023 0.69009719 +N 7.96000000 -6.55600000 21.83900000 0.84470249 -0.04109437 -0.25060115 +H 8.24600000 -6.67200000 20.86300000 0.08065637 -0.23306627 -0.70758217 +H 7.55700000 -5.63000000 21.88900000 -0.52886986 1.09641136 0.12732508 +H 7.23800000 -7.23200000 22.05200000 -0.94528858 -0.78808615 0.20346985 +H 9.98100000 -6.18400000 22.28300000 -0.06591994 0.08931362 -0.04621500 +H 9.39500000 -7.74000000 22.88700000 -0.23959724 -0.05738984 -0.09562062 +H 8.91513100 -6.21360700 23.70924000 -0.14315947 -0.14957435 -0.17241809 +C 7.75845380 -4.31195630 14.73421945 -0.32123249 -0.59420243 -0.59916849 +C 8.31845380 -4.10495630 16.12821945 0.43942449 0.19085698 0.70260448 +O 8.51945380 -5.13495630 16.82221945 -0.26731479 -1.80756239 0.04476866 +O 8.61145380 -3.00795630 16.63421945 -0.09760420 1.97633991 -0.42305189 +H 6.82945380 -4.87495630 14.85721945 -0.21456238 -0.21662830 0.01105290 +H 8.44245380 -4.99395630 14.22321945 0.15350223 -0.24391784 -0.10338040 +H 7.52822480 -3.52714930 13.99863945 0.28283702 0.58583985 0.61871965 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.1967352065 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.05795004937235 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.09596403 0.15255510 0.05400508 +C 33.70500000 11.92700000 26.09800000 2.83373346 0.95364648 1.97596119 +O 32.60000000 11.42900000 25.81100000 -0.92649065 -0.50553497 -2.94148067 +O 34.21200000 11.87200000 27.24800000 -0.07613523 0.25968668 -0.56152555 +H 33.75000000 13.28700000 24.44000000 -0.16357722 0.13194912 -0.20479328 +H 34.76300000 11.86300000 24.24500000 0.11998623 -0.14168116 -0.24527435 +H 35.32079000 13.21299000 25.27085000 -0.12216062 -0.22743281 0.16978040 +C 30.51697621 11.41297253 28.35997957 0.08565697 -0.61685292 -0.42877017 +C 30.16897621 9.79197253 26.50897957 0.60343895 2.15410928 1.48065485 +N 30.79097621 10.81897253 27.04797957 -3.66416739 -0.84971192 2.61568844 +N 29.15897621 9.19897253 27.11897957 -1.55395699 -1.41582101 0.25064672 +N 30.54197621 9.36997253 25.32397957 -0.10503581 -1.36240184 -1.83284048 +H 31.59297621 11.18497253 26.53097957 2.07128206 0.76246596 -0.74650431 +H 31.44097621 11.87297253 28.71697957 0.23203588 0.05709405 -0.09157744 +H 30.26097621 10.63497253 29.08197957 -0.12066892 -0.14241685 0.33583627 +H 28.84197621 9.53397253 28.01297957 -0.17909829 -0.03347993 0.10973836 +H 28.66897621 8.43897253 26.64597957 0.04338233 0.26423010 0.50750842 +H 31.31397621 9.83297253 24.86997957 0.41795808 0.23537352 -0.24998174 +H 29.98497621 8.65997253 24.84397957 0.51089590 0.38950867 0.06083216 +H 29.73228621 12.18382253 28.36726957 -0.10304274 -0.06528555 -0.25790390 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.4106882566 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.3057211284280745 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.12677755 0.17294793 0.02621724 +C 33.70500000 11.92700000 26.09800000 2.28488395 0.71268902 1.93532021 +O 32.60000000 11.42900000 25.81100000 -2.69264398 -1.06148470 -1.62569457 +O 34.21200000 11.87200000 27.24800000 0.11420749 0.28699666 -0.39755942 +H 33.75000000 13.28700000 24.44000000 -0.16210101 0.13508546 -0.20479421 +H 34.76300000 11.86300000 24.24500000 0.12227685 -0.13991225 -0.24444028 +H 35.32079000 13.21299000 25.27085000 -0.11039968 -0.21439235 0.16263254 +C 30.30998811 11.30148626 28.44498978 0.16755655 -0.47643389 -0.34426973 +C 29.96198811 9.68048626 26.59398978 0.52342111 1.79372014 1.12575180 +N 30.58398811 10.70748626 27.13298978 -1.80508966 -0.15064038 1.53837691 +N 28.95198811 9.08748626 27.20398978 -1.42650939 -1.26122220 0.25763596 +N 30.33498811 9.25848626 25.40898978 -0.10022213 -1.23453464 -1.65580923 +H 31.38598811 11.07348626 26.61598978 2.08663810 0.77829344 -0.82484725 +H 31.23398811 11.76148626 28.80198978 0.21441133 0.05336081 -0.10043201 +H 30.05398811 10.52348626 29.16698978 -0.10025681 -0.15405788 0.27433054 +H 28.63498811 9.42248626 28.09798978 -0.19093850 -0.04048683 0.12487170 +H 28.46198811 8.32748626 26.73098978 0.05584200 0.27782763 0.49229983 +H 31.10698811 9.72148626 24.95498978 0.45197766 0.21577684 -0.30268485 +H 29.77798811 8.54848626 24.92898978 0.52309851 0.38471884 0.04731413 +H 29.52529811 12.07233626 28.45227978 -0.08292993 -0.07825166 -0.28421932 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.2327176419 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.553735864227719 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.15339310 0.19396425 0.00357428 +C 33.70500000 11.92700000 26.09800000 1.88604410 0.53380831 1.89714902 +O 32.60000000 11.42900000 25.81100000 -3.17425174 -1.23706404 -1.22029190 +O 34.21200000 11.87200000 27.24800000 0.26723492 0.30860333 -0.27420580 +H 33.75000000 13.28700000 24.44000000 -0.16133506 0.13770826 -0.20483260 +H 34.76300000 11.86300000 24.24500000 0.12399168 -0.13931820 -0.24352590 +H 35.32079000 13.21299000 25.27085000 -0.09848164 -0.20210491 0.15638205 +C 30.10300000 11.19000000 28.53000000 0.20676249 -0.38141943 -0.27137453 +C 29.75500000 9.56900000 26.67900000 0.44547743 1.53236715 0.89175696 +N 30.37700000 10.59600000 27.21800000 -0.85094689 0.24486238 1.05533267 +N 28.74500000 8.97600000 27.28900000 -1.32511891 -1.14784488 0.25506355 +N 30.12800000 9.14700000 25.49400000 -0.09334150 -1.14654773 -1.54035708 +H 31.17900000 10.96200000 26.70100000 1.73385682 0.70731707 -0.63980266 +H 31.02700000 11.65000000 28.88700000 0.19882782 0.05351958 -0.09986070 +H 29.84700000 10.41200000 29.25200000 -0.08572171 -0.16256749 0.23636145 +H 28.42800000 9.31100000 28.18300000 -0.20048190 -0.04443449 0.13713395 +H 28.25500000 8.21600000 26.81600000 0.06079211 0.28160167 0.48048799 +H 30.90000000 9.61000000 25.04000000 0.45000344 0.17553284 -0.34944199 +H 29.57100000 8.43700000 25.01400000 0.53161793 0.37842667 0.03317835 +H 29.31831000 11.96085000 28.53729000 -0.06832250 -0.08641032 -0.30272709 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.9362699469 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.801956498056273 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.17759417 0.21395224 -0.01458299 +C 33.70500000 11.92700000 26.09800000 1.58115037 0.39798793 1.85539350 +O 32.60000000 11.42900000 25.81100000 -3.17118630 -1.23616714 -1.12653995 +O 34.21200000 11.87200000 27.24800000 0.39242751 0.32624318 -0.17715378 +H 33.75000000 13.28700000 24.44000000 -0.16098163 0.13959278 -0.20459917 +H 34.76300000 11.86300000 24.24500000 0.12507379 -0.13939182 -0.24254670 +H 35.32079000 13.21299000 25.27085000 -0.08720083 -0.19105308 0.15085592 +C 29.89601189 11.07851374 28.61501022 0.22337661 -0.31627090 -0.21247484 +C 29.54801189 9.45751374 26.76401022 0.37139372 1.33987015 0.73929747 +N 30.17001189 10.48451374 27.30301022 -0.33830685 0.47677755 0.83372148 +N 28.53801189 8.86451374 27.37401022 -1.24457314 -1.06420692 0.24729619 +N 29.92101189 9.03551374 25.57901022 -0.08543396 -1.08518262 -1.46324957 +H 30.97201189 10.85051374 26.78601022 1.34382302 0.60648469 -0.43811532 +H 30.82001189 11.53851374 28.97201022 0.18522753 0.05549477 -0.09378384 +H 29.64001189 10.30051374 29.33701022 -0.07487552 -0.16789587 0.21220875 +H 28.22101189 9.19951374 28.26801022 -0.20839002 -0.04658746 0.14712836 +H 28.04801189 8.10451374 26.90101022 0.06158585 0.28043917 0.47112663 +H 30.69301189 9.49851374 25.12501022 0.42989847 0.13036786 -0.38827642 +H 29.36401189 8.32551374 25.09901022 0.53695483 0.37115754 0.01948519 +H 29.11132189 11.84936374 28.62230022 -0.05755761 -0.09161207 -0.31519091 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.6272234885 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.05035266446833 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.20038562 0.23237943 -0.02834430 +C 33.70500000 11.92700000 26.09800000 1.33488111 0.29192980 1.80396066 +O 32.60000000 11.42900000 25.81100000 -3.00238466 -1.16610089 -1.12786282 +O 34.21200000 11.87200000 27.24800000 0.49679178 0.34079941 -0.09646774 +H 33.75000000 13.28700000 24.44000000 -0.16098506 0.14067625 -0.20369900 +H 34.76300000 11.86300000 24.24500000 0.12560099 -0.13991843 -0.24131018 +H 35.32079000 13.21299000 25.27085000 -0.07673916 -0.18123972 0.14586673 +C 29.68902379 10.96702747 28.70002043 0.22849011 -0.27031880 -0.16653350 +C 29.34102379 9.34602747 26.84902043 0.30266235 1.19197852 0.63871736 +N 29.96302379 10.37302747 27.38802043 -0.04348732 0.62218610 0.72842417 +N 28.33102379 8.75302747 27.45902043 -1.17921075 -1.00027194 0.23783424 +N 29.71402379 8.92402747 25.66402043 -0.07657454 -1.04100162 -1.40966930 +H 30.76502379 10.73902747 26.87102043 1.00785409 0.50695394 -0.27482113 +H 30.61302379 11.42702747 29.05702043 0.17337848 0.05805346 -0.08485322 +H 29.43302379 10.18902747 29.42202043 -0.06656037 -0.17088774 0.19635273 +H 28.01402379 9.08802747 28.35302043 -0.21548968 -0.04746849 0.15578140 +H 27.84102379 7.99302747 26.98602043 0.05961216 0.27611878 0.46255307 +H 30.48602379 9.38702747 25.21002043 0.40249877 0.08839189 -0.41922660 +H 29.15702379 8.21402747 25.18402043 0.53879745 0.36281187 0.00653803 +H 28.90433379 11.73787747 28.70731043 -0.04952138 -0.09507183 -0.32324060 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.3428113505 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.298899690066014 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.22358625 0.24910193 -0.03573556 +C 33.70500000 11.92700000 26.09800000 1.11966275 0.20810561 1.72518491 +O 32.60000000 11.42900000 25.81100000 -2.78572228 -1.07573462 -1.13785499 +O 34.21200000 11.87200000 27.24800000 0.58466631 0.35121202 -0.02263007 +H 33.75000000 13.28700000 24.44000000 -0.16142566 0.14058869 -0.20102662 +H 34.76300000 11.86300000 24.24500000 0.12561553 -0.14075263 -0.23900365 +H 35.32079000 13.21299000 25.27085000 -0.06677027 -0.17217878 0.14079085 +C 29.48203568 10.85554121 28.78503065 0.22846074 -0.23621421 -0.13283664 +C 29.13403568 9.23454121 26.93403065 0.24052674 1.06652370 0.57177460 +N 29.75603568 10.26154121 27.47303065 0.14180422 0.72702704 0.67816192 +N 28.12403568 8.64154121 27.54403065 -1.12403762 -0.94794312 0.23047674 +N 29.50703568 8.81254121 25.74903065 -0.06348843 -1.00654642 -1.37185921 +H 30.55803568 10.62754121 26.95603065 0.73980378 0.41999885 -0.15386355 +H 30.40603568 11.31554121 29.14203065 0.16295967 0.06071738 -0.07463633 +H 29.22603568 10.07754121 29.50703065 -0.06037661 -0.17258896 0.18560065 +H 27.80703568 8.97654121 28.43803065 -0.22298191 -0.04642603 0.16466587 +H 27.63403568 7.88154121 27.07103065 0.05400220 0.26771554 0.45092416 +H 30.27903568 9.27554121 25.29503065 0.37294859 0.05340207 -0.44381961 +H 28.95003568 8.10254121 25.26903065 0.53421022 0.35154059 -0.00666637 +H 28.69734568 11.62639121 28.79232065 -0.04344423 -0.09754866 -0.32764708 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.093822762 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.547577292653992 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.24955379 0.26281744 -0.03059913 +C 33.70500000 11.92700000 26.09800000 0.91407621 0.14989443 1.57178808 +O 32.60000000 11.42900000 25.81100000 -2.54457017 -0.98238518 -1.10561234 +O 34.21200000 11.87200000 27.24800000 0.65207969 0.35038473 0.05883232 +H 33.75000000 13.28700000 24.44000000 -0.16269121 0.13865580 -0.19449129 +H 34.76300000 11.86300000 24.24500000 0.12501701 -0.14189723 -0.23413162 +H 35.32079000 13.21299000 25.27085000 -0.05648092 -0.16295964 0.13449153 +C 29.27504757 10.74405495 28.87004087 0.22823046 -0.20774040 -0.11433068 +C 28.92704757 9.12305495 27.01904087 0.18616515 0.93377730 0.53210867 +N 29.54904757 10.15005495 27.55804087 0.27972182 0.83384150 0.65787340 +N 27.91704757 8.53005495 27.62904087 -1.07582101 -0.90166553 0.23263615 +N 29.30004757 8.70105495 25.83404087 -0.03542975 -0.97465434 -1.35168432 +H 30.35104757 10.51605495 27.04104087 0.52208657 0.34386190 -0.06219683 +H 30.19904757 11.20405495 29.22704087 0.15249094 0.06332756 -0.06344695 +H 29.01904757 9.96605495 29.59204087 -0.05703793 -0.17483834 0.17844318 +H 27.60004757 8.86505495 28.52304087 -0.23322155 -0.04174058 0.17562626 +H 27.42704757 7.77005495 27.15604087 0.03958420 0.25162478 0.42838383 +H 30.07204757 9.16405495 25.38004087 0.33950664 0.02540473 -0.46304717 +H 28.74304757 7.99105495 25.35404087 0.51594035 0.33386166 -0.02328015 +H 28.49035757 11.51490495 28.87733087 -0.03920030 -0.09957059 -0.32736293 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.8818535478 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.796368659594933 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.27228437 0.27102798 -0.01562898 +C 33.70500000 11.92700000 26.09800000 0.74295234 0.12400795 1.36432653 +O 32.60000000 11.42900000 25.81100000 -2.30919976 -0.89914903 -1.03218822 +O 34.21200000 11.87200000 27.24800000 0.68905494 0.33493382 0.14217442 +H 33.75000000 13.28700000 24.44000000 -0.16437219 0.13642433 -0.18663589 +H 34.76300000 11.86300000 24.24500000 0.12454083 -0.14305864 -0.22857444 +H 35.32079000 13.21299000 25.27085000 -0.04661718 -0.15409448 0.12806145 +C 29.06805947 10.63256868 28.95505108 0.23023971 -0.18245888 -0.11032731 +C 28.72005947 9.01156868 27.10405108 0.14138891 0.79340333 0.51484451 +N 29.34205947 10.03856868 27.64305108 0.39604929 0.95486726 0.65680482 +N 27.71005947 8.41856868 27.71405108 -1.03948408 -0.86594508 0.24592752 +N 29.09305947 8.58956868 25.91905108 0.00646566 -0.94676323 -1.35417270 +H 30.14405947 10.40456868 27.12605108 0.34463306 0.27845549 0.00985037 +H 29.99205947 11.09256868 29.31205108 0.14141589 0.06548840 -0.05206413 +H 28.81205947 9.85456868 29.67705108 -0.05613934 -0.17833406 0.17418277 +H 27.39305947 8.75356868 28.60805108 -0.24501117 -0.03563513 0.18552900 +H 27.22005947 7.65856868 27.24105108 0.01834548 0.23301672 0.39943044 +H 29.86505947 9.05256868 25.46505108 0.30086589 -0.00009940 -0.47617043 +H 28.53605947 7.87956868 25.43905108 0.48944553 0.31486633 -0.04234863 +H 28.28336947 11.40341868 28.96234108 -0.03685819 -0.10095366 -0.32302109 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.7032612584 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.045259757225575 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.28204096 0.27139536 -0.00131447 +C 33.70500000 11.92700000 26.09800000 0.64595500 0.13069910 1.17252926 +O 32.60000000 11.42900000 25.81100000 -2.11404875 -0.83310908 -0.95299350 +O 34.21200000 11.87200000 27.24800000 0.69084474 0.30838080 0.20841025 +H 33.75000000 13.28700000 24.44000000 -0.16542414 0.13590792 -0.18188273 +H 34.76300000 11.86300000 24.24500000 0.12479687 -0.14370019 -0.22519778 +H 35.32079000 13.21299000 25.27085000 -0.03976138 -0.14763889 0.12467458 +C 28.86107136 10.52108242 29.04006130 0.23278800 -0.16009525 -0.11280737 +C 28.51307136 8.90008242 27.18906130 0.10233042 0.65926268 0.51228017 +N 29.13507136 9.92708242 27.72806130 0.49244191 1.07070171 0.66712951 +N 27.50307136 8.30708242 27.79906130 -1.00684380 -0.83282641 0.26304112 +N 28.88607136 8.47808242 26.00406130 0.05308922 -0.92087685 -1.36859514 +H 29.93707136 10.29308242 27.21106130 0.20382814 0.22635204 0.06421928 +H 29.78507136 10.98108242 29.39706130 0.13142627 0.06733317 -0.04193324 +H 28.60507136 9.74308242 29.76206130 -0.05647250 -0.18212668 0.17128550 +H 27.18607136 8.64208242 28.69306130 -0.25581213 -0.02972708 0.19427574 +H 27.01307136 7.54708242 27.32606130 -0.00775156 0.21077231 0.36642475 +H 29.65807136 8.94108242 25.55006130 0.26169527 -0.02475908 -0.48208220 +H 28.32907136 7.76808242 25.52406130 0.46044582 0.29609445 -0.06076750 +H 28.07638136 11.29193242 29.04735130 -0.03556835 -0.10204005 -0.31669623 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.5541097392 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.294238740464477 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.28112699 0.26662576 0.00895844 +C 33.70500000 11.92700000 26.09800000 0.60810956 0.15570400 1.02000819 +O 32.60000000 11.42900000 25.81100000 -1.96415658 -0.78367510 -0.88374008 +O 34.21200000 11.87200000 27.24800000 0.67145598 0.27866475 0.25472000 +H 33.75000000 13.28700000 24.44000000 -0.16577869 0.13676313 -0.18014957 +H 34.76300000 11.86300000 24.24500000 0.12548679 -0.14384833 -0.22382116 +H 35.32079000 13.21299000 25.27085000 -0.03588994 -0.14361758 0.12428119 +C 28.65408326 10.40959616 29.12507152 0.23355202 -0.14102288 -0.11653362 +C 28.30608326 8.78859616 27.27407152 0.07064863 0.54009464 0.51729150 +N 28.92808326 9.81559616 27.81307152 0.56721498 1.16783716 0.68189694 +N 27.29608326 8.19559616 27.88407152 -0.97693021 -0.80023998 0.27785834 +N 28.67908326 8.36659616 26.08907152 0.09634369 -0.89754288 -1.38322767 +H 29.73008326 10.18159616 27.29607152 0.09569514 0.18712089 0.10244753 +H 29.57808326 10.86959616 29.48207152 0.12406120 0.06926285 -0.03357271 +H 28.39808326 9.63159616 29.84707152 -0.05726221 -0.18550218 0.16890269 +H 26.97908326 8.53059616 28.77807152 -0.26507467 -0.02385619 0.20281213 +H 26.80608326 7.43559616 27.41107152 -0.03378719 0.18744895 0.33339558 +H 29.45108326 8.82959616 25.63507152 0.22812147 -0.04443558 -0.48427610 +H 28.12208326 7.65659616 25.60907152 0.43143317 0.27738415 -0.07732331 +H 27.86939326 11.18044616 29.13236152 -0.03437013 -0.10316558 -0.30992831 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.4294141671 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.543295591227622 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.27886581 0.26146631 0.01798379 +C 33.70500000 11.92700000 26.09800000 0.58839560 0.18310720 0.89060892 +O 32.60000000 11.42900000 25.81100000 -1.84608960 -0.74692893 -0.81995802 +O 34.21200000 11.87200000 27.24800000 0.64896858 0.25186697 0.29033722 +H 33.75000000 13.28700000 24.44000000 -0.16609520 0.13762921 -0.17895563 +H 34.76300000 11.86300000 24.24500000 0.12607699 -0.14394351 -0.22287097 +H 35.32079000 13.21299000 25.27085000 -0.03292703 -0.14042950 0.12428503 +C 28.44709515 10.29810989 29.21008173 0.23284009 -0.12565334 -0.12094915 +C 28.09909515 8.67710990 27.35908173 0.04803283 0.43992029 0.52456950 +N 28.72109515 9.70410990 27.89808173 0.62417490 1.24750093 0.69706924 +N 27.08909515 8.08410990 27.96908173 -0.95608662 -0.77469308 0.28974248 +N 28.47209515 8.25510990 26.17408173 0.13225042 -0.88027283 -1.39610574 +H 29.52309515 10.07010989 27.38108173 0.01409910 0.15726350 0.12906794 +H 29.37109515 10.75810990 29.56708173 0.11883081 0.07111770 -0.02651389 +H 28.19109515 9.52010990 29.93208173 -0.05811827 -0.18824810 0.16715658 +H 26.77209515 8.41910990 28.86308173 -0.27310983 -0.01846811 0.21020280 +H 26.59909515 7.32410990 27.49608173 -0.05456552 0.16902813 0.30636388 +H 29.24409515 8.71810990 25.72008173 0.20218496 -0.05713356 -0.48674303 +H 27.91509515 7.54510990 25.69408173 0.40557995 0.26102345 -0.09171917 +H 27.66240515 11.06895990 29.21737173 -0.03330795 -0.10415274 -0.30357179 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.3242671172 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.792421743531683 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.27713178 0.25678691 0.02626196 +C 33.70500000 11.92700000 26.09800000 0.57557534 0.20903733 0.77834247 +O 32.60000000 11.42900000 25.81100000 -1.75109155 -0.71910547 -0.76127557 +O 34.21200000 11.87200000 27.24800000 0.62750776 0.22868713 0.31888917 +H 33.75000000 13.28700000 24.44000000 -0.16648832 0.13824975 -0.17771510 +H 34.76300000 11.86300000 24.24500000 0.12650847 -0.14408928 -0.22194567 +H 35.32079000 13.21299000 25.27085000 -0.03039716 -0.13769190 0.12419576 +C 28.24010704 10.18662363 29.29509195 0.23101225 -0.11340096 -0.12530067 +C 27.89210704 8.56562363 27.44409195 0.03198110 0.35639080 0.53232861 +N 28.51410704 9.59262363 27.98309195 0.66726098 1.31191194 0.71157774 +N 26.88210704 7.97262363 28.05409195 -0.94133069 -0.75409548 0.29899221 +N 28.26510704 8.14362363 26.25909195 0.16127474 -0.86764955 -1.40612998 +H 29.31610704 9.95862363 27.46609195 -0.04748983 0.13444625 0.14725618 +H 29.16410704 10.64662363 29.65209195 0.11530177 0.07284590 -0.02065490 +H 27.98410704 9.40862363 30.01709195 -0.05894440 -0.19035780 0.16583792 +H 26.56510704 8.30762363 28.94809195 -0.28004687 -0.01355564 0.21667798 +H 26.39210704 7.21262363 27.58109195 -0.07104990 0.15420450 0.28422335 +H 29.03710704 8.60662363 25.80509195 0.18287597 -0.06419835 -0.48969186 +H 27.70810704 7.43362363 25.77909195 0.38278753 0.24664154 -0.10404461 +H 27.45541704 10.95747363 29.30238195 -0.03237896 -0.10505761 -0.29782499 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.2347035084 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=7.041609824729907 pbc="T T T" +C 34.44500000 12.62500000 24.95900000 0.27599875 0.25269523 0.03375284 +C 33.70500000 11.92700000 26.09800000 0.56603163 0.23227723 0.68114442 +O 32.60000000 11.42900000 25.81100000 -1.67343429 -0.69750892 -0.70845425 +O 34.21200000 11.87200000 27.24800000 0.60799781 0.20892873 0.34199464 +H 33.75000000 13.28700000 24.44000000 -0.16693773 0.13862907 -0.17633818 +H 34.76300000 11.86300000 24.24500000 0.12680674 -0.14428208 -0.22096438 +H 35.32079000 13.21299000 25.27085000 -0.02821235 -0.13533772 0.12402072 +C 28.03311894 10.07513737 29.38010217 0.22842656 -0.10364073 -0.12920875 +C 27.68511894 8.45413737 27.52910217 0.02036697 0.28676369 0.53982052 +N 28.30711894 9.48113737 28.06810217 0.69956216 1.36340293 0.72526948 +N 26.67511894 7.86113737 28.13910217 -0.93016014 -0.73663251 0.30595560 +N 28.05811894 8.03213737 26.34410217 0.18444056 -0.85836094 -1.41317791 +H 29.10911894 9.84713737 27.55110217 -0.09387802 0.11713094 0.15913065 +H 28.95711894 10.53513737 29.73710217 0.11310006 0.07448553 -0.01582396 +H 27.77711894 9.29713737 30.10210217 -0.05969446 -0.19192111 0.16479446 +H 26.35811894 8.19613737 29.03310217 -0.28598595 -0.00908837 0.22247774 +H 26.18511894 7.10113737 27.66610217 -0.08443872 0.14169433 0.26567785 +H 28.83011894 8.49513737 25.89010217 0.16886290 -0.06716863 -0.49284753 +H 27.50111894 7.32213737 25.86410217 0.36269104 0.23383206 -0.11451176 +H 27.24842894 10.84598737 29.38739217 -0.03154351 -0.10589872 -0.29271220 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.9081401654 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=3.8469731647434418 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.27871526 0.83805596 -0.08501017 +C 0.22300000 -9.83900000 1.84900000 0.75686203 -1.64218955 -0.34753908 +N 0.66900000 -11.08600000 1.75700000 -2.47585134 0.59150633 0.75754521 +N -0.87800000 -9.57200000 2.52900000 -1.40186327 0.54489228 0.86122298 +N 0.87600000 -8.85300000 1.26400000 -0.05259618 0.90846800 -0.15170747 +H 1.57500000 -11.24100000 1.31700000 2.00780774 -0.85537331 -0.61464997 +H 0.56800000 -13.14900000 2.09900000 0.19107998 0.09063558 -0.05904077 +H -1.00300000 -12.34300000 1.99900000 -0.32550022 -0.13290884 -0.00963159 +H -1.44200000 -10.32000000 2.89200000 -0.17968762 -0.09757325 0.15115497 +H -1.21900000 -8.62500000 2.58900000 -0.18650498 0.01409089 0.07628546 +H 1.72400000 -9.06300000 0.75200000 1.20344768 -0.42954919 -0.49675778 +H 0.52800000 -7.90900000 1.29900000 -0.01331460 0.12686702 0.00167823 +H 0.01611679 -12.14697000 3.46761900 -0.06319372 -0.13675644 0.07364080 +C 5.22238506 -11.13416331 1.22314191 0.11556106 0.15913358 -0.28653108 +C 3.74238506 -10.97116331 0.90714191 0.50154241 0.42455941 -0.42503432 +O 2.95038506 -11.86716331 1.27514191 -0.16053482 -1.59349250 0.62578125 +O 3.36238506 -9.95116331 0.29014191 -0.23870651 1.48865656 -0.42578625 +H 5.56238506 -12.11816331 0.89214191 0.06385927 -0.21641990 0.06217914 +H 5.36138506 -11.06516331 2.30514191 0.09449032 -0.04180280 0.18136849 +H 5.82695106 -10.36379331 0.72211221 -0.11561249 -0.04079983 0.11083195 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.7856852073 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.09611684385743 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.25491825 0.72592295 -0.04404492 +C 0.22300000 -9.83900000 1.84900000 0.79406799 -1.43290988 -0.35208236 +N 0.66900000 -11.08600000 1.75700000 -1.38027710 0.10461000 0.45682441 +N -0.87800000 -9.57200000 2.52900000 -1.29412298 0.45795589 0.78255904 +N 0.87600000 -8.85300000 1.26400000 0.15869282 0.70185850 -0.24460526 +H 1.57500000 -11.24100000 1.31700000 1.83358777 -0.62122385 -0.51212069 +H 0.56800000 -13.14900000 2.09900000 0.18440642 0.09199461 -0.05556416 +H -1.00300000 -12.34300000 1.99900000 -0.30295145 -0.11780312 -0.01989939 +H -1.44200000 -10.32000000 2.89200000 -0.18552092 -0.10248745 0.16372461 +H -1.21900000 -8.62500000 2.58900000 -0.18062966 0.01566042 0.06742378 +H 1.72400000 -9.06300000 0.75200000 1.06995869 -0.27772880 -0.42048099 +H 0.52800000 -7.90900000 1.29900000 0.03556961 0.13987524 -0.02365366 +H 0.01611679 -12.14697000 3.46761900 -0.04864065 -0.12559934 0.05599310 +C 5.46519253 -11.16558166 1.17257095 0.15568265 0.14569168 -0.29126635 +C 3.98519253 -11.00258166 0.85657095 0.05438858 0.39468804 -0.39556537 +O 3.19319253 -11.89858166 1.22457095 -0.92220637 -1.40708597 0.89318804 +O 3.60519253 -9.98258166 0.23957095 -0.29071724 1.60351670 -0.41372977 +H 5.80519253 -12.14958166 0.84157095 0.07049872 -0.21827959 0.06139273 +H 5.60419253 -11.09658166 2.25457095 0.09655392 -0.04026474 0.18218849 +H 6.06975853 -10.39521166 0.67154125 -0.10325907 -0.03839130 0.10971870 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.4793121379 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.345358884358125 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.23199080 0.64503438 -0.01176249 +C 0.22300000 -9.83900000 1.84900000 0.78382393 -1.27256677 -0.33936878 +N 0.66900000 -11.08600000 1.75700000 -0.79158783 -0.15386765 0.28736116 +N -0.87800000 -9.57200000 2.52900000 -1.20687295 0.39676234 0.72083339 +N 0.87600000 -8.85300000 1.26400000 0.28269201 0.57890389 -0.29839661 +H 1.57500000 -11.24100000 1.31700000 1.51140510 -0.42355706 -0.42542087 +H 0.56800000 -13.14900000 2.09900000 0.17403801 0.08766981 -0.05139897 +H -1.00300000 -12.34300000 1.99900000 -0.28550229 -0.10780310 -0.02832798 +H -1.44200000 -10.32000000 2.89200000 -0.19120436 -0.10646360 0.17331055 +H -1.21900000 -8.62500000 2.58900000 -0.17869759 0.02047459 0.06337946 +H 1.72400000 -9.06300000 0.75200000 0.91866532 -0.15025521 -0.35171983 +H 0.52800000 -7.90900000 1.29900000 0.06583088 0.15368490 -0.04005130 +H 0.01611679 -12.14697000 3.46761900 -0.03756462 -0.11793908 0.04316551 +C 5.70800000 -11.19700000 1.12200000 0.19224199 0.13903683 -0.28731225 +C 4.22800000 -11.03400000 0.80600000 -0.24424548 0.37507589 -0.39011169 +O 3.43600000 -11.93000000 1.17400000 -1.07880010 -1.40109161 1.01601713 +O 3.84800000 -10.01400000 0.18900000 -0.22835513 1.63175584 -0.43369923 +H 6.04800000 -12.18100000 0.79100000 0.07533486 -0.21992801 0.06021524 +H 5.84700000 -11.12800000 2.20400000 0.09936409 -0.03928974 0.18441278 +H 6.31256600 -10.42663000 0.62097030 -0.09255665 -0.03563665 0.10887476 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.1362840472 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.594683282918175 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.21187625 0.58536858 0.01400584 +C 0.22300000 -9.83900000 1.84900000 0.75015433 -1.14897869 -0.31917633 +N 0.66900000 -11.08600000 1.75700000 -0.45410179 -0.30003416 0.18452044 +N -0.87800000 -9.57200000 2.52900000 -1.13473989 0.35207481 0.67108242 +N 0.87600000 -8.85300000 1.26400000 0.35988417 0.50190798 -0.33127802 +H 1.57500000 -11.24100000 1.31700000 1.19422426 -0.28270454 -0.34897591 +H 0.56800000 -13.14900000 2.09900000 0.16283712 0.08102074 -0.04739034 +H -1.00300000 -12.34300000 1.99900000 -0.27181339 -0.10131339 -0.03515917 +H -1.44200000 -10.32000000 2.89200000 -0.19665080 -0.10978085 0.18093258 +H -1.21900000 -8.62500000 2.58900000 -0.17887294 0.02665003 0.06193576 +H 1.72400000 -9.06300000 0.75200000 0.78434189 -0.05224822 -0.29705991 +H 0.52800000 -7.90900000 1.29900000 0.08498385 0.16727850 -0.05112246 +H 0.01611679 -12.14697000 3.46761900 -0.02928296 -0.11268443 0.03358914 +C 5.95080747 -11.22841834 1.07142905 0.22494613 0.13654844 -0.27916908 +C 4.47080747 -11.06541834 0.75542905 -0.45389516 0.35947509 -0.39420639 +O 3.67880747 -11.96141834 1.12342905 -1.01869764 -1.43876663 1.06508204 +O 4.09080747 -10.04541834 0.13842905 -0.13307559 1.62934801 -0.46189776 +H 6.29080747 -12.21241834 0.74042905 0.07884203 -0.22160090 0.05889935 +H 6.08980747 -11.15941834 2.15342905 0.10238580 -0.03872416 0.18724363 +H 6.55537347 -10.45804834 0.57039935 -0.08334567 -0.03283622 0.10814417 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.8103597466 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.844077326852206 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.19484373 0.54023270 0.03483092 +C 0.22300000 -9.83900000 1.84900000 0.70635610 -1.05243339 -0.29650765 +N 0.66900000 -11.08600000 1.75700000 -0.24829009 -0.38899989 0.11867135 +N -0.87800000 -9.57200000 2.52900000 -1.07386264 0.31795944 0.63010618 +N 0.87600000 -8.85300000 1.26400000 0.41107338 0.45141540 -0.35227953 +H 1.57500000 -11.24100000 1.31700000 0.92876135 -0.18821418 -0.28450865 +H 0.56800000 -13.14900000 2.09900000 0.15211577 0.07383949 -0.04387704 +H -1.00300000 -12.34300000 1.99900000 -0.26087269 -0.09713053 -0.04066304 +H -1.44200000 -10.32000000 2.89200000 -0.20186661 -0.11274337 0.18721374 +H -1.21900000 -8.62500000 2.58900000 -0.18017728 0.03350505 0.06188431 +H 1.72400000 -9.06300000 0.75200000 0.67448778 0.02160489 -0.25596588 +H 0.52800000 -7.90900000 1.29900000 0.09730845 0.18031163 -0.05890711 +H 0.01611679 -12.14697000 3.46761900 -0.02307157 -0.10909262 0.02628397 +C 6.19361494 -11.25983669 1.02085809 0.25374746 0.13641898 -0.26914728 +C 4.71361494 -11.09683669 0.70485809 -0.60585840 0.34512657 -0.40097059 +O 3.92161494 -11.99283669 1.07285809 -0.89901259 -1.47720995 1.07858794 +O 4.33361494 -10.07683669 0.08785809 -0.03713262 1.61721277 -0.48994733 +H 6.53361494 -12.24383669 0.68985809 0.08145174 -0.22335860 0.05752385 +H 6.33261494 -11.19083669 2.10285809 0.10538798 -0.03835977 0.19026034 +H 6.79818094 -10.48946669 0.51982839 -0.07538927 -0.03008460 0.10741150 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.5175321924 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.093530768699262 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.18065925 0.50533632 0.05185515 +C 0.22300000 -9.83900000 1.84900000 0.65920699 -0.97579775 -0.27357359 +N 0.66900000 -11.08600000 1.75700000 -0.11558934 -0.44778056 0.07452684 +N -0.87800000 -9.57200000 2.52900000 -1.02190775 0.29085691 0.59603204 +N 0.87600000 -8.85300000 1.26400000 0.44778176 0.41713067 -0.36648453 +H 1.57500000 -11.24100000 1.31700000 0.72009955 -0.12579905 -0.23210568 +H 0.56800000 -13.14900000 2.09900000 0.14242202 0.06694356 -0.04095650 +H -1.00300000 -12.34300000 1.99900000 -0.25200223 -0.09440450 -0.04507038 +H -1.44200000 -10.32000000 2.89200000 -0.20700827 -0.11557129 0.19252082 +H -1.21900000 -8.62500000 2.58900000 -0.18209514 0.04095679 0.06262700 +H 1.72400000 -9.06300000 0.75200000 0.58665376 0.07743150 -0.22577561 +H 0.52800000 -7.90900000 1.29900000 0.10507333 0.19284196 -0.06450385 +H 0.01611679 -12.14697000 3.46761900 -0.01847636 -0.10666892 0.02064770 +C 6.43642240 -11.29125503 0.97028714 0.27869209 0.13781936 -0.25856043 +C 4.95642240 -11.12825503 0.65428714 -0.71877295 0.33078100 -0.40717513 +O 4.16442240 -12.02425503 1.02228714 -0.77657072 -1.50603337 1.07534924 +O 4.57642240 -10.10825503 0.03728714 0.04881952 1.60263482 -0.51537380 +H 6.77642240 -12.27525503 0.63928714 0.08335611 -0.22514572 0.05612747 +H 6.57542240 -11.22225503 2.05228714 0.10819445 -0.03810727 0.19321012 +H 7.04098840 -10.52088503 0.46925744 -0.06853608 -0.02742447 0.10668311 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.2597247755 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.343035312018525 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.16944016 0.47837498 0.06506596 +C 0.22300000 -9.83900000 1.84900000 0.61156187 -0.91306944 -0.24910022 +N 0.66900000 -11.08600000 1.75700000 -0.02375924 -0.49442608 0.04137971 +N -0.87800000 -9.57200000 2.52900000 -0.97911968 0.26924563 0.56911735 +N 0.87600000 -8.85300000 1.26400000 0.47898003 0.39576555 -0.37839335 +H 1.57500000 -11.24100000 1.31700000 0.55802502 -0.08376926 -0.18877884 +H 0.56800000 -13.14900000 2.09900000 0.13371388 0.06059650 -0.03849119 +H -1.00300000 -12.34300000 1.99900000 -0.24470080 -0.09263366 -0.04844279 +H -1.44200000 -10.32000000 2.89200000 -0.21282501 -0.11856896 0.19668450 +H -1.21900000 -8.62500000 2.58900000 -0.18421827 0.04899149 0.06383088 +H 1.72400000 -9.06300000 0.75200000 0.51495515 0.12039127 -0.20418663 +H 0.52800000 -7.90900000 1.29900000 0.10921543 0.20505579 -0.06884771 +H 0.01611679 -12.14697000 3.46761900 -0.01532505 -0.10515189 0.01664628 +C 6.67922987 -11.32267338 0.91971619 0.29959559 0.14039102 -0.24823353 +C 5.19922987 -11.15967338 0.60371619 -0.79990729 0.31344175 -0.40981500 +O 4.40722987 -12.05567338 0.97171619 -0.66828993 -1.52204206 1.06259369 +O 4.81922987 -10.13967338 -0.01328381 0.12006977 1.58689108 -0.53745230 +H 7.01922987 -12.30667338 0.58871619 0.08453174 -0.22678956 0.05464426 +H 6.81822987 -11.25367338 2.00171619 0.11062746 -0.03781801 0.19585916 +H 7.28379587 -10.55230338 0.41868649 -0.06257083 -0.02487616 0.10591977 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.0362784048 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.592584108580483 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.16831355 0.46505913 0.06474451 +C 0.22300000 -9.83900000 1.84900000 0.56110563 -0.85273512 -0.20016527 +N 0.66900000 -11.08600000 1.75700000 0.07162184 -0.59395285 -0.00644920 +N -0.87800000 -9.57200000 2.52900000 -0.97734329 0.26445506 0.57163380 +N 0.87600000 -8.85300000 1.26400000 0.54054164 0.41949058 -0.41500056 +H 1.57500000 -11.24100000 1.31700000 0.41193190 -0.05304473 -0.13880030 +H 0.56800000 -13.14900000 2.09900000 0.12341992 0.05453220 -0.03538503 +H -1.00300000 -12.34300000 1.99900000 -0.23961836 -0.09319367 -0.04955163 +H -1.44200000 -10.32000000 2.89200000 -0.22265234 -0.11881532 0.19533430 +H -1.21900000 -8.62500000 2.58900000 -0.18640106 0.05123369 0.06434747 +H 1.72400000 -9.06300000 0.75200000 0.43775442 0.16031591 -0.18650669 +H 0.52800000 -7.90900000 1.29900000 0.11127671 0.21289031 -0.07632241 +H 0.01611679 -12.14697000 3.46761900 -0.01538372 -0.10471238 0.01857574 +C 6.92203734 -11.35409172 0.86914523 0.30676639 0.14469313 -0.23711566 +C 5.44203734 -11.19109172 0.55314523 -0.79133285 0.28175194 -0.39426286 +O 4.65003734 -12.08709172 0.92114523 -0.58957174 -1.49788618 1.02245850 +O 5.06203734 -10.17109172 -0.06385477 0.14991436 1.54662940 -0.55190651 +H 7.26203734 -12.33809172 0.53814523 0.08455048 -0.22773721 0.05235331 +H 7.06103734 -11.28509172 1.95114523 0.11291567 -0.03698868 0.19755732 +H 7.52660334 -10.58372172 0.36811553 -0.05780915 -0.02198520 0.10446117 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.8479373626 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.84217148588387 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.17869348 0.46563235 0.05252726 +C 0.22300000 -9.83900000 1.84900000 0.50682943 -0.79724078 -0.13944070 +N 0.66900000 -11.08600000 1.75700000 0.18267041 -0.75185983 -0.06041678 +N -0.87800000 -9.57200000 2.52900000 -1.02280238 0.27773256 0.60730366 +N 0.87600000 -8.85300000 1.26400000 0.63176732 0.49060771 -0.48228664 +H 1.57500000 -11.24100000 1.31700000 0.27365439 -0.02998609 -0.08775623 +H 0.56800000 -13.14900000 2.09900000 0.11171108 0.04895178 -0.03182754 +H -1.00300000 -12.34300000 1.99900000 -0.23802456 -0.09668886 -0.04888891 +H -1.44200000 -10.32000000 2.89200000 -0.23085674 -0.11230169 0.19016857 +H -1.21900000 -8.62500000 2.58900000 -0.18979825 0.04454146 0.06256199 +H 1.72400000 -9.06300000 0.75200000 0.35529877 0.20072245 -0.16294764 +H 0.52800000 -7.90900000 1.29900000 0.11615783 0.21216133 -0.08644051 +H 0.01611679 -12.14697000 3.46761900 -0.01834418 -0.10500978 0.02558714 +C 7.16484481 -11.38551007 0.81857428 0.30041631 0.14982025 -0.22657267 +C 5.68484481 -11.22251007 0.50257428 -0.69704796 0.24073050 -0.35940348 +O 4.89284481 -12.11851007 0.87057428 -0.54594407 -1.43817654 0.95590175 +O 5.30484481 -10.20251007 -0.11442572 0.14000176 1.48277404 -0.55888250 +H 7.50484481 -12.36951007 0.48757428 0.08412973 -0.22805545 0.04963771 +H 7.30384481 -11.31651007 1.90057428 0.11531425 -0.03572598 0.19854906 +H 7.76941081 -10.61514007 0.31754458 -0.05382660 -0.01862943 0.10262647 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.690310812 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.0917926914911416 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.18940231 0.46893452 0.03919691 +C 0.22300000 -9.83900000 1.84900000 0.46065519 -0.75068723 -0.08196819 +N 0.66900000 -11.08600000 1.75700000 0.27724825 -0.89832732 -0.10604519 +N -0.87800000 -9.57200000 2.52900000 -1.07024616 0.29200411 0.64447949 +N 0.87600000 -8.85300000 1.26400000 0.71488716 0.56104845 -0.54709227 +H 1.57500000 -11.24100000 1.31700000 0.16140222 -0.01299473 -0.04770598 +H 0.56800000 -13.14900000 2.09900000 0.10138901 0.04427428 -0.02901039 +H -1.00300000 -12.34300000 1.99900000 -0.23686390 -0.10077037 -0.04751407 +H -1.44200000 -10.32000000 2.89200000 -0.23739565 -0.10562697 0.18547946 +H -1.21900000 -8.62500000 2.58900000 -0.19431330 0.03844501 0.05905206 +H 1.72400000 -9.06300000 0.75200000 0.28585002 0.23388847 -0.14107102 +H 0.52800000 -7.90900000 1.29900000 0.11989167 0.21016805 -0.09548777 +H 0.01611679 -12.14697000 3.46761900 -0.02163759 -0.10487630 0.03296324 +C 7.40765227 -11.41692841 0.76800333 0.29171574 0.15458204 -0.21802825 +C 5.92765227 -11.25392841 0.45200333 -0.59490336 0.20272401 -0.32334818 +O 5.13565227 -12.14992841 0.82000333 -0.51962673 -1.37896830 0.89227427 +O 5.54765227 -10.23392841 -0.16499667 0.12167092 1.42446101 -0.56364163 +H 7.74765227 -12.40092841 0.43700333 0.08375221 -0.22842239 0.04714620 +H 7.54665227 -11.34792841 1.85000333 0.11737027 -0.03449468 0.19944266 +H 8.01221827 -10.64655841 0.26697363 -0.05024828 -0.01536167 0.10087866 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.5579822972 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.3414437515680655 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.19672700 0.47058428 0.02677320 +C 0.22300000 -9.83900000 1.84900000 0.42683777 -0.70963639 -0.02347742 +N 0.66900000 -11.08600000 1.75700000 0.34919017 -1.01592302 -0.14538482 +N -0.87800000 -9.57200000 2.52900000 -1.10304379 0.30091889 0.67135156 +N 0.87600000 -8.85300000 1.26400000 0.78246428 0.61505312 -0.59857853 +H 1.57500000 -11.24100000 1.31700000 0.07482433 -0.00058210 -0.01773273 +H 0.56800000 -13.14900000 2.09900000 0.09294074 0.04025670 -0.02713966 +H -1.00300000 -12.34300000 1.99900000 -0.23494415 -0.10473019 -0.04579002 +H -1.44200000 -10.32000000 2.89200000 -0.24542935 -0.10297140 0.18221639 +H -1.21900000 -8.62500000 2.58900000 -0.20029266 0.03768293 0.05413116 +H 1.72400000 -9.06300000 0.75200000 0.23109900 0.25873892 -0.12623238 +H 0.52800000 -7.90900000 1.29900000 0.11980221 0.21163400 -0.10346127 +H 0.01611679 -12.14697000 3.46761900 -0.02450779 -0.10383654 0.04010354 +C 7.65045974 -11.44834676 0.71743238 0.28330100 0.15842143 -0.21098962 +C 6.17045974 -11.28534676 0.40143238 -0.50691588 0.17223905 -0.29330929 +O 5.37845974 -12.18134676 0.76943238 -0.50104615 -1.32706045 0.83842532 +O 5.79045974 -10.26534676 -0.21556762 0.10357001 1.37412089 -0.56570268 +H 7.99045974 -12.43234676 0.38643238 0.08360380 -0.22870225 0.04521270 +H 7.78945974 -11.37934676 1.79943238 0.11922170 -0.03345633 0.20009488 +H 8.25502574 -10.67797676 0.21640268 -0.04740223 -0.01275152 0.09948966 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.4458455952 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.591121264724983 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.20079415 0.47089814 0.01453532 +C 0.22300000 -9.83900000 1.84900000 0.40449073 -0.67137989 0.03928867 +N 0.66900000 -11.08600000 1.75700000 0.40406813 -1.11234425 -0.18175670 +N -0.87800000 -9.57200000 2.52900000 -1.12445840 0.30485611 0.68980861 +N 0.87600000 -8.85300000 1.26400000 0.83858941 0.65555883 -0.63996828 +H 1.57500000 -11.24100000 1.31700000 0.00606558 0.00931846 0.00535103 +H 0.56800000 -13.14900000 2.09900000 0.08594250 0.03693497 -0.02610333 +H -1.00300000 -12.34300000 1.99900000 -0.23188516 -0.10858825 -0.04336800 +H -1.44200000 -10.32000000 2.89200000 -0.25480534 -0.10361776 0.17957438 +H -1.21900000 -8.62500000 2.58900000 -0.20746595 0.04188755 0.04754512 +H 1.72400000 -9.06300000 0.75200000 0.18671109 0.27678957 -0.11726342 +H 0.52800000 -7.90900000 1.29900000 0.11562405 0.21595767 -0.11047764 +H 0.01611679 -12.14697000 3.46761900 -0.02710037 -0.10187204 0.04696485 +C 7.89326721 -11.47976510 0.66686142 0.27452727 0.16138362 -0.20511345 +C 6.41326721 -11.31676510 0.35086142 -0.42407604 0.14662122 -0.26666535 +O 5.62126721 -12.21276510 0.71886142 -0.48982031 -1.28085954 0.79190373 +O 6.03326721 -10.29676510 -0.26613858 0.08389369 1.33036312 -0.56634942 +H 8.23326721 -12.46376510 0.33586142 0.08345693 -0.22906646 0.04339697 +H 8.03226721 -11.41076510 1.74886142 0.12063989 -0.03247313 0.20062866 +H 8.49783321 -10.70939510 0.16583172 -0.04519186 -0.01036794 0.09806826 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.3502094055 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.840822332851757 pbc="T T T" +C 0.01900000 -12.24500000 2.37200000 0.20171431 0.46937381 0.00343342 +C 0.22300000 -9.83900000 1.84900000 0.39095826 -0.63518641 0.10344824 +N 0.66900000 -11.08600000 1.75700000 0.44433145 -1.18751832 -0.21400308 +N -0.87800000 -9.57200000 2.52900000 -1.13342234 0.30289572 0.69882410 +N 0.87600000 -8.85300000 1.26400000 0.88330443 0.68157361 -0.67084088 +H 1.57500000 -11.24100000 1.31700000 -0.04837342 0.01738490 0.02219075 +H 0.56800000 -13.14900000 2.09900000 0.08036152 0.03411721 -0.02582823 +H -1.00300000 -12.34300000 1.99900000 -0.22803668 -0.11220655 -0.04056073 +H -1.44200000 -10.32000000 2.89200000 -0.26518225 -0.10751286 0.17802857 +H -1.21900000 -8.62500000 2.58900000 -0.21568250 0.05153275 0.03986342 +H 1.72400000 -9.06300000 0.75200000 0.15174450 0.28921488 -0.11329110 +H 0.52800000 -7.90900000 1.29900000 0.10779590 0.22365360 -0.11634670 +H 0.01611679 -12.14697000 3.46761900 -0.02927588 -0.09914488 0.05316309 +C 8.13607468 -11.51118345 0.61629047 0.26612719 0.16366842 -0.20026703 +C 6.65607468 -11.34818345 0.30029047 -0.35026230 0.12508483 -0.24368593 +O 5.86407468 -12.24418345 0.66829047 -0.48246824 -1.24010348 0.75213565 +O 6.27607468 -10.32818345 -0.31670953 0.06497741 1.29237407 -0.56573821 +H 8.47607468 -12.49518345 0.28529047 0.08327780 -0.22934906 0.04175715 +H 8.27507468 -11.44218345 1.69829047 0.12164936 -0.03153099 0.20096322 +H 8.74064068 -10.74081345 0.11526077 -0.04353852 -0.00832125 0.09675427 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.1115388962 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.704493481824777 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.40439544 0.08914220 0.57535744 +C 5.89300000 2.10500000 10.26700000 0.16019653 -2.31726166 -0.64039693 +N 6.46800000 0.95000000 9.98900000 -3.11130508 0.82437598 0.74434870 +N 4.58400000 2.24900000 10.11300000 -1.79074637 0.31341570 -0.30796675 +N 6.62900000 3.10900000 10.69900000 0.29120695 1.70245664 0.55313784 +H 5.91600000 0.16800000 9.69300000 -0.31680885 -0.21576103 -0.14273722 +H 7.49000000 0.89000000 9.89100000 2.63842974 -0.52530405 -0.10186304 +H 4.18700000 3.12900000 10.38500000 -0.36890377 0.31839094 0.07850719 +H 6.22600000 4.01600000 10.92500000 0.21336658 -0.31717796 -0.10944353 +H 7.61200000 2.96300000 10.84200000 0.53745365 -0.09515022 0.02705853 +H 3.74200000 0.36200000 10.38300000 -0.12380943 -0.29276866 0.12196133 +H 4.02000000 0.78400000 8.69500000 -0.06822676 0.05875477 -0.34612732 +H 2.63834300 1.49675000 9.60785000 0.34621342 0.25978349 -0.06359272 +C 10.78436703 -0.25434056 8.77464597 0.22825679 0.93541833 -0.28019153 +C 9.75136703 0.15865944 9.81364597 1.51591460 -1.15509802 2.11686077 +O 8.73736703 0.78465944 9.43564597 -0.71510592 1.46641871 -2.18779487 +O 9.94136703 -0.14134056 11.01164597 0.43822550 -0.29227316 0.13684542 +H 10.76336703 0.47265944 7.96064597 -0.05849142 0.15445200 -0.33131613 +H 10.52736703 -1.20934056 8.33264597 0.01263351 -0.55869397 -0.01546639 +H 11.81150703 -0.23918246 9.16803397 -0.23289509 -0.35312002 0.17281920 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.1325079383 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.953620894759154 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.37888400 0.04463359 0.55514750 +C 5.89300000 2.10500000 10.26700000 0.15154001 -1.80967718 -0.53664104 +N 6.46800000 0.95000000 9.98900000 -1.29274741 0.53900417 0.33856233 +N 4.58400000 2.24900000 10.11300000 -1.62538969 0.18499881 -0.29948065 +N 6.62900000 3.10900000 10.69900000 0.23297236 1.55684924 0.49712791 +H 5.91600000 0.16800000 9.69300000 -0.19213749 -0.26823870 -0.16142720 +H 7.49000000 0.89000000 9.89100000 2.26787578 -0.57861006 -0.20911902 +H 4.18700000 3.12900000 10.38500000 -0.34249680 0.31696609 0.09170678 +H 6.22600000 4.01600000 10.92500000 0.21086533 -0.30546035 -0.10983505 +H 7.61200000 2.96300000 10.84200000 0.57923186 -0.07742589 0.03881227 +H 3.74200000 0.36200000 10.38300000 -0.13217237 -0.28473010 0.12532683 +H 4.02000000 0.78400000 8.69500000 -0.07251918 0.06538812 -0.34952809 +H 2.63834300 1.49675000 9.60785000 0.35275626 0.25410894 -0.06426086 +C 11.01568351 -0.34017028 8.73432298 0.26795480 0.91517326 -0.29836194 +C 9.98268351 0.07282972 9.77332298 1.06981857 -0.91336664 2.00851760 +O 8.96868351 0.69882972 9.39532298 -2.15803649 1.50820145 -1.74604301 +O 10.17268351 -0.22717028 10.97132298 0.56024954 -0.38590733 0.29878620 +H 10.99468351 0.38682972 7.92032298 -0.05659098 0.15655890 -0.33104201 +H 10.75868351 -1.29517028 8.29232298 0.01621570 -0.56297290 -0.01553040 +H 12.04282351 -0.32501218 9.12771098 -0.21627379 -0.35549340 0.16728187 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.8976680601 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.202832026952576 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.35925429 0.01074807 0.54026134 +C 5.89300000 2.10500000 10.26700000 0.11243039 -1.45123740 -0.45959956 +N 6.46800000 0.95000000 9.98900000 -0.35156154 0.32046186 0.13504399 +N 4.58400000 2.24900000 10.11300000 -1.49915397 0.09575973 -0.29694833 +N 6.62900000 3.10900000 10.69900000 0.19864494 1.45229206 0.45801406 +H 5.91600000 0.16800000 9.69300000 -0.12415238 -0.30899058 -0.17400101 +H 7.49000000 0.89000000 9.89100000 1.70787868 -0.56381673 -0.16040867 +H 4.18700000 3.12900000 10.38500000 -0.32692571 0.32076929 0.10003298 +H 6.22600000 4.01600000 10.92500000 0.21056084 -0.29340729 -0.10849500 +H 7.61200000 2.96300000 10.84200000 0.60170260 -0.05010476 0.05564895 +H 3.74200000 0.36200000 10.38300000 -0.13761320 -0.27870287 0.12814576 +H 4.02000000 0.78400000 8.69500000 -0.07639135 0.07047833 -0.35204344 +H 2.63834300 1.49675000 9.60785000 0.35714911 0.25082701 -0.06483867 +C 11.24700000 -0.42600000 8.69400000 0.30148954 0.89447292 -0.31361860 +C 10.21400000 -0.01300000 9.73300000 0.75193029 -0.73064867 1.91589351 +O 9.20000000 0.61300000 9.35500000 -2.49982183 1.48654937 -1.64298006 +O 10.40400000 -0.31300000 10.93100000 0.65286275 -0.45957319 0.42380868 +H 11.22600000 0.30100000 7.88000000 -0.05536759 0.15836486 -0.33049230 +H 10.99000000 -1.38100000 8.25200000 0.01903172 -0.56707172 -0.01648819 +H 12.27414000 -0.41084190 9.08738800 -0.20194758 -0.35717031 0.16306455 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.6002785534 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.4521153909805475 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.34414440 -0.01502930 0.52899160 +C 5.89300000 2.10500000 10.26700000 0.05705550 -1.19428300 -0.40130021 +N 6.46800000 0.95000000 9.98900000 0.16331685 0.15975693 0.02717455 +N 4.58400000 2.24900000 10.11300000 -1.40154337 0.03264753 -0.29688434 +N 6.62900000 3.10900000 10.69900000 0.18061872 1.37697758 0.43020242 +H 5.91600000 0.16800000 9.69300000 -0.08912151 -0.33969764 -0.18227821 +H 7.49000000 0.89000000 9.89100000 1.20022936 -0.51698942 -0.09157667 +H 4.18700000 3.12900000 10.38500000 -0.31796585 0.32683760 0.10559126 +H 6.22600000 4.01600000 10.92500000 0.21108064 -0.28161129 -0.10641640 +H 7.61200000 2.96300000 10.84200000 0.61044778 -0.01989693 0.07322318 +H 3.74200000 0.36200000 10.38300000 -0.14136851 -0.27421738 0.13060811 +H 4.02000000 0.78400000 8.69500000 -0.07979265 0.07439611 -0.35393197 +H 2.63834300 1.49675000 9.60785000 0.36011547 0.24889686 -0.06531599 +C 11.47831649 -0.51182972 8.65367702 0.33097677 0.87492896 -0.32549802 +C 10.44531649 -0.09882972 9.69267702 0.51360441 -0.58583595 1.82877328 +O 9.43131649 0.52717028 9.31467702 -2.44451601 1.42145593 -1.63801061 +O 10.63531649 -0.39882972 10.89067702 0.72596925 -0.51889098 0.52407775 +H 11.45731649 0.21517028 7.83967702 -0.05486274 0.15985913 -0.32942705 +H 11.22131649 -1.46682972 8.21167702 0.02108925 -0.57071547 -0.01767102 +H 12.50545649 -0.49667162 9.04706502 -0.18947775 -0.35858929 0.15966835 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.3115292232 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.7014615040648895 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.33341623 -0.03316118 0.52044273 +C 5.89300000 2.10500000 10.26700000 -0.00653237 -1.00453795 -0.35331860 +N 6.46800000 0.95000000 9.98900000 0.47104796 0.03291116 -0.03767565 +N 4.58400000 2.24900000 10.11300000 -1.33084774 -0.01286014 -0.29962581 +N 6.62900000 3.10900000 10.69900000 0.17778874 1.32678990 0.41154460 +H 5.91600000 0.16800000 9.69300000 -0.07205139 -0.36226978 -0.18775851 +H 7.49000000 0.89000000 9.89100000 0.79353080 -0.46154196 -0.03588224 +H 4.18700000 3.12900000 10.38500000 -0.31301525 0.33351272 0.10946953 +H 6.22600000 4.01600000 10.92500000 0.21187158 -0.27058884 -0.10435613 +H 7.61200000 2.96300000 10.84200000 0.60915547 0.00976008 0.08927126 +H 3.74200000 0.36200000 10.38300000 -0.14410078 -0.27151816 0.13304260 +H 4.02000000 0.78400000 8.69500000 -0.08294422 0.07716246 -0.35547103 +H 2.63834300 1.49675000 9.60785000 0.36206729 0.24772247 -0.06576772 +C 11.70963297 -0.59765944 8.61335403 0.35744935 0.85657248 -0.33287152 +C 10.67663297 -0.18465944 9.65235403 0.32753481 -0.46546125 1.73372422 +O 9.66263297 0.44134056 9.27435403 -2.26754680 1.33658044 -1.64321075 +O 10.86663297 -0.48465944 10.85035403 0.78426036 -0.56660461 0.60764578 +H 11.68863297 0.12934056 7.79935403 -0.05531267 0.16119141 -0.32723107 +H 11.45263297 -1.55265944 8.17135403 0.02252734 -0.57372773 -0.01858201 +H 12.73677297 -0.58250134 9.00674203 -0.17829873 -0.35993152 0.15661032 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.0558351795 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.950862494024427 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.33239374 -0.03260084 0.51995435 +C 5.89300000 2.10500000 10.26700000 -0.08240113 -0.85131495 -0.31501166 +N 6.46800000 0.95000000 9.98900000 0.71457998 -0.12870005 -0.09229459 +N 4.58400000 2.24900000 10.11300000 -1.33308522 -0.03750281 -0.31340883 +N 6.62900000 3.10900000 10.69900000 0.21857970 1.33470233 0.41498292 +H 5.91600000 0.16800000 9.69300000 -0.06045866 -0.37491968 -0.18873586 +H 7.49000000 0.89000000 9.89100000 0.45312926 -0.40473079 -0.00077446 +H 4.18700000 3.12900000 10.38500000 -0.30993549 0.33319002 0.11196196 +H 6.22600000 4.01600000 10.92500000 0.21621137 -0.26563177 -0.10149813 +H 7.61200000 2.96300000 10.84200000 0.58985666 0.04153468 0.10490527 +H 3.74200000 0.36200000 10.38300000 -0.14768959 -0.27431826 0.13580133 +H 4.02000000 0.78400000 8.69500000 -0.08604623 0.07695946 -0.35861025 +H 2.63834300 1.49675000 9.60785000 0.36291639 0.24577354 -0.06636495 +C 11.94094946 -0.68348916 8.57303105 0.37943500 0.83634352 -0.32615146 +C 10.90794946 -0.27048916 9.61203105 0.19272743 -0.35793831 1.55409552 +O 9.89394946 0.35551084 9.23403105 -2.04870609 1.22741194 -1.58383376 +O 11.09794946 -0.57048916 10.81003105 0.81030589 -0.59456990 0.69107617 +H 11.91994946 0.04351084 7.75903105 -0.05847885 0.16319620 -0.32061736 +H 11.68394946 -1.63848916 8.13103105 0.02369628 -0.57563579 -0.01834808 +H 12.96808946 -0.66833106 8.96641905 -0.16703044 -0.36124852 0.15287188 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.8404623106 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.20031171854279 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.33839452 -0.01941137 0.52991258 +C 5.89300000 2.10500000 10.26700000 -0.15818724 -0.71530628 -0.31094276 +N 6.46800000 0.95000000 9.98900000 0.92241453 -0.32109975 -0.12772385 +N 4.58400000 2.24900000 10.11300000 -1.38870820 -0.04868368 -0.33334668 +N 6.62900000 3.10900000 10.69900000 0.28932217 1.38260043 0.43651110 +H 5.91600000 0.16800000 9.69300000 -0.05062105 -0.38049547 -0.18508076 +H 7.49000000 0.89000000 9.89100000 0.17521852 -0.35396026 0.01908812 +H 4.18700000 3.12900000 10.38500000 -0.30831020 0.32768769 0.11597183 +H 6.22600000 4.01600000 10.92500000 0.22119804 -0.26493482 -0.09362987 +H 7.61200000 2.96300000 10.84200000 0.55905558 0.07204777 0.12176243 +H 3.74200000 0.36200000 10.38300000 -0.15316018 -0.28052822 0.13687446 +H 4.02000000 0.78400000 8.69500000 -0.08716849 0.07462977 -0.36441078 +H 2.63834300 1.49675000 9.60785000 0.36293453 0.24312416 -0.06651286 +C 12.17226594 -0.76931887 8.53270807 0.39153733 0.81704238 -0.30866266 +C 11.13926594 -0.35631887 9.57170807 0.11187139 -0.26881974 1.31963101 +O 10.12526594 0.26968113 9.19370807 -1.83072233 1.11143527 -1.48263349 +O 11.32926594 -0.65631887 10.76970807 0.79896296 -0.60288334 0.77475475 +H 12.15126594 -0.04231887 7.71870807 -0.06241186 0.16605810 -0.31297256 +H 11.91526594 -1.72431887 8.09070807 0.02499737 -0.57673609 -0.01791320 +H 13.19940594 -0.75416077 8.92609607 -0.15661738 -0.36176655 0.14932322 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.6614529744 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.44980360654561 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.34578585 -0.00383099 0.53906116 +C 5.89300000 2.10500000 10.26700000 -0.22774561 -0.60987211 -0.30451012 +N 6.46800000 0.95000000 9.98900000 1.07968766 -0.49217433 -0.15109173 +N 4.58400000 2.24900000 10.11300000 -1.44889759 -0.05444518 -0.35354415 +N 6.62900000 3.10900000 10.69900000 0.35859479 1.43343715 0.46283321 +H 5.91600000 0.16800000 9.69300000 -0.04385167 -0.38298999 -0.18086601 +H 7.49000000 0.89000000 9.89100000 -0.02951935 -0.31255280 0.02776123 +H 4.18700000 3.12900000 10.38500000 -0.30728099 0.32365742 0.11591371 +H 6.22600000 4.01600000 10.92500000 0.22576028 -0.26421628 -0.08769937 +H 7.61200000 2.96300000 10.84200000 0.52857041 0.09847872 0.13514679 +H 3.74200000 0.36200000 10.38300000 -0.15691221 -0.28683225 0.13860407 +H 4.02000000 0.78400000 8.69500000 -0.08906844 0.07162956 -0.36993109 +H 2.63834300 1.49675000 9.60785000 0.36270046 0.24100626 -0.06698838 +C 12.40358243 -0.85514859 8.49238508 0.39568919 0.80214417 -0.29190314 +C 11.37058243 -0.44214859 9.53138508 0.06861251 -0.20391619 1.11285359 +O 10.35658243 0.18385141 9.15338508 -1.64709792 1.01248660 -1.39145650 +O 11.56058243 -0.74214859 10.72938508 0.77245197 -0.60206212 0.84460441 +H 12.38258243 -0.12814859 7.67838508 -0.06515899 0.16892689 -0.30779636 +H 12.14658243 -1.81014859 8.05038508 0.02620888 -0.57748656 -0.01799426 +H 13.43072243 -0.83999049 8.88577308 -0.14852921 -0.36138795 0.14700297 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.5130935556 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.69933336882864 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.35374022 0.01218831 0.54194124 +C 5.89300000 2.10500000 10.26700000 -0.29365954 -0.53888379 -0.26987506 +N 6.46800000 0.95000000 9.98900000 1.19829668 -0.63007213 -0.17751501 +N 4.58400000 2.24900000 10.11300000 -1.50186573 -0.05806003 -0.37392216 +N 6.62900000 3.10900000 10.69900000 0.42040056 1.47911109 0.48810210 +H 5.91600000 0.16800000 9.69300000 -0.03978192 -0.38349495 -0.17825621 +H 7.49000000 0.89000000 9.89100000 -0.17609655 -0.27872691 0.02815756 +H 4.18700000 3.12900000 10.38500000 -0.30671580 0.32328042 0.11033049 +H 6.22600000 4.01600000 10.92500000 0.23039129 -0.26256523 -0.08808989 +H 7.61200000 2.96300000 10.84200000 0.50118675 0.12110309 0.14309914 +H 3.74200000 0.36200000 10.38300000 -0.15760594 -0.29298710 0.14263788 +H 4.02000000 0.78400000 8.69500000 -0.09345589 0.06838630 -0.37344316 +H 2.63834300 1.49675000 9.60785000 0.36234278 0.23982147 -0.06826090 +C 12.63489891 -0.94097831 8.45206210 0.39576870 0.79090710 -0.27773254 +C 11.60189891 -0.52797831 9.49106210 0.05213831 -0.16092360 0.94349705 +O 10.58789891 0.09802169 9.11306210 -1.50490665 0.93376099 -1.30990758 +O 11.79189891 -0.82797831 10.68906210 0.74205155 -0.59557770 0.89657890 +H 12.61389891 -0.21397831 7.63806210 -0.06699924 0.17141020 -0.30450809 +H 12.37789891 -1.89597831 8.01006210 0.02718557 -0.57802938 -0.01837073 +H 13.66203891 -0.92582021 8.84545010 -0.14241516 -0.36064813 0.14553697 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.389301489 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.948896944752651 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.36201778 0.02632900 0.53765622 +C 5.89300000 2.10500000 10.26700000 -0.35735533 -0.49500614 -0.20594762 +N 6.46800000 0.95000000 9.98900000 1.28614612 -0.73396490 -0.20909149 +N 4.58400000 2.24900000 10.11300000 -1.53801286 -0.06556456 -0.39436338 +N 6.62900000 3.10900000 10.69900000 0.47213638 1.51154539 0.50865186 +H 5.91600000 0.16800000 9.69300000 -0.03863434 -0.38298168 -0.17793478 +H 7.49000000 0.89000000 9.89100000 -0.27860140 -0.25035947 0.02359613 +H 4.18700000 3.12900000 10.38500000 -0.30757421 0.33048744 0.10134203 +H 6.22600000 4.01600000 10.92500000 0.23248318 -0.25697632 -0.09433757 +H 7.61200000 2.96300000 10.84200000 0.47859576 0.13977947 0.14587069 +H 3.74200000 0.36200000 10.38300000 -0.15542504 -0.29858462 0.14884982 +H 4.02000000 0.78400000 8.69500000 -0.10034840 0.06523998 -0.37457863 +H 2.63834300 1.49675000 9.60785000 0.36148485 0.24017084 -0.07013562 +C 12.86621540 -1.02680803 8.41173911 0.39401719 0.78212346 -0.26548929 +C 11.83321540 -0.61380803 9.45073911 0.05137299 -0.13270778 0.80246933 +O 10.81921540 0.01219197 9.07273911 -1.39567559 0.87103837 -1.23523439 +O 12.02321540 -0.91380803 10.64873911 0.71156854 -0.58595215 0.93498178 +H 12.84521540 -0.29980803 7.59773911 -0.06842743 0.17355678 -0.30211152 +H 12.60921540 -1.98180803 7.96973911 0.02792528 -0.57837258 -0.01873862 +H 13.89335540 -1.01164993 8.80512711 -0.13769347 -0.35980051 0.14454506 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.2850015633 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=7.198490797924341 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.37025873 0.03679320 0.52726109 +C 5.89300000 2.10500000 10.26700000 -0.41874010 -0.46961901 -0.12040590 +N 6.46800000 0.95000000 9.98900000 1.34751112 -0.80634360 -0.24293597 +N 4.58400000 2.24900000 10.11300000 -1.55215781 -0.08038552 -0.41480523 +N 6.62900000 3.10900000 10.69900000 0.51246308 1.52573121 0.52245485 +H 5.91600000 0.16800000 9.69300000 -0.04051190 -0.38227501 -0.17992099 +H 7.49000000 0.89000000 9.89100000 -0.34726553 -0.22579504 0.01649408 +H 4.18700000 3.12900000 10.38500000 -0.31033252 0.34691896 0.09153114 +H 6.22600000 4.01600000 10.92500000 0.22989670 -0.24535900 -0.10444081 +H 7.61200000 2.96300000 10.84200000 0.46163630 0.15441190 0.14439421 +H 3.74200000 0.36200000 10.38300000 -0.15109713 -0.30323069 0.15641170 +H 4.02000000 0.78400000 8.69500000 -0.10900300 0.06248358 -0.37354656 +H 2.63834300 1.49675000 9.60785000 0.35989764 0.24229754 -0.07224353 +C 13.09753188 -1.11263775 8.37141613 0.39169488 0.77482976 -0.25428975 +C 12.06453188 -0.69963775 9.41041613 0.05855810 -0.11324835 0.68078827 +O 11.05053188 -0.07363775 9.03241613 -1.31009938 0.81985723 -1.16603783 +O 12.25453188 -0.99963775 10.60841613 0.68249918 -0.57500845 0.96441802 +H 13.07653188 -0.38563775 7.55741613 -0.06978467 0.17546626 -0.29992190 +H 12.84053188 -2.06763775 7.92941613 0.02845336 -0.57854165 -0.01893824 +H 14.12467188 -1.09747965 8.76480413 -0.13387705 -0.35898331 0.14373335 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.1962812111 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=7.448111902988495 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.37754720 0.04359837 0.51512072 +C 5.89300000 2.10500000 10.26700000 -0.47367109 -0.45303108 -0.03487791 +N 6.46800000 0.95000000 9.98900000 1.38861066 -0.85680080 -0.27239639 +N 4.58400000 2.24900000 10.11300000 -1.55122778 -0.09896012 -0.43428794 +N 6.62900000 3.10900000 10.69900000 0.54284081 1.52685641 0.53011787 +H 5.91600000 0.16800000 9.69300000 -0.04442488 -0.38195291 -0.18311568 +H 7.49000000 0.89000000 9.89100000 -0.39197710 -0.20464706 0.00900612 +H 4.18700000 3.12900000 10.38500000 -0.31420362 0.36755733 0.08382543 +H 6.22600000 4.01600000 10.92500000 0.22365429 -0.23011075 -0.11440689 +H 7.61200000 2.96300000 10.84200000 0.44973989 0.16517788 0.14117202 +H 3.74200000 0.36200000 10.38300000 -0.14643947 -0.30690576 0.16358271 +H 4.02000000 0.78400000 8.69500000 -0.11741531 0.06036758 -0.37152548 +H 2.63834300 1.49675000 9.60785000 0.35787965 0.24533246 -0.07406850 +C 13.32884837 -1.19846747 8.33109315 0.38951719 0.76854351 -0.24401572 +C 12.29584837 -0.78546747 9.37009315 0.06823686 -0.09870700 0.57508989 +O 11.28184837 -0.15946747 8.99209315 -1.24176287 0.77751437 -1.10303557 +O 12.48584837 -1.08546747 10.56809315 0.65619671 -0.56414546 0.98744130 +H 13.30784837 -0.47146747 7.51709315 -0.07118391 0.17716960 -0.29769075 +H 13.07184837 -2.15346747 7.88909315 0.02879423 -0.57858633 -0.01892994 +H 14.35598837 -1.18330937 8.72448115 -0.13071147 -0.35827024 0.14299471 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.1201126211 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=7.697757592338221 pbc="T T T" +C 3.69000000 1.17800000 9.65700000 0.38350043 0.04787129 0.50399312 +C 5.89300000 2.10500000 10.26700000 -0.52018448 -0.44024597 0.03892637 +N 6.46800000 0.95000000 9.98900000 1.41572337 -0.89417673 -0.29492878 +N 4.58400000 2.24900000 10.11300000 -1.54381014 -0.11717377 -0.45207714 +N 6.62900000 3.10900000 10.69900000 0.56579697 1.52207410 0.53385264 +H 5.91600000 0.16800000 9.69300000 -0.04928940 -0.38205144 -0.18657280 +H 7.49000000 0.89000000 9.89100000 -0.42072231 -0.18652066 0.00197465 +H 4.18700000 3.12900000 10.38500000 -0.31823617 0.38776721 0.07881884 +H 6.22600000 4.01600000 10.92500000 0.21581989 -0.21424380 -0.12238360 +H 7.61200000 2.96300000 10.84200000 0.44168674 0.17276817 0.13778616 +H 3.74200000 0.36200000 10.38300000 -0.14240354 -0.30984250 0.16956974 +H 4.02000000 0.78400000 8.69500000 -0.12455528 0.05884660 -0.36934326 +H 2.63834300 1.49675000 9.60785000 0.35581531 0.24846438 -0.07543273 +C 13.56016485 -1.28429719 8.29077016 0.38748686 0.76318281 -0.23499964 +C 12.52716485 -0.87129719 9.32977016 0.07871107 -0.08787234 0.48493287 +O 11.51316485 -0.24529719 8.95177016 -1.18652256 0.74248316 -1.04749047 +O 12.71716485 -1.17129719 10.52777016 0.63287983 -0.55387046 1.00532110 +H 13.53916485 -0.55729719 7.47677016 -0.07253754 0.17868370 -0.29555378 +H 13.30316485 -2.23929719 7.84877016 0.02897402 -0.57854115 -0.01876909 +H 14.58730485 -1.26913909 8.68415816 -0.12813309 -0.35760260 0.14237580 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.434099606 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.234635908871504 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 0.01478298 -0.02673130 -0.06649977 +C 25.43700000 -3.85300000 -1.56500000 -2.19596691 -0.40845873 -0.24091970 +O 26.43300000 -3.22700000 -1.14000000 2.95246173 0.09947169 0.01044332 +O 24.27400000 -3.40300000 -1.47500000 -0.61717201 -0.07186745 -0.23253201 +H 26.34900000 -5.06000000 -3.05900000 0.34482881 -0.12896995 -0.16052409 +H 24.71500000 -5.57700000 -2.64500000 -0.14184215 -0.08356096 0.07285538 +H 26.07672000 -5.94638300 -1.53698600 0.05570445 0.10000252 -0.02955307 +C 25.01868999 0.94028982 1.66744602 -0.33311378 -0.17561577 -0.54357879 +C 25.44768999 -0.19971018 -0.47955398 0.73865200 -1.41414437 1.40217655 +N 25.98668999 -1.23271018 0.14444602 -0.41403746 2.77828796 1.25253205 +N 24.98468999 0.83728982 0.20644602 -0.45419181 1.50420659 0.82713143 +N 25.36468999 -0.21271018 -1.79455398 -0.10012869 0.42692558 -1.37512881 +H 26.14768999 -1.20471018 1.13444602 -0.16631449 0.09122990 0.34376481 +H 26.25868999 -2.06271018 -0.39055398 0.26146095 -2.30380404 -1.30570976 +H 24.60468999 1.61828982 -0.31055398 -0.05992581 0.06060549 0.01899363 +H 25.01468999 0.59228982 -2.29355398 -0.04795805 -0.12465318 -0.11495049 +H 25.78768999 -0.97071018 -2.31055398 -0.08126554 -0.33622536 -0.05168432 +H 24.80868999 1.97128982 1.96044602 -0.04016367 0.08190611 -0.06323108 +H 26.00868999 0.68128982 2.04844602 0.17548997 -0.05440713 0.11839257 +H 24.25272999 0.28405892 2.10637702 0.10869947 -0.01419760 0.13802216 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.4095196711 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.484376426240713 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 0.00273026 -0.06174100 -0.08231323 +C 25.43700000 -3.85300000 -1.56500000 -1.81793911 -0.07845036 -0.05356085 +O 26.43300000 -3.22700000 -1.14000000 2.62227439 1.03002551 0.59781226 +O 24.27400000 -3.40300000 -1.47500000 -0.84403718 -0.04452061 -0.24893233 +H 26.34900000 -5.06000000 -3.05900000 0.34135003 -0.12680825 -0.16074181 +H 24.71500000 -5.57700000 -2.64500000 -0.14454553 -0.09783094 0.06523007 +H 26.07672000 -5.94638300 -1.53698600 0.05243828 0.09605397 -0.02907044 +C 25.00884500 1.16864491 1.76872301 -0.33555583 -0.18236146 -0.49605107 +C 25.43784500 0.02864491 -0.37827699 0.58372835 -1.17442642 1.04663712 +N 25.97684500 -1.00435509 0.24572301 -0.09256694 1.41052472 0.51007664 +N 24.97484500 1.06564491 0.30772301 -0.37042039 1.35013080 0.82855842 +N 25.35484500 0.01564491 -1.69327699 -0.08450647 0.38053229 -1.23111975 +H 26.13784500 -0.97635509 1.23572301 -0.11643521 -0.03844047 0.30546144 +H 26.24884500 -1.83435509 -0.28927699 0.13851684 -2.02093547 -1.02508585 +H 24.59484500 1.84664491 -0.20927699 -0.04913269 0.04519536 0.00257139 +H 25.00484500 0.82064491 -2.19227699 -0.05461016 -0.11775466 -0.12248771 +H 25.77784500 -0.74235509 -2.20927699 -0.07967461 -0.39083589 -0.09935094 +H 24.79884500 2.19964491 2.06172301 -0.03379450 0.07387408 -0.06191496 +H 25.99884500 0.90964491 2.14972301 0.17708496 -0.04464721 0.12127108 +H 24.24288500 0.51241401 2.20765401 0.10509551 -0.00758397 0.13301053 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.1715863393 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.734144335052735 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.00720444 -0.09229022 -0.09735001 +C 25.43700000 -3.85300000 -1.56500000 -1.54048458 0.16397162 0.08479951 +O 26.43300000 -3.22700000 -1.14000000 2.46330385 1.19829533 0.71225161 +O 24.27400000 -3.40300000 -1.47500000 -1.01079428 -0.04135087 -0.26208442 +H 26.34900000 -5.06000000 -3.05900000 0.33869880 -0.12485425 -0.16116924 +H 24.71500000 -5.57700000 -2.64500000 -0.14782331 -0.10965738 0.05846671 +H 26.07672000 -5.94638300 -1.53698600 0.05013175 0.09318524 -0.02808354 +C 24.99900000 1.39700000 1.87000000 -0.33619998 -0.18683754 -0.45816277 +C 25.42800000 0.25700000 -0.27700000 0.46832267 -0.97267440 0.82186186 +N 25.96700000 -0.77600000 0.34700000 0.06757647 0.67119693 0.15651319 +N 24.96500000 1.29400000 0.40900000 -0.30904297 1.23247290 0.82032107 +N 25.34500000 0.24400000 -1.59200000 -0.07478063 0.34361838 -1.13265661 +H 26.12800000 -0.74800000 1.33700000 -0.08394056 -0.11621515 0.29214431 +H 26.23900000 -1.60600000 -0.18800000 0.05142474 -1.60578117 -0.70496041 +H 24.58500000 2.07500000 -0.10800000 -0.04377883 0.03941582 -0.01019538 +H 24.99500000 1.04900000 -2.09100000 -0.05891874 -0.11196327 -0.13300817 +H 25.76800000 -0.51400000 -2.10800000 -0.07705718 -0.40911834 -0.14881912 +H 24.78900000 2.42800000 2.16300000 -0.02975249 0.06857294 -0.06153557 +H 25.98900000 1.13800000 2.25100000 0.17795814 -0.03760176 0.12273814 +H 24.23304000 0.74076910 2.30893100 0.10236157 -0.00238481 0.12892885 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.8815163103 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.983935517010137 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.01628402 -0.11935261 -0.11233664 +C 25.43700000 -3.85300000 -1.56500000 -1.32446867 0.34499724 0.18986761 +O 26.43300000 -3.22700000 -1.14000000 2.36636784 1.10438470 0.67714523 +O 24.27400000 -3.40300000 -1.47500000 -1.13936889 -0.05125087 -0.27278601 +H 26.34900000 -5.06000000 -3.05900000 0.33676363 -0.12311210 -0.16167538 +H 24.71500000 -5.57700000 -2.64500000 -0.15126033 -0.11971344 0.05236338 +H 26.07672000 -5.94638300 -1.53698600 0.04850762 0.09109153 -0.02686815 +C 24.98915500 1.62535509 1.97127699 -0.33583574 -0.18990243 -0.42749986 +C 25.41815500 0.48535509 -0.17572301 0.38089171 -0.80276037 0.67964239 +N 25.95715500 -0.54764491 0.44827699 0.15428052 0.24205869 -0.01982784 +N 24.95515500 1.52235509 0.51027699 -0.26272221 1.13981087 0.80712334 +N 25.33515500 0.47235509 -1.49072301 -0.06919197 0.31168821 -1.06489448 +H 26.11815500 -0.51964491 1.43827699 -0.06168949 -0.16292551 0.29095501 +H 26.22915500 -1.37764491 -0.08672301 -0.00108426 -1.22736215 -0.43940677 +H 24.57515500 2.30335509 -0.00672301 -0.04144604 0.03862284 -0.02034127 +H 24.98515500 1.27735509 -1.98972301 -0.06187873 -0.10687129 -0.14467866 +H 25.75815500 -0.28564491 -2.00672301 -0.07319776 -0.40375402 -0.19414486 +H 24.77915500 2.65635509 2.26427699 -0.02709212 0.06487330 -0.06161683 +H 25.97915500 1.36635509 2.35227699 0.17852724 -0.03232098 0.12339590 +H 24.22319500 0.96912419 2.41020799 0.10018167 0.00179838 0.12558389 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.5976487247 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.233746639606387 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.02457583 -0.14287467 -0.12667042 +C 25.43700000 -3.85300000 -1.56500000 -1.15024785 0.48192575 0.27112924 +O 26.43300000 -3.22700000 -1.14000000 2.29370442 0.94059550 0.60532708 +O 24.27400000 -3.40300000 -1.47500000 -1.24157638 -0.06804811 -0.28187319 +H 26.34900000 -5.06000000 -3.05900000 0.33543428 -0.12157948 -0.16227024 +H 24.71500000 -5.57700000 -2.64500000 -0.15462966 -0.12830728 0.04690626 +H 26.07672000 -5.94638300 -1.53698600 0.04738910 0.08948846 -0.02548417 +C 24.97931001 1.85371018 2.07255398 -0.33498138 -0.19215461 -0.40221457 +C 25.40831001 0.71371018 -0.07444602 0.31332548 -0.65862905 0.58879798 +N 25.94731001 -0.31928982 0.54955398 0.20462919 -0.02606294 -0.11121301 +N 24.94531001 1.75071018 0.61155398 -0.22652446 1.06428609 0.79205350 +N 25.32531001 0.70071018 -1.38944602 -0.06647447 0.28276270 -1.01819820 +H 26.10831001 -0.29128982 1.53955398 -0.04553189 -0.19128515 0.29543094 +H 26.21931001 -1.14928982 0.01455398 -0.02858454 -0.92366379 -0.23850401 +H 24.56531001 2.53171018 0.09455398 -0.04096362 0.04070778 -0.02880251 +H 24.97531001 1.50571018 -1.88844602 -0.06414620 -0.10195896 -0.15637197 +H 25.74831001 -0.05728982 -1.90544602 -0.06824883 -0.38457340 -0.23259449 +H 24.76931001 2.88471018 2.36555398 -0.02535085 0.06228181 -0.06192792 +H 25.96931001 1.59471018 2.45355398 0.17897296 -0.02822307 0.12362162 +H 24.21335001 1.19747928 2.51148498 0.09838052 0.00531242 0.12285808 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.3385023881 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.483574974256216 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.03179903 -0.16367972 -0.14063061 +C 25.43700000 -3.85300000 -1.56500000 -1.00776979 0.58684647 0.33490802 +O 26.43300000 -3.22700000 -1.14000000 2.23286206 0.77721388 0.53437628 +O 24.27400000 -3.40300000 -1.47500000 -1.32358341 -0.08816560 -0.28971796 +H 26.34900000 -5.06000000 -3.05900000 0.33452822 -0.12031318 -0.16289057 +H 24.71500000 -5.57700000 -2.64500000 -0.15786723 -0.13558667 0.04214258 +H 26.07672000 -5.94638300 -1.53698600 0.04659999 0.08817127 -0.02394025 +C 24.96946501 2.08206527 2.17383096 -0.33395748 -0.19402607 -0.38110997 +C 25.39846501 0.94206527 0.02683096 0.26045338 -0.53503745 0.53019406 +N 25.93746501 -0.09093473 0.65083096 0.23535818 -0.20539944 -0.15910069 +N 24.93546501 1.97906527 0.71283096 -0.19738079 1.00074262 0.77720470 +N 25.31546501 0.92906527 -1.28816904 -0.06582195 0.25574602 -0.98650037 +H 26.09846501 -0.06293473 1.64083096 -0.03316942 -0.20869137 0.30241715 +H 26.20946501 -0.92093473 0.11583096 -0.04012098 -0.69141430 -0.09193791 +H 24.55546501 2.76006527 0.19583096 -0.04177162 0.04485904 -0.03642289 +H 24.96546501 1.73406527 -1.78716904 -0.06617361 -0.09678583 -0.16746794 +H 25.73846501 0.17106527 -1.80416904 -0.06245884 -0.35846910 -0.26344718 +H 24.75946501 3.11306527 2.46683096 -0.02424537 0.06059665 -0.06240015 +H 25.95946501 1.82306527 2.55483096 0.17943472 -0.02496715 0.12363763 +H 24.20350501 1.42583437 2.61276196 0.09688298 0.00835993 0.12068609 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.1076496113 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.733418286779269 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.03777314 -0.18073865 -0.15283819 +C 25.43700000 -3.85300000 -1.56500000 -0.88773952 0.66251515 0.38374356 +O 26.43300000 -3.22700000 -1.14000000 2.17605209 0.63439949 0.47262313 +O 24.27400000 -3.40300000 -1.47500000 -1.38753233 -0.10665508 -0.29504592 +H 26.34900000 -5.06000000 -3.05900000 0.33377386 -0.11920578 -0.16358126 +H 24.71500000 -5.57700000 -2.64500000 -0.16100694 -0.14153399 0.03803804 +H 26.07672000 -5.94638300 -1.53698600 0.04594276 0.08717550 -0.02240545 +C 24.95962002 2.31042037 2.27510795 -0.33278054 -0.19593390 -0.36478750 +C 25.38862002 1.17042037 0.12810795 0.21747811 -0.42529171 0.49234322 +N 25.92762002 0.13742037 0.75210795 0.25582104 -0.34037708 -0.18139179 +N 24.92562002 2.20742037 0.81410795 -0.17417951 0.94917803 0.76663104 +N 25.30562002 1.15742037 -1.18689205 -0.06822013 0.22810978 -0.97065838 +H 26.08862002 0.16542037 1.74210795 -0.02306738 -0.21933524 0.30996659 +H 26.19962002 -0.69257963 0.21710795 -0.04185409 -0.51295236 0.01539898 +H 24.54562002 2.98842037 0.29710795 -0.04296012 0.05178889 -0.04401425 +H 24.95562002 1.96242037 -1.68589205 -0.06766195 -0.09098860 -0.17750288 +H 25.72862002 0.39942037 -1.70289205 -0.05604282 -0.32840941 -0.28677314 +H 24.74962002 3.34142037 2.56810795 -0.02358620 0.05979909 -0.06297609 +H 25.94962002 2.05142037 2.65610795 0.17985177 -0.02221663 0.12393525 +H 24.19366002 1.65418947 2.71403895 0.09548503 0.01067252 0.11929501 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.9073116316 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.983274680706614 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.04697711 -0.17864904 -0.15518480 +C 25.43700000 -3.85300000 -1.56500000 -0.72530526 0.60405922 0.37206550 +O 26.43300000 -3.22700000 -1.14000000 2.04035619 0.53956199 0.42669274 +O 24.27400000 -3.40300000 -1.47500000 -1.40770419 -0.07921543 -0.27002536 +H 26.34900000 -5.06000000 -3.05900000 0.33105578 -0.11695696 -0.16402126 +H 24.71500000 -5.57700000 -2.64500000 -0.16596953 -0.14771955 0.03273865 +H 26.07672000 -5.94638300 -1.53698600 0.04320332 0.08795534 -0.02080123 +C 24.94977502 2.53877546 2.37638494 -0.32482020 -0.19427369 -0.37457700 +C 25.37877502 1.39877546 0.22938494 0.12605606 -0.32510601 0.47145518 +N 25.91777502 0.36577546 0.85338494 0.32746196 -0.53348284 -0.15948086 +N 24.91577502 2.43577546 0.91538494 -0.17445264 0.95928571 0.79830500 +N 25.29577502 1.38577546 -1.08561506 -0.07873289 0.18322050 -1.03749556 +H 26.07877502 0.39377546 1.84338494 -0.00779484 -0.22572562 0.30856380 +H 26.18977502 -0.46422454 0.31838494 -0.04256240 -0.33638276 0.12095249 +H 24.53577502 3.21677546 0.39838494 -0.03501628 0.06578787 -0.05124595 +H 24.94577502 2.19077546 -1.58461506 -0.05847545 -0.07583416 -0.18883457 +H 25.71877502 0.62777546 -1.60161506 -0.04742696 -0.27470674 -0.29907204 +H 24.73977502 3.56977546 2.66938494 -0.02180874 0.05983711 -0.06255187 +H 25.93977502 2.27977546 2.75738494 0.17887311 -0.01804756 0.13047981 +H 24.18381502 1.88254456 2.81531594 0.09004007 0.00639264 0.12203734 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.7385235753 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.233142590610293 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.05580857 -0.17108762 -0.15378602 +C 25.43700000 -3.85300000 -1.56500000 -0.58131702 0.51109991 0.33964965 +O 26.43300000 -3.22700000 -1.14000000 1.90181014 0.47931435 0.39802489 +O 24.27400000 -3.40300000 -1.47500000 -1.40785744 -0.04363963 -0.23943019 +H 26.34900000 -5.06000000 -3.05900000 0.32846862 -0.11484266 -0.16463427 +H 24.71500000 -5.57700000 -2.64500000 -0.17072528 -0.15318664 0.02760716 +H 26.07672000 -5.94638300 -1.53698600 0.04051124 0.08872440 -0.01949925 +C 24.93993003 2.76713055 2.47766193 -0.31509757 -0.19157025 -0.38930336 +C 25.36893003 1.62713055 0.33066193 0.02798797 -0.24639176 0.46036261 +N 25.90793003 0.59413055 0.95466193 0.40814117 -0.70515029 -0.12851091 +N 24.90593003 2.66413055 1.01666193 -0.18011326 0.98079719 0.83549321 +N 25.28593003 1.61413055 -0.98433807 -0.08651364 0.14011066 -1.11429129 +H 26.06893003 0.62213055 1.94466193 0.00721208 -0.22943826 0.30588142 +H 26.17993003 -0.23586945 0.41966193 -0.04441689 -0.19281672 0.20676410 +H 24.52593003 3.44513055 0.49966193 -0.02713037 0.07930055 -0.05830437 +H 24.93593003 2.41913055 -1.48333807 -0.04840547 -0.05633948 -0.20070586 +H 25.70893003 0.85613055 -1.50033807 -0.03837376 -0.22167502 -0.30623660 +H 24.72993003 3.79813055 2.77066193 -0.02003956 0.06016482 -0.06202049 +H 25.92993003 2.50813055 2.85866193 0.17765801 -0.01428161 0.13769663 +H 24.17397003 2.11089965 2.91659293 0.08400960 0.00090806 0.12524293 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.5961329345 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.48302068543071 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.06303104 -0.16249435 -0.15099462 +C 25.43700000 -3.85300000 -1.56500000 -0.46299967 0.41553878 0.30336215 +O 26.43300000 -3.22700000 -1.14000000 1.78280394 0.43911967 0.37890457 +O 24.27400000 -3.40300000 -1.47500000 -1.40217679 -0.00869193 -0.21064581 +H 26.34900000 -5.06000000 -3.05900000 0.32641089 -0.11289306 -0.16555923 +H 24.71500000 -5.57700000 -2.64500000 -0.17532078 -0.15767561 0.02314488 +H 26.07672000 -5.94638300 -1.53698600 0.03829224 0.08916945 -0.01819089 +C 24.93008503 2.99548564 2.57893892 -0.30554053 -0.18940464 -0.40305294 +C 25.35908503 1.85548564 0.43193892 -0.06026893 -0.18323461 0.45475419 +N 25.89808503 0.82248564 1.05593892 0.47910854 -0.84670485 -0.09780572 +N 24.89608503 2.89248564 1.11793892 -0.18517059 1.00140448 0.86982123 +N 25.27608503 1.84248564 -0.88306108 -0.09314183 0.10068928 -1.18331049 +H 26.05908503 0.85048564 2.04593892 0.02016475 -0.23080588 0.30356841 +H 26.17008503 -0.00751436 0.52093892 -0.04528960 -0.08029537 0.27207594 +H 24.51608503 3.67348564 0.60093892 -0.02033887 0.09204692 -0.06543985 +H 24.92608503 2.64748564 -1.38206108 -0.03971947 -0.03640469 -0.21113276 +H 25.69908503 1.08448564 -1.39906108 -0.02953805 -0.17518621 -0.30980275 +H 24.72008503 4.02648564 2.87193892 -0.01868199 0.06079203 -0.06182397 +H 25.92008503 2.73648564 2.95993892 0.17586066 -0.01080067 0.14413321 +H 24.16412503 2.33925474 3.01786992 0.07857712 -0.00416875 0.12799445 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.4753909764 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.732907830696661 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.06874745 -0.15532656 -0.14871687 +C 25.43700000 -3.85300000 -1.56500000 -0.37059648 0.34096991 0.27492736 +O 26.43300000 -3.22700000 -1.14000000 1.68474690 0.40744213 0.36365850 +O 24.27400000 -3.40300000 -1.47500000 -1.39254489 0.01869988 -0.18749397 +H 26.34900000 -5.06000000 -3.05900000 0.32470813 -0.11164204 -0.16612752 +H 24.71500000 -5.57700000 -2.64500000 -0.17849777 -0.16129036 0.01957414 +H 26.07672000 -5.94638300 -1.53698600 0.03649125 0.08944626 -0.01745855 +C 24.92024004 3.22384073 2.68021591 -0.29691993 -0.18784774 -0.41277065 +C 25.34924004 2.08384073 0.53321591 -0.13495099 -0.13206680 0.45151490 +N 25.88824004 1.05084073 1.15721591 0.53289749 -0.95506663 -0.07370039 +N 24.88624004 3.12084073 1.21921591 -0.18547521 1.01091849 0.89545232 +N 25.26624004 2.07084073 -0.78178409 -0.09869449 0.06665803 -1.23369191 +H 26.04924004 1.07884073 2.14721591 0.03117697 -0.23131608 0.30487829 +H 26.16024004 0.22084073 0.62221591 -0.04416944 0.00478574 0.31981766 +H 24.50624004 3.90184073 0.70221591 -0.01621432 0.10547350 -0.07344623 +H 24.91624004 2.87584073 -1.28078409 -0.03400802 -0.01624068 -0.22160120 +H 25.68924004 1.31284073 -1.29778409 -0.02028770 -0.13888479 -0.31270429 +H 24.71024004 4.25484073 2.97321591 -0.01745588 0.06187800 -0.06172835 +H 25.91024004 2.96484073 3.06121591 0.17472244 -0.00797236 0.14948695 +H 24.15428004 2.56760983 3.11914691 0.07381939 -0.00861789 0.13012980 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.3722607997 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.982803051457227 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.07341265 -0.14803780 -0.14575823 +C 25.43700000 -3.85300000 -1.56500000 -0.29297357 0.26850244 0.24610376 +O 26.43300000 -3.22700000 -1.14000000 1.60027063 0.38605706 0.35292650 +O 24.27400000 -3.40300000 -1.47500000 -1.38161765 0.04465404 -0.16637260 +H 26.34900000 -5.06000000 -3.05900000 0.32322971 -0.11028653 -0.16679780 +H 24.71500000 -5.57700000 -2.64500000 -0.18161418 -0.16426097 0.01648803 +H 26.07672000 -5.94638300 -1.53698600 0.03489391 0.08968838 -0.01660099 +C 24.91039504 3.45219582 2.78149289 -0.28820582 -0.18681857 -0.42121584 +C 25.33939504 2.31219582 0.63449289 -0.20388508 -0.09139960 0.45013052 +N 25.87839504 1.27919582 1.25849289 0.57970589 -1.04478346 -0.05138096 +N 24.87639504 3.34919582 1.32049289 -0.18424074 1.01861396 0.91878489 +N 25.25639504 2.29919582 -0.68050711 -0.10344678 0.03594690 -1.27646054 +H 26.03939504 1.30719582 2.24849289 0.04077274 -0.23041907 0.30632760 +H 26.15039504 0.44919582 0.72349289 -0.04239163 0.07290146 0.35612796 +H 24.49639504 4.13019582 0.80349289 -0.01262108 0.11856202 -0.08177028 +H 24.90639504 3.10419582 -1.17950711 -0.02934563 0.00427515 -0.23080539 +H 25.67939504 1.54119582 -1.19650711 -0.01102302 -0.10843248 -0.31380274 +H 24.70039504 4.48319582 3.07449289 -0.01651246 0.06319122 -0.06195931 +H 25.90039504 3.19319582 3.16249289 0.17289808 -0.00519888 0.15424830 +H 24.14443504 2.79596492 3.22042389 0.06951933 -0.01275528 0.13178712 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.283584221 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=7.232705517383349 pbc="T T T" +C 25.65400000 -5.20500000 -2.23100000 -0.07701164 -0.14144769 -0.14280134 +C 25.43700000 -3.85300000 -1.56500000 -0.22954974 0.20492092 0.22045168 +O 26.43300000 -3.22700000 -1.14000000 1.52868993 0.37040271 0.34462456 +O 24.27400000 -3.40300000 -1.47500000 -1.36979711 0.06708799 -0.14825066 +H 26.34900000 -5.06000000 -3.05900000 0.32191463 -0.10900815 -0.16738145 +H 24.71500000 -5.57700000 -2.64500000 -0.18428671 -0.16659603 0.01392968 +H 26.07672000 -5.94638300 -1.53698600 0.03347384 0.08995873 -0.01583419 +C 24.90055005 3.68055091 2.88276988 -0.27967752 -0.18626508 -0.42746477 +C 25.32955005 2.54055091 0.73576988 -0.26637601 -0.05916111 0.44949244 +N 25.86855005 1.50755091 1.35976988 0.61775732 -1.11624141 -0.03256894 +N 24.86655005 3.57755091 1.42176988 -0.18025487 1.02148660 0.93806925 +N 25.24655005 2.52755091 -0.57923012 -0.10744427 0.00894870 -1.30882863 +H 26.02955005 1.53555091 2.34976988 0.04912671 -0.22873752 0.30893427 +H 26.14055005 0.67755091 0.82476988 -0.03959243 0.12672612 0.38287074 +H 24.48655005 4.35855091 0.90476988 -0.01002740 0.13167916 -0.09057240 +H 24.89655005 3.33255091 -1.07823012 -0.02615095 0.02497777 -0.23928534 +H 25.66955005 1.76955091 -1.09523012 -0.00152467 -0.08439543 -0.31424625 +H 24.69055005 4.71155091 3.17576988 -0.01575815 0.06476085 -0.06241988 +H 25.89055005 3.42155091 3.26376988 0.17081394 -0.00258637 0.15834054 +H 24.13459005 3.02432001 3.32170088 0.06567511 -0.01651077 0.13294069 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.2894487694 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=3.911637245564241 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.91749302 -0.01307912 0.97976456 +C 31.01900000 -11.54600000 60.23100000 0.15930957 1.14094872 -1.01979669 +N 29.86200000 -11.49700000 60.84900000 -1.23949050 -0.99774146 1.18252303 +N 31.29100000 -10.55900000 59.39400000 2.78575208 -2.02478630 -1.05462080 +N 31.82000000 -12.58200000 60.45800000 0.70977221 -0.85360608 0.33862873 +H 29.30600000 -10.65300000 60.75300000 -0.34430883 0.92659963 -0.10477047 +H 29.60200000 -12.19700000 61.53200000 0.01447233 0.03338724 -0.07806569 +H 30.57700000 -9.82700000 59.36500000 -1.41575420 1.35014656 0.57428387 +H 32.67200000 -12.69900000 59.93600000 0.12649005 -0.18983316 0.02378014 +H 31.49700000 -13.30000000 61.09500000 0.33426279 -0.07741387 -0.15765094 +H 32.42700000 -9.97000000 57.72400000 0.03030579 0.01446144 -0.14272433 +H 33.27200000 -11.11900000 58.79900000 0.19682963 -0.06530720 -0.06155264 +H 32.99285000 -9.42516400 59.34181000 0.44226853 -0.00741592 -0.31050909 +C 29.25927182 -8.35837272 57.78753400 0.28862041 0.37609784 -0.48575306 +C 28.87927182 -8.31037272 59.24853400 -2.99015733 2.07112234 -1.13011838 +O 29.49027182 -9.07537272 60.01553400 1.28772129 -1.43524387 1.80178795 +O 27.90127182 -7.60237272 59.55853400 0.22997245 0.08453952 0.03079462 +H 28.71627182 -9.18237272 57.31853400 -0.12557445 -0.15546186 -0.14890725 +H 30.32527182 -8.55737272 57.68153400 0.39825686 -0.01187292 -0.30469341 +H 28.99992182 -7.42286772 57.27026400 0.02874434 -0.16554152 0.06759986 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.3603857223 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.158329697640593 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.90172371 0.12871010 0.92032356 +C 31.01900000 -11.54600000 60.23100000 0.17600159 1.01636289 -0.93118290 +N 29.86200000 -11.49700000 60.84900000 -1.24451297 -0.57300723 1.03535432 +N 31.29100000 -10.55900000 59.39400000 1.94256997 -1.35900971 -0.72477895 +N 31.82000000 -12.58200000 60.45800000 0.64149945 -0.76740453 0.29703589 +H 29.30600000 -10.65300000 60.75300000 -0.40832903 0.83122077 -0.10602299 +H 29.60200000 -12.19700000 61.53200000 -0.04405607 0.08643057 -0.06936744 +H 30.57700000 -9.82700000 59.36500000 -1.36441762 1.42380935 0.28936412 +H 32.67200000 -12.69900000 59.93600000 0.13211265 -0.19358611 0.02260982 +H 31.49700000 -13.30000000 61.09500000 0.33184594 -0.08539067 -0.15573867 +H 32.42700000 -9.97000000 57.72400000 0.02059284 0.01689826 -0.13274990 +H 33.27200000 -11.11900000 58.79900000 0.13770921 -0.06887196 -0.04132607 +H 32.99285000 -9.42516400 59.34181000 0.43186679 -0.01598132 -0.31629966 +C 29.11013591 -8.17968636 57.69626700 0.28731099 0.37458746 -0.51406445 +C 28.73013591 -8.13168636 59.15726700 -2.61724985 1.69236590 -1.03996204 +O 29.34113591 -8.89668636 59.92426700 2.05590837 -2.34871777 1.78653479 +O 27.75213591 -7.42368636 59.46726700 0.11966767 0.18560274 0.04988769 +H 28.56713591 -9.00368636 57.22726700 -0.13385219 -0.15498115 -0.15039346 +H 30.17613591 -8.37868636 57.59026700 0.41480759 -0.03474115 -0.25924159 +H 28.85078591 -7.24418136 57.17899700 0.02224841 -0.15429644 0.04001794 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.1700065143 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.40539507967846 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.87100741 0.22908970 0.86816072 +C 31.01900000 -11.54600000 60.23100000 0.18443116 0.90051754 -0.85458082 +N 29.86200000 -11.49700000 60.84900000 -1.25285790 -0.33649210 0.95389649 +N 31.29100000 -10.55900000 59.39400000 1.42094902 -0.91036104 -0.56976584 +N 31.82000000 -12.58200000 60.45800000 0.58348227 -0.68449169 0.26050929 +H 29.30600000 -10.65300000 60.75300000 -0.44451662 0.67564855 -0.06876312 +H 29.60200000 -12.19700000 61.53200000 -0.08655168 0.11454391 -0.06068137 +H 30.57700000 -9.82700000 59.36500000 -1.13455971 1.30397346 0.04296863 +H 32.67200000 -12.69900000 59.93600000 0.13836881 -0.19653967 0.02032466 +H 31.49700000 -13.30000000 61.09500000 0.32825666 -0.09280612 -0.15195979 +H 32.42700000 -9.97000000 57.72400000 0.01358948 0.01721160 -0.12458035 +H 33.27200000 -11.11900000 58.79900000 0.09502809 -0.07214661 -0.02615546 +H 32.99285000 -9.42516400 59.34181000 0.42405268 -0.02278433 -0.32054946 +C 28.96100000 -8.00100000 57.60500000 0.28842676 0.38067258 -0.55285192 +C 28.58100000 -7.95300000 59.06600000 -2.31597445 1.39380103 -0.93543962 +O 29.19200000 -8.71800000 59.83300000 2.33878729 -2.64306908 1.81861959 +O 27.60300000 -7.24500000 59.37600000 0.00203537 0.28858500 0.06466103 +H 28.41800000 -8.82500000 57.13600000 -0.13894671 -0.15551101 -0.15334135 +H 30.02700000 -8.20000000 57.49900000 0.41252555 -0.04603752 -0.23067550 +H 28.70165000 -7.06549500 57.08773000 0.01448134 -0.14380421 0.02020421 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.8790231591 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.652773983572788 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.83526613 0.29950260 0.82425804 +C 31.01900000 -11.54600000 60.23100000 0.19323442 0.79824747 -0.79242718 +N 29.86200000 -11.49700000 60.84900000 -1.26086408 -0.19966722 0.90778704 +N 31.29100000 -10.55900000 59.39400000 1.10377667 -0.61579259 -0.50382294 +N 31.82000000 -12.58200000 60.45800000 0.53487977 -0.60919410 0.22971529 +H 29.30600000 -10.65300000 60.75300000 -0.45751204 0.51621801 -0.01867909 +H 29.60200000 -12.19700000 61.53200000 -0.11773083 0.12807091 -0.05198146 +H 30.57700000 -9.82700000 59.36500000 -0.86179519 1.11018593 -0.12781882 +H 32.67200000 -12.69900000 59.93600000 0.14477215 -0.19884630 0.01745339 +H 31.49700000 -13.30000000 61.09500000 0.32392248 -0.10079831 -0.14614695 +H 32.42700000 -9.97000000 57.72400000 0.00876132 0.01653565 -0.11836809 +H 33.27200000 -11.11900000 58.79900000 0.06464319 -0.07433943 -0.01515722 +H 32.99285000 -9.42516400 59.34181000 0.41905905 -0.02804159 -0.32357040 +C 28.81186409 -7.82231364 57.51373300 0.29197922 0.38824577 -0.59010748 +C 28.43186409 -7.77431364 58.97473300 -2.07095515 1.15553756 -0.83449341 +O 29.04286409 -8.53931364 59.74173300 2.36361062 -2.62866791 1.82892596 +O 27.45386409 -7.06631364 59.28473300 -0.11190680 0.38513074 0.07798340 +H 28.26886409 -8.64631364 57.04473300 -0.14203949 -0.15647777 -0.15658864 +H 29.87786409 -8.02131364 57.40773300 0.40220156 -0.05148013 -0.21244290 +H 28.55251409 -6.88680864 56.99646300 0.00722927 -0.13436929 0.00548146 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.5702881476 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=4.900418928698813 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.79966515 0.34917884 0.78818312 +C 31.01900000 -11.54600000 60.23100000 0.20578081 0.70768154 -0.74257051 +N 29.86200000 -11.49700000 60.84900000 -1.26809388 -0.11633240 0.88004502 +N 31.29100000 -10.55900000 59.39400000 0.91017946 -0.42237577 -0.48101333 +N 31.82000000 -12.58200000 60.45800000 0.49440814 -0.54107819 0.20282650 +H 29.30600000 -10.65300000 60.75300000 -0.45550678 0.37758047 0.03005677 +H 29.60200000 -12.19700000 61.53200000 -0.14074351 0.13202686 -0.04269193 +H 30.57700000 -9.82700000 59.36500000 -0.61137768 0.90970119 -0.23130381 +H 32.67200000 -12.69900000 59.93600000 0.15145228 -0.20063354 0.01408882 +H 31.49700000 -13.30000000 61.09500000 0.31807652 -0.11102448 -0.13704734 +H 32.42700000 -9.97000000 57.72400000 0.00554855 0.01548165 -0.11415784 +H 33.27200000 -11.11900000 58.79900000 0.04276203 -0.07507642 -0.00737357 +H 32.99285000 -9.42516400 59.34181000 0.41645736 -0.03204815 -0.32549582 +C 28.66272818 -7.64362728 57.42246600 0.29636601 0.39534135 -0.62149377 +C 28.28272818 -7.59562728 58.88346600 -1.86416250 0.95868067 -0.74606550 +O 28.89372818 -8.36062728 59.65046600 2.27064035 -2.48234520 1.80654346 +O 27.30472818 -6.88762728 59.19346600 -0.21801292 0.47247527 0.09280700 +H 28.11972818 -8.46762728 56.95346600 -0.14391037 -0.15748904 -0.15942968 +H 29.72872818 -7.84262728 57.31646600 0.38883778 -0.05386563 -0.19997531 +H 28.40337818 -6.70812228 56.90519600 0.00096353 -0.12587902 -0.00593228 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.2810237195 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.148291523570566 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.76642732 0.38517155 0.75871653 +C 31.01900000 -11.54600000 60.23100000 0.22295109 0.62361295 -0.70056300 +N 29.86200000 -11.49700000 60.84900000 -1.27538847 -0.06100909 0.86086519 +N 31.29100000 -10.55900000 59.39400000 0.79006408 -0.29182939 -0.47996261 +N 31.82000000 -12.58200000 60.45800000 0.46045961 -0.47519486 0.17603910 +H 29.30600000 -10.65300000 60.75300000 -0.44466307 0.26628662 0.07170912 +H 29.60200000 -12.19700000 61.53200000 -0.15725325 0.12741491 -0.03149843 +H 30.57700000 -9.82700000 59.36500000 -0.40505101 0.73166711 -0.28666056 +H 32.67200000 -12.69900000 59.93600000 0.16013025 -0.20193247 0.00908375 +H 31.49700000 -13.30000000 61.09500000 0.30796338 -0.12716287 -0.12088727 +H 32.42700000 -9.97000000 57.72400000 0.00345050 0.01434229 -0.11203416 +H 33.27200000 -11.11900000 58.79900000 0.02630155 -0.07428898 -0.00187481 +H 32.99285000 -9.42516400 59.34181000 0.41584524 -0.03496600 -0.32630742 +C 28.51359227 -7.46494092 57.33119900 0.29886075 0.40196018 -0.64498167 +C 28.13359227 -7.41694092 58.79219900 -1.67367778 0.78362585 -0.67721402 +O 28.74459227 -8.18194092 59.55919900 2.12820022 -2.28804172 1.75866015 +O 27.15559227 -6.70894092 59.10219900 -0.31695946 0.55094860 0.11339635 +H 27.97059227 -8.28894092 56.86219900 -0.14496588 -0.15806069 -0.16135899 +H 29.57959227 -7.66394092 57.22519900 0.37436291 -0.05440806 -0.18979288 +H 28.25424227 -6.52943592 56.81392900 -0.00420335 -0.11813593 -0.01533436 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.0250648029 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.396360398172885 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.73702783 0.41307297 0.73428376 +C 31.01900000 -11.54600000 60.23100000 0.24650699 0.53960751 -0.65997370 +N 29.86200000 -11.49700000 60.84900000 -1.28393199 -0.01795957 0.84392951 +N 31.29100000 -10.55900000 59.39400000 0.71266265 -0.19712316 -0.49218280 +N 31.82000000 -12.58200000 60.45800000 0.42959576 -0.40417716 0.14564445 +H 29.30600000 -10.65300000 60.75300000 -0.42923901 0.18053110 0.10490997 +H 29.60200000 -12.19700000 61.53200000 -0.16811410 0.11349872 -0.01717985 +H 30.57700000 -9.82700000 59.36500000 -0.24212000 0.58238843 -0.31090727 +H 32.67200000 -12.69900000 59.93600000 0.17484675 -0.20308260 -0.00035795 +H 31.49700000 -13.30000000 61.09500000 0.29017382 -0.15392282 -0.09322909 +H 32.42700000 -9.97000000 57.72400000 0.00220386 0.01305681 -0.11189160 +H 33.27200000 -11.11900000 58.79900000 0.01334698 -0.07301651 0.00235286 +H 32.99285000 -9.42516400 59.34181000 0.41688868 -0.03687851 -0.32586982 +C 28.36445636 -7.28625456 57.23993200 0.29598510 0.40883590 -0.65877894 +C 27.98445636 -7.23825456 58.70093200 -1.47891402 0.61319768 -0.63261512 +O 28.59545636 -8.00325456 59.46793200 1.96284126 -2.07732544 1.69251224 +O 27.00645636 -6.53025456 59.01093200 -0.41208647 0.62208698 0.14389820 +H 27.82145636 -8.11025456 56.77093200 -0.14554446 -0.15783212 -0.16189161 +H 29.43045636 -7.48525456 57.13393200 0.36009813 -0.05387210 -0.17919288 +H 28.10510636 -6.35074956 56.72266200 -0.00817211 -0.11108612 -0.02346035 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.8051596708 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.6445996742594495 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.71341569 0.43614239 0.71404428 +C 31.01900000 -11.54600000 60.23100000 0.27679472 0.45797867 -0.61668560 +N 29.86200000 -11.49700000 60.84900000 -1.29447375 0.01918983 0.82785179 +N 31.29100000 -10.55900000 59.39400000 0.66052126 -0.12402373 -0.51293902 +N 31.82000000 -12.58200000 60.45800000 0.39880414 -0.32991500 0.11387645 +H 29.30600000 -10.65300000 60.75300000 -0.41249575 0.11452297 0.13084679 +H 29.60200000 -12.19700000 61.53200000 -0.17499845 0.09374845 -0.00145217 +H 30.57700000 -9.82700000 59.36500000 -0.11618746 0.46090719 -0.31757379 +H 32.67200000 -12.69900000 59.93600000 0.19619265 -0.20468174 -0.01485454 +H 31.49700000 -13.30000000 61.09500000 0.26662391 -0.18827466 -0.05837366 +H 32.42700000 -9.97000000 57.72400000 0.00175158 0.01155821 -0.11322541 +H 33.27200000 -11.11900000 58.79900000 0.00332296 -0.07265593 0.00594588 +H 32.99285000 -9.42516400 59.34181000 0.41908751 -0.03781941 -0.32431010 +C 28.21532045 -7.10756820 57.14866500 0.28753211 0.41510978 -0.66309397 +C 27.83532045 -7.05956820 58.60966500 -1.28651775 0.45137298 -0.60913816 +O 28.44632045 -7.82456820 59.37666500 1.79668971 -1.87311633 1.61778377 +O 26.85732045 -6.35156820 58.91966500 -0.50075767 0.68459614 0.18120303 +H 27.67232045 -7.93156820 56.67966500 -0.14587412 -0.15689988 -0.16140570 +H 29.28132045 -7.30656820 57.04266500 0.34831318 -0.05307887 -0.16820781 +H 27.95597045 -6.17206320 56.63139500 -0.01091309 -0.10466108 -0.03029206 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.6187222884 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=5.892987817628019 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.69578274 0.45507072 0.69757015 +C 31.01900000 -11.54600000 60.23100000 0.31102319 0.38600186 -0.57097927 +N 29.86200000 -11.49700000 60.84900000 -1.30622107 0.05044476 0.81358437 +N 31.29100000 -10.55900000 59.39400000 0.62471507 -0.06759684 -0.53811556 +N 31.82000000 -12.58200000 60.45800000 0.36907741 -0.26084889 0.08494493 +H 29.30600000 -10.65300000 60.75300000 -0.39708639 0.06424461 0.15051835 +H 29.60200000 -12.19700000 61.53200000 -0.17963305 0.07284470 0.01326890 +H 30.57700000 -9.82700000 59.36500000 -0.02135687 0.36497238 -0.31554307 +H 32.67200000 -12.69900000 59.93600000 0.22008330 -0.20702850 -0.03183463 +H 31.49700000 -13.30000000 61.09500000 0.24228397 -0.22314818 -0.02449740 +H 32.42700000 -9.97000000 57.72400000 0.00209260 0.00974930 -0.11518223 +H 33.27200000 -11.11900000 58.79900000 -0.00416539 -0.07316804 0.00887730 +H 32.99285000 -9.42516400 59.34181000 0.42186746 -0.03796336 -0.32197359 +C 28.06618454 -6.92888184 57.05739800 0.27708708 0.41898586 -0.66060350 +C 27.68618454 -6.88088184 58.51839800 -1.11632586 0.31220609 -0.59993626 +O 28.29718454 -7.64588184 59.28539800 1.64827593 -1.69317091 1.54474468 +O 26.70818454 -6.17288184 58.82839800 -0.57745808 0.73584055 0.21922462 +H 27.52318454 -7.75288184 56.58839800 -0.14600652 -0.15575964 -0.16044485 +H 29.13218454 -7.12788184 56.95139800 0.34021068 -0.05269692 -0.15828856 +H 27.80683454 -5.99337684 56.54012800 -0.01268072 -0.09897955 -0.03533438 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.4610685095 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.141506759716005 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.68333797 0.46999934 0.68424615 +C 31.01900000 -11.54600000 60.23100000 0.34783159 0.32738940 -0.52287693 +N 29.86200000 -11.49700000 60.84900000 -1.31927437 0.07591202 0.80205960 +N 31.29100000 -10.55900000 59.39400000 0.59953176 -0.02397709 -0.56611966 +N 31.82000000 -12.58200000 60.45800000 0.34214774 -0.20160055 0.06018444 +H 29.30600000 -10.65300000 60.75300000 -0.38408029 0.02588988 0.16497004 +H 29.60200000 -12.19700000 61.53200000 -0.18312841 0.05320462 0.02581607 +H 30.57700000 -9.82700000 59.36500000 0.04937226 0.28998742 -0.30992996 +H 32.67200000 -12.69900000 59.93600000 0.24322269 -0.21010667 -0.04926215 +H 31.49700000 -13.30000000 61.09500000 0.21951807 -0.25518371 0.00455295 +H 32.42700000 -9.97000000 57.72400000 0.00318239 0.00761205 -0.11719264 +H 33.27200000 -11.11900000 58.79900000 -0.00979166 -0.07382722 0.01106741 +H 32.99285000 -9.42516400 59.34181000 0.42496558 -0.03728320 -0.31902491 +C 27.91704864 -6.75019548 56.96613100 0.26693544 0.42040020 -0.65397015 +C 27.53704864 -6.70219548 58.42713100 -0.97521493 0.19954534 -0.60011525 +O 28.14804864 -7.46719548 59.19413100 1.52346396 -1.54249538 1.47878760 +O 26.55904864 -5.99419548 58.73713100 -0.64079166 0.77604896 0.25482319 +H 27.37404864 -7.57419548 56.49713100 -0.14598836 -0.15465307 -0.15934813 +H 28.98304864 -6.94919548 56.86013100 0.33525464 -0.05280325 -0.15007651 +H 27.65769864 -5.81469048 56.44886100 -0.01381846 -0.09405908 -0.03859114 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.3275196466 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.3901412514497204 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.67556998 0.48114604 0.67347096 +C 31.01900000 -11.54600000 60.23100000 0.38828894 0.28425424 -0.47011248 +N 29.86200000 -11.49700000 60.84900000 -1.33538414 0.09614740 0.79443829 +N 31.29100000 -10.55900000 59.39400000 0.58084385 0.01058843 -0.59785043 +N 31.82000000 -12.58200000 60.45800000 0.31923276 -0.15448540 0.03963439 +H 29.30600000 -10.65300000 60.75300000 -0.37336100 -0.00462049 0.17515359 +H 29.60200000 -12.19700000 61.53200000 -0.18609565 0.03626210 0.03522690 +H 30.57700000 -9.82700000 59.36500000 0.10239633 0.23070009 -0.30375034 +H 32.67200000 -12.69900000 59.93600000 0.26375376 -0.21403760 -0.06626089 +H 31.49700000 -13.30000000 61.09500000 0.19904988 -0.28348659 0.02706955 +H 32.42700000 -9.97000000 57.72400000 0.00503816 0.00513439 -0.11888807 +H 33.27200000 -11.11900000 58.79900000 -0.01416576 -0.07410003 0.01249732 +H 32.99285000 -9.42516400 59.34181000 0.42838078 -0.03557061 -0.31543481 +C 27.76791273 -6.57150912 56.87486400 0.25802719 0.41988910 -0.64518376 +C 27.38791273 -6.52350912 58.33586400 -0.86125989 0.11045906 -0.60585572 +O 27.99891273 -7.28850912 59.10286400 1.42097744 -1.41874006 1.42112226 +O 26.40991273 -5.81550912 58.64586400 -0.69223185 0.80717743 0.28685402 +H 27.22491273 -7.39550912 56.40586400 -0.14584059 -0.15369059 -0.15820966 +H 28.83391273 -6.77050912 56.76886400 0.33245571 -0.05321003 -0.14350648 +H 27.50856273 -5.63600412 56.35759400 -0.01453594 -0.08981689 -0.04041461 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.214086767 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.638878304932434 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.67313950 0.48939384 0.66604829 +C 31.01900000 -11.54600000 60.23100000 0.43282771 0.25632200 -0.41267337 +N 29.86200000 -11.49700000 60.84900000 -1.36179148 0.11119109 0.79418219 +N 31.29100000 -10.55900000 59.39400000 0.56605728 0.04407773 -0.63863942 +N 31.82000000 -12.58200000 60.45800000 0.30504744 -0.12688244 0.02555156 +H 29.30600000 -10.65300000 60.75300000 -0.36385494 -0.03155397 0.18292552 +H 29.60200000 -12.19700000 61.53200000 -0.18888442 0.02469834 0.04044140 +H 30.57700000 -9.82700000 59.36500000 0.14409190 0.18210800 -0.29829108 +H 32.67200000 -12.69900000 59.93600000 0.27891798 -0.21905009 -0.08105782 +H 31.49700000 -13.30000000 61.09500000 0.18306222 -0.30547520 0.04019923 +H 32.42700000 -9.97000000 57.72400000 0.00789150 0.00236691 -0.12015259 +H 33.27200000 -11.11900000 58.79900000 -0.01765861 -0.07374205 0.01319539 +H 32.99285000 -9.42516400 59.34181000 0.43282367 -0.03286116 -0.31155952 +C 27.61877682 -6.39282276 56.78359700 0.25049808 0.41803862 -0.63555507 +C 27.23877682 -6.34482276 58.24459700 -0.76936472 0.03994866 -0.61400106 +O 27.84977682 -7.10982276 59.01159700 1.33738234 -1.31731664 1.37097444 +O 26.26077682 -5.63682276 58.55459700 -0.73431825 0.83155262 0.31485757 +H 27.07577682 -7.21682276 56.31459700 -0.14561116 -0.15287019 -0.15701509 +H 28.68477682 -6.59182276 56.67759700 0.33102850 -0.05378677 -0.13821878 +H 27.35942682 -5.45731776 56.26632700 -0.01500554 -0.08615931 -0.04121179 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.1173661601 label=CC chargeA=1 energyA=-6669.20645149176 chargeB=-1 energyB=-6220.48400518575 distance=6.887706811428899 pbc="T T T" +C 32.59000000 -10.26800000 58.76100000 -0.67547662 0.49796535 0.66590576 +C 31.01900000 -11.54600000 60.23100000 0.46521004 0.22648834 -0.37384505 +N 29.86200000 -11.49700000 60.84900000 -1.40736197 0.12035287 0.80438725 +N 31.29100000 -10.55900000 59.39400000 0.55668522 0.09258687 -0.69156763 +N 31.82000000 -12.58200000 60.45800000 0.31136931 -0.13106384 0.02447997 +H 29.30600000 -10.65300000 60.75300000 -0.35299860 -0.05510572 0.19301531 +H 29.60200000 -12.19700000 61.53200000 -0.19068326 0.02157441 0.04430828 +H 30.57700000 -9.82700000 59.36500000 0.18089925 0.14212448 -0.29102685 +H 32.67200000 -12.69900000 59.93600000 0.28439606 -0.22365073 -0.08737639 +H 31.49700000 -13.30000000 61.09500000 0.17777444 -0.31322752 0.04305616 +H 32.42700000 -9.97000000 57.72400000 0.01150713 0.00006915 -0.12186087 +H 33.27200000 -11.11900000 58.79900000 -0.02002494 -0.07333594 0.01365877 +H 32.99285000 -9.42516400 59.34181000 0.43975783 -0.03147117 -0.30989358 +C 27.46964091 -6.21413640 56.69232999 0.24398758 0.41570973 -0.62611045 +C 27.08964091 -6.16613640 58.15332999 -0.69450481 -0.01714453 -0.62155422 +O 27.70064091 -6.93113640 58.92032999 1.26904250 -1.23366099 1.32712521 +O 26.11164091 -5.45813640 58.46332999 -0.76948126 0.85136322 0.33848566 +H 26.92664091 -7.03813640 56.22332999 -0.14533983 -0.15216913 -0.15583608 +H 28.53564091 -6.41313640 56.58632999 0.33050273 -0.05443052 -0.13385341 +H 27.21029091 -5.27863140 56.17505999 -0.01526082 -0.08297435 -0.04149787 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.9246626702 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=3.7613583409405105 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.52452169 -0.28619317 0.72096010 +C 12.12100000 17.80500000 24.71700000 2.21408214 2.18812285 -0.75915466 +O 11.25200000 16.92500000 24.47100000 2.11413223 -1.98302672 2.53485071 +O 12.41100000 18.73500000 23.94100000 -0.31893391 0.09595292 -0.18811490 +H 13.24200000 18.68100000 26.32900000 0.04176507 0.11901159 -0.01327467 +H 13.90100000 17.18800000 25.64900000 0.20824339 -0.20295969 0.07853017 +H 12.47004000 17.11600000 26.73359000 0.23600879 -0.11427064 0.10019126 +C 9.28616557 17.04075360 21.75593517 0.01022189 -0.12868529 0.99347384 +C 8.54316557 16.94475360 24.13793517 0.94362085 -0.02263722 -1.95547121 +N 9.48016557 16.99175360 23.21193517 -4.76491835 0.16219278 -3.78728209 +N 7.24016557 16.97575360 23.84493517 -1.08905422 0.01892054 -0.14788854 +N 8.95616557 16.84975360 25.37793517 -1.26679211 -0.10628742 2.36376708 +H 10.43916557 16.97275360 23.55593517 1.83562408 0.22322149 0.42177608 +H 6.93016557 16.99275360 22.88193517 -0.03790231 0.01379012 0.18836515 +H 6.55916557 16.94475360 24.58693517 -0.20231265 0.01379429 -0.07250211 +H 9.96316557 16.79375360 25.50893517 0.79494405 -0.07357183 0.02776080 +H 8.29516557 16.74375360 26.13893517 0.12777807 0.02702250 -0.07874070 +H 8.24616557 17.20875360 21.47893517 -0.22676782 0.23887852 -0.26094684 +H 9.58716557 16.07675360 21.34093517 0.06292919 -0.20953657 -0.23925543 +H 9.93345657 17.81936360 21.32608517 -0.15814667 0.02626095 0.07295594 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.5346918468 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.008434058469108 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.45717832 -0.30604280 0.73336053 +C 12.12100000 17.80500000 24.71700000 1.66946977 1.86026438 -0.88454898 +O 11.25200000 16.92500000 24.47100000 -0.81338486 -1.85076209 0.84621153 +O 12.41100000 18.73500000 23.94100000 -0.19513729 0.28617674 -0.23703278 +H 13.24200000 18.68100000 26.32900000 0.04877554 0.12391231 -0.00905760 +H 13.90100000 17.18800000 25.64900000 0.22160478 -0.19708773 0.08591396 +H 12.47004000 17.11600000 26.73359000 0.22814364 -0.10946904 0.08665593 +C 9.06558278 16.99637680 21.64696759 0.23083977 -0.14607193 0.87946333 +C 8.32258278 16.90037680 24.02896759 0.76661121 -0.04386949 -1.49594302 +N 9.25958278 16.94737680 23.10296759 -2.48404797 0.09573326 -2.43095769 +N 7.01958278 16.93137680 23.73596759 -0.92983502 0.02406594 -0.22286162 +N 8.73558278 16.80537680 25.26896759 -0.92892864 -0.11999976 1.89718002 +H 10.21858278 16.92837680 23.44696759 1.93394680 0.24604376 0.85246024 +H 6.70958278 16.94837680 22.77296759 -0.05777762 0.01691414 0.18881534 +H 6.33858278 16.90037680 24.47796759 -0.18649488 0.01245309 -0.06367508 +H 9.74258278 16.74937680 25.39996759 1.03561195 0.02643897 0.13224594 +H 8.07458278 16.69937680 26.02996759 0.20468454 0.02546569 -0.04866066 +H 8.02558278 17.16437680 21.36996759 -0.18146010 0.23442168 -0.15601577 +H 9.36658278 16.03237680 21.23196759 0.06194954 -0.19564380 -0.23116086 +H 9.71287378 17.77498680 21.21711759 -0.16739282 0.01705669 0.07760723 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.5274231876 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.255851334685677 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.40132950 -0.31446027 0.74982442 +C 12.12100000 17.80500000 24.71700000 1.26542010 1.58882507 -0.97075617 +O 11.25200000 16.92500000 24.47100000 -1.96690723 -1.81005264 0.30919771 +O 12.41100000 18.73500000 23.94100000 -0.09240703 0.45134851 -0.28006818 +H 13.24200000 18.68100000 26.32900000 0.05565854 0.12994510 -0.00223809 +H 13.90100000 17.18800000 25.64900000 0.23155387 -0.19346702 0.09088397 +H 12.47004000 17.11600000 26.73359000 0.22145245 -0.10632285 0.07844984 +C 8.84500000 16.95200000 21.53800000 0.36092414 -0.15640932 0.77987018 +C 8.10200000 16.85600000 23.92000000 0.61176197 -0.05370538 -1.21445212 +N 9.03900000 16.90300000 22.99400000 -1.34600571 0.10282110 -1.80568371 +N 6.79900000 16.88700000 23.62700000 -0.79340257 0.02368493 -0.25965070 +N 8.51500000 16.76100000 25.16000000 -0.64408202 -0.12590001 1.62094082 +H 9.99800000 16.88400000 23.33800000 1.70755109 0.26043800 0.74690600 +H 6.48900000 16.90400000 22.66400000 -0.07036194 0.01965125 0.18574545 +H 6.11800000 16.85600000 24.36900000 -0.18206345 0.01110527 -0.05461514 +H 9.52200000 16.70500000 25.29100000 1.04864592 0.08905143 0.27528163 +H 7.85400000 16.65500000 25.92100000 0.26447430 0.02552964 -0.01551448 +H 7.80500000 17.12000000 21.26100000 -0.15696822 0.23294433 -0.09273930 +H 9.14600000 15.98800000 21.12300000 0.06102331 -0.18657038 -0.22259280 +H 9.49229100 17.73061000 21.10815000 -0.17493800 0.01154325 0.08121065 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12894.280031935 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.503553881387339 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.35575176 -0.31589437 0.76694120 +C 12.12100000 17.80500000 24.71700000 0.95525929 1.35221535 -1.03847820 +O 11.25200000 16.92500000 24.47100000 -2.29128963 -1.76045920 0.18225512 +O 12.41100000 18.73500000 23.94100000 -0.00507030 0.59766514 -0.31911878 +H 13.24200000 18.68100000 26.32900000 0.06184794 0.13602021 0.00537219 +H 13.90100000 17.18800000 25.64900000 0.23907087 -0.19129135 0.09412720 +H 12.47004000 17.11600000 26.73359000 0.21582576 -0.10429758 0.07343542 +C 8.62441722 16.90762320 21.42903241 0.43728495 -0.16337958 0.69830249 +C 7.88141722 16.81162320 23.81103241 0.48126016 -0.05831989 -1.04739221 +N 8.81841722 16.85862320 22.88503241 -0.75736343 0.12568904 -1.51508035 +N 6.57841722 16.84262320 23.51803241 -0.67959141 0.02106224 -0.27391103 +N 8.29441722 16.71662320 25.05103241 -0.42916165 -0.12687640 1.46400579 +H 9.77741722 16.83962320 23.22903241 1.40546307 0.25034604 0.53613276 +H 6.26841722 16.85962320 22.55503241 -0.07861232 0.02166134 0.18113630 +H 5.89741722 16.81162320 24.26003241 -0.18333030 0.01006571 -0.04607384 +H 9.30141722 16.66062320 25.18203241 0.94051350 0.11892595 0.40858788 +H 7.63341722 16.61062320 25.81203241 0.30730104 0.02617990 0.01633883 +H 7.58441722 17.07562320 21.15203241 -0.14223176 0.23278413 -0.05381600 +H 8.92541722 15.94362320 21.01403241 0.05994826 -0.18056810 -0.21551611 +H 9.27170822 17.68623320 20.99918241 -0.18137227 0.00847143 0.08275133 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.9610992283 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.751497090066203 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.31869302 -0.31248010 0.78320767 +C 12.12100000 17.80500000 24.71700000 0.71018168 1.13963358 -1.09219769 +O 11.25200000 16.92500000 24.47100000 -2.25709526 -1.69050868 0.19641113 +O 12.41100000 18.73500000 23.94100000 0.07062387 0.72734557 -0.35525506 +H 13.24200000 18.68100000 26.32900000 0.06746731 0.14181234 0.01316363 +H 13.90100000 17.18800000 25.64900000 0.24491367 -0.19001164 0.09616522 +H 12.47004000 17.11600000 26.73359000 0.21099152 -0.10297925 0.07020133 +C 8.40383443 16.86324640 21.32006483 0.48319671 -0.16876882 0.63280836 +C 7.66083443 16.76724640 23.70206483 0.36970116 -0.06073945 -0.94869559 +N 8.59783443 16.81424640 22.77606483 -0.43251767 0.14817694 -1.37459707 +N 6.35783443 16.79824640 23.40906483 -0.58448359 0.01785566 -0.27639383 +N 8.07383443 16.67224640 24.94206483 -0.27499824 -0.12486786 1.37605163 +H 9.55683443 16.79524640 23.12006483 1.12161120 0.22682018 0.33822668 +H 6.04783443 16.81524640 22.44606483 -0.08459904 0.02298974 0.17570959 +H 5.67683443 16.76724640 24.15106483 -0.18741804 0.00927191 -0.03797811 +H 9.08083443 16.61624640 25.07306483 0.78528118 0.12602404 0.51473331 +H 7.41283443 16.56624640 25.70306483 0.33636392 0.02683060 0.04507434 +H 7.36383443 17.03124640 21.04306483 -0.13226724 0.23318188 -0.02908268 +H 8.70483443 15.89924640 20.90506483 0.05871704 -0.17654692 -0.21013258 +H 9.05112543 17.64185640 20.89021483 -0.18697717 0.00696028 0.08257973 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.6417526352 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=4.999645142729246 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.28811898 -0.30568602 0.79825392 +C 12.12100000 17.80500000 24.71700000 0.51062320 0.94459191 -1.13281032 +O 11.25200000 16.92500000 24.47100000 -2.08743016 -1.60679740 0.25293453 +O 12.41100000 18.73500000 23.94100000 0.13685490 0.84193762 -0.38925819 +H 13.24200000 18.68100000 26.32900000 0.07265372 0.14721934 0.02075202 +H 13.90100000 17.18800000 25.64900000 0.24961557 -0.18922421 0.09726704 +H 12.47004000 17.11600000 26.73359000 0.20655691 -0.10197987 0.06754006 +C 8.18325165 16.81886961 21.21109724 0.51198318 -0.17337082 0.58036133 +C 7.44025165 16.72286961 23.59309724 0.27233828 -0.06193547 -0.88954246 +N 8.37725165 16.76986961 22.66709724 -0.24015890 0.16707170 -1.30390492 +N 6.13725165 16.75386961 23.30009724 -0.50409794 0.01481735 -0.27340795 +N 7.85325165 16.62786961 24.83309724 -0.16654766 -0.12103506 1.32695728 +H 9.33625165 16.75086961 23.01109724 0.88659457 0.19894469 0.18147458 +H 5.82725165 16.77086961 22.33709724 -0.08964785 0.02370175 0.16945893 +H 5.45625165 16.72286961 24.04209724 -0.19305701 0.00855014 -0.02985300 +H 8.86025165 16.57186961 24.96409724 0.62652264 0.11967150 0.59125694 +H 7.19225165 16.52186961 25.59409724 0.35482764 0.02711708 0.07030344 +H 7.14325165 16.98686961 20.93409724 -0.12485611 0.23377607 -0.01275032 +H 8.48425165 15.85486961 20.79609724 0.05730635 -0.17382975 -0.20622745 +H 8.83054265 17.59747961 20.78124724 -0.19196235 0.00645945 0.08119454 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.3487761903 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.247968996564185 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.26214910 -0.29555882 0.81086678 +C 12.12100000 17.80500000 24.71700000 0.34186037 0.75825628 -1.15724763 +O 11.25200000 16.92500000 24.47100000 -1.88051904 -1.51331328 0.31440509 +O 12.41100000 18.73500000 23.94100000 0.19510784 0.94356250 -0.42263603 +H 13.24200000 18.68100000 26.32900000 0.07766337 0.15218788 0.02817619 +H 13.90100000 17.18800000 25.64900000 0.25343543 -0.18864217 0.09766410 +H 12.47004000 17.11600000 26.73359000 0.20204296 -0.10081794 0.06426360 +C 7.96266886 16.77449281 21.10212966 0.53134956 -0.17766572 0.53829803 +C 7.21966886 16.67849281 23.48412966 0.18455214 -0.06057164 -0.85264148 +N 8.15666886 16.72549281 22.55812966 -0.11680591 0.18210251 -1.26840912 +N 5.91666886 16.70949281 23.19112966 -0.43434197 0.01216932 -0.26831748 +N 7.63266886 16.58349281 24.72412966 -0.08919987 -0.11582051 1.30018792 +H 9.11566886 16.70649281 22.90212966 0.70177637 0.17135634 0.06539813 +H 5.60666886 16.72649281 22.22812966 -0.09476899 0.02359951 0.16112187 +H 5.23566886 16.67849281 23.93312966 -0.20022341 0.00745750 -0.02026001 +H 8.63966886 16.52749281 24.85512966 0.48526670 0.10605556 0.64255380 +H 6.97166886 16.47749281 25.48512966 0.36461892 0.02660435 0.09258376 +H 6.92266886 16.94249281 20.82512966 -0.11906271 0.23433519 -0.00143067 +H 8.26366886 15.81049281 20.68712966 0.05569782 -0.17197901 -0.20355794 +H 8.60995986 17.55310281 20.67227966 -0.19630050 0.00668215 0.07898108 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12893.0896501194 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.496444811251947 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.23863500 -0.28001340 0.81897402 +C 12.12100000 17.80500000 24.71700000 0.19187624 0.55994359 -1.14972697 +O 11.25200000 16.92500000 24.47100000 -1.66813568 -1.40103290 0.36259613 +O 12.41100000 18.73500000 23.94100000 0.24473620 1.03550299 -0.46193218 +H 13.24200000 18.68100000 26.32900000 0.08308216 0.15686928 0.03592068 +H 13.90100000 17.18800000 25.64900000 0.25641209 -0.18791731 0.09729401 +H 12.47004000 17.11600000 26.73359000 0.19654636 -0.09850820 0.05818435 +C 7.74208608 16.73011601 20.99316207 0.54694955 -0.18261069 0.50494457 +C 6.99908608 16.63411601 23.37516207 0.09704433 -0.04896869 -0.82700123 +N 7.93608608 16.68111601 22.44916207 -0.02368459 0.19196933 -1.25552057 +N 5.69608608 16.66511601 23.08216207 -0.37051152 0.00996477 -0.26284114 +N 7.41208608 16.53911601 24.61516207 -0.02700958 -0.10945606 1.28969508 +H 8.89508608 16.66211601 22.79316207 0.55455688 0.14546255 -0.02003825 +H 5.38608608 16.68211601 22.11916207 -0.10180087 0.02141181 0.14613025 +H 5.01508608 16.63411601 23.82416207 -0.21099944 0.00445347 -0.00511924 +H 8.41908608 16.48311601 24.74616207 0.36587270 0.08701041 0.67466966 +H 6.75108608 16.43311601 25.37616207 0.36538692 0.02420252 0.11322315 +H 6.70208608 16.89811601 20.71616207 -0.11519815 0.23460244 0.00709593 +H 8.04308608 15.76611601 20.57816207 0.05336809 -0.17049229 -0.20242199 +H 8.38937708 17.50872601 20.56331207 -0.19985670 0.00760640 0.07587373 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.8656952745 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.74505288404184 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.21841617 -0.25773311 0.81765747 +C 12.12100000 17.80500000 24.71700000 0.06368914 0.33431113 -1.08389305 +O 11.25200000 16.92500000 24.47100000 -1.45620914 -1.25698468 0.38285305 +O 12.41100000 18.73500000 23.94100000 0.27780293 1.11619368 -0.51722346 +H 13.24200000 18.68100000 26.32900000 0.08908107 0.16152544 0.04447157 +H 13.90100000 17.18800000 25.64900000 0.25855307 -0.18697689 0.09638655 +H 12.47004000 17.11600000 26.73359000 0.18943276 -0.09461980 0.04862264 +C 7.52150329 16.68573921 20.88419448 0.56460656 -0.19020991 0.48159778 +C 6.77850329 16.58973921 23.26619448 -0.00253807 -0.01159939 -0.80686964 +N 7.71550329 16.63673921 22.34019448 0.07338768 0.19333257 -1.26744401 +N 5.47550329 16.62073921 22.97319448 -0.31713790 0.00911639 -0.25859072 +N 7.19150329 16.49473921 24.50619448 0.03874044 -0.10410267 1.30382415 +H 8.67450329 16.61773921 22.68419448 0.42772330 0.12144033 -0.08727429 +H 5.16550329 16.63773921 22.01019448 -0.11217448 0.01440414 0.12198086 +H 4.79450329 16.58973921 23.71519448 -0.22680930 -0.00335257 0.01716738 +H 8.19850329 16.43873921 24.63719448 0.25981863 0.06206905 0.69279918 +H 6.53050329 16.38873921 25.26719448 0.35828146 0.01810604 0.13237445 +H 6.48150329 16.85373921 20.60719448 -0.11472301 0.23436341 0.01432358 +H 7.82250329 15.72173921 20.46919448 0.04917858 -0.16859704 -0.20403341 +H 8.16879429 17.46434921 20.45434448 -0.20228754 0.00931389 0.07126991 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.6773656391 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=5.9937767370030866 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.17755875 -0.18954708 0.72681690 +C 12.12100000 17.80500000 24.71700000 0.12093818 -0.05925948 -0.47097423 +O 11.25200000 16.92500000 24.47100000 -1.26513527 -1.01531755 0.20007969 +O 12.41100000 18.73500000 23.94100000 0.23840123 1.22876233 -0.77880250 +H 13.24200000 18.68100000 26.32900000 0.09707844 0.19379480 0.05660562 +H 13.90100000 17.18800000 25.64900000 0.26455416 -0.19502315 0.08302623 +H 12.47004000 17.11600000 26.73359000 0.14235947 -0.09265902 0.03773811 +C 7.30092051 16.64136241 20.77522690 0.62197895 -0.22450392 0.49211641 +C 6.55792051 16.54536241 23.15722690 -0.16883942 0.24378298 -0.77252562 +N 7.49492051 16.59236241 22.23122690 0.32085341 0.10585654 -1.41364654 +N 5.25492051 16.57636241 22.86422690 -0.34687004 -0.00326828 -0.27834801 +N 6.97092051 16.45036241 24.39722690 0.21696832 -0.14119585 1.45930807 +H 8.45392051 16.57336241 22.57522690 0.22136113 0.09804013 -0.15989885 +H 4.94492051 16.59336241 21.90122690 -0.13229592 -0.02571329 0.07775715 +H 4.57392051 16.54536241 23.60622690 -0.23688651 -0.04037733 0.06031952 +H 7.97792051 16.39436241 24.52822690 0.09671188 0.00322368 0.68294141 +H 6.30992051 16.34436241 25.15822690 0.31762238 0.00394836 0.10795693 +H 6.26092051 16.80936241 20.49822690 -0.13305450 0.23694503 0.03834569 +H 7.60192051 15.67736241 20.36022690 0.01212386 -0.13895713 -0.21175425 +H 7.94821151 17.41997241 20.34537690 -0.21031101 0.01146825 0.06293827 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.5157633701 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.242602554777832 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.19902086 -0.21962487 0.79759456 +C 12.12100000 17.80500000 24.71700000 -0.07212314 -0.04678756 -0.86501817 +O 11.25200000 16.92500000 24.47100000 -1.10840021 -0.97359089 0.36308635 +O 12.41100000 18.73500000 23.94100000 0.28353617 1.21417220 -0.64199958 +H 13.24200000 18.68100000 26.32900000 0.09755719 0.16998956 0.05852058 +H 13.90100000 17.18800000 25.64900000 0.26133120 -0.18608930 0.09462405 +H 12.47004000 17.11600000 26.73359000 0.17708639 -0.08818795 0.03422642 +C 7.08033772 16.59698561 20.66625931 0.60250224 -0.21079416 0.46195515 +C 6.33733772 16.50098561 23.04825931 -0.19954284 0.10334833 -0.78388242 +N 7.27433772 16.54798561 22.12225931 0.28330326 0.18351434 -1.34550810 +N 5.03433772 16.53198561 22.75525931 -0.28067357 0.01214492 -0.25972692 +N 6.75033772 16.40598561 24.28825931 0.17517426 -0.10358347 1.40189714 +H 8.23333772 16.52898561 22.46625931 0.22866139 0.08124412 -0.18486193 +H 4.72433772 16.54898561 21.79225931 -0.13145976 -0.00628563 0.08230926 +H 4.35333772 16.50098561 23.49725931 -0.25482322 -0.02607318 0.05285152 +H 7.75733772 16.34998561 24.41925931 0.07905647 0.01324028 0.70439672 +H 6.08933772 16.29998561 25.04925931 0.34399691 0.00023920 0.15957650 +H 6.04033772 16.76498561 20.38925931 -0.11863734 0.23346324 0.02503616 +H 7.38133772 15.63298561 20.25125931 0.03751118 -0.16408846 -0.21421672 +H 7.72762872 17.37559561 20.23640931 -0.20503571 0.01374927 0.05913944 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.3810554246 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.49151858631955 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.20049264 -0.21222207 0.78578852 +C 12.12100000 17.80500000 24.71700000 -0.08114254 -0.16115964 -0.76188208 +O 11.25200000 16.92500000 24.47100000 -0.98509251 -0.86818306 0.34591765 +O 12.41100000 18.73500000 23.94100000 0.26454304 1.23176054 -0.69412000 +H 13.24200000 18.68100000 26.32900000 0.09825999 0.17334000 0.06188686 +H 13.90100000 17.18800000 25.64900000 0.26194532 -0.18634940 0.09387513 +H 12.47004000 17.11600000 26.73359000 0.17371919 -0.08685246 0.03241141 +C 6.85975494 16.55260882 20.55729173 0.61783355 -0.22130036 0.45552224 +C 6.11675494 16.45660882 22.93929173 -0.28356764 0.16168982 -0.77976292 +N 7.05375494 16.50360882 22.01329173 0.36629609 0.17819733 -1.38439953 +N 4.81375494 16.48760882 22.64629173 -0.26694977 0.01236471 -0.26285313 +N 6.52975494 16.36160882 24.17929173 0.23442561 -0.10523413 1.45146182 +H 8.01275494 16.48460882 22.35729173 0.15921619 0.06282215 -0.21722171 +H 4.50375494 16.50460882 21.68329173 -0.13920475 -0.01489227 0.06483187 +H 4.13275494 16.45660882 23.38829173 -0.27045244 -0.03830225 0.07291924 +H 7.53675494 16.30560882 24.31029173 0.01014500 -0.00506237 0.70163248 +H 5.86875494 16.25560882 24.94029173 0.33376884 -0.00869694 0.17022065 +H 5.81975494 16.72060882 20.28029173 -0.12073234 0.23283155 0.02921484 +H 7.16075494 15.58860882 20.14229173 0.03197443 -0.16152666 -0.21925355 +H 7.50704594 17.33121882 20.12744173 -0.20449260 0.01677551 0.05381023 +20 +Lattice="30.0 0.0 0.0 0.0 30.0 0.0 0.0 0.0 30.0" Properties=species:S:1:pos:R:3:forces:R:3 energy=-12892.2676780833 label=CC chargeA=-1 energyA=-6220.48891391419 chargeB=1 energyB=-6669.20926086133 distance=6.7405148650607 pbc="T T T" +C 12.98100000 17.69200000 25.94800000 -0.20465684 -0.20879396 0.77489349 +C 12.12100000 17.80500000 24.71700000 -0.07406187 -0.24280278 -0.67109250 +O 11.25200000 16.92500000 24.47100000 -0.88911534 -0.78339650 0.32763136 +O 12.41100000 18.73500000 23.94100000 0.24234614 1.23858709 -0.73741840 +H 13.24200000 18.68100000 26.32900000 0.09790387 0.17615115 0.06389835 +H 13.90100000 17.18800000 25.64900000 0.26225113 -0.18674535 0.09316017 +H 12.47004000 17.11600000 26.73359000 0.17139489 -0.08603439 0.03199290 +C 6.63917215 16.50823202 20.44832414 0.62928346 -0.23076605 0.44868090 +C 5.89617215 16.41223202 22.83032414 -0.35358521 0.21491756 -0.77655509 +N 6.83317215 16.45923202 21.90432414 0.42730570 0.17333066 -1.41507016 +N 4.59317215 16.44323202 22.53732414 -0.24885732 0.01007956 -0.26579087 +N 6.30917215 16.31723202 24.07032414 0.28102862 -0.10445439 1.48792934 +H 7.79217215 16.44023202 22.24832414 0.10759492 0.04630070 -0.23998216 +H 4.28317215 16.46023202 21.57432414 -0.14595726 -0.02196272 0.04750568 +H 3.91217215 16.41223202 23.27932414 -0.28573770 -0.04903540 0.09395175 +H 7.31617215 16.26123202 24.20132414 -0.03970395 -0.02142110 0.69643279 +H 5.64817215 16.21123202 24.83132414 0.32055445 -0.01705460 0.18072457 +H 5.59917215 16.67623202 20.17132414 -0.12215852 0.23214034 0.03270120 +H 6.94017215 15.54423202 20.03332414 0.02732817 -0.15908053 -0.22313365 +H 7.28646315 17.28684202 20.01847414 -0.20315733 0.02004071 0.04954034 diff --git a/latest/_downloads/4dd8b470da0d1f3672e0a6f90c77c550/sample-selection.py b/latest/_downloads/4dd8b470da0d1f3672e0a6f90c77c550/sample-selection.py new file mode 100644 index 00000000..75d8abea --- /dev/null +++ b/latest/_downloads/4dd8b470da0d1f3672e0a6f90c77c550/sample-selection.py @@ -0,0 +1,371 @@ +""" +Sample and Feature Selection with FPS and CUR +============================================= + +:Authors: Davide Tisi `@DavideTisi `_ + +In this tutorial we generate descriptors using rascaline, then select a subset +of structures using both the farthest-point sampling (FPS) and CUR algorithms +implemented in scikit-matter. Finally, we also generate a selection of +the most important features using the same techniques. + +First, import all the necessary packages +""" + +# %% + +import ase.io +import chemiscope +import metatensor +import numpy as np +from equisolve.numpy import feature_selection, sample_selection +from matplotlib import pyplot as plt +from rascaline import SoapPowerSpectrum +from sklearn.decomposition import PCA +from skmatter import feature_selection as skfeat_selection + + +# %% +# Load molecular data +# ------------------- +# +# Load 500 example BTO structures from file, reading them using +# `ASE `_. + +# Load a subset of :download:`structures ` of the example dataset +n_frames = 500 +frames = ase.io.read("input-fps.xyz", f":{n_frames}", format="extxyz") + +# %% +# Compute SOAP descriptors using rascaline +# ---------------------------------------- +# +# First, define the rascaline hyperparameters used to compute SOAP. + + +# rascaline hyperparameters +hypers = { + "cutoff": 6.0, + "max_radial": 8, + "max_angular": 6, + "atomic_gaussian_width": 0.3, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + "radial_basis": {"Gto": {"accuracy": 1e-6}}, + "radial_scaling": {"Willatt2018": {"exponent": 4, "rate": 1, "scale": 3.5}}, + "center_atom_weight": 1.0, +} + +# Generate a SOAP power spectrum +calculator = SoapPowerSpectrum(**hypers) +rho2i = calculator.compute(frames) + + +# Makes a dense block +atom_soap = rho2i.keys_to_properties(["species_neighbor_1", "species_neighbor_2"]) + +atom_soap_single_block = atom_soap.keys_to_samples(keys_to_move=["species_center"]) + +# Sum over atomic centers to compute structure features +struct_soap = metatensor.sum_over_samples( + atom_soap_single_block, sample_names=["center", "species_center"] +) + + +print("atom feature descriptor shape:", atom_soap.block(0).values.shape) +print( + "atom feature descriptor (all in one block) shape:", + atom_soap_single_block.block(0).values.shape, +) +print("structure feature descriptor shape:", struct_soap.block(0).values.shape) + + +# %% +# Perform atomic environment (i.e. sample) selection +# --------------------------------------------------- +# +# Using FPS and CUR algorithms, we can perform selection of atomic environments. +# These are implemented in equisolve, which provides a wrapper around +# scikit-matter to allow for interfacing with data stored in the metatensor +# format. +# +# Suppose we want to select the 10 most diverse environments for each chemical +# species. +# +# First, we can use the `keys_to_properties` operation in metatensor to move the +# neighbour species indices to the properties of the TensorBlocks. The resulting +# descriptor will be a TensorMap comprised of three blocks, one for each +# chemical species, where the chemical species indices are solely present in the +# keys. + + +print("----Atomic environment selection-----") +# Define the number of structures to select using FPS/CUR +n_envs = 25 + +print(atom_soap) +print(atom_soap.block(0)) + +# %% Now let's perform sample selection on the atomic environments. We want to +# select 10 atomic environments for each chemical species. + +# Define the number of structures *per block* to select using FPS +n_envs = 10 + +# FPS sample selection +selector_atomic_fps = sample_selection.FPS(n_to_select=n_envs, initialize="random").fit( + atom_soap +) + +# Print the selected envs for each block +print("atomic envs selected with FPS:\n") +for key, block in selector_atomic_fps.support.items(): + print("species_center:", key, "\n(struct_idx, atom_idx)\n", block.samples.values) + +selector_atomic_cur = sample_selection.CUR(n_to_select=n_envs).fit(atom_soap) +# Print the selected envs for each block +print("atomic envs selected with CUR:\n") +for key, block in selector_atomic_cur.support.items(): + print("species_center:", key, "\n(struct_idx, atom_idx)\n", block.samples.values) + + +# %% +# Selecting from a combined pool of atomic environments +# ----------------------------------------------------- +# +# One can also select from a combined pool of atomic environments and +# structures, instead of selecting an equal number of atomic environments for +# each chemical species. In this case, we can move the 'species_center' key to samples +# such that our descriptor is a TensorMap consisting of a single block. Upon +# sample selection, the most diverse atomic environments will be selected, +# regardless of their chemical species. +print("----All atomic environment selection-----") + +print("keys", atom_soap.keys) +print("blocks", atom_soap[0]) +print("samples in first block", atom_soap[0].samples) + +# Using the original SOAP descriptor, move all keys to properties. + + +# Define the number of structures to select using FPS +n_envs = 10 + +# FPS sample selection +selector_atomic_fps = sample_selection.FPS(n_to_select=n_envs, initialize="random").fit( + atom_soap_single_block +) +print( + "atomic envs selected with FPS: \n (struct_idx, atom_idx, species_center) \n", + selector_atomic_fps.support.block(0).samples.values, +) + + +# %% +# Perform structure (i.e. sample) selection with FPS/CUR +# --------------------------------------------------------- +# +# Instead of atomic environments, one can also select diverse structures. We can +# use the `sum_over_samples` operation in metatensor to define features in the +# structural basis instead of the atomic basis. This is done by summing over the +# atomic environments, labeled by the 'center' index in the samples of the +# TensorMap. +# +# Alternatively, one could use the `mean_over_samples` operation, depending on +# the specific inhomogeneity of the size of the structures in the training set. + +print("----Structure selection-----") + +# Define the number of structures to select *per block* using FPS +n_structures = 10 + +# FPS structure selection +selector_struct_fps = sample_selection.FPS( + n_to_select=n_structures, initialize="random" +).fit(struct_soap) +struct_fps_idxs = selector_struct_fps.support.block(0).samples.values.flatten() + +print("structures selected with FPS:\n", struct_fps_idxs) + +# CUR structure selection +selector_struct_cur = sample_selection.CUR(n_to_select=n_structures).fit(struct_soap) +struct_cur_idxs = selector_struct_cur.support.block(0).samples.values.flatten() +print("structures selected with CUR:\n", struct_cur_idxs) + + +# Slice structure descriptor along axis 0 to contain only the selected structures +struct_soap_fps = struct_soap.block(0).values[struct_fps_idxs, :] +struct_soap_cur = struct_soap.block(0).values[struct_cur_idxs, :] +assert struct_soap_fps.shape == struct_soap_cur.shape + +print("Structure descriptor shape before selection ", struct_soap.block(0).values.shape) +print("Structure descriptor shape after selection (FPS)", struct_soap_fps.shape) +print("Structure descriptor shape after selection (CUR)", struct_soap_cur.shape) + + +# %% +# Visualize selected structures +# ----------------------------- +# +# sklearn can be used to perform PCA dimensionality reduction on the SOAP +# descriptors. The resulting PC coordinates can be used to visualize the the +# data alongside their structures in a chemiscope widget. +# +# Note: chemiscope widgets are not currently integrated into our sphinx gallery: +# coming soon. + + +# Generate a structure PCA +struct_soap_pca = PCA(n_components=2).fit_transform(struct_soap.block(0).values) +assert struct_soap_pca.shape == (n_frames, 2) + + +# %% +# Plot the PCA map +# ~~~~~~~~~~~~~~~~ +# +# Notice how the selected points avoid the densely-sampled area, and cover +# the periphery of the dataset + +# Matplotlib plot +fig, ax = plt.subplots(1, 1, figsize=(6, 4)) +scatter = ax.scatter(struct_soap_pca[:, 0], struct_soap_pca[:, 1], c="red") +ax.plot( + struct_soap_pca[struct_cur_idxs, 0], + struct_soap_pca[struct_cur_idxs, 1], + "ko", + fillstyle="none", + label="FPS selection", +) +ax.set_xlabel("PCA[1]") +ax.set_ylabel("PCA[2]") +ax.legend() +fig.show() + + +# %% +# Creates a chemiscope viewer +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Interactive viewer (only works in notebooks) + +# Selected level +selection_levels = [] +for i in range(len(frames)): + level = 0 + if i in struct_cur_idxs: + level += 1 + if i in struct_fps_idxs: + level += 2 + if level == 0: + level = "Not selected" + elif level == 1: + level = "CUR" + elif level == 2: + level = "FPS" + else: + level = "FPS+CUR" + selection_levels.append(level) + +properties = chemiscope.extract_properties(frames) + +properties.update( + { + "PC1": struct_soap_pca[:, 0], + "PC2": struct_soap_pca[:, 1], + "selection": np.array(selection_levels), + } +) + + +# Display with chemiscope. This currently does not work - as raised in issue #8 +# https://github.com/lab-cosmo/software-cookbook/issues/8 +widget = chemiscope.show( + frames, + properties=properties, + settings={ + "map": { + "x": {"property": "PC1"}, + "y": {"property": "PC2"}, + "color": {"property": "energy"}, + "symbol": "selection", + "size": {"factor": 50}, + }, + "structure": [{"unitCell": True}], + }, +) + +if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(widget) +else: + widget.save("sample-selection.json.gz") + + +# %% +# Perform feature selection +# ------------------------- +# +# Now perform feature selection. In this example we will go back to using the +# descriptor decomposed into atomic environments, as opposed to the one +# decomposed into structure environments, but only use FPS for brevity. +print("----Feature selection-----") + +# Define the number of features to select +n_features = 200 + +# FPS feature selection +feat_fps = feature_selection.FPS(n_to_select=n_features, initialize="random").fit( + atom_soap_single_block +) + +# Slice atomic descriptor along axis 1 to contain only the selected features +# atom_soap_single_block_fps = atom_soap_single_block.block(0).values[:, feat_fps_idxs] +atom_soap_single_block_fps = metatensor.slice( + atom_soap_single_block, + axis="properties", + labels=feat_fps.support.block(0).properties, +) + +print( + "atomic descriptor shape before selection ", + atom_soap_single_block.block(0).values.shape, +) +print( + "atomic descriptor shape after selection ", + atom_soap_single_block_fps.block(0).values.shape, +) + +# %% + +# %% +# Perform feature selection (skmatter) +# ------------------------------------ +# +# Now perform feature selection. In this example we will go back to using the +# descriptor decomposed into atomic environments, as opposed to the one +# decomposed into structure environments, but only use FPS for brevity. + +print("----Feature selection (skmatter)-----") + +# Define the number of features to select +n_features = 200 + +# FPS feature selection +feat_fps = skfeat_selection.FPS(n_to_select=n_features, initialize="random").fit( + atom_soap_single_block.block(0).values +) +feat_fps_idxs = feat_fps.selected_idx_ + +print("Feature indices obtained with FPS ", feat_fps_idxs) + +# Slice atomic descriptor along axis 1 to contain only the selected features +atom_dscrptr_fps = atom_soap_single_block.block(0).values[:, feat_fps_idxs] + +print( + "atomic descriptor shape before selection ", + atom_soap_single_block.block(0).values.shape, +) +print("atomic descriptor shape after selection ", atom_dscrptr_fps.shape) + +# %% diff --git a/latest/_downloads/54cb049367bea2b1604e2df18dc055b4/sample-selection.ipynb b/latest/_downloads/54cb049367bea2b1604e2df18dc055b4/sample-selection.ipynb new file mode 100644 index 00000000..3ed8f364 --- /dev/null +++ b/latest/_downloads/54cb049367bea2b1604e2df18dc055b4/sample-selection.ipynb @@ -0,0 +1,241 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Sample and Feature Selection with FPS and CUR\n\n:Authors: Davide Tisi [@DavideTisi](https://github.com/DavideTisi)\n\nIn this tutorial we generate descriptors using rascaline, then select a subset\nof structures using both the farthest-point sampling (FPS) and CUR algorithms\nimplemented in scikit-matter. Finally, we also generate a selection of\nthe most important features using the same techniques.\n\nFirst, import all the necessary packages\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import ase.io\nimport chemiscope\nimport metatensor\nimport numpy as np\nfrom equisolve.numpy import feature_selection, sample_selection\nfrom matplotlib import pyplot as plt\nfrom rascaline import SoapPowerSpectrum\nfrom sklearn.decomposition import PCA\nfrom skmatter import feature_selection as skfeat_selection" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load molecular data\n\nLoad 500 example BTO structures from file, reading them using\n[ASE](https://wiki.fysik.dtu.dk/ase/).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Load a subset of :download:`structures ` of the example dataset\nn_frames = 500\nframes = ase.io.read(\"input-fps.xyz\", f\":{n_frames}\", format=\"extxyz\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Compute SOAP descriptors using rascaline\n\nFirst, define the rascaline hyperparameters used to compute SOAP.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# rascaline hyperparameters\nhypers = {\n \"cutoff\": 6.0,\n \"max_radial\": 8,\n \"max_angular\": 6,\n \"atomic_gaussian_width\": 0.3,\n \"cutoff_function\": {\"ShiftedCosine\": {\"width\": 0.5}},\n \"radial_basis\": {\"Gto\": {\"accuracy\": 1e-6}},\n \"radial_scaling\": {\"Willatt2018\": {\"exponent\": 4, \"rate\": 1, \"scale\": 3.5}},\n \"center_atom_weight\": 1.0,\n}\n\n# Generate a SOAP power spectrum\ncalculator = SoapPowerSpectrum(**hypers)\nrho2i = calculator.compute(frames)\n\n\n# Makes a dense block\natom_soap = rho2i.keys_to_properties([\"species_neighbor_1\", \"species_neighbor_2\"])\n\natom_soap_single_block = atom_soap.keys_to_samples(keys_to_move=[\"species_center\"])\n\n# Sum over atomic centers to compute structure features\nstruct_soap = metatensor.sum_over_samples(\n atom_soap_single_block, sample_names=[\"center\", \"species_center\"]\n)\n\n\nprint(\"atom feature descriptor shape:\", atom_soap.block(0).values.shape)\nprint(\n \"atom feature descriptor (all in one block) shape:\",\n atom_soap_single_block.block(0).values.shape,\n)\nprint(\"structure feature descriptor shape:\", struct_soap.block(0).values.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Perform atomic environment (i.e. sample) selection\n\nUsing FPS and CUR algorithms, we can perform selection of atomic environments.\nThese are implemented in equisolve, which provides a wrapper around\nscikit-matter to allow for interfacing with data stored in the metatensor\nformat.\n\nSuppose we want to select the 10 most diverse environments for each chemical\nspecies.\n\nFirst, we can use the `keys_to_properties` operation in metatensor to move the\nneighbour species indices to the properties of the TensorBlocks. The resulting\ndescriptor will be a TensorMap comprised of three blocks, one for each\nchemical species, where the chemical species indices are solely present in the\nkeys.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"----Atomic environment selection-----\")\n# Define the number of structures to select using FPS/CUR\nn_envs = 25\n\nprint(atom_soap)\nprint(atom_soap.block(0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "select 10 atomic environments for each chemical species.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Define the number of structures *per block* to select using FPS\nn_envs = 10\n\n# FPS sample selection\nselector_atomic_fps = sample_selection.FPS(n_to_select=n_envs, initialize=\"random\").fit(\n atom_soap\n)\n\n# Print the selected envs for each block\nprint(\"atomic envs selected with FPS:\\n\")\nfor key, block in selector_atomic_fps.support.items():\n print(\"species_center:\", key, \"\\n(struct_idx, atom_idx)\\n\", block.samples.values)\n\nselector_atomic_cur = sample_selection.CUR(n_to_select=n_envs).fit(atom_soap)\n# Print the selected envs for each block\nprint(\"atomic envs selected with CUR:\\n\")\nfor key, block in selector_atomic_cur.support.items():\n print(\"species_center:\", key, \"\\n(struct_idx, atom_idx)\\n\", block.samples.values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Selecting from a combined pool of atomic environments\n\nOne can also select from a combined pool of atomic environments and\nstructures, instead of selecting an equal number of atomic environments for\neach chemical species. In this case, we can move the 'species_center' key to samples\nsuch that our descriptor is a TensorMap consisting of a single block. Upon\nsample selection, the most diverse atomic environments will be selected,\nregardless of their chemical species.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"----All atomic environment selection-----\")\n\nprint(\"keys\", atom_soap.keys)\nprint(\"blocks\", atom_soap[0])\nprint(\"samples in first block\", atom_soap[0].samples)\n\n# Using the original SOAP descriptor, move all keys to properties.\n\n\n# Define the number of structures to select using FPS\nn_envs = 10\n\n# FPS sample selection\nselector_atomic_fps = sample_selection.FPS(n_to_select=n_envs, initialize=\"random\").fit(\n atom_soap_single_block\n)\nprint(\n \"atomic envs selected with FPS: \\n (struct_idx, atom_idx, species_center) \\n\",\n selector_atomic_fps.support.block(0).samples.values,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Perform structure (i.e. sample) selection with FPS/CUR\n\nInstead of atomic environments, one can also select diverse structures. We can\nuse the `sum_over_samples` operation in metatensor to define features in the\nstructural basis instead of the atomic basis. This is done by summing over the\natomic environments, labeled by the 'center' index in the samples of the\nTensorMap.\n\nAlternatively, one could use the `mean_over_samples` operation, depending on\nthe specific inhomogeneity of the size of the structures in the training set.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"----Structure selection-----\")\n\n# Define the number of structures to select *per block* using FPS\nn_structures = 10\n\n# FPS structure selection\nselector_struct_fps = sample_selection.FPS(\n n_to_select=n_structures, initialize=\"random\"\n).fit(struct_soap)\nstruct_fps_idxs = selector_struct_fps.support.block(0).samples.values.flatten()\n\nprint(\"structures selected with FPS:\\n\", struct_fps_idxs)\n\n# CUR structure selection\nselector_struct_cur = sample_selection.CUR(n_to_select=n_structures).fit(struct_soap)\nstruct_cur_idxs = selector_struct_cur.support.block(0).samples.values.flatten()\nprint(\"structures selected with CUR:\\n\", struct_cur_idxs)\n\n\n# Slice structure descriptor along axis 0 to contain only the selected structures\nstruct_soap_fps = struct_soap.block(0).values[struct_fps_idxs, :]\nstruct_soap_cur = struct_soap.block(0).values[struct_cur_idxs, :]\nassert struct_soap_fps.shape == struct_soap_cur.shape\n\nprint(\"Structure descriptor shape before selection \", struct_soap.block(0).values.shape)\nprint(\"Structure descriptor shape after selection (FPS)\", struct_soap_fps.shape)\nprint(\"Structure descriptor shape after selection (CUR)\", struct_soap_cur.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize selected structures\n\nsklearn can be used to perform PCA dimensionality reduction on the SOAP\ndescriptors. The resulting PC coordinates can be used to visualize the the\ndata alongside their structures in a chemiscope widget.\n\nNote: chemiscope widgets are not currently integrated into our sphinx gallery:\ncoming soon.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Generate a structure PCA\nstruct_soap_pca = PCA(n_components=2).fit_transform(struct_soap.block(0).values)\nassert struct_soap_pca.shape == (n_frames, 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot the PCA map\n\nNotice how the selected points avoid the densely-sampled area, and cover\nthe periphery of the dataset\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Matplotlib plot\nfig, ax = plt.subplots(1, 1, figsize=(6, 4))\nscatter = ax.scatter(struct_soap_pca[:, 0], struct_soap_pca[:, 1], c=\"red\")\nax.plot(\n struct_soap_pca[struct_cur_idxs, 0],\n struct_soap_pca[struct_cur_idxs, 1],\n \"ko\",\n fillstyle=\"none\",\n label=\"FPS selection\",\n)\nax.set_xlabel(\"PCA[1]\")\nax.set_ylabel(\"PCA[2]\")\nax.legend()\nfig.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creates a chemiscope viewer\n\nInteractive viewer (only works in notebooks)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Selected level\nselection_levels = []\nfor i in range(len(frames)):\n level = 0\n if i in struct_cur_idxs:\n level += 1\n if i in struct_fps_idxs:\n level += 2\n if level == 0:\n level = \"Not selected\"\n elif level == 1:\n level = \"CUR\"\n elif level == 2:\n level = \"FPS\"\n else:\n level = \"FPS+CUR\"\n selection_levels.append(level)\n\nproperties = chemiscope.extract_properties(frames)\n\nproperties.update(\n {\n \"PC1\": struct_soap_pca[:, 0],\n \"PC2\": struct_soap_pca[:, 1],\n \"selection\": np.array(selection_levels),\n }\n)\n\n\n# Display with chemiscope. This currently does not work - as raised in issue #8\n# https://github.com/lab-cosmo/software-cookbook/issues/8\nwidget = chemiscope.show(\n frames,\n properties=properties,\n settings={\n \"map\": {\n \"x\": {\"property\": \"PC1\"},\n \"y\": {\"property\": \"PC2\"},\n \"color\": {\"property\": \"energy\"},\n \"symbol\": \"selection\",\n \"size\": {\"factor\": 50},\n },\n \"structure\": [{\"unitCell\": True}],\n },\n)\n\nif chemiscope.jupyter._is_running_in_notebook():\n from IPython.display import display\n\n display(widget)\nelse:\n widget.save(\"sample-selection.json.gz\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Perform feature selection\n\nNow perform feature selection. In this example we will go back to using the\ndescriptor decomposed into atomic environments, as opposed to the one\ndecomposed into structure environments, but only use FPS for brevity.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"----Feature selection-----\")\n\n# Define the number of features to select\nn_features = 200\n\n# FPS feature selection\nfeat_fps = feature_selection.FPS(n_to_select=n_features, initialize=\"random\").fit(\n atom_soap_single_block\n)\n\n# Slice atomic descriptor along axis 1 to contain only the selected features\n# atom_soap_single_block_fps = atom_soap_single_block.block(0).values[:, feat_fps_idxs]\natom_soap_single_block_fps = metatensor.slice(\n atom_soap_single_block,\n axis=\"properties\",\n labels=feat_fps.support.block(0).properties,\n)\n\nprint(\n \"atomic descriptor shape before selection \",\n atom_soap_single_block.block(0).values.shape,\n)\nprint(\n \"atomic descriptor shape after selection \",\n atom_soap_single_block_fps.block(0).values.shape,\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Perform feature selection (skmatter)\n\nNow perform feature selection. In this example we will go back to using the\ndescriptor decomposed into atomic environments, as opposed to the one\ndecomposed into structure environments, but only use FPS for brevity.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\"----Feature selection (skmatter)-----\")\n\n# Define the number of features to select\nn_features = 200\n\n# FPS feature selection\nfeat_fps = skfeat_selection.FPS(n_to_select=n_features, initialize=\"random\").fit(\n atom_soap_single_block.block(0).values\n)\nfeat_fps_idxs = feat_fps.selected_idx_\n\nprint(\"Feature indices obtained with FPS \", feat_fps_idxs)\n\n# Slice atomic descriptor along axis 1 to contain only the selected features\natom_dscrptr_fps = atom_soap_single_block.block(0).values[:, feat_fps_idxs]\n\nprint(\n \"atomic descriptor shape before selection \",\n atom_soap_single_block.block(0).values.shape,\n)\nprint(\"atomic descriptor shape after selection \", atom_dscrptr_fps.shape)" + ] + } + ], + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/5b1c4e22a9037fdd90b3ffe8aaf577e9/environment.yml b/latest/_downloads/5b1c4e22a9037fdd90b3ffe8aaf577e9/environment.yml new file mode 100644 index 00000000..7b8a2c5a --- /dev/null +++ b/latest/_downloads/5b1c4e22a9037fdd90b3ffe8aaf577e9/environment.yml @@ -0,0 +1,13 @@ +channels: + - conda-forge +dependencies: + - python=3.11 + - pip + - rust > 1.65 + - pip: + - ase + - matplotlib + - rascaline @ git+https://github.com/Luthaf/rascaline@ca957642f512e141c7570e987aadc05c7ac71983 + - torch + - scipy + - numpy diff --git a/latest/_downloads/61cac41226274764c3aff5e112f310da/roy-gch.ipynb b/latest/_downloads/61cac41226274764c3aff5e112f310da/roy-gch.ipynb new file mode 100644 index 00000000..a58087d5 --- /dev/null +++ b/latest/_downloads/61cac41226274764c3aff5e112f310da/roy-gch.ipynb @@ -0,0 +1,248 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Generalized Convex Hull construction for the polymorphs of ROY\n\n:Authors: Michele Ceriotti [@ceriottm](https://github.com/ceriottm/)\n\nThis notebook analyzes the structures of 264 polymorphs of ROY, from\n[Beran et Al, Chemical Science\n(2022)](https://doi.org/10.1039/D1SC06074K)_, comparing the\nconventional density-energy convex hull with a Generalized Convex Hull\n(GCH) analysis (see [Anelli et al., Phys. Rev. Materials\n(2018)](https://doi.org/10.1103/PhysRevMaterials.2.103804)_).\nIt uses features computed with [rascaline](https://github.com/lab-cosmo/rascaline)_\nand uses the directional convex hull function from\n[scikit-matter](https://github.com/lab-cosmo/scikit-matter)_\nto make the figure.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import chemiscope\nimport matplotlib.tri\nimport numpy as np\nfrom matplotlib import pyplot as plt\nfrom metatensor import mean_over_samples\nfrom rascaline import SoapPowerSpectrum\nfrom sklearn.decomposition import PCA\nfrom skmatter.datasets import load_roy_dataset\nfrom skmatter.sample_selection import DirectionalConvexHull" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loads the structures (that also contain properties in the ``info`` field)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "roy_data = load_roy_dataset()\n\nstructures = roy_data[\"structures\"]\n\ndensity = np.array([s.info[\"density\"] for s in structures])\nenergy = np.array([s.info[\"energy\"] for s in structures])\nstructype = np.array([s.info[\"type\"] for s in structures])\niknown = np.where(structype == \"known\")[0]\niothers = np.where(structype != \"known\")[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Energy-density hull\n\nThe Directional Convex Hull routines can be used to compute a\nconventional density-energy hull\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dch_builder = DirectionalConvexHull(low_dim_idx=[0])\ndch_builder.fit(density.reshape(-1, 1), energy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can get the indices of the selection, and compute the distance from\nthe hull\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sel = dch_builder.selected_idx_\ndch_dist = dch_builder.score_samples(density.reshape(-1, 1), energy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Hull energies\n\nStructures on the hull are stable with respect to synthesis at constant\nmolar volume. Any other structure would lower the energy by decomposing\ninto a mixture of the two nearest structures along the hull. Given that\nthe lattice energy is an imperfect proxy for the free energy, and that\nsynthesis can be performed in other ways than by fixing the density,\nstructures that are not exactly on the hull might also be stable. One\ncan compute a \u201chull energy\u201d as an indication of how close these\nstructures are to being stable.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(1, 1, figsize=(6, 4))\nax.scatter(density, energy, c=dch_dist, marker=\".\")\nssel = sel[np.argsort(density[sel])]\nax.plot(density[ssel], energy[ssel], \"k--\")\nax.set_xlabel(\"density / g/cm$^3$\")\nax.set_ylabel(\"energy / kJ/mol\")\n\nprint(\n f\"Mean hull energy for 'known' stable structures {dch_dist[iknown].mean()} kJ/mol\"\n)\nprint(f\"Mean hull energy for 'other' structures {dch_dist[iothers].mean()} kJ/mol\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Interactive visualization\n\nYou can also visualize the hull with ``chemiscope``.\nThis runs only in a notebook, and\nrequires having the ``chemiscope`` package installed.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cs = chemiscope.show(\n structures,\n dict(\n energy=energy,\n density=density,\n hull_energy=dch_dist,\n structure_type=structype,\n ),\n settings={\n \"map\": {\n \"x\": {\"property\": \"density\"},\n \"y\": {\"property\": \"energy\"},\n \"color\": {\"property\": \"hull_energy\"},\n \"symbol\": \"structure_type\",\n \"size\": {\"factor\": 35},\n },\n \"structure\": [{\"unitCell\": True, \"supercell\": {\"0\": 2, \"1\": 2, \"2\": 2}}],\n },\n)\n\n\nif chemiscope.jupyter._is_running_in_notebook():\n from IPython.display import display\n\n display(cs)\nelse:\n cs.save(\"roy_ch.json.gz\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generalized Convex Hull\n\nA GCH is a similar construction, in which generic structural descriptors\nare used in lieu of composition, density or other thermodynamic\nconstraints. The idea is that configurations that are found close to the\nGCH are locally stable with respect to structurally-similar\nconfigurations. In other terms, one can hope to find a thermodynamic\nconstraint (i.e.\u00a0synthesis conditions) that act differently on these\nstructures in comparison with the others, and may potentially stabilize\nthem.\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Compute structural descriptors\n\nA first step is to computes suitable ML descriptors. Here we have used\n``rascaline`` to evaluate average SOAP features for the structures.\nIf you don't want to install these dependencies for this example you\ncan also use the pre-computed features, but you can use this as a stub\nto apply this analysis to other chemical systems\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "hypers = {\n \"cutoff\": 4,\n \"max_radial\": 6,\n \"max_angular\": 4,\n \"atomic_gaussian_width\": 0.7,\n \"cutoff_function\": {\"ShiftedCosine\": {\"width\": 0.5}},\n \"radial_basis\": {\"Gto\": {\"accuracy\": 1e-6}},\n \"center_atom_weight\": 1.0,\n}\ncalculator = SoapPowerSpectrum(**hypers)\nrho2i = calculator.compute(structures)\nrho2i = rho2i.keys_to_samples([\"species_center\"]).keys_to_properties(\n [\"species_neighbor_1\", \"species_neighbor_2\"]\n)\nrho2i_structure = mean_over_samples(rho2i, sample_names=[\"center\", \"species_center\"])\nnp.savez(\"roy_features.npz\", feats=rho2i_structure.block(0).values)\n\n\n# features = roy_data[\"features\"]\nfeatures = rho2i_structure.block(0).values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### PCA projection\n\nComputes PCA projection to generate low-dimensional descriptors that\nreflect structural diversity. Any other dimensionality reduction scheme\ncould be used in a similar fashion.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pca = PCA(n_components=4)\npca_features = pca.fit_transform(features)\n\nfig, ax = plt.subplots(1, 1, figsize=(6, 4))\nscatter = ax.scatter(pca_features[:, 0], pca_features[:, 1], c=energy)\nax.set_xlabel(\"PCA[1]\")\nax.set_ylabel(\"PCA[2]\")\ncbar = fig.colorbar(scatter, ax=ax)\ncbar.set_label(\"energy / kJ/mol\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Builds the Generalized Convex Hull\n\nBuilds a convex hull on the first two PCA features\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dch_builder = DirectionalConvexHull(low_dim_idx=[0, 1])\ndch_builder.fit(pca_features, energy)\nsel = dch_builder.selected_idx_\ndch_dist = dch_builder.score_samples(pca_features, energy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Generates a 3D Plot\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "triang = matplotlib.tri.Triangulation(pca_features[sel, 0], pca_features[sel, 1])\nfig = plt.figure(figsize=(7, 5), tight_layout=True)\nax = fig.add_subplot(projection=\"3d\")\nax.plot_trisurf(triang, energy[sel], color=\"gray\")\nax.scatter(pca_features[:, 0], pca_features[:, 1], energy, c=dch_dist)\nax.set_xlabel(\"PCA[1]\")\nax.set_ylabel(\"PCA[2]\")\nax.set_zlabel(\"energy / kJ/mol\\n \\n\", labelpad=11)\nax.view_init(25, 110)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The GCH construction improves the separation between the hull energies\nof \u201cknown\u201d and hypothetical polymorphs (compare with the density-energy\nvalues above)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\n f\"Mean hull energy for 'known' stable structures {dch_dist[iknown].mean()} kJ/mol\"\n)\nprint(f\"Mean hull energy for 'other' structures {dch_dist[iothers].mean()} kJ/mol\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualize in ``chemiscope``. This runs only in a notebook, and\nrequires having the ``chemiscope`` package installed.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for i, f in enumerate(structures):\n for j in range(len(pca_features[i])):\n f.info[\"pca_\" + str(j + 1)] = pca_features[i, j]\nstructure_properties = chemiscope.extract_properties(structures)\nstructure_properties.update({\"per_atom_energy\": energy, \"hull_energy\": dch_dist})\n\n# shows chemiscope if not run in terminal\n\ncs = chemiscope.show(\n frames=structures,\n properties=structure_properties,\n meta={\n \"name\": \"GCH for ROY polymorphs\",\n \"description\": \"\"\"\nDemonstration of the Generalized Convex Hull construction for\npolymorphs of the ROY molecule. Molecules that are closest to\nthe hull built on PCA-based structural descriptors and having the\ninternal energy predicted by electronic-structure calculations as\nthe z axis are the most thermodynamically stable. Indeed most of the\nknown polymorphs of ROY are on (or very close) to this hull.\n\"\"\",\n \"authors\": [\"Michele Ceriotti \"],\n \"references\": [\n 'A. Anelli, E. A. Engel, C. J. Pickard, and M. Ceriotti, \\\n \"Generalized convex hull construction for materials discovery,\" \\\n Physical Review Materials 2(10), 103804 (2018).',\n 'G. J. O. Beran, I. J. Sugden, C. Greenwell, D. H. Bowskill, \\\n C. C. Pantelides, and C. S. Adjiman, \"How many more polymorphs of \\\n ROY remain undiscovered,\" Chem. Sci. 13(5), 1288\u20131297 (2022).',\n ],\n },\n settings={\n \"map\": {\n \"x\": {\"property\": \"pca_1\"},\n \"y\": {\"property\": \"pca_2\"},\n \"z\": {\"property\": \"energy\"},\n \"symbol\": \"type\",\n \"color\": {\"property\": \"hull_energy\"},\n \"size\": {\n \"factor\": 35,\n \"mode\": \"linear\",\n \"property\": \"\",\n \"reverse\": True,\n },\n },\n \"structure\": [\n {\n \"bonds\": True,\n \"unitCell\": True,\n \"keepOrientation\": True,\n }\n ],\n },\n)\n\nif chemiscope.jupyter._is_running_in_notebook():\n from IPython.display import display\n\n display(cs)\nelse:\n cs.save(\"roy_gch.json.gz\")" + ] + } + ], + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/62b1217b7f64a94ea92cd43a62433b84/dos-align.ipynb b/latest/_downloads/62b1217b7f64a94ea92cd43a62433b84/dos-align.ipynb new file mode 100644 index 00000000..1c07491f --- /dev/null +++ b/latest/_downloads/62b1217b7f64a94ea92cd43a62433b84/dos-align.ipynb @@ -0,0 +1,543 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Training the DOS with different Energy References\n:Authors: How Wei Bin [@HowWeiBin](https://github.com/HowWeiBin/)\n\nThis tutorial would go through the entire machine learning framework for the electronic\ndensity of states (DOS). It will cover the construction of the DOS and SOAP\ndescriptors from ase Atoms and eigenenergy results. A simple neural network will\nthen be constructed and the model parameters, along with the energy reference will be\noptimized during training. A total of three energy reference will be used, the average\nHartree potential, the Fermi level, and an optimized energy reference starting from\nthe Fermi level energy reference. The performance of each model is then compared.\n\n\n\nFirstly, lets begin by importing the necessary packages and helper functions\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\nimport zipfile\n\nimport ase\nimport ase.io\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport requests\nimport torch\nfrom rascaline import SoapPowerSpectrum\nfrom scipy.interpolate import CubicHermiteSpline, interp1d\nfrom scipy.optimize import brentq\nfrom torch.utils.data import BatchSampler, DataLoader, Dataset, RandomSampler" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 0: Load Structures and Eigenenergies\n1) Downloading and Extracting Data\n2) Loading Data\n3) Find range of eigenenergies\n\nWe take a small subset of 104 structures in the Si dataset from `Bartok et al.,\n2018 `.\nEach structure in the dataset contains two atoms.\n\n\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1) Downloading and Extracting Data\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "filename = \"dataset.zip\"\nif not os.path.exists(filename):\n url = \"https://github.com/HowWeiBin/datasets/archive/refs/tags/Silicon-Diamonds.zip\"\n response = requests.get(url)\n response.raise_for_status()\n with open(filename, \"wb\") as f:\n f.write(response.content)\n\nwith zipfile.ZipFile(\"./dataset.zip\", \"r\") as zip_ref:\n zip_ref.extractall(\"./\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2) Loading Data\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "structures = ase.io.read(\"./datasets-Silicon-Diamonds/diamonds.xyz\", \":\")\nn_structures = len(structures)\nn_atoms = torch.tensor([len(i) for i in structures])\neigenenergies = torch.load(\"./datasets-Silicon-Diamonds/diamond_energies.pt\")\nk_normalization = torch.tensor(\n [len(i) for i in eigenenergies]\n) # Calculates number of kpoints sampled per structure\nprint(f\"Total number of structures: {len(structures)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3) Find range of eigenenergies\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Process eigenenergies to flattened torch tensors\n\ntotal_eigenenergies = [torch.flatten(torch.tensor(i)) for i in eigenenergies]\n\n# Get lowest and highest value of eigenenergies to know the range of eigenenergies\n\nall_eigenenergies = torch.hstack(total_eigenenergies)\nminE = torch.min(all_eigenenergies)\nmaxE = torch.max(all_eigenenergies)\nprint(f\"The lowest eigenenergy in the dataset is {minE:.3}\")\nprint(f\"The highest eigenenergy in the dataset is {maxE:.3}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 1: Constructing the DOS with different energy references\n1) Construct the DOS using the original reference\n2) Calculate the Fermi level from the DOS\n3) Build a set of eigenenergies, with the energy reference set to the fermi level\n4) Truncate the DOS energy window so that the DOS is well-defined at each point\n5) Construct the DOS in the truncated energy window under both references\n6) Construct Splines for the DOS to facilitate interpolation during model training\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1) Construct the DOS using the original reference\nThe DOS will first be constructed from the full set of eigenenergies to\ndetermine the Fermi level of each structure. The original reference is the\nAverage Hartree Potential in this example.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# To ensure that all the eigenenergies are fully represented after\n# gaussian broadening, the energy axis of the DOS extends\n# 3eV wider than the range of values for the eigenenergies\nenergy_lower_bound = minE - 1.5\nenergy_upper_bound = maxE + 1.5\n\n# Gaussian Smearing for the eDOS, 0.3eV is the appropriate value for this dataset\n\nsigma = torch.tensor(0.3)\nenergy_interval = 0.05\n# energy axis, with a grid interval of 0.05 eV\n\nx_dos = torch.arange(energy_lower_bound, energy_upper_bound, energy_interval)\nprint(\n f\"The energy axis ranges from {energy_lower_bound:.3} to \\\n{energy_upper_bound:.3}, consisting of {len(x_dos)} grid points\"\n)\n\n# normalization factor for each DOS, factor of 2 is included\n# because each eigenenergy can be occupied by 2 electrons\n\nnormalization = 2 * (\n 1 / torch.sqrt(2 * torch.tensor(np.pi) * sigma**2) / n_atoms / k_normalization\n)\n\ntotal_edos = []\n\nfor structure_eigenenergies in total_eigenenergies:\n e_dos = torch.sum(\n # Builds a gaussian on each eigenenergy\n # and calculates the value on each grid point\n torch.exp(-0.5 * ((x_dos - structure_eigenenergies.view(-1, 1)) / sigma) ** 2),\n dim=0,\n )\n total_edos.append(e_dos)\n\ntotal_edos = torch.vstack(total_edos)\ntotal_edos = (total_edos.T * normalization).T\n\nprint(f\"The final shape of all the DOS in the dataset is: {list(total_edos.shape)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2) Calculate the Fermi level from the DOS\nNow we integration the DOS, and then use cubic interpolation and brentq\nto calculate the fermi level. Since only the 4 valence electrons in Silicon\nare represented in this energy range, we take the point where the DOS integrates\nto 4 as the fermi level.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fermi_levels = []\ntotal_i_edos = torch.cumulative_trapezoid(\n total_edos, x_dos, axis=1\n) # Integrate the DOS along the energy axis\nfor i in total_i_edos:\n interpolated = interp1d(\n x_dos[:-1], i - 4, kind=\"cubic\", copy=True, assume_sorted=True\n ) # We use i-4 because Silicon has 4 electrons in this energy range\n Ef = brentq(\n interpolated, x_dos[0] + 0.1, x_dos[-1] - 0.1\n ) # Fermi Level is the point where the (integrated DOS - 4) = 0\n # 0.1 is added and subtracted to prevent brentq from going out of range\n fermi_levels.append(Ef)\nfermi_levels = torch.tensor(fermi_levels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3) Build a set of eigenenergies, with the energy reference set to the fermi level\nUsing the fermi levels, we are now able to change the energy reference\nof the eigenenergies to the fermi level\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "total_eigenenergies_Ef = []\nfor index, energies in enumerate(total_eigenenergies):\n total_eigenenergies_Ef.append(energies - fermi_levels[index])\n\nall_eigenenergies_Ef = torch.hstack(total_eigenenergies_Ef)\n\nminE_Ef = torch.min(all_eigenenergies_Ef)\nmaxE_Ef = torch.max(all_eigenenergies_Ef)\nprint(f\"The lowest eigenenergy using the fermi level energy reference is {minE_Ef:.3}\")\nprint(f\"The highest eigenenergy using the fermi level energy reference is {maxE_Ef:.3}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4) Truncate the DOS energy window so that the DOS is well-defined at each point\nWith the fermi levels, we can also truncate the energy window for DOS prediction.\nIn this example, we truncate the energy window such that it is 3eV above\nthe highest Fermi level in the dataset.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# For the Average Hartree Potential energy reference\nx_dos_H = torch.arange(minE - 1.5, max(fermi_levels) + 3, energy_interval)\n\n# For the Fermi Level Energy Reference, all the Fermi levels in the dataset is 0eV\nx_dos_Ef = torch.arange(minE_Ef - 1.5, 3, energy_interval)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5) Construct the DOS in the truncated energy window under both references\nHere we construct 2 different targets where they differ in the energy reference\nchosen. These targets will then be treated as different datasets for the model\nto learn on.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# For the Average Hartree Potential energy reference\n\ntotal_edos_H = []\n\nfor structure_eigenenergies_H in total_eigenenergies:\n e_dos = torch.sum(\n torch.exp(\n -0.5 * ((x_dos_H - structure_eigenenergies_H.view(-1, 1)) / sigma) ** 2\n ),\n dim=0,\n )\n total_edos_H.append(e_dos)\n\ntotal_edos_H = torch.vstack(total_edos_H)\ntotal_edos_H = (total_edos_H.T * normalization).T\n\n\n# For the Fermi Level Energy Reference\n\ntotal_edos_Ef = []\n\nfor structure_eigenenergies_Ef in total_eigenenergies_Ef:\n e_dos = torch.sum(\n torch.exp(\n -0.5 * ((x_dos_Ef - structure_eigenenergies_Ef.view(-1, 1)) / sigma) ** 2\n ),\n dim=0,\n )\n total_edos_Ef.append(e_dos)\n\ntotal_edos_Ef = torch.vstack(total_edos_Ef)\ntotal_edos_Ef = (total_edos_Ef.T * normalization).T" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 6) Construct Splines for the DOS to facilitate interpolation during model training\nBuilding Cubic Hermite Splines on the DOS on the truncated energy window\nto facilitate interpolation during training. Cubic Hermite Splines takes\nin information on the value and derivative of a function at a point to build splines.\nThus, we will have to compute both the value and derivative at each spline position\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Functions to compute the value and derivative of the DOS at each energy value, x\ndef edos_value(x, eigenenergies, normalization):\n e_dos_E = (\n torch.sum(\n torch.exp(-0.5 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2), dim=0\n )\n * normalization\n )\n\n return e_dos_E\n\n\ndef edos_derivative(x, eigenenergies, normalization):\n dfn_dos_E = (\n torch.sum(\n torch.exp(-0.5 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2)\n * (-1 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2),\n dim=0,\n )\n * normalization\n )\n\n return dfn_dos_E\n\n\ntotal_splines_H = []\n# the splines have a higher energy range in case the shift is high\nspline_positions_H = torch.arange(minE - 2, max(fermi_levels) + 6, energy_interval)\n\nfor index, structure_eigenenergies_H in enumerate(total_eigenenergies):\n e_dos_H = edos_value(\n spline_positions_H, structure_eigenenergies_H, normalization[index]\n )\n e_dos_H_grad = edos_derivative(\n spline_positions_H, structure_eigenenergies_H, normalization[index]\n )\n spliner = CubicHermiteSpline(spline_positions_H, e_dos_H, e_dos_H_grad)\n total_splines_H.append(torch.tensor(spliner.c))\n\ntotal_splines_H = torch.stack(total_splines_H)\n\ntotal_splines_Ef = []\nspline_positions_Ef = torch.arange(minE_Ef - 2, 6, energy_interval)\n\nfor index, structure_eigenenergies_Ef in enumerate(total_eigenenergies_Ef):\n e_dos_Ef = edos_value(\n spline_positions_Ef, structure_eigenenergies_Ef, normalization[index]\n )\n e_dos_Ef_grad = edos_derivative(\n spline_positions_Ef, structure_eigenenergies_Ef, normalization[index]\n )\n spliner = CubicHermiteSpline(spline_positions_Ef, e_dos_Ef, e_dos_Ef_grad)\n total_splines_Ef.append(torch.tensor(spliner.c))\n\ntotal_splines_Ef = torch.stack(total_splines_Ef)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have stored the splines coefficients (spliner.c) as torch tensors,\nas such as we will need to write a function to evaluate the DOS from\nthe splines positions and coefficients.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def evaluate_spline(spline_coefs, spline_positions, x):\n \"\"\"\n spline_coefs: shape of (n x 4 x spline_positions)\n\n return value: shape of (n x x)\n\n x : shape of (n x n_points)\n \"\"\"\n interval = torch.round(\n spline_positions[1] - spline_positions[0], decimals=4\n ) # get spline grid intervals\n x = torch.clamp(\n x, min=spline_positions[0], max=spline_positions[-1] - 0.0005\n ) # restrict x to fall within the spline interval\n # 0.0005 is substracted to combat errors arising from precision\n indexes = torch.floor(\n (x - spline_positions[0]) / interval\n ).long() # Obtain the index for the appropriate spline coefficients\n expanded_index = indexes.unsqueeze(dim=1).expand(-1, 4, -1)\n x_1 = x - spline_positions[indexes]\n x_2 = x_1 * x_1\n x_3 = x_2 * x_1\n x_0 = torch.ones_like(x_1)\n x_powers = torch.stack([x_3, x_2, x_1, x_0]).permute(1, 0, 2)\n value = torch.sum(\n torch.mul(x_powers, torch.gather(spline_coefs, 2, expanded_index)), axis=1\n )\n\n return value # returns the value of the DOS at the energy positions, x." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets look at the accuracy of the splines.\nTest 1: Ability to reproduce the correct values at the default x_dos positions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "shifts = torch.zeros(n_structures)\nx_dos_splines = x_dos_H + shifts.view(-1, 1)\nspline_dos_H = evaluate_spline(total_splines_H, spline_positions_H, x_dos_splines)\n\nplt.plot(x_dos_H, total_edos_H[0], color=\"red\", label=\"True DOS\")\nplt.plot(x_dos_H, spline_dos_H[0], color=\"blue\", linestyle=\"--\", label=\"Spline DOS\")\nplt.legend()\nplt.xlabel(\"Energy [eV]\")\nplt.ylabel(\"DOS\")\nprint(\"Both lines lie on each other\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Test 2: Ability to reproduce the correct values at the shifted x_dos positions\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "shifts = torch.zeros(n_structures) + 0.3\nx_dos_splines = x_dos_Ef + shifts.view(-1, 1)\nspline_dos_Ef = evaluate_spline(total_splines_Ef, spline_positions_Ef, x_dos_splines)\n\nplt.plot(x_dos_Ef, total_edos_Ef[0], color=\"red\", label=\"True DOS\")\nplt.plot(x_dos_Ef, spline_dos_Ef[0], color=\"blue\", linestyle=\"--\", label=\"Spline DOS\")\nplt.legend()\nplt.xlabel(\"Energy [eV]\")\nplt.ylabel(\"DOS\")\nprint(\"Both spectras look very similar\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 2: Compute SOAP power spectrum for the dataset\n\nWe first define the hyperparameters to compute the\nSOAP power spectrum using rascaline.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "HYPER_PARAMETERS = {\n \"cutoff\": 4.0,\n \"max_radial\": 8,\n \"max_angular\": 6,\n \"atomic_gaussian_width\": 0.45,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\"Gto\": {}},\n \"cutoff_function\": {\n \"Step\": {},\n },\n \"radial_scaling\": {\n \"Willatt2018\": {\n \"exponent\": 5,\n \"rate\": 1,\n \"scale\": 3.0,\n },\n },\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We feed the Hyperparameters into rascaline to compute the SOAP Power spectrum\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "calculator = SoapPowerSpectrum(**HYPER_PARAMETERS)\nR_total_soap = calculator.compute(structures)\n# Transform the tensormap to a single block containing a dense representation\nR_total_soap.keys_to_samples(\"species_center\")\nR_total_soap.keys_to_properties([\"species_neighbor_1\", \"species_neighbor_2\"])\n\n# Now we extract the data tensor from the single block\ntotal_atom_soap = []\nfor structure_i in range(n_structures):\n a_i = R_total_soap.block(0).samples[\"structure\"] == structure_i\n total_atom_soap.append(torch.tensor(R_total_soap.block(0).values[a_i, :]))\n\ntotal_soap = torch.stack(total_atom_soap)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 3: Building a Simple MLP Model\n\n1) Split the data into Training, Validation and Test\n2) Define the dataloader and the Model Architecture\n3) Define relevant loss functions for training and inference\n4) Define the training loop\n5) Evaluate the model\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1) Split the data into Training, Validation and Test\nWe will first split the data in a 7:1:2 manner, corresponding to train, val and test.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "np.random.seed(0)\ntrain_index = np.arange(n_structures)\nnp.random.shuffle(train_index)\ntest_mark = int(0.8 * n_structures)\nval_mark = int(0.7 * n_structures)\ntest_index = train_index[test_mark:]\nval_index = train_index[val_mark:test_mark]\ntrain_index = train_index[:val_mark]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2) Define the dataloader and the Model Architecture\nWe will now build a dataloader and dataset to facillitate training the model batchwise\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def generate_atomstructure_index(n_atoms_per_structure):\n \"\"\"Generate a sequence of indices for each atom in the structure.\n The indices correspond to index of the structure that the atom belongs to\n\n Args:\n n_atoms_per_structure ([array]):\n [Array containing the number of atoms each structure contains]\n\n Return s:\n [tensor]: [Total index, matching atoms to structure]\n \"\"\"\n # n_structures = len(n_atoms_per_structure)\n total_index = []\n for i, atoms in enumerate(n_atoms_per_structure):\n indiv_index = torch.zeros(atoms) + i\n total_index.append(indiv_index)\n total_index = torch.hstack(total_index)\n return total_index.long()\n\n\nclass AtomicDataset(Dataset):\n def __init__(self, features, n_atoms_per_structure):\n self.features = features\n self.n_structures = len(n_atoms_per_structure)\n self.n_atoms_per_structure = n_atoms_per_structure\n self.index = generate_atomstructure_index(self.n_atoms_per_structure)\n assert torch.sum(n_atoms_per_structure) == len(features)\n\n def __len__(self):\n return self.n_structures\n\n def __getitem__(self, idx):\n if isinstance(idx, list): # If a list of indexes is given\n feature_indexes = []\n\n for i in idx:\n feature_indexes.append((self.index == i).nonzero(as_tuple=True)[0])\n\n feature_indexes = torch.hstack(feature_indexes)\n\n return (\n self.features[feature_indexes],\n idx,\n generate_atomstructure_index(self.n_atoms_per_structure[idx]),\n )\n\n else:\n feature_indexes = (self.index == idx).nonzero(as_tuple=True)[0]\n return (\n self.features[feature_indexes],\n idx,\n self.n_atoms_per_structure[idx],\n )\n\n\ndef collate(\n batch,\n): # Defines how to collate the outputs of the __getitem__ function at each batch\n for x, idx, index in batch:\n return (x, idx, index)\n\n\nx_train = torch.flatten(total_soap[train_index], 0, 1).float()\ntotal_atomic_soaps = torch.vstack(total_atom_soap).float()\ntrain_features = AtomicDataset(x_train, n_atoms[train_index])\nfull_atomstructure_index = generate_atomstructure_index(n_atoms)\n# Will be required later to collate atomic predictions into structural predictions\n\n# Build a Dataloader that samples from the AtomicDataset in random batches\nSampler = RandomSampler(train_features)\nBSampler = BatchSampler(Sampler, batch_size=32, drop_last=False)\ntraindata_loader = DataLoader(train_features, sampler=BSampler, collate_fn=collate)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will now define a simple three layer MLP model, consisting of three layers.\nThe align keyword is used to indicate that the energy reference will be optimized\nduring training. The alignment parameter refers to the adjustments made to the\ninitial energy referenced and will be initialized as zeros.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class SOAP_NN(torch.nn.Module):\n def __init__(self, input_dims, L1, n_train, target_dims, align):\n super(SOAP_NN, self).__init__()\n self.target_dims = target_dims\n self.fc1 = torch.nn.Linear(input_dims, L1)\n self.fc2 = torch.nn.Linear(L1, target_dims)\n self.silu = torch.nn.SiLU()\n self.align = align\n if align:\n initial_alignment = torch.zeros(n_train)\n self.alignment = torch.nn.parameter.Parameter(initial_alignment)\n\n def forward(self, x):\n result = self.fc1(x)\n result = self.silu(result)\n result = self.fc2(result)\n return result" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will use a small network architecture, whereby the input layer corresponds\nto the size of the SOAP features, 448, the intermediate layer corresponds to\na tenth size of the input layer and the final layer corresponds\nto the number of outputs.\n\nAs a shorthand, the model that optimizes the energy reference during\ntraining will be called the alignment model\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "n_outputs_H = len(x_dos_H)\nn_outputs_Ef = len(x_dos_Ef)\n\n\nModel_H = SOAP_NN(\n x_train.shape[1],\n x_train.shape[1] // 10,\n len(train_index),\n n_outputs_H,\n align=False,\n)\nModel_Ef = SOAP_NN(\n x_train.shape[1],\n x_train.shape[1] // 10,\n len(train_index),\n n_outputs_Ef,\n align=False,\n)\nModel_Align = SOAP_NN(\n x_train.shape[1],\n x_train.shape[1] // 10,\n len(train_index),\n n_outputs_Ef,\n align=True,\n)\n# The alignment model takes the fermi level energy reference as the starting point" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3) Define relevant loss functions for training and inference\nWe will now define some loss functions that will be useful when we implement\nthe model training loop later and during model evaluation on the test set.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def t_get_mse(a, b, xdos):\n \"\"\"Compute mean error between two Density of States.\n The mean error is integrated across the entire energy grid\n to provide a single value to characterize the error\n\n Args:\n a ([tensor]): [Predicted DOS]\n b ([tensor]): [True DOS]\n xdos ([tensor], optional): [Energy axis of DOS]\n\n Returns:\n [float]: [MSE]\n \"\"\"\n if len(a.size()) > 1:\n mse = (torch.trapezoid((a - b) ** 2, xdos, axis=1)).mean()\n else:\n mse = (torch.trapezoid((a - b) ** 2, xdos, axis=0)).mean()\n return mse\n\n\ndef t_get_rmse(a, b, xdos):\n \"\"\"Compute root mean squared error between two Density of States .\n\n Args:\n a ([tensor]): [Predicted DOS]\n b ([tensor]): [True DOS]\n xdos ([tensor], optional): [Energy axis of DOS]\n\n Raises:\n ValueError: [Occurs if tensor shapes are mismatched]\n\n Returns:\n [float]: [RMSE or %RMSE]\n \"\"\"\n\n if len(a.size()) > 1:\n rmse = torch.sqrt((torch.trapezoid((a - b) ** 2, xdos, axis=1)).mean())\n else:\n rmse = torch.sqrt((torch.trapezoid((a - b) ** 2, xdos, axis=0)).mean())\n return rmse\n\n\ndef Opt_RMSE_spline(y_pred, xdos, target_splines, spline_positions, n_epochs):\n \"\"\"Evaluates RMSE on the optimal shift of energy axis.\n The optimal shift is found via gradient descent after a gridsearch is performed.\n\n Args:\n y_pred ([tensor]): [Prediction/s of DOS]\n xdos ([tensor]): [Energy axis]\n target_splines ([tensor]): [Contains spline coefficients]\n spline_positions ([tensor]): [Contains spline positions]\n n_epochs ([int]): [Number of epochs to run for Gradient Descent]\n\n Returns:\n [rmse([float]), optimal_shift[tensor]]:\n [RMSE on optimal shift, the optimal shift itself]\n\n \"\"\"\n optim_search_mse = []\n offsets = torch.arange(-2, 2, 0.1)\n # Grid-search is first done to reduce number of epochs needed for\n # gradient descent, typically 50 epochs will be sufficient\n # if searching within 0.1\n with torch.no_grad():\n for offset in offsets:\n shifts = torch.zeros(y_pred.shape[0]) + offset\n shifted_target = evaluate_spline(\n target_splines, spline_positions, xdos + shifts.view(-1, 1)\n )\n loss_i = ((y_pred - shifted_target) ** 2).mean(dim=1)\n optim_search_mse.append(loss_i)\n optim_search_mse = torch.vstack(optim_search_mse)\n min_index = torch.argmin(optim_search_mse, dim=0)\n optimal_offset = offsets[min_index]\n\n offset = optimal_offset\n\n shifts = torch.nn.parameter.Parameter(offset.float())\n opt_adam = torch.optim.Adam([shifts], lr=1e-2)\n best_error = torch.zeros(len(shifts)) + 100\n best_shifts = shifts.clone()\n for _ in range(n_epochs):\n shifted_target = evaluate_spline(\n target_splines, spline_positions, xdos + shifts.view(-1, 1)\n ).detach()\n\n def closure():\n opt_adam.zero_grad()\n shifted_target = evaluate_spline(\n target_splines, spline_positions, xdos + shifts.view(-1, 1)\n )\n loss_i = ((y_pred - shifted_target) ** 2).mean()\n loss_i.backward(gradient=torch.tensor(1), inputs=shifts)\n return loss_i\n\n opt_adam.step(closure)\n\n with torch.no_grad():\n each_loss = ((y_pred - shifted_target) ** 2).mean(dim=1).float()\n index = each_loss < best_error\n best_error[index] = each_loss[index].clone()\n best_shifts[index] = shifts[index].clone()\n\n # Evaluate\n\n optimal_shift = best_shifts\n shifted_target = evaluate_spline(\n target_splines, spline_positions, xdos + optimal_shift.view(-1, 1)\n )\n rmse = t_get_rmse(y_pred, shifted_target, xdos)\n return rmse, optimal_shift" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4) Define the training loop\n\nWe will now define the model training loop, for simplicity we will only\ntrain each model for a fixed number of epochs, learning rate, and batch_size.\nThe training and validation error at each epoch will be saved.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def train_model(model_to_train, fixed_DOS, structure_splines, spline_positions, x_dos):\n \"\"\"Trains a model for 500 epochs\n\n Args:\n model_to_train ([torch.nn.Module]): [ML Model]\n fixed_DOS ([tensor]): [Contains the DOS at a fixed energy reference,\n useful for models that don't optimize the energy reference]\n structure_splines ([tensor]): [Contains spline coefficients]\n spline_positions ([tensor]): [Contains spline positions]\n x_dos ([tensor]): [Energy axis for the prediction]\n\n Returns:\n [train_loss_history([tensor]),\n val_loss_history[tensor],\n structure_results[tensor]]:\n\n [Respective loss histories and final structure predictions]\n \"\"\"\n lr = 1e-2\n n_epochs = 500\n\n opt = torch.optim.Adam(model_to_train.parameters(), lr=lr)\n\n train_loss_history = []\n val_loss_history = []\n\n for _epoch in range(n_epochs):\n for x_data, idx, index in traindata_loader:\n opt.zero_grad()\n predictions = model_to_train.forward(x_data)\n structure_results = torch.zeros([len(idx), model_to_train.target_dims])\n # Sum atomic predictions in each structure\n structure_results = structure_results.index_add_(\n 0, index, predictions\n ) / n_atoms[train_index[idx]].view(-1, 1)\n if model_to_train.align:\n alignment = model_to_train.alignment\n alignment = alignment - torch.mean(alignment)\n # Enforce that the alignments have a mean of zero since a constant\n # value across the dataset is meaningless when optimizing the\n # relative energy reference\n target = evaluate_spline(\n structure_splines[train_index[idx]],\n spline_positions,\n x_dos + alignment[idx].view(-1, 1),\n ) # Shifts the target based on the alignment value\n pred_loss = t_get_mse(structure_results, target, x_dos)\n pred_loss.backward()\n else:\n pred_loss = t_get_mse(\n structure_results, fixed_DOS[train_index[idx]], x_dos\n )\n pred_loss.backward()\n\n opt.step()\n with torch.no_grad():\n all_pred = model_to_train.forward(total_atomic_soaps.float())\n structure_results = torch.zeros([n_structures, model_to_train.target_dims])\n structure_results = structure_results.index_add_(\n 0, full_atomstructure_index, all_pred\n ) / (n_atoms).view(-1, 1)\n if model_to_train.align:\n # Evaluate model on optimal shift as there is no information\n # regarding the shift from the fermi level energy reference\n # during inference\n\n alignment = model_to_train.alignment\n alignment = alignment - torch.mean(alignment)\n target = evaluate_spline(\n structure_splines[train_index],\n spline_positions,\n x_dos + alignment.view(-1, 1),\n )\n\n train_loss = t_get_rmse(structure_results[train_index], target, x_dos)\n val_loss, val_shifts = Opt_RMSE_spline(\n structure_results[val_index],\n x_dos,\n structure_splines[val_index],\n spline_positions,\n 50,\n )\n\n else:\n train_loss = t_get_rmse(\n structure_results[train_index], fixed_DOS[train_index], x_dos\n )\n val_loss = t_get_rmse(\n structure_results[val_index], fixed_DOS[val_index], x_dos\n )\n\n train_loss_history.append(train_loss)\n val_loss_history.append(val_loss)\n train_loss_history = torch.tensor(train_loss_history)\n val_loss_history = torch.tensor(val_loss_history)\n return (\n train_loss_history,\n val_loss_history,\n structure_results,\n )\n # returns the loss history and the final set of predictions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "H_trainloss, H_valloss, H_predictions = train_model(\n Model_H, total_edos_H, total_splines_H, spline_positions_H, x_dos_H\n)\n\nEf_trainloss, Ef_valloss, Ef_predictions = train_model(\n Model_Ef, total_edos_Ef, total_splines_Ef, spline_positions_Ef, x_dos_Ef\n)\n\nAlign_trainloss, Align_valloss, Align_predictions = train_model(\n Model_Align, total_edos_Ef, total_splines_Ef, spline_positions_Ef, x_dos_Ef\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets plot the train loss histories to compare their learning behaviour\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "epochs = np.arange(500)\n\n\nplt.plot(epochs, H_trainloss, color=\"red\", label=\"Avg Hartree Potential\")\nplt.plot(epochs, Ef_trainloss, color=\"blue\", label=\"Fermi Level\")\nplt.plot(epochs, Align_trainloss, color=\"green\", label=\"Optimized Reference\")\nplt.legend()\nplt.yscale(value=\"log\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"RMSE\")\nplt.title(\"Train Loss vs Epoch\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets plot the val loss histories to compare their learning behaviour\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plt.plot(epochs, H_valloss, color=\"red\", label=\"Avg Hartree Potential\")\nplt.plot(epochs, Ef_valloss, color=\"blue\", label=\"Fermi Level\")\nplt.plot(epochs, Align_valloss, color=\"green\", label=\"Optimized Reference\")\nplt.legend()\nplt.yscale(value=\"log\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"RMSE\")\nplt.title(\"Validation Loss vs Epoch\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5) Evaluate the model\nWe will now evaluate the model performance on the test set\nbased on the model predictions we obtained previously\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "H_testloss = Opt_RMSE_spline(\n H_predictions[test_index],\n x_dos_H,\n total_splines_H[test_index],\n spline_positions_H,\n 200,\n) # We use 200 epochs just so it the error a little bit more converged\nEf_testloss = Opt_RMSE_spline(\n Ef_predictions[test_index],\n x_dos_Ef,\n total_splines_Ef[test_index],\n spline_positions_Ef,\n 200,\n) # We use 200 epochs just so it the error a little bit more converged\nAlign_testloss = Opt_RMSE_spline(\n Align_predictions[test_index],\n x_dos_Ef,\n total_splines_Ef[test_index],\n spline_positions_Ef,\n 200,\n) # We use 200 epochs just so it the error a little bit more converged\n\nprint(f\"Test RMSE for average Hartree Potential: {H_testloss[0].item():.3}\")\nprint(f\"Test RMSE for Fermi Level: {Ef_testloss[0].item():.3}\")\nprint(f\"Test RMSE for Optimized Reference: {Align_testloss[0].item():.3}\")\n\nprint(\n \"The difference in effectiveness between the Optimized Reference \\\nand the Fermi Level will increase with more epochs\"\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot Training DOSes at different energy reference to visualize\nthe impact of the energy reference. From the plots we can see\nthat the optimized energy reference has better alignment of\ncommon spectral patterns across the dataset\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAverage Hartree Energy Reference\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for i in total_edos_H[train_index]:\n plt.plot(x_dos_H, i, color=\"C0\", alpha=0.6)\nplt.title(\"Energy Reference - Average Hartree Potential\")\nplt.xlabel(\"Energy [eV]\")\nplt.ylabel(\"DOS\")\nprint(\"The DOSes, despite looking similar, are offset along the energy axis\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fermi Level Energy Reference\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for i in total_edos_Ef[train_index]:\n plt.plot(x_dos_Ef, i, color=\"C0\", alpha=0.6)\nplt.title(\"Energy Reference - Fermi Level\")\nplt.xlabel(\"Energy [eV]\")\nplt.ylabel(\"DOS\")\n\nprint(\"It is better aligned but still quite some offset\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Optimized Energy Reference\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "shifts = Model_Align.alignment.detach()\nshifts = shifts - torch.mean(shifts)\nx_dos_splines = x_dos_Ef + shifts.view(-1, 1)\ntotal_edos_align = evaluate_spline(\n total_splines_Ef[train_index], spline_positions_Ef, x_dos_splines\n)\n\nfor i in total_edos_align:\n plt.plot(x_dos_Ef, i, color=\"C0\", alpha=0.6)\nplt.title(\"Energy Reference - Optimized\")\nplt.xlabel(\"Energy [eV]\")\nplt.ylabel(\"DOS\")\nprint(\"The DOS alignment is better under the optimized energy reference\")\nprint(\"The difference will increase with more training epochs\")" + ] + } + ], + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/6cadff1f3492fc92f1615765051399cd/environment.yml b/latest/_downloads/6cadff1f3492fc92f1615765051399cd/environment.yml new file mode 100644 index 00000000..74144273 --- /dev/null +++ b/latest/_downloads/6cadff1f3492fc92f1615765051399cd/environment.yml @@ -0,0 +1,12 @@ +channels: + - conda-forge +dependencies: + - python=3.11 + - pip + - rust >=1.65 + - pip: + - ase + - equisolve @ git+https://github.com/lab-cosmo/equisolve.git@c858bedef4b2799eb445e4c92535ee387224089a + - matplotlib + - metatensor + - rascaline @ git+https://github.com/Luthaf/rascaline@ca957642f512e141c7570e987aadc05c7ac71983 diff --git a/latest/_downloads/6e397e9158b2a5505af1904db0846a5c/run_calcs.sh b/latest/_downloads/6e397e9158b2a5505af1904db0846a5c/run_calcs.sh new file mode 100644 index 00000000..59a8ff53 --- /dev/null +++ b/latest/_downloads/6e397e9158b2a5505af1904db0846a5c/run_calcs.sh @@ -0,0 +1,7 @@ +#! /bin/bash + +for i in $(find ./production/ -mindepth 1 -type d); do + cd $i + cp2k.ssmp -i in.cp2k + cd - +done diff --git a/latest/_downloads/8052f55b323764c2ee21cbfef5187bf4/lpr.ipynb b/latest/_downloads/8052f55b323764c2ee21cbfef5187bf4/lpr.ipynb new file mode 100644 index 00000000..af9ef9ce --- /dev/null +++ b/latest/_downloads/8052f55b323764c2ee21cbfef5187bf4/lpr.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# LPR analysis for amorphous silicon dataset\n\n:Authors: Sanggyu \"Raymond\" Chong [@SanggyuChong](https://github.com/sanggyuChong/),\n Federico Grasselli [@fgrassel](https://github.com/fgrassel/)\n\nIn this tutorial, we calculate the SOAP descriptors of an amorphous\nsilicon dataset using rascaline, then compute the local prediction\nrigidity (LPR) for the atoms of a \"test\" set before and after\nmodifications to the \"training\" dataset has been made.\n\nFirst, we import all the necessary packages:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\nimport tarfile\n\nimport numpy as np\nimport requests\nfrom ase.io import read\nfrom matplotlib import pyplot as plt\nfrom matplotlib.colors import LogNorm\nfrom rascaline import SoapPowerSpectrum\nfrom sklearn.decomposition import PCA\nfrom skmatter.metrics import local_prediction_rigidity as lpr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load and prepare amorphous silicon data\n\n\nWe first download the dataset associated with LPR\nanalysis from Materials Cloud and load the the amorphous\nsilicon structures using [ASE](https://wiki.fysik.dtu.dk/ase/).\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "filename = \"LPR_supp_notebook_dataset.tar.gz\"\nif not os.path.exists(filename):\n url = \"https://rb.gy/wxsrug\" # shortened URL\n response = requests.get(url)\n response.raise_for_status()\n with open(filename, \"wb\") as f:\n f.write(response.content)\n\nwith tarfile.open(filename) as tar:\n tar.extractall(path=\".\")\n\nframes_pristine = read(\"datasets/Si_amo_defect_free.xyz\", \":\")\nframes_defect = read(\"datasets/Si_amo_defect_containing.xyz\", \":\")\n\n# Randomly shuffle the structures\n\nnp.random.seed(20230215)\n\nids = list(range(len(frames_pristine)))\nnp.random.shuffle(ids)\nframes_pristine = [frames_pristine[ii] for ii in ids]\n\nids = list(range(len(frames_defect)))\nnp.random.shuffle(ids)\nframes_defect = [frames_defect[ii] for ii in ids]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now further refine the loaded datasets according the the\nnumber of coordinated atoms that each atomic environment exhibits.\n\"Pristine\" refers to structures where all of the atoms have strictly\n4 coordinating atoms. \"Defect\" refers to structures that contain\natoms with coordination numbers other than 4.\n\nWe use :code:`get_all_distances` funciton of :code:`ase.Atoms` to detect the\nnumber of coordinated atoms.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cur_cutoff = 2.7\nrefined_pristine_frames = []\nfor frame in frames_pristine:\n neighs = (frame.get_all_distances(mic=True) < cur_cutoff).sum(axis=0) - 1\n if neighs.max() > 4 or neighs.min() < 4:\n continue\n else:\n refined_pristine_frames.append(frame)\n\nrefined_defect_frames = []\nfor frame in frames_defect:\n neighs = (frame.get_all_distances(mic=True) < cur_cutoff).sum(axis=0) - 1\n num_defects = (neighs > 4).sum() + (neighs < 4).sum()\n if num_defects > 4:\n refined_defect_frames.append(frame)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Compute SOAP descriptors using rascaline\n\nNow, we move on and compute the SOAP descriptors for the refined\nstructures. First, define the rascaline hyperparameters used to\ncompute SOAP. Among the hypers, notice that the cutoff is chosen\nto be 2.85 \u00c5, and the radial scaling is turned off. These were\nheuristic choices made to accentuate the difference in the LPR\nbased on the nearest-neighbor coordination. (Do not blindly\nuse this set of hypers for production-quality model training!)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Hypers dictionary\nhypers = {\n \"cutoff\": 2.85,\n \"max_radial\": 10,\n \"max_angular\": 12,\n \"atomic_gaussian_width\": 0.5,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\"Gto\": {\"spline_accuracy\": 1e-8}},\n \"cutoff_function\": {\"ShiftedCosine\": {\"width\": 0.1}},\n \"radial_scaling\": None,\n}\n# Define rascaline calculator\ncalculator = SoapPowerSpectrum(**hypers)\n\n# Calculate the SOAP power spectrum\nXlist_pristine = []\nfor frame in refined_pristine_frames:\n descriptor = calculator.compute(frame)\n Xlist_pristine.append(np.array(descriptor.block().values))\n\nXlist_defect = []\nfor frame in refined_defect_frames:\n descriptor = calculator.compute(frame)\n Xlist_defect.append(np.array(descriptor.block().values))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Organize structures into \"training\" and \"test\" sets\n\nNow we move on and compute the SOAP descriptors for the refined\nstructures. First, define the rascaline hyperparameters used to\ncompute SOAP.\n\nNotice that the format in which we handle the descriptors is as a\nlist of :code:`np.array` descriptor blocks. This is to ensure\ncompatibility with how things have been implemented in the LPR\nmodule of :code:`scikit-matter`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "n_train = 400\nn_add = 50\nn_test = 50\n\nX_pristine = [Xlist for Xlist in Xlist_pristine[: n_train + n_add]]\nX_defect = [Xlist for Xlist in Xlist_defect[:n_add]]\nX_test = [Xlist for Xlist in Xlist_defect[n_add : n_add + n_test]]\n\n# Save coordination values for visualization\ntest_coord = []\nfor frame in refined_defect_frames[n_add : n_add + n_test]:\n coord = (frame.get_all_distances(mic=True) < cur_cutoff - 0.05).sum(axis=0) - 1\n test_coord += coord.tolist()\ntest_coord = np.array(test_coord)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Compute the LPR for the test set\n\nNext, we will use the :code:`local_prediction_rigidity` module of\n[scikit-matter](https://scikit-matter.readthedocs.io/en/latest/)\nto compute the LPRs for the test set that we have set apart.\n\nLPR reflects how the ML model perceives a local environment,\ngiven a collection of other structures, similar or different.\nIt should then carry over some of the details involved in training\nthe model, in this case the regularization strength.\n\nFor this example, we have foregone on the actual model training,\nand so we define an arbitrary value for the alpha.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "alpha = 1e-4\nLPR_test, rank = lpr(X_pristine, X_test, alpha)\nLPR_test = np.hstack(LPR_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing the LPR on a PCA map\n\nWe now visualize the LPRs of the test set on a PCA map,\nwhere the PCA is performed on the SOAP descriptors of\ndefect-containing dataset.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "pca = PCA(n_components=5)\ndescriptors_all = calculator.compute(refined_defect_frames)\npca.fit_transform(descriptors_all.block().values)\nPCA_test = pca.transform(np.vstack(X_test))\n\nrmin = np.log10(LPR_test.min()) + 0.5\nrmax = np.log10(LPR_test.max()) - 0.5\n\nfig = plt.figure(figsize=(5, 4), dpi=200)\nax = fig.add_subplot()\nim = ax.scatter(\n PCA_test[:, 0],\n PCA_test[:, 1],\n c=LPR_test,\n s=20,\n linewidths=0,\n norm=LogNorm(vmin=10**rmin, vmax=10**rmax),\n cmap=\"viridis\",\n)\n\nax.set_xlabel(\"PC1\")\nax.set_ylabel(\"PC2\")\nfig.colorbar(im, ax=ax, label=\"LPR\")\nax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the PCA map, where each point corresponds to an\natomic environment of the test set structures, one\ncan observe 4 different clusters of points, arranged\nalong PC1. This corresponds to the coordination numbers\nranging from 3 to 6. Since the training set contains\nstructures exclusively composed of 4-coordinated atoms,\nLPR is distinctly high for the second, main cluster of\npoints, and quite low for the three other clusters.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Studying the LPR after dataset modification\n\nWe now want to see what would happen when defect structures\nare included into the training set of the model. For this,\nwe first create a modified dataset that incorporates in the\ndefect structures, and recompute the LPR.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X_new = X_pristine[:n_train] + X_defect[:n_add]\nLPR_test_new, rank = lpr(X_new, X_test, alpha)\nLPR_test_new = np.hstack(LPR_test_new)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We then visualize the change in the LPR with the\nmodification of the dataset by plotting the same PCA\nmap, but now colored by the ratio of new set of LPR\nvalues (after dataset modification) over the original\none.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(5, 4), dpi=200)\nax = fig.add_subplot()\nim = ax.scatter(\n PCA_test[:, 0],\n PCA_test[:, 1],\n c=LPR_test_new / LPR_test,\n s=20,\n linewidths=0,\n # norm=LogNorm(vmin=10**rmin, vmax=10**rmax),\n cmap=\"OrRd\",\n)\nax.set_xlabel(\"PC1\")\nax.set_ylabel(\"PC2\")\nfig.colorbar(im, ax=ax, label=r\"LPR$_{\\mathrm{new}}$ / LPR$_{\\mathrm{old}}$\")\nax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is apparent that while the LPR stays more or less consistent for the\n4-coordinated atoms, it is significantly enhanced for the defective environments\nas a result of the inclusion of defective structures in the training set.\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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/87860011d67b243cba3a72df0fa64d08/lode-linear.ipynb b/latest/_downloads/87860011d67b243cba3a72df0fa64d08/lode-linear.ipynb new file mode 100644 index 00000000..a8ef52ec --- /dev/null +++ b/latest/_downloads/87860011d67b243cba3a72df0fa64d08/lode-linear.ipynb @@ -0,0 +1,446 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# LODE Tutorial\n\n:Authors: Philip Loche [@PicoCentauri](https://github.com/PicoCentauri/),\n Kevin Huguenin-Dumittan [@kvhuguenin](https://github.com/kvhuguenin)\n\nThis tutorial explains how Long range equivariant descriptors can be constructed using\nrascaline and the resulting descriptors be used to construct a linear model with\nequisolve\n\nFirst, import all the necessary packages\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import ase.io\nimport matplotlib.pyplot as plt\nimport metatensor\nimport numpy as np\nfrom equisolve.numpy.models.linear_model import Ridge\nfrom equisolve.utils.convert import ase_to_tensormap\nfrom rascaline import AtomicComposition, LodeSphericalExpansion, SphericalExpansion\nfrom rascaline.utils import PowerSpectrum" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 0: Prepare Data Set\n\n### Get structures\n\nWe take a small subset of the dimer dataset from [A. Grisafi et al.,\n2021](https://pubs.rsc.org/en/content/articlelanding/2021/sc/d0sc04934d)\nfor which we additionally calculated the forces. Each structure in the\ndataset contains two small organic molecules which are extended along a\ncertain direction in the subsequent structures.\n\nFor speeding up the calculations we already selected the first 130\n:download:`structures ` of the charge-charge molecule\npairs.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "frames = ase.io.read(\"charge-charge.xyz\", \":\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Convert target properties to metatensor format\n\nIf we want to train models using the\n[equisolve](https://github.com/lab-cosmo/equisolve) package, we need to\nconvert the target properties (in this case, the energies and forces)\ninto the appropriate format #justequistorethings\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "y = ase_to_tensormap(frames, energy=\"energy\", forces=\"forces\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 1: Compute short-range and LODE features\n\nDefine hypers and get the expansion coefficients $\\langle anlm | \\rho_i \\rangle$\nand $\\langle anlm | V_i \\rangle$\n\nThe short-range and long-range descriptors have very similar hyperparameters. We\nhighlight the differences below.\n\nWe first define the hyperparameters for the short-range (SR) part. These will be used\nto create SOAP features.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "SR_HYPERS = {\n \"cutoff\": 3.0,\n \"max_radial\": 6,\n \"max_angular\": 2,\n \"atomic_gaussian_width\": 0.3,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\"Gto\": {}},\n \"cutoff_function\": {\"ShiftedCosine\": {\"width\": 0.5}},\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And next the hyperparaters for the LODE / long-range (LR) part\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "LR_HYPERS = {\n # Cutoff on which to project potential density\n \"cutoff\": 3.0,\n # keep max_radial slightly smaller than for SR part\n \"max_radial\": 3,\n # max_angular should be <= 4, more precisely, max_angular + potential_exponent < 10\n \"max_angular\": 2,\n # keep at >=1, WARNING: CUBIC SCALING, do not use values <0.5\n \"atomic_gaussian_width\": 3.0,\n \"center_atom_weight\": 1.0,\n \"radial_basis\": {\"Gto\": {}},\n # the exponent p that determines the 1/r^p potential\n \"potential_exponent\": 1,\n}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We then use the above defined hyperparaters to define the per atom short range (sr)\nand long range (sr) descriptors.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "calculator_sr = SphericalExpansion(**SR_HYPERS)\ncalculator_lr = LodeSphericalExpansion(**LR_HYPERS)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that LODE requires periodic systems. Therefore, if the data set does not come\nwith periodic boundary conditions by default you can not use the data set and you will\nface an error if you try to compute the features.\n\nAs you notices the calculation of the long range features takes significant more time\ncompared to the sr features.\n\nTaking a look at the output we find that the resulting\n:py:class:`metatensor.TensorMap` are quite similar in their structure. The short range\n:py:class:`metatensor.TensorMap` contains more blocks due to the higher\n``max_angular`` paramater we choosed above.\n\n### Generate the rotational invariants (power spectra)\n\nRotationally invariant features can be obtained by taking two of the calculators that\nwere defines above.\n\nFor the short-range part, we use the SOAP vector which is obtained by computing the\ninvariant combinations of the form $\\rho \\otimes \\rho$.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ps_calculator_sr = PowerSpectrum(calculator_sr, calculator_sr)\nps_sr = ps_calculator_sr.compute(frames, gradients=[\"positions\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We calculate gradients with respect to pistions by providing the\n``gradients=[\"positions\"]`` option to the\n:py:meth:`rascaline.calculators.CalculatorBase.compute()` method.\n\nFor the long-range part, we combine the long-range descriptor $V$ with one a\nshort-range density $\\rho$ to get $\\rho \\otimes V$ features.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ps_calculator_lr = PowerSpectrum(calculator_sr, calculator_lr)\nps_lr = ps_calculator_lr.compute(systems=frames, gradients=[\"positions\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 2: Building a Simple Linear SR + LR Model with energy baselining\n\n### Preprocessing (model dependent)\n\nFor our current model, we do not wish to treat the individual center and\nneighbor species separately. Thus, we move the ``\"species_center\"`` key\ninto the ``sample`` direction, over which we will later sum over.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ps_sr = ps_sr.keys_to_samples(\"species_center\")\nps_lr = ps_lr.keys_to_samples(\"species_center\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For linear models only: Sum features up over atoms (``samples``) in the same\nstructure.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sample_names_to_sum = [\"center\", \"species_center\"]\n\nps_sr = metatensor.sum_over_samples(ps_sr, sample_names=sample_names_to_sum)\nps_lr = metatensor.sum_over_samples(ps_lr, sample_names=sample_names_to_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Initialize tensormaps for energy baselining\n\nWe add a simple extra descriptor :py:class:`rascaline.AtomicComposition` that stores\nhow many atoms of each chemical species are contained in the structures. This is used\nfor energy baselining.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "calculator_co = AtomicComposition(per_structure=False)\ndescriptor_co = calculator_co.compute(frames, gradients=[\"positions\"])\n\nco = descriptor_co.keys_to_properties([\"species_center\"])\nco = metatensor.sum_over_samples(co, sample_names=[\"center\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The :py:class:`rascaline.AtomicComposition` calculator also allows to directly perform\nthe the sum over center atoms by using the following lines.\n\n.. code:: python\n\n descriptor_co = AtomicComposition(per_structure=True).compute(**compute_args)\n co = descriptor_co.keys_to_properties([\"species_center\"])\n\n### Stack all the features together for linear model\n\nA linear model on SR + LR features can be thought of as a linear model\nbuilt on a feature vector that is simply the concatenation of the SR and\nLR features.\n\nFurthermore, energy baselining can be performed by concatenating the information about\nchemical species as well. There is an metatensor function called\n:py:func:`metatensor.join()` for this purpose. Formally, we can write for the SR\nmodel.\n\nX_sr: $1 \\oplus \\left(\\rho \\otimes \\rho\\right)$\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X_sr = metatensor.join([co, ps_sr], axis=\"properties\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We used the ``axis=\"properties\"`` parameter since we want to concatenate along the\nfeatures/properties dimensions.\n\nFor the long range model we can formerly write\n\nX_lr: $1 \\oplus \\left(\\rho \\otimes \\rho\\right) \\oplus \\left(\\rho \\otimes\nV\\right)$\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X_lr = metatensor.join([co, ps_sr, ps_lr], axis=\"properties\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The features are now ready! Let us now perform some actual learning. Below we\ninitialize two instances of the :py:class:`equisolve.numpy.models.linear_model.Ridge`\nclass. :py:class:`equisolve.numpy.models.linear_model.Ridge` will perform a regression\nwith respect to ``\"values\"`` (energies) and ``\"positions\"`` gradients (forces).\n\nIf you only want a fit with respect to energies you can remove the gradients with\n``metatensor.remove_gradients()``\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "clf_sr = Ridge()\nclf_lr = Ridge()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Split training and target data into train and test dat\n\nSplit the training and the test data by the distance $r_{\\rm\ntrain}=6\\,\\mathrm{\u00c5}$ between the center of mass of the two molecules. A structure\nwith a $r_{\\rm train}<6 {\\rm \u00c5}$ is used for training.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "r_cut = 6.0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We calculate the indices from the dataset by list comprehension. The center of mass\ndistance is stored in the ``\"distance\"\"`` attribute.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "idx_train = [i for i, f in enumerate(frames) if f.info[\"distance\"] < r_cut]\nidx_test = [i for i, f in enumerate(frames) if f.info[\"distance\"] >= r_cut]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For doing the split we define two ``Labels`` instances and combine them in a\n:py:class:`List`.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "samples_train = metatensor.Labels([\"structure\"], np.reshape(idx_train, (-1, 1)))\nsamples_test = metatensor.Labels([\"structure\"], np.reshape(idx_test, (-1, 1)))\ngrouped_labels = [samples_train, samples_test]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That we use as input to the :py:func:`metatensor.split()` function\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "X_sr_train, X_sr_test = metatensor.split(\n X_sr, axis=\"samples\", grouped_labels=grouped_labels\n)\n\nX_lr_train, X_lr_test = metatensor.split(\n X_lr, axis=\"samples\", grouped_labels=grouped_labels\n)\n\ny_train, y_test = metatensor.split(y, axis=\"samples\", grouped_labels=grouped_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fit the model\n\nFor this model, we use a very simple regularization scheme where all features are\nregularized in the same way (the amount being controlled by the parameter ``alpha``).\nFor more advanced regularization schemes (regularizing energies and forces differently\nand/or the SR and LR parts differently), see further down.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "clf_sr.fit(X_sr_train, y_train, alpha=1e-6)\nclf_lr.fit(X_lr_train, y_train, alpha=1e-6)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation\n\nFor evaluating the model we calculate the RMSEs using the ``score()`` method. With the\n``parameter_key`` parameter we select which RMSE should be calculated.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "print(\n \"SR: RMSE energies = \"\n f\"{clf_sr.score(X_sr_test, y_test, parameter_key='values')[0]:.3f} eV\"\n)\nprint(\n \"SR: RMSE forces = \"\n f\"{clf_sr.score(X_sr_test, y_test, parameter_key='positions')[0]:.3f} eV/\u00c5\"\n)\n\nprint(\n \"LR: RMSE energies = \"\n f\"{clf_lr.score(X_lr_test, y_test, parameter_key='values')[0]:.3f} eV\"\n)\nprint(\n \"LR: RMSE forces = \"\n f\"{clf_lr.score(X_lr_test, y_test, parameter_key='positions')[0]:.3f} eV/\u00c5\"\n)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We find that the RMSE of the energy and the force of the LR model is smaller compared\nto the SR model. From this we conclude that the LR model performs better for the\nselection of the dataset.\n\nWe additionally, can plot of the binding energy as a function of the distance. For the\nplot we select some properties from the dataset\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dist = np.array([f.info[\"distance\"] for f in frames])\nenergies = np.array([f.info[\"energy\"] for f in frames])\nmonomer_energies = np.array([f.info[\"energyA\"] + f.info[\"energyB\"] for f in frames])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and select only the indices corresponding to our test set.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we calculate the predicted SR and LR ``TensorMaps``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "y_sr_pred = clf_sr.predict(X_sr)\ny_lr_pred = clf_lr.predict(X_lr)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And, finally perform the plot.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "plt.scatter(\n dist, y.block().values[:, 0] - monomer_energies, label=\"target data\", color=\"black\"\n)\n\nplt.scatter(\n dist,\n y_sr_pred.block().values[:, 0] - monomer_energies,\n label=\"short range model\",\n marker=\"x\",\n)\n\nplt.scatter(\n dist,\n y_lr_pred.block().values[:, 0] - monomer_energies,\n label=\"long range model\",\n marker=\"s\",\n facecolor=\"None\",\n edgecolor=\"orange\",\n)\n\nplt.xlabel(\"center of mass distance in \u00c5\")\nplt.ylabel(r\"$E - E_\\mathrm{monomer}$ in eV\")\nplt.axvline(r_cut, c=\"red\", label=r\"$r_\\mathrm{train}$\")\n\nplt.legend()\nplt.tight_layout()\nplt.show()" + ] + } + ], + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/89f739150c737d83b9f5bb306c62ba22/lode-linear.py b/latest/_downloads/89f739150c737d83b9f5bb306c62ba22/lode-linear.py new file mode 100644 index 00000000..23ac620b --- /dev/null +++ b/latest/_downloads/89f739150c737d83b9f5bb306c62ba22/lode-linear.py @@ -0,0 +1,395 @@ +""" +LODE Tutorial +============= + +:Authors: Philip Loche `@PicoCentauri `_, + Kevin Huguenin-Dumittan `@kvhuguenin `_ + +This tutorial explains how Long range equivariant descriptors can be constructed using +rascaline and the resulting descriptors be used to construct a linear model with +equisolve + +First, import all the necessary packages +""" + +# %% + +import ase.io +import matplotlib.pyplot as plt +import metatensor +import numpy as np +from equisolve.numpy.models.linear_model import Ridge +from equisolve.utils.convert import ase_to_tensormap +from rascaline import AtomicComposition, LodeSphericalExpansion, SphericalExpansion +from rascaline.utils import PowerSpectrum + + +# %% +# +# Step 0: Prepare Data Set +# ------------------------ +# +# Get structures +# ~~~~~~~~~~~~~~ +# +# We take a small subset of the dimer dataset from `A. Grisafi et al., +# 2021 `_ +# for which we additionally calculated the forces. Each structure in the +# dataset contains two small organic molecules which are extended along a +# certain direction in the subsequent structures. +# +# For speeding up the calculations we already selected the first 130 +# :download:`structures ` of the charge-charge molecule +# pairs. + +frames = ase.io.read("charge-charge.xyz", ":") + + +# %% +# +# Convert target properties to metatensor format +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# If we want to train models using the +# `equisolve `_ package, we need to +# convert the target properties (in this case, the energies and forces) +# into the appropriate format #justequistorethings + +y = ase_to_tensormap(frames, energy="energy", forces="forces") + + +# %% +# +# Step 1: Compute short-range and LODE features +# --------------------------------------------- +# +# Define hypers and get the expansion coefficients :math:`\langle anlm | \rho_i \rangle` +# and :math:`\langle anlm | V_i \rangle` +# +# The short-range and long-range descriptors have very similar hyperparameters. We +# highlight the differences below. +# +# We first define the hyperparameters for the short-range (SR) part. These will be used +# to create SOAP features. + +SR_HYPERS = { + "cutoff": 3.0, + "max_radial": 6, + "max_angular": 2, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {}}, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, +} + + +# %% +# +# And next the hyperparaters for the LODE / long-range (LR) part + + +LR_HYPERS = { + # Cutoff on which to project potential density + "cutoff": 3.0, + # keep max_radial slightly smaller than for SR part + "max_radial": 3, + # max_angular should be <= 4, more precisely, max_angular + potential_exponent < 10 + "max_angular": 2, + # keep at >=1, WARNING: CUBIC SCALING, do not use values <0.5 + "atomic_gaussian_width": 3.0, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {}}, + # the exponent p that determines the 1/r^p potential + "potential_exponent": 1, +} + + +# %% +# We then use the above defined hyperparaters to define the per atom short range (sr) +# and long range (sr) descriptors. + +calculator_sr = SphericalExpansion(**SR_HYPERS) +calculator_lr = LodeSphericalExpansion(**LR_HYPERS) + + +# %% +# +# Note that LODE requires periodic systems. Therefore, if the data set does not come +# with periodic boundary conditions by default you can not use the data set and you will +# face an error if you try to compute the features. +# +# As you notices the calculation of the long range features takes significant more time +# compared to the sr features. +# +# Taking a look at the output we find that the resulting +# :py:class:`metatensor.TensorMap` are quite similar in their structure. The short range +# :py:class:`metatensor.TensorMap` contains more blocks due to the higher +# ``max_angular`` paramater we choosed above. +# +# Generate the rotational invariants (power spectra) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Rotationally invariant features can be obtained by taking two of the calculators that +# were defines above. +# +# For the short-range part, we use the SOAP vector which is obtained by computing the +# invariant combinations of the form :math:`\rho \otimes \rho`. + +ps_calculator_sr = PowerSpectrum(calculator_sr, calculator_sr) +ps_sr = ps_calculator_sr.compute(frames, gradients=["positions"]) + + +# %% +# +# We calculate gradients with respect to pistions by providing the +# ``gradients=["positions"]`` option to the +# :py:meth:`rascaline.calculators.CalculatorBase.compute()` method. +# +# For the long-range part, we combine the long-range descriptor :math:`V` with one a +# short-range density :math:`\rho` to get :math:`\rho \otimes V` features. + +ps_calculator_lr = PowerSpectrum(calculator_sr, calculator_lr) +ps_lr = ps_calculator_lr.compute(systems=frames, gradients=["positions"]) + + +# %% +# +# Step 2: Building a Simple Linear SR + LR Model with energy baselining +# --------------------------------------------------------------------- +# +# Preprocessing (model dependent) +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# For our current model, we do not wish to treat the individual center and +# neighbor species separately. Thus, we move the ``"species_center"`` key +# into the ``sample`` direction, over which we will later sum over. + +ps_sr = ps_sr.keys_to_samples("species_center") +ps_lr = ps_lr.keys_to_samples("species_center") + + +# %% +# +# For linear models only: Sum features up over atoms (``samples``) in the same +# structure. + +sample_names_to_sum = ["center", "species_center"] + +ps_sr = metatensor.sum_over_samples(ps_sr, sample_names=sample_names_to_sum) +ps_lr = metatensor.sum_over_samples(ps_lr, sample_names=sample_names_to_sum) + + +# %% +# +# Initialize tensormaps for energy baselining +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# We add a simple extra descriptor :py:class:`rascaline.AtomicComposition` that stores +# how many atoms of each chemical species are contained in the structures. This is used +# for energy baselining. + +calculator_co = AtomicComposition(per_structure=False) +descriptor_co = calculator_co.compute(frames, gradients=["positions"]) + +co = descriptor_co.keys_to_properties(["species_center"]) +co = metatensor.sum_over_samples(co, sample_names=["center"]) + +# %% +# +# The :py:class:`rascaline.AtomicComposition` calculator also allows to directly perform +# the the sum over center atoms by using the following lines. +# +# .. code:: python +# +# descriptor_co = AtomicComposition(per_structure=True).compute(**compute_args) +# co = descriptor_co.keys_to_properties(["species_center"]) +# +# Stack all the features together for linear model +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# A linear model on SR + LR features can be thought of as a linear model +# built on a feature vector that is simply the concatenation of the SR and +# LR features. +# +# Furthermore, energy baselining can be performed by concatenating the information about +# chemical species as well. There is an metatensor function called +# :py:func:`metatensor.join()` for this purpose. Formally, we can write for the SR +# model. +# +# X_sr: :math:`1 \oplus \left(\rho \otimes \rho\right)` + +X_sr = metatensor.join([co, ps_sr], axis="properties") + + +# %% +# +# We used the ``axis="properties"`` parameter since we want to concatenate along the +# features/properties dimensions. +# +# For the long range model we can formerly write +# +# X_lr: :math:`1 \oplus \left(\rho \otimes \rho\right) \oplus \left(\rho \otimes +# V\right)` + +X_lr = metatensor.join([co, ps_sr, ps_lr], axis="properties") + + +# %% +# +# The features are now ready! Let us now perform some actual learning. Below we +# initialize two instances of the :py:class:`equisolve.numpy.models.linear_model.Ridge` +# class. :py:class:`equisolve.numpy.models.linear_model.Ridge` will perform a regression +# with respect to ``"values"`` (energies) and ``"positions"`` gradients (forces). +# +# If you only want a fit with respect to energies you can remove the gradients with +# ``metatensor.remove_gradients()`` + +clf_sr = Ridge() +clf_lr = Ridge() + + +# %% +# +# Split training and target data into train and test dat +# ------------------------------------------------------ +# +# Split the training and the test data by the distance :math:`r_{\rm +# train}=6\,\mathrm{Å}` between the center of mass of the two molecules. A structure +# with a :math:`r_{\rm train}<6 {\rm Å}` is used for training. + +r_cut = 6.0 + + +# %% +# +# We calculate the indices from the dataset by list comprehension. The center of mass +# distance is stored in the ``"distance""`` attribute. + +idx_train = [i for i, f in enumerate(frames) if f.info["distance"] < r_cut] +idx_test = [i for i, f in enumerate(frames) if f.info["distance"] >= r_cut] + + +# %% +# +# For doing the split we define two ``Labels`` instances and combine them in a +# :py:class:`List`. + +samples_train = metatensor.Labels(["structure"], np.reshape(idx_train, (-1, 1))) +samples_test = metatensor.Labels(["structure"], np.reshape(idx_test, (-1, 1))) +grouped_labels = [samples_train, samples_test] + + +# %% +# +# That we use as input to the :py:func:`metatensor.split()` function + +X_sr_train, X_sr_test = metatensor.split( + X_sr, axis="samples", grouped_labels=grouped_labels +) + +X_lr_train, X_lr_test = metatensor.split( + X_lr, axis="samples", grouped_labels=grouped_labels +) + +y_train, y_test = metatensor.split(y, axis="samples", grouped_labels=grouped_labels) + + +# %% +# +# Fit the model +# ------------- +# +# For this model, we use a very simple regularization scheme where all features are +# regularized in the same way (the amount being controlled by the parameter ``alpha``). +# For more advanced regularization schemes (regularizing energies and forces differently +# and/or the SR and LR parts differently), see further down. + +clf_sr.fit(X_sr_train, y_train, alpha=1e-6) +clf_lr.fit(X_lr_train, y_train, alpha=1e-6) + + +# %% +# +# Evaluation +# ---------- +# +# For evaluating the model we calculate the RMSEs using the ``score()`` method. With the +# ``parameter_key`` parameter we select which RMSE should be calculated. + +print( + "SR: RMSE energies = " + f"{clf_sr.score(X_sr_test, y_test, parameter_key='values')[0]:.3f} eV" +) +print( + "SR: RMSE forces = " + f"{clf_sr.score(X_sr_test, y_test, parameter_key='positions')[0]:.3f} eV/Å" +) + +print( + "LR: RMSE energies = " + f"{clf_lr.score(X_lr_test, y_test, parameter_key='values')[0]:.3f} eV" +) +print( + "LR: RMSE forces = " + f"{clf_lr.score(X_lr_test, y_test, parameter_key='positions')[0]:.3f} eV/Å" +) + + +# %% +# +# We find that the RMSE of the energy and the force of the LR model is smaller compared +# to the SR model. From this we conclude that the LR model performs better for the +# selection of the dataset. +# +# We additionally, can plot of the binding energy as a function of the distance. For the +# plot we select some properties from the dataset + +dist = np.array([f.info["distance"] for f in frames]) +energies = np.array([f.info["energy"] for f in frames]) +monomer_energies = np.array([f.info["energyA"] + f.info["energyB"] for f in frames]) + + +# %% +# +# and select only the indices corresponding to our test set. + + +# %% +# +# Next we calculate the predicted SR and LR ``TensorMaps``. + +y_sr_pred = clf_sr.predict(X_sr) +y_lr_pred = clf_lr.predict(X_lr) + + +# %% +# +# And, finally perform the plot. + +plt.scatter( + dist, y.block().values[:, 0] - monomer_energies, label="target data", color="black" +) + +plt.scatter( + dist, + y_sr_pred.block().values[:, 0] - monomer_energies, + label="short range model", + marker="x", +) + +plt.scatter( + dist, + y_lr_pred.block().values[:, 0] - monomer_energies, + label="long range model", + marker="s", + facecolor="None", + edgecolor="orange", +) + +plt.xlabel("center of mass distance in Å") +plt.ylabel(r"$E - E_\mathrm{monomer}$ in eV") +plt.axvline(r_cut, c="red", label=r"$r_\mathrm{train}$") + +plt.legend() +plt.tight_layout() +plt.show() diff --git a/latest/_downloads/9ae4cdde3e7099e2bf76d10302eae3e8/environment.yml b/latest/_downloads/9ae4cdde3e7099e2bf76d10302eae3e8/environment.yml new file mode 100644 index 00000000..2388afd2 --- /dev/null +++ b/latest/_downloads/9ae4cdde3e7099e2bf76d10302eae3e8/environment.yml @@ -0,0 +1,12 @@ +channels: + - conda-forge +dependencies: + - python=3.11 + - pip + - lammps + - pip: + - ase + - ipi + - chemiscope + - matplotlib + - skmatter diff --git a/latest/_downloads/a58e2543da5a6b5daa9cea5c8b3c3a21/lpr.py b/latest/_downloads/a58e2543da5a6b5daa9cea5c8b3c3a21/lpr.py new file mode 100644 index 00000000..f5017655 --- /dev/null +++ b/latest/_downloads/a58e2543da5a6b5daa9cea5c8b3c3a21/lpr.py @@ -0,0 +1,263 @@ +""" +LPR analysis for amorphous silicon dataset +========================================== + +:Authors: Sanggyu "Raymond" Chong `@SanggyuChong `_, + Federico Grasselli `@fgrassel `_ + +In this tutorial, we calculate the SOAP descriptors of an amorphous +silicon dataset using rascaline, then compute the local prediction +rigidity (LPR) for the atoms of a "test" set before and after +modifications to the "training" dataset has been made. + +First, we import all the necessary packages: +""" + +# %% +import os +import tarfile + +import numpy as np +import requests +from ase.io import read +from matplotlib import pyplot as plt +from matplotlib.colors import LogNorm +from rascaline import SoapPowerSpectrum +from sklearn.decomposition import PCA +from skmatter.metrics import local_prediction_rigidity as lpr + + +# %% +# Load and prepare amorphous silicon data +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# +# We first download the dataset associated with LPR +# analysis from Materials Cloud and load the the amorphous +# silicon structures using `ASE `_. + +filename = "LPR_supp_notebook_dataset.tar.gz" +if not os.path.exists(filename): + url = "https://rb.gy/wxsrug" # shortened URL + response = requests.get(url) + response.raise_for_status() + with open(filename, "wb") as f: + f.write(response.content) + +with tarfile.open(filename) as tar: + tar.extractall(path=".") + +frames_pristine = read("datasets/Si_amo_defect_free.xyz", ":") +frames_defect = read("datasets/Si_amo_defect_containing.xyz", ":") + +# Randomly shuffle the structures + +np.random.seed(20230215) + +ids = list(range(len(frames_pristine))) +np.random.shuffle(ids) +frames_pristine = [frames_pristine[ii] for ii in ids] + +ids = list(range(len(frames_defect))) +np.random.shuffle(ids) +frames_defect = [frames_defect[ii] for ii in ids] + +# %% +# We now further refine the loaded datasets according the the +# number of coordinated atoms that each atomic environment exhibits. +# "Pristine" refers to structures where all of the atoms have strictly +# 4 coordinating atoms. "Defect" refers to structures that contain +# atoms with coordination numbers other than 4. +# +# We use :code:`get_all_distances` funciton of :code:`ase.Atoms` to detect the +# number of coordinated atoms. + +cur_cutoff = 2.7 +refined_pristine_frames = [] +for frame in frames_pristine: + neighs = (frame.get_all_distances(mic=True) < cur_cutoff).sum(axis=0) - 1 + if neighs.max() > 4 or neighs.min() < 4: + continue + else: + refined_pristine_frames.append(frame) + +refined_defect_frames = [] +for frame in frames_defect: + neighs = (frame.get_all_distances(mic=True) < cur_cutoff).sum(axis=0) - 1 + num_defects = (neighs > 4).sum() + (neighs < 4).sum() + if num_defects > 4: + refined_defect_frames.append(frame) + + +# %% +# Compute SOAP descriptors using rascaline +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Now, we move on and compute the SOAP descriptors for the refined +# structures. First, define the rascaline hyperparameters used to +# compute SOAP. Among the hypers, notice that the cutoff is chosen +# to be 2.85 Å, and the radial scaling is turned off. These were +# heuristic choices made to accentuate the difference in the LPR +# based on the nearest-neighbor coordination. (Do not blindly +# use this set of hypers for production-quality model training!) + +# Hypers dictionary +hypers = { + "cutoff": 2.85, + "max_radial": 10, + "max_angular": 12, + "atomic_gaussian_width": 0.5, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {"spline_accuracy": 1e-8}}, + "cutoff_function": {"ShiftedCosine": {"width": 0.1}}, + "radial_scaling": None, +} +# Define rascaline calculator +calculator = SoapPowerSpectrum(**hypers) + +# Calculate the SOAP power spectrum +Xlist_pristine = [] +for frame in refined_pristine_frames: + descriptor = calculator.compute(frame) + Xlist_pristine.append(np.array(descriptor.block().values)) + +Xlist_defect = [] +for frame in refined_defect_frames: + descriptor = calculator.compute(frame) + Xlist_defect.append(np.array(descriptor.block().values)) + +# %% +# Organize structures into "training" and "test" sets +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Now we move on and compute the SOAP descriptors for the refined +# structures. First, define the rascaline hyperparameters used to +# compute SOAP. +# +# Notice that the format in which we handle the descriptors is as a +# list of :code:`np.array` descriptor blocks. This is to ensure +# compatibility with how things have been implemented in the LPR +# module of :code:`scikit-matter`. + +n_train = 400 +n_add = 50 +n_test = 50 + +X_pristine = [Xlist for Xlist in Xlist_pristine[: n_train + n_add]] +X_defect = [Xlist for Xlist in Xlist_defect[:n_add]] +X_test = [Xlist for Xlist in Xlist_defect[n_add : n_add + n_test]] + +# Save coordination values for visualization +test_coord = [] +for frame in refined_defect_frames[n_add : n_add + n_test]: + coord = (frame.get_all_distances(mic=True) < cur_cutoff - 0.05).sum(axis=0) - 1 + test_coord += coord.tolist() +test_coord = np.array(test_coord) + +# %% +# Compute the LPR for the test set +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Next, we will use the :code:`local_prediction_rigidity` module of +# `scikit-matter `_ +# to compute the LPRs for the test set that we have set apart. +# +# LPR reflects how the ML model perceives a local environment, +# given a collection of other structures, similar or different. +# It should then carry over some of the details involved in training +# the model, in this case the regularization strength. +# +# For this example, we have foregone on the actual model training, +# and so we define an arbitrary value for the alpha. + +alpha = 1e-4 +LPR_test, rank = lpr(X_pristine, X_test, alpha) +LPR_test = np.hstack(LPR_test) + +# %% +# Visualizing the LPR on a PCA map +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# We now visualize the LPRs of the test set on a PCA map, +# where the PCA is performed on the SOAP descriptors of +# defect-containing dataset. + +pca = PCA(n_components=5) +descriptors_all = calculator.compute(refined_defect_frames) +pca.fit_transform(descriptors_all.block().values) +PCA_test = pca.transform(np.vstack(X_test)) + +rmin = np.log10(LPR_test.min()) + 0.5 +rmax = np.log10(LPR_test.max()) - 0.5 + +fig = plt.figure(figsize=(5, 4), dpi=200) +ax = fig.add_subplot() +im = ax.scatter( + PCA_test[:, 0], + PCA_test[:, 1], + c=LPR_test, + s=20, + linewidths=0, + norm=LogNorm(vmin=10**rmin, vmax=10**rmax), + cmap="viridis", +) + +ax.set_xlabel("PC1") +ax.set_ylabel("PC2") +fig.colorbar(im, ax=ax, label="LPR") +ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False) + +# %% +# In the PCA map, where each point corresponds to an +# atomic environment of the test set structures, one +# can observe 4 different clusters of points, arranged +# along PC1. This corresponds to the coordination numbers +# ranging from 3 to 6. Since the training set contains +# structures exclusively composed of 4-coordinated atoms, +# LPR is distinctly high for the second, main cluster of +# points, and quite low for the three other clusters. + + +# %% +# Studying the LPR after dataset modification +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# We now want to see what would happen when defect structures +# are included into the training set of the model. For this, +# we first create a modified dataset that incorporates in the +# defect structures, and recompute the LPR. + +X_new = X_pristine[:n_train] + X_defect[:n_add] +LPR_test_new, rank = lpr(X_new, X_test, alpha) +LPR_test_new = np.hstack(LPR_test_new) + +# %% +# We then visualize the change in the LPR with the +# modification of the dataset by plotting the same PCA +# map, but now colored by the ratio of new set of LPR +# values (after dataset modification) over the original +# one. + +fig = plt.figure(figsize=(5, 4), dpi=200) +ax = fig.add_subplot() +im = ax.scatter( + PCA_test[:, 0], + PCA_test[:, 1], + c=LPR_test_new / LPR_test, + s=20, + linewidths=0, + # norm=LogNorm(vmin=10**rmin, vmax=10**rmax), + cmap="OrRd", +) +ax.set_xlabel("PC1") +ax.set_ylabel("PC2") +fig.colorbar(im, ax=ax, label=r"LPR$_{\mathrm{new}}$ / LPR$_{\mathrm{old}}$") +ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False) + +# %% +# It is apparent that while the LPR stays more or less consistent for the +# 4-coordinated atoms, it is significantly enhanced for the defective environments +# as a result of the inclusion of defective structures in the training set. + + +# %% diff --git a/latest/_downloads/acef7f4b78ef4bb781ee98c79cb1dfe9/gaas-map.ipynb b/latest/_downloads/acef7f4b78ef4bb781ee98c79cb1dfe9/gaas-map.ipynb new file mode 100644 index 00000000..c32461c9 --- /dev/null +++ b/latest/_downloads/acef7f4b78ef4bb781ee98c79cb1dfe9/gaas-map.ipynb @@ -0,0 +1,169 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# PCA/PCovR Visualization for the rattled GaAs training dataset\n\n:Authors: Michele Ceriotti [@ceriottm](https://github.com/ceriottm/),\n Giulio Imbalzano\n\nThis example uses ``rascaline`` and ``metatensor`` to compute\nstructural properties for the structures in a training for a ML model.\nThese are then used with simple dimensionality reduction algorithms\n(implemented in ``sklearn`` and ``skmatter``) to obtain a simplified\ndescription of the dataset, that is then visualized using\n``chemiscope``.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\n\nimport ase\nimport ase.io\nimport chemiscope\nimport numpy as np\nimport requests\nfrom matplotlib import pyplot as plt\nfrom metatensor import mean_over_samples\nfrom rascaline import AtomicComposition, SoapPowerSpectrum\nfrom sklearn.decomposition import PCA\nfrom sklearn.linear_model import RidgeCV\nfrom skmatter.decomposition import PCovR\nfrom skmatter.preprocessing import StandardFlexibleScaler" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we load the structures, extracting some of the properties for\nmore convenient manipulation. These are\n$\\mathrm{Ga}_x\\mathrm{As}_{1-x}$ structures used in [Imbalzano &\nCeriotti (2021)](http://doi.org/10.1103/PhysRevMaterials.5.063804)_ to\ntrain a ML potential to describe the full composition range.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "filename = \"gaas_training.xyz\"\nif not os.path.exists(filename):\n url = f\"https://zenodo.org/records/10566825/files/{filename}\"\n response = requests.get(url)\n response.raise_for_status()\n with open(filename, \"wb\") as f:\n f.write(response.content)\n\nstructures = ase.io.read(filename, \":\")\nenergy = np.array([f.info[\"energy\"] for f in structures])\nnatoms = np.array([len(f) for f in structures])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Remove atomic energy baseline\n\nEnergies from an electronic structure calculation contain a very large\n\u201cself\u201d contributions from the atoms, which can obscure the important\ndifferences in cohesive energies between structures. We can build an\napproximate model based on the chemical nature of the atoms, $a_i$\n\n\\begin{align}E(A) = \\sum_{i\\in A} e_{a_i}\\end{align}\n\nwhere $e_a$ are atomic energies that can be determined by linear\nregression.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# rascaline has an `AtomicComposition` calculator that streamlines\n# this (simple) calculation\ncalculator = AtomicComposition(**{\"per_structure\": True})\nrho0 = calculator.compute(structures)\n\n# the descriptors are returned as a `TensorMap` object, that contains\n# the composition data in a sparse storage format\nrho0\n\n# for easier manipulation, we extract the features as a dense vector\n# of composition weights\ncomp_feats = rho0.keys_to_properties([\"species_center\"]).block(0).values\n\n# a one-liner to fit a linear model and compute \"dressed energies\"\natom_energy = (\n RidgeCV(alphas=np.geomspace(1e-8, 1e2, 20))\n .fit(comp_feats, energy)\n .predict(comp_feats)\n)\ncohesive_peratom = (energy - atom_energy) / natoms" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The baseline makes up a large fraction of the total energy, but actually\nthe residual (which is the part that matters) is still large.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(1, 1, figsize=(6, 4))\nax.plot(energy / natoms, atom_energy / natoms, \"b.\")\nax.set_xlabel(\"Energy / (eV/atom)\")\nax.set_ylabel(\"Atomic e. / (eV/atom)\")\nprint(f\"RMSE / (eV/atom): {np.sqrt(np.mean((cohesive_peratom)**2))}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Compute structural descriptors\n\nIn order to visualize the structures as a low-dimensional map, we start\nby computing suitable ML descriptors. Here we have used ``rascaline`` to\nevaluate average SOAP features for the structures.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# hypers for evaluating rascaline features\nhypers = {\n \"cutoff\": 4.5,\n \"max_radial\": 6,\n \"max_angular\": 4,\n \"atomic_gaussian_width\": 0.3,\n \"cutoff_function\": {\"ShiftedCosine\": {\"width\": 0.5}},\n \"radial_basis\": {\"Gto\": {\"accuracy\": 1e-6}},\n \"center_atom_weight\": 1.0,\n}\ncalculator = SoapPowerSpectrum(**hypers)\nrho2i = calculator.compute(structures)\n\n# neighbor types go to the keys for sparsity (this way one can\n# compute a heterogeneous dataset without having blocks of zeros)\nrho2i = rho2i.keys_to_samples([\"species_center\"]).keys_to_properties(\n [\"species_neighbor_1\", \"species_neighbor_2\"]\n)\n\n# computes structure-level descriptors and then extracts\n# the features as a dense array\nrho2i_structure = mean_over_samples(rho2i, sample_names=[\"center\", \"species_center\"])\nrho2i = None # releases memory\nfeatures = rho2i_structure.block(0).values" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We standardize (per atom) energy and features (computed as a *mean* over\natomic environments) so that they can be combined on the same footings.\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sf_energy = StandardFlexibleScaler().fit_transform(cohesive_peratom.reshape(-1, 1))\nsf_feats = StandardFlexibleScaler().fit_transform(features)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## PCA and PCovR projection\n\nComputes PCA projection to generate low-dimensional descriptors that\nreflect structural diversity. Any other dimensionality reduction scheme\ncould be used in a similar fashion.\n\nWe also compute the principal covariate regression (PCovR) descriptors,\nthat reduce dimensionality while combining a variance preserving\ncriterion with the requirement that the low-dimensional features are\ncapable of estimating a target quantity (here, the energy).\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# PCA\npca = PCA(n_components=4)\npca_features = pca.fit_transform(sf_feats)\n\nfig, ax = plt.subplots(1, 1, figsize=(6, 4))\nscatter = ax.scatter(pca_features[:, 0], pca_features[:, 1], c=cohesive_peratom)\nax.set_xlabel(\"PCA[1]\")\nax.set_ylabel(\"PCA[2]\")\ncbar = fig.colorbar(scatter, ax=ax)\ncbar.set_label(\"energy / eV/at.\")\n\n# computes PCovR map\npcovr = PCovR(n_components=4)\npcovr_features = pcovr.fit_transform(sf_feats, sf_energy)\n\nfig, ax = plt.subplots(1, 1, figsize=(6, 4))\nscatter = ax.scatter(pcovr_features[:, 0], pcovr_features[:, 1], c=cohesive_peratom)\nax.set_xlabel(\"PCovR[1]\")\nax.set_ylabel(\"PCovR[2]\")\ncbar = fig.colorbar(scatter, ax=ax)\ncbar.set_label(\"energy / (eV/at.)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Chemiscope visualization\n\nVisualizes the structure-property map using a chemiscope widget (and\ngenerates a .json file that can be viewed on\n[chemiscope.org](https://chemiscope.org)_).\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# extracts force data (adding considerably to the dataset size...)\nforce_vectors = chemiscope.ase_vectors_to_arrows(structures, scale=1)\nforce_vectors[\"parameters\"][\"global\"][\"color\"] = 0x505050\n\n# adds properties to the ASE frames\nfor i, f in enumerate(structures):\n for j in range(len(pca_features[i])):\n f.info[\"pca_\" + str(j + 1)] = pca_features[i, j]\nfor i, f in enumerate(structures):\n for j in range(len(pcovr_features[i])):\n f.info[\"pcovr_\" + str(j + 1)] = pcovr_features[i, j]\nfor i, f in enumerate(structures):\n f.info[\"cohesive_energy\"] = cohesive_peratom[i]\n f.info[\"x_ga\"] = comp_feats[i, 0] / comp_feats[i].sum()\n\n# it would also be easy to add the properties manually, this is just a dictionary\nstructure_properties = chemiscope.extract_properties(structures)\n\ncs = chemiscope.show(\n frames=structures,\n properties=structure_properties,\n shapes={\"forces\": force_vectors},\n # the settings are a tad verbose, but give full control over the visualization\n settings={\n \"map\": {\n \"x\": {\"property\": \"pcovr_1\"},\n \"y\": {\"property\": \"pcovr_2\"},\n \"color\": {\"property\": \"x_ga\"},\n },\n \"structure\": [\n {\n \"bonds\": True,\n \"unitCell\": True,\n \"shape\": [\"forces\"],\n \"keepOrientation\": False,\n }\n ],\n },\n meta={\n \"name\": \"GaAs training data\",\n \"description\": \"\"\"\nA collection of Ga(x)As(1-x) structures to train a MLIP,\nincluding force and energy data.\n\"\"\",\n \"authors\": [\"Giulio Imbalzano\", \"Michele Ceriotti\"],\n \"references\": [\n \"\"\"\nG. Imbalzano and M. Ceriotti, 'Modeling the Ga/As binary system across\ntemperatures and compositions from first principles,'\nPhys. Rev. Materials 5(6), 063804 (2021).\n\"\"\",\n \"Original dataset: https://archive.materialscloud.org/record/2021.226\",\n ],\n },\n)\n\n# shows chemiscope if run in a jupyter environment\nif chemiscope.jupyter._is_running_in_notebook():\n from IPython.display import display\n\n display(cs)\nelse:\n cs.save(\"gaas_map.chemiscope.json.gz\")" + ] + } + ], + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/ae0da8b1ee160a1314e0f4a70d65ba5f/reference-trajectory.py b/latest/_downloads/ae0da8b1ee160a1314e0f4a70d65ba5f/reference-trajectory.py new file mode 100644 index 00000000..4fb6e77c --- /dev/null +++ b/latest/_downloads/ae0da8b1ee160a1314e0f4a70d65ba5f/reference-trajectory.py @@ -0,0 +1,304 @@ +r""" +Batch run of CP2K calculations +============================== + +:Authors: Matthias Kellner `@bananenpampe `_, + Philip Loche `@PicoCentauri `_ + +This is an example how to perform single point calculations based on list of structures +using `CP2K `_ using its `reftraj functionality +`_. The inputs are a +set of structures in :download:`example.xyz` using the DFT parameters defined in +:download:`reftraj_template.cp2k`. The reference DFT parameters are taken from `Cheng et +al. Ab initio thermodynamics of liquid and solid water 2019 +`_. Due to the small size of the test +structure and convergence issues, we have decreased the size of the ``CUTOFF_RADIUS`` +from :math:`6.0\,\mathrm{Å}` to :math:`3.0\,\mathrm{Å}`. For actual production +calculations adapt the template! +""" + +# %% +# We start the example by importing the required packages. + +import os +import platform +import subprocess +from typing import List, Union + +import ase.io +import ase.visualize.plot +import matplotlib.pyplot as plt +import numpy as np +import requests + + +# %% +# +# Install CP2K +# ------------ +# +# We'll need a working installation of cp2k. The best way to do so depends on your +# platform, here are some possible solutions, but feel free to replace them with another +# installation method. + +if platform.system() == "Linux": + # use conda on Linux + subprocess.run(["conda", "install", "cp2k", "-c", "conda-forge", "-y"], check=True) +elif platform.system() == "Darwin": + # use homebrew on macOS + subprocess.run(["brew", "install", "cp2k"], check=True) +else: + print("no known way to install cp2k, skipping installation") + + +# %% +# Define necessary functions +# -------------------------- +# Next we below define necessary helper functions to run the example. + + +def write_reftraj(fname: str, frames: Union[ase.Atoms, List[ase.Atoms]]) -> None: + """Writes a list of ase atoms objects to a reference trajectory. + + A reference trajectory is the CP2K compatible format for the compuation of batches. + All frames must have the stoichiometry/composition. + """ + + if isinstance(frames, ase.Atoms): + frames = [frames] + + out = "" + for i, atoms in enumerate(frames): + if ( + len(atoms) != len(frames[0]) + or atoms.get_chemical_formula() != frames[0].get_chemical_formula() + ): + raise ValueError( + f"Atom symbols in frame {i},{atoms.get_chemical_formula()} are " + f"different compared to inital frame " + f"{frames[0].get_chemical_formula()}. " + "CP2K does not support changing atom types within a reftraj run!" + ) + + out += f"{len(atoms):>8}\n i = {i + 1:>8}, time = {0:>12.3f}\n" + for atom in atoms: + pos = atom.position + out += f"{atom.symbol}{pos[0]:24.15f}{pos[1]:24.15f}{pos[2]:24.15f}\n" + out += "\n" + with open(fname, "w") as f: + f.write(out) + + +# %% + + +def write_cellfile(fname: str, frames: Union[ase.Atoms, List[ase.Atoms]]) -> None: + """Writes a cellfile for a list of ``ase.Atoms``. + + A Cellfile accompanies a reftraj containing the cell parameters. + """ + if isinstance(frames, ase.Atoms): + frames = [frames] + + out = ( + "# " + "Step " + "Time [fs] " + "Ax [Angstrom] " + "Ay [Angstrom] " + "Az [Angstrom] " + "Bx [Angstrom] " + "By [Angstrom] " + "Bz [Angstrom] " + "Cx [Angstrom] " + "Cy [Angstrom] " + "Cz [Angstrom] " + "Volume [Angstrom^3]\n" + ) + + for i, atoms in enumerate(frames): + out += f"{i + 1:>8}{0:>12.3f}" + out += "".join([f"{c:>20.10f}" for c in atoms.cell.flatten()]) + out += f"{atoms.cell.volume:>25.10f}" + out += "\n" + + with open(fname, "w") as f: + f.write(out) + + +# %% + + +def write_cp2k_in( + fname: str, project_name: str, last_snapshot: int, cell: List[float] +) -> None: + """Writes a cp2k input file from a template. + + Importantly, it writes the location of the basis set definitions, + determined from the path of the system CP2K install to the input file. + """ + + cp2k_in = open("reftraj_template.cp2k", "r").read() + + cp2k_in = cp2k_in.replace("//PROJECT//", project_name) + cp2k_in = cp2k_in.replace("//LAST_SNAPSHOT//", str(last_snapshot)) + cp2k_in = cp2k_in.replace("//CELL//", " ".join([f"{c:.6f}" for c in cell])) + + with open(fname, "w") as f: + f.write(cp2k_in) + + +# %% +# +# We will now download basis set files from CP2K website. Depending on your CP2K +# installation, this might not be necessary! + + +def download_parameter(file): + path = os.path.join("parameters", file) + + if not os.path.exists(path): + url = f"https://raw.githubusercontent.com/cp2k/cp2k/support/v2024.1/data/{file}" + response = requests.get(url) + response.raise_for_status() + with open(path, "wb") as f: + f.write(response.content) + + +os.makedirs("parameters", exist_ok=True) +for file in ["GTH_BASIS_SETS", "BASIS_ADMM", "POTENTIAL", "dftd3.dat", "t_c_g.dat"]: + download_parameter(file) + + +# %% +# Prepare calculation inputs +# -------------------------- +# During this example we will create a directory named ``project_directory`` containing +# the subdirectories for each stoichiometry. This is necessary, because CP2K can only +# run calculations using a fixed stoichiometry at a time, using its ``reftraj`` +# functionality. +# +# Below we define the general information for the CP2K run. This includes the reference +# files for the structures, the ``project_name`` used to build the name of the +# trajectory during the CP2K run, the ``project_directory`` where we store all +# simulation output as well as the path ``write_to_file`` which is the name of the file +# containing the computed energies and forces of the simulation. + +frames_full = ase.io.read("example.xyz", ":") +project_name = "test_calcs" # name of the global PROJECT +project_directory = "production" +write_to_file = "out.xyz" + +# %% +# Below we show the initial configuration of two water molecules in a cubic box with a +# side length of :math:`\approx 4\,\mathrm{Å}`. + +ase.visualize.plot.plot_atoms(frames_full[0]) + +plt.xlabel("Å") +plt.ylabel("Å") + +plt.show() + +# %% +# We now extract the stoichiometry from the input dataset using ASE's +# :py:meth:`ase.symbols.Symbols.get_chemical_formula` method. + +frames_dict = {} + +for atoms in frames_full: + chemical_formula = atoms.get_chemical_formula() + try: + frames_dict[chemical_formula] + except KeyError: + frames_dict[chemical_formula] = [] + + frames_dict[chemical_formula].append(atoms) + +# %% +# Based on the stoichiometries we create one calculation subdirectories for the +# calculations. (reftraj, input and cellfile). For our example this is only is one +# directory named ``H4O2`` because our dataset consists only of a single structure with +# two water molecules. + +for stoichiometry, frames in frames_dict.items(): + current_directory = f"{project_directory}/{stoichiometry}" + os.makedirs(current_directory, exist_ok=True) + + write_cp2k_in( + f"{current_directory}/in.cp2k", + project_name=project_name, + last_snapshot=len(frames), + cell=frames[0].cell.diagonal(), + ) + + ase.io.write(f"{current_directory}/init.xyz", frames[0]) + write_reftraj(f"{current_directory}/reftraj.xyz", frames) + write_cellfile(f"{current_directory}/reftraj.cell", frames) + +# %% +# Run simulations +# --------------- +# Now we have all ingredients to run the simulations. Below we call the bash script +# :download:`run_calcs.sh`. +# +# .. literalinclude:: run_calcs.sh +# :language: bash +# +# This script will loop through all stoichiometry subdirectories and call the CP2K +# engine. + +# run the bash script directly from this script +subprocess.run("bash run_calcs.sh", shell=True) + +# %% +# .. note:: +# +# For a usage on an HPC environment you can parallelize the loop over the +# sub-directories and submit and single job per stoichiometry. +# +# Load results +# ------------ +# After the simulation we load the results and perform a unit version from the default +# CP2K output units (Bohr and Hartree) to Å and eV. + +cflength = 0.529177210903 # Bohr -> Å +cfenergy = 27.211386245988 # Hartree -> eV +cfforce = cfenergy / cflength # Hartree/Bohr -> eV/Å + +# %% +# Finally, we store the results as :class:`ase.Atoms` in the ``new_frames`` list and +# write them to the ``project_directory`` using the ``new_fname``. Here it will be +# written to ``production/out_dft.xyz``. + +new_frames = [] + +for stoichiometry, frames in frames_dict.items(): + current_directory = f"{project_directory}/{stoichiometry}" + + frames_dft = ase.io.read(f"{current_directory}/{project_name}-pos-1.xyz", ":") + forces_dft = ase.io.read(f"{current_directory}/{project_name}-frc-1.xyz", ":") + cell_dft = np.atleast_2d(np.loadtxt(f"{current_directory}/{project_name}-1.cell"))[ + :, 2:-1 + ] + + for i_atoms, atoms in enumerate(frames_dft): + frames_ref = frames[i_atoms] + + # Check consistent positions + if not np.allclose(atoms.positions, frames_ref.positions): + raise ValueError(f"Positions in frame {i_atoms} are not the same.") + + # Check consistent cell + if not np.allclose(frames_ref.cell.flatten(), cell_dft[i_atoms]): + raise ValueError(f"Cell dimensions in frame {i_atoms} are not the same.") + + atoms.info["E"] *= cfenergy + atoms.pbc = True + atoms.cell = frames_ref.cell + atoms.set_array("forces", cfforce * forces_dft[i_atoms].positions) + + new_frames += frames_dft + +new_fname = f"{os.path.splitext(os.path.basename(write_to_file))[0]}_dft.xyz" +ase.io.write(f"{project_directory}/{new_fname}", new_frames) diff --git a/latest/_downloads/b130988d387c627a2afb4ff91c430422/environment.yml b/latest/_downloads/b130988d387c627a2afb4ff91c430422/environment.yml new file mode 100644 index 00000000..877dff7c --- /dev/null +++ b/latest/_downloads/b130988d387c627a2afb4ff91c430422/environment.yml @@ -0,0 +1,12 @@ +channels: + - conda-forge +dependencies: + - python=3.11 + - pip + - rust >=1.65 + - pip: + - ase + - chemiscope + - matplotlib + - rascaline @ git+https://github.com/Luthaf/rascaline@5c2a79838bda0a52d0fde2fbe65941f4792c4cae + - skmatter diff --git a/latest/_downloads/c1382a1742282359674fed148953d82f/environment.yml b/latest/_downloads/c1382a1742282359674fed148953d82f/environment.yml new file mode 100644 index 00000000..27afd282 --- /dev/null +++ b/latest/_downloads/c1382a1742282359674fed148953d82f/environment.yml @@ -0,0 +1,14 @@ +channels: + - conda-forge +dependencies: + - python=3.11 + - pip + - rust >=1.65 + - pip: + - ase + - chemiscope + - matplotlib + - metatensor + - rascaline @ git+https://github.com/Luthaf/rascaline@ca957642f512e141c7570e987aadc05c7ac71983 + - scikit-learn + - skmatter diff --git a/latest/_downloads/c30ae838fdaa9326592e1ef5414c0d62/gaas-map.py b/latest/_downloads/c30ae838fdaa9326592e1ef5414c0d62/gaas-map.py new file mode 100644 index 00000000..c0175812 --- /dev/null +++ b/latest/_downloads/c30ae838fdaa9326592e1ef5414c0d62/gaas-map.py @@ -0,0 +1,255 @@ +""" +PCA/PCovR Visualization for the rattled GaAs training dataset +============================================================= + +:Authors: Michele Ceriotti `@ceriottm `_, + Giulio Imbalzano + +This example uses ``rascaline`` and ``metatensor`` to compute +structural properties for the structures in a training for a ML model. +These are then used with simple dimensionality reduction algorithms +(implemented in ``sklearn`` and ``skmatter``) to obtain a simplified +description of the dataset, that is then visualized using +``chemiscope``. + +""" + +import os + +import ase +import ase.io +import chemiscope +import numpy as np +import requests +from matplotlib import pyplot as plt +from metatensor import mean_over_samples +from rascaline import AtomicComposition, SoapPowerSpectrum +from sklearn.decomposition import PCA +from sklearn.linear_model import RidgeCV +from skmatter.decomposition import PCovR +from skmatter.preprocessing import StandardFlexibleScaler + + +###################################################################### +# First, we load the structures, extracting some of the properties for +# more convenient manipulation. These are +# :math:`\mathrm{Ga}_x\mathrm{As}_{1-x}` structures used in `Imbalzano & +# Ceriotti (2021) `__ to +# train a ML potential to describe the full composition range. +# + +filename = "gaas_training.xyz" +if not os.path.exists(filename): + url = f"https://zenodo.org/records/10566825/files/{filename}" + response = requests.get(url) + response.raise_for_status() + with open(filename, "wb") as f: + f.write(response.content) + +structures = ase.io.read(filename, ":") +energy = np.array([f.info["energy"] for f in structures]) +natoms = np.array([len(f) for f in structures]) + + +###################################################################### +# Remove atomic energy baseline +# ----------------------------- +# +# Energies from an electronic structure calculation contain a very large +# “self” contributions from the atoms, which can obscure the important +# differences in cohesive energies between structures. We can build an +# approximate model based on the chemical nature of the atoms, :math:`a_i` +# +# .. math:: E(A) = \sum_{i\in A} e_{a_i} +# +# where :math:`e_a` are atomic energies that can be determined by linear +# regression. +# + +# rascaline has an `AtomicComposition` calculator that streamlines +# this (simple) calculation +calculator = AtomicComposition(**{"per_structure": True}) +rho0 = calculator.compute(structures) + +# the descriptors are returned as a `TensorMap` object, that contains +# the composition data in a sparse storage format +rho0 + +# for easier manipulation, we extract the features as a dense vector +# of composition weights +comp_feats = rho0.keys_to_properties(["species_center"]).block(0).values + +# a one-liner to fit a linear model and compute "dressed energies" +atom_energy = ( + RidgeCV(alphas=np.geomspace(1e-8, 1e2, 20)) + .fit(comp_feats, energy) + .predict(comp_feats) +) +cohesive_peratom = (energy - atom_energy) / natoms + + +###################################################################### +# The baseline makes up a large fraction of the total energy, but actually +# the residual (which is the part that matters) is still large. +# + +fig, ax = plt.subplots(1, 1, figsize=(6, 4)) +ax.plot(energy / natoms, atom_energy / natoms, "b.") +ax.set_xlabel("Energy / (eV/atom)") +ax.set_ylabel("Atomic e. / (eV/atom)") +print(f"RMSE / (eV/atom): {np.sqrt(np.mean((cohesive_peratom)**2))}") + + +###################################################################### +# Compute structural descriptors +# ------------------------------ +# +# In order to visualize the structures as a low-dimensional map, we start +# by computing suitable ML descriptors. Here we have used ``rascaline`` to +# evaluate average SOAP features for the structures. +# + +# hypers for evaluating rascaline features +hypers = { + "cutoff": 4.5, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + "radial_basis": {"Gto": {"accuracy": 1e-6}}, + "center_atom_weight": 1.0, +} +calculator = SoapPowerSpectrum(**hypers) +rho2i = calculator.compute(structures) + +# neighbor types go to the keys for sparsity (this way one can +# compute a heterogeneous dataset without having blocks of zeros) +rho2i = rho2i.keys_to_samples(["species_center"]).keys_to_properties( + ["species_neighbor_1", "species_neighbor_2"] +) + +# computes structure-level descriptors and then extracts +# the features as a dense array +rho2i_structure = mean_over_samples(rho2i, sample_names=["center", "species_center"]) +rho2i = None # releases memory +features = rho2i_structure.block(0).values + + +###################################################################### +# We standardize (per atom) energy and features (computed as a *mean* over +# atomic environments) so that they can be combined on the same footings. +# + +sf_energy = StandardFlexibleScaler().fit_transform(cohesive_peratom.reshape(-1, 1)) +sf_feats = StandardFlexibleScaler().fit_transform(features) + + +###################################################################### +# PCA and PCovR projection +# ------------------------ +# +# Computes PCA projection to generate low-dimensional descriptors that +# reflect structural diversity. Any other dimensionality reduction scheme +# could be used in a similar fashion. +# +# We also compute the principal covariate regression (PCovR) descriptors, +# that reduce dimensionality while combining a variance preserving +# criterion with the requirement that the low-dimensional features are +# capable of estimating a target quantity (here, the energy). +# + +# PCA +pca = PCA(n_components=4) +pca_features = pca.fit_transform(sf_feats) + +fig, ax = plt.subplots(1, 1, figsize=(6, 4)) +scatter = ax.scatter(pca_features[:, 0], pca_features[:, 1], c=cohesive_peratom) +ax.set_xlabel("PCA[1]") +ax.set_ylabel("PCA[2]") +cbar = fig.colorbar(scatter, ax=ax) +cbar.set_label("energy / eV/at.") + +# computes PCovR map +pcovr = PCovR(n_components=4) +pcovr_features = pcovr.fit_transform(sf_feats, sf_energy) + +fig, ax = plt.subplots(1, 1, figsize=(6, 4)) +scatter = ax.scatter(pcovr_features[:, 0], pcovr_features[:, 1], c=cohesive_peratom) +ax.set_xlabel("PCovR[1]") +ax.set_ylabel("PCovR[2]") +cbar = fig.colorbar(scatter, ax=ax) +cbar.set_label("energy / (eV/at.)") + + +###################################################################### +# Chemiscope visualization +# ------------------------ +# +# Visualizes the structure-property map using a chemiscope widget (and +# generates a .json file that can be viewed on +# `chemiscope.org `__). +# + +# extracts force data (adding considerably to the dataset size...) +force_vectors = chemiscope.ase_vectors_to_arrows(structures, scale=1) +force_vectors["parameters"]["global"]["color"] = 0x505050 + +# adds properties to the ASE frames +for i, f in enumerate(structures): + for j in range(len(pca_features[i])): + f.info["pca_" + str(j + 1)] = pca_features[i, j] +for i, f in enumerate(structures): + for j in range(len(pcovr_features[i])): + f.info["pcovr_" + str(j + 1)] = pcovr_features[i, j] +for i, f in enumerate(structures): + f.info["cohesive_energy"] = cohesive_peratom[i] + f.info["x_ga"] = comp_feats[i, 0] / comp_feats[i].sum() + +# it would also be easy to add the properties manually, this is just a dictionary +structure_properties = chemiscope.extract_properties(structures) + +cs = chemiscope.show( + frames=structures, + properties=structure_properties, + shapes={"forces": force_vectors}, + # the settings are a tad verbose, but give full control over the visualization + settings={ + "map": { + "x": {"property": "pcovr_1"}, + "y": {"property": "pcovr_2"}, + "color": {"property": "x_ga"}, + }, + "structure": [ + { + "bonds": True, + "unitCell": True, + "shape": ["forces"], + "keepOrientation": False, + } + ], + }, + meta={ + "name": "GaAs training data", + "description": """ +A collection of Ga(x)As(1-x) structures to train a MLIP, +including force and energy data. +""", + "authors": ["Giulio Imbalzano", "Michele Ceriotti"], + "references": [ + """ +G. Imbalzano and M. Ceriotti, 'Modeling the Ga/As binary system across +temperatures and compositions from first principles,' +Phys. Rev. Materials 5(6), 063804 (2021). +""", + "Original dataset: https://archive.materialscloud.org/record/2021.226", + ], + }, +) + +# shows chemiscope if run in a jupyter environment +if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) +else: + cs.save("gaas_map.chemiscope.json.gz") diff --git a/latest/_downloads/d997f92a427513b3b0c833f5b65889cf/reftraj_template.cp2k b/latest/_downloads/d997f92a427513b3b0c833f5b65889cf/reftraj_template.cp2k new file mode 100644 index 00000000..fe83ba8d --- /dev/null +++ b/latest/_downloads/d997f92a427513b3b0c833f5b65889cf/reftraj_template.cp2k @@ -0,0 +1,144 @@ +@SET PREP 0 + +@SET SCF_GUESS RESTART +@SET SCREEN_ON_INITIAL_P TRUE + +@IF ${PREP} + @SET SCF_GUESS ATOMIC + @SET SCREEN_ON_INITIAL_P FALSE +@ENDIF + +&GLOBAL + PROJECT //PROJECT// + PREFERRED_FFT_LIBRARY FFTW + FFTW_PLAN_TYPE MEASURE + RUN_TYPE MD + PRINT_LEVEL LOW +&END GLOBAL + +&MOTION + &PRINT + &CELL + &EACH + MD 1 + &END EACH + &END CELL + &FORCES + &EACH + MD 1 + &END EACH + &END FORCES + &END PRINT + &MD + ENSEMBLE REFTRAJ + &REFTRAJ ! Loads an external trajectory file and performs analysis on the loaded snapshots. + EVAL_ENERGY_FORCES TRUE + EVAL_FORCES TRUE + CELL_FILE_NAME reftraj.cell + TRAJ_FILE_NAME reftraj.xyz + FIRST_SNAPSHOT 1 + VARIABLE_VOLUME TRUE + LAST_SNAPSHOT //LAST_SNAPSHOT// + &END REFTRAJ + &END MD +&END MOTION + +&FORCE_EVAL + &PRINT + &FORCES + &EACH + MD 1 + &END EACH + &END FORCES + &END PRINT + &DFT + BASIS_SET_FILE_NAME ../../parameters/GTH_BASIS_SETS + BASIS_SET_FILE_NAME ../../parameters/BASIS_ADMM + POTENTIAL_FILE_NAME ../../parameters/POTENTIAL + &MGRID + CUTOFF 400 + &END MGRID + &SCF + SCF_GUESS ${SCF_GUESS} + MAX_SCF 20 + EPS_SCF 5.0E-7 + &OT + MINIMIZER DIIS + PRECONDITIONER FULL_ALL + &END OT + &OUTER_SCF + MAX_SCF 20 + EPS_SCF 5.0E-7 + &END OUTER_SCF + &END SCF + &QS + EPS_DEFAULT 1.0E-12 + EPS_PGF_ORB 1.0E-16 + EXTRAPOLATION_ORDER 5 + &END QS + &XC # revPBE0-TC-D3 + &XC_FUNCTIONAL + &PBE + PARAMETRIZATION REVPBE + SCALE_X 0.75 + SCALE_C 1.0 + &END + &END XC_FUNCTIONAL + &HF + FRACTION 0.25 + &SCREENING + EPS_SCHWARZ 1.0E-6 + SCREEN_ON_INITIAL_P ${SCREEN_ON_INITIAL_P} + &END + &MEMORY + MAX_MEMORY 37000 + EPS_STORAGE_SCALING 0.1 + &END + &INTERACTION_POTENTIAL + POTENTIAL_TYPE TRUNCATED + CUTOFF_RADIUS 3.0 + T_C_G_DATA ../../parameters/t_c_g.dat + &END + &HF_INFO + &END HF_INFO + &END + &VDW_POTENTIAL + POTENTIAL_TYPE PAIR_POTENTIAL + &PAIR_POTENTIAL + TYPE DFTD3 + R_CUTOFF 15 + LONG_RANGE_CORRECTION TRUE + REFERENCE_FUNCTIONAL revPBE0 + PARAMETER_FILE_NAME ../../parameters/dftd3.dat + &END + &END + &XC_GRID + XC_DERIV SPLINE2 + &END + &END XC + &AUXILIARY_DENSITY_MATRIX_METHOD + METHOD BASIS_PROJECTION + ADMM_PURIFICATION_METHOD MO_DIAG + &END AUXILIARY_DENSITY_MATRIX_METHOD + &END DFT + &SUBSYS + &TOPOLOGY + COORD_FILE_NAME init.xyz + COORD_FILE_FORMAT XYZ + CONN_FILE_FORMAT GENERATE + &END TOPOLOGY + &CELL + ABC [angstrom] //CELL// + &END CELL + &KIND H + BASIS_SET TZV2P-GTH + BASIS_SET AUX_FIT cpFIT3 + POTENTIAL GTH-PBE-q1 + &END KIND + &KIND O + BASIS_SET TZV2P-GTH + BASIS_SET AUX_FIT cpFIT3 + POTENTIAL GTH-PBE-q6 + &END KIND + &END SUBSYS +&END FORCE_EVAL diff --git a/latest/_downloads/db9adeac0042e3126c9d37f1c33e3b6f/reference-trajectory.ipynb b/latest/_downloads/db9adeac0042e3126c9d37f1c33e3b6f/reference-trajectory.ipynb new file mode 100644 index 00000000..28043f25 --- /dev/null +++ b/latest/_downloads/db9adeac0042e3126c9d37f1c33e3b6f/reference-trajectory.ipynb @@ -0,0 +1,252 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Batch run of CP2K calculations\n\n:Authors: Matthias Kellner [@bananenpampe](https://github.com/bananenpampe/),\n Philip Loche [@PicoCentauri](https://github.com/PicoCentauri/)\n\nThis is an example how to perform single point calculations based on list of structures\nusing [CP2K](https://www.cp2k.org) using its [reftraj functionality](https://manual.cp2k.org/trunk/CP2K_INPUT/MOTION/MD/REFTRAJ.html). The inputs are a\nset of structures in :download:`example.xyz` using the DFT parameters defined in\n:download:`reftraj_template.cp2k`. The reference DFT parameters are taken from [Cheng et\nal. Ab initio thermodynamics of liquid and solid water 2019](https://www.pnas.org/doi/10.1073/pnas.1815117116). Due to the small size of the test\nstructure and convergence issues, we have decreased the size of the ``CUTOFF_RADIUS``\nfrom $6.0\\,\\mathrm{\u00c5}$ to $3.0\\,\\mathrm{\u00c5}$. For actual production\ncalculations adapt the template!\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We start the example by importing the required packages.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\nimport platform\nimport subprocess\nfrom typing import List, Union\n\nimport ase.io\nimport ase.visualize.plot\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install CP2K\n\nWe'll need a working installation of cp2k. The best way to do so depends on your\nplatform, here are some possible solutions, but feel free to replace them with another\ninstallation method.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "if platform.system() == \"Linux\":\n # use conda on Linux\n subprocess.run([\"conda\", \"install\", \"cp2k\", \"-c\", \"conda-forge\", \"-y\"], check=True)\nelif platform.system() == \"Darwin\":\n # use homebrew on macOS\n subprocess.run([\"brew\", \"install\", \"cp2k\"], check=True)\nelse:\n print(\"no known way to install cp2k, skipping installation\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define necessary functions\nNext we below define necessary helper functions to run the example.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def write_reftraj(fname: str, frames: Union[ase.Atoms, List[ase.Atoms]]) -> None:\n \"\"\"Writes a list of ase atoms objects to a reference trajectory.\n\n A reference trajectory is the CP2K compatible format for the compuation of batches.\n All frames must have the stoichiometry/composition.\n \"\"\"\n\n if isinstance(frames, ase.Atoms):\n frames = [frames]\n\n out = \"\"\n for i, atoms in enumerate(frames):\n if (\n len(atoms) != len(frames[0])\n or atoms.get_chemical_formula() != frames[0].get_chemical_formula()\n ):\n raise ValueError(\n f\"Atom symbols in frame {i},{atoms.get_chemical_formula()} are \"\n f\"different compared to inital frame \"\n f\"{frames[0].get_chemical_formula()}. \"\n \"CP2K does not support changing atom types within a reftraj run!\"\n )\n\n out += f\"{len(atoms):>8}\\n i = {i + 1:>8}, time = {0:>12.3f}\\n\"\n for atom in atoms:\n pos = atom.position\n out += f\"{atom.symbol}{pos[0]:24.15f}{pos[1]:24.15f}{pos[2]:24.15f}\\n\"\n out += \"\\n\"\n with open(fname, \"w\") as f:\n f.write(out)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def write_cellfile(fname: str, frames: Union[ase.Atoms, List[ase.Atoms]]) -> None:\n \"\"\"Writes a cellfile for a list of ``ase.Atoms``.\n\n A Cellfile accompanies a reftraj containing the cell parameters.\n \"\"\"\n if isinstance(frames, ase.Atoms):\n frames = [frames]\n\n out = (\n \"# \"\n \"Step \"\n \"Time [fs] \"\n \"Ax [Angstrom] \"\n \"Ay [Angstrom] \"\n \"Az [Angstrom] \"\n \"Bx [Angstrom] \"\n \"By [Angstrom] \"\n \"Bz [Angstrom] \"\n \"Cx [Angstrom] \"\n \"Cy [Angstrom] \"\n \"Cz [Angstrom] \"\n \"Volume [Angstrom^3]\\n\"\n )\n\n for i, atoms in enumerate(frames):\n out += f\"{i + 1:>8}{0:>12.3f}\"\n out += \"\".join([f\"{c:>20.10f}\" for c in atoms.cell.flatten()])\n out += f\"{atoms.cell.volume:>25.10f}\"\n out += \"\\n\"\n\n with open(fname, \"w\") as f:\n f.write(out)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def write_cp2k_in(\n fname: str, project_name: str, last_snapshot: int, cell: List[float]\n) -> None:\n \"\"\"Writes a cp2k input file from a template.\n\n Importantly, it writes the location of the basis set definitions,\n determined from the path of the system CP2K install to the input file.\n \"\"\"\n\n cp2k_in = open(\"reftraj_template.cp2k\", \"r\").read()\n\n cp2k_in = cp2k_in.replace(\"//PROJECT//\", project_name)\n cp2k_in = cp2k_in.replace(\"//LAST_SNAPSHOT//\", str(last_snapshot))\n cp2k_in = cp2k_in.replace(\"//CELL//\", \" \".join([f\"{c:.6f}\" for c in cell]))\n\n with open(fname, \"w\") as f:\n f.write(cp2k_in)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will now download basis set files from CP2K website. Depending on your CP2K\ninstallation, this might not be necessary!\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def download_parameter(file):\n path = os.path.join(\"parameters\", file)\n\n if not os.path.exists(path):\n url = f\"https://raw.githubusercontent.com/cp2k/cp2k/support/v2024.1/data/{file}\"\n response = requests.get(url)\n response.raise_for_status()\n with open(path, \"wb\") as f:\n f.write(response.content)\n\n\nos.makedirs(\"parameters\", exist_ok=True)\nfor file in [\"GTH_BASIS_SETS\", \"BASIS_ADMM\", \"POTENTIAL\", \"dftd3.dat\", \"t_c_g.dat\"]:\n download_parameter(file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prepare calculation inputs\nDuring this example we will create a directory named ``project_directory`` containing\nthe subdirectories for each stoichiometry. This is necessary, because CP2K can only\nrun calculations using a fixed stoichiometry at a time, using its ``reftraj``\nfunctionality.\n\nBelow we define the general information for the CP2K run. This includes the reference\nfiles for the structures, the ``project_name`` used to build the name of the\ntrajectory during the CP2K run, the ``project_directory`` where we store all\nsimulation output as well as the path ``write_to_file`` which is the name of the file\ncontaining the computed energies and forces of the simulation.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "frames_full = ase.io.read(\"example.xyz\", \":\")\nproject_name = \"test_calcs\" # name of the global PROJECT\nproject_directory = \"production\"\nwrite_to_file = \"out.xyz\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Below we show the initial configuration of two water molecules in a cubic box with a\nside length of $\\approx 4\\,\\mathrm{\u00c5}$.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ase.visualize.plot.plot_atoms(frames_full[0])\n\nplt.xlabel(\"\u00c5\")\nplt.ylabel(\"\u00c5\")\n\nplt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now extract the stoichiometry from the input dataset using ASE's\n:py:meth:`ase.symbols.Symbols.get_chemical_formula` method.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "frames_dict = {}\n\nfor atoms in frames_full:\n chemical_formula = atoms.get_chemical_formula()\n try:\n frames_dict[chemical_formula]\n except KeyError:\n frames_dict[chemical_formula] = []\n\n frames_dict[chemical_formula].append(atoms)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Based on the stoichiometries we create one calculation subdirectories for the\ncalculations. (reftraj, input and cellfile). For our example this is only is one\ndirectory named ``H4O2`` because our dataset consists only of a single structure with\ntwo water molecules.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "for stoichiometry, frames in frames_dict.items():\n current_directory = f\"{project_directory}/{stoichiometry}\"\n os.makedirs(current_directory, exist_ok=True)\n\n write_cp2k_in(\n f\"{current_directory}/in.cp2k\",\n project_name=project_name,\n last_snapshot=len(frames),\n cell=frames[0].cell.diagonal(),\n )\n\n ase.io.write(f\"{current_directory}/init.xyz\", frames[0])\n write_reftraj(f\"{current_directory}/reftraj.xyz\", frames)\n write_cellfile(f\"{current_directory}/reftraj.cell\", frames)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Run simulations\nNow we have all ingredients to run the simulations. Below we call the bash script\n:download:`run_calcs.sh`.\n\n.. literalinclude:: run_calcs.sh\n :language: bash\n\nThis script will loop through all stoichiometry subdirectories and call the CP2K\nengine.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# run the bash script directly from this script\nsubprocess.run(\"bash run_calcs.sh\", shell=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Note

For a usage on an HPC environment you can parallelize the loop over the\n sub-directories and submit and single job per stoichiometry.

\n\n## Load results\nAfter the simulation we load the results and perform a unit version from the default\nCP2K output units (Bohr and Hartree) to \u00c5 and eV.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "cflength = 0.529177210903 # Bohr -> \u00c5\ncfenergy = 27.211386245988 # Hartree -> eV\ncfforce = cfenergy / cflength # Hartree/Bohr -> eV/\u00c5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we store the results as :class:`ase.Atoms` in the ``new_frames`` list and\nwrite them to the ``project_directory`` using the ``new_fname``. Here it will be\nwritten to ``production/out_dft.xyz``.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "new_frames = []\n\nfor stoichiometry, frames in frames_dict.items():\n current_directory = f\"{project_directory}/{stoichiometry}\"\n\n frames_dft = ase.io.read(f\"{current_directory}/{project_name}-pos-1.xyz\", \":\")\n forces_dft = ase.io.read(f\"{current_directory}/{project_name}-frc-1.xyz\", \":\")\n cell_dft = np.atleast_2d(np.loadtxt(f\"{current_directory}/{project_name}-1.cell\"))[\n :, 2:-1\n ]\n\n for i_atoms, atoms in enumerate(frames_dft):\n frames_ref = frames[i_atoms]\n\n # Check consistent positions\n if not np.allclose(atoms.positions, frames_ref.positions):\n raise ValueError(f\"Positions in frame {i_atoms} are not the same.\")\n\n # Check consistent cell\n if not np.allclose(frames_ref.cell.flatten(), cell_dft[i_atoms]):\n raise ValueError(f\"Cell dimensions in frame {i_atoms} are not the same.\")\n\n atoms.info[\"E\"] *= cfenergy\n atoms.pbc = True\n atoms.cell = frames_ref.cell\n atoms.set_array(\"forces\", cfforce * forces_dft[i_atoms].positions)\n\n new_frames += frames_dft\n\nnew_fname = f\"{os.path.splitext(os.path.basename(write_to_file))[0]}_dft.xyz\"\nase.io.write(f\"{project_directory}/{new_fname}\", new_frames)" + ] + } + ], + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_downloads/e7554e760ee8c061289c684f5c666feb/path-integrals.py b/latest/_downloads/e7554e760ee8c061289c684f5c666feb/path-integrals.py new file mode 100644 index 00000000..36dc033a --- /dev/null +++ b/latest/_downloads/e7554e760ee8c061289c684f5c666feb/path-integrals.py @@ -0,0 +1,339 @@ +""" +Path integral molecular dynamics +================================ + +:Authors: Michele Ceriotti `@ceriottm `_ + +This example shows how to run a path integral molecular dynamics +simulation using ``i-PI``, analyze the output and visualize the +trajectory in ``chemiscope``. It uses `LAMMPS `_ +as the driver to simulate the `q-TIP4P/f water +model `_. +""" + +import subprocess +import time + +import chemiscope +import ipi +import matplotlib.pyplot as plt +import numpy as np + + +# %% +# Quantum nuclear effects and path integral methods +# ------------------------------------------------- +# +# The Born-Oppenheimer approximation separates the joint quantum mechanical +# problem for electrons and nuclei into two independent problems. Even though +# often one makes the additional approximation of treating nuclei as classical +# particles, this is not necessary, and in some cases (typically when H atoms are +# present) can add considerable error. +# +# +# .. figure:: pimd-slices-round.png +# :align: center +# :width: 600px +# +# A representation of ther ring-polymer Hamiltonian for a water molecule. +# +# In order to describe the quantum mechanical nature of light nuclei +# (nuclear quantum effects) one of the most widely-applicable methods uses +# the *path integral formalism* to map the quantum partition function of a +# set of distinguishable particles onto the classical partition function of +# *ring polymers* composed by multiple beads (replicas) with +# corresponding atoms in adjacent replicas being connected by harmonic +# springs. +# `The textbook by Tuckerman `_ +# contains a pedagogic introduction to the topic, while +# `this paper `_ outlines the implementation +# used in ``i-PI``. +# +# The classical partition function of the path converges to quantum statistics +# in the limit of a large number of replicas. In this example, we will use a +# technique based on generalized Langevin dynamics, known as +# `PIGLET `_ to accelerate the +# convergence. + + +# %% +# Running PIMD calculations with ``i-PI`` +# --------------------------------------- +# +# `i-PI `_ is based on a client-server model, with ``i-PI`` +# controlling the nuclear dynamics (in this case sampling the path Hamiltonian using +# molecular dynamics) while the calculation of energies and forces is delegated to +# an external client program, in this example ``LAMMPS``. +# +# An i-PI calculation is specified by an XML file. + +# Open and read the XML file +with open("input_pimd.xml", "r") as file: + xml_content = file.read() +print(xml_content) + +# %% +# NB1: In a realistic simulation you may want to increase the field +# ``total_steps``, to simulate at least a few 100s of picoseconds. +# +# NB2: To converge a simulation of water at room temperature, you +# typically need at least 32 beads. We will see later how to accelerate +# convergence using a colored-noise thermostat, but you can try to +# modify the input to check convergence with conventional PIMD + +# %% +# i-PI and lammps should be run separately, and it is possible to +# launch separate lammps processes to parallelize the evaluation over +# the beads. On the the command line, this amounts to launching +# +# .. code-block:: bash +# +# i-pi input_pimd.xml > log & +# sleep 2 +# lmp -in in.lmp & +# lmp -in in.lmp & +# +# Note how ``i-PI`` and ``LAMMPS`` are completely independent, and +# therefore need a separate set of input files. The client-side communication +# in ``LAMMPS`` is described in the ``fix_ipi`` section, that matches the socket +# name and mode defined in the ``ffsocket`` field in the ``i-PI`` file. +# +# We can launch the external processes from a Python script as follows + +ipi_process = subprocess.Popen(["i-pi", "input_pimd.xml"]) +time.sleep(2) # wait for i-PI to start +lmp_process = [subprocess.Popen(["lmp", "-in", "in.lmp"]) for i in range(2)] + +# %% +# If you run this in a notebook, you can go ahead and start loading +# output files _before_ i-PI and lammps have finished running, by +# skipping this cell + +ipi_process.wait() +lmp_process[0].wait() +lmp_process[1].wait() + + +# %% +# After the simulation has run, you can visualize and post-process the trajectory data. +# Note that i-PI prints a separate trajectory for each bead, as structural properties +# can be computed averaging over the configurations of any of the beads. + +output_data, output_desc = ipi.read_output("simulation.out") +traj_data = [ipi.read_trajectory(f"simulation.pos_{i}.xyz") for i in range(8)] + + +# %% +# The simulation parameters are pushed at the limits: with the aggressive stochastic +# thermostatting and the high-frequency normal modes of the ring polymer, there are +# fairly large fluctuations of the conserved quantity. This is usually not affecting +# physical observables, but if you see this level of drift in a production run, check +# carefully for convergence and stability with a reduced time step. + +fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True) +ax.plot( + output_data["time"], + output_data["potential"] - output_data["potential"][0], + "b-", + label="Potential, $V$", +) +ax.plot( + output_data["time"], + output_data["conserved"] - output_data["conserved"][0], + "r-", + label="Conserved, $H$", +) +ax.set_xlabel(r"$t$ / ps") +ax.set_ylabel(r"energy / eV") +ax.legend() + +# %% +# While the potential energy is simply the mean over the beads of the +# energy of individual replicas, computing the kinetic energy requires +# averaging special quantities that involve also the correlations between beads. +# Here we compare two of these *estimators*: the 'thermodynamic' estimator becomes +# statistically inefficient when increasing the number of beads, whereas the +# 'centroid virial' estimator remains well-behaved. Note how quickly these estimators +# equilibrate to roughly their stationary value, much faster than the equilibration +# of the potential energy above. This is thanks to the ``pile_g`` thermostat +# (see `DOI:10.1063/1.3489925 `_) that is +# optimally coupled to the normal modes of the ring polymer. + +fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True) +ax.plot( + output_data["time"], + output_data["kinetic_cv"], + "b-", + label="Centroid virial, $K_{CV}$", +) +ax.plot( + output_data["time"], + output_data["kinetic_td"], + "r-", + label="Thermodynamic, $K_{TD}$", +) +ax.set_xlabel(r"$t$ / ps") +ax.set_ylabel(r"energy / eV") +ax.legend() + +# %% +# You can also visualize the (very short) trajectory in a way that highlights the +# fast spreading out of the beads of the ring polymer. ``chemiscope`` provides a +# utility function to interleave the trajectories of the beads, forming a trajectory +# that shows the connecttions between the replicas of each atom. Each atom and its +# connections are color-coded. + +traj_pimd = chemiscope.ase_merge_pi_frames(traj_data) +# we also tweak the visualization options, and then show the viewer +traj_pimd["shapes"]["paths"]["parameters"]["global"]["radius"] = 0.05 +traj_pimd["settings"]["structure"][0].update( + dict( + atoms=False, + keepOrientation=True, + color={"property": "bead_id", "palette": "hsv (periodic)"}, + ) +) + +cs = chemiscope.show(**traj_pimd, mode="structure") + +if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) +else: + cs.save("path-integrals.json.gz") + +# %% +# Accelerating PIMD with a PIGLET thermostat +# ------------------------------------------ +# +# The simulations in the previous sections are very far from converged -- typically +# one would need approximately 32 replicas to converge a simulation of +# room-temperature water. To address this problem we will use a method based on +# generalized Langevin equations, called +# `PIGLET `_ +# +# The input file is ``input_piglet.xml``, that only differs by the definition of +# the thermostat, that uses a ``nm_gle`` mode in which each normal mode +# of the ring polymer is attached to a different colored-noise Generalized Langevin +# equation. This makes it possible to converge exactly the simulation results with +# a small number of replicas, and to accelerate greatly convergence for realistic +# systems such as this. The thermostat parameters can be generated on +# `the GLE4MD website `_ +# + +ipi_process = subprocess.Popen(["i-pi", "input_piglet.xml"]) +time.sleep(2) # wait for i-PI to start +lmp_process = [subprocess.Popen(["lmp", "-in", "in.lmp"]) for i in range(2)] + +ipi_process.wait() +lmp_process[0].wait() +lmp_process[1].wait() + +# %% +# The mean potential energy from the PIGLET trajectory is higher than that for the +# PIMD one, because it is closer to the converged value (try to run a PIMD trajectory +# with 64 beads for comparison) + +output_gle, desc_gle = ipi.read_output("simulation_piglet.out") +traj_gle = [ipi.read_trajectory(f"simulation_piglet.pos_{i}.xyz") for i in range(8)] + +fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True) +ax.plot( + output_data["time"], + output_data["potential"] - output_data["potential"][0], + "b--", + label="PIMD", +) +ax.plot( + output_gle["time"], + output_gle["potential"] - output_gle["potential"][0], + "b-", + label="PIGLET", +) +ax.set_xlabel(r"$t$ / ps") +ax.set_ylabel(r"energy / eV") +ax.legend() + +# %% +# However, you should be somewhat careful: PIGLET converges *some* but not all the +# correlations within a path. For instance, it is designed to converge the +# centroid-virial estimator for the kinetic energy, but not the thermodynamic +# estimator. For the same reason, don't try to look at equilibration in terms of +# the mean temperature: it won't match the target value, because PIGLET uses a +# Langevin equation that breaks the classical fluctuation-dissipation theorem, and +# generates a steady-state distribution that mimics quantum fluctuations. + +fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True) +ax.plot(output_data["time"], output_data["kinetic_cv"], "b--", label="PIMD, $K_{CV}$") +ax.plot(output_gle["time"], output_gle["kinetic_cv"], "b", label="PIGLET, $K_{CV}$") +ax.plot(output_data["time"], output_data["kinetic_td"], "r--", label="PIMD, $K_{TD}$") +ax.plot(output_gle["time"], output_gle["kinetic_td"], "r", label="PIGLET, $K_{TD}$") +ax.set_xlabel(r"$t$ / ps") +ax.set_ylabel(r"energy / eV") +ax.legend() + +# %% +# Kinetic energy tensors +# ~~~~~~~~~~~~~~~~~~~~~~ +# +# While we're at it, let's do something more complicated (and instructive). +# Classically, the momentum distribution of any atom is isotropic, so the +# kinetic energy tensor (KET) :math:`\mathbf{p}\mathbf{p}^T/2m` is a constant +# times the identity matrix. Quantum mechanically, the kinetic energy tensor +# has more structure, that reflects the higher kinetic energy of particles +# along directions with stiff bonds. We can compute a moving average of the +# centroid virial estimator of the KET, and plot it to show the direction +# of anisotropy. Note that there are some subtleties connected with the +# evaluation of the moving average, see e.g. +# `DOI:10.1103/PhysRevLett.109.100604 `_ + +# %% +# We first need to postprocess the components of the kinetic energy tensors +# (that i-PI prints out separating the diagonal and off-diagonal bits), averaging +# them over the last 10 frames and combining them with the centroid configuration +# from the last frame in the trajectory. + +kinetic_cv = ipi.read_trajectory("simulation_piglet.kin.xyz") +kinetic_od = ipi.read_trajectory("simulation_piglet.kod.xyz") +kinetic_tens = np.hstack( + [ + np.asarray([k.positions for k in kinetic_cv[-10:]]).mean(axis=0), + np.asarray([k.positions for k in kinetic_od[-10:]]).mean(axis=0), + ] +) + +centroid = traj_gle[-1][-1].copy() +centroid.positions = np.asarray([t[-1].positions for t in traj_gle]).mean(axis=0) +centroid.arrays["kinetic_cv"] = kinetic_tens + +# %% +# We can then view these in ``chemiscope``, setting the proper parameters to +# visualize the ellipsoids associated with the KET. Note that some KETs have +# negative eigenvalues, because we are averaging over a few frames, which is +# insufficient to converge the estimator fully. + +ellipsoids = chemiscope.ase_tensors_to_ellipsoids( + [centroid], "kinetic_cv", scale=15, force_positive=True +) + +cs = chemiscope.show( + [centroid], + shapes={"kinetic_cv": ellipsoids}, + mode="structure", + settings=chemiscope.quick_settings( + structure_settings={ + "shape": ["kinetic_cv"], + "unitCell": True, + } + ), +) + +# %% + +if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) +else: + cs.save("path-integrals.json.gz") diff --git a/latest/_downloads/ecc5d2823a1b00229494ffc2024c524d/dos-align.py b/latest/_downloads/ecc5d2823a1b00229494ffc2024c524d/dos-align.py new file mode 100644 index 00000000..ca11263a --- /dev/null +++ b/latest/_downloads/ecc5d2823a1b00229494ffc2024c524d/dos-align.py @@ -0,0 +1,948 @@ +""" +Training the DOS with different Energy References +============================================================================== +:Authors: How Wei Bin `@HowWeiBin `_ + +This tutorial would go through the entire machine learning framework for the electronic +density of states (DOS). It will cover the construction of the DOS and SOAP +descriptors from ase Atoms and eigenenergy results. A simple neural network will +then be constructed and the model parameters, along with the energy reference will be +optimized during training. A total of three energy reference will be used, the average +Hartree potential, the Fermi level, and an optimized energy reference starting from +the Fermi level energy reference. The performance of each model is then compared. + + + +Firstly, lets begin by importing the necessary packages and helper functions +""" + +# %% + +import os +import zipfile + +import ase +import ase.io +import matplotlib.pyplot as plt +import numpy as np +import requests +import torch +from rascaline import SoapPowerSpectrum +from scipy.interpolate import CubicHermiteSpline, interp1d +from scipy.optimize import brentq +from torch.utils.data import BatchSampler, DataLoader, Dataset, RandomSampler + + +# %% +# +# Step 0: Load Structures and Eigenenergies +# ------------------------------------------------ +# 1) Downloading and Extracting Data +# 2) Loading Data +# 3) Find range of eigenenergies +# +# We take a small subset of 104 structures in the Si dataset from `Bartok et al., +# 2018 `. +# Each structure in the dataset contains two atoms. +# +# + + +# %% +# 1) Downloading and Extracting Data +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +filename = "dataset.zip" +if not os.path.exists(filename): + url = "https://github.com/HowWeiBin/datasets/archive/refs/tags/Silicon-Diamonds.zip" + response = requests.get(url) + response.raise_for_status() + with open(filename, "wb") as f: + f.write(response.content) + +with zipfile.ZipFile("./dataset.zip", "r") as zip_ref: + zip_ref.extractall("./") +# %% +# 2) Loading Data +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +structures = ase.io.read("./datasets-Silicon-Diamonds/diamonds.xyz", ":") +n_structures = len(structures) +n_atoms = torch.tensor([len(i) for i in structures]) +eigenenergies = torch.load("./datasets-Silicon-Diamonds/diamond_energies.pt") +k_normalization = torch.tensor( + [len(i) for i in eigenenergies] +) # Calculates number of kpoints sampled per structure +print(f"Total number of structures: {len(structures)}") + +# %% +# 3) Find range of eigenenergies +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Process eigenenergies to flattened torch tensors + +total_eigenenergies = [torch.flatten(torch.tensor(i)) for i in eigenenergies] + +# Get lowest and highest value of eigenenergies to know the range of eigenenergies + +all_eigenenergies = torch.hstack(total_eigenenergies) +minE = torch.min(all_eigenenergies) +maxE = torch.max(all_eigenenergies) +print(f"The lowest eigenenergy in the dataset is {minE:.3}") +print(f"The highest eigenenergy in the dataset is {maxE:.3}") +# %% +# +# Step 1: Constructing the DOS with different energy references +# ------------------------------------------------------------------------------------------ +# 1) Construct the DOS using the original reference +# 2) Calculate the Fermi level from the DOS +# 3) Build a set of eigenenergies, with the energy reference set to the fermi level +# 4) Truncate the DOS energy window so that the DOS is well-defined at each point +# 5) Construct the DOS in the truncated energy window under both references +# 6) Construct Splines for the DOS to facilitate interpolation during model training +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# %% +# 1) Construct the DOS using the original reference +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# The DOS will first be constructed from the full set of eigenenergies to +# determine the Fermi level of each structure. The original reference is the +# Average Hartree Potential in this example. + +# To ensure that all the eigenenergies are fully represented after +# gaussian broadening, the energy axis of the DOS extends +# 3eV wider than the range of values for the eigenenergies +energy_lower_bound = minE - 1.5 +energy_upper_bound = maxE + 1.5 + +# Gaussian Smearing for the eDOS, 0.3eV is the appropriate value for this dataset + +sigma = torch.tensor(0.3) +energy_interval = 0.05 +# energy axis, with a grid interval of 0.05 eV + +x_dos = torch.arange(energy_lower_bound, energy_upper_bound, energy_interval) +print( + f"The energy axis ranges from {energy_lower_bound:.3} to \ +{energy_upper_bound:.3}, consisting of {len(x_dos)} grid points" +) + +# normalization factor for each DOS, factor of 2 is included +# because each eigenenergy can be occupied by 2 electrons + +normalization = 2 * ( + 1 / torch.sqrt(2 * torch.tensor(np.pi) * sigma**2) / n_atoms / k_normalization +) + +total_edos = [] + +for structure_eigenenergies in total_eigenenergies: + e_dos = torch.sum( + # Builds a gaussian on each eigenenergy + # and calculates the value on each grid point + torch.exp(-0.5 * ((x_dos - structure_eigenenergies.view(-1, 1)) / sigma) ** 2), + dim=0, + ) + total_edos.append(e_dos) + +total_edos = torch.vstack(total_edos) +total_edos = (total_edos.T * normalization).T + +print(f"The final shape of all the DOS in the dataset is: {list(total_edos.shape)}") + +# %% +# 2) Calculate the Fermi level from the DOS +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Now we integration the DOS, and then use cubic interpolation and brentq +# to calculate the fermi level. Since only the 4 valence electrons in Silicon +# are represented in this energy range, we take the point where the DOS integrates +# to 4 as the fermi level. + +fermi_levels = [] +total_i_edos = torch.cumulative_trapezoid( + total_edos, x_dos, axis=1 +) # Integrate the DOS along the energy axis +for i in total_i_edos: + interpolated = interp1d( + x_dos[:-1], i - 4, kind="cubic", copy=True, assume_sorted=True + ) # We use i-4 because Silicon has 4 electrons in this energy range + Ef = brentq( + interpolated, x_dos[0] + 0.1, x_dos[-1] - 0.1 + ) # Fermi Level is the point where the (integrated DOS - 4) = 0 + # 0.1 is added and subtracted to prevent brentq from going out of range + fermi_levels.append(Ef) +fermi_levels = torch.tensor(fermi_levels) +# %% +# 3) Build a set of eigenenergies, with the energy reference set to the fermi level +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Using the fermi levels, we are now able to change the energy reference +# of the eigenenergies to the fermi level + +total_eigenenergies_Ef = [] +for index, energies in enumerate(total_eigenenergies): + total_eigenenergies_Ef.append(energies - fermi_levels[index]) + +all_eigenenergies_Ef = torch.hstack(total_eigenenergies_Ef) + +minE_Ef = torch.min(all_eigenenergies_Ef) +maxE_Ef = torch.max(all_eigenenergies_Ef) +print(f"The lowest eigenenergy using the fermi level energy reference is {minE_Ef:.3}") +print(f"The highest eigenenergy using the fermi level energy reference is {maxE_Ef:.3}") + + +# %% +# 4) Truncate the DOS energy window so that the DOS is well-defined at each point +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# With the fermi levels, we can also truncate the energy window for DOS prediction. +# In this example, we truncate the energy window such that it is 3eV above +# the highest Fermi level in the dataset. + +# For the Average Hartree Potential energy reference +x_dos_H = torch.arange(minE - 1.5, max(fermi_levels) + 3, energy_interval) + +# For the Fermi Level Energy Reference, all the Fermi levels in the dataset is 0eV +x_dos_Ef = torch.arange(minE_Ef - 1.5, 3, energy_interval) +# %% +# 5) Construct the DOS in the truncated energy window under both references +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Here we construct 2 different targets where they differ in the energy reference +# chosen. These targets will then be treated as different datasets for the model +# to learn on. + +# For the Average Hartree Potential energy reference + +total_edos_H = [] + +for structure_eigenenergies_H in total_eigenenergies: + e_dos = torch.sum( + torch.exp( + -0.5 * ((x_dos_H - structure_eigenenergies_H.view(-1, 1)) / sigma) ** 2 + ), + dim=0, + ) + total_edos_H.append(e_dos) + +total_edos_H = torch.vstack(total_edos_H) +total_edos_H = (total_edos_H.T * normalization).T + + +# For the Fermi Level Energy Reference + +total_edos_Ef = [] + +for structure_eigenenergies_Ef in total_eigenenergies_Ef: + e_dos = torch.sum( + torch.exp( + -0.5 * ((x_dos_Ef - structure_eigenenergies_Ef.view(-1, 1)) / sigma) ** 2 + ), + dim=0, + ) + total_edos_Ef.append(e_dos) + +total_edos_Ef = torch.vstack(total_edos_Ef) +total_edos_Ef = (total_edos_Ef.T * normalization).T + +# %% +# 6) Construct Splines for the DOS to facilitate interpolation during model training +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Building Cubic Hermite Splines on the DOS on the truncated energy window +# to facilitate interpolation during training. Cubic Hermite Splines takes +# in information on the value and derivative of a function at a point to build splines. +# Thus, we will have to compute both the value and derivative at each spline position + + +# Functions to compute the value and derivative of the DOS at each energy value, x +def edos_value(x, eigenenergies, normalization): + e_dos_E = ( + torch.sum( + torch.exp(-0.5 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2), dim=0 + ) + * normalization + ) + + return e_dos_E + + +def edos_derivative(x, eigenenergies, normalization): + dfn_dos_E = ( + torch.sum( + torch.exp(-0.5 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2) + * (-1 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2), + dim=0, + ) + * normalization + ) + + return dfn_dos_E + + +total_splines_H = [] +# the splines have a higher energy range in case the shift is high +spline_positions_H = torch.arange(minE - 2, max(fermi_levels) + 6, energy_interval) + +for index, structure_eigenenergies_H in enumerate(total_eigenenergies): + e_dos_H = edos_value( + spline_positions_H, structure_eigenenergies_H, normalization[index] + ) + e_dos_H_grad = edos_derivative( + spline_positions_H, structure_eigenenergies_H, normalization[index] + ) + spliner = CubicHermiteSpline(spline_positions_H, e_dos_H, e_dos_H_grad) + total_splines_H.append(torch.tensor(spliner.c)) + +total_splines_H = torch.stack(total_splines_H) + +total_splines_Ef = [] +spline_positions_Ef = torch.arange(minE_Ef - 2, 6, energy_interval) + +for index, structure_eigenenergies_Ef in enumerate(total_eigenenergies_Ef): + e_dos_Ef = edos_value( + spline_positions_Ef, structure_eigenenergies_Ef, normalization[index] + ) + e_dos_Ef_grad = edos_derivative( + spline_positions_Ef, structure_eigenenergies_Ef, normalization[index] + ) + spliner = CubicHermiteSpline(spline_positions_Ef, e_dos_Ef, e_dos_Ef_grad) + total_splines_Ef.append(torch.tensor(spliner.c)) + +total_splines_Ef = torch.stack(total_splines_Ef) + + +# %% +# We have stored the splines coefficients (spliner.c) as torch tensors, +# as such as we will need to write a function to evaluate the DOS from +# the splines positions and coefficients. + + +def evaluate_spline(spline_coefs, spline_positions, x): + """ + spline_coefs: shape of (n x 4 x spline_positions) + + return value: shape of (n x x) + + x : shape of (n x n_points) + """ + interval = torch.round( + spline_positions[1] - spline_positions[0], decimals=4 + ) # get spline grid intervals + x = torch.clamp( + x, min=spline_positions[0], max=spline_positions[-1] - 0.0005 + ) # restrict x to fall within the spline interval + # 0.0005 is substracted to combat errors arising from precision + indexes = torch.floor( + (x - spline_positions[0]) / interval + ).long() # Obtain the index for the appropriate spline coefficients + expanded_index = indexes.unsqueeze(dim=1).expand(-1, 4, -1) + x_1 = x - spline_positions[indexes] + x_2 = x_1 * x_1 + x_3 = x_2 * x_1 + x_0 = torch.ones_like(x_1) + x_powers = torch.stack([x_3, x_2, x_1, x_0]).permute(1, 0, 2) + value = torch.sum( + torch.mul(x_powers, torch.gather(spline_coefs, 2, expanded_index)), axis=1 + ) + + return value # returns the value of the DOS at the energy positions, x. + + +# %% +# Lets look at the accuracy of the splines. +# Test 1: Ability to reproduce the correct values at the default x_dos positions + +shifts = torch.zeros(n_structures) +x_dos_splines = x_dos_H + shifts.view(-1, 1) +spline_dos_H = evaluate_spline(total_splines_H, spline_positions_H, x_dos_splines) + +plt.plot(x_dos_H, total_edos_H[0], color="red", label="True DOS") +plt.plot(x_dos_H, spline_dos_H[0], color="blue", linestyle="--", label="Spline DOS") +plt.legend() +plt.xlabel("Energy [eV]") +plt.ylabel("DOS") +print("Both lines lie on each other") +# %% +# Test 2: Ability to reproduce the correct values at the shifted x_dos positions + +shifts = torch.zeros(n_structures) + 0.3 +x_dos_splines = x_dos_Ef + shifts.view(-1, 1) +spline_dos_Ef = evaluate_spline(total_splines_Ef, spline_positions_Ef, x_dos_splines) + +plt.plot(x_dos_Ef, total_edos_Ef[0], color="red", label="True DOS") +plt.plot(x_dos_Ef, spline_dos_Ef[0], color="blue", linestyle="--", label="Spline DOS") +plt.legend() +plt.xlabel("Energy [eV]") +plt.ylabel("DOS") +print("Both spectras look very similar") +# %% +# +# Step 2: Compute SOAP power spectrum for the dataset +# ------------------------------------------------------------------------------------------ +# +# We first define the hyperparameters to compute the +# SOAP power spectrum using rascaline. + +HYPER_PARAMETERS = { + "cutoff": 4.0, + "max_radial": 8, + "max_angular": 6, + "atomic_gaussian_width": 0.45, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {}}, + "cutoff_function": { + "Step": {}, + }, + "radial_scaling": { + "Willatt2018": { + "exponent": 5, + "rate": 1, + "scale": 3.0, + }, + }, +} + +# %% +# +# We feed the Hyperparameters into rascaline to compute the SOAP Power spectrum + + +calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) +R_total_soap = calculator.compute(structures) +# Transform the tensormap to a single block containing a dense representation +R_total_soap.keys_to_samples("species_center") +R_total_soap.keys_to_properties(["species_neighbor_1", "species_neighbor_2"]) + +# Now we extract the data tensor from the single block +total_atom_soap = [] +for structure_i in range(n_structures): + a_i = R_total_soap.block(0).samples["structure"] == structure_i + total_atom_soap.append(torch.tensor(R_total_soap.block(0).values[a_i, :])) + +total_soap = torch.stack(total_atom_soap) +# %% +# +# Step 3: Building a Simple MLP Model +# --------------------------------------------------------------------- +# +# 1) Split the data into Training, Validation and Test +# 2) Define the dataloader and the Model Architecture +# 3) Define relevant loss functions for training and inference +# 4) Define the training loop +# 5) Evaluate the model +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# %% +# 1) Split the data into Training, Validation and Test +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# We will first split the data in a 7:1:2 manner, corresponding to train, val and test. +np.random.seed(0) +train_index = np.arange(n_structures) +np.random.shuffle(train_index) +test_mark = int(0.8 * n_structures) +val_mark = int(0.7 * n_structures) +test_index = train_index[test_mark:] +val_index = train_index[val_mark:test_mark] +train_index = train_index[:val_mark] + +# %% +# 2) Define the dataloader and the Model Architecture +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# We will now build a dataloader and dataset to facillitate training the model batchwise + + +def generate_atomstructure_index(n_atoms_per_structure): + """Generate a sequence of indices for each atom in the structure. + The indices correspond to index of the structure that the atom belongs to + + Args: + n_atoms_per_structure ([array]): + [Array containing the number of atoms each structure contains] + + Return s: + [tensor]: [Total index, matching atoms to structure] + """ + # n_structures = len(n_atoms_per_structure) + total_index = [] + for i, atoms in enumerate(n_atoms_per_structure): + indiv_index = torch.zeros(atoms) + i + total_index.append(indiv_index) + total_index = torch.hstack(total_index) + return total_index.long() + + +class AtomicDataset(Dataset): + def __init__(self, features, n_atoms_per_structure): + self.features = features + self.n_structures = len(n_atoms_per_structure) + self.n_atoms_per_structure = n_atoms_per_structure + self.index = generate_atomstructure_index(self.n_atoms_per_structure) + assert torch.sum(n_atoms_per_structure) == len(features) + + def __len__(self): + return self.n_structures + + def __getitem__(self, idx): + if isinstance(idx, list): # If a list of indexes is given + feature_indexes = [] + + for i in idx: + feature_indexes.append((self.index == i).nonzero(as_tuple=True)[0]) + + feature_indexes = torch.hstack(feature_indexes) + + return ( + self.features[feature_indexes], + idx, + generate_atomstructure_index(self.n_atoms_per_structure[idx]), + ) + + else: + feature_indexes = (self.index == idx).nonzero(as_tuple=True)[0] + return ( + self.features[feature_indexes], + idx, + self.n_atoms_per_structure[idx], + ) + + +def collate( + batch, +): # Defines how to collate the outputs of the __getitem__ function at each batch + for x, idx, index in batch: + return (x, idx, index) + + +x_train = torch.flatten(total_soap[train_index], 0, 1).float() +total_atomic_soaps = torch.vstack(total_atom_soap).float() +train_features = AtomicDataset(x_train, n_atoms[train_index]) +full_atomstructure_index = generate_atomstructure_index(n_atoms) +# Will be required later to collate atomic predictions into structural predictions + +# Build a Dataloader that samples from the AtomicDataset in random batches +Sampler = RandomSampler(train_features) +BSampler = BatchSampler(Sampler, batch_size=32, drop_last=False) +traindata_loader = DataLoader(train_features, sampler=BSampler, collate_fn=collate) + + +# %% +# +# We will now define a simple three layer MLP model, consisting of three layers. +# The align keyword is used to indicate that the energy reference will be optimized +# during training. The alignment parameter refers to the adjustments made to the +# initial energy referenced and will be initialized as zeros. +# + + +class SOAP_NN(torch.nn.Module): + def __init__(self, input_dims, L1, n_train, target_dims, align): + super(SOAP_NN, self).__init__() + self.target_dims = target_dims + self.fc1 = torch.nn.Linear(input_dims, L1) + self.fc2 = torch.nn.Linear(L1, target_dims) + self.silu = torch.nn.SiLU() + self.align = align + if align: + initial_alignment = torch.zeros(n_train) + self.alignment = torch.nn.parameter.Parameter(initial_alignment) + + def forward(self, x): + result = self.fc1(x) + result = self.silu(result) + result = self.fc2(result) + return result + + +# %% +# We will use a small network architecture, whereby the input layer corresponds +# to the size of the SOAP features, 448, the intermediate layer corresponds to +# a tenth size of the input layer and the final layer corresponds +# to the number of outputs. +# +# As a shorthand, the model that optimizes the energy reference during +# training will be called the alignment model +# + +n_outputs_H = len(x_dos_H) +n_outputs_Ef = len(x_dos_Ef) + + +Model_H = SOAP_NN( + x_train.shape[1], + x_train.shape[1] // 10, + len(train_index), + n_outputs_H, + align=False, +) +Model_Ef = SOAP_NN( + x_train.shape[1], + x_train.shape[1] // 10, + len(train_index), + n_outputs_Ef, + align=False, +) +Model_Align = SOAP_NN( + x_train.shape[1], + x_train.shape[1] // 10, + len(train_index), + n_outputs_Ef, + align=True, +) +# The alignment model takes the fermi level energy reference as the starting point + +# %% +# 3) Define relevant loss functions for training and inference +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# We will now define some loss functions that will be useful when we implement +# the model training loop later and during model evaluation on the test set. + + +def t_get_mse(a, b, xdos): + """Compute mean error between two Density of States. + The mean error is integrated across the entire energy grid + to provide a single value to characterize the error + + Args: + a ([tensor]): [Predicted DOS] + b ([tensor]): [True DOS] + xdos ([tensor], optional): [Energy axis of DOS] + + Returns: + [float]: [MSE] + """ + if len(a.size()) > 1: + mse = (torch.trapezoid((a - b) ** 2, xdos, axis=1)).mean() + else: + mse = (torch.trapezoid((a - b) ** 2, xdos, axis=0)).mean() + return mse + + +def t_get_rmse(a, b, xdos): + """Compute root mean squared error between two Density of States . + + Args: + a ([tensor]): [Predicted DOS] + b ([tensor]): [True DOS] + xdos ([tensor], optional): [Energy axis of DOS] + + Raises: + ValueError: [Occurs if tensor shapes are mismatched] + + Returns: + [float]: [RMSE or %RMSE] + """ + + if len(a.size()) > 1: + rmse = torch.sqrt((torch.trapezoid((a - b) ** 2, xdos, axis=1)).mean()) + else: + rmse = torch.sqrt((torch.trapezoid((a - b) ** 2, xdos, axis=0)).mean()) + return rmse + + +def Opt_RMSE_spline(y_pred, xdos, target_splines, spline_positions, n_epochs): + """Evaluates RMSE on the optimal shift of energy axis. + The optimal shift is found via gradient descent after a gridsearch is performed. + + Args: + y_pred ([tensor]): [Prediction/s of DOS] + xdos ([tensor]): [Energy axis] + target_splines ([tensor]): [Contains spline coefficients] + spline_positions ([tensor]): [Contains spline positions] + n_epochs ([int]): [Number of epochs to run for Gradient Descent] + + Returns: + [rmse([float]), optimal_shift[tensor]]: + [RMSE on optimal shift, the optimal shift itself] + + """ + optim_search_mse = [] + offsets = torch.arange(-2, 2, 0.1) + # Grid-search is first done to reduce number of epochs needed for + # gradient descent, typically 50 epochs will be sufficient + # if searching within 0.1 + with torch.no_grad(): + for offset in offsets: + shifts = torch.zeros(y_pred.shape[0]) + offset + shifted_target = evaluate_spline( + target_splines, spline_positions, xdos + shifts.view(-1, 1) + ) + loss_i = ((y_pred - shifted_target) ** 2).mean(dim=1) + optim_search_mse.append(loss_i) + optim_search_mse = torch.vstack(optim_search_mse) + min_index = torch.argmin(optim_search_mse, dim=0) + optimal_offset = offsets[min_index] + + offset = optimal_offset + + shifts = torch.nn.parameter.Parameter(offset.float()) + opt_adam = torch.optim.Adam([shifts], lr=1e-2) + best_error = torch.zeros(len(shifts)) + 100 + best_shifts = shifts.clone() + for _ in range(n_epochs): + shifted_target = evaluate_spline( + target_splines, spline_positions, xdos + shifts.view(-1, 1) + ).detach() + + def closure(): + opt_adam.zero_grad() + shifted_target = evaluate_spline( + target_splines, spline_positions, xdos + shifts.view(-1, 1) + ) + loss_i = ((y_pred - shifted_target) ** 2).mean() + loss_i.backward(gradient=torch.tensor(1), inputs=shifts) + return loss_i + + opt_adam.step(closure) + + with torch.no_grad(): + each_loss = ((y_pred - shifted_target) ** 2).mean(dim=1).float() + index = each_loss < best_error + best_error[index] = each_loss[index].clone() + best_shifts[index] = shifts[index].clone() + + # Evaluate + + optimal_shift = best_shifts + shifted_target = evaluate_spline( + target_splines, spline_positions, xdos + optimal_shift.view(-1, 1) + ) + rmse = t_get_rmse(y_pred, shifted_target, xdos) + return rmse, optimal_shift + + +# %% +# +# 4) Define the training loop +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# We will now define the model training loop, for simplicity we will only +# train each model for a fixed number of epochs, learning rate, and batch_size. +# The training and validation error at each epoch will be saved. + + +def train_model(model_to_train, fixed_DOS, structure_splines, spline_positions, x_dos): + """Trains a model for 500 epochs + + Args: + model_to_train ([torch.nn.Module]): [ML Model] + fixed_DOS ([tensor]): [Contains the DOS at a fixed energy reference, + useful for models that don't optimize the energy reference] + structure_splines ([tensor]): [Contains spline coefficients] + spline_positions ([tensor]): [Contains spline positions] + x_dos ([tensor]): [Energy axis for the prediction] + + Returns: + [train_loss_history([tensor]), + val_loss_history[tensor], + structure_results[tensor]]: + + [Respective loss histories and final structure predictions] + """ + lr = 1e-2 + n_epochs = 500 + + opt = torch.optim.Adam(model_to_train.parameters(), lr=lr) + + train_loss_history = [] + val_loss_history = [] + + for _epoch in range(n_epochs): + for x_data, idx, index in traindata_loader: + opt.zero_grad() + predictions = model_to_train.forward(x_data) + structure_results = torch.zeros([len(idx), model_to_train.target_dims]) + # Sum atomic predictions in each structure + structure_results = structure_results.index_add_( + 0, index, predictions + ) / n_atoms[train_index[idx]].view(-1, 1) + if model_to_train.align: + alignment = model_to_train.alignment + alignment = alignment - torch.mean(alignment) + # Enforce that the alignments have a mean of zero since a constant + # value across the dataset is meaningless when optimizing the + # relative energy reference + target = evaluate_spline( + structure_splines[train_index[idx]], + spline_positions, + x_dos + alignment[idx].view(-1, 1), + ) # Shifts the target based on the alignment value + pred_loss = t_get_mse(structure_results, target, x_dos) + pred_loss.backward() + else: + pred_loss = t_get_mse( + structure_results, fixed_DOS[train_index[idx]], x_dos + ) + pred_loss.backward() + + opt.step() + with torch.no_grad(): + all_pred = model_to_train.forward(total_atomic_soaps.float()) + structure_results = torch.zeros([n_structures, model_to_train.target_dims]) + structure_results = structure_results.index_add_( + 0, full_atomstructure_index, all_pred + ) / (n_atoms).view(-1, 1) + if model_to_train.align: + # Evaluate model on optimal shift as there is no information + # regarding the shift from the fermi level energy reference + # during inference + + alignment = model_to_train.alignment + alignment = alignment - torch.mean(alignment) + target = evaluate_spline( + structure_splines[train_index], + spline_positions, + x_dos + alignment.view(-1, 1), + ) + + train_loss = t_get_rmse(structure_results[train_index], target, x_dos) + val_loss, val_shifts = Opt_RMSE_spline( + structure_results[val_index], + x_dos, + structure_splines[val_index], + spline_positions, + 50, + ) + + else: + train_loss = t_get_rmse( + structure_results[train_index], fixed_DOS[train_index], x_dos + ) + val_loss = t_get_rmse( + structure_results[val_index], fixed_DOS[val_index], x_dos + ) + + train_loss_history.append(train_loss) + val_loss_history.append(val_loss) + train_loss_history = torch.tensor(train_loss_history) + val_loss_history = torch.tensor(val_loss_history) + return ( + train_loss_history, + val_loss_history, + structure_results, + ) + # returns the loss history and the final set of predictions + + +# %% We will now train the respective models + +H_trainloss, H_valloss, H_predictions = train_model( + Model_H, total_edos_H, total_splines_H, spline_positions_H, x_dos_H +) + +Ef_trainloss, Ef_valloss, Ef_predictions = train_model( + Model_Ef, total_edos_Ef, total_splines_Ef, spline_positions_Ef, x_dos_Ef +) + +Align_trainloss, Align_valloss, Align_predictions = train_model( + Model_Align, total_edos_Ef, total_splines_Ef, spline_positions_Ef, x_dos_Ef +) +# %% +# Lets plot the train loss histories to compare their learning behaviour +# + +epochs = np.arange(500) + + +plt.plot(epochs, H_trainloss, color="red", label="Avg Hartree Potential") +plt.plot(epochs, Ef_trainloss, color="blue", label="Fermi Level") +plt.plot(epochs, Align_trainloss, color="green", label="Optimized Reference") +plt.legend() +plt.yscale(value="log") +plt.xlabel("Epochs") +plt.ylabel("RMSE") +plt.title("Train Loss vs Epoch") +# %% +# Lets plot the val loss histories to compare their learning behaviour +# + + +plt.plot(epochs, H_valloss, color="red", label="Avg Hartree Potential") +plt.plot(epochs, Ef_valloss, color="blue", label="Fermi Level") +plt.plot(epochs, Align_valloss, color="green", label="Optimized Reference") +plt.legend() +plt.yscale(value="log") +plt.xlabel("Epochs") +plt.ylabel("RMSE") +plt.title("Validation Loss vs Epoch") + + +# %% +# +# 5) Evaluate the model +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# We will now evaluate the model performance on the test set +# based on the model predictions we obtained previously +# + +H_testloss = Opt_RMSE_spline( + H_predictions[test_index], + x_dos_H, + total_splines_H[test_index], + spline_positions_H, + 200, +) # We use 200 epochs just so it the error a little bit more converged +Ef_testloss = Opt_RMSE_spline( + Ef_predictions[test_index], + x_dos_Ef, + total_splines_Ef[test_index], + spline_positions_Ef, + 200, +) # We use 200 epochs just so it the error a little bit more converged +Align_testloss = Opt_RMSE_spline( + Align_predictions[test_index], + x_dos_Ef, + total_splines_Ef[test_index], + spline_positions_Ef, + 200, +) # We use 200 epochs just so it the error a little bit more converged + +print(f"Test RMSE for average Hartree Potential: {H_testloss[0].item():.3}") +print(f"Test RMSE for Fermi Level: {Ef_testloss[0].item():.3}") +print(f"Test RMSE for Optimized Reference: {Align_testloss[0].item():.3}") + +print( + "The difference in effectiveness between the Optimized Reference \ +and the Fermi Level will increase with more epochs" +) +# %% +# +# Plot Training DOSes at different energy reference to visualize +# the impact of the energy reference. From the plots we can see +# that the optimized energy reference has better alignment of +# common spectral patterns across the dataset +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Average Hartree Energy Reference +# + +for i in total_edos_H[train_index]: + plt.plot(x_dos_H, i, color="C0", alpha=0.6) +plt.title("Energy Reference - Average Hartree Potential") +plt.xlabel("Energy [eV]") +plt.ylabel("DOS") +print("The DOSes, despite looking similar, are offset along the energy axis") + +# %% +# Fermi Level Energy Reference +for i in total_edos_Ef[train_index]: + plt.plot(x_dos_Ef, i, color="C0", alpha=0.6) +plt.title("Energy Reference - Fermi Level") +plt.xlabel("Energy [eV]") +plt.ylabel("DOS") + +print("It is better aligned but still quite some offset") +# %% +# Optimized Energy Reference +shifts = Model_Align.alignment.detach() +shifts = shifts - torch.mean(shifts) +x_dos_splines = x_dos_Ef + shifts.view(-1, 1) +total_edos_align = evaluate_spline( + total_splines_Ef[train_index], spline_positions_Ef, x_dos_splines +) + +for i in total_edos_align: + plt.plot(x_dos_Ef, i, color="C0", alpha=0.6) +plt.title("Energy Reference - Optimized") +plt.xlabel("Energy [eV]") +plt.ylabel("DOS") +print("The DOS alignment is better under the optimized energy reference") +print("The difference will increase with more training epochs") +# %% diff --git a/latest/_downloads/edc4de60777e3b3373ed9e627d585459/environment.yml b/latest/_downloads/edc4de60777e3b3373ed9e627d585459/environment.yml new file mode 100644 index 00000000..fe3f1a41 --- /dev/null +++ b/latest/_downloads/edc4de60777e3b3373ed9e627d585459/environment.yml @@ -0,0 +1,13 @@ +channels: + - conda-forge +dependencies: + - python=3.11 + - pip + - rust >=1.65 + - pip: + - ase + - chemiscope + - matplotlib + - metatensor + - rascaline @ git+https://github.com/Luthaf/rascaline@ca957642f512e141c7570e987aadc05c7ac71983 + - skmatter diff --git a/latest/_downloads/fe6711aca3f0f5f2cec13f8a8ebe3462/example.xyz b/latest/_downloads/fe6711aca3f0f5f2cec13f8a8ebe3462/example.xyz new file mode 100644 index 00000000..c0031e2d --- /dev/null +++ b/latest/_downloads/fe6711aca3f0f5f2cec13f8a8ebe3462/example.xyz @@ -0,0 +1,8 @@ +6 +Lattice="3.9111732301689224 0.0 0.0 0.0 3.9111732301689224 0.0 0.0 0.0 3.9111732301689224" Properties=species:S:1:pos:R:3 #=T CELL(abcABC):=T 3.91117=T 90.00000=T Step:=T 1975600=T Bead:=T 0=T x_centroidangstrom=T cellangstrom=T count=0 pbc="T T T" +H 2.55799292 0.30476323 0.67883354 +H 1.46739292 0.53584100 3.59015677 +O 1.78619292 3.82685646 0.31171354 +H 3.52058031 2.55936677 2.71091323 +H 0.84863385 2.05009677 1.85452646 +O 0.09813385 1.75660677 2.33837646 diff --git a/latest/_downloads/fece03724daaa69643cea3d483b9c18e/path-integrals.ipynb b/latest/_downloads/fece03724daaa69643cea3d483b9c18e/path-integrals.ipynb new file mode 100644 index 00000000..6482e4b4 --- /dev/null +++ b/latest/_downloads/fece03724daaa69643cea3d483b9c18e/path-integrals.ipynb @@ -0,0 +1,291 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n# Path integral molecular dynamics\n\n:Authors: Michele Ceriotti [@ceriottm](https://github.com/ceriottm/)\n\nThis example shows how to run a path integral molecular dynamics\nsimulation using ``i-PI``, analyze the output and visualize the\ntrajectory in ``chemiscope``. It uses [LAMMPS](http://lammps.org)\nas the driver to simulate the [q-TIP4P/f water\nmodel](http://doi.org/10.1063/1.3167790).\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import subprocess\nimport time\n\nimport chemiscope\nimport ipi\nimport matplotlib.pyplot as plt\nimport numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Quantum nuclear effects and path integral methods\n\nThe Born-Oppenheimer approximation separates the joint quantum mechanical\nproblem for electrons and nuclei into two independent problems. Even though\noften one makes the additional approximation of treating nuclei as classical\nparticles, this is not necessary, and in some cases (typically when H atoms are\npresent) can add considerable error.\n\n\n.. figure:: pimd-slices-round.png\n :align: center\n :width: 600px\n\n A representation of ther ring-polymer Hamiltonian for a water molecule.\n\nIn order to describe the quantum mechanical nature of light nuclei\n(nuclear quantum effects) one of the most widely-applicable methods uses\nthe *path integral formalism* to map the quantum partition function of a\nset of distinguishable particles onto the classical partition function of\n*ring polymers* composed by multiple beads (replicas) with\ncorresponding atoms in adjacent replicas being connected by harmonic\nsprings.\n[The textbook by Tuckerman](https://tinyurl.com/bdfhk2tx)\ncontains a pedagogic introduction to the topic, while\n[this paper](https://doi.org/10.1063/1.3489925) outlines the implementation\nused in ``i-PI``.\n\nThe classical partition function of the path converges to quantum statistics\nin the limit of a large number of replicas. In this example, we will use a\ntechnique based on generalized Langevin dynamics, known as\n[PIGLET](http://doi.org/10.1103/PhysRevLett.109.100604) to accelerate the\nconvergence.\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running PIMD calculations with ``i-PI``\n\n[i-PI](http://ipi-code.org) is based on a client-server model, with ``i-PI``\ncontrolling the nuclear dynamics (in this case sampling the path Hamiltonian using\nmolecular dynamics) while the calculation of energies and forces is delegated to\nan external client program, in this example ``LAMMPS``.\n\nAn i-PI calculation is specified by an XML file.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Open and read the XML file\nwith open(\"input_pimd.xml\", \"r\") as file:\n xml_content = file.read()\nprint(xml_content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "NB1: In a realistic simulation you may want to increase the field\n``total_steps``, to simulate at least a few 100s of picoseconds.\n\nNB2: To converge a simulation of water at room temperature, you\ntypically need at least 32 beads. We will see later how to accelerate\nconvergence using a colored-noise thermostat, but you can try to\nmodify the input to check convergence with conventional PIMD\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "i-PI and lammps should be run separately, and it is possible to\nlaunch separate lammps processes to parallelize the evaluation over\nthe beads. On the the command line, this amounts to launching\n\n```bash\ni-pi input_pimd.xml > log &\nsleep 2\nlmp -in in.lmp &\nlmp -in in.lmp &\n```\nNote how ``i-PI`` and ``LAMMPS`` are completely independent, and\ntherefore need a separate set of input files. The client-side communication\nin ``LAMMPS`` is described in the ``fix_ipi`` section, that matches the socket\nname and mode defined in the ``ffsocket`` field in the ``i-PI`` file.\n\nWe can launch the external processes from a Python script as follows\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ipi_process = subprocess.Popen([\"i-pi\", \"input_pimd.xml\"])\ntime.sleep(2) # wait for i-PI to start\nlmp_process = [subprocess.Popen([\"lmp\", \"-in\", \"in.lmp\"]) for i in range(2)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you run this in a notebook, you can go ahead and start loading\noutput files _before_ i-PI and lammps have finished running, by\nskipping this cell\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ipi_process.wait()\nlmp_process[0].wait()\nlmp_process[1].wait()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After the simulation has run, you can visualize and post-process the trajectory data.\nNote that i-PI prints a separate trajectory for each bead, as structural properties\ncan be computed averaging over the configurations of any of the beads.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "output_data, output_desc = ipi.read_output(\"simulation.out\")\ntraj_data = [ipi.read_trajectory(f\"simulation.pos_{i}.xyz\") for i in range(8)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The simulation parameters are pushed at the limits: with the aggressive stochastic\nthermostatting and the high-frequency normal modes of the ring polymer, there are\nfairly large fluctuations of the conserved quantity. This is usually not affecting\nphysical observables, but if you see this level of drift in a production run, check\ncarefully for convergence and stability with a reduced time step.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True)\nax.plot(\n output_data[\"time\"],\n output_data[\"potential\"] - output_data[\"potential\"][0],\n \"b-\",\n label=\"Potential, $V$\",\n)\nax.plot(\n output_data[\"time\"],\n output_data[\"conserved\"] - output_data[\"conserved\"][0],\n \"r-\",\n label=\"Conserved, $H$\",\n)\nax.set_xlabel(r\"$t$ / ps\")\nax.set_ylabel(r\"energy / eV\")\nax.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While the potential energy is simply the mean over the beads of the\nenergy of individual replicas, computing the kinetic energy requires\naveraging special quantities that involve also the correlations between beads.\nHere we compare two of these *estimators*: the 'thermodynamic' estimator becomes\nstatistically inefficient when increasing the number of beads, whereas the\n'centroid virial' estimator remains well-behaved. Note how quickly these estimators\nequilibrate to roughly their stationary value, much faster than the equilibration\nof the potential energy above. This is thanks to the ``pile_g`` thermostat\n(see [DOI:10.1063/1.3489925](http://doi.org/10.1063/1.3489925)) that is\noptimally coupled to the normal modes of the ring polymer.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True)\nax.plot(\n output_data[\"time\"],\n output_data[\"kinetic_cv\"],\n \"b-\",\n label=\"Centroid virial, $K_{CV}$\",\n)\nax.plot(\n output_data[\"time\"],\n output_data[\"kinetic_td\"],\n \"r-\",\n label=\"Thermodynamic, $K_{TD}$\",\n)\nax.set_xlabel(r\"$t$ / ps\")\nax.set_ylabel(r\"energy / eV\")\nax.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also visualize the (very short) trajectory in a way that highlights the\nfast spreading out of the beads of the ring polymer. ``chemiscope`` provides a\nutility function to interleave the trajectories of the beads, forming a trajectory\nthat shows the connecttions between the replicas of each atom. Each atom and its\nconnections are color-coded.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "traj_pimd = chemiscope.ase_merge_pi_frames(traj_data)\n# we also tweak the visualization options, and then show the viewer\ntraj_pimd[\"shapes\"][\"paths\"][\"parameters\"][\"global\"][\"radius\"] = 0.05\ntraj_pimd[\"settings\"][\"structure\"][0].update(\n dict(\n atoms=False,\n keepOrientation=True,\n color={\"property\": \"bead_id\", \"palette\": \"hsv (periodic)\"},\n )\n)\n\ncs = chemiscope.show(**traj_pimd, mode=\"structure\")\n\nif chemiscope.jupyter._is_running_in_notebook():\n from IPython.display import display\n\n display(cs)\nelse:\n cs.save(\"path-integrals.json.gz\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Accelerating PIMD with a PIGLET thermostat\n\nThe simulations in the previous sections are very far from converged -- typically\none would need approximately 32 replicas to converge a simulation of\nroom-temperature water. To address this problem we will use a method based on\ngeneralized Langevin equations, called\n[PIGLET](http://doi.org/10.1103/PhysRevLett.109.100604)\n\nThe input file is ``input_piglet.xml``, that only differs by the definition of\nthe thermostat, that uses a ``nm_gle`` mode in which each normal mode\nof the ring polymer is attached to a different colored-noise Generalized Langevin\nequation. This makes it possible to converge exactly the simulation results with\na small number of replicas, and to accelerate greatly convergence for realistic\nsystems such as this. The thermostat parameters can be generated on\n[the GLE4MD website](https://tinyurl.com/4y2e45jx)\n\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ipi_process = subprocess.Popen([\"i-pi\", \"input_piglet.xml\"])\ntime.sleep(2) # wait for i-PI to start\nlmp_process = [subprocess.Popen([\"lmp\", \"-in\", \"in.lmp\"]) for i in range(2)]\n\nipi_process.wait()\nlmp_process[0].wait()\nlmp_process[1].wait()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The mean potential energy from the PIGLET trajectory is higher than that for the\nPIMD one, because it is closer to the converged value (try to run a PIMD trajectory\nwith 64 beads for comparison)\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "output_gle, desc_gle = ipi.read_output(\"simulation_piglet.out\")\ntraj_gle = [ipi.read_trajectory(f\"simulation_piglet.pos_{i}.xyz\") for i in range(8)]\n\nfix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True)\nax.plot(\n output_data[\"time\"],\n output_data[\"potential\"] - output_data[\"potential\"][0],\n \"b--\",\n label=\"PIMD\",\n)\nax.plot(\n output_gle[\"time\"],\n output_gle[\"potential\"] - output_gle[\"potential\"][0],\n \"b-\",\n label=\"PIGLET\",\n)\nax.set_xlabel(r\"$t$ / ps\")\nax.set_ylabel(r\"energy / eV\")\nax.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, you should be somewhat careful: PIGLET converges *some* but not all the\ncorrelations within a path. For instance, it is designed to converge the\ncentroid-virial estimator for the kinetic energy, but not the thermodynamic\nestimator. For the same reason, don't try to look at equilibration in terms of\nthe mean temperature: it won't match the target value, because PIGLET uses a\nLangevin equation that breaks the classical fluctuation-dissipation theorem, and\ngenerates a steady-state distribution that mimics quantum fluctuations.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True)\nax.plot(output_data[\"time\"], output_data[\"kinetic_cv\"], \"b--\", label=\"PIMD, $K_{CV}$\")\nax.plot(output_gle[\"time\"], output_gle[\"kinetic_cv\"], \"b\", label=\"PIGLET, $K_{CV}$\")\nax.plot(output_data[\"time\"], output_data[\"kinetic_td\"], \"r--\", label=\"PIMD, $K_{TD}$\")\nax.plot(output_gle[\"time\"], output_gle[\"kinetic_td\"], \"r\", label=\"PIGLET, $K_{TD}$\")\nax.set_xlabel(r\"$t$ / ps\")\nax.set_ylabel(r\"energy / eV\")\nax.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Kinetic energy tensors\n\nWhile we're at it, let's do something more complicated (and instructive).\nClassically, the momentum distribution of any atom is isotropic, so the\nkinetic energy tensor (KET) $\\mathbf{p}\\mathbf{p}^T/2m$ is a constant\ntimes the identity matrix. Quantum mechanically, the kinetic energy tensor\nhas more structure, that reflects the higher kinetic energy of particles\nalong directions with stiff bonds. We can compute a moving average of the\ncentroid virial estimator of the KET, and plot it to show the direction\nof anisotropy. Note that there are some subtleties connected with the\nevaluation of the moving average, see e.g.\n[DOI:10.1103/PhysRevLett.109.100604](http://doi.org/10.1103/PhysRevLett.109.100604)\n\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We first need to postprocess the components of the kinetic energy tensors\n(that i-PI prints out separating the diagonal and off-diagonal bits), averaging\nthem over the last 10 frames and combining them with the centroid configuration\nfrom the last frame in the trajectory.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "kinetic_cv = ipi.read_trajectory(\"simulation_piglet.kin.xyz\")\nkinetic_od = ipi.read_trajectory(\"simulation_piglet.kod.xyz\")\nkinetic_tens = np.hstack(\n [\n np.asarray([k.positions for k in kinetic_cv[-10:]]).mean(axis=0),\n np.asarray([k.positions for k in kinetic_od[-10:]]).mean(axis=0),\n ]\n)\n\ncentroid = traj_gle[-1][-1].copy()\ncentroid.positions = np.asarray([t[-1].positions for t in traj_gle]).mean(axis=0)\ncentroid.arrays[\"kinetic_cv\"] = kinetic_tens" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can then view these in ``chemiscope``, setting the proper parameters to\nvisualize the ellipsoids associated with the KET. Note that some KETs have\nnegative eigenvalues, because we are averaging over a few frames, which is\ninsufficient to converge the estimator fully.\n\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ellipsoids = chemiscope.ase_tensors_to_ellipsoids(\n [centroid], \"kinetic_cv\", scale=15, force_positive=True\n)\n\ncs = chemiscope.show(\n [centroid],\n shapes={\"kinetic_cv\": ellipsoids},\n mode=\"structure\",\n settings=chemiscope.quick_settings(\n structure_settings={\n \"shape\": [\"kinetic_cv\"],\n \"unitCell\": True,\n }\n ),\n)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "if chemiscope.jupyter._is_running_in_notebook():\n from IPython.display import display\n\n display(cs)\nelse:\n cs.save(\"path-integrals.json.gz\")" + ] + } + ], + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/latest/_images/pimd-slices-round.png b/latest/_images/pimd-slices-round.png new file mode 100644 index 00000000..39ae9416 Binary files /dev/null and b/latest/_images/pimd-slices-round.png differ diff --git a/latest/_images/sphx_glr_dos-align_001.png b/latest/_images/sphx_glr_dos-align_001.png new file mode 100644 index 00000000..696b22ac Binary files /dev/null and b/latest/_images/sphx_glr_dos-align_001.png differ diff --git a/latest/_images/sphx_glr_dos-align_002.png b/latest/_images/sphx_glr_dos-align_002.png new file mode 100644 index 00000000..61b96a6b Binary files /dev/null and b/latest/_images/sphx_glr_dos-align_002.png differ diff --git a/latest/_images/sphx_glr_dos-align_003.png b/latest/_images/sphx_glr_dos-align_003.png new file mode 100644 index 00000000..7e3e5978 Binary files /dev/null and b/latest/_images/sphx_glr_dos-align_003.png differ diff --git a/latest/_images/sphx_glr_dos-align_004.png b/latest/_images/sphx_glr_dos-align_004.png new file mode 100644 index 00000000..0ad237b6 Binary files /dev/null and b/latest/_images/sphx_glr_dos-align_004.png differ diff --git a/latest/_images/sphx_glr_dos-align_005.png b/latest/_images/sphx_glr_dos-align_005.png new file mode 100644 index 00000000..4d17890d Binary files /dev/null and b/latest/_images/sphx_glr_dos-align_005.png differ diff --git a/latest/_images/sphx_glr_dos-align_006.png b/latest/_images/sphx_glr_dos-align_006.png new file mode 100644 index 00000000..8087ba53 Binary files /dev/null and b/latest/_images/sphx_glr_dos-align_006.png differ diff --git a/latest/_images/sphx_glr_dos-align_007.png b/latest/_images/sphx_glr_dos-align_007.png new file mode 100644 index 00000000..dd3d1f36 Binary files /dev/null and b/latest/_images/sphx_glr_dos-align_007.png differ diff --git a/latest/_images/sphx_glr_gaas-map_001.png b/latest/_images/sphx_glr_gaas-map_001.png new file mode 100644 index 00000000..f5d34a1c Binary files /dev/null and b/latest/_images/sphx_glr_gaas-map_001.png differ diff --git a/latest/_images/sphx_glr_gaas-map_002.png b/latest/_images/sphx_glr_gaas-map_002.png new file mode 100644 index 00000000..7363cf94 Binary files /dev/null and b/latest/_images/sphx_glr_gaas-map_002.png differ diff --git a/latest/_images/sphx_glr_gaas-map_003.png b/latest/_images/sphx_glr_gaas-map_003.png new file mode 100644 index 00000000..da6ef250 Binary files /dev/null and b/latest/_images/sphx_glr_gaas-map_003.png differ diff --git a/latest/_images/sphx_glr_lode-linear_001.png b/latest/_images/sphx_glr_lode-linear_001.png new file mode 100644 index 00000000..0b5824fb Binary files /dev/null and b/latest/_images/sphx_glr_lode-linear_001.png differ diff --git a/latest/_images/sphx_glr_lpr_001.png b/latest/_images/sphx_glr_lpr_001.png new file mode 100644 index 00000000..dd65702f Binary files /dev/null and b/latest/_images/sphx_glr_lpr_001.png differ diff --git a/latest/_images/sphx_glr_lpr_002.png b/latest/_images/sphx_glr_lpr_002.png new file mode 100644 index 00000000..38e7930e Binary files /dev/null and b/latest/_images/sphx_glr_lpr_002.png differ diff --git a/latest/_images/sphx_glr_path-integrals_001.png b/latest/_images/sphx_glr_path-integrals_001.png new file mode 100644 index 00000000..0096a11d Binary files /dev/null and b/latest/_images/sphx_glr_path-integrals_001.png differ diff --git a/latest/_images/sphx_glr_path-integrals_002.png b/latest/_images/sphx_glr_path-integrals_002.png new file mode 100644 index 00000000..804177f6 Binary files /dev/null and b/latest/_images/sphx_glr_path-integrals_002.png differ diff --git a/latest/_images/sphx_glr_path-integrals_003.png b/latest/_images/sphx_glr_path-integrals_003.png new file mode 100644 index 00000000..83597f4b Binary files /dev/null and b/latest/_images/sphx_glr_path-integrals_003.png differ diff --git a/latest/_images/sphx_glr_path-integrals_004.png b/latest/_images/sphx_glr_path-integrals_004.png new file mode 100644 index 00000000..f1817e53 Binary files /dev/null and b/latest/_images/sphx_glr_path-integrals_004.png differ diff --git a/latest/_images/sphx_glr_reference-trajectory_001.png b/latest/_images/sphx_glr_reference-trajectory_001.png new file mode 100644 index 00000000..07da724f Binary files /dev/null and b/latest/_images/sphx_glr_reference-trajectory_001.png differ diff --git a/latest/_images/sphx_glr_roy-gch_001.png b/latest/_images/sphx_glr_roy-gch_001.png new file mode 100644 index 00000000..de08a555 Binary files /dev/null and b/latest/_images/sphx_glr_roy-gch_001.png differ diff --git a/latest/_images/sphx_glr_roy-gch_002.png b/latest/_images/sphx_glr_roy-gch_002.png new file mode 100644 index 00000000..fc79faba Binary files /dev/null and b/latest/_images/sphx_glr_roy-gch_002.png differ diff --git a/latest/_images/sphx_glr_roy-gch_003.png b/latest/_images/sphx_glr_roy-gch_003.png new file mode 100644 index 00000000..d6f79078 Binary files /dev/null and b/latest/_images/sphx_glr_roy-gch_003.png differ diff --git a/latest/_images/sphx_glr_sample-selection_001.png b/latest/_images/sphx_glr_sample-selection_001.png new file mode 100644 index 00000000..8ede4c99 Binary files /dev/null and b/latest/_images/sphx_glr_sample-selection_001.png differ diff --git a/latest/_sources/examples/batch-cp2k/reference-trajectory.rst.txt b/latest/_sources/examples/batch-cp2k/reference-trajectory.rst.txt new file mode 100644 index 00000000..2d9d61ae --- /dev/null +++ b/latest/_sources/examples/batch-cp2k/reference-trajectory.rst.txt @@ -0,0 +1,520 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/batch-cp2k/reference-trajectory.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_batch-cp2k_reference-trajectory.py: + + +Batch run of CP2K calculations +============================== + +:Authors: Matthias Kellner `@bananenpampe `_, + Philip Loche `@PicoCentauri `_ + +This is an example how to perform single point calculations based on list of structures +using `CP2K `_ using its `reftraj functionality +`_. The inputs are a +set of structures in :download:`example.xyz` using the DFT parameters defined in +:download:`reftraj_template.cp2k`. The reference DFT parameters are taken from `Cheng et +al. Ab initio thermodynamics of liquid and solid water 2019 +`_. Due to the small size of the test +structure and convergence issues, we have decreased the size of the ``CUTOFF_RADIUS`` +from :math:`6.0\,\mathrm{Å}` to :math:`3.0\,\mathrm{Å}`. For actual production +calculations adapt the template! + +.. GENERATED FROM PYTHON SOURCE LINES 21-22 + +We start the example by importing the required packages. + +.. GENERATED FROM PYTHON SOURCE LINES 22-35 + +.. code-block:: Python + + + import os + import platform + import subprocess + from typing import List, Union + + import ase.io + import ase.visualize.plot + import matplotlib.pyplot as plt + import numpy as np + import requests + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 36-42 + +Install CP2K +------------ + +We'll need a working installation of cp2k. The best way to do so depends on your +platform, here are some possible solutions, but feel free to replace them with another +installation method. + +.. GENERATED FROM PYTHON SOURCE LINES 43-54 + +.. code-block:: Python + + + if platform.system() == "Linux": + # use conda on Linux + subprocess.run(["conda", "install", "cp2k", "-c", "conda-forge", "-y"], check=True) + elif platform.system() == "Darwin": + # use homebrew on macOS + subprocess.run(["brew", "install", "cp2k"], check=True) + else: + print("no known way to install cp2k, skipping installation") + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 55-58 + +Define necessary functions +-------------------------- +Next we below define necessary helper functions to run the example. + +.. GENERATED FROM PYTHON SOURCE LINES 58-92 + +.. code-block:: Python + + + + def write_reftraj(fname: str, frames: Union[ase.Atoms, List[ase.Atoms]]) -> None: + """Writes a list of ase atoms objects to a reference trajectory. + + A reference trajectory is the CP2K compatible format for the compuation of batches. + All frames must have the stoichiometry/composition. + """ + + if isinstance(frames, ase.Atoms): + frames = [frames] + + out = "" + for i, atoms in enumerate(frames): + if ( + len(atoms) != len(frames[0]) + or atoms.get_chemical_formula() != frames[0].get_chemical_formula() + ): + raise ValueError( + f"Atom symbols in frame {i},{atoms.get_chemical_formula()} are " + f"different compared to inital frame " + f"{frames[0].get_chemical_formula()}. " + "CP2K does not support changing atom types within a reftraj run!" + ) + + out += f"{len(atoms):>8}\n i = {i + 1:>8}, time = {0:>12.3f}\n" + for atom in atoms: + pos = atom.position + out += f"{atom.symbol}{pos[0]:24.15f}{pos[1]:24.15f}{pos[2]:24.15f}\n" + out += "\n" + with open(fname, "w") as f: + f.write(out) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 93-129 + +.. code-block:: Python + + + + def write_cellfile(fname: str, frames: Union[ase.Atoms, List[ase.Atoms]]) -> None: + """Writes a cellfile for a list of ``ase.Atoms``. + + A Cellfile accompanies a reftraj containing the cell parameters. + """ + if isinstance(frames, ase.Atoms): + frames = [frames] + + out = ( + "# " + "Step " + "Time [fs] " + "Ax [Angstrom] " + "Ay [Angstrom] " + "Az [Angstrom] " + "Bx [Angstrom] " + "By [Angstrom] " + "Bz [Angstrom] " + "Cx [Angstrom] " + "Cy [Angstrom] " + "Cz [Angstrom] " + "Volume [Angstrom^3]\n" + ) + + for i, atoms in enumerate(frames): + out += f"{i + 1:>8}{0:>12.3f}" + out += "".join([f"{c:>20.10f}" for c in atoms.cell.flatten()]) + out += f"{atoms.cell.volume:>25.10f}" + out += "\n" + + with open(fname, "w") as f: + f.write(out) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 130-151 + +.. code-block:: Python + + + + def write_cp2k_in( + fname: str, project_name: str, last_snapshot: int, cell: List[float] + ) -> None: + """Writes a cp2k input file from a template. + + Importantly, it writes the location of the basis set definitions, + determined from the path of the system CP2K install to the input file. + """ + + cp2k_in = open("reftraj_template.cp2k", "r").read() + + cp2k_in = cp2k_in.replace("//PROJECT//", project_name) + cp2k_in = cp2k_in.replace("//LAST_SNAPSHOT//", str(last_snapshot)) + cp2k_in = cp2k_in.replace("//CELL//", " ".join([f"{c:.6f}" for c in cell])) + + with open(fname, "w") as f: + f.write(cp2k_in) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 152-154 + +We will now download basis set files from CP2K website. Depending on your CP2K +installation, this might not be necessary! + +.. GENERATED FROM PYTHON SOURCE LINES 155-173 + +.. code-block:: Python + + + + def download_parameter(file): + path = os.path.join("parameters", file) + + if not os.path.exists(path): + url = f"https://raw.githubusercontent.com/cp2k/cp2k/support/v2024.1/data/{file}" + response = requests.get(url) + response.raise_for_status() + with open(path, "wb") as f: + f.write(response.content) + + + os.makedirs("parameters", exist_ok=True) + for file in ["GTH_BASIS_SETS", "BASIS_ADMM", "POTENTIAL", "dftd3.dat", "t_c_g.dat"]: + download_parameter(file) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 174-186 + +Prepare calculation inputs +-------------------------- +During this example we will create a directory named ``project_directory`` containing +the subdirectories for each stoichiometry. This is necessary, because CP2K can only +run calculations using a fixed stoichiometry at a time, using its ``reftraj`` +functionality. + +Below we define the general information for the CP2K run. This includes the reference +files for the structures, the ``project_name`` used to build the name of the +trajectory during the CP2K run, the ``project_directory`` where we store all +simulation output as well as the path ``write_to_file`` which is the name of the file +containing the computed energies and forces of the simulation. + +.. GENERATED FROM PYTHON SOURCE LINES 186-192 + +.. code-block:: Python + + + frames_full = ase.io.read("example.xyz", ":") + project_name = "test_calcs" # name of the global PROJECT + project_directory = "production" + write_to_file = "out.xyz" + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 193-195 + +Below we show the initial configuration of two water molecules in a cubic box with a +side length of :math:`\approx 4\,\mathrm{Å}`. + +.. GENERATED FROM PYTHON SOURCE LINES 195-203 + +.. code-block:: Python + + + ase.visualize.plot.plot_atoms(frames_full[0]) + + plt.xlabel("Å") + plt.ylabel("Å") + + plt.show() + + + + +.. image-sg:: /examples/batch-cp2k/images/sphx_glr_reference-trajectory_001.png + :alt: reference trajectory + :srcset: /examples/batch-cp2k/images/sphx_glr_reference-trajectory_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 204-206 + +We now extract the stoichiometry from the input dataset using ASE's +:py:meth:`ase.symbols.Symbols.get_chemical_formula` method. + +.. GENERATED FROM PYTHON SOURCE LINES 206-218 + +.. code-block:: Python + + + frames_dict = {} + + for atoms in frames_full: + chemical_formula = atoms.get_chemical_formula() + try: + frames_dict[chemical_formula] + except KeyError: + frames_dict[chemical_formula] = [] + + frames_dict[chemical_formula].append(atoms) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 219-223 + +Based on the stoichiometries we create one calculation subdirectories for the +calculations. (reftraj, input and cellfile). For our example this is only is one +directory named ``H4O2`` because our dataset consists only of a single structure with +two water molecules. + +.. GENERATED FROM PYTHON SOURCE LINES 223-239 + +.. code-block:: Python + + + for stoichiometry, frames in frames_dict.items(): + current_directory = f"{project_directory}/{stoichiometry}" + os.makedirs(current_directory, exist_ok=True) + + write_cp2k_in( + f"{current_directory}/in.cp2k", + project_name=project_name, + last_snapshot=len(frames), + cell=frames[0].cell.diagonal(), + ) + + ase.io.write(f"{current_directory}/init.xyz", frames[0]) + write_reftraj(f"{current_directory}/reftraj.xyz", frames) + write_cellfile(f"{current_directory}/reftraj.cell", frames) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 240-250 + +Run simulations +--------------- +Now we have all ingredients to run the simulations. Below we call the bash script +:download:`run_calcs.sh`. + +.. literalinclude:: run_calcs.sh + :language: bash + +This script will loop through all stoichiometry subdirectories and call the CP2K +engine. + +.. GENERATED FROM PYTHON SOURCE LINES 250-254 + +.. code-block:: Python + + + # run the bash script directly from this script + subprocess.run("bash run_calcs.sh", shell=True) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + CompletedProcess(args='bash run_calcs.sh', returncode=0) + + + +.. GENERATED FROM PYTHON SOURCE LINES 255-264 + +.. note:: + + For a usage on an HPC environment you can parallelize the loop over the + sub-directories and submit and single job per stoichiometry. + +Load results +------------ +After the simulation we load the results and perform a unit version from the default +CP2K output units (Bohr and Hartree) to Å and eV. + +.. GENERATED FROM PYTHON SOURCE LINES 264-269 + +.. code-block:: Python + + + cflength = 0.529177210903 # Bohr -> Å + cfenergy = 27.211386245988 # Hartree -> eV + cfforce = cfenergy / cflength # Hartree/Bohr -> eV/Å + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 270-273 + +Finally, we store the results as :class:`ase.Atoms` in the ``new_frames`` list and +write them to the ``project_directory`` using the ``new_fname``. Here it will be +written to ``production/out_dft.xyz``. + +.. GENERATED FROM PYTHON SOURCE LINES 273-305 + +.. code-block:: Python + + + new_frames = [] + + for stoichiometry, frames in frames_dict.items(): + current_directory = f"{project_directory}/{stoichiometry}" + + frames_dft = ase.io.read(f"{current_directory}/{project_name}-pos-1.xyz", ":") + forces_dft = ase.io.read(f"{current_directory}/{project_name}-frc-1.xyz", ":") + cell_dft = np.atleast_2d(np.loadtxt(f"{current_directory}/{project_name}-1.cell"))[ + :, 2:-1 + ] + + for i_atoms, atoms in enumerate(frames_dft): + frames_ref = frames[i_atoms] + + # Check consistent positions + if not np.allclose(atoms.positions, frames_ref.positions): + raise ValueError(f"Positions in frame {i_atoms} are not the same.") + + # Check consistent cell + if not np.allclose(frames_ref.cell.flatten(), cell_dft[i_atoms]): + raise ValueError(f"Cell dimensions in frame {i_atoms} are not the same.") + + atoms.info["E"] *= cfenergy + atoms.pbc = True + atoms.cell = frames_ref.cell + atoms.set_array("forces", cfforce * forces_dft[i_atoms].positions) + + new_frames += frames_dft + + new_fname = f"{os.path.splitext(os.path.basename(write_to_file))[0]}_dft.xyz" + ase.io.write(f"{project_directory}/{new_fname}", new_frames) + + + + + + + + +.. _sphx_glr_download_examples_batch-cp2k_reference-trajectory.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + .. container:: sphx-glr-download + + :download:`Download Conda environment file: environment.yml ` + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: reference-trajectory.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: reference-trajectory.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ + diff --git a/latest/_sources/examples/batch-cp2k/sg_execution_times.rst.txt b/latest/_sources/examples/batch-cp2k/sg_execution_times.rst.txt new file mode 100644 index 00000000..0112525c --- /dev/null +++ b/latest/_sources/examples/batch-cp2k/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_examples_batch-cp2k_sg_execution_times: + + +Computation times +================= +**00:43.872** total execution time for 1 file **from examples/batch-cp2k**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_batch-cp2k_reference-trajectory.py` (``reference-trajectory.py``) + - 00:43.872 + - 0.0 diff --git a/latest/_sources/examples/dos-align/dos-align.rst.txt b/latest/_sources/examples/dos-align/dos-align.rst.txt new file mode 100644 index 00000000..08463876 --- /dev/null +++ b/latest/_sources/examples/dos-align/dos-align.rst.txt @@ -0,0 +1,1461 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/dos-align/dos-align.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_dos-align_dos-align.py: + + +Training the DOS with different Energy References +============================================================================== +:Authors: How Wei Bin `@HowWeiBin `_ + +This tutorial would go through the entire machine learning framework for the electronic +density of states (DOS). It will cover the construction of the DOS and SOAP +descriptors from ase Atoms and eigenenergy results. A simple neural network will +then be constructed and the model parameters, along with the energy reference will be +optimized during training. A total of three energy reference will be used, the average +Hartree potential, the Fermi level, and an optimized energy reference starting from +the Fermi level energy reference. The performance of each model is then compared. + + + +Firstly, lets begin by importing the necessary packages and helper functions + +.. GENERATED FROM PYTHON SOURCE LINES 20-36 + +.. code-block:: Python + + + import os + import zipfile + + import ase + import ase.io + import matplotlib.pyplot as plt + import numpy as np + import requests + import torch + from rascaline import SoapPowerSpectrum + from scipy.interpolate import CubicHermiteSpline, interp1d + from scipy.optimize import brentq + from torch.utils.data import BatchSampler, DataLoader, Dataset, RandomSampler + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 37-48 + +Step 0: Load Structures and Eigenenergies +------------------------------------------------ +1) Downloading and Extracting Data +2) Loading Data +3) Find range of eigenenergies + +We take a small subset of 104 structures in the Si dataset from `Bartok et al., +2018 `. +Each structure in the dataset contains two atoms. + + + +.. GENERATED FROM PYTHON SOURCE LINES 52-54 + +1) Downloading and Extracting Data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. GENERATED FROM PYTHON SOURCE LINES 54-64 + +.. code-block:: Python + + filename = "dataset.zip" + if not os.path.exists(filename): + url = "https://github.com/HowWeiBin/datasets/archive/refs/tags/Silicon-Diamonds.zip" + response = requests.get(url) + response.raise_for_status() + with open(filename, "wb") as f: + f.write(response.content) + + with zipfile.ZipFile("./dataset.zip", "r") as zip_ref: + zip_ref.extractall("./") + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 65-67 + +2) Loading Data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. GENERATED FROM PYTHON SOURCE LINES 67-76 + +.. code-block:: Python + + structures = ase.io.read("./datasets-Silicon-Diamonds/diamonds.xyz", ":") + n_structures = len(structures) + n_atoms = torch.tensor([len(i) for i in structures]) + eigenenergies = torch.load("./datasets-Silicon-Diamonds/diamond_energies.pt") + k_normalization = torch.tensor( + [len(i) for i in eigenenergies] + ) # Calculates number of kpoints sampled per structure + print(f"Total number of structures: {len(structures)}") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Total number of structures: 104 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 77-79 + +3) Find range of eigenenergies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. GENERATED FROM PYTHON SOURCE LINES 79-91 + +.. code-block:: Python + + + # Process eigenenergies to flattened torch tensors + + total_eigenenergies = [torch.flatten(torch.tensor(i)) for i in eigenenergies] + + # Get lowest and highest value of eigenenergies to know the range of eigenenergies + + all_eigenenergies = torch.hstack(total_eigenenergies) + minE = torch.min(all_eigenenergies) + maxE = torch.max(all_eigenenergies) + print(f"The lowest eigenenergy in the dataset is {minE:.3}") + print(f"The highest eigenenergy in the dataset is {maxE:.3}") + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + The lowest eigenenergy in the dataset is -20.5 + The highest eigenenergy in the dataset is 8.65 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 92-102 + +Step 1: Constructing the DOS with different energy references +------------------------------------------------------------------------------------------ +1) Construct the DOS using the original reference +2) Calculate the Fermi level from the DOS +3) Build a set of eigenenergies, with the energy reference set to the fermi level +4) Truncate the DOS energy window so that the DOS is well-defined at each point +5) Construct the DOS in the truncated energy window under both references +6) Construct Splines for the DOS to facilitate interpolation during model training + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. GENERATED FROM PYTHON SOURCE LINES 105-110 + +1) Construct the DOS using the original reference +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The DOS will first be constructed from the full set of eigenenergies to +determine the Fermi level of each structure. The original reference is the +Average Hartree Potential in this example. + +.. GENERATED FROM PYTHON SOURCE LINES 110-152 + +.. code-block:: Python + + + # To ensure that all the eigenenergies are fully represented after + # gaussian broadening, the energy axis of the DOS extends + # 3eV wider than the range of values for the eigenenergies + energy_lower_bound = minE - 1.5 + energy_upper_bound = maxE + 1.5 + + # Gaussian Smearing for the eDOS, 0.3eV is the appropriate value for this dataset + + sigma = torch.tensor(0.3) + energy_interval = 0.05 + # energy axis, with a grid interval of 0.05 eV + + x_dos = torch.arange(energy_lower_bound, energy_upper_bound, energy_interval) + print( + f"The energy axis ranges from {energy_lower_bound:.3} to \ + {energy_upper_bound:.3}, consisting of {len(x_dos)} grid points" + ) + + # normalization factor for each DOS, factor of 2 is included + # because each eigenenergy can be occupied by 2 electrons + + normalization = 2 * ( + 1 / torch.sqrt(2 * torch.tensor(np.pi) * sigma**2) / n_atoms / k_normalization + ) + + total_edos = [] + + for structure_eigenenergies in total_eigenenergies: + e_dos = torch.sum( + # Builds a gaussian on each eigenenergy + # and calculates the value on each grid point + torch.exp(-0.5 * ((x_dos - structure_eigenenergies.view(-1, 1)) / sigma) ** 2), + dim=0, + ) + total_edos.append(e_dos) + + total_edos = torch.vstack(total_edos) + total_edos = (total_edos.T * normalization).T + + print(f"The final shape of all the DOS in the dataset is: {list(total_edos.shape)}") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + The energy axis ranges from -22.0 to 10.1, consisting of 644 grid points + The final shape of all the DOS in the dataset is: [104, 644] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 153-159 + +2) Calculate the Fermi level from the DOS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Now we integration the DOS, and then use cubic interpolation and brentq +to calculate the fermi level. Since only the 4 valence electrons in Silicon +are represented in this energy range, we take the point where the DOS integrates +to 4 as the fermi level. + +.. GENERATED FROM PYTHON SOURCE LINES 159-174 + +.. code-block:: Python + + + fermi_levels = [] + total_i_edos = torch.cumulative_trapezoid( + total_edos, x_dos, axis=1 + ) # Integrate the DOS along the energy axis + for i in total_i_edos: + interpolated = interp1d( + x_dos[:-1], i - 4, kind="cubic", copy=True, assume_sorted=True + ) # We use i-4 because Silicon has 4 electrons in this energy range + Ef = brentq( + interpolated, x_dos[0] + 0.1, x_dos[-1] - 0.1 + ) # Fermi Level is the point where the (integrated DOS - 4) = 0 + # 0.1 is added and subtracted to prevent brentq from going out of range + fermi_levels.append(Ef) + fermi_levels = torch.tensor(fermi_levels) + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 175-179 + +3) Build a set of eigenenergies, with the energy reference set to the fermi level +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Using the fermi levels, we are now able to change the energy reference +of the eigenenergies to the fermi level + +.. GENERATED FROM PYTHON SOURCE LINES 179-192 + +.. code-block:: Python + + + total_eigenenergies_Ef = [] + for index, energies in enumerate(total_eigenenergies): + total_eigenenergies_Ef.append(energies - fermi_levels[index]) + + all_eigenenergies_Ef = torch.hstack(total_eigenenergies_Ef) + + minE_Ef = torch.min(all_eigenenergies_Ef) + maxE_Ef = torch.max(all_eigenenergies_Ef) + print(f"The lowest eigenenergy using the fermi level energy reference is {minE_Ef:.3}") + print(f"The highest eigenenergy using the fermi level energy reference is {maxE_Ef:.3}") + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + The lowest eigenenergy using the fermi level energy reference is -13.8 + The highest eigenenergy using the fermi level energy reference is 14.9 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 193-198 + +4) Truncate the DOS energy window so that the DOS is well-defined at each point +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +With the fermi levels, we can also truncate the energy window for DOS prediction. +In this example, we truncate the energy window such that it is 3eV above +the highest Fermi level in the dataset. + +.. GENERATED FROM PYTHON SOURCE LINES 198-204 + +.. code-block:: Python + + + # For the Average Hartree Potential energy reference + x_dos_H = torch.arange(minE - 1.5, max(fermi_levels) + 3, energy_interval) + + # For the Fermi Level Energy Reference, all the Fermi levels in the dataset is 0eV + x_dos_Ef = torch.arange(minE_Ef - 1.5, 3, energy_interval) + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 205-210 + +5) Construct the DOS in the truncated energy window under both references +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Here we construct 2 different targets where they differ in the energy reference +chosen. These targets will then be treated as different datasets for the model +to learn on. + +.. GENERATED FROM PYTHON SOURCE LINES 210-244 + +.. code-block:: Python + + + # For the Average Hartree Potential energy reference + + total_edos_H = [] + + for structure_eigenenergies_H in total_eigenenergies: + e_dos = torch.sum( + torch.exp( + -0.5 * ((x_dos_H - structure_eigenenergies_H.view(-1, 1)) / sigma) ** 2 + ), + dim=0, + ) + total_edos_H.append(e_dos) + + total_edos_H = torch.vstack(total_edos_H) + total_edos_H = (total_edos_H.T * normalization).T + + + # For the Fermi Level Energy Reference + + total_edos_Ef = [] + + for structure_eigenenergies_Ef in total_eigenenergies_Ef: + e_dos = torch.sum( + torch.exp( + -0.5 * ((x_dos_Ef - structure_eigenenergies_Ef.view(-1, 1)) / sigma) ** 2 + ), + dim=0, + ) + total_edos_Ef.append(e_dos) + + total_edos_Ef = torch.vstack(total_edos_Ef) + total_edos_Ef = (total_edos_Ef.T * normalization).T + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 245-251 + +6) Construct Splines for the DOS to facilitate interpolation during model training +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Building Cubic Hermite Splines on the DOS on the truncated energy window +to facilitate interpolation during training. Cubic Hermite Splines takes +in information on the value and derivative of a function at a point to build splines. +Thus, we will have to compute both the value and derivative at each spline position + +.. GENERATED FROM PYTHON SOURCE LINES 251-310 + +.. code-block:: Python + + + + # Functions to compute the value and derivative of the DOS at each energy value, x + def edos_value(x, eigenenergies, normalization): + e_dos_E = ( + torch.sum( + torch.exp(-0.5 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2), dim=0 + ) + * normalization + ) + + return e_dos_E + + + def edos_derivative(x, eigenenergies, normalization): + dfn_dos_E = ( + torch.sum( + torch.exp(-0.5 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2) + * (-1 * ((x - eigenenergies.view(-1, 1)) / sigma) ** 2), + dim=0, + ) + * normalization + ) + + return dfn_dos_E + + + total_splines_H = [] + # the splines have a higher energy range in case the shift is high + spline_positions_H = torch.arange(minE - 2, max(fermi_levels) + 6, energy_interval) + + for index, structure_eigenenergies_H in enumerate(total_eigenenergies): + e_dos_H = edos_value( + spline_positions_H, structure_eigenenergies_H, normalization[index] + ) + e_dos_H_grad = edos_derivative( + spline_positions_H, structure_eigenenergies_H, normalization[index] + ) + spliner = CubicHermiteSpline(spline_positions_H, e_dos_H, e_dos_H_grad) + total_splines_H.append(torch.tensor(spliner.c)) + + total_splines_H = torch.stack(total_splines_H) + + total_splines_Ef = [] + spline_positions_Ef = torch.arange(minE_Ef - 2, 6, energy_interval) + + for index, structure_eigenenergies_Ef in enumerate(total_eigenenergies_Ef): + e_dos_Ef = edos_value( + spline_positions_Ef, structure_eigenenergies_Ef, normalization[index] + ) + e_dos_Ef_grad = edos_derivative( + spline_positions_Ef, structure_eigenenergies_Ef, normalization[index] + ) + spliner = CubicHermiteSpline(spline_positions_Ef, e_dos_Ef, e_dos_Ef_grad) + total_splines_Ef.append(torch.tensor(spliner.c)) + + total_splines_Ef = torch.stack(total_splines_Ef) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 311-314 + +We have stored the splines coefficients (spliner.c) as torch tensors, +as such as we will need to write a function to evaluate the DOS from +the splines positions and coefficients. + +.. GENERATED FROM PYTHON SOURCE LINES 314-347 + +.. code-block:: Python + + + + def evaluate_spline(spline_coefs, spline_positions, x): + """ + spline_coefs: shape of (n x 4 x spline_positions) + + return value: shape of (n x x) + + x : shape of (n x n_points) + """ + interval = torch.round( + spline_positions[1] - spline_positions[0], decimals=4 + ) # get spline grid intervals + x = torch.clamp( + x, min=spline_positions[0], max=spline_positions[-1] - 0.0005 + ) # restrict x to fall within the spline interval + # 0.0005 is substracted to combat errors arising from precision + indexes = torch.floor( + (x - spline_positions[0]) / interval + ).long() # Obtain the index for the appropriate spline coefficients + expanded_index = indexes.unsqueeze(dim=1).expand(-1, 4, -1) + x_1 = x - spline_positions[indexes] + x_2 = x_1 * x_1 + x_3 = x_2 * x_1 + x_0 = torch.ones_like(x_1) + x_powers = torch.stack([x_3, x_2, x_1, x_0]).permute(1, 0, 2) + value = torch.sum( + torch.mul(x_powers, torch.gather(spline_coefs, 2, expanded_index)), axis=1 + ) + + return value # returns the value of the DOS at the energy positions, x. + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 348-350 + +Lets look at the accuracy of the splines. +Test 1: Ability to reproduce the correct values at the default x_dos positions + +.. GENERATED FROM PYTHON SOURCE LINES 350-361 + +.. code-block:: Python + + + shifts = torch.zeros(n_structures) + x_dos_splines = x_dos_H + shifts.view(-1, 1) + spline_dos_H = evaluate_spline(total_splines_H, spline_positions_H, x_dos_splines) + + plt.plot(x_dos_H, total_edos_H[0], color="red", label="True DOS") + plt.plot(x_dos_H, spline_dos_H[0], color="blue", linestyle="--", label="Spline DOS") + plt.legend() + plt.xlabel("Energy [eV]") + plt.ylabel("DOS") + print("Both lines lie on each other") + + + +.. image-sg:: /examples/dos-align/images/sphx_glr_dos-align_001.png + :alt: dos align + :srcset: /examples/dos-align/images/sphx_glr_dos-align_001.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Both lines lie on each other + + + + +.. GENERATED FROM PYTHON SOURCE LINES 362-363 + +Test 2: Ability to reproduce the correct values at the shifted x_dos positions + +.. GENERATED FROM PYTHON SOURCE LINES 363-374 + +.. code-block:: Python + + + shifts = torch.zeros(n_structures) + 0.3 + x_dos_splines = x_dos_Ef + shifts.view(-1, 1) + spline_dos_Ef = evaluate_spline(total_splines_Ef, spline_positions_Ef, x_dos_splines) + + plt.plot(x_dos_Ef, total_edos_Ef[0], color="red", label="True DOS") + plt.plot(x_dos_Ef, spline_dos_Ef[0], color="blue", linestyle="--", label="Spline DOS") + plt.legend() + plt.xlabel("Energy [eV]") + plt.ylabel("DOS") + print("Both spectras look very similar") + + + +.. image-sg:: /examples/dos-align/images/sphx_glr_dos-align_002.png + :alt: dos align + :srcset: /examples/dos-align/images/sphx_glr_dos-align_002.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Both spectras look very similar + + + + +.. GENERATED FROM PYTHON SOURCE LINES 375-380 + +Step 2: Compute SOAP power spectrum for the dataset +------------------------------------------------------------------------------------------ + +We first define the hyperparameters to compute the +SOAP power spectrum using rascaline. + +.. GENERATED FROM PYTHON SOURCE LINES 381-401 + +.. code-block:: Python + + + HYPER_PARAMETERS = { + "cutoff": 4.0, + "max_radial": 8, + "max_angular": 6, + "atomic_gaussian_width": 0.45, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {}}, + "cutoff_function": { + "Step": {}, + }, + "radial_scaling": { + "Willatt2018": { + "exponent": 5, + "rate": 1, + "scale": 3.0, + }, + }, + } + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 402-403 + +We feed the Hyperparameters into rascaline to compute the SOAP Power spectrum + +.. GENERATED FROM PYTHON SOURCE LINES 404-419 + +.. code-block:: Python + + + + calculator = SoapPowerSpectrum(**HYPER_PARAMETERS) + R_total_soap = calculator.compute(structures) + # Transform the tensormap to a single block containing a dense representation + R_total_soap.keys_to_samples("species_center") + R_total_soap.keys_to_properties(["species_neighbor_1", "species_neighbor_2"]) + + # Now we extract the data tensor from the single block + total_atom_soap = [] + for structure_i in range(n_structures): + a_i = R_total_soap.block(0).samples["structure"] == structure_i + total_atom_soap.append(torch.tensor(R_total_soap.block(0).values[a_i, :])) + + total_soap = torch.stack(total_atom_soap) + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 420-430 + +Step 3: Building a Simple MLP Model +--------------------------------------------------------------------- + +1) Split the data into Training, Validation and Test +2) Define the dataloader and the Model Architecture +3) Define relevant loss functions for training and inference +4) Define the training loop +5) Evaluate the model + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. GENERATED FROM PYTHON SOURCE LINES 433-436 + +1) Split the data into Training, Validation and Test +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We will first split the data in a 7:1:2 manner, corresponding to train, val and test. + +.. GENERATED FROM PYTHON SOURCE LINES 436-445 + +.. code-block:: Python + + np.random.seed(0) + train_index = np.arange(n_structures) + np.random.shuffle(train_index) + test_mark = int(0.8 * n_structures) + val_mark = int(0.7 * n_structures) + test_index = train_index[test_mark:] + val_index = train_index[val_mark:test_mark] + train_index = train_index[:val_mark] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 446-449 + +2) Define the dataloader and the Model Architecture +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We will now build a dataloader and dataset to facillitate training the model batchwise + +.. GENERATED FROM PYTHON SOURCE LINES 449-525 + +.. code-block:: Python + + + + def generate_atomstructure_index(n_atoms_per_structure): + """Generate a sequence of indices for each atom in the structure. + The indices correspond to index of the structure that the atom belongs to + + Args: + n_atoms_per_structure ([array]): + [Array containing the number of atoms each structure contains] + + Return s: + [tensor]: [Total index, matching atoms to structure] + """ + # n_structures = len(n_atoms_per_structure) + total_index = [] + for i, atoms in enumerate(n_atoms_per_structure): + indiv_index = torch.zeros(atoms) + i + total_index.append(indiv_index) + total_index = torch.hstack(total_index) + return total_index.long() + + + class AtomicDataset(Dataset): + def __init__(self, features, n_atoms_per_structure): + self.features = features + self.n_structures = len(n_atoms_per_structure) + self.n_atoms_per_structure = n_atoms_per_structure + self.index = generate_atomstructure_index(self.n_atoms_per_structure) + assert torch.sum(n_atoms_per_structure) == len(features) + + def __len__(self): + return self.n_structures + + def __getitem__(self, idx): + if isinstance(idx, list): # If a list of indexes is given + feature_indexes = [] + + for i in idx: + feature_indexes.append((self.index == i).nonzero(as_tuple=True)[0]) + + feature_indexes = torch.hstack(feature_indexes) + + return ( + self.features[feature_indexes], + idx, + generate_atomstructure_index(self.n_atoms_per_structure[idx]), + ) + + else: + feature_indexes = (self.index == idx).nonzero(as_tuple=True)[0] + return ( + self.features[feature_indexes], + idx, + self.n_atoms_per_structure[idx], + ) + + + def collate( + batch, + ): # Defines how to collate the outputs of the __getitem__ function at each batch + for x, idx, index in batch: + return (x, idx, index) + + + x_train = torch.flatten(total_soap[train_index], 0, 1).float() + total_atomic_soaps = torch.vstack(total_atom_soap).float() + train_features = AtomicDataset(x_train, n_atoms[train_index]) + full_atomstructure_index = generate_atomstructure_index(n_atoms) + # Will be required later to collate atomic predictions into structural predictions + + # Build a Dataloader that samples from the AtomicDataset in random batches + Sampler = RandomSampler(train_features) + BSampler = BatchSampler(Sampler, batch_size=32, drop_last=False) + traindata_loader = DataLoader(train_features, sampler=BSampler, collate_fn=collate) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 526-531 + +We will now define a simple three layer MLP model, consisting of three layers. +The align keyword is used to indicate that the energy reference will be optimized +during training. The alignment parameter refers to the adjustments made to the +initial energy referenced and will be initialized as zeros. + + +.. GENERATED FROM PYTHON SOURCE LINES 532-553 + +.. code-block:: Python + + + + class SOAP_NN(torch.nn.Module): + def __init__(self, input_dims, L1, n_train, target_dims, align): + super(SOAP_NN, self).__init__() + self.target_dims = target_dims + self.fc1 = torch.nn.Linear(input_dims, L1) + self.fc2 = torch.nn.Linear(L1, target_dims) + self.silu = torch.nn.SiLU() + self.align = align + if align: + initial_alignment = torch.zeros(n_train) + self.alignment = torch.nn.parameter.Parameter(initial_alignment) + + def forward(self, x): + result = self.fc1(x) + result = self.silu(result) + result = self.fc2(result) + return result + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 554-562 + +We will use a small network architecture, whereby the input layer corresponds +to the size of the SOAP features, 448, the intermediate layer corresponds to +a tenth size of the input layer and the final layer corresponds +to the number of outputs. + +As a shorthand, the model that optimizes the energy reference during +training will be called the alignment model + + +.. GENERATED FROM PYTHON SOURCE LINES 562-590 + +.. code-block:: Python + + + n_outputs_H = len(x_dos_H) + n_outputs_Ef = len(x_dos_Ef) + + + Model_H = SOAP_NN( + x_train.shape[1], + x_train.shape[1] // 10, + len(train_index), + n_outputs_H, + align=False, + ) + Model_Ef = SOAP_NN( + x_train.shape[1], + x_train.shape[1] // 10, + len(train_index), + n_outputs_Ef, + align=False, + ) + Model_Align = SOAP_NN( + x_train.shape[1], + x_train.shape[1] // 10, + len(train_index), + n_outputs_Ef, + align=True, + ) + # The alignment model takes the fermi level energy reference as the starting point + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 591-595 + +3) Define relevant loss functions for training and inference +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We will now define some loss functions that will be useful when we implement +the model training loop later and during model evaluation on the test set. + +.. GENERATED FROM PYTHON SOURCE LINES 595-710 + +.. code-block:: Python + + + + def t_get_mse(a, b, xdos): + """Compute mean error between two Density of States. + The mean error is integrated across the entire energy grid + to provide a single value to characterize the error + + Args: + a ([tensor]): [Predicted DOS] + b ([tensor]): [True DOS] + xdos ([tensor], optional): [Energy axis of DOS] + + Returns: + [float]: [MSE] + """ + if len(a.size()) > 1: + mse = (torch.trapezoid((a - b) ** 2, xdos, axis=1)).mean() + else: + mse = (torch.trapezoid((a - b) ** 2, xdos, axis=0)).mean() + return mse + + + def t_get_rmse(a, b, xdos): + """Compute root mean squared error between two Density of States . + + Args: + a ([tensor]): [Predicted DOS] + b ([tensor]): [True DOS] + xdos ([tensor], optional): [Energy axis of DOS] + + Raises: + ValueError: [Occurs if tensor shapes are mismatched] + + Returns: + [float]: [RMSE or %RMSE] + """ + + if len(a.size()) > 1: + rmse = torch.sqrt((torch.trapezoid((a - b) ** 2, xdos, axis=1)).mean()) + else: + rmse = torch.sqrt((torch.trapezoid((a - b) ** 2, xdos, axis=0)).mean()) + return rmse + + + def Opt_RMSE_spline(y_pred, xdos, target_splines, spline_positions, n_epochs): + """Evaluates RMSE on the optimal shift of energy axis. + The optimal shift is found via gradient descent after a gridsearch is performed. + + Args: + y_pred ([tensor]): [Prediction/s of DOS] + xdos ([tensor]): [Energy axis] + target_splines ([tensor]): [Contains spline coefficients] + spline_positions ([tensor]): [Contains spline positions] + n_epochs ([int]): [Number of epochs to run for Gradient Descent] + + Returns: + [rmse([float]), optimal_shift[tensor]]: + [RMSE on optimal shift, the optimal shift itself] + + """ + optim_search_mse = [] + offsets = torch.arange(-2, 2, 0.1) + # Grid-search is first done to reduce number of epochs needed for + # gradient descent, typically 50 epochs will be sufficient + # if searching within 0.1 + with torch.no_grad(): + for offset in offsets: + shifts = torch.zeros(y_pred.shape[0]) + offset + shifted_target = evaluate_spline( + target_splines, spline_positions, xdos + shifts.view(-1, 1) + ) + loss_i = ((y_pred - shifted_target) ** 2).mean(dim=1) + optim_search_mse.append(loss_i) + optim_search_mse = torch.vstack(optim_search_mse) + min_index = torch.argmin(optim_search_mse, dim=0) + optimal_offset = offsets[min_index] + + offset = optimal_offset + + shifts = torch.nn.parameter.Parameter(offset.float()) + opt_adam = torch.optim.Adam([shifts], lr=1e-2) + best_error = torch.zeros(len(shifts)) + 100 + best_shifts = shifts.clone() + for _ in range(n_epochs): + shifted_target = evaluate_spline( + target_splines, spline_positions, xdos + shifts.view(-1, 1) + ).detach() + + def closure(): + opt_adam.zero_grad() + shifted_target = evaluate_spline( + target_splines, spline_positions, xdos + shifts.view(-1, 1) + ) + loss_i = ((y_pred - shifted_target) ** 2).mean() + loss_i.backward(gradient=torch.tensor(1), inputs=shifts) + return loss_i + + opt_adam.step(closure) + + with torch.no_grad(): + each_loss = ((y_pred - shifted_target) ** 2).mean(dim=1).float() + index = each_loss < best_error + best_error[index] = each_loss[index].clone() + best_shifts[index] = shifts[index].clone() + + # Evaluate + + optimal_shift = best_shifts + shifted_target = evaluate_spline( + target_splines, spline_positions, xdos + optimal_shift.view(-1, 1) + ) + rmse = t_get_rmse(y_pred, shifted_target, xdos) + return rmse, optimal_shift + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 711-717 + +4) Define the training loop +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We will now define the model training loop, for simplicity we will only +train each model for a fixed number of epochs, learning rate, and batch_size. +The training and validation error at each epoch will be saved. + +.. GENERATED FROM PYTHON SOURCE LINES 718-823 + +.. code-block:: Python + + + + def train_model(model_to_train, fixed_DOS, structure_splines, spline_positions, x_dos): + """Trains a model for 500 epochs + + Args: + model_to_train ([torch.nn.Module]): [ML Model] + fixed_DOS ([tensor]): [Contains the DOS at a fixed energy reference, + useful for models that don't optimize the energy reference] + structure_splines ([tensor]): [Contains spline coefficients] + spline_positions ([tensor]): [Contains spline positions] + x_dos ([tensor]): [Energy axis for the prediction] + + Returns: + [train_loss_history([tensor]), + val_loss_history[tensor], + structure_results[tensor]]: + + [Respective loss histories and final structure predictions] + """ + lr = 1e-2 + n_epochs = 500 + + opt = torch.optim.Adam(model_to_train.parameters(), lr=lr) + + train_loss_history = [] + val_loss_history = [] + + for _epoch in range(n_epochs): + for x_data, idx, index in traindata_loader: + opt.zero_grad() + predictions = model_to_train.forward(x_data) + structure_results = torch.zeros([len(idx), model_to_train.target_dims]) + # Sum atomic predictions in each structure + structure_results = structure_results.index_add_( + 0, index, predictions + ) / n_atoms[train_index[idx]].view(-1, 1) + if model_to_train.align: + alignment = model_to_train.alignment + alignment = alignment - torch.mean(alignment) + # Enforce that the alignments have a mean of zero since a constant + # value across the dataset is meaningless when optimizing the + # relative energy reference + target = evaluate_spline( + structure_splines[train_index[idx]], + spline_positions, + x_dos + alignment[idx].view(-1, 1), + ) # Shifts the target based on the alignment value + pred_loss = t_get_mse(structure_results, target, x_dos) + pred_loss.backward() + else: + pred_loss = t_get_mse( + structure_results, fixed_DOS[train_index[idx]], x_dos + ) + pred_loss.backward() + + opt.step() + with torch.no_grad(): + all_pred = model_to_train.forward(total_atomic_soaps.float()) + structure_results = torch.zeros([n_structures, model_to_train.target_dims]) + structure_results = structure_results.index_add_( + 0, full_atomstructure_index, all_pred + ) / (n_atoms).view(-1, 1) + if model_to_train.align: + # Evaluate model on optimal shift as there is no information + # regarding the shift from the fermi level energy reference + # during inference + + alignment = model_to_train.alignment + alignment = alignment - torch.mean(alignment) + target = evaluate_spline( + structure_splines[train_index], + spline_positions, + x_dos + alignment.view(-1, 1), + ) + + train_loss = t_get_rmse(structure_results[train_index], target, x_dos) + val_loss, val_shifts = Opt_RMSE_spline( + structure_results[val_index], + x_dos, + structure_splines[val_index], + spline_positions, + 50, + ) + + else: + train_loss = t_get_rmse( + structure_results[train_index], fixed_DOS[train_index], x_dos + ) + val_loss = t_get_rmse( + structure_results[val_index], fixed_DOS[val_index], x_dos + ) + + train_loss_history.append(train_loss) + val_loss_history.append(val_loss) + train_loss_history = torch.tensor(train_loss_history) + val_loss_history = torch.tensor(val_loss_history) + return ( + train_loss_history, + val_loss_history, + structure_results, + ) + # returns the loss history and the final set of predictions + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 824-836 + +.. code-block:: Python + + + H_trainloss, H_valloss, H_predictions = train_model( + Model_H, total_edos_H, total_splines_H, spline_positions_H, x_dos_H + ) + + Ef_trainloss, Ef_valloss, Ef_predictions = train_model( + Model_Ef, total_edos_Ef, total_splines_Ef, spline_positions_Ef, x_dos_Ef + ) + + Align_trainloss, Align_valloss, Align_predictions = train_model( + Model_Align, total_edos_Ef, total_splines_Ef, spline_positions_Ef, x_dos_Ef + ) + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 837-839 + +Lets plot the train loss histories to compare their learning behaviour + + +.. GENERATED FROM PYTHON SOURCE LINES 839-851 + +.. code-block:: Python + + + epochs = np.arange(500) + + + plt.plot(epochs, H_trainloss, color="red", label="Avg Hartree Potential") + plt.plot(epochs, Ef_trainloss, color="blue", label="Fermi Level") + plt.plot(epochs, Align_trainloss, color="green", label="Optimized Reference") + plt.legend() + plt.yscale(value="log") + plt.xlabel("Epochs") + plt.ylabel("RMSE") + plt.title("Train Loss vs Epoch") + + + +.. image-sg:: /examples/dos-align/images/sphx_glr_dos-align_003.png + :alt: Train Loss vs Epoch + :srcset: /examples/dos-align/images/sphx_glr_dos-align_003.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + Text(0.5, 1.0, 'Train Loss vs Epoch') + + + +.. GENERATED FROM PYTHON SOURCE LINES 852-854 + +Lets plot the val loss histories to compare their learning behaviour + + +.. GENERATED FROM PYTHON SOURCE LINES 854-866 + +.. code-block:: Python + + + + plt.plot(epochs, H_valloss, color="red", label="Avg Hartree Potential") + plt.plot(epochs, Ef_valloss, color="blue", label="Fermi Level") + plt.plot(epochs, Align_valloss, color="green", label="Optimized Reference") + plt.legend() + plt.yscale(value="log") + plt.xlabel("Epochs") + plt.ylabel("RMSE") + plt.title("Validation Loss vs Epoch") + + + + + +.. image-sg:: /examples/dos-align/images/sphx_glr_dos-align_004.png + :alt: Validation Loss vs Epoch + :srcset: /examples/dos-align/images/sphx_glr_dos-align_004.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + Text(0.5, 1.0, 'Validation Loss vs Epoch') + + + +.. GENERATED FROM PYTHON SOURCE LINES 867-872 + +5) Evaluate the model +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We will now evaluate the model performance on the test set +based on the model predictions we obtained previously + + +.. GENERATED FROM PYTHON SOURCE LINES 873-904 + +.. code-block:: Python + + + H_testloss = Opt_RMSE_spline( + H_predictions[test_index], + x_dos_H, + total_splines_H[test_index], + spline_positions_H, + 200, + ) # We use 200 epochs just so it the error a little bit more converged + Ef_testloss = Opt_RMSE_spline( + Ef_predictions[test_index], + x_dos_Ef, + total_splines_Ef[test_index], + spline_positions_Ef, + 200, + ) # We use 200 epochs just so it the error a little bit more converged + Align_testloss = Opt_RMSE_spline( + Align_predictions[test_index], + x_dos_Ef, + total_splines_Ef[test_index], + spline_positions_Ef, + 200, + ) # We use 200 epochs just so it the error a little bit more converged + + print(f"Test RMSE for average Hartree Potential: {H_testloss[0].item():.3}") + print(f"Test RMSE for Fermi Level: {Ef_testloss[0].item():.3}") + print(f"Test RMSE for Optimized Reference: {Align_testloss[0].item():.3}") + + print( + "The difference in effectiveness between the Optimized Reference \ + and the Fermi Level will increase with more epochs" + ) + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Test RMSE for average Hartree Potential: 0.058 + Test RMSE for Fermi Level: 0.0464 + Test RMSE for Optimized Reference: 0.0391 + The difference in effectiveness between the Optimized Reference and the Fermi Level will increase with more epochs + + + + +.. GENERATED FROM PYTHON SOURCE LINES 905-914 + +Plot Training DOSes at different energy reference to visualize +the impact of the energy reference. From the plots we can see +that the optimized energy reference has better alignment of +common spectral patterns across the dataset + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Average Hartree Energy Reference + + +.. GENERATED FROM PYTHON SOURCE LINES 915-923 + +.. code-block:: Python + + + for i in total_edos_H[train_index]: + plt.plot(x_dos_H, i, color="C0", alpha=0.6) + plt.title("Energy Reference - Average Hartree Potential") + plt.xlabel("Energy [eV]") + plt.ylabel("DOS") + print("The DOSes, despite looking similar, are offset along the energy axis") + + + + +.. image-sg:: /examples/dos-align/images/sphx_glr_dos-align_005.png + :alt: Energy Reference - Average Hartree Potential + :srcset: /examples/dos-align/images/sphx_glr_dos-align_005.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + The DOSes, despite looking similar, are offset along the energy axis + + + + +.. GENERATED FROM PYTHON SOURCE LINES 924-925 + +Fermi Level Energy Reference + +.. GENERATED FROM PYTHON SOURCE LINES 925-932 + +.. code-block:: Python + + for i in total_edos_Ef[train_index]: + plt.plot(x_dos_Ef, i, color="C0", alpha=0.6) + plt.title("Energy Reference - Fermi Level") + plt.xlabel("Energy [eV]") + plt.ylabel("DOS") + + print("It is better aligned but still quite some offset") + + + +.. image-sg:: /examples/dos-align/images/sphx_glr_dos-align_006.png + :alt: Energy Reference - Fermi Level + :srcset: /examples/dos-align/images/sphx_glr_dos-align_006.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + It is better aligned but still quite some offset + + + + +.. GENERATED FROM PYTHON SOURCE LINES 933-934 + +Optimized Energy Reference + +.. GENERATED FROM PYTHON SOURCE LINES 934-948 + +.. code-block:: Python + + shifts = Model_Align.alignment.detach() + shifts = shifts - torch.mean(shifts) + x_dos_splines = x_dos_Ef + shifts.view(-1, 1) + total_edos_align = evaluate_spline( + total_splines_Ef[train_index], spline_positions_Ef, x_dos_splines + ) + + for i in total_edos_align: + plt.plot(x_dos_Ef, i, color="C0", alpha=0.6) + plt.title("Energy Reference - Optimized") + plt.xlabel("Energy [eV]") + plt.ylabel("DOS") + print("The DOS alignment is better under the optimized energy reference") + print("The difference will increase with more training epochs") + + + +.. image-sg:: /examples/dos-align/images/sphx_glr_dos-align_007.png + :alt: Energy Reference - Optimized + :srcset: /examples/dos-align/images/sphx_glr_dos-align_007.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + The DOS alignment is better under the optimized energy reference + The difference will increase with more training epochs + + + + + +.. rst-class:: sphx-glr-timing + + **Total running time of the script:** (1 minutes 56.652 seconds) + + +.. _sphx_glr_download_examples_dos-align_dos-align.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + .. container:: sphx-glr-download + + :download:`Download Conda environment file: environment.yml ` + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: dos-align.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: dos-align.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ + diff --git a/latest/_sources/examples/dos-align/sg_execution_times.rst.txt b/latest/_sources/examples/dos-align/sg_execution_times.rst.txt new file mode 100644 index 00000000..6f00f577 --- /dev/null +++ b/latest/_sources/examples/dos-align/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_examples_dos-align_sg_execution_times: + + +Computation times +================= +**01:56.652** total execution time for 1 file **from examples/dos-align**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_dos-align_dos-align.py` (``dos-align.py``) + - 01:56.652 + - 0.0 diff --git a/latest/_sources/examples/gaas-map/gaas-map.rst.txt b/latest/_sources/examples/gaas-map/gaas-map.rst.txt new file mode 100644 index 00000000..1900f8a7 --- /dev/null +++ b/latest/_sources/examples/gaas-map/gaas-map.rst.txt @@ -0,0 +1,436 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/gaas-map/gaas-map.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_gaas-map_gaas-map.py: + + +PCA/PCovR Visualization for the rattled GaAs training dataset +============================================================= + +:Authors: Michele Ceriotti `@ceriottm `_, + Giulio Imbalzano + +This example uses ``rascaline`` and ``metatensor`` to compute +structural properties for the structures in a training for a ML model. +These are then used with simple dimensionality reduction algorithms +(implemented in ``sklearn`` and ``skmatter``) to obtain a simplified +description of the dataset, that is then visualized using +``chemiscope``. + +.. GENERATED FROM PYTHON SOURCE LINES 16-33 + +.. code-block:: Python + + + import os + + import ase + import ase.io + import chemiscope + import numpy as np + import requests + from matplotlib import pyplot as plt + from metatensor import mean_over_samples + from rascaline import AtomicComposition, SoapPowerSpectrum + from sklearn.decomposition import PCA + from sklearn.linear_model import RidgeCV + from skmatter.decomposition import PCovR + from skmatter.preprocessing import StandardFlexibleScaler + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 34-40 + +First, we load the structures, extracting some of the properties for +more convenient manipulation. These are +:math:`\mathrm{Ga}_x\mathrm{As}_{1-x}` structures used in `Imbalzano & +Ceriotti (2021) `__ to +train a ML potential to describe the full composition range. + + +.. GENERATED FROM PYTHON SOURCE LINES 40-54 + +.. code-block:: Python + + + filename = "gaas_training.xyz" + if not os.path.exists(filename): + url = f"https://zenodo.org/records/10566825/files/{filename}" + response = requests.get(url) + response.raise_for_status() + with open(filename, "wb") as f: + f.write(response.content) + + structures = ase.io.read(filename, ":") + energy = np.array([f.info["energy"] for f in structures]) + natoms = np.array([len(f) for f in structures]) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 55-68 + +Remove atomic energy baseline +----------------------------- + +Energies from an electronic structure calculation contain a very large +“self” contributions from the atoms, which can obscure the important +differences in cohesive energies between structures. We can build an +approximate model based on the chemical nature of the atoms, :math:`a_i` + +.. math:: E(A) = \sum_{i\in A} e_{a_i} + +where :math:`e_a` are atomic energies that can be determined by linear +regression. + + +.. GENERATED FROM PYTHON SOURCE LINES 68-91 + +.. code-block:: Python + + + # rascaline has an `AtomicComposition` calculator that streamlines + # this (simple) calculation + calculator = AtomicComposition(**{"per_structure": True}) + rho0 = calculator.compute(structures) + + # the descriptors are returned as a `TensorMap` object, that contains + # the composition data in a sparse storage format + rho0 + + # for easier manipulation, we extract the features as a dense vector + # of composition weights + comp_feats = rho0.keys_to_properties(["species_center"]).block(0).values + + # a one-liner to fit a linear model and compute "dressed energies" + atom_energy = ( + RidgeCV(alphas=np.geomspace(1e-8, 1e2, 20)) + .fit(comp_feats, energy) + .predict(comp_feats) + ) + cohesive_peratom = (energy - atom_energy) / natoms + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 92-95 + +The baseline makes up a large fraction of the total energy, but actually +the residual (which is the part that matters) is still large. + + +.. GENERATED FROM PYTHON SOURCE LINES 95-103 + +.. code-block:: Python + + + fig, ax = plt.subplots(1, 1, figsize=(6, 4)) + ax.plot(energy / natoms, atom_energy / natoms, "b.") + ax.set_xlabel("Energy / (eV/atom)") + ax.set_ylabel("Atomic e. / (eV/atom)") + print(f"RMSE / (eV/atom): {np.sqrt(np.mean((cohesive_peratom)**2))}") + + + + + +.. image-sg:: /examples/gaas-map/images/sphx_glr_gaas-map_001.png + :alt: gaas map + :srcset: /examples/gaas-map/images/sphx_glr_gaas-map_001.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + RMSE / (eV/atom): 0.25095652580859984 + + + + +.. GENERATED FROM PYTHON SOURCE LINES 104-111 + +Compute structural descriptors +------------------------------ + +In order to visualize the structures as a low-dimensional map, we start +by computing suitable ML descriptors. Here we have used ``rascaline`` to +evaluate average SOAP features for the structures. + + +.. GENERATED FROM PYTHON SOURCE LINES 111-138 + +.. code-block:: Python + + + # hypers for evaluating rascaline features + hypers = { + "cutoff": 4.5, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.3, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + "radial_basis": {"Gto": {"accuracy": 1e-6}}, + "center_atom_weight": 1.0, + } + calculator = SoapPowerSpectrum(**hypers) + rho2i = calculator.compute(structures) + + # neighbor types go to the keys for sparsity (this way one can + # compute a heterogeneous dataset without having blocks of zeros) + rho2i = rho2i.keys_to_samples(["species_center"]).keys_to_properties( + ["species_neighbor_1", "species_neighbor_2"] + ) + + # computes structure-level descriptors and then extracts + # the features as a dense array + rho2i_structure = mean_over_samples(rho2i, sample_names=["center", "species_center"]) + rho2i = None # releases memory + features = rho2i_structure.block(0).values + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 139-142 + +We standardize (per atom) energy and features (computed as a *mean* over +atomic environments) so that they can be combined on the same footings. + + +.. GENERATED FROM PYTHON SOURCE LINES 142-147 + +.. code-block:: Python + + + sf_energy = StandardFlexibleScaler().fit_transform(cohesive_peratom.reshape(-1, 1)) + sf_feats = StandardFlexibleScaler().fit_transform(features) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 148-160 + +PCA and PCovR projection +------------------------ + +Computes PCA projection to generate low-dimensional descriptors that +reflect structural diversity. Any other dimensionality reduction scheme +could be used in a similar fashion. + +We also compute the principal covariate regression (PCovR) descriptors, +that reduce dimensionality while combining a variance preserving +criterion with the requirement that the low-dimensional features are +capable of estimating a target quantity (here, the energy). + + +.. GENERATED FROM PYTHON SOURCE LINES 160-184 + +.. code-block:: Python + + + # PCA + pca = PCA(n_components=4) + pca_features = pca.fit_transform(sf_feats) + + fig, ax = plt.subplots(1, 1, figsize=(6, 4)) + scatter = ax.scatter(pca_features[:, 0], pca_features[:, 1], c=cohesive_peratom) + ax.set_xlabel("PCA[1]") + ax.set_ylabel("PCA[2]") + cbar = fig.colorbar(scatter, ax=ax) + cbar.set_label("energy / eV/at.") + + # computes PCovR map + pcovr = PCovR(n_components=4) + pcovr_features = pcovr.fit_transform(sf_feats, sf_energy) + + fig, ax = plt.subplots(1, 1, figsize=(6, 4)) + scatter = ax.scatter(pcovr_features[:, 0], pcovr_features[:, 1], c=cohesive_peratom) + ax.set_xlabel("PCovR[1]") + ax.set_ylabel("PCovR[2]") + cbar = fig.colorbar(scatter, ax=ax) + cbar.set_label("energy / (eV/at.)") + + + + + +.. rst-class:: sphx-glr-horizontal + + + * + + .. image-sg:: /examples/gaas-map/images/sphx_glr_gaas-map_002.png + :alt: gaas map + :srcset: /examples/gaas-map/images/sphx_glr_gaas-map_002.png + :class: sphx-glr-multi-img + + * + + .. image-sg:: /examples/gaas-map/images/sphx_glr_gaas-map_003.png + :alt: gaas map + :srcset: /examples/gaas-map/images/sphx_glr_gaas-map_003.png + :class: sphx-glr-multi-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 185-192 + +Chemiscope visualization +------------------------ + +Visualizes the structure-property map using a chemiscope widget (and +generates a .json file that can be viewed on +`chemiscope.org `__). + + +.. GENERATED FROM PYTHON SOURCE LINES 192-256 + +.. code-block:: Python + + + # extracts force data (adding considerably to the dataset size...) + force_vectors = chemiscope.ase_vectors_to_arrows(structures, scale=1) + force_vectors["parameters"]["global"]["color"] = 0x505050 + + # adds properties to the ASE frames + for i, f in enumerate(structures): + for j in range(len(pca_features[i])): + f.info["pca_" + str(j + 1)] = pca_features[i, j] + for i, f in enumerate(structures): + for j in range(len(pcovr_features[i])): + f.info["pcovr_" + str(j + 1)] = pcovr_features[i, j] + for i, f in enumerate(structures): + f.info["cohesive_energy"] = cohesive_peratom[i] + f.info["x_ga"] = comp_feats[i, 0] / comp_feats[i].sum() + + # it would also be easy to add the properties manually, this is just a dictionary + structure_properties = chemiscope.extract_properties(structures) + + cs = chemiscope.show( + frames=structures, + properties=structure_properties, + shapes={"forces": force_vectors}, + # the settings are a tad verbose, but give full control over the visualization + settings={ + "map": { + "x": {"property": "pcovr_1"}, + "y": {"property": "pcovr_2"}, + "color": {"property": "x_ga"}, + }, + "structure": [ + { + "bonds": True, + "unitCell": True, + "shape": ["forces"], + "keepOrientation": False, + } + ], + }, + meta={ + "name": "GaAs training data", + "description": """ + A collection of Ga(x)As(1-x) structures to train a MLIP, + including force and energy data. + """, + "authors": ["Giulio Imbalzano", "Michele Ceriotti"], + "references": [ + """ + G. Imbalzano and M. Ceriotti, 'Modeling the Ga/As binary system across + temperatures and compositions from first principles,' + Phys. Rev. Materials 5(6), 063804 (2021). + """, + "Original dataset: https://archive.materialscloud.org/record/2021.226", + ], + }, + ) + + # shows chemiscope if run in a jupyter environment + if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) + else: + cs.save("gaas_map.chemiscope.json.gz") + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /home/runner/work/software-cookbook/software-cookbook/.nox/gaas-map/lib/python3.11/site-packages/chemiscope/jupyter.py:245: UserWarning: chemiscope.show only works inside a jupyter notebook + warnings.warn("chemiscope.show only works inside a jupyter notebook") + + + + + +.. _sphx_glr_download_examples_gaas-map_gaas-map.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + .. container:: sphx-glr-download + + :download:`Download Conda environment file: environment.yml ` + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: gaas-map.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: gaas-map.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ + diff --git a/latest/_sources/examples/gaas-map/sg_execution_times.rst.txt b/latest/_sources/examples/gaas-map/sg_execution_times.rst.txt new file mode 100644 index 00000000..dbc1ae03 --- /dev/null +++ b/latest/_sources/examples/gaas-map/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_examples_gaas-map_sg_execution_times: + + +Computation times +================= +**00:49.570** total execution time for 1 file **from examples/gaas-map**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_gaas-map_gaas-map.py` (``gaas-map.py``) + - 00:49.570 + - 0.0 diff --git a/latest/_sources/examples/lode-linear/lode-linear.rst.txt b/latest/_sources/examples/lode-linear/lode-linear.rst.txt new file mode 100644 index 00000000..c4f72e70 --- /dev/null +++ b/latest/_sources/examples/lode-linear/lode-linear.rst.txt @@ -0,0 +1,733 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/lode-linear/lode-linear.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_lode-linear_lode-linear.py: + + +LODE Tutorial +============= + +:Authors: Philip Loche `@PicoCentauri `_, + Kevin Huguenin-Dumittan `@kvhuguenin `_ + +This tutorial explains how Long range equivariant descriptors can be constructed using +rascaline and the resulting descriptors be used to construct a linear model with +equisolve + +First, import all the necessary packages + +.. GENERATED FROM PYTHON SOURCE LINES 16-27 + +.. code-block:: Python + + + import ase.io + import matplotlib.pyplot as plt + import metatensor + import numpy as np + from equisolve.numpy.models.linear_model import Ridge + from equisolve.utils.convert import ase_to_tensormap + from rascaline import AtomicComposition, LodeSphericalExpansion, SphericalExpansion + from rascaline.utils import PowerSpectrum + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 28-43 + +Step 0: Prepare Data Set +------------------------ + +Get structures +~~~~~~~~~~~~~~ + +We take a small subset of the dimer dataset from `A. Grisafi et al., +2021 `_ +for which we additionally calculated the forces. Each structure in the +dataset contains two small organic molecules which are extended along a +certain direction in the subsequent structures. + +For speeding up the calculations we already selected the first 130 +:download:`structures ` of the charge-charge molecule +pairs. + +.. GENERATED FROM PYTHON SOURCE LINES 44-48 + +.. code-block:: Python + + + frames = ase.io.read("charge-charge.xyz", ":") + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 49-56 + +Convert target properties to metatensor format +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If we want to train models using the +`equisolve `_ package, we need to +convert the target properties (in this case, the energies and forces) +into the appropriate format #justequistorethings + +.. GENERATED FROM PYTHON SOURCE LINES 57-61 + +.. code-block:: Python + + + y = ase_to_tensormap(frames, energy="energy", forces="forces") + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 62-73 + +Step 1: Compute short-range and LODE features +--------------------------------------------- + +Define hypers and get the expansion coefficients :math:`\langle anlm | \rho_i \rangle` +and :math:`\langle anlm | V_i \rangle` + +The short-range and long-range descriptors have very similar hyperparameters. We +highlight the differences below. + +We first define the hyperparameters for the short-range (SR) part. These will be used +to create SOAP features. + +.. GENERATED FROM PYTHON SOURCE LINES 74-86 + +.. code-block:: Python + + + SR_HYPERS = { + "cutoff": 3.0, + "max_radial": 6, + "max_angular": 2, + "atomic_gaussian_width": 0.3, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {}}, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + } + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 87-88 + +And next the hyperparaters for the LODE / long-range (LR) part + +.. GENERATED FROM PYTHON SOURCE LINES 89-107 + +.. code-block:: Python + + + + LR_HYPERS = { + # Cutoff on which to project potential density + "cutoff": 3.0, + # keep max_radial slightly smaller than for SR part + "max_radial": 3, + # max_angular should be <= 4, more precisely, max_angular + potential_exponent < 10 + "max_angular": 2, + # keep at >=1, WARNING: CUBIC SCALING, do not use values <0.5 + "atomic_gaussian_width": 3.0, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {}}, + # the exponent p that determines the 1/r^p potential + "potential_exponent": 1, + } + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 108-110 + +We then use the above defined hyperparaters to define the per atom short range (sr) +and long range (sr) descriptors. + +.. GENERATED FROM PYTHON SOURCE LINES 110-115 + +.. code-block:: Python + + + calculator_sr = SphericalExpansion(**SR_HYPERS) + calculator_lr = LodeSphericalExpansion(**LR_HYPERS) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 116-136 + +Note that LODE requires periodic systems. Therefore, if the data set does not come +with periodic boundary conditions by default you can not use the data set and you will +face an error if you try to compute the features. + +As you notices the calculation of the long range features takes significant more time +compared to the sr features. + +Taking a look at the output we find that the resulting +:py:class:`metatensor.TensorMap` are quite similar in their structure. The short range +:py:class:`metatensor.TensorMap` contains more blocks due to the higher +``max_angular`` paramater we choosed above. + +Generate the rotational invariants (power spectra) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Rotationally invariant features can be obtained by taking two of the calculators that +were defines above. + +For the short-range part, we use the SOAP vector which is obtained by computing the +invariant combinations of the form :math:`\rho \otimes \rho`. + +.. GENERATED FROM PYTHON SOURCE LINES 137-142 + +.. code-block:: Python + + + ps_calculator_sr = PowerSpectrum(calculator_sr, calculator_sr) + ps_sr = ps_calculator_sr.compute(frames, gradients=["positions"]) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 143-149 + +We calculate gradients with respect to pistions by providing the +``gradients=["positions"]`` option to the +:py:meth:`rascaline.calculators.CalculatorBase.compute()` method. + +For the long-range part, we combine the long-range descriptor :math:`V` with one a +short-range density :math:`\rho` to get :math:`\rho \otimes V` features. + +.. GENERATED FROM PYTHON SOURCE LINES 150-155 + +.. code-block:: Python + + + ps_calculator_lr = PowerSpectrum(calculator_sr, calculator_lr) + ps_lr = ps_calculator_lr.compute(systems=frames, gradients=["positions"]) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 156-165 + +Step 2: Building a Simple Linear SR + LR Model with energy baselining +--------------------------------------------------------------------- + +Preprocessing (model dependent) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For our current model, we do not wish to treat the individual center and +neighbor species separately. Thus, we move the ``"species_center"`` key +into the ``sample`` direction, over which we will later sum over. + +.. GENERATED FROM PYTHON SOURCE LINES 166-171 + +.. code-block:: Python + + + ps_sr = ps_sr.keys_to_samples("species_center") + ps_lr = ps_lr.keys_to_samples("species_center") + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 172-174 + +For linear models only: Sum features up over atoms (``samples``) in the same +structure. + +.. GENERATED FROM PYTHON SOURCE LINES 175-182 + +.. code-block:: Python + + + sample_names_to_sum = ["center", "species_center"] + + ps_sr = metatensor.sum_over_samples(ps_sr, sample_names=sample_names_to_sum) + ps_lr = metatensor.sum_over_samples(ps_lr, sample_names=sample_names_to_sum) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 183-189 + +Initialize tensormaps for energy baselining +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We add a simple extra descriptor :py:class:`rascaline.AtomicComposition` that stores +how many atoms of each chemical species are contained in the structures. This is used +for energy baselining. + +.. GENERATED FROM PYTHON SOURCE LINES 190-197 + +.. code-block:: Python + + + calculator_co = AtomicComposition(per_structure=False) + descriptor_co = calculator_co.compute(frames, gradients=["positions"]) + + co = descriptor_co.keys_to_properties(["species_center"]) + co = metatensor.sum_over_samples(co, sample_names=["center"]) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 198-219 + +The :py:class:`rascaline.AtomicComposition` calculator also allows to directly perform +the the sum over center atoms by using the following lines. + +.. code:: python + + descriptor_co = AtomicComposition(per_structure=True).compute(**compute_args) + co = descriptor_co.keys_to_properties(["species_center"]) + +Stack all the features together for linear model +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A linear model on SR + LR features can be thought of as a linear model +built on a feature vector that is simply the concatenation of the SR and +LR features. + +Furthermore, energy baselining can be performed by concatenating the information about +chemical species as well. There is an metatensor function called +:py:func:`metatensor.join()` for this purpose. Formally, we can write for the SR +model. + +X_sr: :math:`1 \oplus \left(\rho \otimes \rho\right)` + +.. GENERATED FROM PYTHON SOURCE LINES 220-224 + +.. code-block:: Python + + + X_sr = metatensor.join([co, ps_sr], axis="properties") + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 225-232 + +We used the ``axis="properties"`` parameter since we want to concatenate along the +features/properties dimensions. + +For the long range model we can formerly write + +X_lr: :math:`1 \oplus \left(\rho \otimes \rho\right) \oplus \left(\rho \otimes +V\right)` + +.. GENERATED FROM PYTHON SOURCE LINES 233-237 + +.. code-block:: Python + + + X_lr = metatensor.join([co, ps_sr, ps_lr], axis="properties") + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 238-245 + +The features are now ready! Let us now perform some actual learning. Below we +initialize two instances of the :py:class:`equisolve.numpy.models.linear_model.Ridge` +class. :py:class:`equisolve.numpy.models.linear_model.Ridge` will perform a regression +with respect to ``"values"`` (energies) and ``"positions"`` gradients (forces). + +If you only want a fit with respect to energies you can remove the gradients with +``metatensor.remove_gradients()`` + +.. GENERATED FROM PYTHON SOURCE LINES 246-251 + +.. code-block:: Python + + + clf_sr = Ridge() + clf_lr = Ridge() + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 252-258 + +Split training and target data into train and test dat +------------------------------------------------------ + +Split the training and the test data by the distance :math:`r_{\rm +train}=6\,\mathrm{Å}` between the center of mass of the two molecules. A structure +with a :math:`r_{\rm train}<6 {\rm Å}` is used for training. + +.. GENERATED FROM PYTHON SOURCE LINES 259-263 + +.. code-block:: Python + + + r_cut = 6.0 + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 264-266 + +We calculate the indices from the dataset by list comprehension. The center of mass +distance is stored in the ``"distance""`` attribute. + +.. GENERATED FROM PYTHON SOURCE LINES 267-272 + +.. code-block:: Python + + + idx_train = [i for i, f in enumerate(frames) if f.info["distance"] < r_cut] + idx_test = [i for i, f in enumerate(frames) if f.info["distance"] >= r_cut] + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 273-275 + +For doing the split we define two ``Labels`` instances and combine them in a +:py:class:`List`. + +.. GENERATED FROM PYTHON SOURCE LINES 276-282 + +.. code-block:: Python + + + samples_train = metatensor.Labels(["structure"], np.reshape(idx_train, (-1, 1))) + samples_test = metatensor.Labels(["structure"], np.reshape(idx_test, (-1, 1))) + grouped_labels = [samples_train, samples_test] + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 283-284 + +That we use as input to the :py:func:`metatensor.split()` function + +.. GENERATED FROM PYTHON SOURCE LINES 285-297 + +.. code-block:: Python + + + X_sr_train, X_sr_test = metatensor.split( + X_sr, axis="samples", grouped_labels=grouped_labels + ) + + X_lr_train, X_lr_test = metatensor.split( + X_lr, axis="samples", grouped_labels=grouped_labels + ) + + y_train, y_test = metatensor.split(y, axis="samples", grouped_labels=grouped_labels) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 298-305 + +Fit the model +------------- + +For this model, we use a very simple regularization scheme where all features are +regularized in the same way (the amount being controlled by the parameter ``alpha``). +For more advanced regularization schemes (regularizing energies and forces differently +and/or the SR and LR parts differently), see further down. + +.. GENERATED FROM PYTHON SOURCE LINES 306-311 + +.. code-block:: Python + + + clf_sr.fit(X_sr_train, y_train, alpha=1e-6) + clf_lr.fit(X_lr_train, y_train, alpha=1e-6) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 312-317 + +Evaluation +---------- + +For evaluating the model we calculate the RMSEs using the ``score()`` method. With the +``parameter_key`` parameter we select which RMSE should be calculated. + +.. GENERATED FROM PYTHON SOURCE LINES 318-338 + +.. code-block:: Python + + + print( + "SR: RMSE energies = " + f"{clf_sr.score(X_sr_test, y_test, parameter_key='values')[0]:.3f} eV" + ) + print( + "SR: RMSE forces = " + f"{clf_sr.score(X_sr_test, y_test, parameter_key='positions')[0]:.3f} eV/Å" + ) + + print( + "LR: RMSE energies = " + f"{clf_lr.score(X_lr_test, y_test, parameter_key='values')[0]:.3f} eV" + ) + print( + "LR: RMSE forces = " + f"{clf_lr.score(X_lr_test, y_test, parameter_key='positions')[0]:.3f} eV/Å" + ) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + SR: RMSE energies = 0.557 eV + SR: RMSE forces = 0.188 eV/Å + LR: RMSE energies = 0.158 eV + LR: RMSE forces = 0.178 eV/Å + + + + +.. GENERATED FROM PYTHON SOURCE LINES 339-345 + +We find that the RMSE of the energy and the force of the LR model is smaller compared +to the SR model. From this we conclude that the LR model performs better for the +selection of the dataset. + +We additionally, can plot of the binding energy as a function of the distance. For the +plot we select some properties from the dataset + +.. GENERATED FROM PYTHON SOURCE LINES 346-352 + +.. code-block:: Python + + + dist = np.array([f.info["distance"] for f in frames]) + energies = np.array([f.info["energy"] for f in frames]) + monomer_energies = np.array([f.info["energyA"] + f.info["energyB"] for f in frames]) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 353-354 + +and select only the indices corresponding to our test set. + +.. GENERATED FROM PYTHON SOURCE LINES 358-359 + +Next we calculate the predicted SR and LR ``TensorMaps``. + +.. GENERATED FROM PYTHON SOURCE LINES 360-365 + +.. code-block:: Python + + + y_sr_pred = clf_sr.predict(X_sr) + y_lr_pred = clf_lr.predict(X_lr) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 366-367 + +And, finally perform the plot. + +.. GENERATED FROM PYTHON SOURCE LINES 368-396 + +.. code-block:: Python + + + plt.scatter( + dist, y.block().values[:, 0] - monomer_energies, label="target data", color="black" + ) + + plt.scatter( + dist, + y_sr_pred.block().values[:, 0] - monomer_energies, + label="short range model", + marker="x", + ) + + plt.scatter( + dist, + y_lr_pred.block().values[:, 0] - monomer_energies, + label="long range model", + marker="s", + facecolor="None", + edgecolor="orange", + ) + + plt.xlabel("center of mass distance in Å") + plt.ylabel(r"$E - E_\mathrm{monomer}$ in eV") + plt.axvline(r_cut, c="red", label=r"$r_\mathrm{train}$") + + plt.legend() + plt.tight_layout() + plt.show() + + + +.. image-sg:: /examples/lode-linear/images/sphx_glr_lode-linear_001.png + :alt: lode linear + :srcset: /examples/lode-linear/images/sphx_glr_lode-linear_001.png + :class: sphx-glr-single-img + + + + + + +.. _sphx_glr_download_examples_lode-linear_lode-linear.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + .. container:: sphx-glr-download + + :download:`Download Conda environment file: environment.yml ` + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: lode-linear.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: lode-linear.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ + diff --git a/latest/_sources/examples/lode-linear/sg_execution_times.rst.txt b/latest/_sources/examples/lode-linear/sg_execution_times.rst.txt new file mode 100644 index 00000000..7c899f38 --- /dev/null +++ b/latest/_sources/examples/lode-linear/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_examples_lode-linear_sg_execution_times: + + +Computation times +================= +**00:11.624** total execution time for 1 file **from examples/lode-linear**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_lode-linear_lode-linear.py` (``lode-linear.py``) + - 00:11.624 + - 0.0 diff --git a/latest/_sources/examples/lpr/lpr.rst.txt b/latest/_sources/examples/lpr/lpr.rst.txt new file mode 100644 index 00000000..346d41e1 --- /dev/null +++ b/latest/_sources/examples/lpr/lpr.rst.txt @@ -0,0 +1,430 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/lpr/lpr.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_lpr_lpr.py: + + +LPR analysis for amorphous silicon dataset +========================================== + +:Authors: Sanggyu "Raymond" Chong `@SanggyuChong `_, + Federico Grasselli `@fgrassel `_ + +In this tutorial, we calculate the SOAP descriptors of an amorphous +silicon dataset using rascaline, then compute the local prediction +rigidity (LPR) for the atoms of a "test" set before and after +modifications to the "training" dataset has been made. + +First, we import all the necessary packages: + +.. GENERATED FROM PYTHON SOURCE LINES 17-30 + +.. code-block:: Python + + import os + import tarfile + + import numpy as np + import requests + from ase.io import read + from matplotlib import pyplot as plt + from matplotlib.colors import LogNorm + from rascaline import SoapPowerSpectrum + from sklearn.decomposition import PCA + from skmatter.metrics import local_prediction_rigidity as lpr + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-38 + +Load and prepare amorphous silicon data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + +We first download the dataset associated with LPR +analysis from Materials Cloud and load the the amorphous +silicon structures using `ASE `_. + +.. GENERATED FROM PYTHON SOURCE LINES 38-65 + +.. code-block:: Python + + + filename = "LPR_supp_notebook_dataset.tar.gz" + if not os.path.exists(filename): + url = "https://rb.gy/wxsrug" # shortened URL + response = requests.get(url) + response.raise_for_status() + with open(filename, "wb") as f: + f.write(response.content) + + with tarfile.open(filename) as tar: + tar.extractall(path=".") + + frames_pristine = read("datasets/Si_amo_defect_free.xyz", ":") + frames_defect = read("datasets/Si_amo_defect_containing.xyz", ":") + + # Randomly shuffle the structures + + np.random.seed(20230215) + + ids = list(range(len(frames_pristine))) + np.random.shuffle(ids) + frames_pristine = [frames_pristine[ii] for ii in ids] + + ids = list(range(len(frames_defect))) + np.random.shuffle(ids) + frames_defect = [frames_defect[ii] for ii in ids] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 66-74 + +We now further refine the loaded datasets according the the +number of coordinated atoms that each atomic environment exhibits. +"Pristine" refers to structures where all of the atoms have strictly +4 coordinating atoms. "Defect" refers to structures that contain +atoms with coordination numbers other than 4. + +We use :code:`get_all_distances` funciton of :code:`ase.Atoms` to detect the +number of coordinated atoms. + +.. GENERATED FROM PYTHON SOURCE LINES 74-92 + +.. code-block:: Python + + + cur_cutoff = 2.7 + refined_pristine_frames = [] + for frame in frames_pristine: + neighs = (frame.get_all_distances(mic=True) < cur_cutoff).sum(axis=0) - 1 + if neighs.max() > 4 or neighs.min() < 4: + continue + else: + refined_pristine_frames.append(frame) + + refined_defect_frames = [] + for frame in frames_defect: + neighs = (frame.get_all_distances(mic=True) < cur_cutoff).sum(axis=0) - 1 + num_defects = (neighs > 4).sum() + (neighs < 4).sum() + if num_defects > 4: + refined_defect_frames.append(frame) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 93-103 + +Compute SOAP descriptors using rascaline +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now, we move on and compute the SOAP descriptors for the refined +structures. First, define the rascaline hyperparameters used to +compute SOAP. Among the hypers, notice that the cutoff is chosen +to be 2.85 Å, and the radial scaling is turned off. These were +heuristic choices made to accentuate the difference in the LPR +based on the nearest-neighbor coordination. (Do not blindly +use this set of hypers for production-quality model training!) + +.. GENERATED FROM PYTHON SOURCE LINES 103-129 + +.. code-block:: Python + + + # Hypers dictionary + hypers = { + "cutoff": 2.85, + "max_radial": 10, + "max_angular": 12, + "atomic_gaussian_width": 0.5, + "center_atom_weight": 1.0, + "radial_basis": {"Gto": {"spline_accuracy": 1e-8}}, + "cutoff_function": {"ShiftedCosine": {"width": 0.1}}, + "radial_scaling": None, + } + # Define rascaline calculator + calculator = SoapPowerSpectrum(**hypers) + + # Calculate the SOAP power spectrum + Xlist_pristine = [] + for frame in refined_pristine_frames: + descriptor = calculator.compute(frame) + Xlist_pristine.append(np.array(descriptor.block().values)) + + Xlist_defect = [] + for frame in refined_defect_frames: + descriptor = calculator.compute(frame) + Xlist_defect.append(np.array(descriptor.block().values)) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 130-141 + +Organize structures into "training" and "test" sets +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now we move on and compute the SOAP descriptors for the refined +structures. First, define the rascaline hyperparameters used to +compute SOAP. + +Notice that the format in which we handle the descriptors is as a +list of :code:`np.array` descriptor blocks. This is to ensure +compatibility with how things have been implemented in the LPR +module of :code:`scikit-matter`. + +.. GENERATED FROM PYTHON SOURCE LINES 141-157 + +.. code-block:: Python + + + n_train = 400 + n_add = 50 + n_test = 50 + + X_pristine = [Xlist for Xlist in Xlist_pristine[: n_train + n_add]] + X_defect = [Xlist for Xlist in Xlist_defect[:n_add]] + X_test = [Xlist for Xlist in Xlist_defect[n_add : n_add + n_test]] + + # Save coordination values for visualization + test_coord = [] + for frame in refined_defect_frames[n_add : n_add + n_test]: + coord = (frame.get_all_distances(mic=True) < cur_cutoff - 0.05).sum(axis=0) - 1 + test_coord += coord.tolist() + test_coord = np.array(test_coord) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 158-172 + +Compute the LPR for the test set +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Next, we will use the :code:`local_prediction_rigidity` module of +`scikit-matter `_ +to compute the LPRs for the test set that we have set apart. + +LPR reflects how the ML model perceives a local environment, +given a collection of other structures, similar or different. +It should then carry over some of the details involved in training +the model, in this case the regularization strength. + +For this example, we have foregone on the actual model training, +and so we define an arbitrary value for the alpha. + +.. GENERATED FROM PYTHON SOURCE LINES 172-177 + +.. code-block:: Python + + + alpha = 1e-4 + LPR_test, rank = lpr(X_pristine, X_test, alpha) + LPR_test = np.hstack(LPR_test) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 178-184 + +Visualizing the LPR on a PCA map +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We now visualize the LPRs of the test set on a PCA map, +where the PCA is performed on the SOAP descriptors of +defect-containing dataset. + +.. GENERATED FROM PYTHON SOURCE LINES 184-210 + +.. code-block:: Python + + + pca = PCA(n_components=5) + descriptors_all = calculator.compute(refined_defect_frames) + pca.fit_transform(descriptors_all.block().values) + PCA_test = pca.transform(np.vstack(X_test)) + + rmin = np.log10(LPR_test.min()) + 0.5 + rmax = np.log10(LPR_test.max()) - 0.5 + + fig = plt.figure(figsize=(5, 4), dpi=200) + ax = fig.add_subplot() + im = ax.scatter( + PCA_test[:, 0], + PCA_test[:, 1], + c=LPR_test, + s=20, + linewidths=0, + norm=LogNorm(vmin=10**rmin, vmax=10**rmax), + cmap="viridis", + ) + + ax.set_xlabel("PC1") + ax.set_ylabel("PC2") + fig.colorbar(im, ax=ax, label="LPR") + ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False) + + + + +.. image-sg:: /examples/lpr/images/sphx_glr_lpr_001.png + :alt: lpr + :srcset: /examples/lpr/images/sphx_glr_lpr_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 211-219 + +In the PCA map, where each point corresponds to an +atomic environment of the test set structures, one +can observe 4 different clusters of points, arranged +along PC1. This corresponds to the coordination numbers +ranging from 3 to 6. Since the training set contains +structures exclusively composed of 4-coordinated atoms, +LPR is distinctly high for the second, main cluster of +points, and quite low for the three other clusters. + +.. GENERATED FROM PYTHON SOURCE LINES 222-229 + +Studying the LPR after dataset modification +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We now want to see what would happen when defect structures +are included into the training set of the model. For this, +we first create a modified dataset that incorporates in the +defect structures, and recompute the LPR. + +.. GENERATED FROM PYTHON SOURCE LINES 229-234 + +.. code-block:: Python + + + X_new = X_pristine[:n_train] + X_defect[:n_add] + LPR_test_new, rank = lpr(X_new, X_test, alpha) + LPR_test_new = np.hstack(LPR_test_new) + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 235-240 + +We then visualize the change in the LPR with the +modification of the dataset by plotting the same PCA +map, but now colored by the ratio of new set of LPR +values (after dataset modification) over the original +one. + +.. GENERATED FROM PYTHON SOURCE LINES 240-257 + +.. code-block:: Python + + + fig = plt.figure(figsize=(5, 4), dpi=200) + ax = fig.add_subplot() + im = ax.scatter( + PCA_test[:, 0], + PCA_test[:, 1], + c=LPR_test_new / LPR_test, + s=20, + linewidths=0, + # norm=LogNorm(vmin=10**rmin, vmax=10**rmax), + cmap="OrRd", + ) + ax.set_xlabel("PC1") + ax.set_ylabel("PC2") + fig.colorbar(im, ax=ax, label=r"LPR$_{\mathrm{new}}$ / LPR$_{\mathrm{old}}$") + ax.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False) + + + + +.. image-sg:: /examples/lpr/images/sphx_glr_lpr_002.png + :alt: lpr + :srcset: /examples/lpr/images/sphx_glr_lpr_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 258-261 + +It is apparent that while the LPR stays more or less consistent for the +4-coordinated atoms, it is significantly enhanced for the defective environments +as a result of the inclusion of defective structures in the training set. + + +.. _sphx_glr_download_examples_lpr_lpr.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + .. container:: sphx-glr-download + + :download:`Download Conda environment file: environment.yml ` + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: lpr.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: lpr.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ + diff --git a/latest/_sources/examples/lpr/sg_execution_times.rst.txt b/latest/_sources/examples/lpr/sg_execution_times.rst.txt new file mode 100644 index 00000000..6a5e055c --- /dev/null +++ b/latest/_sources/examples/lpr/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_examples_lpr_sg_execution_times: + + +Computation times +================= +**00:16.390** total execution time for 1 file **from examples/lpr**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_lpr_lpr.py` (``lpr.py``) + - 00:16.390 + - 0.0 diff --git a/latest/_sources/examples/path-integrals/path-integrals.rst.txt b/latest/_sources/examples/path-integrals/path-integrals.rst.txt new file mode 100644 index 00000000..d7e142e7 --- /dev/null +++ b/latest/_sources/examples/path-integrals/path-integrals.rst.txt @@ -0,0 +1,674 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/path-integrals/path-integrals.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_path-integrals_path-integrals.py: + + +Path integral molecular dynamics +================================ + +:Authors: Michele Ceriotti `@ceriottm `_ + +This example shows how to run a path integral molecular dynamics +simulation using ``i-PI``, analyze the output and visualize the +trajectory in ``chemiscope``. It uses `LAMMPS `_ +as the driver to simulate the `q-TIP4P/f water +model `_. + +.. GENERATED FROM PYTHON SOURCE LINES 13-23 + +.. code-block:: Python + + + import subprocess + import time + + import chemiscope + import ipi + import matplotlib.pyplot as plt + import numpy as np + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 24-57 + +Quantum nuclear effects and path integral methods +------------------------------------------------- + +The Born-Oppenheimer approximation separates the joint quantum mechanical +problem for electrons and nuclei into two independent problems. Even though +often one makes the additional approximation of treating nuclei as classical +particles, this is not necessary, and in some cases (typically when H atoms are +present) can add considerable error. + + +.. figure:: pimd-slices-round.png + :align: center + :width: 600px + + A representation of ther ring-polymer Hamiltonian for a water molecule. + +In order to describe the quantum mechanical nature of light nuclei +(nuclear quantum effects) one of the most widely-applicable methods uses +the *path integral formalism* to map the quantum partition function of a +set of distinguishable particles onto the classical partition function of +*ring polymers* composed by multiple beads (replicas) with +corresponding atoms in adjacent replicas being connected by harmonic +springs. +`The textbook by Tuckerman `_ +contains a pedagogic introduction to the topic, while +`this paper `_ outlines the implementation +used in ``i-PI``. + +The classical partition function of the path converges to quantum statistics +in the limit of a large number of replicas. In this example, we will use a +technique based on generalized Langevin dynamics, known as +`PIGLET `_ to accelerate the +convergence. + +.. GENERATED FROM PYTHON SOURCE LINES 60-69 + +Running PIMD calculations with ``i-PI`` +--------------------------------------- + +`i-PI `_ is based on a client-server model, with ``i-PI`` +controlling the nuclear dynamics (in this case sampling the path Hamiltonian using +molecular dynamics) while the calculation of energies and forces is delegated to +an external client program, in this example ``LAMMPS``. + +An i-PI calculation is specified by an XML file. + +.. GENERATED FROM PYTHON SOURCE LINES 69-75 + +.. code-block:: Python + + + # Open and read the XML file + with open("input_pimd.xml", "r") as file: + xml_content = file.read() + print(xml_content) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + [ step, time{picosecond}, conserved{electronvolt}, temperature{kelvin}, kinetic_cv{electronvolt}, potential{electronvolt}, pressure_cv{megapascal}, kinetic_td{electronvolt} ] + positions + kinetic_cv + kinetic_od + + 200 + + 32342 + + +
h2o-lammps
1e-4 +
+ + + water_32.pdb + 298 + + + lmpserial + + + 298 + + + + + 5.0 + + 0.5 + + + +
+ + + + + +.. GENERATED FROM PYTHON SOURCE LINES 76-83 + +NB1: In a realistic simulation you may want to increase the field +``total_steps``, to simulate at least a few 100s of picoseconds. + +NB2: To converge a simulation of water at room temperature, you +typically need at least 32 beads. We will see later how to accelerate +convergence using a colored-noise thermostat, but you can try to +modify the input to check convergence with conventional PIMD + +.. GENERATED FROM PYTHON SOURCE LINES 85-102 + +i-PI and lammps should be run separately, and it is possible to +launch separate lammps processes to parallelize the evaluation over +the beads. On the the command line, this amounts to launching + +.. code-block:: bash + + i-pi input_pimd.xml > log & + sleep 2 + lmp -in in.lmp & + lmp -in in.lmp & + +Note how ``i-PI`` and ``LAMMPS`` are completely independent, and +therefore need a separate set of input files. The client-side communication +in ``LAMMPS`` is described in the ``fix_ipi`` section, that matches the socket +name and mode defined in the ``ffsocket`` field in the ``i-PI`` file. + +We can launch the external processes from a Python script as follows + +.. GENERATED FROM PYTHON SOURCE LINES 102-107 + +.. code-block:: Python + + + ipi_process = subprocess.Popen(["i-pi", "input_pimd.xml"]) + time.sleep(2) # wait for i-PI to start + lmp_process = [subprocess.Popen(["lmp", "-in", "in.lmp"]) for i in range(2)] + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 108-111 + +If you run this in a notebook, you can go ahead and start loading +output files _before_ i-PI and lammps have finished running, by +skipping this cell + +.. GENERATED FROM PYTHON SOURCE LINES 111-117 + +.. code-block:: Python + + + ipi_process.wait() + lmp_process[0].wait() + lmp_process[1].wait() + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + 1 + + + +.. GENERATED FROM PYTHON SOURCE LINES 118-121 + +After the simulation has run, you can visualize and post-process the trajectory data. +Note that i-PI prints a separate trajectory for each bead, as structural properties +can be computed averaging over the configurations of any of the beads. + +.. GENERATED FROM PYTHON SOURCE LINES 121-126 + +.. code-block:: Python + + + output_data, output_desc = ipi.read_output("simulation.out") + traj_data = [ipi.read_trajectory(f"simulation.pos_{i}.xyz") for i in range(8)] + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 127-132 + +The simulation parameters are pushed at the limits: with the aggressive stochastic +thermostatting and the high-frequency normal modes of the ring polymer, there are +fairly large fluctuations of the conserved quantity. This is usually not affecting +physical observables, but if you see this level of drift in a production run, check +carefully for convergence and stability with a reduced time step. + +.. GENERATED FROM PYTHON SOURCE LINES 132-150 + +.. code-block:: Python + + + fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True) + ax.plot( + output_data["time"], + output_data["potential"] - output_data["potential"][0], + "b-", + label="Potential, $V$", + ) + ax.plot( + output_data["time"], + output_data["conserved"] - output_data["conserved"][0], + "r-", + label="Conserved, $H$", + ) + ax.set_xlabel(r"$t$ / ps") + ax.set_ylabel(r"energy / eV") + ax.legend() + + + + +.. image-sg:: /examples/path-integrals/images/sphx_glr_path-integrals_001.png + :alt: path integrals + :srcset: /examples/path-integrals/images/sphx_glr_path-integrals_001.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 151-161 + +While the potential energy is simply the mean over the beads of the +energy of individual replicas, computing the kinetic energy requires +averaging special quantities that involve also the correlations between beads. +Here we compare two of these *estimators*: the 'thermodynamic' estimator becomes +statistically inefficient when increasing the number of beads, whereas the +'centroid virial' estimator remains well-behaved. Note how quickly these estimators +equilibrate to roughly their stationary value, much faster than the equilibration +of the potential energy above. This is thanks to the ``pile_g`` thermostat +(see `DOI:10.1063/1.3489925 `_) that is +optimally coupled to the normal modes of the ring polymer. + +.. GENERATED FROM PYTHON SOURCE LINES 161-179 + +.. code-block:: Python + + + fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True) + ax.plot( + output_data["time"], + output_data["kinetic_cv"], + "b-", + label="Centroid virial, $K_{CV}$", + ) + ax.plot( + output_data["time"], + output_data["kinetic_td"], + "r-", + label="Thermodynamic, $K_{TD}$", + ) + ax.set_xlabel(r"$t$ / ps") + ax.set_ylabel(r"energy / eV") + ax.legend() + + + + +.. image-sg:: /examples/path-integrals/images/sphx_glr_path-integrals_002.png + :alt: path integrals + :srcset: /examples/path-integrals/images/sphx_glr_path-integrals_002.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 180-185 + +You can also visualize the (very short) trajectory in a way that highlights the +fast spreading out of the beads of the ring polymer. ``chemiscope`` provides a +utility function to interleave the trajectories of the beads, forming a trajectory +that shows the connecttions between the replicas of each atom. Each atom and its +connections are color-coded. + +.. GENERATED FROM PYTHON SOURCE LINES 185-206 + +.. code-block:: Python + + + traj_pimd = chemiscope.ase_merge_pi_frames(traj_data) + # we also tweak the visualization options, and then show the viewer + traj_pimd["shapes"]["paths"]["parameters"]["global"]["radius"] = 0.05 + traj_pimd["settings"]["structure"][0].update( + dict( + atoms=False, + keepOrientation=True, + color={"property": "bead_id", "palette": "hsv (periodic)"}, + ) + ) + + cs = chemiscope.show(**traj_pimd, mode="structure") + + if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) + else: + cs.save("path-integrals.json.gz") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /home/runner/work/software-cookbook/software-cookbook/.nox/path-integrals/lib/python3.11/site-packages/chemiscope/jupyter.py:245: UserWarning: chemiscope.show only works inside a jupyter notebook + warnings.warn("chemiscope.show only works inside a jupyter notebook") + + + + +.. GENERATED FROM PYTHON SOURCE LINES 207-224 + +Accelerating PIMD with a PIGLET thermostat +------------------------------------------ + +The simulations in the previous sections are very far from converged -- typically +one would need approximately 32 replicas to converge a simulation of +room-temperature water. To address this problem we will use a method based on +generalized Langevin equations, called +`PIGLET `_ + +The input file is ``input_piglet.xml``, that only differs by the definition of +the thermostat, that uses a ``nm_gle`` mode in which each normal mode +of the ring polymer is attached to a different colored-noise Generalized Langevin +equation. This makes it possible to converge exactly the simulation results with +a small number of replicas, and to accelerate greatly convergence for realistic +systems such as this. The thermostat parameters can be generated on +`the GLE4MD website `_ + + +.. GENERATED FROM PYTHON SOURCE LINES 224-233 + +.. code-block:: Python + + + ipi_process = subprocess.Popen(["i-pi", "input_piglet.xml"]) + time.sleep(2) # wait for i-PI to start + lmp_process = [subprocess.Popen(["lmp", "-in", "in.lmp"]) for i in range(2)] + + ipi_process.wait() + lmp_process[0].wait() + lmp_process[1].wait() + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + 1 + + + +.. GENERATED FROM PYTHON SOURCE LINES 234-237 + +The mean potential energy from the PIGLET trajectory is higher than that for the +PIMD one, because it is closer to the converged value (try to run a PIMD trajectory +with 64 beads for comparison) + +.. GENERATED FROM PYTHON SOURCE LINES 237-258 + +.. code-block:: Python + + + output_gle, desc_gle = ipi.read_output("simulation_piglet.out") + traj_gle = [ipi.read_trajectory(f"simulation_piglet.pos_{i}.xyz") for i in range(8)] + + fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True) + ax.plot( + output_data["time"], + output_data["potential"] - output_data["potential"][0], + "b--", + label="PIMD", + ) + ax.plot( + output_gle["time"], + output_gle["potential"] - output_gle["potential"][0], + "b-", + label="PIGLET", + ) + ax.set_xlabel(r"$t$ / ps") + ax.set_ylabel(r"energy / eV") + ax.legend() + + + + +.. image-sg:: /examples/path-integrals/images/sphx_glr_path-integrals_003.png + :alt: path integrals + :srcset: /examples/path-integrals/images/sphx_glr_path-integrals_003.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 259-266 + +However, you should be somewhat careful: PIGLET converges *some* but not all the +correlations within a path. For instance, it is designed to converge the +centroid-virial estimator for the kinetic energy, but not the thermodynamic +estimator. For the same reason, don't try to look at equilibration in terms of +the mean temperature: it won't match the target value, because PIGLET uses a +Langevin equation that breaks the classical fluctuation-dissipation theorem, and +generates a steady-state distribution that mimics quantum fluctuations. + +.. GENERATED FROM PYTHON SOURCE LINES 266-276 + +.. code-block:: Python + + + fix, ax = plt.subplots(1, 1, figsize=(4, 3), constrained_layout=True) + ax.plot(output_data["time"], output_data["kinetic_cv"], "b--", label="PIMD, $K_{CV}$") + ax.plot(output_gle["time"], output_gle["kinetic_cv"], "b", label="PIGLET, $K_{CV}$") + ax.plot(output_data["time"], output_data["kinetic_td"], "r--", label="PIMD, $K_{TD}$") + ax.plot(output_gle["time"], output_gle["kinetic_td"], "r", label="PIGLET, $K_{TD}$") + ax.set_xlabel(r"$t$ / ps") + ax.set_ylabel(r"energy / eV") + ax.legend() + + + + +.. image-sg:: /examples/path-integrals/images/sphx_glr_path-integrals_004.png + :alt: path integrals + :srcset: /examples/path-integrals/images/sphx_glr_path-integrals_004.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 277-290 + +Kinetic energy tensors +~~~~~~~~~~~~~~~~~~~~~~ + +While we're at it, let's do something more complicated (and instructive). +Classically, the momentum distribution of any atom is isotropic, so the +kinetic energy tensor (KET) :math:`\mathbf{p}\mathbf{p}^T/2m` is a constant +times the identity matrix. Quantum mechanically, the kinetic energy tensor +has more structure, that reflects the higher kinetic energy of particles +along directions with stiff bonds. We can compute a moving average of the +centroid virial estimator of the KET, and plot it to show the direction +of anisotropy. Note that there are some subtleties connected with the +evaluation of the moving average, see e.g. +`DOI:10.1103/PhysRevLett.109.100604 `_ + +.. GENERATED FROM PYTHON SOURCE LINES 292-296 + +We first need to postprocess the components of the kinetic energy tensors +(that i-PI prints out separating the diagonal and off-diagonal bits), averaging +them over the last 10 frames and combining them with the centroid configuration +from the last frame in the trajectory. + +.. GENERATED FROM PYTHON SOURCE LINES 296-310 + +.. code-block:: Python + + + kinetic_cv = ipi.read_trajectory("simulation_piglet.kin.xyz") + kinetic_od = ipi.read_trajectory("simulation_piglet.kod.xyz") + kinetic_tens = np.hstack( + [ + np.asarray([k.positions for k in kinetic_cv[-10:]]).mean(axis=0), + np.asarray([k.positions for k in kinetic_od[-10:]]).mean(axis=0), + ] + ) + + centroid = traj_gle[-1][-1].copy() + centroid.positions = np.asarray([t[-1].positions for t in traj_gle]).mean(axis=0) + centroid.arrays["kinetic_cv"] = kinetic_tens + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 311-315 + +We can then view these in ``chemiscope``, setting the proper parameters to +visualize the ellipsoids associated with the KET. Note that some KETs have +negative eigenvalues, because we are averaging over a few frames, which is +insufficient to converge the estimator fully. + +.. GENERATED FROM PYTHON SOURCE LINES 315-332 + +.. code-block:: Python + + + ellipsoids = chemiscope.ase_tensors_to_ellipsoids( + [centroid], "kinetic_cv", scale=15, force_positive=True + ) + + cs = chemiscope.show( + [centroid], + shapes={"kinetic_cv": ellipsoids}, + mode="structure", + settings=chemiscope.quick_settings( + structure_settings={ + "shape": ["kinetic_cv"], + "unitCell": True, + } + ), + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /home/runner/work/software-cookbook/software-cookbook/.nox/path-integrals/lib/python3.11/site-packages/chemiscope/jupyter.py:245: UserWarning: chemiscope.show only works inside a jupyter notebook + warnings.warn("chemiscope.show only works inside a jupyter notebook") + + + + +.. GENERATED FROM PYTHON SOURCE LINES 333-340 + +.. code-block:: Python + + + if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) + else: + cs.save("path-integrals.json.gz") + + + + + + + + +.. _sphx_glr_download_examples_path-integrals_path-integrals.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + .. container:: sphx-glr-download + + :download:`Download Conda environment file: environment.yml ` + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: path-integrals.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: path-integrals.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ + diff --git a/latest/_sources/examples/path-integrals/sg_execution_times.rst.txt b/latest/_sources/examples/path-integrals/sg_execution_times.rst.txt new file mode 100644 index 00000000..d3a6f5c0 --- /dev/null +++ b/latest/_sources/examples/path-integrals/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_examples_path-integrals_sg_execution_times: + + +Computation times +================= +**00:18.308** total execution time for 1 file **from examples/path-integrals**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_path-integrals_path-integrals.py` (``path-integrals.py``) + - 00:18.308 + - 0.0 diff --git a/latest/_sources/examples/roy-gch/roy-gch.rst.txt b/latest/_sources/examples/roy-gch/roy-gch.rst.txt new file mode 100644 index 00000000..6fd7932c --- /dev/null +++ b/latest/_sources/examples/roy-gch/roy-gch.rst.txt @@ -0,0 +1,541 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/roy-gch/roy-gch.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_roy-gch_roy-gch.py: + + +Generalized Convex Hull construction for the polymorphs of ROY +============================================================== + +:Authors: Michele Ceriotti `@ceriottm `_ + +This notebook analyzes the structures of 264 polymorphs of ROY, from +`Beran et Al, Chemical Science +(2022) `__, comparing the +conventional density-energy convex hull with a Generalized Convex Hull +(GCH) analysis (see `Anelli et al., Phys. Rev. Materials +(2018) `__). +It uses features computed with `rascaline `__ +and uses the directional convex hull function from +`scikit-matter `__ +to make the figure. + +.. GENERATED FROM PYTHON SOURCE LINES 18-30 + +.. code-block:: Python + + + import chemiscope + import matplotlib.tri + import numpy as np + from matplotlib import pyplot as plt + from metatensor import mean_over_samples + from rascaline import SoapPowerSpectrum + from sklearn.decomposition import PCA + from skmatter.datasets import load_roy_dataset + from skmatter.sample_selection import DirectionalConvexHull + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 31-32 + +Loads the structures (that also contain properties in the ``info`` field) + +.. GENERATED FROM PYTHON SOURCE LINES 32-44 + +.. code-block:: Python + + + roy_data = load_roy_dataset() + + structures = roy_data["structures"] + + density = np.array([s.info["density"] for s in structures]) + energy = np.array([s.info["energy"] for s in structures]) + structype = np.array([s.info["type"] for s in structures]) + iknown = np.where(structype == "known")[0] + iothers = np.where(structype != "known")[0] + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 45-50 + +Energy-density hull +------------------- + +The Directional Convex Hull routines can be used to compute a +conventional density-energy hull + +.. GENERATED FROM PYTHON SOURCE LINES 50-54 + +.. code-block:: Python + + + dch_builder = DirectionalConvexHull(low_dim_idx=[0]) + dch_builder.fit(density.reshape(-1, 1), energy) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 55-57 + +We can get the indices of the selection, and compute the distance from +the hull + +.. GENERATED FROM PYTHON SOURCE LINES 57-62 + +.. code-block:: Python + + + sel = dch_builder.selected_idx_ + dch_dist = dch_builder.score_samples(density.reshape(-1, 1), energy) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 63-74 + +Hull energies +^^^^^^^^^^^^^ + +Structures on the hull are stable with respect to synthesis at constant +molar volume. Any other structure would lower the energy by decomposing +into a mixture of the two nearest structures along the hull. Given that +the lattice energy is an imperfect proxy for the free energy, and that +synthesis can be performed in other ways than by fixing the density, +structures that are not exactly on the hull might also be stable. One +can compute a “hull energy” as an indication of how close these +structures are to being stable. + +.. GENERATED FROM PYTHON SOURCE LINES 75-89 + +.. code-block:: Python + + + fig, ax = plt.subplots(1, 1, figsize=(6, 4)) + ax.scatter(density, energy, c=dch_dist, marker=".") + ssel = sel[np.argsort(density[sel])] + ax.plot(density[ssel], energy[ssel], "k--") + ax.set_xlabel("density / g/cm$^3$") + ax.set_ylabel("energy / kJ/mol") + + print( + f"Mean hull energy for 'known' stable structures {dch_dist[iknown].mean()} kJ/mol" + ) + print(f"Mean hull energy for 'other' structures {dch_dist[iothers].mean()} kJ/mol") + + + + + +.. image-sg:: /examples/roy-gch/images/sphx_glr_roy-gch_001.png + :alt: roy gch + :srcset: /examples/roy-gch/images/sphx_glr_roy-gch_001.png + :class: sphx-glr-single-img + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Mean hull energy for 'known' stable structures 1.816657381014075 kJ/mol + Mean hull energy for 'other' structures 6.312730486304906 kJ/mol + + + + +.. GENERATED FROM PYTHON SOURCE LINES 90-97 + +Interactive visualization +^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can also visualize the hull with ``chemiscope``. +This runs only in a notebook, and +requires having the ``chemiscope`` package installed. + + +.. GENERATED FROM PYTHON SOURCE LINES 97-126 + +.. code-block:: Python + + + cs = chemiscope.show( + structures, + dict( + energy=energy, + density=density, + hull_energy=dch_dist, + structure_type=structype, + ), + settings={ + "map": { + "x": {"property": "density"}, + "y": {"property": "energy"}, + "color": {"property": "hull_energy"}, + "symbol": "structure_type", + "size": {"factor": 35}, + }, + "structure": [{"unitCell": True, "supercell": {"0": 2, "1": 2, "2": 2}}], + }, + ) + + + if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) + else: + cs.save("roy_ch.json.gz") + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /home/runner/work/software-cookbook/software-cookbook/.nox/roy-gch/lib/python3.11/site-packages/chemiscope/jupyter.py:245: UserWarning: chemiscope.show only works inside a jupyter notebook + warnings.warn("chemiscope.show only works inside a jupyter notebook") + + + + +.. GENERATED FROM PYTHON SOURCE LINES 127-139 + +Generalized Convex Hull +----------------------- + +A GCH is a similar construction, in which generic structural descriptors +are used in lieu of composition, density or other thermodynamic +constraints. The idea is that configurations that are found close to the +GCH are locally stable with respect to structurally-similar +configurations. In other terms, one can hope to find a thermodynamic +constraint (i.e. synthesis conditions) that act differently on these +structures in comparison with the others, and may potentially stabilize +them. + + +.. GENERATED FROM PYTHON SOURCE LINES 142-150 + +Compute structural descriptors +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A first step is to computes suitable ML descriptors. Here we have used +``rascaline`` to evaluate average SOAP features for the structures. +If you don't want to install these dependencies for this example you +can also use the pre-computed features, but you can use this as a stub +to apply this analysis to other chemical systems + +.. GENERATED FROM PYTHON SOURCE LINES 150-173 + +.. code-block:: Python + + + hypers = { + "cutoff": 4, + "max_radial": 6, + "max_angular": 4, + "atomic_gaussian_width": 0.7, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + "radial_basis": {"Gto": {"accuracy": 1e-6}}, + "center_atom_weight": 1.0, + } + calculator = SoapPowerSpectrum(**hypers) + rho2i = calculator.compute(structures) + rho2i = rho2i.keys_to_samples(["species_center"]).keys_to_properties( + ["species_neighbor_1", "species_neighbor_2"] + ) + rho2i_structure = mean_over_samples(rho2i, sample_names=["center", "species_center"]) + np.savez("roy_features.npz", feats=rho2i_structure.block(0).values) + + + # features = roy_data["features"] + features = rho2i_structure.block(0).values + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 174-180 + +PCA projection +^^^^^^^^^^^^^^ + +Computes PCA projection to generate low-dimensional descriptors that +reflect structural diversity. Any other dimensionality reduction scheme +could be used in a similar fashion. + +.. GENERATED FROM PYTHON SOURCE LINES 180-192 + +.. code-block:: Python + + + pca = PCA(n_components=4) + pca_features = pca.fit_transform(features) + + fig, ax = plt.subplots(1, 1, figsize=(6, 4)) + scatter = ax.scatter(pca_features[:, 0], pca_features[:, 1], c=energy) + ax.set_xlabel("PCA[1]") + ax.set_ylabel("PCA[2]") + cbar = fig.colorbar(scatter, ax=ax) + cbar.set_label("energy / kJ/mol") + + + + + +.. image-sg:: /examples/roy-gch/images/sphx_glr_roy-gch_002.png + :alt: roy gch + :srcset: /examples/roy-gch/images/sphx_glr_roy-gch_002.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 193-197 + +Builds the Generalized Convex Hull +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Builds a convex hull on the first two PCA features + +.. GENERATED FROM PYTHON SOURCE LINES 197-204 + +.. code-block:: Python + + + dch_builder = DirectionalConvexHull(low_dim_idx=[0, 1]) + dch_builder.fit(pca_features, energy) + sel = dch_builder.selected_idx_ + dch_dist = dch_builder.score_samples(pca_features, energy) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 205-207 + +Generates a 3D Plot + + +.. GENERATED FROM PYTHON SOURCE LINES 207-219 + +.. code-block:: Python + + + triang = matplotlib.tri.Triangulation(pca_features[sel, 0], pca_features[sel, 1]) + fig = plt.figure(figsize=(7, 5), tight_layout=True) + ax = fig.add_subplot(projection="3d") + ax.plot_trisurf(triang, energy[sel], color="gray") + ax.scatter(pca_features[:, 0], pca_features[:, 1], energy, c=dch_dist) + ax.set_xlabel("PCA[1]") + ax.set_ylabel("PCA[2]") + ax.set_zlabel("energy / kJ/mol\n \n", labelpad=11) + ax.view_init(25, 110) + + + + + +.. image-sg:: /examples/roy-gch/images/sphx_glr_roy-gch_003.png + :alt: roy gch + :srcset: /examples/roy-gch/images/sphx_glr_roy-gch_003.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 220-223 + +The GCH construction improves the separation between the hull energies +of “known” and hypothetical polymorphs (compare with the density-energy +values above) + +.. GENERATED FROM PYTHON SOURCE LINES 223-230 + +.. code-block:: Python + + + print( + f"Mean hull energy for 'known' stable structures {dch_dist[iknown].mean()} kJ/mol" + ) + print(f"Mean hull energy for 'other' structures {dch_dist[iothers].mean()} kJ/mol") + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + Mean hull energy for 'known' stable structures 0.8537845044685686 kJ/mol + Mean hull energy for 'other' structures 5.19887158185277 kJ/mol + + + + +.. GENERATED FROM PYTHON SOURCE LINES 231-233 + +Visualize in ``chemiscope``. This runs only in a notebook, and +requires having the ``chemiscope`` package installed. + +.. GENERATED FROM PYTHON SOURCE LINES 233-295 + +.. code-block:: Python + + + for i, f in enumerate(structures): + for j in range(len(pca_features[i])): + f.info["pca_" + str(j + 1)] = pca_features[i, j] + structure_properties = chemiscope.extract_properties(structures) + structure_properties.update({"per_atom_energy": energy, "hull_energy": dch_dist}) + + # shows chemiscope if not run in terminal + + cs = chemiscope.show( + frames=structures, + properties=structure_properties, + meta={ + "name": "GCH for ROY polymorphs", + "description": """ + Demonstration of the Generalized Convex Hull construction for + polymorphs of the ROY molecule. Molecules that are closest to + the hull built on PCA-based structural descriptors and having the + internal energy predicted by electronic-structure calculations as + the z axis are the most thermodynamically stable. Indeed most of the + known polymorphs of ROY are on (or very close) to this hull. + """, + "authors": ["Michele Ceriotti "], + "references": [ + 'A. Anelli, E. A. Engel, C. J. Pickard, and M. Ceriotti, \ + "Generalized convex hull construction for materials discovery," \ + Physical Review Materials 2(10), 103804 (2018).', + 'G. J. O. Beran, I. J. Sugden, C. Greenwell, D. H. Bowskill, \ + C. C. Pantelides, and C. S. Adjiman, "How many more polymorphs of \ + ROY remain undiscovered," Chem. Sci. 13(5), 1288–1297 (2022).', + ], + }, + settings={ + "map": { + "x": {"property": "pca_1"}, + "y": {"property": "pca_2"}, + "z": {"property": "energy"}, + "symbol": "type", + "color": {"property": "hull_energy"}, + "size": { + "factor": 35, + "mode": "linear", + "property": "", + "reverse": True, + }, + }, + "structure": [ + { + "bonds": True, + "unitCell": True, + "keepOrientation": True, + } + ], + }, + ) + + if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(cs) + else: + cs.save("roy_gch.json.gz") + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /home/runner/work/software-cookbook/software-cookbook/.nox/roy-gch/lib/python3.11/site-packages/chemiscope/jupyter.py:245: UserWarning: chemiscope.show only works inside a jupyter notebook + warnings.warn("chemiscope.show only works inside a jupyter notebook") + + + + + +.. _sphx_glr_download_examples_roy-gch_roy-gch.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + .. container:: sphx-glr-download + + :download:`Download Conda environment file: environment.yml ` + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download Jupyter notebook: roy-gch.ipynb ` + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download Python source code: roy-gch.py ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ + diff --git a/latest/_sources/examples/roy-gch/sg_execution_times.rst.txt b/latest/_sources/examples/roy-gch/sg_execution_times.rst.txt new file mode 100644 index 00000000..dda8caaf --- /dev/null +++ b/latest/_sources/examples/roy-gch/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_examples_roy-gch_sg_execution_times: + + +Computation times +================= +**00:17.696** total execution time for 1 file **from examples/roy-gch**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_roy-gch_roy-gch.py` (``roy-gch.py``) + - 00:17.696 + - 0.0 diff --git a/latest/_sources/examples/sample-selection/sample-selection.rst.txt b/latest/_sources/examples/sample-selection/sample-selection.rst.txt new file mode 100644 index 00000000..13db09b4 --- /dev/null +++ b/latest/_sources/examples/sample-selection/sample-selection.rst.txt @@ -0,0 +1,765 @@ + +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "examples/sample-selection/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_sample-selection.py: + + +Sample and Feature Selection with FPS and CUR +============================================= + +:Authors: Davide Tisi `@DavideTisi `_ + +In this tutorial we generate descriptors using rascaline, then select a subset +of structures using both the farthest-point sampling (FPS) and CUR algorithms +implemented in scikit-matter. Finally, we also generate a selection of +the most important features using the same techniques. + +First, import all the necessary packages + +.. GENERATED FROM PYTHON SOURCE LINES 16-28 + +.. code-block:: Python + + + import ase.io + import chemiscope + import metatensor + import numpy as np + from equisolve.numpy import feature_selection, sample_selection + from matplotlib import pyplot as plt + from rascaline import SoapPowerSpectrum + from sklearn.decomposition import PCA + from skmatter import feature_selection as skfeat_selection + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 29-34 + +Load molecular data +------------------- + +Load 500 example BTO structures from file, reading them using +`ASE `_. + +.. GENERATED FROM PYTHON SOURCE LINES 34-39 + +.. code-block:: Python + + + # Load a subset of :download:`structures ` of the example dataset + n_frames = 500 + frames = ase.io.read("input-fps.xyz", f":{n_frames}", format="extxyz") + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 40-44 + +Compute SOAP descriptors using rascaline +---------------------------------------- + +First, define the rascaline hyperparameters used to compute SOAP. + +.. GENERATED FROM PYTHON SOURCE LINES 44-82 + +.. code-block:: Python + + + + # rascaline hyperparameters + hypers = { + "cutoff": 6.0, + "max_radial": 8, + "max_angular": 6, + "atomic_gaussian_width": 0.3, + "cutoff_function": {"ShiftedCosine": {"width": 0.5}}, + "radial_basis": {"Gto": {"accuracy": 1e-6}}, + "radial_scaling": {"Willatt2018": {"exponent": 4, "rate": 1, "scale": 3.5}}, + "center_atom_weight": 1.0, + } + + # Generate a SOAP power spectrum + calculator = SoapPowerSpectrum(**hypers) + rho2i = calculator.compute(frames) + + + # Makes a dense block + atom_soap = rho2i.keys_to_properties(["species_neighbor_1", "species_neighbor_2"]) + + atom_soap_single_block = atom_soap.keys_to_samples(keys_to_move=["species_center"]) + + # Sum over atomic centers to compute structure features + struct_soap = metatensor.sum_over_samples( + atom_soap_single_block, sample_names=["center", "species_center"] + ) + + + print("atom feature descriptor shape:", atom_soap.block(0).values.shape) + print( + "atom feature descriptor (all in one block) shape:", + atom_soap_single_block.block(0).values.shape, + ) + print("structure feature descriptor shape:", struct_soap.block(0).values.shape) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + atom feature descriptor shape: (12000, 2688) + atom feature descriptor (all in one block) shape: (20000, 2688) + structure feature descriptor shape: (500, 2688) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 83-99 + +Perform atomic environment (i.e. sample) selection +--------------------------------------------------- + +Using FPS and CUR algorithms, we can perform selection of atomic environments. +These are implemented in equisolve, which provides a wrapper around +scikit-matter to allow for interfacing with data stored in the metatensor +format. + +Suppose we want to select the 10 most diverse environments for each chemical +species. + +First, we can use the `keys_to_properties` operation in metatensor to move the +neighbour species indices to the properties of the TensorBlocks. The resulting +descriptor will be a TensorMap comprised of three blocks, one for each +chemical species, where the chemical species indices are solely present in the +keys. + +.. GENERATED FROM PYTHON SOURCE LINES 99-108 + +.. code-block:: Python + + + + print("----Atomic environment selection-----") + # Define the number of structures to select using FPS/CUR + n_envs = 25 + + print(atom_soap) + print(atom_soap.block(0)) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ----Atomic environment selection----- + TensorMap with 3 blocks + keys: species_center + 8 + 22 + 56 + TensorBlock + samples (12000): ['structure', 'center'] + components (): [] + properties (2688): ['species_neighbor_1', 'species_neighbor_2', 'l', 'n1', 'n2'] + gradients: None + + + + +.. GENERATED FROM PYTHON SOURCE LINES 109-110 + +select 10 atomic environments for each chemical species. + +.. GENERATED FROM PYTHON SOURCE LINES 110-131 + +.. code-block:: Python + + + # Define the number of structures *per block* to select using FPS + n_envs = 10 + + # FPS sample selection + selector_atomic_fps = sample_selection.FPS(n_to_select=n_envs, initialize="random").fit( + atom_soap + ) + + # Print the selected envs for each block + print("atomic envs selected with FPS:\n") + for key, block in selector_atomic_fps.support.items(): + print("species_center:", key, "\n(struct_idx, atom_idx)\n", block.samples.values) + + selector_atomic_cur = sample_selection.CUR(n_to_select=n_envs).fit(atom_soap) + # Print the selected envs for each block + print("atomic envs selected with CUR:\n") + for key, block in selector_atomic_cur.support.items(): + print("species_center:", key, "\n(struct_idx, atom_idx)\n", block.samples.values) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + atomic envs selected with FPS: + + species_center: LabelsEntry(species_center=8) + (struct_idx, atom_idx) + [[ 68 18] + [113 36] + [140 21] + [285 20] + [339 16] + [339 23] + [339 24] + [341 17] + [347 37] + [436 22]] + species_center: LabelsEntry(species_center=22) + (struct_idx, atom_idx) + [[ 19 8] + [ 55 13] + [166 15] + [198 12] + [216 8] + [285 9] + [324 8] + [341 12] + [433 13] + [466 9]] + species_center: LabelsEntry(species_center=56) + (struct_idx, atom_idx) + [[ 40 7] + [140 2] + [238 3] + [289 6] + [339 3] + [341 4] + [407 0] + [407 7] + [436 6] + [451 7]] + atomic envs selected with CUR: + + species_center: LabelsEntry(species_center=8) + (struct_idx, atom_idx) + [[ 55 21] + [ 68 20] + [ 77 30] + [198 36] + [267 32] + [336 33] + [339 24] + [339 36] + [341 17] + [436 19]] + species_center: LabelsEntry(species_center=22) + (struct_idx, atom_idx) + [[ 10 39] + [ 40 10] + [ 70 10] + [130 10] + [166 15] + [170 14] + [216 8] + [285 9] + [326 10] + [466 10]] + species_center: LabelsEntry(species_center=56) + (struct_idx, atom_idx) + [[ 40 7] + [ 77 3] + [172 3] + [219 7] + [289 6] + [296 2] + [339 5] + [339 6] + [407 0] + [436 2]] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 132-141 + +Selecting from a combined pool of atomic environments +----------------------------------------------------- + +One can also select from a combined pool of atomic environments and +structures, instead of selecting an equal number of atomic environments for +each chemical species. In this case, we can move the 'species_center' key to samples +such that our descriptor is a TensorMap consisting of a single block. Upon +sample selection, the most diverse atomic environments will be selected, +regardless of their chemical species. + +.. GENERATED FROM PYTHON SOURCE LINES 141-163 + +.. code-block:: Python + + print("----All atomic environment selection-----") + + print("keys", atom_soap.keys) + print("blocks", atom_soap[0]) + print("samples in first block", atom_soap[0].samples) + + # Using the original SOAP descriptor, move all keys to properties. + + + # Define the number of structures to select using FPS + n_envs = 10 + + # FPS sample selection + selector_atomic_fps = sample_selection.FPS(n_to_select=n_envs, initialize="random").fit( + atom_soap_single_block + ) + print( + "atomic envs selected with FPS: \n (struct_idx, atom_idx, species_center) \n", + selector_atomic_fps.support.block(0).samples.values, + ) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ----All atomic environment selection----- + keys Labels( + species_center + 8 + 22 + 56 + ) + blocks TensorBlock + samples (12000): ['structure', 'center'] + components (): [] + properties (2688): ['species_neighbor_1', 'species_neighbor_2', 'l', 'n1', 'n2'] + gradients: None + samples in first block Labels( + structure center + 0 16 + 0 17 + ... + 499 30 + 499 31 + ) + atomic envs selected with FPS: + (struct_idx, atom_idx, species_center) + [[ 68 12 22] + [ 77 30 8] + [140 21 8] + [166 15 22] + [216 8 22] + [289 6 56] + [339 18 8] + [407 0 56] + [460 4 56] + [466 34 8]] + + + + +.. GENERATED FROM PYTHON SOURCE LINES 164-175 + +Perform structure (i.e. sample) selection with FPS/CUR +--------------------------------------------------------- + +Instead of atomic environments, one can also select diverse structures. We can +use the `sum_over_samples` operation in metatensor to define features in the +structural basis instead of the atomic basis. This is done by summing over the +atomic environments, labeled by the 'center' index in the samples of the +TensorMap. + +Alternatively, one could use the `mean_over_samples` operation, depending on +the specific inhomogeneity of the size of the structures in the training set. + +.. GENERATED FROM PYTHON SOURCE LINES 175-205 + +.. code-block:: Python + + + print("----Structure selection-----") + + # Define the number of structures to select *per block* using FPS + n_structures = 10 + + # FPS structure selection + selector_struct_fps = sample_selection.FPS( + n_to_select=n_structures, initialize="random" + ).fit(struct_soap) + struct_fps_idxs = selector_struct_fps.support.block(0).samples.values.flatten() + + print("structures selected with FPS:\n", struct_fps_idxs) + + # CUR structure selection + selector_struct_cur = sample_selection.CUR(n_to_select=n_structures).fit(struct_soap) + struct_cur_idxs = selector_struct_cur.support.block(0).samples.values.flatten() + print("structures selected with CUR:\n", struct_cur_idxs) + + + # Slice structure descriptor along axis 0 to contain only the selected structures + struct_soap_fps = struct_soap.block(0).values[struct_fps_idxs, :] + struct_soap_cur = struct_soap.block(0).values[struct_cur_idxs, :] + assert struct_soap_fps.shape == struct_soap_cur.shape + + print("Structure descriptor shape before selection ", struct_soap.block(0).values.shape) + print("Structure descriptor shape after selection (FPS)", struct_soap_fps.shape) + print("Structure descriptor shape after selection (CUR)", struct_soap_cur.shape) + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ----Structure selection----- + structures selected with FPS: + [ 15 71 140 167 172 257 317 326 356 496] + structures selected with CUR: + [ 39 40 68 110 140 326 386 398 438 476] + Structure descriptor shape before selection (500, 2688) + Structure descriptor shape after selection (FPS) (10, 2688) + Structure descriptor shape after selection (CUR) (10, 2688) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 206-215 + +Visualize selected structures +----------------------------- + +sklearn can be used to perform PCA dimensionality reduction on the SOAP +descriptors. The resulting PC coordinates can be used to visualize the the +data alongside their structures in a chemiscope widget. + +Note: chemiscope widgets are not currently integrated into our sphinx gallery: +coming soon. + +.. GENERATED FROM PYTHON SOURCE LINES 215-222 + +.. code-block:: Python + + + + # Generate a structure PCA + struct_soap_pca = PCA(n_components=2).fit_transform(struct_soap.block(0).values) + assert struct_soap_pca.shape == (n_frames, 2) + + + + + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 223-228 + +Plot the PCA map +~~~~~~~~~~~~~~~~ + +Notice how the selected points avoid the densely-sampled area, and cover +the periphery of the dataset + +.. GENERATED FROM PYTHON SOURCE LINES 228-245 + +.. code-block:: Python + + + # Matplotlib plot + fig, ax = plt.subplots(1, 1, figsize=(6, 4)) + scatter = ax.scatter(struct_soap_pca[:, 0], struct_soap_pca[:, 1], c="red") + ax.plot( + struct_soap_pca[struct_cur_idxs, 0], + struct_soap_pca[struct_cur_idxs, 1], + "ko", + fillstyle="none", + label="FPS selection", + ) + ax.set_xlabel("PCA[1]") + ax.set_ylabel("PCA[2]") + ax.legend() + fig.show() + + + + + +.. image-sg:: /examples/sample-selection/images/sphx_glr_sample-selection_001.png + :alt: sample selection + :srcset: /examples/sample-selection/images/sphx_glr_sample-selection_001.png + :class: sphx-glr-single-img + + + + + +.. GENERATED FROM PYTHON SOURCE LINES 246-250 + +Creates a chemiscope viewer +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Interactive viewer (only works in notebooks) + +.. GENERATED FROM PYTHON SOURCE LINES 250-305 + +.. code-block:: Python + + + # Selected level + selection_levels = [] + for i in range(len(frames)): + level = 0 + if i in struct_cur_idxs: + level += 1 + if i in struct_fps_idxs: + level += 2 + if level == 0: + level = "Not selected" + elif level == 1: + level = "CUR" + elif level == 2: + level = "FPS" + else: + level = "FPS+CUR" + selection_levels.append(level) + + properties = chemiscope.extract_properties(frames) + + properties.update( + { + "PC1": struct_soap_pca[:, 0], + "PC2": struct_soap_pca[:, 1], + "selection": np.array(selection_levels), + } + ) + + + # Display with chemiscope. This currently does not work - as raised in issue #8 + # https://github.com/lab-cosmo/software-cookbook/issues/8 + widget = chemiscope.show( + frames, + properties=properties, + settings={ + "map": { + "x": {"property": "PC1"}, + "y": {"property": "PC2"}, + "color": {"property": "energy"}, + "symbol": "selection", + "size": {"factor": 50}, + }, + "structure": [{"unitCell": True}], + }, + ) + + if chemiscope.jupyter._is_running_in_notebook(): + from IPython.display import display + + display(widget) + else: + widget.save("sample-selection.json.gz") + + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + /home/runner/work/software-cookbook/software-cookbook/.nox/sample-selection/lib/python3.11/site-packages/chemiscope/structures/_ase.py:90: UserWarning: the following structure properties properties are only defined for a subset of frames: ['stress']; they will be ignored + warnings.warn( + /home/runner/work/software-cookbook/software-cookbook/.nox/sample-selection/lib/python3.11/site-packages/chemiscope/jupyter.py:245: UserWarning: chemiscope.show only works inside a jupyter notebook + warnings.warn("chemiscope.show only works inside a jupyter notebook") + + + + +.. GENERATED FROM PYTHON SOURCE LINES 306-312 + +Perform feature selection +------------------------- + +Now perform feature selection. In this example we will go back to using the +descriptor decomposed into atomic environments, as opposed to the one +decomposed into structure environments, but only use FPS for brevity. + +.. GENERATED FROM PYTHON SOURCE LINES 312-339 + +.. code-block:: Python + + print("----Feature selection-----") + + # Define the number of features to select + n_features = 200 + + # FPS feature selection + feat_fps = feature_selection.FPS(n_to_select=n_features, initialize="random").fit( + atom_soap_single_block + ) + + # Slice atomic descriptor along axis 1 to contain only the selected features + # atom_soap_single_block_fps = atom_soap_single_block.block(0).values[:, feat_fps_idxs] + atom_soap_single_block_fps = metatensor.slice( + atom_soap_single_block, + axis="properties", + labels=feat_fps.support.block(0).properties, + ) + + print( + "atomic descriptor shape before selection ", + atom_soap_single_block.block(0).values.shape, + ) + print( + "atomic descriptor shape after selection ", + atom_soap_single_block_fps.block(0).values.shape, + ) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ----Feature selection----- + atomic descriptor shape before selection (20000, 2688) + atomic descriptor shape after selection (20000, 200) + + + + +.. GENERATED FROM PYTHON SOURCE LINES 342-348 + +Perform feature selection (skmatter) +------------------------------------ + +Now perform feature selection. In this example we will go back to using the +descriptor decomposed into atomic environments, as opposed to the one +decomposed into structure environments, but only use FPS for brevity. + +.. GENERATED FROM PYTHON SOURCE LINES 348-371 + +.. code-block:: Python + + + print("----Feature selection (skmatter)-----") + + # Define the number of features to select + n_features = 200 + + # FPS feature selection + feat_fps = skfeat_selection.FPS(n_to_select=n_features, initialize="random").fit( + atom_soap_single_block.block(0).values + ) + feat_fps_idxs = feat_fps.selected_idx_ + + print("Feature indices obtained with FPS ", feat_fps_idxs) + + # Slice atomic descriptor along axis 1 to contain only the selected features + atom_dscrptr_fps = atom_soap_single_block.block(0).values[:, feat_fps_idxs] + + print( + "atomic descriptor shape before selection ", + atom_soap_single_block.block(0).values.shape, + ) + print("atomic descriptor shape after selection ", atom_dscrptr_fps.shape) + + + + + +.. rst-class:: sphx-glr-script-out + + .. code-block:: none + + ----Feature selection (skmatter)----- + Feature indices obtained with FPS [2607 0 920 464 3 411 1 488 1824 921 5 465 29 1179 + 27 2240 468 1344 4 2244 602 923 489 274 1825 45 916 1180 + 28 1308 475 470 731 924 46 283 1828 474 450 30 491 2241 + 730 412 2084 12 477 1835 1636 859 476 1827 1796 496 413 931 + 936 21 453 1345 899 466 939 940 11 1816 1324 934 900 948 + 861 928 1490 19 860 925 2 1170 2276 456 1347 1819 1181 1310 + 13 858 1380 36 210 1372 1812 926 929 2195 947 458 1196 451 + 1307 492 2267 472 2212 915 462 449 733 725 922 18 37 2523 + 2532 1365 932 1746 347 473 868 912 502 275 927 1362 2246 1172 + 485 54 504 484 285 866 395 31 499 1348 480 1316 2092 38 + 1805 901 913 1941 723 944 2213 898 1187 1939 941 402 907 1364 + 6 1947 469 1309 467 490 1940 10 905 498 2242 1637 908 904 + 452 2083 942 1820 937 724 1171 500 933 338 420 2524 1682 2254 + 483 2221 22 1792 1764 494 7 738 949 9 2268 1832 1618 1323 + 478 482 950 461] + atomic descriptor shape before selection (20000, 2688) + atomic descriptor shape after selection (20000, 200) + + + + + +.. _sphx_glr_download_examples_sample-selection_sample-selection.py: + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-example + + + .. container:: sphx-glr-download + + :download:`Download Conda environment file: environment.yml ` + .. 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 ` + + +.. only:: html + + .. rst-class:: sphx-glr-signature + + `Gallery generated by Sphinx-Gallery `_ + diff --git a/latest/_sources/examples/sample-selection/sg_execution_times.rst.txt b/latest/_sources/examples/sample-selection/sg_execution_times.rst.txt new file mode 100644 index 00000000..0c361033 --- /dev/null +++ b/latest/_sources/examples/sample-selection/sg_execution_times.rst.txt @@ -0,0 +1,37 @@ + +:orphan: + +.. _sphx_glr_examples_sample-selection_sg_execution_times: + + +Computation times +================= +**00:25.276** total execution time for 1 file **from examples/sample-selection**: + +.. container:: + + .. raw:: html + + + + + + + + .. list-table:: + :header-rows: 1 + :class: table table-striped sg-datatable + + * - Example + - Time + - Mem (MB) + * - :ref:`sphx_glr_examples_sample-selection_sample-selection.py` (``sample-selection.py``) + - 00:25.276 + - 0.0 diff --git a/latest/_sources/index.rst.txt b/latest/_sources/index.rst.txt new file mode 100644 index 00000000..e720680c --- /dev/null +++ b/latest/_sources/index.rst.txt @@ -0,0 +1,32 @@ +COSMO Software Cookbook +======================= + +.. include:: ../../README.rst + :start-after: marker-intro-start + :end-before: marker-intro-end + + +All the examples provide an ``environment.yml`` file that you can download and +then use with conda to create a new environment with all the required +dependencies for this example. + +.. code-block:: bash + + # Pick a name for the environment and replace with it + conda env create --name --file environment.yml + + # when you want to use the environment + conda env activate --name + +.. toctree:: + :caption: Table of Contents + :maxdepth: 1 + + examples/dos-align/dos-align + examples/batch-cp2k/reference-trajectory + examples/path-integrals/path-integrals + examples/gaas-map/gaas-map + examples/lpr/lpr + examples/sample-selection/sample-selection + examples/lode-linear/lode-linear + examples/roy-gch/roy-gch diff --git a/latest/_static/basic.css b/latest/_static/basic.css new file mode 100644 index 00000000..f316efcb --- /dev/null +++ b/latest/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/latest/_static/binder_badge_logo.svg b/latest/_static/binder_badge_logo.svg new file mode 100644 index 00000000..327f6b63 --- /dev/null +++ b/latest/_static/binder_badge_logo.svg @@ -0,0 +1 @@ + launchlaunchbinderbinder \ No newline at end of file diff --git a/latest/_static/broken_example.png b/latest/_static/broken_example.png new file mode 100644 index 00000000..4fea24e7 Binary files /dev/null and b/latest/_static/broken_example.png differ diff --git a/latest/_static/debug.css b/latest/_static/debug.css new file mode 100644 index 00000000..74d4aec3 --- /dev/null +++ b/latest/_static/debug.css @@ -0,0 +1,69 @@ +/* + This CSS file should be overridden by the theme authors. It's + meant for debugging and developing the skeleton that this theme provides. +*/ +body { + font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; + background: lavender; +} +.sb-announcement { + background: rgb(131, 131, 131); +} +.sb-announcement__inner { + background: black; + color: white; +} +.sb-header { + background: lightskyblue; +} +.sb-header__inner { + background: royalblue; + color: white; +} +.sb-header-secondary { + background: lightcyan; +} +.sb-header-secondary__inner { + background: cornflowerblue; + color: white; +} +.sb-sidebar-primary { + background: lightgreen; +} +.sb-main { + background: blanchedalmond; +} +.sb-main__inner { + background: antiquewhite; +} +.sb-header-article { + background: lightsteelblue; +} +.sb-article-container { + background: snow; +} +.sb-article-main { + background: white; +} +.sb-footer-article { + background: lightpink; +} +.sb-sidebar-secondary { + background: lightgoldenrodyellow; +} +.sb-footer-content { + background: plum; +} +.sb-footer-content__inner { + background: palevioletred; +} +.sb-footer { + background: pink; +} +.sb-footer__inner { + background: salmon; +} +.sb-article { + background: white; +} diff --git a/latest/_static/doctools.js b/latest/_static/doctools.js new file mode 100644 index 00000000..4d67807d --- /dev/null +++ b/latest/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/latest/_static/documentation_options.js b/latest/_static/documentation_options.js new file mode 100644 index 00000000..7e4c114f --- /dev/null +++ b/latest/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/latest/_static/file.png b/latest/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/latest/_static/file.png differ diff --git a/latest/_static/jupyterlite_badge_logo.svg b/latest/_static/jupyterlite_badge_logo.svg new file mode 100644 index 00000000..5de36d7f --- /dev/null +++ b/latest/_static/jupyterlite_badge_logo.svg @@ -0,0 +1,3 @@ + + +launchlaunchlitelite \ No newline at end of file diff --git a/latest/_static/language_data.js b/latest/_static/language_data.js new file mode 100644 index 00000000..367b8ed8 --- /dev/null +++ b/latest/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/latest/_static/minus.png b/latest/_static/minus.png new file mode 100644 index 00000000..d96755fd Binary files /dev/null and b/latest/_static/minus.png differ diff --git a/latest/_static/no_image.png b/latest/_static/no_image.png new file mode 100644 index 00000000..8c2d48d5 Binary files /dev/null and b/latest/_static/no_image.png differ diff --git a/latest/_static/plus.png b/latest/_static/plus.png new file mode 100644 index 00000000..7107cec9 Binary files /dev/null and b/latest/_static/plus.png differ diff --git a/latest/_static/pygments.css b/latest/_static/pygments.css new file mode 100644 index 00000000..02b4b128 --- /dev/null +++ b/latest/_static/pygments.css @@ -0,0 +1,258 @@ +.highlight pre { line-height: 125%; } +.highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +.highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #204a87; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #ce5c00; font-weight: bold } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #000000; font-style: italic } /* Generic.Output */ +.highlight .gp { color: #8f5902 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #204a87; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #0000cf; font-weight: bold } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #204a87 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #204a87; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #204a87; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8 } /* Text.Whitespace */ +.highlight .mb { color: #0000cf; font-weight: bold } /* Literal.Number.Bin */ +.highlight .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */ +.highlight .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */ +.highlight .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */ +.highlight .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */ +@media not print { +body[data-theme="dark"] .highlight pre { line-height: 125%; } +body[data-theme="dark"] .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body[data-theme="dark"] .highlight .hll { background-color: #404040 } +body[data-theme="dark"] .highlight { background: #202020; color: #d0d0d0 } +body[data-theme="dark"] .highlight .c { color: #ababab; font-style: italic } /* Comment */ +body[data-theme="dark"] .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +body[data-theme="dark"] .highlight .esc { color: #d0d0d0 } /* Escape */ +body[data-theme="dark"] .highlight .g { color: #d0d0d0 } /* Generic */ +body[data-theme="dark"] .highlight .k { color: #6ebf26; font-weight: bold } /* Keyword */ +body[data-theme="dark"] .highlight .l { color: #d0d0d0 } /* Literal */ +body[data-theme="dark"] .highlight .n { color: #d0d0d0 } /* Name */ +body[data-theme="dark"] .highlight .o { color: #d0d0d0 } /* Operator */ +body[data-theme="dark"] .highlight .x { color: #d0d0d0 } /* Other */ +body[data-theme="dark"] .highlight .p { color: #d0d0d0 } /* Punctuation */ +body[data-theme="dark"] .highlight .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */ +body[data-theme="dark"] .highlight .cm { color: #ababab; font-style: italic } /* Comment.Multiline */ +body[data-theme="dark"] .highlight .cp { color: #ff3a3a; font-weight: bold } /* Comment.Preproc */ +body[data-theme="dark"] .highlight .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */ +body[data-theme="dark"] .highlight .c1 { color: #ababab; font-style: italic } /* Comment.Single */ +body[data-theme="dark"] .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body[data-theme="dark"] .highlight .gd { color: #ff3a3a } /* Generic.Deleted */ +body[data-theme="dark"] .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +body[data-theme="dark"] .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body[data-theme="dark"] .highlight .gr { color: #ff3a3a } /* Generic.Error */ +body[data-theme="dark"] .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +body[data-theme="dark"] .highlight .gi { color: #589819 } /* Generic.Inserted */ +body[data-theme="dark"] .highlight .go { color: #cccccc } /* Generic.Output */ +body[data-theme="dark"] .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +body[data-theme="dark"] .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +body[data-theme="dark"] .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +body[data-theme="dark"] .highlight .gt { color: #ff3a3a } /* Generic.Traceback */ +body[data-theme="dark"] .highlight .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */ +body[data-theme="dark"] .highlight .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */ +body[data-theme="dark"] .highlight .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */ +body[data-theme="dark"] .highlight .kp { color: #6ebf26 } /* Keyword.Pseudo */ +body[data-theme="dark"] .highlight .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */ +body[data-theme="dark"] .highlight .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */ +body[data-theme="dark"] .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +body[data-theme="dark"] .highlight .m { color: #51b2fd } /* Literal.Number */ +body[data-theme="dark"] .highlight .s { color: #ed9d13 } /* Literal.String */ +body[data-theme="dark"] .highlight .na { color: #bbbbbb } /* Name.Attribute */ +body[data-theme="dark"] .highlight .nb { color: #2fbccd } /* Name.Builtin */ +body[data-theme="dark"] .highlight .nc { color: #71adff; text-decoration: underline } /* Name.Class */ +body[data-theme="dark"] .highlight .no { color: #40ffff } /* Name.Constant */ +body[data-theme="dark"] .highlight .nd { color: #ffa500 } /* Name.Decorator */ +body[data-theme="dark"] .highlight .ni { color: #d0d0d0 } /* Name.Entity */ +body[data-theme="dark"] .highlight .ne { color: #bbbbbb } /* Name.Exception */ +body[data-theme="dark"] .highlight .nf { color: #71adff } /* Name.Function */ +body[data-theme="dark"] .highlight .nl { color: #d0d0d0 } /* Name.Label */ +body[data-theme="dark"] .highlight .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */ +body[data-theme="dark"] .highlight .nx { color: #d0d0d0 } /* Name.Other */ +body[data-theme="dark"] .highlight .py { color: #d0d0d0 } /* Name.Property */ +body[data-theme="dark"] .highlight .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */ +body[data-theme="dark"] .highlight .nv { color: #40ffff } /* Name.Variable */ +body[data-theme="dark"] .highlight .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */ +body[data-theme="dark"] .highlight .pm { color: #d0d0d0 } /* Punctuation.Marker */ +body[data-theme="dark"] .highlight .w { color: #666666 } /* Text.Whitespace */ +body[data-theme="dark"] .highlight .mb { color: #51b2fd } /* Literal.Number.Bin */ +body[data-theme="dark"] .highlight .mf { color: #51b2fd } /* Literal.Number.Float */ +body[data-theme="dark"] .highlight .mh { color: #51b2fd } /* Literal.Number.Hex */ +body[data-theme="dark"] .highlight .mi { color: #51b2fd } /* Literal.Number.Integer */ +body[data-theme="dark"] .highlight .mo { color: #51b2fd } /* Literal.Number.Oct */ +body[data-theme="dark"] .highlight .sa { color: #ed9d13 } /* Literal.String.Affix */ +body[data-theme="dark"] .highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +body[data-theme="dark"] .highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +body[data-theme="dark"] .highlight .dl { color: #ed9d13 } /* Literal.String.Delimiter */ +body[data-theme="dark"] .highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +body[data-theme="dark"] .highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +body[data-theme="dark"] .highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +body[data-theme="dark"] .highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +body[data-theme="dark"] .highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +body[data-theme="dark"] .highlight .sx { color: #ffa500 } /* Literal.String.Other */ +body[data-theme="dark"] .highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +body[data-theme="dark"] .highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +body[data-theme="dark"] .highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +body[data-theme="dark"] .highlight .bp { color: #2fbccd } /* Name.Builtin.Pseudo */ +body[data-theme="dark"] .highlight .fm { color: #71adff } /* Name.Function.Magic */ +body[data-theme="dark"] .highlight .vc { color: #40ffff } /* Name.Variable.Class */ +body[data-theme="dark"] .highlight .vg { color: #40ffff } /* Name.Variable.Global */ +body[data-theme="dark"] .highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +body[data-theme="dark"] .highlight .vm { color: #40ffff } /* Name.Variable.Magic */ +body[data-theme="dark"] .highlight .il { color: #51b2fd } /* Literal.Number.Integer.Long */ +@media (prefers-color-scheme: dark) { +body:not([data-theme="light"]) .highlight pre { line-height: 125%; } +body:not([data-theme="light"]) .highlight td.linenos .normal { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos { color: #aaaaaa; background-color: transparent; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +body:not([data-theme="light"]) .highlight .hll { background-color: #404040 } +body:not([data-theme="light"]) .highlight { background: #202020; color: #d0d0d0 } +body:not([data-theme="light"]) .highlight .c { color: #ababab; font-style: italic } /* Comment */ +body:not([data-theme="light"]) .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +body:not([data-theme="light"]) .highlight .esc { color: #d0d0d0 } /* Escape */ +body:not([data-theme="light"]) .highlight .g { color: #d0d0d0 } /* Generic */ +body:not([data-theme="light"]) .highlight .k { color: #6ebf26; font-weight: bold } /* Keyword */ +body:not([data-theme="light"]) .highlight .l { color: #d0d0d0 } /* Literal */ +body:not([data-theme="light"]) .highlight .n { color: #d0d0d0 } /* Name */ +body:not([data-theme="light"]) .highlight .o { color: #d0d0d0 } /* Operator */ +body:not([data-theme="light"]) .highlight .x { color: #d0d0d0 } /* Other */ +body:not([data-theme="light"]) .highlight .p { color: #d0d0d0 } /* Punctuation */ +body:not([data-theme="light"]) .highlight .ch { color: #ababab; font-style: italic } /* Comment.Hashbang */ +body:not([data-theme="light"]) .highlight .cm { color: #ababab; font-style: italic } /* Comment.Multiline */ +body:not([data-theme="light"]) .highlight .cp { color: #ff3a3a; font-weight: bold } /* Comment.Preproc */ +body:not([data-theme="light"]) .highlight .cpf { color: #ababab; font-style: italic } /* Comment.PreprocFile */ +body:not([data-theme="light"]) .highlight .c1 { color: #ababab; font-style: italic } /* Comment.Single */ +body:not([data-theme="light"]) .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +body:not([data-theme="light"]) .highlight .gd { color: #ff3a3a } /* Generic.Deleted */ +body:not([data-theme="light"]) .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +body:not([data-theme="light"]) .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +body:not([data-theme="light"]) .highlight .gr { color: #ff3a3a } /* Generic.Error */ +body:not([data-theme="light"]) .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +body:not([data-theme="light"]) .highlight .gi { color: #589819 } /* Generic.Inserted */ +body:not([data-theme="light"]) .highlight .go { color: #cccccc } /* Generic.Output */ +body:not([data-theme="light"]) .highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +body:not([data-theme="light"]) .highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +body:not([data-theme="light"]) .highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +body:not([data-theme="light"]) .highlight .gt { color: #ff3a3a } /* Generic.Traceback */ +body:not([data-theme="light"]) .highlight .kc { color: #6ebf26; font-weight: bold } /* Keyword.Constant */ +body:not([data-theme="light"]) .highlight .kd { color: #6ebf26; font-weight: bold } /* Keyword.Declaration */ +body:not([data-theme="light"]) .highlight .kn { color: #6ebf26; font-weight: bold } /* Keyword.Namespace */ +body:not([data-theme="light"]) .highlight .kp { color: #6ebf26 } /* Keyword.Pseudo */ +body:not([data-theme="light"]) .highlight .kr { color: #6ebf26; font-weight: bold } /* Keyword.Reserved */ +body:not([data-theme="light"]) .highlight .kt { color: #6ebf26; font-weight: bold } /* Keyword.Type */ +body:not([data-theme="light"]) .highlight .ld { color: #d0d0d0 } /* Literal.Date */ +body:not([data-theme="light"]) .highlight .m { color: #51b2fd } /* Literal.Number */ +body:not([data-theme="light"]) .highlight .s { color: #ed9d13 } /* Literal.String */ +body:not([data-theme="light"]) .highlight .na { color: #bbbbbb } /* Name.Attribute */ +body:not([data-theme="light"]) .highlight .nb { color: #2fbccd } /* Name.Builtin */ +body:not([data-theme="light"]) .highlight .nc { color: #71adff; text-decoration: underline } /* Name.Class */ +body:not([data-theme="light"]) .highlight .no { color: #40ffff } /* Name.Constant */ +body:not([data-theme="light"]) .highlight .nd { color: #ffa500 } /* Name.Decorator */ +body:not([data-theme="light"]) .highlight .ni { color: #d0d0d0 } /* Name.Entity */ +body:not([data-theme="light"]) .highlight .ne { color: #bbbbbb } /* Name.Exception */ +body:not([data-theme="light"]) .highlight .nf { color: #71adff } /* Name.Function */ +body:not([data-theme="light"]) .highlight .nl { color: #d0d0d0 } /* Name.Label */ +body:not([data-theme="light"]) .highlight .nn { color: #71adff; text-decoration: underline } /* Name.Namespace */ +body:not([data-theme="light"]) .highlight .nx { color: #d0d0d0 } /* Name.Other */ +body:not([data-theme="light"]) .highlight .py { color: #d0d0d0 } /* Name.Property */ +body:not([data-theme="light"]) .highlight .nt { color: #6ebf26; font-weight: bold } /* Name.Tag */ +body:not([data-theme="light"]) .highlight .nv { color: #40ffff } /* Name.Variable */ +body:not([data-theme="light"]) .highlight .ow { color: #6ebf26; font-weight: bold } /* Operator.Word */ +body:not([data-theme="light"]) .highlight .pm { color: #d0d0d0 } /* Punctuation.Marker */ +body:not([data-theme="light"]) .highlight .w { color: #666666 } /* Text.Whitespace */ +body:not([data-theme="light"]) .highlight .mb { color: #51b2fd } /* Literal.Number.Bin */ +body:not([data-theme="light"]) .highlight .mf { color: #51b2fd } /* Literal.Number.Float */ +body:not([data-theme="light"]) .highlight .mh { color: #51b2fd } /* Literal.Number.Hex */ +body:not([data-theme="light"]) .highlight .mi { color: #51b2fd } /* Literal.Number.Integer */ +body:not([data-theme="light"]) .highlight .mo { color: #51b2fd } /* Literal.Number.Oct */ +body:not([data-theme="light"]) .highlight .sa { color: #ed9d13 } /* Literal.String.Affix */ +body:not([data-theme="light"]) .highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +body:not([data-theme="light"]) .highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +body:not([data-theme="light"]) .highlight .dl { color: #ed9d13 } /* Literal.String.Delimiter */ +body:not([data-theme="light"]) .highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +body:not([data-theme="light"]) .highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +body:not([data-theme="light"]) .highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +body:not([data-theme="light"]) .highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +body:not([data-theme="light"]) .highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +body:not([data-theme="light"]) .highlight .sx { color: #ffa500 } /* Literal.String.Other */ +body:not([data-theme="light"]) .highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +body:not([data-theme="light"]) .highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +body:not([data-theme="light"]) .highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +body:not([data-theme="light"]) .highlight .bp { color: #2fbccd } /* Name.Builtin.Pseudo */ +body:not([data-theme="light"]) .highlight .fm { color: #71adff } /* Name.Function.Magic */ +body:not([data-theme="light"]) .highlight .vc { color: #40ffff } /* Name.Variable.Class */ +body:not([data-theme="light"]) .highlight .vg { color: #40ffff } /* Name.Variable.Global */ +body:not([data-theme="light"]) .highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +body:not([data-theme="light"]) .highlight .vm { color: #40ffff } /* Name.Variable.Magic */ +body:not([data-theme="light"]) .highlight .il { color: #51b2fd } /* Literal.Number.Integer.Long */ +} +} \ No newline at end of file diff --git a/latest/_static/scripts/furo-extensions.js b/latest/_static/scripts/furo-extensions.js new file mode 100644 index 00000000..e69de29b diff --git a/latest/_static/scripts/furo.js b/latest/_static/scripts/furo.js new file mode 100644 index 00000000..0267c7e1 --- /dev/null +++ b/latest/_static/scripts/furo.js @@ -0,0 +1,3 @@ +/*! For license information please see furo.js.LICENSE.txt */ +(()=>{var t={856:function(t,e,n){var o,r;r=void 0!==n.g?n.g:"undefined"!=typeof window?window:this,o=function(){return function(t){"use strict";var e={navClass:"active",contentClass:"active",nested:!1,nestedClass:"active",offset:0,reflow:!1,events:!0},n=function(t,e,n){if(n.settings.events){var o=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:n});e.dispatchEvent(o)}},o=function(t){var e=0;if(t.offsetParent)for(;t;)e+=t.offsetTop,t=t.offsetParent;return e>=0?e:0},r=function(t){t&&t.sort((function(t,e){return o(t.content)=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.body.clientHeight,document.documentElement.clientHeight)},l=function(t,e){var n=t[t.length-1];if(function(t,e){return!(!s()||!c(t.content,e,!0))}(n,e))return n;for(var o=t.length-1;o>=0;o--)if(c(t[o].content,e))return t[o]},a=function(t,e){if(e.nested&&t.parentNode){var n=t.parentNode.closest("li");n&&(n.classList.remove(e.nestedClass),a(n,e))}},i=function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.remove(e.navClass),t.content.classList.remove(e.contentClass),a(o,e),n("gumshoeDeactivate",o,{link:t.nav,content:t.content,settings:e}))}},u=function(t,e){if(e.nested){var n=t.parentNode.closest("li");n&&(n.classList.add(e.nestedClass),u(n,e))}};return function(o,c){var s,a,d,f,m,v={setup:function(){s=document.querySelectorAll(o),a=[],Array.prototype.forEach.call(s,(function(t){var e=document.getElementById(decodeURIComponent(t.hash.substr(1)));e&&a.push({nav:t,content:e})})),r(a)},detect:function(){var t=l(a,m);t?d&&t.content===d.content||(i(d,m),function(t,e){if(t){var o=t.nav.closest("li");o&&(o.classList.add(e.navClass),t.content.classList.add(e.contentClass),u(o,e),n("gumshoeActivate",o,{link:t.nav,content:t.content,settings:e}))}}(t,m),d=t):d&&(i(d,m),d=null)}},h=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame(v.detect)},g=function(e){f&&t.cancelAnimationFrame(f),f=t.requestAnimationFrame((function(){r(a),v.detect()}))};return v.destroy=function(){d&&i(d,m),t.removeEventListener("scroll",h,!1),m.reflow&&t.removeEventListener("resize",g,!1),a=null,s=null,d=null,f=null,m=null},m=function(){var t={};return Array.prototype.forEach.call(arguments,(function(e){for(var n in e){if(!e.hasOwnProperty(n))return;t[n]=e[n]}})),t}(e,c||{}),v.setup(),v.detect(),t.addEventListener("scroll",h,!1),m.reflow&&t.addEventListener("resize",g,!1),v}}(r)}.apply(e,[]),void 0===o||(t.exports=o)}},e={};function n(o){var r=e[o];if(void 0!==r)return r.exports;var c=e[o]={exports:{}};return t[o].call(c.exports,c,c.exports,n),c.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),(()=>{"use strict";var t=n(856),e=n.n(t),o=null,r=null,c=window.pageYOffset||document.documentElement.scrollTop;const s=64;function l(){const t=localStorage.getItem("theme")||"auto";var e;"light"!==(e=window.matchMedia("(prefers-color-scheme: dark)").matches?"auto"===t?"light":"light"==t?"dark":"auto":"auto"===t?"dark":"dark"==t?"light":"auto")&&"dark"!==e&&"auto"!==e&&(console.error(`Got invalid theme mode: ${e}. Resetting to auto.`),e="auto"),document.body.dataset.theme=e,localStorage.setItem("theme",e),console.log(`Changed to ${e} mode.`)}function a(){!function(){const t=document.getElementsByClassName("theme-toggle");Array.from(t).forEach((t=>{t.addEventListener("click",l)}))}(),function(){let t=0,e=!1;window.addEventListener("scroll",(function(n){t=window.scrollY,e||(window.requestAnimationFrame((function(){var n;n=t,0==Math.floor(r.getBoundingClientRect().top)?r.classList.add("scrolled"):r.classList.remove("scrolled"),function(t){tc&&document.documentElement.classList.remove("show-back-to-top"),c=t}(n),function(t){null!==o&&(0==t?o.scrollTo(0,0):Math.ceil(t)>=Math.floor(document.documentElement.scrollHeight-window.innerHeight)?o.scrollTo(0,o.scrollHeight):document.querySelector(".scroll-current"))}(n),e=!1})),e=!0)})),window.scroll()}(),null!==o&&new(e())(".toc-tree a",{reflow:!0,recursive:!0,navClass:"scroll-current",offset:()=>{let t=parseFloat(getComputedStyle(document.documentElement).fontSize);return r.getBoundingClientRect().height+2.5*t+1}})}document.addEventListener("DOMContentLoaded",(function(){document.body.parentNode.classList.remove("no-js"),r=document.querySelector("header"),o=document.querySelector(".toc-scroll"),a()}))})()})(); +//# sourceMappingURL=furo.js.map \ No newline at end of file diff --git a/latest/_static/scripts/furo.js.LICENSE.txt b/latest/_static/scripts/furo.js.LICENSE.txt new file mode 100644 index 00000000..1632189c --- /dev/null +++ b/latest/_static/scripts/furo.js.LICENSE.txt @@ -0,0 +1,7 @@ +/*! + * gumshoejs v5.1.2 (patched by @pradyunsg) + * A simple, framework-agnostic scrollspy script. + * (c) 2019 Chris Ferdinandi + * MIT License + * http://github.com/cferdinandi/gumshoe + */ diff --git a/latest/_static/scripts/furo.js.map b/latest/_static/scripts/furo.js.map new file mode 100644 index 00000000..c3b37aaa --- /dev/null +++ b/latest/_static/scripts/furo.js.map @@ -0,0 +1 @@ +{"version":3,"file":"scripts/furo.js","mappings":";iCAAA,MAQWA,SAWS,IAAX,EAAAC,EACH,EAAAA,EACkB,oBAAXC,OACLA,OACAC,KAbO,EAAF,WACP,OAaJ,SAAUD,GACR,aAMA,IAAIE,EAAW,CAEbC,SAAU,SACVC,aAAc,SAGdC,QAAQ,EACRC,YAAa,SAGbC,OAAQ,EACRC,QAAQ,EAGRC,QAAQ,GA6BNC,EAAY,SAAUC,EAAMC,EAAMC,GAEpC,GAAKA,EAAOC,SAASL,OAArB,CAGA,IAAIM,EAAQ,IAAIC,YAAYL,EAAM,CAChCM,SAAS,EACTC,YAAY,EACZL,OAAQA,IAIVD,EAAKO,cAAcJ,EAVgB,CAWrC,EAOIK,EAAe,SAAUR,GAC3B,IAAIS,EAAW,EACf,GAAIT,EAAKU,aACP,KAAOV,GACLS,GAAYT,EAAKW,UACjBX,EAAOA,EAAKU,aAGhB,OAAOD,GAAY,EAAIA,EAAW,CACpC,EAMIG,EAAe,SAAUC,GACvBA,GACFA,EAASC,MAAK,SAAUC,EAAOC,GAG7B,OAFcR,EAAaO,EAAME,SACnBT,EAAaQ,EAAMC,UACF,EACxB,CACT,GAEJ,EAwCIC,EAAW,SAAUlB,EAAME,EAAUiB,GACvC,IAAIC,EAASpB,EAAKqB,wBACd1B,EAnCU,SAAUO,GAExB,MAA+B,mBAApBA,EAASP,OACX2B,WAAWpB,EAASP,UAItB2B,WAAWpB,EAASP,OAC7B,CA2Be4B,CAAUrB,GACvB,OAAIiB,EAEAK,SAASJ,EAAOD,OAAQ,KACvB/B,EAAOqC,aAAeC,SAASC,gBAAgBC,cAG7CJ,SAASJ,EAAOS,IAAK,KAAOlC,CACrC,EAMImC,EAAa,WACf,OACEC,KAAKC,KAAK5C,EAAOqC,YAAcrC,EAAO6C,cAnCjCF,KAAKG,IACVR,SAASS,KAAKC,aACdV,SAASC,gBAAgBS,aACzBV,SAASS,KAAKE,aACdX,SAASC,gBAAgBU,aACzBX,SAASS,KAAKP,aACdF,SAASC,gBAAgBC,aAkC7B,EAmBIU,EAAY,SAAUzB,EAAUX,GAClC,IAAIqC,EAAO1B,EAASA,EAAS2B,OAAS,GACtC,GAbgB,SAAUC,EAAMvC,GAChC,SAAI4B,MAAgBZ,EAASuB,EAAKxB,QAASf,GAAU,GAEvD,CAUMwC,CAAYH,EAAMrC,GAAW,OAAOqC,EACxC,IAAK,IAAII,EAAI9B,EAAS2B,OAAS,EAAGG,GAAK,EAAGA,IACxC,GAAIzB,EAASL,EAAS8B,GAAG1B,QAASf,GAAW,OAAOW,EAAS8B,EAEjE,EAOIC,EAAmB,SAAUC,EAAK3C,GAEpC,GAAKA,EAAST,QAAWoD,EAAIC,WAA7B,CAGA,IAAIC,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASR,aAG7BkD,EAAiBG,EAAI7C,GAV0B,CAWjD,EAOIiD,EAAa,SAAUC,EAAOlD,GAEhC,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUC,OAAOhD,EAASX,UAC7B6D,EAAMnC,QAAQgC,UAAUC,OAAOhD,EAASV,cAGxCoD,EAAiBG,EAAI7C,GAGrBJ,EAAU,oBAAqBiD,EAAI,CACjCM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,EAOIoD,EAAiB,SAAUT,EAAK3C,GAElC,GAAKA,EAAST,OAAd,CAGA,IAAIsD,EAAKF,EAAIC,WAAWE,QAAQ,MAC3BD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASR,aAG1B4D,EAAeP,EAAI7C,GAVS,CAW9B,EA6LA,OA1JkB,SAAUsD,EAAUC,GAKpC,IACIC,EAAU7C,EAAU8C,EAASC,EAAS1D,EADtC2D,EAAa,CAUjBA,MAAmB,WAEjBH,EAAWhC,SAASoC,iBAAiBN,GAGrC3C,EAAW,GAGXkD,MAAMC,UAAUC,QAAQC,KAAKR,GAAU,SAAUjB,GAE/C,IAAIxB,EAAUS,SAASyC,eACrBC,mBAAmB3B,EAAK4B,KAAKC,OAAO,KAEjCrD,GAGLJ,EAAS0D,KAAK,CACZ1B,IAAKJ,EACLxB,QAASA,GAEb,IAGAL,EAAaC,EACf,EAKAgD,OAAoB,WAElB,IAAIW,EAASlC,EAAUzB,EAAUX,GAG5BsE,EASDb,GAAWa,EAAOvD,UAAY0C,EAAQ1C,UAG1CkC,EAAWQ,EAASzD,GAzFT,SAAUkD,EAAOlD,GAE9B,GAAKkD,EAAL,CAGA,IAAIL,EAAKK,EAAMP,IAAIG,QAAQ,MACtBD,IAGLA,EAAGE,UAAUM,IAAIrD,EAASX,UAC1B6D,EAAMnC,QAAQgC,UAAUM,IAAIrD,EAASV,cAGrC8D,EAAeP,EAAI7C,GAGnBJ,EAAU,kBAAmBiD,EAAI,CAC/BM,KAAMD,EAAMP,IACZ5B,QAASmC,EAAMnC,QACff,SAAUA,IAjBM,CAmBpB,CAqEIuE,CAASD,EAAQtE,GAGjByD,EAAUa,GAfJb,IACFR,EAAWQ,EAASzD,GACpByD,EAAU,KAchB,GAMIe,EAAgB,SAAUvE,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,sBAAsBf,EAAWgB,OACpD,EAMIC,EAAgB,SAAU3E,GAExByD,GACFxE,EAAOuF,qBAAqBf,GAI9BA,EAAUxE,EAAOwF,uBAAsB,WACrChE,EAAaC,GACbgD,EAAWgB,QACb,GACF,EAkDA,OA7CAhB,EAAWkB,QAAU,WAEfpB,GACFR,EAAWQ,EAASzD,GAItBd,EAAO4F,oBAAoB,SAAUN,GAAe,GAChDxE,EAASN,QACXR,EAAO4F,oBAAoB,SAAUF,GAAe,GAItDjE,EAAW,KACX6C,EAAW,KACXC,EAAU,KACVC,EAAU,KACV1D,EAAW,IACb,EAOEA,EA3XS,WACX,IAAI+E,EAAS,CAAC,EAOd,OANAlB,MAAMC,UAAUC,QAAQC,KAAKgB,WAAW,SAAUC,GAChD,IAAK,IAAIC,KAAOD,EAAK,CACnB,IAAKA,EAAIE,eAAeD,GAAM,OAC9BH,EAAOG,GAAOD,EAAIC,EACpB,CACF,IACOH,CACT,CAkXeK,CAAOhG,EAAUmE,GAAW,CAAC,GAGxCI,EAAW0B,QAGX1B,EAAWgB,SAGXzF,EAAOoG,iBAAiB,SAAUd,GAAe,GAC7CxE,EAASN,QACXR,EAAOoG,iBAAiB,SAAUV,GAAe,GAS9CjB,CACT,CAOF,CArcW4B,CAAQvG,EAChB,UAFM,SAEN,uBCXDwG,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAaE,QAGrB,IAAIC,EAASN,EAAyBE,GAAY,CAGjDG,QAAS,CAAC,GAOX,OAHAE,EAAoBL,GAAU1B,KAAK8B,EAAOD,QAASC,EAAQA,EAAOD,QAASJ,GAGpEK,EAAOD,OACf,CCrBAJ,EAAoBO,EAAKF,IACxB,IAAIG,EAASH,GAAUA,EAAOI,WAC7B,IAAOJ,EAAiB,QACxB,IAAM,EAEP,OADAL,EAAoBU,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,CAAM,ECLdR,EAAoBU,EAAI,CAACN,EAASQ,KACjC,IAAI,IAAInB,KAAOmB,EACXZ,EAAoBa,EAAED,EAAYnB,KAASO,EAAoBa,EAAET,EAASX,IAC5EqB,OAAOC,eAAeX,EAASX,EAAK,CAAEuB,YAAY,EAAMC,IAAKL,EAAWnB,IAE1E,ECNDO,EAAoBxG,EAAI,WACvB,GAA0B,iBAAf0H,WAAyB,OAAOA,WAC3C,IACC,OAAOxH,MAAQ,IAAIyH,SAAS,cAAb,EAChB,CAAE,MAAOC,GACR,GAAsB,iBAAX3H,OAAqB,OAAOA,MACxC,CACA,CAPuB,GCAxBuG,EAAoBa,EAAI,CAACrB,EAAK6B,IAAUP,OAAOzC,UAAUqB,eAAenB,KAAKiB,EAAK6B,4CCK9EC,EAAY,KACZC,EAAS,KACTC,EAAgB/H,OAAO6C,aAAeP,SAASC,gBAAgByF,UACnE,MAAMC,EAAmB,GA2EzB,SAASC,IACP,MAAMC,EAAeC,aAAaC,QAAQ,UAAY,OAZxD,IAAkBC,EACH,WADGA,EAaItI,OAAOuI,WAAW,gCAAgCC,QAI/C,SAAjBL,EACO,QACgB,SAAhBA,EACA,OAEA,OAIU,SAAjBA,EACO,OACgB,QAAhBA,EACA,QAEA,SA9BoB,SAATG,GAA4B,SAATA,IACzCG,QAAQC,MAAM,2BAA2BJ,yBACzCA,EAAO,QAGThG,SAASS,KAAK4F,QAAQC,MAAQN,EAC9BF,aAAaS,QAAQ,QAASP,GAC9BG,QAAQK,IAAI,cAAcR,UA0B5B,CAkDA,SAASnC,KART,WAEE,MAAM4C,EAAUzG,SAAS0G,uBAAuB,gBAChDrE,MAAMsE,KAAKF,GAASlE,SAASqE,IAC3BA,EAAI9C,iBAAiB,QAAS8B,EAAe,GAEjD,CAGEiB,GA9CF,WAEE,IAAIC,EAA6B,EAC7BC,GAAU,EAEdrJ,OAAOoG,iBAAiB,UAAU,SAAUuB,GAC1CyB,EAA6BpJ,OAAOsJ,QAE/BD,IACHrJ,OAAOwF,uBAAsB,WAzDnC,IAAuB+D,IA0DDH,EA9GkC,GAAlDzG,KAAK6G,MAAM1B,EAAO7F,wBAAwBQ,KAC5CqF,EAAOjE,UAAUM,IAAI,YAErB2D,EAAOjE,UAAUC,OAAO,YAI5B,SAAmCyF,GAC7BA,EAAYtB,EACd3F,SAASC,gBAAgBsB,UAAUC,OAAO,oBAEtCyF,EAAYxB,EACdzF,SAASC,gBAAgBsB,UAAUM,IAAI,oBAC9BoF,EAAYxB,GACrBzF,SAASC,gBAAgBsB,UAAUC,OAAO,oBAG9CiE,EAAgBwB,CAClB,CAoCEE,CAA0BF,GAlC5B,SAA6BA,GACT,OAAd1B,IAKa,GAAb0B,EACF1B,EAAU6B,SAAS,EAAG,GAGtB/G,KAAKC,KAAK2G,IACV5G,KAAK6G,MAAMlH,SAASC,gBAAgBS,aAAehD,OAAOqC,aAE1DwF,EAAU6B,SAAS,EAAG7B,EAAU7E,cAGhBV,SAASqH,cAAc,mBAc3C,CAKEC,CAAoBL,GAwDdF,GAAU,CACZ,IAEAA,GAAU,EAEd,IACArJ,OAAO6J,QACT,CA6BEC,GA1BkB,OAAdjC,GAKJ,IAAI,IAAJ,CAAY,cAAe,CACzBrH,QAAQ,EACRuJ,WAAW,EACX5J,SAAU,iBACVI,OAAQ,KACN,IAAIyJ,EAAM9H,WAAW+H,iBAAiB3H,SAASC,iBAAiB2H,UAChE,OAAOpC,EAAO7F,wBAAwBkI,OAAS,IAAMH,EAAM,CAAC,GAiBlE,CAcA1H,SAAS8D,iBAAiB,oBAT1B,WACE9D,SAASS,KAAKW,WAAWG,UAAUC,OAAO,SAE1CgE,EAASxF,SAASqH,cAAc,UAChC9B,EAAYvF,SAASqH,cAAc,eAEnCxD,GACF","sources":["webpack:///./src/furo/assets/scripts/gumshoe-patched.js","webpack:///webpack/bootstrap","webpack:///webpack/runtime/compat get default export","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/global","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///./src/furo/assets/scripts/furo.js"],"sourcesContent":["/*!\n * gumshoejs v5.1.2 (patched by @pradyunsg)\n * A simple, framework-agnostic scrollspy script.\n * (c) 2019 Chris Ferdinandi\n * MIT License\n * http://github.com/cferdinandi/gumshoe\n */\n\n(function (root, factory) {\n if (typeof define === \"function\" && define.amd) {\n define([], function () {\n return factory(root);\n });\n } else if (typeof exports === \"object\") {\n module.exports = factory(root);\n } else {\n root.Gumshoe = factory(root);\n }\n})(\n typeof global !== \"undefined\"\n ? global\n : typeof window !== \"undefined\"\n ? window\n : this,\n function (window) {\n \"use strict\";\n\n //\n // Defaults\n //\n\n var defaults = {\n // Active classes\n navClass: \"active\",\n contentClass: \"active\",\n\n // Nested navigation\n nested: false,\n nestedClass: \"active\",\n\n // Offset & reflow\n offset: 0,\n reflow: false,\n\n // Event support\n events: true,\n };\n\n //\n // Methods\n //\n\n /**\n * Merge two or more objects together.\n * @param {Object} objects The objects to merge together\n * @returns {Object} Merged values of defaults and options\n */\n var extend = function () {\n var merged = {};\n Array.prototype.forEach.call(arguments, function (obj) {\n for (var key in obj) {\n if (!obj.hasOwnProperty(key)) return;\n merged[key] = obj[key];\n }\n });\n return merged;\n };\n\n /**\n * Emit a custom event\n * @param {String} type The event type\n * @param {Node} elem The element to attach the event to\n * @param {Object} detail Any details to pass along with the event\n */\n var emitEvent = function (type, elem, detail) {\n // Make sure events are enabled\n if (!detail.settings.events) return;\n\n // Create a new event\n var event = new CustomEvent(type, {\n bubbles: true,\n cancelable: true,\n detail: detail,\n });\n\n // Dispatch the event\n elem.dispatchEvent(event);\n };\n\n /**\n * Get an element's distance from the top of the Document.\n * @param {Node} elem The element\n * @return {Number} Distance from the top in pixels\n */\n var getOffsetTop = function (elem) {\n var location = 0;\n if (elem.offsetParent) {\n while (elem) {\n location += elem.offsetTop;\n elem = elem.offsetParent;\n }\n }\n return location >= 0 ? location : 0;\n };\n\n /**\n * Sort content from first to last in the DOM\n * @param {Array} contents The content areas\n */\n var sortContents = function (contents) {\n if (contents) {\n contents.sort(function (item1, item2) {\n var offset1 = getOffsetTop(item1.content);\n var offset2 = getOffsetTop(item2.content);\n if (offset1 < offset2) return -1;\n return 1;\n });\n }\n };\n\n /**\n * Get the offset to use for calculating position\n * @param {Object} settings The settings for this instantiation\n * @return {Float} The number of pixels to offset the calculations\n */\n var getOffset = function (settings) {\n // if the offset is a function run it\n if (typeof settings.offset === \"function\") {\n return parseFloat(settings.offset());\n }\n\n // Otherwise, return it as-is\n return parseFloat(settings.offset);\n };\n\n /**\n * Get the document element's height\n * @private\n * @returns {Number}\n */\n var getDocumentHeight = function () {\n return Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight,\n document.body.offsetHeight,\n document.documentElement.offsetHeight,\n document.body.clientHeight,\n document.documentElement.clientHeight,\n );\n };\n\n /**\n * Determine if an element is in view\n * @param {Node} elem The element\n * @param {Object} settings The settings for this instantiation\n * @param {Boolean} bottom If true, check if element is above bottom of viewport instead\n * @return {Boolean} Returns true if element is in the viewport\n */\n var isInView = function (elem, settings, bottom) {\n var bounds = elem.getBoundingClientRect();\n var offset = getOffset(settings);\n if (bottom) {\n return (\n parseInt(bounds.bottom, 10) <\n (window.innerHeight || document.documentElement.clientHeight)\n );\n }\n return parseInt(bounds.top, 10) <= offset;\n };\n\n /**\n * Check if at the bottom of the viewport\n * @return {Boolean} If true, page is at the bottom of the viewport\n */\n var isAtBottom = function () {\n if (\n Math.ceil(window.innerHeight + window.pageYOffset) >=\n getDocumentHeight()\n )\n return true;\n return false;\n };\n\n /**\n * Check if the last item should be used (even if not at the top of the page)\n * @param {Object} item The last item\n * @param {Object} settings The settings for this instantiation\n * @return {Boolean} If true, use the last item\n */\n var useLastItem = function (item, settings) {\n if (isAtBottom() && isInView(item.content, settings, true)) return true;\n return false;\n };\n\n /**\n * Get the active content\n * @param {Array} contents The content areas\n * @param {Object} settings The settings for this instantiation\n * @return {Object} The content area and matching navigation link\n */\n var getActive = function (contents, settings) {\n var last = contents[contents.length - 1];\n if (useLastItem(last, settings)) return last;\n for (var i = contents.length - 1; i >= 0; i--) {\n if (isInView(contents[i].content, settings)) return contents[i];\n }\n };\n\n /**\n * Deactivate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var deactivateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested || !nav.parentNode) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Remove the active class\n li.classList.remove(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n deactivateNested(li, settings);\n };\n\n /**\n * Deactivate a nav and content area\n * @param {Object} items The nav item and content to deactivate\n * @param {Object} settings The settings for this instantiation\n */\n var deactivate = function (items, settings) {\n // Make sure there are items to deactivate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Remove the active class from the nav and content\n li.classList.remove(settings.navClass);\n items.content.classList.remove(settings.contentClass);\n\n // Deactivate any parent navs in a nested navigation\n deactivateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeDeactivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Activate parent navs in a nested navigation\n * @param {Node} nav The starting navigation element\n * @param {Object} settings The settings for this instantiation\n */\n var activateNested = function (nav, settings) {\n // If nesting isn't activated, bail\n if (!settings.nested) return;\n\n // Get the parent navigation\n var li = nav.parentNode.closest(\"li\");\n if (!li) return;\n\n // Add the active class\n li.classList.add(settings.nestedClass);\n\n // Apply recursively to any parent navigation elements\n activateNested(li, settings);\n };\n\n /**\n * Activate a nav and content area\n * @param {Object} items The nav item and content to activate\n * @param {Object} settings The settings for this instantiation\n */\n var activate = function (items, settings) {\n // Make sure there are items to activate\n if (!items) return;\n\n // Get the parent list item\n var li = items.nav.closest(\"li\");\n if (!li) return;\n\n // Add the active class to the nav and content\n li.classList.add(settings.navClass);\n items.content.classList.add(settings.contentClass);\n\n // Activate any parent navs in a nested navigation\n activateNested(li, settings);\n\n // Emit a custom event\n emitEvent(\"gumshoeActivate\", li, {\n link: items.nav,\n content: items.content,\n settings: settings,\n });\n };\n\n /**\n * Create the Constructor object\n * @param {String} selector The selector to use for navigation items\n * @param {Object} options User options and settings\n */\n var Constructor = function (selector, options) {\n //\n // Variables\n //\n\n var publicAPIs = {};\n var navItems, contents, current, timeout, settings;\n\n //\n // Methods\n //\n\n /**\n * Set variables from DOM elements\n */\n publicAPIs.setup = function () {\n // Get all nav items\n navItems = document.querySelectorAll(selector);\n\n // Create contents array\n contents = [];\n\n // Loop through each item, get it's matching content, and push to the array\n Array.prototype.forEach.call(navItems, function (item) {\n // Get the content for the nav item\n var content = document.getElementById(\n decodeURIComponent(item.hash.substr(1)),\n );\n if (!content) return;\n\n // Push to the contents array\n contents.push({\n nav: item,\n content: content,\n });\n });\n\n // Sort contents by the order they appear in the DOM\n sortContents(contents);\n };\n\n /**\n * Detect which content is currently active\n */\n publicAPIs.detect = function () {\n // Get the active content\n var active = getActive(contents, settings);\n\n // if there's no active content, deactivate and bail\n if (!active) {\n if (current) {\n deactivate(current, settings);\n current = null;\n }\n return;\n }\n\n // If the active content is the one currently active, do nothing\n if (current && active.content === current.content) return;\n\n // Deactivate the current content and activate the new content\n deactivate(current, settings);\n activate(active, settings);\n\n // Update the currently active content\n current = active;\n };\n\n /**\n * Detect the active content on scroll\n * Debounced for performance\n */\n var scrollHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(publicAPIs.detect);\n };\n\n /**\n * Update content sorting on resize\n * Debounced for performance\n */\n var resizeHandler = function (event) {\n // If there's a timer, cancel it\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n // Setup debounce callback\n timeout = window.requestAnimationFrame(function () {\n sortContents(contents);\n publicAPIs.detect();\n });\n };\n\n /**\n * Destroy the current instantiation\n */\n publicAPIs.destroy = function () {\n // Undo DOM changes\n if (current) {\n deactivate(current, settings);\n }\n\n // Remove event listeners\n window.removeEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.removeEventListener(\"resize\", resizeHandler, false);\n }\n\n // Reset variables\n contents = null;\n navItems = null;\n current = null;\n timeout = null;\n settings = null;\n };\n\n /**\n * Initialize the current instantiation\n */\n var init = function () {\n // Merge user options into defaults\n settings = extend(defaults, options || {});\n\n // Setup variables based on the current DOM\n publicAPIs.setup();\n\n // Find the currently active content\n publicAPIs.detect();\n\n // Setup event listeners\n window.addEventListener(\"scroll\", scrollHandler, false);\n if (settings.reflow) {\n window.addEventListener(\"resize\", resizeHandler, false);\n }\n };\n\n //\n // Initialize and return the public APIs\n //\n\n init();\n return publicAPIs;\n };\n\n //\n // Return the Constructor\n //\n\n return Constructor;\n },\n);\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import Gumshoe from \"./gumshoe-patched.js\";\n\n////////////////////////////////////////////////////////////////////////////////\n// Scroll Handling\n////////////////////////////////////////////////////////////////////////////////\nvar tocScroll = null;\nvar header = null;\nvar lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;\nconst GO_TO_TOP_OFFSET = 64;\n\nfunction scrollHandlerForHeader() {\n if (Math.floor(header.getBoundingClientRect().top) == 0) {\n header.classList.add(\"scrolled\");\n } else {\n header.classList.remove(\"scrolled\");\n }\n}\n\nfunction scrollHandlerForBackToTop(positionY) {\n if (positionY < GO_TO_TOP_OFFSET) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n } else {\n if (positionY < lastScrollTop) {\n document.documentElement.classList.add(\"show-back-to-top\");\n } else if (positionY > lastScrollTop) {\n document.documentElement.classList.remove(\"show-back-to-top\");\n }\n }\n lastScrollTop = positionY;\n}\n\nfunction scrollHandlerForTOC(positionY) {\n if (tocScroll === null) {\n return;\n }\n\n // top of page.\n if (positionY == 0) {\n tocScroll.scrollTo(0, 0);\n } else if (\n // bottom of page.\n Math.ceil(positionY) >=\n Math.floor(document.documentElement.scrollHeight - window.innerHeight)\n ) {\n tocScroll.scrollTo(0, tocScroll.scrollHeight);\n } else {\n // somewhere in the middle.\n const current = document.querySelector(\".scroll-current\");\n if (current == null) {\n return;\n }\n\n // https://github.com/pypa/pip/issues/9159 This breaks scroll behaviours.\n // // scroll the currently \"active\" heading in toc, into view.\n // const rect = current.getBoundingClientRect();\n // if (0 > rect.top) {\n // current.scrollIntoView(true); // the argument is \"alignTop\"\n // } else if (rect.bottom > window.innerHeight) {\n // current.scrollIntoView(false);\n // }\n }\n}\n\nfunction scrollHandler(positionY) {\n scrollHandlerForHeader();\n scrollHandlerForBackToTop(positionY);\n scrollHandlerForTOC(positionY);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Theme Toggle\n////////////////////////////////////////////////////////////////////////////////\nfunction setTheme(mode) {\n if (mode !== \"light\" && mode !== \"dark\" && mode !== \"auto\") {\n console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);\n mode = \"auto\";\n }\n\n document.body.dataset.theme = mode;\n localStorage.setItem(\"theme\", mode);\n console.log(`Changed to ${mode} mode.`);\n}\n\nfunction cycleThemeOnce() {\n const currentTheme = localStorage.getItem(\"theme\") || \"auto\";\n const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n\n if (prefersDark) {\n // Auto (dark) -> Light -> Dark\n if (currentTheme === \"auto\") {\n setTheme(\"light\");\n } else if (currentTheme == \"light\") {\n setTheme(\"dark\");\n } else {\n setTheme(\"auto\");\n }\n } else {\n // Auto (light) -> Dark -> Light\n if (currentTheme === \"auto\") {\n setTheme(\"dark\");\n } else if (currentTheme == \"dark\") {\n setTheme(\"light\");\n } else {\n setTheme(\"auto\");\n }\n }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Setup\n////////////////////////////////////////////////////////////////////////////////\nfunction setupScrollHandler() {\n // Taken from https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event\n let last_known_scroll_position = 0;\n let ticking = false;\n\n window.addEventListener(\"scroll\", function (e) {\n last_known_scroll_position = window.scrollY;\n\n if (!ticking) {\n window.requestAnimationFrame(function () {\n scrollHandler(last_known_scroll_position);\n ticking = false;\n });\n\n ticking = true;\n }\n });\n window.scroll();\n}\n\nfunction setupScrollSpy() {\n if (tocScroll === null) {\n return;\n }\n\n // Scrollspy -- highlight table on contents, based on scroll\n new Gumshoe(\".toc-tree a\", {\n reflow: true,\n recursive: true,\n navClass: \"scroll-current\",\n offset: () => {\n let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);\n return header.getBoundingClientRect().height + 2.5 * rem + 1;\n },\n });\n}\n\nfunction setupTheme() {\n // Attach event handlers for toggling themes\n const buttons = document.getElementsByClassName(\"theme-toggle\");\n Array.from(buttons).forEach((btn) => {\n btn.addEventListener(\"click\", cycleThemeOnce);\n });\n}\n\nfunction setup() {\n setupTheme();\n setupScrollHandler();\n setupScrollSpy();\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Main entrypoint\n////////////////////////////////////////////////////////////////////////////////\nfunction main() {\n document.body.parentNode.classList.remove(\"no-js\");\n\n header = document.querySelector(\"header\");\n tocScroll = document.querySelector(\".toc-scroll\");\n\n setup();\n}\n\ndocument.addEventListener(\"DOMContentLoaded\", main);\n"],"names":["root","g","window","this","defaults","navClass","contentClass","nested","nestedClass","offset","reflow","events","emitEvent","type","elem","detail","settings","event","CustomEvent","bubbles","cancelable","dispatchEvent","getOffsetTop","location","offsetParent","offsetTop","sortContents","contents","sort","item1","item2","content","isInView","bottom","bounds","getBoundingClientRect","parseFloat","getOffset","parseInt","innerHeight","document","documentElement","clientHeight","top","isAtBottom","Math","ceil","pageYOffset","max","body","scrollHeight","offsetHeight","getActive","last","length","item","useLastItem","i","deactivateNested","nav","parentNode","li","closest","classList","remove","deactivate","items","link","activateNested","add","selector","options","navItems","current","timeout","publicAPIs","querySelectorAll","Array","prototype","forEach","call","getElementById","decodeURIComponent","hash","substr","push","active","activate","scrollHandler","cancelAnimationFrame","requestAnimationFrame","detect","resizeHandler","destroy","removeEventListener","merged","arguments","obj","key","hasOwnProperty","extend","setup","addEventListener","factory","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","n","getter","__esModule","d","a","definition","o","Object","defineProperty","enumerable","get","globalThis","Function","e","prop","tocScroll","header","lastScrollTop","scrollTop","GO_TO_TOP_OFFSET","cycleThemeOnce","currentTheme","localStorage","getItem","mode","matchMedia","matches","console","error","dataset","theme","setItem","log","buttons","getElementsByClassName","from","btn","setupTheme","last_known_scroll_position","ticking","scrollY","positionY","floor","scrollHandlerForBackToTop","scrollTo","querySelector","scrollHandlerForTOC","scroll","setupScrollHandler","recursive","rem","getComputedStyle","fontSize","height"],"sourceRoot":""} \ No newline at end of file diff --git a/latest/_static/searchtools.js b/latest/_static/searchtools.js new file mode 100644 index 00000000..92da3f8b --- /dev/null +++ b/latest/_static/searchtools.js @@ -0,0 +1,619 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlinks", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/latest/_static/sg_gallery-binder.css b/latest/_static/sg_gallery-binder.css new file mode 100644 index 00000000..420005d2 --- /dev/null +++ b/latest/_static/sg_gallery-binder.css @@ -0,0 +1,11 @@ +/* CSS for binder integration */ + +div.binder-badge { + margin: 1em auto; + vertical-align: middle; +} + +div.lite-badge { + margin: 1em auto; + vertical-align: middle; +} diff --git a/latest/_static/sg_gallery-dataframe.css b/latest/_static/sg_gallery-dataframe.css new file mode 100644 index 00000000..fac74c43 --- /dev/null +++ b/latest/_static/sg_gallery-dataframe.css @@ -0,0 +1,47 @@ +/* Pandas dataframe css */ +/* Taken from: https://github.com/spatialaudio/nbsphinx/blob/fb3ba670fc1ba5f54d4c487573dbc1b4ecf7e9ff/src/nbsphinx.py#L587-L619 */ +html[data-theme="light"] { + --sg-text-color: #000; + --sg-tr-odd-color: #f5f5f5; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); +} +html[data-theme="dark"] { + --sg-text-color: #fff; + --sg-tr-odd-color: #373737; + --sg-tr-hover-color: rgba(30, 81, 122, 0.2); +} + +table.dataframe { + border: none !important; + border-collapse: collapse; + border-spacing: 0; + border-color: transparent; + color: var(--sg-text-color); + font-size: 12px; + table-layout: fixed; + width: auto; +} +table.dataframe thead { + border-bottom: 1px solid var(--sg-text-color); + vertical-align: bottom; +} +table.dataframe tr, +table.dataframe th, +table.dataframe td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +table.dataframe th { + font-weight: bold; +} +table.dataframe tbody tr:nth-child(odd) { + background: var(--sg-tr-odd-color); +} +table.dataframe tbody tr:hover { + background: var(--sg-tr-hover-color); +} diff --git a/latest/_static/sg_gallery-rendered-html.css b/latest/_static/sg_gallery-rendered-html.css new file mode 100644 index 00000000..93dc2ffb --- /dev/null +++ b/latest/_static/sg_gallery-rendered-html.css @@ -0,0 +1,224 @@ +/* Adapted from notebook/static/style/style.min.css */ +html[data-theme="light"] { + --sg-text-color: #000; + --sg-background-color: #ffffff; + --sg-code-background-color: #eff0f1; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); + --sg-tr-odd-color: #f5f5f5; +} +html[data-theme="dark"] { + --sg-text-color: #fff; + --sg-background-color: #121212; + --sg-code-background-color: #2f2f30; + --sg-tr-hover-color: rgba(66, 165, 245, 0.2); + --sg-tr-odd-color: #1f1f1f; +} + +.rendered_html { + color: var(--sg-text-color); + /* any extras will just be numbers: */ +} +.rendered_html em { + font-style: italic; +} +.rendered_html strong { + font-weight: bold; +} +.rendered_html u { + text-decoration: underline; +} +.rendered_html :link { + text-decoration: underline; +} +.rendered_html :visited { + text-decoration: underline; +} +.rendered_html h1 { + font-size: 185.7%; + margin: 1.08em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h2 { + font-size: 157.1%; + margin: 1.27em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h3 { + font-size: 128.6%; + margin: 1.55em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h4 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; +} +.rendered_html h5 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; + font-style: italic; +} +.rendered_html h6 { + font-size: 100%; + margin: 2em 0 0 0; + font-weight: bold; + line-height: 1.0; + font-style: italic; +} +.rendered_html h1:first-child { + margin-top: 0.538em; +} +.rendered_html h2:first-child { + margin-top: 0.636em; +} +.rendered_html h3:first-child { + margin-top: 0.777em; +} +.rendered_html h4:first-child { + margin-top: 1em; +} +.rendered_html h5:first-child { + margin-top: 1em; +} +.rendered_html h6:first-child { + margin-top: 1em; +} +.rendered_html ul:not(.list-inline), +.rendered_html ol:not(.list-inline) { + padding-left: 2em; +} +.rendered_html ul { + list-style: disc; +} +.rendered_html ul ul { + list-style: square; + margin-top: 0; +} +.rendered_html ul ul ul { + list-style: circle; +} +.rendered_html ol { + list-style: decimal; +} +.rendered_html ol ol { + list-style: upper-alpha; + margin-top: 0; +} +.rendered_html ol ol ol { + list-style: lower-alpha; +} +.rendered_html ol ol ol ol { + list-style: lower-roman; +} +.rendered_html ol ol ol ol ol { + list-style: decimal; +} +.rendered_html * + ul { + margin-top: 1em; +} +.rendered_html * + ol { + margin-top: 1em; +} +.rendered_html hr { + color: var(--sg-text-color); + background-color: var(--sg-text-color); +} +.rendered_html pre { + margin: 1em 2em; + padding: 0px; + background-color: var(--sg-background-color); +} +.rendered_html code { + background-color: var(--sg-code-background-color); +} +.rendered_html p code { + padding: 1px 5px; +} +.rendered_html pre code { + background-color: var(--sg-background-color); +} +.rendered_html pre, +.rendered_html code { + border: 0; + color: var(--sg-text-color); + font-size: 100%; +} +.rendered_html blockquote { + margin: 1em 2em; +} +.rendered_html table { + margin-left: auto; + margin-right: auto; + border: none; + border-collapse: collapse; + border-spacing: 0; + color: var(--sg-text-color); + font-size: 12px; + table-layout: fixed; +} +.rendered_html thead { + border-bottom: 1px solid var(--sg-text-color); + vertical-align: bottom; +} +.rendered_html tr, +.rendered_html th, +.rendered_html td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} +.rendered_html th { + font-weight: bold; +} +.rendered_html tbody tr:nth-child(odd) { + background: var(--sg-tr-odd-color); +} +.rendered_html tbody tr:hover { + color: var(--sg-text-color); + background: var(--sg-tr-hover-color); +} +.rendered_html * + table { + margin-top: 1em; +} +.rendered_html p { + text-align: left; +} +.rendered_html * + p { + margin-top: 1em; +} +.rendered_html img { + display: block; + margin-left: auto; + margin-right: auto; +} +.rendered_html * + img { + margin-top: 1em; +} +.rendered_html img, +.rendered_html svg { + max-width: 100%; + height: auto; +} +.rendered_html img.unconfined, +.rendered_html svg.unconfined { + max-width: none; +} +.rendered_html .alert { + margin-bottom: initial; +} +.rendered_html * + .alert { + margin-top: 1em; +} +[dir="rtl"] .rendered_html p { + text-align: right; +} diff --git a/latest/_static/sg_gallery.css b/latest/_static/sg_gallery.css new file mode 100644 index 00000000..72227837 --- /dev/null +++ b/latest/_static/sg_gallery.css @@ -0,0 +1,342 @@ +/* +Sphinx-Gallery has compatible CSS to fix default sphinx themes +Tested for Sphinx 1.3.1 for all themes: default, alabaster, sphinxdoc, +scrolls, agogo, traditional, nature, haiku, pyramid +Tested for Read the Docs theme 0.1.7 */ + +/* Define light colors */ +:root, html[data-theme="light"], body[data-theme="light"]{ + --sg-tooltip-foreground: black; + --sg-tooltip-background: rgba(250, 250, 250, 0.9); + --sg-tooltip-border: #ccc transparent; + --sg-thumb-box-shadow-color: #6c757d40; + --sg-thumb-hover-border: #0069d9; + --sg-script-out: #888; + --sg-script-pre: #fafae2; + --sg-pytb-foreground: #000; + --sg-pytb-background: #ffe4e4; + --sg-pytb-border-color: #f66; + --sg-download-a-background-color: #ffc; + --sg-download-a-background-image: linear-gradient(to bottom, #ffc, #d5d57e); + --sg-download-a-border-color: 1px solid #c2c22d; + --sg-download-a-color: #000; + --sg-download-a-hover-background-color: #d5d57e; + --sg-download-a-hover-box-shadow-1: rgba(255, 255, 255, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(0, 0, 0, 0.25); +} +@media(prefers-color-scheme: light) { + :root[data-theme="auto"], html[data-theme="auto"], body[data-theme="auto"] { + --sg-tooltip-foreground: black; + --sg-tooltip-background: rgba(250, 250, 250, 0.9); + --sg-tooltip-border: #ccc transparent; + --sg-thumb-box-shadow-color: #6c757d40; + --sg-thumb-hover-border: #0069d9; + --sg-script-out: #888; + --sg-script-pre: #fafae2; + --sg-pytb-foreground: #000; + --sg-pytb-background: #ffe4e4; + --sg-pytb-border-color: #f66; + --sg-download-a-background-color: #ffc; + --sg-download-a-background-image: linear-gradient(to bottom, #ffc, #d5d57e); + --sg-download-a-border-color: 1px solid #c2c22d; + --sg-download-a-color: #000; + --sg-download-a-hover-background-color: #d5d57e; + --sg-download-a-hover-box-shadow-1: rgba(255, 255, 255, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(0, 0, 0, 0.25); + } +} + +html[data-theme="dark"], body[data-theme="dark"] { + --sg-tooltip-foreground: white; + --sg-tooltip-background: rgba(10, 10, 10, 0.9); + --sg-tooltip-border: #333 transparent; + --sg-thumb-box-shadow-color: #79848d40; + --sg-thumb-hover-border: #003975; + --sg-script-out: rgb(179, 179, 179); + --sg-script-pre: #2e2e22; + --sg-pytb-foreground: #fff; + --sg-pytb-background: #1b1717; + --sg-pytb-border-color: #622; + --sg-download-a-background-color: #443; + --sg-download-a-background-image: linear-gradient(to bottom, #443, #221); + --sg-download-a-border-color: 1px solid #3a3a0d; + --sg-download-a-color: #fff; + --sg-download-a-hover-background-color: #616135; + --sg-download-a-hover-box-shadow-1: rgba(0, 0, 0, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(255, 255, 255, 0.25); +} +@media(prefers-color-scheme: dark){ + html[data-theme="auto"], body[data-theme="auto"] { + --sg-tooltip-foreground: white; + --sg-tooltip-background: rgba(10, 10, 10, 0.9); + --sg-tooltip-border: #333 transparent; + --sg-thumb-box-shadow-color: #79848d40; + --sg-thumb-hover-border: #003975; + --sg-script-out: rgb(179, 179, 179); + --sg-script-pre: #2e2e22; + --sg-pytb-foreground: #fff; + --sg-pytb-background: #1b1717; + --sg-pytb-border-color: #622; + --sg-download-a-background-color: #443; + --sg-download-a-background-image: linear-gradient(to bottom, #443, #221); + --sg-download-a-border-color: 1px solid #3a3a0d; + --sg-download-a-color: #fff; + --sg-download-a-hover-background-color: #616135; + --sg-download-a-hover-box-shadow-1: rgba(0, 0, 0, 0.1); + --sg-download-a-hover-box-shadow-2: rgba(255, 255, 255, 0.25); + } +} + +.sphx-glr-thumbnails { + width: 100%; + margin: 0px 0px 20px 0px; + + /* align thumbnails on a grid */ + justify-content: space-between; + display: grid; + /* each grid column should be at least 160px (this will determine + the actual number of columns) and then take as much of the + remaining width as possible */ + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 15px; +} +.sphx-glr-thumbnails .toctree-wrapper { + /* hide empty toctree divs added to the DOM + by sphinx even though the toctree is hidden + (they would fill grid places with empty divs) */ + display: none; +} +.sphx-glr-thumbcontainer { + background: transparent; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + box-shadow: 0 0 10px var(--sg-thumb-box-shadow-color); + + /* useful to absolutely position link in div */ + position: relative; + + /* thumbnail width should include padding and borders + and take all available space */ + box-sizing: border-box; + width: 100%; + padding: 10px; + border: 1px solid transparent; + + /* align content in thumbnail */ + display: flex; + flex-direction: column; + align-items: center; + gap: 7px; +} +.sphx-glr-thumbcontainer p { + position: absolute; + top: 0; + left: 0; +} +.sphx-glr-thumbcontainer p, +.sphx-glr-thumbcontainer p a { + /* link should cover the whole thumbnail div */ + width: 100%; + height: 100%; +} +.sphx-glr-thumbcontainer p a span { + /* text within link should be masked + (we are just interested in the href) */ + display: none; +} +.sphx-glr-thumbcontainer:hover { + border: 1px solid; + border-color: var(--sg-thumb-hover-border); + cursor: pointer; +} +.sphx-glr-thumbcontainer a.internal { + bottom: 0; + display: block; + left: 0; + box-sizing: border-box; + padding: 150px 10px 0; + position: absolute; + right: 0; + top: 0; +} +/* Next one is to avoid Sphinx traditional theme to cover all the +thumbnail with its default link Background color */ +.sphx-glr-thumbcontainer a.internal:hover { + background-color: transparent; +} + +.sphx-glr-thumbcontainer p { + margin: 0 0 0.1em 0; +} +.sphx-glr-thumbcontainer .figure { + margin: 10px; + width: 160px; +} +.sphx-glr-thumbcontainer img { + display: inline; + max-height: 112px; + max-width: 160px; +} +.sphx-glr-thumbcontainer[tooltip]:hover:after { + background: var(--sg-tooltip-background); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + color: var(--sg-tooltip-foreground); + content: attr(tooltip); + padding: 10px; + z-index: 98; + width: 100%; + height: 100%; + position: absolute; + pointer-events: none; + top: 0; + box-sizing: border-box; + overflow: hidden; + backdrop-filter: blur(3px); +} + +.sphx-glr-script-out { + color: var(--sg-script-out); + display: flex; + gap: 0.5em; +} +.sphx-glr-script-out::before { + content: "Out:"; + /* These numbers come from the pre style in the pydata sphinx theme. This + * turns out to match perfectly on the rtd theme, but be a bit too low for + * the pydata sphinx theme. As I could not find a dimension to use that was + * scaled the same way, I just picked one option that worked pretty close for + * both. */ + line-height: 1.4; + padding-top: 10px; +} +.sphx-glr-script-out .highlight { + background-color: transparent; + /* These options make the div expand... */ + flex-grow: 1; + /* ... but also keep it from overflowing its flex container. */ + overflow: auto; +} +.sphx-glr-script-out .highlight pre { + background-color: var(--sg-script-pre); + border: 0; + max-height: 30em; + overflow: auto; + padding-left: 1ex; + /* This margin is necessary in the pydata sphinx theme because pre has a box + * shadow which would be clipped by the overflow:auto in the parent div + * above. */ + margin: 2px; + word-break: break-word; +} +.sphx-glr-script-out + p { + margin-top: 1.8em; +} +blockquote.sphx-glr-script-out { + margin-left: 0pt; +} +.sphx-glr-script-out.highlight-pytb .highlight pre { + color: var(--sg-pytb-foreground); + background-color: var(--sg-pytb-background); + border: 1px solid var(--sg-pytb-border-color); + margin-top: 10px; + padding: 7px; +} + +div.sphx-glr-footer { + text-align: center; +} + +div.sphx-glr-download { + margin: 1em auto; + vertical-align: middle; +} + +div.sphx-glr-download a { + background-color: var(--sg-download-a-background-color); + background-image: var(--sg-download-a-background-image); + border-radius: 4px; + border: 1px solid var(--sg-download-a-border-color); + color: var(--sg-download-a-color); + display: inline-block; + font-weight: bold; + padding: 1ex; + text-align: center; +} + +div.sphx-glr-download code.download { + display: inline-block; + white-space: normal; + word-break: normal; + overflow-wrap: break-word; + /* border and background are given by the enclosing 'a' */ + border: none; + background: none; +} + +div.sphx-glr-download a:hover { + box-shadow: inset 0 1px 0 var(--sg-download-a-hover-box-shadow-1), 0 1px 5px var(--sg-download-a-hover-box-shadow-2); + text-decoration: none; + background-image: none; + background-color: var(--sg-download-a-hover-background-color); +} + +.sphx-glr-example-title:target::before { + display: block; + content: ""; + margin-top: -50px; + height: 50px; + visibility: hidden; +} + +ul.sphx-glr-horizontal { + list-style: none; + padding: 0; +} +ul.sphx-glr-horizontal li { + display: inline; +} +ul.sphx-glr-horizontal img { + height: auto !important; +} + +.sphx-glr-single-img { + margin: auto; + display: block; + max-width: 100%; +} + +.sphx-glr-multi-img { + max-width: 42%; + height: auto; +} + +div.sphx-glr-animation { + margin: auto; + display: block; + max-width: 100%; +} +div.sphx-glr-animation .animation { + display: block; +} + +p.sphx-glr-signature a.reference.external { + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + padding: 3px; + font-size: 75%; + text-align: right; + margin-left: auto; + display: table; +} + +.sphx-glr-clear { + clear: both; +} + +a.sphx-glr-backref-instance { + text-decoration: none; +} diff --git a/latest/_static/skeleton.css b/latest/_static/skeleton.css new file mode 100644 index 00000000..467c878c --- /dev/null +++ b/latest/_static/skeleton.css @@ -0,0 +1,296 @@ +/* Some sane resets. */ +html { + height: 100%; +} + +body { + margin: 0; + min-height: 100%; +} + +/* All the flexbox magic! */ +body, +.sb-announcement, +.sb-content, +.sb-main, +.sb-container, +.sb-container__inner, +.sb-article-container, +.sb-footer-content, +.sb-header, +.sb-header-secondary, +.sb-footer { + display: flex; +} + +/* These order things vertically */ +body, +.sb-main, +.sb-article-container { + flex-direction: column; +} + +/* Put elements in the center */ +.sb-header, +.sb-header-secondary, +.sb-container, +.sb-content, +.sb-footer, +.sb-footer-content { + justify-content: center; +} +/* Put elements at the ends */ +.sb-article-container { + justify-content: space-between; +} + +/* These elements grow. */ +.sb-main, +.sb-content, +.sb-container, +article { + flex-grow: 1; +} + +/* Because padding making this wider is not fun */ +article { + box-sizing: border-box; +} + +/* The announcements element should never be wider than the page. */ +.sb-announcement { + max-width: 100%; +} + +.sb-sidebar-primary, +.sb-sidebar-secondary { + flex-shrink: 0; + width: 17rem; +} + +.sb-announcement__inner { + justify-content: center; + + box-sizing: border-box; + height: 3rem; + + overflow-x: auto; + white-space: nowrap; +} + +/* Sidebars, with checkbox-based toggle */ +.sb-sidebar-primary, +.sb-sidebar-secondary { + position: fixed; + height: 100%; + top: 0; +} + +.sb-sidebar-primary { + left: -17rem; + transition: left 250ms ease-in-out; +} +.sb-sidebar-secondary { + right: -17rem; + transition: right 250ms ease-in-out; +} + +.sb-sidebar-toggle { + display: none; +} +.sb-sidebar-overlay { + position: fixed; + top: 0; + width: 0; + height: 0; + + transition: width 0ms ease 250ms, height 0ms ease 250ms, opacity 250ms ease; + + opacity: 0; + background-color: rgba(0, 0, 0, 0.54); +} + +#sb-sidebar-toggle--primary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--primary"], +#sb-sidebar-toggle--secondary:checked + ~ .sb-sidebar-overlay[for="sb-sidebar-toggle--secondary"] { + width: 100%; + height: 100%; + opacity: 1; + transition: width 0ms ease, height 0ms ease, opacity 250ms ease; +} + +#sb-sidebar-toggle--primary:checked ~ .sb-container .sb-sidebar-primary { + left: 0; +} +#sb-sidebar-toggle--secondary:checked ~ .sb-container .sb-sidebar-secondary { + right: 0; +} + +/* Full-width mode */ +.drop-secondary-sidebar-for-full-width-content + .hide-when-secondary-sidebar-shown { + display: none !important; +} +.drop-secondary-sidebar-for-full-width-content .sb-sidebar-secondary { + display: none !important; +} + +/* Mobile views */ +.sb-page-width { + width: 100%; +} + +.sb-article-container, +.sb-footer-content__inner, +.drop-secondary-sidebar-for-full-width-content .sb-article, +.drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 100vw; +} + +.sb-article, +.match-content-width { + padding: 0 1rem; + box-sizing: border-box; +} + +@media (min-width: 32rem) { + .sb-article, + .match-content-width { + padding: 0 2rem; + } +} + +/* Tablet views */ +@media (min-width: 42rem) { + .sb-article-container { + width: auto; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 42rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 46rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 46rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 50rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 50rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Tablet views */ +@media (min-width: 59rem) { + .sb-sidebar-secondary { + position: static; + } + .hide-when-secondary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} +@media (min-width: 63rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } + .sb-article, + .match-content-width { + width: 46rem; + } +} +@media (min-width: 67rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-article, + .match-content-width { + width: 50rem; + } +} + +/* Desktop views */ +@media (min-width: 76rem) { + .sb-sidebar-primary { + position: static; + } + .hide-when-primary-sidebar-shown { + display: none !important; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 59rem; + } + .sb-article, + .match-content-width { + width: 42rem; + } +} + +/* Full desktop views */ +@media (min-width: 80rem) { + .sb-article, + .match-content-width { + width: 46rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 63rem; + } +} + +@media (min-width: 84rem) { + .sb-article, + .match-content-width { + width: 50rem; + } + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } +} + +@media (min-width: 88rem) { + .sb-footer-content__inner, + .drop-secondary-sidebar-for-full-width-content .sb-article, + .drop-secondary-sidebar-for-full-width-content .match-content-width { + width: 67rem; + } + .sb-page-width { + width: 88rem; + } +} diff --git a/latest/_static/sphinx_highlight.js b/latest/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/latest/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/latest/_static/styles/furo-extensions.css b/latest/_static/styles/furo-extensions.css new file mode 100644 index 00000000..bc447f22 --- /dev/null +++ b/latest/_static/styles/furo-extensions.css @@ -0,0 +1,2 @@ +#furo-sidebar-ad-placement{padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)}#furo-sidebar-ad-placement .ethical-sidebar{background:var(--color-background-secondary);border:none;box-shadow:none}#furo-sidebar-ad-placement .ethical-sidebar:hover{background:var(--color-background-hover)}#furo-sidebar-ad-placement .ethical-sidebar a{color:var(--color-foreground-primary)}#furo-sidebar-ad-placement .ethical-callout a{color:var(--color-foreground-secondary)!important}#furo-readthedocs-versions{background:transparent;display:block;position:static;width:100%}#furo-readthedocs-versions .rst-versions{background:#1a1c1e}#furo-readthedocs-versions .rst-current-version{background:var(--color-sidebar-item-background);cursor:unset}#furo-readthedocs-versions .rst-current-version:hover{background:var(--color-sidebar-item-background)}#furo-readthedocs-versions .rst-current-version .fa-book{color:var(--color-foreground-primary)}#furo-readthedocs-versions>.rst-other-versions{padding:0}#furo-readthedocs-versions>.rst-other-versions small{opacity:1}#furo-readthedocs-versions .injected .rst-versions{position:unset}#furo-readthedocs-versions:focus-within,#furo-readthedocs-versions:hover{box-shadow:0 0 0 1px var(--color-sidebar-background-border)}#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:hover .rst-current-version{background:#1a1c1e;font-size:inherit;height:auto;line-height:inherit;padding:12px;text-align:right}#furo-readthedocs-versions:focus-within .rst-current-version .fa-book,#furo-readthedocs-versions:hover .rst-current-version .fa-book{color:#fff;float:left}#furo-readthedocs-versions:focus-within .fa-caret-down,#furo-readthedocs-versions:hover .fa-caret-down{display:none}#furo-readthedocs-versions:focus-within .injected,#furo-readthedocs-versions:focus-within .rst-current-version,#furo-readthedocs-versions:focus-within .rst-other-versions,#furo-readthedocs-versions:hover .injected,#furo-readthedocs-versions:hover .rst-current-version,#furo-readthedocs-versions:hover .rst-other-versions{display:block}#furo-readthedocs-versions:focus-within>.rst-current-version,#furo-readthedocs-versions:hover>.rst-current-version{display:none}.highlight:hover button.copybtn{color:var(--color-code-foreground)}.highlight button.copybtn{align-items:center;background-color:var(--color-code-background);border:none;color:var(--color-background-item);cursor:pointer;height:1.25em;opacity:1;right:.5rem;top:.625rem;transition:color .3s,opacity .3s;width:1.25em}.highlight button.copybtn:hover{background-color:var(--color-code-background);color:var(--color-brand-content)}.highlight button.copybtn:after{background-color:transparent;color:var(--color-code-foreground);display:none}.highlight button.copybtn.success{color:#22863a;transition:color 0ms}.highlight button.copybtn.success:after{display:block}.highlight button.copybtn svg{padding:0}body{--sd-color-primary:var(--color-brand-primary);--sd-color-primary-highlight:var(--color-brand-content);--sd-color-primary-text:var(--color-background-primary);--sd-color-shadow:rgba(0,0,0,.05);--sd-color-card-border:var(--color-card-border);--sd-color-card-border-hover:var(--color-brand-content);--sd-color-card-background:var(--color-card-background);--sd-color-card-text:var(--color-foreground-primary);--sd-color-card-header:var(--color-card-marginals-background);--sd-color-card-footer:var(--color-card-marginals-background);--sd-color-tabs-label-active:var(--color-brand-content);--sd-color-tabs-label-hover:var(--color-foreground-muted);--sd-color-tabs-label-inactive:var(--color-foreground-muted);--sd-color-tabs-underline-active:var(--color-brand-content);--sd-color-tabs-underline-hover:var(--color-foreground-border);--sd-color-tabs-underline-inactive:var(--color-background-border);--sd-color-tabs-overline:var(--color-background-border);--sd-color-tabs-underline:var(--color-background-border)}.sd-tab-content{box-shadow:0 -2px var(--sd-color-tabs-overline),0 1px var(--sd-color-tabs-underline)}.sd-card{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)}.sd-shadow-sm{box-shadow:0 .1rem .25rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-md{box-shadow:0 .3rem .75rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-shadow-lg{box-shadow:0 .6rem 1.5rem var(--sd-color-shadow),0 0 .0625rem rgba(0,0,0,.1)!important}.sd-card-hover:hover{transform:none}.sd-cards-carousel{gap:.25rem;padding:.25rem}body{--tabs--label-text:var(--color-foreground-muted);--tabs--label-text--hover:var(--color-foreground-muted);--tabs--label-text--active:var(--color-brand-content);--tabs--label-text--active--hover:var(--color-brand-content);--tabs--label-background:transparent;--tabs--label-background--hover:transparent;--tabs--label-background--active:transparent;--tabs--label-background--active--hover:transparent;--tabs--padding-x:0.25em;--tabs--margin-x:1em;--tabs--border:var(--color-background-border);--tabs--label-border:transparent;--tabs--label-border--hover:var(--color-foreground-muted);--tabs--label-border--active:var(--color-brand-content);--tabs--label-border--active--hover:var(--color-brand-content)}[role=main] .container{max-width:none;padding-left:0;padding-right:0}.shadow.docutils{border:none;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)!important}.sphinx-bs .card{background-color:var(--color-background-secondary);color:var(--color-foreground)} +/*# sourceMappingURL=furo-extensions.css.map*/ \ No newline at end of file diff --git a/latest/_static/styles/furo-extensions.css.map b/latest/_static/styles/furo-extensions.css.map new file mode 100644 index 00000000..9ba5637f --- /dev/null +++ b/latest/_static/styles/furo-extensions.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo-extensions.css","mappings":"AAGA,2BACE,oFACA,4CAKE,6CAHA,YACA,eAEA,CACA,kDACE,yCAEF,8CACE,sCAEJ,8CACE,kDAEJ,2BAGE,uBACA,cAHA,gBACA,UAEA,CAGA,yCACE,mBAEF,gDAEE,gDADA,YACA,CACA,sDACE,gDACF,yDACE,sCAEJ,+CACE,UACA,qDACE,UAGF,mDACE,eAEJ,yEAEE,4DAEA,mHASE,mBAPA,kBAEA,YADA,oBAGA,aADA,gBAIA,CAEA,qIAEE,WADA,UACA,CAEJ,uGACE,aAEF,iUAGE,cAEF,mHACE,aC1EJ,gCACE,mCAEF,0BAKE,mBAUA,8CACA,YAFA,mCAKA,eAZA,cALA,UASA,YADA,YAYA,iCAdA,YAcA,CAEA,gCAEE,8CADA,gCACA,CAEF,gCAGE,6BADA,mCADA,YAEA,CAEF,kCAEE,cADA,oBACA,CACA,wCACE,cAEJ,8BACE,UC5CN,KAEE,6CAA8C,CAC9C,uDAAwD,CACxD,uDAAwD,CAGxD,iCAAsC,CAGtC,+CAAgD,CAChD,uDAAwD,CACxD,uDAAwD,CACxD,oDAAqD,CACrD,6DAA8D,CAC9D,6DAA8D,CAG9D,uDAAwD,CACxD,yDAA0D,CAC1D,4DAA6D,CAC7D,2DAA4D,CAC5D,8DAA+D,CAC/D,iEAAkE,CAClE,uDAAwD,CACxD,wDAAyD,CAG3D,gBACE,qFAGF,SACE,6EAEF,cACE,uFAEF,cACE,uFAEF,cACE,uFAGF,qBACE,eAEF,mBACE,WACA,eChDF,KACE,gDAAiD,CACjD,uDAAwD,CACxD,qDAAsD,CACtD,4DAA6D,CAC7D,oCAAqC,CACrC,2CAA4C,CAC5C,4CAA6C,CAC7C,mDAAoD,CACpD,wBAAyB,CACzB,oBAAqB,CACrB,6CAA8C,CAC9C,gCAAiC,CACjC,yDAA0D,CAC1D,uDAAwD,CACxD,8DAA+D,CCbjE,uBACE,eACA,eACA,gBAGF,iBACE,YACA,+EAGF,iBACE,mDACA","sources":["webpack:///./src/furo/assets/styles/extensions/_readthedocs.sass","webpack:///./src/furo/assets/styles/extensions/_copybutton.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-design.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-inline-tabs.sass","webpack:///./src/furo/assets/styles/extensions/_sphinx-panels.sass"],"sourcesContent":["// This file contains the styles used for tweaking how ReadTheDoc's embedded\n// contents would show up inside the theme.\n\n#furo-sidebar-ad-placement\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n .ethical-sidebar\n // Remove the border and box-shadow.\n border: none\n box-shadow: none\n // Manage the background colors.\n background: var(--color-background-secondary)\n &:hover\n background: var(--color-background-hover)\n // Ensure the text is legible.\n a\n color: var(--color-foreground-primary)\n\n .ethical-callout a\n color: var(--color-foreground-secondary) !important\n\n#furo-readthedocs-versions\n position: static\n width: 100%\n background: transparent\n display: block\n\n // Make the background color fit with the theme's aesthetic.\n .rst-versions\n background: rgb(26, 28, 30)\n\n .rst-current-version\n cursor: unset\n background: var(--color-sidebar-item-background)\n &:hover\n background: var(--color-sidebar-item-background)\n .fa-book\n color: var(--color-foreground-primary)\n\n > .rst-other-versions\n padding: 0\n small\n opacity: 1\n\n .injected\n .rst-versions\n position: unset\n\n &:hover,\n &:focus-within\n box-shadow: 0 0 0 1px var(--color-sidebar-background-border)\n\n .rst-current-version\n // Undo the tweaks done in RTD's CSS\n font-size: inherit\n line-height: inherit\n height: auto\n text-align: right\n padding: 12px\n\n // Match the rest of the body\n background: #1a1c1e\n\n .fa-book\n float: left\n color: white\n\n .fa-caret-down\n display: none\n\n .rst-current-version,\n .rst-other-versions,\n .injected\n display: block\n\n > .rst-current-version\n display: none\n",".highlight\n &:hover button.copybtn\n color: var(--color-code-foreground)\n\n button.copybtn\n // Make it visible\n opacity: 1\n\n // Align things correctly\n align-items: center\n\n height: 1.25em\n width: 1.25em\n\n top: 0.625rem // $code-spacing-vertical\n right: 0.5rem\n\n // Make it look better\n color: var(--color-background-item)\n background-color: var(--color-code-background)\n border: none\n\n // Change to cursor to make it obvious that you can click on it\n cursor: pointer\n\n // Transition smoothly, for aesthetics\n transition: color 300ms, opacity 300ms\n\n &:hover\n color: var(--color-brand-content)\n background-color: var(--color-code-background)\n\n &::after\n display: none\n color: var(--color-code-foreground)\n background-color: transparent\n\n &.success\n transition: color 0ms\n color: #22863a\n &::after\n display: block\n\n svg\n padding: 0\n","body\n // Colors\n --sd-color-primary: var(--color-brand-primary)\n --sd-color-primary-highlight: var(--color-brand-content)\n --sd-color-primary-text: var(--color-background-primary)\n\n // Shadows\n --sd-color-shadow: rgba(0, 0, 0, 0.05)\n\n // Cards\n --sd-color-card-border: var(--color-card-border)\n --sd-color-card-border-hover: var(--color-brand-content)\n --sd-color-card-background: var(--color-card-background)\n --sd-color-card-text: var(--color-foreground-primary)\n --sd-color-card-header: var(--color-card-marginals-background)\n --sd-color-card-footer: var(--color-card-marginals-background)\n\n // Tabs\n --sd-color-tabs-label-active: var(--color-brand-content)\n --sd-color-tabs-label-hover: var(--color-foreground-muted)\n --sd-color-tabs-label-inactive: var(--color-foreground-muted)\n --sd-color-tabs-underline-active: var(--color-brand-content)\n --sd-color-tabs-underline-hover: var(--color-foreground-border)\n --sd-color-tabs-underline-inactive: var(--color-background-border)\n --sd-color-tabs-overline: var(--color-background-border)\n --sd-color-tabs-underline: var(--color-background-border)\n\n// Tabs\n.sd-tab-content\n box-shadow: 0 -2px var(--sd-color-tabs-overline), 0 1px var(--sd-color-tabs-underline)\n\n// Shadows\n.sd-card // Have a shadow by default\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n.sd-shadow-sm\n box-shadow: 0 0.1rem 0.25rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-md\n box-shadow: 0 0.3rem 0.75rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n.sd-shadow-lg\n box-shadow: 0 0.6rem 1.5rem var(--sd-color-shadow), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Cards\n.sd-card-hover:hover // Don't change scale on hover\n transform: none\n\n.sd-cards-carousel // Have a bit of gap in the carousel by default\n gap: 0.25rem\n padding: 0.25rem\n","// This file contains styles to tweak sphinx-inline-tabs to work well with Furo.\n\nbody\n --tabs--label-text: var(--color-foreground-muted)\n --tabs--label-text--hover: var(--color-foreground-muted)\n --tabs--label-text--active: var(--color-brand-content)\n --tabs--label-text--active--hover: var(--color-brand-content)\n --tabs--label-background: transparent\n --tabs--label-background--hover: transparent\n --tabs--label-background--active: transparent\n --tabs--label-background--active--hover: transparent\n --tabs--padding-x: 0.25em\n --tabs--margin-x: 1em\n --tabs--border: var(--color-background-border)\n --tabs--label-border: transparent\n --tabs--label-border--hover: var(--color-foreground-muted)\n --tabs--label-border--active: var(--color-brand-content)\n --tabs--label-border--active--hover: var(--color-brand-content)\n","// This file contains styles to tweak sphinx-panels to work well with Furo.\n\n// sphinx-panels includes Bootstrap 4, which uses .container which can conflict\n// with docutils' `.. container::` directive.\n[role=\"main\"] .container\n max-width: initial\n padding-left: initial\n padding-right: initial\n\n// Make the panels look nicer!\n.shadow.docutils\n border: none\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1) !important\n\n// Make panel colors respond to dark mode\n.sphinx-bs .card\n background-color: var(--color-background-secondary)\n color: var(--color-foreground)\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/latest/_static/styles/furo.css b/latest/_static/styles/furo.css new file mode 100644 index 00000000..e3d4e57b --- /dev/null +++ b/latest/_static/styles/furo.css @@ -0,0 +1,2 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}@media print{.content-icon-container,.headerlink,.mobile-header,.related-pages{display:none!important}.highlight{border:.1pt solid var(--color-foreground-border)}a,blockquote,dl,ol,pre,table,ul{page-break-inside:avoid}caption,figure,h1,h2,h3,h4,h5,h6,img{page-break-after:avoid;page-break-inside:avoid}dl,ol,ul{page-break-before:avoid}}.visually-hidden{height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;width:1px!important;clip:rect(0,0,0,0)!important;background:var(--color-background-primary);border:0!important;color:var(--color-foreground-primary);white-space:nowrap!important}:-moz-focusring{outline:auto}body{--font-stack:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;--font-stack--monospace:"SFMono-Regular",Menlo,Consolas,Monaco,Liberation Mono,Lucida Console,monospace;--font-stack--headings:var(--font-stack);--font-size--normal:100%;--font-size--small:87.5%;--font-size--small--2:81.25%;--font-size--small--3:75%;--font-size--small--4:62.5%;--sidebar-caption-font-size:var(--font-size--small--2);--sidebar-item-font-size:var(--font-size--small);--sidebar-search-input-font-size:var(--font-size--small);--toc-font-size:var(--font-size--small--3);--toc-font-size--mobile:var(--font-size--normal);--toc-title-font-size:var(--font-size--small--4);--admonition-font-size:0.8125rem;--admonition-title-font-size:0.8125rem;--code-font-size:var(--font-size--small--2);--api-font-size:var(--font-size--small);--header-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*4);--header-padding:0.5rem;--sidebar-tree-space-above:1.5rem;--sidebar-caption-space-above:1rem;--sidebar-item-line-height:1rem;--sidebar-item-spacing-vertical:0.5rem;--sidebar-item-spacing-horizontal:1rem;--sidebar-item-height:calc(var(--sidebar-item-line-height) + var(--sidebar-item-spacing-vertical)*2);--sidebar-expander-width:var(--sidebar-item-height);--sidebar-search-space-above:0.5rem;--sidebar-search-input-spacing-vertical:0.5rem;--sidebar-search-input-spacing-horizontal:0.5rem;--sidebar-search-input-height:1rem;--sidebar-search-icon-size:var(--sidebar-search-input-height);--toc-title-padding:0.25rem 0;--toc-spacing-vertical:1.5rem;--toc-spacing-horizontal:1.5rem;--toc-item-spacing-vertical:0.4rem;--toc-item-spacing-horizontal:1rem;--icon-search:url('data:image/svg+xml;charset=utf-8,');--icon-pencil:url('data:image/svg+xml;charset=utf-8,');--icon-abstract:url('data:image/svg+xml;charset=utf-8,');--icon-info:url('data:image/svg+xml;charset=utf-8,');--icon-flame:url('data:image/svg+xml;charset=utf-8,');--icon-question:url('data:image/svg+xml;charset=utf-8,');--icon-warning:url('data:image/svg+xml;charset=utf-8,');--icon-failure:url('data:image/svg+xml;charset=utf-8,');--icon-spark:url('data:image/svg+xml;charset=utf-8,');--color-admonition-title--caution:#ff9100;--color-admonition-title-background--caution:rgba(255,145,0,.2);--color-admonition-title--warning:#ff9100;--color-admonition-title-background--warning:rgba(255,145,0,.2);--color-admonition-title--danger:#ff5252;--color-admonition-title-background--danger:rgba(255,82,82,.2);--color-admonition-title--attention:#ff5252;--color-admonition-title-background--attention:rgba(255,82,82,.2);--color-admonition-title--error:#ff5252;--color-admonition-title-background--error:rgba(255,82,82,.2);--color-admonition-title--hint:#00c852;--color-admonition-title-background--hint:rgba(0,200,82,.2);--color-admonition-title--tip:#00c852;--color-admonition-title-background--tip:rgba(0,200,82,.2);--color-admonition-title--important:#00bfa5;--color-admonition-title-background--important:rgba(0,191,165,.2);--color-admonition-title--note:#00b0ff;--color-admonition-title-background--note:rgba(0,176,255,.2);--color-admonition-title--seealso:#448aff;--color-admonition-title-background--seealso:rgba(68,138,255,.2);--color-admonition-title--admonition-todo:grey;--color-admonition-title-background--admonition-todo:hsla(0,0%,50%,.2);--color-admonition-title:#651fff;--color-admonition-title-background:rgba(101,31,255,.2);--icon-admonition-default:var(--icon-abstract);--color-topic-title:#14b8a6;--color-topic-title-background:rgba(20,184,166,.2);--icon-topic-default:var(--icon-pencil);--color-problematic:#b30000;--color-foreground-primary:#000;--color-foreground-secondary:#5a5c63;--color-foreground-muted:#6b6f76;--color-foreground-border:#878787;--color-background-primary:#fff;--color-background-secondary:#f8f9fb;--color-background-hover:#efeff4;--color-background-hover--transparent:#efeff400;--color-background-border:#eeebee;--color-background-item:#ccc;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#0a4bff;--color-brand-content:#2757dd;--color-brand-visited:#872ee0;--color-api-background:var(--color-background-hover--transparent);--color-api-background-hover:var(--color-background-hover);--color-api-overall:var(--color-foreground-secondary);--color-api-name:var(--color-problematic);--color-api-pre-name:var(--color-problematic);--color-api-paren:var(--color-foreground-secondary);--color-api-keyword:var(--color-foreground-primary);--color-api-added:#21632c;--color-api-added-border:#38a84d;--color-api-changed:#046172;--color-api-changed-border:#06a1bc;--color-api-deprecated:#605706;--color-api-deprecated-border:#f0d90f;--color-api-removed:#b30000;--color-api-removed-border:#ff5c5c;--color-highlight-on-target:#ffc;--color-inline-code-background:var(--color-background-secondary);--color-highlighted-background:#def;--color-highlighted-text:var(--color-foreground-primary);--color-guilabel-background:#ddeeff80;--color-guilabel-border:#bedaf580;--color-guilabel-text:var(--color-foreground-primary);--color-admonition-background:transparent;--color-table-header-background:var(--color-background-secondary);--color-table-border:var(--color-background-border);--color-card-border:var(--color-background-secondary);--color-card-background:transparent;--color-card-marginals-background:var(--color-background-secondary);--color-header-background:var(--color-background-primary);--color-header-border:var(--color-background-border);--color-header-text:var(--color-foreground-primary);--color-sidebar-background:var(--color-background-secondary);--color-sidebar-background-border:var(--color-background-border);--color-sidebar-brand-text:var(--color-foreground-primary);--color-sidebar-caption-text:var(--color-foreground-muted);--color-sidebar-link-text:var(--color-foreground-secondary);--color-sidebar-link-text--top-level:var(--color-brand-primary);--color-sidebar-item-background:var(--color-sidebar-background);--color-sidebar-item-background--current:var( --color-sidebar-item-background );--color-sidebar-item-background--hover:linear-gradient(90deg,var(--color-background-hover--transparent) 0%,var(--color-background-hover) var(--sidebar-item-spacing-horizontal),var(--color-background-hover) 100%);--color-sidebar-item-expander-background:transparent;--color-sidebar-item-expander-background--hover:var( --color-background-hover );--color-sidebar-search-text:var(--color-foreground-primary);--color-sidebar-search-background:var(--color-background-secondary);--color-sidebar-search-background--focus:var(--color-background-primary);--color-sidebar-search-border:var(--color-background-border);--color-sidebar-search-icon:var(--color-foreground-muted);--color-toc-background:var(--color-background-primary);--color-toc-title-text:var(--color-foreground-muted);--color-toc-item-text:var(--color-foreground-secondary);--color-toc-item-text--hover:var(--color-foreground-primary);--color-toc-item-text--active:var(--color-brand-primary);--color-content-foreground:var(--color-foreground-primary);--color-content-background:transparent;--color-link:var(--color-brand-content);--color-link-underline:var(--color-background-border);--color-link--hover:var(--color-brand-content);--color-link-underline--hover:var(--color-foreground-border);--color-link--visited:var(--color-brand-visited);--color-link-underline--visited:var(--color-background-border);--color-link--visited--hover:var(--color-brand-visited);--color-link-underline--visited--hover:var(--color-foreground-border)}.only-light{display:block!important}html body .only-dark{display:none!important}@media not print{body[data-theme=dark]{--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body[data-theme=dark] .only-light{display:none!important}body[data-theme=dark] .only-dark{display:block!important}@media(prefers-color-scheme:dark){body:not([data-theme=light]){--color-problematic:#ee5151;--color-foreground-primary:#cfd0d0;--color-foreground-secondary:#9ca0a5;--color-foreground-muted:#81868d;--color-foreground-border:#666;--color-background-primary:#131416;--color-background-secondary:#1a1c1e;--color-background-hover:#1e2124;--color-background-hover--transparent:#1e212400;--color-background-border:#303335;--color-background-item:#444;--color-announcement-background:#000000dd;--color-announcement-text:#eeebee;--color-brand-primary:#3d94ff;--color-brand-content:#5ca5ff;--color-brand-visited:#b27aeb;--color-highlighted-background:#083563;--color-guilabel-background:#08356380;--color-guilabel-border:#13395f80;--color-api-keyword:var(--color-foreground-secondary);--color-highlight-on-target:#330;--color-api-added:#3db854;--color-api-added-border:#267334;--color-api-changed:#09b0ce;--color-api-changed-border:#056d80;--color-api-deprecated:#b1a10b;--color-api-deprecated-border:#6e6407;--color-api-removed:#ff7575;--color-api-removed-border:#b03b3b;--color-admonition-background:#18181a;--color-card-border:var(--color-background-secondary);--color-card-background:#18181a;--color-card-marginals-background:var(--color-background-hover)}html body:not([data-theme=light]) .only-light{display:none!important}body:not([data-theme=light]) .only-dark{display:block!important}}}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:block}@media(prefers-color-scheme:dark){body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-dark{display:block}body[data-theme=auto] .theme-toggle svg.theme-icon-when-auto-light{display:none}}body[data-theme=dark] .theme-toggle svg.theme-icon-when-dark,body[data-theme=light] .theme-toggle svg.theme-icon-when-light{display:block}body{font-family:var(--font-stack)}code,kbd,pre,samp{font-family:var(--font-stack--monospace)}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}article{line-height:1.5}h1,h2,h3,h4,h5,h6{border-radius:.5rem;font-family:var(--font-stack--headings);font-weight:700;line-height:1.25;margin:.5rem -.5rem;padding-left:.5rem;padding-right:.5rem}h1+p,h2+p,h3+p,h4+p,h5+p,h6+p{margin-top:0}h1{font-size:2.5em;margin-bottom:1rem}h1,h2{margin-top:1.75rem}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.25em}h5{font-size:1.125em}h6{font-size:1em}small{font-size:80%;opacity:75%}p{margin-bottom:.75rem;margin-top:.5rem}hr.docutils{background-color:var(--color-background-border);border:0;height:1px;margin:2rem 0;padding:0}.centered{text-align:center}a{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}a:visited{color:var(--color-link--visited);text-decoration-color:var(--color-link-underline--visited)}a:visited:hover{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}a:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link{color:inherit}a.muted-link:hover{color:var(--color-link--hover);text-decoration-color:var(--color-link-underline--hover)}a.muted-link:hover:visited{color:var(--color-link--visited--hover);text-decoration-color:var(--color-link-underline--visited--hover)}html{overflow-x:hidden;overflow-y:scroll;scroll-behavior:smooth}.sidebar-scroll,.toc-scroll,article[role=main] *{scrollbar-color:var(--color-foreground-border) transparent;scrollbar-width:thin}.sidebar-scroll::-webkit-scrollbar,.toc-scroll::-webkit-scrollbar,article[role=main] ::-webkit-scrollbar{height:.25rem;width:.25rem}.sidebar-scroll::-webkit-scrollbar-thumb,.toc-scroll::-webkit-scrollbar-thumb,article[role=main] ::-webkit-scrollbar-thumb{background-color:var(--color-foreground-border);border-radius:.125rem}body,html{height:100%}.skip-to-content,body,html{background:var(--color-background-primary);color:var(--color-foreground-primary)}.skip-to-content{border-radius:1rem;left:.25rem;padding:1rem;position:fixed;top:.25rem;transform:translateY(-200%);transition:transform .3s ease-in-out;z-index:40}.skip-to-content:focus-within{transform:translateY(0)}article{background:var(--color-content-background);color:var(--color-content-foreground);overflow-wrap:break-word}.page{display:flex;min-height:100%}.mobile-header{background-color:var(--color-header-background);border-bottom:1px solid var(--color-header-border);color:var(--color-header-text);display:none;height:var(--header-height);width:100%;z-index:10}.mobile-header.scrolled{border-bottom:none;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2)}.mobile-header .header-center a{color:var(--color-header-text);text-decoration:none}.main{display:flex;flex:1}.sidebar-drawer{background:var(--color-sidebar-background);border-right:1px solid var(--color-sidebar-background-border);box-sizing:border-box;display:flex;justify-content:flex-end;min-width:15em;width:calc(50% - 26em)}.sidebar-container,.toc-drawer{box-sizing:border-box;width:15em}.toc-drawer{background:var(--color-toc-background);padding-right:1rem}.sidebar-sticky,.toc-sticky{display:flex;flex-direction:column;height:min(100%,100vh);height:100vh;position:sticky;top:0}.sidebar-scroll,.toc-scroll{flex-grow:1;flex-shrink:1;overflow:auto;scroll-behavior:smooth}.content{display:flex;flex-direction:column;justify-content:space-between;padding:0 3em;width:46em}.icon{display:inline-block;height:1rem;width:1rem}.icon svg{height:100%;width:100%}.announcement{align-items:center;background-color:var(--color-announcement-background);color:var(--color-announcement-text);display:flex;height:var(--header-height);overflow-x:auto}.announcement+.page{min-height:calc(100% - var(--header-height))}.announcement-content{box-sizing:border-box;min-width:100%;padding:.5rem;text-align:center;white-space:nowrap}.announcement-content a{color:var(--color-announcement-text);text-decoration-color:var(--color-announcement-text)}.announcement-content a:hover{color:var(--color-announcement-text);text-decoration-color:var(--color-link--hover)}.no-js .theme-toggle-container{display:none}.theme-toggle-container{vertical-align:middle}.theme-toggle{background:transparent;border:none;cursor:pointer;padding:0}.theme-toggle svg{color:var(--color-foreground-primary);display:none;height:1.25rem;vertical-align:middle;width:1.25rem}.theme-toggle-header{float:left;padding:1rem .5rem}.nav-overlay-icon,.toc-overlay-icon{cursor:pointer;display:none}.nav-overlay-icon .icon,.toc-overlay-icon .icon{color:var(--color-foreground-secondary);height:1.25rem;width:1.25rem}.nav-overlay-icon,.toc-header-icon{align-items:center;justify-content:center}.toc-content-icon{height:1.5rem;width:1.5rem}.content-icon-container{display:flex;float:right;gap:.5rem;margin-bottom:1rem;margin-left:1rem;margin-top:1.5rem}.content-icon-container .edit-this-page svg,.content-icon-container .view-this-page svg{color:inherit;height:1.25rem;width:1.25rem}.sidebar-toggle{display:none;position:absolute}.sidebar-toggle[name=__toc]{left:20px}.sidebar-toggle:checked{left:40px}.overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms,height 0ms,opacity .25s ease-out;width:0}.sidebar-overlay{z-index:20}.toc-overlay{z-index:40}.sidebar-drawer{transition:left .25s ease-in-out;z-index:30}.toc-drawer{transition:right .25s ease-in-out;z-index:50}#__navigation:checked~.sidebar-overlay{height:100%;opacity:1;width:100%}#__navigation:checked~.page .sidebar-drawer{left:0;top:0}#__toc:checked~.toc-overlay{height:100%;opacity:1;width:100%}#__toc:checked~.page .toc-drawer{right:0;top:0}.back-to-top{background:var(--color-background-primary);border-radius:1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 1px 0 hsla(220,9%,46%,.502);display:none;font-size:.8125rem;left:0;margin-left:50%;padding:.5rem .75rem .5rem .5rem;position:fixed;text-decoration:none;top:1rem;transform:translateX(-50%);z-index:10}.back-to-top svg{height:1rem;width:1rem;fill:currentColor;display:inline-block}.back-to-top span{margin-left:.25rem}.show-back-to-top .back-to-top{align-items:center;display:flex}@media(min-width:97em){html{font-size:110%}}@media(max-width:82em){.toc-content-icon{display:flex}.toc-drawer{border-left:1px solid var(--color-background-muted);height:100vh;position:fixed;right:-15em;top:0}.toc-tree{border-left:none;font-size:var(--toc-font-size--mobile)}.sidebar-drawer{width:calc(50% - 18.5em)}}@media(max-width:67em){.nav-overlay-icon{display:flex}.sidebar-drawer{height:100vh;left:-15em;position:fixed;top:0;width:15em}.toc-header-icon{display:flex}.theme-toggle-content,.toc-content-icon{display:none}.theme-toggle-header{display:block}.mobile-header{align-items:center;display:flex;justify-content:space-between;position:sticky;top:0}.mobile-header .header-left,.mobile-header .header-right{display:flex;height:var(--header-height);padding:0 var(--header-padding)}.mobile-header .header-left label,.mobile-header .header-right label{height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.nav-overlay-icon .icon,.theme-toggle svg{height:1.25rem;width:1.25rem}:target{scroll-margin-top:calc(var(--header-height) + 2.5rem)}.back-to-top{top:calc(var(--header-height) + .5rem)}.page{flex-direction:column;justify-content:center}.content{margin-left:auto;margin-right:auto}}@media(max-width:52em){.content{overflow-x:auto;width:100%}}@media(max-width:46em){.content{padding:0 1em}article aside.sidebar{float:none;margin:1rem 0;width:100%}}.admonition,.topic{background:var(--color-admonition-background);border-radius:.2rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);font-size:var(--admonition-font-size);margin:1rem auto;overflow:hidden;padding:0 .5rem .5rem;page-break-inside:avoid}.admonition>:nth-child(2),.topic>:nth-child(2){margin-top:0}.admonition>:last-child,.topic>:last-child{margin-bottom:0}.admonition p.admonition-title,p.topic-title{font-size:var(--admonition-title-font-size);font-weight:500;line-height:1.3;margin:0 -.5rem .5rem;padding:.4rem .5rem .4rem 2rem;position:relative}.admonition p.admonition-title:before,p.topic-title:before{content:"";height:1rem;left:.5rem;position:absolute;width:1rem}p.admonition-title{background-color:var(--color-admonition-title-background)}p.admonition-title:before{background-color:var(--color-admonition-title);-webkit-mask-image:var(--icon-admonition-default);mask-image:var(--icon-admonition-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}p.topic-title{background-color:var(--color-topic-title-background)}p.topic-title:before{background-color:var(--color-topic-title);-webkit-mask-image:var(--icon-topic-default);mask-image:var(--icon-topic-default);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}.admonition{border-left:.2rem solid var(--color-admonition-title)}.admonition.caution{border-left-color:var(--color-admonition-title--caution)}.admonition.caution>.admonition-title{background-color:var(--color-admonition-title-background--caution)}.admonition.caution>.admonition-title:before{background-color:var(--color-admonition-title--caution);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.warning{border-left-color:var(--color-admonition-title--warning)}.admonition.warning>.admonition-title{background-color:var(--color-admonition-title-background--warning)}.admonition.warning>.admonition-title:before{background-color:var(--color-admonition-title--warning);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.danger{border-left-color:var(--color-admonition-title--danger)}.admonition.danger>.admonition-title{background-color:var(--color-admonition-title-background--danger)}.admonition.danger>.admonition-title:before{background-color:var(--color-admonition-title--danger);-webkit-mask-image:var(--icon-spark);mask-image:var(--icon-spark)}.admonition.attention{border-left-color:var(--color-admonition-title--attention)}.admonition.attention>.admonition-title{background-color:var(--color-admonition-title-background--attention)}.admonition.attention>.admonition-title:before{background-color:var(--color-admonition-title--attention);-webkit-mask-image:var(--icon-warning);mask-image:var(--icon-warning)}.admonition.error{border-left-color:var(--color-admonition-title--error)}.admonition.error>.admonition-title{background-color:var(--color-admonition-title-background--error)}.admonition.error>.admonition-title:before{background-color:var(--color-admonition-title--error);-webkit-mask-image:var(--icon-failure);mask-image:var(--icon-failure)}.admonition.hint{border-left-color:var(--color-admonition-title--hint)}.admonition.hint>.admonition-title{background-color:var(--color-admonition-title-background--hint)}.admonition.hint>.admonition-title:before{background-color:var(--color-admonition-title--hint);-webkit-mask-image:var(--icon-question);mask-image:var(--icon-question)}.admonition.tip{border-left-color:var(--color-admonition-title--tip)}.admonition.tip>.admonition-title{background-color:var(--color-admonition-title-background--tip)}.admonition.tip>.admonition-title:before{background-color:var(--color-admonition-title--tip);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.important{border-left-color:var(--color-admonition-title--important)}.admonition.important>.admonition-title{background-color:var(--color-admonition-title-background--important)}.admonition.important>.admonition-title:before{background-color:var(--color-admonition-title--important);-webkit-mask-image:var(--icon-flame);mask-image:var(--icon-flame)}.admonition.note{border-left-color:var(--color-admonition-title--note)}.admonition.note>.admonition-title{background-color:var(--color-admonition-title-background--note)}.admonition.note>.admonition-title:before{background-color:var(--color-admonition-title--note);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition.seealso{border-left-color:var(--color-admonition-title--seealso)}.admonition.seealso>.admonition-title{background-color:var(--color-admonition-title-background--seealso)}.admonition.seealso>.admonition-title:before{background-color:var(--color-admonition-title--seealso);-webkit-mask-image:var(--icon-info);mask-image:var(--icon-info)}.admonition.admonition-todo{border-left-color:var(--color-admonition-title--admonition-todo)}.admonition.admonition-todo>.admonition-title{background-color:var(--color-admonition-title-background--admonition-todo)}.admonition.admonition-todo>.admonition-title:before{background-color:var(--color-admonition-title--admonition-todo);-webkit-mask-image:var(--icon-pencil);mask-image:var(--icon-pencil)}.admonition-todo>.admonition-title{text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd{margin-left:2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:first-child{margin-top:.125rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list,dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>:last-child{margin-bottom:.75rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list>dt{font-size:var(--font-size--small);text-transform:uppercase}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd:empty{margin-bottom:.5rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul{margin-left:-1.2rem}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p:nth-child(2){margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list dd>ul>li>p+p:last-child:empty{margin-bottom:0;margin-top:0}dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt{color:var(--color-api-overall)}.sig:not(.sig-inline){background:var(--color-api-background);border-radius:.25rem;font-family:var(--font-stack--monospace);font-size:var(--api-font-size);font-weight:700;margin-left:-.25rem;margin-right:-.25rem;padding:.25rem .5rem .25rem 3em;text-indent:-2.5em;transition:background .1s ease-out}.sig:not(.sig-inline):hover{background:var(--color-api-background-hover)}.sig:not(.sig-inline) a.reference .viewcode-link{font-weight:400;width:4.25rem}em.property{font-style:normal}em.property:first-child{color:var(--color-api-keyword)}.sig-name{color:var(--color-api-name)}.sig-prename{color:var(--color-api-pre-name);font-weight:400}.sig-paren{color:var(--color-api-paren)}.sig-param{font-style:normal}div.deprecated,div.versionadded,div.versionchanged,div.versionremoved{border-left:.1875rem solid;border-radius:.125rem;padding-left:.75rem}div.deprecated p,div.versionadded p,div.versionchanged p,div.versionremoved p{margin-bottom:.125rem;margin-top:.125rem}div.versionadded{border-color:var(--color-api-added-border)}div.versionadded .versionmodified{color:var(--color-api-added)}div.versionchanged{border-color:var(--color-api-changed-border)}div.versionchanged .versionmodified{color:var(--color-api-changed)}div.deprecated{border-color:var(--color-api-deprecated-border)}div.deprecated .versionmodified{color:var(--color-api-deprecated)}div.versionremoved{border-color:var(--color-api-removed-border)}div.versionremoved .versionmodified{color:var(--color-api-removed)}.viewcode-back,.viewcode-link{float:right;text-align:right}.line-block{margin-bottom:.75rem;margin-top:.5rem}.line-block .line-block{margin-bottom:0;margin-top:0;padding-left:1rem}.code-block-caption,article p.caption,table>caption{font-size:var(--font-size--small);text-align:center}.toctree-wrapper.compound .caption,.toctree-wrapper.compound :not(.caption)>.caption-text{font-size:var(--font-size--small);margin-bottom:0;text-align:initial;text-transform:uppercase}.toctree-wrapper.compound>ul{margin-bottom:0;margin-top:0}.sig-inline,code.literal{background:var(--color-inline-code-background);border-radius:.2em;font-size:var(--font-size--small--2);padding:.1em .2em}pre.literal-block .sig-inline,pre.literal-block code.literal{font-size:inherit;padding:0}p .sig-inline,p code.literal{border:1px solid var(--color-background-border)}.sig-inline{font-family:var(--font-stack--monospace)}div[class*=" highlight-"],div[class^=highlight-]{display:flex;margin:1em 0}div[class*=" highlight-"] .table-wrapper,div[class^=highlight-] .table-wrapper,pre{margin:0;padding:0}pre{overflow:auto}article[role=main] .highlight pre{line-height:1.5}.highlight pre,pre.literal-block{font-size:var(--code-font-size);padding:.625rem .875rem}pre.literal-block{background-color:var(--color-code-background);border-radius:.2rem;color:var(--color-code-foreground);margin-bottom:1rem;margin-top:1rem}.highlight{border-radius:.2rem;width:100%}.highlight .gp,.highlight span.linenos{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlight .hll{display:block;margin-left:-.875rem;margin-right:-.875rem;padding-left:.875rem;padding-right:.875rem}.code-block-caption{background-color:var(--color-code-background);border-bottom:1px solid;border-radius:.25rem;border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:var(--color-background-border);color:var(--color-code-foreground);display:flex;font-weight:300;padding:.625rem .875rem}.code-block-caption+div[class]{margin-top:0}.code-block-caption+div[class] pre{border-top-left-radius:0;border-top-right-radius:0}.highlighttable{display:block;width:100%}.highlighttable tbody{display:block}.highlighttable tr{display:flex}.highlighttable td.linenos{background-color:var(--color-code-background);border-bottom-left-radius:.2rem;border-top-left-radius:.2rem;color:var(--color-code-foreground);padding:.625rem 0 .625rem .875rem}.highlighttable .linenodiv{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;font-size:var(--code-font-size);padding-right:.875rem}.highlighttable td.code{display:block;flex:1;overflow:hidden;padding:0}.highlighttable td.code .highlight{border-bottom-left-radius:0;border-top-left-radius:0}.highlight span.linenos{box-shadow:-.0625rem 0 var(--color-foreground-border) inset;display:inline-block;margin-right:.875rem;padding-left:0;padding-right:.875rem}.footnote-reference{font-size:var(--font-size--small--4);vertical-align:super}dl.footnote.brackets{color:var(--color-foreground-secondary);display:grid;font-size:var(--font-size--small);grid-template-columns:max-content auto}dl.footnote.brackets dt{margin:0}dl.footnote.brackets dt>.fn-backref{margin-left:.25rem}dl.footnote.brackets dt:after{content:":"}dl.footnote.brackets dt .brackets:before{content:"["}dl.footnote.brackets dt .brackets:after{content:"]"}dl.footnote.brackets dd{margin:0;padding:0 1rem}aside.footnote{color:var(--color-foreground-secondary);font-size:var(--font-size--small)}aside.footnote>span,div.citation>span{float:left;font-weight:500;padding-right:.25rem}aside.footnote>:not(span),div.citation>p{margin-left:2rem}img{box-sizing:border-box;height:auto;max-width:100%}article .figure,article figure{border-radius:.2rem;margin:0}article .figure :last-child,article figure :last-child{margin-bottom:0}article .align-left{clear:left;float:left;margin:0 1rem 1rem}article .align-right{clear:right;float:right;margin:0 1rem 1rem}article .align-center,article .align-default{display:block;margin-left:auto;margin-right:auto;text-align:center}article table.align-default{display:table;text-align:initial}.domainindex-jumpbox,.genindex-jumpbox{border-bottom:1px solid var(--color-background-border);border-top:1px solid var(--color-background-border);padding:.25rem}.domainindex-section h2,.genindex-section h2{margin-bottom:.5rem;margin-top:.75rem}.domainindex-section ul,.genindex-section ul{margin-bottom:0;margin-top:0}ol,ul{margin-bottom:1rem;margin-top:1rem;padding-left:1.2rem}ol li>p:first-child,ul li>p:first-child{margin-bottom:.25rem;margin-top:.25rem}ol li>p:last-child,ul li>p:last-child{margin-top:.25rem}ol li>ol,ol li>ul,ul li>ol,ul li>ul{margin-bottom:.5rem;margin-top:.5rem}ol.arabic{list-style:decimal}ol.loweralpha{list-style:lower-alpha}ol.upperalpha{list-style:upper-alpha}ol.lowerroman{list-style:lower-roman}ol.upperroman{list-style:upper-roman}.simple li>ol,.simple li>ul,.toctree-wrapper li>ol,.toctree-wrapper li>ul{margin-bottom:0;margin-top:0}.field-list dt,.option-list dt,dl.footnote dt,dl.glossary dt,dl.simple dt,dl:not([class]) dt{font-weight:500;margin-top:.25rem}.field-list dt+dt,.option-list dt+dt,dl.footnote dt+dt,dl.glossary dt+dt,dl.simple dt+dt,dl:not([class]) dt+dt{margin-top:0}.field-list dt .classifier:before,.option-list dt .classifier:before,dl.footnote dt .classifier:before,dl.glossary dt .classifier:before,dl.simple dt .classifier:before,dl:not([class]) dt .classifier:before{content:":";margin-left:.2rem;margin-right:.2rem}.field-list dd ul,.field-list dd>p:first-child,.option-list dd ul,.option-list dd>p:first-child,dl.footnote dd ul,dl.footnote dd>p:first-child,dl.glossary dd ul,dl.glossary dd>p:first-child,dl.simple dd ul,dl.simple dd>p:first-child,dl:not([class]) dd ul,dl:not([class]) dd>p:first-child{margin-top:.125rem}.field-list dd ul,.option-list dd ul,dl.footnote dd ul,dl.glossary dd ul,dl.simple dd ul,dl:not([class]) dd ul{margin-bottom:.125rem}.math-wrapper{overflow-x:auto;width:100%}div.math{position:relative;text-align:center}div.math .headerlink,div.math:focus .headerlink{display:none}div.math:hover .headerlink{display:inline-block}div.math span.eqno{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);z-index:1}abbr[title]{cursor:help}.problematic{color:var(--color-problematic)}kbd:not(.compound){background-color:var(--color-background-secondary);border:1px solid var(--color-foreground-border);border-radius:.2rem;box-shadow:0 .0625rem 0 rgba(0,0,0,.2),inset 0 0 0 .125rem var(--color-background-primary);color:var(--color-foreground-primary);display:inline-block;font-size:var(--font-size--small--3);margin:0 .2rem;padding:0 .2rem;vertical-align:text-bottom}blockquote{background:var(--color-background-secondary);border-left:4px solid var(--color-background-border);margin-left:0;margin-right:0;padding:.5rem 1rem}blockquote .attribution{font-weight:600;text-align:right}blockquote.highlights,blockquote.pull-quote{font-size:1.25em}blockquote.epigraph,blockquote.pull-quote{border-left-width:0;border-radius:.5rem}blockquote.highlights{background:transparent;border-left-width:0}p .reference img{vertical-align:middle}p.rubric{font-size:1.125em;font-weight:700;line-height:1.25}dd p.rubric{font-size:var(--font-size--small);font-weight:inherit;line-height:inherit;text-transform:uppercase}article .sidebar{background-color:var(--color-background-secondary);border:1px solid var(--color-background-border);border-radius:.2rem;clear:right;float:right;margin-left:1rem;margin-right:0;width:30%}article .sidebar>*{padding-left:1rem;padding-right:1rem}article .sidebar>ol,article .sidebar>ul{padding-left:2.2rem}article .sidebar .sidebar-title{border-bottom:1px solid var(--color-background-border);font-weight:500;margin:0;padding:.5rem 1rem}.table-wrapper{margin-bottom:.5rem;margin-top:1rem;overflow-x:auto;padding:.2rem .2rem .75rem;width:100%}table.docutils{border-collapse:collapse;border-radius:.2rem;border-spacing:0;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1)}table.docutils th{background:var(--color-table-header-background)}table.docutils td,table.docutils th{border-bottom:1px solid var(--color-table-border);border-left:1px solid var(--color-table-border);border-right:1px solid var(--color-table-border);padding:0 .25rem}table.docutils td p,table.docutils th p{margin:.25rem}table.docutils td:first-child,table.docutils th:first-child{border-left:none}table.docutils td:last-child,table.docutils th:last-child{border-right:none}table.docutils td.text-left,table.docutils th.text-left{text-align:left}table.docutils td.text-right,table.docutils th.text-right{text-align:right}table.docutils td.text-center,table.docutils th.text-center{text-align:center}:target{scroll-margin-top:2.5rem}@media(max-width:67em){:target{scroll-margin-top:calc(2.5rem + var(--header-height))}section>span:target{scroll-margin-top:calc(2.8rem + var(--header-height))}}.headerlink{font-weight:100;-webkit-user-select:none;-moz-user-select:none;user-select:none}.code-block-caption>.headerlink,dl dt>.headerlink,figcaption p>.headerlink,h1>.headerlink,h2>.headerlink,h3>.headerlink,h4>.headerlink,h5>.headerlink,h6>.headerlink,p.caption>.headerlink,table>caption>.headerlink{margin-left:.5rem;visibility:hidden}.code-block-caption:hover>.headerlink,dl dt:hover>.headerlink,figcaption p:hover>.headerlink,h1:hover>.headerlink,h2:hover>.headerlink,h3:hover>.headerlink,h4:hover>.headerlink,h5:hover>.headerlink,h6:hover>.headerlink,p.caption:hover>.headerlink,table>caption:hover>.headerlink{visibility:visible}.code-block-caption>.toc-backref,dl dt>.toc-backref,figcaption p>.toc-backref,h1>.toc-backref,h2>.toc-backref,h3>.toc-backref,h4>.toc-backref,h5>.toc-backref,h6>.toc-backref,p.caption>.toc-backref,table>caption>.toc-backref{color:inherit;text-decoration-line:none}figure:hover>figcaption>p>.headerlink,table:hover>caption>.headerlink{visibility:visible}:target>h1:first-of-type,:target>h2:first-of-type,:target>h3:first-of-type,:target>h4:first-of-type,:target>h5:first-of-type,:target>h6:first-of-type,span:target~h1:first-of-type,span:target~h2:first-of-type,span:target~h3:first-of-type,span:target~h4:first-of-type,span:target~h5:first-of-type,span:target~h6:first-of-type{background-color:var(--color-highlight-on-target)}:target>h1:first-of-type code.literal,:target>h2:first-of-type code.literal,:target>h3:first-of-type code.literal,:target>h4:first-of-type code.literal,:target>h5:first-of-type code.literal,:target>h6:first-of-type code.literal,span:target~h1:first-of-type code.literal,span:target~h2:first-of-type code.literal,span:target~h3:first-of-type code.literal,span:target~h4:first-of-type code.literal,span:target~h5:first-of-type code.literal,span:target~h6:first-of-type code.literal{background-color:transparent}.literal-block-wrapper:target .code-block-caption,.this-will-duplicate-information-and-it-is-still-useful-here li :target,figure:target,table:target>caption{background-color:var(--color-highlight-on-target)}dt:target{background-color:var(--color-highlight-on-target)!important}.footnote-reference:target,.footnote>dt:target+dd{background-color:var(--color-highlight-on-target)}.guilabel{background-color:var(--color-guilabel-background);border:1px solid var(--color-guilabel-border);border-radius:.5em;color:var(--color-guilabel-text);font-size:.9em;padding:0 .3em}footer{display:flex;flex-direction:column;font-size:var(--font-size--small);margin-top:2rem}.bottom-of-page{align-items:center;border-top:1px solid var(--color-background-border);color:var(--color-foreground-secondary);display:flex;justify-content:space-between;line-height:1.5;margin-top:1rem;padding-bottom:1rem;padding-top:1rem}@media(max-width:46em){.bottom-of-page{flex-direction:column-reverse;gap:.25rem;text-align:center}}.bottom-of-page .left-details{font-size:var(--font-size--small)}.bottom-of-page .right-details{display:flex;flex-direction:column;gap:.25rem;text-align:right}.bottom-of-page .icons{display:flex;font-size:1rem;gap:.25rem;justify-content:flex-end}.bottom-of-page .icons a{text-decoration:none}.bottom-of-page .icons img,.bottom-of-page .icons svg{font-size:1.125rem;height:1em;width:1em}.related-pages a{align-items:center;display:flex;text-decoration:none}.related-pages a:hover .page-info .title{color:var(--color-link);text-decoration:underline;text-decoration-color:var(--color-link-underline)}.related-pages a svg.furo-related-icon,.related-pages a svg.furo-related-icon>use{color:var(--color-foreground-border);flex-shrink:0;height:.75rem;margin:0 .5rem;width:.75rem}.related-pages a.next-page{clear:right;float:right;max-width:50%;text-align:right}.related-pages a.prev-page{clear:left;float:left;max-width:50%}.related-pages a.prev-page svg{transform:rotate(180deg)}.page-info{display:flex;flex-direction:column;overflow-wrap:anywhere}.next-page .page-info{align-items:flex-end}.page-info .context{align-items:center;color:var(--color-foreground-muted);display:flex;font-size:var(--font-size--small);padding-bottom:.1rem;text-decoration:none}ul.search{list-style:none;padding-left:0}ul.search li{border-bottom:1px solid var(--color-background-border);padding:1rem 0}[role=main] .highlighted{background-color:var(--color-highlighted-background);color:var(--color-highlighted-text)}.sidebar-brand{display:flex;flex-direction:column;flex-shrink:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none}.sidebar-brand-text{color:var(--color-sidebar-brand-text);font-size:1.5rem;overflow-wrap:break-word}.sidebar-brand-text,.sidebar-logo-container{margin:var(--sidebar-item-spacing-vertical) 0}.sidebar-logo{display:block;margin:0 auto;max-width:100%}.sidebar-search-container{align-items:center;background:var(--color-sidebar-search-background);display:flex;margin-top:var(--sidebar-search-space-above);position:relative}.sidebar-search-container:focus-within,.sidebar-search-container:hover{background:var(--color-sidebar-search-background--focus)}.sidebar-search-container:before{background-color:var(--color-sidebar-search-icon);content:"";height:var(--sidebar-search-icon-size);left:var(--sidebar-item-spacing-horizontal);-webkit-mask-image:var(--icon-search);mask-image:var(--icon-search);position:absolute;width:var(--sidebar-search-icon-size)}.sidebar-search{background:transparent;border:none;border-bottom:1px solid var(--color-sidebar-search-border);border-top:1px solid var(--color-sidebar-search-border);box-sizing:border-box;color:var(--color-sidebar-search-foreground);padding:var(--sidebar-search-input-spacing-vertical) var(--sidebar-search-input-spacing-horizontal) var(--sidebar-search-input-spacing-vertical) calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size));width:100%;z-index:10}.sidebar-search:focus{outline:none}.sidebar-search::-moz-placeholder{font-size:var(--sidebar-search-input-font-size)}.sidebar-search::placeholder{font-size:var(--sidebar-search-input-font-size)}#searchbox .highlight-link{margin:0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0;text-align:center}#searchbox .highlight-link a{color:var(--color-sidebar-search-icon);font-size:var(--font-size--small--2)}.sidebar-tree{font-size:var(--sidebar-item-font-size);margin-bottom:var(--sidebar-item-spacing-vertical);margin-top:var(--sidebar-tree-space-above)}.sidebar-tree ul{display:flex;flex-direction:column;list-style:none;margin-bottom:0;margin-top:0;padding:0}.sidebar-tree li{margin:0;position:relative}.sidebar-tree li>ul{margin-left:var(--sidebar-item-spacing-horizontal)}.sidebar-tree .icon,.sidebar-tree .reference{color:var(--color-sidebar-link-text)}.sidebar-tree .reference{box-sizing:border-box;display:inline-block;height:100%;line-height:var(--sidebar-item-line-height);overflow-wrap:anywhere;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-decoration:none;width:100%}.sidebar-tree .reference:hover{background:var(--color-sidebar-item-background--hover);color:var(--color-sidebar-link-text)}.sidebar-tree .reference.external:after{color:var(--color-sidebar-link-text);content:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23607D8B' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' viewBox='0 0 24 24'%3E%3Cpath stroke='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M11 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-5M10 14 20 4M15 4h5v5'/%3E%3C/svg%3E");margin:0 .25rem;vertical-align:middle}.sidebar-tree .current-page>.reference{font-weight:700}.sidebar-tree label{align-items:center;cursor:pointer;display:flex;height:var(--sidebar-item-height);justify-content:center;position:absolute;right:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:var(--sidebar-expander-width)}.sidebar-tree .caption,.sidebar-tree :not(.caption)>.caption-text{color:var(--color-sidebar-caption-text);font-size:var(--sidebar-caption-font-size);font-weight:700;margin:var(--sidebar-caption-space-above) 0 0 0;padding:var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal);text-transform:uppercase}.sidebar-tree li.has-children>.reference{padding-right:var(--sidebar-expander-width)}.sidebar-tree .toctree-l1>.reference,.sidebar-tree .toctree-l1>label .icon{color:var(--color-sidebar-link-text--top-level)}.sidebar-tree label{background:var(--color-sidebar-item-expander-background)}.sidebar-tree label:hover{background:var(--color-sidebar-item-expander-background--hover)}.sidebar-tree .current>.reference{background:var(--color-sidebar-item-background--current)}.sidebar-tree .current>.reference:hover{background:var(--color-sidebar-item-background--hover)}.toctree-checkbox{display:none;position:absolute}.toctree-checkbox~ul{display:none}.toctree-checkbox~label .icon svg{transform:rotate(90deg)}.toctree-checkbox:checked~ul{display:block}.toctree-checkbox:checked~label .icon svg{transform:rotate(-90deg)}.toc-title-container{padding:var(--toc-title-padding);padding-top:var(--toc-spacing-vertical)}.toc-title{color:var(--color-toc-title-text);font-size:var(--toc-title-font-size);padding-left:var(--toc-spacing-horizontal);text-transform:uppercase}.no-toc{display:none}.toc-tree-container{padding-bottom:var(--toc-spacing-vertical)}.toc-tree{border-left:1px solid var(--color-background-border);font-size:var(--toc-font-size);line-height:1.3;padding-left:calc(var(--toc-spacing-horizontal) - var(--toc-item-spacing-horizontal))}.toc-tree>ul>li:first-child{padding-top:0}.toc-tree>ul>li:first-child>ul{padding-left:0}.toc-tree>ul>li:first-child>a{display:none}.toc-tree ul{list-style-type:none;margin-bottom:0;margin-top:0;padding-left:var(--toc-item-spacing-horizontal)}.toc-tree li{padding-top:var(--toc-item-spacing-vertical)}.toc-tree li.scroll-current>.reference{color:var(--color-toc-item-text--active);font-weight:700}.toc-tree a.reference{color:var(--color-toc-item-text);overflow-wrap:anywhere;text-decoration:none}.toc-scroll{max-height:100vh;overflow-y:scroll}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here){background:rgba(255,0,0,.25);color:var(--color-problematic)}.contents:not(.this-will-duplicate-information-and-it-is-still-useful-here):before{content:"ERROR: Adding a table of contents in Furo-based documentation is unnecessary, and does not work well with existing styling. Add a 'this-will-duplicate-information-and-it-is-still-useful-here' class, if you want an escape hatch."}.text-align\:left>p{text-align:left}.text-align\:center>p{text-align:center}.text-align\:right>p{text-align:right} +/*# sourceMappingURL=furo.css.map*/ \ No newline at end of file diff --git a/latest/_static/styles/furo.css.map b/latest/_static/styles/furo.css.map new file mode 100644 index 00000000..6e02d0b1 --- /dev/null +++ b/latest/_static/styles/furo.css.map @@ -0,0 +1 @@ +{"version":3,"file":"styles/furo.css","mappings":"AAAA,2EAA2E,CAU3E,KACE,gBAAiB,CACjB,6BACF,CASA,KACE,QACF,CAMA,KACE,aACF,CAOA,GACE,aAAc,CACd,cACF,CAUA,GACE,sBAAuB,CACvB,QAAS,CACT,gBACF,CAOA,IACE,+BAAiC,CACjC,aACF,CASA,EACE,4BACF,CAOA,YACE,kBAAmB,CACnB,yBAA0B,CAC1B,gCACF,CAMA,SAEE,kBACF,CAOA,cAGE,+BAAiC,CACjC,aACF,CAeA,QAEE,aAAc,CACd,aAAc,CACd,iBAAkB,CAClB,uBACF,CAEA,IACE,aACF,CAEA,IACE,SACF,CASA,IACE,iBACF,CAUA,sCAKE,mBAAoB,CACpB,cAAe,CACf,gBAAiB,CACjB,QACF,CAOA,aAEE,gBACF,CAOA,cAEE,mBACF,CAMA,gDAIE,yBACF,CAMA,wHAIE,iBAAkB,CAClB,SACF,CAMA,4GAIE,6BACF,CAMA,SACE,0BACF,CASA,OACE,qBAAsB,CACtB,aAAc,CACd,aAAc,CACd,cAAe,CACf,SAAU,CACV,kBACF,CAMA,SACE,uBACF,CAMA,SACE,aACF,CAOA,6BAEE,qBAAsB,CACtB,SACF,CAMA,kFAEE,WACF,CAOA,cACE,4BAA6B,CAC7B,mBACF,CAMA,yCACE,uBACF,CAOA,6BACE,yBAA0B,CAC1B,YACF,CASA,QACE,aACF,CAMA,QACE,iBACF,CAiBA,kBACE,YACF,CCvVA,aAcE,kEACE,uBAOF,WACE,iDAMF,gCACE,wBAEF,qCAEE,uBADA,uBACA,CAEF,SACE,wBAtBA,CCpBJ,iBAGE,qBAEA,sBACA,0BAFA,oBAHA,4BACA,oBAKA,6BAIA,2CAFA,mBACA,sCAFA,4BAGA,CAEF,gBACE,aCTF,KCGE,mHAEA,wGAEA,wCAAyC,CAEzC,wBAAyB,CACzB,wBAAyB,CACzB,4BAA6B,CAC7B,yBAA0B,CAC1B,2BAA4B,CAG5B,sDAAuD,CACvD,gDAAiD,CACjD,wDAAyD,CAGzD,0CAA2C,CAC3C,gDAAiD,CACjD,gDAAiD,CAKjD,gCAAiC,CACjC,sCAAuC,CAGvC,2CAA4C,CAG5C,uCAAwC,CCjCxC,+FAGA,uBAAwB,CAGxB,iCAAkC,CAClC,kCAAmC,CAEnC,+BAAgC,CAChC,sCAAuC,CACvC,sCAAuC,CACvC,qGAIA,mDAAoD,CAEpD,mCAAoC,CACpC,8CAA+C,CAC/C,gDAAiD,CACjD,kCAAmC,CACnC,6DAA8D,CAG9D,6BAA8B,CAC9B,6BAA8B,CAC9B,+BAAgC,CAChC,kCAAmC,CACnC,kCAAmC,CCPjC,+jBCYA,iqCAZF,iaCVA,8KAOA,4SAWA,4SAUA,0CACA,gEAGA,0CAGA,gEAGA,yCACA,+DAIA,4CACA,kEAGA,wCAUA,8DACA,uCAGA,4DACA,sCACA,2DAGA,4CACA,kEACA,uCAGA,6DACA,2GAGA,sHAEA,yFAEA,+CACA,+EAGA,4MAOA,gCACA,sHAIA,kCACA,uEACA,gEACA,4DACA,kEAGA,2DACA,sDACA,0CACA,8CACA,wGAGA,0BACA,iCAGA,+DACA,+BACA,sCACA,+DAEA,kGACA,oCACA,yDACA,sCL7HF,kCAEA,sDAIA,0CK2HE,kEAIA,oDACA,sDAGA,oCACA,oEAEA,0DACA,qDAIA,oDACA,6DAIA,iEAIA,2DAIA,2DAGA,4DACA,gEAIA,gEAEA,gFAEA,oNASA,qDLxKE,gFAGE,4DAIF,oEKkHF,yEAEA,6DAGA,0DAEA,uDACA,qDACA,wDAIA,6DAIA,yDACA,2DAIA,uCAGA,wCACA,sDAGA,+CAGA,6DAEA,iDACA,+DAEA,wDAEA,sEAMA,0DACA,sBACA,mEL9JI,wEAEA,iCACE,+BAMN,wEAGA,iCACE,kFAEA,uEAIF,gEACE,8BAGF,qEMvDA,sCAKA,wFAKA,iCAIA,0BAWA,iCACA,4BACA,mCAGA,+BAEA,sCACA,4BAEA,mCAEA,sCAKA,sDAIA,gCAEA,gEAQF,wCAME,sBACA,kCAKA,uBAEA,gEAIA,2BAIA,mCAEA,qCACA,iCAGE,+BACA,wEAEE,iCACA,kFAGF,6BACA,0CACF,kCAEE,8BACE,8BACA,qEAEE,sCACA,wFCjFN,iCAGF,2DAEE,4BACA,oCAGA,mIAGA,4HACE,gEAMJ,+CAGE,sBACA,yCAEF,uBAEE,sEAKA,gDACA,kEAGA,iFAGE,YAGF,EACA,4HAQF,mBACE,6BACA,mBACA,wCACA,wCACA,2CAIA,eAGA,mBAKE,mBAGA,CAJA,uCACA,iBAFF,gBACE,CAKE,mBACA,mBAGJ,oBAIF,+BAGE,kDACA,OADA,kBAGA,CAFA,gBAEA,mBACA,oBAEA,sCACA,OAGF,cAHE,WAGF,GAEE,oBACA,CAHF,gBAGE,CChHc,YDmHd,+CAIF,SAEE,CAPF,UACE,wBAMA,4BAEA,GAGA,uBACA,CAJA,yBAGA,CACA,iDAKA,2CAGA,2DAQA,iBACA,uCAGA,kEAKE,SAKJ,8BACE,yDACA,2BAEA,oBACA,8BAEA,yDAEE,4BAEJ,uCACE,CACA,iEAGA,CAEA,wCACE,uBACA,kDAEA,0DAEE,CAJF,oBAIE,0GASJ,aAEF,CAFE,YAEF,4HASE,+CACA,sBAGF,sBASE,4BAFF,0CAEE,CARA,qCAwBF,CAhBE,iBAEA,kBACE,aADF,4BACE,WAOF,2BAEF,qCAIA,CAbI,UAaJ,+BACE,uBAEA,SAGA,0CAGE,CANF,qCAGA,CAGE,2DACE,gBAKJ,+CAGF,CAEA,kDAME,CARF,8BAEA,CAQE,YAEA,CAlBI,2BAGJ,CAJI,UACA,CAcJ,UAIA,4GAIF,iCAGE,8BAIA,qBACA,mBACF,QACE,gBAOE,0CAGA,CATF,6DAME,CANF,sBASE,qCAKF,CAEE,cACA,CAHF,sBAGE,gCAEA,qBAOJ,wBACE,sCAIA,mBAEA,6BAKA,kCACA,CAHA,sBAEA,cAJA,eACA,MAIA,2FAIA,UACA,YACA,sBACE,8BAEA,CALF,aACA,WAIE,CACA,0BAEF,aACE,qBAEF,qCAgBA,kBACE,CAhBA,qDASA,qCAEJ,CAGI,YACF,CAJF,2BAGI,CAGA,eACE,CAAF,oBAEA,mEAEA,qBACA,eAGF,CAHE,cAIA,kBADF,kBACE,yBAEJ,oCAGI,qDAIA,+BAMF,oCAEA,+CAEA,gCAIA,YACE,yBAEA,qBACA,eAGA,uBAFA,WAEA,CAHA,cACA,CAEA,4BAIE,qCACA,cAFA,eADA,qBACA,cAEA,mDACE,CACA,oCACA,4EAEN,uCAMA,eACE,kDAIA,mBADF,sBACE,mBAIA,aACA,sCAGA,aADA,WACA,CAMA,UAFF,kBAEE,CAJJ,gBAEE,CAJE,iBAMA,yFAQA,aACA,eEpbJ,cACE,iBACA,YAEA,CAFA,iBAEA,+DAGA,mBAKA,gCAGA,CARA,SAIA,SACA,CALA,0EAIA,CAJA,OAQA,0CACE,UAGF,iDAGF,CAHE,UAGF,8CAEE,CAFF,UAEE,CACA,uCAEA,WACA,WAFA,UAEA,6CAIA,yCACA,WAGA,WAJA,UAIA,gDACE,aASF,0CACE,CAFF,mBAEE,wEACA,CATA,YACA,CAKF,kBACA,CALE,MAGJ,CAII,eACA,CAJF,iCALE,cACA,CAHA,oBACA,CAKJ,SAKI,2BADA,UACA,6BAEJ,WACE,0DACA,kBACE,gCACA,mBADA,YACA,oEACA,2CAMF,mDAII,CAJJ,aADF,cACE,kBAII,kEACA,iBACE,mEACA,6BACE,wBADF,cACE,mCACA,qDANN,kCACE,6BAEE,mBADF,0CACE,CAFF,eACA,MACE,0DACA,wCACE,sGACA,WANN,yBACE,uCACA,CAFF,UAEE,2CACE,0FACA,cACE,kEACA,mEANN,yBACE,4DACA,sBACE,+EAEE,iEACA,qEANN,sCACE,CAGE,iBAHF,gBAGE,qBACE,CAJJ,uBACA,gDACE,wDACA,6DAHF,2CACA,CADA,gBACA,eACE,CAGE,sBANN,8BACE,CAII,iBAFF,4DACA,WACE,YADF,uCACE,6EACA,2BANN,8CACE,kDACA,0CACE,8BACA,yFACE,sBACA,sFALJ,mEACA,sBACE,kEACA,6EACE,uCACA,kEALJ,qGAEE,kEACA,6EACE,uCACA,kEALJ,8CACA,uDACE,sEACA,2EACE,sCACA,iEALJ,mGACA,qCACE,oDACA,0DACE,6GACA,gDAGR,yDCrEA,sEACE,CACA,6GACE,gEACF,iGAIF,wFACE,qDAGA,mGAEE,2CAEF,4FACE,gCACF,wGACE,8DAEE,6FAIA,iJAKN,6GACE,gDAKF,yDACA,qCAGA,6BACA,kBACA,qDAKA,oCAEA,+DAGA,2CAGE,oDAIA,oEAEE,qBAGJ,wDAEE,uCAEF,kEAGA,8CAEA,uDAIF,gEAIE,6BACA,gEAIA,+CACE,0EAIF,sDAEE,+DAGF,sCACA,8BACE,oCAEJ,wBACE,4FAEE,gBAEJ,yGAGI,kBAGJ,CCnHE,2MCFF,oBAGE,wGAKA,iCACE,CADF,wBACE,8GAQA,mBCjBJ,2GAIE,mBACA,6HAMA,YACE,mIAYF,eACA,CAHF,YAGE,4FAGE,8BAKF,uBAkBE,sCACA,CADA,qBAbA,wCAIA,CALF,8BACE,CADF,gBAKE,wCACA,CAOA,kDACA,CACA,kCAKF,6BAGA,4CACE,kDACA,eAGF,cACE,aACA,iBACA,yBACA,8BACA,WAGJ,2BACE,cAGA,+BACA,CAHA,eAGA,wCACA,YACA,iBACA,uEAGA,0BACA,2CAEA,8EAGI,qBACA,CAFF,kBAEE,kBAGN,0CAGE,mCAGA,4BAIA,gEACE,qCACA,8BAEA,gBACA,+CACA,iCAEF,iCAEE,gEACA,qCAGF,8BAEE,+BAIA,yCAEE,qBADA,gBACA,yBAKF,eACA,CAFF,YACE,CACA,iBACA,qDAEA,mDCvIJ,2FAOE,iCACA,CAEA,eACA,CAHA,kBAEA,CAFA,wBAGA,8BACA,eACE,CAFF,YAEE,0BACA,8CAGA,oBACE,oCAGA,kBACE,8DAEA,iBAEN,UACE,8BAIJ,+CAEE,qDAEF,kDAIE,YAEF,CAFE,YAEF,CCpCE,mFADA,kBAKE,CAJF,IAGA,aACE,mCAGA,iDACE,+BAEJ,wBAEE,mBAMA,6CAEF,CAJE,mBAEA,CAEF,kCAGE,CARF,kBACE,CAHA,eAUA,YACA,mBACA,CADA,UACA,wCC9BF,oBDkCE,wBCnCJ,uCACE,+BACA,+DACA,sBAGA,qBCDA,6CAIE,CAPF,uBAGA,CDGE,oBACF,yDAEE,CCDE,2CAGF,CAJA,kCACE,CDJJ,YACE,CAIA,eCTF,CDKE,uBCMA,gCACE,YAEF,oCAEE,wBACA,0BAIF,iBAEA,cADF,UACE,uBAEA,iCAEA,wCAEA,6CAMA,CAYF,gCATI,4BASJ,CAZE,mCAEE,iCAUJ,4BAGE,4DADA,+BACA,CAHF,qBAGE,sCACE,OAEF,iBAHA,SAGA,iHACE,2DAKF,CANA,8EAMA,uSAEE,kBAEF,+FACE,yCCjEJ,WACA,yBAGA,uBACA,gBAEA,uCAIA,CAJA,iCAIA,uCAGA,UACE,gBACA,qBAEA,0CClBJ,gBACE,KAGF,qBACE,YAGF,CAHE,cAGF,gCAEE,mBACA,iEAEA,oCACA,wCAEA,sBACA,WAEA,CAFA,YAEA,8EAEA,mCAFA,iBAEA,6BAIA,wEAKA,sDAIE,CARF,mDAIA,CAIE,cAEF,8CAIA,oBAFE,iBAEF,8CAGE,eAEF,CAFE,YAEF,OAEE,kBAGJ,CAJI,eACA,CAFF,mBAKF,yCCjDE,oBACA,CAFA,iBAEA,uCAKE,iBACA,qCAGA,mBCZJ,CDWI,gBCXJ,6BAEE,eACA,sBAGA,eAEA,sBACA,oDACA,iGAMA,gBAFE,YAEF,8FAME,iJClBF,YACA,gNAUE,6BAEF,oTAcI,kBACF,gHAIA,qBACE,eACF,qDACE,kBACF,6DACE,4BCxCJ,oBAEF,qCAEI,+CAGF,uBACE,uDAGJ,oBAiBI,kDACF,CAhBA,+CAaA,CAbA,oBAaA,0FAEE,CAFF,gGAdA,cACA,iBAaA,0BAGA,mQAIA,oNAEE,iBAGJ,CAHI,gBAFF,gBAKF,8CAYI,CAZJ,wCAYI,sVACE,iCAGA,uEAHA,QAGA,qXAKJ,iDAGF,CARM,+CACE,iDAIN,CALI,gBAQN,mHACE,gBAGF,2DACE,0EAOA,0EAGF,gBAEE,6DC/EA,kDACA,gCACA,qDAGA,qBACA,qDCFA,cACA,eAEA,yBAGF,sBAEE,iBACA,sNAWA,iBACE,kBACA,wRAgBA,kBAEA,iOAgBA,uCACE,uEAEA,kBAEF,qUAuBE,iDAIJ,CACA,geCxFF,4BAEE,CAQA,6JACA,iDAIA,sEAGA,mDAOF,iDAGE,4DAIA,8CACA,qDAEE,eAFF,cAEE,oBAEF,uBAFE,kCAGA,eACA,iBACA,mBAIA,mDACA,CAHA,uCAEA,CAJA,0CACA,CAIA,gBAJA,gBACA,oBADA,gBAIA,wBAEJ,gBAGE,6BACA,YAHA,iBAGA,gCACA,iEAEA,6CACA,sDACA,0BADA,wBACA,0BACA,oIAIA,mBAFA,YAEA,qBACA,0CAIE,uBAEF,CAHA,yBACE,CAEF,iDACE,mFAKJ,oCACE,CANE,aAKJ,CACE,qEAIA,YAFA,WAEA,CAHA,aACA,CAEA,gBACE,4BACA,sBADA,aACA,gCAMF,oCACA,yDACA,2CAEA,qBAGE,kBAEA,CACA,mCAIF,CARE,YACA,CAOF,iCAEE,CAPA,oBACA,CAQA,oBACE,uDAEJ,sDAGA,CAHA,cAGA,0BACE,oDAIA,oCACA,4BACA,sBAGA,cAEA,oFAGA,sBAEA,yDACE,CAIF,iBAJE,wBAIF,6CAHE,6CAKA,eACA,aACA,CADA,cACA,yCAGJ,kBACE,CAKA,iDAEA,CARF,aACE,4CAGA,kBAIA,wEAGA,wDAGA,kCAOA,iDAGA,CAPF,WAEE,sCAEA,CAJF,2CACE,CAMA,qCACA,+BARF,kBACE,qCAOA,iBAsBA,sBACE,CAvBF,WAKA,CACE,0DAIF,CALA,uDACE,CANF,sBAqBA,4CACA,CALA,gRAIA,YAEE,6CAEN,mCAEE,+CASA,6EAIA,4BChNA,SDmNA,qFCnNA,gDACA,sCAGA,qCACA,sDACA,CAKA,kDAGA,CARA,0CAQA,kBAGA,YACA,sBACA,iBAFA,gBADF,YACE,CAHA,SAKA,kBAEA,SAFA,iBAEA,uEAGA,CAEE,6CAFF,oCAgBI,CAdF,yBACE,qBACF,CAGF,oBACE,CAIF,WACE,CALA,2CAGA,uBACF,CACE,mFAGE,CALF,qBAEA,UAGE,gCAIF,sDAEA,CALE,oCAKF,yCC7CJ,oCACE,CD+CA,yXAQE,sCCrDJ,wCAGA,oCACE","sources":["webpack:///./node_modules/normalize.css/normalize.css","webpack:///./src/furo/assets/styles/base/_print.sass","webpack:///./src/furo/assets/styles/base/_screen-readers.sass","webpack:///./src/furo/assets/styles/base/_theme.sass","webpack:///./src/furo/assets/styles/variables/_fonts.scss","webpack:///./src/furo/assets/styles/variables/_spacing.scss","webpack:///./src/furo/assets/styles/variables/_icons.scss","webpack:///./src/furo/assets/styles/variables/_admonitions.scss","webpack:///./src/furo/assets/styles/variables/_colors.scss","webpack:///./src/furo/assets/styles/base/_typography.sass","webpack:///./src/furo/assets/styles/_scaffold.sass","webpack:///./src/furo/assets/styles/variables/_layout.scss","webpack:///./src/furo/assets/styles/content/_admonitions.sass","webpack:///./src/furo/assets/styles/content/_api.sass","webpack:///./src/furo/assets/styles/content/_blocks.sass","webpack:///./src/furo/assets/styles/content/_captions.sass","webpack:///./src/furo/assets/styles/content/_code.sass","webpack:///./src/furo/assets/styles/content/_footnotes.sass","webpack:///./src/furo/assets/styles/content/_images.sass","webpack:///./src/furo/assets/styles/content/_indexes.sass","webpack:///./src/furo/assets/styles/content/_lists.sass","webpack:///./src/furo/assets/styles/content/_math.sass","webpack:///./src/furo/assets/styles/content/_misc.sass","webpack:///./src/furo/assets/styles/content/_rubrics.sass","webpack:///./src/furo/assets/styles/content/_sidebar.sass","webpack:///./src/furo/assets/styles/content/_tables.sass","webpack:///./src/furo/assets/styles/content/_target.sass","webpack:///./src/furo/assets/styles/content/_gui-labels.sass","webpack:///./src/furo/assets/styles/components/_footer.sass","webpack:///./src/furo/assets/styles/components/_sidebar.sass","webpack:///./src/furo/assets/styles/components/_table_of_contents.sass","webpack:///./src/furo/assets/styles/_shame.sass"],"sourcesContent":["/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\nsmall {\n font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\nimg {\n border-style: none;\n}\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput { /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect { /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\nfieldset {\n padding: 0.35em 0.75em 0.625em;\n}\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\ndetails {\n display: block;\n}\n\n/*\n * Add the correct display in all browsers.\n */\n\nsummary {\n display: list-item;\n}\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n","// This file contains styles for managing print media.\n\n////////////////////////////////////////////////////////////////////////////////\n// Hide elements not relevant to print media.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Hide icon container.\n .content-icon-container\n display: none !important\n\n // Hide showing header links if hovering over when printing.\n .headerlink\n display: none !important\n\n // Hide mobile header.\n .mobile-header\n display: none !important\n\n // Hide navigation links.\n .related-pages\n display: none !important\n\n////////////////////////////////////////////////////////////////////////////////\n// Tweaks related to decolorization.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n // Apply a border around code which no longer have a color background.\n .highlight\n border: 0.1pt solid var(--color-foreground-border)\n\n////////////////////////////////////////////////////////////////////////////////\n// Avoid page break in some relevant cases.\n////////////////////////////////////////////////////////////////////////////////\n@media print\n ul, ol, dl, a, table, pre, blockquote\n page-break-inside: avoid\n\n h1, h2, h3, h4, h5, h6, img, figure, caption\n page-break-inside: avoid\n page-break-after: avoid\n\n ul, ol, dl\n page-break-before: avoid\n",".visually-hidden\n position: absolute !important\n width: 1px !important\n height: 1px !important\n padding: 0 !important\n margin: -1px !important\n overflow: hidden !important\n clip: rect(0,0,0,0) !important\n white-space: nowrap !important\n border: 0 !important\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n:-moz-focusring\n outline: auto\n","// This file serves as the \"skeleton\" of the theming logic.\n//\n// This contains the bulk of the logic for handling dark mode, color scheme\n// toggling and the handling of color-scheme-specific hiding of elements.\n\nbody\n @include fonts\n @include spacing\n @include icons\n @include admonitions\n @include default-admonition(#651fff, \"abstract\")\n @include default-topic(#14B8A6, \"pencil\")\n\n @include colors\n\n.only-light\n display: block !important\nhtml body .only-dark\n display: none !important\n\n// Ignore dark-mode hints if print media.\n@media not print\n // Enable dark-mode, if requested.\n body[data-theme=\"dark\"]\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n // Enable dark mode, unless explicitly told to avoid.\n @media (prefers-color-scheme: dark)\n body:not([data-theme=\"light\"])\n @include colors-dark\n\n html & .only-light\n display: none !important\n .only-dark\n display: block !important\n\n//\n// Theme toggle presentation\n//\nbody[data-theme=\"auto\"]\n .theme-toggle svg.theme-icon-when-auto-light\n display: block\n\n @media (prefers-color-scheme: dark)\n .theme-toggle svg.theme-icon-when-auto-dark\n display: block\n .theme-toggle svg.theme-icon-when-auto-light\n display: none\n\nbody[data-theme=\"dark\"]\n .theme-toggle svg.theme-icon-when-dark\n display: block\n\nbody[data-theme=\"light\"]\n .theme-toggle svg.theme-icon-when-light\n display: block\n","// Fonts used by this theme.\n//\n// There are basically two things here -- using the system font stack and\n// defining sizes for various elements in %ages. We could have also used `em`\n// but %age is easier to reason about for me.\n\n@mixin fonts {\n // These are adapted from https://systemfontstack.com/\n --font-stack: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,\n sans-serif, Apple Color Emoji, Segoe UI Emoji;\n --font-stack--monospace: \"SFMono-Regular\", Menlo, Consolas, Monaco,\n Liberation Mono, Lucida Console, monospace;\n --font-stack--headings: var(--font-stack);\n\n --font-size--normal: 100%;\n --font-size--small: 87.5%;\n --font-size--small--2: 81.25%;\n --font-size--small--3: 75%;\n --font-size--small--4: 62.5%;\n\n // Sidebar\n --sidebar-caption-font-size: var(--font-size--small--2);\n --sidebar-item-font-size: var(--font-size--small);\n --sidebar-search-input-font-size: var(--font-size--small);\n\n // Table of Contents\n --toc-font-size: var(--font-size--small--3);\n --toc-font-size--mobile: var(--font-size--normal);\n --toc-title-font-size: var(--font-size--small--4);\n\n // Admonitions\n //\n // These aren't defined in terms of %ages, since nesting these is permitted.\n --admonition-font-size: 0.8125rem;\n --admonition-title-font-size: 0.8125rem;\n\n // Code\n --code-font-size: var(--font-size--small--2);\n\n // API\n --api-font-size: var(--font-size--small);\n}\n","// Spacing for various elements on the page\n//\n// If the user wants to tweak things in a certain way, they are permitted to.\n// They also have to deal with the consequences though!\n\n@mixin spacing {\n // Header!\n --header-height: calc(\n var(--sidebar-item-line-height) + 4 * #{var(--sidebar-item-spacing-vertical)}\n );\n --header-padding: 0.5rem;\n\n // Sidebar\n --sidebar-tree-space-above: 1.5rem;\n --sidebar-caption-space-above: 1rem;\n\n --sidebar-item-line-height: 1rem;\n --sidebar-item-spacing-vertical: 0.5rem;\n --sidebar-item-spacing-horizontal: 1rem;\n --sidebar-item-height: calc(\n var(--sidebar-item-line-height) + 2 *#{var(--sidebar-item-spacing-vertical)}\n );\n\n --sidebar-expander-width: var(--sidebar-item-height); // be square\n\n --sidebar-search-space-above: 0.5rem;\n --sidebar-search-input-spacing-vertical: 0.5rem;\n --sidebar-search-input-spacing-horizontal: 0.5rem;\n --sidebar-search-input-height: 1rem;\n --sidebar-search-icon-size: var(--sidebar-search-input-height);\n\n // Table of Contents\n --toc-title-padding: 0.25rem 0;\n --toc-spacing-vertical: 1.5rem;\n --toc-spacing-horizontal: 1.5rem;\n --toc-item-spacing-vertical: 0.4rem;\n --toc-item-spacing-horizontal: 1rem;\n}\n","// Expose theme icons as CSS variables.\n\n$icons: (\n // Adapted from tabler-icons\n // url: https://tablericons.com/\n \"search\":\n url('data:image/svg+xml;charset=utf-8,'),\n // Factored out from mkdocs-material on 24-Aug-2020.\n // url: https://squidfunk.github.io/mkdocs-material/reference/admonitions/\n \"pencil\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"abstract\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"info\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"flame\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"question\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"warning\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"failure\":\n url('data:image/svg+xml;charset=utf-8,'),\n \"spark\":\n url('data:image/svg+xml;charset=utf-8,')\n);\n\n@mixin icons {\n @each $name, $glyph in $icons {\n --icon-#{$name}: #{$glyph};\n }\n}\n","// Admonitions\n\n// Structure of these is:\n// admonition-class: color \"icon-name\";\n//\n// The colors are translated into CSS variables below. The icons are\n// used directly in the main declarations to set the `mask-image` in\n// the title.\n\n// prettier-ignore\n$admonitions: (\n // Each of these has an reST directives for it.\n \"caution\": #ff9100 \"spark\",\n \"warning\": #ff9100 \"warning\",\n \"danger\": #ff5252 \"spark\",\n \"attention\": #ff5252 \"warning\",\n \"error\": #ff5252 \"failure\",\n \"hint\": #00c852 \"question\",\n \"tip\": #00c852 \"info\",\n \"important\": #00bfa5 \"flame\",\n \"note\": #00b0ff \"pencil\",\n \"seealso\": #448aff \"info\",\n \"admonition-todo\": #808080 \"pencil\"\n);\n\n@mixin default-admonition($color, $icon-name) {\n --color-admonition-title: #{$color};\n --color-admonition-title-background: #{rgba($color, 0.2)};\n\n --icon-admonition-default: var(--icon-#{$icon-name});\n}\n\n@mixin default-topic($color, $icon-name) {\n --color-topic-title: #{$color};\n --color-topic-title-background: #{rgba($color, 0.2)};\n\n --icon-topic-default: var(--icon-#{$icon-name});\n}\n\n@mixin admonitions {\n @each $name, $values in $admonitions {\n --color-admonition-title--#{$name}: #{nth($values, 1)};\n --color-admonition-title-background--#{$name}: #{rgba(\n nth($values, 1),\n 0.2\n )};\n }\n}\n","// Colors used throughout this theme.\n//\n// The aim is to give the user more control. Thus, instead of hard-coding colors\n// in various parts of the stylesheet, the approach taken is to define all\n// colors as CSS variables and reusing them in all the places.\n//\n// `colors-dark` depends on `colors` being included at a lower specificity.\n\n@mixin colors {\n --color-problematic: #b30000;\n\n // Base Colors\n --color-foreground-primary: black; // for main text and headings\n --color-foreground-secondary: #5a5c63; // for secondary text\n --color-foreground-muted: #6b6f76; // for muted text\n --color-foreground-border: #878787; // for content borders\n\n --color-background-primary: white; // for content\n --color-background-secondary: #f8f9fb; // for navigation + ToC\n --color-background-hover: #efeff4ff; // for navigation-item hover\n --color-background-hover--transparent: #efeff400;\n --color-background-border: #eeebee; // for UI borders\n --color-background-item: #ccc; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #0a4bff;\n --color-brand-content: #2757dd;\n --color-brand-visited: #872ee0;\n\n // API documentation\n --color-api-background: var(--color-background-hover--transparent);\n --color-api-background-hover: var(--color-background-hover);\n --color-api-overall: var(--color-foreground-secondary);\n --color-api-name: var(--color-problematic);\n --color-api-pre-name: var(--color-problematic);\n --color-api-paren: var(--color-foreground-secondary);\n --color-api-keyword: var(--color-foreground-primary);\n\n --color-api-added: #21632c;\n --color-api-added-border: #38a84d;\n --color-api-changed: #046172;\n --color-api-changed-border: #06a1bc;\n --color-api-deprecated: #605706;\n --color-api-deprecated-border: #f0d90f;\n --color-api-removed: #b30000;\n --color-api-removed-border: #ff5c5c;\n\n --color-highlight-on-target: #ffffcc;\n\n // Inline code background\n --color-inline-code-background: var(--color-background-secondary);\n\n // Highlighted text (search)\n --color-highlighted-background: #ddeeff;\n --color-highlighted-text: var(--color-foreground-primary);\n\n // GUI Labels\n --color-guilabel-background: #ddeeff80;\n --color-guilabel-border: #bedaf580;\n --color-guilabel-text: var(--color-foreground-primary);\n\n // Admonitions!\n --color-admonition-background: transparent;\n\n //////////////////////////////////////////////////////////////////////////////\n // Everything below this should be one of:\n // - var(...)\n // - *-gradient(...)\n // - special literal values (eg: transparent, none)\n //////////////////////////////////////////////////////////////////////////////\n\n // Tables\n --color-table-header-background: var(--color-background-secondary);\n --color-table-border: var(--color-background-border);\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: transparent;\n --color-card-marginals-background: var(--color-background-secondary);\n\n // Header\n --color-header-background: var(--color-background-primary);\n --color-header-border: var(--color-background-border);\n --color-header-text: var(--color-foreground-primary);\n\n // Sidebar (left)\n --color-sidebar-background: var(--color-background-secondary);\n --color-sidebar-background-border: var(--color-background-border);\n\n --color-sidebar-brand-text: var(--color-foreground-primary);\n --color-sidebar-caption-text: var(--color-foreground-muted);\n --color-sidebar-link-text: var(--color-foreground-secondary);\n --color-sidebar-link-text--top-level: var(--color-brand-primary);\n\n --color-sidebar-item-background: var(--color-sidebar-background);\n --color-sidebar-item-background--current: var(\n --color-sidebar-item-background\n );\n --color-sidebar-item-background--hover: linear-gradient(\n 90deg,\n var(--color-background-hover--transparent) 0%,\n var(--color-background-hover) var(--sidebar-item-spacing-horizontal),\n var(--color-background-hover) 100%\n );\n\n --color-sidebar-item-expander-background: transparent;\n --color-sidebar-item-expander-background--hover: var(\n --color-background-hover\n );\n\n --color-sidebar-search-text: var(--color-foreground-primary);\n --color-sidebar-search-background: var(--color-background-secondary);\n --color-sidebar-search-background--focus: var(--color-background-primary);\n --color-sidebar-search-border: var(--color-background-border);\n --color-sidebar-search-icon: var(--color-foreground-muted);\n\n // Table of Contents (right)\n --color-toc-background: var(--color-background-primary);\n --color-toc-title-text: var(--color-foreground-muted);\n --color-toc-item-text: var(--color-foreground-secondary);\n --color-toc-item-text--hover: var(--color-foreground-primary);\n --color-toc-item-text--active: var(--color-brand-primary);\n\n // Actual page contents\n --color-content-foreground: var(--color-foreground-primary);\n --color-content-background: transparent;\n\n // Links\n --color-link: var(--color-brand-content);\n --color-link-underline: var(--color-background-border);\n --color-link--hover: var(--color-brand-content);\n --color-link-underline--hover: var(--color-foreground-border);\n\n --color-link--visited: var(--color-brand-visited);\n --color-link-underline--visited: var(--color-background-border);\n --color-link--visited--hover: var(--color-brand-visited);\n --color-link-underline--visited--hover: var(--color-foreground-border);\n}\n\n@mixin colors-dark {\n --color-problematic: #ee5151;\n\n // Base Colors\n --color-foreground-primary: #cfd0d0; // for main text and headings\n --color-foreground-secondary: #9ca0a5; // for secondary text\n --color-foreground-muted: #81868d; // for muted text\n --color-foreground-border: #666666; // for content borders\n\n --color-background-primary: #131416; // for content\n --color-background-secondary: #1a1c1e; // for navigation + ToC\n --color-background-hover: #1e2124ff; // for navigation-item hover\n --color-background-hover--transparent: #1e212400;\n --color-background-border: #303335; // for UI borders\n --color-background-item: #444; // for \"background\" items (eg: copybutton)\n\n // Announcements\n --color-announcement-background: #000000dd;\n --color-announcement-text: #eeebee;\n\n // Brand colors\n --color-brand-primary: #3d94ff;\n --color-brand-content: #5ca5ff;\n --color-brand-visited: #b27aeb;\n\n // Highlighted text (search)\n --color-highlighted-background: #083563;\n\n // GUI Labels\n --color-guilabel-background: #08356380;\n --color-guilabel-border: #13395f80;\n\n // API documentation\n --color-api-keyword: var(--color-foreground-secondary);\n --color-highlight-on-target: #333300;\n\n --color-api-added: #3db854;\n --color-api-added-border: #267334;\n --color-api-changed: #09b0ce;\n --color-api-changed-border: #056d80;\n --color-api-deprecated: #b1a10b;\n --color-api-deprecated-border: #6e6407;\n --color-api-removed: #ff7575;\n --color-api-removed-border: #b03b3b;\n\n // Admonitions\n --color-admonition-background: #18181a;\n\n // Cards\n --color-card-border: var(--color-background-secondary);\n --color-card-background: #18181a;\n --color-card-marginals-background: var(--color-background-hover);\n}\n","// This file contains the styling for making the content throughout the page,\n// including fonts, paragraphs, headings and spacing among these elements.\n\nbody\n font-family: var(--font-stack)\npre,\ncode,\nkbd,\nsamp\n font-family: var(--font-stack--monospace)\n\n// Make fonts look slightly nicer.\nbody\n -webkit-font-smoothing: antialiased\n -moz-osx-font-smoothing: grayscale\n\n// Line height from Bootstrap 4.1\narticle\n line-height: 1.5\n\n//\n// Headings\n//\nh1,\nh2,\nh3,\nh4,\nh5,\nh6\n line-height: 1.25\n font-family: var(--font-stack--headings)\n font-weight: bold\n\n border-radius: 0.5rem\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n margin-left: -0.5rem\n margin-right: -0.5rem\n padding-left: 0.5rem\n padding-right: 0.5rem\n\n + p\n margin-top: 0\n\nh1\n font-size: 2.5em\n margin-top: 1.75rem\n margin-bottom: 1rem\nh2\n font-size: 2em\n margin-top: 1.75rem\nh3\n font-size: 1.5em\nh4\n font-size: 1.25em\nh5\n font-size: 1.125em\nh6\n font-size: 1em\n\nsmall\n opacity: 75%\n font-size: 80%\n\n// Paragraph\np\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n\n// Horizontal rules\nhr.docutils\n height: 1px\n padding: 0\n margin: 2rem 0\n background-color: var(--color-background-border)\n border: 0\n\n.centered\n text-align: center\n\n// Links\na\n text-decoration: underline\n\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n &:visited\n color: var(--color-link--visited)\n text-decoration-color: var(--color-link-underline--visited)\n &:hover\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &.muted-link\n color: inherit\n &:hover\n color: var(--color-link--hover)\n text-decoration-color: var(--color-link-underline--hover)\n &:visited\n color: var(--color-link--visited--hover)\n text-decoration-color: var(--color-link-underline--visited--hover)\n","// This file contains the styles for the overall layouting of the documentation\n// skeleton, including the responsive changes as well as sidebar toggles.\n//\n// This is implemented as a mobile-last design, which isn't ideal, but it is\n// reasonably good-enough and I got pretty tired by the time I'd finished this\n// to move the rules around to fix this. Shouldn't take more than 3-4 hours,\n// if you know what you're doing tho.\n\n// HACK: Not all browsers account for the scrollbar width in media queries.\n// This results in horizontal scrollbars in the breakpoint where we go\n// from displaying everything to hiding the ToC. We accomodate for this by\n// adding a bit of padding to the TOC drawer, disabling the horizontal\n// scrollbar and allowing the scrollbars to cover the padding.\n// https://www.456bereastreet.com/archive/201301/media_query_width_and_vertical_scrollbars/\n\n// HACK: Always having the scrollbar visible, prevents certain browsers from\n// causing the content to stutter horizontally between taller-than-viewport and\n// not-taller-than-viewport pages.\n\n$icon-size: 1.25rem\n\nhtml\n overflow-x: hidden\n overflow-y: scroll\n scroll-behavior: smooth\n\n.sidebar-scroll, .toc-scroll, article[role=main] *\n // Override Firefox scrollbar style\n scrollbar-width: thin\n scrollbar-color: var(--color-foreground-border) transparent\n\n // Override Chrome scrollbar styles\n &::-webkit-scrollbar\n width: 0.25rem\n height: 0.25rem\n &::-webkit-scrollbar-thumb\n background-color: var(--color-foreground-border)\n border-radius: 0.125rem\n\n//\n// Overalls\n//\nhtml,\nbody\n height: 100%\n color: var(--color-foreground-primary)\n background: var(--color-background-primary)\n\n.skip-to-content\n position: fixed\n padding: 1rem\n border-radius: 1rem\n left: 0.25rem\n top: 0.25rem\n z-index: 40\n background: var(--color-background-primary)\n color: var(--color-foreground-primary)\n\n transform: translateY(-200%)\n transition: transform 300ms ease-in-out\n\n &:focus-within\n transform: translateY(0%)\n\narticle\n color: var(--color-content-foreground)\n background: var(--color-content-background)\n overflow-wrap: break-word\n\n.page\n display: flex\n // fill the viewport for pages with little content.\n min-height: 100%\n\n.mobile-header\n width: 100%\n height: var(--header-height)\n background-color: var(--color-header-background)\n color: var(--color-header-text)\n border-bottom: 1px solid var(--color-header-border)\n\n // Looks like sub-script/super-script have this, and we need this to\n // be \"on top\" of those.\n z-index: 10\n\n // We don't show the header on large screens.\n display: none\n\n // Add shadow when scrolled\n &.scrolled\n border-bottom: none\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2)\n\n .header-center\n a\n color: var(--color-header-text)\n text-decoration: none\n\n.main\n display: flex\n flex: 1\n\n// Sidebar (left) also covers the entire left portion of screen.\n.sidebar-drawer\n box-sizing: border-box\n\n border-right: 1px solid var(--color-sidebar-background-border)\n background: var(--color-sidebar-background)\n\n display: flex\n justify-content: flex-end\n // These next two lines took me two days to figure out.\n width: calc((100% - #{$full-width}) / 2 + #{$sidebar-width})\n min-width: $sidebar-width\n\n// Scroll-along sidebars\n.sidebar-container,\n.toc-drawer\n box-sizing: border-box\n width: $sidebar-width\n\n.toc-drawer\n background: var(--color-toc-background)\n // See HACK described on top of this document\n padding-right: 1rem\n\n.sidebar-sticky,\n.toc-sticky\n position: sticky\n top: 0\n height: min(100%, 100vh)\n height: 100vh\n\n display: flex\n flex-direction: column\n\n.sidebar-scroll,\n.toc-scroll\n flex-grow: 1\n flex-shrink: 1\n\n overflow: auto\n scroll-behavior: smooth\n\n// Central items.\n.content\n padding: 0 $content-padding\n width: $content-width\n\n display: flex\n flex-direction: column\n justify-content: space-between\n\n.icon\n display: inline-block\n height: 1rem\n width: 1rem\n svg\n width: 100%\n height: 100%\n\n//\n// Accommodate announcement banner\n//\n.announcement\n background-color: var(--color-announcement-background)\n color: var(--color-announcement-text)\n\n height: var(--header-height)\n display: flex\n align-items: center\n overflow-x: auto\n & + .page\n min-height: calc(100% - var(--header-height))\n\n.announcement-content\n box-sizing: border-box\n padding: 0.5rem\n min-width: 100%\n white-space: nowrap\n text-align: center\n\n a\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-announcement-text)\n\n &:hover\n color: var(--color-announcement-text)\n text-decoration-color: var(--color-link--hover)\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for theme\n////////////////////////////////////////////////////////////////////////////////\n.no-js .theme-toggle-container // don't show theme toggle if there's no JS\n display: none\n\n.theme-toggle-container\n vertical-align: middle\n\n.theme-toggle\n cursor: pointer\n border: none\n padding: 0\n background: transparent\n\n.theme-toggle svg\n vertical-align: middle\n height: $icon-size\n width: $icon-size\n color: var(--color-foreground-primary)\n display: none\n\n.theme-toggle-header\n float: left\n padding: 1rem 0.5rem\n\n////////////////////////////////////////////////////////////////////////////////\n// Toggles for elements\n////////////////////////////////////////////////////////////////////////////////\n.toc-overlay-icon, .nav-overlay-icon\n display: none\n cursor: pointer\n\n .icon\n color: var(--color-foreground-secondary)\n height: $icon-size\n width: $icon-size\n\n.toc-header-icon, .nav-overlay-icon\n // for when we set display: flex\n justify-content: center\n align-items: center\n\n.toc-content-icon\n height: 1.5rem\n width: 1.5rem\n\n.content-icon-container\n float: right\n display: flex\n margin-top: 1.5rem\n margin-left: 1rem\n margin-bottom: 1rem\n gap: 0.5rem\n\n .edit-this-page, .view-this-page\n svg\n color: inherit\n height: $icon-size\n width: $icon-size\n\n.sidebar-toggle\n position: absolute\n display: none\n// \n.sidebar-toggle[name=\"__toc\"]\n left: 20px\n.sidebar-toggle:checked\n left: 40px\n// \n\n.overlay\n position: fixed\n top: 0\n width: 0\n height: 0\n\n transition: width 0ms, height 0ms, opacity 250ms ease-out\n\n opacity: 0\n background-color: rgba(0, 0, 0, 0.54)\n.sidebar-overlay\n z-index: 20\n.toc-overlay\n z-index: 40\n\n// Keep things on top and smooth.\n.sidebar-drawer\n z-index: 30\n transition: left 250ms ease-in-out\n.toc-drawer\n z-index: 50\n transition: right 250ms ease-in-out\n\n// Show the Sidebar\n#__navigation:checked\n & ~ .sidebar-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .sidebar-drawer\n top: 0\n left: 0\n // Show the toc sidebar\n#__toc:checked\n & ~ .toc-overlay\n width: 100%\n height: 100%\n opacity: 1\n & ~ .page\n .toc-drawer\n top: 0\n right: 0\n\n////////////////////////////////////////////////////////////////////////////////\n// Back to top\n////////////////////////////////////////////////////////////////////////////////\n.back-to-top\n text-decoration: none\n\n display: none\n position: fixed\n left: 0\n top: 1rem\n padding: 0.5rem\n padding-right: 0.75rem\n border-radius: 1rem\n font-size: 0.8125rem\n\n background: var(--color-background-primary)\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), #6b728080 0px 0px 1px 0px\n\n z-index: 10\n\n margin-left: 50%\n transform: translateX(-50%)\n svg\n height: 1rem\n width: 1rem\n fill: currentColor\n display: inline-block\n\n span\n margin-left: 0.25rem\n\n .show-back-to-top &\n display: flex\n align-items: center\n\n////////////////////////////////////////////////////////////////////////////////\n// Responsive layouting\n////////////////////////////////////////////////////////////////////////////////\n// Make things a bit bigger on bigger screens.\n@media (min-width: $full-width + $sidebar-width)\n html\n font-size: 110%\n\n@media (max-width: $full-width)\n // Collapse \"toc\" into the icon.\n .toc-content-icon\n display: flex\n .toc-drawer\n position: fixed\n height: 100vh\n top: 0\n right: -$sidebar-width\n border-left: 1px solid var(--color-background-muted)\n .toc-tree\n border-left: none\n font-size: var(--toc-font-size--mobile)\n\n // Accomodate for a changed content width.\n .sidebar-drawer\n width: calc((100% - #{$full-width - $sidebar-width}) / 2 + #{$sidebar-width})\n\n@media (max-width: $full-width - $sidebar-width)\n // Collapse \"navigation\".\n .nav-overlay-icon\n display: flex\n .sidebar-drawer\n position: fixed\n height: 100vh\n width: $sidebar-width\n\n top: 0\n left: -$sidebar-width\n\n // Swap which icon is visible.\n .toc-header-icon\n display: flex\n .toc-content-icon, .theme-toggle-content\n display: none\n .theme-toggle-header\n display: block\n\n // Show the header.\n .mobile-header\n position: sticky\n top: 0\n display: flex\n justify-content: space-between\n align-items: center\n\n .header-left,\n .header-right\n display: flex\n height: var(--header-height)\n padding: 0 var(--header-padding)\n label\n height: 100%\n width: 100%\n user-select: none\n\n .nav-overlay-icon .icon,\n .theme-toggle svg\n height: $icon-size\n width: $icon-size\n\n // Add a scroll margin for the content\n :target\n scroll-margin-top: calc(var(--header-height) + 2.5rem)\n\n // Show back-to-top below the header\n .back-to-top\n top: calc(var(--header-height) + 0.5rem)\n\n // Center the page, and accommodate for the header.\n .page\n flex-direction: column\n justify-content: center\n .content\n margin-left: auto\n margin-right: auto\n\n@media (max-width: $content-width + 2* $content-padding)\n // Content should respect window limits.\n .content\n width: 100%\n overflow-x: auto\n\n@media (max-width: $content-width)\n .content\n padding: 0 $content-padding--small\n // Don't float sidebars to the right.\n article aside.sidebar\n float: none\n width: 100%\n margin: 1rem 0\n","// Overall Layout Variables\n//\n// Because CSS variables can't be used in media queries. The fact that this\n// makes the layout non-user-configurable is a good thing.\n$content-padding: 3em;\n$content-padding--small: 1em;\n$content-width: 46em;\n$sidebar-width: 15em;\n$full-width: $content-width + 2 * ($content-padding + $sidebar-width);\n","//\n// The design here is strongly inspired by mkdocs-material.\n.admonition, .topic\n margin: 1rem auto\n padding: 0 0.5rem 0.5rem 0.5rem\n\n background: var(--color-admonition-background)\n\n border-radius: 0.2rem\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n font-size: var(--admonition-font-size)\n\n overflow: hidden\n page-break-inside: avoid\n\n // First element should have no margin, since the title has it.\n > :nth-child(2)\n margin-top: 0\n\n // Last item should have no margin, since we'll control that w/ padding\n > :last-child\n margin-bottom: 0\n\n.admonition p.admonition-title,\np.topic-title\n position: relative\n margin: 0 -0.5rem 0.5rem\n padding-left: 2rem\n padding-right: .5rem\n padding-top: .4rem\n padding-bottom: .4rem\n\n font-weight: 500\n font-size: var(--admonition-title-font-size)\n line-height: 1.3\n\n // Our fancy icon\n &::before\n content: \"\"\n position: absolute\n left: 0.5rem\n width: 1rem\n height: 1rem\n\n// Default styles\np.admonition-title\n background-color: var(--color-admonition-title-background)\n &::before\n background-color: var(--color-admonition-title)\n mask-image: var(--icon-admonition-default)\n mask-repeat: no-repeat\n\np.topic-title\n background-color: var(--color-topic-title-background)\n &::before\n background-color: var(--color-topic-title)\n mask-image: var(--icon-topic-default)\n mask-repeat: no-repeat\n\n//\n// Variants\n//\n.admonition\n border-left: 0.2rem solid var(--color-admonition-title)\n\n @each $type, $value in $admonitions\n &.#{$type}\n border-left-color: var(--color-admonition-title--#{$type})\n > .admonition-title\n background-color: var(--color-admonition-title-background--#{$type})\n &::before\n background-color: var(--color-admonition-title--#{$type})\n mask-image: var(--icon-#{nth($value, 2)})\n\n.admonition-todo > .admonition-title\n text-transform: uppercase\n","// This file stylizes the API documentation (stuff generated by autodoc). It's\n// deeply nested due to how autodoc structures the HTML without enough classes\n// to select the relevant items.\n\n// API docs!\ndl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)\n // Tweak the spacing of all the things!\n dd\n margin-left: 2rem\n > :first-child\n margin-top: 0.125rem\n > :last-child\n margin-bottom: 0.75rem\n\n // This is used for the arguments\n .field-list\n margin-bottom: 0.75rem\n\n // \"Headings\" (like \"Parameters\" and \"Return\")\n > dt\n text-transform: uppercase\n font-size: var(--font-size--small)\n\n dd:empty\n margin-bottom: 0.5rem\n dd > ul\n margin-left: -1.2rem\n > li\n > p:nth-child(2)\n margin-top: 0\n // When the last-empty-paragraph follows a paragraph, it doesn't need\n // to augument the existing spacing.\n > p + p:last-child:empty\n margin-top: 0\n margin-bottom: 0\n\n // Colorize the elements\n > dt\n color: var(--color-api-overall)\n\n.sig:not(.sig-inline)\n font-weight: bold\n\n font-size: var(--api-font-size)\n font-family: var(--font-stack--monospace)\n\n margin-left: -0.25rem\n margin-right: -0.25rem\n padding-top: 0.25rem\n padding-bottom: 0.25rem\n padding-right: 0.5rem\n\n // These are intentionally em, to properly match the font size.\n padding-left: 3em\n text-indent: -2.5em\n\n border-radius: 0.25rem\n\n background: var(--color-api-background)\n transition: background 100ms ease-out\n\n &:hover\n background: var(--color-api-background-hover)\n\n // adjust the size of the [source] link on the right.\n a.reference\n .viewcode-link\n font-weight: normal\n width: 4.25rem\n\nem.property\n font-style: normal\n &:first-child\n color: var(--color-api-keyword)\n.sig-name\n color: var(--color-api-name)\n.sig-prename\n font-weight: normal\n color: var(--color-api-pre-name)\n.sig-paren\n color: var(--color-api-paren)\n.sig-param\n font-style: normal\n\ndiv.versionadded,\ndiv.versionchanged,\ndiv.deprecated,\ndiv.versionremoved\n border-left: 0.1875rem solid\n border-radius: 0.125rem\n\n padding-left: 0.75rem\n\n p\n margin-top: 0.125rem\n margin-bottom: 0.125rem\n\ndiv.versionadded\n border-color: var(--color-api-added-border)\n .versionmodified\n color: var(--color-api-added)\n\ndiv.versionchanged\n border-color: var(--color-api-changed-border)\n .versionmodified\n color: var(--color-api-changed)\n\ndiv.deprecated\n border-color: var(--color-api-deprecated-border)\n .versionmodified\n color: var(--color-api-deprecated)\n\ndiv.versionremoved\n border-color: var(--color-api-removed-border)\n .versionmodified\n color: var(--color-api-removed)\n\n// Align the [docs] and [source] to the right.\n.viewcode-link, .viewcode-back\n float: right\n text-align: right\n",".line-block\n margin-top: 0.5rem\n margin-bottom: 0.75rem\n .line-block\n margin-top: 0rem\n margin-bottom: 0rem\n padding-left: 1rem\n","// Captions\narticle p.caption,\ntable > caption,\n.code-block-caption\n font-size: var(--font-size--small)\n text-align: center\n\n// Caption above a TOCTree\n.toctree-wrapper.compound\n .caption, :not(.caption) > .caption-text\n font-size: var(--font-size--small)\n text-transform: uppercase\n\n text-align: initial\n margin-bottom: 0\n\n > ul\n margin-top: 0\n margin-bottom: 0\n","// Inline code\ncode.literal, .sig-inline\n background: var(--color-inline-code-background)\n border-radius: 0.2em\n // Make the font smaller, and use padding to recover.\n font-size: var(--font-size--small--2)\n padding: 0.1em 0.2em\n\n pre.literal-block &\n font-size: inherit\n padding: 0\n\n p &\n border: 1px solid var(--color-background-border)\n\n.sig-inline\n font-family: var(--font-stack--monospace)\n\n// Code and Literal Blocks\n$code-spacing-vertical: 0.625rem\n$code-spacing-horizontal: 0.875rem\n\n// Wraps every literal block + line numbers.\ndiv[class*=\" highlight-\"],\ndiv[class^=\"highlight-\"]\n margin: 1em 0\n display: flex\n\n .table-wrapper\n margin: 0\n padding: 0\n\npre\n margin: 0\n padding: 0\n overflow: auto\n\n // Needed to have more specificity than pygments' \"pre\" selector. :(\n article[role=\"main\"] .highlight &\n line-height: 1.5\n\n &.literal-block,\n .highlight &\n font-size: var(--code-font-size)\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n // Make it look like all the other blocks.\n &.literal-block\n margin-top: 1rem\n margin-bottom: 1rem\n\n border-radius: 0.2rem\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n\n// All code is always contained in this.\n.highlight\n width: 100%\n border-radius: 0.2rem\n\n // Make line numbers and prompts un-selectable.\n .gp, span.linenos\n user-select: none\n pointer-events: none\n\n // Expand the line-highlighting.\n .hll\n display: block\n margin-left: -$code-spacing-horizontal\n margin-right: -$code-spacing-horizontal\n padding-left: $code-spacing-horizontal\n padding-right: $code-spacing-horizontal\n\n/* Make code block captions be nicely integrated */\n.code-block-caption\n display: flex\n padding: $code-spacing-vertical $code-spacing-horizontal\n\n border-radius: 0.25rem\n border-bottom-left-radius: 0\n border-bottom-right-radius: 0\n font-weight: 300\n border-bottom: 1px solid\n\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n border-color: var(--color-background-border)\n\n + div[class]\n margin-top: 0\n pre\n border-top-left-radius: 0\n border-top-right-radius: 0\n\n// When `html_codeblock_linenos_style` is table.\n.highlighttable\n width: 100%\n display: block\n tbody\n display: block\n\n tr\n display: flex\n\n // Line numbers\n td.linenos\n background-color: var(--color-code-background)\n color: var(--color-code-foreground)\n padding: $code-spacing-vertical $code-spacing-horizontal\n padding-right: 0\n border-top-left-radius: 0.2rem\n border-bottom-left-radius: 0.2rem\n\n .linenodiv\n padding-right: $code-spacing-horizontal\n font-size: var(--code-font-size)\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n\n // Actual code\n td.code\n padding: 0\n display: block\n flex: 1\n overflow: hidden\n\n .highlight\n border-top-left-radius: 0\n border-bottom-left-radius: 0\n\n// When `html_codeblock_linenos_style` is inline.\n.highlight\n span.linenos\n display: inline-block\n padding-left: 0\n padding-right: $code-spacing-horizontal\n margin-right: $code-spacing-horizontal\n box-shadow: -0.0625rem 0 var(--color-foreground-border) inset\n","// Inline Footnote Reference\n.footnote-reference\n font-size: var(--font-size--small--4)\n vertical-align: super\n\n// Definition list, listing the content of each note.\n// docutils <= 0.17\ndl.footnote.brackets\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\n display: grid\n grid-template-columns: max-content auto\n dt\n margin: 0\n > .fn-backref\n margin-left: 0.25rem\n\n &:after\n content: \":\"\n\n .brackets\n &:before\n content: \"[\"\n &:after\n content: \"]\"\n\n dd\n margin: 0\n padding: 0 1rem\n\n// docutils >= 0.18\naside.footnote\n font-size: var(--font-size--small)\n color: var(--color-foreground-secondary)\n\naside.footnote > span,\ndiv.citation > span\n float: left\n font-weight: 500\n padding-right: 0.25rem\n\naside.footnote > *:not(span),\ndiv.citation > p\n margin-left: 2rem\n","//\n// Figures\n//\nimg\n box-sizing: border-box\n max-width: 100%\n height: auto\n\narticle\n figure, .figure\n border-radius: 0.2rem\n\n margin: 0\n :last-child\n margin-bottom: 0\n\n .align-left\n float: left\n clear: left\n margin: 0 1rem 1rem\n\n .align-right\n float: right\n clear: right\n margin: 0 1rem 1rem\n\n .align-default,\n .align-center\n display: block\n text-align: center\n margin-left: auto\n margin-right: auto\n\n // WELL, table needs to be stylised like a table.\n table.align-default\n display: table\n text-align: initial\n",".genindex-jumpbox, .domainindex-jumpbox\n border-top: 1px solid var(--color-background-border)\n border-bottom: 1px solid var(--color-background-border)\n padding: 0.25rem\n\n.genindex-section, .domainindex-section\n h2\n margin-top: 0.75rem\n margin-bottom: 0.5rem\n ul\n margin-top: 0\n margin-bottom: 0\n","ul,\nol\n padding-left: 1.2rem\n\n // Space lists out like paragraphs\n margin-top: 1rem\n margin-bottom: 1rem\n // reduce margins within li.\n li\n > p:first-child\n margin-top: 0.25rem\n margin-bottom: 0.25rem\n\n > p:last-child\n margin-top: 0.25rem\n\n > ul,\n > ol\n margin-top: 0.5rem\n margin-bottom: 0.5rem\n\nol\n &.arabic\n list-style: decimal\n &.loweralpha\n list-style: lower-alpha\n &.upperalpha\n list-style: upper-alpha\n &.lowerroman\n list-style: lower-roman\n &.upperroman\n list-style: upper-roman\n\n// Don't space lists out when they're \"simple\" or in a `.. toctree::`\n.simple,\n.toctree-wrapper\n li\n > ul,\n > ol\n margin-top: 0\n margin-bottom: 0\n\n// Definition Lists\n.field-list,\n.option-list,\ndl:not([class]),\ndl.simple,\ndl.footnote,\ndl.glossary\n dt\n font-weight: 500\n margin-top: 0.25rem\n + dt\n margin-top: 0\n\n .classifier::before\n content: \":\"\n margin-left: 0.2rem\n margin-right: 0.2rem\n\n dd\n > p:first-child,\n ul\n margin-top: 0.125rem\n\n ul\n margin-bottom: 0.125rem\n",".math-wrapper\n width: 100%\n overflow-x: auto\n\ndiv.math\n position: relative\n text-align: center\n\n .headerlink,\n &:focus .headerlink\n display: none\n\n &:hover .headerlink\n display: inline-block\n\n span.eqno\n position: absolute\n right: 0.5rem\n top: 50%\n transform: translate(0, -50%)\n z-index: 1\n","// Abbreviations\nabbr[title]\n cursor: help\n\n// \"Problematic\" content, as identified by Sphinx\n.problematic\n color: var(--color-problematic)\n\n// Keyboard / Mouse \"instructions\"\nkbd:not(.compound)\n margin: 0 0.2rem\n padding: 0 0.2rem\n border-radius: 0.2rem\n border: 1px solid var(--color-foreground-border)\n color: var(--color-foreground-primary)\n vertical-align: text-bottom\n\n font-size: var(--font-size--small--3)\n display: inline-block\n\n box-shadow: 0 0.0625rem 0 rgba(0, 0, 0, 0.2), inset 0 0 0 0.125rem var(--color-background-primary)\n\n background-color: var(--color-background-secondary)\n\n// Blockquote\nblockquote\n border-left: 4px solid var(--color-background-border)\n background: var(--color-background-secondary)\n\n margin-left: 0\n margin-right: 0\n padding: 0.5rem 1rem\n\n .attribution\n font-weight: 600\n text-align: right\n\n &.pull-quote,\n &.highlights\n font-size: 1.25em\n\n &.epigraph,\n &.pull-quote\n border-left-width: 0\n border-radius: 0.5rem\n\n &.highlights\n border-left-width: 0\n background: transparent\n\n// Center align embedded-in-text images\np .reference img\n vertical-align: middle\n","p.rubric\n line-height: 1.25\n font-weight: bold\n font-size: 1.125em\n\n // For Numpy-style documentation that's got rubrics within it.\n // https://github.com/pradyunsg/furo/discussions/505\n dd &\n line-height: inherit\n font-weight: inherit\n\n font-size: var(--font-size--small)\n text-transform: uppercase\n","article .sidebar\n float: right\n clear: right\n width: 30%\n\n margin-left: 1rem\n margin-right: 0\n\n border-radius: 0.2rem\n background-color: var(--color-background-secondary)\n border: var(--color-background-border) 1px solid\n\n > *\n padding-left: 1rem\n padding-right: 1rem\n\n > ul, > ol // lists need additional padding, because bullets.\n padding-left: 2.2rem\n\n .sidebar-title\n margin: 0\n padding: 0.5rem 1rem\n border-bottom: var(--color-background-border) 1px solid\n\n font-weight: 500\n\n// TODO: subtitle\n// TODO: dedicated variables?\n",".table-wrapper\n width: 100%\n overflow-x: auto\n margin-top: 1rem\n margin-bottom: 0.5rem\n padding: 0.2rem 0.2rem 0.75rem\n\ntable.docutils\n border-radius: 0.2rem\n border-spacing: 0\n border-collapse: collapse\n\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.0625rem rgba(0, 0, 0, 0.1)\n\n th\n background: var(--color-table-header-background)\n\n td,\n th\n // Space things out properly\n padding: 0 0.25rem\n\n // Get the borders looking just-right.\n border-left: 1px solid var(--color-table-border)\n border-right: 1px solid var(--color-table-border)\n border-bottom: 1px solid var(--color-table-border)\n\n p\n margin: 0.25rem\n\n &:first-child\n border-left: none\n &:last-child\n border-right: none\n\n // MyST-parser tables set these classes for control of column alignment\n &.text-left\n text-align: left\n &.text-right\n text-align: right\n &.text-center\n text-align: center\n",":target\n scroll-margin-top: 2.5rem\n\n@media (max-width: $full-width - $sidebar-width)\n :target\n scroll-margin-top: calc(2.5rem + var(--header-height))\n\n // When a heading is selected\n section > span:target\n scroll-margin-top: calc(2.8rem + var(--header-height))\n\n// Permalinks\n.headerlink\n font-weight: 100\n user-select: none\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\ndl dt,\np.caption,\nfigcaption p,\ntable > caption,\n.code-block-caption\n > .headerlink\n margin-left: 0.5rem\n visibility: hidden\n &:hover > .headerlink\n visibility: visible\n\n // Don't change to link-like, if someone adds the contents directive.\n > .toc-backref\n color: inherit\n text-decoration-line: none\n\n// Figure and table captions are special.\nfigure:hover > figcaption > p > .headerlink,\ntable:hover > caption > .headerlink\n visibility: visible\n\n:target >, // Regular section[id] style anchors\nspan:target ~ // Non-regular span[id] style \"extra\" anchors\n h1,\n h2,\n h3,\n h4,\n h5,\n h6\n &:nth-of-type(1)\n background-color: var(--color-highlight-on-target)\n // .headerlink\n // visibility: visible\n code.literal\n background-color: transparent\n\ntable:target > caption,\nfigure:target\n background-color: var(--color-highlight-on-target)\n\n// Inline page contents\n.this-will-duplicate-information-and-it-is-still-useful-here li :target\n background-color: var(--color-highlight-on-target)\n\n// Code block permalinks\n.literal-block-wrapper:target .code-block-caption\n background-color: var(--color-highlight-on-target)\n\n// When a definition list item is selected\n//\n// There isn't really an alternative to !important here, due to the\n// high-specificity of API documentation's selector.\ndt:target\n background-color: var(--color-highlight-on-target) !important\n\n// When a footnote reference is selected\n.footnote > dt:target + dd,\n.footnote-reference:target\n background-color: var(--color-highlight-on-target)\n",".guilabel\n background-color: var(--color-guilabel-background)\n border: 1px solid var(--color-guilabel-border)\n color: var(--color-guilabel-text)\n\n padding: 0 0.3em\n border-radius: 0.5em\n font-size: 0.9em\n","// This file contains the styles used for stylizing the footer that's shown\n// below the content.\n\nfooter\n font-size: var(--font-size--small)\n display: flex\n flex-direction: column\n\n margin-top: 2rem\n\n// Bottom of page information\n.bottom-of-page\n display: flex\n align-items: center\n justify-content: space-between\n\n margin-top: 1rem\n padding-top: 1rem\n padding-bottom: 1rem\n\n color: var(--color-foreground-secondary)\n border-top: 1px solid var(--color-background-border)\n\n line-height: 1.5\n\n @media (max-width: $content-width)\n text-align: center\n flex-direction: column-reverse\n gap: 0.25rem\n\n .left-details\n font-size: var(--font-size--small)\n\n .right-details\n display: flex\n flex-direction: column\n gap: 0.25rem\n text-align: right\n\n .icons\n display: flex\n justify-content: flex-end\n gap: 0.25rem\n font-size: 1rem\n\n a\n text-decoration: none\n\n svg,\n img\n font-size: 1.125rem\n height: 1em\n width: 1em\n\n// Next/Prev page information\n.related-pages\n a\n display: flex\n align-items: center\n\n text-decoration: none\n &:hover .page-info .title\n text-decoration: underline\n color: var(--color-link)\n text-decoration-color: var(--color-link-underline)\n\n svg.furo-related-icon,\n svg.furo-related-icon > use\n flex-shrink: 0\n\n color: var(--color-foreground-border)\n\n width: 0.75rem\n height: 0.75rem\n margin: 0 0.5rem\n\n &.next-page\n max-width: 50%\n\n float: right\n clear: right\n text-align: right\n\n &.prev-page\n max-width: 50%\n\n float: left\n clear: left\n\n svg\n transform: rotate(180deg)\n\n.page-info\n display: flex\n flex-direction: column\n overflow-wrap: anywhere\n\n .next-page &\n align-items: flex-end\n\n .context\n display: flex\n align-items: center\n\n padding-bottom: 0.1rem\n\n color: var(--color-foreground-muted)\n font-size: var(--font-size--small)\n text-decoration: none\n","// This file contains the styles for the contents of the left sidebar, which\n// contains the navigation tree, logo, search etc.\n\n////////////////////////////////////////////////////////////////////////////////\n// Brand on top of the scrollable tree.\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-brand\n display: flex\n flex-direction: column\n flex-shrink: 0\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n text-decoration: none\n\n.sidebar-brand-text\n color: var(--color-sidebar-brand-text)\n overflow-wrap: break-word\n margin: var(--sidebar-item-spacing-vertical) 0\n font-size: 1.5rem\n\n.sidebar-logo-container\n margin: var(--sidebar-item-spacing-vertical) 0\n\n.sidebar-logo\n margin: 0 auto\n display: block\n max-width: 100%\n\n////////////////////////////////////////////////////////////////////////////////\n// Search\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-search-container\n display: flex\n align-items: center\n margin-top: var(--sidebar-search-space-above)\n\n position: relative\n\n background: var(--color-sidebar-search-background)\n &:hover,\n &:focus-within\n background: var(--color-sidebar-search-background--focus)\n\n &::before\n content: \"\"\n position: absolute\n left: var(--sidebar-item-spacing-horizontal)\n width: var(--sidebar-search-icon-size)\n height: var(--sidebar-search-icon-size)\n\n background-color: var(--color-sidebar-search-icon)\n mask-image: var(--icon-search)\n\n.sidebar-search\n box-sizing: border-box\n\n border: none\n border-top: 1px solid var(--color-sidebar-search-border)\n border-bottom: 1px solid var(--color-sidebar-search-border)\n\n padding-top: var(--sidebar-search-input-spacing-vertical)\n padding-bottom: var(--sidebar-search-input-spacing-vertical)\n padding-right: var(--sidebar-search-input-spacing-horizontal)\n padding-left: calc(var(--sidebar-item-spacing-horizontal) + var(--sidebar-search-input-spacing-horizontal) + var(--sidebar-search-icon-size))\n\n width: 100%\n\n color: var(--color-sidebar-search-foreground)\n background: transparent\n z-index: 10\n\n &:focus\n outline: none\n\n &::placeholder\n font-size: var(--sidebar-search-input-font-size)\n\n//\n// Hide Search Matches link\n//\n#searchbox .highlight-link\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal) 0\n margin: 0\n text-align: center\n\n a\n color: var(--color-sidebar-search-icon)\n font-size: var(--font-size--small--2)\n\n////////////////////////////////////////////////////////////////////////////////\n// Structure/Skeleton of the navigation tree (left)\n////////////////////////////////////////////////////////////////////////////////\n.sidebar-tree\n font-size: var(--sidebar-item-font-size)\n margin-top: var(--sidebar-tree-space-above)\n margin-bottom: var(--sidebar-item-spacing-vertical)\n\n ul\n padding: 0\n margin-top: 0\n margin-bottom: 0\n\n display: flex\n flex-direction: column\n\n list-style: none\n\n li\n position: relative\n margin: 0\n\n > ul\n margin-left: var(--sidebar-item-spacing-horizontal)\n\n .icon\n color: var(--color-sidebar-link-text)\n\n .reference\n box-sizing: border-box\n color: var(--color-sidebar-link-text)\n\n // Fill the parent.\n display: inline-block\n line-height: var(--sidebar-item-line-height)\n text-decoration: none\n\n // Don't allow long words to cause wrapping.\n overflow-wrap: anywhere\n\n height: 100%\n width: 100%\n\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n &:hover\n color: var(--color-sidebar-link-text)\n background: var(--color-sidebar-item-background--hover)\n\n // Add a nice little \"external-link\" arrow here.\n &.external::after\n content: url('data:image/svg+xml,')\n margin: 0 0.25rem\n vertical-align: middle\n color: var(--color-sidebar-link-text)\n\n // Make the current page reference bold.\n .current-page > .reference\n font-weight: bold\n\n label\n position: absolute\n top: 0\n right: 0\n height: var(--sidebar-item-height)\n width: var(--sidebar-expander-width)\n\n cursor: pointer\n user-select: none\n\n display: flex\n justify-content: center\n align-items: center\n\n .caption, :not(.caption) > .caption-text\n font-size: var(--sidebar-caption-font-size)\n color: var(--color-sidebar-caption-text)\n\n font-weight: bold\n text-transform: uppercase\n\n margin: var(--sidebar-caption-space-above) 0 0 0\n padding: var(--sidebar-item-spacing-vertical) var(--sidebar-item-spacing-horizontal)\n\n // If it has children, add a bit more padding to wrap the content to avoid\n // overlapping with the