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,346 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from scipy.special import erf
|
|
3
|
+
from multioptpy.Utils.bond_connectivity import BondConnectivity
|
|
4
|
+
from multioptpy.Utils.calc_tools import Calculationtools
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShortRangeCorrectionHessian:
|
|
8
|
+
"""
|
|
9
|
+
Class for calculating short-range correction to model Hessians, excluding bonded atom pairs.
|
|
10
|
+
|
|
11
|
+
This class computes the second derivatives of the short-range part of
|
|
12
|
+
the Coulomb operator used in range-separated hybrid functionals (e.g., ωB97X-D).
|
|
13
|
+
The short-range part is defined as (1-erf(ω*r))/r, where ω is the range-separation parameter.
|
|
14
|
+
|
|
15
|
+
References:
|
|
16
|
+
[1] J.-D. Chai and M. Head-Gordon, J. Chem. Phys., 2008, 128, 084106 (ωB97X)
|
|
17
|
+
[2] J.-D. Chai and M. Head-Gordon, Phys. Chem. Chem. Phys., 2008, 10, 6615 (ωB97X-D)
|
|
18
|
+
"""
|
|
19
|
+
def __init__(self, omega=0.2, cx_sr=0.78, scaling_factor=0.5):
|
|
20
|
+
"""Initialize the ShortRangeCorrectionHessian class.
|
|
21
|
+
|
|
22
|
+
Parameters:
|
|
23
|
+
-----------
|
|
24
|
+
omega : float
|
|
25
|
+
Range-separation parameter in Bohr^-1 (default: 0.2 for ωB97X-D)
|
|
26
|
+
cx_sr : float
|
|
27
|
+
Short-range DFT exchange coefficient (default: 0.78 for ωB97X-D)
|
|
28
|
+
scaling_factor : float
|
|
29
|
+
Overall scaling factor for the correction (default: 0.5)
|
|
30
|
+
"""
|
|
31
|
+
self.omega = omega # Range-separation parameter (Bohr^-1)
|
|
32
|
+
self.cx_sr = cx_sr # Short-range exchange coefficient
|
|
33
|
+
self.scaling_factor = scaling_factor # Overall scaling factor
|
|
34
|
+
self.sr_cutoff = 15.0 # Cutoff distance for short-range interactions (Bohr)
|
|
35
|
+
|
|
36
|
+
def detect_bonds(self, coord, element_list):
|
|
37
|
+
"""Detect bonded atom pairs in the molecule.
|
|
38
|
+
|
|
39
|
+
Parameters:
|
|
40
|
+
-----------
|
|
41
|
+
coord : numpy.ndarray
|
|
42
|
+
Atomic coordinates (Bohr)
|
|
43
|
+
element_list : list
|
|
44
|
+
List of element symbols
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
--------
|
|
48
|
+
set
|
|
49
|
+
Set of tuples (i,j) representing bonded atom pairs
|
|
50
|
+
"""
|
|
51
|
+
# Use BondConnectivity class from MultiOptPy to detect bonds
|
|
52
|
+
bc = BondConnectivity()
|
|
53
|
+
bond_matrix = bc.bond_connect_matrix(element_list, coord)
|
|
54
|
+
|
|
55
|
+
# Create a set of bonded atom pairs
|
|
56
|
+
bonded_pairs = set()
|
|
57
|
+
for i in range(len(coord)):
|
|
58
|
+
for j in range(i+1, len(coord)):
|
|
59
|
+
if bond_matrix[i, j] == 1:
|
|
60
|
+
bonded_pairs.add((i, j))
|
|
61
|
+
bonded_pairs.add((j, i))
|
|
62
|
+
|
|
63
|
+
return bonded_pairs
|
|
64
|
+
|
|
65
|
+
def sr_coulomb(self, r):
|
|
66
|
+
"""Calculate short-range Coulomb potential.
|
|
67
|
+
|
|
68
|
+
V_SR(r) = (1 - erf(ω*r)) / r
|
|
69
|
+
|
|
70
|
+
Parameters:
|
|
71
|
+
-----------
|
|
72
|
+
r : float
|
|
73
|
+
Distance between two atoms (Bohr)
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
--------
|
|
77
|
+
float
|
|
78
|
+
Short-range Coulomb potential
|
|
79
|
+
"""
|
|
80
|
+
if r < 1e-10:
|
|
81
|
+
# Use limit as r→0 (Taylor expansion)
|
|
82
|
+
return 2 * self.omega / np.sqrt(np.pi)
|
|
83
|
+
return (1.0 - erf(self.omega * r)) / r
|
|
84
|
+
|
|
85
|
+
def sr_coulomb_first_derivative(self, r):
|
|
86
|
+
"""Calculate first derivative of short-range Coulomb potential.
|
|
87
|
+
|
|
88
|
+
dV_SR(r)/dr = -V_SR(r)/r - 2ω/√π * exp(-ω²r²)/r
|
|
89
|
+
|
|
90
|
+
Parameters:
|
|
91
|
+
-----------
|
|
92
|
+
r : float
|
|
93
|
+
Distance between two atoms
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
--------
|
|
97
|
+
float
|
|
98
|
+
First derivative of short-range Coulomb potential
|
|
99
|
+
"""
|
|
100
|
+
if r < 1e-10:
|
|
101
|
+
# Use limit as r→0 (Taylor expansion)
|
|
102
|
+
return -2 * self.omega**3 / (3 * np.sqrt(np.pi))
|
|
103
|
+
|
|
104
|
+
# Error function term
|
|
105
|
+
erf_term = erf(self.omega * r)
|
|
106
|
+
|
|
107
|
+
# Exponential term
|
|
108
|
+
exp_term = 2 * self.omega * np.exp(-(self.omega * r)**2) / (np.sqrt(np.pi) * r)
|
|
109
|
+
|
|
110
|
+
# Coulomb term
|
|
111
|
+
coulomb_term = (erf_term - 1.0) / r**2
|
|
112
|
+
|
|
113
|
+
return exp_term + coulomb_term
|
|
114
|
+
|
|
115
|
+
def sr_coulomb_second_derivative(self, r):
|
|
116
|
+
"""Calculate second derivative of short-range Coulomb potential.
|
|
117
|
+
|
|
118
|
+
d²V_SR(r)/dr² = 2(1-erf(ω*r))/r³ + 2erf(ω*r)/r³ + 4ω/(√π*r²)*e^(-ω²r²) + 2ω³/√π*e^(-ω²r²)
|
|
119
|
+
|
|
120
|
+
Parameters:
|
|
121
|
+
-----------
|
|
122
|
+
r : float
|
|
123
|
+
Distance between two atoms
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
--------
|
|
127
|
+
float
|
|
128
|
+
Second derivative of short-range Coulomb potential
|
|
129
|
+
"""
|
|
130
|
+
if r < 1e-10:
|
|
131
|
+
# Use limit as r→0 (Taylor expansion)
|
|
132
|
+
return 0.0
|
|
133
|
+
|
|
134
|
+
# Error function term
|
|
135
|
+
erf_term = erf(self.omega * r)
|
|
136
|
+
|
|
137
|
+
# Exponential terms
|
|
138
|
+
exp_factor = np.exp(-(self.omega * r)**2) / np.sqrt(np.pi)
|
|
139
|
+
exp_term1 = 4 * self.omega * exp_factor / r**2
|
|
140
|
+
exp_term2 = 2 * (self.omega**3) * exp_factor
|
|
141
|
+
|
|
142
|
+
# Coulomb term
|
|
143
|
+
coulomb_term = 2 * (2 * erf_term - 1) / r**3
|
|
144
|
+
|
|
145
|
+
return coulomb_term + exp_term1 + exp_term2
|
|
146
|
+
|
|
147
|
+
def estimate_atomic_charges(self, element_list):
|
|
148
|
+
"""Estimate atomic charges based on Pauling electronegativity.
|
|
149
|
+
|
|
150
|
+
Parameters:
|
|
151
|
+
-----------
|
|
152
|
+
element_list : list
|
|
153
|
+
List of element symbols
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
--------
|
|
157
|
+
numpy.ndarray
|
|
158
|
+
Estimated atomic charges
|
|
159
|
+
"""
|
|
160
|
+
# Pauling electronegativity values
|
|
161
|
+
electronegativity = {
|
|
162
|
+
'H': 2.20, 'He': 0.00,
|
|
163
|
+
'Li': 0.98, 'Be': 1.57, 'B': 2.04, 'C': 2.55, 'N': 3.04,
|
|
164
|
+
'O': 3.44, 'F': 3.98, 'Ne': 0.00,
|
|
165
|
+
'Na': 0.93, 'Mg': 1.31, 'Al': 1.61, 'Si': 1.90, 'P': 2.19,
|
|
166
|
+
'S': 2.58, 'Cl': 3.16, 'Ar': 0.00,
|
|
167
|
+
'K': 0.82, 'Ca': 1.00, 'Sc': 1.36, 'Ti': 1.54, 'V': 1.63,
|
|
168
|
+
'Cr': 1.66, 'Mn': 1.55, 'Fe': 1.83, 'Co': 1.88, 'Ni': 1.91,
|
|
169
|
+
'Cu': 1.90, 'Zn': 1.65, 'Ga': 1.81, 'Ge': 2.01, 'As': 2.18,
|
|
170
|
+
'Se': 2.55, 'Br': 2.96, 'Kr': 0.00
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
n_atoms = len(element_list)
|
|
174
|
+
charges = np.zeros(n_atoms)
|
|
175
|
+
|
|
176
|
+
# Calculate average electronegativity (reference value)
|
|
177
|
+
en_values = [electronegativity.get(element, 2.0) for element in element_list]
|
|
178
|
+
avg_en = sum(en_values) / len(en_values)
|
|
179
|
+
|
|
180
|
+
# Assign charges based on electronegativity differences
|
|
181
|
+
for i, element in enumerate(element_list):
|
|
182
|
+
en = electronegativity.get(element, 2.0)
|
|
183
|
+
charges[i] = 0.2 * (avg_en - en) # Scale by 0.2
|
|
184
|
+
|
|
185
|
+
return charges
|
|
186
|
+
|
|
187
|
+
def calculate_pair_hessian(self, r_vec, r_ij, atomic_charges, atom_i, atom_j):
|
|
188
|
+
"""Calculate Hessian contribution from short-range Coulomb between atom pair.
|
|
189
|
+
|
|
190
|
+
Parameters:
|
|
191
|
+
-----------
|
|
192
|
+
r_vec : numpy.ndarray
|
|
193
|
+
Relative position vector from atom i to atom j
|
|
194
|
+
r_ij : float
|
|
195
|
+
Distance between atoms i and j
|
|
196
|
+
atomic_charges : numpy.ndarray
|
|
197
|
+
Array of atomic charges
|
|
198
|
+
atom_i, atom_j : int
|
|
199
|
+
Atom indices
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
--------
|
|
203
|
+
numpy.ndarray
|
|
204
|
+
3x3 Hessian block matrix
|
|
205
|
+
"""
|
|
206
|
+
# Return zeros if beyond cutoff distance
|
|
207
|
+
if r_ij > self.sr_cutoff:
|
|
208
|
+
return np.zeros((3, 3))
|
|
209
|
+
|
|
210
|
+
# Unit direction vector
|
|
211
|
+
r_unit = r_vec / r_ij
|
|
212
|
+
|
|
213
|
+
# Charge-based coefficient
|
|
214
|
+
q_i = atomic_charges[atom_i]
|
|
215
|
+
q_j = atomic_charges[atom_j]
|
|
216
|
+
q_factor = q_i * q_j * self.cx_sr * self.scaling_factor
|
|
217
|
+
|
|
218
|
+
# Calculate second derivative
|
|
219
|
+
d2v = self.sr_coulomb_second_derivative(r_ij)
|
|
220
|
+
|
|
221
|
+
# Calculate tensor using outer product
|
|
222
|
+
r_outer = np.outer(r_unit, r_unit)
|
|
223
|
+
|
|
224
|
+
# Calculate Hessian block
|
|
225
|
+
identity = np.eye(3)
|
|
226
|
+
hessian_block = q_factor * (d2v * r_outer +
|
|
227
|
+
self.sr_coulomb_first_derivative(r_ij) / r_ij * (identity - r_outer))
|
|
228
|
+
|
|
229
|
+
return hessian_block
|
|
230
|
+
|
|
231
|
+
def calculate_correction_hessian(self, coord, element_list):
|
|
232
|
+
"""Calculate complete short-range correction Hessian, excluding bonded pairs.
|
|
233
|
+
|
|
234
|
+
Parameters:
|
|
235
|
+
-----------
|
|
236
|
+
coord : numpy.ndarray
|
|
237
|
+
Atomic coordinates (Bohr)
|
|
238
|
+
element_list : list
|
|
239
|
+
List of element symbols
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
--------
|
|
243
|
+
numpy.ndarray
|
|
244
|
+
Short-range correction Hessian
|
|
245
|
+
"""
|
|
246
|
+
n_atoms = len(coord)
|
|
247
|
+
hessian = np.zeros((3 * n_atoms, 3 * n_atoms))
|
|
248
|
+
|
|
249
|
+
# Detect bonded atom pairs
|
|
250
|
+
bonded_pairs = self.detect_bonds(coord, element_list)
|
|
251
|
+
|
|
252
|
+
# Estimate atomic charges
|
|
253
|
+
atomic_charges = self.estimate_atomic_charges(element_list)
|
|
254
|
+
|
|
255
|
+
# Number of bonded pairs and total pairs for statistics
|
|
256
|
+
num_total_pairs = n_atoms * (n_atoms - 1) // 2
|
|
257
|
+
num_bonded_pairs = len(bonded_pairs) // 2 # Divide by 2 because we stored both (i,j) and (j,i)
|
|
258
|
+
print(f"Detected {num_bonded_pairs} bonded pairs out of {num_total_pairs} total pairs")
|
|
259
|
+
print(f"Short-range correction will be applied to {num_total_pairs - num_bonded_pairs} non-bonded pairs only")
|
|
260
|
+
|
|
261
|
+
# Loop over all atom pairs
|
|
262
|
+
for i in range(n_atoms):
|
|
263
|
+
for j in range(i+1, n_atoms):
|
|
264
|
+
# Skip bonded atom pairs
|
|
265
|
+
if (i, j) in bonded_pairs or (j, i) in bonded_pairs:
|
|
266
|
+
continue
|
|
267
|
+
|
|
268
|
+
# Calculate interatomic vector and distance
|
|
269
|
+
r_vec = coord[j] - coord[i]
|
|
270
|
+
r_ij = np.linalg.norm(r_vec)
|
|
271
|
+
|
|
272
|
+
# Calculate Hessian block for this pair
|
|
273
|
+
hess_block = self.calculate_pair_hessian(
|
|
274
|
+
r_vec, r_ij, atomic_charges, i, j
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# Add to the Hessian matrix
|
|
278
|
+
for a in range(3):
|
|
279
|
+
for b in range(3):
|
|
280
|
+
# Diagonal blocks
|
|
281
|
+
hessian[3*i+a, 3*i+b] += hess_block[a, b]
|
|
282
|
+
hessian[3*j+a, 3*j+b] += hess_block[a, b]
|
|
283
|
+
|
|
284
|
+
# Off-diagonal blocks
|
|
285
|
+
hessian[3*i+a, 3*j+b] -= hess_block[a, b]
|
|
286
|
+
hessian[3*j+a, 3*i+b] -= hess_block[a, b]
|
|
287
|
+
|
|
288
|
+
return hessian
|
|
289
|
+
|
|
290
|
+
def apply_correction(self, base_hessian, coord, element_list):
|
|
291
|
+
"""Apply short-range correction to an existing Hessian.
|
|
292
|
+
|
|
293
|
+
Parameters:
|
|
294
|
+
-----------
|
|
295
|
+
base_hessian : numpy.ndarray
|
|
296
|
+
Base model Hessian
|
|
297
|
+
coord : numpy.ndarray
|
|
298
|
+
Atomic coordinates (Bohr)
|
|
299
|
+
element_list : list
|
|
300
|
+
List of element symbols
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
--------
|
|
304
|
+
numpy.ndarray
|
|
305
|
+
Corrected Hessian
|
|
306
|
+
"""
|
|
307
|
+
tools = Calculationtools()
|
|
308
|
+
# Calculate short-range correction
|
|
309
|
+
correction = self.calculate_correction_hessian(coord, element_list)
|
|
310
|
+
correction = tools.project_out_hess_tr_and_rot_for_coord(correction, element_list, coord, display_eigval=False)
|
|
311
|
+
# Add correction to base Hessian
|
|
312
|
+
corrected_hessian = base_hessian + correction
|
|
313
|
+
|
|
314
|
+
corrected_hessian = 0.5 * (corrected_hessian + corrected_hessian.T) # Symmetrize
|
|
315
|
+
# Remove translational and rotational modes
|
|
316
|
+
|
|
317
|
+
return corrected_hessian
|
|
318
|
+
|
|
319
|
+
def main(self, coord, element_list, base_hessian):
|
|
320
|
+
"""Main method to apply short-range correction to a model Hessian.
|
|
321
|
+
|
|
322
|
+
Parameters:
|
|
323
|
+
-----------
|
|
324
|
+
coord : numpy.ndarray
|
|
325
|
+
Atomic coordinates (Bohr)
|
|
326
|
+
element_list : list
|
|
327
|
+
List of element symbols
|
|
328
|
+
base_hessian : numpy.ndarray
|
|
329
|
+
Base model Hessian
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
--------
|
|
333
|
+
numpy.ndarray
|
|
334
|
+
Hessian with short-range correction
|
|
335
|
+
"""
|
|
336
|
+
print(f"Applying short-range correction (ω={self.omega:.3f}) to model Hessian...")
|
|
337
|
+
print("The correction will be applied only to non-bonded atom pairs.")
|
|
338
|
+
|
|
339
|
+
# Apply correction
|
|
340
|
+
corrected_hessian = self.apply_correction(base_hessian, coord, element_list)
|
|
341
|
+
|
|
342
|
+
# Handle NaN values
|
|
343
|
+
corrected_hessian = np.nan_to_num(corrected_hessian, nan=0.0)
|
|
344
|
+
|
|
345
|
+
print("Short-range correction applied successfully")
|
|
346
|
+
return corrected_hessian
|