def check_rot_diffusion(self, n): """ The rotational diffusion tests based on the reference work [Perrin, F. (1936) Journal de Physique et Le Radium, 7(1), 1-11. https://doi.org/10.1051/jphysrad:01936007010100] with a theoretical background of [Perrin, F. (1934) Journal de Physique et Le Radium, 5(10), 497-511. https://doi.org/10.1051/jphysrad:01934005010049700] Parameters ---------- n : :obj:`int` Number of particles. """ # Global diffusivity tensor in the body frame: D = self.kT / self.gamma_global # Thermalizing... therm_steps = 100 self.system.integrator.run(therm_steps) # Measuring... # Set the initial conditions according to the [Perrin1936], p.3. # The body angular velocity is rotated now, but there is only the # thermal velocity, hence, this does not impact the test and its # physical context. for ind in range(n): self.system.part[ind].quat = [1.0, 0.0, 0.0, 0.0] # Average direction cosines # Diagonal ones: dcosjj_validate = np.zeros((3)) dcosjj_dev = np.zeros((3)) # same to the power of 2 dcosjj2_validate = np.zeros((3)) dcosjj2_dev = np.zeros((3)) # The non-diagonal elements for 2 different tests: negative ("nn") and # positive ("pp") ones. dcosijpp_validate = np.ones((3, 3)) dcosijpp_dev = np.zeros((3, 3)) dcosijnn_validate = np.ones((3, 3)) dcosijnn_dev = np.zeros((3, 3)) # The non-diagonal elements to the power of 2 dcosij2_validate = np.ones((3, 3)) dcosij2_dev = np.zeros((3, 3)) self.system.time = 0.0 int_steps = 20 loops = 100 for _ in range(loops): self.system.integrator.run(steps=int_steps) dcosjj = np.zeros((3)) dcosjj2 = np.zeros((3)) dcosijpp = np.zeros((3, 3)) dcosijnn = np.zeros((3, 3)) dcosij2 = np.zeros((3, 3)) for ind in range(n): # Just a direction cosines functions averaging.. dir_cos = tests_common.rotation_matrix_quat(self.system, ind) for j in range(3): # the LHS of eq. (23) [Perrin1936]. dcosjj[j] += dir_cos[j, j] # the LHS of eq. (32) [Perrin1936]. dcosjj2[j] += dir_cos[j, j]**2.0 for i in range(3): if i != j: # the LHS of eq. (24) [Perrin1936]. dcosijpp[i, j] += dir_cos[i, i] * dir_cos[j, j] + \ dir_cos[i, j] * dir_cos[j, i] # the LHS of eq. (25) [Perrin1936]. dcosijnn[i, j] += dir_cos[i, i] * dir_cos[j, j] - \ dir_cos[i, j] * dir_cos[j, i] # the LHS of eq. (33) [Perrin1936]. dcosij2[i, j] += dir_cos[i, j]**2.0 dcosjj /= n dcosjj2 /= n dcosijpp /= n dcosijnn /= n dcosij2 /= n # Actual comparison. tolerance = 0.2 # Too small values of the direction cosines are out of interest # compare to 0..1 range. min_value = 0.14 # Eq. (23) [Perrin1936]. dcosjj_validate[0] = np.exp(-(D[1] + D[2]) * self.system.time) dcosjj_validate[1] = np.exp(-(D[0] + D[2]) * self.system.time) dcosjj_validate[2] = np.exp(-(D[0] + D[1]) * self.system.time) dcosjj_dev = np.absolute( dcosjj - dcosjj_validate) / dcosjj_validate for j in range(3): if np.absolute(dcosjj_validate[j]) < min_value: dcosjj_dev[j] = 0.0 # Eq. (24) [Perrin1936]. dcosijpp_validate[0, 1] = np.exp( -(4 * D[2] + D[1] + D[0]) * self.system.time) dcosijpp_validate[1, 0] = np.exp( -(4 * D[2] + D[1] + D[0]) * self.system.time) dcosijpp_validate[0, 2] = np.exp( -(4 * D[1] + D[2] + D[0]) * self.system.time) dcosijpp_validate[2, 0] = np.exp( -(4 * D[1] + D[2] + D[0]) * self.system.time) dcosijpp_validate[1, 2] = np.exp( -(4 * D[0] + D[2] + D[1]) * self.system.time) dcosijpp_validate[2, 1] = np.exp( -(4 * D[0] + D[2] + D[1]) * self.system.time) dcosijpp_dev = np.absolute( dcosijpp - dcosijpp_validate) / dcosijpp_validate for i in range(3): for j in range(3): if np.absolute(dcosijpp_validate[i, j]) < min_value: dcosijpp_dev[i, j] = 0.0 # Eq. (25) [Perrin1936]. dcosijnn_validate[0, 1] = np.exp(-(D[1] + D[0]) * self.system.time) dcosijnn_validate[1, 0] = np.exp(-(D[1] + D[0]) * self.system.time) dcosijnn_validate[0, 2] = np.exp(-(D[2] + D[0]) * self.system.time) dcosijnn_validate[2, 0] = np.exp(-(D[2] + D[0]) * self.system.time) dcosijnn_validate[1, 2] = np.exp(-(D[2] + D[1]) * self.system.time) dcosijnn_validate[2, 1] = np.exp(-(D[2] + D[1]) * self.system.time) dcosijnn_dev = np.absolute( dcosijnn - dcosijnn_validate) / dcosijnn_validate for i in range(3): for j in range(3): if np.absolute(dcosijnn_validate[i, j]) < min_value: dcosijnn_dev[i, j] = 0.0 # Eq. (30) [Perrin1936]. D0 = sum(D[:]) / 3.0 D1D1 = 0.0 for j in range(3): for i in range(3): if i != j: D1D1 += D[i] * D[j] D1D1 /= 6.0 # Eq. (32) [Perrin1936]. dcosjj2_validate = 1. / 3. + (1. / 3.) * (1. + (D - D0) / (2. * np.sqrt(D0**2 - D1D1))) \ * np.exp(-6. * (D0 - np.sqrt(D0**2 - D1D1)) * self.system.time) \ + (1. / 3.) * (1. - (D - D0) / (2. * np.sqrt(D0**2 - D1D1))) \ * np.exp(-6. * (D0 + np.sqrt(D0**2 - D1D1)) * self.system.time) dcosjj2_dev = np.absolute( dcosjj2 - dcosjj2_validate) / dcosjj2_validate for j in range(3): if np.absolute(dcosjj2_validate[j]) < min_value: dcosjj2_dev[j] = 0.0 # Eq. (33) [Perrin1936]. dcosij2_validate[0, 1] = 1. / 3. - (1. / 6.) * (1. - (D[2] - D0) / (2. * np.sqrt(D0**2 - D1D1))) \ * np.exp(-6. * (D0 - np.sqrt(D0**2 - D1D1)) * self.system.time) \ - (1. / 6.) * (1. + (D[2] - D0) / (2. * np.sqrt(D0**2 - D1D1))) \ * np.exp(-6. * (D0 + np.sqrt(D0**2 - D1D1)) * self.system.time) dcosij2_validate[1, 0] = dcosij2_validate[0, 1] dcosij2_validate[0, 2] = 1. / 3. - (1. / 6.) * (1. - (D[1] - D0) / (2. * np.sqrt(D0**2 - D1D1))) \ * np.exp(-6. * (D0 - np.sqrt(D0**2 - D1D1)) * self.system.time) \ - (1. / 6.) * (1. + (D[1] - D0) / (2. * np.sqrt(D0**2 - D1D1))) \ * np.exp(-6. * (D0 + np.sqrt(D0**2 - D1D1)) * self.system.time) dcosij2_validate[2, 0] = dcosij2_validate[0, 2] dcosij2_validate[1, 2] = 1. / 3. - (1. / 6.) * (1. - (D[0] - D0) / (2. * np.sqrt(D0**2 - D1D1))) \ * np.exp(-6. * (D0 - np.sqrt(D0**2 - D1D1)) * self.system.time) \ - (1. / 6.) * (1. + (D[0] - D0) / (2. * np.sqrt(D0**2 - D1D1))) \ * np.exp(-6. * (D0 + np.sqrt(D0**2 - D1D1)) * self.system.time) dcosij2_validate[2, 1] = dcosij2_validate[1, 2] dcosij2_dev = np.absolute( dcosij2 - dcosij2_validate) / dcosij2_validate for i in range(3): for j in range(3): if np.absolute(dcosij2_validate[i, j]) < min_value: dcosij2_dev[i, j] = 0.0 for j in range(3): self.assertLessEqual( abs(dcosjj_dev[j]), tolerance, msg='Relative deviation dcosjj_dev[{0}] in a rotational ' 'diffusion is too large: {1}'.format(j, dcosjj_dev[j])) self.assertLessEqual( abs(dcosjj2_dev[j]), tolerance, msg='Relative deviation dcosjj2_dev[{0}] in a rotational ' 'diffusion is too large: {1}'.format(j, dcosjj2_dev[j])) for i in range(3): if i != j: self.assertLessEqual( abs(dcosijpp_dev[i, j]), tolerance, msg='Relative deviation dcosijpp_dev[{0},{1}] in a ' 'rotational diffusion is too large: {2}' .format(i, j, dcosijpp_dev[i, j])) self.assertLessEqual( abs(dcosijnn_dev[i, j]), tolerance, msg='Relative deviation dcosijnn_dev[{0},{1}] in a ' 'rotational diffusion is too large: {2}' .format(i, j, dcosijnn_dev[i, j])) self.assertLessEqual( abs(dcosij2_dev[i, j]), tolerance, msg='Relative deviation dcosij2_dev[{0},{1}] in a ' 'rotational diffusion is too large: {2}' .format(i, j, dcosij2_dev[i, j]))
def convert_vec_body_to_space(self, part, vec): A = tests_common.rotation_matrix_quat(self.system, part) return np.dot(A.transpose(), vec)