diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml new file mode 100644 index 0000000..a6ddbf2 --- /dev/null +++ b/.github/workflows/actions.yml @@ -0,0 +1,63 @@ +name: TREXIO CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + trexio_ubuntu: + + runs-on: ubuntu-latest + name: x86 Ubuntu latest + + steps: + - uses: actions/checkout@v2 + + - name: install dependencies + run: | + sudo add-apt-repository ppa:kelleyk/emacs + sudo apt-get install libhdf5-dev emacs26 + + - name: configure with autotools + run: | + ./autogen.sh + TREXIO_DEVEL=1 ./configure --enable-silent-rules + + - name: compile TREXIO + run: make -j 2 + + - name: check TREXIO + run: make check + + - name: clean + run: make clean + + trexio_macos: + + runs-on: macos-latest + name: x86 MacOS latest + + steps: + - uses: actions/checkout@v2 + + - name: install dependencies + run: | + brew install emacs + brew install hdf5 + brew install automake + + - name: configure with autotools + run: | + ./autogen.sh + TREXIO_DEVEL=1 ./configure FC=gfortran-10 --enable-silent-rules + + - name: compile TREXIO + run: make -j 2 + + - name: check TREXIO + run: make check + + - name: clean + run: make clean diff --git a/Makefile.am b/Makefile.am index c262c9b..d606f39 100644 --- a/Makefile.am +++ b/Makefile.am @@ -87,7 +87,7 @@ tests_test_f_SOURCES = $(test_trexio_f) tests/test_f.f90 tests_test_f_LDADD = src/libtrexio.la tests_test_f_LDFLAGS = -no-install -$(test_trexio_f): +$(test_trexio_f): $(trexio_f) cp $(trexio_f) $(test_trexio_f) clean-local: diff --git a/src/templates_front/templator_front.org b/src/templates_front/templator_front.org index f0e9741..cdd63ba 100644 --- a/src/templates_front/templator_front.org +++ b/src/templates_front/templator_front.org @@ -25,11 +25,12 @@ module trexio implicit none integer, parameter :: trexio_exit_code = 4 + integer, parameter :: trexio_backend = 4 - integer, parameter :: TREXIO_HDF5 = 0 - integer, parameter :: TREXIO_TEXT = 1 -! integer, parameter :: TREXIO_JSON = 2 - integer, parameter :: TREXIO_INVALID_BACK_END = 2 + integer(trexio_backend), parameter :: TREXIO_HDF5 = 0 + integer(trexio_backend), parameter :: TREXIO_TEXT = 1 +! integer(trexio_backend), parameter :: TREXIO_JSON = 2 + integer(trexio_backend), parameter :: TREXIO_INVALID_BACK_END = 2 #+end_src #+end_src @@ -586,9 +587,10 @@ trexio_open(const char* file_name, const char mode, interface integer(8) function trexio_open_c (filename, mode, backend) bind(C, name="trexio_open") use, intrinsic :: iso_c_binding - character(kind=c_char), dimension(*) :: filename - character, intent(in), value :: mode - integer, intent(in), value :: backend + import + character(kind=c_char), dimension(*) :: filename + character, intent(in), value :: mode + integer(trexio_backend), intent(in), value :: backend end function trexio_open_c end interface #+end_src @@ -1560,10 +1562,9 @@ contains integer(8) function trexio_open (filename, mode, backend) use, intrinsic :: iso_c_binding implicit none - character(len=*) :: filename - character, intent(in), value :: mode - integer, intent(in), value :: backend - + character(len=*) :: filename + character, intent(in), value :: mode + integer(trexio_backend), intent(in), value :: backend character(len=len_trim(filename)+1) :: filename_c integer :: rc diff --git a/src/templates_hdf5/templator_hdf5.org b/src/templates_hdf5/templator_hdf5.org index 1f61684..f6510b9 100644 --- a/src/templates_hdf5/templator_hdf5.org +++ b/src/templates_hdf5/templator_hdf5.org @@ -332,7 +332,7 @@ trexio_hdf5_read_$group_dset$ (trexio_t* const file, $group_dset_dtype$* const $ /* High-level H5LT API. No need to deal with dataspaces and datatypes */ status = H5LTread_dataset(f->$group$_group, $GROUP_DSET$_NAME, - H5T_NATIVE_$GROUP_DSET_H5_DTYPE$, + H5T_$GROUP_DSET_H5_DTYPE$, $group_dset$); if (status < 0) return TREXIO_FAILURE; @@ -362,7 +362,7 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, const $group_dset_dtype$* const herr_t status = H5LTmake_dataset(f->$group$_group, $GROUP_DSET$_NAME, (int) rank, (const hsize_t*) dims, - H5T_NATIVE_$GROUP_DSET_H5_DTYPE$, + H5T_$GROUP_DSET_H5_DTYPE$, $group_dset$); if (status < 0) return TREXIO_FAILURE; @@ -372,7 +372,7 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, const $group_dset_dtype$* if (dset_id <= 0) return TREXIO_INVALID_ID; const herr_t status = H5Dwrite(dset_id, - H5T_NATIVE_$GROUP_DSET_H5_DTYPE$, + H5T_$GROUP_DSET_H5_DTYPE$, H5S_ALL, H5S_ALL, H5P_DEFAULT, $group_dset$); diff --git a/tests/test.c b/tests/test.c index ddb26d5..9b038d6 100644 --- a/tests/test.c +++ b/tests/test.c @@ -15,11 +15,15 @@ int main() { assert (rc == 0); test_write("test_write.h5", TREXIO_HDF5); test_read ("test_write.h5", TREXIO_HDF5); + rc = system("rm -rf test_write.h5"); + assert (rc == 0); rc = system("rm -rf test_write.dir"); assert (rc == 0); test_write("test_write.dir", TREXIO_TEXT); test_read ("test_write.dir", TREXIO_TEXT); + rc = system("rm -rf test_write.dir"); + assert (rc == 0); return 0; } diff --git a/tests/test_f.f90 b/tests/test_f.f90 index 259c2a0..9ceef27 100644 --- a/tests/test_f.f90 +++ b/tests/test_f.f90 @@ -1,21 +1,39 @@ program test_trexio + use trexio + implicit none - call test_write() - call test_read() + call system('rm -rf trexio_test_fort') + print *, 'call test_write(''trexio_test_fort'', TREXIO_TEXT)' + call test_write('trexio_test_fort', TREXIO_TEXT) + print *, 'call test_read(''trexio_test_fort'', TREXIO_TEXT)' + call test_read('trexio_test_fort', TREXIO_TEXT) + call system('rm -rf trexio_test_fort') + + call system('rm -rf trexio_test_fort') + print *, 'call test_write(''trexio_test_fort.h5'', TREXIO_HDF5)' + call test_write('trexio_test_fort.h5', TREXIO_HDF5) + print *, 'call test_read(''trexio_test_fort.h5'', TREXIO_HDF5)' + call test_read('trexio_test_fort.h5', TREXIO_HDF5) + call system('rm -rf trexio_test_fort.h5') end program test_trexio -subroutine test_write() +subroutine test_write(file_name, back_end) ! ============ Test write functionality =============== ! use trexio implicit none + character*(*), intent(in) :: file_name + integer(trexio_backend), intent(in) :: back_end + integer(8) :: trex_file integer :: rc = 1 integer :: num + character*(128) :: str + double precision :: charge(12) double precision :: coord(3,12) @@ -39,33 +57,84 @@ subroutine test_write() ! ================= START OF TEST ===================== ! - trex_file = trexio_open('trexio_test_fort', 'w', TREXIO_TEXT) -! trex_file = trexio_open('test_hdf5_fort.h5', 'w', TREXIO_HDF5) + trex_file = trexio_open(file_name, 'w', back_end) rc = trexio_has_nucleus_num(trex_file) - if (rc == TREXIO_HAS_NOT) write(*,*) 'SUCCESS HAS NOT 1' + if (rc == TREXIO_HAS_NOT) then + write(*,*) 'SUCCESS HAS NOT 1' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif + rc = trexio_has_nucleus_charge(trex_file) - if (rc == TREXIO_HAS_NOT) write(*,*) 'SUCCESS HAS NOT 2' + if (rc == TREXIO_HAS_NOT) then + write(*,*) 'SUCCESS HAS NOT 2' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif + rc = trexio_write_nucleus_num(trex_file, num) - if (rc == TREXIO_SUCCESS) write(*,*) 'SUCCESS WRITE NUM' + if (rc == TREXIO_SUCCESS) then + write(*,*) 'SUCCESS WRITE NUM' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif rc = trexio_write_nucleus_charge(trex_file, charge) - if (rc == TREXIO_SUCCESS) write(*,*) 'SUCCESS WRITE CHARGE' + if (rc == TREXIO_SUCCESS) then + write(*,*) 'SUCCESS WRITE CHARGE' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif rc = trexio_write_nucleus_coord(trex_file, coord) - if (rc == TREXIO_SUCCESS) write(*,*) 'SUCCESS WRITE COORD' + if (rc == TREXIO_SUCCESS) then + write(*,*) 'SUCCESS WRITE COORD' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif rc = trexio_has_nucleus_num(trex_file) - if (rc == TREXIO_SUCCESS) write(*,*) 'SUCCESS HAS 1' + if (rc == TREXIO_SUCCESS) then + write(*,*) 'SUCCESS HAS 1' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif + rc = trexio_has_nucleus_coord(trex_file) - if (rc == TREXIO_SUCCESS) write(*,*) 'SUCCESS HAS 2' + if (rc == TREXIO_SUCCESS) then + write(*,*) 'SUCCESS HAS 2' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif rc = trexio_close(trex_file) - if (rc == TREXIO_SUCCESS) write(*,*) 'SUCCESS CLOSE' + if (rc == TREXIO_SUCCESS) then + write(*,*) 'SUCCESS CLOSE' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif + ! ---------------------------------- ! -! to modify fiels of existing file: +! to modify fields of existing file: ! text backend -> open with 'w' ! hdf5 backend -> open with 'a' ! ---------------------------------- ! @@ -85,13 +154,19 @@ subroutine test_write() end subroutine test_write -subroutine test_read() + + + +subroutine test_read(file_name, back_end) ! ============ Test read functionality =============== ! use trexio implicit none + character*(*), intent(in) :: file_name + integer(trexio_backend), intent(in) :: back_end + integer(8) :: trex_file integer :: rc = 1 @@ -106,26 +181,48 @@ subroutine test_read() ! ================= START OF TEST ===================== ! - trex_file = trexio_open('trexio_test_fort', 'r', TREXIO_TEXT) -! trex_file = trexio_open('test_hdf5_fort.h5', 'r', TREXIO_HDF5) + trex_file = trexio_open(file_name, 'r', back_end) rc = trexio_read_nucleus_num(trex_file, num_read) - if (rc == TREXIO_SUCCESS .and. num_read == num) write(*,*) 'SUCCESS READ NUM' + if (rc == TREXIO_SUCCESS .and. num_read == num) then + write(*,*) 'SUCCESS READ NUM' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif + rc = trexio_read_nucleus_charge(trex_file, charge) - if (rc == TREXIO_SUCCESS .and. (abs(charge(11) - 1.0) < 1.0D-8) ) write(*,*) 'SUCCESS READ CHARGE' + if (rc == TREXIO_SUCCESS .and. (dabs(charge(11) - 1.d0) < 1.0D-8) ) then + write(*,*) 'SUCCESS READ CHARGE' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(-1) + endif rc = trexio_read_nucleus_coord(trex_file, coord) - if (rc == TREXIO_SUCCESS .and. (abs(coord(2,1) - 1.39250319d0) < 1.0D-8) ) write(*,*) 'SUCCESS READ COORD' + if (rc == TREXIO_SUCCESS .and. (dabs(coord(2,1) - 1.39250319d0) < 1.0D-8) ) then + write(*,*) 'SUCCESS READ COORD' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(-1) + endif rc = trexio_close(trex_file) - if (rc == TREXIO_SUCCESS) write(*,*) 'SUCCESS CLOSE' + if (rc == TREXIO_SUCCESS) then + write(*,*) 'SUCCESS CLOSE' + else + call trexio_string_of_error(TREXIO_READONLY,str) + print *, trim(str) + call exit(1) + endif - call trexio_string_of_error(TREXIO_READONLY,str) - write(*,*) str ! ================= END OF TEST ===================== ! diff --git a/tools/generator_tools.py b/tools/generator_tools.py index fcc4401..03adfd9 100644 --- a/tools/generator_tools.py +++ b/tools/generator_tools.py @@ -462,7 +462,7 @@ def split_dset_dict_detailed (datasets: dict) -> tuple: # specify details required to replace templated variables later if v[0] == 'float': datatype = 'double' - group_dset_h5_dtype = 'double' + group_dset_h5_dtype = 'native_double' group_dset_f_dtype_default= 'real(8)' group_dset_f_dtype_double = 'real(8)' group_dset_f_dtype_single = 'real(4)' @@ -474,7 +474,7 @@ def split_dset_dict_detailed (datasets: dict) -> tuple: group_dset_std_dtype_in = 'lf' elif v[0] == 'int': datatype = 'int64_t' - group_dset_h5_dtype = 'int64' + group_dset_h5_dtype = 'native_int64' group_dset_f_dtype_default= 'integer(4)' group_dset_f_dtype_double = 'integer(8)' group_dset_f_dtype_single = 'integer(4)' diff --git a/trex.json b/trex.json index 9870240..3588937 100644 --- a/trex.json +++ b/trex.json @@ -37,17 +37,18 @@ } , "basis": { - "type" : [ "str" , [] ] - , "shell_num" : [ "int" , [] ] - , "shell_center" : [ "index", [ "basis.shell_num" ] ] - , "shell_ang_mom" : [ "int" , [ "basis.shell_num" ] ] - , "shell_prim_num" : [ "int" , [ "basis.shell_num" ] ] - , "shell_factor" : [ "float", [ "basis.shell_num" ] ] - , "prim_index" : [ "index", [ "basis.shell_num" ] ] - , "prim_num" : [ "int" , [] ] - , "exponent" : [ "float", [ "basis.prim_num" ] ] - , "coefficient" : [ "float", [ "basis.prim_num" ] ] - , "prim_factor" : [ "float", [ "basis.prim_num" ] ] + "type" : [ "str" , [] ] + , "num" : [ "int" , [] ] + , "prim_num" : [ "int" , [] ] + , "nucleus_index" : [ "index" , [ "nucleus.num" ] ] + , "nucleus_shell_num" : [ "int" , [ "nucleus.num" ] ] + , "shell_ang_mom" : [ "int" , [ "basis.num" ] ] + , "shell_prim_num" : [ "int" , [ "basis.num" ] ] + , "shell_factor" : [ "float", [ "basis.num" ] ] + , "shell_prim_index" : [ "index" , [ "basis.num" ] ] + , "exponent" : [ "float", [ "basis.prim_num" ] ] + , "coefficient" : [ "float", [ "basis.prim_num" ] ] + , "prim_factor" : [ "float", [ "basis.prim_num" ] ] } , "ao": { diff --git a/trex.org b/trex.org index 57b336d..06befce 100644 --- a/trex.org +++ b/trex.org @@ -162,8 +162,8 @@ arrays are 0-base. Hence, we introduce the ~index~ type which is an * Basis set We consider here basis functions centered on nuclei. Hence, we enable - the possibility to define \emph{dummy atoms} to place basis functions - in random positions. + the possibility to define /dummy atoms/ to place basis functions in + random positions. The atomic basis set is defined as a list of shells. Each shell $s$ is centered on a center $A$, possesses a given angular momentum $l$ and a @@ -189,25 +189,28 @@ arrays are 0-base. Hence, we introduce the ~index~ type which is an Some codes assume that the contraction coefficients are for a linear combination of /normalized/ primitives. This implies that a normalization constant for the primitive $ks$ needs to be computed and stored. If - this normalization factor is not required, set $f_{ks}$ to one. + this normalization factor is not required, $f_{ks}=1$. Some codes assume that the basis function are normalized. This implies the computation of an extra normalization factor, $\mathcal{N}_s$. - If the the basis function is not normalized, set $\mathcal{N}_s=1$. + If the the basis function is not considered normalized, $\mathcal{N}_s=1$. + All the basis set parameters are stored in one-dimensional arrays: + #+NAME: basis - | ~type~ | ~str~ | | Type of basis set: "Gaussian" or "Slater" | - | ~shell_num~ | ~int~ | | Total Number of shells | - | ~shell_center~ | ~index~ | ~(basis.shell_num)~ | Nucleus on which the shell is centered ($A$) | - | ~shell_ang_mom~ | ~int~ | ~(basis.shell_num)~ | Angular momentum ~0:S, 1:P, 2:D, ...~ | - | ~shell_prim_num~ | ~int~ | ~(basis.shell_num)~ | Number of primitives in the shell ($N_{\text{prim}}$) | - | ~shell_factor~ | ~float~ | ~(basis.shell_num)~ | Normalization factor of the shell ($\mathcal{N}_s$) | - | ~prim_index~ | ~index~ | ~(basis.shell_num)~ | Index of the first primitive in the complete list | - | ~prim_num~ | ~int~ | | Total number of primitives | - | ~exponent~ | ~float~ | ~(basis.prim_num)~ | Exponents of the primitives ($\gamma_{ks}) | - | ~coefficient~ | ~float~ | ~(basis.prim_num)~ | Coefficients of the primitives ($a_{ks}$) | - | ~prim_factor~ | ~float~ | ~(basis.prim_num)~ | Normalization coefficients for the primitives ($f_{ks}$) | + | ~type~ | ~str~ | | Type of basis set: "Gaussian" or "Slater" | + | ~num~ | ~int~ | | Total Number of shells | + | ~prim_num~ | ~int~ | | Total number of primitives | + | ~nucleus_index~ | ~index~ | ~(nucleus.num)~ | Index of the first shell of each nucleus ($A$) | + | ~nucleus_shell_num~ | ~int~ | ~(nucleus.num)~ | Number of shells for each nucleus | + | ~shell_ang_mom~ | ~int~ | ~(basis.num)~ | Angular momentum ~0:S, 1:P, 2:D, ...~ | + | ~shell_prim_num~ | ~int~ | ~(basis.num)~ | Number of primitives in the shell ($N_{\text{prim}}$) | + | ~shell_factor~ | ~float~ | ~(basis.num)~ | Normalization factor of the shell ($\mathcal{N}_s$) | + | ~shell_prim_index~ | ~index~ | ~(basis.num)~ | Index of the first primitive in the complete list | + | ~exponent~ | ~float~ | ~(basis.prim_num)~ | Exponents of the primitives ($\gamma_{ks}) | + | ~coefficient~ | ~float~ | ~(basis.prim_num)~ | Coefficients of the primitives ($a_{ks}$) | + | ~prim_factor~ | ~float~ | ~(basis.prim_num)~ | Normalization coefficients for the primitives ($f_{ks}$) | #+CALL: json(data=basis, title="basis") @@ -215,21 +218,78 @@ arrays are 0-base. Hence, we introduce the ~index~ type which is an :results: #+begin_src python :tangle trex.json "basis": { - "type" : [ "str" , [] ] - , "shell_num" : [ "int" , [] ] - , "shell_center" : [ "index", [ "basis.shell_num" ] ] - , "shell_ang_mom" : [ "int" , [ "basis.shell_num" ] ] - , "shell_prim_num" : [ "int" , [ "basis.shell_num" ] ] - , "shell_factor" : [ "float", [ "basis.shell_num" ] ] - , "prim_index" : [ "index", [ "basis.shell_num" ] ] - , "prim_num" : [ "int" , [] ] - , "exponent" : [ "float", [ "basis.prim_num" ] ] - , "coefficient" : [ "float", [ "basis.prim_num" ] ] - , "prim_factor" : [ "float", [ "basis.prim_num" ] ] + "type" : [ "str" , [] ] + , "num" : [ "int" , [] ] + , "prim_num" : [ "int" , [] ] + , "nucleus_index" : [ "index" , [ "nucleus.num" ] ] + , "nucleus_shell_num" : [ "int" , [ "nucleus.num" ] ] + , "shell_ang_mom" : [ "int" , [ "basis.num" ] ] + , "shell_prim_num" : [ "int" , [ "basis.num" ] ] + , "shell_factor" : [ "float", [ "basis.num" ] ] + , "shell_prim_index" : [ "index" , [ "basis.num" ] ] + , "exponent" : [ "float", [ "basis.prim_num" ] ] + , "coefficient" : [ "float", [ "basis.prim_num" ] ] + , "prim_factor" : [ "float", [ "basis.prim_num" ] ] } , #+end_src :end: + For example, consider H_2 with the following basis set (in GAMESS + format), where both the AOs and primitives are considered normalized: + + #+BEGIN_EXAMPLE +HYDROGEN +S 5 +1 3.387000E+01 6.068000E-03 +2 5.095000E+00 4.530800E-02 +3 1.159000E+00 2.028220E-01 +4 3.258000E-01 5.039030E-01 +5 1.027000E-01 3.834210E-01 +S 1 +1 3.258000E-01 1.000000E+00 +S 1 +1 1.027000E-01 1.000000E+00 +P 1 +1 1.407000E+00 1.000000E+00 +P 1 +1 3.880000E-01 1.000000E+00 +D 1 +1 1.057000E+00 1.0000000 + #+END_EXAMPLE + + we have: + + #+BEGIN_EXAMPLE +type = "Gaussian" +num = 12 +prim_num = 20 + +nucleus_index = [0 , 6] +shell_ang_mom = [0 , 0 , 0 , 1 , 1 , 2 , 0 , 0 , 0 , 1 , 1 , 2 ] +shell_prim_num = [5 , 1 , 1 , 1 , 1 , 1 , 5 , 1 , 1 , 1 , 1 , 1 ] +shell_prim_index = [0 , 5 , 6 , 7 , 8 , 9 , 10, 15, 16, 17, 18, 19] +shell_factor = [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.] + +exponent = +[ 33.87, 5.095, 1.159, 0.3258, 0.1027, 0.3258, 0.1027, 1.407, + 0.388, 1.057, 33.87, 5.095, 1.159, 0.3258, 0.1027, 0.3258, 0.1027, 1.407, + 0.388, 1.057] + +coefficient = +[ 0.006068, 0.045308, 0.202822, 0.503903, 0.383421, 1.0, 1.0, + 1.0, 1.0, 1.0, 0.006068, 0.045308, 0.202822, 0.503903, 0.383421, 1.0, 1.0, + 1.0, 1.0, 1.0] + +prim_factor = +[ 1.0006253235944540e+01, 2.4169531573445120e+00, 7.9610924849766440e-01 + 3.0734305383061117e-01, 1.2929684417481876e-01, 3.0734305383061117e-01, + 1.2929684417481876e-01, 2.1842769845268308e+00, 4.3649547399719840e-01, + 1.8135965626177861e+00, 1.0006253235944540e+01, 2.4169531573445120e+00, + 7.9610924849766440e-01, 3.0734305383061117e-01, 1.2929684417481876e-01, + 3.0734305383061117e-01, 1.2929684417481876e-01, 2.1842769845268308e+00, + 4.3649547399719840e-01, 1.8135965626177861e+00 ] + #+END_EXAMPLE + * Atomic orbitals Going from the atomic basis set to AOs implies a systematic @@ -254,7 +314,8 @@ arrays are 0-base. Hence, we introduce the ~index~ type which is an \chi_i (\mathbf{r}) = \mathcal{N}_i\, P_{\eta(i)}(\mathbf{r})\, R_{\theta(i)} (\mathbf{r}) \] - where $i$ is the atomic orbital index, $P$ encodes for either the + where $i$ is the atomic orbital index, + $P$ encodes for either the polynomials or the spherical harmonics, $\theta(i)$ returns the shell on which the AO is expanded, and $\eta(i)$ denotes which angular function is chosen.