From 391850f85236fbff2aa4b56206f83df4520b66f9 Mon Sep 17 00:00:00 2001 From: kylebystrom Date: Tue, 26 Nov 2024 17:30:11 -0500 Subject: [PATCH] add some docs on some complicated low-level functions --- ciderpress/dft/lcao_interpolation.py | 20 +++++++++ ciderpress/dft/settings.py | 24 ++++++++++ ciderpress/gpaw/calculator.py | 2 +- ciderpress/gpaw/descriptors.py | 3 ++ ciderpress/lib/mod_cider/conv_interpolation.c | 44 +++++++++++++++++++ ciderpress/pyscf/sdmx.py | 11 +++++ 6 files changed, 103 insertions(+), 1 deletion(-) diff --git a/ciderpress/dft/lcao_interpolation.py b/ciderpress/dft/lcao_interpolation.py index 9db28cc..e28e06a 100644 --- a/ciderpress/dft/lcao_interpolation.py +++ b/ciderpress/dft/lcao_interpolation.py @@ -376,6 +376,14 @@ def natm(self): return self.atco.natm def _set_num_ai(self, all_coords): + """ + This function computes the number of coordinates in + all_coords that fall in each spline "box" for the radial + interpolation grid on each atom. The result is then + used to create the _loc_ai member, which in turn + is used by the _compute_sline_ind_order function + to order grid coordinates by their spline box on a given atom. + """ if all_coords is None: assert self.is_num_ai_setup return @@ -425,6 +433,12 @@ def _set_num_ai(self, all_coords): self.is_num_ai_setup = True def _compute_spline_ind_order(self, a): + """ + Assuming _set_num_ai has been called previously, order + self.all_coords such that each coordinate is in increasing + order of spline index for the radial interpolation grid + on atom a. + """ if not self.is_num_ai_setup: raise RuntimeError ngrids_tot = self.all_coords.shape[0] @@ -452,6 +466,12 @@ def _compute_spline_ind_order(self, a): return self._coords_ord, self._ind_ord_fwd def _eval_spline_bas_single(self, a): + """ + Note that _set_num_ai must have been called previously, because + it is required for _compute_spline_ind_order to work, which + is called by this function. TODO might be better to have a cleaner + solution for this algorithm. + """ self._compute_spline_ind_order(a) ngrids = self._coords_ord.shape[0] if self.onsite_direct: diff --git a/ciderpress/dft/settings.py b/ciderpress/dft/settings.py index 19450cf..1be4336 100644 --- a/ciderpress/dft/settings.py +++ b/ciderpress/dft/settings.py @@ -72,6 +72,9 @@ def _get_fl_ueg(s): def get_cider_exponent( rho, sigma, tau, a0=1.0, grad_mul=0.0, tau_mul=0.03125, rhocut=1e-10, nspin=1 ): + """ + Evaluate an NLDF length-scale exponent at the MGGA level. + """ if nspin > 2: raise ValueError if isinstance(rho, np.ndarray): @@ -113,6 +116,9 @@ def get_cider_exponent( def get_cider_exponent_gga(rho, sigma, a0=1.0, grad_mul=0.03125, rhocut=1e-10, nspin=1): + """ + Evaluate an NLDF length-scale exponent at the GGA level. + """ if nspin > 2: raise ValueError if isinstance(rho, np.ndarray): @@ -161,6 +167,13 @@ def _get_ueg_expnt(aval, tval, rho): class BaseSettings(ABC): + """ + This is a base class for storing the settings for different + types of density/density matrix feature in CiderPress. + Settings objects indicate which features must be evaluated, + and with which hyperparameters, to use as input to an ML functional. + """ + @property @abstractmethod def nfeat(self): @@ -171,6 +184,9 @@ def nfeat(self): @property def is_empty(self): + """ + Return true of this settings object specifies zero features. + """ return self.nfeat == 0 @abstractmethod @@ -201,6 +217,14 @@ def get_reasonable_normalizer(self): class EmptySettings(BaseSettings): + """ + The EmptySettings class is a representation of a feature set containing + zero features. It is used when a certain type of feature is not + present in a model. (For example, if a model does not use SDMX + features, that model's FeatureSettings.sdmx_settings will be + an EmptySettings instance.) + """ + @property def nfeat(self): return 0 diff --git a/ciderpress/gpaw/calculator.py b/ciderpress/gpaw/calculator.py index 9d74885..efef283 100644 --- a/ciderpress/gpaw/calculator.py +++ b/ciderpress/gpaw/calculator.py @@ -142,7 +142,7 @@ class is returned to evaluate the semilocal functional. raise NotImplementedError( "Currently only version j NLDF features are implemented in GPAW. " "Other versions are planned for future development. The version " - "of your functional's features is: {}".format( + "of this functional's NLDF features is: {}".format( mlfunc.settings.nldf_settings.version ) ) diff --git a/ciderpress/gpaw/descriptors.py b/ciderpress/gpaw/descriptors.py index 32dd890..2e65d1a 100644 --- a/ciderpress/gpaw/descriptors.py +++ b/ciderpress/gpaw/descriptors.py @@ -83,6 +83,9 @@ def get_descriptors( use_paw (bool, True): Whether to use PAW corrections. screen_dens (bool, True): Whether to remove low-density grids from the return feature vectors. + kwargs: Any additional arguments to be passed to the + Cider functional object (like qmax, lambd, etc.) + to compute the functional. Returns: if p_i is None: diff --git a/ciderpress/lib/mod_cider/conv_interpolation.c b/ciderpress/lib/mod_cider/conv_interpolation.c index fd901c5..832194b 100644 --- a/ciderpress/lib/mod_cider/conv_interpolation.c +++ b/ciderpress/lib/mod_cider/conv_interpolation.c @@ -302,6 +302,25 @@ void compute_num_spline_contribs_multi(spline_locator *spline_locs, } } +/** + * Compute the number of coordinates (coords) that fall within each + * radial spline block. The result (num_ai) can then be used + * in compute_spline_ind_order_new + * to order the grids by their distance from the atom at atm_coord. + * num_ai: The result, num_ai[ia * nrad + ir] contains the number of + * grid points that fall in spline index ir of atom with index ia. + * coords: coords + 3 * g is the real-space coordinate of grid g. + * atm_coords: atm_coords + 3 * ia is the real-space coordinate of atom ia. + * aparam, dparam: The radial grid with index ir is + * aparam * (exp(dparam * ir) - 1) + * natm: Number of atoms + * ngrids: Number of 3D real-space grids + * nrad: Number of grids for the radial spline on each atom. + * iatom_g: coords + 3 * g is part of the atomic grid belonging + * to the atom with index iatom_g[g]. If iatom_g is NULL, + * it is ignored. If it is not NULL, it is used to ignore + * on-site grids when constructing num_ai. + */ void compute_num_spline_contribs_new(int *num_ai, double *coords, double *atm_coords, double aparam, double dparam, int natm, int ngrids, @@ -432,6 +451,31 @@ void compute_spline_ind_order(int *loc_i, double *coords, double *atm_coord, free(num_i_tmp); } +/** + * TODO this function should be modified to run in parallel. + * This function sorts the grid coordinates (coords) in order of their + * distance from the atomic coordinate (atm_coord). + * loc_i: For each radial index ir, loc_i[ir] says where each batch + * corresponding to index ir of the radial spline is located + * in the coords_ord array. It is constructed in the + * _set_num_ai function of ciderpress.dft.lcao_interpolation. + * coords: 3-D grid coordinations + * atm_coord: Atomic coordinate + * coords_ord: OUTPUT. The ordered coordinates are saved to this array. + * ind_ord_fwd, ind_ord_bwd: OUTPUT. After execution, for x in 0, 1, 2, + * the following relationships hold: + * coords_ord[3 * g + x] == coords[3 * ind_ord_fwd[g] + x] + * coords_ord[3 * ind_ord_bwd[g] + x] == coords[3 * g + x] + * aparam, dparam: The radial grid with index ir is + * aparam * (exp(dparam * ir) - 1) + * ngrids: Number of 3D real-space grids + * nrad: Number of grids for the radial spline on each atom. + * iatom_g: coords + 3 * g is part of the atomic grid belonging + * to the atom with index iatom_g[g]. If iatom_g is NULL, + * it is ignored. If it is not NULL, it is used to ignore + * on-site grids when constructing num_ai. + * iatom: Index of the atom of for which the grids are being ordered. + */ void compute_spline_ind_order_new(int *loc_i, double *coords, double *atm_coord, double *coords_ord, int *ind_ord_fwd, int *ind_ord_bwd, double aparam, diff --git a/ciderpress/pyscf/sdmx.py b/ciderpress/pyscf/sdmx.py index 581366d..e0f6974 100644 --- a/ciderpress/pyscf/sdmx.py +++ b/ciderpress/pyscf/sdmx.py @@ -43,10 +43,21 @@ def _get_ylm_atom_loc(mol): def _get_nrf(mol): + """ + Get the number of unique radial functions associated with a basis + """ return np.sum(mol._bas[:, NCTR_OF]) def _get_rf_loc(mol): + """ + Get an integer numpy array with that gives the location of the + unique radial functions corresponding to each shell. + So rf_loc[shl : shl + 1] is the range of radial functions contained + in the shell. This is similar to ao_loc, except that it does not + include spherical harmonics, so each shell has a factor of 2l+1 + more functions in ao_loc than rf_loc. + """ rf_loc = mol._bas[:, NCTR_OF] rf_loc = np.append([0], np.cumsum(rf_loc)).astype(np.int32) return rf_loc