Эту задачу можно так сформулировать?:
Да, мне как раз тоже пришла такая идея.
В итоге реализовал что-то, что вроде меня сейчас устраивает. Привожу то, что сделал для проверки.
Допустим, у нас есть изначальный вектор
, мы его хотим перевести в вектор, который параметризован как
, где
(т.е. мы уменьшаем проекцию
на плоскость
, но эта проекция остаётся в том же направлении).
Дополнительным условием сделаем, что расстояние от начала координат
до новой точки по поверхности должно остаться прежним, т.е.
.
Решая это уравнение, находим
, которое и даёт нам искомые координаты.
На примере коронена получилось вот что:
(код этого алгоритма)
Код:
import numpy as np
from math import *
from copy import deepcopy
import scipy.optimize as spo
inpf=open("coronene.xyz", "r")
atn=[]
xyz=[]
nline=0
nat=0
for line in inpf:
nline+=1
words=line.split()
if nline==1:
nat=int(words[0])
elif nline>2 and len(words)>3:
atn.append(words[0])
xyz.append(np.array(words[1:4], dtype=float))
if nat!=len(xyz):
print("Number of atoms specified is inconsistent with xyz definition")
exit(1)
def curv_length(t, A, B):
return (A*np.arcsinh(sqrt(B/A)*t)/(2.0*sqrt(B)) + 0.5*t*sqrt(B*t**2 + A) )
def lsqf(t, r0, A, B):
return (curv_length(t, A, B) - r0)**2
def get_new_coords(xyz, a, b, c):
lvec=sqrt(np.dot(xyz,xyz))
newxyz = deepcopy(xyz)
Q=2.0*(a*xyz[0]**2 + b*xyz[0]*xyz[1] + c*xyz[1]**2)
if lvec>1.0e-2 and abs(Q)>1.0e-2:
A=xyz[0]**2 + xyz[1]**2
B=Q**2
res=spo.minimize_scalar(lsqf, bounds=(0., 1.), args=(lvec, A,B), method='Golden')
if res.success:
newxyz[0]=xyz[0]*res.x
newxyz[1]=xyz[1]*res.x
newxyz[2]=0.5*Q*res.x**2
else:
print("Failed convergence in coordinates!")
exit(1)
return newxyz
for i in range(0,100):
abc=0.05*2.0*(np.random.rand(3)-np.array([0.5,0.5,0.5]))
print("%i\n %f %f %f" % (nat, abc[0], abc[1], abc[2]))
for n in range(0,len(atn)):
tr=get_new_coords(xyz[n], abc[0], abc[1], abc[2])
print(" %3s %15.4f %15.4f %15.4f " % (atn[n], tr[0], tr[1], tr[2]))
Спасибо большое всем за помощь и участие!