MultiOptPy 1.20.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- multioptpy/Calculator/__init__.py +0 -0
- multioptpy/Calculator/ase_calculation_tools.py +424 -0
- multioptpy/Calculator/ase_tools/__init__.py +0 -0
- multioptpy/Calculator/ase_tools/fairchem.py +28 -0
- multioptpy/Calculator/ase_tools/gamess.py +19 -0
- multioptpy/Calculator/ase_tools/gaussian.py +165 -0
- multioptpy/Calculator/ase_tools/mace.py +28 -0
- multioptpy/Calculator/ase_tools/mopac.py +19 -0
- multioptpy/Calculator/ase_tools/nwchem.py +31 -0
- multioptpy/Calculator/ase_tools/orca.py +22 -0
- multioptpy/Calculator/ase_tools/pygfn0.py +37 -0
- multioptpy/Calculator/dxtb_calculation_tools.py +344 -0
- multioptpy/Calculator/emt_calculation_tools.py +458 -0
- multioptpy/Calculator/gpaw_calculation_tools.py +183 -0
- multioptpy/Calculator/lj_calculation_tools.py +314 -0
- multioptpy/Calculator/psi4_calculation_tools.py +334 -0
- multioptpy/Calculator/pwscf_calculation_tools.py +189 -0
- multioptpy/Calculator/pyscf_calculation_tools.py +327 -0
- multioptpy/Calculator/sqm1_calculation_tools.py +611 -0
- multioptpy/Calculator/sqm2_calculation_tools.py +376 -0
- multioptpy/Calculator/tblite_calculation_tools.py +352 -0
- multioptpy/Calculator/tersoff_calculation_tools.py +818 -0
- multioptpy/Constraint/__init__.py +0 -0
- multioptpy/Constraint/constraint_condition.py +834 -0
- multioptpy/Coordinate/__init__.py +0 -0
- multioptpy/Coordinate/polar_coordinate.py +199 -0
- multioptpy/Coordinate/redundant_coordinate.py +638 -0
- multioptpy/IRC/__init__.py +0 -0
- multioptpy/IRC/converge_criteria.py +28 -0
- multioptpy/IRC/dvv.py +544 -0
- multioptpy/IRC/euler.py +439 -0
- multioptpy/IRC/hpc.py +564 -0
- multioptpy/IRC/lqa.py +540 -0
- multioptpy/IRC/modekill.py +662 -0
- multioptpy/IRC/rk4.py +579 -0
- multioptpy/Interpolation/__init__.py +0 -0
- multioptpy/Interpolation/adaptive_interpolation.py +283 -0
- multioptpy/Interpolation/binomial_interpolation.py +179 -0
- multioptpy/Interpolation/geodesic_interpolation.py +785 -0
- multioptpy/Interpolation/interpolation.py +156 -0
- multioptpy/Interpolation/linear_interpolation.py +473 -0
- multioptpy/Interpolation/savitzky_golay_interpolation.py +252 -0
- multioptpy/Interpolation/spline_interpolation.py +353 -0
- multioptpy/MD/__init__.py +0 -0
- multioptpy/MD/thermostat.py +185 -0
- multioptpy/MEP/__init__.py +0 -0
- multioptpy/MEP/pathopt_bneb_force.py +443 -0
- multioptpy/MEP/pathopt_dmf_force.py +448 -0
- multioptpy/MEP/pathopt_dneb_force.py +130 -0
- multioptpy/MEP/pathopt_ewbneb_force.py +207 -0
- multioptpy/MEP/pathopt_gpneb_force.py +512 -0
- multioptpy/MEP/pathopt_lup_force.py +113 -0
- multioptpy/MEP/pathopt_neb_force.py +225 -0
- multioptpy/MEP/pathopt_nesb_force.py +205 -0
- multioptpy/MEP/pathopt_om_force.py +153 -0
- multioptpy/MEP/pathopt_qsm_force.py +174 -0
- multioptpy/MEP/pathopt_qsmv2_force.py +304 -0
- multioptpy/ModelFunction/__init__.py +7 -0
- multioptpy/ModelFunction/avoiding_model_function.py +29 -0
- multioptpy/ModelFunction/binary_image_ts_search_model_function.py +47 -0
- multioptpy/ModelFunction/conical_model_function.py +26 -0
- multioptpy/ModelFunction/opt_meci.py +50 -0
- multioptpy/ModelFunction/opt_mesx.py +47 -0
- multioptpy/ModelFunction/opt_mesx_2.py +49 -0
- multioptpy/ModelFunction/seam_model_function.py +27 -0
- multioptpy/ModelHessian/__init__.py +0 -0
- multioptpy/ModelHessian/approx_hessian.py +147 -0
- multioptpy/ModelHessian/calc_params.py +227 -0
- multioptpy/ModelHessian/fischer.py +236 -0
- multioptpy/ModelHessian/fischerd3.py +360 -0
- multioptpy/ModelHessian/fischerd4.py +398 -0
- multioptpy/ModelHessian/gfn0xtb.py +633 -0
- multioptpy/ModelHessian/gfnff.py +709 -0
- multioptpy/ModelHessian/lindh.py +165 -0
- multioptpy/ModelHessian/lindh2007d2.py +707 -0
- multioptpy/ModelHessian/lindh2007d3.py +822 -0
- multioptpy/ModelHessian/lindh2007d4.py +1030 -0
- multioptpy/ModelHessian/morse.py +106 -0
- multioptpy/ModelHessian/schlegel.py +144 -0
- multioptpy/ModelHessian/schlegeld3.py +322 -0
- multioptpy/ModelHessian/schlegeld4.py +559 -0
- multioptpy/ModelHessian/shortrange.py +346 -0
- multioptpy/ModelHessian/swartd2.py +496 -0
- multioptpy/ModelHessian/swartd3.py +706 -0
- multioptpy/ModelHessian/swartd4.py +918 -0
- multioptpy/ModelHessian/tshess.py +40 -0
- multioptpy/Optimizer/QHAdam.py +61 -0
- multioptpy/Optimizer/__init__.py +0 -0
- multioptpy/Optimizer/abc_fire.py +83 -0
- multioptpy/Optimizer/adabelief.py +58 -0
- multioptpy/Optimizer/adabound.py +68 -0
- multioptpy/Optimizer/adadelta.py +65 -0
- multioptpy/Optimizer/adaderivative.py +56 -0
- multioptpy/Optimizer/adadiff.py +68 -0
- multioptpy/Optimizer/adafactor.py +70 -0
- multioptpy/Optimizer/adam.py +65 -0
- multioptpy/Optimizer/adamax.py +62 -0
- multioptpy/Optimizer/adamod.py +83 -0
- multioptpy/Optimizer/adamw.py +65 -0
- multioptpy/Optimizer/adiis.py +523 -0
- multioptpy/Optimizer/afire_neb.py +282 -0
- multioptpy/Optimizer/block_hessian_update.py +709 -0
- multioptpy/Optimizer/c2diis.py +491 -0
- multioptpy/Optimizer/component_wise_scaling.py +405 -0
- multioptpy/Optimizer/conjugate_gradient.py +82 -0
- multioptpy/Optimizer/conjugate_gradient_neb.py +345 -0
- multioptpy/Optimizer/coordinate_locking.py +405 -0
- multioptpy/Optimizer/dic_rsirfo.py +1015 -0
- multioptpy/Optimizer/ediis.py +417 -0
- multioptpy/Optimizer/eve.py +76 -0
- multioptpy/Optimizer/fastadabelief.py +61 -0
- multioptpy/Optimizer/fire.py +77 -0
- multioptpy/Optimizer/fire2.py +249 -0
- multioptpy/Optimizer/fire_neb.py +92 -0
- multioptpy/Optimizer/gan_step.py +486 -0
- multioptpy/Optimizer/gdiis.py +609 -0
- multioptpy/Optimizer/gediis.py +203 -0
- multioptpy/Optimizer/geodesic_step.py +433 -0
- multioptpy/Optimizer/gpmin.py +633 -0
- multioptpy/Optimizer/gpr_step.py +364 -0
- multioptpy/Optimizer/gradientdescent.py +78 -0
- multioptpy/Optimizer/gradientdescent_neb.py +52 -0
- multioptpy/Optimizer/hessian_update.py +433 -0
- multioptpy/Optimizer/hybrid_rfo.py +998 -0
- multioptpy/Optimizer/kdiis.py +625 -0
- multioptpy/Optimizer/lars.py +21 -0
- multioptpy/Optimizer/lbfgs.py +253 -0
- multioptpy/Optimizer/lbfgs_neb.py +355 -0
- multioptpy/Optimizer/linesearch.py +236 -0
- multioptpy/Optimizer/lookahead.py +40 -0
- multioptpy/Optimizer/nadam.py +64 -0
- multioptpy/Optimizer/newton.py +200 -0
- multioptpy/Optimizer/prodigy.py +70 -0
- multioptpy/Optimizer/purtubation.py +16 -0
- multioptpy/Optimizer/quickmin_neb.py +245 -0
- multioptpy/Optimizer/radam.py +75 -0
- multioptpy/Optimizer/rfo_neb.py +302 -0
- multioptpy/Optimizer/ric_rfo.py +842 -0
- multioptpy/Optimizer/rl_step.py +627 -0
- multioptpy/Optimizer/rmspropgrave.py +65 -0
- multioptpy/Optimizer/rsirfo.py +1647 -0
- multioptpy/Optimizer/rsprfo.py +1056 -0
- multioptpy/Optimizer/sadam.py +60 -0
- multioptpy/Optimizer/samsgrad.py +63 -0
- multioptpy/Optimizer/tr_lbfgs.py +678 -0
- multioptpy/Optimizer/trim.py +273 -0
- multioptpy/Optimizer/trust_radius.py +207 -0
- multioptpy/Optimizer/trust_radius_neb.py +121 -0
- multioptpy/Optimizer/yogi.py +60 -0
- multioptpy/OtherMethod/__init__.py +0 -0
- multioptpy/OtherMethod/addf.py +1150 -0
- multioptpy/OtherMethod/dimer.py +895 -0
- multioptpy/OtherMethod/elastic_image_pair.py +629 -0
- multioptpy/OtherMethod/modelfunction.py +456 -0
- multioptpy/OtherMethod/newton_traj.py +454 -0
- multioptpy/OtherMethod/twopshs.py +1095 -0
- multioptpy/PESAnalyzer/__init__.py +0 -0
- multioptpy/PESAnalyzer/calc_irc_curvature.py +125 -0
- multioptpy/PESAnalyzer/cmds_analysis.py +152 -0
- multioptpy/PESAnalyzer/koopman_analysis.py +268 -0
- multioptpy/PESAnalyzer/pca_analysis.py +314 -0
- multioptpy/Parameters/__init__.py +0 -0
- multioptpy/Parameters/atomic_mass.py +20 -0
- multioptpy/Parameters/atomic_number.py +22 -0
- multioptpy/Parameters/covalent_radii.py +44 -0
- multioptpy/Parameters/d2.py +61 -0
- multioptpy/Parameters/d3.py +63 -0
- multioptpy/Parameters/d4.py +103 -0
- multioptpy/Parameters/dreiding.py +34 -0
- multioptpy/Parameters/gfn0xtb_param.py +137 -0
- multioptpy/Parameters/gfnff_param.py +315 -0
- multioptpy/Parameters/gnb.py +104 -0
- multioptpy/Parameters/parameter.py +22 -0
- multioptpy/Parameters/uff.py +72 -0
- multioptpy/Parameters/unit_values.py +20 -0
- multioptpy/Potential/AFIR_potential.py +55 -0
- multioptpy/Potential/LJ_repulsive_potential.py +345 -0
- multioptpy/Potential/__init__.py +0 -0
- multioptpy/Potential/anharmonic_keep_potential.py +28 -0
- multioptpy/Potential/asym_elllipsoidal_potential.py +718 -0
- multioptpy/Potential/electrostatic_potential.py +69 -0
- multioptpy/Potential/flux_potential.py +30 -0
- multioptpy/Potential/gaussian_potential.py +101 -0
- multioptpy/Potential/idpp.py +516 -0
- multioptpy/Potential/keep_angle_potential.py +146 -0
- multioptpy/Potential/keep_dihedral_angle_potential.py +105 -0
- multioptpy/Potential/keep_outofplain_angle_potential.py +70 -0
- multioptpy/Potential/keep_potential.py +99 -0
- multioptpy/Potential/mechano_force_potential.py +74 -0
- multioptpy/Potential/nanoreactor_potential.py +52 -0
- multioptpy/Potential/potential.py +896 -0
- multioptpy/Potential/spacer_model_potential.py +221 -0
- multioptpy/Potential/switching_potential.py +258 -0
- multioptpy/Potential/universal_potential.py +34 -0
- multioptpy/Potential/value_range_potential.py +36 -0
- multioptpy/Potential/void_point_potential.py +25 -0
- multioptpy/SQM/__init__.py +0 -0
- multioptpy/SQM/sqm1/__init__.py +0 -0
- multioptpy/SQM/sqm1/sqm1_core.py +1792 -0
- multioptpy/SQM/sqm2/__init__.py +0 -0
- multioptpy/SQM/sqm2/calc_tools.py +95 -0
- multioptpy/SQM/sqm2/sqm2_basis.py +850 -0
- multioptpy/SQM/sqm2/sqm2_bond.py +119 -0
- multioptpy/SQM/sqm2/sqm2_core.py +303 -0
- multioptpy/SQM/sqm2/sqm2_data.py +1229 -0
- multioptpy/SQM/sqm2/sqm2_disp.py +65 -0
- multioptpy/SQM/sqm2/sqm2_eeq.py +243 -0
- multioptpy/SQM/sqm2/sqm2_overlapint.py +704 -0
- multioptpy/SQM/sqm2/sqm2_qm.py +578 -0
- multioptpy/SQM/sqm2/sqm2_rep.py +66 -0
- multioptpy/SQM/sqm2/sqm2_srb.py +70 -0
- multioptpy/Thermo/__init__.py +0 -0
- multioptpy/Thermo/normal_mode_analyzer.py +865 -0
- multioptpy/Utils/__init__.py +0 -0
- multioptpy/Utils/bond_connectivity.py +264 -0
- multioptpy/Utils/calc_tools.py +884 -0
- multioptpy/Utils/oniom.py +96 -0
- multioptpy/Utils/pbc.py +48 -0
- multioptpy/Utils/riemann_curvature.py +208 -0
- multioptpy/Utils/symmetry_analyzer.py +482 -0
- multioptpy/Visualization/__init__.py +0 -0
- multioptpy/Visualization/visualization.py +156 -0
- multioptpy/WFAnalyzer/MO_analysis.py +104 -0
- multioptpy/WFAnalyzer/__init__.py +0 -0
- multioptpy/Wrapper/__init__.py +0 -0
- multioptpy/Wrapper/autots.py +1239 -0
- multioptpy/Wrapper/ieip_wrapper.py +93 -0
- multioptpy/Wrapper/md_wrapper.py +92 -0
- multioptpy/Wrapper/neb_wrapper.py +94 -0
- multioptpy/Wrapper/optimize_wrapper.py +76 -0
- multioptpy/__init__.py +5 -0
- multioptpy/entrypoints.py +916 -0
- multioptpy/fileio.py +660 -0
- multioptpy/ieip.py +340 -0
- multioptpy/interface.py +1086 -0
- multioptpy/irc.py +529 -0
- multioptpy/moleculardynamics.py +432 -0
- multioptpy/neb.py +1267 -0
- multioptpy/optimization.py +1553 -0
- multioptpy/optimizer.py +709 -0
- multioptpy-1.20.2.dist-info/METADATA +438 -0
- multioptpy-1.20.2.dist-info/RECORD +246 -0
- multioptpy-1.20.2.dist-info/WHEEL +5 -0
- multioptpy-1.20.2.dist-info/entry_points.txt +9 -0
- multioptpy-1.20.2.dist-info/licenses/LICENSE +674 -0
- multioptpy-1.20.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,850 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from multioptpy.SQM.sqm2.calc_tools import factorial2, dfactorial
|
|
5
|
+
|
|
6
|
+
class BasisSet:
|
|
7
|
+
def __init__(self, element_list, param):
|
|
8
|
+
self.element_list = element_list
|
|
9
|
+
self.param = param
|
|
10
|
+
|
|
11
|
+
# --- Pre-calculate atom properties ---
|
|
12
|
+
# These properties depend only on the element_list,
|
|
13
|
+
# so they can be set once.
|
|
14
|
+
self.nshells_list = []
|
|
15
|
+
self.ang_shells_list = []
|
|
16
|
+
self.principal_qn_list = []
|
|
17
|
+
self.slater_exponents_list = []
|
|
18
|
+
self.self_energy_list = []
|
|
19
|
+
self.kCN_list = []
|
|
20
|
+
self.en_shell_list = []
|
|
21
|
+
self.atomic_radius_list = []
|
|
22
|
+
self.ref_occ_list = []
|
|
23
|
+
|
|
24
|
+
for atn in self.element_list:
|
|
25
|
+
self.nshells_list.append(param.nShell[atn])
|
|
26
|
+
self.ang_shells_list.append(param.angShell[atn])
|
|
27
|
+
self.principal_qn_list.append(param.principalQuantumNumber[atn])
|
|
28
|
+
self.slater_exponents_list.append(param.slaterExponent[atn])
|
|
29
|
+
self.self_energy_list.append(param.selfEnergy[atn])
|
|
30
|
+
self.kCN_list.append(param.kCN[atn])
|
|
31
|
+
self.en_shell_list.append(param.electronegativity[atn])
|
|
32
|
+
self.atomic_radius_list.append(param.atomicRad[atn])
|
|
33
|
+
self.ref_occ_list.append(param.referenceOcc[atn])
|
|
34
|
+
|
|
35
|
+
self.is_tm_list, self.is_g11_element_list = self.check_transition_metals()
|
|
36
|
+
|
|
37
|
+
# --- Run the main basis setup ---
|
|
38
|
+
self._set_basis(param)
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
def _dim_basis(self, param):
|
|
42
|
+
"""
|
|
43
|
+
Calculates the total number of shells (nshell), AOs (nao), and CGFs (nbf).
|
|
44
|
+
Corresponds to Fortran subroutine: dim_basis
|
|
45
|
+
"""
|
|
46
|
+
n_atoms = len(self.element_list)
|
|
47
|
+
nao = 0
|
|
48
|
+
nbf = 0
|
|
49
|
+
nshell = 0
|
|
50
|
+
|
|
51
|
+
for i in range(n_atoms):
|
|
52
|
+
atn = self.element_list[i] # 0-indexed
|
|
53
|
+
k = 0
|
|
54
|
+
|
|
55
|
+
# Directly reference nShell and angShell from param
|
|
56
|
+
n_shell_for_atom = param.nShell[atn]
|
|
57
|
+
ang_shell_for_atom = param.angShell[atn]
|
|
58
|
+
|
|
59
|
+
for j in range(n_shell_for_atom):
|
|
60
|
+
l = ang_shell_for_atom[j]
|
|
61
|
+
k += 1
|
|
62
|
+
nshell += 1
|
|
63
|
+
if l == 0: # s
|
|
64
|
+
nbf += 1
|
|
65
|
+
nao += 1
|
|
66
|
+
elif l == 1: # p
|
|
67
|
+
nbf += 3
|
|
68
|
+
nao += 3
|
|
69
|
+
elif l == 2: # d
|
|
70
|
+
nbf += 6 # 6 Cartesian CGFs
|
|
71
|
+
nao += 5 # 5 spherical AOs
|
|
72
|
+
elif l == 3: # f
|
|
73
|
+
nbf += 10 # 10 Cartesian CGFs
|
|
74
|
+
nao += 7 # 7 spherical AOs
|
|
75
|
+
elif l == 4: # g
|
|
76
|
+
nbf += 15
|
|
77
|
+
nao += 9
|
|
78
|
+
if k == 0:
|
|
79
|
+
raise Exception(f"No basis found for atom {i} Z={atn+1}")
|
|
80
|
+
|
|
81
|
+
return nshell, nao, nbf
|
|
82
|
+
|
|
83
|
+
def _get_max_shells_per_atom(self):
|
|
84
|
+
"""
|
|
85
|
+
Returns the maximum number of shells for any atom in the system.
|
|
86
|
+
Used for allocating caoshell/saoshell arrays.
|
|
87
|
+
"""
|
|
88
|
+
max_shells = 0
|
|
89
|
+
for i in range(len(self.element_list)):
|
|
90
|
+
n_shells = self.nshells_list[i]
|
|
91
|
+
if n_shells > max_shells:
|
|
92
|
+
max_shells = n_shells
|
|
93
|
+
return max_shells
|
|
94
|
+
|
|
95
|
+
def _set_basis(self, param):
|
|
96
|
+
"""
|
|
97
|
+
Main basis set setup routine.
|
|
98
|
+
Corresponds to Fortran subroutine: newBasisset
|
|
99
|
+
"""
|
|
100
|
+
n_atoms = len(self.element_list)
|
|
101
|
+
|
|
102
|
+
self.basis = {}
|
|
103
|
+
|
|
104
|
+
# --- Global Counts (calculated by _dim_basis) ---
|
|
105
|
+
n_shell_total, n_ao_total, n_cgf_total = self._dim_basis(param)
|
|
106
|
+
max_shells_per_atom = self._get_max_shells_per_atom()
|
|
107
|
+
|
|
108
|
+
self.basis["number_of_atoms"] = n_atoms
|
|
109
|
+
self.basis["number_of_cgf"] = n_cgf_total # Corresponds to: nbf
|
|
110
|
+
self.basis["number_of_ao"] = n_ao_total # Corresponds to: nao
|
|
111
|
+
self.basis["number_of_shells"] = n_shell_total # Corresponds to: nshell
|
|
112
|
+
self.basis["total_number_of_primitives"] = 0 # Final 'ipr' value
|
|
113
|
+
|
|
114
|
+
# --- Per-Atom Indices ---
|
|
115
|
+
# Corresponds to Fortran: shells(2,n), fila(2,n), fila2(2,n)
|
|
116
|
+
self.basis["atom_shells_map"] = np.zeros((n_atoms, 2), dtype=int) # [iat, 0]=start, [iat, 1]=end
|
|
117
|
+
self.basis["atom_cgf_map"] = np.zeros((n_atoms, 2), dtype=int) # [iat, 0]=start, [iat, 1]=end (fila)
|
|
118
|
+
self.basis["atom_ao_map"] = np.zeros((n_atoms, 2), dtype=int) # [iat, 0]=start, [iat, 1]=end (fila2)
|
|
119
|
+
|
|
120
|
+
# --- Per-Atom Per-Shell Mappings (NEW - corresponds to caoshell/saoshell) ---
|
|
121
|
+
# caoshell(m, iat) = CGF index at start of shell m for atom iat
|
|
122
|
+
# saoshell(m, iat) = AO index at start of shell m for atom iat
|
|
123
|
+
# Using shape (n_atoms, max_shells_per_atom) with -1 for unused slots
|
|
124
|
+
self.basis["atom_shell_cgf_offset"] = np.full((n_atoms, max_shells_per_atom), -1, dtype=int) # caoshell
|
|
125
|
+
self.basis["atom_shell_ao_offset"] = np.full((n_atoms, max_shells_per_atom), -1, dtype=int) # saoshell
|
|
126
|
+
|
|
127
|
+
# --- Per-Shell Data (Lists) ---
|
|
128
|
+
self.basis["shell_amqn_list"] = [] # lsh(ish)
|
|
129
|
+
self.basis["shell_atom_list"] = [] # ash(ish)
|
|
130
|
+
self.basis["shell_cgf_map"] = [] # sh2bf(1:2, ish) -> [start, count]
|
|
131
|
+
self.basis["shell_ao_map"] = [] # sh2ao(1:2, ish) -> [start, count]
|
|
132
|
+
self.basis["shell_level_list"] = [] # level(ish)
|
|
133
|
+
self.basis["shell_zeta_list"] = [] # zeta(ish)
|
|
134
|
+
self.basis["shell_valence_flag_list"] = [] # valsh(ish)
|
|
135
|
+
self.basis["shell_min_alpha_list"] = [] # minalp(ish)
|
|
136
|
+
|
|
137
|
+
# --- Per-CGF (Contracted Gaussian Function / Cartesian BF) Data (Lists) ---
|
|
138
|
+
self.basis["cgf_primitive_start_idx_list"] = [] # primcount(ibf)
|
|
139
|
+
self.basis["cgf_valence_flag_list"] = [] # valao(ibf)
|
|
140
|
+
self.basis["cgf_atom_list"] = [] # aoat(ibf)
|
|
141
|
+
self.basis["cgf_type_id_list"] = [] # lao(ibf)
|
|
142
|
+
self.basis["cgf_primitive_count_list"] = [] # nprim(ibf)
|
|
143
|
+
self.basis["cgf_energy_list"] = [] # hdiag(ibf)
|
|
144
|
+
|
|
145
|
+
# --- Per-AO (Spherical Atomic Orbital) Data (Lists) ---
|
|
146
|
+
self.basis["ao_valence_flag_list"] = [] # valao2(iao)
|
|
147
|
+
self.basis["ao_atom_list"] = [] # aoat2(iao)
|
|
148
|
+
self.basis["ao_type_id_list"] = [] # lao2(iao)
|
|
149
|
+
self.basis["ao_energy_list"] = [] # hdiag2(iao)
|
|
150
|
+
self.basis["ao_zeta_list"] = [] # aoexp(iao)
|
|
151
|
+
self.basis["ao_shell_list"] = [] # ao2sh(iao)
|
|
152
|
+
|
|
153
|
+
# --- Per-PGF (Primitive Gaussian Function) Data (Lists) ---
|
|
154
|
+
self.basis["primitive_alpha_list"] = [] # alp(ipr)
|
|
155
|
+
self.basis["primitive_coeff_list"] = [] # cont(ipr)
|
|
156
|
+
|
|
157
|
+
# --- Transformation factors for d/f functions ---
|
|
158
|
+
# Corresponds to Fortran trafo arrays in set_d_function and set_f_function
|
|
159
|
+
d_trafo = { 5: 1.0, 6: 1.0, 7: 1.0, 8: np.sqrt(3.0), 9: np.sqrt(3.0), 10: np.sqrt(3.0) }
|
|
160
|
+
f_trafo = { 11: 1.0, 12: 1.0, 13: 1.0, 14: np.sqrt(5.0), 15: np.sqrt(5.0),
|
|
161
|
+
16: np.sqrt(5.0), 17: np.sqrt(5.0), 18: np.sqrt(5.0), 19: np.sqrt(5.0),
|
|
162
|
+
20: np.sqrt(15.0) }
|
|
163
|
+
|
|
164
|
+
# --- Global 0-indexed Counters ---
|
|
165
|
+
ibf = 0 # CGF counter
|
|
166
|
+
iao = 0 # AO counter
|
|
167
|
+
ipr = 0 # Primitive counter
|
|
168
|
+
ish = 0 # Shell counter
|
|
169
|
+
|
|
170
|
+
# === Main Loop (Corresponds to: atoms: do iat=1,n) ===
|
|
171
|
+
for iat in range(n_atoms):
|
|
172
|
+
atn = self.element_list[iat] # 0-indexed atomic number
|
|
173
|
+
ati = atn + 1 # 1-indexed atomic number (for H/He checks)
|
|
174
|
+
|
|
175
|
+
# These are held within the iat loop and used for diffuse s processing
|
|
176
|
+
nprim_s_val = 0
|
|
177
|
+
alpha_s_val = np.array([])
|
|
178
|
+
coeff_s_val = np.array([])
|
|
179
|
+
|
|
180
|
+
# Set Per-Atom Start Indices
|
|
181
|
+
# Corresponds to: basis%shells(1,iat)=ish+1, basis%fila(1,iat)=ibf+1, basis%fila2(1,iat)=iao+1
|
|
182
|
+
self.basis["atom_shells_map"][iat, 0] = ish
|
|
183
|
+
self.basis["atom_cgf_map"][iat, 0] = ibf
|
|
184
|
+
self.basis["atom_ao_map"][iat, 0] = iao
|
|
185
|
+
|
|
186
|
+
# Corresponds to: shells: do m=1,xtbData%nShell(ati)
|
|
187
|
+
nshell_i = self.nshells_list[iat]
|
|
188
|
+
for m in range(nshell_i):
|
|
189
|
+
# --- Get Shell Parameters ---
|
|
190
|
+
l = self.ang_shells_list[iat][m]
|
|
191
|
+
npq = self.principal_qn_list[iat][m]
|
|
192
|
+
level = self.self_energy_list[iat][m]
|
|
193
|
+
zeta = self.slater_exponents_list[iat][m]
|
|
194
|
+
|
|
195
|
+
valao = self.ref_occ_list[iat][m] # The valence flag
|
|
196
|
+
is_valence = (valao != 0)
|
|
197
|
+
|
|
198
|
+
current_nprim_or_R = self.get_number_of_primitives(atn, l, npq, is_valence=is_valence)
|
|
199
|
+
|
|
200
|
+
ibf_start_shell = ibf
|
|
201
|
+
iao_start_shell = iao
|
|
202
|
+
|
|
203
|
+
# --- Store Per-Atom Per-Shell Offsets (caoshell/saoshell) ---
|
|
204
|
+
self.basis["atom_shell_cgf_offset"][iat, m] = ibf
|
|
205
|
+
self.basis["atom_shell_ao_offset"][iat, m] = iao
|
|
206
|
+
|
|
207
|
+
# --- Store Per-Shell Data (at index ish) ---
|
|
208
|
+
self.basis["shell_amqn_list"].append(l)
|
|
209
|
+
self.basis["shell_atom_list"].append(iat)
|
|
210
|
+
self.basis["shell_cgf_map"].append([ibf_start_shell, 0]) # [start, count]
|
|
211
|
+
self.basis["shell_ao_map"].append([iao_start_shell, 0]) # [start, count]
|
|
212
|
+
self.basis["shell_level_list"].append(level)
|
|
213
|
+
self.basis["shell_zeta_list"].append(zeta)
|
|
214
|
+
self.basis["shell_valence_flag_list"].append(valao)
|
|
215
|
+
|
|
216
|
+
min_alpha_for_shell = np.inf
|
|
217
|
+
|
|
218
|
+
# === Process Shells by Type ===
|
|
219
|
+
|
|
220
|
+
# --- H-He s (Valence) ---
|
|
221
|
+
if l == 0 and ati <= 2 and is_valence:
|
|
222
|
+
|
|
223
|
+
alpha, coeff = self.slater2gauss(current_nprim_or_R, npq, l, zeta, param, need_normalization=True)
|
|
224
|
+
min_alpha_for_shell = np.min(alpha)
|
|
225
|
+
|
|
226
|
+
nprim_s_val = current_nprim_or_R
|
|
227
|
+
alpha_s_val = alpha.copy()
|
|
228
|
+
coeff_s_val = coeff.copy()
|
|
229
|
+
|
|
230
|
+
# Add CGF (1)
|
|
231
|
+
self.basis["cgf_primitive_start_idx_list"].append(ipr)
|
|
232
|
+
self.basis["cgf_valence_flag_list"].append(valao)
|
|
233
|
+
self.basis["cgf_atom_list"].append(iat)
|
|
234
|
+
self.basis["cgf_type_id_list"].append(1) # 1=s
|
|
235
|
+
self.basis["cgf_primitive_count_list"].append(current_nprim_or_R)
|
|
236
|
+
self.basis["cgf_energy_list"].append(level)
|
|
237
|
+
ibf += 1
|
|
238
|
+
|
|
239
|
+
# Add Primitives
|
|
240
|
+
for p in range(current_nprim_or_R):
|
|
241
|
+
self.basis["primitive_alpha_list"].append(alpha[p])
|
|
242
|
+
self.basis["primitive_coeff_list"].append(coeff[p])
|
|
243
|
+
ipr += 1
|
|
244
|
+
|
|
245
|
+
# Add AO (1)
|
|
246
|
+
self.basis["ao_valence_flag_list"].append(valao)
|
|
247
|
+
self.basis["ao_atom_list"].append(iat)
|
|
248
|
+
self.basis["ao_type_id_list"].append(1) # 1=s
|
|
249
|
+
self.basis["ao_energy_list"].append(level)
|
|
250
|
+
self.basis["ao_zeta_list"].append(zeta)
|
|
251
|
+
self.basis["ao_shell_list"].append(ish)
|
|
252
|
+
iao += 1
|
|
253
|
+
|
|
254
|
+
# --- H-He s (Diffuse) ---
|
|
255
|
+
elif l == 0 and ati <= 2 and not is_valence:
|
|
256
|
+
|
|
257
|
+
alpha_R, coeff_R = self.slater2gauss(current_nprim_or_R, npq, l, zeta, param, need_normalization=True)
|
|
258
|
+
|
|
259
|
+
# Get overlap with valence s
|
|
260
|
+
ss = self.calc_overlap_int_for_diffuse_func(0, alpha_s_val, alpha_R, coeff_s_val, coeff_R)
|
|
261
|
+
min_alpha_for_shell = min(np.min(alpha_s_val), np.min(alpha_R))
|
|
262
|
+
|
|
263
|
+
nprim_total = current_nprim_or_R + nprim_s_val
|
|
264
|
+
|
|
265
|
+
# Add CGF (1)
|
|
266
|
+
self.basis["cgf_primitive_start_idx_list"].append(ipr)
|
|
267
|
+
self.basis["cgf_valence_flag_list"].append(valao)
|
|
268
|
+
self.basis["cgf_atom_list"].append(iat)
|
|
269
|
+
self.basis["cgf_type_id_list"].append(1) # 1=s
|
|
270
|
+
self.basis["cgf_primitive_count_list"].append(nprim_total)
|
|
271
|
+
self.basis["cgf_energy_list"].append(level)
|
|
272
|
+
ibf += 1
|
|
273
|
+
|
|
274
|
+
# Add Primitives (Diffuse part first, then valence orthogonalized)
|
|
275
|
+
all_alphas = []
|
|
276
|
+
all_coeffs = []
|
|
277
|
+
prim_start_idx_for_this_cgf = ipr
|
|
278
|
+
|
|
279
|
+
for p in range(current_nprim_or_R):
|
|
280
|
+
alpha_p = alpha_R[p]
|
|
281
|
+
coeff_p = coeff_R[p]
|
|
282
|
+
self.basis["primitive_alpha_list"].append(alpha_p)
|
|
283
|
+
self.basis["primitive_coeff_list"].append(coeff_p)
|
|
284
|
+
all_alphas.append(alpha_p)
|
|
285
|
+
all_coeffs.append(coeff_p)
|
|
286
|
+
ipr += 1
|
|
287
|
+
|
|
288
|
+
# Add Primitives (Valence part, orthogonalized)
|
|
289
|
+
for p in range(nprim_s_val):
|
|
290
|
+
alpha_p = alpha_s_val[p]
|
|
291
|
+
coeff_p = -ss * coeff_s_val[p]
|
|
292
|
+
self.basis["primitive_alpha_list"].append(alpha_p)
|
|
293
|
+
self.basis["primitive_coeff_list"].append(coeff_p)
|
|
294
|
+
all_alphas.append(alpha_p)
|
|
295
|
+
all_coeffs.append(coeff_p)
|
|
296
|
+
ipr += 1
|
|
297
|
+
|
|
298
|
+
# Renormalize the new CGF
|
|
299
|
+
all_alphas = np.array(all_alphas)
|
|
300
|
+
all_coeffs = np.array(all_coeffs)
|
|
301
|
+
ss_norm = self.calc_overlap_int_for_diffuse_func(0, all_alphas, all_alphas, all_coeffs, all_coeffs)
|
|
302
|
+
norm_factor = 1.0 / np.sqrt(ss_norm)
|
|
303
|
+
|
|
304
|
+
# Update the coefficients in the global list
|
|
305
|
+
for p in range(nprim_total):
|
|
306
|
+
self.basis["primitive_coeff_list"][prim_start_idx_for_this_cgf + p] *= norm_factor
|
|
307
|
+
|
|
308
|
+
# Add AO (1)
|
|
309
|
+
self.basis["ao_valence_flag_list"].append(valao)
|
|
310
|
+
self.basis["ao_atom_list"].append(iat)
|
|
311
|
+
self.basis["ao_type_id_list"].append(1) # 1=s
|
|
312
|
+
self.basis["ao_energy_list"].append(level)
|
|
313
|
+
self.basis["ao_zeta_list"].append(zeta)
|
|
314
|
+
self.basis["ao_shell_list"].append(ish)
|
|
315
|
+
iao += 1
|
|
316
|
+
|
|
317
|
+
# --- H-He p (Polarization) ---
|
|
318
|
+
elif l == 1 and ati <= 2:
|
|
319
|
+
valao_p_pol = -valao
|
|
320
|
+
|
|
321
|
+
alpha, coeff = self.slater2gauss(current_nprim_or_R, npq, l, zeta, param, need_normalization=True)
|
|
322
|
+
min_alpha_for_shell = np.min(alpha)
|
|
323
|
+
|
|
324
|
+
for j_type in [2, 3, 4]: # px, py, pz
|
|
325
|
+
# Add CGF (1)
|
|
326
|
+
self.basis["cgf_primitive_start_idx_list"].append(ipr)
|
|
327
|
+
self.basis["cgf_valence_flag_list"].append(valao_p_pol)
|
|
328
|
+
self.basis["cgf_atom_list"].append(iat)
|
|
329
|
+
self.basis["cgf_type_id_list"].append(j_type)
|
|
330
|
+
self.basis["cgf_primitive_count_list"].append(current_nprim_or_R)
|
|
331
|
+
self.basis["cgf_energy_list"].append(level)
|
|
332
|
+
ibf += 1
|
|
333
|
+
|
|
334
|
+
# Add Primitives
|
|
335
|
+
for p in range(current_nprim_or_R):
|
|
336
|
+
self.basis["primitive_alpha_list"].append(alpha[p])
|
|
337
|
+
self.basis["primitive_coeff_list"].append(coeff[p])
|
|
338
|
+
ipr += 1
|
|
339
|
+
|
|
340
|
+
# Add AO (1)
|
|
341
|
+
self.basis["ao_valence_flag_list"].append(valao_p_pol)
|
|
342
|
+
self.basis["ao_atom_list"].append(iat)
|
|
343
|
+
self.basis["ao_type_id_list"].append(j_type)
|
|
344
|
+
self.basis["ao_energy_list"].append(level)
|
|
345
|
+
self.basis["ao_zeta_list"].append(zeta)
|
|
346
|
+
self.basis["ao_shell_list"].append(ish)
|
|
347
|
+
iao += 1
|
|
348
|
+
|
|
349
|
+
# --- General s (Valence) ---
|
|
350
|
+
elif l == 0 and ati > 2 and is_valence:
|
|
351
|
+
alpha, coeff = self.slater2gauss(current_nprim_or_R, npq, l, zeta, param, need_normalization=True)
|
|
352
|
+
min_alpha_for_shell = np.min(alpha)
|
|
353
|
+
|
|
354
|
+
# Store for use by diffuse shell
|
|
355
|
+
nprim_s_val = current_nprim_or_R
|
|
356
|
+
alpha_s_val = alpha.copy()
|
|
357
|
+
coeff_s_val = coeff.copy()
|
|
358
|
+
|
|
359
|
+
# Add CGF (1)
|
|
360
|
+
self.basis["cgf_primitive_start_idx_list"].append(ipr)
|
|
361
|
+
self.basis["cgf_valence_flag_list"].append(valao)
|
|
362
|
+
self.basis["cgf_atom_list"].append(iat)
|
|
363
|
+
self.basis["cgf_type_id_list"].append(1) # 1=s
|
|
364
|
+
self.basis["cgf_primitive_count_list"].append(current_nprim_or_R)
|
|
365
|
+
self.basis["cgf_energy_list"].append(level)
|
|
366
|
+
ibf += 1
|
|
367
|
+
|
|
368
|
+
# Add Primitives
|
|
369
|
+
for p in range(current_nprim_or_R):
|
|
370
|
+
self.basis["primitive_alpha_list"].append(alpha[p])
|
|
371
|
+
self.basis["primitive_coeff_list"].append(coeff[p])
|
|
372
|
+
ipr += 1
|
|
373
|
+
|
|
374
|
+
# Add AO (1)
|
|
375
|
+
self.basis["ao_valence_flag_list"].append(valao)
|
|
376
|
+
self.basis["ao_atom_list"].append(iat)
|
|
377
|
+
self.basis["ao_type_id_list"].append(1) # 1=s
|
|
378
|
+
self.basis["ao_energy_list"].append(level)
|
|
379
|
+
self.basis["ao_zeta_list"].append(zeta)
|
|
380
|
+
self.basis["ao_shell_list"].append(ish)
|
|
381
|
+
iao += 1
|
|
382
|
+
|
|
383
|
+
# --- General p ---
|
|
384
|
+
elif l == 1 and ati > 2:
|
|
385
|
+
alpha, coeff = self.slater2gauss(current_nprim_or_R, npq, l, zeta, param, need_normalization=True)
|
|
386
|
+
min_alpha_for_shell = np.min(alpha)
|
|
387
|
+
|
|
388
|
+
for j_type in [2, 3, 4]: # px, py, pz
|
|
389
|
+
# Add CGF (1)
|
|
390
|
+
self.basis["cgf_primitive_start_idx_list"].append(ipr)
|
|
391
|
+
self.basis["cgf_valence_flag_list"].append(valao)
|
|
392
|
+
self.basis["cgf_atom_list"].append(iat)
|
|
393
|
+
self.basis["cgf_type_id_list"].append(j_type)
|
|
394
|
+
self.basis["cgf_primitive_count_list"].append(current_nprim_or_R)
|
|
395
|
+
self.basis["cgf_energy_list"].append(level)
|
|
396
|
+
ibf += 1
|
|
397
|
+
|
|
398
|
+
# Add Primitives
|
|
399
|
+
for p in range(current_nprim_or_R):
|
|
400
|
+
self.basis["primitive_alpha_list"].append(alpha[p])
|
|
401
|
+
self.basis["primitive_coeff_list"].append(coeff[p])
|
|
402
|
+
ipr += 1
|
|
403
|
+
|
|
404
|
+
# Add AO (1)
|
|
405
|
+
self.basis["ao_valence_flag_list"].append(valao)
|
|
406
|
+
self.basis["ao_atom_list"].append(iat)
|
|
407
|
+
self.basis["ao_type_id_list"].append(j_type)
|
|
408
|
+
self.basis["ao_energy_list"].append(level)
|
|
409
|
+
self.basis["ao_zeta_list"].append(zeta)
|
|
410
|
+
self.basis["ao_shell_list"].append(ish)
|
|
411
|
+
iao += 1
|
|
412
|
+
|
|
413
|
+
# --- General s (Diffuse) ---
|
|
414
|
+
elif l == 0 and ati > 2 and not is_valence:
|
|
415
|
+
alpha_R, coeff_R = self.slater2gauss(current_nprim_or_R, npq, l, zeta, param, need_normalization=True)
|
|
416
|
+
# Get overlap with valence s
|
|
417
|
+
ss = self.calc_overlap_int_for_diffuse_func(0, alpha_s_val, alpha_R, coeff_s_val, coeff_R)
|
|
418
|
+
min_alpha_for_shell = min(np.min(alpha_s_val), np.min(alpha_R))
|
|
419
|
+
|
|
420
|
+
nprim_total = current_nprim_or_R + nprim_s_val
|
|
421
|
+
|
|
422
|
+
# Add CGF (1)
|
|
423
|
+
self.basis["cgf_primitive_start_idx_list"].append(ipr)
|
|
424
|
+
self.basis["cgf_valence_flag_list"].append(valao)
|
|
425
|
+
self.basis["cgf_atom_list"].append(iat)
|
|
426
|
+
self.basis["cgf_type_id_list"].append(1) # 1=s
|
|
427
|
+
self.basis["cgf_primitive_count_list"].append(nprim_total)
|
|
428
|
+
self.basis["cgf_energy_list"].append(level)
|
|
429
|
+
ibf += 1
|
|
430
|
+
|
|
431
|
+
# Add Primitives (Diffuse part)
|
|
432
|
+
all_alphas = []
|
|
433
|
+
all_coeffs = []
|
|
434
|
+
prim_start_idx_for_this_cgf = ipr
|
|
435
|
+
|
|
436
|
+
for p in range(current_nprim_or_R):
|
|
437
|
+
alpha_p = alpha_R[p]
|
|
438
|
+
coeff_p = coeff_R[p]
|
|
439
|
+
self.basis["primitive_alpha_list"].append(alpha_p)
|
|
440
|
+
self.basis["primitive_coeff_list"].append(coeff_p)
|
|
441
|
+
all_alphas.append(alpha_p)
|
|
442
|
+
all_coeffs.append(coeff_p)
|
|
443
|
+
ipr += 1
|
|
444
|
+
|
|
445
|
+
# Add Primitives (Valence part, orthogonalized)
|
|
446
|
+
for p in range(nprim_s_val):
|
|
447
|
+
alpha_p = alpha_s_val[p]
|
|
448
|
+
coeff_p = -ss * coeff_s_val[p]
|
|
449
|
+
self.basis["primitive_alpha_list"].append(alpha_p)
|
|
450
|
+
self.basis["primitive_coeff_list"].append(coeff_p)
|
|
451
|
+
all_alphas.append(alpha_p)
|
|
452
|
+
all_coeffs.append(coeff_p)
|
|
453
|
+
ipr += 1
|
|
454
|
+
|
|
455
|
+
# Renormalize the new CGF
|
|
456
|
+
all_alphas = np.array(all_alphas)
|
|
457
|
+
all_coeffs = np.array(all_coeffs)
|
|
458
|
+
ss_norm = self.calc_overlap_int_for_diffuse_func(0, all_alphas, all_alphas, all_coeffs, all_coeffs)
|
|
459
|
+
norm_factor = 1.0 / np.sqrt(ss_norm)
|
|
460
|
+
|
|
461
|
+
# Update the coefficients in the global list
|
|
462
|
+
for p in range(nprim_total):
|
|
463
|
+
self.basis["primitive_coeff_list"][prim_start_idx_for_this_cgf + p] *= norm_factor
|
|
464
|
+
|
|
465
|
+
# Add AO (1)
|
|
466
|
+
self.basis["ao_valence_flag_list"].append(valao)
|
|
467
|
+
self.basis["ao_atom_list"].append(iat)
|
|
468
|
+
self.basis["ao_type_id_list"].append(1) # 1=s
|
|
469
|
+
self.basis["ao_energy_list"].append(level)
|
|
470
|
+
self.basis["ao_zeta_list"].append(zeta)
|
|
471
|
+
self.basis["ao_shell_list"].append(ish)
|
|
472
|
+
iao += 1
|
|
473
|
+
|
|
474
|
+
# --- d functions ---
|
|
475
|
+
elif l == 2:
|
|
476
|
+
alpha, coeff = self.slater2gauss(current_nprim_or_R, npq, l, zeta, param, need_normalization=True)
|
|
477
|
+
min_alpha_for_shell = np.min(alpha)
|
|
478
|
+
|
|
479
|
+
for j_type in range(5, 11): # 5..10 (6 CGFs: dxx, dyy, dzz, dxy, dxz, dyz)
|
|
480
|
+
# Add CGF (1)
|
|
481
|
+
self.basis["cgf_primitive_start_idx_list"].append(ipr)
|
|
482
|
+
self.basis["cgf_valence_flag_list"].append(valao)
|
|
483
|
+
self.basis["cgf_atom_list"].append(iat)
|
|
484
|
+
self.basis["cgf_type_id_list"].append(j_type)
|
|
485
|
+
self.basis["cgf_primitive_count_list"].append(current_nprim_or_R)
|
|
486
|
+
self.basis["cgf_energy_list"].append(level)
|
|
487
|
+
ibf += 1
|
|
488
|
+
|
|
489
|
+
# Add Primitives (with transformation factor)
|
|
490
|
+
trafo = d_trafo[j_type]
|
|
491
|
+
for p in range(current_nprim_or_R):
|
|
492
|
+
self.basis["primitive_alpha_list"].append(alpha[p])
|
|
493
|
+
self.basis["primitive_coeff_list"].append(coeff[p] * trafo)
|
|
494
|
+
ipr += 1
|
|
495
|
+
|
|
496
|
+
# Add AO (5 spherical AOs for 6 Cartesian CGFs)
|
|
497
|
+
# Skip for j_type=5 (dxx) - Fortran: if (j .eq.5) cycle
|
|
498
|
+
if j_type != 5:
|
|
499
|
+
ao_type_id = j_type - 1 # AO IDs: 4,5,6,7,8,9 for j_type 6,7,8,9,10
|
|
500
|
+
self.basis["ao_valence_flag_list"].append(valao)
|
|
501
|
+
self.basis["ao_atom_list"].append(iat)
|
|
502
|
+
self.basis["ao_type_id_list"].append(ao_type_id)
|
|
503
|
+
self.basis["ao_energy_list"].append(level)
|
|
504
|
+
self.basis["ao_zeta_list"].append(zeta)
|
|
505
|
+
self.basis["ao_shell_list"].append(ish)
|
|
506
|
+
iao += 1
|
|
507
|
+
|
|
508
|
+
# --- f functions ---
|
|
509
|
+
elif l == 3:
|
|
510
|
+
# Fortran hardcodes valao=1 for f functions
|
|
511
|
+
valao_f = 1
|
|
512
|
+
|
|
513
|
+
alpha, coeff = self.slater2gauss(current_nprim_or_R, npq, l, zeta, param, need_normalization=True)
|
|
514
|
+
min_alpha_for_shell = np.min(alpha)
|
|
515
|
+
|
|
516
|
+
for j_type in range(11, 21): # 11..20 (10 Cartesian CGFs)
|
|
517
|
+
# Add CGF (1)
|
|
518
|
+
self.basis["cgf_primitive_start_idx_list"].append(ipr)
|
|
519
|
+
self.basis["cgf_valence_flag_list"].append(valao_f)
|
|
520
|
+
self.basis["cgf_atom_list"].append(iat)
|
|
521
|
+
self.basis["cgf_type_id_list"].append(j_type)
|
|
522
|
+
self.basis["cgf_primitive_count_list"].append(current_nprim_or_R)
|
|
523
|
+
self.basis["cgf_energy_list"].append(level)
|
|
524
|
+
ibf += 1
|
|
525
|
+
|
|
526
|
+
# Add Primitives (with transformation factor)
|
|
527
|
+
trafo = f_trafo[j_type]
|
|
528
|
+
for p in range(current_nprim_or_R):
|
|
529
|
+
self.basis["primitive_alpha_list"].append(alpha[p])
|
|
530
|
+
self.basis["primitive_coeff_list"].append(coeff[p] * trafo)
|
|
531
|
+
ipr += 1
|
|
532
|
+
|
|
533
|
+
# Add AO (7 spherical AOs for 10 Cartesian CGFs)
|
|
534
|
+
# Skip for j_type 11,12,13 (fxxx, fyyy, fzzz)
|
|
535
|
+
# Fortran: if (j.ge.11 .and.j.le.13) cycle
|
|
536
|
+
if j_type > 13:
|
|
537
|
+
ao_type_id = j_type - 3 # AO IDs: 11,12,13,14,15,16,17 for j_type 14..20
|
|
538
|
+
self.basis["ao_valence_flag_list"].append(valao_f)
|
|
539
|
+
self.basis["ao_atom_list"].append(iat)
|
|
540
|
+
self.basis["ao_type_id_list"].append(ao_type_id)
|
|
541
|
+
self.basis["ao_energy_list"].append(level)
|
|
542
|
+
self.basis["ao_zeta_list"].append(zeta)
|
|
543
|
+
self.basis["ao_shell_list"].append(ish)
|
|
544
|
+
iao += 1
|
|
545
|
+
|
|
546
|
+
# --- End of shell type processing ---
|
|
547
|
+
|
|
548
|
+
# Store min alpha for this shell
|
|
549
|
+
self.basis["shell_min_alpha_list"].append(min_alpha_for_shell)
|
|
550
|
+
|
|
551
|
+
# --- Set Per-Shell Counts ---
|
|
552
|
+
self.basis["shell_cgf_map"][ish][1] = ibf - ibf_start_shell
|
|
553
|
+
self.basis["shell_ao_map"][ish][1] = iao - iao_start_shell
|
|
554
|
+
|
|
555
|
+
# --- Increment global shell counter ---
|
|
556
|
+
ish += 1
|
|
557
|
+
|
|
558
|
+
# --- Set Per-Atom End Indices ---
|
|
559
|
+
self.basis["atom_shells_map"][iat, 1] = ish
|
|
560
|
+
self.basis["atom_cgf_map"][iat, 1] = ibf
|
|
561
|
+
self.basis["atom_ao_map"][iat, 1] = iao
|
|
562
|
+
|
|
563
|
+
# --- Finalize Global Counts ---
|
|
564
|
+
self.basis["total_number_of_primitives"] = ipr
|
|
565
|
+
|
|
566
|
+
# --- Final Sanity Checks (corresponds to Fortran ok check) ---
|
|
567
|
+
all_alphas_positive = all(a > 0.0 for a in self.basis["primitive_alpha_list"])
|
|
568
|
+
if n_cgf_total != ibf:
|
|
569
|
+
print(f"Warning: CGF count mismatch. Calculated={n_cgf_total}, Found={ibf}")
|
|
570
|
+
if n_ao_total != iao:
|
|
571
|
+
print(f"Warning: AO count mismatch.Calculated={n_ao_total}, Found={iao}")
|
|
572
|
+
if n_shell_total != ish:
|
|
573
|
+
print(f"Warning: Shell count mismatch. Calculated={n_shell_total}, Found={ish}")
|
|
574
|
+
if not all_alphas_positive:
|
|
575
|
+
print("Warning: Some primitive exponents are non-positive!")
|
|
576
|
+
|
|
577
|
+
return
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def get_number_of_primitives(self, element, angmn, pqn, is_valence):
|
|
581
|
+
"""
|
|
582
|
+
Returns the number of primitive Gaussians for STO-nG expansion.
|
|
583
|
+
|
|
584
|
+
This function determines nprim based on element type and orbital type.
|
|
585
|
+
Note: In the original Fortran, this would be read from xtbData%hamiltonian%numberOfPrimitives.
|
|
586
|
+
Here we use hardcoded rules matching typical GFN0 behavior.
|
|
587
|
+
"""
|
|
588
|
+
atom_num = element + 1 # Convert 0-indexed to 1-indexed atomic number
|
|
589
|
+
|
|
590
|
+
if atom_num <= 2: # H, He
|
|
591
|
+
if is_valence:
|
|
592
|
+
n = 3 # STO-3G
|
|
593
|
+
else:
|
|
594
|
+
n = 2 # STO-2G (thisprimR for diffuse)
|
|
595
|
+
else:
|
|
596
|
+
if angmn == 0: # s orbital
|
|
597
|
+
if pqn > 5:
|
|
598
|
+
n = 6 # STO-6G
|
|
599
|
+
else:
|
|
600
|
+
n = 4 # STO-4G
|
|
601
|
+
elif angmn == 1: # p orbital
|
|
602
|
+
if pqn > 5:
|
|
603
|
+
n = 6 # STO-6G
|
|
604
|
+
else:
|
|
605
|
+
n = 3 # STO-3G
|
|
606
|
+
elif angmn == 2 or angmn == 3: # d orbital or f orbital
|
|
607
|
+
n = 4 # STO-4G
|
|
608
|
+
else:
|
|
609
|
+
raise ValueError(f"Error in get_number_of_primitives: angmn={angmn} > 3")
|
|
610
|
+
|
|
611
|
+
return n
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def check_transition_metals(self):
|
|
615
|
+
"""
|
|
616
|
+
Identifies transition metals and Group 11 elements in the element list.
|
|
617
|
+
"""
|
|
618
|
+
is_tm_list = []
|
|
619
|
+
is_g11_element_list = []
|
|
620
|
+
|
|
621
|
+
g11_z_numbers = {29, 47, 79, 111} # Cu, Ag, Au, Rg
|
|
622
|
+
|
|
623
|
+
for atn in self.element_list:
|
|
624
|
+
z = atn + 1
|
|
625
|
+
|
|
626
|
+
if z in g11_z_numbers:
|
|
627
|
+
is_g11_element_list.append(True)
|
|
628
|
+
is_tm_list.append(False)
|
|
629
|
+
elif (z >= 21 and z <= 30) or \
|
|
630
|
+
(z >= 39 and z <= 48) or \
|
|
631
|
+
(z >= 57 and z <= 80) or \
|
|
632
|
+
(z >= 89 and z <= 112):
|
|
633
|
+
is_tm_list.append(True)
|
|
634
|
+
is_g11_element_list.append(False)
|
|
635
|
+
else:
|
|
636
|
+
is_tm_list.append(False)
|
|
637
|
+
is_g11_element_list.append(False)
|
|
638
|
+
|
|
639
|
+
return is_tm_list, is_g11_element_list
|
|
640
|
+
|
|
641
|
+
def set_valence_orbitals(self):
|
|
642
|
+
"""
|
|
643
|
+
Determines which shells are valence vs diffuse based on angular momentum.
|
|
644
|
+
NOTE: This method is not called by _set_basis.
|
|
645
|
+
It may be used elsewhere for analysis.
|
|
646
|
+
"""
|
|
647
|
+
self.valence_orbitals_list = []
|
|
648
|
+
for i in range(len(self.element_list)):
|
|
649
|
+
seen_ang_mom = set()
|
|
650
|
+
for shell_idx in range(self.nshells_list[i]):
|
|
651
|
+
ang = self.ang_shells_list[i][shell_idx]
|
|
652
|
+
if ang not in seen_ang_mom:
|
|
653
|
+
self.valence_orbitals_list.append(True)
|
|
654
|
+
seen_ang_mom.add(ang)
|
|
655
|
+
else:
|
|
656
|
+
self.valence_orbitals_list.append(False)
|
|
657
|
+
|
|
658
|
+
return self.valence_orbitals_list
|
|
659
|
+
|
|
660
|
+
def slater2gauss(self, nprim, pqn, angmn, slater_exp, param, need_normalization=True):
|
|
661
|
+
"""
|
|
662
|
+
Converts Slater-type orbital to a sum of Gaussian primitives (STO-nG).
|
|
663
|
+
Corresponds to Fortran subroutine: slaterToGauss
|
|
664
|
+
|
|
665
|
+
Parameters:
|
|
666
|
+
nprim: Number of primitive Gaussians
|
|
667
|
+
pqn: Principal quantum number
|
|
668
|
+
angmn: Angular momentum quantum number (0=s, 1=p, 2=d, 3=f)
|
|
669
|
+
slater_exp: Slater exponent (zeta)
|
|
670
|
+
param: Parameter object containing STO-nG coefficients
|
|
671
|
+
need_normalization: Whether to normalize the primitives
|
|
672
|
+
|
|
673
|
+
Returns:
|
|
674
|
+
alpha: Array of Gaussian exponents
|
|
675
|
+
coeff: Array of contraction coefficients
|
|
676
|
+
"""
|
|
677
|
+
alpha = np.zeros(nprim)
|
|
678
|
+
coeff = np.zeros(nprim)
|
|
679
|
+
|
|
680
|
+
if pqn < angmn + 1:
|
|
681
|
+
raise ValueError(f"Error in slater2gauss: pqn ({pqn}) < angmn + 1 ({angmn + 1})")
|
|
682
|
+
|
|
683
|
+
if slater_exp <= 0.0:
|
|
684
|
+
raise ValueError(f"Error in slater2gauss: non-positive slater exponent ({slater_exp})")
|
|
685
|
+
|
|
686
|
+
# Determine index into parameter tables based on orbital type
|
|
687
|
+
tmp_num = -1
|
|
688
|
+
if angmn == 0: # s orbital
|
|
689
|
+
tmp_num = pqn - 1
|
|
690
|
+
elif angmn == 1: # p orbital
|
|
691
|
+
tmp_num = 4 + pqn - 1
|
|
692
|
+
elif angmn == 2: # d orbital
|
|
693
|
+
tmp_num = 7 + pqn - 1
|
|
694
|
+
elif angmn == 3: # f orbital
|
|
695
|
+
tmp_num = 9 + pqn - 1
|
|
696
|
+
elif angmn == 4: # g orbital
|
|
697
|
+
tmp_num = 10 + pqn - 1
|
|
698
|
+
else:
|
|
699
|
+
raise ValueError(f"Error in slater2gauss: angmn ({angmn}) > 4")
|
|
700
|
+
|
|
701
|
+
slater_exp_sq = slater_exp ** 2.0
|
|
702
|
+
|
|
703
|
+
if nprim == 1:
|
|
704
|
+
alpha[0] = param.pAlpha1[tmp_num] * slater_exp_sq
|
|
705
|
+
coeff[0] = 1.0
|
|
706
|
+
elif nprim == 2:
|
|
707
|
+
alpha = param.pAlpha2[tmp_num, :].copy() * slater_exp_sq
|
|
708
|
+
coeff = param.pCoeff2[tmp_num, :].copy()
|
|
709
|
+
elif nprim == 3:
|
|
710
|
+
alpha = param.pAlpha3[tmp_num, :].copy() * slater_exp_sq
|
|
711
|
+
coeff = param.pCoeff3[tmp_num, :].copy()
|
|
712
|
+
elif nprim == 4:
|
|
713
|
+
alpha = param.pAlpha4[tmp_num, :].copy() * slater_exp_sq
|
|
714
|
+
coeff = param.pCoeff4[tmp_num, :].copy()
|
|
715
|
+
elif nprim == 5:
|
|
716
|
+
alpha = param.pAlpha5[tmp_num, :].copy() * slater_exp_sq
|
|
717
|
+
coeff = param.pCoeff5[tmp_num, :].copy()
|
|
718
|
+
elif nprim == 6:
|
|
719
|
+
if pqn == 6:
|
|
720
|
+
if angmn == 0:
|
|
721
|
+
alpha = param.pAlpha6s[:].copy() * slater_exp_sq
|
|
722
|
+
coeff = param.pCoeff6s[:].copy()
|
|
723
|
+
elif angmn == 1:
|
|
724
|
+
alpha = param.pAlpha6p[:].copy() * slater_exp_sq
|
|
725
|
+
coeff = param.pCoeff6p[:].copy()
|
|
726
|
+
else:
|
|
727
|
+
raise ValueError(f"Error in slater2gauss: invalid angmn ({angmn}) for pqn=6 with nprim=6")
|
|
728
|
+
else:
|
|
729
|
+
alpha = param.pAlpha6[tmp_num, :].copy() * slater_exp_sq
|
|
730
|
+
coeff = param.pCoeff6[tmp_num, :].copy()
|
|
731
|
+
else:
|
|
732
|
+
raise ValueError(f"Error in slater2gauss: invalid number of primitives ({nprim})")
|
|
733
|
+
|
|
734
|
+
if need_normalization:
|
|
735
|
+
# Normalize primitives
|
|
736
|
+
# Formula: coeff = coeff * (2/pi * alpha)^(3/4) * (4*alpha)^(l/2) / sqrt((2l-1)! !)
|
|
737
|
+
# where (2l-1)!! is the double factorial
|
|
738
|
+
top = 2.0 / np.pi
|
|
739
|
+
# dfactorial(angmn + 1) should give (2*angmn - 1)!!
|
|
740
|
+
# For l=0: (2*0-1)!! = (-1)!! = 1
|
|
741
|
+
# For l=1: (2*1-1)!! = 1!! = 1
|
|
742
|
+
# For l=2: (2*2-1)!! = 3!! = 3
|
|
743
|
+
# For l=3: (2*3-1)!! = 5!! = 15
|
|
744
|
+
coeff = coeff * (top * alpha) ** 0.75 * np.sqrt(4.0 * alpha) ** angmn / np.sqrt(dfactorial(angmn + 1))
|
|
745
|
+
|
|
746
|
+
return alpha, coeff
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
def calc_overlap_int_for_diffuse_func(self, angmn, alpha_A, alpha_B, coeff_A, coeff_B):
|
|
750
|
+
"""
|
|
751
|
+
Calculates the overlap integral <A|B> for two CGFs on the same center.
|
|
752
|
+
Corresponds to Fortran subroutine: atovlp
|
|
753
|
+
|
|
754
|
+
Parameters:
|
|
755
|
+
angmn: Angular momentum quantum number (0=s, 1=p)
|
|
756
|
+
alpha_A, alpha_B: Primitive exponent arrays
|
|
757
|
+
coeff_A, coeff_B: Contraction coefficient arrays
|
|
758
|
+
|
|
759
|
+
Returns:
|
|
760
|
+
overlap_int: The overlap integral value
|
|
761
|
+
"""
|
|
762
|
+
overlap_int = 0.0
|
|
763
|
+
|
|
764
|
+
n_prim_A = len(coeff_A)
|
|
765
|
+
n_prim_B = len(coeff_B)
|
|
766
|
+
|
|
767
|
+
if n_prim_A == 0 or n_prim_B == 0:
|
|
768
|
+
print("Warning: calc_overlap_int_for_diffuse_func called with empty primitive list.")
|
|
769
|
+
return 0.0
|
|
770
|
+
|
|
771
|
+
for ii in range(n_prim_A):
|
|
772
|
+
for jj in range(n_prim_B):
|
|
773
|
+
ab = 1.0 / (alpha_A[ii] + alpha_B[jj])
|
|
774
|
+
s00 = (np.pi * ab) ** 1.5
|
|
775
|
+
|
|
776
|
+
sss = 0.0
|
|
777
|
+
if angmn == 0: # s-s overlap
|
|
778
|
+
sss = s00
|
|
779
|
+
elif angmn == 1: # p-p overlap (same component)
|
|
780
|
+
ab05 = ab * 0.5
|
|
781
|
+
sss = s00 * ab05
|
|
782
|
+
|
|
783
|
+
overlap_int += sss * coeff_A[ii] * coeff_B[jj]
|
|
784
|
+
|
|
785
|
+
return overlap_int
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
# === Accessor methods for convenient data retrieval ===
|
|
789
|
+
|
|
790
|
+
def get_cgf_offset_for_atom_shell(self, iat, m):
|
|
791
|
+
"""
|
|
792
|
+
Returns the CGF index at the start of shell m for atom iat.
|
|
793
|
+
Corresponds to Fortran: caoshell(m, iat)
|
|
794
|
+
"""
|
|
795
|
+
return self.basis["atom_shell_cgf_offset"][iat, m]
|
|
796
|
+
|
|
797
|
+
def get_ao_offset_for_atom_shell(self, iat, m):
|
|
798
|
+
"""
|
|
799
|
+
Returns the AO index at the start of shell m for atom iat.
|
|
800
|
+
Corresponds to Fortran: saoshell(m, iat)
|
|
801
|
+
"""
|
|
802
|
+
return self.basis["atom_shell_ao_offset"][iat, m]
|
|
803
|
+
|
|
804
|
+
def get_shell_range_for_atom(self, iat):
|
|
805
|
+
"""
|
|
806
|
+
Returns (start_shell, end_shell) for atom iat.
|
|
807
|
+
Corresponds to Fortran: shells(1:2, iat)
|
|
808
|
+
"""
|
|
809
|
+
return (self.basis["atom_shells_map"][iat, 0],
|
|
810
|
+
self.basis["atom_shells_map"][iat, 1])
|
|
811
|
+
|
|
812
|
+
def get_cgf_range_for_atom(self, iat):
|
|
813
|
+
"""
|
|
814
|
+
Returns (start_cgf, end_cgf) for atom iat.
|
|
815
|
+
Corresponds to Fortran: fila(1:2, iat)
|
|
816
|
+
"""
|
|
817
|
+
return (self.basis["atom_cgf_map"][iat, 0],
|
|
818
|
+
self.basis["atom_cgf_map"][iat, 1])
|
|
819
|
+
|
|
820
|
+
def get_ao_range_for_atom(self, iat):
|
|
821
|
+
"""
|
|
822
|
+
Returns (start_ao, end_ao) for atom iat.
|
|
823
|
+
Corresponds to Fortran: fila2(1:2, iat)
|
|
824
|
+
"""
|
|
825
|
+
return (self.basis["atom_ao_map"][iat, 0],
|
|
826
|
+
self.basis["atom_ao_map"][iat, 1])
|
|
827
|
+
|
|
828
|
+
def get_cgf_range_for_shell(self, ish):
|
|
829
|
+
"""
|
|
830
|
+
Returns (start_cgf, count) for shell ish.
|
|
831
|
+
Corresponds to Fortran: sh2bf(1:2, ish)
|
|
832
|
+
"""
|
|
833
|
+
return tuple(self.basis["shell_cgf_map"][ish])
|
|
834
|
+
|
|
835
|
+
def get_ao_range_for_shell(self, ish):
|
|
836
|
+
"""
|
|
837
|
+
Returns (start_ao, count) for shell ish.
|
|
838
|
+
Corresponds to Fortran: sh2ao(1:2, ish)
|
|
839
|
+
"""
|
|
840
|
+
return tuple(self.basis["shell_ao_map"][ish])
|
|
841
|
+
|
|
842
|
+
def get_primitives_for_cgf(self, ibf):
|
|
843
|
+
"""
|
|
844
|
+
Returns (start_prim_idx, nprim, alphas, coeffs) for CGF ibf.
|
|
845
|
+
"""
|
|
846
|
+
start_idx = self.basis["cgf_primitive_start_idx_list"][ibf]
|
|
847
|
+
nprim = self.basis["cgf_primitive_count_list"][ibf]
|
|
848
|
+
alphas = self.basis["primitive_alpha_list"][start_idx:start_idx + nprim]
|
|
849
|
+
coeffs = self.basis["primitive_coeff_list"][start_idx:start_idx + nprim]
|
|
850
|
+
return start_idx, nprim, alphas, coeffs
|