def pcs_pivot_motion_rotor_qr_int(full_in_ref_frame=None, r_pivot_atom=None, r_pivot_atom_rev=None, r_ln_pivot=None, A=None, Ri=None, pcs_theta=None, pcs_theta_err=None, missing_pcs=None): """Calculate the PCS value after a pivoted motion for the rotor model. @keyword full_in_ref_frame: An array of flags specifying if the tensor in the reference frame is the full or reduced tensor. @type full_in_ref_frame: numpy rank-1 array @keyword r_pivot_atom: The pivot point to atom vector. @type r_pivot_atom: numpy rank-2, 3D array @keyword r_pivot_atom_rev: The reversed pivot point to atom vector. @type r_pivot_atom_rev: numpy rank-2, 3D array @keyword r_ln_pivot: The lanthanide position to pivot point vector. @type r_ln_pivot: numpy rank-2, 3D array @keyword A: The full alignment tensor of the non-moving domain. @type A: numpy rank-2, 3D array @keyword Ri: The frame-shifted, pre-calculated rotation matrix for state i. @type Ri: numpy rank-2, 3D array @keyword pcs_theta: The storage structure for the back-calculated PCS values. @type pcs_theta: numpy rank-2 array @keyword pcs_theta_err: The storage structure for the back-calculated PCS errors. @type pcs_theta_err: numpy rank-2 array @keyword missing_pcs: A structure used to indicate which PCS values are missing. @type missing_pcs: numpy rank-2 array """ # Pre-calculate all the new vectors. rot_vect = dot(r_pivot_atom, Ri) + r_ln_pivot # The vector length (to the 5th power). length = 1.0 / norm(rot_vect, axis=1)**5 # The reverse vectors and lengths. if min(full_in_ref_frame) == 0: rot_vect_rev = dot(r_pivot_atom_rev, Ri) + r_ln_pivot length_rev = 1.0 / norm(rot_vect_rev, axis=1)**5 # Loop over the atoms. for j in range(len(r_pivot_atom[:, 0])): # Loop over the alignments. for i in range(len(pcs_theta)): # Skip missing data. if missing_pcs[i, j]: continue # The projection. if full_in_ref_frame[i]: proj = dot(rot_vect[j], dot(A[i], rot_vect[j])) length_i = length[j] else: proj = dot(rot_vect_rev[j], dot(A[i], rot_vect_rev[j])) length_i = length_rev[j] # The PCS. pcs_theta[i, j] += proj * length_i
def build_axes_pivot_com(self): """A standard axis system for the CaM system with the z-axis along the pivot-com axis.""" # The z-axis for the rotations (the pivot point to CoM axis). axis_z = self.COM - self.PIVOT axis_z = axis_z / norm(axis_z) # The y-axis (to check the torsion angle). axis_y = cross(axis_z, array([0, 0, 1])) axis_y = axis_y / norm(axis_y) # The x-axis. axis_x = cross(axis_y, axis_z) axis_x = axis_x / norm(axis_x) # The eigenframe. self.axes = transpose(array([axis_x, axis_y, axis_z])) alpha, beta, gamma = R_to_euler_zyz(self.axes) # Printout. print("CoM-pivot axis: %s, norm = %s" % (repr(axis_z), norm(axis_z))) print("Rotation axis: %s, norm = %s" % (repr(self.axes[:, 2]), norm(self.axes[:, 2]))) print("Full axis system:\n%s" % self.axes) print("Full axis system Euler angles:\n\talpha: %s\n\tbeta: %s\n\tgamma: %s" % (repr(alpha), repr(beta), repr(gamma)))
def axes_to_pdb_full(self): """Create a PDB for the motional axis system.""" # Create a data pipe for the data. self.interpreter.pipe.create('axes', 'N-state') # The end points of the vectors. end_pt_x = self.axes[:, 0] * norm(self.COM - self.PIVOT) + self.PIVOT end_pt_y = self.axes[:, 1] * norm(self.COM - self.PIVOT) + self.PIVOT end_pt_z = self.axes[:, 2] * norm(self.COM - self.PIVOT) + self.PIVOT # Add atoms for the system. self.interpreter.structure.add_atom(atom_name='C', res_name='AXE', res_num=1, pos=self.PIVOT, element='C') self.interpreter.structure.add_atom(atom_name='N', res_name='AXE', res_num=1, pos=end_pt_x, element='N') self.interpreter.structure.add_atom(atom_name='N', res_name='AXE', res_num=1, pos=end_pt_y, element='N') self.interpreter.structure.add_atom(atom_name='N', res_name='AXE', res_num=1, pos=end_pt_z, element='N') # Connect the atoms to form the vectors. self.interpreter.structure.connect_atom(index1=0, index2=1) self.interpreter.structure.connect_atom(index1=0, index2=2) self.interpreter.structure.connect_atom(index1=0, index2=3) # Write out the PDB. self.interpreter.structure.write_pdb('axis.pdb', dir=self.save_path, compress_type=0, force=True)
def pcs_pivot_motion_rotor_quad_int(sigma_i, r_pivot_atom, r_ln_pivot, A, R_eigen, RT_eigen, Ri_prime): """Calculate the PCS value after a pivoted motion for the rotor model. @param sigma_i: The rotor angle for state i. @type sigma_i: float @param r_pivot_atom: The pivot point to atom vector. @type r_pivot_atom: numpy rank-1, 3D array @param r_ln_pivot: The lanthanide position to pivot point vector. @type r_ln_pivot: numpy rank-1, 3D array @param A: The full alignment tensor of the non-moving domain. @type A: numpy rank-2, 3D array @param R_eigen: The eigenframe rotation matrix. @type R_eigen: numpy rank-2, 3D array @param RT_eigen: The transpose of the eigenframe rotation matrix (for faster calculations). @type RT_eigen: numpy rank-2, 3D array @param Ri_prime: The empty rotation matrix for the in-frame rotor motion for state i. @type Ri_prime: numpy rank-2, 3D array @return: The PCS value for the changed position. @rtype: float """ # The rotation matrix. c_sigma = cos(sigma_i) s_sigma = sin(sigma_i) Ri_prime[0, 0] = c_sigma Ri_prime[0, 1] = -s_sigma Ri_prime[1, 0] = s_sigma Ri_prime[1, 1] = c_sigma # The rotation. R_i = dot(R_eigen, dot(Ri_prime, RT_eigen)) # Calculate the new vector. vect = dot(R_i, r_pivot_atom) + r_ln_pivot # The vector length. length = norm(vect) # The projection. proj = dot(vect, dot(A, vect)) # The PCS. pcs = proj / length**5 # Return the PCS value (without the PCS constant). return pcs
def build_axes_alt(self): """An alternative axis system for the CaM system.""" # The z-axis for the rotations (the pivot point to CoM axis). axis_z = self.COM - self.PIVOT axis_z = axis_z / norm(axis_z) # The y-axis (to check the torsion angle). axis_y = cross(axis_z, array([0, 0, 1])) axis_y = axis_y / norm(axis_y) # The x-axis. axis_x = cross(axis_y, axis_z) axis_x = axis_x / norm(axis_x) # The eigenframe. axes = transpose(array([axis_x, axis_y, axis_z])) # Init a rotation matrix. R = zeros((3, 3), float64) # Tilt the axes system by x degrees. tilt_axis = cross(axis_z, array([0, 0, 1])) tilt_axis = tilt_axis / norm(tilt_axis) axis_angle_to_R(tilt_axis, self.TILT_ANGLE * 2.0 * pi / 360.0, R) # Rotate the eigenframe. self.axes = dot(R, axes) alpha, beta, gamma = R_to_euler_zyz(self.axes) # Printout. print("Tilt axis: %s, norm = %s" % (repr(tilt_axis), norm(tilt_axis))) print("CoM-pivot axis: %s, norm = %s" % (repr(axis_z), norm(axis_z))) print("Rotation axis: %s, norm = %s" % (repr(self.axes[:, 2]), norm(self.axes[:, 2]))) print("Full axis system:\n%s" % self.axes) print("Full axis system Euler angles:\n\talpha: %s\n\tbeta: %s\n\tgamma: %s" % (repr(alpha), repr(beta), repr(gamma)))
def pcs_pivot_motion_double_rotor_quad_int(sigma_i, sigma2_i, r_pivot_atom, r_ln_pivot, r_inter_pivot, A, R_eigen, RT_eigen, Ri_prime, Ri2_prime): """Calculate the PCS value after a pivoted motion for the double rotor model. @param sigma_i: The 1st torsion angle for state i. @type sigma_i: float @param sigma2_i: The 1st torsion angle for state i. @type sigma2_i: float @param r_pivot_atom: The pivot point to atom vector. @type r_pivot_atom: numpy rank-2, 3D array @param r_ln_pivot: The lanthanide position to pivot point vector. @type r_ln_pivot: numpy rank-2, 3D array @param r_inter_pivot: The vector between the two pivots. @type r_inter_pivot: numpy rank-1, 3D array @param A: The full alignment tensor of the non-moving domain. @type A: numpy rank-2, 3D array @param R_eigen: The eigenframe rotation matrix. @type R_eigen: numpy rank-2, 3D array @param RT_eigen: The transpose of the eigenframe rotation matrix (for faster calculations). @type RT_eigen: numpy rank-2, 3D array @param Ri_prime: The empty rotation matrix for state i. @type Ri_prime: numpy rank-2, 3D array @param Ri2_prime: The 2nd empty rotation matrix for state i. @type Ri2_prime: numpy rank-2, 3D array @return: The PCS value for the changed position. @rtype: float """ # The 1st rotation matrix. c_sigma = cos(sigma_i) s_sigma = sin(sigma_i) Ri_prime[0, 0] = c_sigma Ri_prime[0, 2] = s_sigma Ri_prime[2, 0] = -s_sigma Ri_prime[2, 2] = c_sigma # The 2nd rotation matrix. c_sigma = cos(sigma2_i) s_sigma = sin(sigma2_i) Ri2_prime[1, 1] = c_sigma Ri2_prime[1, 2] = -s_sigma Ri2_prime[2, 1] = s_sigma Ri2_prime[2, 2] = c_sigma # The rotations. Ri = dot(R_eigen, dot(Ri_prime, RT_eigen)) Ri2 = dot(R_eigen, dot(Ri2_prime, RT_eigen)) # Rotate the first pivot to atomic position vectors. rot_vect = dot(r_pivot_atom, Ri) # Add the inter-pivot vector to obtain the 2nd pivot to atomic position vectors. add(r_inter_pivot, rot_vect, rot_vect) # Rotate the 2nd pivot to atomic position vectors. rot_vect = dot(rot_vect, Ri2) # Add the lanthanide to pivot vector. add(rot_vect, r_ln_pivot, rot_vect) # The vector length. length = norm(rot_vect) # The projection. proj = dot(rot_vect, dot(A, rot_vect)) # The PCS. pcs = proj / length**5 # Return the PCS value (without the PCS constant). return pcs
def _calculate_pcs(self): """Calculate the averaged PCS for all states.""" # Printout. sys.stdout.write("\n\nRotating %s states for the PCS:\n\n" % locale.format("%d", self.N**self.MODES, grouping=True)) # Turn off the relax interpreter echoing to allow the progress meter to be shown correctly. self.interpreter.off() # Set up some data structures for faster calculations. spins = [] spin_pos = [] d = {} for tag in self._tensors: d[tag] = [] for spin in spin_loop(): # Nothing to do. if not hasattr(spin, 'pos'): continue # Initialise the PCS structure (as a 1D numpy.float128 array for speed and minimising truncation artifacts). spin.pcs = {} for tag in self._tensors: spin.pcs[tag] = zeros(1, float128) # Pack the spin containers and positions. spins.append(spin) spin_pos.append(spin.pos[0]) # Calculate the partial PCS constant (with no vector length). for tag in self._tensors: d[tag].append(pcs_constant(cdp.temperature[tag], cdp.spectrometer_frq[tag] * 2.0 * pi / periodic_table.gyromagnetic_ratio('1H'), 1.0)) # Repackage the data for speed. spin_pos = array(spin_pos, float64) num_spins = len(spin_pos) for tag in self._tensors: d[tag] = array(d[tag], float64) # Store the alignment tensors. A = [] for i in range(len(self._tensors)): A.append(cdp.align_tensors[i].A) # Loop over each position. for global_index, mode_indices in self._state_loop(): # The progress meter. self._progress(global_index) # Data initialisation. new_pos = spin_pos # Loop over each motional mode. for motion_index in range(self.MODES): # Generate the distribution specific rotation. self.rotation(mode_indices[motion_index], motion_index=motion_index) # Rotate the atomic positions. new_pos = transpose(tensordot(self.R, transpose(new_pos - self.PIVOT[motion_index]), axes=1)) + self.PIVOT[motion_index] # The vectors. vectors = new_pos - cdp.paramagnetic_centre # The lengths. r = norm(vectors, axis=1) # The scaling factor that includes the Angstrom to meter converted length cubed and the ppm conversion. fact = 1e6 / (r / 1e10)**3 # Normalise. vectors = transpose(vectors) / r # Loop over each alignment. for i in range(len(self._tensors)): # Calculate the PCS as quickly as possible (the 1e36 is from the 1e10**3 Angstrom conversion and the 1e6 ppm conversion). pcss = d[self._tensors[i]] * fact * tensordot(transpose(vectors), tensordot(A[i], vectors, axes=1), axes=1) # Store the values. for j in range(len(spins)): spins[j].pcs[self._tensors[i]][0] += pcss[j, j] # Print out. sys.stdout.write('\n\n') # Reactive the interpreter echoing. self.interpreter.on() # Average the PCS and write the data. for tag in self._tensors: # Average. for spin in spin_loop(): spin.pcs[tag] = spin.pcs[tag][0] / self.N**self.MODES # Save. self.interpreter.pcs.write(align_id=tag, file='pcs_%s.txt'%tag, dir=self.save_path, force=True)