77from pyscf import gto , data
88from qstack import constants
99from qstack .reorder import get_mrange
10- from qstack .mathutils .array import stack_padding
10+ from qstack .mathutils .array import stack_padding , loadtxtvar
1111from qstack .mathutils .rotation_matrix import rotate_euler
1212from qstack .tools import Cursor
1313
@@ -144,8 +144,9 @@ def xyz_to_mol(inp, basis="def2-svp", charge=None, spin=None, ignore=False, unit
144144 if ignore :
145145 if charge not in (0 , None ) or spin not in (0 , None ):
146146 warnings .warn ("Spin and charge values are overwritten" , RuntimeWarning , stacklevel = 2 )
147+ atoms = [int (q ) if q .isdigit () else data .elements .ELEMENTS_PROTON [q ] for q in loadtxtvar (molxyz , dtype = 'str' , usecols = 0 )]
147148 mol .spin = 0
148- mol .charge = - sum (mol . atom_charges ()) % 2
149+ mol .charge = - ( sum (atoms ) % 2 )
149150 else :
150151 if charge is not None :
151152 mol .charge = charge
@@ -162,8 +163,7 @@ def xyz_to_mol(inp, basis="def2-svp", charge=None, spin=None, ignore=False, unit
162163 mol .spin = 0
163164
164165 mol .build ()
165- species_charges = [data .elements .charge (z ) for z in mol .elements ]
166- if mol .basis == 'minao' and ecp is None and (np .array (species_charges ) > 36 ).any ():
166+ if mol .basis == 'minao' and ecp is None and (numbers (mol ) > 36 ).any ():
167167 msg = f"{ mol .basis } basis set requires the use of effective core potentials for atoms with Z>36"
168168 raise RuntimeError (msg )
169169 return mol
@@ -303,64 +303,31 @@ def make_atom(q, basis, ecp=None):
303303 return mol
304304
305305
306- def singleatom_basis_enumerator (basis ):
307- """Enumerate the different tensors of atomic orbitals within a 1-atom basis set.
308-
309- Each tensor is a 2l+1-sized group of orbitals that share a radial function and l value.
310-
311- Args:
312- basis (list): Basis set definition in pyscf format.
313-
314- Returns:
315- tuple: A tuple containing:
316- - l_per_bas (list): Angular momentum quantum number l for each basis shell.
317- - n_per_bas (list): Radial function counter n (starting at 0) for each basis shell.
318- - ao_starts (list): Starting index in AO array for each basis shell.
319- """
320- ao_starts = []
321- l_per_bas = []
322- n_per_bas = []
323- cursor = Cursor (action = 'ranger' )
324- cursor_per_l = []
325- for bas in basis :
326- # shape of `bas`, l, then another optional constant, then lists [exp, coeff, coeff, coeff]
327- # that make a matrix between the number of functions (number of coeff per list)
328- # and the number of primitive gaussians (one per list)
329- l = bas [0 ]
330- while len (cursor_per_l ) <= l :
331- cursor_per_l .append (Cursor (action = 'ranger' ))
332- n_count = len (bas [- 1 ])- 1
333- l_per_bas += [l ] * n_count
334- n_per_bas .extend (cursor_per_l [l ].add (n_count ))
335- msize = 2 * l + 1
336- ao_starts .extend (cursor .add (msize * n_count )[::msize ])
337- return l_per_bas , n_per_bas , ao_starts
338-
339-
340306def basis_flatten (mol , return_both = True , return_shells = False ):
341307 """Flatten a basis set definition for AOs.
342308
343309 Args:
344310 mol (pyscf.gto.Mole): pyscf Mole object.
345311 return_both (bool): Whether to return both AO info and primitive Gaussian info. Defaults to True.
346- return_shells (bool): Whether to return angular momenta per shell. Defaults to False.
312+ return_shells (bool): Whether to return angular momenta and starting indices per shell
313+ (2l+1-sized group of orbitals that share a radial function and l value). Defaults to False.
347314
348315 Returns:
349316 - numpy.ndarray: 3×mol.nao int array where each column corresponds to an AO and rows are:
350- - 0: atom index
351- - 1: angular momentum quantum number l
352- - 2: magnetic quantum number m
317+ - 0: atom index,
318+ - 1: angular momentum quantum number l,
319+ - 2: magnetic quantum number m.
353320 If return_both is True, also returns:
354321 - numpy.ndarray: 2×mol.nao×max_n float array where index (i,j,k) means:
355- - i: 0 for exponent, 1 for contraction coefficient of a primitive Gaussian
356- - j: AO index
357- - k: radial function index (padded with zeros if necessary)
358- If return_shell is True, also returns:
359- - numpy.ndarray: angular momentum quantum number for each shell
360-
322+ - i: 0 for exponent, 1 for contraction coefficient of a primitive Gaussian,
323+ - j: AO index,
324+ - k: radial function index (padded with zeros if necessary).
325+ If return_shells is True, also returns:
326+ - numpy.ndarray: starting AO indices for each shell.
361327 """
362328 x = []
363- L = []
329+ ao_starts = []
330+ cursor = Cursor (action = 'ranger' )
364331 y = np .zeros ((3 , mol .nao ), dtype = int )
365332 i = Cursor (action = 'slicer' )
366333 a = mol .bas_exps ()
@@ -376,11 +343,26 @@ def basis_flatten(mol, return_both=True, return_shells=False):
376343 x .extend ([ac ]* msize )
377344 y [:,i (msize * n )] = np .vstack ((np .array ([[iat , l ]]* msize * n ).T , [* get_mrange (l )]* n ))
378345 if return_shells :
379- L .extend ([ l ] * n )
346+ ao_starts .extend (cursor . add ( msize * n )[:: msize ] )
380347
381348 ret = [y ]
382349 if return_both :
383350 ret .append (stack_padding (x ).transpose ((1 ,0 ,2 )))
384351 if return_shells :
385- ret .append (np .array (L ))
352+ ret .append (np .array (ao_starts ))
386353 return ret [0 ] if len (ret )== 1 else ret
354+
355+
356+ def numbers (mol ):
357+ """Get atom numbers of a molecule.
358+
359+ Use this function to get atomic NUMBERS to index elements.
360+ Use `mol.atom_charges()` to get CHARGES (it returns effective charges when ECP are used).
361+
362+ Args:
363+ mol (pyscf.gto.Mole): pyscf Mole object.
364+
365+ Returns:
366+ numpy.ndarray: Array of atomic numbers.
367+ """
368+ return np .array ([data .elements .charge (q ) for q in mol .elements ])
0 commit comments