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,249 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import copy
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class FIRE2:
|
|
6
|
+
"""Fast Inertial Relaxation Engine 2.0 (FIRE2.0) Optimization Algorithm.
|
|
7
|
+
|
|
8
|
+
Implementation of the FIRE2.0 algorithm as described in:
|
|
9
|
+
J. Guénolé, W.G. Nöhring, A. Vaid, F. Houllé, Z. Xie, A. Prakash, E. Bitzek,
|
|
10
|
+
Assessment and optimization of the fast inertial relaxation engine (fire)
|
|
11
|
+
for energy minimization in atomistic simulations and its implementation in lammps,
|
|
12
|
+
Comput. Mater. Sci. 175 (2020) 109584.
|
|
13
|
+
https://doi.org/10.1016/j.commatsci.2020.109584.
|
|
14
|
+
|
|
15
|
+
This implementation uses the Euler semi-implicit integrator.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, **config):
|
|
19
|
+
"""Initialize FIRE2.0 optimizer with configuration parameters.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
N_min : int, optional
|
|
24
|
+
Minimum steps before time step increase, default 5
|
|
25
|
+
f_inc : float, optional
|
|
26
|
+
Factor to increase time step, default 1.10
|
|
27
|
+
f_alpha : float, optional
|
|
28
|
+
Factor to decrease alpha, default 0.99
|
|
29
|
+
f_dec : float, optional
|
|
30
|
+
Factor to decrease time step, default 0.50
|
|
31
|
+
dt_max : float, optional
|
|
32
|
+
Maximum time step, default 1.0
|
|
33
|
+
dt_min : float, optional
|
|
34
|
+
Minimum time step, default 0.01
|
|
35
|
+
alpha_start : float, optional
|
|
36
|
+
Initial mixing parameter, default 0.25
|
|
37
|
+
maxstep : float, optional
|
|
38
|
+
Maximum step size per coordinate, default 0.2
|
|
39
|
+
halfstepback : bool, optional
|
|
40
|
+
Whether to perform half step back when power becomes negative, default True
|
|
41
|
+
display_flag : bool, optional
|
|
42
|
+
Print optimization information, default True
|
|
43
|
+
max_vdotf_negatif : int, optional
|
|
44
|
+
Maximum number of consecutive negative power steps before stopping, default 0 (disabled)
|
|
45
|
+
"""
|
|
46
|
+
# Default parameters (based on the FIRE2.0 paper)
|
|
47
|
+
self.N_min = 5
|
|
48
|
+
self.f_inc = 1.10
|
|
49
|
+
self.f_alpha = 0.99
|
|
50
|
+
self.f_dec = 0.50
|
|
51
|
+
self.dt_max = 1.0
|
|
52
|
+
self.dt_min = 0.01
|
|
53
|
+
self.alpha_start = 0.25
|
|
54
|
+
self.maxstep = 0.2
|
|
55
|
+
self.halfstepback = True
|
|
56
|
+
self.display_flag = True
|
|
57
|
+
self.max_vdotf_negatif = 0 # Default: disabled
|
|
58
|
+
|
|
59
|
+
# Override defaults with user config
|
|
60
|
+
for key, value in config.items():
|
|
61
|
+
setattr(self, key, value)
|
|
62
|
+
|
|
63
|
+
# Internal state variables
|
|
64
|
+
self.iteration = 1
|
|
65
|
+
self.Initialization = True
|
|
66
|
+
self.hessian = None
|
|
67
|
+
self.bias_hessian = None
|
|
68
|
+
self.vdotf_negatif = 0
|
|
69
|
+
self.last_positions = None
|
|
70
|
+
self.last_energy = None
|
|
71
|
+
|
|
72
|
+
def run(self, geom_num_list, B_g, pre_B_g=[], pre_geom=[], B_e=0.0, pre_B_e=0.0,
|
|
73
|
+
pre_move_vector=[], initial_geom_num_list=[], g=[], pre_g=[]):
|
|
74
|
+
"""Run one step of the FIRE2.0 optimization algorithm.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
geom_num_list : numpy.ndarray
|
|
79
|
+
Current geometry/coordinates
|
|
80
|
+
B_g : numpy.ndarray
|
|
81
|
+
Current gradient/forces
|
|
82
|
+
pre_B_g : numpy.ndarray, optional
|
|
83
|
+
Previous gradient
|
|
84
|
+
pre_geom : numpy.ndarray, optional
|
|
85
|
+
Previous geometry
|
|
86
|
+
B_e : float, optional
|
|
87
|
+
Current energy
|
|
88
|
+
pre_B_e : float, optional
|
|
89
|
+
Previous energy
|
|
90
|
+
pre_move_vector : numpy.ndarray, optional
|
|
91
|
+
Previous move vector
|
|
92
|
+
initial_geom_num_list : numpy.ndarray, optional
|
|
93
|
+
Initial geometry
|
|
94
|
+
g : numpy.ndarray, optional
|
|
95
|
+
Alternative gradient representation
|
|
96
|
+
pre_g : numpy.ndarray, optional
|
|
97
|
+
Alternative previous gradient representation
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
numpy.ndarray
|
|
102
|
+
Move vector to update positions
|
|
103
|
+
"""
|
|
104
|
+
# Initialize on first call
|
|
105
|
+
if self.Initialization:
|
|
106
|
+
self.dt = 0.1
|
|
107
|
+
self.alpha = self.alpha_start
|
|
108
|
+
self.Nsteps = 0
|
|
109
|
+
self.velocity = np.zeros_like(geom_num_list)
|
|
110
|
+
self.last_positions = geom_num_list.copy()
|
|
111
|
+
self.last_energy = B_e
|
|
112
|
+
self.Initialization = False
|
|
113
|
+
|
|
114
|
+
# Save the current positions and energy for potential rollback
|
|
115
|
+
current_positions = geom_num_list.copy()
|
|
116
|
+
current_energy = B_e
|
|
117
|
+
|
|
118
|
+
# Calculate power (P = F·V)
|
|
119
|
+
power = np.dot(self.velocity.flatten(), B_g.flatten())
|
|
120
|
+
|
|
121
|
+
if power > 0.0:
|
|
122
|
+
# Moving downhill
|
|
123
|
+
# Increment Nsteps and check if we should increase dt and decrease alpha
|
|
124
|
+
self.Nsteps += 1
|
|
125
|
+
if self.Nsteps > self.N_min:
|
|
126
|
+
self.dt = min(self.dt * self.f_inc, self.dt_max)
|
|
127
|
+
self.alpha *= self.f_alpha
|
|
128
|
+
else:
|
|
129
|
+
# Moving uphill or starting
|
|
130
|
+
# Reset Nsteps, decrease dt, and reset alpha
|
|
131
|
+
self.Nsteps = 0
|
|
132
|
+
self.dt = max(self.dt * self.f_dec, self.dt_min)
|
|
133
|
+
self.alpha = self.alpha_start
|
|
134
|
+
|
|
135
|
+
# Count consecutive negative power steps
|
|
136
|
+
self.vdotf_negatif += 1
|
|
137
|
+
if self.max_vdotf_negatif > 0 and self.vdotf_negatif > self.max_vdotf_negatif:
|
|
138
|
+
if self.display_flag:
|
|
139
|
+
print("Maximum number of consecutive negative power steps reached")
|
|
140
|
+
return np.zeros_like(geom_num_list)
|
|
141
|
+
|
|
142
|
+
# Apply half step back correction if enabled
|
|
143
|
+
if self.halfstepback and power < 0.0:
|
|
144
|
+
# Back up half a step
|
|
145
|
+
half_step_correction = -0.5 * self.dt * self.velocity
|
|
146
|
+
geom_num_list += half_step_correction
|
|
147
|
+
|
|
148
|
+
if self.display_flag:
|
|
149
|
+
print("Applying half step back correction")
|
|
150
|
+
|
|
151
|
+
# Reset velocity
|
|
152
|
+
self.velocity = np.zeros_like(geom_num_list)
|
|
153
|
+
|
|
154
|
+
# Update velocity using Euler semi-implicit integration
|
|
155
|
+
# First update velocity with current forces (v += dt * F)
|
|
156
|
+
self.velocity += self.dt * B_g
|
|
157
|
+
|
|
158
|
+
# Only apply FIRE mixing if power was positive
|
|
159
|
+
if power > 0.0:
|
|
160
|
+
# Calculate the velocity magnitude and force magnitude
|
|
161
|
+
v_norm = np.linalg.norm(self.velocity)
|
|
162
|
+
f_norm = np.linalg.norm(B_g)
|
|
163
|
+
|
|
164
|
+
if v_norm > 1e-10 and f_norm > 1e-10:
|
|
165
|
+
# Apply FIRE mixing: v = (1-α)v + α|v|F̂
|
|
166
|
+
# Where F̂ is the normalized force vector
|
|
167
|
+
scaled_velocity = (1.0 - self.alpha) * self.velocity
|
|
168
|
+
scaled_force = self.alpha * (v_norm / f_norm) * B_g
|
|
169
|
+
self.velocity = scaled_velocity + scaled_force
|
|
170
|
+
|
|
171
|
+
# Calculate the move vector (dr = dt * v)
|
|
172
|
+
move_vector = self.dt * self.velocity
|
|
173
|
+
|
|
174
|
+
# Check if the maximum step size is exceeded
|
|
175
|
+
move_norm = np.linalg.norm(move_vector)
|
|
176
|
+
if move_norm > self.maxstep:
|
|
177
|
+
move_vector *= (self.maxstep / move_norm)
|
|
178
|
+
|
|
179
|
+
if self.display_flag:
|
|
180
|
+
print("FIRE2.0")
|
|
181
|
+
print(f"Iteration: {self.iteration}")
|
|
182
|
+
print(f"dt: {self.dt:.6f}, alpha: {self.alpha:.6f}, Nsteps: {self.Nsteps}")
|
|
183
|
+
print(f"Power (v·F): {power:.6e}")
|
|
184
|
+
print(f"Max velocity: {np.max(np.abs(self.velocity)):.6e}")
|
|
185
|
+
print(f"Max force: {np.max(np.abs(B_g)):.6e}")
|
|
186
|
+
print(f"Max step: {np.max(np.abs(move_vector)):.6e}")
|
|
187
|
+
|
|
188
|
+
# Update state for next iteration
|
|
189
|
+
self.last_positions = current_positions
|
|
190
|
+
self.last_energy = current_energy
|
|
191
|
+
self.iteration += 1
|
|
192
|
+
|
|
193
|
+
# Reset negative power counter if power is positive
|
|
194
|
+
if power > 0.0:
|
|
195
|
+
self.vdotf_negatif = 0
|
|
196
|
+
|
|
197
|
+
return move_vector
|
|
198
|
+
|
|
199
|
+
def set_hessian(self, hessian):
|
|
200
|
+
"""Set Hessian matrix for the optimizer.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
hessian : numpy.ndarray
|
|
205
|
+
Hessian matrix
|
|
206
|
+
"""
|
|
207
|
+
self.hessian = hessian
|
|
208
|
+
|
|
209
|
+
def set_bias_hessian(self, bias_hessian):
|
|
210
|
+
"""Set bias Hessian matrix for the optimizer.
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
bias_hessian : numpy.ndarray
|
|
215
|
+
Bias Hessian matrix
|
|
216
|
+
"""
|
|
217
|
+
self.bias_hessian = bias_hessian
|
|
218
|
+
|
|
219
|
+
def get_hessian(self):
|
|
220
|
+
"""Get Hessian matrix.
|
|
221
|
+
|
|
222
|
+
Returns
|
|
223
|
+
-------
|
|
224
|
+
numpy.ndarray
|
|
225
|
+
Hessian matrix
|
|
226
|
+
"""
|
|
227
|
+
return self.hessian
|
|
228
|
+
|
|
229
|
+
def get_bias_hessian(self):
|
|
230
|
+
"""Get bias Hessian matrix.
|
|
231
|
+
|
|
232
|
+
Returns
|
|
233
|
+
-------
|
|
234
|
+
numpy.ndarray
|
|
235
|
+
Bias Hessian matrix
|
|
236
|
+
"""
|
|
237
|
+
return self.bias_hessian
|
|
238
|
+
|
|
239
|
+
def reset(self):
|
|
240
|
+
"""Reset the optimizer to initial state."""
|
|
241
|
+
self.dt = 0.1
|
|
242
|
+
self.alpha = self.alpha_start
|
|
243
|
+
self.Nsteps = 0
|
|
244
|
+
self.velocity = None
|
|
245
|
+
self.Initialization = True
|
|
246
|
+
self.iteration = 1
|
|
247
|
+
self.vdotf_negatif = 0
|
|
248
|
+
self.last_positions = None
|
|
249
|
+
self.last_energy = None
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from multioptpy.Optimizer import trust_radius_neb
|
|
4
|
+
|
|
5
|
+
class OptimizationAlgorithm(ABC):
|
|
6
|
+
"""Base class for optimization algorithms"""
|
|
7
|
+
|
|
8
|
+
@abstractmethod
|
|
9
|
+
def optimize(self, geometry_num_list, total_force_list, **kwargs):
|
|
10
|
+
"""Execute optimization step"""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FIREOptimizer(OptimizationAlgorithm):
|
|
15
|
+
"""FIRE method optimizer"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config):
|
|
18
|
+
self.config = config
|
|
19
|
+
# FIRE method parameters
|
|
20
|
+
self.dt = config.dt
|
|
21
|
+
self.a = config.a
|
|
22
|
+
self.n_reset = config.n_reset
|
|
23
|
+
self.FIRE_N_accelerate = config.FIRE_N_accelerate
|
|
24
|
+
self.FIRE_f_inc = config.FIRE_f_inc
|
|
25
|
+
self.FIRE_f_accelerate = config.FIRE_f_accelerate
|
|
26
|
+
self.FIRE_f_decelerate = config.FIRE_f_decelerate
|
|
27
|
+
self.FIRE_a_start = config.FIRE_a_start
|
|
28
|
+
self.FIRE_dt_max = config.FIRE_dt_max
|
|
29
|
+
|
|
30
|
+
# Initialize NEB trust radius
|
|
31
|
+
self.NEB_TR = trust_radius_neb.TR_NEB(
|
|
32
|
+
NEB_FOLDER_DIRECTORY=config.NEB_FOLDER_DIRECTORY,
|
|
33
|
+
fix_init_edge=config.fix_init_edge,
|
|
34
|
+
fix_end_edge=config.fix_end_edge,
|
|
35
|
+
apply_convergence_criteria=config.apply_convergence_criteria
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def optimize(self, geometry_num_list, total_force_list, pre_total_velocity,
|
|
39
|
+
optimize_num, total_velocity, cos_list, biased_energy_list,
|
|
40
|
+
pre_biased_energy_list, pre_geom):
|
|
41
|
+
"""FIRE method optimization"""
|
|
42
|
+
velocity_neb = []
|
|
43
|
+
|
|
44
|
+
for num in range(len(total_velocity)):
|
|
45
|
+
part_velocity_neb = []
|
|
46
|
+
for i in range(len(total_force_list[0])):
|
|
47
|
+
force_norm = np.linalg.norm(total_force_list[num][i])
|
|
48
|
+
velocity_norm = np.linalg.norm(total_velocity[num][i])
|
|
49
|
+
if force_norm > 1e-10: # avoid division by zero
|
|
50
|
+
part_velocity_neb.append(
|
|
51
|
+
(1.0 - self.a) * total_velocity[num][i] +
|
|
52
|
+
self.a * (velocity_norm / force_norm) * total_force_list[num][i]
|
|
53
|
+
)
|
|
54
|
+
else:
|
|
55
|
+
part_velocity_neb.append(total_velocity[num][i])
|
|
56
|
+
velocity_neb.append(part_velocity_neb)
|
|
57
|
+
|
|
58
|
+
velocity_neb = np.array(velocity_neb)
|
|
59
|
+
|
|
60
|
+
np_dot_param = 0.0
|
|
61
|
+
if optimize_num != 0 and len(pre_total_velocity) > 1:
|
|
62
|
+
np_dot_param = np.sum([np.dot(pre_total_velocity[num_1][num_2], total_force_num.T)
|
|
63
|
+
for num_1, total_force in enumerate(total_force_list)
|
|
64
|
+
for num_2, total_force_num in enumerate(total_force)])
|
|
65
|
+
print(np_dot_param)
|
|
66
|
+
|
|
67
|
+
if optimize_num > 0 and np_dot_param > 0 and len(pre_total_velocity) > 1:
|
|
68
|
+
if self.n_reset > self.FIRE_N_accelerate:
|
|
69
|
+
self.dt = min(self.dt * self.FIRE_f_inc, self.FIRE_dt_max)
|
|
70
|
+
self.a *= self.FIRE_f_inc
|
|
71
|
+
self.n_reset += 1
|
|
72
|
+
else:
|
|
73
|
+
velocity_neb *= 0
|
|
74
|
+
self.a = self.FIRE_a_start
|
|
75
|
+
self.dt *= self.FIRE_f_decelerate
|
|
76
|
+
self.n_reset = 0
|
|
77
|
+
|
|
78
|
+
total_velocity = velocity_neb + self.dt * total_force_list
|
|
79
|
+
|
|
80
|
+
if optimize_num != 0 and len(pre_total_velocity) > 1:
|
|
81
|
+
total_delta = self.dt * (total_velocity + pre_total_velocity)
|
|
82
|
+
else:
|
|
83
|
+
total_delta = self.dt * total_velocity
|
|
84
|
+
|
|
85
|
+
# Calculate the movement vector using TR_calc
|
|
86
|
+
move_vector = self.NEB_TR.TR_calc(geometry_num_list, total_force_list, total_delta,
|
|
87
|
+
biased_energy_list, pre_biased_energy_list, pre_geom)
|
|
88
|
+
|
|
89
|
+
# Update geometry using the move vector
|
|
90
|
+
new_geometry = (geometry_num_list + move_vector) * self.config.bohr2angstroms
|
|
91
|
+
|
|
92
|
+
return new_geometry
|