├── .gitmodules
├── .readthedocs.yaml
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── docs
├── api.md
├── assets
│ ├── SALTED_icon_vanilla_long.png
│ └── SALTED_icon_vanilla_square.png
├── examples
│ ├── au_cp2k.md
│ ├── water_aims.md
│ └── water_pyscf.md
├── index.md
├── input.md
├── installation.md
├── javascripts
│ └── mathjax.js
├── requirements.txt
├── stylesheets
│ └── extra.css
├── theory.md
├── tutorial
│ ├── dataset.md
│ ├── predict.md
│ └── training.md
└── workflow.md
├── example
├── Au100-Na_CP2K
│ ├── Au-RI_AUTO_OPT-ccGRB
│ ├── Au-RI_AUTO_OPT-ccGRB-small
│ ├── README.rst
│ ├── coords-qmmm.xyz
│ ├── cp2k-inputs
│ │ ├── get_RI-AUTO_basis.inp
│ │ └── qmmm_RI-print.inp
│ └── inp.yaml
├── water_monomer_AIMS
│ ├── README.rst
│ ├── control.in
│ ├── control_read.in
│ ├── control_read_setup.in
│ ├── inp.yaml
│ ├── run-aims-predict-reorder.sbatch
│ ├── run-aims-predict.sbatch
│ ├── run-aims.sbatch
│ ├── run-ml.sbatch
│ ├── water_dimers_10.xyz
│ └── water_monomers_100.xyz
├── water_monomer_AIMS_response
│ ├── README
│ ├── control.in
│ ├── control_read.in
│ ├── covariance_test.py
│ ├── inp.yaml
│ ├── move_data.py
│ ├── move_rho1_data.py
│ ├── run-aims.sbatch
│ ├── run_test_serial.sh
│ └── water_monomers_1k.xyz
└── water_monomer_PySCF
│ ├── README.rst
│ ├── covariance_test.py
│ ├── inp.yaml
│ ├── interface.py
│ ├── run_test_parallel.sh
│ ├── run_test_serial.sh
│ ├── water_dimers_10.xyz
│ ├── water_monomers_1k.xyz
│ └── water_total.xyz
├── mkdocs.yaml
├── salted
├── __init__.py
├── aims
│ ├── _deprecated_
│ │ └── get_basis_info_deprecated.py
│ ├── collect_energies.py
│ ├── get_basis_info.py
│ ├── get_df_err.py
│ ├── get_ml_err.py
│ ├── make_geoms.py
│ ├── move_data.py
│ ├── move_data_in.py
│ └── move_data_in_reorder.py
├── basis.py
├── basis_client.py
├── cp2k
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-39.pyc
│ │ └── cp2k2salted.cpython-39.pyc
│ ├── _deprecated_
│ │ ├── alphas-cp2k.py
│ │ ├── contracted
│ │ │ ├── coefs-contra-cp2k.py
│ │ │ ├── contract_coefs-cp2k.py
│ │ │ ├── contract_projs-cp2k.py
│ │ │ ├── contraction-cp2k.py
│ │ │ ├── contraction-multi-cp2k.py
│ │ │ ├── df2cube-cp2k-contra.py
│ │ │ ├── dp2cube-cp2k-contra.py
│ │ │ ├── feature_vector-contracted.py
│ │ │ ├── get_contra-averages.py
│ │ │ ├── init_data-cp2k-contra.py
│ │ │ ├── matrices-contracted.py
│ │ │ ├── minimize_loss-parallel-contracted.py
│ │ │ ├── minimize_loss-serial-contracted.py
│ │ │ ├── overlap-contracted-cp2k.py
│ │ │ ├── prediction-contracted-cp2k.py
│ │ │ ├── rebuild_contra-projs.py
│ │ │ └── validation-contracted-cp2k.py
│ │ ├── overlap-cp2k.py
│ │ ├── projs-cp2k-perat-unrestricted.py
│ │ └── projs-cp2k-perat.py
│ ├── cp2k2salted.py
│ ├── df2cube.py
│ ├── get_basis_info.py
│ ├── polarizability.py
│ ├── uncontract_ri_basis.py
│ ├── utils.py
│ └── xyz2sys.py
├── efield.py
├── get_averages.py
├── get_basis_info.py
├── hessian_matrix.py
├── init_pred.py
├── initialize.py
├── minimize_loss.py
├── ortho
│ ├── ortho_error.py
│ ├── ortho_projections.py
│ └── ortho_regression.py
├── prediction.py
├── pyscf
│ ├── __init__.py
│ ├── _deprecated_
│ │ ├── dm2df-pyscf_deprecated.py
│ │ └── run-pyscf_deprecated.py
│ ├── dm2df.py
│ ├── electro_energy.py
│ ├── electro_error.py
│ ├── get_basis_info.py
│ └── run_pyscf.py
├── rkhs_projector.py
├── rkhs_vector.py
├── salted_prediction.py
├── scalar_vector.py
├── solve_regression.py
├── sparse-gpr_energies.py
├── sparse_descriptor.py
├── sparse_selection.py
├── sparsify_features.py
├── sph_utils.py
├── sys_utils.py
├── validation.py
└── wigner.py
├── setup.py
└── src
├── antiequicomb.f90
├── antiequicombnonorm.f90
├── antiequicombsparse.f90
├── equicomb.f90
├── equicombfield.f90
├── equicombfps.f90
├── equicombnonorm.f90
├── equicombsparse.f90
├── kernelequicomb.f90
├── kernelnorm.f90
├── ovlp2c.f90
├── ovlp2cXYperiodic.f90
├── ovlp2cnonperiodic.f90
├── ovlp3c.f90
├── ovlp3cXYperiodic.f90
└── ovlp3cnonperiodic.f90
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/.gitmodules
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # .readthedocs.yaml
2 | # Read the Docs configuration file
3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4 |
5 | # Required
6 | version: 2
7 |
8 | # Set the version of Python and other tools you might need
9 | build:
10 | os: ubuntu-22.04
11 | tools:
12 | python: "3.10"
13 |
14 | mkdocs:
15 | configuration: mkdocs.yaml
16 |
17 | # Optionally declare the Python requirements required to build your docs
18 | python:
19 | install:
20 | - requirements: docs/requirements.txt
21 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include salted/lib/equicomb.so
2 | include salted/lib/equicombnonorm.so
3 | include salted/lib/equicombsparse.so
4 | include salted/lib/equicombfps.so
5 | include salted/lib/equicombnonorm.so
6 | include salted/lib/equicombsparse.so
7 | include salted/lib/antiequicomb.so
8 | include salted/lib/antiequicombnonorm.so
9 | include salted/lib/antiequicombsparse.so
10 | include salted/lib/kernelequicomb.so
11 | include salted/lib/kernelnorm.so
12 | include salted/lib/equicombfield.so
13 | include salted/lib/ovlp2cnonperiodic.so
14 | include salted/lib/ovlp2c.so
15 | include salted/lib/ovlp2cXYperiodic.so
16 | include salted/lib/ovlp3cnonperiodic.so
17 | include salted/lib/ovlp3c.so
18 | include salted/lib/ovlp3cXYperiodic.so
19 |
--------------------------------------------------------------------------------
/docs/api.md:
--------------------------------------------------------------------------------
1 | # API
2 |
3 | ---
4 |
5 | ## Density fitting basis IO
6 |
7 | ::: salted.basis_client.BasisClient
8 | options:
9 | show_root_heading: true
10 |
11 |
12 |
13 | ---
14 |
15 | ## Utility functions
16 |
17 | ::: salted.sys_utils.sort_grid_data
18 | options:
19 | show_root_heading: true
20 |
21 |
22 |
23 | ---
24 |
25 | ## Input file IO
26 |
27 | ::: salted.sys_utils.ParseConfig
28 |
29 |
30 |
31 |
32 | ---
33 |
34 |
--------------------------------------------------------------------------------
/docs/assets/SALTED_icon_vanilla_long.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/docs/assets/SALTED_icon_vanilla_long.png
--------------------------------------------------------------------------------
/docs/assets/SALTED_icon_vanilla_square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/docs/assets/SALTED_icon_vanilla_square.png
--------------------------------------------------------------------------------
/docs/examples/au_cp2k.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/docs/examples/au_cp2k.md
--------------------------------------------------------------------------------
/docs/examples/water_aims.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/docs/examples/water_aims.md
--------------------------------------------------------------------------------
/docs/examples/water_pyscf.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/docs/examples/water_pyscf.md
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Welcome to SALTED documentation!
2 |
3 | Ab initio electronic-structure methods are computationally expensive, making the calculation of electronic properties impractical for large systems and/or long simulation trajectories. In this context, the **S**ymmetry-**A**dapted **L**earning of **T**hree-dimensional **E**lectron **D**ensities (SALTED) program represents a highly transferable machine-learning method that can be used to perform inexpensive, yet accurate, predictions of the electronic charge density of a system. The transferability of the model is derived from a suitable decomposition of the electron density, which follows density-fitting, a.k.a. resolution of the identity (RI), approximations, commonly used in electronic-structure codes. In particular, we rely on a linear expansion of the electron density over a basis made of atom-centered radial functions and spherical harmonics, which can be used to represent the three-dimensional scalar field via a set of local atom-centered coefficients. From this representation of the electron density, a symmetry-adapted extension of Gaussian Process Regression is then used to perform equivariant predictions of the expansion coefficients, thus bypassing the need to learn the rotational symmetry of spherical harmonics from data.
4 |
5 | The core ideas of the method have been first introduced in [10.1021/acscentsci.8b00551](https://pubs.acs.org/doi/10.1021/acscentsci.8b00551) and [10.1039/C9SC02696G](https://pubs.rsc.org/en/content/articlelanding/2019/sc/c9sc02696g) with applications to isolated molecules. SALTED has then been formally presented in [10.1021/acs.jctc.1c00576 ](https://pubs.acs.org/doi/10.1021/acs.jctc.1c00576) in the context of extending the method to periodic condensed-phase systems. The current implementation of SALTED, as well as the present documentation, follows the advancements reported in [10.1021/acs.jctc.2c00850 ](https://pubs.acs.org/doi/full/10.1021/acs.jctc.2c00850), where an optimization of the method is carried out by recasting the learning problem into the Reproducing Kernel Hilbert Space (RKHS).
6 |
7 |
8 | Check out [installation](installation) to install the project. You can find out more in the [theory](theory) and [tutorial](tutorial) sections.
9 |
10 | !!! note
11 |
12 | This project is under active development.
13 |
14 |
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | !!! warning "Linux only 🐧"
4 | SALTED is only available on Linux OS. For Windows users, please use WSL or virtual machines.
5 |
6 | ## Install SALTED
7 |
8 | You can find the SALTED program on [GitHub](https://github.com/andreagrisafi/SALTED). In the SALTED directory, simply run `make`, followed by `pip install .`
9 |
10 | ??? note "Editable python package"
11 | If you want to modify the code, you can install SALTED with the following command:
12 |
13 | ```bash
14 | python -m pip install -e .
15 | ```
16 |
17 | where `-e` means editable installation, which means you can modify the code and the changes will be reflected in the installed package.
18 | This is useful for looking into the code / debugging.
19 |
20 |
21 | ### Dependencies
22 |
23 | - `featomic`: featomic installation requires a RUST compiler. To install a RUST compiler, run: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh && source "$HOME/.cargo/env"`. featomic can then be installed using `pip install git+https://github.com/metatensor/featomic.git`.
24 |
25 | - `mpi4py`: mpi4py is required to use MPI parallelisation; SALTED can nonetheless be run without this. A parallel h5py installation is required to use MPI parellelisation. This can be installed by running: `HDF5_MPI="ON" CC=mpicc pip install --no-cache-dir --no-binary=h5py h5py` provided HDF5 has been compiled with MPI support.
26 |
27 | - `pip install meson ninja` to run f2py using meson backend following versions of Python > 3.12.
28 |
29 | ## Install electronic-structure codes
30 |
31 | SALTED is to date interfaced with the following electronic-structure codes: *CP2K*, *PySCF*, and *FHI-aims*. If you are interested in using SALTED in combination with other codes, please contact one of the developers.
32 |
33 | ### PySCF
34 |
35 | To install PySCF, you can follow the instructions [here](https://pyscf.org/install.html).
36 |
37 | Please note that PySCF works well with small systems like molecules and clusters, but it lacks the scalability to handle periodic systems.
38 | We suggest using CP2K or FHI-aims for these applications.
39 |
40 |
41 | ### FHI-aims
42 |
43 |
44 | Please use recent versions of FHI-aims, the tutorial presented in this documentation will use the version `240403`.
45 |
46 | To install FHI-aims on your cluster or PC, you will need a FHI-aims licence and you can find further information [here](https://fhi-aims.org/get-the-code).
47 | Then you can follow the tutorial [Basics of Running FHI-aims](https://fhi-aims-club.gitlab.io/tutorials/basics-of-running-fhi-aims/preparations/) to install FHI-aims.
48 | The `CMake` file is important and you can find more information in the [CMake Tutorial for Compiling FHI-aims (parallel version)](https://aims-git.rz-berlin.mpg.de/aims/FHIaims/-/wikis/CMake%20Tutorial).
49 |
50 | Especially, you can find an FHI-aims focused tutorial on SALTED [here in FHI-aims-club](https://fhi-aims-club.gitlab.io/tutorials/fhi-aims-with-salted).
51 |
52 | ### CP2K
53 |
54 | Printing of RI density coefficients and 2-center auxiliary integrals needed to train SALTED is made available starting from the v2023.1 release of CP2K.
55 |
--------------------------------------------------------------------------------
/docs/javascripts/mathjax.js:
--------------------------------------------------------------------------------
1 | window.MathJax = {
2 | tex: {
3 | inlineMath: [["\\(", "\\)"]],
4 | displayMath: [["\\[", "\\]"]],
5 | processEscapes: true,
6 | processEnvironments: true
7 | },
8 | options: {
9 | ignoreHtmlClass: ".*|",
10 | processHtmlClass: "arithmatex"
11 | }
12 | };
13 |
14 | document$.subscribe(() => {
15 | MathJax.startup.output.clearCache()
16 | MathJax.typesetClear()
17 | MathJax.texReset()
18 | MathJax.typesetPromise()
19 | })
20 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | #
2 | # This file is autogenerated by pip-compile with python 3.10
3 | # To update, run:
4 | #
5 | # pip-compile docs/requirements.in
6 | #
7 | click==8.1.3
8 | # via mkdocs
9 | ghp-import==2.1.0
10 | # via mkdocs
11 | griffe==0.22.0
12 | # via mkdocstrings-python
13 | importlib-metadata==4.12.0
14 | # via mkdocs
15 | jinja2==3.1.2
16 | # via
17 | # mkdocs
18 | # mkdocstrings
19 | markdown==3.3.7
20 | # via
21 | # markdown-include
22 | # mkdocs
23 | # mkdocs-autorefs
24 | # mkdocstrings
25 | # pymdown-extensions
26 | markdown-include==0.6.0
27 | # via -r docs/requirements.in
28 | markupsafe==2.1.1
29 | # via
30 | # jinja2
31 | # mkdocstrings
32 | mergedeep==1.3.4
33 | # via mkdocs
34 | mkdocs==1.3.0
35 | # via
36 | # -r docs/requirements.in
37 | # mkdocs-autorefs
38 | # mkdocstrings
39 | mkdocs-autorefs==0.4.1
40 | # via mkdocstrings
41 | mkdocstrings[python]==0.19.0
42 | # via
43 | # -r docs/requirements.in
44 | # mkdocstrings-python
45 | mkdocstrings-python==0.7.1
46 | # via mkdocstrings
47 | packaging==21.3
48 | # via mkdocs
49 | pymdown-extensions==9.5
50 | # via mkdocstrings
51 | pyparsing==3.0.9
52 | # via packaging
53 | python-dateutil==2.8.2
54 | # via ghp-import
55 | pyyaml==6.0
56 | # via
57 | # mkdocs
58 | # pyyaml-env-tag
59 | pyyaml-env-tag==0.1
60 | # via mkdocs
61 | six==1.16.0
62 | # via python-dateutil
63 | watchdog==2.1.9
64 | # via mkdocs
65 | zipp==3.8.0
66 | # via importlib-metadata
--------------------------------------------------------------------------------
/docs/stylesheets/extra.css:
--------------------------------------------------------------------------------
1 | /* Maximum space for text block
2 | see https://squidfunk.github.io/mkdocs-material/setup/setting-up-navigation/#content-area-width
3 | */
4 | .md-grid {
5 | max-width: 100%; /* 100%, if you want to stretch to full-width */
6 | }
7 |
8 | /* wrapping lines in tables instead of adding horizontal scroll bars
9 | see https://github.com/mkdocs/mkdocs/discussions/3035
10 | */
11 | .wy-table-responsive table td, .wy-table-responsive table th {
12 | white-space: normal !important;
13 | }
14 |
15 | .wy-table-responsive {
16 | overflow : visible !important;
17 | }
--------------------------------------------------------------------------------
/docs/tutorial/dataset.md:
--------------------------------------------------------------------------------
1 | # Prepare Dataset
2 |
3 | This section describes how to prepare the dataset for training the SALTED model with different ab initio software packages.
4 |
5 | ## What do we need?
6 |
7 | 1. Product basis overlap matrices
8 | 1. Density fitting coefficients
9 |
10 | ## Generate Dataset
11 |
12 | To date, support for generating these overlap matrices and coefficients is included in three electronic structure packages - PySCF, FHI-aims and CP2K. If you develop another package and would like to develop SALTED integration, please contact one of the developers.
13 |
14 | Whichever code is used, the result should be the generation of new directories named `overlaps` and `coefficients` in the `saltedpath` directory. These will be used to train a SALTED model as described in the next section.
15 |
16 | ### PySCF
17 |
18 | 1. The following input arguments must be added to the `inp.qm` section:
19 | - `qmcode`: define the quantum-mechanical code as `pyscf`
20 | - `path2qm`: set the path where the PySCF data are going to be saved
21 | - `qmbasis`: define the wave function basis set for the Kohn-Sham calculation (example: `cc-pvqz`)
22 | - `functional`: define the functional for the Kohn-Sham calculation (example: `b3lyp`)
23 | 1. Define the auxiliary basis set using the input variable `dfbasis`, as provided in the `inp.qm` section. This must be chosen consistently with the wave function basis set (example: `RI-cc-pvqz`). Then, add this basis set information to SALTED by running:
24 | ```bash
25 | python3 -m salted.get_basis_info
26 | ```
27 | 1. Run PySCF to compute the Kohn-Sham density matrices:
28 | ```bash
29 | python3 -m salted.pyscf.run_pyscf
30 | ```
31 | 1. From the computed density matrices, perform the density fitting on the selected auxiliary basis set by running:
32 | ```bash
33 | python3 -m salted.pyscf.dm2df
34 | ```
35 |
36 | ### FHI-aims
37 |
38 | A detailed description of how to generate the training data for SALTED using FHI-aims can be found at [the dedicated SALTED/FHI-aims tutorial](https://fhi-aims-club.gitlab.io/tutorials/fhi-aims-with-salted).
39 |
40 |
41 | ### CP2K
42 |
43 | 1. The following input arguments must be added to the `inp.qm` section:
44 | - `qmcode`: define quantum-mechanical code as `cp2k`
45 | - `path2qm`: set the path where the CP2K data are going to be saved
46 | - `periodic`: set the periodicity of the system (`0D,2D,3D`)
47 | - `coeffile`: filename of RI density coefficients as printed by CP2K
48 | - `ovlpfile`: filename of 2-center auxiliary integrals as printed by CP2K
49 | - `dfbasis`: define auxiliary basis for the electron density expansion
50 | - `pseudocharge`: define pseudocharge according to the adopted GTH pseudopotential
51 | 1. Initialize the systems used for the CP2K calculation by running:
52 | ```bash
53 | python3 -m salted.cp2k.xyz2sys
54 | ```
55 | System cells and coordinates will be automatically saved in folders named `conf_1`, `conf_2`, ... up to the total number of structures included in the dataset, located into the selected `inp.qm.path2qm`.
56 | 1. Print auxiliary basis set information from the CP2K automatically generated RI basis set, as described in https://doi.org/10.1021/acs.jctc.6b01041. An example of a CP2K input file can be found in `cp2k-inputs/get_RI-AUTO_basis.inp`.
57 | 1. An uncontracted version of this basis can be produced to increase the efficiency of the RI printing workflow, by running:
58 | ```bash
59 | python3 -m salted.cp2k.uncontract_ri_basis contracted_basis_file uncontracted_basis_file
60 | ```
61 | Then, copy `uncontracted_basis_file` to the `cp2k/data/` folder in order to use this basis set to produce the reference density-fitting data, and set the corresponding filename in the `inp.qm.dfbasis` input variable.
62 | 1. Add the selected auxiliary basis to SALTED by running:
63 | ```bash
64 | python3 -m salted.get_basis_info
65 | ```
66 | 1. Run the CP2K calculations using the selected auxiliary basis and print out the training data made of reference RI coefficients and 2-center auxiliary integrals. An example of a CP2K input file can be found in `cp2k-inputs/qmmm_RI-print.inp`.
67 | 1. Set the `inp.qm.coeffile` and `inp.qm.ovlpfile` variables according to the filename of the generated training data and convert them to SALTED format by running:
68 | ```bash
69 | python3 -m salted.cp2k.cp2k2salted
70 | ```
71 |
--------------------------------------------------------------------------------
/docs/tutorial/predict.md:
--------------------------------------------------------------------------------
1 | # Predict Properties
2 |
3 | (for developing, please ref https://gitlab.com/FHI-aims-club/tutorials/fhi-aims-with-salted/-/blob/optimization/Tutorial/Tutorial-4/README.md?ref_type=heads&plain=1)
4 |
--------------------------------------------------------------------------------
/docs/workflow.md:
--------------------------------------------------------------------------------
1 | # Workflow
2 |
3 | The general SALTED workflow is summarised below. Detailed descriptions of each step will given in the following sections of the tutorial.
4 |
5 | ## SALTED workflow
6 |
7 | 1. Calculate electron density and [density fitting (DF)](theory.md#density-fitting-method) coefficients.
8 | 1. Generate (optionally sparse) [$\lambda$-SOAP descriptors](theory.md#symmetry-adapted-descriptor) by rascaline, and sparsify the atomic environments by [farthest point sampling (FPS) method](theory.md#farthest-point-sampling). This step uses the salted functions `initialize`, `sparse_selection`, and `sparse_descriptor`.
9 | 1. Calculate [RKHS](theory.md#reproducing-kernel-hilbert-space-rkhs) related quantities, including kernel matrix $\mathbf{K}_{MM}$, associated projectors, and the feature vector $\mathbf{\Psi}_{ND}$. This step uses the salted functions `rkhs_projector` and `rkhs_vector`.
10 | 1. Optimize [GPR weights](theory.md#gpr-optimization) by either [direct inversion](theory.md#direct-inversion) or [CG method](theory.md#conjugate-gradient-method), and save the optimized weights. This uses either the functions `hessian_matrix` and `solve_regression`, or `minimize_loss`.
11 | 1. Validate the model using the `validation` function.
12 | 1. Predict [density fitting coefficients](theory.md#density-fitting-method) of new structures using the [GPR weights](theory.md#gpr-optimization) obtained in the previous step, saving the predicted density coefficients. This uses the `prediction` function.
13 | 1. Use the predicted density coefficients to calculate properties derived from the predicted electron density.
14 |
15 |
--------------------------------------------------------------------------------
/example/Au100-Na_CP2K/Au-RI_AUTO_OPT-ccGRB:
--------------------------------------------------------------------------------
1 | Au RI_AUTO_OPT-ccGRB
2 | 42
3 | 1 0 0 1 1
4 | 10.0801255113 1.0
5 | 1 0 0 1 1
6 | 5.6000697285 1.0
7 | 1 0 0 1 1
8 | 3.1111498492 1.0
9 | 1 0 0 1 1
10 | 1.7284165829 1.0
11 | 1 0 0 1 1
12 | 0.9602314349 1.0
13 | 1 0 0 1 1
14 | 0.5334619083 1.0
15 | 1 0 0 1 1
16 | 0.2963677268 1.0
17 | 1 0 0 1 1
18 | 0.1646487371 1.0
19 | 1 1 1 1 1
20 | 10.0801255113 1.0
21 | 1 1 1 1 1
22 | 5.6000697285 1.0
23 | 1 1 1 1 1
24 | 3.1111498492 1.0
25 | 1 1 1 1 1
26 | 1.7284165829 1.0
27 | 1 1 1 1 1
28 | 0.9602314349 1.0
29 | 1 1 1 1 1
30 | 0.5334619083 1.0
31 | 1 1 1 1 1
32 | 0.2963677268 1.0
33 | 1 1 1 1 1
34 | 0.1646487371 1.0
35 | 1 2 2 1 1
36 | 10.0801255113 1.0
37 | 1 2 2 1 1
38 | 5.6000697285 1.0
39 | 1 2 2 1 1
40 | 3.1111498492 1.0
41 | 1 2 2 1 1
42 | 1.7284165829 1.0
43 | 1 2 2 1 1
44 | 0.9602314349 1.0
45 | 1 2 2 1 1
46 | 0.5334619083 1.0
47 | 1 2 2 1 1
48 | 0.2963677268 1.0
49 | 1 2 2 1 1
50 | 0.1646487371 1.0
51 | 1 3 3 1 1
52 | 10.0801255113 1.0
53 | 1 3 3 1 1
54 | 5.6000697285 1.0
55 | 1 3 3 1 1
56 | 3.1111498492 1.0
57 | 1 3 3 1 1
58 | 1.7284165829 1.0
59 | 1 3 3 1 1
60 | 0.9602314349 1.0
61 | 1 3 3 1 1
62 | 0.5334619083 1.0
63 | 1 3 3 1 1
64 | 0.2963677268 1.0
65 | 1 3 3 1 1
66 | 0.1646487371 1.0
67 | 1 4 4 1 1
68 | 10.0801255113 1.0
69 | 1 4 4 1 1
70 | 5.6000697285 1.0
71 | 1 4 4 1 1
72 | 3.1111498492 1.0
73 | 1 4 4 1 1
74 | 1.7284165829 1.0
75 | 1 4 4 1 1
76 | 0.9602314349 1.0
77 | 1 4 4 1 1
78 | 0.5334619083 1.0
79 | 1 4 4 1 1
80 | 0.2963677268 1.0
81 | 1 4 4 1 1
82 | 0.1646487371 1.0
83 | 1 5 5 1 1
84 | 0.9742243686 1.0
85 | 1 6 6 1 1
86 | 0.9742243686 1.0
87 |
--------------------------------------------------------------------------------
/example/Au100-Na_CP2K/Au-RI_AUTO_OPT-ccGRB-small:
--------------------------------------------------------------------------------
1 | Au RI_AUTO_OPT-ccGRB-small
2 | 38
3 | 1 0 0 1 1
4 | 10.0801255113 1.0
5 | 1 0 0 1 1
6 | 5.6000697285 1.0
7 | 1 0 0 1 1
8 | 3.1111498492 1.0
9 | 1 0 0 1 1
10 | 1.7284165829 1.0
11 | 1 0 0 1 1
12 | 0.9602314349 1.0
13 | 1 0 0 1 1
14 | 0.5334619083 1.0
15 | 1 0 0 1 1
16 | 0.2963677268 1.0
17 | 1 0 0 1 1
18 | 0.1646487371 1.0
19 | 1 1 1 1 1
20 | 10.0801255113 1.0
21 | 1 1 1 1 1
22 | 5.6000697285 1.0
23 | 1 1 1 1 1
24 | 3.1111498492 1.0
25 | 1 1 1 1 1
26 | 1.7284165829 1.0
27 | 1 1 1 1 1
28 | 0.9602314349 1.0
29 | 1 1 1 1 1
30 | 0.5334619083 1.0
31 | 1 1 1 1 1
32 | 0.2963677268 1.0
33 | 1 1 1 1 1
34 | 0.1646487371 1.0
35 | 1 2 2 1 1
36 | 10.0801255113 1.0
37 | 1 2 2 1 1
38 | 5.6000697285 1.0
39 | 1 2 2 1 1
40 | 3.1111498492 1.0
41 | 1 2 2 1 1
42 | 1.7284165829 1.0
43 | 1 2 2 1 1
44 | 0.9602314349 1.0
45 | 1 2 2 1 1
46 | 0.5334619083 1.0
47 | 1 2 2 1 1
48 | 0.2963677268 1.0
49 | 1 2 2 1 1
50 | 0.1646487371 1.0
51 | 1 3 3 1 1
52 | 10.0801255113 1.0
53 | 1 3 3 1 1
54 | 5.6000697285 1.0
55 | 1 3 3 1 1
56 | 3.1111498492 1.0
57 | 1 3 3 1 1
58 | 1.7284165829 1.0
59 | 1 3 3 1 1
60 | 0.9602314349 1.0
61 | 1 3 3 1 1
62 | 0.5334619083 1.0
63 | 1 3 3 1 1
64 | 0.2963677268 1.0
65 | 1 3 3 1 1
66 | 0.1646487371 1.0
67 | 1 4 4 1 1
68 | 10.0801255113 1.0
69 | 1 4 4 1 1
70 | 5.6000697285 1.0
71 | 1 4 4 1 1
72 | 3.1111498492 1.0
73 | 1 4 4 1 1
74 | 1.7284165829 1.0
75 | 1 4 4 1 1
76 | 0.9602314349 1.0
77 | 1 4 4 1 1
78 | 0.5334619083 1.0
79 |
--------------------------------------------------------------------------------
/example/Au100-Na_CP2K/README.rst:
--------------------------------------------------------------------------------
1 | Generate QM/MM training data using CP2K
2 | ---------------------------------------
3 | In what follows, we describe how to generate training electron densities of a dataset made of Au(100) slabs that interact with a classical Gaussian charge, using the CP2K simulation program. NB: this is made possible through to the official development version of CP2K (https://github.com/cp2k/cp2k).
4 |
5 | 1. The following input arguments must be added to the :code:`inp.qm` section:
6 |
7 | :code:`qmcode`: define quantum-mechanical code as :code:`cp2k`
8 |
9 | :code:`path2qm`: set the path where the CP2K data are going to be saved
10 |
11 | :code:`periodic`: set the periodicity of the system (:code:`0D,2D,3D`)
12 |
13 | :code:`coeffile`: filename of RI density coefficients as printed by CP2K
14 |
15 | :code:`ovlpfile`: filename of 2-center auxiliary integrals as printed by CP2K
16 |
17 | :code:`dfbasis`: define auxiliary basis for the electron density expansion
18 |
19 | :code:`pseudocharge`: define pseudocharge according to the adopted GTH pseudopotential
20 |
21 | 2. Initialize the systems used for the CP2K calculation by running:
22 |
23 | :code:`python3 -m salted.cp2k.xyz2sys`
24 |
25 | System cells and coordinates will be automatically saved in folders named :code:`conf_1`, :code:`conf_2`, ... up to the total number of structures included in the dataset, located into the selected :code:`inp.qm.path2qm`.
26 |
27 | 2. Print auxiliary basis set information from the CP2K automatically generated RI basis set, as described in https://doi.org/10.1021/acs.jctc.6b01041. An example of a CP2K input file can be found in :code:`cp2k-inputs/get_RI-AUTO_basis.inp`.
28 |
29 | 3. An uncontracted version of this basis can be produced to increase the efficiency of the RI printing workflow, by running:
30 |
31 | :code:`python3 -m salted.cp2k.uncontract_ri_basis contracted_basis_file uncontracted_basis_file`
32 |
33 | Then, copy :code:`uncontracted_basis_file` to the :code:`cp2k/data/` folder in order to use this basis set to produce the reference density-fitting data, and set the corresponding filename in the :code:`inp.qm.dfbasis` input variable.
34 |
35 | 4. Add the selected auxiliary basis to SALTED by running:
36 |
37 | :code:`python3 -m salted.get_basis_info`
38 |
39 | 5. Run the CP2K calculations using the selected auxiliary basis and print out the training data made of reference RI coefficients and 2-center auxiliary integrals. An example of a CP2K input file can be found in :code:`cp2k-inputs/qmmm_RI-print.inp`.
40 |
41 | 6. Set the :code:`inp.qm.coeffile` and :code:`inp.qm.ovlpfile` variables according to the filename of the generated training data and convert them to SALTED format by running:
42 |
43 | :code:`python3 -m salted.cp2k.cp2k2salted`
44 |
45 |
--------------------------------------------------------------------------------
/example/Au100-Na_CP2K/cp2k-inputs/get_RI-AUTO_basis.inp:
--------------------------------------------------------------------------------
1 | @set PROJECT Au
2 | @set RUN ENERGY
3 |
4 | &FORCE_EVAL
5 | METHOD QMMM
6 | &DFT
7 | BASIS_SET_FILE_NAME BASIS_ccGRB_UZH
8 | POTENTIAL_FILE_NAME POTENTIAL_UZH
9 | ! Select RI basis set size among SMALL, MEDIUM, LARGE
10 | AUTO_BASIS RI_HFX MEDIUM
11 | &MGRID
12 | CUTOFF 800
13 | REL_CUTOFF 80
14 | COMMENSURATE
15 | &END MGRID
16 | &POISSON
17 | PERIODIC XY
18 | POISSON_SOLVER MT
19 | &END POISSON
20 | ! Print basis set information
21 | &PRINT
22 | &BASIS_SET_FILE
23 | &END
24 | &END
25 | &SCF
26 | SCF_GUESS ATOMIC
27 | EPS_SCF 1.0E-8
28 | MAX_SCF 1
29 | ADDED_MOS 2000
30 | CHOLESKY INVERSE
31 | &SMEAR ON
32 | METHOD FERMI_DIRAC
33 | ELECTRONIC_TEMPERATURE [K] 300
34 | &END SMEAR
35 | &DIAGONALIZATION
36 | ALGORITHM STANDARD
37 | &END DIAGONALIZATION
38 | &MIXING
39 | METHOD BROYDEN_MIXING
40 | ALPHA 0.1
41 | BETA 1.5
42 | NBROYDEN 8
43 | &END MIXING
44 | &PRINT
45 | &RESTART
46 | &END
47 | &END
48 | &END SCF
49 | &XC
50 | &XC_FUNCTIONAL PBE
51 | &END XC_FUNCTIONAL
52 | &HF
53 | FRACTION 0.0
54 | &RI
55 | RI_METRIC IDENTITY
56 | &END
57 | &INTERACTION_POTENTIAL
58 | POTENTIAL_TYPE IDENTITY
59 | &END
60 | &END
61 | &END XC
62 | &END DFT
63 | &MM
64 | &FORCEFIELD
65 | &CHARGE
66 | ATOM Na
67 | CHARGE 1.000000
68 | &END CHARGE
69 | &CHARGE
70 | ATOM Au
71 | CHARGE 0.0
72 | &END CHARGE
73 | &NONBONDED
74 | &LENNARD-JONES
75 | atoms Na Na
76 | EPSILON 0.0
77 | SIGMA 3.166
78 | RCUT 11.4
79 | &END LENNARD-JONES
80 | &LENNARD-JONES
81 | atoms Na Au
82 | EPSILON 0.0
83 | SIGMA 3.6705
84 | RCUT 11.4
85 | &END LENNARD-JONES
86 | &LENNARD-JONES
87 | atoms Au Au
88 | EPSILON 0.0
89 | SIGMA 3.6705
90 | RCUT 11.4
91 | &END LENNARD-JONES
92 | &END NONBONDED
93 | &END FORCEFIELD
94 | &POISSON
95 | &EWALD
96 | EWALD_TYPE ewald
97 | ALPHA .44
98 | GMAX 21
99 | &END EWALD
100 | &END POISSON
101 | &END MM
102 | &QMMM
103 | MM_POTENTIAL_FILE_NAME MM_POTENTIAL
104 | USE_GEEP_LIB 12
105 | @include cell.sys
106 | ECOUPL GAUSS
107 | NOCOMPATIBILITY
108 | &PERIODIC
109 | &POISSON
110 | PERIODIC XY
111 | POISSON_SOLVER MT
112 | &END POISSON
113 | &MULTIPOLE OFF
114 | &END
115 | &END PERIODIC
116 | &MM_KIND Na
117 | RADIUS 2.27 !ionic radius
118 | &END MM_KIND
119 | &QM_KIND Au
120 | MM_INDEX 1..12
121 | &END QM_KIND
122 | &END QMMM
123 | &SUBSYS
124 | @include cell.sys
125 | @include coords.sys
126 | &KIND Au
127 | BASIS_SET ccGRB-D-q11
128 | POTENTIAL GTH-PBE-q11
129 | &END KIND
130 | &KIND Na
131 | BASIS_SET ccGRB-D-q11
132 | POTENTIAL GTH-PBE-q11
133 | &END KIND
134 | &TOPOLOGY
135 | &END TOPOLOGY
136 | &END SUBSYS
137 | &END FORCE_EVAL
138 | &GLOBAL
139 | PROJECT ${PROJECT}
140 | RUN_TYPE ${RUN}
141 | PRINT_LEVEL MEDIUM
142 | EXTENDED_FFT_LENGTHS
143 | &END GLOBAL
144 |
--------------------------------------------------------------------------------
/example/Au100-Na_CP2K/cp2k-inputs/qmmm_RI-print.inp:
--------------------------------------------------------------------------------
1 | @set PROJECT Au
2 | @set RUN ENERGY
3 |
4 | &FORCE_EVAL
5 | METHOD QMMM
6 | &DFT
7 | BASIS_SET_FILE_NAME BASIS_ccGRB_UZH
8 | BASIS_SET_FILE_NAME RI_AUTO_OPT
9 | POTENTIAL_FILE_NAME POTENTIAL_UZH
10 | &MGRID
11 | CUTOFF 800
12 | REL_CUTOFF 80
13 | COMMENSURATE
14 | &END MGRID
15 | &POISSON
16 | PERIODIC XY
17 | POISSON_SOLVER MT
18 | &END POISSON
19 | &SCF
20 | SCF_GUESS ATOMIC
21 | EPS_SCF 1.0E-8
22 | MAX_SCF 1000
23 | ADDED_MOS 2000
24 | CHOLESKY INVERSE
25 | &SMEAR ON
26 | METHOD FERMI_DIRAC
27 | ELECTRONIC_TEMPERATURE [K] 300
28 | &END SMEAR
29 | &DIAGONALIZATION
30 | ALGORITHM STANDARD
31 | &END DIAGONALIZATION
32 | &MIXING
33 | METHOD BROYDEN_MIXING
34 | ALPHA 0.1
35 | BETA 1.5
36 | NBROYDEN 8
37 | &END MIXING
38 | &PRINT
39 | &RESTART
40 | &END
41 | &END
42 | &END SCF
43 | &XC
44 | &XC_FUNCTIONAL PBE
45 | &END XC_FUNCTIONAL
46 | !The following HF section has no effect on the result of the calculation
47 | !it is only there because the relevant quantities are only available in RI-HFX
48 | &HF
49 | FRACTION 0.0 !we do not want any HF
50 | &INTERACTION_POTENTIAL
51 | !this is completely irrelevant, except that we need a short range potential for the calculation
52 | !to go through in PBCs, so IDENTITY (=overlap) is fine
53 | POTENTIAL_TYPE IDENTITY
54 | &END
55 | !This is the critical section
56 | &RI
57 | RI_METRIC IDENTITY !this is the metric used for the projection of the density (overlap here)
58 | MEMORY_CUT 1
59 | &PRINT
60 | !Subsection required to have the RI density coefficient printed (in demo-RI_DENSITY_COEFFS.dat)
61 | &RI_DENSITY_COEFFS
62 | !MULT_BY_S !uncomment to have the RI coefficients directly multiplied by the metric (overlap here)
63 | &END
64 | !To get the metric 2c integrals, use the following (in demo-RI_2C_INTS.fm), unformated
65 | &RI_METRIC_2C_INTS
66 | &END
67 | &END
68 | &END
69 | &END
70 | &END XC
71 | &END DFT
72 | &MM
73 | &FORCEFIELD
74 | &CHARGE
75 | ATOM Na
76 | CHARGE 1.000000
77 | &END CHARGE
78 | &CHARGE
79 | ATOM Au
80 | CHARGE 0.0
81 | &END CHARGE
82 | &NONBONDED
83 | &LENNARD-JONES
84 | atoms Na Na
85 | EPSILON 0.0
86 | SIGMA 3.166
87 | RCUT 11.4
88 | &END LENNARD-JONES
89 | &LENNARD-JONES
90 | atoms Na Au
91 | EPSILON 0.0
92 | SIGMA 3.6705
93 | RCUT 11.4
94 | &END LENNARD-JONES
95 | &LENNARD-JONES
96 | atoms Au Au
97 | EPSILON 0.0
98 | SIGMA 3.6705
99 | RCUT 11.4
100 | &END LENNARD-JONES
101 | &END NONBONDED
102 | &END FORCEFIELD
103 | &POISSON
104 | &EWALD
105 | EWALD_TYPE ewald
106 | ALPHA .44
107 | GMAX 21
108 | &END EWALD
109 | &END POISSON
110 | &END MM
111 | &QMMM
112 | MM_POTENTIAL_FILE_NAME MM_POTENTIAL
113 | USE_GEEP_LIB 12
114 | @include cell.sys
115 | ECOUPL GAUSS
116 | NOCOMPATIBILITY
117 | &PERIODIC
118 | &POISSON
119 | PERIODIC XY
120 | POISSON_SOLVER MT
121 | &END POISSON
122 | &MULTIPOLE OFF
123 | &END
124 | &END PERIODIC
125 | &MM_KIND Na
126 | RADIUS 2.27 !ionic radius
127 | &END MM_KIND
128 | &QM_KIND Au
129 | MM_INDEX 1..12
130 | &END QM_KIND
131 | &END QMMM
132 | &SUBSYS
133 | @include cell.sys
134 | @include coords.sys
135 | &KIND Au
136 | BASIS_SET ccGRB-D-q11
137 | BASIS_SET RI_HFX RI_AUTO_OPT-ccGRB
138 | POTENTIAL GTH-PBE-q11
139 | &END KIND
140 | &KIND Na
141 | BASIS_SET ccGRB-D-q11
142 | BASIS_SET RI_HFX RI_AUTO_OPT-ccGRB
143 | POTENTIAL GTH-PBE-q11
144 | &END KIND
145 | &TOPOLOGY
146 | &END TOPOLOGY
147 | &END SUBSYS
148 | &END FORCE_EVAL
149 | &GLOBAL
150 | PROJECT ${PROJECT}
151 | RUN_TYPE ${RUN}
152 | PRINT_LEVEL MEDIUM
153 | EXTENDED_FFT_LENGTHS
154 | &END GLOBAL
155 |
--------------------------------------------------------------------------------
/example/Au100-Na_CP2K/inp.yaml:
--------------------------------------------------------------------------------
1 | # workflow label and root directory
2 | salted:
3 | saltedname: rc8.0_rho-sg0.5_V-sg0.5
4 | saltedpath: ./
5 |
6 | # system general parameters
7 | system:
8 | filename: ./coords-qmmm.xyz
9 | species: [Au]
10 | parallel: False
11 |
12 | # quantum mechanical info
13 | qm:
14 | path2qm: ./
15 | qmcode: cp2k
16 | periodic: 2D
17 | dfbasis: RI_AUTO_OPT-ccGRB-small
18 | coeffile: Au-RI_DENSITY_COEFFS.dat
19 | ovlpfile: Au-RI_2C_INTS.fm
20 | pseudocharge: 11.0
21 |
22 | # descriptor parameters
23 | descriptor:
24 | rep1:
25 | type: rho
26 | rcut: 8.0
27 | sig: 0.5
28 | nrad: 6
29 | nang: 6
30 | neighspe: [Au,Na]
31 | rep2:
32 | type: V
33 | rcut: 8.0
34 | sig: 0.5
35 | nrad: 6
36 | nang: 6
37 | neighspe: [Au,Na]
38 |
39 | # Gaussian process regression variables
40 | gpr:
41 | z: 2.0
42 | Menv: 50
43 | Ntrain: 32
44 | trainfrac: 1.0
45 | trainsel: sequential
46 | blocksize: 100
47 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/README.rst:
--------------------------------------------------------------------------------
1 | Please refer to the following link for how to use SALTED in combination with FHI-AIMS:
2 |
3 | https://gitlab.com/FHI-aims-club/tutorials/fhi-aims-with-salted
4 |
5 |
6 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/control.in:
--------------------------------------------------------------------------------
1 | #########################################################################################
2 | #
3 | # Volker Blum, 2017 : Test run input file control.in for simple H2O
4 | #
5 | #########################################################################################
6 | #
7 | # Physical model
8 | #
9 | xc pbe
10 | spin none
11 | relativistic none
12 | charge 0.
13 | k_grid 1 1 1
14 | ri_density_restart write
15 | ri_full_output .True.
16 | ri_output_density_only .True.
17 |
18 | default_max_l_prodbas 5
19 | default_prodbas_acc 1d-4
20 | wave_threshold 1e-8
21 |
22 | ################################################################################
23 |
24 | ################################################################################
25 | #
26 | # FHI-aims code project
27 | # VB, Fritz-Haber Institut, 2009
28 | #
29 | # Suggested "light" defaults for O atom (to be pasted into control.in file)
30 | # Be sure to double-check any results obtained with these settings for post-processing,
31 | # e.g., with the "tight" defaults and larger basis sets.
32 | #
33 | ################################################################################
34 | species O
35 | # global species definitions
36 | nucleus 8
37 | mass 15.9994
38 | #
39 | l_hartree 6
40 | #
41 | cut_pot 4.0 2.0 1.0
42 | basis_dep_cutoff 1e-4
43 | #
44 | radial_base 36 7.0
45 | radial_multiplier 2
46 | angular_grids specified
47 | division 0.2659 50
48 | division 0.4451 110
49 | division 0.6052 194
50 | division 0.7543 302
51 | division 0.8014 434
52 | # division 0.8507 590
53 | # division 0.8762 770
54 | # division 0.9023 974
55 | # division 1.2339 1202
56 | # outer_grid 974
57 | outer_grid 434
58 | ################################################################################
59 | #
60 | # Definition of "minimal" basis
61 | #
62 | ################################################################################
63 | # valence basis states
64 | valence 2 s 2.
65 | valence 2 p 4.
66 | # ion occupancy
67 | ion_occ 2 s 1.
68 | ion_occ 2 p 3.
69 | ################################################################################
70 | #
71 | # Suggested additional basis functions. For production calculations,
72 | # uncomment them one after another (the most important basis functions are
73 | # listed first).
74 | #
75 | #
76 | ################################################################################
77 | # "First tier" - improvements: -699.05 meV to -159.38 meV
78 | hydro 2 p 1.8
79 | hydro 3 d 7.6
80 | hydro 3 s 6.4
81 | # "Second tier" - improvements: -49.91 meV to -5.39 meV
82 | hydro 4 f 11.6
83 | hydro 3 p 6.2
84 | hydro 3 d 5.6
85 | hydro 5 g 17.6
86 | hydro 1 s 0.75
87 | # "Third tier" - improvements: -2.83 meV to -0.50 meV
88 | # ionic 2 p auto
89 | # hydro 4 f 10.8
90 | # hydro 4 d 4.7
91 | # hydro 2 s 6.8
92 | # "Fourth tier" - improvements: -0.40 meV to -0.12 meV
93 | # hydro 3 p 5
94 | # hydro 3 s 3.3
95 | # hydro 5 g 15.6
96 | # hydro 4 f 17.6
97 | # hydro 4 d 14
98 | # Further basis functions - -0.08 meV and below
99 | # hydro 3 s 2.1
100 | # hydro 4 d 11.6
101 | # hydro 3 p 16
102 | # hydro 2 s 17.2
103 | ################################################################################
104 | #
105 | # FHI-aims code project
106 | # VB, Fritz-Haber Institut, 2009
107 | #
108 | # Suggested "light" defaults for H atom (to be pasted into control.in file)
109 | # Be sure to double-check any results obtained with these settings for post-processing,
110 | # e.g., with the "tight" defaults and larger basis sets.
111 | #
112 | ################################################################################
113 | species H
114 | # global species definitions
115 | nucleus 1
116 | mass 1.00794
117 | #
118 | l_hartree 6
119 | #
120 | cut_pot 4.0 2.0 1.0
121 | basis_dep_cutoff 1e-4
122 | #
123 | radial_base 24 7.0
124 | radial_multiplier 2
125 | angular_grids specified
126 | division 0.2421 50
127 | division 0.3822 110
128 | division 0.4799 194
129 | division 0.5341 302
130 | division 0.5626 434
131 | # division 0.5922 590
132 | # division 0.6542 770
133 | # division 0.6868 1202
134 | # outer_grid 770
135 | outer_grid 434
136 | ################################################################################
137 | #
138 | # Definition of "minimal" basis
139 | #
140 | ################################################################################
141 | # valence basis states
142 | valence 1 s 1.
143 | # ion occupancy
144 | ion_occ 1 s 0.5
145 | ################################################################################
146 | #
147 | # Suggested additional basis functions. For production calculations,
148 | # uncomment them one after another (the most important basis functions are
149 | # listed first).
150 | #
151 | # Basis constructed for dimers: 0.5 A, 0.7 A, 1.0 A, 1.5 A, 2.5 A
152 | #
153 | ################################################################################
154 | # "First tier" - improvements: -1014.90 meV to -62.69 meV
155 | hydro 2 s 2.1
156 | hydro 2 p 3.5
157 | # "Second tier" - improvements: -12.89 meV to -1.83 meV
158 | hydro 1 s 0.85
159 | hydro 2 p 3.7
160 | hydro 2 s 1.2
161 | hydro 3 d 7
162 | # "Third tier" - improvements: -0.25 meV to -0.12 meV
163 | # hydro 4 f 11.2
164 | # hydro 3 p 4.8
165 | # hydro 4 d 9
166 | # hydro 3 s 3.2
167 | #
168 |
169 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/control_read.in:
--------------------------------------------------------------------------------
1 | #########################################################################################
2 | #
3 | # Volker Blum, 2017 : Test run input file control.in for simple H2O
4 | #
5 | #########################################################################################
6 | #
7 | # Physical model
8 | #
9 | xc pbe
10 | spin none
11 | relativistic none
12 | charge 0.
13 | # k_grid 1 1 1
14 | ri_density_restart read 0
15 | ri_full_output .True.
16 |
17 | default_max_l_prodbas 5
18 | default_prodbas_acc 1d-4
19 |
20 | ################################################################################
21 |
22 | ################################################################################
23 | #
24 | # FHI-aims code project
25 | # VB, Fritz-Haber Institut, 2009
26 | #
27 | # Suggested "light" defaults for O atom (to be pasted into control.in file)
28 | # Be sure to double-check any results obtained with these settings for post-processing,
29 | # e.g., with the "tight" defaults and larger basis sets.
30 | #
31 | ################################################################################
32 | species O
33 | # global species definitions
34 | nucleus 8
35 | mass 15.9994
36 | #
37 | l_hartree 6
38 | #
39 | cut_pot 4.0 2.0 1.0
40 | basis_dep_cutoff 1e-4
41 | #
42 | radial_base 36 7.0
43 | radial_multiplier 2
44 | angular_grids specified
45 | division 0.2659 50
46 | division 0.4451 110
47 | division 0.6052 194
48 | division 0.7543 302
49 | division 0.8014 434
50 | # division 0.8507 590
51 | # division 0.8762 770
52 | # division 0.9023 974
53 | # division 1.2339 1202
54 | # outer_grid 974
55 | outer_grid 434
56 | ################################################################################
57 | #
58 | # Definition of "minimal" basis
59 | #
60 | ################################################################################
61 | # valence basis states
62 | valence 2 s 2.
63 | valence 2 p 4.
64 | # ion occupancy
65 | ion_occ 2 s 1.
66 | ion_occ 2 p 3.
67 | ################################################################################
68 | #
69 | # Suggested additional basis functions. For production calculations,
70 | # uncomment them one after another (the most important basis functions are
71 | # listed first).
72 | #
73 | #
74 | ################################################################################
75 | # "First tier" - improvements: -699.05 meV to -159.38 meV
76 | hydro 2 p 1.8
77 | hydro 3 d 7.6
78 | hydro 3 s 6.4
79 | # "Second tier" - improvements: -49.91 meV to -5.39 meV
80 | hydro 4 f 11.6
81 | hydro 3 p 6.2
82 | hydro 3 d 5.6
83 | hydro 5 g 17.6
84 | hydro 1 s 0.75
85 | # "Third tier" - improvements: -2.83 meV to -0.50 meV
86 | # ionic 2 p auto
87 | # hydro 4 f 10.8
88 | # hydro 4 d 4.7
89 | # hydro 2 s 6.8
90 | # "Fourth tier" - improvements: -0.40 meV to -0.12 meV
91 | # hydro 3 p 5
92 | # hydro 3 s 3.3
93 | # hydro 5 g 15.6
94 | # hydro 4 f 17.6
95 | # hydro 4 d 14
96 | # Further basis functions - -0.08 meV and below
97 | # hydro 3 s 2.1
98 | # hydro 4 d 11.6
99 | # hydro 3 p 16
100 | # hydro 2 s 17.2
101 | ################################################################################
102 | #
103 | # FHI-aims code project
104 | # VB, Fritz-Haber Institut, 2009
105 | #
106 | # Suggested "light" defaults for H atom (to be pasted into control.in file)
107 | # Be sure to double-check any results obtained with these settings for post-processing,
108 | # e.g., with the "tight" defaults and larger basis sets.
109 | #
110 | ################################################################################
111 | species H
112 | # global species definitions
113 | nucleus 1
114 | mass 1.00794
115 | #
116 | l_hartree 6
117 | #
118 | cut_pot 4.0 2.0 1.0
119 | basis_dep_cutoff 1e-4
120 | #
121 | radial_base 24 7.0
122 | radial_multiplier 2
123 | angular_grids specified
124 | division 0.2421 50
125 | division 0.3822 110
126 | division 0.4799 194
127 | division 0.5341 302
128 | division 0.5626 434
129 | # division 0.5922 590
130 | # division 0.6542 770
131 | # division 0.6868 1202
132 | # outer_grid 770
133 | outer_grid 434
134 | ################################################################################
135 | #
136 | # Definition of "minimal" basis
137 | #
138 | ################################################################################
139 | # valence basis states
140 | valence 1 s 1.
141 | # ion occupancy
142 | ion_occ 1 s 0.5
143 | ################################################################################
144 | #
145 | # Suggested additional basis functions. For production calculations,
146 | # uncomment them one after another (the most important basis functions are
147 | # listed first).
148 | #
149 | # Basis constructed for dimers: 0.5 A, 0.7 A, 1.0 A, 1.5 A, 2.5 A
150 | #
151 | ################################################################################
152 | # "First tier" - improvements: -1014.90 meV to -62.69 meV
153 | hydro 2 s 2.1
154 | hydro 2 p 3.5
155 | # "Second tier" - improvements: -12.89 meV to -1.83 meV
156 | hydro 1 s 0.85
157 | hydro 2 p 3.7
158 | hydro 2 s 1.2
159 | hydro 3 d 7
160 | # "Third tier" - improvements: -0.25 meV to -0.12 meV
161 | # hydro 4 f 11.2
162 | # hydro 3 p 4.8
163 | # hydro 4 d 9
164 | # hydro 3 s 3.2
165 | #
166 |
167 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/control_read_setup.in:
--------------------------------------------------------------------------------
1 | #########################################################################################
2 | #
3 | # Volker Blum, 2017 : Test run input file control.in for simple H2O
4 | #
5 | #########################################################################################
6 | #
7 | # Physical model
8 | #
9 | xc pbe
10 | spin none
11 | relativistic none
12 | charge 0.
13 | # k_grid 1 1 1
14 | ri_density_restart read_init
15 |
16 | default_max_l_prodbas 5
17 | default_prodbas_acc 1d-4
18 |
19 | ################################################################################
20 |
21 | ################################################################################
22 | #
23 | # FHI-aims code project
24 | # VB, Fritz-Haber Institut, 2009
25 | #
26 | # Suggested "light" defaults for O atom (to be pasted into control.in file)
27 | # Be sure to double-check any results obtained with these settings for post-processing,
28 | # e.g., with the "tight" defaults and larger basis sets.
29 | #
30 | ################################################################################
31 | species O
32 | # global species definitions
33 | nucleus 8
34 | mass 15.9994
35 | #
36 | l_hartree 6
37 | #
38 | cut_pot 4.0 2.0 1.0
39 | basis_dep_cutoff 1e-4
40 | #
41 | radial_base 36 7.0
42 | radial_multiplier 2
43 | angular_grids specified
44 | division 0.2659 50
45 | division 0.4451 110
46 | division 0.6052 194
47 | division 0.7543 302
48 | division 0.8014 434
49 | # division 0.8507 590
50 | # division 0.8762 770
51 | # division 0.9023 974
52 | # division 1.2339 1202
53 | # outer_grid 974
54 | outer_grid 434
55 | ################################################################################
56 | #
57 | # Definition of "minimal" basis
58 | #
59 | ################################################################################
60 | # valence basis states
61 | valence 2 s 2.
62 | valence 2 p 4.
63 | # ion occupancy
64 | ion_occ 2 s 1.
65 | ion_occ 2 p 3.
66 | ################################################################################
67 | #
68 | # Suggested additional basis functions. For production calculations,
69 | # uncomment them one after another (the most important basis functions are
70 | # listed first).
71 | #
72 | #
73 | ################################################################################
74 | # "First tier" - improvements: -699.05 meV to -159.38 meV
75 | hydro 2 p 1.8
76 | hydro 3 d 7.6
77 | hydro 3 s 6.4
78 | # "Second tier" - improvements: -49.91 meV to -5.39 meV
79 | hydro 4 f 11.6
80 | hydro 3 p 6.2
81 | hydro 3 d 5.6
82 | hydro 5 g 17.6
83 | hydro 1 s 0.75
84 | # "Third tier" - improvements: -2.83 meV to -0.50 meV
85 | # ionic 2 p auto
86 | # hydro 4 f 10.8
87 | # hydro 4 d 4.7
88 | # hydro 2 s 6.8
89 | # "Fourth tier" - improvements: -0.40 meV to -0.12 meV
90 | # hydro 3 p 5
91 | # hydro 3 s 3.3
92 | # hydro 5 g 15.6
93 | # hydro 4 f 17.6
94 | # hydro 4 d 14
95 | # Further basis functions - -0.08 meV and below
96 | # hydro 3 s 2.1
97 | # hydro 4 d 11.6
98 | # hydro 3 p 16
99 | # hydro 2 s 17.2
100 | ################################################################################
101 | #
102 | # FHI-aims code project
103 | # VB, Fritz-Haber Institut, 2009
104 | #
105 | # Suggested "light" defaults for H atom (to be pasted into control.in file)
106 | # Be sure to double-check any results obtained with these settings for post-processing,
107 | # e.g., with the "tight" defaults and larger basis sets.
108 | #
109 | ################################################################################
110 | species H
111 | # global species definitions
112 | nucleus 1
113 | mass 1.00794
114 | #
115 | l_hartree 6
116 | #
117 | cut_pot 4.0 2.0 1.0
118 | basis_dep_cutoff 1e-4
119 | #
120 | radial_base 24 7.0
121 | radial_multiplier 2
122 | angular_grids specified
123 | division 0.2421 50
124 | division 0.3822 110
125 | division 0.4799 194
126 | division 0.5341 302
127 | division 0.5626 434
128 | # division 0.5922 590
129 | # division 0.6542 770
130 | # division 0.6868 1202
131 | # outer_grid 770
132 | outer_grid 434
133 | ################################################################################
134 | #
135 | # Definition of "minimal" basis
136 | #
137 | ################################################################################
138 | # valence basis states
139 | valence 1 s 1.
140 | # ion occupancy
141 | ion_occ 1 s 0.5
142 | ################################################################################
143 | #
144 | # Suggested additional basis functions. For production calculations,
145 | # uncomment them one after another (the most important basis functions are
146 | # listed first).
147 | #
148 | # Basis constructed for dimers: 0.5 A, 0.7 A, 1.0 A, 1.5 A, 2.5 A
149 | #
150 | ################################################################################
151 | # "First tier" - improvements: -1014.90 meV to -62.69 meV
152 | hydro 2 s 2.1
153 | hydro 2 p 3.5
154 | # "Second tier" - improvements: -12.89 meV to -1.83 meV
155 | hydro 1 s 0.85
156 | hydro 2 p 3.7
157 | hydro 2 s 1.2
158 | hydro 3 d 7
159 | # "Third tier" - improvements: -0.25 meV to -0.12 meV
160 | # hydro 4 f 11.2
161 | # hydro 3 p 4.8
162 | # hydro 4 d 9
163 | # hydro 3 s 3.2
164 | #
165 |
166 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/inp.yaml:
--------------------------------------------------------------------------------
1 | # workflow label and root directory
2 | salted:
3 | saltedname: test
4 | saltedpath: ./
5 |
6 | # system general parameters
7 | system:
8 | filename: ./water_monomers_100.xyz
9 | species: [H, O]
10 | parallel: False
11 |
12 | # quantum mechanical info
13 | qm:
14 | path2qm: ./
15 | qmcode: aims
16 | dfbasis: FHI-aims-clusters
17 |
18 | # prediction data
19 | prediction:
20 | filename: ./water_dimers_10.xyz
21 | predname: prediction
22 | predict_data: ./aims_pred_data
23 |
24 | # atomic environment parameters (for rascaline)
25 | descriptor:
26 | rep1:
27 | type: rho
28 | rcut: 4.0
29 | sig: 0.3
30 | nrad: 8
31 | nang: 6
32 | neighspe: [H, O]
33 | rep2:
34 | type: rho
35 | rcut: 4.0
36 | sig: 0.3
37 | nrad: 8
38 | nang: 6
39 | neighspe: [H, O]
40 |
41 | # Gaussian process regression variables
42 | gpr:
43 | z: 2.0
44 | Menv: 100
45 | Ntrain: 40
46 | trainfrac: 1.0
47 | blocksize: 10
48 | trainsel: "random"
49 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/run-aims-predict-reorder.sbatch:
--------------------------------------------------------------------------------
1 | #! /bin/bash -l
2 |
3 | #SBATCH -o ./predict.out.%j
4 | #SBATCH -e ./predict.err.%j
5 | #SBATCH -J predict
6 | #SBATCH --partition=public
7 | #SBATCH --nodes=1
8 | #SBATCH --ntasks-per-node=16
9 | #SBATCH --mem-per-cpu=3800
10 |
11 | export OMP_NUM_THREADS=1
12 | ulimit -s unlimited
13 |
14 | DATADIR='qmdata/predicted_data'
15 | AIMS=~/aims.master.gnu.x
16 |
17 | mkdir $DATADIR
18 |
19 | python -m salted.aims.make_geoms --predict
20 |
21 | n=$(ls $DATADIR/geoms | grep -c 'in')
22 |
23 | for (( i=1; i<=$n; i++ )); do
24 | mkdir $DATADIR/$i
25 | cp control_read_setup.in ${DATADIR}/$i/control.in
26 | cp $DATADIR/geoms/$i.in $DATADIR/$i/geometry.in
27 |
28 | cd ${DATADIR}/$i
29 | srun --exclusive -n 1 $AIMS < /dev/null > temp.out
30 | cd -
31 | done
32 |
33 | wait
34 |
35 | python -m salted.aims.move_data_in_reorder
36 |
37 | for (( i=1; i<=$n; i++ )); do
38 | cp control_read.in ${DATADIR}/$i/control.in
39 |
40 | cd ${DATADIR}/$i
41 |
42 | mv ri_restart_coeffs_predicted.out ri_restart_coeffs.out
43 | srun --exclusive -n 1 $AIMS < /dev/null > aims_predict.out && mv rho_rebuilt_ri.out rho_ml.out && mv ri_restart_coeffs.out ri_restart_coeffs_ml.out &
44 |
45 | cd -
46 | done
47 |
48 | wait
49 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/run-aims-predict.sbatch:
--------------------------------------------------------------------------------
1 | #! /bin/bash -l
2 |
3 | #SBATCH -o ./predict.out.%j
4 | #SBATCH -e ./predict.err.%j
5 | #SBATCH -J predict
6 | #SBATCH --partition=public
7 | #SBATCH --nodes=1
8 | #SBATCH --ntasks-per-node=16
9 | #SBATCH --mem-per-cpu=3800
10 |
11 | export OMP_NUM_THREADS=1
12 | ulimit -s unlimited
13 |
14 | DATADIR='qmdata/predicted_data'
15 | AIMS=~/aims.master.gnu.x
16 |
17 | mkdir $DATADIR
18 |
19 | python -m salted.aims.make_geoms --predict
20 |
21 | n=$(ls $DATADIR/geoms | grep -c 'in')
22 |
23 | for (( i=1; i<=$n; i++ )); do
24 | mkdir $DATADIR/$i
25 | cp control_read.in ${DATADIR}/$i/control.in
26 | cp $DATADIR/geoms/$i.in $DATADIR/$i/geometry.in
27 | cd -
28 | done
29 |
30 | wait
31 |
32 | python -m salted.aims.move_data_in
33 |
34 | for (( i=1; i<=$n; i++ )); do
35 | cd ${DATADIR}/$i
36 | mv ri_restart_coeffs_predicted.out ri_restart_coeffs.out
37 | srun --exclusive -n 1 $AIMS < /dev/null > aims_predict.out && mv rho_rebuilt_ri.out rho_ml.out && mv ri_restart_coeffs.out ri_restart_coeffs_ml.out &
38 |
39 | cd -
40 | done
41 |
42 | wait
43 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/run-aims.sbatch:
--------------------------------------------------------------------------------
1 | #! /bin/bash -l
2 |
3 | #SBATCH -o ./gen_data.out.%j
4 | #SBATCH -e ./gen_data.err.%j
5 | #SBATCH -J gen_data
6 | #SBATCH --partition=XXXX
7 | #SBATCH --nodes=4
8 | #SBATCH --ntasks-per-node=16
9 | #SBATCH --mem-per-cpu=3800
10 | #SBATCH --cpus-per-task=1
11 |
12 | export OMP_NUM_THREADS=1
13 | ulimit -s unlimited
14 |
15 | QMDIR='qmdata/'
16 | AIMS=~/aims.master.mkl.x
17 |
18 | DATADIR=${QMDIR}data
19 |
20 | n=$(ls $DATADIR/geoms | grep -c 'in')
21 |
22 | for (( i=1; i<=$n; i++ )); do
23 | mkdir ${DATADIR}/$i
24 | cp control.in ${DATADIR}/$i
25 | cp ${DATADIR}/geoms/$i.in ${DATADIR}/$i/geometry.in
26 | cd ${DATADIR}/$i
27 |
28 | srun --exclusive -n 1 $AIMS < /dev/null > aims.out && mv rho_rebuilt_ri.out rho_df.out && mv ri_restart_coeffs.out ri_restart_coeffs_df.out &
29 |
30 | cd -
31 | done
32 |
33 | wait
34 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/run-ml.sbatch:
--------------------------------------------------------------------------------
1 | #!/bin/bash -l
2 | # Standard output and error:
3 | #SBATCH -o ./ML-water.out
4 | ##SBATCH -e ./ML-setup.err
5 | # Initial working directory:
6 | ##SBATCH -D ./
7 | # Job Name:
8 | #SBATCH -J ML-water
9 | # Queue (Partition):
10 | #SBATCH --partition=XXXX
11 | #SBATCH --nodes=1
12 | ##SBATCH --ntasks-per-node=4
13 | ##SBATCH --ntasks=32
14 | # for OpenMP:
15 | ##SBATCH --cpus-per-task=1
16 | #
17 | # Memory usage of the job [MB], 3800 MB per task:
18 | #SBATCH --mem-per-cpu=3800
19 | #
20 | #SBATCH --mail-type=none
21 | #
22 | # Wall clock limit:
23 | #SBATCH --time=8:00:00
24 |
25 | ### SET UP ENVIRONMENT VARIABLES: (uncomment and edit as needed)
26 |
27 |
28 | ### RUN YOUR CODE:
29 |
30 | python -m salted.get_basis_info
31 | python -m salted.initialize
32 | python -m salted.sparse_selection
33 | srun -n 16 python -m salted.sparse_descriptor
34 |
35 | python -m salted.rkhs_projector
36 | srun -n 16 python -m salted.rkhs_vector
37 |
38 | srun -n 16 python -m salted.hessian_matrix
39 | python -m salted.solve_regression
40 | srun -n 16 python -m salted.validation > validation.out
41 |
42 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS/water_dimers_10.xyz:
--------------------------------------------------------------------------------
1 | 6
2 |
3 | O -1.448231 -0.081379 -0.105305
4 | H -2.349368 -0.238126 0.154288
5 | H -0.920321 -0.870113 0.130561
6 | O -8.266929320802502 -2.341042516841843 -0.00028421402118565704
7 | H -7.334035320802503 -2.2343155168418427 -0.10325621402118565
8 | H -8.743914320802503 -1.5216505168418428 0.30555678597881436
9 | 6
10 |
11 | O 1.308677 -0.061683 -0.077667
12 | H 2.340557 -0.170448 0.241996
13 | H 1.279453 0.913258 0.023276
14 | O 8.486827629955043 1.0649779302103308 0.28930622645369747
15 | H 9.100163629955041 1.0056199302103308 0.9824172264536974
16 | H 9.009458629955041 1.006449930210331 -0.5068677735463025
17 | 6
18 |
19 | O -1.436475 0.007308 -0.081158
20 | H -1.273543 0.605991 -0.704585
21 | H -0.885895 0.167717 0.795994
22 | O -8.319075031526259 2.0908455599035407 -0.47403010037300913
23 | H -8.964200031526259 1.6040195599035407 -1.0067271003730092
24 | H -8.450736031526258 1.8567655599035406 0.49321489962699083
25 | 6
26 |
27 | O -1.376878 -0.007296 0.016908
28 | H -1.309553 0.419908 -0.823355
29 | H -1.076478 0.503867 0.678168
30 | O -8.325719323806974 2.3383487970677272 -0.10811253738857235
31 | H -8.598829323806973 1.9752257970677274 -0.9174885373885724
32 | H -8.529544323806974 1.8290127970677275 0.5829354626114276
33 | 6
34 |
35 | O -1.55773 -0.004156 0.049576
36 | H -1.487733 0.448778 -0.852129
37 | H -0.970713 0.463031 0.65099
38 | O -8.167161388575565 2.1289035370670355 0.044094007693886404
39 | H -8.367817388575565 1.7520255370670357 -0.8549559923061136
40 | H -8.870769388575566 1.7348755370670357 0.6456740076938864
41 | 6
42 |
43 | O -1.276934 -0.02905 -0.012972
44 | H -1.386544 0.562856 -0.773419
45 | H -1.313408 0.573499 0.729404
46 | O -8.333387448758744 2.6570453552258666 -0.15680694056552374
47 | H -8.504184448758744 2.1604503552258665 -0.8789999405655238
48 | H -8.205527448758744 2.0732593552258667 0.6219210594344762
49 | 6
50 |
51 | O -1.346976 -0.026594 0.039616
52 | H -1.366962 0.361552 -0.880903
53 | H -1.050459 0.579139 0.622652
54 | O -8.298008527645383 2.1785521398715555 -0.12868296149798286
55 | H -8.786513527645383 2.0197171398715557 -1.006903961497983
56 | H -8.712882527645382 1.7218061398715556 0.4903430385020171
57 | 6
58 |
59 | O -1.484872 0.02172 0.003656
60 | H -1.239773 0.471165 -0.757217
61 | H -0.848837 0.252188 0.742181
62 | O -8.328408842146587 2.093994952519581 0.00286879736356536
63 | H -8.469418842146588 1.5813689525195809 -0.7588772026364345
64 | H -8.858521842146587 1.799968952519581 0.7426337973635654
65 | 6
66 |
67 | O -1.633346 0.025042 0.009668
68 | H -0.899352 0.394495 -0.649576
69 | H -1.374678 0.397302 0.850931
70 | O -8.181342937068466 2.116557378592031 0.3702035727861667
71 | H -8.303163937068465 1.5629343785920309 -0.3840154272138333
72 | H -8.759776937068466 1.752001378592031 1.1194335727861668
73 | 6
74 |
75 | O 0.004454 0.09803 1.583859
76 | H 0.74712 -0.146956 0.971211
77 | H -0.740049 -0.307239 0.965109
78 | O -0.10757567447600846 -0.45437469214350495 8.539116526214325
79 | H -0.09577867447600846 -1.187761692143505 7.925768526214325
80 | H 0.06139832552399152 0.32860630785649503 7.994576526214325
81 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS_response/README:
--------------------------------------------------------------------------------
1 | Note that in this folder we are creating RI coeffs of the density response
2 | for a periodic calculation with DFPT dielectric. Change to DFPT polarizability
3 | for non-periodic systems.
4 |
5 | The workflow for the ML learning and prediction is then the same as for the other examples.
6 | Only the data generation and the calculation of derived quantities (reading in RI coefficients)
7 | is different in FHI-aims and the files in this folder cover these aspects.
8 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS_response/covariance_test.py:
--------------------------------------------------------------------------------
1 | from ase.io import read
2 | import numpy as np
3 | import spherical
4 | import quaternionic
5 |
6 | def complex_to_real_transformation(sizes):
7 | """Transformation matrix from complex to real spherical harmonics"""
8 | matrices = []
9 | for i in range(len(sizes)):
10 | lval = int((sizes[i]-1)/2)
11 | st = (-1.0)**(lval+1)
12 | transformation_matrix = np.zeros((sizes[i],sizes[i]),dtype=complex)
13 | for j in range(lval):
14 | transformation_matrix[j][j] = 1.0j
15 | transformation_matrix[j][sizes[i]-j-1] = st*1.0j
16 | transformation_matrix[sizes[i]-j-1][j] = 1.0
17 | transformation_matrix[sizes[i]-j-1][sizes[i]-j-1] = st*-1.0
18 | st = st * -1.0
19 | transformation_matrix[lval][lval] = np.sqrt(2.0)
20 | transformation_matrix /= np.sqrt(2.0)
21 | matrices.append(transformation_matrix)
22 | return matrices
23 |
24 | f = read("water_monomers_1k.xyz",":")
25 |
26 | itest = 10
27 |
28 | # shift coordinates about position center
29 | coords_1 = f[0].get_positions()
30 | coords_2 = f[itest].get_positions()
31 | center_1 = np.mean(coords_1,axis=0)
32 | center_2 = np.mean(coords_2,axis=0)
33 | coords_1 -= center_1
34 | coords_2 -= center_2
35 |
36 | # compute OH distance vectors
37 | d1_OH1 = coords_1[1]-coords_1[0]
38 | d1_OH2 = coords_1[2]-coords_1[0]
39 | d2_OH1 = coords_2[1]-coords_2[0]
40 | d2_OH2 = coords_2[2]-coords_2[0]
41 |
42 | # Define dipole unit vectors
43 | v1 = (d1_OH1+d1_OH2)/np.linalg.norm(d1_OH1+d1_OH2)
44 | v2 = (d2_OH1+d2_OH2)/np.linalg.norm(d2_OH1+d2_OH2)
45 |
46 | # Compute alignement matrix of v2 onto v1
47 | v = np.cross(v2,v1)
48 | c = np.dot(v2,v1)
49 |
50 | vmat = np.zeros((3,3))
51 | vmat[0,1] = -v[2]
52 | vmat[0,2] = v[1]
53 | vmat[1,0] = v[2]
54 | vmat[1,2] = -v[0]
55 | vmat[2,0] = -v[1]
56 | vmat[2,1] = v[0]
57 |
58 | vmat2 = np.dot(vmat,vmat)
59 |
60 | rmat1 = np.eye(3) + vmat + vmat2 / (1+c)
61 |
62 | rot_coords_2 = np.zeros((3,3))
63 |
64 | # rotate coordinates
65 | for i in range(3):
66 | rot_coords_2[i] = np.dot(rmat1,coords_2[i])
67 |
68 | # compute HH distance vectors of rotated molecules
69 | d1_HH = coords_1[2]-coords_1[1]
70 | d2_HH = rot_coords_2[2]-rot_coords_2[1]
71 |
72 | # define unit vectors
73 | v1 = d1_HH/np.linalg.norm(d1_HH)
74 | v2 = d2_HH/np.linalg.norm(d2_HH)
75 |
76 | # Compute alignement matrix of v2 onto v1
77 | v = np.cross(v2,v1)
78 | c = np.dot(v2,v1)
79 |
80 | vmat = np.zeros((3,3))
81 | vmat[0,1] = -v[2]
82 | vmat[0,2] = v[1]
83 | vmat[1,0] = v[2]
84 | vmat[1,2] = -v[0]
85 | vmat[2,0] = -v[1]
86 | vmat[2,1] = v[0]
87 |
88 | vmat2 = np.dot(vmat,vmat)
89 |
90 | rmat2 = np.eye(3) + vmat + vmat2 / (1+c)
91 |
92 | # rotate coordinates
93 | for i in range(3):
94 | coords_2[i] = np.dot(rmat2,rot_coords_2[i])
95 |
96 | # check alignement
97 | #print(coords_2-coords_1)
98 |
99 | # compute global rotation matrix
100 | rmat = np.dot(rmat2,rmat1)
101 |
102 | # compute quaternionic representation of rotation
103 | R = quaternionic.array.from_rotation_matrix(rmat)
104 |
105 | # compute Wigner-D matrices up to lmax
106 | lmax = 1
107 | wigner = spherical.Wigner(lmax)
108 | wigner_D = wigner.D(R)
109 |
110 | # select Wigner-D matrix for the given L
111 | L = 1
112 | msize = 2*L+1
113 | D = wigner_D[1:].reshape(msize,msize)
114 |
115 | # compute complex to real transformation
116 | c2r = complex_to_real_transformation([msize])[0]
117 |
118 | # make Wigner-D matrix real
119 | D_real = np.real(np.dot(c2r,np.dot(D,np.conj(c2r.T))))
120 | np.save("Dreal_L1_from_"+str(itest)+"_to_0.npy",D_real)
121 |
122 | #cvec_1 = np.load("coefficients/coefficients_conf0.npy")[10:13]
123 | #cvec_2 = np.load("coefficients/coefficients_conf"+str(itest)+".npy")[10:13]
124 | #print(cvec_1)
125 | #print(np.dot(D_real,cvec_2))
126 |
127 | path2qm = "./"
128 |
129 | # L=0 covariance test
130 | print("L=0 : ")
131 |
132 | cvec_1 = np.zeros(3)
133 | cvec_1[0] = np.load(path2qm+"coefficients/x/coefficients_conf0.npy")[0]
134 | cvec_1[1] = np.load(path2qm+"coefficients/y/coefficients_conf0.npy")[0]
135 | cvec_1[2] = np.load(path2qm+"coefficients/z/coefficients_conf0.npy")[0]
136 |
137 | cvec_2 = np.zeros(3)
138 | cvec_2[0] = np.load(path2qm+"coefficients/x/coefficients_conf1.npy")[0]
139 | cvec_2[1] = np.load(path2qm+"coefficients/y/coefficients_conf1.npy")[0]
140 | cvec_2[2] = np.load(path2qm+"coefficients/z/coefficients_conf1.npy")[0]
141 |
142 | print(cvec_1)
143 | print(np.dot(rmat,cvec_2))
144 | print("error:")
145 | print(np.dot(rmat,cvec_2)-cvec_1)
146 |
147 | print("")
148 |
149 | # L=1 covariance test
150 | print("L=1 : ")
151 |
152 | cvec_1 = np.zeros((3,3))
153 | cvec_1[0,:] = np.load(path2qm+"coefficients/x/coefficients_conf0.npy")[9:12]
154 | cvec_1[1,:] = np.load(path2qm+"coefficients/y/coefficients_conf0.npy")[9:12]
155 | cvec_1[2,:] = np.load(path2qm+"coefficients/z/coefficients_conf0.npy")[9:12]
156 |
157 | cvec_2 = np.zeros((3,3))
158 | cvec_2[0,:] = np.load(path2qm+"coefficients/x/coefficients_conf1.npy")[9:12]
159 | cvec_2[1,:] = np.load(path2qm+"coefficients/y/coefficients_conf1.npy")[9:12]
160 | cvec_2[2,:] = np.load(path2qm+"coefficients/z/coefficients_conf1.npy")[9:12]
161 |
162 | print(cvec_1)
163 | print(np.dot(rmat,np.dot(cvec_2,D_real.T)))
164 | print("error:")
165 | print(np.dot(rmat,np.dot(cvec_2,D_real.T))-cvec_1)
166 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS_response/inp.yaml:
--------------------------------------------------------------------------------
1 |
2 | # workflow label and root directory
3 | salted:
4 | saltedname: test
5 | saltedpath: ./
6 | saltedtype: 'density-response'
7 |
8 | # system general parameters
9 | system:
10 | filename: ./water_monomers_1k.xyz
11 | species: [H, O]
12 | parallel: False
13 | average: False
14 |
15 | # quantum mechanical info
16 | qm:
17 | path2qm: ./
18 | qmcode: aims
19 | dfbasis: RI-aims
20 |
21 | # atomic environment parameters (for rascaline)
22 | descriptor:
23 | rep1:
24 | type: rho
25 | rcut: 4.0
26 | sig: 0.3
27 | nrad: 8
28 | nang: 6
29 | neighspe: [H, O]
30 | rep2:
31 | type: rho
32 | rcut: 4.0
33 | sig: 0.3
34 | nrad: 8
35 | nang: 6
36 | neighspe: [H, O]
37 |
38 | # Gaussian process regression variables
39 | gpr:
40 | z: 2.0
41 | Menv: 100
42 | Ntrain: 100
43 | trainfrac: 1.0
44 | trainsel: "random"
45 | regul: 1e-8
46 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS_response/move_data.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import os
3 | import inp
4 | from mpi4py import MPI
5 | from ase.io import read
6 |
7 | # MPI information
8 | comm = MPI.COMM_WORLD
9 | size = comm.Get_size()
10 | rank = comm.Get_rank()
11 | print('This is task',rank+1,'of',size,flush=True)
12 |
13 | if (rank == 0):
14 | if not os.path.exists(inp.path2qm+inp.ovlpdir):
15 | os.mkdir(inp.path2qm+inp.ovlpdir)
16 | if not os.path.exists(inp.path2qm+'coefficients/'):
17 | os.mkdir(inp.path2qm+'coefficients/')
18 | if not os.path.exists(inp.path2qm+'projections/'):
19 | os.mkdir(inp.path2qm+'projections/')
20 |
21 | xyzfile = read(inp.filename,":")
22 | ndata = len(xyzfile)
23 |
24 | # Distribute structures to tasks
25 | if rank == 0:
26 | conf_range = [[] for _ in range(size)]
27 | blocksize = int(round(ndata/float(size)))
28 | for i in range(size):
29 | if i == (size-1):
30 | conf_range[i] = list(range(ndata))[i*blocksize:ndata]
31 | else:
32 | conf_range[i] = list(range(ndata))[i*blocksize:(i+1)*blocksize]
33 | else:
34 | conf_range = None
35 | conf_range = comm.scatter(conf_range,root=0)
36 |
37 | for i in conf_range:
38 | dirpath = inp.path2qm+'data/'+str(i+1)+'/'
39 | #idx = np.loadtxt(dirpath+'idx_prodbas.out').astype(int)
40 | #cs_list = np.loadtxt(dirpath+'prodbas_condon_shotley_list.out').astype(int)
41 | #idx -= 1
42 | #cs_list -= 1
43 | #idx = list(idx)
44 | #cs_list = list(cs_list)
45 | o = np.loadtxt(dirpath+'ri_projections.out').reshape(-1)
46 | t = np.loadtxt(dirpath+'ri_restart_coeffs.out').reshape(-1)
47 | ovlp = np.loadtxt(dirpath+'ri_ovlp.out').reshape(-1)
48 |
49 | n = len(o)
50 | ovlp = ovlp.reshape(n,n)
51 |
52 | #for j in cs_list:
53 | # ovlp[j,:] *= -1
54 | # ovlp[:,j] *= -1
55 | # o[j] *= -1
56 | # t[j] *= -1
57 |
58 | #o = o[idx]
59 | #t = t[idx]
60 | #ovlp = ovlp[idx,:]
61 | #ovlp = ovlp[:,idx]
62 | np.save(inp.path2qm+inp.ovlpdir+'overlap_conf'+str(i)+'.npy',ovlp)
63 | np.save(inp.path2qm+'projections/projections_conf'+str(i)+'.npy',o)
64 | np.save(inp.path2qm+'coefficients/coefficients_conf'+str(i)+'.npy',t)
65 | os.remove(dirpath+'ri_ovlp.out')
66 | os.remove(dirpath+'ri_projections.out')
67 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS_response/move_rho1_data.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import os
3 | import inp
4 | from mpi4py import MPI
5 | from ase.io import read
6 | from sys import argv
7 |
8 | # MPI information
9 | comm = MPI.COMM_WORLD
10 | size = comm.Get_size()
11 | rank = comm.Get_rank()
12 | print('This is task',rank+1,'of',size,flush=True)
13 | #rank = 0
14 |
15 | if (rank == 0):
16 | if not os.path.exists(inp.path2qm+'coefficients_rho1'):
17 | os.mkdir(inp.path2qm+'coefficients_rho1')
18 | if not os.path.exists(inp.path2qm+'coefficients_rho1/x'):
19 | os.mkdir(inp.path2qm+'coefficients_rho1/x')
20 | if not os.path.exists(inp.path2qm+'coefficients_rho1/y'):
21 | os.mkdir(inp.path2qm+'coefficients_rho1/y')
22 | if not os.path.exists(inp.path2qm+'coefficients_rho1/z'):
23 | os.mkdir(inp.path2qm+'coefficients_rho1/z')
24 | if not os.path.exists(inp.path2qm+'projections_rho1'):
25 | os.mkdir(inp.path2qm+'projections_rho1')
26 | if not os.path.exists(inp.path2qm+'projections_rho1/x'):
27 | os.mkdir(inp.path2qm+'projections_rho1/x')
28 | if not os.path.exists(inp.path2qm+'projections_rho1/y'):
29 | os.mkdir(inp.path2qm+'projections_rho1/y')
30 | if not os.path.exists(inp.path2qm+'projections_rho1/z'):
31 | os.mkdir(inp.path2qm+'projections_rho1/z')
32 |
33 | xyzfile = read(inp.filename,":")
34 | ndata = len(xyzfile)
35 |
36 | # Distribute structures to tasks
37 | if rank == 0:
38 | conf_range = [[] for _ in range(size)]
39 | blocksize = int(round(ndata/float(size)))
40 | for i in range(size):
41 | if i == (size-1):
42 | conf_range[i] = list(range(ndata))[i*blocksize:ndata]
43 | else:
44 | conf_range[i] = list(range(ndata))[i*blocksize:(i+1)*blocksize]
45 | else:
46 | conf_range = None
47 | conf_range = comm.scatter(conf_range,root=0)
48 |
49 | for i in conf_range:
50 | dirpath = inp.path2qm+'data/'+str(i+1)+'/'
51 | #idx = np.loadtxt(dirpath+'idx_prodbas.out').astype(int)
52 | #cs_list = np.loadtxt(dirpath+'prodbas_condon_shotley_list.out').astype(int)
53 | #idx -= 1
54 | #cs_list -= 1
55 | #idx = list(idx)
56 | #cs_list = list(cs_list)
57 | o = np.loadtxt(dirpath+'ri_projections_rho1.out').transpose()
58 | t = []
59 | t.append(np.loadtxt(dirpath+'ri_rho1_restart_coeffs_1.out'))
60 | t.append(np.loadtxt(dirpath+'ri_rho1_restart_coeffs_2.out'))
61 | t.append(np.loadtxt(dirpath+'ri_rho1_restart_coeffs_3.out'))
62 | t = np.array(t)
63 |
64 | n = len(o)
65 |
66 | #for j in cs_list:
67 | # o[:,j] *= -1
68 | # t[:,j] *= -1
69 |
70 | #o = o[:,idx]
71 | #t = t[:,idx]
72 | np.save(inp.path2qm+'projections_rho1/x/projections_conf'+str(i)+'.npy',o[0,:])
73 | np.save(inp.path2qm+'projections_rho1/y/projections_conf'+str(i)+'.npy',o[1,:])
74 | np.save(inp.path2qm+'projections_rho1/z/projections_conf'+str(i)+'.npy',o[2,:])
75 | np.save(inp.path2qm+'coefficients_rho1/x/coefficients_conf'+str(i)+'.npy',t[0,:])
76 | np.save(inp.path2qm+'coefficients_rho1/y/coefficients_conf'+str(i)+'.npy',t[1,:])
77 | np.save(inp.path2qm+'coefficients_rho1/z/coefficients_conf'+str(i)+'.npy',t[2,:])
78 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS_response/run-aims.sbatch:
--------------------------------------------------------------------------------
1 | #! /bin/bash -l
2 |
3 | #SBATCH -o ./gen_data.out.%j
4 | #SBATCH -e ./gen_data.err.%j
5 | #SBATCH -J gen_data
6 | #SBATCH --partition=p.ada
7 | #SBATCH --nodes=1
8 | #SBATCH --ntasks-per-node=72
9 | #SBATCH --mem-per-cpu=6000
10 | #SBATCH --time=1:00:00
11 |
12 |
13 | export OMP_NUM_THREADS=1
14 | ulimit -s unlimited
15 | #export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$INTEL_HOME/compilers_and_libraries/linux/lib/intel64/:$MKL_HOME/lib/intel64/:$HOME/.local/lib
16 |
17 | QMDIR='/ada/ptmp/mpsd/alewis/water_aligned/qmdata/'
18 | AIMS=~/aims.x
19 |
20 | DATADIR=${QMDIR}data
21 |
22 | python make_geoms.py
23 |
24 | n=$(ls $DATADIR/geoms | grep -c 'in')
25 | for (( i=1; i<=$n; i++ )); do
26 | let j=$i-1
27 | mkdir ${DATADIR}/$i
28 | cp control.in ${DATADIR}/$i
29 | cp ${DATADIR}/geoms/$i.in ${DATADIR}/$i/geometry.in
30 | cd ${DATADIR}/$i
31 |
32 | srun --exclusive -n 16 $AIMS < /dev/null > aims.out && mv rho_rebuilt_ri.out rho_df.out && mv ri_restart_coeffs.out ri_restart_coeffs_df.out &
33 |
34 | cd -
35 | done
36 |
37 | wait
38 |
39 | srun -n 72 python move_data.py
40 | srun -n 72 python move_rho1_data.py
41 |
--------------------------------------------------------------------------------
/example/water_monomer_AIMS_response/run_test_serial.sh:
--------------------------------------------------------------------------------
1 | python3 -m salted.initialize
2 | python3 -m salted.sparse_selection
3 | python3 -m salted.sparse_descriptor
4 | python3 -m salted.rkhs_projector
5 | python3 -m salted.rkhs_vector
6 | python3 -m salted.hessian_matrix
7 | python3 -m salted.solve_regression
8 | python3 -m salted.validation
9 |
--------------------------------------------------------------------------------
/example/water_monomer_PySCF/README.rst:
--------------------------------------------------------------------------------
1 | Generate training data using PySCF
2 | ----------------------------------
3 |
4 | In what follows, we describe how to generate the training electron density data using the PySCF quantum-chemistry program.
5 |
6 | 1. The following input arguments must be added to the :code:`inp.qm` section:
7 |
8 | :code:`qmcode:`: define the quantum-mechanical code as :code:`pyscf`
9 |
10 | :code:`path2qm`: set the path where the PySCF data are going to be saved
11 |
12 | :code:`qmbasis`: define the wave function basis set for the Kohn-Sham calculation (example: :code:`cc-pvqz`)
13 |
14 | :code:`functional`: define the functional for the Kohn-Sham calculation (example: :code:`b3lyp`)
15 |
16 | 2. Define the auxiliary basis set using the input variable :code:`dfbasis`, as provided in the :code:`inp.qm` section. This must be chosen consistently with the wave function basis set (example: :code:`RI-cc-pvqz`). Then, add this basis set information to SALTED by running:
17 |
18 | :code:`python3 -m salted.get_basis_info`
19 |
20 | 3. Run PySCF to compute the Kohn-Sham density matrices:
21 |
22 | :code:`python3 -m salted.pyscf.run_pyscf`
23 |
24 | 4. From the computed density matrices, perform the density fitting on the selected auxiliary basis set by running:
25 |
26 | :code:`python3 -m salted.pyscf.dm2df`
27 |
28 | Indirect prediction of electrostatic energies
29 | ---------------------------------------------
30 |
31 | From the predicted density coefficients, it is possible to validate the model computing the electrostatic energy and compare it against the reference PySCF values.
32 |
33 | 1. Calculate the reference energies of the water molecules used for validation, by running:
34 |
35 | :code:`python3 -m salted.pyscf.electro_energy`
36 |
37 | 2. Calculate the energies derived from the predicted densities on the validation set and evaluate the error in kcal/mol, by running:
38 |
39 | :code:`python3 -m salted.pyscf.electro_error`
40 |
--------------------------------------------------------------------------------
/example/water_monomer_PySCF/covariance_test.py:
--------------------------------------------------------------------------------
1 | from ase.io import read
2 | import numpy as np
3 | import spherical
4 | import quaternionic
5 |
6 | def complex_to_real_transformation(sizes):
7 | """Transformation matrix from complex to real spherical harmonics"""
8 | matrices = []
9 | for i in range(len(sizes)):
10 | lval = int((sizes[i]-1)/2)
11 | st = (-1.0)**(lval+1)
12 | transformation_matrix = np.zeros((sizes[i],sizes[i]),dtype=complex)
13 | for j in range(lval):
14 | transformation_matrix[j][j] = 1.0j
15 | transformation_matrix[j][sizes[i]-j-1] = st*1.0j
16 | transformation_matrix[sizes[i]-j-1][j] = 1.0
17 | transformation_matrix[sizes[i]-j-1][sizes[i]-j-1] = st*-1.0
18 | st = st * -1.0
19 | transformation_matrix[lval][lval] = np.sqrt(2.0)
20 | transformation_matrix /= np.sqrt(2.0)
21 | matrices.append(transformation_matrix)
22 | return matrices
23 |
24 | f = read("water_monomers_1k.xyz",":")
25 |
26 | itest = 1
27 |
28 | # shift coordinates about position center
29 | coords_1 = f[0].get_positions()
30 | coords_2 = f[itest].get_positions()
31 | center_1 = np.mean(coords_1,axis=0)
32 | center_2 = np.mean(coords_2,axis=0)
33 | coords_1 -= center_1
34 | coords_2 -= center_2
35 |
36 | # compute OH distance vectors
37 | d1_OH1 = coords_1[1]-coords_1[0]
38 | d1_OH2 = coords_1[2]-coords_1[0]
39 | d2_OH1 = coords_2[1]-coords_2[0]
40 | d2_OH2 = coords_2[2]-coords_2[0]
41 |
42 | # Define dipole unit vectors
43 | v1 = (d1_OH1+d1_OH2)/np.linalg.norm(d1_OH1+d1_OH2)
44 | v2 = (d2_OH1+d2_OH2)/np.linalg.norm(d2_OH1+d2_OH2)
45 |
46 | # Compute alignement matrix of v2 onto v1
47 | v = np.cross(v2,v1)
48 | c = np.dot(v2,v1)
49 |
50 | vmat = np.zeros((3,3))
51 | vmat[0,1] = -v[2]
52 | vmat[0,2] = v[1]
53 | vmat[1,0] = v[2]
54 | vmat[1,2] = -v[0]
55 | vmat[2,0] = -v[1]
56 | vmat[2,1] = v[0]
57 |
58 | vmat2 = np.dot(vmat,vmat)
59 |
60 | rmat1 = np.eye(3) + vmat + vmat2 / (1+c)
61 |
62 | rot_coords_2 = np.zeros((3,3))
63 |
64 | # rotate coordinates
65 | for i in range(3):
66 | rot_coords_2[i] = np.dot(rmat1,coords_2[i])
67 |
68 | # compute HH distance vectors of rotated molecules
69 | d1_HH = coords_1[2]-coords_1[1]
70 | d2_HH = rot_coords_2[2]-rot_coords_2[1]
71 |
72 | # define unit vectors
73 | v1 = d1_HH/np.linalg.norm(d1_HH)
74 | v2 = d2_HH/np.linalg.norm(d2_HH)
75 |
76 | # Compute alignement matrix of v2 onto v1
77 | v = np.cross(v2,v1)
78 | c = np.dot(v2,v1)
79 |
80 | vmat = np.zeros((3,3))
81 | vmat[0,1] = -v[2]
82 | vmat[0,2] = v[1]
83 | vmat[1,0] = v[2]
84 | vmat[1,2] = -v[0]
85 | vmat[2,0] = -v[1]
86 | vmat[2,1] = v[0]
87 |
88 | vmat2 = np.dot(vmat,vmat)
89 |
90 | rmat2 = np.eye(3) + vmat + vmat2 / (1+c)
91 |
92 | # rotate coordinates
93 | for i in range(3):
94 | coords_2[i] = np.dot(rmat2,rot_coords_2[i])
95 |
96 | # check alignement
97 | #print(coords_2-coords_1)
98 |
99 | # compute global rotation matrix
100 | rmat = np.dot(rmat2,rmat1)
101 |
102 | # compute quaternionic representation of rotation
103 | R = quaternionic.array.from_rotation_matrix(rmat)
104 |
105 | # compute Wigner-D matrices up to lmax
106 | lmax = 1
107 | wigner = spherical.Wigner(lmax)
108 | wigner_D = wigner.D(R)
109 |
110 | # select Wigner-D matrix for the give L
111 | L = 1
112 | msize = 2*L+1
113 | D = wigner_D[1:].reshape(msize,msize)
114 |
115 | # compute complex to real transformation
116 | c2r = complex_to_real_transformation([msize])[0]
117 |
118 | # make Wigner-D matrix real
119 | D_real = np.real(np.dot(c2r,np.dot(D,np.conj(c2r.T))))
120 |
121 | cvec_1 = np.load("coefficients/coefficients_conf0.npy")[10:13]
122 | cvec_2 = np.load("coefficients/coefficients_conf"+str(itest)+".npy")[10:13]
123 | print(cvec_1)
124 | print(np.dot(D_real,cvec_2))
125 |
126 | #path2qm = "/gpfsstore/rech/kln/ulo49cx/water_monomer/"
127 | #
128 | ## L=0 covariance test
129 | #
130 | #cvec_1 = np.zeros(3)
131 | #cvec_1[0] = np.load(path2qm+"coefficients/coefficients-x_conf0.npy")[0]
132 | #cvec_1[1] = np.load(path2qm+"coefficients/coefficients-y_conf0.npy")[0]
133 | #cvec_1[2] = np.load(path2qm+"coefficients/coefficients-z_conf0.npy")[0]
134 | #
135 | #cvec_2 = np.zeros(3)
136 | #cvec_2[0] = np.load(path2qm+"coefficients/coefficients-x_conf1.npy")[0]
137 | #cvec_2[1] = np.load(path2qm+"coefficients/coefficients-y_conf1.npy")[0]
138 | #cvec_2[2] = np.load(path2qm+"coefficients/coefficients-z_conf1.npy")[0]
139 | #
140 | #print(cvec_1)
141 | #print(np.dot(rmat,cvec_2))
142 | #
143 | ## L=1 covariance test
144 | #
145 | #cvec_1 = np.zeros((3,3))
146 | #cvec_1[0,:] = np.load(path2qm+"coefficients/coefficients-x_conf0.npy")[9:12]
147 | #cvec_1[1,:] = np.load(path2qm+"coefficients/coefficients-y_conf0.npy")[9:12]
148 | #cvec_1[2,:] = np.load(path2qm+"coefficients/coefficients-z_conf0.npy")[9:12]
149 | #
150 | #cvec_2 = np.zeros((3,3))
151 | #cvec_2[0,:] = np.load(path2qm+"coefficients/coefficients-x_conf1.npy")[9:12]
152 | #cvec_2[1,:] = np.load(path2qm+"coefficients/coefficients-y_conf1.npy")[9:12]
153 | #cvec_2[2,:] = np.load(path2qm+"coefficients/coefficients-z_conf1.npy")[9:12]
154 | #
155 | #print(cvec_1)
156 | #print(np.dot(rmat,np.dot(cvec_2,D_real.T)))
157 |
--------------------------------------------------------------------------------
/example/water_monomer_PySCF/inp.yaml:
--------------------------------------------------------------------------------
1 | # workflow label and root directory
2 | salted:
3 | saltedname: test
4 | saltedpath: ./
5 |
6 | # system general parameters
7 | system:
8 | filename: ./water_total.xyz
9 | #filename: ./water_monomers_1k.xyz
10 | species: [H, O]
11 | parallel: False
12 |
13 | # quantum mechanical info
14 | qm:
15 | path2qm: ./
16 | qmcode: pyscf
17 | dfbasis: RI-cc-pvqz
18 | qmbasis: cc-pvqz
19 | functional: b3lyp
20 |
21 | # prediction data
22 | prediction:
23 | filename: ./water_dimers_10.xyz
24 | predname: dimer
25 |
26 | # descriptor parameters
27 | descriptor:
28 | rep1:
29 | type: rho
30 | rcut: 4.0
31 | sig: 0.3
32 | nrad: 8
33 | nang: 6
34 | neighspe: [H, O]
35 | rep2:
36 | type: rho
37 | rcut: 4.0
38 | sig: 0.3
39 | nrad: 8
40 | nang: 6
41 | neighspe: [H, O]
42 | sparsify:
43 | nsamples: 100
44 | ncut: 1000
45 |
46 | # Gaussian process regression variables
47 | gpr:
48 | z: 2.0
49 | Menv: 100
50 | Ntrain: 1000
51 | trainfrac: 1.0
52 | trainsel: sequential
53 | #blocksize: 250
54 |
--------------------------------------------------------------------------------
/example/water_monomer_PySCF/interface.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import time
3 | import numpy as np
4 | from ase.io import read
5 | from salted import init_pred
6 | from salted import salted_prediction
7 |
8 | from salted.sys_utils import ParseConfig
9 | inp = ParseConfig().parse_input()
10 |
11 | # Initialize SALTED prediction
12 | lmax,nmax,lmax_max,weights,power_env_sparse,Mspe,Vmat,vfps,charge_integrals = init_pred.build()
13 |
14 | # do prediction for the given structure
15 | frames = read(inp.prediction.filename,":")
16 | for i in range(len(frames)):
17 | structure = frames[i]
18 | coefs = salted_prediction.build(lmax,nmax,lmax_max,weights,power_env_sparse,Mspe,Vmat,vfps,charge_integrals,structure)
19 | np.savetxt("dynamics/COEFFS-"+str(i+1)+".dat",coefs)
20 |
--------------------------------------------------------------------------------
/example/water_monomer_PySCF/run_test_parallel.sh:
--------------------------------------------------------------------------------
1 | python3 -m salted.initialize
2 | python3 -m salted.sparse_selection
3 | mpirun -n 4 python3 -m salted.sparse_descriptor
4 | python3 -m salted.rkhs_projector
5 | mpirun -n 4 python3 -m salted.rkhs_vector
6 | mpirun -n 4 python3 -m salted.hessian_matrix
7 | python3 -m salted.solve_regression
8 | python3 -m salted.validation
9 |
--------------------------------------------------------------------------------
/example/water_monomer_PySCF/run_test_serial.sh:
--------------------------------------------------------------------------------
1 | python3 -m salted.initialize
2 | python3 -m salted.sparse_selection
3 | python3 -m salted.sparse_descriptor
4 | python3 -m salted.rkhs_projector
5 | python3 -m salted.rkhs_vector
6 | python3 -m salted.hessian_matrix
7 | python3 -m salted.solve_regression
8 | python3 -m salted.validation
9 |
--------------------------------------------------------------------------------
/example/water_monomer_PySCF/water_dimers_10.xyz:
--------------------------------------------------------------------------------
1 | 6
2 |
3 | O -1.448231 -0.081379 -0.105305
4 | H -2.349368 -0.238126 0.154288
5 | H -0.920321 -0.870113 0.130561
6 | O -8.266929320802502 -2.341042516841843 -0.00028421402118565704
7 | H -7.334035320802503 -2.2343155168418427 -0.10325621402118565
8 | H -8.743914320802503 -1.5216505168418428 0.30555678597881436
9 | 6
10 |
11 | O 1.308677 -0.061683 -0.077667
12 | H 2.340557 -0.170448 0.241996
13 | H 1.279453 0.913258 0.023276
14 | O 8.486827629955043 1.0649779302103308 0.28930622645369747
15 | H 9.100163629955041 1.0056199302103308 0.9824172264536974
16 | H 9.009458629955041 1.006449930210331 -0.5068677735463025
17 | 6
18 |
19 | O -1.436475 0.007308 -0.081158
20 | H -1.273543 0.605991 -0.704585
21 | H -0.885895 0.167717 0.795994
22 | O -8.319075031526259 2.0908455599035407 -0.47403010037300913
23 | H -8.964200031526259 1.6040195599035407 -1.0067271003730092
24 | H -8.450736031526258 1.8567655599035406 0.49321489962699083
25 | 6
26 |
27 | O -1.376878 -0.007296 0.016908
28 | H -1.309553 0.419908 -0.823355
29 | H -1.076478 0.503867 0.678168
30 | O -8.325719323806974 2.3383487970677272 -0.10811253738857235
31 | H -8.598829323806973 1.9752257970677274 -0.9174885373885724
32 | H -8.529544323806974 1.8290127970677275 0.5829354626114276
33 | 6
34 |
35 | O -1.55773 -0.004156 0.049576
36 | H -1.487733 0.448778 -0.852129
37 | H -0.970713 0.463031 0.65099
38 | O -8.167161388575565 2.1289035370670355 0.044094007693886404
39 | H -8.367817388575565 1.7520255370670357 -0.8549559923061136
40 | H -8.870769388575566 1.7348755370670357 0.6456740076938864
41 | 6
42 |
43 | O -1.276934 -0.02905 -0.012972
44 | H -1.386544 0.562856 -0.773419
45 | H -1.313408 0.573499 0.729404
46 | O -8.333387448758744 2.6570453552258666 -0.15680694056552374
47 | H -8.504184448758744 2.1604503552258665 -0.8789999405655238
48 | H -8.205527448758744 2.0732593552258667 0.6219210594344762
49 | 6
50 |
51 | O -1.346976 -0.026594 0.039616
52 | H -1.366962 0.361552 -0.880903
53 | H -1.050459 0.579139 0.622652
54 | O -8.298008527645383 2.1785521398715555 -0.12868296149798286
55 | H -8.786513527645383 2.0197171398715557 -1.006903961497983
56 | H -8.712882527645382 1.7218061398715556 0.4903430385020171
57 | 6
58 |
59 | O -1.484872 0.02172 0.003656
60 | H -1.239773 0.471165 -0.757217
61 | H -0.848837 0.252188 0.742181
62 | O -8.328408842146587 2.093994952519581 0.00286879736356536
63 | H -8.469418842146588 1.5813689525195809 -0.7588772026364345
64 | H -8.858521842146587 1.799968952519581 0.7426337973635654
65 | 6
66 |
67 | O -1.633346 0.025042 0.009668
68 | H -0.899352 0.394495 -0.649576
69 | H -1.374678 0.397302 0.850931
70 | O -8.181342937068466 2.116557378592031 0.3702035727861667
71 | H -8.303163937068465 1.5629343785920309 -0.3840154272138333
72 | H -8.759776937068466 1.752001378592031 1.1194335727861668
73 | 6
74 |
75 | O 0.004454 0.09803 1.583859
76 | H 0.74712 -0.146956 0.971211
77 | H -0.740049 -0.307239 0.965109
78 | O -0.10757567447600846 -0.45437469214350495 8.539116526214325
79 | H -0.09577867447600846 -1.187761692143505 7.925768526214325
80 | H 0.06139832552399152 0.32860630785649503 7.994576526214325
81 |
--------------------------------------------------------------------------------
/mkdocs.yaml:
--------------------------------------------------------------------------------
1 | site_name: "SALTED: Symmetry-Adapted Learning of Three-dimensional Electron Densities"
2 |
3 | theme:
4 | name: readthedocs
5 | highlightjs: true
6 | # logo: assets/SALTED_icon_vanilla_long.png
7 | # favicon: assets/SALTED_icon_vanilla_long.png
8 |
9 | site_url: https://github.com/andreagrisafi/SALTED
10 |
11 | nav:
12 | - Home: index.md
13 | - Installation: installation.md
14 | - Theory: theory.md
15 | - Workflow: workflow.md
16 | - Input: input.md
17 | - Tutorial:
18 | - Part 1 - Dataset: tutorial/dataset.md
19 | - Part 2 - Training: tutorial/training.md
20 | # - Part 3 - Predict Properties: tutorial/predict.md
21 | # - Examples:
22 | # - Example 1 - Water & PySCF: examples/water_pyscf.md
23 | # - Example 2 - Water & FHI-aims: examples/water_aims.md
24 | # - Example 3 - Au slab & CP2K: examples/au_cp2k.md
25 | - API: api.md
26 |
27 | plugins:
28 | - search
29 | - mkdocstrings:
30 | handlers:
31 | # See: https://mkdocstrings.github.io/python/usage/
32 | python:
33 | options:
34 | docstring_style: google
35 | show_root_heading: true
36 | show_source: false
37 |
38 | markdown_extensions:
39 | - markdown_include.include:
40 | base_path: .
41 | - admonition
42 | - pymdownx.arithmatex:
43 | generic: true
44 | - pymdownx.superfences
45 | - attr_list
46 | - footnotes
47 | - md_in_html
48 | - pymdownx.details
49 | - pymdownx.snippets
50 |
51 | extra_javascript:
52 | - javascripts/mathjax.js # mathjax support
53 | - https://polyfill.io/v3/polyfill.min.js?features=es6
54 | - https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js
55 |
56 | extra_css:
57 | - stylesheets/extra.css
58 |
--------------------------------------------------------------------------------
/salted/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/salted/__init__.py
--------------------------------------------------------------------------------
/salted/aims/_deprecated_/get_basis_info_deprecated.py:
--------------------------------------------------------------------------------
1 | import os
2 | import os.path as osp
3 |
4 | import numpy as np
5 | from ase.io import read
6 |
7 | from salted import basis
8 | import inp
9 |
10 | # read species
11 | spelist = inp.species
12 |
13 | xyzfile = read(inp.filename,":")
14 |
15 | done_list = []
16 |
17 | dirpath = osp.join(inp.path2qm, 'data')
18 |
19 | afname = basis.__file__
20 |
21 | n_list = {}
22 | l_list = {}
23 | for iconf in range(len(xyzfile)):
24 | natoms = len(xyzfile[iconf])
25 | atomic_symbols = xyzfile[iconf].get_chemical_symbols()
26 | for iat in range(natoms):
27 | spe = atomic_symbols[iat]
28 | if spe not in done_list:
29 | f = open(osp.join(dirpath, str(iconf+1), 'basis_info.out'))
30 | l = 0
31 | while True:
32 | line = f.readline()
33 | if not line:
34 | f.close()
35 | break
36 |
37 | line = line.split()
38 |
39 | if line[0] == 'atom' and int(line[1])-1 == iat:
40 | read_atom = True
41 | continue
42 |
43 | if line[1] == 'atom' and int(line[2])-1 == iat:
44 | read_atom = False
45 | l_list[spe] = l
46 | f.close()
47 | break
48 |
49 | if read_atom:
50 | n_list[spe,l] = int(line[6])
51 | l += 1
52 |
53 |
54 | done_list.append(spe)
55 | if sorted(done_list) == sorted(spelist):
56 | f = open('new_basis_entry','w+')
57 | g = open(afname,'a')
58 | f.write(' if basis=="'+inp.dfbasis+'":\n\n')
59 | g.write(' if basis=="'+inp.dfbasis+'":\n\n')
60 | for spe in spelist:
61 | f.write(' lmax["'+spe+'"] = '+str(l_list[spe]-1)+'\n')
62 | g.write(' lmax["'+spe+'"] = '+str(l_list[spe]-1)+'\n')
63 | f.write('\n')
64 | g.write('\n')
65 | for spe in spelist:
66 | for l in range(l_list[spe]):
67 | f.write(' nmax[("'+spe+'",'+str(l)+')] = '+str(n_list[spe,l])+'\n')
68 | g.write(' nmax[("'+spe+'",'+str(l)+')] = '+str(n_list[spe,l])+'\n')
69 | f.write('\n')
70 | g.write('\n')
71 | f.write(' return [lmax,nmax]\n\n')
72 | g.write(' return [lmax,nmax]\n\n')
73 |
74 | f.close()
75 | g.close()
76 | exit
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/salted/aims/collect_energies.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | import numpy as np
5 |
6 | from salted.sys_utils import ParseConfig
7 | inp = ParseConfig().parse_input()
8 |
9 | dn = os.path.join(inp.qm.path2qm, inp.prediction.predict_data)
10 | l = os.listdir(os.path.join(dn, "geoms"))
11 | nfiles = len(l)
12 | testset = list(range(nfiles))
13 | testset = [x+1 for x in testset]
14 |
15 | es = []
16 | xcs = []
17 | eles = []
18 | n_atoms = []
19 |
20 |
21 | for k,i in enumerate(testset):
22 | e = []
23 | xc = []
24 | har = []
25 | ele = []
26 | dirn = os.path.join(dn, str(i))
27 |
28 | f1 = open(os.path.join(dirn, 'aims.out'))
29 | for line in f1:
30 | if line.find('| Number of atoms') != -1:
31 | n_atoms.append(line.split()[5])
32 | elif line.find('| Electrostatic energy') != -1:
33 | ele.append(line.split()[6])
34 | elif line.find('XC energy correction') != -1:
35 | xc.append(line.split()[7])
36 | elif line.find('| Electronic free energy per atom') != -1:
37 | e.append(line.split()[7])
38 | else:
39 | continue
40 |
41 | f1 = open(os.path.join(dirn, 'aims_predict.out'))
42 | for line in f1:
43 | if line.find('| Electrostatic energy') != -1:
44 | ele.append(line.split()[6])
45 | elif line.find('XC energy correction') != -1:
46 | xc.append(line.split()[7])
47 | elif line.find('| Electronic free energy per atom') != -1:
48 | e.append(line.split()[7])
49 | else:
50 | continue
51 |
52 | es.append([])
53 | xcs.append([])
54 | eles.append([])
55 | es[k].append(e[-2])
56 | xcs[k].append(xc[-2])
57 | eles[k].append(ele[-2])
58 | es[k].append(e[-1])
59 | xcs[k].append(xc[-1])
60 | eles[k].append(ele[-1])
61 |
62 | es = np.array(es,dtype = float)
63 | xcs = np.array(xcs,dtype = float)
64 | eles = np.array(eles,dtype = float)
65 | n_atoms = np.array(n_atoms,dtype = float)
66 |
67 | for i in range(2):
68 | xcs[:,i] /= n_atoms
69 | eles[:,i] /= n_atoms
70 |
71 | np.savetxt('predict_reference_electrostatic_energy.dat',np.vstack([eles[:,1],eles[:,0]]).T)
72 | np.savetxt('predict_reference_xc_energy.dat',np.vstack([xcs[:,1],xcs[:,0]]).T)
73 | np.savetxt('predict_reference_total_energy.dat',np.vstack([es[:,1],es[:,0]]).T)
74 |
75 | print('Mean absolute errors (eV/atom):')
76 | print('Electrostatic energy:',np.average(np.abs(eles[:,1]-eles[:,0])))
77 | print('XC energy:',np.average(np.abs(xcs[:,1]-xcs[:,0])))
78 | print('Total energy:',np.average(np.abs(es[:,1]-es[:,0])))
79 |
--------------------------------------------------------------------------------
/salted/aims/get_basis_info.py:
--------------------------------------------------------------------------------
1 | """Translate basis info from FHI-aims calculation to SALTED basis info"""
2 | import os
3 | from typing import Dict, List
4 | from ase.io import read
5 |
6 | from salted.basis_client import (
7 | BasisClient,
8 | SpeciesBasisData,
9 | compare_species_basis_data,
10 | )
11 | from salted.get_basis_info import get_parser
12 | from salted.sys_utils import ParseConfig
13 |
14 |
15 | def build(dryrun: bool = False, force_overwrite: bool = False):
16 | """Scheme: parse all basis_info.out one by one,
17 | update the basis_data dict,
18 | and write to the database when all species are recorded.
19 | """
20 | inp = ParseConfig().parse_input()
21 | assert inp.qm.qmcode.lower() == "aims", f"{inp.qm.qmcode=}, but expected 'aims'"
22 |
23 | spe_set = set(inp.system.species)
24 | geoms_list = read(inp.system.filename, ":")
25 | qmdata_dpath = os.path.join(inp.qm.path2qm, "data")
26 | basis_data: Dict[str, SpeciesBasisData] = {} # hold all species basis data
27 |
28 | for iconf, geom in enumerate(geoms_list):
29 | """parse basis_info.out for this geometry"""
30 | basis_info_fpath = os.path.join(qmdata_dpath, str(iconf + 1), "basis_info.out")
31 | spe_basis_data_list = parse_file_basis_info(basis_info_fpath)
32 | chem_syms = geom.get_chemical_symbols()
33 | assert len(chem_syms) == len(
34 | spe_basis_data_list
35 | ), f"{len(chem_syms)=}, {len(spe_basis_data_list)=}, {basis_info_fpath=}"
36 | chem_syms_uniq_idxes = [chem_syms.index(spe) for spe in set(chem_syms)]
37 | chem_syms_uniq = [chem_syms[i] for i in chem_syms_uniq_idxes]
38 | spe_basis_data_list_uniq = [
39 | spe_basis_data_list[i] for i in chem_syms_uniq_idxes
40 | ]
41 |
42 | """update/compare basis data for each species"""
43 | for spe, spe_basis_data in zip(
44 | chem_syms_uniq, spe_basis_data_list_uniq, strict=True
45 | ):
46 | if spe not in basis_data.keys():
47 | basis_data[spe] = spe_basis_data
48 | else:
49 | if not compare_species_basis_data(basis_data[spe], spe_basis_data):
50 | raise ValueError(
51 | f"Species {spe} has inconsistent basis data: {basis_data[spe]} and {spe_basis_data}, "
52 | f"file: {basis_info_fpath}"
53 | )
54 |
55 | """check if all species are recorded"""
56 | if set(basis_data.keys()) == spe_set:
57 | break
58 |
59 | """double check if all species are recorded"""
60 | if set(basis_data.keys()) != spe_set:
61 | raise ValueError(
62 | f"Not all species are recorded: {basis_data.keys()} vs {spe_set}"
63 | )
64 |
65 | """write to the database"""
66 | if dryrun:
67 | print("Dryrun mode, not writing to the database")
68 | print(f"{basis_data=}")
69 | else:
70 | BasisClient().write(inp.qm.dfbasis, basis_data, force_overwrite)
71 |
72 |
73 | def parse_file_basis_info(basis_info_fpath: str) -> List[SpeciesBasisData]:
74 | """Parse basis_info.out by FHI-aims.
75 | Parse by str.strip().split().
76 |
77 | File example: (might have multiple atoms, has a space at the beginning of each line)
78 | ```text
79 | atom 1
80 | For L = 0 there are 9 radial functions
81 | For L = 1 there are 10 radial functions
82 | For L = 2 there are 9 radial functions
83 | For L = 3 there are 8 radial functions
84 | For L = 4 there are 6 radial functions
85 | For L = 5 there are 4 radial functions
86 | For atom 1 max L = 5
87 | ```
88 |
89 | Return: in the format of List[SpeciesBasisData]
90 | ```python
91 | [
92 | {
93 | "lmax": 5,
94 | "nmax": [9, 10, 9, 8, 6, 4],
95 | },
96 | ... # other atoms
97 | ]
98 | ```
99 | """
100 |
101 | with open(basis_info_fpath) as f:
102 | lines_raw = f.readlines()
103 | lines_raw = [i.strip().split() for i in lines_raw]
104 |
105 | """Step 1: further split the current list by the keyword `atom`"""
106 | boundary_1atom = [
107 | idx for idx, line in enumerate(lines_raw) if line[0] == "atom"
108 | ] + [len(lines_raw)]
109 | lines_by_atoms = [
110 | lines_raw[boundary_1atom[i] : boundary_1atom[i + 1]]
111 | for i in range(len(boundary_1atom) - 1)
112 | ]
113 | # if dryrun:
114 | # print(f"{boundary_1atom=}")
115 | # print(f"{lines_by_atoms=}")
116 |
117 | """Step 2: derive SpeciesBasisData and do some checks (to ensure the file is not corrupted)"""
118 | basis_data: List[SpeciesBasisData] = []
119 | for lines_atom in lines_by_atoms:
120 | err_msg = f"{basis_info_fpath=}, {lines_atom=}"
121 | assert lines_atom[0][0] == "atom", err_msg # check the first line
122 | assert lines_atom[-1][0] == "For", err_msg # check the last line
123 | assert (
124 | len(lines_atom) == int(lines_atom[-1][-1]) + 3
125 | ), err_msg # check the number of lines
126 | basis_spe_data = {
127 | "lmax": int(lines_atom[-1][-1]),
128 | "nmax": [int(i[6]) for i in lines_atom[1:-1]],
129 | }
130 | assert (
131 | len(basis_spe_data["nmax"]) == basis_spe_data["lmax"] + 1
132 | ), f"{basis_info_fpath=}, {basis_spe_data=}"
133 | basis_data.append(basis_spe_data)
134 |
135 | return basis_data
136 |
137 |
138 | if __name__ == "__main__":
139 | print("Please call `python -m salted.get_basis_info` instead of this file")
140 |
141 | parser = get_parser()
142 | args = parser.parse_args()
143 |
144 | build(dryrun=args.dryrun, force_overwrite=args.force_overwrite)
145 |
--------------------------------------------------------------------------------
/salted/aims/get_df_err.py:
--------------------------------------------------------------------------------
1 | """
2 | Compare the density from DF and from SCF, output the real space electron density MAE
3 | TODO: parallelize the comparison code
4 | """
5 |
6 | import time
7 | import sys
8 | import os.path as osp
9 |
10 | import numpy as np
11 |
12 | from salted.sys_utils import ParseConfig, read_system, sort_grid_data
13 |
14 | def main():
15 | inp = ParseConfig().parse_input()
16 | spelist, lmax, nmax, llmax, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
17 |
18 | start_time = time.time()
19 |
20 | dirname = osp.join(inp.qm.path2qm, 'data')
21 | av_err = 0
22 | errs = np.zeros(ndata)
23 | g = open(osp.join(inp.salted.saltedpath, 'df_maes'),'w+') # stay in salted dir
24 | for i in range(1,ndata+1):
25 | dirn = osp.join(dirname, str(i))
26 | # f = open(dirn+'rho_scf.out')
27 | # r_con = [float(line.split()[-1]) for line in f]
28 | # f = open(dirn+'rho_df.out')
29 | # r_ri = [float(line.split()[-1]) for line in f]
30 | # f = open(dirn+'partition_tab.out')
31 | # part = [float(line.split()[-1]) for line in f]
32 |
33 | r_con = np.loadtxt(osp.join(dirn, 'rho_scf.out'))
34 | r_ri = np.loadtxt(osp.join(dirn, 'rho_df.out'))
35 | part = np.loadtxt(osp.join(dirn, 'partition_tab.out'))
36 | # print("before sort by coord")
37 | # print(i, np.allclose(r_ri[:,:3], r_con[:,:3]), np.allclose(r_ri[:,:3], part[:,:3]))
38 | # print(i, np.linalg.norm(r_ri[:,:3] - r_con[:,:3]), np.linalg.norm(r_ri[:,:3] - part[:,:3]))
39 | r_con = sort_grid_data(r_con)
40 | r_ri = sort_grid_data(r_ri)
41 | part = sort_grid_data(part)
42 | # r_con.view('f8,f8,f8,f8').sort(order=['f0','f1','f2'],axis = 0)
43 | # r_ri.view('f8,f8,f8,f8').sort(order=['f0','f1','f2'],axis = 0)
44 | # part.view('f8,f8,f8,f8').sort(order=['f0','f1','f2'],axis = 0)
45 | # print("after sort by coord")
46 | # print(i, np.allclose(r_ri[:,:3], r_con[:,:3]), np.allclose(r_ri[:,:3], part[:,:3]))
47 | # print(i, np.linalg.norm(r_ri[:,:3] - r_con[:,:3]), np.linalg.norm(r_ri[:,:3] - part[:,:3]))
48 |
49 | err = np.abs(r_ri[:,3]-r_con[:,3])
50 | norm = np.dot(r_con[:,3],part[:,3])
51 | int_err = np.dot(err,part[:,3])*100/norm
52 | errs[i-1] = int_err
53 | g.write(str(i)+' '+str(int_err)+'\n')
54 | g.flush()
55 |
56 | g.close()
57 | av_err = np.average(errs)
58 | sem = np.std(errs)/np.sqrt(ndata)
59 |
60 | print('% MAE =', av_err)
61 | end_time = time.time()
62 | print(f"time_cost = {end_time - start_time:.2f} s")
63 |
64 | if __name__ == '__main__':
65 | main()
66 |
--------------------------------------------------------------------------------
/salted/aims/get_ml_err.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import sys
4 | import os.path as osp
5 |
6 | import numpy as np
7 |
8 | from salted.sys_utils import ParseConfig, sort_grid_data, read_system
9 |
10 |
11 | def main():
12 | inp = ParseConfig().parse_input()
13 | spelist, lmax, nmax, llmax, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
14 |
15 | start_time = time.time()
16 |
17 | dirname = osp.join(inp.qm.path2qm, inp.prediction.predict_data)
18 | av_err = 0
19 | errs = np.zeros(ndata)
20 | g = open('ml_maes', 'w+')
21 | for i in range(1,ndata+1):
22 | dirn = osp.join(dirname, str(i))
23 | # f = open(dirn+'rho_scf.out')
24 | # r_con = [float(line.split()[-1]) for line in f]
25 | # f = open(dirn+'rho_df.out')
26 | # r_ri = [float(line.split()[-1]) for line in f]
27 | # f = open(dirn+'partition_tab.out')
28 | # part = [float(line.split()[-1]) for line in f]
29 |
30 | r_con = np.loadtxt(osp.join(dirn, 'rho_scf.out'))
31 | r_ri = np.loadtxt(osp.join(dirn, 'rho_ml.out'))
32 | part = np.loadtxt(osp.join(dirn, 'partition_tab.out'))
33 | # r_con.view('f8,f8,f8,f8').sort(order=['f0','f1','f2'],axis = 0)
34 | # r_ri.view('f8,f8,f8,f8').sort(order=['f0','f1','f2'],axis = 0)
35 | # part.view('f8,f8,f8,f8').sort(order=['f0','f1','f2'],axis = 0)
36 | r_con = sort_grid_data(r_con)
37 | r_ri = sort_grid_data(r_ri)
38 | part = sort_grid_data(part)
39 |
40 | err = np.abs(r_ri[:,3]-r_con[:,3])
41 | norm = np.dot(r_con[:,3],part[:,3])
42 | int_err = np.dot(err,part[:,3])*100/norm
43 | errs[i-1] = int_err
44 | g.write(str(i)+' '+str(int_err)+'\n')
45 | g.flush()
46 |
47 | g.close()
48 | av_err = np.average(errs)
49 | sem = np.std(errs)/np.sqrt(ndata)
50 |
51 | print('% MAE =', av_err)
52 | end_time = time.time()
53 | print(f"time_cost = {end_time - start_time:.2f} s")
54 |
55 | main()
56 |
--------------------------------------------------------------------------------
/salted/aims/make_geoms.py:
--------------------------------------------------------------------------------
1 | import os
2 | import argparse
3 | import os.path as osp
4 |
5 | from ase.io import read, write
6 |
7 | from salted.sys_utils import ParseConfig
8 | inp = ParseConfig().parse_input()
9 |
10 | def add_command_line_arguments_contraction():
11 | parser = argparse.ArgumentParser()
12 | parser.add_argument("-pr", "--predict", action='store_true', help="Prepare geometries for a true prediction")
13 | args = parser.parse_args()
14 | return args
15 |
16 | args = add_command_line_arguments_contraction()
17 | predict = args.predict
18 |
19 | if predict:
20 | datadir = inp.prediction.predict_data
21 | fname = inp.prediction.filename
22 | else:
23 | datadir = "data/"
24 | fname = inp.system.filename
25 |
26 | dirpath = osp.join(inp.qm.path2qm, datadir, "geoms")
27 | if not osp.exists(dirpath):
28 | os.makedirs(dirpath)
29 |
30 | xyz_file = read(fname,":")
31 | n = len(xyz_file)
32 | for i in range(n):
33 | write(osp.join(dirpath, f"{i+1}.in"), xyz_file[i])
34 |
--------------------------------------------------------------------------------
/salted/aims/move_data.py:
--------------------------------------------------------------------------------
1 | import os
2 | import os.path as osp
3 |
4 | import numpy as np
5 | from ase.io import read
6 | from salted.sys_utils import ParseConfig, get_conf_range
7 |
8 | def build():
9 | inp = ParseConfig().parse_input()
10 |
11 | if inp.system.parallel:
12 | from mpi4py import MPI
13 | # MPI information
14 | comm = MPI.COMM_WORLD
15 | size = comm.Get_size()
16 | rank = comm.Get_rank()
17 | print('This is task',rank+1,'of',size,flush=True)
18 | else:
19 | rank = 0
20 | size = 1
21 |
22 | if (rank == 0):
23 | """check if all subdirectories exist, if not create them"""
24 | sub_dirs = [
25 | osp.join(inp.salted.saltedpath, d)
26 | for d in ("overlaps", "coefficients", "projections")
27 | ]
28 | for sub_dir in sub_dirs:
29 | if not osp.exists(sub_dir):
30 | os.mkdir(sub_dir)
31 |
32 | xyzfile = read(inp.system.filename,":")
33 | ndata = len(xyzfile)
34 |
35 | # Distribute structures to tasks
36 | if inp.system.parallel:
37 | conf_range = get_conf_range(rank,size,ndata,list(range(ndata)))
38 | conf_range = comm.scatter(conf_range,root=0)
39 | else:
40 | conf_range = list(range(ndata))
41 |
42 | def get_reorder_bool(dirpath):
43 | """Determine the version of FHI-aims used.
44 | If a version newer than 240403, coefficients are
45 | internally reordered on input/output, and the
46 | SALTED helper functions should not also reorder coefficients.
47 |
48 | Args:
49 | dirpath (string): directory containing AIMS outputs
50 | Returns:
51 | boolean: whether SALTED helper functions should reorder
52 | """
53 |
54 | with open(osp.join(dirpath,'aims.out'),'r') as afile:
55 | for i,line in enumerate(afile):
56 | if i == 51:
57 | if line.split()[:2] == ['FHI-aims','version']:
58 | if int(line.split()[-1]) >= 240403:
59 | reorder = False
60 | else:
61 | reorder = True
62 | return reorder
63 | else:
64 | print('The aims.out file does not have the FHI-aims version listed on line 52 as expected')
65 | break
66 | elif i > 51:
67 | print('The aims.out file does not have the FHI-aims version listed on line 52 as expected')
68 | break
69 | else:
70 | print('The aims.out is very short; FHI-aims has not executed properly')
71 |
72 | for i in conf_range:
73 |
74 | dirpath = osp.join(inp.qm.path2qm, 'data', str(i+1))
75 | reorder = get_reorder_bool(dirpath)
76 |
77 | o = np.loadtxt(osp.join(dirpath, 'ri_projections.out')).reshape(-1)
78 | t = np.loadtxt(osp.join(dirpath, 'ri_restart_coeffs_df.out')).reshape(-1)
79 | ovlp = np.loadtxt(osp.join(dirpath, 'ri_ovlp.out')).reshape(-1)
80 |
81 | n = len(o)
82 | ovlp = ovlp.reshape(n,n)
83 |
84 | if reorder:
85 | idx = np.loadtxt(osp.join(dirpath, 'idx_prodbas.out')).astype(int)
86 | cs_list = np.loadtxt(osp.join(dirpath, 'prodbas_condon_shotley_list.out')).astype(int)
87 | idx -= 1
88 | cs_list -= 1
89 | idx = list(idx)
90 | cs_list = list(cs_list)
91 |
92 |
93 | for j in cs_list:
94 | ovlp[j,:] *= -1
95 | ovlp[:,j] *= -1
96 | o[j] *= -1
97 | t[j] *= -1
98 |
99 | o = o[idx]
100 | t = t[idx]
101 | ovlp = ovlp[idx,:]
102 | ovlp = ovlp[:,idx]
103 |
104 | np.save(osp.join(inp.salted.saltedpath, "overlaps", f"overlap_conf{i}.npy"), ovlp)
105 | np.save(osp.join(inp.salted.saltedpath, "projections", f"projections_conf{i}.npy"), o)
106 | np.save(osp.join(inp.salted.saltedpath, "coefficients", f"coefficients_conf{i}.npy"), t)
107 |
108 | if size > 1: comm.Barrier()
109 |
110 | """delte ri basis overlap and proj coeffs files"""
111 |
112 | for i in conf_range:
113 | dirpath = osp.join(inp.qm.path2qm, 'data', str(i+1))
114 | os.remove(osp.join(dirpath, 'ri_ovlp.out'))
115 | os.remove(osp.join(dirpath, 'ri_projections.out'))
116 |
117 | if __name__ == "__main__":
118 | build()
119 |
--------------------------------------------------------------------------------
/salted/aims/move_data_in.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | import numpy as np
5 |
6 | from salted.sys_utils import ParseConfig, get_conf_range, read_system
7 |
8 |
9 | def build():
10 | inp = ParseConfig().parse_input()
11 |
12 | if inp.system.parallel:
13 | from mpi4py import MPI
14 | # MPI information
15 | comm = MPI.COMM_WORLD
16 | size = comm.Get_size()
17 | rank = comm.Get_rank()
18 | print('This is task',rank+1,'of',size,flush=True)
19 | else:
20 | rank = 0
21 | size = 1
22 |
23 | if rank == 0: print("WARNING! This script assumes you will use an AIMS version >= 240403 to read the predicted RI coefficients. If this is not true, please use move_data_in_reorder instead.")
24 |
25 | species, lmax, nmax, lmax_max, nnmax, ndata, atomic_symbols, natoms, natmax = read_system(filename=inp.prediction.filename,spelist = inp.system.species, dfbasis = inp.qm.dfbasis)
26 |
27 | pdir = f"predictions_{inp.salted.saltedname}_{inp.prediction.predname}"
28 |
29 | ntrain = int(inp.gpr.trainfrac*inp.gpr.Ntrain)
30 |
31 | # Distribute structures to tasks
32 | if inp.system.parallel:
33 | conf_range = get_conf_range(rank,size,ndata,list(range(ndata)))
34 | conf_range = comm.scatter(conf_range,root=0)
35 | else:
36 | conf_range = list(range(ndata))
37 |
38 | for i in conf_range:
39 | print(f"processing {i+1}/{ndata} frame")
40 | t = np.loadtxt(os.path.join(
41 | inp.salted.saltedpath, pdir,
42 | f"M{inp.gpr.Menv}_zeta{inp.gpr.z}", f"N{ntrain}_reg{int(np.log10(inp.gpr.regul))}",
43 | f"COEFFS-{i+1}.dat",
44 | ))
45 | n = len(t)
46 |
47 | dirpath = os.path.join(inp.qm.path2qm, inp.prediction.predict_data, f"{i+1}")
48 | if not os.path.exists(dirpath):
49 | os.makedirs(dirpath, exist_ok=True)
50 |
51 | np.savetxt(os.path.join(dirpath, f"ri_restart_coeffs_predicted.out"), t)
52 |
53 | if __name__ == "__main__":
54 | build()
55 |
--------------------------------------------------------------------------------
/salted/aims/move_data_in_reorder.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | import numpy as np
5 | from salted.sys_utils import ParseConfig, read_system, get_conf_range
6 |
7 | def build():
8 | inp = ParseConfig().parse_input()
9 |
10 | print("WARNING! This script assumes you will use an AIMS version < 240403 to read the predicted RI coefficients. If this is not true, please use move_data_in instead.")
11 |
12 | if inp.system.parallel:
13 | from mpi4py import MPI
14 | # MPI information
15 | comm = MPI.COMM_WORLD
16 | size = comm.Get_size()
17 | rank = comm.Get_rank()
18 | print('This is task',rank+1,'of',size,flush=True)
19 | else:
20 | rank = 0
21 | size = 1
22 |
23 | species, lmax, nmax, lmax_max, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
24 |
25 | pdir = f"predictions_{inp.salted.saltedname}_{inp.prediction.predname}"
26 |
27 | ntrain = int(inp.gpr.trainfrac * inp.gpr.Ntrain)
28 |
29 | # Distribute structures to tasks
30 | if inp.system.parallel:
31 | conf_range = get_conf_range(rank,size,ndata,list(range(ndata)))
32 | conf_range = comm.scatter(conf_range,root=0)
33 | else:
34 | conf_range = list(range(ndata))
35 |
36 | for i in conf_range:
37 | print(f"processing {i+1}/{ndata} frame")
38 | t = np.load(os.path.join(
39 | inp.salted.saltedpath, pdir,
40 | f"M{inp.gpr.Menv}_zeta{inp.gpr.z}", f"N{ntrain}_reg{int(np.log10(inp.gpr.regul))}",
41 | f"prediction_conf{i}.npy",
42 | ))
43 | n = len(t)
44 |
45 | dirpath = os.path.join(inp.qm.path2qm, inp.prediction.predict_data, f"{i+1}")
46 |
47 | idx = np.loadtxt(os.path.join(dirpath, f"idx_prodbas.out")).astype(int)
48 | idx -= 1
49 |
50 | # accelerated method
51 | idx_rev = np.empty_like(idx)
52 | idx_rev[idx] = np.arange(len(idx))
53 |
54 | cs_list = np.loadtxt(os.path.join(
55 | dirpath, f"prodbas_condon_shotley_list.out"
56 | )).astype(int)
57 | cs_list -= 1
58 |
59 | # accelerated method
60 | t = t[idx_rev]
61 | t[cs_list] *= -1
62 |
63 | np.savetxt(os.path.join(dirpath, f"ri_restart_coeffs_predicted.out"), t)
64 |
65 | if __name__ == "__main__":
66 | build()
67 |
--------------------------------------------------------------------------------
/salted/basis.py:
--------------------------------------------------------------------------------
1 | from salted.basis_client import BasisClient
2 |
3 |
4 | def basiset(basis: str):
5 | """read basis data and return as the old format
6 |
7 | WARNING: Please use BasisClient() to read basis data instead of this function.
8 | See BasisClient docstring for more information.
9 |
10 | Return:
11 | (lmax, nmax), using the old format
12 |
13 | Old format:
14 | ```python
15 | lmax = {
16 | "H": 1,
17 | "O": 2,
18 | }
19 | nmax = {
20 | ("H", 0): 4,
21 | ("H", 1): 3,
22 | ("O", 0): 5,
23 | ("O", 1): 4,
24 | ("O", 2): 3,
25 | }
26 | ```
27 | """
28 | return BasisClient().read_as_old_format(basis) # use default basis data file
29 |
--------------------------------------------------------------------------------
/salted/cp2k/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/salted/cp2k/__init__.py
--------------------------------------------------------------------------------
/salted/cp2k/__pycache__/__init__.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/salted/cp2k/__pycache__/__init__.cpython-39.pyc
--------------------------------------------------------------------------------
/salted/cp2k/__pycache__/cp2k2salted.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/salted/cp2k/__pycache__/cp2k2salted.cpython-39.pyc
--------------------------------------------------------------------------------
/salted/cp2k/_deprecated_/alphas-cp2k.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import math
4 | import numpy as np
5 | from ase.io import read
6 | from itertools import islice
7 | import copy
8 | import argparse
9 | import ctypes
10 | import time
11 |
12 | from salted.sys_utils import ParseConfig
13 | inp = ParseConfig().parse_input()
14 |
15 | species = inp.system.species
16 |
17 | print("Reading AOs info...")
18 | laomax = {}
19 | naomax = {}
20 | npgf = {}
21 | aoalphas = {}
22 | contra = {}
23 | lmax = {}
24 | nmax = {}
25 | for spe in species:
26 | with open("BASIS_MOLOPT") as f:
27 | for line in f:
28 | if line.rstrip().split()[0] == spe and line.rstrip().split()[1] == inp.qm.qmbasis:
29 | line = list(islice(f, 2))[1]
30 | laomax[spe] = int(line.split()[2])
31 | npgf[spe] = int(line.split()[3])
32 | for l in range(laomax[spe]+1):
33 | naomax[(spe,l)] = int(line.split()[4+l])
34 | contra[(spe,l)] = np.zeros((naomax[(spe,l)],npgf[spe]))
35 | lines = list(islice(f, npgf[spe]))
36 | aoalphas[spe] = np.zeros(npgf[spe])
37 | for ipgf in range(npgf[spe]):
38 | line = lines[ipgf].split()
39 | aoalphas[spe][ipgf] = float(line[0])
40 | icount = 0
41 | for l in range(laomax[spe]+1):
42 | for n in range(naomax[(spe,l)]):
43 | contra[(spe,l)][n,ipgf] = line[1+icount]
44 | icount += 1
45 | break
46 | nalphas = npgf[spe]*3
47 | alphamin = min(aoalphas[spe])
48 | alphamax = max(aoalphas[spe])
49 | alphamin -= alphamin/3
50 | alphamax += alphamax/3
51 | r=(alphamax/alphamin)**(1.0/float(nalphas-1))
52 | alphas=np.zeros(nalphas)
53 | for i in range(nalphas):
54 | alphas[i] = 2*alphamin*r**i
55 | np.savetxt("alphas-"+str(spe)+".txt",-np.sort(-alphas))
56 |
--------------------------------------------------------------------------------
/salted/cp2k/_deprecated_/contracted/contract_coefs-cp2k.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import math
4 | import numpy as np
5 | from ase.io import read
6 | from scipy import special
7 | from itertools import islice
8 | from scipy.optimize import minimize
9 | import copy
10 | import argparse
11 | import time
12 |
13 | SALTEDPATHLIB = str(pathlib.Path(__file__).parent.resolve())+"/../"
14 | sys.path.append(SALTEDPATHLIB)
15 | import basis
16 |
17 | def add_command_line_arguments(parsetext):
18 | parser = argparse.ArgumentParser(description=parsetext,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
19 | parser.add_argument("-iconf", "--confidx", type=int, default=1, help="Structure index")
20 | args = parser.parse_args()
21 | return args
22 |
23 | def set_variable_values(args):
24 | iconf = args.confidx
25 | return iconf
26 |
27 | args = add_command_line_arguments("")
28 | iconf = set_variable_values(args)
29 |
30 | #print("conf", iconf)
31 | iconf -= 1 # 0-based indexing
32 |
33 | bohr2angs = 0.529177210670
34 |
35 | sys.path.insert(0, './')
36 | import inp
37 |
38 | xyzfile = read(inp.filename,":")
39 | ndata = len(xyzfile)
40 | species = inp.species
41 | [lmax,nmax] = basis.basiset(inp.dfbasis)
42 |
43 | # get basis set info from CP2K BASIS_LRIGPW_AUXMOLOPT
44 | alphas = {}
45 | sigmas = {}
46 | for spe in species:
47 | for l in range(lmax[spe]+1):
48 | avals = np.loadtxt(spe+"-"+inp.dfbasis+"-alphas-L"+str(l)+".dat")
49 | if nmax[(spe,l)]==1:
50 | alphas[(spe,l,0)] = float(avals)
51 | sigmas[(spe,l,0)] = np.sqrt(0.5/alphas[(spe,l,0)]) # bohr
52 | else:
53 | for n in range(nmax[(spe,l)]):
54 | alphas[(spe,l,n)] = avals[n]
55 | sigmas[(spe,l,n)] = np.sqrt(0.5/alphas[(spe,l,n)]) # bohr
56 |
57 | # init geometry
58 | geom = xyzfile[iconf]
59 | geom.wrap()
60 | symbols = geom.get_chemical_symbols()
61 | valences = geom.get_atomic_numbers()
62 | coords = geom.get_positions()/bohr2angs
63 | cell = geom.get_cell()/bohr2angs
64 | natoms = len(coords)
65 |
66 | projector = {}
67 | ncut = {}
68 | normfact = {}
69 | for spe in species:
70 | for l in range(lmax[spe]+1):
71 | projector[(spe,l)] = np.load("contractions/contra_spe"+str(spe)+"_l"+str(l)+".npy")
72 | ncut[(spe,l)] = projector[(spe,l)].shape[-1]
73 | normfact[(spe,l)] = np.zeros(nmax[(spe,l)])
74 | for n in range(nmax[(spe,l)]):
75 | inner = 0.5*special.gamma(l+1.5)*(sigmas[(spe,l,n)]**2)**(l+1.5)
76 | normfact[(spe,l)][n] = np.sqrt(inner)
77 |
78 | norm_projector = {}
79 | norm_primitive = {}
80 | nfact = {}
81 | for spe in species:
82 | for l in range(lmax[spe]+1):
83 | prefac = 2.0**l*(2.0/np.pi)**0.75
84 | expalpha = 0.25*float(2*l + 3)
85 | norm_projector[(spe,l)] = np.zeros((nmax[(spe,l)],ncut[(spe,l)]))
86 | norm_primitive[(spe,l)] = np.zeros(nmax[(spe,l)])
87 | for n in range(nmax[(spe,l)]):
88 | norm_primitive[(spe,l)][n] = 1.0/(prefac*alphas[(spe,l,n)]**expalpha)
89 | norm_projector[(spe,l)][n] = projector[(spe,l)][n] * prefac*alphas[(spe,l,n)]**expalpha
90 | nfact[(spe,l)] = np.zeros(ncut[(spe,l)])
91 | for n in range(ncut[(spe,l)]):
92 | nfact_temp = 0.0
93 | for ipgf1 in range(nmax[(spe,l)]):
94 | for ipgf2 in range(nmax[(spe,l)]):
95 | nfact_temp += norm_projector[(spe,l)][ipgf1,n] * norm_projector[(spe,l)][ipgf2,n] * 0.5 * special.gamma(l+1.5) / ( (alphas[(spe,l,ipgf1)] + alphas[(spe,l,ipgf2)])**(l+1.5) )
96 | nfact[(spe,l)][n] = np.sqrt(nfact_temp)
97 |
98 | aux_projs = np.loadtxt(inp.path2qm+"conf_"+str(iconf+1)+"/Au-RI_DENSITY_COEFFS.dat")
99 | #aux_projs = np.loadtxt(inp.path2qm+"conf_"+str(iconf+1)+"/efield/Au-RI_DENSITY_COEFFS.dat")
100 | print("starting dimension:",len(aux_projs))
101 |
102 | naux_proj = 0
103 | for iat in range(natoms):
104 | spe = symbols[iat]
105 | for l in range(lmax[spe]+1):
106 | naux_proj += ncut[(spe,l)]*(2*l+1)
107 | print("final dimension:",naux_proj,flush=True)
108 |
109 | # contract
110 | contr_proj = np.zeros(naux_proj)
111 | iaux = 0
112 | iaux_proj = 0
113 | for iat in range(natoms):
114 | spe = symbols[iat]
115 | for l in range(lmax[spe]+1):
116 | blocksize = nmax[(spe,l)]*(2*l+1)
117 | blocksize_proj = ncut[(spe,l)]*(2*l+1)
118 | proj_slice = aux_projs[iaux:iaux+blocksize].reshape(nmax[(spe,l)],2*l+1)
119 | contr_proj[iaux_proj:iaux_proj+blocksize_proj] = np.dot(projector[(spe,l)].T,proj_slice).reshape(blocksize_proj)
120 | iaux += blocksize
121 | iaux_proj += blocksize_proj
122 |
123 | # rescale for different CP2K normalization
124 | iaux = 0
125 | contra_coefs_renorm = np.zeros(naux_proj)
126 | for iat in range(natoms):
127 | spe = symbols[iat]
128 | for l in range(lmax[spe]+1):
129 | blocksize = ncut[(spe,l)]*(2*l+1)
130 | coefs_primit = np.einsum('a,ab->ab',norm_primitive[(spe,l)]/normfact[(spe,l)],np.dot(projector[(spe,l)],contr_proj[iaux:iaux+blocksize].reshape(ncut[(spe,l)],2*l+1)))
131 | contra_coefs_renorm[iaux:iaux+blocksize] = np.einsum('a,ab->ab',nfact[(spe,l)],np.dot(projector[(spe,l)].T,coefs_primit)).reshape(blocksize)
132 | iaux += blocksize
133 |
134 | np.savetxt(inp.path2qm+"conf_"+str(iconf+1)+"/Au-RI_DENSITY_COEFFS_CONTRACTED.dat",contra_coefs_renorm)
135 | #np.savetxt(inp.path2qm+"conf_"+str(iconf+1)+"/efield/Au-RI_DENSITY_COEFFS_CONTRACTED.dat",contra_coefs_renorm)
136 |
--------------------------------------------------------------------------------
/salted/cp2k/_deprecated_/contracted/contract_projs-cp2k.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import math
4 | import numpy as np
5 | from ase.io import read
6 | from scipy import special
7 | from itertools import islice
8 | from scipy.optimize import minimize
9 | import copy
10 | import argparse
11 | import time
12 |
13 | import basis
14 |
15 | def add_command_line_arguments(parsetext):
16 | parser = argparse.ArgumentParser(description=parsetext,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
17 | parser.add_argument("-iconf", "--confidx", type=int, default=1, help="Structure index")
18 | args = parser.parse_args()
19 | return args
20 |
21 | def set_variable_values(args):
22 | iconf = args.confidx
23 | return iconf
24 |
25 | args = add_command_line_arguments("")
26 | iconf = set_variable_values(args)
27 |
28 | #print("conf", iconf)
29 | iconf -= 1 # 0-based indexing
30 |
31 | bohr2angs = 0.529177210670
32 |
33 | sys.path.insert(0, './')
34 | import inp
35 |
36 | xyzfile = read(inp.filename,":")
37 | ndata = len(xyzfile)
38 | species = inp.species
39 | [lmax,nmax] = basis.basiset(inp.dfbasis)
40 |
41 | # get basis set info from CP2K BASIS_LRIGPW_AUXMOLOPT
42 | print("Reading auxiliary basis info...")
43 | alphas = {}
44 | sigmas = {}
45 | for spe in species:
46 | avals = np.loadtxt("alphas-"+str(spe)+".txt")
47 | for l in range(lmax[spe]+1):
48 | for n in range(nmax[(spe,l)]):
49 | alphas[(spe,l,n)] = avals[n]
50 | sigmas[(spe,l,n)] = np.sqrt(0.5/alphas[(spe,l,n)]) # bohr
51 |
52 | # init geometry
53 | geom = xyzfile[iconf]
54 | geom.wrap()
55 | symbols = geom.get_chemical_symbols()
56 | valences = geom.get_atomic_numbers()
57 | coords = geom.get_positions()/bohr2angs
58 | cell = geom.get_cell()/bohr2angs
59 | natoms = len(coords)
60 |
61 | aux_projs = np.load(inp.path2qm+inp.primprojdir+"projections_conf"+str(iconf)+".npy")
62 | print("starting dimension:",len(aux_projs))
63 |
64 | projector = {}
65 | ncut = {}
66 | for spe in species:
67 | for l in range(lmax[spe]+1):
68 | projector[(spe,l)] = np.load("contractions/contra_spe"+str(spe)+"_l"+str(l)+".npy")
69 | ncut[(spe,l)] = projector[(spe,l)].shape[-1]
70 |
71 | naux_proj = 0
72 | for iat in range(natoms):
73 | spe = symbols[iat]
74 | for l in range(lmax[spe]+1):
75 | naux_proj += ncut[(spe,l)]*(2*l+1)
76 | print("final dimension:",naux_proj,flush=True)
77 |
78 | # project overlap over most relevant radial channels
79 | contr_proj = np.zeros(naux_proj)
80 | iaux = 0
81 | iaux_proj = 0
82 | for iat in range(natoms):
83 | spe = symbols[iat]
84 | for l in range(lmax[spe]+1):
85 | blocksize = nmax[(spe,l)]*(2*l+1)
86 | blocksize_proj = ncut[(spe,l)]*(2*l+1)
87 | # contract projections
88 | proj_slice = aux_projs[iaux:iaux+blocksize].reshape(nmax[(spe,l)],2*l+1)
89 | contr_proj[iaux_proj:iaux_proj+blocksize_proj] = np.dot(projector[(spe,l)].T,proj_slice).reshape(blocksize_proj)
90 | iaux += blocksize
91 | iaux_proj += blocksize_proj
92 |
93 | dirpath = os.path.join(inp.path2qm, inp.projdir)
94 | if not os.path.exists(dirpath):
95 | os.mkdir(dirpath)
96 | np.save(inp.path2qm+inp.projdir+"projections_conf"+str(iconf)+".npy",contr_proj)
97 |
--------------------------------------------------------------------------------
/salted/cp2k/_deprecated_/contracted/get_contra-averages.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import numpy as np
3 | import time
4 | import ase
5 | from ase import io
6 | from ase.io import read
7 |
8 | import basis
9 | sys.path.insert(0, './')
10 | import inp
11 |
12 | # read species
13 | species = inp.species
14 |
15 | # read basis
16 | [lmax,nmax] = basis.basiset(inp.dfbasis)
17 |
18 |
19 | # read system
20 | xyzfile = read(inp.filename,":")
21 | ndata = len(xyzfile)
22 |
23 | #======================= system parameters
24 | atomic_symbols = []
25 | atomic_valence = []
26 | natoms = np.zeros(ndata,int)
27 | for i in range(len(xyzfile)):
28 | atomic_symbols.append(xyzfile[i].get_chemical_symbols())
29 | atomic_valence.append(xyzfile[i].get_atomic_numbers())
30 | natoms[i] = int(len(atomic_symbols[i]))
31 | natmax = max(natoms)
32 |
33 | projector = {}
34 | ncut = {}
35 | for spe in species:
36 | for l in range(lmax[spe]+1):
37 | projector[(spe,l)] = np.load("contractions/contra_spe"+str(spe)+"_l"+str(l)+".npy")
38 | ncut[(spe,l)] = projector[(spe,l)].shape[-1]
39 |
40 | avcoefs = {}
41 | nat_per_species = {}
42 | for spe in species:
43 | nat_per_species[spe] = 0
44 | avcoefs[spe] = np.zeros(nmax[(spe,0)],float)
45 |
46 | print("computing averages...")
47 | for iconf in range(ndata):
48 | atoms = atomic_symbols[iconf]
49 | coefs = np.load(inp.path2qm+"coefficients/coefficients_conf"+str(iconf)+".npy")
50 | i = 0
51 | for iat in range(natoms[iconf]):
52 | spe = atoms[iat]
53 | nat_per_species[spe] += 1
54 | for l in range(lmax[spe]+1):
55 | for n in range(ncut[(spe,l)]):
56 | for im in range(2*l+1):
57 | if l==0:
58 | avcoefs[spe][n] += coefs[i]
59 | i += 1
60 |
61 | for spe in species:
62 | avcoefs[spe] /= nat_per_species[spe]
63 | np.save("averages_"+str(spe)+".npy",avcoefs[spe])
64 |
--------------------------------------------------------------------------------
/salted/cp2k/_deprecated_/contracted/matrices-contracted.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import numpy as np
4 | import time
5 | import ase
6 | from ase import io
7 | from ase.io import read
8 | import random
9 | from random import shuffle
10 | from scipy import sparse
11 |
12 | import basis
13 |
14 | sys.path.insert(0, './')
15 | import inp
16 |
17 | # system definition
18 | spelist = inp.species
19 | xyzfile = read(inp.filename,":")
20 | ndata = len(xyzfile)
21 |
22 | # basis definition
23 | [lmax,nmax] = basis.basiset(inp.dfbasis)
24 |
25 | llist = []
26 | nlist = []
27 | for spe in spelist:
28 | llist.append(lmax[spe])
29 | for l in range(lmax[spe]+1):
30 | nlist.append(nmax[(spe,l)])
31 | llmax = max(llist)
32 | nnmax = max(nlist)
33 |
34 | # sparse-GPR parameters
35 | M = inp.Menv
36 | eigcut = inp.eigcut
37 | reg = inp.regul
38 |
39 | pdir = inp.preddir
40 | coefdir = inp.coefdir
41 | regrdir = inp.regrdir
42 | featdir = inp.featdir
43 |
44 | # species dependent arrays
45 | atoms_per_spe = {}
46 | natoms_per_spe = {}
47 | for iconf in range(ndata):
48 | for spe in spelist:
49 | atoms_per_spe[(iconf,spe)] = []
50 | natoms_per_spe[(iconf,spe)] = 0
51 |
52 | atomic_symbols = []
53 | valences = []
54 | natoms = np.zeros(ndata,int)
55 | for iconf in range(ndata):
56 | atomic_symbols.append(xyzfile[iconf].get_chemical_symbols())
57 | valences.append(xyzfile[iconf].get_atomic_numbers())
58 | natoms[iconf] = int(len(atomic_symbols[iconf]))
59 | for iat in range(natoms[iconf]):
60 | spe = atomic_symbols[iconf][iat]
61 | atoms_per_spe[(iconf,spe)].append(iat)
62 | natoms_per_spe[(iconf,spe)] += 1
63 | natmax = max(natoms)
64 |
65 | projector = {}
66 | ncut = {}
67 | for spe in spelist:
68 | for l in range(lmax[spe]+1):
69 | projector[(spe,l)] = np.load("contractions/contra_spe"+str(spe)+"_l"+str(l)+".npy")
70 | ncut[(spe,l)] = projector[(spe,l)].shape[-1]
71 |
72 | p = sparse.load_npz(inp.path2ml+featdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/psi-nm_conf0.npz")
73 | totsize = p.shape[-1]
74 | print("problem dimensionality:", totsize,flush=True)
75 | if totsize>70000:
76 | print("ERROR: problem dimension too large, minimize directly loss-function instead!")
77 | sys.exit(0)
78 |
79 | # load average density coefficients
80 | av_coefs = {}
81 | for spe in spelist:
82 | av_coefs[spe] = np.load("averages_"+str(spe)+".npy")
83 |
84 | # define training set at random
85 | dataset = list(range(ndata))
86 | #random.Random(3).shuffle(dataset)
87 | trainrangetot = dataset[:inp.Ntrain]
88 | np.savetxt("training_set_N"+str(inp.Ntrain)+".txt",trainrangetot,fmt='%i')
89 | #trainrangetot = np.loadtxt("training_set_upto443.txt",int)
90 | #trainrangetot = np.loadtxt("training_set_upto663.txt",int)
91 |
92 | # Distribute structures to tasks
93 | ntrain = int(inp.trainfrac*inp.Ntrain)
94 | trainrange = trainrangetot[:ntrain]
95 |
96 | dirpath = os.path.join(inp.path2ml, regrdir)
97 | if not os.path.exists(dirpath):
98 | os.mkdir(dirpath)
99 | dirpath = os.path.join(inp.path2ml+regrdir, "M"+str(M)+"_eigcut"+str(int(np.log10(eigcut))))
100 | if not os.path.exists(dirpath):
101 | os.mkdir(dirpath)
102 |
103 | print("computing regression matrices...")
104 | Avec = np.zeros(totsize)
105 | Bmat = np.zeros((totsize,totsize))
106 | #Avec = np.load(inp.path2ml+regrdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/Avec_N90.npy")*90
107 | #Bmat = np.load(inp.path2ml+regrdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/Bmat_N90.npy")*90
108 | for iconf in trainrange:
109 | print("conf:", iconf+1,flush=True)
110 |
111 | # load reference QM data
112 | ref_coefs = np.load(inp.path2qm+coefdir+"coefficients_conf"+str(iconf)+".npy")
113 | over = np.load(inp.path2qm+"overlaps/overlap_conf"+str(iconf)+".npy")
114 | psivec = sparse.load_npz(inp.path2ml+featdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/psi-nm_conf"+str(iconf)+".npz")
115 | psi = psivec.toarray()
116 |
117 | #TODO comment this to test learning of difference!
118 | Av_coeffs = np.zeros(ref_coefs.shape[0])
119 | i = 0
120 | for iat in range(natoms[iconf]):
121 | spe = atomic_symbols[iconf][iat]
122 | for l in range(lmax[spe]+1):
123 | for n in range(ncut[(spe,l)]):
124 | if l==0:
125 | Av_coeffs[i] = av_coefs[spe][n]
126 | i += 2*l+1
127 |
128 | ref_coefs -= Av_coeffs
129 | ref_projs = np.dot(over,ref_coefs)
130 |
131 | Avec += np.dot(psi.T,ref_projs)
132 | Bmat += np.dot(psi.T,np.dot(over,psi))
133 |
134 | if iconf+1==4 or iconf+1==8 or iconf+1==16 or iconf+1==32 or iconf+1==39:
135 | np.save(inp.path2ml+regrdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/Avec_N"+str(iconf+1)+".npy",Avec/float(iconf+1))
136 | np.save(inp.path2ml+regrdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/Bmat_N"+str(iconf+1)+".npy",Bmat/float(iconf+1))
137 |
138 | Avec /= float(ntrain)
139 | Bmat /= float(ntrain)
140 |
141 | np.save(inp.path2ml+regrdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/Avec_N"+str(ntrain)+".npy",Avec)
142 | np.save(inp.path2ml+regrdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/Bmat_N"+str(ntrain)+".npy",Bmat)
143 |
--------------------------------------------------------------------------------
/salted/cp2k/_deprecated_/contracted/rebuild_contra-projs.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import math
4 | import numpy as np
5 | from ase.io import read
6 | import copy
7 | import argparse
8 | import time
9 |
10 | import basis
11 |
12 | def add_command_line_arguments(parsetext):
13 | parser = argparse.ArgumentParser(description=parsetext,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
14 | parser.add_argument("-iconf", "--confidx", type=int, default=1, help="Structure index")
15 | args = parser.parse_args()
16 | return args
17 |
18 | def set_variable_values(args):
19 | iconf = args.confidx
20 | return [iconf]
21 |
22 | args = add_command_line_arguments("")
23 | [iconf] = set_variable_values(args)
24 |
25 | print("conf", iconf)
26 | iconf -= 1 # 0-based indexing
27 |
28 | sys.path.insert(0, './')
29 | import inp
30 |
31 | species = inp.species
32 |
33 | qmpath = inp.path2qm
34 |
35 | xyzfile = read(inp.filename,":")
36 | [lmax,nmax] = basis.basiset(inp.dfbasis)
37 |
38 | # init geometry
39 | geom = xyzfile[iconf]
40 | symbols = geom.get_chemical_symbols()
41 | natoms = len(symbols)
42 |
43 | # compute total number of auxiliary functions
44 | psize = 0
45 | for iat in range(natoms):
46 | spe = symbols[iat]
47 | for l in range(lmax[spe]+1):
48 | for n in range(nmax[(spe,l)]):
49 | psize += 2*l+1
50 |
51 |
52 | dirpath = os.path.join(qmpath, inp.projdir)
53 | if not os.path.exists(dirpath):
54 | os.mkdir(dirpath)
55 |
56 | projs = np.zeros(psize)
57 | i = 0
58 | for iat in range(natoms):
59 | projs_perat = np.load(qmpath+inp.projdir+"projections_conf"+str(iconf)+"_atom"+str(iat)+".npy")
60 | psize_perat = len(projs_perat)
61 | projs[i:i+psize_perat] = projs_perat
62 | i += psize_perat
63 |
64 | projector = {}
65 | ncut = {}
66 | for spe in species:
67 | for l in range(lmax[spe]+1):
68 | projector[(spe,l)] = np.load("contractions/contra_spe"+str(spe)+"_l"+str(l)+".npy")
69 | ncut[(spe,l)] = projector[(spe,l)].shape[-1]
70 |
71 | naux_proj = 0
72 | for iat in range(natoms):
73 | spe = symbols[iat]
74 | for l in range(lmax[spe]+1):
75 | naux_proj += ncut[(spe,l)]*(2*l+1)
76 |
77 | # project overlap over most relevant radial channels
78 | contr_proj = np.zeros(naux_proj)
79 | iaux = 0
80 | iaux_proj = 0
81 | for iat in range(natoms):
82 | spe = symbols[iat]
83 | for l in range(lmax[spe]+1):
84 | blocksize = nmax[(spe,l)]*(2*l+1)
85 | blocksize_proj = ncut[(spe,l)]*(2*l+1)
86 | # contract projections
87 | proj_slice = projs[iaux:iaux+blocksize].reshape(nmax[(spe,l)],2*l+1)
88 | contr_proj[iaux_proj:iaux_proj+blocksize_proj] = np.dot(projector[(spe,l)].T,proj_slice).reshape(blocksize_proj)
89 | iaux += blocksize
90 | iaux_proj += blocksize_proj
91 |
92 | np.save(qmpath+inp.projdir+"projections_conf"+str(iconf)+".npy",contr_proj)
93 |
--------------------------------------------------------------------------------
/salted/cp2k/cp2k2salted.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import math
4 | import numpy as np
5 | from ase.io import read
6 | from scipy import special
7 | from itertools import islice
8 | import copy
9 | import time
10 |
11 | from salted import basis
12 | from salted.sys_utils import ParseConfig, read_system, get_atom_idx, get_conf_range
13 |
14 | inp = ParseConfig().parse_input()
15 |
16 | xyzfile = read(inp.system.filename,":")
17 | ndata = len(xyzfile)
18 | species = inp.system.species
19 | [lmax,nmax] = basis.basiset(inp.qm.dfbasis)
20 |
21 | if inp.system.parallel:
22 |
23 | from mpi4py import MPI
24 | comm = MPI.COMM_WORLD
25 | size = comm.Get_size()
26 | rank = comm.Get_rank()
27 |
28 | if rank==0:
29 |
30 | dirpath = os.path.join(inp.salted.saltedpath, "coefficients")
31 | if not os.path.exists(dirpath):
32 | os.mkdir(dirpath)
33 |
34 | if inp.salted.saltedtype=="density-response":
35 | for icart in ["x","y","z"]:
36 | dirpath = os.path.join(inp.salted.saltedpath, "coefficients", f"{icart}")
37 | if not os.path.exists(dirpath):
38 | os.mkdir(dirpath)
39 |
40 |
41 | if inp.system.parallel:
42 |
43 | comm.Barrier()
44 |
45 | if ndata < size:
46 | if rank == 0:
47 | raise ValueError(
48 | f"More processes {size=} have been requested than confiturations {ndata=}. "
49 | f"Please reduce the number of processes."
50 | )
51 | else:
52 | exit()
53 | conf_range = get_conf_range(rank, size, ndata, np.arange(ndata,dtype=int))
54 | conf_range = comm.scatter(conf_range, root=0)
55 | print(
56 | f"Task {rank+1} handles the following configurations: {conf_range}", flush=True
57 | )
58 |
59 | else:
60 |
61 | conf_range = np.arange(ndata,dtype=int)
62 |
63 |
64 | # init geometry
65 | for iconf in conf_range:
66 |
67 | geom = xyzfile[iconf]
68 | symbols = geom.get_chemical_symbols()
69 | natoms = len(symbols)
70 | # compute basis set size
71 | nRI = 0
72 | for iat in range(natoms):
73 | spe = symbols[iat]
74 | if spe in species:
75 | for l in range(lmax[spe]+1):
76 | for n in range(nmax[(spe,l)]):
77 | nRI += 2*l+1
78 |
79 | print("conf", iconf+1, "size =", nRI, flush=True)
80 |
81 | # save overlap matrix in SALTED format
82 | overlap = np.zeros((nRI, nRI)).astype(np.double)
83 | for i in range(nRI):
84 | offset = 4 + i*((nRI+1)*8)
85 | overlap[:, i] = np.fromfile(os.path.join(
86 | inp.qm.path2qm, f"conf_{iconf+1}", inp.qm.ovlpfile
87 | ), dtype=np.float64, offset = offset, count=nRI)
88 |
89 | dirpath = os.path.join(inp.salted.saltedpath, "overlaps")
90 | if not os.path.exists(dirpath):
91 | os.mkdir(dirpath)
92 | np.save(os.path.join(inp.salted.saltedpath, "overlaps", f"overlap_conf{iconf}.npy"), overlap)
93 |
94 | if inp.salted.saltedtype=="density":
95 |
96 | # load density coefficients and check dimension
97 | coefficients = np.loadtxt(os.path.join(inp.qm.path2qm, f"conf_{iconf+1}", inp.qm.coeffile))
98 | if len(coefficients)!=nRI:
99 | print("ERROR: basis set size does not correspond to size of coefficients vector!")
100 | sys.exit(0)
101 |
102 | # save coefficients vector in SALTED format
103 | #if natoms%2 != 0:
104 | # coefficients = np.sum(coefficients,axis=1)
105 | np.save(os.path.join(inp.salted.saltedpath, "coefficients", f"coefficients_conf{iconf}.npy"), coefficients)
106 |
107 |
108 | elif inp.salted.saltedtype=="density-response":
109 |
110 | # load density-response coefficients and check dimension
111 | for icart in ["x","y","z"]:
112 | # Estimate derivative by finite differences applying an electric field of 0.01V/angs
113 | coefficients = np.loadtxt(os.path.join(inp.qm.path2qm, f"conf_{iconf+1}", f"{icart}_positive", inp.qm.coeffile))
114 | coefficients -= np.loadtxt(os.path.join(inp.qm.path2qm, f"conf_{iconf+1}", f"{icart}_negative", inp.qm.coeffile))
115 | coefficients /= (2*0.0001945) # 0.01 V/angs
116 | if len(coefficients)!=nRI:
117 | print("ERROR: basis set size does not correspond to size of coefficients vector!")
118 | sys.exit(0)
119 |
120 | # save coefficients vector in SALTED format
121 | np.save(os.path.join(inp.salted.saltedpath, "coefficients", f"{icart}", f"coefficients_conf{iconf}.npy"), coefficients)
122 |
123 | ## save projections vector in SALTED format
124 | #projections = np.dot(overlap,coefficients)
125 | #dirpath = os.path.join(inp.salted.saltedpath, "projections")
126 | #if not os.path.exists(dirpath):
127 | # os.mkdir(dirpath)
128 | #np.save(inp.salted.saltedpath+"projections/projections_conf"+str(iconf)+".npy",projections)
129 |
--------------------------------------------------------------------------------
/salted/cp2k/polarizability.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import time
4 | import os.path as osp
5 |
6 | import numpy as np
7 | from scipy import special
8 | from scipy import sparse
9 |
10 | from salted import basis
11 | from salted.sys_utils import ParseConfig, read_system, get_atom_idx, get_conf_range, init_property_file
12 | from salted.cp2k.utils import init_moments, compute_charge_and_dipole, compute_polarizability
13 |
14 | def build(iconf,ref_coefs):
15 | """Compute polarizability tensor for the given structure and related set of density-response coefficients."""
16 |
17 | inp = ParseConfig().parse_input()
18 | (saltedname, saltedpath, saltedtype,
19 | filename, species, average, parallel,
20 | path2qm, qmcode, qmbasis, dfbasis,
21 | filename_pred, predname, predict_data, alpha_only,
22 | rep1, rcut1, sig1, nrad1, nang1, neighspe1,
23 | rep2, rcut2, sig2, nrad2, nang2, neighspe2,
24 | sparsify, nsamples, ncut,
25 | zeta, Menv, Ntrain, trainfrac, regul, eigcut,
26 | gradtol, restart, blocksize, trainsel, nspe1, nspe2, HYPER_PARAMETERS_DENSITY, HYPER_PARAMETERS_POTENTIAL) = ParseConfig().get_all_params()
27 |
28 | species, lmax, nmax, lmax_max, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
29 |
30 | if qmcode=="cp2k":
31 | from ase.io import read
32 | xyzfile = read(filename, ":")
33 | # Initialize calculation of density/density-response moments
34 | charge_integrals,dipole_integrals = init_moments(inp,species,lmax,nmax,0)
35 |
36 | ref_alpha = compute_polarizability(xyzfile[iconf],natoms[iconf],atomic_symbols[iconf],lmax,nmax,species,charge_integrals,dipole_integrals,ref_coefs)
37 |
38 | # Save polarizabilities
39 | return ref_alpha
40 | #print(ref_alpha[("x","x")],ref_alpha[("x","y")],ref_alpha[("x","z")])
41 | #print(ref_alpha[("y","x")],ref_alpha[("y","y")],ref_alpha[("y","z")])
42 | #print(ref_alpha[("z","x")],ref_alpha[("z","y")],ref_alpha[("z","z")])
43 |
--------------------------------------------------------------------------------
/salted/cp2k/uncontract_ri_basis.py:
--------------------------------------------------------------------------------
1 | # Given a CP2K output file using an automatically generated RI HFX basis, this script produces a
2 | #CP2K basis set file containing a fully decontracted version of the same basis, for each element
3 |
4 | #usage:
5 | #python uncontract_ri_basis.py cp2k_output_file new_basis_set_file
6 |
7 | import sys
8 |
9 | #reading arguments
10 | cp2k_output = sys.argv[1]
11 | basis_file = sys.argv[2]
12 |
13 | #defining some helper functions
14 | def get_l_from_string(string):
15 | if "s" in string:
16 | return 0
17 | if "p" in string:
18 | return 1
19 | if "d" in string:
20 | return 2
21 | if "f" in string:
22 | return 3
23 | if "g" in string:
24 | return 4
25 | if "h" in string:
26 | return 5
27 | if "i" in string:
28 | return 6
29 | if "j" in string:
30 | return 7
31 | if "k" in string:
32 | return 8
33 | return "not a valid l quantum number"
34 |
35 | def get_set_exponents(kind, iset, lines):
36 | correct_kind = False
37 | correct_basis = False
38 | correct_set = False
39 |
40 | exps = []
41 | momenta = []
42 | for line in lines:
43 | if " Atomic kind: " in line:
44 | if line.split()[3] == kind:
45 | correct_kind = True
46 | else:
47 | correct_kind = False
48 |
49 | if "Basis Set " in line:
50 | if "RI HFX " in line:
51 | correct_basis = True
52 | if not "RI-AUX" in line:
53 | print("Warning: the script is meant to be used with automatically generated RI basis sets")
54 | else:
55 | correct_basis = False
56 |
57 | if len(line) == 1:
58 | correct_set = False
59 |
60 | if correct_kind and correct_basis and len(line) > 1:
61 | if line.split()[0] == str(iset):
62 | correct_set = True
63 | momenta.append(get_l_from_string(line.split()[2]))
64 |
65 | if correct_kind and correct_basis and correct_set:
66 | exps.append(line.split()[-2])
67 |
68 | if " Atomic covalent radius " in line:
69 | break
70 |
71 | #remove values appearing multiple times before return
72 | exps = [float(e) for e in dict.fromkeys(exps).keys()]
73 | momenta = [l for l in dict.fromkeys(momenta).keys()]
74 |
75 | return exps, momenta
76 |
77 | def get_kinds(lines):
78 | kinds = []
79 | for line in output_lines:
80 | if " Atomic kind: " in line:
81 | kinds.append(line.split()[3])
82 | return kinds
83 |
84 | def get_sets(lines):
85 | nsets = []
86 | for i, line in enumerate(output_lines):
87 | if " Number of orbital shell sets: " in line:
88 | if "RI HFX Basis Set" in output_lines[i-2]:
89 | nsets.append(int(line.split()[-1]))
90 | return nsets
91 |
92 |
93 | #reading the CP2K output file
94 | with open(cp2k_output, "r") as myfile:
95 | output_lines = myfile.readlines()
96 |
97 | #parse the number of atomic kinds
98 | kinds = get_kinds(output_lines)
99 | nkinds = len(kinds)
100 |
101 | #parse the number of sets per kind
102 | nsets = get_sets(output_lines)
103 |
104 | #printing to new basis set file
105 | with open(basis_file, "w") as myfile:
106 |
107 | for ikind, kind in enumerate(kinds):
108 |
109 | #get total number of basis functions for this kind
110 | nfunc = 0
111 | nset = nsets[ikind]
112 | for iset in range(1, nset + 1):
113 | exps, momenta = get_set_exponents(kind, iset, output_lines)
114 | nfunc += len(exps)*len(momenta)
115 |
116 | myfile.write("{} RI_AUTO_uncontracted\n".format(kind))
117 | myfile.write(" {}\n".format(nfunc))
118 |
119 | for iset in range(1, nset+1):
120 | exps, momenta = get_set_exponents(kind, iset, output_lines)
121 | nfunc += len(exps)*len(momenta)
122 | for l in momenta:
123 | for exp in exps:
124 | myfile.write(" 1 {} {} 1 1\n".format(l,l))
125 | myfile.write(" {:11.6f} 1.0\n".format(exp))
126 |
127 | myfile.write("\n")
128 |
129 |
--------------------------------------------------------------------------------
/salted/cp2k/xyz2sys.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import argparse
4 |
5 | from ase.io import read
6 |
7 | from salted.sys_utils import ParseConfig
8 |
9 | inp = ParseConfig().parse_input()
10 |
11 | filename = inp.system.filename
12 | path2qm = inp.qm.path2qm
13 | periodic = inp.qm.periodic
14 |
15 | xyz = read(filename, ":")
16 | ndata = len(xyz)
17 |
18 | if periodic=="0D":
19 | PERIODIC = "None"
20 | elif periodic=="2D":
21 | PERIODIC = "XY"
22 | elif periodic=="3D":
23 | PERIODIC = "XYZ"
24 |
25 | for iconf in range(ndata):
26 | dirpath = os.path.join(path2qm, "conf_"+str(iconf+1))
27 | if not os.path.exists(dirpath):
28 | os.mkdir(dirpath)
29 | symbol = xyz[iconf].get_chemical_symbols()
30 | coords = xyz[iconf].get_positions()
31 | natoms = len(coords)
32 | f = open(os.path.join(path2qm, f"conf_{iconf+1}", "coords.sys"), "w")
33 | print("&COORD",file=f)
34 | for iat in range(natoms):
35 | print(symbol[iat],coords[iat,0],coords[iat,1],coords[iat,2],file=f)
36 | print("&END COORD",file=f)
37 | f.close()
38 | cell = xyz[iconf].get_cell()
39 | f = open(os.path.join(path2qm, f"conf_{iconf+1}", "cell.sys"), "w")
40 | print("&CELL",file=f)
41 | print("PERIODIC "+str(PERIODIC),file=f)
42 | print("A",cell[0,0],cell[0,1],cell[0,2],file=f)
43 | print("B",cell[1,0],cell[1,1],cell[1,2],file=f)
44 | print("C",cell[2,0],cell[2,1],cell[2,2],file=f)
45 | print("&END CELL",file=f)
46 | f.close()
47 |
--------------------------------------------------------------------------------
/salted/efield.py:
--------------------------------------------------------------------------------
1 | import sys,os
2 | import numpy as np
3 | import scipy.special as sc
4 |
5 | def setup_orthomatrix(nmax,rc):
6 | """Compute orthogonalization matrix"""
7 |
8 | sigma = np.zeros(nmax,float)
9 | for i in range(nmax):
10 | sigma[i] = max(np.sqrt(float(i)),1.0)*(rc)/float(nmax)
11 |
12 | overlap = np.zeros((nmax,nmax),float)
13 | for n1 in range(nmax):
14 | for n2 in range(nmax):
15 | overlap[n1,n2] = (0.5/(sigma[n1])**2 + 0.5/(sigma[n2])**2)**(-0.5*(3.0 +n1 +n2)) \
16 | /(sigma[n1]**n1 * sigma[n2]**n2)*\
17 | sc.gamma(0.5*(3.0 + n1 + n2))/ ( \
18 | (sigma[n1]*sigma[n2])**1.5 * np.sqrt(sc.gamma(1.5+n1)*sc.gamma(1.5+n2)) )
19 |
20 | eigenvalues, unitary = np.linalg.eig(overlap)
21 | sqrteigen = np.sqrt(eigenvalues)
22 | diagoverlap = np.diag(sqrteigen)
23 | newoverlap = np.dot(np.conj(unitary),np.dot(diagoverlap,unitary.T))
24 | orthomatrix = np.linalg.inv(newoverlap)
25 |
26 | return [orthomatrix,sigma]
27 |
28 |
29 | def radint_efield(nmax,sigma):
30 | """Compute external field contribution to local potential"""
31 |
32 | # compute radial integrals int_0^\infty dr r^3 R_n(r)
33 | radint = np.zeros(nmax)
34 | for n in range(nmax):
35 | inner = 0.5*sc.gamma(n+1.5)*(sigma[n]**2)**(n+1.5)
36 | radint[n] = 2**float(1.0+float(n)/2.0) * sigma[n]**(4+n) * sc.gamma(2.0+float(n)/2.0) / np.sqrt(inner)
37 |
38 | return radint
39 |
40 | def get_efield_sph(nmax,rc):
41 | """Compute the SPH components (l=1, m=0) of a uniform and constant field aligned along Z"""
42 |
43 | [orthomatrix,sigma] = setup_orthomatrix(nmax,rc)
44 |
45 | radint = radint_efield(nmax,sigma)
46 |
47 | orthoradint = np.dot(orthomatrix,radint)
48 |
49 | efield_coef = np.zeros(nmax,complex)
50 | for n in range(nmax):
51 | efield_coef[n] = complex(np.sqrt(4.0*np.pi/3.0)*orthoradint[n],0.0)
52 |
53 | return efield_coef
54 |
--------------------------------------------------------------------------------
/salted/get_averages.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import numpy as np
4 | import os.path as osp
5 |
6 | from salted.sys_utils import ParseConfig, read_system
7 |
8 | def build():
9 |
10 | inp = ParseConfig().parse_input()
11 |
12 | spelist, lmax, nmax, llmax, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
13 |
14 | avcoefs = {}
15 | nat_per_species = {}
16 | for spe in spelist:
17 | nat_per_species[spe] = 0
18 | avcoefs[spe] = np.zeros(nmax[(spe,0)],float)
19 |
20 | print("computing averages...")
21 | for iconf in range(ndata):
22 | atoms = atomic_symbols[iconf]
23 | coefs = np.load(os.path.join(inp.salted.saltedpath, "coefficients", f"coefficients_conf{iconf}.npy"))
24 | i = 0
25 | for iat in range(natoms[iconf]):
26 | spe = atoms[iat]
27 | nat_per_species[spe] += 1
28 | for l in range(lmax[spe]+1):
29 | for n in range(nmax[(spe,l)]):
30 | for im in range(2*l+1):
31 | if l==0:
32 | avcoefs[spe][n] += coefs[i]
33 | i += 1
34 |
35 | adir = os.path.join(inp.salted.saltedpath, "coefficients", "averages")
36 | if not osp.exists(adir):
37 | os.mkdir(adir)
38 |
39 | for spe in spelist:
40 | avcoefs[spe] /= nat_per_species[spe]
41 | np.save(os.path.join(inp.salted.saltedpath, "coefficients", "averages", f"averages_{spe}.npy"), avcoefs[spe])
42 |
43 | return
44 |
45 | if __name__ == "__main__":
46 | build()
47 |
--------------------------------------------------------------------------------
/salted/get_basis_info.py:
--------------------------------------------------------------------------------
1 | """Translate density fitting basis info from FHI-aims / CP2K to SALTED density fitting basis info.
2 | This is just an entry point for the actual implementation.
3 | in salted/aims/get_basis_info.py and salted/cp2k/get_basis_info.py.
4 | """
5 |
6 | import argparse
7 | import sys
8 |
9 | from salted.sys_utils import ParseConfig
10 |
11 |
12 | def get_parser():
13 | parser = argparse.ArgumentParser()
14 | parser.add_argument(
15 | "--dryrun",
16 | action="store_true",
17 | help="run without writing to files, and print the result",
18 | )
19 | parser.add_argument(
20 | "--force_overwrite",
21 | action="store_true",
22 | help="force overwrite the existing basis data",
23 | )
24 | return parser
25 |
26 |
27 | if __name__ == "__main__":
28 | parser = get_parser()
29 | args = parser.parse_args()
30 |
31 | inp = ParseConfig().parse_input()
32 | if inp.qm.qmcode.lower() == "aims":
33 | from salted.aims.get_basis_info import build
34 | elif inp.qm.qmcode.lower() == "cp2k":
35 | from salted.cp2k.get_basis_info import build
36 | elif inp.qm.qmcode.lower() == "pyscf":
37 | from salted.pyscf.get_basis_info import build
38 | else:
39 | raise ValueError(f"Unknown qmcode: {inp.qm.qmcode}")
40 |
41 | build(dryrun=args.dryrun, force_overwrite=args.force_overwrite)
42 |
--------------------------------------------------------------------------------
/salted/init_pred.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import time
4 | import os.path as osp
5 |
6 | import h5py
7 | import numpy as np
8 | from scipy import special
9 |
10 | from salted import basis
11 | from salted.sys_utils import ParseConfig, get_feats_projs
12 |
13 | def build():
14 |
15 | inp = ParseConfig().parse_input()
16 |
17 | saltedname = inp.salted.saltedname
18 | saltedpath = inp.salted.saltedpath
19 | species = inp.system.species
20 | Menv = inp.gpr.Menv
21 | zeta = inp.gpr.z
22 | reg = inp.gpr.regul
23 | ncut = inp.descriptor.sparsify.ncut
24 | sparsify = True if inp.descriptor.sparsify.ncut > 0 else False
25 |
26 | # read basis
27 | [lmax,nmax] = basis.basiset(inp.qm.dfbasis)
28 | llist = []
29 | nlist = []
30 | for spe in species:
31 | llist.append(lmax[spe])
32 | for l in range(lmax[spe]+1):
33 | nlist.append(nmax[(spe,l)])
34 | lmax_max = max(llist)
35 |
36 | charge_integrals = {}
37 | if inp.qm.qmcode=="cp2k":
38 | # Initialize calculation of density/density-response moments
39 | from salted.cp2k.utils import init_moments
40 | charge_integrals,dipole_integrals = init_moments(inp,species,lmax,nmax,0)
41 |
42 | loadstart = time.time()
43 |
44 | # Load feature space sparsification information if required
45 | if sparsify:
46 | vfps = {}
47 | for lam in range(lmax_max+1):
48 | vfps[lam] = np.load(osp.join(
49 | saltedpath, f"equirepr_{saltedname}", f"fps{ncut}-{lam}.npy"
50 | ))
51 |
52 | # Load training feature vectors and RKHS projection matrix
53 | Vmat,Mspe,power_env_sparse = get_feats_projs(species,lmax)
54 |
55 | # load regression weights
56 | ntrain = int(inp.gpr.Ntrain*inp.gpr.trainfrac)
57 | weights = np.load(osp.join(
58 | saltedpath, f"regrdir_{saltedname}", f"M{Menv}_zeta{zeta}", f"weights_N{ntrain}_reg{int(np.log10(reg))}.npy"
59 | ))
60 |
61 | print("load time:", (time.time()-loadstart))
62 |
63 | return [lmax,nmax,lmax_max,weights,power_env_sparse,Mspe,Vmat,vfps,charge_integrals]
64 |
65 | if __name__ == "__main__":
66 | build()
67 |
--------------------------------------------------------------------------------
/salted/initialize.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import time
4 |
5 | from salted import wigner, sparsify_features, scalar_vector
6 | from salted.sys_utils import ParseConfig
7 |
8 |
9 | def build():
10 |
11 | inp = ParseConfig().parse_input()
12 | # check for destructive interactions
13 | if inp.system.average == True and inp.salted.saltedtype == "density-response":
14 | raise ValueError(
15 | "Invalid configuration: 'average' cannot be True when 'saltedtype' is 'density-response'. Please change your input settings."
16 | )
17 |
18 | # Precompute and save the required Wigner-3j symbols and Clebsch-Gordan, depending on SALTED target
19 | wigner.build()
20 |
21 | # Sparsify the feature space of symmetry-adapted descriptors?
22 | if inp.descriptor.sparsify.ncut > 0:
23 |
24 | if inp.salted.saltedtype == "density-response":
25 | print(
26 | "ERROR: feature space sparsification not allowed with inp.salted.saltedtype: density-response!"
27 | )
28 | sys.exit(0)
29 |
30 | # Precompute and save the feature space sparsification details
31 | sparsify_features.build()
32 |
33 | # Compute and save the sparsified scalar descriptor
34 | scalar_vector.build()
35 |
36 | else:
37 |
38 | # Compute and save the unsparsified scalar descriptor
39 | scalar_vector.build()
40 |
41 |
42 | if __name__ == "__main__":
43 | build()
44 |
--------------------------------------------------------------------------------
/salted/ortho/ortho_error.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import numpy as np
4 | import sys
5 |
6 | from sys_utils import read_system
7 |
8 | sys.path.insert(0, './')
9 | import inp
10 |
11 | spelist, lmax, nmax, llmax, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
12 |
13 | # number of sparse environments
14 | M = inp.Menv
15 | eigcut = inp.eigcut
16 |
17 | pdir = inp.valcdir
18 |
19 | # load predicted coefficients for test structures
20 | trainrangetot = np.loadtxt("training_set.txt",int)
21 | ntrain = int(inp.trainfrac*len(trainrangetot))
22 | testrange = np.setdiff1d(list(range(ndata)),trainrangetot)
23 | ntest = len(testrange)
24 | natoms_test = natoms[testrange]
25 |
26 | dirpath = os.path.join(inp.path2qm+pdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/","N_"+str(ntrain))
27 | if not os.path.exists(dirpath):
28 | os.mkdir(dirpath)
29 |
30 | ortho_coeffs = np.load(inp.path2qm+pdir+"M"+str(M)+"_eigcut"+str(int(np.log10(inp.eigcut)))+"/ortho-predictions_N"+str(ntrain)+"_reg"+str(int(np.log10(inp.regul)))+".npy")
31 |
32 | av_coefs = {}
33 | for spe in spelist:
34 | av_coefs[spe] = np.load("averages_"+str(spe)+".npy")
35 |
36 | itest=0
37 | Oerror_density = 0.0
38 | variance = 0.0
39 | preds = np.zeros((ntest,natmax,llmax+1,nnmax,2*llmax+1))
40 | for iconf in testrange:
41 | # print(iconf+1)
42 | start = time.time()
43 | atoms = atomic_symbols[iconf]
44 | #================================================
45 | projs_ref = np.load(inp.path2qm+inp.projdir+"projections_conf"+str(iconf)+".npy")
46 | coeffs_ref = np.load(inp.path2qm+inp.coefdir+"coefficients_conf"+str(iconf)+".npy")
47 | size_coeffs = coeffs_ref.shape
48 | # compute orthogonalization matrix
49 | orthomatrix = np.load(inp.path2qm+inp.ovlpdir+"orthomatrix_"+str(iconf)+".npy")
50 | OCoeffs = np.zeros(size_coeffs)
51 | i = 0
52 | for iat in range(natoms[iconf]):
53 | for l in range(lmax[atoms[iat]]+1):
54 | for n in range(nmax[(atoms[iat],l)]):
55 | for im in range(2*l+1):
56 | OCoeffs[i] = ortho_coeffs[itest,iat,l,n,im]
57 | i+=1
58 | OCoef = np.dot(orthomatrix,OCoeffs)
59 | #================================================
60 | coefficients = np.zeros(size_coeffs,float)
61 | averages = np.zeros(size_coeffs,float)
62 | icoeff = 0
63 | for iat in range(natoms[iconf]):
64 | for l in range(lmax[atoms[iat]]+1):
65 | for n in range(nmax[(atoms[iat],l)]):
66 | for im in range(2*l+1):
67 | if l==0:
68 | OCoef[icoeff] += av_coefs[atoms[iat]][n]
69 | averages[icoeff] = av_coefs[atoms[iat]][n]
70 | preds[itest,iat,l,n,im] = OCoef[icoeff]
71 | icoeff +=1
72 | np.save(inp.path2qm+pdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/N_"+str(ntrain)+"/prediction_conf"+str(iconf)+".npy",OCoef)
73 | overl = np.load(inp.path2qm+inp.ovlpdir+"overlap_conf"+str(iconf)+".npy")
74 | OProj = np.dot(overl,OCoef)
75 | #================================================
76 | Oerror = np.dot(OCoef-coeffs_ref,OProj-projs_ref)
77 | Oerror_density += Oerror
78 | projs_ref -= np.dot(overl,averages)
79 | coeffs_ref -= averages
80 | var = np.dot(coeffs_ref,projs_ref)
81 | variance += var
82 | print(iconf+1, ":", np.sqrt(Oerror/var)*100, "% RMSE",flush=True)
83 | # print("time:",time.time()-start)
84 | itest+=1
85 |
86 |
87 | print("% RMSE =", 100*np.sqrt(Oerror_density/variance))
88 | #np.save(inp.path2qm+pdir+"M"+str(M)+"_eigcut"+str(int(np.log10(inp.eigcut)))+"/pred-coeffs_N"+str(ntrain)+"_reg"+str(int(np.log10(inp.regul)))+".npy",preds)
89 |
--------------------------------------------------------------------------------
/salted/ortho/ortho_projections.py:
--------------------------------------------------------------------------------
1 | import os
2 | import numpy as np
3 | import time
4 | #import argparse
5 | import sys
6 | sys.path.insert(0, './')
7 | import inp
8 | from sys_utils import read_system, get_atom_idx
9 |
10 | spelist, lmax, nmax, llmax, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
11 | atom_idx, natoms_spe = get_atom_idx(ndata,natoms,spelist,atomic_symbols)
12 |
13 | #def add_command_line_arguments_contraction(parsetext):
14 | # parser = argparse.ArgumentParser(description=parsetext)
15 | # parser.add_argument("-j1", "--istart", type=int, default=0, help="starting index")
16 | # parser.add_argument("-j2", "--iend", type=int, default=0, help="ending index")
17 | # parser.add_argument("-iconf", "--iselection", type=int, default=0, help="selected conf")
18 | # args = parser.parse_args()
19 | # return args
20 |
21 | #args = add_command_line_arguments_contraction("dataset subselection")
22 | # dataset slice boundaries
23 | #istart = args.istart-1
24 | #iend = args.iend
25 | #isel = args.iselection # 0 based
26 |
27 | ocut = inp.overcut
28 |
29 | # init averages
30 | av_coefs = {}
31 | for spe in spelist:
32 | av_coefs[spe] = np.zeros(nmax[(spe,0)],float)
33 |
34 | # compute averages
35 | for iconf in range(ndata):
36 | species = atomic_symbols[iconf]
37 | #==================================================
38 | Coef = np.load(inp.path2qm+inp.coefdir+"coefficients_conf"+str(iconf)+".npy")
39 | #==================================================
40 | i = 0
41 | for iat in range(natoms[iconf]):
42 | spe = species[iat]
43 | for l in range(lmax[spe]+1):
44 | for n in range(nmax[(spe,l)]):
45 | for im in range(2*l+1):
46 | if l==0:
47 | av_coefs[spe][n] += Coef[i]
48 | i += 1
49 |
50 | nenv = {}
51 | for spe in spelist:
52 | nenv[spe] = 0
53 | for iconf in range(ndata):
54 | nenv[spe] += natoms_spe[iconf,spe]
55 |
56 | # save averages
57 | for spe in spelist:
58 | av_coefs[spe] /= nenv[spe]
59 | np.save("averages_"+str(spe)+".npy",av_coefs[spe])
60 | for l in range(lmax[spe]+1):
61 | for n in range(nmax[(spe,l)]):
62 | dirpath = os.path.join(inp.path2qm+inp.projdir, "spe"+str(spe)+"_l"+str(l)+"_n"+str(n))
63 | if not os.path.exists(dirpath):
64 | os.mkdir(dirpath)
65 |
66 | #for iconf in range(istart,iend):
67 | for iconf in range(ndata):
68 | print(iconf+1)
69 |
70 | start = time.time()
71 | species = atomic_symbols[iconf]
72 | # init orthogonal projections
73 | projs = {}
74 | for spe in spelist:
75 | for l in range(lmax[spe]+1):
76 | for n in range(nmax[(spe,l)]):
77 | projs[(spe,l,n)] = np.zeros((natoms_spe[iconf,spe],(2*l+1)))
78 | # compute coefficients
79 | Coef = np.load(inp.path2qm+inp.coefdir+"coefficients_conf"+str(iconf)+".npy")
80 | Over = np.load(inp.path2qm+inp.ovlpdir+"overlap_conf"+str(iconf)+".npy")
81 | # remove L=0 average
82 | i = 0
83 | for iat in range(natoms[iconf]):
84 | spe = species[iat]
85 | for l in range(lmax[spe]+1):
86 | for n in range(nmax[(spe,l)]):
87 | for im in range(2*l+1):
88 | if l==0:
89 | Coef[i] -= av_coefs[spe][n]
90 | i += 1
91 | # compute baselined projections
92 | DProj = np.dot(Over,Coef)
93 | # compute orthogonalization matrix
94 | eigenvalues, unitary = np.linalg.eigh(Over)
95 | eigenvalues = eigenvalues[eigenvalues>ocut]
96 | Mcut = len(eigenvalues)
97 | sqrteigen = np.sqrt(eigenvalues)
98 | diagoverlap = np.diag(1.0/sqrteigen)
99 | orthomatrix = np.dot(np.conj(unitary[:,-Mcut:]),np.dot(diagoverlap,unitary[:,-Mcut:].T))
100 | np.save(inp.path2qm+inp.ovlpdir+"orthomatrix_"+str(iconf)+".npy",orthomatrix)
101 | # orthogonalize projections
102 | OProj = np.dot(orthomatrix,DProj)
103 | # init species counting
104 | specount = {}
105 | for spe in spelist:
106 | specount[spe] = 0
107 | # fill array of orthogonal projections
108 | i = 0
109 | for iat in range(natoms[iconf]):
110 | spe = species[iat]
111 | for l in range(lmax[spe]+1):
112 | for n in range(nmax[(spe,l)]):
113 | for im in range(2*l+1):
114 | projs[(spe,l,n)][specount[spe],im] = OProj[i]
115 | i += 1
116 | specount[spe] += 1
117 | # save orthogonal projections
118 | for spe in spelist:
119 | for l in range(lmax[spe]+1):
120 | for n in range(nmax[(spe,l)]):
121 | np.save(inp.path2qm+inp.projdir+"spe"+str(spe)+"_l"+str(l)+"_n"+str(n)+"/ortho_projections_conf"+str(iconf)+".npy",projs[(spe,l,n)].reshape(natoms_spe[(iconf,spe)]*(2*l+1)))
122 |
123 | print((time.time()-start)/60.0, "minutes")
124 |
--------------------------------------------------------------------------------
/salted/ortho/ortho_regression.py:
--------------------------------------------------------------------------------
1 | import os
2 | import numpy as np
3 | import random
4 | import sys
5 | sys.path.insert(0, './')
6 | import inp
7 | from sys_utils import read_system, get_atom_idx
8 |
9 | spelist, lmax, nmax, llmax, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
10 | atom_idx, natom_dict = get_atom_idx(ndata,natoms,spelist,atomic_symbols)
11 |
12 | # number of sparse environments
13 | M = inp.Menv
14 | # number of training configurations
15 | N = inp.Ntrain
16 | # training set fraction
17 | frac = inp.trainfrac
18 | # number of sparse environments
19 | reg = inp.regul
20 | eigcut = inp.eigcut
21 | kdir = inp.kerndir
22 | pdir = inp.valcdir
23 |
24 | dirpath = os.path.join(inp.path2qm, pdir)
25 | if not os.path.exists(dirpath):
26 | os.mkdir(dirpath)
27 | dirpath = os.path.join(inp.path2qm+pdir, "M"+str(M)+"_eigcut"+str(int(np.log10(eigcut))))
28 | if not os.path.exists(dirpath):
29 | os.mkdir(dirpath)
30 |
31 | # training set selection
32 | dataset = list(range(ndata))
33 | random.Random(3).shuffle(dataset)
34 | trainrangetot = dataset[:N]
35 | np.savetxt("training_set.txt",trainrangetot,fmt='%i')
36 | #trainrangetot = np.loadtxt("training_set2.txt",int)
37 | ntrain = int(frac*len(trainrangetot))
38 | trainrange = trainrangetot[0:ntrain]
39 | natoms_train = natoms[trainrange]
40 | print("Number of training configurations =", ntrain)
41 | testrange = np.setdiff1d(list(range(ndata)),trainrangetot)
42 | ntest = len(testrange)
43 | natoms_test = natoms[testrange]
44 |
45 | ortho_preds = np.zeros((ntest,natmax,llmax+1,nnmax,2*llmax+1))
46 | for spe in spelist:
47 |
48 | for l in range(lmax[spe]+1):
49 |
50 | # get truncated size
51 | Mcut = np.load(inp.path2ml+kdir+"spe"+str(spe)+"_l"+str(l)+"/M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/psi-nm_conf"+str(0)+".npy").shape[1]
52 | # compute B matrix
53 | B = np.zeros((Mcut,Mcut))
54 | for iconf in trainrange:
55 | psi_nm = np.load(inp.path2ml+kdir+"spe"+str(spe)+"_l"+str(l)+"/M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/psi-nm_conf"+str(iconf)+".npy")
56 | B += np.dot(psi_nm.T,psi_nm)
57 | B /= ntrain
58 |
59 | for n in range(nmax[(spe,l)]):
60 |
61 | # compute A vector
62 | A = np.zeros(Mcut)
63 | for iconf in trainrange:
64 | psi_nm = np.load(inp.path2ml+kdir+"spe"+str(spe)+"_l"+str(l)+"/M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/psi-nm_conf"+str(iconf)+".npy")
65 | ortho_projs = np.load(inp.path2qm+inp.projdir+"spe"+str(spe)+"_l"+str(l)+"_n"+str(n)+"/ortho_projections_conf"+str(iconf)+".npy")
66 |
67 | A += np.dot(psi_nm.T,ortho_projs)
68 | A /= ntrain
69 |
70 | print("")
71 | print("spe:",spe,"L:",l,"n:",n)
72 | print("------------------------")
73 |
74 | x = np.linalg.solve( B + reg*np.eye(Mcut) , A )
75 |
76 | error_total = 0
77 | variance = 0
78 | itest = 0
79 | for iconf in testrange:
80 |
81 | # predict
82 | psi_nm = np.load(inp.path2ml+kdir+"spe"+str(spe)+"_l"+str(l)+"/M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/psi-nm_conf"+str(iconf)+".npy")
83 | ortho_projs = np.dot(psi_nm,x)
84 |
85 | # reference
86 | ortho_projs_ref = np.load(inp.path2qm+inp.projdir+"spe"+str(spe)+"_l"+str(l)+"_n"+str(n)+"/ortho_projections_conf"+str(iconf)+".npy")
87 |
88 | # compute error
89 | delta = ortho_projs-ortho_projs_ref
90 | error_total += np.dot(delta,delta)
91 | variance += np.dot(ortho_projs_ref,ortho_projs_ref)
92 | #print iconf+1, ":", np.sqrt(error/var)*100, "% RMSE"
93 |
94 | i = 0
95 | for iat in atom_idx[(iconf,spe)]:
96 | for im in range(2*l+1):
97 | ortho_preds[itest,iat,l,n,im] = ortho_projs.reshape(len(atom_idx[(iconf,spe)]),2*l+1)[i,im]
98 | i+=1
99 | itest += 1
100 |
101 | print("% RMSE =", 100*np.sqrt(error_total/variance))
102 |
103 | np.save(inp.path2qm+pdir+"M"+str(M)+"_eigcut"+str(int(np.log10(eigcut)))+"/ortho-predictions_N"+str(ntrain)+"_reg"+str(int(np.log10(reg)))+".npy",ortho_preds)
104 |
--------------------------------------------------------------------------------
/salted/pyscf/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/andreagrisafi/SALTED/15e84a809b6b674793f19763d62acc2492a7b108/salted/pyscf/__init__.py
--------------------------------------------------------------------------------
/salted/pyscf/_deprecated_/run-pyscf_deprecated.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import os
3 | import sys
4 |
5 | import numpy as np
6 | from ase.io import read
7 | from pyscf import gto
8 | from pyscf import scf,dft
9 | from pyscf import grad
10 | from scipy import special
11 |
12 | from salted.sys_utils import ParseConfig
13 |
14 | inp = ParseConfig().parse_input()
15 |
16 | def add_command_line_arguments(parsetext):
17 | parser = argparse.ArgumentParser(description=parsetext,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
18 | parser.add_argument("-iconf", "--confidx", type=int, default=-1, help="Structure index")
19 | args = parser.parse_args()
20 | return args
21 |
22 | def set_variable_values(args):
23 | iconf = args.confidx
24 | return iconf
25 |
26 | args = add_command_line_arguments("")
27 | iconf = set_variable_values(args)
28 |
29 | # Initialize geometry
30 | geoms = read(inp.system.filename,":")
31 |
32 | dirpath = inp.qm.path2qm
33 | if not os.path.exists(dirpath):
34 | os.mkdir(dirpath)
35 |
36 | if iconf != -1:
37 | print("Calculating density matrix for configuration", iconf)
38 | iconf -= 1 # 0-based indexing
39 | conf_list = [iconf]
40 | else:
41 | conf_list = range(len(geoms))
42 |
43 | for iconf in conf_list:
44 | geom = geoms[iconf]
45 | symb = geom.get_chemical_symbols()
46 | coords = geom.get_positions()
47 | natoms = len(coords)
48 | atoms = []
49 | for i in range(natoms):
50 | coord = coords[i]
51 | atoms.append([symb[i],(coord[0],coord[1],coord[2])])
52 |
53 | # Get PySCF objects for wave-function and density-fitted basis
54 | mol = gto.M(atom=atoms,basis=inp.qm.qmbasis)
55 | m = dft.RKS(mol)
56 | m.xc = inp.qm.functional
57 | # Save density matrix
58 | m.kernel()
59 |
60 | #ks_scanner = m.apply(grad.RKS).as_scanner()
61 | #etot, grad = ks_scanner(mol)
62 | #
63 | #f = open("gradients/grad_conf"+str(iconf+1)+".dat","w")
64 | #for i in range(natoms):
65 | # print >> f, symb[i], grad[i,0], grad[i,1], grad[i,2]
66 | #f.close()
67 |
68 | dm = m.make_rdm1()
69 |
70 | dirpath = os.path.join(inp.qm.path2qm, "density_matrices")
71 | if not os.path.exists(dirpath):
72 | os.mkdir(dirpath)
73 |
74 | np.save(os.path.join(dirpath, f"dm_conf{iconf+1}.npy"), dm)
75 |
--------------------------------------------------------------------------------
/salted/pyscf/get_basis_info.py:
--------------------------------------------------------------------------------
1 | """Translate basis info from PySCF calculation to SALTED basis info"""
2 |
3 | from typing import Dict, List
4 |
5 | from pyscf import df
6 | from pyscf.gto import basis
7 |
8 | from salted.basis_client import (
9 | BasisClient,
10 | SpeciesBasisData,
11 | )
12 | from salted.get_basis_info import get_parser
13 | from salted.sys_utils import ParseConfig
14 |
15 |
16 | def build(dryrun: bool = False, force_overwrite: bool = False):
17 | """Scheme: load density fitting basis from pyscf module,
18 | update the basis_data dict,
19 | and write to the database when all species are recorded.
20 | """
21 | inp = ParseConfig().parse_input()
22 | assert inp.qm.qmcode.lower() == "pyscf", f"{inp.qm.qmcode=}, but expected 'pyscf'"
23 |
24 | spe_set = set(inp.system.species) # remove duplicates
25 | qmbasis = inp.qm.qmbasis
26 |
27 | """load density fitting basis from pyscf module"""
28 | basis_data: Dict[str, SpeciesBasisData] = load_from_pyscf(list(spe_set), qmbasis)
29 |
30 | """write to the database"""
31 | if dryrun:
32 | print("Dryrun mode, not writing to the database")
33 | print(f"{basis_data=}")
34 | else:
35 | BasisClient().write(inp.qm.dfbasis, basis_data, force_overwrite)
36 |
37 |
38 |
39 | def load_from_pyscf(species_list: List[str], qmbasis: str):
40 | """load the xxx-jkfit density fitting basis from PySCF
41 |
42 | Args:
43 | species_list: list of species, e.g. [H, O]
44 | qmbasis: quantum chemistry basis set name, e.g. cc-pvdz
45 |
46 | Returns:
47 | Dict[str, SpeciesBasisData]: species and basis data
48 | """
49 | ribasis = df.addons.DEFAULT_AUXBASIS[basis._format_basis_name(qmbasis)][0] # get the proper DF basis name in PySCF
50 | print(f"{species_list=}, {qmbasis=}, and the parsed {ribasis=}")
51 | spe_ribasis_info = {spe: basis.load(ribasis, spe) for spe in species_list} # load with PySCF basis module
52 | """
53 | Each dict value is like:
54 | format: [angular_momentum, [exponents, coefficients], ...]
55 | there might be multiple [exponents, coefficients] for one atomic orbital
56 | [
57 | [
58 | 0,
59 | [883.9992943, 0.33024477],
60 | [286.8428015, 0.80999791],
61 | ],
62 | [0, [48.12711454, 1.0]],
63 | [0, [2.50686566, 1.0]],
64 | [0, [0.1918516, 1.0]],
65 | [1, [102.99176249, 1.0]],
66 | [1, [3.3490545, 1.0]],
67 | [1, [0.20320063, 1.0]],
68 | [2, [10.59406836, 1.0]],
69 | [2, [0.51949765, 1.0]],
70 | ...
71 | ]
72 |
73 | Extract the l numbers and compose the Dict[str, SpeciesBasisData] (species and basis data)
74 | """
75 | basis_data = {spe: collect_l_nums(ribasis_info) for spe, ribasis_info in spe_ribasis_info.items()}
76 | return basis_data
77 |
78 |
79 | # def collect_l_nums(data:List[int, List[float]]) -> SpeciesBasisData:
80 | # use Annotated
81 | def collect_l_nums(data: List) -> SpeciesBasisData:
82 | """collect l numbers for each species based on the data from PySCF
83 | input: above dict value,
84 | e.g.
85 | [
86 | [
87 | 0,
88 | [883.9992943, 0.33024477],
89 | [286.8428015, 0.80999791],
90 | ],
91 | [0, [48.12711454, 1.0]],
92 | [1, [102.99176249, 1.0]],
93 | [2, [10.59406836, 1.0]],
94 | ...
95 | ]
96 | there might be multiple [exponents, coefficients] for one atomic orbital
97 | output: max l number, and a list of counts of each l number
98 | """
99 | l_nums = [d for d, *_ in data] # [0, 0, 0, 0, 1, 1, 1, 2, 2, ...]
100 | l_max = max(l_nums)
101 | l_cnt = [0 for _ in range(l_max + 1)] # [0, 0, 0, ...] to the max l number
102 | for l_num in l_nums:
103 | l_cnt[l_num] += 1
104 | return {
105 | "lmax": max(l_nums),
106 | "nmax": l_cnt,
107 | }
108 |
109 |
110 |
111 | if __name__ == "__main__":
112 | print("Please call `python -m salted.get_basis_info` instead of this file")
113 |
114 | parser = get_parser()
115 | args = parser.parse_args()
116 |
117 | build(dryrun=args.dryrun, force_overwrite=args.force_overwrite)
118 |
119 |
--------------------------------------------------------------------------------
/salted/pyscf/run_pyscf.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import os
3 | import sys
4 | import time
5 | from typing import List, Tuple, Union
6 |
7 | import numpy as np
8 | from ase.io import read
9 | from pyscf import dft, gto, lib
10 |
11 | from salted.sys_utils import ARGHELP_INDEX_STR, ParseConfig, parse_index_str
12 |
13 |
14 | def run_pyscf(
15 | atoms: List,
16 | basis: str,
17 | xc: str,
18 | ):
19 | mol = gto.M(atom=atoms, basis=basis, verbose=0)
20 | mf = dft.RKS(mol, xc=xc)
21 | mf.kernel()
22 | return mf.make_rdm1()
23 |
24 |
25 | def main(geom_indexes: Union[List[int], None], num_threads: int = None):
26 | inp = ParseConfig().parse_input()
27 | geoms_all = read(inp.system.filename, ":")
28 | if geom_indexes is None:
29 | geom_indexes = list(range(len(geoms_all)))
30 | else:
31 | geom_indexes = [i for i in geom_indexes if i < len(geoms_all)] # indexes start from 0
32 | print(f"Calculating density matrix for configurations: {geom_indexes}")
33 | geoms = [geoms_all[i] for i in geom_indexes]
34 |
35 | """ prepare the output directory """
36 | dirpath = os.path.join(inp.qm.path2qm, "density_matrices")
37 | if not os.path.exists(dirpath):
38 | os.mkdir(dirpath)
39 |
40 | """ set pyscf.lib.num_threads """
41 | if num_threads is not None:
42 | lib.num_threads(num_threads)
43 |
44 | """ do DFT calculation """
45 | start_time = time.time()
46 | for cal_idx, (geom_idx, geom) in enumerate(zip(geom_indexes, geoms)):
47 | print(f"calcualte {geom_idx=}, progress: {cal_idx}/{len(geom_indexes)}")
48 | symb = geom.get_chemical_symbols()
49 | coords = geom.get_positions()
50 | atoms = [(s, c) for s, c in zip(symb, coords)]
51 |
52 | dm = run_pyscf(atoms, inp.qm.qmbasis, inp.qm.functional)
53 | np.save(os.path.join(dirpath, f"dm_conf{geom_idx+1}.npy"), dm)
54 | end_time = time.time()
55 | print(f"Calculation finished, wall time cost on DFT: {end_time - start_time:.2f}s")
56 |
57 |
58 | if __name__ == "__main__":
59 | parser = argparse.ArgumentParser()
60 | # create a parser obj, which accepts the indexes to calculate, start from 0
61 | # formats: 1,2,3 or 1-3 or None (all structures)
62 | parser.add_argument(
63 | "-i", "--idx", type=str, default="all",
64 | help=ARGHELP_INDEX_STR,
65 | )
66 | parser.add_argument(
67 | "-c", "--cpu", type=int, default=None,
68 | help="Number of CPU cores to use. Default is None (for do nothing)."
69 | )
70 | args = parser.parse_args()
71 |
72 | main(parse_index_str(args.idx), args.cpu)
73 |
--------------------------------------------------------------------------------
/salted/scalar_vector.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import time
4 | import os.path as osp
5 | from ase.io import read
6 | import h5py
7 |
8 | import numpy as np
9 | from scipy import sparse
10 | from ase.data import atomic_numbers
11 |
12 | from salted.sys_utils import read_system,get_atom_idx,get_conf_range
13 |
14 | from salted import sph_utils
15 | from salted import basis
16 | from salted.sys_utils import ParseConfig
17 |
18 | from salted.lib import equicomb
19 | from salted.lib import equicombsparse
20 |
21 | def build():
22 |
23 | inp = ParseConfig().parse_input()
24 | # salted parameters
25 | (saltedname, saltedpath, saltedtype,
26 | filename, species, average, parallel,
27 | path2qm, qmcode, qmbasis, dfbasis,
28 | filename_pred, predname, predict_data, alpha_only,
29 | rep1, rcut1, sig1, nrad1, nang1, neighspe1,
30 | rep2, rcut2, sig2, nrad2, nang2, neighspe2,
31 | sparsify, nsamples, ncut,
32 | zeta, Menv, Ntrain, trainfrac, regul, eigcut,
33 | gradtol, restart, blocksize, trainsel, nspe1, nspe2, HYPER_PARAMETERS_DENSITY, HYPER_PARAMETERS_POTENTIAL) = ParseConfig().get_all_params()
34 |
35 | sdir = osp.join(saltedpath, f"equirepr_{saltedname}")
36 |
37 | if sparsify==False:
38 | # Generate directories for saving descriptors
39 | if not osp.exists(sdir):
40 | os.mkdir(sdir)
41 |
42 | species, lmax, nmax, lmax_max, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
43 | atom_idx, natom_dict = get_atom_idx(ndata,natoms,species,atomic_symbols)
44 |
45 | # Load feature space sparsification information if required
46 | if sparsify:
47 | vfps = {}
48 | for lam in range(lmax_max+1):
49 | vfps[lam] = np.load(osp.join(
50 | saltedpath, f"equirepr_{saltedname}", f"fps{ncut}-{lam}.npy"
51 | ))
52 |
53 | frames = read(filename,":")
54 | natoms_total = sum(natoms)
55 | conf_range = range(ndata)
56 |
57 | lam = 0
58 | llmax, llvec = sph_utils.get_angular_indexes_symmetric(lam,nang1,nang2)
59 |
60 | # Load the relevant Wigner-3J symbols associated with the given triplet (lam, lmax1, lmax2)
61 | wigner3j = np.loadtxt(os.path.join(
62 | saltedpath, "wigners", f"wigner_lam-{lam}_lmax1-{nang1}_lmax2-{nang2}.dat"
63 | ))
64 | wigdim = wigner3j.size
65 |
66 | omega1 = sph_utils.get_representation_coeffs(frames,rep1,HYPER_PARAMETERS_DENSITY,HYPER_PARAMETERS_POTENTIAL,0,neighspe1,species,nang1,nrad1,natoms_total)
67 | omega2 = sph_utils.get_representation_coeffs(frames,rep2,HYPER_PARAMETERS_DENSITY,HYPER_PARAMETERS_POTENTIAL,0,neighspe2,species,nang2,nrad2,natoms_total)
68 |
69 | # Reshape arrays of expansion coefficients for optimal Fortran indexing
70 | v1 = np.transpose(omega1,(2,0,3,1))
71 | v2 = np.transpose(omega2,(2,0,3,1))
72 |
73 | # Compute complex to real transformation matrix for the given lambda value
74 | c2r = sph_utils.complex_to_real_transformation([2*lam+1])[0]
75 |
76 | start = time.time()
77 |
78 | if sparsify:
79 |
80 | featsize = nspe1*nspe2*nrad1*nrad2*llmax
81 | nfps = len(vfps[lam])
82 | p = equicombsparse.equicombsparse(natoms_total,nang1,nang2,nspe1*nrad1,nspe2*nrad2,v1,v2,wigdim,wigner3j,llmax,llvec.T,lam,c2r,featsize,nfps,vfps[lam])
83 | p = np.transpose(p,(2,0,1))
84 | featsize = ncut
85 |
86 | else:
87 |
88 | featsize = nspe1*nspe2*nrad1*nrad2*llmax
89 | p = equicomb.equicomb(natoms_total,nang1,nang2,nspe1*nrad1,nspe2*nrad2,v1,v2,wigdim,wigner3j,llmax,llvec.T,lam,c2r,featsize)
90 | p = np.transpose(p,(2,0,1))
91 |
92 | print("time = ", time.time()-start)
93 |
94 | #TODO modify SALTED to directly deal with compact natoms_total dimension
95 | p = p.reshape(natoms_total,featsize)
96 | pvec = np.zeros((ndata,natmax,featsize))
97 |
98 | j = 0
99 | for i,iconf in enumerate(conf_range):
100 | for iat in range(natoms[iconf]):
101 | pvec[i,iat] = p[j]
102 | j += 1
103 |
104 | h5f = h5py.File(osp.join(sdir, f"FEAT-0.h5"), 'w')
105 | h5f.create_dataset("descriptor",data=pvec)
106 | h5f.close()
107 |
108 | if __name__ == "__main__":
109 | build()
110 |
--------------------------------------------------------------------------------
/salted/solve_regression.py:
--------------------------------------------------------------------------------
1 | import os
2 | import os.path as osp
3 | import sys
4 | import time
5 |
6 | import numpy as np
7 |
8 | from salted.sys_utils import ParseConfig
9 |
10 |
11 | def build():
12 |
13 | inp = ParseConfig().parse_input()
14 | saltedname, saltedpath = inp.salted.saltedname, inp.salted.saltedpath
15 |
16 | # sparse-GPR parameters
17 | Menv = inp.gpr.Menv
18 | regul = inp.gpr.regul
19 | zeta = inp.gpr.z
20 |
21 | fdir = f"rkhs-vectors_{saltedname}"
22 | rdir = f"regrdir_{saltedname}"
23 |
24 | # define training set size
25 | ntrain = round(inp.gpr.trainfrac*inp.gpr.Ntrain)
26 |
27 | # load regression matrices
28 | Avec = np.load(osp.join(saltedpath, rdir, f"M{Menv}_zeta{zeta}", f"Avec_N{ntrain}.npy"))
29 | totsize = Avec.shape[0]
30 | print("problem dimensionality:", totsize,flush=True)
31 | if totsize > 100000:
32 | raise ValueError(f"problem dimension too large ({totsize=}), minimize directly loss-function instead!")
33 | Bmat = np.load(osp.join(saltedpath, rdir, f"M{Menv}_zeta{zeta}", f"Bmat_N{ntrain}.npy"))
34 |
35 | start = time.time()
36 |
37 | w = np.linalg.solve(Bmat+np.eye(totsize)*regul,Avec)
38 |
39 | print(f"regression time: {((time.time()-start)/60):.3f} minutes",flush=True)
40 |
41 | np.save(osp.join(saltedpath, rdir, f"M{Menv}_zeta{zeta}", f"weights_N{ntrain}_reg{int(np.log10(regul))}.npy"), w)
42 |
43 | return
44 |
45 | if __name__ == "__main__":
46 | build()
47 |
--------------------------------------------------------------------------------
/salted/sparse_selection.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import sys
3 | import h5py
4 | import os
5 | import os.path as osp
6 |
7 | from salted.sys_utils import ParseConfig, read_system, get_atom_idx, do_fps
8 |
9 | def build():
10 | inp = ParseConfig().parse_input()
11 |
12 | species, lmax, nmax, llmax, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
13 |
14 | atom_idx, natom_dict = get_atom_idx(ndata,natoms,species,atomic_symbols)
15 |
16 | # number of sparse environments
17 | M, zeta, eigcut = inp.gpr.Menv, inp.gpr.z, inp.gpr.eigcut
18 | sdir = osp.join(inp.salted.saltedpath, f"equirepr_{inp.salted.saltedname}")
19 |
20 | # compute number of atomic environments for each species
21 | ispe = 0
22 | species_idx = {}
23 | for spe in species:
24 | species_idx[spe] = ispe
25 | ispe += 1
26 |
27 | species_array = np.zeros((ndata,natmax),int)
28 | natoms_total = 0
29 | for iconf in range(ndata):
30 | for iat in range(natoms[iconf]):
31 | spe = atomic_symbols[iconf][iat]
32 | species_array[iconf,iat] = species_idx[spe]
33 | natoms_total += 1
34 | species_array = species_array.reshape(ndata*natmax)
35 |
36 | # load lambda=0 power spectrum
37 | power = h5py.File(osp.join(sdir, "FEAT-0.h5"), 'r')['descriptor'][:]
38 | nfeat = power.shape[-1]
39 |
40 | power_dense = np.zeros((natoms_total,nfeat))
41 | idx = 0
42 | for iconf in range(ndata):
43 | power_dense[idx:idx+natoms[iconf]] = power[iconf,:natoms[iconf]]
44 | idx += natoms[iconf]
45 | # compute sparse set with FPS
46 | fps_idx = np.array(do_fps(power_dense,M),int)
47 | fps_species = species_array[fps_idx]
48 | sparse_set = np.vstack((fps_idx,fps_species)).T
49 | print("Computed sparse set made of ", M, "environments")
50 | np.savetxt(osp.join(sdir, f"sparse_set_{M}.txt"), sparse_set, fmt='%i')
51 |
52 | if __name__ == "__main__":
53 | build()
54 |
--------------------------------------------------------------------------------
/salted/sparsify_features.py:
--------------------------------------------------------------------------------
1 | import os
2 | import random
3 | import sys
4 | import time
5 | import os.path as osp
6 |
7 | import numpy as np
8 | import h5py
9 | from ase.data import atomic_numbers
10 | from ase.io import read
11 |
12 | from salted import sph_utils
13 | from salted import basis
14 |
15 | from salted.lib import equicomb, equicombfps
16 | from salted.sys_utils import ParseConfig, read_system, get_atom_idx, get_conf_range, do_fps
17 |
18 | def build():
19 |
20 | inp = ParseConfig().parse_input()
21 | (saltedname, saltedpath, saltedtype,
22 | filename, species, average, parallel,
23 | path2qm, qmcode, qmbasis, dfbasis,
24 | filename_pred, predname, predict_data, alpha_only,
25 | rep1, rcut1, sig1, nrad1, nang1, neighspe1,
26 | rep2, rcut2, sig2, nrad2, nang2, neighspe2,
27 | sparsify, nsamples, ncut,
28 | zeta, Menv, Ntrain, trainfrac, regul, eigcut,
29 | gradtol, restart, blocksize, trainsel, nspe1, nspe2, HYPER_PARAMETERS_DENSITY, HYPER_PARAMETERS_POTENTIAL) = ParseConfig().get_all_params()
30 |
31 | # Generate directories for saving descriptors
32 | sdir = osp.join(saltedpath, f"equirepr_{saltedname}")
33 | if not osp.exists(sdir):
34 | os.mkdir(sdir)
35 |
36 | if not sparsify:
37 | print(
38 | "ERROR: inp parameter sparsify=False. "
39 | "Make sure to include a sparsify section with ncut>0 if you want to sparsify the descriptor\n",
40 | file=sys.stderr
41 | )
42 | sys.exit(1)
43 |
44 | species, lmax, nmax, lmax_max, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
45 | atom_idx, natom_dict = get_atom_idx(ndata,natoms,species,atomic_symbols)
46 |
47 | start = time.time()
48 |
49 | ndata_true = ndata
50 | print(f"The dataset contains {ndata_true} frames.")
51 |
52 | conf_range = list(range(ndata_true))
53 | random.Random(3).shuffle(conf_range)
54 |
55 | if nsamples <= ndata:
56 | ndata = nsamples
57 | else:
58 | print("ERROR: nsamples cannot be greater than ndata!")
59 | sys.exit(1)
60 |
61 | conf_range = conf_range[:ndata]
62 | print(f"Selected {ndata} frames.")
63 |
64 | frames = read(filename,":")
65 | frames = list( frames[i] for i in conf_range )
66 | natoms = list( natoms[i] for i in conf_range )
67 | natoms_total = sum(natoms)
68 |
69 | omega1 = sph_utils.get_representation_coeffs(frames,rep1,HYPER_PARAMETERS_DENSITY,HYPER_PARAMETERS_POTENTIAL,0,neighspe1,species,nang1,nrad1,natoms_total)
70 | omega2 = sph_utils.get_representation_coeffs(frames,rep2,HYPER_PARAMETERS_DENSITY,HYPER_PARAMETERS_POTENTIAL,0,neighspe2,species,nang2,nrad2,natoms_total)
71 |
72 | # Reshape arrays of expansion coefficients for optimal Fortran indexing
73 | v1 = np.transpose(omega1,(2,0,3,1))
74 | v2 = np.transpose(omega2,(2,0,3,1))
75 |
76 | # Compute equivariant descriptors for each lambda value entering the SPH expansion of the electron density
77 | for lam in range(lmax_max+1):
78 |
79 | llmax, llvec = sph_utils.get_angular_indexes_symmetric(lam,nang1,nang2)
80 |
81 | # Load the relevant Wigner-3J symbols associated with the given triplet (lam, lmax1, lmax2)
82 | wigner3j = np.loadtxt(osp.join(saltedpath, "wigners", f"wigner_lam-{lam}_lmax1-{nang1}_lmax2-{nang2}.dat"))
83 | wigdim = wigner3j.size
84 |
85 | # Compute complex to real transformation matrix for the given lambda value
86 | c2r = sph_utils.complex_to_real_transformation([2*lam+1])[0]
87 |
88 | # compute normalized equivariant descriptor
89 | featsize = nspe1*nspe2*nrad1*nrad2*llmax
90 |
91 | print(f"lambda = {lam}, feature space size = {featsize}")
92 |
93 | # Do feature selection with FPS sparsification
94 | if ncut >= featsize:
95 | print("ERROR: requested number of sparse features larger than total feature space size! Please get rid of the inp.descriptor.sparsify section.")
96 | sys.exit(1)
97 |
98 | pvec = equicombfps.equicombfps(natoms_total,nang1,nang2,nspe1*nrad1,nspe2*nrad2,v1,v2,wigdim,wigner3j,llmax,llvec.T,lam,c2r,featsize)
99 | vfps = do_fps(pvec,ncut)
100 | np.save(osp.join(sdir, f"fps{ncut}-{lam}.npy"), vfps)
101 |
102 | if __name__ == "__main__":
103 | build()
104 |
--------------------------------------------------------------------------------
/salted/wigner.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import time
4 | import os.path as osp
5 | import io
6 |
7 | import ase
8 | import numpy as np
9 | from sympy.physics.wigner import wigner_3j
10 |
11 | from salted import sph_utils
12 | from salted.sys_utils import ParseConfig
13 |
14 | def build():
15 | inp = ParseConfig().parse_input()
16 |
17 | from salted.sys_utils import read_system, get_atom_idx
18 | species, lmax, nmax, lmax_max, nnmax, ndata, atomic_symbols, natoms, natmax = read_system()
19 | atom_idx, natom_dict = get_atom_idx(ndata,natoms,species,atomic_symbols)
20 |
21 | nang1, nang2 = inp.descriptor.rep1.nang, inp.descriptor.rep2.nang
22 |
23 | # Generate directories for saving descriptors
24 | dirpath = os.path.join(inp.salted.saltedpath, "wigners")
25 | if not os.path.exists(dirpath):
26 | os.mkdir(dirpath)
27 |
28 | def get_wigner3j(llmax:int, llvec:np.ndarray, lam:int, wig:io.TextIOWrapper):
29 | """Compute and save Wigner-3J symbols needed for symmetry-adapted combination"""
30 |
31 | for il in range(llmax):
32 | l1 = int(llvec[il,0])
33 | l2 = int(llvec[il,1])
34 | for imu in range(2*lam+1):
35 | mu = imu-lam
36 | for im1 in range(2*l1+1):
37 | m1 = im1-l1
38 | m2 = m1-mu
39 | if abs(m2) <= l2:
40 | im2 = m2+l2
41 | # for wigner_3j, all the parameters should be integers or half-integers
42 | w3j = wigner_3j(lam,l2,l1,mu,m2,-m1) * (-1.0)**(m1)
43 | print(float(w3j),file=wig)
44 |
45 | if inp.salted.saltedtype=="density-response":
46 | lmax_max += 1
47 | for spe in species:
48 | lmax[spe] += 1
49 |
50 | for lam in range(lmax_max+1):
51 |
52 | [llmax,llvec] = sph_utils.get_angular_indexes_symmetric(lam,nang1,nang2)
53 |
54 | wig = open(osp.join(
55 | inp.salted.saltedpath, "wigners", f"wigner_lam-{lam}_lmax1-{nang1}_lmax2-{nang2}.dat"
56 | ), "a")
57 | get_wigner3j(llmax,llvec,lam,wig)
58 | wig.close()
59 |
60 | if inp.salted.saltedtype=="density-response":
61 |
62 | for lam in range(1,lmax_max):
63 |
64 | llmax, llvec = sph_utils.get_angular_indexes_antisymmetric(lam,nang1,nang2)
65 |
66 | wig = open(osp.join(
67 | inp.salted.saltedpath, "wigners", f"wigner_antisymm_lam-{lam}_lmax1-{nang1}_lmax2-{nang2}.dat"
68 | ), "a")
69 | get_wigner3j(llmax,llvec,lam,wig)
70 | wig.close()
71 |
72 | for L in [lam-1,lam,lam+1]:
73 |
74 | cgfile = open(osp.join(
75 | inp.salted.saltedpath, "wigners", f"cg_response_lam-{lam}_L-{L}.dat"
76 | ), "a")
77 |
78 | icg = 0
79 | for imu in range(2*lam+1):
80 | mu = imu-lam
81 | for ik in range(3):
82 | k = ik-1
83 | M = mu+k
84 | if abs(M)<=L:
85 | cg = wigner_3j(lam,1,L,mu,k,-M) * (-1.0)**(-lam+1-M) * np.sqrt(float(2*L+1))
86 | print(float(cg),file=cgfile)
87 | icg += 1
88 |
89 | cgfile.close()
90 |
91 | if __name__ == "__main__":
92 | build()
93 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | setup(
4 | name='salted',
5 | version='3.0.0',
6 | description='Symmetry-Adapted Learning of Three-Dimensional Electron Densities',
7 | url='https://github.com/andreagrisafi/SALTED',
8 | author='Andrea Grisafi, Alan Lewis',
9 | author_email='andrea.grisafi@ens.psl.eu, alan.m.lewis@york.ac.uk',
10 | license='GNU GENERAL PUBLIC LICENSE',
11 | packages=['salted','salted.cp2k','salted.pyscf','salted.aims','salted.lib'],
12 | install_requires=['mpi4py','featomic','ase','numpy','scipy','h5py','sympy','pyyaml'],
13 | include_package_data=True,
14 | package_data={"salted": ["salted/lib/*.so"]},
15 | classifiers=[
16 | 'Development Status :: 1 - Planning',
17 | 'Intended Audience :: Science/Research',
18 | 'License :: OSI Approved :: BSD License',
19 | 'Operating System :: POSIX :: Linux',
20 | 'Programming Language :: Python :: 3',
21 | ],
22 | )
23 |
--------------------------------------------------------------------------------
/src/antiequicomb.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE antiequicomb(natoms,nang1,nang2,nrad1,nrad2,v1,v2,&
2 | wigdim,w3j,llmax,llvec,lam,c2r,featsize,p)
3 |
4 | !use omp_lib
5 | IMPLICIT NONE
6 | INTEGER:: natoms,nang1,nang2,nrad1,nrad2,llmax,lam,wigdim,ifeat
7 | INTEGER:: iat,n1,n2,iwig,l1,l2,il,imu,im1,im2,mu,m1,m2,featsize
8 | INTEGER, DIMENSION(2,llmax):: llvec
9 | REAL*8, DIMENSION(wigdim):: w3j
10 | REAL*8, DIMENSION(2*lam+1):: pimag
11 | COMPLEX*16, DIMENSION(2*lam+1):: pcmplx
12 | COMPLEX*16, DIMENSION(2*lam+1,2*lam+1):: c2r
13 | COMPLEX*16, DIMENSION(2*nang1+1,nang1+1,nrad1,natoms):: v1
14 | COMPLEX*16, DIMENSION(2*nang2+1,nang2+1,nrad2,natoms):: v2
15 | REAL*8, DIMENSION(2*lam+1,featsize):: ptemp
16 | REAL*8, DIMENSION(2*lam+1,featsize,natoms):: p
17 | REAL*8:: inner, normfact
18 |
19 | !f2py intent(in) natoms,nang1,nang2,nrad1,nrad2,v1,v2,wigdim,w3j,llmax,llvec,lam,c2r
20 | !f2py intent(in) featsize
21 | !f2py intent(out) p
22 | !f2py depend(natoms) p, v1, v2
23 | !f2py depend(nrad1) v1
24 | !f2py depend(nrad2) v2
25 | !f2py depend(nang1) v1
26 | !f2py depend(nang2) v2
27 | !f2py depend(lam) p, c2r
28 | !f2py depend(llmax) llvec
29 | !f2py depend(wigdim) w3j
30 | !f2py depend(featsize) p
31 |
32 | p = 0.d0
33 |
34 | !$OMP PARALLEL DEFAULT(private) &
35 | !$OMP FIRSTPRIVATE(natoms,nang1,nang2,nrad1,nrad2,w3j,llmax,llvec,lam,c2r,featsize) &
36 | !$OMP SHARED(p,v1,v2)
37 | !$OMP DO SCHEDULE(dynamic)
38 | do iat=1,natoms
39 | inner = 0.0
40 | ptemp = 0.0
41 | ifeat = 1
42 | do n1=1,nrad1
43 | do n2=1,nrad2
44 | iwig = 1
45 | do il=1,llmax
46 | l1 = llvec(1,il)
47 | l2 = llvec(2,il)
48 | pcmplx = dcmplx(0.0,0.0)
49 | do imu=1,2*lam+1
50 | mu = imu-1-lam
51 | do im1=1,2*l1+1
52 | m1 = im1-1-l1
53 | m2 = m1-mu
54 | if (abs(m2)<=l2) then
55 | im2 = m2+l2+1
56 | pcmplx(imu) = pcmplx(imu) &
57 | + w3j(iwig) * v1(im1,l1+1,n1,iat) * dconjg(v2(im2,l2+1,n2,iat))
58 | iwig = iwig + 1
59 | endif
60 | enddo
61 | enddo
62 | pimag = dimag(matmul(c2r,pcmplx))
63 | do imu=1,2*lam+1
64 | inner = inner + pimag(imu)**2
65 | ptemp(imu,ifeat) = pimag(imu)
66 | enddo
67 | ifeat = ifeat + 1
68 | enddo
69 | enddo
70 | enddo
71 | normfact = dsqrt(inner)
72 | do ifeat=1,featsize
73 | do imu=1,2*lam+1
74 | p(imu,ifeat,iat) = ptemp(imu,ifeat) / normfact
75 | enddo
76 | enddo
77 | enddo
78 | !$OMP END DO
79 | !$OMP END PARALLEL
80 |
81 | return
82 | END
83 |
--------------------------------------------------------------------------------
/src/antiequicombnonorm.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE antiequicombnonorm(natoms,nang1,nang2,nrad1,nrad2,v1,v2,&
2 | wigdim,w3j,llmax,llvec,lam,c2r,featsize,p)
3 |
4 | !use omp_lib
5 | IMPLICIT NONE
6 | INTEGER:: natoms,nang1,nang2,nrad1,nrad2,llmax,lam,wigdim,ifeat
7 | INTEGER:: iat,n1,n2,iwig,l1,l2,il,imu,im1,im2,mu,m1,m2,featsize
8 | INTEGER, DIMENSION(2,llmax):: llvec
9 | REAL*8, DIMENSION(wigdim):: w3j
10 | REAL*8, DIMENSION(2*lam+1):: pimag
11 | COMPLEX*16, DIMENSION(2*lam+1):: pcmplx
12 | COMPLEX*16, DIMENSION(2*lam+1,2*lam+1):: c2r
13 | COMPLEX*16, DIMENSION(2*nang1+1,nang1+1,nrad1,natoms):: v1
14 | COMPLEX*16, DIMENSION(2*nang2+1,nang2+1,nrad2,natoms):: v2
15 | REAL*8, DIMENSION(2*lam+1,featsize):: ptemp
16 | REAL*8, DIMENSION(2*lam+1,featsize,natoms):: p
17 |
18 | !f2py intent(in) natoms,nang1,nang2,nrad1,nrad2,v1,v2,wigdim,w3j,llmax,llvec,lam,c2r
19 | !f2py intent(in) featsize
20 | !f2py intent(out) p
21 | !f2py depend(natoms) p, v1, v2
22 | !f2py depend(nrad1) v1
23 | !f2py depend(nrad2) v2
24 | !f2py depend(nang1) v1
25 | !f2py depend(nang2) v2
26 | !f2py depend(lam) p, c2r
27 | !f2py depend(llmax) llvec
28 | !f2py depend(wigdim) w3j
29 | !f2py depend(featsize) p
30 |
31 | p = 0.d0
32 |
33 | !$OMP PARALLEL DEFAULT(private) &
34 | !$OMP FIRSTPRIVATE(natoms,nang1,nang2,nrad1,nrad2,w3j,llmax,llvec,lam,c2r,featsize) &
35 | !$OMP SHARED(p,v1,v2)
36 | !$OMP DO SCHEDULE(dynamic)
37 | do iat=1,natoms
38 | ptemp = 0.0
39 | ifeat = 1
40 | do n1=1,nrad1
41 | do n2=1,nrad2
42 | iwig = 1
43 | do il=1,llmax
44 | l1 = llvec(1,il)
45 | l2 = llvec(2,il)
46 | pcmplx = dcmplx(0.0,0.0)
47 | do imu=1,2*lam+1
48 | mu = imu-1-lam
49 | do im1=1,2*l1+1
50 | m1 = im1-1-l1
51 | m2 = m1-mu
52 | if (abs(m2)<=l2) then
53 | im2 = m2+l2+1
54 | pcmplx(imu) = pcmplx(imu) &
55 | + w3j(iwig) * v1(im1,l1+1,n1,iat) * dconjg(v2(im2,l2+1,n2,iat))
56 | iwig = iwig + 1
57 | endif
58 | enddo
59 | enddo
60 | pimag = dimag(matmul(c2r,pcmplx))
61 | do imu=1,2*lam+1
62 | ptemp(imu,ifeat) = pimag(imu)
63 | enddo
64 | ifeat = ifeat + 1
65 | enddo
66 | enddo
67 | enddo
68 | do ifeat=1,featsize
69 | do imu=1,2*lam+1
70 | p(imu,ifeat,iat) = ptemp(imu,ifeat)
71 | enddo
72 | enddo
73 | enddo
74 | !$OMP END DO
75 | !$OMP END PARALLEL
76 |
77 | return
78 | END
79 |
--------------------------------------------------------------------------------
/src/antiequicombsparse.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE antiequicombsparse(natoms,nang1,nang2,nrad1,nrad2,v1,v2,&
2 | wigdim,w3j,llmax,llvec,lam,c2r,&
3 | featsize,nfps,vfps,p)
4 |
5 | !use omp_lib
6 | IMPLICIT NONE
7 | INTEGER:: natoms,nang1,nang2,nrad1,nrad2,llmax,lam,wigdim,ifps,ifeat,n
8 | INTEGER:: iat,n1,n2,iwig,l1,l2,il,imu,im1,im2,mu,m1,m2,featsize,nfps
9 | INTEGER, DIMENSION(nfps):: vfps
10 | INTEGER, DIMENSION(2,llmax):: llvec
11 | REAL*8, DIMENSION(wigdim):: w3j
12 | REAL*8, DIMENSION(2*lam+1):: pimag
13 | COMPLEX*16, DIMENSION(2*lam+1):: pcmplx
14 | COMPLEX*16, DIMENSION(2*lam+1,2*lam+1):: c2r
15 | COMPLEX*16, DIMENSION(2*nang1+1,nang1+1,nrad1,natoms):: v1
16 | COMPLEX*16, DIMENSION(2*nang2+1,nang2+1,nrad2,natoms):: v2
17 | REAL*8, DIMENSION(2*lam+1,featsize):: ptemp
18 | REAL*8, DIMENSION(2*lam+1,nfps,natoms):: p
19 | REAL*8:: inner,normfact
20 |
21 | !f2py intent(in) natoms,nang1,nang2,nrad1,nrad2,v1,v2,wigdim,w3j,llmax,llvec,lam,c2r
22 | !f2py intent(in) featsize, nfps, vfps
23 | !f2py intent(out) p
24 | !f2py depend(natoms) p, v1, v2
25 | !f2py depend(nrad1) v1
26 | !f2py depend(nrad2) v2
27 | !f2py depend(nang1) v1
28 | !f2py depend(nang2) v2
29 | !f2py depend(lam) p, c2r
30 | !f2py depend(llmax) llvec
31 | !f2py depend(wigdim) w3j
32 | !f2py depend(nfps) vfps, p
33 |
34 | p = 0.d0
35 |
36 | !$OMP PARALLEL DEFAULT(private) &
37 | !$OMP FIRSTPRIVATE(natoms,nang1,nang2,nrad1,nrad2,w3j,llmax,llvec,lam,c2r,nfps,vfps) &
38 | !$OMP SHARED(p,v1,v2)
39 | !$OMP DO SCHEDULE(dynamic)
40 | do iat=1,natoms
41 | inner = 0.0
42 | ptemp = 0.0
43 | ifeat = 1
44 | do n1=1,nrad1
45 | do n2=1,nrad2
46 | iwig = 1
47 | do il=1,llmax
48 | l1 = llvec(1,il)
49 | l2 = llvec(2,il)
50 | pcmplx = dcmplx(0.0,0.0)
51 | do imu=1,2*lam+1
52 | mu = imu-1-lam
53 | do im1=1,2*l1+1
54 | m1 = im1-1-l1
55 | m2 = m1-mu
56 | if (abs(m2)<=l2) then
57 | im2 = m2+l2+1
58 | pcmplx(imu) = pcmplx(imu) &
59 | + w3j(iwig) * v1(im1,l1+1,n1,iat) * dconjg(v2(im2,l2+1,n2,iat))
60 | iwig = iwig + 1
61 | endif
62 | enddo
63 | enddo
64 | pimag = dimag(matmul(c2r,pcmplx))
65 | do imu=1,2*lam+1
66 | inner = inner + pimag(imu)**2
67 | ptemp(imu,ifeat) = pimag(imu)
68 | enddo
69 | ifeat = ifeat + 1
70 | enddo
71 | enddo
72 | enddo
73 | normfact = dsqrt(inner)
74 | do n=1,nfps
75 | ifps = vfps(n) + 1
76 | do imu=1,2*lam+1
77 | p(imu,n,iat) = ptemp(imu,ifps) / normfact
78 | enddo
79 | enddo
80 | enddo
81 | !$OMP END DO
82 | !$OMP END PARALLEL
83 |
84 | return
85 | END
86 |
--------------------------------------------------------------------------------
/src/equicomb.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE equicomb(natoms,nang1,nang2,nrad1,nrad2,v1,v2,&
2 | wigdim,w3j,llmax,llvec,lam,c2r,featsize,p)
3 |
4 | !use omp_lib
5 | IMPLICIT NONE
6 | INTEGER:: natoms,nang1,nang2,nrad1,nrad2,llmax,lam,wigdim,ifeat
7 | INTEGER:: iat,n1,n2,iwig,l1,l2,il,imu,im1,im2,mu,m1,m2,featsize
8 | INTEGER, DIMENSION(2,llmax):: llvec
9 | REAL*8, DIMENSION(wigdim):: w3j
10 | REAL*8, DIMENSION(2*lam+1):: preal
11 | COMPLEX*16, DIMENSION(2*lam+1):: pcmplx
12 | COMPLEX*16, DIMENSION(2*lam+1,2*lam+1):: c2r
13 | COMPLEX*16, DIMENSION(2*nang1+1,nang1+1,nrad1,natoms):: v1
14 | COMPLEX*16, DIMENSION(2*nang2+1,nang2+1,nrad2,natoms):: v2
15 | REAL*8, DIMENSION(2*lam+1,featsize):: ptemp
16 | REAL*8, DIMENSION(2*lam+1,featsize,natoms):: p
17 | REAL*8:: inner, normfact
18 |
19 | !f2py intent(in) natoms,nang1,nang2,nrad1,nrad2,v1,v2,wigdim,w3j,llmax,llvec,lam,c2r
20 | !f2py intent(in) featsize
21 | !f2py intent(out) p
22 | !f2py depend(natoms) p, v1, v2
23 | !f2py depend(nrad1) v1
24 | !f2py depend(nrad2) v2
25 | !f2py depend(nang1) v1
26 | !f2py depend(nang2) v2
27 | !f2py depend(lam) p, c2r
28 | !f2py depend(llmax) llvec
29 | !f2py depend(wigdim) w3j
30 | !f2py depend(featsize) p
31 |
32 | p = 0.d0
33 |
34 | !$OMP PARALLEL DEFAULT(private) &
35 | !$OMP FIRSTPRIVATE(natoms,nang1,nang2,nrad1,nrad2,w3j,llmax,llvec,lam,c2r,featsize) &
36 | !$OMP SHARED(p,v1,v2)
37 | !$OMP DO SCHEDULE(dynamic)
38 | do iat=1,natoms
39 | inner = 0.0
40 | ptemp = 0.0
41 | ifeat = 1
42 | do n1=1,nrad1
43 | do n2=1,nrad2
44 | iwig = 1
45 | do il=1,llmax
46 | l1 = llvec(1,il)
47 | l2 = llvec(2,il)
48 | pcmplx = dcmplx(0.0,0.0)
49 | do imu=1,2*lam+1
50 | mu = imu-1-lam
51 | do im1=1,2*l1+1
52 | m1 = im1-1-l1
53 | m2 = m1-mu
54 | if (abs(m2)<=l2) then
55 | im2 = m2+l2+1
56 | pcmplx(imu) = pcmplx(imu) &
57 | + w3j(iwig) * v1(im1,l1+1,n1,iat) * dconjg(v2(im2,l2+1,n2,iat))
58 | iwig = iwig + 1
59 | endif
60 | enddo
61 | enddo
62 | preal = dreal(matmul(c2r,pcmplx))
63 | do imu=1,2*lam+1
64 | inner = inner + preal(imu)**2
65 | ptemp(imu,ifeat) = preal(imu)
66 | enddo
67 | ifeat = ifeat + 1
68 | enddo
69 | enddo
70 | enddo
71 | normfact = dsqrt(inner)
72 | do ifeat=1,featsize
73 | do imu=1,2*lam+1
74 | p(imu,ifeat,iat) = ptemp(imu,ifeat) / normfact
75 | enddo
76 | enddo
77 | enddo
78 | !$OMP END DO
79 | !$OMP END PARALLEL
80 |
81 | return
82 | END
83 |
--------------------------------------------------------------------------------
/src/equicombfield.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE equicombfield(natoms,nang1,nrad1,nrad2,v1,v2,wigdim,w3j,llmax,llvec,lam,c2r,p)
2 |
3 | !use omp_lib
4 | IMPLICIT NONE
5 | INTEGER:: natoms,nang1,nrad1,nrad2,llmax,lam,wigdim
6 | INTEGER:: iat,n1,n2,iwig,l1,l2,il,imu,im1,im2,mu,m1,m2
7 | INTEGER, DIMENSION(2,llmax):: llvec
8 | REAL*8, DIMENSION(wigdim):: w3j
9 | REAL*8, DIMENSION(2*lam+1):: preal
10 | COMPLEX*16, DIMENSION(2*lam+1):: pcmplx
11 | COMPLEX*16, DIMENSION(2*lam+1,2*lam+1):: c2r
12 | COMPLEX*16, DIMENSION(2*nang1+1,nang1+1,nrad1,natoms):: v1
13 | COMPLEX*16, DIMENSION(nrad2,natoms):: v2
14 | REAL*8, DIMENSION(2*lam+1,llmax,nrad2,nrad1,natoms):: p
15 |
16 | !f2py intent(in) natoms,nang1,nrad1,nrad2,v1,v2,wigdim,w3j,llmax,llvec,lam,c2r
17 | !f2py intent(out) p
18 | !f2py depend(natoms) p, v1, v2
19 | !f2py depend(nrad1) p, v1
20 | !f2py depend(nrad2) p, v2
21 | !f2py depend(nang1) p, v1
22 | !f2py depend(lam) p, c2r
23 | !f2py depend(llmax) p,llvec
24 | !f2py depend(wigdim) w3j
25 |
26 | p = dcmplx(0.d0,0.d0)
27 |
28 | !$OMP PARALLEL DEFAULT(private) &
29 | !$OMP FIRSTPRIVATE(natoms,nang1,nrad1,nrad2,w3j,llmax,llvec,lam,c2r) &
30 | !$OMP SHARED(p,v1,v2)
31 | !$OMP DO SCHEDULE(dynamic)
32 | do iat=1,natoms
33 | do n1=1,nrad1
34 | do n2=1,nrad2
35 | iwig = 1
36 | do il=1,llmax
37 | l1 = llvec(1,il)
38 | l2 = llvec(2,il)
39 | pcmplx = dcmplx(0.0,0.0)
40 | do imu=1,2*lam+1
41 | mu = imu-1-lam
42 | do im1=1,2*l1+1
43 | m1 = im1-1-l1
44 | m2 = m1-mu
45 | if (abs(m2)<=l2 .and. m2==0) then
46 | im2 = m2+l2+1
47 | pcmplx(imu) = pcmplx(imu) &
48 | + w3j(iwig) * v1(im1,l1+1,n1,iat) * dconjg(v2(n2,iat))
49 | iwig = iwig + 1
50 | endif
51 | enddo
52 | enddo
53 | preal = dreal(matmul(c2r,pcmplx))
54 | do imu=1,2*lam+1
55 | p(imu,il,n2,n1,iat) = preal(imu)
56 | enddo
57 | enddo
58 | enddo
59 | enddo
60 | enddo
61 | !$OMP END DO
62 | !$OMP END PARALLEL
63 |
64 | return
65 | END
66 |
--------------------------------------------------------------------------------
/src/equicombfps.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE equicombfps(natoms, nang1, nang2, nrad1, nrad2, v1, v2, &
2 | wigdim, w3j, llmax, llvec, lam, c2r, featsize, pvec)
3 |
4 | use omp_lib
5 | IMPLICIT NONE
6 | INTEGER :: natoms, nang1, nang2, nrad1, nrad2, llmax, lam, wigdim, ifeat
7 | INTEGER :: iat, n1, n2, iwig, l1, l2, il, imu, im1, im2, mu, m1, m2, featsize, temp1, temp2
8 | INTEGER, DIMENSION(2, llmax) :: llvec
9 | REAL*8, DIMENSION(wigdim) :: w3j
10 | REAL*8, DIMENSION(2*lam+1) :: preal
11 | COMPLEX*16, DIMENSION(2*lam+1) :: pcmplx
12 | COMPLEX*16, DIMENSION(2*lam+1, 2*lam+1) :: c2r
13 | COMPLEX*16, DIMENSION(2*nang1+1, nang1+1, nrad1, natoms) :: v1
14 | COMPLEX*16, DIMENSION(2*nang2+1, nang2+1, nrad2, natoms) :: v2
15 | REAL*8, DIMENSION(2*lam+1, featsize) :: ptemp
16 | REAL*8, DIMENSION(featsize, natoms * (2*lam+1)) :: pvec
17 | REAL*8 :: inner, normfact
18 |
19 | !f2py intent(in) natoms, nang1, nang2, nrad1, nrad2, v1, v2, wigdim, w3j, llmax, llvec, lam, c2r
20 | !f2py intent(in) featsize
21 | !f2py intent(out) pvec
22 | !f2py depend(natoms) pvec, v1, v2
23 | !f2py depend(nrad1) v1
24 | !f2py depend(nrad2) v2
25 | !f2py depend(nang1) v1
26 | !f2py depend(nang2) v2
27 | !f2py depend(lam) pvec, c2r
28 | !f2py depend(llmax) llvec
29 | !f2py depend(wigdim) w3j
30 | !f2py depend(featsize) pvec
31 |
32 | !$OMP PARALLEL DEFAULT(private) &
33 | !$OMP FIRSTPRIVATE(natoms, nang1, nang2, nrad1, nrad2, w3j, llmax, llvec, lam, c2r, featsize) &
34 | !$OMP SHARED(pvec, v1, v2)
35 | !$OMP DO SCHEDULE(dynamic)
36 | do iat = 1, natoms
37 | inner = 0.0
38 | ptemp = 0.0
39 | ifeat = 1
40 | do n1 = 1, nrad1
41 | do n2 = 1, nrad2
42 | iwig = 1
43 | do il = 1, llmax
44 | l1 = llvec(1, il)
45 | l2 = llvec(2, il)
46 | pcmplx = dcmplx(0.0, 0.0)
47 | do imu = 1, 2*lam+1
48 | mu = imu - 1 - lam
49 | do im1 = 1, 2*l1+1
50 | m1 = im1 - 1 - l1
51 | m2 = m1 - mu
52 | if (abs(m2) <= l2) then
53 | im2 = m2 + l2 + 1
54 | pcmplx(imu) = pcmplx(imu) &
55 | + w3j(iwig) * v1(im1, l1+1, n1, iat) * dconjg(v2(im2, l2+1, n2, iat))
56 | iwig = iwig + 1
57 | endif
58 | enddo
59 | enddo
60 | preal = dreal(matmul(c2r, pcmplx))
61 | do imu = 1, 2*lam+1
62 | inner = inner + preal(imu)**2
63 | ptemp(imu, ifeat) = preal(imu)
64 | enddo
65 | ifeat = ifeat + 1
66 | enddo
67 | enddo
68 | enddo
69 | normfact = dsqrt(inner)
70 | do ifeat = 1, featsize
71 | do imu = 1, 2*lam+1
72 | pvec(ifeat, (iat-1)*(2*lam+1) + imu) = ptemp(imu, ifeat) / normfact
73 | enddo
74 | enddo
75 | enddo
76 | !$OMP END DO
77 | !$OMP END PARALLEL
78 |
79 | return
80 | END SUBROUTINE equicombfps
--------------------------------------------------------------------------------
/src/equicombnonorm.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE equicombnonorm(natoms,nang1,nang2,nrad1,nrad2,v1,v2,&
2 | wigdim,w3j,llmax,llvec,lam,c2r,featsize,p)
3 |
4 | !use omp_lib
5 | IMPLICIT NONE
6 | INTEGER:: natoms,nang1,nang2,nrad1,nrad2,llmax,lam,wigdim,ifeat
7 | INTEGER:: iat,n1,n2,iwig,l1,l2,il,imu,im1,im2,mu,m1,m2,featsize
8 | INTEGER, DIMENSION(2,llmax):: llvec
9 | REAL*8, DIMENSION(wigdim):: w3j
10 | REAL*8, DIMENSION(2*lam+1):: preal
11 | COMPLEX*16, DIMENSION(2*lam+1):: pcmplx
12 | COMPLEX*16, DIMENSION(2*lam+1,2*lam+1):: c2r
13 | COMPLEX*16, DIMENSION(2*nang1+1,nang1+1,nrad1,natoms):: v1
14 | COMPLEX*16, DIMENSION(2*nang2+1,nang2+1,nrad2,natoms):: v2
15 | REAL*8, DIMENSION(2*lam+1,featsize):: ptemp
16 | REAL*8, DIMENSION(2*lam+1,featsize,natoms):: p
17 |
18 | !f2py intent(in) natoms,nang1,nang2,nrad1,nrad2,v1,v2,wigdim,w3j,llmax,llvec,lam,c2r
19 | !f2py intent(in) featsize
20 | !f2py intent(out) p
21 | !f2py depend(natoms) p, v1, v2
22 | !f2py depend(nrad1) v1
23 | !f2py depend(nrad2) v2
24 | !f2py depend(nang1) v1
25 | !f2py depend(nang2) v2
26 | !f2py depend(lam) p, c2r
27 | !f2py depend(llmax) llvec
28 | !f2py depend(wigdim) w3j
29 | !f2py depend(featsize) p
30 |
31 | p = 0.d0
32 |
33 | !$OMP PARALLEL DEFAULT(private) &
34 | !$OMP FIRSTPRIVATE(natoms,nang1,nang2,nrad1,nrad2,w3j,llmax,llvec,lam,c2r,featsize) &
35 | !$OMP SHARED(p,v1,v2)
36 | !$OMP DO SCHEDULE(dynamic)
37 | do iat=1,natoms
38 | ptemp = 0.0
39 | ifeat = 1
40 | do n1=1,nrad1
41 | do n2=1,nrad2
42 | iwig = 1
43 | do il=1,llmax
44 | l1 = llvec(1,il)
45 | l2 = llvec(2,il)
46 | pcmplx = dcmplx(0.0,0.0)
47 | do imu=1,2*lam+1
48 | mu = imu-1-lam
49 | do im1=1,2*l1+1
50 | m1 = im1-1-l1
51 | m2 = m1-mu
52 | if (abs(m2)<=l2) then
53 | im2 = m2+l2+1
54 | pcmplx(imu) = pcmplx(imu) &
55 | + w3j(iwig) * v1(im1,l1+1,n1,iat) * dconjg(v2(im2,l2+1,n2,iat))
56 | iwig = iwig + 1
57 | endif
58 | enddo
59 | enddo
60 | preal = dreal(matmul(c2r,pcmplx))
61 | do imu=1,2*lam+1
62 | ptemp(imu,ifeat) = preal(imu)
63 | enddo
64 | ifeat = ifeat + 1
65 | enddo
66 | enddo
67 | enddo
68 | do ifeat=1,featsize
69 | do imu=1,2*lam+1
70 | p(imu,ifeat,iat) = ptemp(imu,ifeat)
71 | enddo
72 | enddo
73 | enddo
74 | !$OMP END DO
75 | !$OMP END PARALLEL
76 |
77 | return
78 | END
79 |
--------------------------------------------------------------------------------
/src/equicombsparse.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE equicombsparse(natoms,nang1,nang2,nrad1,nrad2,v1,v2,&
2 | wigdim,w3j,llmax,llvec,lam,c2r,&
3 | featsize,nfps,vfps,p)
4 |
5 | !use omp_lib
6 | IMPLICIT NONE
7 | INTEGER:: natoms,nang1,nang2,nrad1,nrad2,llmax,lam,wigdim,ifps,ifeat,n
8 | INTEGER:: iat,n1,n2,iwig,l1,l2,il,imu,im1,im2,mu,m1,m2,featsize,nfps
9 | INTEGER, DIMENSION(nfps):: vfps
10 | INTEGER, DIMENSION(2,llmax):: llvec
11 | REAL*8, DIMENSION(wigdim):: w3j
12 | REAL*8, DIMENSION(2*lam+1):: preal
13 | COMPLEX*16, DIMENSION(2*lam+1):: pcmplx
14 | COMPLEX*16, DIMENSION(2*lam+1,2*lam+1):: c2r
15 | COMPLEX*16, DIMENSION(2*nang1+1,nang1+1,nrad1,natoms):: v1
16 | COMPLEX*16, DIMENSION(2*nang2+1,nang2+1,nrad2,natoms):: v2
17 | REAL*8, DIMENSION(2*lam+1,featsize):: ptemp
18 | REAL*8, DIMENSION(2*lam+1,nfps,natoms):: p
19 | REAL*8:: inner,normfact
20 |
21 | !f2py intent(in) natoms,nang1,nang2,nrad1,nrad2,v1,v2,wigdim,w3j,llmax,llvec,lam,c2r
22 | !f2py intent(in) featsize, nfps, vfps
23 | !f2py intent(out) p
24 | !f2py depend(natoms) p, v1, v2
25 | !f2py depend(nrad1) v1
26 | !f2py depend(nrad2) v2
27 | !f2py depend(nang1) v1
28 | !f2py depend(nang2) v2
29 | !f2py depend(lam) p, c2r
30 | !f2py depend(llmax) llvec
31 | !f2py depend(wigdim) w3j
32 | !f2py depend(nfps) vfps, p
33 |
34 | p = 0.d0
35 |
36 | !$OMP PARALLEL DEFAULT(private) &
37 | !$OMP FIRSTPRIVATE(natoms,nang1,nang2,nrad1,nrad2,w3j,llmax,llvec,lam,c2r,nfps,vfps) &
38 | !$OMP SHARED(p,v1,v2)
39 | !$OMP DO SCHEDULE(dynamic)
40 | do iat=1,natoms
41 | inner = 0.0
42 | ptemp = 0.0
43 | ifeat = 1
44 | do n1=1,nrad1
45 | do n2=1,nrad2
46 | iwig = 1
47 | do il=1,llmax
48 | l1 = llvec(1,il)
49 | l2 = llvec(2,il)
50 | pcmplx = dcmplx(0.0,0.0)
51 | do imu=1,2*lam+1
52 | mu = imu-1-lam
53 | do im1=1,2*l1+1
54 | m1 = im1-1-l1
55 | m2 = m1-mu
56 | if (abs(m2)<=l2) then
57 | im2 = m2+l2+1
58 | pcmplx(imu) = pcmplx(imu) &
59 | + w3j(iwig) * v1(im1,l1+1,n1,iat) * dconjg(v2(im2,l2+1,n2,iat))
60 | iwig = iwig + 1
61 | endif
62 | enddo
63 | enddo
64 | preal = dreal(matmul(c2r,pcmplx))
65 | do imu=1,2*lam+1
66 | inner = inner + preal(imu)**2
67 | ptemp(imu,ifeat) = preal(imu)
68 | enddo
69 | ifeat = ifeat + 1
70 | enddo
71 | enddo
72 | enddo
73 | normfact = dsqrt(inner)
74 | do n=1,nfps
75 | ifps = vfps(n) + 1
76 | do imu=1,2*lam+1
77 | p(imu,n,iat) = ptemp(imu,ifps) / normfact
78 | enddo
79 | enddo
80 | enddo
81 | !$OMP END DO
82 | !$OMP END PARALLEL
83 |
84 | return
85 | END
86 |
--------------------------------------------------------------------------------
/src/kernelequicomb.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE kernelequicomb(n1,n2,lam1,lam2,L,nsize,msize,&
2 | cgsize,cgcoefs,knm,k0,kernel)
3 |
4 | !use omp_lib
5 | IMPLICIT NONE
6 | INTEGER:: n1,n2,lam1,lam2,L,nsize,msize,cgsize
7 | REAL*8, DIMENSION(cgsize):: cgcoefs
8 | REAL*8, DIMENSION(n2,n1):: k0
9 | COMPLEX*16, DIMENSION(n2*(2*L+1),n1*(2*L+1)):: knm
10 | COMPLEX*16, DIMENSION(msize,nsize):: kernel
11 |
12 | INTEGER:: i1,i2,iM1,iM2,idx1,idx2,icg1,icg2,mu1size,mu2size
13 | INTEGER:: imu1,imu2,mu1,mu2,ik1,ik2,k1,k2,M1,M2,j1,j2
14 | REAL*8:: cg1,cg2
15 |
16 | !f2py intent(in) n1,n2,lam1,lam2,L,nsize,msize
17 | !f2py intent(in) cgsize,cgcoefs,knm,k0
18 | !f2py intent(out) kernel
19 | !f2py depend(nsize) kernel
20 | !f2py depend(msize) kernel
21 | !f2py depend(cgsize) cgcoefs
22 | !f2py depend(n1) k0,knm
23 | !f2py depend(n2) k0,knm
24 | !f2py depend(L) knm
25 |
26 | mu1size = 2*lam1+1
27 | mu2size = 2*lam2+1
28 |
29 | kernel = 0.d0
30 |
31 | iM1 = 1
32 | idx1 = 1
33 | do i1=1,n1
34 | icg1 = 1
35 | do imu1=1,mu1size
36 | mu1 = imu1-1-lam1
37 | do ik1=1,mu2size
38 | k1 = ik1-1-lam2
39 | M1 = mu1+k1
40 | if (abs(M1).le.L) then
41 | j1 = M1+L
42 | cg1 = cgcoefs(icg1)
43 | iM2 = 1
44 | idx2 = 1
45 | do i2=1,n2
46 | icg2 = 1
47 | do imu2=1,mu1size
48 | mu2 = imu2-1-lam1
49 | do ik2=1,mu2size
50 | k2 = ik2-1-lam2
51 | M2 = mu2+k2
52 | if (abs(M2).le.L) then
53 | j2 = M2+L
54 | cg2 = cgcoefs(icg2)
55 | kernel(iM2,iM1) = kernel(iM2,iM1) + cg1 * cg2 &
56 | * knm(idx2+j2,idx1+j1) * k0(i2,i1)
57 | icg2 = icg2 + 1
58 | endif
59 | iM2 = iM2 + 1
60 | enddo
61 | enddo
62 | idx2 = idx2 + 2*L+1
63 | enddo
64 | icg1 = icg1 + 1
65 | endif
66 | iM1 = iM1 + 1
67 | enddo
68 | enddo
69 | idx1 = idx1 + 2*L+1
70 | enddo
71 |
72 | return
73 | END
74 |
--------------------------------------------------------------------------------
/src/kernelnorm.f90:
--------------------------------------------------------------------------------
1 | SUBROUTINE kernelnorm(n1,n2,msize,normfact1,normfact2,kernel,knorm)
2 |
3 | !use omp_lib
4 | IMPLICIT NONE
5 | INTEGER:: n1,n2,msize,i1,i2,j1,j2,im1,im2
6 | REAL*8, DIMENSION(n2*msize,n1*msize):: kernel, knorm
7 | REAL*8, DIMENSION(n1):: normfact1
8 | REAL*8, DIMENSION(n2):: normfact2
9 |
10 | !f2py intent(in) n1,n2,msize,normfact1,normfact2,kernel
11 | !f2py intent(out) knorm
12 | !f2py depend(n1) kernel, knorm , normfact1
13 | !f2py depend(n2) kernel, knorm , normfact2
14 | !f2py depend(msize) kernel, knorm
15 |
16 | j1 = 1
17 | do i1=1,n1
18 | do im1=1,msize
19 | j2 = 1
20 | do i2=1,n2
21 | do im2=1,msize
22 | knorm(j2,j1) = kernel(j2,j1) / dsqrt(normfact1(i1)*normfact2(i2))
23 | j2 = j2 + 1
24 | enddo
25 | enddo
26 | j1 = j1 + 1
27 | enddo
28 | enddo
29 |
30 | return
31 | END
32 |
--------------------------------------------------------------------------------