def test_wave_arrays(self): u_array, v_array = wave_arrays(1) self.assertArrayAlmostEqual( np.array([-1, -1, -1, 0, 0, 0, 1, 1, 1]), u_array ) self.assertArrayAlmostEqual( np.array([-1, 0, 1, -1, 0, 1, -1, 0, 1]), v_array ) u_array, v_array = wave_arrays(2) self.assertEqual((25,), u_array.shape) self.assertEqual((25,), v_array.shape)
def get_frequency_set(qm, qu, dim): """ Returns set of unique frequencies in Fourier series Parameters ---------- qm: int Maximum number of wave frequencies in Fourier Sum representing intrinsic surface dim: float, array_like; shape=(3) XYZ dimensions of simulation cell Returns ------- q_set: float, array_like Set of unique frequencies q2_set: float, array_like Set of unique frequencies to bin coefficients to """ u_array, v_array = wave_arrays(qm) indices = wave_indices(qu, u_array, v_array) q, q2 = calculate_frequencies(u_array[indices], v_array[indices], dim) q_set = np.unique(q)[1:] q2_set = np.unique(q2)[1:] return q_set, q2_set
def coeff_to_fourier(coeff, qm, dim): """ Returns Fouier coefficients for Fouier series representing intrinsic surface from linear algebra coefficients Parameters ---------- coeff: float, array_like; shape=(n_waves**2) Optimised linear algebra surface coefficients qm: int Maximum number of wave frequencies in Fouier Sum representing intrinsic surface Returns ------- f_coeff: float, array_like; shape=(n_waves**2) Optimised Fouier surface coefficients """ n_waves = 2 * qm + 1 u_array, v_array = wave_arrays(qm) frequencies, _ = calculate_frequencies(u_array, v_array, dim) amplitudes = np.zeros(coeff.shape, dtype=complex) for u in range(-qm, qm + 1): for v in range(-qm, qm + 1): index = n_waves * (u + qm) + (v + qm) j1 = n_waves * (abs(u) + qm) + (abs(v) + qm) j2 = n_waves * (-abs(u) + qm) + (abs(v) + qm) j3 = n_waves * (abs(u) + qm) + (-abs(v) + qm) j4 = n_waves * (-abs(u) + qm) + (-abs(v) + qm) if abs(u) + abs(v) == 0: value = coeff[j1] elif v == 0: value = (coeff[j1] - np.sign(u) * 1j * coeff[j2]) / 2. elif u == 0: value = (coeff[j1] - np.sign(v) * 1j * coeff[j3]) / 2. elif u < 0 and v < 0: value = (coeff[j1] + 1j * (coeff[j2] + coeff[j3]) - coeff[j4]) / 4. elif u > 0 and v > 0: value = (coeff[j1] - 1j * (coeff[j2] + coeff[j3]) - coeff[j4]) / 4. elif u < 0: value = (coeff[j1] + 1j * (coeff[j2] - coeff[j3]) + coeff[j4]) / 4. elif v < 0: value = (coeff[j1] - 1j * (coeff[j2] - coeff[j3]) + coeff[j4]) / 4. amplitudes[index] = value return amplitudes, frequencies
def xi_var(coeff, qm, qu): """Calculate average variance of surface heights Parameters ---------- coeff: float, array_like; shape=(n_frame, 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 Returns ------- calc_var: float Variance of surface heights across whole surface """ u_array, v_array = wave_arrays(qm) indices = wave_indices(qu, u_array, v_array) Psi = vcheck(u_array[indices], v_array[indices]) / 4. coeff_filter = coeff[:, :, indices] mid_point = len(indices) / 2 av_coeff = np.mean(coeff_filter[:, :, mid_point], axis=0) av_coeff_2 = np.mean(coeff_filter**2, axis=(0, 1)) * Psi calc_var = np.sum(av_coeff_2) - np.mean(av_coeff**2, axis=0) return calc_var
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 initialise_surface(qm, phi, dim): """ Calculate initial parameters for ISM Parameters ---------- qm: int Maximum number of wave frequencies in Fourier Sum representing intrinsic surface phi: float Weighting factor of minimum surface area term in surface optimisation function dim: float, array_like; shape=(3) XYZ dimensions of simulation cell Returns ------- coeff: array_like (float); shape=(n_waves**2) Optimised surface coefficients A: float, array_like; shape=(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=(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 area_diag: float, array_like; shape=(n_waves**2) Surface area diagonal terms for A matrix """ n_waves = 2*qm+1 # Form the diagonal xi^2 terms u_array, v_array = wave_arrays(qm) uv_check = vcheck(u_array, v_array) # Make diagonal terms of A matrix area_diag = phi * ( u_array**2 * dim[1] / dim[0] + v_array**2 * dim[0] / dim[1] ) area_diag = 4 * np.pi**2 * np.diagflat(area_diag * uv_check) # Create empty A matrix and b vector for linear algebra # equation Ax = b A = np.zeros((2, n_waves**2, n_waves**2)) b = np.zeros((2, n_waves**2)) coeff = np.zeros((2, n_waves**2)) return coeff, A, b, area_diag
def initialise_recon(qm, phi, dim): """ Calculate initial parameters for reconstructed ISM fitting procedure Parameters ---------- qm: int Maximum number of wave frequencies in Fourier Sum representing intrinsic surface phi: float Weighting factor of minimum surface area term in surface optimisation function dim: float, array_like; shape=(3) XYZ dimensions of simulation cell Returns ------- psi: float Weighting factor for surface reconstruction function curve_matrix: float, array_like; shape=(n_waves**2, n_waves**2) Surface curvature terms for A matrix H_var: float, array_like; shape=(n_waves**2) Diagonal terms for global variance of mean curvature """ psi = phi * dim[0] * dim[1] n_waves = 2 * qm + 1 "Form the diagonal xi^2 terms" u_array, v_array = wave_arrays(qm) uv_check = vcheck(u_array, v_array) u_matrix = np.tile(u_array, (n_waves**2, 1)) v_matrix = np.tile(v_array, (n_waves**2, 1)) H_var = 4 * np.pi**4 * uv_check * ( u_array**4 / dim[0]**4 + v_array**4 / dim[1]**4 + 2 * (u_array * v_array)**2 / np.prod(dim**2) ) curve_matrix = 16 * np.pi**4 * ( (u_matrix * u_matrix.T)**2 / dim[0]**4 + (v_matrix * v_matrix.T)**2 / dim[1]**4 + ((u_matrix * v_matrix.T)**2 + (u_matrix.T * v_matrix)**2) / np.prod(dim**2) ) return psi, curve_matrix, H_var
def surface_tension_coeff(coeff_2, qm, qu, dim, T): """ Returns spectrum of surface tension, corresponding to the frequencies in q2_set Parameters ---------- coeff_2: float, array_like; shape=(n_waves**2) Square of 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 T: float Average temperature of simulation (K) Returns ------- unique_q: float, array_like Set of frequencies for power spectrum histogram av_gamma: float, array_like Surface tension histogram of Fourier series frequencies """ u_array, v_array = wave_arrays(qm) indices = wave_indices(qu, u_array, v_array) q, q2 = calculate_frequencies(u_array[indices], v_array[indices], dim) int_A = dim[0] * dim[1] * q2 * coeff_2[indices] * vcheck( u_array[indices], v_array[indices]) / 4 gamma = con.k * T * 1E23 / int_A unique_q, av_gamma = filter_frequencies(q, gamma) return unique_q, av_gamma
def power_spectrum_coeff(coeff_2, qm, qu, dim): """ Returns power spectrum of average surface coefficients, corresponding to the frequencies in q2_set Parameters ---------- coeff_2: float, array_like; shape=(n_waves**2) Square of 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 ------- unique_q: float, array_like Set of frequencies for power spectrum histogram av_fourier: float, array_like Power spectrum histogram of Fourier series coefficients """ u_array, v_array = wave_arrays(qm) indices = wave_indices(qu, u_array, v_array) q, q2 = calculate_frequencies(u_array[indices], v_array[indices], dim) fourier = coeff_2[indices] / 4 * vcheck(u_array[indices], v_array[indices]) # Remove redundant frequencies unique_q, av_fourier = filter_frequencies(q, fourier) return unique_q, av_fourier
def intrinsic_area(coeff, qm, qu, dim): """ Calculate the intrinsic surface area from coefficients at resolution qu Parameters ---------- 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 ------- int_A: float Relative size of intrinsic surface area, compared to cell cross section XY """ u_array, v_array = wave_arrays(qm) indices = wave_indices(qu, u_array, v_array) q2 = np.pi**2 * (u_array[indices]**2 / dim[0]**2 + v_array[indices]**2 / dim[1]**2) int_A = q2 * coeff[indices]**2 * vcheck(u_array[indices], v_array[indices]) int_A = 1 + 0.5 * np.sum(int_A) return int_A