from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
#from __future__ import unicode_literals
'''
SASMOL: Copyright (C) 2011 Joseph E. Curtis, Ph.D.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''
import sys
import numpy
import sasmol as sasmol
import sasmol.linear_algebra as linear_algebra
# OPERATE
#
# 12/13/2009 -- initial coding : jc
# 07/23/2016 -- refactored for release : jc
# 07/23/2016 -- refactored for Python 3 : jc
#
# 1 2 3 4 5 6 7
# LC4567890123456789012345678901234567890123456789012345678901234567890123456789
# * **
'''
Operate contains the classes and methods to perform the basic
translation, rotation, and alignment operations on instances of objects
described in the sasmol module.
The methods in this class move entire objects, not pieces
of single objects (i.e. no intra-object movements)
'''
[docs]class Move():
""" Base class containing methods to perform basic translation, rotation,
and alignment operations on instances of system objects.
The methods in this class move entire objects, not pieces
of single objects (i.e. no intra-object movements)
Examples
========
First example shows how to use class methods from system object:
>>> import sasmol.system as system ; import math
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> frame = 0 ; axis = 'x' ; theta = 45.0 * math.pi / 180.0
>>> molecule.rotate(frame, axis, theta)
Second example shows how to use class methods directly:
>>> import sasmol.system as system ; import math
>>> import sasmol.operate as operate
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> frame = 0 ; axis = 'x' ; theta = 45.0 * math.pi / 180.0
>>> operate.Move.rotate(molecule, frame, axis, theta)
Note
----
`self` parameter is not shown in the ``Parameters`` section in the documentation
"""
'''
moveto moves the COM to a point in space (x,y,z)
'''
[docs] def mass_check(self, **kwargs):
'''
Note
----
mass_check determines if mass is defined for the object so that
center of mass can be calculated
Parameters
----------
kwargs
optional future arguments
Returns
-------
None
updated self._total_mass
Examples
-------
>>> import sasmol.system as system
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> molecule.mass_check()
'''
if(self._total_mass <= 0.0):
self.calculate_mass()
return
[docs] def translate(self, frame, value, **kwargs):
'''
translate moves the object
Parameters
----------
frame
integer : trajectory frame number to use
value
list of x, y, z float values
kwargs
point = True : will translate to a fixed point
given by value variable
Returns
-------
None
updated self._coor and self._center_of_mass
Examples
-------
>>> import sasmol.system as system
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> frame = 0
>>> molecule.calculate_center_of_mass(frame)
array([ -6.79114736, -23.71577133, 8.06558513])
>>> displacement = [3.0, 4.0, 5.0]
>>> molecule.translate(frame, displacement)
>>> molecule.calculate_center_of_mass(frame)
array([ -3.79114736, -19.71577133, 13.06558513])
>>> import sasmol.system as system
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> frame = 0
>>> final_position = [3.0, 4.0, 5.0]
>>> molecule.translate(frame, final_position, point=True)
>>> molecule.calculate_center_of_mass(frame)
array([ 3., 4., 5.])
Note
----------
mass_check is called to validate self._total_mass()
'''
try:
point_flag = kwargs['point']
except:
point_flag = False
self.mass_check()
if point_flag:
self._com = self.calculate_center_of_mass(frame)
self._coor[frame, :, 0] -= self._com[0]
self._coor[frame, :, 1] -= self._com[1]
self._coor[frame, :, 2] -= self._com[2]
self._coor[frame, :, 0] += value[0]
self._coor[frame, :, 1] += value[1]
self._coor[frame, :, 2] += value[2]
self._com = self.calculate_center_of_mass(frame)
return
[docs] def center(self, frame, **kwargs):
'''
Method moves the center of mass of object to [0.0, 0.0, 0.0]
Parameters
----------
frame
integer : trajectory frame number to use
kwargs
optional future arguments
Returns
-------
None
updated self._coor and self._center_of_mass
Examples
-------
>>> import sasmol.system as system
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> frame = 0
>>> molecule.calculate_center_of_mass(frame)
array([ -6.79114736, -23.71577133, 8.06558513])
>>> molecule.center(frame)
>>> molecule.calculate_center_of_mass(frame)
array([ 7.11544707e-13, 2.48159571e-12, -8.45832820e-13])
Note
----------
mass_check is called to validate self._total_mass()
Can achieve same result using self.translate(frame, [0,0,0], point=True)
'''
self.mass_check()
self._com = self.calculate_center_of_mass(frame)
self._coor[frame, :, 0] = self._coor[frame, :, 0] - self._com[0]
self._coor[frame, :, 1] = self._coor[frame, :, 1] - self._com[1]
self._coor[frame, :, 2] = self._coor[frame, :, 2] - self._com[2]
self._com = self.calculate_center_of_mass(frame)
return
[docs] def align(self, other, self_basis, other_basis, **kwargs):
'''
Alignment of one object on top of another
"self" is aligned onto "other" using the basis
of molecule 2 to align onto the basis of molecule 1
and the transformation is then done to all the atoms of
molecule 2
self = molecule_2
other = molecule_1
self aligned to other
molecule_2 aligned to molecule_1
Parameters
----------
frame
integer : trajectory frame number to use
other
system object : molecule 1
self_basis
string : unique description of atoms used for alignment
other_basis
string : unique description of atoms used for alignment
kwargs
optional future arguments
Returns
-------
None
updated self._coor
Examples
-------
>>> import sasmol.system as system
>>> molecule_1 = system.Molecule('hiv1_gag.pdb')
>>> molecule_2 = system.Molecule('moved_and_rotated_hiv1_gag.pdb')
>>> frame = 0
>>> basis_1 = 'name[i] == "CA"'
>>> basis_2 = 'name[i] == "CA"'
>>> molecule_2.align(molecule_1, basis_1, basis_2)
>>> com_sub_2 = molecule_2.calculate_center_of_mass(frame)
Note
----
mass_check determines if mass is defined for the object so that
center of mass can be calculated
'''
frame = 0
### other = molecule_1 (reference)
error, other_mask = other.get_subset_mask(other_basis)
subset_other = sasmol.system.Molecule()
error = other.copy_molecule_using_mask(subset_other, other_mask, frame)
com_subset_other = subset_other.calculate_center_of_mass(frame)
subset_other.center(frame)
coor_subset_other = subset_other.coor()[frame]
### self = molecule_2 (to be aligned to other / molecule_1)
error, self_mask = self.get_subset_mask(self_basis)
subset_self = sasmol.system.Molecule()
error = self.copy_molecule_using_mask(subset_self, self_mask, frame)
com_subset_self = subset_self.calculate_center_of_mass(frame)
subset_self.center(frame)
coor_subset_self = subset_self.coor()[frame]
u = linear_algebra.find_u(coor_subset_self, coor_subset_other)
tao = numpy.transpose(self.coor()[frame] - com_subset_other)
error, nat2 = linear_algebra.matrix_multiply(u, tao)
ncoor = numpy.transpose(nat2) + com_subset_other
self._coor[frame, :] = ncoor
return
[docs] def rotate(self, frame, axis, theta, **kwargs):
'''
Simple rotation about the x, y, or z axis.
Parameters
----------
frame
integer : trajectory frame number to use
axis
string : 'x', 'y', or 'z'
theta
float : angle in radians
kwargs
optional future arguments
Returns
-------
None
updated self._coor
Examples
-------
>>> import sasmol.system as system ; import math
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> frame = 0 ; axis = 'x' ; theta = 45.0 * math.pi / 180.0
>>> molecule.rotate(frame, axis, theta)
Note
----------
Calculations are carried out using radians
'''
cs = numpy.cos(theta)
si = numpy.sin(theta)
if(axis == 'x'):
mat = numpy.array(
[[1.0, 0.0, 0.0], [0.0, cs, -si], [0.0, si, cs]])
elif(axis == 'y'):
mat = numpy.array(
[[cs, 0.0, si], [0.0, 1.0, 0.0], [-si, 0.0, cs]])
elif(axis == 'z'):
mat = numpy.array(
[[cs, -si, 0.0], [si, cs, 0.0], [0.0, 0.0, 1.0]])
coordt = self._coor[frame, :].T
error, matrix_product = linear_algebra.matrix_multiply(mat, coordt)
ncoord = matrix_product.T
self._coor[frame, :] = ncoord
return
[docs] def rotate_general_axis(self, frame, theta, unit_axis, **kwargs):
'''
The general rotation of a molecule along an arbitrarily
given unit axis (ux,uy,uz) by an angle theta.
Parameters
----------
frame
integer : trajectory frame number to use
theta
float : angle in radians
unit_axis
float : [ux, uy, uz] components of unit axis
kwargs
optional future arguments
Returns
-------
None
updated self._coor
Examples
-------
>>> import sasmol.system as system ; import math
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> frame = 0 ; theta = 45.0 * math.pi / 180.0
>>> unit_axis = [ 0.2, 1.3, -3.5 ]
>>> molecule.rotate_general_axis(frame, theta, unit_axis)
Note
----------
Calculations are carried out using radians
'''
ux = unit_axis[0]
uy = unit_axis[1]
uz = unit_axis[2]
c11 = numpy.cos(theta) + pow(ux, 2) * (1 - numpy.cos(theta))
c12 = ux * uy * (1 - numpy.cos(theta)) - uz * numpy.sin(theta)
c13 = ux * uz * (1 - numpy.cos(theta)) + uy * numpy.sin(theta)
c21 = uy * ux * (1 - numpy.cos(theta)) + uz * numpy.sin(theta)
c22 = numpy.cos(theta) + pow(uy, 2) * (1 - numpy.cos(theta))
c23 = uy * uz * (1 - numpy.cos(theta)) - ux * numpy.sin(theta)
c31 = uz * ux * (1 - numpy.cos(theta)) - uy * numpy.sin(theta)
c32 = uz * uy * (1 - numpy.cos(theta)) + ux * numpy.sin(theta)
c33 = numpy.cos(theta) + pow(uz, 2) * (1 - numpy.cos(theta))
C = numpy.matrix(
[[c11, c12, c13], [c21, c22, c23], [c31, c32, c33]])
coor = numpy.array(self.coor()[frame] * C)
self.coor()[frame, :] = coor
return
[docs] def rotate_euler(self, frame, phi, theta, psi, **kwargs):
'''
Rotate the molecule by a euler angle set (phi,theta,psi)
Parameters
----------
frame
integer : trajectory frame number to use
phi
float : phi angle
theta
float : theta angle
psi
float : psi angle
kwargs
optional future arguments
Returns
-------
None
updated self._coor
Examples
-------
>>> import sasmol.system as system ; import math
>>> molecule = system.Molecule('hiv1_gag.pdb')
>>> frame = 0
>>> phi = 45.0 * math.pi / 180.0
>>> theta = 45.0 * math.pi / 180.0
>>> psi = 32.0 * math.pi / 180.0
>>> molecule.euler_rotate(frame, phi, theta, psi)
Note
----------
Calculations are carried out using radians
'''
c11 = numpy.cos(theta) * numpy.cos(psi)
c12 = numpy.cos(phi) * numpy.sin(psi) + \
numpy.sin(phi) * numpy.sin(theta) * numpy.cos(psi)
c13 = numpy.sin(phi) * numpy.sin(psi) - \
numpy.cos(phi) * numpy.sin(theta) * numpy.cos(psi)
c21 = -numpy.cos(theta) * numpy.sin(psi)
c22 = numpy.cos(phi) * numpy.cos(psi) - \
numpy.sin(phi) * numpy.sin(theta) * numpy.sin(psi)
c23 = numpy.sin(phi) * numpy.cos(psi) + \
numpy.cos(phi) * numpy.sin(theta) * numpy.sin(psi)
c31 = numpy.sin(theta)
c32 = -numpy.sin(phi) * numpy.cos(theta)
c33 = numpy.cos(phi) * numpy.cos(theta)
C = numpy.matrix(
[[c11, c12, c13], [c21, c22, c23], [c31, c32, c33]])
coor = numpy.array(self.coor()[frame] * C)
self.coor()[frame, :] = coor
return