def __init__(self, gd, scale=1.0, n=1, dtype=float, k2=0.0): """Helmholtz for general non orthorhombic grid. gd: GridDescriptor Descriptor for grid. scale: float Scaling factor. Use scale=-0.5 for a kinetic energy operator. n: int Range of stencil. Stencil has O(h^(2n)) error. dtype: float or complex Datatype to work on. """ # Order the 13 neighbor grid points: M_ic = np.indices((3, 3, 3)).reshape((3, -3)).T[-13:] - 1 u_cv = gd.h_cv / (gd.h_cv**2).sum(1)[:, np.newaxis]**0.5 u2_i = (np.dot(M_ic, u_cv)**2).sum(1) i_d = u2_i.argsort() m_mv = np.array([(2, 0, 0), (0, 2, 0), (0, 0, 2), (0, 1, 1), (1, 0, 1), (1, 1, 0)]) # Try 3, 4, 5 and 6 directions: for D in range(3, 7): h_dv = np.dot(M_ic[i_d[:D]], gd.h_cv) A_md = (h_dv**m_mv[:, np.newaxis, :]).prod(2) a_d, residual, rank, s = np.linalg.lstsq(A_md, [1, 1, 1, 0, 0, 0], rcond=-1) if residual.sum() < 1e-14: assert rank == D, 'You have a weird unit cell!' # D directions was OK break a_d *= scale offsets = [(0, 0, 0)] coefs = [laplace[n][0] * a_d.sum()] coefs[0] += k2 * scale for d in range(D): M_c = M_ic[i_d[d]] offsets.extend(np.arange(1, n + 1)[:, np.newaxis] * M_c) coefs.extend(a_d[d] * np.array(laplace[n][1:])) offsets.extend(np.arange(-1, -n - 1, -1)[:, np.newaxis] * M_c) coefs.extend(a_d[d] * np.array(laplace[n][1:])) FDOperator.__init__(self, coefs, offsets, gd, dtype) self.description = ( '%d*%d+1=%d point O(h^%d) finite-difference Helmholtz' % ((self.npoints - 1) // n, n, self.npoints, 2 * n))
def initialize_metric(self, gd): self.gd = gd if self.weight == 1: self.metric = None else: a = 0.125 * (self.weight + 7) b = 0.0625 * (self.weight - 1) c = 0.03125 * (self.weight - 1) d = 0.015625 * (self.weight - 1) self.metric = FDOperator([a, b, b, b, b, b, b, c, c, c, c, c, c, c, c, c, c, c, c, d, d, d, d, d, d, d, d], [(0, 0, 0), # a (-1, 0, 0), (1, 0, 0), # b (0, -1, 0), (0, 1, 0), (0, 0, -1), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1), # c (1, -1, 0), (1, 0, -1), (0, 1, -1), (-1, 1, 0), (-1, 0, 1), (0, -1, 1), (-1, -1, 0), (-1, 0, -1), (0, -1, -1), (1, 1, 1), (1, 1, -1), (1, -1, 1), # d (-1, 1, 1), (1, -1, -1), (-1, -1, 1), (-1, 1, -1), (-1, -1, -1)], gd, float).apply self.mR_G = gd.empty()
def __init__(self, gd, scale=1.0, n=1, dtype=float, k2=0.0): """Helmholtz for general non orthorhombic grid. gd: GridDescriptor Descriptor for grid. scale: float Scaling factor. Use scale=-0.5 for a kinetic energy operator. n: int Range of stencil. Stencil has O(h^(2n)) error. dtype: float or complex Datatype to work on. """ # Order the 13 neighbor grid points: M_ic = np.indices((3, 3, 3)).reshape((3, -3)).T[-13:] - 1 u_cv = gd.h_cv / (gd.h_cv**2).sum(1)[:, np.newaxis]**0.5 u2_i = (np.dot(M_ic, u_cv)**2).sum(1) i_d = u2_i.argsort() m_mv = np.array([(2, 0, 0), (0, 2, 0), (0, 0, 2), (0, 1, 1), (1, 0, 1), (1, 1, 0)]) # Try 3, 4, 5 and 6 directions: for D in range(3, 7): h_dv = np.dot(M_ic[i_d[:D]], gd.h_cv) A_md = (h_dv**m_mv[:, np.newaxis, :]).prod(2) a_d, residual, rank, s = np.linalg.lstsq(A_md, [1, 1, 1, 0, 0, 0]) if residual.sum() < 1e-14: assert rank == D, 'You have a weird unit cell!' # D directions was OK break a_d *= scale offsets = [(0, 0, 0)] coefs = [laplace[n][0] * a_d.sum()] coefs[0] += k2 * scale for d in range(D): M_c = M_ic[i_d[d]] offsets.extend(np.arange(1, n + 1)[:, np.newaxis] * M_c) coefs.extend(a_d[d] * np.array(laplace[n][1:])) offsets.extend(np.arange(-1, -n - 1, -1)[:, np.newaxis] * M_c) coefs.extend(a_d[d] * np.array(laplace[n][1:])) FDOperator.__init__(self, coefs, offsets, gd, dtype) self.description = ( '%d*%d+1=%d point O(h^%d) finite-difference Helmholtz' % ((self.npoints - 1) // n, n, self.npoints, 2 * n))