Пример #1
0
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
Пример #2
0
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
Пример #3
0
    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)))
Пример #4
0
    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)
Пример #5
0
    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)))
Пример #6
0
    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)
Пример #7
0
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
Пример #8
0
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
Пример #9
0
    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)))
Пример #10
0
    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)))
Пример #11
0
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
Пример #12
0
    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)
Пример #13
0
    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)
Пример #14
0
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