MolHandling Translation
In this commit were created a System class to manage the functions between two atoms and various new functions were translated Signed-off-by: Vitor Hideyoshi <vitor.h.n.batista@gmail.com>
This commit is contained in:
@@ -11,144 +11,144 @@ from DPpack.SetGlobals import *
|
|||||||
|
|
||||||
####################################### functions ######################################
|
####################################### functions ######################################
|
||||||
|
|
||||||
def center_of_mass(molecule):
|
# def center_of_mass(molecule):
|
||||||
|
|
||||||
com = np.zeros(3)
|
# com = np.zeros(3)
|
||||||
total_mass = 0.0
|
# total_mass = 0.0
|
||||||
for atom in molecule:
|
# for atom in molecule:
|
||||||
total_mass += atom['mass']
|
# total_mass += atom['mass']
|
||||||
position = np.array([atom['rx'], atom['ry'], atom['rz']])
|
# position = np.array([atom['rx'], atom['ry'], atom['rz']])
|
||||||
com += atom['mass'] * position
|
# com += atom['mass'] * position
|
||||||
|
|
||||||
com = com / total_mass
|
# com = com / total_mass
|
||||||
|
|
||||||
return com
|
# return com
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def center_of_mass_distance(molecule1, molecule2):
|
# def center_of_mass_distance(molecule1, molecule2):
|
||||||
|
|
||||||
com1 = center_of_mass(molecule1)
|
# com1 = center_of_mass(molecule1)
|
||||||
com2 = center_of_mass(molecule2)
|
# com2 = center_of_mass(molecule2)
|
||||||
dx = com1[0] - com2[0]
|
# dx = com1[0] - com2[0]
|
||||||
dy = com1[1] - com2[1]
|
# dy = com1[1] - com2[1]
|
||||||
dz = com1[2] - com2[2]
|
# dz = com1[2] - com2[2]
|
||||||
distance = math.sqrt(dx**2 + dy**2 + dz**2)
|
# distance = math.sqrt(dx**2 + dy**2 + dz**2)
|
||||||
|
|
||||||
return distance
|
# return distance
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def center_of_mass_to_origin(molecule):
|
# def center_of_mass_to_origin(molecule):
|
||||||
|
|
||||||
com = center_of_mass(molecule)
|
# com = center_of_mass(molecule)
|
||||||
for atom in molecule:
|
# for atom in molecule:
|
||||||
atom['rx'] -= com[0]
|
# atom['rx'] -= com[0]
|
||||||
atom['ry'] -= com[1]
|
# atom['ry'] -= com[1]
|
||||||
atom['rz'] -= com[2]
|
# atom['rz'] -= com[2]
|
||||||
|
|
||||||
return
|
# return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def charges_and_dipole(molecule):
|
# def charges_and_dipole(molecule):
|
||||||
|
|
||||||
eA_to_Debye = 1/0.20819434
|
# eA_to_Debye = 1/0.20819434
|
||||||
charge = 0
|
# charge = 0
|
||||||
dipole = np.zeros(3)
|
# dipole = np.zeros(3)
|
||||||
for atom in molecule:
|
# for atom in molecule:
|
||||||
position = np.array([ atom['rx'], atom['ry'], atom['rz'] ])
|
# position = np.array([ atom['rx'], atom['ry'], atom['rz'] ])
|
||||||
dipole += atom['chg'] * position
|
# dipole += atom['chg'] * position
|
||||||
charge += atom['chg']
|
# charge += atom['chg']
|
||||||
|
|
||||||
dipole *= eA_to_Debye
|
# dipole *= eA_to_Debye
|
||||||
total_dipole = math.sqrt(dipole[0]**2 + dipole[1]**2 + dipole[2]**2)
|
# total_dipole = math.sqrt(dipole[0]**2 + dipole[1]**2 + dipole[2]**2)
|
||||||
|
|
||||||
return [charge, dipole[0], dipole[1], dipole[2], total_dipole]
|
# return [charge, dipole[0], dipole[1], dipole[2], total_dipole]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def distances_between_atoms(molecule):
|
# def distances_between_atoms(molecule):
|
||||||
|
|
||||||
distances = []
|
# distances = []
|
||||||
dim = len(molecule)
|
# dim = len(molecule)
|
||||||
for atom1 in molecule:
|
# for atom1 in molecule:
|
||||||
if atom1['na'] != ghost_number:
|
# if atom1['na'] != ghost_number:
|
||||||
for atom2 in molecule:
|
# for atom2 in molecule:
|
||||||
if atom2['na'] != ghost_number:
|
# if atom2['na'] != ghost_number:
|
||||||
dx = atom1['rx'] - atom2['rx']
|
# dx = atom1['rx'] - atom2['rx']
|
||||||
dy = atom1['ry'] - atom2['ry']
|
# dy = atom1['ry'] - atom2['ry']
|
||||||
dz = atom1['rz'] - atom2['rz']
|
# dz = atom1['rz'] - atom2['rz']
|
||||||
distances.append(math.sqrt(dx**2 + dy**2 + dz**2))
|
# distances.append(math.sqrt(dx**2 + dy**2 + dz**2))
|
||||||
|
|
||||||
return np.array(distances).reshape(dim, dim)
|
# return np.array(distances).reshape(dim, dim)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def eixos(molecule):
|
# def eixos(molecule):
|
||||||
|
|
||||||
eixos = np.zeros(3)
|
# eixos = np.zeros(3)
|
||||||
if len(molecule) == 2:
|
# if len(molecule) == 2:
|
||||||
position1 = np.array([ molecule[0]['rx'], molecule[0]['ry'], molecule[0]['rz'] ])
|
# position1 = np.array([ molecule[0]['rx'], molecule[0]['ry'], molecule[0]['rz'] ])
|
||||||
position2 = np.array([ molecule[1]['rx'], molecule[1]['ry'], molecule[1]['rz'] ])
|
# position2 = np.array([ molecule[1]['rx'], molecule[1]['ry'], molecule[1]['rz'] ])
|
||||||
eixos = position2 - position1
|
# eixos = position2 - position1
|
||||||
eixos /= linalg.norm(eixos)
|
# eixos /= linalg.norm(eixos)
|
||||||
elif len(molecule) > 2:
|
# elif len(molecule) > 2:
|
||||||
position1 = np.array([ molecule[0]['rx'], molecule[0]['ry'], molecule[0]['rz'] ])
|
# position1 = np.array([ molecule[0]['rx'], molecule[0]['ry'], molecule[0]['rz'] ])
|
||||||
position2 = np.array([ molecule[1]['rx'], molecule[1]['ry'], molecule[1]['rz'] ])
|
# position2 = np.array([ molecule[1]['rx'], molecule[1]['ry'], molecule[1]['rz'] ])
|
||||||
position3 = np.array([ molecule[2]['rx'], molecule[2]['ry'], molecule[2]['rz'] ])
|
# position3 = np.array([ molecule[2]['rx'], molecule[2]['ry'], molecule[2]['rz'] ])
|
||||||
v1 = position2 - position1
|
# v1 = position2 - position1
|
||||||
v2 = position3 - position1
|
# v2 = position3 - position1
|
||||||
v3 = np.cross(v1, v2)
|
# v3 = np.cross(v1, v2)
|
||||||
v2 = np.cross(v1, v3)
|
# v2 = np.cross(v1, v3)
|
||||||
v1 /= linalg.norm(v1)
|
# v1 /= linalg.norm(v1)
|
||||||
v2 /= linalg.norm(v2)
|
# v2 /= linalg.norm(v2)
|
||||||
v3 /= linalg.norm(v3)
|
# v3 /= linalg.norm(v3)
|
||||||
eixos = np.array([[v1[0], v1[1], v1[2]],
|
# eixos = np.array([[v1[0], v1[1], v1[2]],
|
||||||
[v2[0], v2[1], v2[2]],
|
# [v2[0], v2[1], v2[2]],
|
||||||
[v3[0], v3[1], v3[2]]])
|
# [v3[0], v3[1], v3[2]]])
|
||||||
|
|
||||||
return eixos
|
# return eixos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def inertia_tensor(molecule):
|
# def inertia_tensor(molecule):
|
||||||
|
|
||||||
com = center_of_mass(molecule)
|
# com = center_of_mass(molecule)
|
||||||
Ixx = Ixy = Ixz = Iyy = Iyz = Izz = 0.0
|
# Ixx = Ixy = Ixz = Iyy = Iyz = Izz = 0.0
|
||||||
for atom in molecule:
|
# for atom in molecule:
|
||||||
#### Obtain the displacement from the center of mass
|
# #### Obtain the displacement from the center of mass
|
||||||
dx = atom['rx'] - com[0]
|
# dx = atom['rx'] - com[0]
|
||||||
dy = atom['ry'] - com[1]
|
# dy = atom['ry'] - com[1]
|
||||||
dz = atom['rz'] - com[2]
|
# dz = atom['rz'] - com[2]
|
||||||
#### Update the diagonal components of the tensor
|
# #### Update the diagonal components of the tensor
|
||||||
Ixx += atom['mass'] * (dy**2 + dz**2)
|
# Ixx += atom['mass'] * (dy**2 + dz**2)
|
||||||
Iyy += atom['mass'] * (dz**2 + dx**2)
|
# Iyy += atom['mass'] * (dz**2 + dx**2)
|
||||||
Izz += atom['mass'] * (dx**2 + dy**2)
|
# Izz += atom['mass'] * (dx**2 + dy**2)
|
||||||
#### Update the off-diagonal components of the tensor
|
# #### Update the off-diagonal components of the tensor
|
||||||
Ixy += atom['mass'] * dx * dy * -1
|
# Ixy += atom['mass'] * dx * dy * -1
|
||||||
Ixz += atom['mass'] * dx * dz * -1
|
# Ixz += atom['mass'] * dx * dz * -1
|
||||||
Iyz += atom['mass'] * dy * dz * -1
|
# Iyz += atom['mass'] * dy * dz * -1
|
||||||
|
|
||||||
return np.array([[Ixx, Ixy, Ixz],
|
# return np.array([[Ixx, Ixy, Ixz],
|
||||||
[Ixy, Iyy, Iyz],
|
# [Ixy, Iyy, Iyz],
|
||||||
[Ixz, Iyz, Izz]])
|
# [Ixz, Iyz, Izz]])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def minimum_distance(molecule1, molecule2):
|
# def minimum_distance(molecule1, molecule2):
|
||||||
|
|
||||||
distances = []
|
# distances = []
|
||||||
for atom1 in molecule1:
|
# for atom1 in molecule1:
|
||||||
if atom1['na'] != ghost_number:
|
# if atom1['na'] != ghost_number:
|
||||||
for atom2 in molecule2:
|
# for atom2 in molecule2:
|
||||||
if atom2['na'] != ghost_number:
|
# if atom2['na'] != ghost_number:
|
||||||
dx = atom1['rx'] - atom2['rx']
|
# dx = atom1['rx'] - atom2['rx']
|
||||||
dy = atom1['ry'] - atom2['ry']
|
# dy = atom1['ry'] - atom2['ry']
|
||||||
dz = atom1['rz'] - atom2['rz']
|
# dz = atom1['rz'] - atom2['rz']
|
||||||
distances.append(math.sqrt(dx**2 + dy**2 + dz**2))
|
# distances.append(math.sqrt(dx**2 + dy**2 + dz**2))
|
||||||
|
|
||||||
return min(distances)
|
# return min(distances)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -224,15 +224,15 @@ def calculate_step(gradient, hessian, fh):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def read_position(molecule):
|
# def read_position(molecule):
|
||||||
|
|
||||||
position_list = []
|
# position_list = []
|
||||||
for atom in molecule:
|
# for atom in molecule:
|
||||||
position_list.extend([ atom['rx'], atom['ry'], atom['rz'] ])
|
# position_list.extend([ atom['rx'], atom['ry'], atom['rz'] ])
|
||||||
position = np.array(position_list)
|
# position = np.array(position_list)
|
||||||
position *= ang2bohr
|
# position *= ang2bohr
|
||||||
|
|
||||||
return position
|
# return position
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -254,17 +254,17 @@ def update_molecule(position, fh):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def update_hessian(step, cur_gradient, old_gradient, hessian): ## According to the BFGS
|
# def update_hessian(step, cur_gradient, old_gradient, hessian): ## According to the BFGS
|
||||||
|
|
||||||
dif_gradient = cur_gradient - old_gradient
|
# dif_gradient = cur_gradient - old_gradient
|
||||||
|
|
||||||
mat1 = 1/np.dot(dif_gradient, step) * np.matmul(dif_gradient.T, dif_gradient)
|
# mat1 = 1/np.dot(dif_gradient, step) * np.matmul(dif_gradient.T, dif_gradient)
|
||||||
mat2 = 1/np.dot(step, np.matmul(hessian, step.T).T)
|
# mat2 = 1/np.dot(step, np.matmul(hessian, step.T).T)
|
||||||
mat2 *= np.matmul( np.matmul(hessian, step.T), np.matmul(step, hessian) )
|
# mat2 *= np.matmul( np.matmul(hessian, step.T), np.matmul(step, hessian) )
|
||||||
|
|
||||||
hessian += mat1 - mat2
|
# hessian += mat1 - mat2
|
||||||
|
|
||||||
return hessian
|
# return hessian
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -406,14 +406,14 @@ def populate_asec_vdw(cycle, fh):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def principal_axes(inertia_tensor):
|
# def principal_axes(inertia_tensor):
|
||||||
|
|
||||||
try:
|
# try:
|
||||||
evals, evecs = linalg.eigh(inertia_tensor)
|
# evals, evecs = linalg.eigh(inertia_tensor)
|
||||||
except:
|
# except:
|
||||||
sys.exit("Error: diagonalization of inertia tensor did not converge")
|
# sys.exit("Error: diagonalization of inertia tensor did not converge")
|
||||||
|
|
||||||
return evals, evecs
|
# return evals, evecs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -463,73 +463,73 @@ def print_mol_info(molecule, fh):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def sizes_of_molecule(molecule):
|
# def sizes_of_molecule(molecule):
|
||||||
|
|
||||||
x_list = []
|
# x_list = []
|
||||||
y_list = []
|
# y_list = []
|
||||||
z_list = []
|
# z_list = []
|
||||||
for atom in molecule:
|
# for atom in molecule:
|
||||||
if atom['na'] != ghost_number:
|
# if atom['na'] != ghost_number:
|
||||||
x_list.append(atom['rx'])
|
# x_list.append(atom['rx'])
|
||||||
y_list.append(atom['ry'])
|
# y_list.append(atom['ry'])
|
||||||
z_list.append(atom['rz'])
|
# z_list.append(atom['rz'])
|
||||||
|
|
||||||
x_max = max(x_list)
|
# x_max = max(x_list)
|
||||||
x_min = min(x_list)
|
# x_min = min(x_list)
|
||||||
y_max = max(y_list)
|
# y_max = max(y_list)
|
||||||
y_min = min(y_list)
|
# y_min = min(y_list)
|
||||||
z_max = max(z_list)
|
# z_max = max(z_list)
|
||||||
z_min = min(z_list)
|
# z_min = min(z_list)
|
||||||
|
|
||||||
sizes = [x_max - x_min, y_max - y_min, z_max - z_min]
|
# sizes = [x_max - x_min, y_max - y_min, z_max - z_min]
|
||||||
|
|
||||||
return sizes
|
# return sizes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def standard_orientation(molecule):
|
# def standard_orientation(molecule):
|
||||||
|
|
||||||
center_of_mass_to_origin(molecule)
|
# center_of_mass_to_origin(molecule)
|
||||||
tensor = inertia_tensor(molecule)
|
# tensor = inertia_tensor(molecule)
|
||||||
evals, evecs = principal_axes(tensor)
|
# evals, evecs = principal_axes(tensor)
|
||||||
if round(linalg.det(evecs)) == -1:
|
# if round(linalg.det(evecs)) == -1:
|
||||||
evecs[0,2] *= -1
|
# evecs[0,2] *= -1
|
||||||
evecs[1,2] *= -1
|
# evecs[1,2] *= -1
|
||||||
evecs[2,2] *= -1
|
# evecs[2,2] *= -1
|
||||||
if round(linalg.det(evecs)) != 1:
|
# if round(linalg.det(evecs)) != 1:
|
||||||
sys.exit("Error: could not make a rotation matrix while adopting the standard orientation")
|
# sys.exit("Error: could not make a rotation matrix while adopting the standard orientation")
|
||||||
|
|
||||||
rot_matrix = evecs.T
|
# rot_matrix = evecs.T
|
||||||
for atom in molecule:
|
# for atom in molecule:
|
||||||
position = np.array([ atom['rx'], atom['ry'], atom['rz'] ])
|
# position = np.array([ atom['rx'], atom['ry'], atom['rz'] ])
|
||||||
new_position = np.matmul(rot_matrix, position.T).T
|
# new_position = np.matmul(rot_matrix, position.T).T
|
||||||
atom['rx'] = new_position[0]
|
# atom['rx'] = new_position[0]
|
||||||
atom['ry'] = new_position[1]
|
# atom['ry'] = new_position[1]
|
||||||
atom['rz'] = new_position[2]
|
# atom['rz'] = new_position[2]
|
||||||
|
|
||||||
return
|
# return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def total_mass(molecule):
|
# def total_mass(molecule):
|
||||||
|
|
||||||
mass = 0
|
# mass = 0
|
||||||
for atom in molecule:
|
# for atom in molecule:
|
||||||
mass += atom['mass']
|
# mass += atom['mass']
|
||||||
|
|
||||||
return mass
|
# return mass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def translate(molecule, vector):
|
# def translate(molecule, vector):
|
||||||
|
|
||||||
new_molecule = deepcopy(molecule)
|
# new_molecule = deepcopy(molecule)
|
||||||
for atom in new_molecule:
|
# for atom in new_molecule:
|
||||||
atom['rx'] += vector[0]
|
# atom['rx'] += vector[0]
|
||||||
atom['ry'] += vector[1]
|
# atom['ry'] += vector[1]
|
||||||
atom['rz'] += vector[2]
|
# atom['rz'] += vector[2]
|
||||||
|
|
||||||
return new_molecule
|
# return new_molecule
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,83 @@
|
|||||||
|
from DPpack.MolHandling import total_mass
|
||||||
import os, sys
|
import os, sys
|
||||||
import math
|
import math
|
||||||
import shutil
|
import shutil
|
||||||
import textwrap
|
import textwrap
|
||||||
import numpy as np
|
import sys, math
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from numpy import linalg
|
||||||
|
|
||||||
from DPpack.PTable import *
|
|
||||||
from DPpack.Misc import *
|
from DPpack.Misc import *
|
||||||
|
from DPpack.PTable import *
|
||||||
|
from DPpack.SetGlobals import *
|
||||||
|
|
||||||
|
# Usaremos uma nova classe que ira conter toda interação entre moleculas
|
||||||
|
|
||||||
|
class System:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.molecule = []
|
||||||
|
|
||||||
|
def add_molecule(self, m):
|
||||||
|
|
||||||
|
self.molecule.append(m)
|
||||||
|
|
||||||
|
# Função que calcula a distância entre dois centros de massa
|
||||||
|
# e por se tratar de uma função de dois atomos não deve ser
|
||||||
|
# inserida dentro de Molecule
|
||||||
|
def center_of_mass_distance(self, a, b):
|
||||||
|
|
||||||
|
com1 = self.molecule[a].center_of_mass()
|
||||||
|
com2 = self.molecule[b].center_of_mass()
|
||||||
|
dx = com1[0] - com2[0]
|
||||||
|
dy = com1[1] - com2[1]
|
||||||
|
dz = com1[2] - com2[2]
|
||||||
|
distance = math.sqrt(dx**2 + dy**2 + dz**2)
|
||||||
|
|
||||||
|
return distance
|
||||||
|
|
||||||
|
def minimum_distance(self, index1, index2):
|
||||||
|
|
||||||
|
distances = []
|
||||||
|
for atom1 in self.molecule[index1]:
|
||||||
|
if atom1.na != ghost_number:
|
||||||
|
for atom2 in self.molecule[index2]:
|
||||||
|
if atom2.na != ghost_number:
|
||||||
|
dx = atom1.rx - atom2.rx
|
||||||
|
dy = atom1.ry - atom2.ry
|
||||||
|
dz = atom1.rz - atom2.rz
|
||||||
|
distances.append(math.sqrt(dx**2 + dy**2 + dz**2))
|
||||||
|
|
||||||
|
return min(distances)
|
||||||
|
|
||||||
|
# Classe que conterá toda informação e funções relacionadas a uma unica molecula
|
||||||
|
|
||||||
class Molecule:
|
class Molecule:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self.atoms = [] # Lista de instancias de Atom
|
self.atom = [] # Lista de instancias de Atom
|
||||||
self.positions = None # Array Numpy
|
self.position = None # Array Numpy
|
||||||
self.energy = None # Array Numpy
|
self.energy = None # Array Numpy
|
||||||
self.gradient = None # Array Numpy
|
self.gradient = None # Array Numpy
|
||||||
self.hessian = None # Array Numpy
|
self.hessian = None # Array Numpy
|
||||||
|
self.total_mass = 0
|
||||||
|
|
||||||
def add_atom(self, a):
|
def add_atom(self, a):
|
||||||
|
|
||||||
self.atoms.append(a) # Inserção de um novo atomo
|
self.atom.append(a) # Inserção de um novo atomo
|
||||||
|
self.total_mass += a.mass
|
||||||
|
|
||||||
def center_of_mass(self):
|
def center_of_mass(self):
|
||||||
|
|
||||||
com = np.zeros(3)
|
com = np.zeros(3)
|
||||||
total_mass = 0.0
|
total_mass = 0.0
|
||||||
for atom in self.atoms:
|
|
||||||
|
for atom in self.atom:
|
||||||
|
|
||||||
total_mass += atom.mass
|
total_mass += atom.mass
|
||||||
com += atom.mass * np.array([atom.rx, atom.ry, atom.rz])
|
com += atom.mass * np.array([atom.rx, atom.ry, atom.rz])
|
||||||
|
|
||||||
@@ -33,6 +85,182 @@ class Molecule:
|
|||||||
|
|
||||||
return com
|
return com
|
||||||
|
|
||||||
|
def center_of_mass_to_origin(self):
|
||||||
|
|
||||||
|
com = self.center_of_mass()
|
||||||
|
|
||||||
|
for atom in self.atom:
|
||||||
|
|
||||||
|
atom.rx -= com[0]
|
||||||
|
atom.ry -= com[1]
|
||||||
|
atom.rz -= com[2]
|
||||||
|
|
||||||
|
def charges_and_dipole(self):
|
||||||
|
|
||||||
|
eA_to_Debye = 1/0.20819434
|
||||||
|
charge = 0
|
||||||
|
dipole = np.zeros(3)
|
||||||
|
for atom in self.atom:
|
||||||
|
position = np.array([ atom.rx, atom.ry, atom.rz ])
|
||||||
|
dipole += atom.chg * position
|
||||||
|
charge += atom.chg
|
||||||
|
|
||||||
|
dipole *= eA_to_Debye
|
||||||
|
total_dipole = math.sqrt(dipole[0]**2 + dipole[1]**2 + dipole[2]**2)
|
||||||
|
|
||||||
|
return [charge, dipole[0], dipole[1], dipole[2], total_dipole]
|
||||||
|
|
||||||
|
def distances_between_atoms(self):
|
||||||
|
|
||||||
|
distances = []
|
||||||
|
dim = len(self.atom)
|
||||||
|
for atom1 in self.atom:
|
||||||
|
if atom1.na != ghost_number:
|
||||||
|
for atom2 in self.atom:
|
||||||
|
if atom2.na != ghost_number:
|
||||||
|
dx = atom1.rx - atom2.rx
|
||||||
|
dy = atom1.ry - atom2.ry
|
||||||
|
dz = atom1.rz - atom2.rz
|
||||||
|
distances.append(math.sqrt(dx**2 + dy**2 + dz**2))
|
||||||
|
|
||||||
|
return np.array(distances).reshape(dim, dim)
|
||||||
|
|
||||||
|
def eixos(self):
|
||||||
|
|
||||||
|
eixos = np.zeros(3)
|
||||||
|
if len(self.atom) == 2:
|
||||||
|
|
||||||
|
position1 = np.array([ self.atom[0].rx, self.atom[0].ry, self.atom[0].rz ])
|
||||||
|
position2 = np.array([ self.atom[1].rx, self.atom[1].ry, self.atom[1].rz ])
|
||||||
|
eixos = position2 - position1
|
||||||
|
eixos /= linalg.norm(eixos)
|
||||||
|
|
||||||
|
elif len(self.atom) > 2:
|
||||||
|
|
||||||
|
position1 = np.array([ self.atom[0].rx, self.atom[0].ry, self.atom[0].rz ])
|
||||||
|
position2 = np.array([ self.atom[1].rx, self.atom[1].ry, self.atom[1].rz ])
|
||||||
|
position3 = np.array([ self.atom[2].rx, self.atom[2].ry, self.atom[2].rz ])
|
||||||
|
v1 = position2 - position1
|
||||||
|
v2 = position3 - position1
|
||||||
|
v3 = np.cross(v1, v2)
|
||||||
|
v2 = np.cross(v1, v3)
|
||||||
|
v1 /= linalg.norm(v1)
|
||||||
|
v2 /= linalg.norm(v2)
|
||||||
|
v3 /= linalg.norm(v3)
|
||||||
|
eixos = np.array([[v1[0], v1[1], v1[2]],
|
||||||
|
[v2[0], v2[1], v2[2]],
|
||||||
|
[v3[0], v3[1], v3[2]]])
|
||||||
|
|
||||||
|
return eixos
|
||||||
|
|
||||||
|
def inertia_tensor(self):
|
||||||
|
|
||||||
|
com = self.center_of_mass()
|
||||||
|
Ixx = Ixy = Ixz = Iyy = Iyz = Izz = 0.0
|
||||||
|
|
||||||
|
for atom in self.atom:
|
||||||
|
|
||||||
|
#### Obtain the displacement from the center of mass
|
||||||
|
dx = atom.rx - com[0]
|
||||||
|
dy = atom.ry - com[1]
|
||||||
|
dz = atom.rz - com[2]
|
||||||
|
#### Update the diagonal components of the tensor
|
||||||
|
Ixx += atom.mass * (dy**2 + dz**2)
|
||||||
|
Iyy += atom.mass * (dz**2 + dx**2)
|
||||||
|
Izz += atom.mass * (dx**2 + dy**2)
|
||||||
|
#### Update the off-diagonal components of the tensor
|
||||||
|
Ixy += atom.mass * dx * dy * -1
|
||||||
|
Ixz += atom.mass * dx * dz * -1
|
||||||
|
Iyz += atom.mass * dy * dz * -1
|
||||||
|
|
||||||
|
return np.array([ [Ixx, Ixy, Ixz],
|
||||||
|
[Ixy, Iyy, Iyz],
|
||||||
|
[Ixz, Iyz, Izz] ])
|
||||||
|
|
||||||
|
def principal_axes(self):
|
||||||
|
|
||||||
|
try:
|
||||||
|
evals, evecs = linalg.eigh(self.inertia_tensor())
|
||||||
|
except:
|
||||||
|
sys.exit("Error: diagonalization of inertia tensor did not converge")
|
||||||
|
|
||||||
|
return evals, evecs
|
||||||
|
|
||||||
|
def read_position(self):
|
||||||
|
|
||||||
|
position_list = []
|
||||||
|
for atom in self.atom:
|
||||||
|
position_list.extend([ atom.rx, atom.ry, atom.rz ])
|
||||||
|
position = np.array(position_list)
|
||||||
|
position *= ang2bohr
|
||||||
|
|
||||||
|
return position
|
||||||
|
|
||||||
|
def update_hessian(self, step, cur_gradient): ## According to the BFGS
|
||||||
|
|
||||||
|
dif_gradient = cur_gradient - self.gradient
|
||||||
|
|
||||||
|
mat1 = 1/np.dot(dif_gradient, step) * np.matmul(dif_gradient.T, dif_gradient)
|
||||||
|
mat2 = 1/np.dot(step, np.matmul(self.hessian, step.T).T)
|
||||||
|
mat2 *= np.matmul( np.matmul(self.hessian, step.T), np.matmul(step, hessian) )
|
||||||
|
|
||||||
|
self.hessian += mat1 - mat2
|
||||||
|
|
||||||
|
def sizes_of_molecule(self):
|
||||||
|
|
||||||
|
x_list = []
|
||||||
|
y_list = []
|
||||||
|
z_list = []
|
||||||
|
|
||||||
|
for atom in self.atom:
|
||||||
|
if atom.na != ghost_number:
|
||||||
|
x_list.append(atom.rx)
|
||||||
|
y_list.append(atom.ry)
|
||||||
|
z_list.append(atom.rz)
|
||||||
|
|
||||||
|
x_max = max(x_list)
|
||||||
|
x_min = min(x_list)
|
||||||
|
y_max = max(y_list)
|
||||||
|
y_min = min(y_list)
|
||||||
|
z_max = max(z_list)
|
||||||
|
z_min = min(z_list)
|
||||||
|
|
||||||
|
sizes = [x_max - x_min, y_max - y_min, z_max - z_min]
|
||||||
|
|
||||||
|
return sizes
|
||||||
|
|
||||||
|
def standard_orientation(self):
|
||||||
|
|
||||||
|
self.center_of_mass_to_origin()
|
||||||
|
tensor = self.inertia_tensor()
|
||||||
|
evals, evecs = self.principal_axes()
|
||||||
|
|
||||||
|
if round(linalg.det(evecs)) == -1:
|
||||||
|
evecs[0,2] *= -1
|
||||||
|
evecs[1,2] *= -1
|
||||||
|
evecs[2,2] *= -1
|
||||||
|
if round(linalg.det(evecs)) != 1:
|
||||||
|
sys.exit("Error: could not make a rotation matrix while adopting the standard orientation")
|
||||||
|
|
||||||
|
rot_matrix = evecs.T
|
||||||
|
for atom in self.atom:
|
||||||
|
position = np.array([ atom.rx, atom.ry, atom.rz ])
|
||||||
|
new_position = np.matmul(rot_matrix, position.T).T
|
||||||
|
atom.rx = new_position[0]
|
||||||
|
atom.ry = new_position[1]
|
||||||
|
atom.rz = new_position[2]
|
||||||
|
|
||||||
|
def translate(self, vector):
|
||||||
|
|
||||||
|
new_molecule = deepcopy(self)
|
||||||
|
|
||||||
|
for atom in new_molecule.atom:
|
||||||
|
|
||||||
|
atom.rx += vector[0]
|
||||||
|
atom.ry += vector[1]
|
||||||
|
atom.rz += vector[2]
|
||||||
|
|
||||||
|
return new_molecule
|
||||||
|
|
||||||
class Atom:
|
class Atom:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user