4 |
5 | CiderPress: Machine Learned Exchange-Correlation Functionals
6 | ------------------------------------------------------------
7 | 
8 |
9 | CiderPress provides tools for training and evaluating CIDER functionals for use in Density Functional Theory calculations. Interfaces to the GPAW and PySCF codes are included.
10 |
11 | Please see the [CiderPress website](https://mir-group.github.io/CiderPress/) for installation instructions and documentation.
12 |
13 | ## Questions and Comments
14 |
15 | Find a bug? Areas of code unclearly documented? Other questions? Feel free to contact
16 | Kyle Bystrom at kylebystrom@gmail.com AND/OR create an issue on the [Github page](https://github.com/mir-group/CiderPress/).
17 |
18 | ## Citing
19 |
20 | If you find CiderPress or CIDER functionals useful in your research, please cite the following article
21 | ```
22 | @article{PhysRevB.110.075130,
23 | title = {Nonlocal machine-learned exchange functional for molecules and solids},
24 | author = {Bystrom, Kyle and Kozinsky, Boris},
25 | journal = {Phys. Rev. B},
26 | volume = {110},
27 | issue = {7},
28 | pages = {075130},
29 | numpages = {30},
30 | year = {2024},
31 | month = {Aug},
32 | publisher = {American Physical Society},
33 | doi = {10.1103/PhysRevB.110.075130},
34 | url = {https://link.aps.org/doi/10.1103/PhysRevB.110.075130}
35 | }
36 | ```
37 | The above article introduces the CIDER23X functionals and much of the algorithms in CiderPress. If you use the CIDER24X functionals, please also cite
38 | ```
39 | @article{doi:10.1021/acs.jctc.4c00999,
40 | author = {Bystrom, Kyle and Falletta, Stefano and Kozinsky, Boris},
41 | title = {Training Machine-Learned Density Functionals on Band Gaps},
42 | journal = {Journal of Chemical Theory and Computation},
43 | volume = {20},
44 | number = {17},
45 | pages = {7516-7532},
46 | year = {2024},
47 | doi = {10.1021/acs.jctc.4c00999},
48 | note ={PMID: 39178337},
49 | URL = {https://doi.org/10.1021/acs.jctc.4c00999},
50 | eprint = {https://doi.org/10.1021/acs.jctc.4c00999}
51 | }
52 | ```
53 |
--------------------------------------------------------------------------------
/ciderpress/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = "0.4.0"
2 |
--------------------------------------------------------------------------------
/ciderpress/data/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import os
22 |
23 | import numpy as np
24 |
25 | DATA_PATH = os.path.dirname(os.path.abspath(__file__))
26 |
27 |
28 | def get_hgbs_min_exps(Z):
29 | dpath = os.path.join(DATA_PATH, "expnt_mins.npy")
30 | return np.load(dpath)[int(Z)]
31 |
32 |
33 | def get_hgbs_max_exps(Z):
34 | dpath = os.path.join(DATA_PATH, "expnt_maxs.npy")
35 | return np.load(dpath)[int(Z)]
36 |
--------------------------------------------------------------------------------
/ciderpress/data/expnt_maxs.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/data/expnt_maxs.npy
--------------------------------------------------------------------------------
/ciderpress/data/expnt_mins.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/data/expnt_mins.npy
--------------------------------------------------------------------------------
/ciderpress/dft/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/dft/__init__.py
--------------------------------------------------------------------------------
/ciderpress/dft/debug_numint.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import ctypes
22 |
23 | import numpy as np
24 |
25 | from ciderpress.dft.plans import get_cider_exponent
26 | from ciderpress.lib import load_library as load_cider_library
27 |
28 | libcider = load_cider_library("libmcider")
29 |
30 |
31 | def get_get_exponent(gg_kwargs):
32 | def _get_exponent(rho_data):
33 | rho = rho_data[0]
34 | sigma = np.einsum("xg,xg->g", rho_data[1:4], rho_data[1:4])
35 | tau = rho_data[4]
36 | return get_cider_exponent(
37 | rho,
38 | sigma,
39 | tau,
40 | a0=gg_kwargs["a0"],
41 | grad_mul=0,
42 | tau_mul=gg_kwargs["fac_mul"],
43 | nspin=1,
44 | )[0]
45 |
46 | return _get_exponent
47 |
48 |
49 | def get_nonlocal_features(
50 | rho, coords, vvrho, vvweight, vvcoords, get_exponent_r, get_exponent_rp, version="i"
51 | ):
52 | thresh = 1e-8
53 | nfeat = 12 if version == "i" else 4
54 | feat = np.zeros((rho[0].size, nfeat))
55 |
56 | threshind = rho[0] >= thresh
57 | coords = coords[threshind]
58 | expnt_data = get_exponent_r(rho[:, threshind])
59 |
60 | innerthreshind = vvrho[0] >= thresh
61 | vvcoords = vvcoords[innerthreshind]
62 | vvweight = vvweight[innerthreshind]
63 | vvexpnt_data = get_exponent_rp(vvrho[:, innerthreshind])
64 |
65 | vvf = vvrho[0, innerthreshind] * vvweight
66 |
67 | vvcoords = np.asarray(vvcoords, order="C")
68 | coords = np.asarray(coords, order="C")
69 | _feat = np.empty((expnt_data.shape[0], nfeat))
70 |
71 | if version == "i":
72 | libcider.debug_numint_vi(
73 | _feat.ctypes.data_as(ctypes.c_void_p),
74 | vvexpnt_data.ctypes.data_as(ctypes.c_void_p),
75 | vvf.ctypes.data_as(ctypes.c_void_p),
76 | vvcoords.ctypes.data_as(ctypes.c_void_p),
77 | coords.ctypes.data_as(ctypes.c_void_p),
78 | ctypes.c_int(vvcoords.shape[0]),
79 | ctypes.c_int(coords.shape[0]),
80 | )
81 | else:
82 | if version == "j":
83 | fn = libcider.debug_numint_vj
84 | elif version == "k":
85 | fn = libcider.debug_numint_vk
86 | else:
87 | raise ValueError("Version must be i, j, or k")
88 | fn(
89 | _feat.ctypes.data_as(ctypes.c_void_p),
90 | vvexpnt_data.ctypes.data_as(ctypes.c_void_p),
91 | expnt_data.ctypes.data_as(ctypes.c_void_p),
92 | vvf.ctypes.data_as(ctypes.c_void_p),
93 | vvcoords.ctypes.data_as(ctypes.c_void_p),
94 | coords.ctypes.data_as(ctypes.c_void_p),
95 | ctypes.c_int(vvcoords.shape[0]),
96 | ctypes.c_int(coords.shape[0]),
97 | ctypes.c_double(2.0),
98 | )
99 | feat[threshind, :] = _feat
100 | return feat
101 |
--------------------------------------------------------------------------------
/ciderpress/dft/density_util.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import numpy as np
22 |
23 |
24 | def get_sigma(grad_svg):
25 | nspin = grad_svg.shape[0]
26 | shape = grad_svg.shape[2:]
27 | if nspin not in [1, 2]:
28 | raise ValueError("Only 1 or 2 spins supported")
29 | sigma_xg = np.empty((2 * nspin - 1,) + shape)
30 | sigma_xg[::2] = np.einsum("sv...,sv...->s...", grad_svg, grad_svg)
31 | if nspin == 2:
32 | sigma_xg[1] = np.einsum("v...,v...->...", grad_svg[0], grad_svg[1])
33 | return sigma_xg
34 |
35 |
36 | def get_dsigmadf(grad_svg, dgraddf_ovg, spins):
37 | norb = len(spins)
38 | assert dgraddf_ovg.shape[0] == norb
39 | shape = grad_svg.shape[2:]
40 | dsigmadf_og = np.empty((norb,) + shape)
41 | for o, s in enumerate(spins):
42 | dsigmadf_og[o] = 2 * np.einsum("vg,vg->g", grad_svg[s], dgraddf_ovg[o])
43 | return dsigmadf_og
44 |
--------------------------------------------------------------------------------
/ciderpress/dft/model_utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import joblib
22 | import yaml
23 |
24 | from ciderpress.dft.xc_evaluator import MappedXC
25 | from ciderpress.dft.xc_evaluator2 import MappedXC2
26 |
27 |
28 | def load_cider_model(mlfunc, mlfunc_format):
29 | if isinstance(mlfunc, str):
30 | if mlfunc_format is None:
31 | if mlfunc.endswith(".yaml"):
32 | mlfunc_format = "yaml"
33 | elif mlfunc.endswith(".joblib"):
34 | mlfunc_format = "joblib"
35 | else:
36 | raise ValueError("Unsupported file format")
37 | if mlfunc_format == "yaml":
38 | with open(mlfunc, "r") as f:
39 | mlfunc = yaml.load(f, Loader=yaml.CLoader)
40 | elif mlfunc_format == "joblib":
41 | mlfunc = joblib.load(mlfunc)
42 | else:
43 | raise ValueError("Unsupported file format")
44 | if not isinstance(mlfunc, (MappedXC, MappedXC2)):
45 | raise ValueError("mlfunc must be MappedXC")
46 | return mlfunc
47 |
48 |
49 | def get_slxc_settings(xc, xkernel, ckernel, xmix):
50 | if xc is None:
51 | # xc is another way to specify non-mixed part of kernel
52 | xc = ""
53 | if ckernel is not None:
54 | xc = ckernel + " + " + xc
55 | if xkernel is not None:
56 | xc = "{} * {} + {}".format(1 - xmix, xkernel, xc)
57 | if xc.endswith(" + "):
58 | xc = xc[:-3]
59 | return xc
60 |
--------------------------------------------------------------------------------
/ciderpress/dft/sph_harm_coeff.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import numpy as np
22 | from sympy.physics.wigner import clebsch_gordan
23 |
24 | from ciderpress.lib import load_library as load_cider_library
25 |
26 | libcider = load_cider_library("libmcider")
27 |
28 |
29 | def change_basis_real_to_complex(l: int) -> np.ndarray:
30 | # https://en.wikipedia.org/wiki/Spherical_harmonics#Real_form
31 | q = np.zeros((2 * l + 1, 2 * l + 1), dtype=np.complex128)
32 | for m in range(-l, 0):
33 | q[l + m, l + abs(m)] = 1 / np.sqrt(2)
34 | q[l + m, l - abs(m)] = -1j / np.sqrt(2)
35 | q[l, l] = 1
36 | for m in range(1, l + 1):
37 | q[l + m, l + abs(m)] = (-1) ** m / np.sqrt(2)
38 | q[l + m, l - abs(m)] = 1j * (-1) ** m / np.sqrt(2)
39 | # Added factor of 1j**l to make the Clebsch-Gordan coefficients real
40 | return (-1j) ** l * q
41 |
42 |
43 | def su2_clebsch_gordan(l1, l2, l3):
44 | mat = np.zeros(
45 | [
46 | 2 * l1 + 1,
47 | 2 * l2 + 1,
48 | 2 * l3 + 1,
49 | ]
50 | )
51 | for m1 in range(2 * l1 + 1):
52 | for m2 in range(2 * l2 + 1):
53 | for m3 in range(2 * l3 + 1):
54 | mat[m1, m2, m3] = clebsch_gordan(l1, l2, l3, m1 - l1, m2 - l2, m3 - l3)
55 | return mat
56 |
57 |
58 | def clebsch_gordan_e3nn(l1: int, l2: int, l3: int) -> np.ndarray:
59 | r"""
60 | The Clebsch-Gordan coefficients of the real irreducible representations of :math:`SO(3)`.
61 | This function taken from https://github.com/e3nn/e3nn
62 |
63 | Args:
64 | l1 (int): the representation order of the first irrep
65 | l2 (int): the representation order of the second irrep
66 | l3 (int): the representation order of the third irrep
67 |
68 | Returns:
69 | np.ndarray: the Clebsch-Gordan coefficients
70 | """
71 | C = su2_clebsch_gordan(l1, l2, l3)
72 | Q1 = change_basis_real_to_complex(l1)
73 | Q2 = change_basis_real_to_complex(l2)
74 | Q3 = change_basis_real_to_complex(l3)
75 | C = np.einsum("ij,kl,mn,ikn->jlm", Q1, Q2, np.conj(Q3.T), C)
76 |
77 | assert np.all(np.abs(np.imag(C)) < 1e-5)
78 | return np.real(C)
79 |
80 |
81 | def get_deriv_ylm_coeff(lmax):
82 | nlm = (lmax + 1) * (lmax + 1)
83 | gaunt_coeff = np.zeros((5, nlm))
84 | for l in range(lmax + 1):
85 | fe = clebsch_gordan_e3nn(l, 1, l + 1)
86 | for im in range(2 * l + 1):
87 | lm = l * l + im
88 | m = abs(im - l)
89 | l1m = l + 1 - m
90 | fac = ((2 * l + 3) * (l + 1)) ** 0.5
91 | gaunt_coeff[0, lm] = fac * fe[im, 2, im]
92 | gaunt_coeff[1, lm] = fac * fe[im, 2, im + 2]
93 | gaunt_coeff[2, lm] = fac * fe[im, 0, 2 * l - im]
94 | gaunt_coeff[3, lm] = fac * fe[im, 0, 2 * l - im + 2]
95 | gaunt_coeff[4, lm] = np.sqrt(
96 | ((2.0 * l + 3) * l1m * (l + 1 + m) / (2 * l + 1))
97 | )
98 | return gaunt_coeff
99 |
--------------------------------------------------------------------------------
/ciderpress/dft/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/dft/tests/__init__.py
--------------------------------------------------------------------------------
/ciderpress/dft/tests/test_grids_indexer.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import ctypes
22 | import unittest
23 |
24 | import numpy as np
25 | from numpy.testing import assert_almost_equal
26 | from pyscf import gto
27 | from pyscf.dft.gen_grid import libdft
28 |
29 | from ciderpress.pyscf.gen_cider_grid import CiderGrids
30 |
31 |
32 | class TestAtomicGridsIndexer(unittest.TestCase):
33 | def test_a2y(self):
34 | mol = gto.M(atom="H 0 0 0; F 0 0 0.9", basis="def2-tzvp")
35 | grids = CiderGrids(mol)
36 | n = 194
37 | grids.atom_grid = {"H": (30, n), "F": (50, n)}
38 | grids.prune = None
39 | grids.build()
40 | grid = np.empty((n, 4))
41 | libdft.MakeAngularGrid(grid.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(n))
42 | ang_wt = np.ascontiguousarray(grid[:, 3])
43 | indexer = grids.grids_indexer
44 | nalpha = 10
45 | theta_rlmq = indexer.empty_rlmq(nalpha)
46 | theta_new_rlmq = indexer.empty_rlmq(nalpha)
47 | theta_gq = indexer.empty_gq(nalpha)
48 | np.random.seed(89)
49 | theta_rlmq[:] = np.random.normal(size=theta_rlmq.shape)
50 | indexer.reduce_angc_ylm_(theta_rlmq, theta_gq, a2y=False)
51 | shape = theta_gq.shape
52 | theta_gq.shape = (-1, n, nalpha)
53 | theta_gq *= ang_wt[None, :, None] * 4 * np.pi
54 | theta_gq.shape = shape
55 | indexer.reduce_angc_ylm_(theta_new_rlmq, theta_gq, a2y=True)
56 | assert_almost_equal(theta_new_rlmq, theta_rlmq)
57 |
58 | theta_big_gq = np.zeros((theta_gq.shape[0], nalpha + 7))
59 | indexer.reduce_angc_ylm_(theta_rlmq, theta_gq, a2y=False)
60 | indexer.reduce_angc_ylm_(theta_rlmq, theta_big_gq, a2y=False, offset=3)
61 | assert (theta_big_gq[:, :3] == 0).all()
62 | assert (theta_big_gq[:, -4:] == 0).all()
63 | assert_almost_equal(theta_big_gq[:, 3:-4], theta_gq, 14)
64 | theta_big_gq[:, :3] = np.random.normal(size=theta_big_gq[:, :3].shape)
65 | theta_big_gq[:, -4:] = np.random.normal(size=theta_big_gq[:, -4:].shape)
66 | theta_new2_rlmq = np.empty_like(theta_new_rlmq)
67 | indexer.reduce_angc_ylm_(theta_new_rlmq, theta_gq, a2y=True, offset=0)
68 | indexer.reduce_angc_ylm_(theta_new2_rlmq, theta_big_gq, a2y=True, offset=3)
69 | # NOTE this test is fine on laptop with 14 digits but fails on Github CI
70 | assert_almost_equal(theta_new2_rlmq, theta_new_rlmq, 13)
71 |
72 |
73 | if __name__ == "__main__":
74 | unittest.main()
75 |
--------------------------------------------------------------------------------
/ciderpress/external/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/external/__init__.py
--------------------------------------------------------------------------------
/ciderpress/external/sgx_tools.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Copyright 2014-2020 The PySCF Developers. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | # Author: Qiming Sun
17 | # Edits by Kyle Bystrom
18 | #
19 |
20 | import time
21 |
22 | import numpy
23 | from pyscf.sgx.sgx_jk import _gen_batch_nuc, _gen_jk_direct, lib, logger
24 |
25 |
26 | def get_jk_densities(sgx, dm, hermi=1, direct_scf_tol=1e-13):
27 | t0 = time.monotonic(), time.time()
28 | mol = sgx.mol
29 | grids = sgx.grids
30 | gthrd = sgx.grids_thrd
31 |
32 | dms = numpy.asarray(dm)
33 | dm_shape = dms.shape
34 | nao = dm_shape[-1]
35 | dms = dms.reshape(-1, nao, nao)
36 | nset = dms.shape[0]
37 |
38 | if sgx.debug:
39 | batch_nuc = _gen_batch_nuc(mol)
40 | else:
41 | batch_jk = _gen_jk_direct(
42 | mol, "s2", True, True, direct_scf_tol, sgx._opt, pjs=False
43 | )
44 | logger.timer_debug1(mol, "sgX initialziation", *t0)
45 |
46 | ngrids = grids.coords.shape[0]
47 | max_memory = sgx.max_memory - lib.current_memory()[0]
48 | sblk = sgx.blockdim
49 | blksize = min(ngrids, max(4, int(min(sblk, max_memory * 1e6 / 8 / nao**2))))
50 | tnuc = 0, 0
51 | ej, ek = numpy.zeros((nset, ngrids)), numpy.zeros((nset, ngrids))
52 | for i0, i1 in lib.prange(0, ngrids, blksize):
53 | coords = grids.coords[i0:i1]
54 | ao = mol.eval_gto("GTOval", coords)
55 | wao = ao * grids.weights[i0:i1, None]
56 |
57 | fg = lib.einsum("gi,xij->xgj", wao, dms)
58 | fgnw = lib.einsum("gi,xij->xgj", ao, dms)
59 | mask = numpy.zeros(i1 - i0, dtype=bool)
60 | for i in range(nset):
61 | mask |= numpy.any(fg[i] > gthrd, axis=1)
62 | mask |= numpy.any(fg[i] < -gthrd, axis=1)
63 |
64 | inds = numpy.arange(i0, i1)
65 |
66 | numpy.einsum("xgu,gu->xg", fg, ao)
67 | rho = numpy.einsum("xgu,gu->xg", fgnw, ao)
68 |
69 | if sgx.debug:
70 | tnuc = tnuc[0] - time.monotonic(), tnuc[1] - time.time()
71 | gbn = batch_nuc(mol, coords)
72 | tnuc = tnuc[0] + time.monotonic(), tnuc[1] + time.time()
73 | jg = numpy.einsum("gij,xij->xg", gbn, dms)
74 | gv = lib.einsum("gvt,xgt->xgv", gbn, fgnw)
75 | gbn = None
76 | else:
77 | tnuc = tnuc[0] - time.monotonic(), tnuc[1] - time.time()
78 | jg, gv = batch_jk(mol, coords, dms, fgnw.copy(), None)
79 | tnuc = tnuc[0] + time.monotonic(), tnuc[1] + time.time()
80 |
81 | jg = numpy.sum(jg, axis=0)
82 | ej[:, inds] = jg * rho / 2.0
83 | for i in range(nset):
84 | ek[i, inds] = lib.einsum("gu,gu->g", fgnw[i], gv[i])
85 |
86 | jg = gv = None
87 |
88 | ek *= -0.5
89 | return ej, ek
90 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/gpaw/__init__.py
--------------------------------------------------------------------------------
/ciderpress/gpaw/cider_sl.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import numpy as np
22 | import yaml
23 |
24 | from ciderpress.gpaw.cider_kernel import CiderGGAHybridKernel, CiderMGGAHybridKernel
25 | from ciderpress.gpaw.interp_paw import DiffGGA, DiffMGGA
26 |
27 |
28 | class SLCiderGGAHybridWrapper(CiderGGAHybridKernel):
29 | def calculate(self, e_g, n_sg, v_sg, sigma_xg, dedsigma_xg):
30 | super(SLCiderGGAHybridWrapper, self).calculate(
31 | e_g,
32 | n_sg,
33 | v_sg,
34 | sigma_xg,
35 | dedsigma_xg,
36 | np.zeros(
37 | (
38 | n_sg.shape[0],
39 | 3,
40 | )
41 | + e_g.shape,
42 | dtype=e_g.dtype,
43 | ),
44 | )
45 |
46 |
47 | class SLCiderMGGAHybridWrapper(CiderMGGAHybridKernel):
48 | def calculate(self, e_g, n_sg, v_sg, sigma_xg, dedsigma_xg, tau_sg, dedtau_sg):
49 | super(SLCiderMGGAHybridWrapper, self).calculate(
50 | e_g,
51 | n_sg,
52 | v_sg,
53 | sigma_xg,
54 | dedsigma_xg,
55 | tau_sg,
56 | dedtau_sg,
57 | np.zeros(
58 | (
59 | n_sg.shape[0],
60 | 3,
61 | )
62 | + e_g.shape,
63 | dtype=e_g.dtype,
64 | ),
65 | )
66 |
67 |
68 | class _SLCiderBase:
69 | def get_setup_name(self):
70 | return "PBE"
71 |
72 | def todict(self):
73 | kparams = self.kernel.todict()
74 | return {
75 | "kernel_params": kparams,
76 | }
77 |
78 | def get_mlfunc_data(self):
79 | return yaml.dump(self.kernel.mlfunc, Dumper=yaml.CDumper)
80 |
81 |
82 | class SLCiderGGA(_SLCiderBase, DiffGGA):
83 | def todict(self):
84 | d = super(SLCiderGGA, self).todict()
85 | d["_cider_type"] = "SLCiderGGA"
86 | return d
87 |
88 |
89 | class SLCiderMGGA(_SLCiderBase, DiffMGGA):
90 | def todict(self):
91 | d = super(SLCiderMGGA, self).todict()
92 | d["_cider_type"] = "SLCiderMGGA"
93 | return d
94 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/config.py:
--------------------------------------------------------------------------------
1 | GPAW_USE_NEW_PLANS = True
2 | GPAW_DEFAULT_RHO_TOL = 1e-8
3 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/tests/__init__.py:
--------------------------------------------------------------------------------
1 | from numpy.testing import assert_allclose
2 |
3 |
4 | def equal(x, y, t):
5 | assert_allclose(x, y, atol=t)
6 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/tests/test_basic_calc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import unittest
22 |
23 | import numpy as np
24 | from ase.build import bulk
25 | from gpaw import PW
26 | from numpy.testing import assert_almost_equal
27 |
28 | from ciderpress.gpaw.calculator import CiderGPAW, get_cider_functional
29 |
30 | NKPT = 4
31 | REFERENCE_ENERGIES = {
32 | "CIDER23X_SL_GGA": -12.866290987790224,
33 | "CIDER23X_NL_GGA": -13.046146980191777,
34 | "CIDER23X_SL_MGGA": -12.265893307629582,
35 | "CIDER23X_NL_MGGA_DTR": -12.53022643638701,
36 | }
37 | USE_AUGMENT_GRIDS = True
38 |
39 |
40 | def run_calc(xc, spinpol, setups="paw"):
41 | atoms = bulk("Si")
42 | mlfunc = "functionals/{}.yaml".format(xc)
43 | xc = get_cider_functional(
44 | mlfunc,
45 | xmix=0.25,
46 | qmax=300,
47 | lambd=1.8,
48 | pasdw_store_funcs=True,
49 | pasdw_ovlp_fit=True, # not USE_FAST_GPAW,
50 | use_paw=False if setups == "sg15" else True,
51 | )
52 |
53 | atoms.calc = CiderGPAW(
54 | h=0.18, # use a reasonably small grid spacing
55 | xc=xc, # assign the CIDER functional to xc
56 | mode=PW(520), # plane-wave mode with 520 eV cutoff.
57 | txt="-", # output file, '-' for stdout
58 | occupations={"name": "fermi-dirac", "width": 0.01},
59 | kpts={"size": (NKPT, NKPT, NKPT), "gamma": False}, # kpt mesh parameters
60 | convergence={"energy": 1e-7}, # convergence energy in eV/electron
61 | spinpol=spinpol,
62 | setups=setups,
63 | parallel={"augment_grids": USE_AUGMENT_GRIDS},
64 | )
65 | etot = atoms.get_potential_energy() # run the calculation
66 | return etot
67 |
68 |
69 | def generate_test(xcname):
70 | e_ref = REFERENCE_ENERGIES[xcname]
71 |
72 | def run_test(self):
73 | with np.errstate(all="ignore"):
74 | e_rks = run_calc(xcname, False)
75 | e_uks = run_calc(xcname, True)
76 | assert_almost_equal(e_rks, e_ref, 6)
77 | assert_almost_equal(e_uks, e_ref, 6)
78 |
79 | return run_test
80 |
81 |
82 | class TestEnergy(unittest.TestCase):
83 |
84 | test_sl_gga = generate_test("CIDER23X_SL_GGA")
85 |
86 | test_nl_gga = generate_test("CIDER23X_NL_GGA")
87 |
88 | test_sl_mgga = generate_test("CIDER23X_SL_MGGA")
89 |
90 | test_nl_mgga = generate_test("CIDER23X_NL_MGGA_DTR")
91 |
92 |
93 | if __name__ == "__main__":
94 | unittest.main()
95 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/tests/test_fe_force.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import unittest
22 |
23 | import numpy as np
24 | from ase.build import bulk
25 | from gpaw import GPAW, PW, FermiDirac
26 | from gpaw.mpi import world
27 |
28 | from ciderpress.gpaw.calculator import get_cider_functional
29 | from ciderpress.gpaw.tests import equal
30 |
31 |
32 | def numeric_force(atoms, a, i, d=0.001, get_xc=None):
33 | """Compute numeric force on atom with index a, Cartesian component i,
34 | with finite step of size d
35 | """
36 | p0 = atoms.get_positions()
37 | p = p0.copy()
38 | p[a, i] += d
39 | atoms.set_positions(p, apply_constraint=False)
40 | eplus = atoms.get_potential_energy()
41 | p[a, i] -= 2 * d
42 | atoms.set_positions(p, apply_constraint=False)
43 | eminus = atoms.get_potential_energy()
44 | atoms.set_positions(p0, apply_constraint=False)
45 | return (eminus - eplus) / (2 * d)
46 |
47 |
48 | def _run_cider_forces(functional, get_xc=None):
49 | m = [2.2, 2.2]
50 | fe = bulk("Fe", crystalstructure="bcc")
51 | fe = fe * [2, 1, 1]
52 | fe.set_initial_magnetic_moments(m)
53 | if get_xc is not None:
54 | functional = get_xc()
55 | fe.calc = GPAW(
56 | mode=PW(500),
57 | h=0.2,
58 | occupations=FermiDirac(width=0.1),
59 | xc=functional,
60 | kpts=(2, 4, 4),
61 | convergence={"energy": 1e-8},
62 | parallel={"domain": min(2, world.size), "augment_grids": True},
63 | symmetry="off",
64 | txt="fe.txt",
65 | )
66 | pos = fe.get_positions()
67 | pos[0, 1] += 0.08
68 | fe.set_positions(pos)
69 | fe.get_potential_energy()
70 | f1 = fe.get_forces()[0, 2]
71 |
72 | f2 = numeric_force(fe, 0, 2, 0.001, get_xc=get_xc)
73 | print((f1, f2, f1 - f2))
74 | # This is a really loose bound but same order as with PBE
75 | # Just to make things things aren't totally broken
76 | equal(f1, f2, 0.02)
77 |
78 |
79 | def run_cider_forces(functional, get_xc=None):
80 | with np.errstate(all="ignore"):
81 | _run_cider_forces(functional, get_xc=get_xc)
82 |
83 |
84 | class TestForce(unittest.TestCase):
85 | def test_nl_mgga(self):
86 | def get_xc():
87 | return get_cider_functional(
88 | "functionals/CIDER23X_NL_MGGA_DTR.yaml",
89 | qmax=300,
90 | lambd=1.8,
91 | xmix=0.25,
92 | pasdw_ovlp_fit=False,
93 | pasdw_store_funcs=False,
94 | )
95 |
96 | run_cider_forces(get_xc())
97 |
98 |
99 | if __name__ == "__main__":
100 | unittest.main()
101 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/tests/test_fe_stress.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import unittest
22 |
23 | import numpy as np
24 | from ase.build import bulk
25 | from ase.parallel import parprint
26 | from gpaw import GPAW, PW, FermiDirac
27 | from gpaw.mpi import world
28 |
29 | from ciderpress.gpaw.calculator import get_cider_functional
30 |
31 | USE_STORED_REF = True
32 |
33 |
34 | def _run_pw_si_stress(xc, use_pp=False, s_numerical=None):
35 | # This is based on a test from GPAW
36 | k = 3
37 | m = [2.2]
38 | si = bulk("Fe")
39 | si.set_initial_magnetic_moments(m)
40 | si.calc = GPAW(
41 | mode=PW(800),
42 | h=0.15,
43 | occupations=FermiDirac(width=0.1),
44 | xc=xc,
45 | kpts=(k, k, k),
46 | convergence={"energy": 1e-8},
47 | parallel={"domain": min(2, world.size), "augment_grids": True},
48 | txt="fe.txt",
49 | )
50 |
51 | si.set_cell(
52 | np.dot(si.cell, [[1.02, 0, 0.03], [0, 0.99, -0.02], [0.2, -0.01, 1.03]]),
53 | scale_atoms=True,
54 | )
55 | si.get_potential_energy()
56 |
57 | # Trigger nasty bug (fixed in !486):
58 | si.calc.wfs.pt.blocksize = si.calc.wfs.pd.maxmyng - 1
59 | s_analytical = si.get_stress()
60 | if s_numerical is None:
61 | s_numerical = si.calc.calculate_numerical_stress(si, 1e-5)
62 | s_err = s_numerical - s_analytical
63 |
64 | parprint("Analytical stress:\n", s_analytical)
65 | parprint("Numerical stress:\n", s_numerical)
66 | parprint("Error in stress:\n", s_err)
67 | assert np.all(abs(s_err) < 1e-4)
68 |
69 |
70 | def run_pw_si_stress(xc, use_pp=False, s_numerical=None):
71 | with np.errstate(all="ignore"):
72 | _run_pw_si_stress(xc, use_pp=use_pp, s_numerical=s_numerical)
73 |
74 |
75 | def get_xc(fname, use_paw=True):
76 | return get_cider_functional(fname, xmix=0.25, pasdw_ovlp_fit=False, use_paw=use_paw)
77 |
78 |
79 | class TestStress(unittest.TestCase):
80 | def test_nl_mgga(self):
81 | xc = get_xc("functionals/CIDER23X_NL_MGGA_DTR.yaml")
82 | if USE_STORED_REF:
83 | s_numerical = np.array(
84 | [
85 | -0.03445521,
86 | -0.1184332,
87 | -0.09615671,
88 | -0.03262395,
89 | 0.2034452,
90 | 0.01842121,
91 | ]
92 | )
93 | run_pw_si_stress(xc, s_numerical=s_numerical)
94 | else:
95 | run_pw_si_stress(xc, s_numerical=None)
96 |
97 |
98 | if __name__ == "__main__":
99 | unittest.main()
100 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/tests/test_gpaw_grids.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | import numpy as np
4 | from numpy.testing import assert_allclose
5 |
6 | from ciderpress.gpaw.gpaw_grids import SBTFullGridDescriptor
7 |
8 | LMAX = 6
9 |
10 |
11 | def gaussian(l, alpha, r):
12 | return r**l * np.exp(-alpha * r * r)
13 |
14 |
15 | def gaussian_ft(l, alpha, k):
16 | const = np.pi**1.5 / 2**l / alpha ** (1.5 + l)
17 | return const * k**l * np.exp((-0.25 / alpha) * k * k)
18 |
19 |
20 | class TestSBT(unittest.TestCase):
21 | def test_sbt_gaussian(self):
22 | sbtgd = SBTFullGridDescriptor(0.001, 1e12, 0.02, N=1024, lmax=LMAX)
23 | for l in range(LMAX + 1):
24 | for alpha in [0.01, 0.1, 1.0, 10.0, 100.0]:
25 | scale = alpha ** (1.5 + 0.5 * l)
26 | f_g = scale * gaussian(l, alpha, sbtgd.r_g)
27 | fref_k = scale * gaussian_ft(l, alpha, sbtgd.k_g)
28 | ftest_k = 4 * np.pi * sbtgd.transform_single_fwd(f_g, l)
29 | print("MINMAX", np.min(sbtgd.k_g), np.max(sbtgd.k_g))
30 | print(
31 | np.linalg.norm(ftest_k - fref_k),
32 | np.linalg.norm(fref_k),
33 | np.linalg.norm(ftest_k),
34 | )
35 | print(np.max(np.abs(ftest_k - fref_k)))
36 | assert_allclose(ftest_k, fref_k, atol=1e-4, rtol=0)
37 | ftest_g = (0.25 / np.pi) * sbtgd.transform_single_bwd(ftest_k, l)
38 | assert_allclose(ftest_g, f_g, atol=1e-4, rtol=0)
39 |
40 |
41 | if __name__ == "__main__":
42 | unittest.main()
43 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/tests/test_nldf_interface.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import unittest
22 |
23 | import numpy as np
24 | from gpaw.mpi import MPIComm, world
25 | from gpaw.pw.descriptor import PWDescriptor
26 | from numpy.testing import assert_allclose
27 |
28 | from ciderpress.gpaw.nldf_interface import GridDescriptor, LibCiderPW, wrap_fft_mpi
29 |
30 |
31 | class TestLibCiderPW(unittest.TestCase):
32 | def test_pwutil(self):
33 | np.random.seed(98)
34 | comm = MPIComm(world)
35 | N_c = [100, 80, 110]
36 | cell_cv = np.diag(np.ones(3))
37 | ciderpw = LibCiderPW(N_c, cell_cv, comm)
38 | ciderpw.initialize_backend()
39 | gd = GridDescriptor(N_c, cell_cv, comm=MPIComm(world))
40 | pd = PWDescriptor(180, gd, dtype=float)
41 | wrapper = wrap_fft_mpi(pd)
42 | input = np.random.normal(size=N_c)[None, :, :, :]
43 | input = gd.distribute(input)
44 | output_ref = pd.fft(input)
45 | sum = np.abs(output_ref).sum()
46 | sum = pd.gd.comm.sum_scalar(sum)
47 | for i in range(20):
48 | output_test = wrapper.fft(input)
49 | input_test = wrapper.ifft(output_test)
50 | input_ref = pd.ifft(output_ref)
51 | assert_allclose(output_test[0], output_ref)
52 | assert_allclose(input_test[0], input_ref)
53 |
54 |
55 | if __name__ == "__main__":
56 | unittest.main()
57 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/tests/test_pp_force.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import unittest
22 |
23 | import numpy as np
24 | from ase import Atoms
25 | from gpaw import GPAW, PW, FermiDirac, Mixer
26 |
27 | from ciderpress.gpaw.calculator import get_cider_functional
28 | from ciderpress.gpaw.tests import equal
29 |
30 |
31 | def numeric_force(atoms, a, i, d=0.001, get_xc=None):
32 | """Compute numeric force on atom with index a, Cartesian component i,
33 | with finite step of size d
34 | """
35 | p0 = atoms.get_positions()
36 | p = p0.copy()
37 | p[a, i] += d
38 | atoms.set_positions(p, apply_constraint=False)
39 | eplus = atoms.get_potential_energy()
40 | p[a, i] -= 2 * d
41 | atoms.set_positions(p, apply_constraint=False)
42 | eminus = atoms.get_potential_energy()
43 | atoms.set_positions(p0, apply_constraint=False)
44 | return (eminus - eplus) / (2 * d)
45 |
46 |
47 | def _run_cider_forces(functional, get_xc=None):
48 | a = 5.45
49 | bulk = Atoms(
50 | symbols="Si8",
51 | positions=[
52 | (0, 0, 0.1 / a),
53 | (0, 0.5, 0.5),
54 | (0.5, 0, 0.5),
55 | (0.5, 0.5, 0),
56 | (0.25, 0.25, 0.25),
57 | (0.25, 0.75, 0.75),
58 | (0.75, 0.25, 0.75),
59 | (0.75, 0.75, 0.25),
60 | ],
61 | pbc=True,
62 | )
63 | bulk.set_cell((a, a, a), scale_atoms=True)
64 | if get_xc is not None:
65 | functional = get_xc()
66 | calc = GPAW(
67 | h=0.20,
68 | mode=PW(350),
69 | xc=functional,
70 | nbands="150%",
71 | occupations=FermiDirac(width=0.01),
72 | kpts=(3, 3, 3),
73 | convergence={"energy": 1e-7},
74 | mixer=Mixer(0.7, 8, 50),
75 | setups="sg15",
76 | parallel={"augment_grids": True},
77 | )
78 | bulk.calc = calc
79 | f1 = bulk.get_forces()[0, 2]
80 | bulk.get_potential_energy()
81 |
82 | f2 = numeric_force(bulk, 0, 2, 0.001, get_xc=get_xc)
83 | print((f1, f2, f1 - f2))
84 | equal(f1, f2, 0.0005)
85 |
86 |
87 | def run_cider_forces(functional, get_xc=None):
88 | with np.errstate(all="ignore"):
89 | _run_cider_forces(functional, get_xc=get_xc)
90 |
91 |
92 | class TestForce(unittest.TestCase):
93 | def test_sl_gga(self):
94 | run_cider_forces(get_cider_functional("functionals/CIDER23X_SL_GGA.yaml"))
95 |
96 | @unittest.expectedFailure
97 | def test_sl_mgga(self):
98 | run_cider_forces(get_cider_functional("functionals/CIDER23X_SL_MGGA.yaml"))
99 |
100 | def test_nl_gga(self):
101 | def get_xc():
102 | return get_cider_functional(
103 | "functionals/CIDER23X_NL_GGA.yaml",
104 | qmax=300,
105 | lambd=1.8,
106 | xmix=0.25,
107 | pasdw_ovlp_fit=True,
108 | pasdw_store_funcs=True,
109 | use_paw=False,
110 | )
111 |
112 | run_cider_forces(get_xc())
113 |
114 | @unittest.expectedFailure
115 | def test_nl_mgga(self):
116 | def get_xc():
117 | return get_cider_functional(
118 | "functionals/CIDER23X_NL_MGGA_DTR.yaml",
119 | qmax=300,
120 | lambd=1.8,
121 | xmix=0.25,
122 | pasdw_ovlp_fit=True,
123 | pasdw_store_funcs=False,
124 | use_paw=False,
125 | )
126 |
127 | run_cider_forces(get_xc())
128 |
129 |
130 | if __name__ == "__main__":
131 | unittest.main()
132 |
--------------------------------------------------------------------------------
/ciderpress/gpaw/tests/test_si_force.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import unittest
22 |
23 | import numpy as np
24 | from ase import Atoms
25 | from gpaw import GPAW, PW, FermiDirac, Mixer
26 |
27 | from ciderpress.gpaw.calculator import get_cider_functional
28 | from ciderpress.gpaw.tests import equal
29 |
30 | USE_AUGMENT_GRIDS = True
31 |
32 |
33 | def numeric_force(atoms, a, i, d=0.001, get_xc=None):
34 | """Compute numeric force on atom with index a, Cartesian component i,
35 | with finite step of size d
36 | """
37 | p0 = atoms.get_positions()
38 | p = p0.copy()
39 | p[a, i] += d
40 | atoms.set_positions(p, apply_constraint=False)
41 | eplus = atoms.get_potential_energy()
42 | p[a, i] -= 2 * d
43 | atoms.set_positions(p, apply_constraint=False)
44 | eminus = atoms.get_potential_energy()
45 | atoms.set_positions(p0, apply_constraint=False)
46 | return (eminus - eplus) / (2 * d)
47 |
48 |
49 | def _run_cider_forces(functional, get_xc=None):
50 | a = 5.45
51 | bulk = Atoms(
52 | symbols="Si8",
53 | positions=[
54 | (0, 0, 0.1 / a),
55 | (0, 0.5, 0.5),
56 | (0.5, 0, 0.5),
57 | (0.5, 0.5, 0),
58 | (0.25, 0.25, 0.25),
59 | (0.25, 0.75, 0.75),
60 | (0.75, 0.25, 0.75),
61 | (0.75, 0.75, 0.25),
62 | ],
63 | pbc=True,
64 | )
65 | bulk.set_cell((a, a, a), scale_atoms=True)
66 | if get_xc is not None:
67 | functional = get_xc()
68 | calc = GPAW(
69 | h=0.20,
70 | mode=PW(350),
71 | xc=functional,
72 | nbands="150%",
73 | occupations=FermiDirac(width=0.01),
74 | kpts=(3, 3, 3),
75 | convergence={"energy": 1e-8},
76 | mixer=Mixer(0.7, 8, 50),
77 | parallel={"augment_grids": USE_AUGMENT_GRIDS},
78 | )
79 | bulk.calc = calc
80 | f1 = bulk.get_forces()[0, 2]
81 | bulk.get_potential_energy()
82 |
83 | f2 = numeric_force(bulk, 0, 2, 0.001, get_xc=get_xc)
84 | print((f1, f2, f1 - f2))
85 | equal(f1, f2, 0.001)
86 |
87 |
88 | def run_cider_forces(functional, get_xc=None):
89 | with np.errstate(all="ignore"):
90 | _run_cider_forces(functional, get_xc=get_xc)
91 |
92 |
93 | class TestForce(unittest.TestCase):
94 | def test_sl_gga(self):
95 | run_cider_forces(get_cider_functional("functionals/CIDER23X_SL_GGA.yaml"))
96 |
97 | def test_sl_mgga(self):
98 | run_cider_forces(get_cider_functional("functionals/CIDER23X_SL_MGGA.yaml"))
99 |
100 | def test_nl_gga(self):
101 | def get_xc():
102 | return get_cider_functional(
103 | "functionals/CIDER23X_NL_GGA.yaml",
104 | qmax=300,
105 | lambd=1.8,
106 | xmix=0.25,
107 | pasdw_ovlp_fit=True,
108 | pasdw_store_funcs=True,
109 | )
110 |
111 | run_cider_forces(get_xc())
112 |
113 | def test_nl_mgga(self):
114 | def get_xc():
115 | return get_cider_functional(
116 | "functionals/CIDER23X_NL_MGGA_DTR.yaml",
117 | qmax=300,
118 | lambd=1.8,
119 | xmix=0.25,
120 | pasdw_ovlp_fit=True,
121 | pasdw_store_funcs=False,
122 | )
123 |
124 | run_cider_forces(get_xc())
125 |
126 |
127 | if __name__ == "__main__":
128 | unittest.main()
129 |
--------------------------------------------------------------------------------
/ciderpress/lib/__init__.py:
--------------------------------------------------------------------------------
1 | import ctypes
2 |
3 | from ciderpress.lib.load import load_library
4 |
5 | __all__ = ["load_library", "c_double_p", "c_int_p", "c_null_ptr"]
6 |
7 | c_double_p = ctypes.POINTER(ctypes.c_double)
8 | c_int_p = ctypes.POINTER(ctypes.c_int)
9 | c_null_ptr = ctypes.POINTER(ctypes.c_void_p)
10 |
--------------------------------------------------------------------------------
/ciderpress/lib/fft_plan.py:
--------------------------------------------------------------------------------
1 | import ctypes
2 |
3 | import numpy as np
4 |
5 | from ciderpress.lib import load_library
6 |
7 | libfft = load_library("libfft_wrapper")
8 |
9 | libfft.allocate_fftnd_plan.restype = ctypes.c_void_p
10 | libfft.malloc_fft_plan_in_array.restype = ctypes.c_void_p
11 | libfft.malloc_fft_plan_out_array.restype = ctypes.c_void_p
12 | libfft.get_fft_plan_in_array.restype = ctypes.c_void_p
13 | libfft.get_fft_plan_out_array.restype = ctypes.c_void_p
14 | libfft.get_fft_input_size.restype = ctypes.c_int
15 | libfft.get_fft_output_size.restype = ctypes.c_int
16 |
17 |
18 | class FFTWrapper:
19 | def __init__(
20 | self, dims, ntransform=1, fwd=True, r2c=False, inplace=False, batch_first=True
21 | ):
22 | self._dims = dims
23 | self._ntransform = ntransform
24 | self._fwd = fwd
25 | self._r2c = r2c
26 | self._inplace = inplace
27 | self._batch_first = batch_first
28 | rshape = [d for d in dims]
29 | if r2c:
30 | kshape = [d for d in dims[:-1]] + [dims[-1] // 2 + 1]
31 | else:
32 | kshape = [d for d in dims]
33 | if batch_first:
34 | rshape.insert(0, self._ntransform)
35 | kshape.insert(0, self._ntransform)
36 | else:
37 | rshape.append(self._ntransform)
38 | kshape.append(self._ntransform)
39 | if fwd:
40 | self._inshape = tuple(rshape)
41 | self._outshape = tuple(kshape)
42 | else:
43 | self._inshape = tuple(kshape)
44 | self._outshape = tuple(rshape)
45 | dims = np.asarray(dims, dtype=np.int32)
46 | self._ptr = ctypes.c_void_p(
47 | libfft.allocate_fftnd_plan(
48 | ctypes.c_int(len(dims)),
49 | dims.ctypes.data_as(ctypes.c_void_p),
50 | ctypes.c_int(1 if fwd else 0),
51 | ctypes.c_int(1 if r2c else 0),
52 | ctypes.c_int(self._ntransform),
53 | ctypes.c_int(1 if inplace else 0),
54 | ctypes.c_int(1 if batch_first else 0),
55 | )
56 | )
57 | self._in = ctypes.c_void_p(libfft.malloc_fft_plan_in_array(self._ptr))
58 | if self._inplace:
59 | self._out = None
60 | else:
61 | self._out = ctypes.c_void_p(libfft.malloc_fft_plan_out_array(self._ptr))
62 | libfft.initialize_fft_plan(
63 | self._ptr,
64 | self._in,
65 | self._out,
66 | )
67 |
68 | def __del__(self):
69 | libfft.free_fft_plan(self._ptr)
70 | libfft.free_fft_array(self._in)
71 | if not self._inplace:
72 | libfft.free_fft_array(self._out)
73 |
74 | @property
75 | def input_shape(self):
76 | return self._inshape
77 |
78 | @property
79 | def output_shape(self):
80 | return self._outshape
81 |
82 | def call(self, x):
83 | if x.shape != self._inshape:
84 | raise ValueError(f"Expected input of shape {self._inshape}, got {x.shape}")
85 | dtype = np.float64 if (self._r2c and not self._fwd) else np.complex128
86 | out = np.empty(self._outshape, dtype=dtype)
87 | libfft.write_fft_input(self._ptr, x.ctypes.data_as(ctypes.c_void_p))
88 | libfft.execute_fft_plan(self._ptr)
89 | libfft.read_fft_output(self._ptr, out.ctypes.data_as(ctypes.c_void_p))
90 | return out
91 |
--------------------------------------------------------------------------------
/ciderpress/lib/fft_wrapper/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | if (HAVE_MPI)
3 | add_library(fft_wrapper SHARED
4 | cider_fft.c
5 | cider_mpi_fft.c
6 | )
7 | else()
8 | add_library(fft_wrapper SHARED
9 | cider_fft.c
10 | )
11 | endif()
12 |
13 | set_target_properties(fft_wrapper PROPERTIES
14 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}
15 | COMPILE_FLAGS ${OpenMP_C_FLAGS}
16 | LINK_FLAGS ${OpenMP_C_FLAGS})
17 |
18 | configure_file(
19 | ${PROJECT_SOURCE_DIR}/fft_wrapper/config.h.in
20 | ${PROJECT_SOURCE_DIR}/fft_wrapper/cider_fft_config.h
21 | NEWLINE_STYLE UNIX
22 | )
23 |
24 | if (HAVE_MPI)
25 | target_link_libraries(fft_wrapper PUBLIC MPI::MPI_C)
26 | endif()
27 |
28 | if (FFT_BACKEND EQUAL 1) # MKL
29 | target_include_directories(fft_wrapper PUBLIC ${MKL_INCLUDE_DIR})
30 | target_link_libraries(fft_wrapper PUBLIC MKL::MKL)
31 | if (HAVE_MPI)
32 | target_link_libraries(fft_wrapper PUBLIC MKL::mkl_cdft_core)
33 | endif()
34 | else() # FFTW
35 | target_link_libraries(fft_wrapper PRIVATE fftw3)
36 | target_link_libraries(fft_wrapper PRIVATE fftw3_omp)
37 | if (HAVE_MPI)
38 | target_link_libraries(fft_wrapper PRIVATE fftw3_mpi)
39 | endif()
40 | endif()
41 |
--------------------------------------------------------------------------------
/ciderpress/lib/fft_wrapper/cider_fft.h:
--------------------------------------------------------------------------------
1 | #ifndef _CIDER_FFT_H
2 | #define _CIDER_FFT_H
3 |
4 | #include "cider_fft_config.h"
5 |
6 | #if FFT_BACKEND == FFT_MKL_BACKEND
7 | #include
8 | #include
9 | #include
10 | #else // FFTW
11 | #include
12 | #include
13 | #endif
14 | #if HAVE_MPI
15 | #include
16 | #endif
17 |
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | typedef struct fft_plan {
24 | int is_initialized;
25 | int ndim;
26 | int *dims;
27 | int r2c;
28 | int ntransform;
29 | size_t fft_in_size;
30 | size_t fft_out_size;
31 | int fwd;
32 | int batch_first;
33 | int inplace;
34 | int stride;
35 | int idist;
36 | int odist;
37 | void *in;
38 | void *out;
39 | #if FFT_BACKEND == FFT_MKL_BACKEND
40 | DFTI_DESCRIPTOR_HANDLE handle;
41 | DFTI_DESCRIPTOR_HANDLE xhandle;
42 | DFTI_DESCRIPTOR_HANDLE yhandle;
43 | DFTI_DESCRIPTOR_HANDLE zhandle;
44 | #else // FFTW
45 | fftw_plan plan;
46 | #endif
47 | } fft_plan_t;
48 |
49 | int cider_fft_is_initialized();
50 |
51 | int cider_fft_is_threaded();
52 |
53 | #if FFT_BACKEND == FFT_MKL_BACKEND
54 | int cider_fft_get_num_mkl_threads();
55 | #endif
56 |
57 | void cider_fft_initialize();
58 |
59 | void cider_fft_set_nthread(int nthread);
60 |
61 | #if FFT_BACKEND == FFT_MKL_BACKEND
62 | void cider_fft_init_fft3d_1d_parts(const int ntransform, const int nx,
63 | const int ny, const int nz, const int r2c,
64 | const int transpose, const int inplace,
65 | DFTI_DESCRIPTOR_HANDLE *xhandlep,
66 | DFTI_DESCRIPTOR_HANDLE *yhandlep,
67 | DFTI_DESCRIPTOR_HANDLE *zhandlep);
68 | #endif
69 |
70 | fft_plan_t *allocate_fftnd_plan(int ndim, int *dims, int fwd, int r2c,
71 | int ntransform, int inplace, int batch_first);
72 |
73 | int initialize_fft_plan(fft_plan_t *plan, void *in_array, void *out_array);
74 |
75 | void execute_fft_plan(fft_plan_t *plan);
76 |
77 | void free_fft_plan(fft_plan_t *plan);
78 |
79 | void *malloc_fft_plan_in_array(fft_plan_t *plan);
80 |
81 | void *malloc_fft_plan_out_array(fft_plan_t *plan);
82 |
83 | void *alloc_fft_array(size_t objsize);
84 |
85 | void free_fft_array(void *arr);
86 |
87 | #endif
88 |
--------------------------------------------------------------------------------
/ciderpress/lib/fft_wrapper/cider_mpi_fft.h:
--------------------------------------------------------------------------------
1 | #ifndef _CIDER_MPI_FFT_H
2 | #define _CIDER_MPI_FFT_H
3 | #if 1
4 |
5 | #include "cider_fft_config.h"
6 |
7 | #if FFT_BACKEND == FFT_MKL_BACKEND
8 | #include
9 | #include
10 | #include
11 | #include
12 | #else // FFTW
13 | #include
14 | #include
15 | #include
16 | #endif
17 | #include
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | typedef struct mpi_fft3d_plan {
25 | MPI_Comm comm;
26 | int r_offset[3];
27 | int r_Nlocal[3];
28 | int r_Nglobal[3];
29 | int k_offset[3];
30 | int k_Nlocal[3];
31 | int k_Nglobal[3];
32 | int xpp;
33 | int ypp;
34 | int r2c;
35 | int ntransform;
36 | size_t fft_in_size;
37 | size_t fft_out_size;
38 | size_t work_array_size;
39 | int fwd;
40 | int inplace;
41 | void *work;
42 | #if FFT_BACKEND == FFT_MKL_BACKEND
43 | DFTI_DESCRIPTOR_HANDLE xhandle;
44 | DFTI_DESCRIPTOR_HANDLE yhandle;
45 | DFTI_DESCRIPTOR_HANDLE zhandle;
46 | #else // FFTW
47 | fftw_plan fwd_plan;
48 | fftw_plan bwd_plan;
49 | #endif
50 | } mpi_fft3d_plan_t;
51 |
52 | mpi_fft3d_plan_t *allocate_mpi_fft3d_plan(MPI_Comm comm, const int *dims,
53 | int r2c, int ntransform);
54 |
55 | void execute_mpi_fft3d_fwd(mpi_fft3d_plan_t *plan);
56 |
57 | void execute_mpi_fft3d_bwd(mpi_fft3d_plan_t *plan);
58 |
59 | void free_mpi_fft3d_plan(mpi_fft3d_plan_t *plan);
60 |
61 | #endif
62 | #endif
63 |
--------------------------------------------------------------------------------
/ciderpress/lib/fft_wrapper/config.h.in:
--------------------------------------------------------------------------------
1 | #ifndef _CIDER_FFT_CONFIG_H
2 | #define _CIDER_FFT_CONFIG_H
3 |
4 | #define FFT_MKL_BACKEND 1
5 | #define FFT_FFTW_BACKEND 2
6 |
7 | #cmakedefine01 HAVE_MPI
8 | #cmakedefine FFT_BACKEND @FFT_BACKEND@
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/ciderpress/lib/load.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import numpy
4 |
5 |
6 | def load_library(libname):
7 | _loaderpath = os.path.dirname(__file__)
8 | return numpy.ctypeslib.load_library(libname, _loaderpath)
9 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | add_library(mcider SHARED
3 | frac_lapl.c cider_coefs.c cider_grids.c spline.c sph_harm.c
4 | conv_interpolation.c convolutions.c fast_sdmx.c pbc_tools.c debug_numint.c
5 | model_utils.c
6 | )
7 |
8 | set_target_properties(mcider PROPERTIES
9 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}
10 | COMPILE_FLAGS ${OpenMP_C_FLAGS}
11 | LINK_FLAGS ${OpenMP_C_FLAGS})
12 |
13 | if (HAVE_MPI)
14 | target_link_libraries(mcider PRIVATE MPI::MPI_C)
15 | endif()
16 | if (BUILD_WITH_MKL)
17 | target_link_libraries(mcider PRIVATE MKL::MKL)
18 | target_include_directories(mcider PRIVATE ${MKL_INCLUDE_DIR})
19 | else()
20 | target_link_libraries(mcider PRIVATE ${BLAS_LIBRARIES})
21 | target_link_libraries(mcider PRIVATE ${LAPACK_LIBRARIES})
22 | endif()
23 | target_include_directories(mcider PRIVATE ../fft_wrapper)
24 | target_link_libraries(mcider PRIVATE fft_wrapper)
25 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/cider_grids.c:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #include "fblas.h"
21 | #include
22 | #include
23 |
24 | void reduce_angc_to_ylm(double *theta_rlmq, double *y_glm, double *theta_gq,
25 | int *rad_loc, int *ylm_loc, int nalpha, int nrad,
26 | int ngrids, int nlm, int stride, int offset) {
27 | theta_gq = theta_gq + offset;
28 | #pragma omp parallel
29 | {
30 | double ALPHA = 1.0;
31 | double BETA = 0.0;
32 | char NTRANS = 'N';
33 | char TRANS = 'T';
34 | int r, nw;
35 | double *y_wlm, *theta_lmq, *theta_wq;
36 | #pragma omp for schedule(dynamic, 4)
37 | for (r = 0; r < nrad; r++) {
38 | y_wlm = y_glm + ylm_loc[r] * nlm;
39 | nw = rad_loc[r + 1] - rad_loc[r];
40 | theta_lmq = theta_rlmq + r * nlm * nalpha;
41 | theta_wq = theta_gq + rad_loc[r] * stride;
42 | dgemm_(&NTRANS, &TRANS, &nalpha, &nlm, &nw, &ALPHA, theta_wq,
43 | &stride, y_wlm, &nlm, &BETA, theta_lmq, &nalpha);
44 | }
45 | }
46 | }
47 |
48 | void reduce_ylm_to_angc(double *theta_rlmq, double *y_glm, double *theta_gq,
49 | int *rad_loc, int *ylm_loc, int nalpha, int nrad,
50 | int ngrids, int nlm, int stride, int offset) {
51 | theta_gq = theta_gq + offset;
52 | #pragma omp parallel
53 | {
54 | double ALPHA = 1.0;
55 | double BETA = 0.0;
56 | char NTRANS = 'N';
57 | char TRANS = 'T';
58 | int r, nw;
59 | double *y_wlm, *theta_lmq, *theta_wq;
60 | #pragma omp for schedule(dynamic, 4)
61 | for (r = 0; r < nrad; r++) {
62 | y_wlm = y_glm + ylm_loc[r] * nlm;
63 | nw = rad_loc[r + 1] - rad_loc[r];
64 | theta_lmq = theta_rlmq + r * nlm * nalpha;
65 | theta_wq = theta_gq + rad_loc[r] * stride;
66 | dgemm_(&NTRANS, &NTRANS, &nalpha, &nw, &nlm, &ALPHA, theta_lmq,
67 | &nalpha, y_wlm, &nlm, &BETA, theta_wq, &stride);
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/conv_interpolation.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #ifndef _CONV_INTERPOLATION_H
21 | #define _CONV_INTERPOLATION_H
22 |
23 | typedef struct {
24 | int *loc_i;
25 | int *num_i;
26 | double *rel_ord_coords;
27 | int *ind_ord_fwd;
28 | int *ind_ord_bwd;
29 | int nrad;
30 | double aparam;
31 | double dparam;
32 | int ngrids;
33 | int buffer_size;
34 | } spline_locator;
35 |
36 | typedef struct {
37 | spline_locator *sloc_list;
38 | int natm;
39 | } spline_loc_list;
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/fast_sdmx.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #ifndef FAST_SDMX_H
21 | #define FAST_SDMX_H
22 | #include "pyscf_gto.h"
23 | #include
24 | #include
25 |
26 | void SDMXeval_rad_iter(FPtr_eval_sdmx_rad feval, FPtr_exp_sdmx fexp, double fac,
27 | size_t nao, size_t ngrids, size_t bgrids, int param[],
28 | int *shls_slice, int *rf_loc, double *buf, double *vbas,
29 | double *coord, uint8_t *non0table, int *atm, int natm,
30 | int *bas, int nbas, double *env, double *alphas,
31 | double *alpha_norms, int nalpha);
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/fblas.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #ifndef _CIDER_FBLAS_H
21 | #define _CIDER_FBLAS_H
22 |
23 | #if defined __cplusplus
24 | extern "C" {
25 | #endif
26 | #include
27 |
28 | double ddot_(const int *, const double *, const int *, const double *,
29 | const int *);
30 |
31 | void dgemv_(const char *, const int *, const int *, const double *,
32 | const double *, const int *, const double *, const int *,
33 | const double *, const double *, const int *);
34 |
35 | void dtrtri_(const char *, const char *, const int *, const double *,
36 | const int *, const int *);
37 |
38 | void dtrmv_(const char *, const char *, const char *, const int *,
39 | const double *, const int *, const double *, const int *);
40 |
41 | void dgemm_(const char *, const char *, const int *, const int *, const int *,
42 | const double *, const double *, const int *, const double *,
43 | const int *, const double *, double *, const int *);
44 |
45 | void dpotrs_(const char *, const int *, const int *, const double *,
46 | const int *, const double *, const int *, const int *);
47 |
48 | void dpotrf_(const char *, const int *, const double *, const int *,
49 | const int *);
50 |
51 | #if defined __cplusplus
52 | } // end extern "C"
53 | #endif
54 |
55 | #endif
56 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/pyscf_gto.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #include
21 | #ifndef PYSCF_GTO_H_
22 | #define PYSCF_GTO_H_
23 |
24 | #define CHARGE_OF 0
25 | #define PTR_COORD 1
26 | #define NUC_MOD_OF 2
27 | #define PTR_ZETA 3
28 | #define PTR_FRAC_CHARGE 4
29 | #define RESERVE_ATMSLOT 5
30 | #define ATM_SLOTS 6
31 |
32 | #define ATOM_OF 0
33 | #define ANG_OF 1
34 | #define NPRIM_OF 2
35 | #define NCTR_OF 3
36 | #define KAPPA_OF 4
37 | #define PTR_EXP 5
38 | #define PTR_COEFF 6
39 | #define RESERVE_BASLOT 7
40 | #define BAS_SLOTS 8
41 |
42 | #define POS_E1 0
43 | #define TENSOR 1
44 |
45 | #define LMAX ANG_MAX
46 | #define SIMDD 8
47 | #define NCTR_CART 128
48 | #define BLKSIZE 56
49 | #define NPRIMAX 40
50 | #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
51 | #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
52 |
53 | #define ALIGN8_UP(buf) (void *)(((uintptr_t)buf + 7) & (-(uintptr_t)8))
54 |
55 | typedef int (*FPtr_exp)(double *ectr, double *coord, double *alpha,
56 | double *coeff, int l, int nprim, int nctr,
57 | size_t ngrids, double fac);
58 | typedef void (*FPtr_eval)(double *gto, double *ri, double *exps, double *coord,
59 | double *alpha, double *coeff, double *env, int l,
60 | int np, int nc, size_t nao, size_t ngrids,
61 | size_t blksize);
62 | typedef int (*FPtr_exp_sdmx)(double *ectr, double *coord, double *alpha,
63 | double *coeff, int l, int nprim, int nctr,
64 | size_t ngrids, double fac, double conv_alpha,
65 | double conv_alpha_coeff);
66 | typedef void (*FPtr_eval_sdmx)(double *gto, double *ri, double *exps,
67 | double *coord, double *alpha, double *coeff,
68 | double *env, int l, int np, int nc, size_t nao,
69 | size_t ngrids, size_t blksize, double *ylm_vmg,
70 | int mg_stride);
71 | typedef void (*FPtr_eval_sdmx_rad)(double *vbas, double *exps, int nc,
72 | size_t nao, size_t ngrids, size_t blksize,
73 | int stride);
74 |
75 | #endif
76 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/sph_harm.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #ifndef _SPH_HARM_CIDER
21 | #define _SPH_HARM_CIDER
22 |
23 | #include
24 |
25 | #define SQRT2 1.4142135623730950488
26 | #define SQRT3 1.7320508075688772936
27 | #define SPHF0 0.28209479177387814346
28 |
29 | typedef struct {
30 | int nlm; // (lmax+1) * (lmax+1)
31 | int lmax;
32 | int lp1; // (lmax+1)
33 | double *coef0; // size nlm, indexed as l, m
34 | double *coef1; // size nlm, indexed as l, m
35 | double *c0; // size lp1, indexed as l
36 | double *c1; // size lp1, indexed as l
37 | double complex *ylm; // size nlm, indexed as l, m
38 | double complex *dylm; // size nlm, indexed as l, m
39 | } sphbuf;
40 |
41 | sphbuf setup_sph_harm_buffer(int nlm);
42 |
43 | void free_sph_harm_buffer(sphbuf buf);
44 |
45 | void recursive_sph_harm(sphbuf buf, double *r, double *res);
46 |
47 | void recursive_sph_harm_deriv(sphbuf buf, double *r, double *res, double *dres);
48 |
49 | void remove_radial_grad(sphbuf buf, double *r, double *dres);
50 |
51 | void recursive_sph_harm_vec(int nlm, int n, double *r, double *res);
52 |
53 | void recursive_sph_harm_deriv_vec(int nlm, int n, double *r, double *res,
54 | double *dres);
55 |
56 | #endif
57 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/spline.c:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #include "spline.h"
21 | #include
22 | #include
23 |
24 | void get_cubic_spline_coeff(double *x, double *y, double *spline, int N) {
25 | double **coeff = (double **)malloc(3 * sizeof(double *));
26 | coeff[0] = spline + 2 * N;
27 | coeff[1] = spline + 3 * N;
28 | coeff[2] = spline + 4 * N;
29 |
30 | int i;
31 | for (i = 0; i < N; i++) {
32 | spline[i] = x[i];
33 | spline[N + i] = y[i];
34 | }
35 |
36 | double d1p1 = (y[1] - y[0]) / (x[1] - x[0]);
37 | if (d1p1 > 0.99E30) {
38 | coeff[1][0] = 0;
39 | coeff[0][0] = 0;
40 | } else {
41 | coeff[1][0] = -0.5;
42 | coeff[0][0] =
43 | (3 / (x[1] - x[0])) * ((y[1] - y[0]) / (x[1] - x[0]) - d1p1);
44 | }
45 |
46 | double s = 0, r = 0;
47 |
48 | for (i = 1; i < N - 1; i++) {
49 | s = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
50 | r = s * coeff[1][i - 1] + 2;
51 | coeff[1][i] = (s - 1) / r;
52 | coeff[0][i] = (6 *
53 | ((y[i + 1] - y[i]) / (x[i + 1] - x[i]) -
54 | (y[i] - y[i - 1]) / (x[i] - x[i - 1])) /
55 | (x[i + 1] - x[i - 1]) -
56 | s * coeff[0][i - 1]) /
57 | r;
58 | }
59 |
60 | coeff[0][N - 1] = 0;
61 | coeff[1][N - 1] = 0;
62 | coeff[2][N - 1] = 0;
63 |
64 | for (i = N - 2; i >= 0; i--) {
65 | coeff[1][i] = coeff[1][i] * coeff[1][i + 1] + coeff[0][i];
66 | }
67 |
68 | for (i = 0; i < N - 1; i++) {
69 | s = x[i + 1] - x[i];
70 | r = (coeff[1][i + 1] - coeff[1][i]) / 6;
71 | coeff[2][i] = r / s;
72 | coeff[1][i] = coeff[1][i] / 2;
73 | coeff[0][i] = (y[i + 1] - y[i]) / s - (coeff[1][i] + r) * s;
74 | }
75 |
76 | free(coeff);
77 | }
78 |
79 | double spline_integral(double *spline, int N) {
80 | double *x = spline;
81 | double *a = spline + N;
82 | double *b = spline + 2 * N;
83 | double *c = spline + 3 * N;
84 | double *d = spline + 4 * N;
85 | double dx = 0;
86 | double integral = 0;
87 | int i;
88 | for (i = 0; i < N - 1; i++) {
89 | dx = x[i + 1] - x[i];
90 | integral +=
91 | dx * (a[i] + dx * (b[i] / 2 + dx * (c[i] / 3 + d[i] * dx / 4)));
92 | }
93 |
94 | return integral;
95 | }
96 |
--------------------------------------------------------------------------------
/ciderpress/lib/mod_cider/spline.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #ifndef CIDER_SPLINE_H
21 | #define CIDER_SPLINE_H
22 |
23 | void get_cubic_spline_coeff(double *x, double *y, double *spline, int N);
24 | double spline_integral(double *spline, int N);
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/ciderpress/lib/mpi_fft_plan.py:
--------------------------------------------------------------------------------
1 | import ctypes
2 |
3 | import numpy as np
4 |
5 | from ciderpress.lib import load_library
6 |
7 | libfft = load_library("libfft_wrapper")
8 |
9 | libfft.allocate_mpi_fft3d_plan_world.restype = ctypes.c_void_p
10 | libfft.malloc_fft_plan_in_array.restype = ctypes.c_void_p
11 | libfft.malloc_fft_plan_out_array.restype = ctypes.c_void_p
12 | libfft.get_fft_plan_in_array.restype = ctypes.c_void_p
13 | libfft.get_fft_plan_out_array.restype = ctypes.c_void_p
14 | libfft.get_fft_input_size.restype = ctypes.c_int
15 | libfft.get_fft_output_size.restype = ctypes.c_int
16 |
17 |
18 | class MPIFFTWrapper:
19 | def __init__(self, dims, ntransform=1, r2c=False):
20 | self._dims = dims
21 | self._ntransform = ntransform
22 | self._r2c = r2c
23 | rshape = [d for d in dims]
24 | if r2c:
25 | kshape = [d for d in dims[:-1]] + [dims[-1] // 2 + 1]
26 | else:
27 | kshape = [d for d in dims]
28 | rshape.append(self._ntransform)
29 | kshape.append(self._ntransform)
30 | dims = np.asarray(dims, dtype=np.int32, order="C")
31 | self._ptr = ctypes.c_void_p(
32 | libfft.allocate_mpi_fft3d_plan_world(
33 | dims.ctypes.data_as(ctypes.c_void_p),
34 | ctypes.c_int(1 if r2c else 0),
35 | ctypes.c_int(self._ntransform),
36 | )
37 | )
38 | nproc = ctypes.c_int(0)
39 | rank = ctypes.c_int(0)
40 | libfft.cider_fft_world_size_and_rank(
41 | ctypes.byref(nproc),
42 | ctypes.byref(rank),
43 | )
44 | nproc = nproc.value
45 | rank = rank.value
46 | nx, ny, nz = dims
47 | xpp = -(-nx // nproc)
48 | ypp = -(-ny // nproc)
49 | my_ox = min(xpp * rank, nx)
50 | my_nx = min(xpp * (rank + 1), nx) - my_ox
51 | my_oy = min(ypp * rank, ny)
52 | my_ny = min(ypp * (rank + 1), ny) - my_oy
53 | self._nproc = nproc
54 | self._rank = rank
55 | self._xpp = xpp
56 | self._ypp = ypp
57 | self._my_ox = my_ox
58 | self._my_nx = my_nx
59 | self._my_oy = my_oy
60 | self._my_ny = my_ny
61 | self._rshape = (self._my_nx, self._dims[1], self._dims[2], self._ntransform)
62 | if r2c:
63 | self._kshape = [self._dims[0], self._dims[1], self._dims[2] // 2 + 1]
64 | else:
65 | self._kshape = self._dims
66 | self._kshape = (self._my_ny, self._kshape[0], self._kshape[2], self._ntransform)
67 |
68 | def __del__(self):
69 | libfft.free_mpi_fft3d_plan(self._ptr)
70 |
71 | def _execute_fwd(self):
72 | libfft.execute_mpi_fft3d_fwd(self._ptr)
73 |
74 | def _execute_bwd(self):
75 | libfft.execute_mpi_fft3d_bwd(self._ptr)
76 |
77 | def call(self, x, fwd=True):
78 | if fwd:
79 | if self._r2c:
80 | assert x.dtype == np.float64
81 | else:
82 | assert x.dtype == np.complex128
83 | assert x.shape == self._rshape, "{} {}".format(x.shape, self._rshape)
84 | else:
85 | assert x.dtype == np.complex128
86 | assert x.shape == self._kshape, "{} {}".format(x.shape, self._kshape)
87 | dtype = np.float64 if (self._r2c and not fwd) else np.complex128
88 | out = np.empty(self._kshape if fwd else self._rshape, dtype=dtype)
89 | libfft.write_mpi_fft3d_input(
90 | self._ptr,
91 | x.ctypes.data_as(ctypes.c_void_p),
92 | ctypes.c_int(1 if fwd else 0),
93 | )
94 | if fwd:
95 | self._execute_fwd()
96 | else:
97 | self._execute_bwd()
98 | libfft.read_mpi_fft3d_output(
99 | self._ptr,
100 | out.ctypes.data_as(ctypes.c_void_p),
101 | ctypes.c_int(1 if fwd else 0),
102 | )
103 | return out
104 |
--------------------------------------------------------------------------------
/ciderpress/lib/numint_cider/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | add_library(numint SHARED
3 | nr_numint.c
4 | )
5 |
6 | set_target_properties(numint PROPERTIES
7 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}
8 | COMPILE_FLAGS ${OpenMP_C_FLAGS}
9 | LINK_FLAGS ${OpenMP_C_FLAGS})
10 |
11 | if (HAVE_MPI)
12 | target_link_libraries(numint PRIVATE MPI::MPI_C)
13 | endif()
14 | if (BUILD_WITH_MKL)
15 | target_link_libraries(numint PRIVATE MKL::MKL)
16 | target_include_directories(numint PRIVATE ${MKL_INCLUDE_DIR})
17 | else()
18 | target_link_libraries(numint PRIVATE ${BLAS_LIBRARIES})
19 | endif()
20 |
--------------------------------------------------------------------------------
/ciderpress/lib/pwutil/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | python_add_library(pwutil SHARED
2 | grid_util.c nldf_fft_core.c ../mod_cider/sph_harm.c
3 | )
4 |
5 | set_target_properties(pwutil PROPERTIES
6 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}
7 | COMPILE_FLAGS ${OpenMP_C_FLAGS}
8 | LINK_FLAGS ${OpenMP_C_FLAGS}
9 | )
10 |
11 | configure_file(
12 | ${PROJECT_SOURCE_DIR}/pwutil/config.h.in
13 | ${PROJECT_SOURCE_DIR}/pwutil/config.h
14 | NEWLINE_STYLE UNIX
15 | )
16 |
17 | if (HAVE_MPI)
18 | target_link_libraries(pwutil PRIVATE MPI::MPI_C)
19 | target_sources(pwutil PRIVATE nldf_fft_mpi.c gpaw_interface.c)
20 | else()
21 | target_sources(pwutil PRIVATE nldf_fft_serial.c)
22 | endif()
23 |
24 | target_include_directories(pwutil PRIVATE ../mod_cider/)
25 | target_include_directories(pwutil PRIVATE ${PROJECT_SOURCE_DIR}/pwutil)
26 | target_include_directories(pwutil PRIVATE ../fft_wrapper)
27 | target_link_libraries(pwutil PRIVATE fft_wrapper)
28 |
--------------------------------------------------------------------------------
/ciderpress/lib/pwutil/config.h.in:
--------------------------------------------------------------------------------
1 | #ifndef CIDERPW_CONFIG_H
2 | #define CIDERPW_CONFIG_H
3 |
4 | #cmakedefine01 HAVE_MPI
5 |
6 | #endif
7 |
--------------------------------------------------------------------------------
/ciderpress/lib/pwutil/gpaw_interface.c:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #include "gpaw_interface.h"
21 | #include
22 | #include
23 | #include
24 |
25 | MPI_Comm unpack_gpaw_comm(PyObject *gpaw_mpi_obj) {
26 | MPIObject *gpaw_comm = (MPIObject *)gpaw_mpi_obj;
27 | return gpaw_comm->comm;
28 | }
29 |
30 | static void mpi_ensure_finalized(void) {
31 | int already_finalized = 1;
32 | int ierr = MPI_SUCCESS;
33 |
34 | MPI_Finalized(&already_finalized);
35 | if (!already_finalized) {
36 | ierr = MPI_Finalize();
37 | }
38 | if (ierr != MPI_SUCCESS)
39 | PyErr_SetString(PyExc_RuntimeError, "MPI_Finalize error occurred");
40 | }
41 |
42 | // MPI initialization
43 | void mpi_ensure_initialized(void) {
44 | int already_initialized = 1;
45 | int ierr = MPI_SUCCESS;
46 |
47 | // Check whether MPI is already initialized
48 | MPI_Initialized(&already_initialized);
49 | if (!already_initialized) {
50 | // if not, let's initialize it
51 | int use_threads = 0;
52 | // GPAW turns on threading for GPUs, but we don't have GPU support yet.
53 | // #ifdef GPAW_GPU
54 | // use_threads = 1;
55 | // #endif
56 | #ifdef _OPENMP
57 | use_threads = 1;
58 | #endif
59 | if (!use_threads) {
60 | ierr = MPI_Init(NULL, NULL);
61 | if (ierr == MPI_SUCCESS) {
62 | // No problem: register finalization when at Python exit
63 | Py_AtExit(*mpi_ensure_finalized);
64 | } else {
65 | // We have a problem: raise an exception
66 | char err[MPI_MAX_ERROR_STRING];
67 | int resultlen;
68 | MPI_Error_string(ierr, err, &resultlen);
69 | PyErr_SetString(PyExc_RuntimeError, err);
70 | }
71 | } else {
72 | int granted;
73 | ierr = MPI_Init_thread(NULL, NULL, MPI_THREAD_MULTIPLE, &granted);
74 | if (ierr == MPI_SUCCESS && granted == MPI_THREAD_MULTIPLE) {
75 | // No problem: register finalization when at Python exit
76 | Py_AtExit(*mpi_ensure_finalized);
77 | } else if (granted != MPI_THREAD_MULTIPLE) {
78 | // We have a problem: raise an exception
79 | char err[MPI_MAX_ERROR_STRING] =
80 | "MPI_THREAD_MULTIPLE is not supported";
81 | PyErr_SetString(PyExc_RuntimeError, err);
82 | } else {
83 | // We have a problem: raise an exception
84 | char err[MPI_MAX_ERROR_STRING];
85 | int resultlen;
86 | MPI_Error_string(ierr, err, &resultlen);
87 | PyErr_SetString(PyExc_RuntimeError, err);
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/ciderpress/lib/pwutil/gpaw_interface.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #ifndef GPAW_INTERFACE_H
21 | #define GPAW_INTERFACE_H
22 |
23 | #include
24 | #include
25 | #include
26 |
27 | typedef struct {
28 | PyObject_HEAD int size;
29 | int rank;
30 | MPI_Comm comm;
31 | PyObject *parent;
32 | int *members;
33 | } MPIObject;
34 |
35 | MPI_Comm unpack_gpaw_comm(PyObject *gpaw_mpi_obj);
36 |
37 | #endif
38 |
--------------------------------------------------------------------------------
/ciderpress/lib/pwutil/nldf_fft_mpi.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #ifndef NLDF_FFT_MPI_H
21 | #define NLDF_FFT_MPI_H
22 | #include "nldf_fft_core.h"
23 |
24 | void ciderpw_setup_reciprocal_vectors(ciderpw_data data);
25 |
26 | void ciderpw_g2k_mpi(ciderpw_data data);
27 |
28 | void ciderpw_k2g_mpi(ciderpw_data data);
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/ciderpress/lib/pwutil/nldf_fft_serial.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #ifndef NLDF_FFT_SERIAL_H
21 | #define NLDF_FFT_SERIAL_H
22 | #include "nldf_fft_core.h"
23 |
24 | void ciderpw_setup_reciprocal_vectors(ciderpw_data data);
25 |
26 | void ciderpw_g2k_serial(ciderpw_data data);
27 |
28 | void ciderpw_k2g_serial(ciderpw_data data);
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/ciderpress/lib/sbt/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | add_library(sbt SHARED
3 | sbt.c
4 | )
5 |
6 | set_target_properties(sbt PROPERTIES
7 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}
8 | COMPILE_FLAGS ${OpenMP_C_FLAGS}
9 | LINK_FLAGS ${OpenMP_C_FLAGS})
10 |
11 | # target_link_libraries(sbt ${BLAS_LIBRARIES})
12 | target_include_directories(sbt PRIVATE ../fft_wrapper)
13 | target_link_libraries(sbt PRIVATE fft_wrapper)
14 |
15 | if (HAVE_MPI)
16 | target_link_libraries(sbt PRIVATE MPI::MPI_C)
17 | endif()
18 | if (BUILD_WITH_MKL)
19 | target_link_libraries(sbt PRIVATE MKL::MKL)
20 | target_include_directories(sbt PRIVATE ${MKL_INCLUDE_DIR})
21 | else()
22 | target_link_libraries(sbt PRIVATE ${BLAS_LIBRARIES})
23 | endif()
24 |
--------------------------------------------------------------------------------
/ciderpress/lib/sbt/sbt.h:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | // The following routines are based on the Fortran program NumSBT written by
21 | // J. Talman. The algorithm performs a spherical Bessel transform in O(NlnN)
22 | // time. If you adapt this code for any purpose, please cite: Talman,
23 | // J. Computer Physics Communications 2009, 180, 332-338. The original NumSBT
24 | // code is distributed under the Standard CPC license.
25 |
26 | #ifndef SBT_H
27 | #define SBT_H
28 | // #include "config.h"
29 | #include "cider_fft.h"
30 | #include
31 |
32 | /**
33 | Contains the parameters for a fast spherical Bessel transform.
34 | */
35 | typedef struct sbt_descriptor {
36 | double kmin; ///< Minimum reciprocal space value
37 | double kappamin; ///< ln(kmin)
38 | double rmin; ///< Minimum real space value
39 | double rhomin; ///< ln(rmin)
40 | double drho; ///< linear increment of rho = ln(r), drho == dkappa
41 | double dt; ///< increment of the multiplication table
42 | int N; ///< number of values of r and k
43 | double complex **mult_table; ///< M_l(t) for l up to lmax
44 | double *ks; ///< Reciprocal space grid
45 | double *rs; ///< Real space grid
46 | double *k32; ///< (Recip space grid)^1.5
47 | double *r32; ///< (Real space grid)^1.5
48 | int lmax;
49 | double complex *buffer;
50 | fft_plan_t *plan;
51 | } sbt_descriptor_t;
52 |
53 | /**
54 | Creates an sbt_descriptor_t object from the real space and k-space grids.
55 | Extrapolates the radial grid to have N values lower than the initial rmin,
56 | and the reciprocal grid to have N values higher than the initial kmin.
57 | encut+enbuf is the maximum value of k BEFORE extrapolation.
58 | lmax is the maximum l-value used to construct the the mult_table.
59 | N is the size of the grid BEFORE exprapolation (i.e. length of r and ks).
60 | */
61 | sbt_descriptor_t *spherical_bessel_transform_setup(double encut, int lmax,
62 | int N, double *r,
63 | double *ks);
64 |
65 | /**
66 | Returns the values of radially defined function f
67 | in reciprocal space in a spherical bessel basis.
68 | f is defined on the grid corresponding to the r
69 | passed into spherical_bessesl_transform_setup.
70 | */
71 | void wave_spherical_bessel_transform(sbt_descriptor_t *d, double *f, int l,
72 | double *vals, int l_add);
73 |
74 | /**
75 | Performs the inverse transform of f. Calling this function on the output
76 | of wave_spherical_bessel_transform gives the initial input to
77 | wave_spherical_bessel_transform on the initial radial grid passed to
78 | spherical_bessel_transform_setup
79 | */
80 | void inverse_wave_spherical_bessel_transform(sbt_descriptor_t *d, double *f,
81 | int l, double *vals);
82 |
83 | /**
84 | Free all the memory associated with an sbt descriptor.
85 | */
86 | void free_sbt_descriptor(sbt_descriptor_t *d);
87 |
88 | /** Check whether an array was allocated. If not, exit. */
89 | void sbt_check_allocation(void *ptr);
90 | void sbt_allocation_failed(void);
91 |
92 | #endif
93 |
--------------------------------------------------------------------------------
/ciderpress/lib/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/lib/tests/__init__.py
--------------------------------------------------------------------------------
/ciderpress/lib/tests/tests_fft_plan.py:
--------------------------------------------------------------------------------
1 | import ctypes
2 | import itertools
3 | import unittest
4 |
5 | import numpy as np
6 | from numpy.testing import assert_allclose
7 |
8 | from ciderpress.lib.fft_plan import FFTWrapper, libfft
9 |
10 | # libfft.cider_fft_set_nthread(ctypes.c_int(-1))
11 |
12 | SEED = 1684
13 |
14 | ALL_DIMS = [
15 | [13],
16 | [16],
17 | [13, 9],
18 | [13, 8],
19 | [16, 18],
20 | [13, 9, 17],
21 | [13, 9, 8],
22 | [16, 18, 12],
23 | [4, 4, 4, 4],
24 | ]
25 |
26 |
27 | class TestFFT(unittest.TestCase):
28 | def run_single_test(self, dims, ntrans, fwd, r2c, inplace, batch_first):
29 | np.random.seed(SEED)
30 | ishape = [ntrans] + dims if batch_first else dims + [ntrans]
31 | axes = [i for i in range(len(dims))]
32 | if batch_first:
33 | for i in range(len(axes)):
34 | axes[i] += 1
35 | if r2c:
36 | input_arr = np.empty(shape=ishape, dtype=np.float64)
37 | input_arr[:] = np.random.normal(size=ishape)
38 | else:
39 | input_arr = np.empty(shape=ishape, dtype=np.complex128)
40 | input_arr.real[:] = np.random.normal(size=ishape)
41 | input_arr.imag[:] = np.random.normal(size=ishape)
42 | if not fwd:
43 | if r2c:
44 | input_arr = np.fft.rfftn(input_arr, axes=axes)
45 | else:
46 | input_arr = np.fft.fftn(input_arr, axes=axes)
47 | if fwd and r2c:
48 | ref_output_arr = np.fft.rfftn(input_arr, axes=axes)
49 | elif fwd:
50 | ref_output_arr = np.fft.fftn(input_arr, axes=axes)
51 | elif r2c:
52 | ref_output_arr = np.fft.irfftn(input_arr, axes=axes, s=dims)
53 | else:
54 | ref_output_arr = np.fft.ifftn(input_arr, axes=axes)
55 | wrapper = FFTWrapper(
56 | dims,
57 | ntransform=ntrans,
58 | r2c=r2c,
59 | fwd=fwd,
60 | inplace=inplace,
61 | batch_first=batch_first,
62 | )
63 | input_arr.shape = wrapper.input_shape
64 | ref_output_arr.shape = wrapper.output_shape
65 | test_output_arr = wrapper.call(input_arr)
66 | if not fwd:
67 | test_output_arr /= np.prod(dims)
68 | test_output_arr = test_output_arr.reshape(ref_output_arr.shape)
69 | tol = 1e-15 * 10 ** len(dims)
70 | assert_allclose(test_output_arr, ref_output_arr, atol=tol, rtol=0)
71 |
72 | def test_cider_fft(self):
73 | tf = [True, False]
74 | nts = [1, 5]
75 | settings_gen = itertools.product(ALL_DIMS, nts, tf, tf, tf, tf)
76 | for dims, nt, fwd, r2c, inplace, batch_first in settings_gen:
77 | self.run_single_test(dims, nt, fwd, r2c, inplace, batch_first)
78 |
79 | def test_time(self):
80 | libfft.cider_fft_set_nthread(ctypes.c_int(-1))
81 | import time
82 |
83 | dims = [105, 128, 121]
84 | nt = 10
85 | batch_first = False
86 | if batch_first:
87 | array_size = [nt] + dims
88 | else:
89 | array_size = dims + [nt]
90 | np.random.seed(SEED)
91 | r2c = True
92 | dtype = np.float64 if r2c else np.complex128
93 | matrix = np.random.normal(size=array_size).astype(dtype)
94 | my_matrix = matrix.copy(order="C")
95 | t0 = time.monotonic()
96 | fwr = FFTWrapper(
97 | dims,
98 | ntransform=nt,
99 | fwd=True,
100 | r2c=r2c,
101 | batch_first=batch_first,
102 | inplace=True,
103 | )
104 | bwr = FFTWrapper(
105 | dims,
106 | ntransform=nt,
107 | fwd=False,
108 | r2c=r2c,
109 | batch_first=batch_first,
110 | inplace=True,
111 | )
112 | my_test_kmatrix = fwr.call(my_matrix)
113 | my_test_matrix = bwr.call(my_test_kmatrix)
114 | t1 = time.monotonic()
115 | print("TIME", t1 - t0)
116 | print(my_test_kmatrix.sum())
117 | print(my_test_matrix.sum())
118 |
119 |
120 | if __name__ == "__main__":
121 | unittest.main()
122 |
--------------------------------------------------------------------------------
/ciderpress/lib/xc_utils/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | add_library(xc_utils SHARED
3 | libxc_baselines.c
4 | )
5 |
6 | set_target_properties(xc_utils PROPERTIES
7 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}
8 | COMPILE_FLAGS ${OpenMP_C_FLAGS}
9 | LINK_FLAGS ${OpenMP_C_FLAGS})
10 |
11 | if (HAVE_MPI)
12 | target_link_libraries(xc_utils PRIVATE MPI::MPI_C)
13 | endif()
14 | if (BUILD_WITH_MKL)
15 | target_link_libraries(xc_utils PRIVATE MKL::MKL)
16 | target_include_directories(xc_utils PRIVATE ${MKL_INCLUDE_DIR})
17 | else()
18 | target_link_libraries(xc_utils PRIVATE ${BLAS_LIBRARIES})
19 | endif()
20 | if(BUILD_LIBXC)
21 | target_link_libraries(xc_utils PRIVATE xc)
22 | else()
23 | target_link_libraries(xc_utils PRIVATE Libxc::xc)
24 | endif()
25 |
--------------------------------------------------------------------------------
/ciderpress/lib/xc_utils/libxc_baselines.c:
--------------------------------------------------------------------------------
1 | // CiderPress: Machine-learning based density functional theory calculations
2 | // Copyright (C) 2024 The President and Fellows of Harvard College
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see
16 | //
17 | // Author: Kyle Bystrom
18 | //
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | void get_lda_baseline(int fn_id, int nspin, int size, double *rho, double *exc,
25 | double *vrho, double dens_threshold) {
26 | xc_func_type func;
27 | xc_func_init(&func, fn_id, nspin);
28 | xc_func_set_dens_threshold(&func, dens_threshold);
29 | xc_lda_exc_vxc(&func, size, rho, exc, vrho);
30 | }
31 |
32 | void get_gga_baseline(int fn_id, int nspin, int size, double *rho,
33 | double *sigma, double *exc, double *vrho, double *vsigma,
34 | double dens_threshold) {
35 | xc_func_type func;
36 | xc_func_init(&func, fn_id, nspin);
37 | xc_func_set_dens_threshold(&func, dens_threshold);
38 | xc_gga_exc_vxc(&func, size, rho, sigma, exc, vrho, vsigma);
39 | }
40 |
41 | void get_mgga_baseline(int fn_id, int nspin, int size, double *rho,
42 | double *sigma, double *tau, double *exc, double *vrho,
43 | double *vsigma, double *vtau, double dens_threshold) {
44 | xc_func_type func;
45 | xc_func_init(&func, fn_id, nspin);
46 | xc_func_set_dens_threshold(&func, dens_threshold);
47 | xc_mgga_exc_vxc(&func, size, rho, sigma, rho, tau, exc, vrho, vsigma, NULL,
48 | vtau);
49 | }
50 |
--------------------------------------------------------------------------------
/ciderpress/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/models/__init__.py
--------------------------------------------------------------------------------
/ciderpress/models/kernel_plans/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/models/kernel_plans/__init__.py
--------------------------------------------------------------------------------
/ciderpress/models/kernel_plans/arbf_exchange.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | from ciderpress.dft.xc_evaluator import SplineSetEvaluator
22 | from ciderpress.models.kernel_plans.kernel_tools import get_agpr_kernel
23 | from ciderpress.models.kernel_plans.map_tools import get_mapped_gp_evaluator_additive
24 |
25 |
26 | def get_kernel(
27 | natural_scale=None,
28 | natural_lscale=None,
29 | scale_factor=None,
30 | lscale_factor=None,
31 | **kwargs,
32 | ):
33 | # leave out density from feature vector
34 | slice(1, None, None)
35 | print(lscale_factor, natural_lscale)
36 | print(scale_factor, natural_scale)
37 | return get_agpr_kernel(
38 | slice(0, 1, None),
39 | slice(1, None, None),
40 | lscale_factor * natural_lscale,
41 | scale=[1e-5, 1e-5, scale_factor * natural_scale],
42 | order=2,
43 | nsingle=1,
44 | )
45 |
46 |
47 | def mapping_plan(dft_kernel):
48 | scale, ind_sets, spline_grids, coeff_sets = get_mapped_gp_evaluator_additive(
49 | dft_kernel.kernel,
50 | dft_kernel.X1ctrl,
51 | dft_kernel.alpha,
52 | dft_kernel.feature_list,
53 | )
54 | # TODO this needs to get converted into a class
55 | # that evaluates a specific kernel's contribution to the
56 | # XC energy. This function should then be a component
57 | # called by DFTKernel.map().
58 | # Then these mapping plans need to be combined within some
59 | # overarching evaluator class, which should be created
60 | # by a function like MOLGP.map().
61 | return SplineSetEvaluator(scale, ind_sets, spline_grids, coeff_sets)
62 |
--------------------------------------------------------------------------------
/ciderpress/models/kernel_plans/kernel_tools.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import numpy as np
22 |
23 | from ciderpress.models.kernels import (
24 | DiffAntisymRBF,
25 | DiffConstantKernel,
26 | SubsetARBF,
27 | SubsetRBF,
28 | )
29 |
30 |
31 | def get_rbf_kernel(
32 | indexes, length_scale, scale=1.0, opt_hparams=False, min_lscale=None
33 | ):
34 | if min_lscale is None:
35 | min_lscale = 0.01
36 | length_scale_bounds = (min_lscale, 10) if opt_hparams else "fixed"
37 | scale_bounds = (1e-5, 1e3) if opt_hparams else "fixed"
38 | return DiffConstantKernel(scale, constant_value_bounds=scale_bounds) * SubsetRBF(
39 | indexes,
40 | length_scale=length_scale[indexes],
41 | length_scale_bounds=length_scale_bounds,
42 | )
43 |
44 |
45 | def get_antisym_rbf_kernel(length_scale, scale=1.0, opt_hparams=False, min_lscale=None):
46 | if min_lscale is None:
47 | min_lscale = 0.01
48 | length_scale_bounds = (min_lscale, 10) if opt_hparams else "fixed"
49 | scale_bounds = (1e-5, 1e3) if opt_hparams else "fixed"
50 | length_scale = np.append(
51 | 0.5 * (length_scale[0] + length_scale[1]), length_scale[2:]
52 | )
53 | return DiffConstantKernel(
54 | scale, constant_value_bounds=scale_bounds
55 | ) * DiffAntisymRBF(
56 | length_scale=length_scale,
57 | length_scale_bounds=length_scale_bounds,
58 | )
59 |
60 |
61 | def get_agpr_kernel(
62 | sinds,
63 | ainds,
64 | length_scale,
65 | scale=None,
66 | order=2,
67 | nsingle=1,
68 | opt_hparams=False,
69 | min_lscale=None,
70 | ):
71 | print(sinds, ainds, length_scale[sinds], length_scale[ainds])
72 | if min_lscale is None:
73 | min_lscale = 0.01
74 | length_scale_bounds = (min_lscale, 10) if opt_hparams else "fixed"
75 | scale_bounds = (1e-5, 1e5) if opt_hparams else "fixed"
76 | if scale is None:
77 | scale = [1.0] * (order + 1)
78 | if nsingle == 0:
79 | singles = None
80 | else:
81 | singles = SubsetRBF(
82 | sinds,
83 | length_scale=length_scale[sinds],
84 | length_scale_bounds=length_scale_bounds,
85 | )
86 | cov_kernel = SubsetARBF(
87 | ainds,
88 | order=order,
89 | length_scale=length_scale[ainds],
90 | scale=scale,
91 | length_scale_bounds=length_scale_bounds,
92 | scale_bounds=scale_bounds,
93 | )
94 | if singles is None:
95 | return cov_kernel
96 | else:
97 | return singles * cov_kernel
98 |
--------------------------------------------------------------------------------
/ciderpress/models/kernel_plans/plan_template.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 |
22 | def get_kernel(
23 | natural_scale=None,
24 | natural_lscale=None,
25 | scale_factor=None,
26 | lscale_factor=None,
27 | ):
28 | """
29 | Args:
30 | natural_scale (float, None): Natural scale for covariance,
31 | typically set based on variance of target over training data.
32 | natural_lscale (array, None): Natural length scale for features,
33 | typically set based on variance of features over the
34 | training data.
35 | scale_factor (float, None): Multiplicative factor to tune
36 | covariance scale
37 | lscale_factor (float or array, None): Multiplicative factor
38 | to tune length scale.
39 |
40 | Returns:
41 | An sklearn kernel
42 | """
43 |
44 |
45 | def mapping_plan(model):
46 | """
47 | A function that maps a model based on the kernel above to 'fast'
48 | functions like splines and polynomial evaluations, then returns
49 | an Evaluator object based on the mapping.
50 |
51 | Args:
52 | model:
53 |
54 | Returns:
55 |
56 | """
57 |
--------------------------------------------------------------------------------
/ciderpress/models/kernel_plans/settings_example.yaml:
--------------------------------------------------------------------------------
1 | # init_file: Path to Python file containing two functions,
2 | # `get_kernel` and (optionally) `mapping_plan`,
3 | # as documented in plan_template.py
4 | # feature_list: Serialized feature list or path to yaml file
5 | # containing serialized feature list.
6 | # mode: See DFTKernel documentation. Corresponds to how spin-
7 | # polarization is handled by the kernel.
8 | # multiplicative_baseline: str name (or serialized function)
9 | # for multiplicative baseline used by kernel.
10 | # additive_baseline: Same as above, but for additive baseline
11 | # ctrl_tol: See DFTKernel docs
12 | # ctrl_nmax: See DFTKernel docs
13 | - plan_file: path/to/plan_file1.py
14 | feature_list: path/to/feature_list1.yaml
15 | mode: SEP
16 | multiplicative_baseline: LDA_X
17 | additive_baseline: GGA_X_PBE
18 | ctrl_tol: 1e-5 # optional
19 | ctrl_nmax: null # optional
20 | - plan_file: path/to/plan_file2.py
21 | feature_list:
22 | mode: OSPOL
23 | multiplicative_baseline: RHO
24 | additive_baseline: null
25 | ctrl_nmax: 100
26 |
--------------------------------------------------------------------------------
/ciderpress/pyscf/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/pyscf/__init__.py
--------------------------------------------------------------------------------
/ciderpress/pyscf/debug_numint.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import numpy as np
22 | from pyscf.dft.gen_grid import Grids
23 | from pyscf.dft.numint import NumInt
24 |
25 | from ciderpress.dft.debug_numint import get_get_exponent, get_nonlocal_features
26 |
27 |
28 | def get_nldf_numint(
29 | mol, grids, dms, gg_kwargs, vv_gg_kwargs, version="i", inner_grids_level=3
30 | ):
31 | if dms.ndim == 2:
32 | return _get_nldf_numint(
33 | mol,
34 | grids,
35 | dms,
36 | gg_kwargs,
37 | vv_gg_kwargs,
38 | version=version,
39 | inner_grids_level=inner_grids_level,
40 | )[None, :]
41 | else:
42 | assert dms.shape[0] == 2
43 | dms = dms * 2
44 | res0 = _get_nldf_numint(
45 | mol,
46 | grids,
47 | dms[0],
48 | gg_kwargs,
49 | vv_gg_kwargs,
50 | version=version,
51 | inner_grids_level=inner_grids_level,
52 | )
53 | res1 = _get_nldf_numint(
54 | mol,
55 | grids,
56 | dms[1],
57 | gg_kwargs,
58 | vv_gg_kwargs,
59 | version=version,
60 | inner_grids_level=inner_grids_level,
61 | )
62 | return np.stack([res0, res1])
63 |
64 |
65 | def _get_nldf_numint(
66 | mol, grids, dms, gg_kwargs, vv_gg_kwargs, version="i", inner_grids_level=3
67 | ):
68 | ni = NumInt()
69 | make_rho, nset, nao = ni._gen_rho_evaluator(mol, dms, 1, False)
70 | max_memory = 2000
71 | assert nset == 1
72 |
73 | get_exponent_r = get_get_exponent(gg_kwargs)
74 | get_exponent_rp = get_get_exponent(vv_gg_kwargs)
75 |
76 | assert nset == 1
77 | smgrids = Grids(mol)
78 | smgrids.level = inner_grids_level
79 | smgrids.prune = None
80 | smgrids.build()
81 |
82 | nfeat = 12 if version == "i" else 4
83 | desc = np.empty((0, nfeat))
84 | ao_deriv = 1
85 | vvrho = np.empty([nset, 5, 0])
86 | vvweight = np.empty([nset, 0])
87 | vvcoords = np.empty([nset, 0, 3])
88 | for ao, mask, weight, coords in ni.block_loop(
89 | mol, smgrids, nao, ao_deriv, max_memory
90 | ):
91 | rhotmp = np.empty([0, 5, weight.size])
92 | weighttmp = np.empty([0, weight.size])
93 | coordstmp = np.empty([0, weight.size, 3])
94 | for idm in range(nset):
95 | rho = make_rho(idm, ao, mask, "MGGA")
96 | rho = np.expand_dims(rho, axis=0)
97 | rhotmp = np.concatenate((rhotmp, rho), axis=0)
98 | weighttmp = np.concatenate(
99 | (weighttmp, np.expand_dims(weight, axis=0)),
100 | axis=0,
101 | )
102 | coordstmp = np.concatenate(
103 | (coordstmp, np.expand_dims(coords, axis=0)),
104 | axis=0,
105 | )
106 | vvrho = np.concatenate((vvrho, rhotmp), axis=2)
107 | vvweight = np.concatenate((vvweight, weighttmp), axis=1)
108 | vvcoords = np.concatenate((vvcoords, coordstmp), axis=1)
109 | aow = None
110 | for ao, mask, weight, coords in ni.block_loop(
111 | mol, grids, nao, ao_deriv, max_memory
112 | ):
113 | aow = np.ndarray(ao[0].shape, order="F", buffer=aow)
114 | for idm in range(nset):
115 | rho = make_rho(idm, ao, mask, "MGGA")
116 | feat = get_nonlocal_features(
117 | rho,
118 | coords,
119 | vvrho[idm],
120 | vvweight[idm],
121 | vvcoords[idm],
122 | get_exponent_r,
123 | get_exponent_rp,
124 | version=version,
125 | )
126 | desc = np.append(desc, feat, axis=0)
127 | return desc
128 |
--------------------------------------------------------------------------------
/ciderpress/pyscf/pbc/__init__.py:
--------------------------------------------------------------------------------
1 | import warnings
2 |
3 | warnings.warn(
4 | "WARNING: The ciderpress.pyscf.pbc module is highly experimental. "
5 | "Only the SDMX nonlocal features are supported, and the memory "
6 | "requirements are high. It is provided for the sole purpose "
7 | "of reproducing past results. A more robust and fully-featured "
8 | "version is planned for future development."
9 | )
10 |
--------------------------------------------------------------------------------
/ciderpress/pyscf/pbc/dft.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | from pyscf import lib
22 |
23 | from ciderpress.pyscf.dft import _CiderKS as _MolCiderKS
24 | from ciderpress.pyscf.dft import get_slxc_settings, load_cider_model
25 | from ciderpress.pyscf.pbc.numint import CiderKNumInt, CiderNumInt, numint
26 | from ciderpress.pyscf.pbc.sdmx_fft import PySCFSDMXInitializer
27 |
28 |
29 | def make_cider_calc(
30 | ks,
31 | mlfunc,
32 | xmix=1.0,
33 | xc=None,
34 | xkernel=None,
35 | ckernel=None,
36 | mlfunc_format=None,
37 | nlc_coeff=None,
38 | nldf_init=None,
39 | sdmx_init=None,
40 | dense_mesh=None,
41 | rhocut=None,
42 | ):
43 | """
44 | Same as :func:`ciderpress.pyscf.dft.make_cider_calc`, but
45 | for periodic systems. Note that only semilocal and SDMX
46 | features are supported. The ks object must use a uniform XC
47 | integration grid and pseudopotentials.
48 | """
49 | mlfunc = load_cider_model(mlfunc, mlfunc_format)
50 | ks._xc = get_slxc_settings(xc, xkernel, ckernel, xmix)
51 | # Assign the PySCF-facing functional to be a simple SL
52 | # functional to avoid hybrid DFT being called.
53 | # NOTE this might need to be changed to some nicer
54 | # approach later.
55 | if mlfunc.settings.sl_settings.level == "MGGA":
56 | ks.xc = "R2SCAN"
57 | else:
58 | ks.xc = "PBE"
59 | new_ks = _CiderKS(
60 | ks,
61 | mlfunc,
62 | xmix=xmix,
63 | nldf_init=nldf_init,
64 | sdmx_init=sdmx_init,
65 | rhocut=rhocut,
66 | nlc_coeff=nlc_coeff,
67 | dense_mesh=dense_mesh,
68 | )
69 | return lib.set_class(new_ks, (_CiderKS, ks.__class__))
70 |
71 |
72 | class _CiderKS(_MolCiderKS):
73 | def __init__(
74 | self,
75 | mf,
76 | mlxc,
77 | xmix=1.0,
78 | nldf_init=None,
79 | sdmx_init=None,
80 | rhocut=None,
81 | nlc_coeff=None,
82 | dense_mesh=None,
83 | ):
84 | self.dense_mesh = dense_mesh
85 | super().__init__(mf, mlxc, xmix, nldf_init, sdmx_init, rhocut, nlc_coeff)
86 |
87 | def set_mlxc(
88 | self,
89 | mlxc,
90 | xmix=1.0,
91 | nldf_init=None,
92 | sdmx_init=None,
93 | rhocut=None,
94 | nlc_coeff=None,
95 | ):
96 | if nldf_init is None and mlxc.settings.has_nldf:
97 | raise NotImplementedError
98 | if sdmx_init is None and mlxc.settings.has_sdmx:
99 | sdmx_init = PySCFSDMXInitializer(mlxc.settings.sdmx_settings, lowmem=False)
100 | old_grids = self.grids
101 | changed = False
102 | if mlxc.settings.has_nldf:
103 | raise NotImplementedError
104 | if changed:
105 | for key in (
106 | "atom_grid",
107 | "atomic_radii",
108 | "radii_adjust",
109 | "radi_method",
110 | "becke_scheme",
111 | "prune",
112 | "level",
113 | ):
114 | self.grids.__setattr__(key, old_grids.__getattribute__(key))
115 | settings = mlxc.settings
116 | has_nldf = not settings.nldf_settings.is_empty
117 | has_nlof = not settings.nlof_settings.is_empty
118 | has_kpts = isinstance(self._numint, numint.KNumInt)
119 | if has_nldf and has_nlof:
120 | raise NotImplementedError
121 | elif has_nldf:
122 | raise NotImplementedError
123 | elif has_nlof:
124 | raise NotImplementedError
125 | else:
126 | if has_kpts:
127 | cls = CiderKNumInt
128 | else:
129 | cls = CiderNumInt
130 | self._numint = cls(
131 | mlxc,
132 | self._xc,
133 | nldf_init,
134 | sdmx_init,
135 | xmix=xmix,
136 | rhocut=rhocut,
137 | nlc_coeff=nlc_coeff,
138 | dense_mesh=self.dense_mesh,
139 | )
140 |
--------------------------------------------------------------------------------
/ciderpress/pyscf/pbc/tests/test_fft.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import ctypes
22 | import unittest
23 |
24 | import numpy as np
25 | from numpy.fft import fftn, ifftn, irfftn, rfftn
26 | from numpy.testing import assert_allclose
27 |
28 | from ciderpress.pyscf.pbc.sdmx_fft import libcider
29 |
30 |
31 | def _call_mkl_test(x, fwd, mesh):
32 | nx, ny, nz = mesh
33 | nzc = nz // 2 + 1
34 | if fwd:
35 | xr = x
36 | xk = np.empty((nx, ny, nzc), order="C", dtype=np.complex128)
37 | else:
38 | xk = x
39 | xr = np.empty((nx, ny, nz), order="C", dtype=np.float64)
40 | assert xr.shape == (nx, ny, nz)
41 | assert xk.shape == (nx, ny, nzc)
42 | libcider.test_fft3d(
43 | xr.ctypes.data_as(ctypes.c_void_p),
44 | xk.ctypes.data_as(ctypes.c_void_p),
45 | ctypes.c_int(nx),
46 | ctypes.c_int(ny),
47 | ctypes.c_int(nz),
48 | ctypes.c_int(1 if fwd else 0),
49 | )
50 | if fwd:
51 | return xk
52 | else:
53 | return xr
54 |
55 |
56 | class TestFFT(unittest.TestCase):
57 | def test_fft(self):
58 | np.random.seed(34)
59 | meshes = [
60 | [32, 100, 19],
61 | [32, 100, 20],
62 | [31, 99, 19],
63 | [2, 2, 4],
64 | [81, 81, 81],
65 | [80, 80, 80],
66 | ]
67 |
68 | for mesh in meshes:
69 | kmesh = [mesh[0], mesh[1], mesh[2] // 2 + 1]
70 | xrin = np.random.normal(size=mesh).astype(np.float64)
71 | xkin1 = np.random.normal(size=kmesh)
72 | xkin2 = np.random.normal(size=kmesh)
73 | xkin = np.empty(kmesh, dtype=np.complex128)
74 | xkin.real = xkin1
75 | xkin.imag = xkin2
76 | xkin[:] = rfftn(xrin, norm="backward")
77 | xkc = fftn(xrin.astype(np.complex128), norm="backward")
78 | xkin2 = xkin.copy()
79 | if mesh[2] % 2 == 0:
80 | xkin2[0, 0, 0] = xkin2.real[0, 0, 0]
81 | xkin2[0, 0, -1] = xkin2.real[0, 0, -1]
82 | for ind in [0, -1]:
83 | for i in range(xkin2.shape[-3]):
84 | for j in range(xkin2.shape[-2]):
85 | tmp1 = xkin2[i, j, ind]
86 | tmp2 = xkin2[-i, -j, ind]
87 | xkin2[i, j, ind] = 0.5 * (tmp1 + tmp2.conj())
88 | xkin2[-i, -j, ind] = 0.5 * (tmp1.conj() + tmp2)
89 |
90 | xk_np = rfftn(xrin)
91 | xk_mkl = _call_mkl_test(xrin, True, mesh)
92 | assert (xk_np.shape == np.array(kmesh)).all()
93 | assert (xk_mkl.shape == np.array(kmesh)).all()
94 |
95 | xr2_np = ifftn(xkc.copy(), s=mesh, norm="forward")
96 | xr_np = irfftn(xkin.copy(), s=mesh, norm="forward")
97 | xr3_np = irfftn(xkin2.copy(), s=mesh, norm="forward")
98 | xr_mkl = _call_mkl_test(xkin, False, mesh)
99 | xr2_mkl = _call_mkl_test(xkin2, False, mesh)
100 | assert (xr_np.shape == np.array(mesh)).all()
101 | assert (xr_mkl.shape == np.array(mesh)).all()
102 | assert_allclose(xr2_np.imag, 0, atol=1e-9)
103 | assert_allclose(xr2_np, xr3_np, atol=1e-9)
104 | assert_allclose(xr2_mkl, xr3_np, atol=1e-9)
105 | assert_allclose(xr_mkl, xr_np, atol=1e-9)
106 |
107 |
108 | if __name__ == "__main__":
109 | unittest.main()
110 |
--------------------------------------------------------------------------------
/ciderpress/pyscf/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/pyscf/tests/__init__.py
--------------------------------------------------------------------------------
/ciderpress/pyscf/tests/test_functionals.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import unittest
22 |
23 | import pyscf.dft.radi
24 | from numpy.testing import assert_almost_equal
25 | from pyscf import dft, gto
26 |
27 | from ciderpress.pyscf.dft import make_cider_calc
28 |
29 | """
30 | This is a high-level test to make sure RKS SCF energies are consistent between
31 | commits. It also checks that the functionals are not accidentally changed.
32 | """
33 |
34 | # This is for backward consistency
35 | pyscf.dft.radi.ATOM_SPECIFIC_TREUTLER_GRIDS = False
36 |
37 |
38 | XCVALS = {
39 | "CIDER23X_SL_GGA": -199.442504774708,
40 | "CIDER23X_NL_GGA": -199.410917905451,
41 | "CIDER23X_SL_MGGA": -199.41699396454,
42 | "CIDER23X_NL_MGGA": -199.422085280523,
43 | "CIDER23X_NL_MGGA_PBE": -199.421990307797,
44 | "CIDER23X_NL_MGGA_DTR": -199.423911593205,
45 | "CIDER24Xne": -199.4190650929805,
46 | "CIDER24Xe": -199.4241297851031,
47 | }
48 |
49 |
50 | def run_functional(xcname):
51 | mol = gto.M(
52 | atom="F 0 0 0; F 0 0 1.420608",
53 | basis="def2-qzvppd",
54 | verbose=4,
55 | output="/dev/null",
56 | )
57 | ks = dft.RKS(mol)
58 | ks.xc = "PBE"
59 | ks.grids.level = 3
60 |
61 | xcfile = "functionals/{}.yaml".format(xcname)
62 | ks = make_cider_calc(
63 | ks, xcfile, xmix=0.25, xkernel="GGA_X_PBE", ckernel="GGA_C_PBE"
64 | )
65 | ks = ks.density_fit(auxbasis="def2-universal-jfit")
66 | etot = ks.kernel()
67 | mol.stdout.close()
68 | assert_almost_equal(etot, XCVALS[xcname], 5)
69 |
70 |
71 | class TestFunctionals(unittest.TestCase):
72 | def test_semilocal_gga(self):
73 | run_functional("CIDER23X_SL_GGA")
74 |
75 | def test_nonlocal_gga(self):
76 | run_functional("CIDER23X_NL_GGA")
77 |
78 | def test_semilocal_mgga(self):
79 | run_functional("CIDER23X_SL_MGGA")
80 |
81 | def test_nonlocal_mgga(self):
82 | run_functional("CIDER23X_NL_MGGA")
83 |
84 | def test_nonlocal_mgga_pbe(self):
85 | run_functional("CIDER23X_NL_MGGA_PBE")
86 |
87 | def test_nonlocal_mgga_dtr(self):
88 | run_functional("CIDER23X_NL_MGGA_DTR")
89 |
90 | def test_cider24ne(self):
91 | run_functional("CIDER24Xne")
92 |
93 | def test_cider24e(self):
94 | run_functional("CIDER24Xe")
95 |
96 |
97 | if __name__ == "__main__":
98 | unittest.main()
99 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/_templates/layout.html:
--------------------------------------------------------------------------------
1 | {% extends "!layout.html" %}
2 | {% block footer %} {{ super() }}
3 |
4 |
14 | {% endblock %}
15 |
--------------------------------------------------------------------------------
/docs/c_extensions/c_extensions.rst:
--------------------------------------------------------------------------------
1 | C Extension Libraries
2 | =====================
3 |
4 | .. toctree::
5 | :maxdepth: 3
6 |
7 | pwutil
8 |
--------------------------------------------------------------------------------
/docs/c_extensions/pwutil.rst:
--------------------------------------------------------------------------------
1 | Plane-wave Utilities (pwutil)
2 | =============================
3 |
4 | .. doxygenfile:: nldf_fft_core.h
5 | :project: CiderPress
6 |
--------------------------------------------------------------------------------
/docs/ciderpress/dft/dft.rst:
--------------------------------------------------------------------------------
1 | DFT Module
2 | ==========
3 |
4 | The :py:mod:`ciderpress.dft` module contains many of the core utilities
5 | of the CiderPress code. The most important of these are:
6 |
7 | * The :py:mod:`ciderpress.dft.settings` module, which consists of a set
8 | of classes for specifying the types of features to be computed
9 | for an ML model along with the parametrizations of those features.
10 | * The :py:mod:`ciderpress.dft.plans` module, which provides classes
11 | that specify *how* a given set of features is to be computed.
12 | For example, an instance of :py:class:`NLDFSettingsVJ` from the
13 | :py:mod:`settings` module specifies that version-j :ref:`NLDF `
14 | features are to be computed, and an instance :py:class:`NLDFSplinePlan`
15 | from :py:mod:`plans` instructs CiderPress how to compute these
16 | features using cubic spline interpolation (see
17 | :ref:`NLDF Numerical Evaluation `).
18 | * The :py:mod:`ciderpress.dft.feat_normalizer` module, which provides
19 | utilities to transform "raw" features (which might not be scale-invariant)
20 | to scale-invariant "normalized features". Note it is not necessary to make
21 | every feature scale-invariant unless you want to enforce the uniform
22 | scaling rule for exchange.
23 | * The :py:mod:`ciderpress.dft.transform_data` module, which provides
24 | utilities to transform "normalized" features (which do not necessarily fall
25 | in a finite interval, making them unwieldy for ML models) into
26 | "transformed" features suitable for direct input into Gaussian process
27 | regression.
28 | * The :py:mod:`ciderpress.dft.xc_evaluator` and :py:mod:`ciderpress.dft.xc_evaluator2`
29 | modules, which provide tools to efficiently evaluate trained CIDER models.
30 |
31 | The APIs of these modules are documentation in the subsections below.
32 |
33 | .. toctree::
34 | :maxdepth: 1
35 |
36 | settings
37 | plans
38 | feat_normalizer
39 | transform_data
40 | xc_evaluator
41 |
--------------------------------------------------------------------------------
/docs/ciderpress/dft/feat_normalizer.rst:
--------------------------------------------------------------------------------
1 | .. _feat_normalizer_module:
2 |
3 | The Feature Normalizer Module
4 | =============================
5 |
6 | .. automodule:: ciderpress.dft.feat_normalizer
7 | :members:
8 |
--------------------------------------------------------------------------------
/docs/ciderpress/dft/plans.rst:
--------------------------------------------------------------------------------
1 | .. _plans_module:
2 |
3 | The Plans Module
4 | ================
5 |
6 | .. automodule:: ciderpress.dft.plans
7 | :members:
8 |
--------------------------------------------------------------------------------
/docs/ciderpress/dft/settings.rst:
--------------------------------------------------------------------------------
1 | .. _settings_module:
2 |
3 | The Settings Module
4 | ===================
5 |
6 | .. automodule:: ciderpress.dft.settings
7 | :members:
8 |
--------------------------------------------------------------------------------
/docs/ciderpress/dft/transform_data.rst:
--------------------------------------------------------------------------------
1 | .. _transform_data_module:
2 |
3 | The Transform Data Module
4 | =========================
5 |
6 | .. automodule:: ciderpress.dft.transform_data
7 | :members:
8 |
--------------------------------------------------------------------------------
/docs/ciderpress/dft/xc_evaluator.rst:
--------------------------------------------------------------------------------
1 | .. _xc_evaluator_module:
2 |
3 | The XC Evaluator Modules
4 | ========================
5 |
6 | .. automodule:: ciderpress.dft.xc_evaluator
7 | :members:
8 |
9 | .. automodule:: ciderpress.dft.xc_evaluator2
10 | :members:
11 |
--------------------------------------------------------------------------------
/docs/ciderpress/gpaw/calculator.rst:
--------------------------------------------------------------------------------
1 | .. _GPAW Calculator Interface:
2 |
3 | GPAW Calculator Interface
4 | =========================
5 |
6 | The GPAW calculator interfaces modifies GPAW to be
7 | compatible with CIDER functionals. There are two
8 | key components. The first is the function
9 | :func:`ciderpress.gpaw.calculator.get_cider_functional`,
10 | which generates a CIDER functional for use in GPAW.
11 | The second is the :func:`ciderpress.gpaw.calculator.CiderGPAW`
12 | class, which modifies the ``GPAW`` calculator object
13 | to be able to read and write calculations that use CIDER
14 | functionals. ::
15 |
16 | xc = get_cider_functional(...)
17 | atoms.calc = CiderGPAW(xc=xc, ...)
18 | atoms.get_potential_energy()
19 |
20 | For a full example, see :source:`examples/gpaw/simple_calc.py`
21 | and the other examples in :source:`examples/gpaw`
22 |
23 | .. automodule:: ciderpress.gpaw.calculator
24 | :members:
25 |
--------------------------------------------------------------------------------
/docs/ciderpress/gpaw/gpaw.rst:
--------------------------------------------------------------------------------
1 | GPAW Interface
2 | ==============
3 |
4 | The GPAW interface allows CIDER functionals to be used in the GPAW code.
5 | CIDER has only been tested with the plane-wave mode of GPAW. It is
6 | recommended to use PAW setups (not pseudopotentials) because accurately
7 | computing the CIDER features requires an all-electron formalism.
8 | It is possible to run CIDER functionals with norm-conserving pseudopotentials
9 | (except for semilocal meta-GGA models), but it is not recommended.
10 |
11 | This documentation assumes that you are familiar with the GPAW code and
12 | have a working installation of the software. For GPAW documentation,
13 | see the `GPAW website `_.
14 |
15 | The key user-facing component of the GPAW interface is the
16 | :ref:`calculator` module, which provides tools
17 | to initialize a CIDER functional object that can be used in GPAW.
18 | It also provides a subclass of the ``GPAW`` calculator object.
19 | See the :ref:`calculator` module documentation
20 | for examples and API documentation.
21 |
22 | Note that CIDER does not support ``gpaw.new`` yet.
23 |
24 | .. toctree::
25 | :maxdepth: 1
26 | :caption: Contents:
27 |
28 | calculator
29 |
30 |
--------------------------------------------------------------------------------
/docs/ciderpress/models/dft_kernel.rst:
--------------------------------------------------------------------------------
1 | .. _dftkernel:
2 |
3 | ciderpress.models.dft_kernel
4 | ============================
5 |
6 | The DFTKernel
7 |
8 | .. automodule:: ciderpress.models.dft_kernel
9 | :members:
10 |
11 |
--------------------------------------------------------------------------------
/docs/ciderpress/models/kernel_tools.rst:
--------------------------------------------------------------------------------
1 | Kernel Tools
2 | ============
3 |
4 | .. automodule:: ciderpress.models.kernel_plans.kernel_tools
5 | :members:
6 |
7 |
--------------------------------------------------------------------------------
/docs/ciderpress/models/kernels.rst:
--------------------------------------------------------------------------------
1 | ciderpress.models.kernels
2 | =========================
3 |
4 | .. automodule:: ciderpress.models.kernels
5 | :members:
6 |
7 |
--------------------------------------------------------------------------------
/docs/ciderpress/models/models.rst:
--------------------------------------------------------------------------------
1 | .. _models_module:
2 |
3 | The Models Module
4 | =================
5 |
6 | The :py:mod:`ciderpress.models` module is the workhorse for training
7 | Cider exchange-correlation functionals and mapping them to efficient
8 | models for evaluation in DFT codes. The :py:mod:`train` module
9 | contains the :py:class:`MOLGP` and :py:class:`MOLGP2` classes,
10 | which are used to construct Gaussian process models for the exchange
11 | and correlation energies. While these Gaussian process classes
12 | are custom to CiderPress, the kernel functions used to construct
13 | the covariance matrix are built on top of those in the scikit-learn
14 | package.
15 |
16 | .. toctree::
17 | :maxdepth: 1
18 | :caption: Contents:
19 |
20 | train
21 | dft_kernel
22 | kernels
23 | kernel_tools
24 |
25 |
--------------------------------------------------------------------------------
/docs/ciderpress/models/train.rst:
--------------------------------------------------------------------------------
1 | ciderpress.models.train
2 | =======================
3 |
4 | .. automodule:: ciderpress.models.train
5 | :members:
6 |
7 |
--------------------------------------------------------------------------------
/docs/ciderpress/pyscf/analyzers.rst:
--------------------------------------------------------------------------------
1 | analyzers
2 | =========
3 |
4 | The :py:mod:`ciderpress.pyscf.analyzers` module provides
5 | post-processing tools for analyzing PySCF DFT calculations.
6 | In particular, sub-classes of :py:class:`ciderpress.pyscf.analyzers.ElectronAnalyzer`
7 | can generate densities, kinetic energy densities,
8 | exchange energy densities, etc. on a real-space grid.
9 |
10 | .. automodule:: ciderpress.pyscf.analyzers
11 | :members:
12 |
--------------------------------------------------------------------------------
/docs/ciderpress/pyscf/descriptors.rst:
--------------------------------------------------------------------------------
1 | descriptors
2 | ===========
3 |
4 | The :py:mod:`ciderpress.pyscf.descriptors` module provides the
5 | function :py:func:`get_descriptors`, which computes a
6 | set of requested CIDER features from a completed PySCF calculation.
7 | This is the utility used to generate the features
8 | for training CIDER models
9 |
10 | .. automodule:: ciderpress.pyscf.descriptors
11 | :members:
12 |
--------------------------------------------------------------------------------
/docs/ciderpress/pyscf/dft.rst:
--------------------------------------------------------------------------------
1 | dft
2 | ===
3 |
4 | The :py:mod:`ciderpress.pyscf.dft` module provides the
5 | function :py:func:`make_cider_calc`, which takes
6 | a Pyscf :py:class:`KohnShamDFT` object and a CIDER
7 | functional object (:py:class:`MappedXC` or :py:class:`MappedXC2`)
8 | and returns an instance of a :py:class:`KohnShamDFT`
9 | subclass that uses the CIDER functional. The function
10 | is similar to native PySCF routines like :py:func:`density_fit`,
11 | in which the input SCF object is "decorated" with the
12 | necessary routines to evaluate the CIDER functional.
13 |
14 | The basic use case is::
15 |
16 | from pyscf.dft import RKS
17 | from pyscf import gto
18 | mol = gto.M(...)
19 | ks = dft.RKS(mol)
20 | ks = make_cider_calc(ks, mlfunc, ...)
21 | etot = ks.kernel()
22 |
23 | For a complete example, please see :source:`examples/pyscf/simple_calc.py`
24 | and the other examples in :source:`examples/pyscf`.
25 |
26 | .. automodule:: ciderpress.pyscf.dft
27 | :members:
28 |
--------------------------------------------------------------------------------
/docs/ciderpress/pyscf/pbc/dft.rst:
--------------------------------------------------------------------------------
1 | pbc.dft
2 | =======
3 |
4 | The :py:mod:`ciderpress.pyscf.pbc.dft` module serves the same
5 | purpose as :py:mod:`ciderpress.pyscf.dft` but for periodic
6 | systems. This module's version of :py:func:`make_cider_calc`
7 | modifies a :py:mod:`pbc` Kohn Sham DFT object from PySCF
8 | to evaluate a CIDER functional. Currently only semilocal
9 | and SDMX features are supported.
10 |
11 | **NOTE**: This module is particularly experimental. It is
12 | provided for the purpose of reproducing previous work that
13 | used this module (i.e. :footcite:t:`CIDER24X`) and is not as
14 | close to production readiness as other parts of the code.
15 |
16 | .. automodule:: ciderpress.pyscf.pbc.dft
17 | :members:
18 |
19 | .. footbibliography::
20 |
--------------------------------------------------------------------------------
/docs/ciderpress/pyscf/pyscf.rst:
--------------------------------------------------------------------------------
1 | PySCF Interface
2 | ===============
3 |
4 | The PySCF interface allows CIDER functionals to be used in the PySCF
5 | software package. Most CIDER models are only availabe in the
6 | non-periodic version of PySCF, but SDMX functionals can be performed
7 | with periodic boundary conditions if pseudopotentials and a
8 | uniform XC integration grid are used. We note that the latter
9 | feature is particularly experimental.
10 |
11 | This documentation assumes you are familiar with the PySCF code and
12 | have a working installation of the software.
13 | For PySCF documentation, please see the `PySCF `_
14 | website.
15 |
16 | The main module CiderPress users need to be familiar with is
17 | :py:mod:`ciderpress.pyscf.dft`, which contains tools to
18 | turn a standard Kohn-Sham DFT calculation into one that uses
19 | a CIDER functional. See the module documentation for details.
20 |
21 | For those interested in the experimental periodic boundary
22 | condition feature for SDMX functionals, please see the
23 | :py:mod:`ciderpress.pyscf.pbc.dft` module documentation.
24 |
25 | .. toctree::
26 | :maxdepth: 2
27 |
28 | dft
29 | pbc/dft
30 | analyzers
31 | descriptors
32 |
33 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # For the full list of built-in configuration values, see the documentation:
4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
5 |
6 | import sys
7 | from pathlib import Path
8 | from datetime import datetime
9 | from ciderpress import __version__
10 |
11 | # sys.path.insert(0, str(Path('..').resolve()))
12 | sys.path.append("./tools/extensions")
13 |
14 | # -- Project information -----------------------------------------------------
15 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
16 |
17 | project = 'CiderPress'
18 | author = 'Kyle Bystrom'
19 | year = datetime.now().year
20 | copyright = f"{year}, Kyle Bystrom"
21 | # The short X.Y version.
22 | v,sv = __version__.split('.')[:2]
23 | version = "%s.%s"%(v,sv)
24 | # The full version, including alpha/beta/rc tags.
25 | release = __version__
26 |
27 | # -- General configuration ---------------------------------------------------
28 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
29 |
30 | extensions = [
31 | 'sphinx.ext.autodoc',
32 | 'sphinx_rtd_theme',
33 | 'sphinx.ext.mathjax',
34 | 'sphinx.ext.napoleon',
35 | 'sphinxcontrib.bibtex',
36 | 'ciderdocext',
37 | 'breathe',
38 | ]
39 | bibtex_bibfiles = ['refs/refs.bib', 'refs/cider_refs.bib']
40 |
41 | templates_path = ['_templates']
42 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
43 |
44 | autoclass_content = 'both'
45 |
46 | breathe_projects = {"CiderPress": "xml"}
47 | breathe_default_project = "CiderPress"
48 | breathe_default_members = ("members", "undoc-members")
49 | breathe_domain_by_extension = {
50 | "h" : "c",
51 | }
52 |
53 | napoleon_google_docstring = True
54 | # napoleon_numpy_docstring = True
55 | napoleon_use_param = False
56 |
57 | # -- Options for HTML output -------------------------------------------------
58 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
59 |
60 | html_theme = 'sphinx_rtd_theme'
61 | html_static_path = ['_static']
62 | html_logo = "logos/cider_logo_and_name.png"
63 | html_theme_options = {'logo_only': True}
64 |
65 |
--------------------------------------------------------------------------------
/docs/features/features.rst:
--------------------------------------------------------------------------------
1 | Density and Orbital Features in CiderPress
2 | ==========================================
3 |
4 | To predict the exchange-correlation energy :math:`E_{\text{xc}}`, we need
5 | to train a machine learning model :math:`e_{\text{xc}}(\mathbf{x})` such that
6 |
7 | .. math:: E_{\text{xc}} = \int \text{d}^3\mathbf{r}\, e_\text{xc}(\mathbf{x}[n_1](\mathbf{r}))
8 |
9 | where :math:`\mathbf{x}[n_1](\mathbf{r})` is a position-dependent feature vector that is
10 | a functional of the density :math:`n(\mathbf{r})` in "pure" Kohn-Sham DFT and a
11 | functional of the density matrix :math:`n_1(\mathbf{r}, \mathbf{r}')` in the case of
12 | "generalized" Kohn-Sham DFT. Cider provides several types of feature that can
13 | be used as input to the ML model. These features
14 | can be divided into four categories:
15 |
16 | * :ref:`Semilocal Features (SL) `: Same features as in conventional GGA/meta-GGA functionals (i.e. :math:`n`, :math:`\nabla n`, :math:`\tau`).
17 | NOTE: All Cider models must include semilocal features.
18 | They need not be used explicitly in the model, but evaluating
19 | them is required to evalute baseline functionals and other quantities in the code.
20 | * :ref:`Nonlocal Density Features (NLDF) `: These features are constructed by integrating the density
21 | over a real-space kernel function to characterize the shape of the density around a point :math:`\mathbf{r}`.
22 | * :ref:`Nonlocal Orbital Features (NLOF) `: EXPERIMENTAL, NOT TESTED, NOT RECOMMENDED FOR USE.
23 | One coordinate of the density matrix is operated on by a fractional Laplacian.
24 | * :ref:`Smooth Density Matrix Exchange (SDMX) `:
25 | One coordinate of the density matrix is convolved at different length scales. Then these convolutions
26 | are contracted to approximately characterize the shape of the density matrix around a point :math:`\mathbf{r}`.
27 |
28 | The set of features to be used in a model is specified using the :class:`FeatureSettings` object. To see
29 | the code API for setting up feature settings, see the :ref:`Settings module ` section. To see
30 | mathematical descriptions and physical intuition for the different types of features, see
31 | the subsections below.
32 |
33 | .. toctree::
34 | :maxdepth: 1
35 |
36 | sl
37 | nldf
38 | nlof
39 | sdmx
40 |
41 |
--------------------------------------------------------------------------------
/docs/features/nlof.rst:
--------------------------------------------------------------------------------
1 | .. _nlof_feat:
2 |
3 | Nonlocal Orbital Features (NLOF)
4 | ================================
5 |
6 | **The nonlocal orbital features are still highly experimental. We note here
7 | that they are implemented in the code so that their presence does not cause
8 | confusion, but their use is not encouraged, and they might be removed at a
9 | later date.**
10 |
11 |
--------------------------------------------------------------------------------
/docs/features/sl.rst:
--------------------------------------------------------------------------------
1 | .. _sl_feat:
2 |
3 | Semilocal Features (SL)
4 | =======================
5 |
6 | Semilocal features are the ingredient commonly used in semilocal DFT.
7 | They most basic ingredient is the electron density :math:`n(\mathbf{r})`,
8 | which is defined as
9 |
10 | .. math:: n(\mathbf{r}) = \sum_i f_i |\phi_i(\mathbf{r})|^2
11 |
12 | with :math:`\phi_i(\mathbf{r})` being the Kohn-Sham orbitals. A functional
13 | constructed from :math:`n(\mathbf{r})` only is called a local density
14 | approximation (LDA). The gradient of the density :math:`\nabla n(\mathbf{r})`
15 | is also commonly used and results in a generalized-gradient approximation (GGA).
16 | Lastly, the kinetic energy density
17 |
18 | .. math:: \tau(\mathbf{r}) = \frac{1}{2} \sum_i f_i |\nabla\phi_i(\mathbf{r})|^2
19 |
20 | can be used, resulting in a meta-generalized gradient approximation (meta-GGA or MGGA).
21 | To help enforce physical constraints such as uniform scaling, regularized
22 | features are often introduced, including the reduced gradient\ :footcite:p:`Perdew1996`
23 |
24 | .. math:: p = \frac{|\nabla n|^2}{2(3\pi^2)^{1/3}n^{4/3}}
25 |
26 | and the iso-orbital indicator\ :footcite:p:`Sun2013`
27 |
28 | .. math:: \alpha = \frac{\tau - \tau_W}{\tau_0}
29 |
30 | where :math:`\tau_W=|\nabla n|^2/8n` is the single-electron kinetic energy,
31 | and :math:`\tau_0=\frac{3}{10}(3\pi^2)^{2/3}n^{5/3}` is the kinetic energy
32 | density of the uniform electron gas.
33 |
34 | Note that for simplicity, all of these definitions are provided for the
35 | non-spin-polarized case, where the orbital occupations :math:`f_i\in [0,2]`
36 |
37 | In Cider, the choice of semilocal features is specified using the class:`SemilocalSettings`
38 | class in :py:mod:`ciderpress.dft.settings`. There is only one argument to this
39 | class, :py:obj:`mode`, which specifies which features to compute. There are four choices:
40 |
41 | * ``ns``: :math:`\mathbf{x}_\text{sl} = [n, |\nabla n|^2]`
42 | * ``np``: :math:`\mathbf{x}_\text{sl} = [n, p]`
43 | * ``nst``: :math:`\mathbf{x}_\text{sl} = [n, |\nabla n|^2, \tau]`
44 | * ``npa``: :math:`\mathbf{x}_\text{sl} = [n, p, \alpha]`
45 |
46 | **IMPORTANT NOTE 1**: If the mode is ``ns`` or ``np``, the kinetic energy density :math:`\tau`
47 | is not computed, so it cannot be used at any point in the calculation. This means
48 | that :ref:`Nonlocal Density Features ` must be instantiated with
49 | ``sl_level="GGA"``. If desired, orbital-dependent features can still be incorporated
50 | via :ref:`Smooth Density Matrix Exchange `. If the mode is ``nst`` or ``npa``,
51 | :math:`\tau` is always computed.
52 |
53 | **IMPORTANT NOTE 2**: The regularized features :math:`p` and :math:`\alpha` are
54 | scale-invariant, meaning that
55 | an exchange functional trained with these features and
56 | a proper exchange functional baseline will obey the
57 | uniform scaling rule (see :ref:`Uniform Scaling Constraints `).
58 | The raw features :math:`n`, :math:`|\nabla n|^2`, and :math:`\tau` are not
59 | scale-invariant, and CiderPress does not automatically regularize these features
60 | as it does with nonlocal features. Therefore, these features must be regularized in
61 | the :py:mod:`ciderpress.dft.transform_data` module to enforce the uniform scaling
62 | constraint in trained models. (TODO need to elaborate on this).
63 |
64 | See the :class:`SemilocalSettings` class in the :ref:`Feature Settings `
65 | documentation for more details on the API for setting up these features.
66 |
67 | .. footbibliography::
68 |
69 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. CiderPress documentation master file, created by
2 | sphinx-quickstart on Sat Oct 12 11:17:44 2024.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | CiderPress: Machine Learning Exchange-Correlation Functionals
7 | =============================================================
8 |
9 | Welcome to the CiderPress documentation! CiderPress is a Python package built
10 | for running machine-learned exchange-correlation functionals within the CIDER
11 | framework. This documentation is currently under construction. In the meantime,
12 | please feel free to post a Github issue or reach out the developers at
13 | kylebystrom@gmail.com.
14 |
15 |
16 | .. toctree::
17 | :maxdepth: 2
18 | :caption: Contents:
19 |
20 | installation/installation
21 | theory/theory
22 | features/features
23 | ciderpress/dft/dft
24 | ciderpress/models/models
25 | ciderpress/pyscf/pyscf
26 | ciderpress/gpaw/gpaw
27 | c_extensions/c_extensions
28 |
29 |
--------------------------------------------------------------------------------
/docs/logos/cider_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/logos/cider_logo_and_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/docs/logos/cider_logo_and_name.png
--------------------------------------------------------------------------------
/docs/logos/cider_logo_and_name.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/refs/cider_refs.bib:
--------------------------------------------------------------------------------
1 | @article{CIDER22X,
2 | title = {{{CIDER}}: {{An Expressive}}, {{Nonlocal Feature Set}} for {{Machine Learning Density Functionals}} with {{Exact Constraints}}},
3 | author = {Bystrom, Kyle and Kozinsky, Boris},
4 | year = {2022},
5 | month = apr,
6 | journal = {J. Chem. Theory Comput.},
7 | volume = {18},
8 | number = {4},
9 | pages = {2180--2192},
10 | issn = {1549-9618},
11 | doi = {10.1021/acs.jctc.1c00904}
12 | }
13 |
14 | @article{CIDER23X,
15 | title = {Nonlocal machine-learned exchange functional for molecules and solids},
16 | author = {Bystrom, Kyle and Kozinsky, Boris},
17 | journal = {Phys. Rev. B},
18 | volume = {110},
19 | issue = {7},
20 | pages = {075130},
21 | year = {2024},
22 | month = {Aug},
23 | publisher = {American Physical Society},
24 | doi = {10.1103/PhysRevB.110.075130},
25 | url = {https://link.aps.org/doi/10.1103/PhysRevB.110.075130}
26 | }
27 |
28 | @article{CIDER24X,
29 | author = {Bystrom, Kyle and Falletta, Stefano and Kozinsky, Boris},
30 | title = {Training Machine-Learned Density Functionals on Band Gaps},
31 | journal = {Journal of Chemical Theory and Computation},
32 | volume = {20},
33 | number = {17},
34 | pages = {7516-7532},
35 | year = {2024},
36 | doi = {10.1021/acs.jctc.4c00999},
37 | note ={PMID: 39178337},
38 | URL = {https://doi.org/10.1021/acs.jctc.4c00999},
39 | eprint = {https://doi.org/10.1021/acs.jctc.4c00999}
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/docs/theory/nldf_numerical.rst:
--------------------------------------------------------------------------------
1 | .. _nldf_numerical:
2 |
3 | Numerical Evaluation of NLDF Features
4 | =====================================
5 |
6 | Computing :ref:`Nonlocal Density Features ` (NLDFs) using simple
7 | numerical integration can be unwieldy and computationally costly, so in
8 | practical calculations, the feature integrals are expanded as a sum
9 | of convolutions. The expansion is slightly different for each
10 | feature version.
11 |
12 | For version j, the general form of the feature is
13 |
14 | .. math::
15 |
16 | G_i[n](\mathbf{r}) = \int \text{d}^3\mathbf{r} k(a_0[n](\mathbf{r}'), a_i(\mathbf{r}), |\mathbf{r}-\mathbf{r}'|) n(\mathbf{r}')
17 |
18 | In the context of implementing a nonlocal van der Waals density functional, :footcite:t:`Roman-Perez2009`
19 | found that the kernel :math:`k(a_0[n](\mathbf{r}'), a_i(\mathbf{r}), |\mathbf{r}-\mathbf{r}'|)`
20 | can be approximated as
21 |
22 | .. math::
23 |
24 | k(a, b, r) \approx \sum_\alpha \sum_\beta k(\alpha, \beta, r) p_\alpha(a) p_\beta(b)
25 |
26 | where :math:`\alpha` and :math:`\beta` are a set of interpolating points that span the range
27 | of values taken by :math:`a_0` and :math:`a_i` over the density distribution,
28 | and :math:`p_\alpha(a)` is a cubic spline that is :math:`1` when :math:`a=\alpha` and :math:`0`
29 | when :math:`a=\beta` (with :math:`\beta` being another interpolation point not equal to :math:`\alpha`).
30 | Because the interpolation points are constants independent of the density, the above approximation
31 | converts the feature integral into a sum over convolutions.
32 |
33 | The :py:class:`ciderpress.dft.plans.NLDFSplinePlan` class implements this interpolation
34 | approach.
35 |
36 | The version j integration kernel :math:`k(a, b, r)` is separable in :math:`a` and :math:`b`:
37 |
38 | .. math:: k(a, b, r) = \exp(-(a+b)r^2) = \exp(-a r^2) \exp(-b r^2)
39 |
40 | Because of this, the interpolations can also be performed by expanding :math:`\exp(-a r^2)`
41 | as a linear combination of the interpolation functions :math:`\exp(-\alpha r^2)`. This
42 | modified approach is implemented by the :py:class:`ciderpress.dft.plans.NLDFGaussianPlan` class.
43 |
44 | The details of how this interpolation approximation is used to compute the NLDFs
45 | is dependent on the periodicity, type of grid, and type of basis set used in a DFT
46 | calculation. For details on the implementation of this approach for isolated Gaussian-type
47 | orbital calculations and periodic plane-wave DFT calculations, see :footcite:t:`CIDER23X`.
48 |
49 | The other features versions (i and k) require slightly modified version of this approach,
50 | but the basic idea is the same and the implementation quite similar.
51 |
52 |
--------------------------------------------------------------------------------
/docs/theory/theory.rst:
--------------------------------------------------------------------------------
1 | Theory Overview
2 | ===============
3 |
4 | The theory section provides an overview of some of the important concepts
5 | involved in designing exchange-correlation functionals for DFT,
6 | particularly machine learning-based functionals.
7 |
8 | .. toctree::
9 | :maxdepth: 1
10 | :caption: Contents:
11 |
12 | uniform_scaling
13 | gp
14 | nldf_numerical
15 |
16 |
--------------------------------------------------------------------------------
/docs/theory/uniform_scaling.rst:
--------------------------------------------------------------------------------
1 | .. _unif_scaling:
2 |
3 | Uniform Scaling
4 | ===============
5 |
6 | Uniform scaling is a critical concept for understanding density functional
7 | design. Consider a given electron density distribution :math:`n(\mathbf{r})`.
8 | We can consider a transformed density of the form
9 |
10 | .. math:: n_\lambda(\mathbf{r}) = \lambda^3 n(\lambda \mathbf{r})
11 |
12 | This transformation is called *uniform coordinate scaling*,\ :footcite:p:`Martin2004`
13 | because it essentially involves redefining
14 | :math:`\mathbf{r}\leftarrow\lambda\mathbf{r}`, which squishes
15 | (:math:`\lambda>0`) or expands (:math:`\lambda<0`) the
16 | density while maintaining its relative shape. The :math:`\lambda^3`
17 | prefactor ensures that the particle number is conserved, i.e.
18 |
19 | .. math:: \int \text{d}^3\mathbf{r} n_\lambda(\mathbf{r}) = \int \text{d}^3\mathbf{r} n(\mathbf{r})
20 |
21 | One can also consider uniform scaling of the density *matrix*:
22 |
23 | .. math:: n_1^\lambda(\mathbf{r}, \mathbf{r}') = \lambda^3 n_1(\lambda \mathbf{r}, \lambda \mathbf{r}')
24 |
25 | NOTE: For orbital-dependent functionals, scaling the density and scaling the density matrix are
26 | not precisely equivalent, because there is a distribution of possible density
27 | matrices that can yield a given density. If the orbital-dependent potential
28 | causes the orbitals to rearrange themselves when uniform scaling occurs, the
29 | lowest-energy density matrix for a density :math:`n_\lambda` will not necessarily
30 | be :math:`n_1^\lambda`, i.e. the scaled density matrix obtained
31 | from the lowest-energy density matrix with density :math:`n`. This is a very
32 | subtle point, however, and does not usually make a big impact, so in most
33 | cases we will always refer to scaling the density :math:`n_\lambda` for
34 | simplicity, even when orbital-dependent quantities are involved.
35 | For more details, see :footcite:t:`Gorling1995`.
36 |
37 | The exact exchange functional :math:`E_\text{x}[n]` has a simple,
38 | exact behavior under uniform scaling:\ :footcite:p:`Levy1985`
39 |
40 | .. math:: E_\text{x}[n_\lambda] = \lambda E_\text{x}[n]
41 |
42 | The correlation functional :math:`E_\text{c}[n]` does not have such simple
43 | behavior under uniform scaling, but it does obey the limits\ :footcite:p:`Kaplan2023`
44 |
45 | .. math::
46 |
47 | \lim_{\lambda\rightarrow 0} E_\text{c}[n_\lambda] &= \lambda C_0[n] \\
48 | \lim_{\lambda\rightarrow \infty} E_\text{c}[n_\lambda] &> -\infty
49 |
50 | Therefore, it can be helpful to design features with simple, well-understood
51 | behavior under uniform scaling. In particular, if the feature vector :math:`\mathbf{x}`
52 | for the ML model is *scale-invariant*, i.e. if
53 |
54 | .. math:: \mathbf{x}[n_\lambda](\mathbf{r}) = \mathbf{x}[n](\lambda \mathbf{r})
55 |
56 | then an exchange functional of the form
57 |
58 | .. math:: E_\text{x}[n] = \int \text{d}^3\mathbf{r} e_\text{x}^\text{ML}(\mathbf{x}(\mathbf{r})
59 |
60 | obeys the uniform scaling rule for exchange (:math:`E_\text{x}[n_\lambda] = \lambda E_\text{x}[n]`).
61 | Similar, scale-invariant features can also be useful for correlation functionals because
62 | their behavior under uniform scaling will be the same as the behavior of the multiplicative
63 | baseline functional used for training. If the baseline model has reasonable behavior under
64 | uniform scaling (such as PBE/SCAN), this could help make more physically realistic models.
65 | (However, it could also needlessly restrict the model's flexibility, so there are trade-offs involved).
66 |
67 | .. footbibliography::
68 |
69 |
--------------------------------------------------------------------------------
/docs/tools/extensions/ciderdocext.py:
--------------------------------------------------------------------------------
1 | from sphinx.util.nodes import split_explicit_title
2 | from docutils import nodes, utils
3 |
4 | SOURCE_URI = 'https://github.com/mir-group/CiderPress/tree/main/%s'
5 |
6 | def source_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
7 | has_title, title, target = split_explicit_title(text)
8 | title = utils.unescape(title)
9 | target = utils.unescape(target)
10 | refnode = nodes.reference(title, title, refuri=SOURCE_URI % target)
11 | return [refnode], []
12 |
13 | def setup(app):
14 | app.add_role('source', source_role)
15 | return {'version': '0.1', 'parallel_read_safe': True}
16 |
--------------------------------------------------------------------------------
/examples/gpaw/pp_calc.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from ase.build import bulk
4 | from gpaw import PW
5 |
6 | from ciderpress.gpaw.calculator import CiderGPAW, get_cider_functional
7 |
8 | # NOTE: Run this script as follows:
9 | # mpirun -np python simple_calc.py
10 |
11 | atoms = bulk("Si")
12 |
13 | mlfunc = "functionals/{}.yaml".format(sys.argv[1])
14 |
15 | # This is the initializer for CIDER functionals for GPAW
16 | xc = get_cider_functional(
17 | # IMPORTANT: NormGPFunctional object or a path to a joblib or yaml file
18 | # containing a CIDER functional.
19 | mlfunc,
20 | # IMPORTANT: xmix is the mixing parameter for exact exchange. Default=0.25
21 | # gives the PBE0/CIDER surrogate hybrid.
22 | xmix=0.25,
23 | # largest q for interpolating feature expansion, default=300 is usually fine
24 | qmax=300,
25 | # lambda parameter for interpolating features. default=1.8 is usually fine.
26 | # Lower lambd is more precise
27 | lambd=1.8,
28 | # pasdw_store_funcs=False (default) saves memory. True reduces cost
29 | pasdw_store_funcs=False,
30 | # pasdw_ovlp_fit=True (default) uses overlap fitting to improve precision
31 | # of PAW correction terms of features.
32 | pasdw_ovlp_fit=True,
33 | use_paw=False,
34 | )
35 |
36 | # Using CiderGPAW instead of the default GPAW calculator allows calculations
37 | # to be restarted. GPAW calculations will run with CIDER functionals but
38 | # cannot be saved and loaded properly.
39 | atoms.calc = CiderGPAW(
40 | h=0.13, # use a reasonably small grid spacing
41 | xc=xc, # assign the CIDER functional to xc
42 | mode=PW(520), # plane-wave mode with 520 eV cutoff.
43 | txt="-", # output file, '-' for stdout
44 | occupations={"name": "fermi-dirac", "width": 0.01},
45 | # ^ Fermi smearing with 0.01 eV width
46 | kpts={"size": (12, 12, 12), "gamma": False}, # kpt mesh parameters
47 | convergence={"energy": 1e-5}, # convergence energy in eV/electron
48 | # Set augments_grids=True for CIDER functionals to parallelize
49 | # XC energy and potential evaluation more effectively
50 | parallel={"augment_grids": True},
51 | setups="sg15",
52 | )
53 | etot = atoms.get_potential_energy() # run the calculation
54 |
--------------------------------------------------------------------------------
/examples/gpaw/simple_calc.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | import numpy as np
4 | from ase.build import bulk
5 | from gpaw import PW, Mixer
6 |
7 | from ciderpress.gpaw.calculator import CiderGPAW, get_cider_functional
8 |
9 | # NOTE: Run this script as follows:
10 | # mpirun -np gpaw python simple_calc.py
11 |
12 | MODIFY_CELL = True
13 |
14 | atoms = bulk("Si")
15 |
16 | mlfunc = "functionals/{}.yaml".format(sys.argv[1])
17 |
18 | # This is the initializer for CIDER functionals for GPAW
19 | xc = get_cider_functional(
20 | # IMPORTANT: Path to a joblib or yaml file containing a CIDER functional.
21 | # Object stored in yaml/joblib must be MappedXC or MappedXC2.
22 | # Can also pass the object itself rather than a file name.
23 | mlfunc,
24 | # IMPORTANT: xmix is the mixing parameter for exact exchange. Default=0.25
25 | # gives the PBE0/CIDER surrogate hybrid.
26 | xmix=0.25,
27 | # largest q for interpolating feature expansion, default=300 is usually fine
28 | qmax=300,
29 | # lambda parameter for interpolating features. default=1.8 is usually fine.
30 | # Lower lambd is more precise
31 | lambd=1.8,
32 | # pasdw_store_funcs=False (default) saves memory. True reduces cost
33 | pasdw_store_funcs=False,
34 | # pasdw_ovlp_fit=True (default) uses overlap fitting to improve precision
35 | # of PAW correction terms of features. Usually not needed.
36 | pasdw_ovlp_fit=False,
37 | )
38 |
39 | # Using CiderGPAW instead of the default GPAW calculator allows calculations
40 | # to be restarted. Calculations using GPAW (rather than CiderGPAW)
41 | # will run with CIDER functionals but cannot be saved and loaded properly.
42 | atoms.calc = CiderGPAW(
43 | # use a reasonably small grid spacing
44 | h=0.18,
45 | # assign the CIDER functional to xc
46 | xc=xc,
47 | # plane-wave mode with 520 eV cutoff
48 | mode=PW(520),
49 | # output file, '-' for stdout
50 | txt="-",
51 | # Fermi smearing with 0.01 eV width
52 | occupations={"name": "fermi-dirac", "width": 0.01},
53 | # kpt mesh parameters
54 | kpts={"size": (4, 4, 4), "gamma": False},
55 | # convergence energy in eV/electron
56 | convergence={"energy": 1e-5},
57 | # Set augments_grids=True for CIDER functionals to parallelize
58 | # XC energy and potential evaluation more effectively
59 | parallel={"augment_grids": True},
60 | # Customize the mixer object if desired.
61 | mixer=Mixer(0.7, 8, 50),
62 | # Turn spin polarization on or off.
63 | spinpol=False,
64 | )
65 |
66 | # If desired, make a low-symmetry cell for testing purposes.
67 | if MODIFY_CELL:
68 | atoms.set_cell(
69 | np.dot(atoms.cell, [[1.02, 0, 0.03], [0, 0.99, -0.02], [0.2, -0.01, 1.03]]),
70 | scale_atoms=True,
71 | )
72 |
73 | # run the calculation
74 | etot = atoms.get_potential_energy()
75 |
--------------------------------------------------------------------------------
/examples/pyscf/compute_ae.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from collections import Counter
3 |
4 | import ase
5 | from ase import Atoms
6 | from ase.data import chemical_symbols, ground_state_magnetic_moments
7 | from pyscf import dft, gto, scf
8 | from pyscf.pbc.tools.pyscf_ase import atoms_from_ase
9 |
10 | from ciderpress.pyscf.dft import make_cider_calc
11 |
12 | """
13 | This script demonstrates running a CIDER calculation with accelerated
14 | nonlocal feature evaluation. Example commands:
15 |
16 | python examples/pyscf/fast_cider.py
17 | python examples/pyscf/fast_cider.py H2 0 0 PBE
18 | python examples/pyscf/fast_cider.py O2 0 2 CIDER_NL_MGGA
19 |
20 | is a chemical formula string like CH4, H2, etc. It must be included
21 | in the list of molecules supported by ase.build.molecule()
22 |
23 | is the integer charge of the system.
24 |
25 | is the integer spin of the system 2S.
26 |
27 | is the functional name. It can be the name of a libxc functional,
28 | or it can be the name of a functional in the functionals/ directory, in which case
29 | the corresponding example CIDER functional is run with the PBE0/CIDER
30 | surrogate hybrid functional form. If a path to a joblib file is given, that
31 | file will be read assuming it is a CIDER functional.
32 |
33 | At the end, prints out the total energy of the molecule and its atomization energy
34 | in Ha and eV, then saves the atomization energy in eV to aeresult.txt.
35 | """
36 |
37 | name, charge, spin, functional = sys.argv[1:5]
38 | charge = int(charge)
39 | spin = int(spin)
40 |
41 | spinpol = True if spin > 0 else False
42 | BAS = "def2-qzvppd"
43 | if name == "HF_stretch":
44 | BAS = "def2-svp"
45 | atoms = Atoms(symbols=["H", "F"], positions=[[0, 0, 0], [0, 0, 1.1]])
46 | elif name.startswith("el-"):
47 | el = name[3:]
48 | atoms = Atoms(el)
49 | elif name.endswith(".xyz"):
50 | ismol = True
51 | atoms = ase.io.read(name)
52 | atoms.center(vacuum=4)
53 | else:
54 | ismol = True
55 | from ase.build import molecule
56 |
57 | atoms = molecule(name)
58 | atoms.center(vacuum=4)
59 |
60 | if functional.startswith("CIDER"):
61 | functional = "functionals/{}.yaml".format(functional)
62 | is_cider = True
63 | mlfunc = functional
64 | elif functional.endswith(".joblib"):
65 | is_cider = True
66 | mlfunc = functional
67 | else:
68 | is_cider = False
69 | formula = Counter(atoms.get_atomic_numbers())
70 |
71 | mol = gto.M(
72 | atom=atoms_from_ase(atoms), basis=BAS, ecp=BAS, spin=spin, charge=charge, verbose=4
73 | )
74 |
75 |
76 | def run_calc(mol, spinpol):
77 | if spinpol:
78 | ks = dft.UKS(mol)
79 | else:
80 | ks = dft.RKS(mol)
81 | ks = ks.density_fit()
82 | ks.with_df.auxbasis = "def2-universal-jfit"
83 | ks = ks.apply(scf.addons.remove_linear_dep_)
84 | if is_cider:
85 | ks = make_cider_calc(
86 | ks,
87 | functional,
88 | xmix=0.25,
89 | xkernel="GGA_X_PBE",
90 | ckernel="GGA_C_PBE",
91 | )
92 | else:
93 | ks.xc = functional
94 | ks.grids.level = 3
95 | ks = ks.apply(scf.addons.remove_linear_dep_)
96 | etot = ks.kernel()
97 | return etot
98 |
99 |
100 | if spin == 0:
101 | spinpol = False
102 | else:
103 | spinpol = True
104 |
105 | etot_mol = run_calc(mol, spinpol)
106 | etot_ae = -1 * etot_mol
107 |
108 | for Z, count in formula.items():
109 | atom = gto.M(
110 | atom=chemical_symbols[Z],
111 | basis=BAS,
112 | ecp=BAS,
113 | spin=int(ground_state_magnetic_moments[Z]),
114 | verbose=4,
115 | )
116 | etot_atom = run_calc(atom, True)
117 | etot_ae += count * etot_atom
118 |
119 | print("Total and Atomization Energies, Ha")
120 | print(etot_mol, etot_ae)
121 | eh2ev = 27.211399
122 | print("Total and Atomization Energies, eV")
123 | print(etot_mol * eh2ev, etot_ae * eh2ev)
124 | with open("aeresult.txt", "w") as f:
125 | f.write(str(etot_ae * eh2ev))
126 |
--------------------------------------------------------------------------------
/examples/pyscf/simple_calc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import sys
22 |
23 | from pyscf import dft, gto
24 |
25 | from ciderpress.pyscf.dft import make_cider_calc
26 |
27 | # This is a simple example for running a PySCF calculation with
28 | # a CIDER functional.
29 | # This example runs a "surrogate" PBE0 calculation, where a CIDER exchange
30 | # functional is used in place of exact exchange.
31 | # It takes one command line argument, which is the functional to use.
32 | # For example, you could use "CIDER23X_NL_MGGA_DTR" or "CIDER23X_SL_GGA".
33 |
34 | mlfunc = "functionals/{}.yaml".format(sys.argv[1])
35 |
36 | mol = gto.M(
37 | atom="F 0.0 0.0 0.0; F 0.0 0.0 1.42",
38 | basis="def2-tzvp",
39 | )
40 |
41 | ks = dft.RKS(mol)
42 | ks = make_cider_calc(
43 | # KohnShamDFT object
44 | ks,
45 | # MappedXC, MappedXC2, or path to yaml/joblib file with one of these classes
46 | mlfunc,
47 | # Semi-local exchange and correlation parts
48 | xkernel="GGA_X_PBE",
49 | ckernel="GGA_C_PBE",
50 | # exact exchange mixing parameter
51 | xmix=0.25,
52 | )
53 | ks = ks.density_fit()
54 | ks.with_df.auxbasis = "def2-universal-jfit"
55 | ks.kernel()
56 |
--------------------------------------------------------------------------------
/examples/pyscf/simple_sdmx.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 |
22 | from pyscf import dft, gto
23 |
24 | from ciderpress.pyscf.dft import make_cider_calc
25 |
26 | # This is a simple example for running a PySCF calculation with
27 | # a CIDER functional.
28 | # This is the same as the other example but runs the CIDER24Xe
29 | # exchange functional, which is fit to HOMO-LUMO gaps as well as energetic
30 | # data.
31 |
32 | mlfunc = "functionals/CIDER24Xe.yaml"
33 |
34 | mol = gto.M(
35 | atom="Cl 0.0 0.0 0.0; Cl 0.0 0.0 1.6",
36 | basis="def2-tzvp",
37 | )
38 |
39 | ks = dft.RKS(mol)
40 | ks = make_cider_calc(
41 | # KohnShamDFT object
42 | ks,
43 | # MappedXC, MappedXC2, or path to yaml/joblib file with one of these classes
44 | mlfunc,
45 | # Semi-local exchange and correlation parts
46 | xkernel="GGA_X_PBE",
47 | ckernel="GGA_C_PBE",
48 | # exact exchange mixing parameter
49 | xmix=0.25,
50 | )
51 | ks = ks.density_fit()
52 | ks.with_df.auxbasis = "def2-universal-jfit"
53 | ks.kernel()
54 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools >= 61.0", "wheel", "cmake<3.31"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | ["project"]
6 | name = "ciderpress"
7 | dynamic = ["version"]
8 | description = "CiderPress: DFT Calculations with Machine-Learned XC Functionals"
9 | readme = "README.md"
10 | classifiers = [
11 | "Development Status :: 3 - Alpha",
12 | 'Intended Audience :: Science/Research',
13 | 'Intended Audience :: Developers',
14 | 'Programming Language :: C',
15 | 'Programming Language :: Python',
16 | 'Topic :: Scientific/Engineering',
17 | 'Operating System :: POSIX',
18 | 'Operating System :: Unix',
19 | ]
20 |
21 | maintainers = [{ name = "Kyle Bystrom", email = "kylebystrom@gmail.com" }]
22 |
23 | authors = [{ name = "Kyle Bystrom", email = "kylebystrom@gmail.com" }]
24 |
25 | dependencies = [
26 | "ase>=3.22.0",
27 | "h5py>=3.6.0",
28 | "interpolation>=2.2.7",
29 | "numba>=0.60",
30 | "numpy>=1.20",
31 | "pyscf>=2.6",
32 | "pytest",
33 | "pyyaml",
34 | "scikit-learn>=1.0.1",
35 | "scipy>=1.12",
36 | "sympy",
37 | ]
38 |
39 | [project.urls]
40 | Repository = "https://github.com/mir-group/CiderPress"
41 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | addopts = --import-mode=importlib
3 | -k "not _high_cost and not _skip"
4 | --ignore=examples
5 | --ignore-glob="*_slow*.py"
6 | --ignore-glob="*gpaw/*.py"
7 |
--------------------------------------------------------------------------------
/pytest_mpi.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | addopts = --import-mode=importlib
3 | -k "not _high_cost and not _skip"
4 | --ignore=examples
5 | --ignore-glob="*_slow*.py"
6 |
--------------------------------------------------------------------------------
/scripts/download_functionals.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # CiderPress: Machine-learning based density functional theory calculations
3 | # Copyright (C) 2024 The President and Fellows of Harvard College
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see
17 | #
18 | # Author: Kyle Bystrom
19 | #
20 |
21 | import os
22 | import subprocess
23 |
24 | basedir = __file__
25 | savedir = os.path.basename(os.path.join(basedir, "../functionals"))
26 |
27 | os.makedirs(savedir, exist_ok=True)
28 |
29 | os.chdir(savedir)
30 | cmd = "wget 'https://zenodo.org/api/records/13336814/files-archive' -O cider_functionals.zip"
31 | unzip = "unzip cider_functionals.zip"
32 | rm = "rm -r cider_functionals.zip"
33 | subprocess.call(cmd, shell=True)
34 | subprocess.call(unzip, shell=True)
35 | subprocess.call(rm, shell=True)
36 |
--------------------------------------------------------------------------------
/scripts/generate_etb.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from pyscf.data.elements import ELEMENTS
3 | from pyscf.gto.basis import load
4 |
5 | ZMAX = 118
6 | LMAX = 3
7 | min_data = np.zeros((ZMAX + 1, LMAX + 1), dtype=np.float64)
8 | max_data = np.zeros((ZMAX + 1, LMAX + 1), dtype=np.float64)
9 | for Z in range(1, ZMAX + 1):
10 | symb = ELEMENTS[Z]
11 | print(symb)
12 | # want at least up to d shells
13 | if Z == 1:
14 | basis = "HGBSP2-5"
15 | else:
16 | basis = "HGBSP2-5"
17 | # basis = 'ANO-RCC'
18 | try:
19 | basis = load(basis, symb)
20 | except Exception:
21 | basis = "HGBSP2-5"
22 | basis = load(basis, symb)
23 | try:
24 | basis = basis[symb]
25 | except TypeError:
26 | pass
27 | for lst in basis:
28 | l = lst[0]
29 | if l > 3:
30 | continue
31 | lists = lst[1:]
32 | expnts = []
33 | for lst in lists:
34 | expnts.append(lst[0])
35 | min_data[Z, l] = np.min(expnts)
36 | max_data[Z, l] = np.max(expnts)
37 |
38 | np.save("ciderpress/data/expnt_mins.npy", min_data)
39 | np.save("ciderpress/data/expnt_maxs.npy", max_data)
40 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | from setuptools import find_packages, setup
5 | from setuptools.command.build_py import build_py
6 |
7 | # TODO not using wheel yet, but plan to do so eventually
8 | from wheel.bdist_wheel import bdist_wheel
9 |
10 |
11 | def get_version():
12 | topdir = os.path.abspath(os.path.join(__file__, ".."))
13 | with open(os.path.join(topdir, "ciderpress", "__init__.py"), "r") as f:
14 | for line in f.readlines():
15 | if line.startswith("__version__"):
16 | delim = '"' if '"' in line else "'"
17 | return line.split(delim)[1]
18 | raise ValueError("Version string not found")
19 |
20 |
21 | VERSION = get_version()
22 |
23 |
24 | def get_platform():
25 | from sysconfig import get_platform
26 |
27 | platform = get_platform()
28 | # TODO might want to add darwin OSX support like PySCF
29 | # but only after officially adding OSX support
30 | return platform
31 |
32 |
33 | class CMakeBuildPy(build_py):
34 | def run(self):
35 | self.plat_name = get_platform()
36 | self.build_base = "build"
37 | self.build_lib = os.path.join(self.build_base, "lib")
38 | self.build_temp = os.path.join(self.build_base, f"temp.{self.plat_name}")
39 |
40 | self.announce("Configuring extensions", level=3)
41 | src_dir = os.path.abspath(os.path.join(__file__, "..", "ciderpress", "lib"))
42 | cmd = [
43 | "cmake",
44 | f"-S{src_dir}",
45 | f"-B{self.build_temp}",
46 | "-DCMAKE_PREFIX_PATH={}".format(sys.base_prefix),
47 | "-DCMAKE_BUILD_TYPE=Release",
48 | ]
49 | configure_args = os.getenv("CMAKE_CONFIGURE_ARGS")
50 | if configure_args:
51 | cmd.extend(configure_args.split(" "))
52 | self.spawn(cmd)
53 |
54 | self.announce("Building binaries", level=3)
55 | cmd = ["cmake", "--build", self.build_temp, "-j2"]
56 | build_args = os.getenv("CMAKE_BUILD_ARGS")
57 | if build_args:
58 | cmd.extend(build_args.split(" "))
59 | if self.dry_run:
60 | self.announce(" ".join(cmd))
61 | else:
62 | self.spawn(cmd)
63 | self.editable_mode = False
64 | super().run()
65 |
66 |
67 | # NOTE note trying to support wheal yet, but including
68 | # these code block from PySCF setup.py for future.
69 | initialize_options_1 = bdist_wheel.initialize_options
70 |
71 |
72 | def initialize_with_default_plat_name(self):
73 | initialize_options_1(self)
74 | self.plat_name = get_platform()
75 | self.plat_name_supplied = True
76 |
77 |
78 | bdist_wheel.initialize_options = initialize_with_default_plat_name
79 |
80 | # from PySCF setup.py
81 | try:
82 | from setuptools.command.bdist_wheel import bdist_wheel
83 |
84 | initialize_options_2 = bdist_wheel.initialize_options
85 |
86 | def initialize_with_default_plat_name(self):
87 | initialize_options_2(self)
88 | self.plat_name = get_platform()
89 | self.plat_name_supplied = True
90 |
91 | bdist_wheel.initialize_options = initialize_with_default_plat_name
92 | except ImportError:
93 | pass
94 |
95 | setup(
96 | version=VERSION,
97 | include_package_data=True,
98 | packages=find_packages(exclude=["*test*", "*examples*"]),
99 | cmdclass={"build_py": CMakeBuildPy},
100 | )
101 |
--------------------------------------------------------------------------------