Skip to content

Commit 6ae8e6f

Browse files
authored
Merge pull request #210 from Ali-Tehrani/grid_assesment_default
Default Grid Assesment
2 parents d8443a7 + 078a98e commit 6ae8e6f

File tree

6 files changed

+312
-134
lines changed

6 files changed

+312
-134
lines changed

src/grid/atomgrid.py

+20-7
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@
2222
from typing import Union
2323

2424
import numpy as np
25+
import scipy.constants
2526
from importlib_resources import files
2627
from scipy.interpolate import CubicSpline
2728
from scipy.spatial.transform import Rotation as R
2829

2930
from grid.angular import AngularGrid
3031
from grid.basegrid import Grid, OneDGrid
32+
from grid.onedgrid import UniformInteger
33+
from grid.rtransform import PowerRTransform
3134
from grid.utils import (
35+
_DEFAULT_POWER_RTRANSFORM_PARAMS,
3236
convert_cart_to_sph,
3337
convert_derivative_from_spherical_to_cartesian,
3438
generate_derivative_real_spherical_harmonics,
@@ -52,7 +56,6 @@ class AtomGrid(Grid):
5256
def __init__(
5357
self,
5458
rgrid: OneDGrid,
55-
*,
5659
degrees: Union[np.ndarray, list] = None,
5760
sizes: Union[np.ndarray, list] = None,
5861
center: np.ndarray = None,
@@ -129,10 +132,9 @@ def __init__(
129132
@classmethod
130133
def from_preset(
131134
cls,
132-
rgrid: OneDGrid = None,
133-
*,
134135
atnum: int,
135136
preset: str,
137+
rgrid: OneDGrid = None,
136138
center: np.ndarray = None,
137139
rotate: int = 0,
138140
use_spherical: bool = False,
@@ -142,12 +144,14 @@ def from_preset(
142144
Examples
143145
--------
144146
>>> # construct an atomic grid for H with fine grid setting
145-
>>> atgrid = AtomGrid.from_preset(rgrid, atnum=1, preset="fine")
147+
>>> atgrid = AtomGrid.from_preset(atnum=1, preset="fine", rgrid)
146148
147149
Parameters
148150
----------
149151
rgrid : OneDGrid, optional
150152
The (1-dimensional) radial grid representing the radius of spherical grids.
153+
If None, then using the atomic number it will generate a default radial grid
154+
(PowerRTransform of UniformInteger grid).
151155
atnum : int, keyword-only argument
152156
The atomic number specifying the predefined grid.
153157
preset : str, keyword-only argument
@@ -189,8 +193,18 @@ def from_preset(
189193
if not isinstance(use_spherical, bool):
190194
raise TypeError(f"use_spherical {use_spherical} should be of type bool.")
191195
if rgrid is None:
192-
# TODO: generate a default rgrid, currently raise an error instead
193-
raise ValueError("A default OneDGrid will be generated")
196+
# If the atomic number is found in the default RTransform
197+
if atnum in _DEFAULT_POWER_RTRANSFORM_PARAMS:
198+
rmin, rmax, npt = _DEFAULT_POWER_RTRANSFORM_PARAMS[int(atnum)]
199+
# Convert angstrom to atomic units
200+
ang2bohr = scipy.constants.angstrom / scipy.constants.value("atomic unit of length")
201+
rmin, rmax = rmin * ang2bohr, rmax * ang2bohr
202+
onedgrid = UniformInteger(npt)
203+
rgrid = PowerRTransform(rmin, rmax).transform_1d_grid(onedgrid)
204+
else:
205+
raise ValueError(
206+
f"Default rgrid parameter is not included for the" f" atomic number {atnum}."
207+
)
194208
center = np.zeros(3, dtype=float) if center is None else np.asarray(center, dtype=float)
195209
cls._input_type_check(rgrid, center)
196210
# load radial points and
@@ -221,7 +235,6 @@ def from_pruned(
221235
cls,
222236
rgrid: OneDGrid,
223237
radius: float,
224-
*_,
225238
sectors_r: np.ndarray,
226239
sectors_degree: np.ndarray = None,
227240
sectors_size: np.ndarray = None,

src/grid/molgrid.py

+86-28
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@
2222
from typing import Union
2323

2424
import numpy as np
25+
import scipy.constants
2526

2627
from grid.atomgrid import AtomGrid
2728
from grid.basegrid import Grid, LocalGrid, OneDGrid
29+
from grid.becke import BeckeWeights
30+
from grid.onedgrid import UniformInteger
31+
from grid.rtransform import PowerRTransform
32+
from grid.utils import _DEFAULT_POWER_RTRANSFORM_PARAMS
2833

2934

3035
class MolGrid(Grid):
@@ -75,7 +80,7 @@ class MolGrid(Grid):
7580
specifying the size of each Levedev grid at each radial points.
7681
7782
>>> preset = "fine" # Many choices available.
78-
>>> molgrid = MolGrid.from_preset(charges, coords, rgrid, preset, aim_weights=becke)
83+
>>> molgrid = MolGrid.from_preset(charges,coords,preset,aim_weights=becke,rgrid=rgrid)
7984
8085
The general way to integrate is the following.
8186
@@ -342,10 +347,9 @@ def from_preset(
342347
cls,
343348
atnums: np.ndarray,
344349
atcoords: np.ndarray,
345-
rgrid: Union[OneDGrid, list, dict],
346350
preset: Union[str, list, dict],
347-
aim_weights: Union[callable, np.ndarray],
348-
*_,
351+
rgrid: Union[OneDGrid, list, dict] = None,
352+
aim_weights: Union[callable, np.ndarray] = None,
349353
rotate: int = 37,
350354
store: bool = False,
351355
):
@@ -357,10 +361,6 @@ def from_preset(
357361
Array of atomic numbers.
358362
atcoords : np.ndarray(M, 3)
359363
Atomic coordinates of atoms.
360-
rgrid : (OneDGrid, list[OneDGrid], dict[int: OneDGrid])
361-
One dimensional radial grid. If of type `OneDGrid` then this radial grid is used for
362-
all atoms. If a list is provided,then ith grid correspond to the ith atom. If
363-
dictionary is provided, then the keys correspond to the `atnums[i]`attribute.
364364
preset : (str, list[str], dict[int: str])
365365
Preset grid accuracy scheme. If string is provided, then preset is used
366366
for all atoms, either it is specified by a list, or a dictionary whose keys
@@ -371,8 +371,14 @@ def from_preset(
371371
'sg_0', 'sg_1', 'sg_2', and 'sg_3', and the Ochsenfeld grids:
372372
'g1', 'g2', 'g3', 'g4', 'g5', 'g6', and 'g7', with higher number indicating
373373
greater accuracy but denser grid. See `Notes` for more information.
374-
aim_weights : Callable or np.ndarray(K,)
375-
Atoms in molecule weights.
374+
rgrid : (OneDGrid, list[OneDGrid], dict[int: OneDGrid]), optional
375+
One dimensional radial grid. If of type `OneDGrid` then this radial grid is used for
376+
all atoms. If a list is provided,then ith grid correspond to the ith atom. If
377+
dictionary is provided, then the keys correspond to the `atnums[i]`attribute.
378+
If None, then using atomic numbers it will generate a default radial grid
379+
(PowerRTransform of UniformInteger grid).
380+
aim_weights : Callable or np.ndarray(K,), optional
381+
Atoms in molecule weights. If None, then aim_weights is Becke weights with order=3.
376382
rotate : bool or int, optional
377383
Flag to set auto rotation for atomic grid, if given int, the number
378384
will be used as a seed to generate rantom matrix.
@@ -407,6 +413,8 @@ def from_preset(
407413
"shape of atomic nums does not match with coordinates\n"
408414
f"atomic numbers: {atnums.shape}, coordinates: {atcoords.shape}"
409415
)
416+
if aim_weights is None:
417+
aim_weights = BeckeWeights(order=3)
410418
total_atm = len(atnums)
411419
atomic_grids = []
412420
for i in range(total_atm):
@@ -417,6 +425,9 @@ def from_preset(
417425
rad = rgrid[i]
418426
elif isinstance(rgrid, dict):
419427
rad = rgrid[atnums[i]]
428+
elif rgrid is None:
429+
atnum = atnums[i]
430+
rad = _generate_default_rgrid(atnum)
420431
else:
421432
raise TypeError(f"not supported radial grid input; got input type: {type(rgrid)}")
422433
# get proper grid type
@@ -431,7 +442,7 @@ def from_preset(
431442
f"Not supported preset type; got preset {preset} with type {type(preset)}"
432443
)
433444
at_grid = AtomGrid.from_preset(
434-
rad, atnum=atnums[i], preset=gd_type, center=atcoords[i], rotate=rotate
445+
atnum=atnums[i], preset=gd_type, rgrid=rad, center=atcoords[i], rotate=rotate
435446
)
436447
atomic_grids.append(at_grid)
437448
return cls(atnums, atomic_grids, aim_weights, store=store)
@@ -441,9 +452,9 @@ def from_size(
441452
cls,
442453
atnums: np.ndarray,
443454
atcoords: np.ndarray,
444-
rgrid: OneDGrid,
445455
size: int,
446-
aim_weights: Union[callable, np.ndarray],
456+
rgrid: OneDGrid = None,
457+
aim_weights: Union[callable, np.ndarray] = None,
447458
rotate: int = 37,
448459
store: bool = False,
449460
):
@@ -455,20 +466,21 @@ def from_size(
455466
>>> onedg = UniformInteger(100) # number of points, oned grid before TF.
456467
>>> rgrid = ExpRTransform(1e-5, 2e1).generate_radial(onedg) # radial grid
457468
>>> becke = BeckeWeights(order=3)
458-
>>> molgrid = MolGrid.from_size(atnums, atcoords, rgrid, 110, becke)
469+
>>> molgrid = MolGrid.from_size(atnums, atcoords, 110, becke, rgrid)
459470
460471
Parameters
461472
----------
462473
atnums : np.ndarray(M, 3)
463474
Atomic number of :math:`M` atoms in molecule.
464475
atcoords : np.ndarray(N, 3)
465476
Cartesian coordinates for each atoms
466-
rgrid : OneDGrid
467-
one dimension grid to construct spherical grid
468477
size : int
469478
Num of points on each shell of angular grid
470-
aim_weights : Callable or np.ndarray(K,)
471-
Atoms in molecule weights.
479+
rgrid : OneDGrid, optional
480+
One-dimensional grid to construct the atomic grid. If none, then
481+
default radial grid is generated based on atomic numbers.
482+
aim_weights : Callable or np.ndarray(K,), optional
483+
Atoms in molecule weights. If None, then aim_weights is Becke weights with order=3.
472484
rotate : bool or int , optional
473485
Flag to set auto rotation for atomic grid, if given int, the number
474486
will be used as a seed to generate rantom matrix.
@@ -481,20 +493,27 @@ def from_size(
481493
MolGrid instance with specified grid property
482494
483495
"""
496+
if aim_weights is None:
497+
aim_weights = BeckeWeights(order=3)
484498
at_grids = []
485499
for i in range(len(atcoords)):
486-
at_grids.append(AtomGrid(rgrid, sizes=[size], center=atcoords[i], rotate=rotate))
500+
if rgrid is None:
501+
atnum = atnums[i]
502+
rad_grid = _generate_default_rgrid(atnum)
503+
else:
504+
rad_grid = rgrid
505+
at_grids.append(AtomGrid(rad_grid, sizes=[size], center=atcoords[i], rotate=rotate))
487506
return cls(atnums, at_grids, aim_weights, store=store)
488507

489508
@classmethod
490509
def from_pruned(
491510
cls,
492511
atnums: np.ndarray,
493512
atcoords: np.ndarray,
494-
rgrid: Union[OneDGrid, list],
495513
radius: Union[float, list],
496-
aim_weights: Union[callable, np.ndarray],
497514
sectors_r: np.ndarray,
515+
rgrid: Union[OneDGrid, list] = None,
516+
aim_weights: Union[callable, np.ndarray] = None,
498517
sectors_degree: np.ndarray = None,
499518
sectors_size: np.ndarray = None,
500519
rotate: int = 37,
@@ -509,21 +528,23 @@ def from_pruned(
509528
List of atomic numbers for each atom.
510529
atcoords: np.ndarray(M, 3)
511530
Cartesian coordinates for each atoms
512-
rgrid : OneDGrid or List[OneDGrid] or Dict[int: OneDGrid]
513-
One dimensional grid for the radial component. If a list is provided,then ith
514-
grid correspond to the ith atom. If dictionary is provided, then the keys are
515-
correspond to the `atnums[i]` attribute.
516531
radius: float, List[float]
517532
The atomic radius to be multiplied with `r_sectors` (to make them atom specific).
518533
If float, then the same atomic radius is used for all atoms, else a list specifies
519534
it for each atom.
520-
aim_weights: Callable or np.ndarray(\sum^M_n N_n,)
521-
Atoms in molecule/nuclear weights :math:`{ {w_n(r_k)}_k^{N_i}}_n^{M}`, where
522-
:math:`N_i` is the number of points in the ith atomic grid.
523535
sectors_r: List[List], keyword-only argument
524536
Each row is a sequence of boundary points specifying radial sectors of the pruned grid
525537
for the `m`th atom. The first sector is ``[0, radius*sectors_r[0]]``, then
526538
``[radius*sectors_r[0], radius*sectors_r[1]]``, and so on.
539+
rgrid : OneDGrid or List[OneDGrid] or Dict[int: OneDGrid], optional
540+
One dimensional grid for the radial component. If a list is provided,then ith
541+
grid correspond to the ith atom. If dictionary is provided, then the keys are
542+
correspond to the `atnums[i]` attribute. If None, then using atomic numbers it will
543+
generate a default radial grid (PowerRTransform of UniformInteger grid).
544+
aim_weights: Callable or np.ndarray(\sum^M_n N_n,), optional
545+
Atoms in molecule/nuclear weights :math:`{ {w_n(r_k)}_k^{N_i}}_n^{M}`, where
546+
:math:`N_i` is the number of points in the ith atomic grid. If None, then aim_weights
547+
is Becke weights with order=3.
527548
sectors_degree: List[List], keyword-only argument
528549
Each row is a sequence of Lebedev/angular degrees for each radial sector of the pruned
529550
grid for the `m`th atom. If both `sectors_degree` and `sectors_size` are given,
@@ -548,6 +569,8 @@ def from_pruned(
548569
raise ValueError(
549570
"The dimension of coordinates need to be 2\n" f"got shape: {atcoords.ndim}"
550571
)
572+
if aim_weights is None:
573+
aim_weights = BeckeWeights(order=3)
551574

552575
at_grids = []
553576
num_atoms = len(atcoords)
@@ -563,6 +586,9 @@ def from_pruned(
563586
rad = rgrid[i]
564587
elif isinstance(rgrid, dict):
565588
rad = rgrid[atnums[i]]
589+
elif rgrid is None:
590+
atnum = atnums[i]
591+
rad = _generate_default_rgrid(atnum)
566592
else:
567593
raise TypeError(f"not supported radial grid input; got input type: {type(rgrid)}")
568594

@@ -628,3 +654,35 @@ def __getitem__(self, index: int):
628654
self._atcoords[index],
629655
)
630656
return self._atgrids[index]
657+
658+
659+
def _generate_default_rgrid(atnum: int):
660+
r"""
661+
Generate default radial transformation grid from default Horton.
662+
663+
See _DEFAULT_POWER_RTRANSFORM_PARAMS inside utils for information on how
664+
it was determined
665+
666+
Parameters
667+
----------
668+
atnum: int
669+
Atomic Number
670+
671+
Returns
672+
-------
673+
OneDGrid:
674+
One-dimensional grid that was transformed using PowerRTransform.
675+
676+
"""
677+
if atnum in _DEFAULT_POWER_RTRANSFORM_PARAMS:
678+
rmin, rmax, npt = _DEFAULT_POWER_RTRANSFORM_PARAMS[int(atnum)]
679+
# Convert from Angstrom to atomic units
680+
rmin = rmin * scipy.constants.angstrom / scipy.constants.value("atomic unit of length")
681+
rmax = rmax * scipy.constants.angstrom / scipy.constants.value("atomic unit of length")
682+
onedgrid = UniformInteger(npt)
683+
rgrid = PowerRTransform(rmin, rmax).transform_1d_grid(onedgrid)
684+
return rgrid
685+
else:
686+
raise ValueError(
687+
f"Default rgrid parameter is not included for the" f" atomic number {atnum}."
688+
)

0 commit comments

Comments
 (0)