def dxy_dxi(x, y, coeff, qm, qu, dim): """ Function returning derivatives of intrinsic surface at position (x,y) wrt x and y Parameters ---------- x: float Coordinate in x dimension y: float Coordinate in y dimension coeff: float, array_like; shape=(n_waves**2) Optimised surface coefficients qm: int Maximum number of wave frequencies in Fourier Sum representing intrinsic surface qu: int Upper limit of wave frequencies in Fourier Sum representing intrinsic surface dim: float, array_like; shape=(3) XYZ dimensions of simulation cell Returns ------- dx_dxi: float Derivative of intrinsic surface in x dimension dy_dxi: float Derivative of intrinsic surface in y dimension """ if np.isscalar(x): u_array, v_array = wave_arrays(qm) indices = wave_indices(qu, u_array, v_array) wave_x = wave_function_array(x, u_array[indices], dim[0]) wave_y = wave_function_array(y, v_array[indices], dim[1]) wave_dx = d_wave_function_array(x, u_array[indices], dim[0]) wave_dy = d_wave_function_array(y, v_array[indices], dim[1]) dx_dxi = np.sum(wave_dx * wave_y * coeff[indices]) dy_dxi = np.sum(wave_x * wave_dy * coeff[indices]) else: dx_dxi = np.zeros(x.shape) dy_dxi = np.zeros(x.shape) for u in range(-qu, qu + 1): for v in range(-qu, qu + 1): j = (2 * qm + 1) * (u + qm) + (v + qm) wave_x = wave_function(x, u, dim[0]) wave_y = wave_function(y, v, dim[1]) wave_dx = d_wave_function(x, u, dim[0]) wave_dy = d_wave_function(y, v, dim[1]) dx_dxi += wave_dx * wave_y * coeff[j] dy_dxi += wave_x * wave_dy * coeff[j] return dx_dxi, dy_dxi
def update_A_b(xmol, ymol, zmol, dim, qm, new_pivot): """ Update A matrix and b vector for new pivot selection Parameters ---------- xmol: float, array_like; shape=(nmol) Molecular coordinates in x dimension ymol: float, array_like; shape=(nmol) Molecular coordinates in y dimension zmol: float, array_like; shape=(nmol) Molecular coordinates in z dimension dim: float, array_like; shape=(3) XYZ dimensions of simulation cell qm: int Maximum number of wave frequencies in Fouier Sum representing intrinsic surface n_waves: int Number of coefficients / waves in surface new_pivot: int, array_like Indices of new pivot molecules for both surfaces Returns ------- A: float, array_like; shape=(2, n_waves**2, n_waves**2) Matrix containing wave product weightings f(x, u1, Lx).f(y, v1, Ly).f(x, u2, Lx).f(y, v2, Ly) for each coefficient in the linear algebra equation Ax = b for both surfaces b: float, array_like; shape=(2, n_waves**2) Vector containing solutions z.f(x, u, Lx).f(y, v, Ly) to the linear algebra equation Ax = b for both surfaces """ n_waves = 2 * qm + 1 u_array, v_array = wave_arrays(qm) A = np.zeros((2, n_waves**2, n_waves**2)) b = np.zeros((2, n_waves**2)) fuv = np.zeros((2, n_waves**2, len(new_pivot[0]))) for surf in range(2): for index in range(n_waves**2): wave_x = wave_function(xmol[new_pivot[surf]], u_array[index], dim[0]) wave_y = wave_function(ymol[new_pivot[surf]], v_array[index], dim[1]) fuv[surf][index] = wave_x * wave_y b[surf][index] += np.sum(zmol[new_pivot[index]] * fuv[surf][index]) A[surf] += np.dot(fuv[surf], fuv[surf].T) return A, b, fuv
def H_xy(x, y, coeff, qm, qu, dim): """ H_xy(x, y, coeff, qm, qu, dim) Calculation of mean curvature at position (x,y) at resolution qu Parameters ---------- x: float Coordinate in x dimension y: float Coordinate in y dimension coeff: float, array_like; shape=(n_waves**2) Optimised surface coefficients qm: int Maximum number of wave frequencies in Fouier Sum representing intrinsic surface qu: int Upper limit of wave frequencies in Fouier Sum representing intrinsic surface dim: float, array_like; shape=(3) XYZ dimensions of simulation cell Returns ------- H: float Mean curvature of intrinsic surface at point x,y """ n_waves = 2 * qm + 1 if np.isscalar(x) and np.isscalar(y): u_array = np.array(np.arange(n_waves**2) / n_waves, dtype=int) - qm v_array = np.array(np.arange(n_waves**2) % n_waves, dtype=int) - qm wave_check = ((u_array >= -qu) * (u_array <= qu) * (v_array >= -qu) * (v_array <= qu)) indices = np.argwhere(wave_check).flatten() fuv = wave_function_array(x, u_array[indices], dim[0]) fuv *= wave_function_array(y, v_array[indices], dim[1]) H = -4 * np.pi**2 * np.sum( (u_array[indices]**2 / dim[0]**2 + v_array[indices]**2 / dim[1]**2) * fuv * coeff[indices]) else: H_array = np.zeros(x.shape) for u in range(-qu, qu + 1): for v in range(-qu, qu + 1): j = (2 * qm + 1) * (u + qm) + (v + qm) H_array += (wave_function(x, u, dim[0]) * wave_function(y, v, dim[1]) * (u**2 / dim[0]**2 + v**2 / dim[1]**2) * coeff[j]) H = -4 * np.pi**2 * H_array return H
def test_wave_function(self): self.assertEqual( 1.0, wave_function(0, 0, self.lx)) self.assertEqual( 1.0, wave_function(0, self.lx, self.lx)) self.assertEqual( 1.0, wave_function(self.lx, 0, self.lx)) self.assertEqual( 1.0, wave_function(self.lx, self.lx, self.lx)) self.assertEqual( -1.0, wave_function(1, self.lx / 2, self.lx)) self.assertEqual( 1.0, wave_function(2, self.lx / 2, self.lx))
def make_pos_dxdy(xmol, ymol, coeff, nmol, dim, qm): """ Calculate distances and derivatives at each molecular position with respect to intrinsic surface Parameters ---------- xmol: float, array_like; shape=(nmol) Molecular coordinates in x dimension ymol: float, array_like; shape=(nmol) Molecular coordinates in y dimension coeff: float, array_like; shape=(n_waves**2) Optimised surface coefficients nmol: int Number of molecules in simulation dim: float, array_like; shape=(3) XYZ dimensions of simulation cell qm: int Maximum number of wave frequencies in Fourier Sum representing intrinsic surface Returns ------- int_z_mol: array_like (float); shape=(nframe, 2, qm+1, nmol) Molecular distances from intrinsic surface int_dxdy_mol: array_like (float); shape=(nframe, 4, qm+1, nmol) First derivatives of intrinsic surface wrt x and y at xmol, ymol int_ddxddy_mol: array_like (float); shape=(nframe, 4, qm+1, nmol) Second derivatives of intrinsic surface wrt x and y at xmol, ymol """ int_z_mol = np.zeros((qm + 1, 2, nmol)) int_dxdy_mol = np.zeros((qm + 1, 4, nmol)) int_ddxddy_mol = np.zeros((qm + 1, 4, nmol)) tmp_int_z_mol = np.zeros((2, nmol)) tmp_dxdy_mol = np.zeros((4, nmol)) tmp_ddxddy_mol = np.zeros((4, nmol)) for qu in range(qm + 1): if qu == 0: j = (2 * qm + 1) * qm + qm f_x = wave_function(xmol, 0, dim[0]) f_y = wave_function(ymol, 0, dim[1]) tmp_int_z_mol[0] += f_x * f_y * coeff[0][j] tmp_int_z_mol[1] += f_x * f_y * coeff[1][j] else: for u in [-qu, qu]: for v in range(-qu, qu + 1): j = (2 * qm + 1) * (u + qm) + (v + qm) f_x = wave_function(xmol, u, dim[0]) f_y = wave_function(ymol, v, dim[1]) df_dx = d_wave_function(xmol, u, dim[0]) df_dy = d_wave_function(ymol, v, dim[1]) ddf_ddx = dd_wave_function(xmol, u, dim[0]) ddf_ddy = dd_wave_function(ymol, v, dim[1]) tmp_int_z_mol[0] += f_x * f_y * coeff[0][j] tmp_int_z_mol[1] += f_x * f_y * coeff[1][j] tmp_dxdy_mol[0] += df_dx * f_y * coeff[0][j] tmp_dxdy_mol[1] += f_x * df_dy * coeff[0][j] tmp_dxdy_mol[2] += df_dx * f_y * coeff[1][j] tmp_dxdy_mol[3] += f_x * df_dy * coeff[1][j] tmp_ddxddy_mol[0] += ddf_ddx * f_y * coeff[0][j] tmp_ddxddy_mol[1] += f_x * ddf_ddy * coeff[0][j] tmp_ddxddy_mol[2] += ddf_ddx * f_y * coeff[1][j] tmp_ddxddy_mol[3] += f_x * ddf_ddy * coeff[1][j] for u in range(-qu + 1, qu): for v in [-qu, qu]: j = (2 * qm + 1) * (u + qm) + (v + qm) f_x = wave_function(xmol, u, dim[0]) f_y = wave_function(ymol, v, dim[1]) df_dx = d_wave_function(xmol, u, dim[0]) df_dy = d_wave_function(ymol, v, dim[1]) ddf_ddx = dd_wave_function(xmol, u, dim[0]) ddf_ddy = dd_wave_function(ymol, v, dim[1]) tmp_int_z_mol[0] += f_x * f_y * coeff[0][j] tmp_int_z_mol[1] += f_x * f_y * coeff[1][j] tmp_dxdy_mol[0] += df_dx * f_y * coeff[0][j] tmp_dxdy_mol[1] += f_x * df_dy * coeff[0][j] tmp_dxdy_mol[2] += df_dx * f_y * coeff[1][j] tmp_dxdy_mol[3] += f_x * df_dy * coeff[1][j] tmp_ddxddy_mol[0] += ddf_ddx * f_y * coeff[0][j] tmp_ddxddy_mol[1] += f_x * ddf_ddy * coeff[0][j] tmp_ddxddy_mol[2] += ddf_ddx * f_y * coeff[1][j] tmp_ddxddy_mol[3] += f_x * ddf_ddy * coeff[1][j] int_z_mol[qu] += tmp_int_z_mol int_dxdy_mol[qu] += tmp_dxdy_mol int_ddxddy_mol[qu] += tmp_ddxddy_mol int_z_mol = np.swapaxes(int_z_mol, 0, 1) int_dxdy_mol = np.swapaxes(int_dxdy_mol, 0, 1) int_ddxddy_mol = np.swapaxes(int_ddxddy_mol, 0, 1) return int_z_mol, int_dxdy_mol, int_ddxddy_mol
def H_var_mol(xmol, ymol, coeff, qm, qu, dim): """ Variance of mean curvature H at molecular positions determined by coeff at resolution qu Parameters ---------- xmol: float, array_like; shape=(nmol) Molecular coordinates in x dimension ymol: float, array_like; shape=(nmol) Molecular coordinates in y dimension coeff: float, array_like; shape=(n_waves**2) Optimised surface coefficients qm: int Maximum number of wave frequencies in Fouier Sum representing intrinsic surface qu: int Upper limit of wave frequencies in Fouier Sum representing intrinsic surface dim: float, array_like; shape=(3) XYZ dimensions of simulation cell Returns ------- H_var: float Variance of mean curvature H at pivot points """ if qu == 0: return 0 n_waves = 2 * qm + 1 nmol = xmol.shape[0] # Create arrays of wave frequency indicies u and v u_array = np.array(np.arange(n_waves**2) / n_waves, dtype=int) - qm v_array = np.array(np.arange(n_waves**2) % n_waves, dtype=int) - qm wave_check = ((u_array >= -qu) * (u_array <= qu) * (v_array >= -qu) * (v_array <= qu)) indices = np.argwhere(wave_check).flatten() # Create matrix of wave frequency indicies (u, v)**2 u_matrix = np.tile(u_array[indices], (len([indices]), 1)) v_matrix = np.tile(v_array[indices], (len([indices]), 1)) # Make curvature diagonal terms of A matrix curve_diag = 16 * np.pi**4 * ( u_matrix**2 * u_matrix.T**2 / dim[0]**4 + v_matrix**2 * v_matrix.T**2 / dim[1]**4 + (u_matrix**2 * v_matrix.T**2 + u_matrix.T**2 * v_matrix**2) / (dim[0]**2 * dim[1]**2)) # Form the diagonal xi^2 terms and b vector solutions fuv = np.zeros((n_waves**2, nmol)) for u in range(-qu, qu + 1): for v in range(-qu, qu + 1): j = (2 * qm + 1) * (u + qm) + (v + qm) fuv[j] = (wave_function(xmol, u_array[j], dim[0]) * wave_function(ymol, v_array[j], dim[1])) ffuv = np.dot(fuv[indices], fuv[indices].T) coeff_matrix = np.tile(coeff[indices], (len([indices]), 1)) H_var = np.sum(coeff_matrix * coeff_matrix.T * ffuv * curve_diag / nmol) return H_var