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.
Files changed (246) hide show
  1. multioptpy/Calculator/__init__.py +0 -0
  2. multioptpy/Calculator/ase_calculation_tools.py +424 -0
  3. multioptpy/Calculator/ase_tools/__init__.py +0 -0
  4. multioptpy/Calculator/ase_tools/fairchem.py +28 -0
  5. multioptpy/Calculator/ase_tools/gamess.py +19 -0
  6. multioptpy/Calculator/ase_tools/gaussian.py +165 -0
  7. multioptpy/Calculator/ase_tools/mace.py +28 -0
  8. multioptpy/Calculator/ase_tools/mopac.py +19 -0
  9. multioptpy/Calculator/ase_tools/nwchem.py +31 -0
  10. multioptpy/Calculator/ase_tools/orca.py +22 -0
  11. multioptpy/Calculator/ase_tools/pygfn0.py +37 -0
  12. multioptpy/Calculator/dxtb_calculation_tools.py +344 -0
  13. multioptpy/Calculator/emt_calculation_tools.py +458 -0
  14. multioptpy/Calculator/gpaw_calculation_tools.py +183 -0
  15. multioptpy/Calculator/lj_calculation_tools.py +314 -0
  16. multioptpy/Calculator/psi4_calculation_tools.py +334 -0
  17. multioptpy/Calculator/pwscf_calculation_tools.py +189 -0
  18. multioptpy/Calculator/pyscf_calculation_tools.py +327 -0
  19. multioptpy/Calculator/sqm1_calculation_tools.py +611 -0
  20. multioptpy/Calculator/sqm2_calculation_tools.py +376 -0
  21. multioptpy/Calculator/tblite_calculation_tools.py +352 -0
  22. multioptpy/Calculator/tersoff_calculation_tools.py +818 -0
  23. multioptpy/Constraint/__init__.py +0 -0
  24. multioptpy/Constraint/constraint_condition.py +834 -0
  25. multioptpy/Coordinate/__init__.py +0 -0
  26. multioptpy/Coordinate/polar_coordinate.py +199 -0
  27. multioptpy/Coordinate/redundant_coordinate.py +638 -0
  28. multioptpy/IRC/__init__.py +0 -0
  29. multioptpy/IRC/converge_criteria.py +28 -0
  30. multioptpy/IRC/dvv.py +544 -0
  31. multioptpy/IRC/euler.py +439 -0
  32. multioptpy/IRC/hpc.py +564 -0
  33. multioptpy/IRC/lqa.py +540 -0
  34. multioptpy/IRC/modekill.py +662 -0
  35. multioptpy/IRC/rk4.py +579 -0
  36. multioptpy/Interpolation/__init__.py +0 -0
  37. multioptpy/Interpolation/adaptive_interpolation.py +283 -0
  38. multioptpy/Interpolation/binomial_interpolation.py +179 -0
  39. multioptpy/Interpolation/geodesic_interpolation.py +785 -0
  40. multioptpy/Interpolation/interpolation.py +156 -0
  41. multioptpy/Interpolation/linear_interpolation.py +473 -0
  42. multioptpy/Interpolation/savitzky_golay_interpolation.py +252 -0
  43. multioptpy/Interpolation/spline_interpolation.py +353 -0
  44. multioptpy/MD/__init__.py +0 -0
  45. multioptpy/MD/thermostat.py +185 -0
  46. multioptpy/MEP/__init__.py +0 -0
  47. multioptpy/MEP/pathopt_bneb_force.py +443 -0
  48. multioptpy/MEP/pathopt_dmf_force.py +448 -0
  49. multioptpy/MEP/pathopt_dneb_force.py +130 -0
  50. multioptpy/MEP/pathopt_ewbneb_force.py +207 -0
  51. multioptpy/MEP/pathopt_gpneb_force.py +512 -0
  52. multioptpy/MEP/pathopt_lup_force.py +113 -0
  53. multioptpy/MEP/pathopt_neb_force.py +225 -0
  54. multioptpy/MEP/pathopt_nesb_force.py +205 -0
  55. multioptpy/MEP/pathopt_om_force.py +153 -0
  56. multioptpy/MEP/pathopt_qsm_force.py +174 -0
  57. multioptpy/MEP/pathopt_qsmv2_force.py +304 -0
  58. multioptpy/ModelFunction/__init__.py +7 -0
  59. multioptpy/ModelFunction/avoiding_model_function.py +29 -0
  60. multioptpy/ModelFunction/binary_image_ts_search_model_function.py +47 -0
  61. multioptpy/ModelFunction/conical_model_function.py +26 -0
  62. multioptpy/ModelFunction/opt_meci.py +50 -0
  63. multioptpy/ModelFunction/opt_mesx.py +47 -0
  64. multioptpy/ModelFunction/opt_mesx_2.py +49 -0
  65. multioptpy/ModelFunction/seam_model_function.py +27 -0
  66. multioptpy/ModelHessian/__init__.py +0 -0
  67. multioptpy/ModelHessian/approx_hessian.py +147 -0
  68. multioptpy/ModelHessian/calc_params.py +227 -0
  69. multioptpy/ModelHessian/fischer.py +236 -0
  70. multioptpy/ModelHessian/fischerd3.py +360 -0
  71. multioptpy/ModelHessian/fischerd4.py +398 -0
  72. multioptpy/ModelHessian/gfn0xtb.py +633 -0
  73. multioptpy/ModelHessian/gfnff.py +709 -0
  74. multioptpy/ModelHessian/lindh.py +165 -0
  75. multioptpy/ModelHessian/lindh2007d2.py +707 -0
  76. multioptpy/ModelHessian/lindh2007d3.py +822 -0
  77. multioptpy/ModelHessian/lindh2007d4.py +1030 -0
  78. multioptpy/ModelHessian/morse.py +106 -0
  79. multioptpy/ModelHessian/schlegel.py +144 -0
  80. multioptpy/ModelHessian/schlegeld3.py +322 -0
  81. multioptpy/ModelHessian/schlegeld4.py +559 -0
  82. multioptpy/ModelHessian/shortrange.py +346 -0
  83. multioptpy/ModelHessian/swartd2.py +496 -0
  84. multioptpy/ModelHessian/swartd3.py +706 -0
  85. multioptpy/ModelHessian/swartd4.py +918 -0
  86. multioptpy/ModelHessian/tshess.py +40 -0
  87. multioptpy/Optimizer/QHAdam.py +61 -0
  88. multioptpy/Optimizer/__init__.py +0 -0
  89. multioptpy/Optimizer/abc_fire.py +83 -0
  90. multioptpy/Optimizer/adabelief.py +58 -0
  91. multioptpy/Optimizer/adabound.py +68 -0
  92. multioptpy/Optimizer/adadelta.py +65 -0
  93. multioptpy/Optimizer/adaderivative.py +56 -0
  94. multioptpy/Optimizer/adadiff.py +68 -0
  95. multioptpy/Optimizer/adafactor.py +70 -0
  96. multioptpy/Optimizer/adam.py +65 -0
  97. multioptpy/Optimizer/adamax.py +62 -0
  98. multioptpy/Optimizer/adamod.py +83 -0
  99. multioptpy/Optimizer/adamw.py +65 -0
  100. multioptpy/Optimizer/adiis.py +523 -0
  101. multioptpy/Optimizer/afire_neb.py +282 -0
  102. multioptpy/Optimizer/block_hessian_update.py +709 -0
  103. multioptpy/Optimizer/c2diis.py +491 -0
  104. multioptpy/Optimizer/component_wise_scaling.py +405 -0
  105. multioptpy/Optimizer/conjugate_gradient.py +82 -0
  106. multioptpy/Optimizer/conjugate_gradient_neb.py +345 -0
  107. multioptpy/Optimizer/coordinate_locking.py +405 -0
  108. multioptpy/Optimizer/dic_rsirfo.py +1015 -0
  109. multioptpy/Optimizer/ediis.py +417 -0
  110. multioptpy/Optimizer/eve.py +76 -0
  111. multioptpy/Optimizer/fastadabelief.py +61 -0
  112. multioptpy/Optimizer/fire.py +77 -0
  113. multioptpy/Optimizer/fire2.py +249 -0
  114. multioptpy/Optimizer/fire_neb.py +92 -0
  115. multioptpy/Optimizer/gan_step.py +486 -0
  116. multioptpy/Optimizer/gdiis.py +609 -0
  117. multioptpy/Optimizer/gediis.py +203 -0
  118. multioptpy/Optimizer/geodesic_step.py +433 -0
  119. multioptpy/Optimizer/gpmin.py +633 -0
  120. multioptpy/Optimizer/gpr_step.py +364 -0
  121. multioptpy/Optimizer/gradientdescent.py +78 -0
  122. multioptpy/Optimizer/gradientdescent_neb.py +52 -0
  123. multioptpy/Optimizer/hessian_update.py +433 -0
  124. multioptpy/Optimizer/hybrid_rfo.py +998 -0
  125. multioptpy/Optimizer/kdiis.py +625 -0
  126. multioptpy/Optimizer/lars.py +21 -0
  127. multioptpy/Optimizer/lbfgs.py +253 -0
  128. multioptpy/Optimizer/lbfgs_neb.py +355 -0
  129. multioptpy/Optimizer/linesearch.py +236 -0
  130. multioptpy/Optimizer/lookahead.py +40 -0
  131. multioptpy/Optimizer/nadam.py +64 -0
  132. multioptpy/Optimizer/newton.py +200 -0
  133. multioptpy/Optimizer/prodigy.py +70 -0
  134. multioptpy/Optimizer/purtubation.py +16 -0
  135. multioptpy/Optimizer/quickmin_neb.py +245 -0
  136. multioptpy/Optimizer/radam.py +75 -0
  137. multioptpy/Optimizer/rfo_neb.py +302 -0
  138. multioptpy/Optimizer/ric_rfo.py +842 -0
  139. multioptpy/Optimizer/rl_step.py +627 -0
  140. multioptpy/Optimizer/rmspropgrave.py +65 -0
  141. multioptpy/Optimizer/rsirfo.py +1647 -0
  142. multioptpy/Optimizer/rsprfo.py +1056 -0
  143. multioptpy/Optimizer/sadam.py +60 -0
  144. multioptpy/Optimizer/samsgrad.py +63 -0
  145. multioptpy/Optimizer/tr_lbfgs.py +678 -0
  146. multioptpy/Optimizer/trim.py +273 -0
  147. multioptpy/Optimizer/trust_radius.py +207 -0
  148. multioptpy/Optimizer/trust_radius_neb.py +121 -0
  149. multioptpy/Optimizer/yogi.py +60 -0
  150. multioptpy/OtherMethod/__init__.py +0 -0
  151. multioptpy/OtherMethod/addf.py +1150 -0
  152. multioptpy/OtherMethod/dimer.py +895 -0
  153. multioptpy/OtherMethod/elastic_image_pair.py +629 -0
  154. multioptpy/OtherMethod/modelfunction.py +456 -0
  155. multioptpy/OtherMethod/newton_traj.py +454 -0
  156. multioptpy/OtherMethod/twopshs.py +1095 -0
  157. multioptpy/PESAnalyzer/__init__.py +0 -0
  158. multioptpy/PESAnalyzer/calc_irc_curvature.py +125 -0
  159. multioptpy/PESAnalyzer/cmds_analysis.py +152 -0
  160. multioptpy/PESAnalyzer/koopman_analysis.py +268 -0
  161. multioptpy/PESAnalyzer/pca_analysis.py +314 -0
  162. multioptpy/Parameters/__init__.py +0 -0
  163. multioptpy/Parameters/atomic_mass.py +20 -0
  164. multioptpy/Parameters/atomic_number.py +22 -0
  165. multioptpy/Parameters/covalent_radii.py +44 -0
  166. multioptpy/Parameters/d2.py +61 -0
  167. multioptpy/Parameters/d3.py +63 -0
  168. multioptpy/Parameters/d4.py +103 -0
  169. multioptpy/Parameters/dreiding.py +34 -0
  170. multioptpy/Parameters/gfn0xtb_param.py +137 -0
  171. multioptpy/Parameters/gfnff_param.py +315 -0
  172. multioptpy/Parameters/gnb.py +104 -0
  173. multioptpy/Parameters/parameter.py +22 -0
  174. multioptpy/Parameters/uff.py +72 -0
  175. multioptpy/Parameters/unit_values.py +20 -0
  176. multioptpy/Potential/AFIR_potential.py +55 -0
  177. multioptpy/Potential/LJ_repulsive_potential.py +345 -0
  178. multioptpy/Potential/__init__.py +0 -0
  179. multioptpy/Potential/anharmonic_keep_potential.py +28 -0
  180. multioptpy/Potential/asym_elllipsoidal_potential.py +718 -0
  181. multioptpy/Potential/electrostatic_potential.py +69 -0
  182. multioptpy/Potential/flux_potential.py +30 -0
  183. multioptpy/Potential/gaussian_potential.py +101 -0
  184. multioptpy/Potential/idpp.py +516 -0
  185. multioptpy/Potential/keep_angle_potential.py +146 -0
  186. multioptpy/Potential/keep_dihedral_angle_potential.py +105 -0
  187. multioptpy/Potential/keep_outofplain_angle_potential.py +70 -0
  188. multioptpy/Potential/keep_potential.py +99 -0
  189. multioptpy/Potential/mechano_force_potential.py +74 -0
  190. multioptpy/Potential/nanoreactor_potential.py +52 -0
  191. multioptpy/Potential/potential.py +896 -0
  192. multioptpy/Potential/spacer_model_potential.py +221 -0
  193. multioptpy/Potential/switching_potential.py +258 -0
  194. multioptpy/Potential/universal_potential.py +34 -0
  195. multioptpy/Potential/value_range_potential.py +36 -0
  196. multioptpy/Potential/void_point_potential.py +25 -0
  197. multioptpy/SQM/__init__.py +0 -0
  198. multioptpy/SQM/sqm1/__init__.py +0 -0
  199. multioptpy/SQM/sqm1/sqm1_core.py +1792 -0
  200. multioptpy/SQM/sqm2/__init__.py +0 -0
  201. multioptpy/SQM/sqm2/calc_tools.py +95 -0
  202. multioptpy/SQM/sqm2/sqm2_basis.py +850 -0
  203. multioptpy/SQM/sqm2/sqm2_bond.py +119 -0
  204. multioptpy/SQM/sqm2/sqm2_core.py +303 -0
  205. multioptpy/SQM/sqm2/sqm2_data.py +1229 -0
  206. multioptpy/SQM/sqm2/sqm2_disp.py +65 -0
  207. multioptpy/SQM/sqm2/sqm2_eeq.py +243 -0
  208. multioptpy/SQM/sqm2/sqm2_overlapint.py +704 -0
  209. multioptpy/SQM/sqm2/sqm2_qm.py +578 -0
  210. multioptpy/SQM/sqm2/sqm2_rep.py +66 -0
  211. multioptpy/SQM/sqm2/sqm2_srb.py +70 -0
  212. multioptpy/Thermo/__init__.py +0 -0
  213. multioptpy/Thermo/normal_mode_analyzer.py +865 -0
  214. multioptpy/Utils/__init__.py +0 -0
  215. multioptpy/Utils/bond_connectivity.py +264 -0
  216. multioptpy/Utils/calc_tools.py +884 -0
  217. multioptpy/Utils/oniom.py +96 -0
  218. multioptpy/Utils/pbc.py +48 -0
  219. multioptpy/Utils/riemann_curvature.py +208 -0
  220. multioptpy/Utils/symmetry_analyzer.py +482 -0
  221. multioptpy/Visualization/__init__.py +0 -0
  222. multioptpy/Visualization/visualization.py +156 -0
  223. multioptpy/WFAnalyzer/MO_analysis.py +104 -0
  224. multioptpy/WFAnalyzer/__init__.py +0 -0
  225. multioptpy/Wrapper/__init__.py +0 -0
  226. multioptpy/Wrapper/autots.py +1239 -0
  227. multioptpy/Wrapper/ieip_wrapper.py +93 -0
  228. multioptpy/Wrapper/md_wrapper.py +92 -0
  229. multioptpy/Wrapper/neb_wrapper.py +94 -0
  230. multioptpy/Wrapper/optimize_wrapper.py +76 -0
  231. multioptpy/__init__.py +5 -0
  232. multioptpy/entrypoints.py +916 -0
  233. multioptpy/fileio.py +660 -0
  234. multioptpy/ieip.py +340 -0
  235. multioptpy/interface.py +1086 -0
  236. multioptpy/irc.py +529 -0
  237. multioptpy/moleculardynamics.py +432 -0
  238. multioptpy/neb.py +1267 -0
  239. multioptpy/optimization.py +1553 -0
  240. multioptpy/optimizer.py +709 -0
  241. multioptpy-1.20.2.dist-info/METADATA +438 -0
  242. multioptpy-1.20.2.dist-info/RECORD +246 -0
  243. multioptpy-1.20.2.dist-info/WHEEL +5 -0
  244. multioptpy-1.20.2.dist-info/entry_points.txt +9 -0
  245. multioptpy-1.20.2.dist-info/licenses/LICENSE +674 -0
  246. multioptpy-1.20.2.dist-info/top_level.txt +1 -0
File without changes
@@ -0,0 +1,199 @@
1
+ import numpy as np
2
+
3
+
4
+ def cart2polar(point, reference_point=None):
5
+ point = np.array(point, dtype=float)
6
+ if reference_point is not None:
7
+ point = point - reference_point
8
+
9
+ n = len(point)
10
+ polar_coords = np.zeros(n)
11
+
12
+ r = np.linalg.norm(point)
13
+ polar_coords[0] = r
14
+
15
+ if r < 1e-9:
16
+ return polar_coords
17
+
18
+ for i in range(n-2):
19
+ norm_partial = np.linalg.norm(point[i:])
20
+ if norm_partial == 0:
21
+ polar_coords[i+1] = 0
22
+ else:
23
+ polar_coords[i+1] = np.arccos(point[i] / norm_partial)
24
+
25
+ if n > 1:
26
+ last_angle = np.arctan2(point[-1], point[-2])
27
+ if last_angle < 0:
28
+ last_angle += 2 * np.pi
29
+ polar_coords[-1] = last_angle
30
+
31
+ return polar_coords
32
+
33
+ def polar2cart(polar_coords, reference_point=None):
34
+ r = polar_coords[0]
35
+ n = len(polar_coords)
36
+
37
+ if abs(r) < 1e-9:
38
+ if reference_point is not None:
39
+ return np.array(reference_point)
40
+ return np.zeros(n)
41
+
42
+ cartesian = np.zeros(n)
43
+ cartesian[0] = r * np.cos(polar_coords[1]) if n > 1 else r
44
+
45
+ for i in range(1, n-1):
46
+ prod = r
47
+ for j in range(1, i+1):
48
+ prod *= np.sin(polar_coords[j])
49
+
50
+ if i < n-1:
51
+ cartesian[i] = prod * np.cos(polar_coords[i+1])
52
+ else:
53
+ cartesian[i] = prod
54
+
55
+ if n > 1:
56
+ prod = r
57
+ for j in range(1, n-1):
58
+ prod *= np.sin(polar_coords[j])
59
+ cartesian[-1] = prod * np.sin(polar_coords[-1])
60
+
61
+ if reference_point is not None:
62
+ cartesian += np.array(reference_point)
63
+
64
+ return cartesian
65
+
66
+ def compute_analytical_jacobian(p):
67
+ """
68
+ Compute the Jacobian matrix analytically for the transformation
69
+ from polar to Cartesian coordinates.
70
+
71
+ Parameters:
72
+ p (numpy.ndarray): Polar coordinates [r, θ₁, θ₂, ..., θₙ₋₁]
73
+
74
+ Returns:
75
+ numpy.ndarray: Jacobian matrix J where J[i,j] = ∂xᵢ/∂pⱼ
76
+ """
77
+ p = np.asarray(p, dtype=float)
78
+ n = len(p)
79
+ r = p[0]
80
+ J = np.zeros((n, n))
81
+
82
+ # Handle the special case of zero radius
83
+ if r < 1e-10:
84
+ J[0, 0] = 1 # ∂x₁/∂r = 1 (all others zero)
85
+ return J
86
+
87
+ # Derivatives with respect to r (first column of Jacobian)
88
+ # For all coordinates: ∂xᵢ/∂r = xᵢ/r
89
+ x = cart2polar(p)
90
+ for i in range(n):
91
+ J[i, 0] = x[i] / r
92
+
93
+ if n <= 1:
94
+ return J # Only radius in 1D case
95
+
96
+ # Derivatives with respect to θ₁ (second column)
97
+ # ∂x₁/∂θ₁ = -r sin(θ₁)
98
+ J[0, 1] = -r * np.sin(p[1])
99
+
100
+ # For other coordinates, ∂xᵢ/∂θ₁ for i>1
101
+ for i in range(1, n):
102
+ # Replace sin(θ₁) with cos(θ₁) in the formula for xᵢ
103
+ deriv = r * np.cos(p[1])
104
+
105
+ # Multiply by the remaining terms sin(θⱼ) and cos/sin terms
106
+ for j in range(2, i+1):
107
+ deriv *= np.sin(p[j])
108
+
109
+ if i < n-1:
110
+ deriv *= np.cos(p[i+1])
111
+ else: # Last coordinate
112
+ deriv *= np.sin(p[n-1])
113
+
114
+ J[i, 1] = deriv
115
+
116
+ # Derivatives with respect to other angles (remaining columns)
117
+ for j in range(2, n): # For each angle θⱼ, j=2...n-1
118
+ # xₖ doesn't depend on θⱼ for k < j-1
119
+ for k in range(0, j-1):
120
+ J[k, j] = 0
121
+
122
+ # For coordinates xₖ where k ≥ j-1
123
+ for k in range(j-1, n):
124
+ if k == j-1:
125
+ # ∂x_{j-1}/∂θⱼ = -r·sin(θ₁)·...·sin(θⱼ₋₁)·sin(θⱼ)
126
+ deriv = -r
127
+ for m in range(1, j):
128
+ deriv *= np.sin(p[m])
129
+ deriv *= np.sin(p[j])
130
+ J[k, j] = deriv
131
+ else: # k > j-1
132
+ # Start with radius
133
+ deriv = r
134
+
135
+ # Multiply by sin terms for angles θ₁...θⱼ₋₁
136
+ for m in range(1, j):
137
+ deriv *= np.sin(p[m])
138
+
139
+ # Replace sin(θⱼ) with cos(θⱼ) in the formula
140
+ deriv *= np.cos(p[j])
141
+
142
+ # Multiply by remaining sin terms for θⱼ₊₁...θₖ
143
+ for m in range(j+1, k+1):
144
+ deriv *= np.sin(p[m])
145
+
146
+ # For intermediate coordinates, multiply by cos(θₖ₊₁)
147
+ if k < n-1:
148
+ deriv *= np.cos(p[k+1])
149
+ else: # Last coordinate
150
+ deriv *= np.sin(p[n-1])
151
+
152
+ J[k, j] = deriv
153
+
154
+ # Special handling for the last angle θₙ₋₁
155
+ if n >= 3:
156
+ # Only the last two coordinates depend on the last angle
157
+ for i in range(0, n-2):
158
+ J[i, n-1] = 0
159
+
160
+ # Second-to-last coordinate: ∂x_{n-1}/∂θ_{n-1} = -r·sin(θ₁)·...·sin(θ_{n-2})·sin(θ_{n-1})
161
+ if n >= 3:
162
+ deriv = -r
163
+ for j in range(1, n-1):
164
+ deriv *= np.sin(p[j])
165
+ J[n-2, n-1] = deriv
166
+
167
+ # Last coordinate: ∂xₙ/∂θ_{n-1} = r·sin(θ₁)·...·sin(θ_{n-2})·cos(θ_{n-1})
168
+ deriv = r
169
+ for j in range(1, n-1):
170
+ deriv *= np.sin(p[j])
171
+ deriv *= np.cos(p[n-1])
172
+ J[n-1, n-1] = deriv
173
+
174
+ return J
175
+
176
+ def cart_grad_2_polar_grad(x, grad_x):
177
+ """
178
+ Transform gradient from Cartesian to polar coordinates.
179
+
180
+ Parameters:
181
+ x (numpy.ndarray): Cartesian coordinates where gradient is evaluated
182
+ grad_x (numpy.ndarray): Gradient in Cartesian coordinates [∂f/∂x₁, ∂f/∂x₂, ..., ∂f/∂xₙ]
183
+
184
+ Returns:
185
+ numpy.ndarray: Gradient in polar coordinates [∂f/∂r, ∂f/∂θ₁, ..., ∂f/∂θₙ₋₁]
186
+ """
187
+ x = np.asarray(x, dtype=float)
188
+ grad_x = np.asarray(grad_x, dtype=float)
189
+
190
+ # Convert to polar coordinates
191
+ p = cart2polar(x)
192
+
193
+ # Compute the Jacobian matrix analytically
194
+ J = compute_analytical_jacobian(p)
195
+
196
+ # Transform gradient: ∇ₚf = J^T · ∇ₓf
197
+ grad_p = np.dot(J.T, grad_x)
198
+
199
+ return grad_p