Package lib :: Package structure :: Package represent :: Module rotor
[hide private]
[frames] | no frames]

Source Code for Module lib.structure.represent.rotor

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2013 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """Representations of a mechanical rotor.""" 
 24   
 25  # Python module imports. 
 26  from math import pi 
 27  from numpy import array, cross, dot, float64, transpose, zeros 
 28  from numpy.linalg import norm 
 29   
 30  # relax module imports. 
 31  from lib.geometry.lines import closest_point_ax 
 32  from lib.geometry.rotations import axis_angle_to_R 
 33   
 34   
35 -def rotor_pdb(structure=None, rotor_angle=None, axis=None, axis_pt=True, centre=None, span=2e-9, blade_length=5e-10, model=None, staggered=False):
36 """Create a PDB representation of a rotor motional model. 37 38 @keyword structure: The internal structural object instance to add the rotor to as a molecule. 39 @type structure: lib.structure.internal.object.Internal instance 40 @keyword rotor_angle: The angle of the rotor motion in radian. 41 @type rotor_angle: float 42 @keyword axis: The vector defining the rotor axis. 43 @type axis: numpy rank-1, 3D array 44 @keyword axis_pt: A point lying anywhere on the rotor axis. This is used to define the position of the axis in 3D space. 45 @type axis_pt: numpy rank-1, 3D array 46 @keyword centre: The central point of the representation. If this point is not on the rotor axis, then the closest point on the axis will be used for the centre. 47 @type centre: numpy rank-1, 3D array 48 @keyword span: The distance from the central point to the rotor blades (meters). 49 @type span: float 50 @keyword blade_length: The length of the representative rotor blades. 51 @type blade_length: float 52 @keyword model: The structural model number to add the rotor to. If not supplied, the same rotor structure will be added to all models. 53 @type model: int or None 54 @keyword staggered: A flag which if True will cause the rotor blades to be staggered. This is used to avoid blade overlap. 55 @type staggered: bool 56 """ 57 58 # Convert the arguments to numpy arrays, radians and Angstrom. 59 axis = array(axis, float64) 60 axis_pt = array(axis_pt, float64) 61 centre = array(centre, float64) 62 span = span * 1e10 63 blade_length = blade_length * 1e10 64 65 # Normalise. 66 axis_norm = axis / norm(axis) 67 68 # Add a structure. 69 structure.add_molecule(name='rotor') 70 71 # Loop over the models. 72 for model in structure.model_loop(model): 73 # Alias the single molecule from the single model. 74 mol = structure.get_molecule('rotor', model=model.num) 75 76 # The central point. 77 mid_point = closest_point_ax(line_pt=axis_pt, axis=axis, point=centre) 78 mol.atom_add(pdb_record='HETATM', atom_num=1, atom_name='CTR', res_name='AX', res_num=1, pos=mid_point, element='PT') 79 80 # Centre of the propellers. 81 prop1 = mid_point + axis_norm * span 82 prop1_index = 1 83 mol.atom_add(pdb_record='HETATM', atom_num=2, atom_name='PRP', res_name='PRC', res_num=2, pos=prop1, element='O') 84 mol.atom_connect(index1=0, index2=prop1_index) 85 86 # Centre of the propellers. 87 prop2 = mid_point - axis_norm * span 88 prop2_index = 2 89 mol.atom_add(pdb_record='HETATM', atom_num=3, atom_name='PRP', res_name='PRC', res_num=3, pos=prop2, element='O') 90 mol.atom_connect(index1=0, index2=prop2_index) 91 92 # Create the rotor propellers. 93 rotor_propellers(mol=mol, rotor_angle=rotor_angle, centre=prop1, axis=axis, blade_length=blade_length, staggered=staggered) 94 rotor_propellers(mol=mol, rotor_angle=rotor_angle, centre=prop2, axis=-axis, blade_length=blade_length, staggered=staggered)
95 96
97 -def rotor_propellers(mol=None, rotor_angle=None, centre=None, axis=None, blade_length=5.0, staggered=False):
98 """Create a PDB representation of a rotor motional model. 99 100 @keyword mol: The internal structural object molecule container to add the atoms to. 101 @type mol: MolContainer instance 102 @keyword rotor_angle: The angle of the rotor motion in radians. 103 @type rotor_angle: float 104 @keyword centre: The central point of the propeller. 105 @type centre: numpy rank-1, 3D array 106 @keyword axis: The vector defining the rotor axis. 107 @type axis: numpy rank-1, 3D array 108 @keyword blade_length: The length of the representative rotor blades in Angstrom. 109 @type blade_length: float 110 @keyword staggered: A flag which if True will cause the rotor blades to be staggered. This is used to avoid blade overlap. 111 @type staggered: bool 112 """ 113 114 # Init. 115 step_angle = 2.0 / 360.0 * 2.0 * pi 116 R = zeros((3, 3), float64) 117 res_num = mol.last_residue() + 1 118 119 # Blade vectors. 120 blades = zeros((4, 3), float64) 121 if abs(dot(axis, array([0, 0, 1], float64))) == 1.0: # Avoid failures in artificial situations. 122 blades[0] = cross(axis, array([1, 0, 0], float64)) 123 else: 124 blades[0] = cross(axis, array([0, 0, 1], float64)) 125 blades[0] = blades[0] / norm(blades[0]) 126 blades[1] = cross(axis, blades[0]) 127 blades[1] = blades[1] / norm(blades[1]) 128 blades[2] = -blades[0] 129 blades[3] = -blades[1] 130 131 # Create the 4 blades. 132 for i in range(len(blades)): 133 # Staggering. 134 if staggered and i % 2: 135 blade_origin = centre - axis * 2 136 137 # Non-staggered. 138 else: 139 blade_origin = centre 140 141 # Add an atom for the blage origin. 142 blade_origin_index = mol.atom_add(pdb_record='HETATM', atom_name='BLO', res_name='PRB', res_num=res_num, pos=blade_origin, element='O') 143 144 # The centre edge point of the blade. 145 mid_point = blade_origin + blades[i] * blade_length 146 mid_pt_index = mol.atom_add(pdb_record='HETATM', atom_name='BLD', res_name='PRB', res_num=res_num, pos=mid_point, element='N') 147 mol.atom_connect(index1=mid_pt_index, index2=blade_origin_index) 148 149 # Build the blade. 150 angle = 0.0 151 pos_last_index = mid_pt_index 152 neg_last_index = mid_pt_index 153 while True: 154 # Increase the angle. 155 angle += step_angle 156 157 # The edge rotation. 158 if angle > rotor_angle: 159 axis_angle_to_R(axis, rotor_angle, R) 160 161 # The normal rotation matrix. 162 else: 163 axis_angle_to_R(axis, angle, R) 164 165 # The positive edge. 166 pos_point = dot(R, mid_point - blade_origin) + blade_origin 167 pos_index = mol.atom_add(pdb_record='HETATM', atom_name='BLD', res_name='PRB', res_num=res_num, pos=pos_point, element='N') 168 mol.atom_connect(index1=pos_index, index2=pos_last_index) 169 mol.atom_connect(index1=pos_index, index2=blade_origin_index) 170 171 # The negative edge. 172 neg_point = dot(transpose(R), mid_point - blade_origin) + blade_origin 173 neg_index = mol.atom_add(pdb_record='HETATM', atom_name='BLD', res_name='PRB', res_num=res_num, pos=neg_point, element='N') 174 mol.atom_connect(index1=neg_index, index2=neg_last_index) 175 mol.atom_connect(index1=neg_index, index2=blade_origin_index) 176 177 # Update the indices. 178 pos_last_index = pos_index 179 neg_last_index = neg_index 180 181 # Finish. 182 if angle > rotor_angle: 183 break 184 185 # Increment the residue number. 186 res_num += 1
187