Esempio n. 1
0
    def inject(self, movedata):
        """
        Inject a charge using the coulomb_kmc internal accepted move data structure.

        :arg movedata: Data for injection.
        """ 
        realdata = movedata[:7].view(dtype=REAL)
        new_position = realdata[3:6:]
        charge       = realdata[6]

        # modify the multipole expansion for the coarest level
        self._lee.multipole_exp(spherical(tuple(new_position)),  charge, self.multipole_exp)

        # modify the dot product coefficients
        self._lee.dot_vec(spherical(tuple(new_position)),  charge, self.local_dot_coeffs)
Esempio n. 2
0
def test_c_sph_harm_1():
    rng = np.random.RandomState(9476213)
    N = 20
    L = 20
    ncomp = (L**2) * 2

    offsets = np.zeros(N, dtype=INT64)
    positions = np.array(rng.uniform(low=0., high=1.0, size=(N, 3)),
                         dtype=REAL)
    charges = np.array(rng.uniform(size=N), dtype=REAL)
    moments = np.array(rng.uniform(low=0.0, high=1.0, size=ncomp), dtype=REAL)
    centres = np.array((0.5, 0.5, 0.5), dtype=REAL)
    energy = np.zeros(N, dtype=REAL)

    lib, _ = kmc_octal.LocalCellExpansions._init_host_kernels(L)

    def cptr(arr):
        return arr.ctypes.get_as_parameter()

    lib(INT64(N), cptr(offsets), cptr(centres), cptr(positions), cptr(charges),
        cptr(moments), cptr(energy))

    lee = LocalExpEval(L)

    for ix in range(N):
        pos = tuple(positions[ix, :] - centres)
        sph_coord = spherical(pos)
        e_py = lee.compute_phi_local(moments, sph_coord)[0] * charges[ix]

        err = abs(e_py - energy[ix])

        assert err < 10.**-14
Esempio n. 3
0
def test_c_local_dot_eval_multipole():
    L = 20
    lee = LocalExpEval(L)
    rng = np.random.RandomState(9476213)

    ncomp = (L**2) * 2

    for tx in range(1):
        L_exp = np.zeros(ncomp, dtype=REAL)
        M_exp = np.zeros_like(L_exp)
        L2_exp = np.zeros_like(L_exp)
        M2_exp = np.zeros_like(L_exp)

        pos = (tuple(rng.uniform(size=3)))
        sph_pos = spherical(pos)

        lee.dot_vec(sph_pos, 1, L_exp)
        lee.multipole_exp(sph_pos, 1, M_exp)

        lee.dot_vec_multipole(sph_pos, 1, L2_exp, M2_exp)

        err_l = np.linalg.norm(L_exp - L2_exp, np.inf)
        assert err_l < 10.**-15

        err_m = np.linalg.norm(M_exp - M2_exp, np.inf)
        assert err_m < 10.**-15
Esempio n. 4
0
def test_split_concept_1():
    L = 12
    R = 3

    N = 200
    E = 1.
    rc = E/4

    rng = np.random.RandomState(seed=12415)

    ncomp = (L**2)*2
    half_ncomp = (L**2)
    A = state.State()
    A.domain = domain.BaseDomainHalo(extent=(E,E,E))
    A.domain.boundary_condition = domain.BoundaryTypePeriodic()
    A.npart = N

    A.P = data.PositionDat(ncomp=3)
    A.Q = data.ParticleDat(ncomp=1)

    A.P[:] = rng.uniform(low=-0.5*E, high=0.5*E, size=(N,3))
    for px in range(N):
        A.Q[px,0] = (-1.0)**(px+1)
    bias = np.sum(A.Q[:N:, 0])/N
    A.Q[:, 0] -= bias


    A.scatter_data_from(0)


    fmm_pbc = PyFMM(A.domain, N=N, free_space=False, r=R, l=L)
    fmm_27 = PyFMM(A.domain, N=N, free_space='27', r=R, l=L)

    energy_pbc = fmm_pbc(A.P, A.Q)
    energy_27 = fmm_27(A.P, A.Q)
    
    lee = LocalExpEval(L)
    local_dot_coeffs = np.zeros(ncomp, dtype=REAL)
    for px in range(N):
        lee.dot_vec(spherical(tuple(A.P[px, :])), A.Q[px, :], local_dot_coeffs)
    
    L_exp = np.zeros_like(fmm_pbc.tree_parent[1][0, 0, 0, :])
    
    fmm_pbc._lr_mtl_func(fmm_pbc.tree_halo[0][2,2,2,:], L_exp)
    fmm_pbc.dipole_corrector(fmm_pbc.tree_halo[0][2,2,2,:], L_exp)

    lr_energy = 0.5 * np.dot(L_exp, local_dot_coeffs)
    
    err = abs(energy_pbc - (energy_27 + lr_energy)) / abs(energy_pbc)

    assert err < 10.**-14

    fmm_pbc.free()
    fmm_27.free()
Esempio n. 5
0
    def initialise(self, positions, charges):
        """
        Initialise the data structures K and E (see paper).

        :arg positions: Initial positions of charges.
        :arg charges: Initial charge values.
        """

        self.multipole_exp.fill(0)
        self.local_dot_coeffs.fill(0)
        
        tmp_multipole_exp = np.zeros_like(self.multipole_exp)
        tmp_local_dot_coeffs = np.zeros_like(self.local_dot_coeffs)


        for px in range(positions.npart_local):
            # multipole expansion for the whole cell
            self._lee.multipole_exp(
                spherical(tuple(positions[px,:])),
                charges[px, 0],
                tmp_multipole_exp
            )
            # dot product for the local expansion for the cell
            self._lee.dot_vec(
                spherical(tuple(positions[px,:])),
                charges[px, 0],
                tmp_local_dot_coeffs
            )

        # MPI reduce all coefficients
        self.domain.comm.Allreduce(tmp_multipole_exp, self.multipole_exp)
        self.domain.comm.Allreduce(tmp_local_dot_coeffs, self.local_dot_coeffs)
        
        L_tmp = np.zeros_like(self.local_dot_coeffs)
        self.lrc(self.multipole_exp, L_tmp)
        return 0.5 * np.dot(L_tmp, self.local_dot_coeffs)
Esempio n. 6
0
    def _get_cell_disp(self, cell, position):
        """
        Returns spherical coordinate of particle with local cell centre as an
        origin
        """
        R = self.fmm.R
        extent = self.group.domain.extent
        sl = 2**(R - 1)
        csl = [extent[0] / sl, extent[1] / sl, extent[2] / sl]

        es = [extent[0] * -0.5, extent[1] * -0.5, extent[2] * -0.5]

        ec = [esx + 0.5 * cx + ccx * cx for esx, cx, ccx in zip(es, csl, cell)]

        disp = (position[0] - ec[0], position[1] - ec[1], position[2] - ec[2])
        sph = spherical(disp)

        return sph
Esempio n. 7
0
def get_cell_disp(s, ix, R):
    sl = 2 ** (R - 1)
    csl = [s.domain.extent[0] / sl,
           s.domain.extent[1] / sl,
           s.domain.extent[2] / sl]
    
    es = [s.domain.extent[0] * -0.5,
          s.domain.extent[1] * -0.5,
          s.domain.extent[2] * -0.5]
    

    cc = get_fmm_cell(s, ix, R)

    ec = [esx + 0.5 * cx + ccx * cx for esx, cx, ccx in zip(es, csl, cc)]
    px = (s.P[ix, 0], s.P[ix, 1], s.P[ix, 2])
    
    disp = (px[0] - ec[0], px[1] - ec[1], px[2] - ec[2])
    sph = spherical(disp)
    
    return sph
Esempio n. 8
0
def test_c_local_expansion_creation():
    L = 12
    lee = LocalExpEval(L)
    rng = np.random.RandomState(9476213)

    ncomp = (L**2) * 2

    for tx in range(10):
        to_test = np.zeros(ncomp, REAL)
        correct = np.zeros(ncomp, REAL)

        pos = (tuple(rng.uniform(size=3)))
        sph_pos = spherical(pos)

        lee.local_exp(sph_pos, 1.0, to_test)

        py_local_exp(L, sph_pos, 1.0, correct)

        err = np.linalg.norm(to_test - correct, np.inf)

        assert err < 10.**-10
Esempio n. 9
0
def test_c_local_dot_eval():
    L = 20
    lee = LocalExpEval(L)
    rng = np.random.RandomState(9476213)

    ncomp = (L**2) * 2

    for tx in range(50):
        L_exp = np.array(rng.uniform(size=ncomp), dtype=REAL)
        L_coe = np.zeros_like(L_exp)

        pos = (tuple(rng.uniform(size=3)))
        sph_pos = spherical(pos)
        lee.dot_vec(sph_pos, 1, L_coe)

        eng_c = np.dot(L_coe, L_exp)

        eng_p, _ = compute_phi_local(L, L_exp, sph_pos)

        err = abs(eng_c - eng_p) / abs(eng_c)
        assert err < 10.**-13
Esempio n. 10
0
    def eval_field(self, points, out, use_c=True):
        """
        Evaluate the far-field contribution to the potential field.

        :arg points: Places to evaluate field.
        :arg out: Array to populate with the far-field contribution to the field.
        """
        points = np.atleast_2d(points)

        if points.dtype == REAL and points.shape[1] == 3 and out.dtype == REAL and use_c:
            self._c_eval_field(points, out)
        else:
            assert use_c != 'force'
            npoints = points.shape[0]
            lexp = np.zeros(self.ncomp, REAL)
            self.lrc(self.multipole_exp, lexp)

            for px in range(npoints):
                pointx = points[px, :]
                lr_tmp = self._lee.compute_phi_local(lexp, spherical(tuple(pointx)))[0]
                out[px] += lr_tmp
Esempio n. 11
0
    def py_propose(self, total_movs, num_particles, host_data, cuda_data, arr, use_python=True):
        """
        Propose a move using the coulomb_kmc internal proposed move data structures.
        For details see `coulomb_kmc.kmc_mpi_decomp.FMMMPIDecomp.setup_propose_with_dats`.

        Warning: uses Python and hence will be slow (for testing).
        """       
        es = host_data['exclusive_sum']
        old_pos = host_data['old_positions']
        new_pos = host_data['new_positions']
        old_chr = host_data['old_charges']
        
        assert es.dtype == INT64
        assert old_pos.dtype == REAL
        assert old_chr.dtype == REAL
        assert new_pos.dtype == REAL
        assert arr.dtype == REAL
        
        # tmp vars

        to_remove = np.zeros(self.ncomp, dtype=REAL)
        prop_mexp = np.zeros_like(to_remove)

        to_remove_dot_vec = np.zeros_like(to_remove)
        dot_vec = np.zeros_like(to_remove)

        L_tmp = np.zeros_like(to_remove)
        # get current long range energy
        self.lrc(self.multipole_exp, L_tmp)
        old_energy = 0.5 * np.dot(L_tmp, self.local_dot_coeffs)

        for px in  range(num_particles):
            # assumed charge doesn't change
            charge = old_chr[px]
            opos = old_pos[px, :]

            nprop = es[px+1, 0] - es[px, 0]

            # remove old multipole expansion coeffs
            to_remove.fill(0)
            self._lee.multipole_exp(spherical(tuple(opos)), -charge, to_remove)
            
            # remove dot product coeffs
            to_remove_dot_vec.fill(0)
            self._lee.dot_vec(spherical(tuple(opos)), -charge, to_remove_dot_vec)


            for movxi, movx in enumerate(range(es[px, 0], es[px+1, 0])):
                prop_mexp[:] = self.multipole_exp[:].copy()
                npos = new_pos[movx, :]

                # compute the mutipole expansion of the proposed config
                self._lee.multipole_exp(spherical(tuple(npos)), charge, prop_mexp)
                # remove the old pos
                prop_mexp[:] += to_remove

                # do the same for the dot product vector
                dot_vec[:] = self.local_dot_coeffs.copy()
                dot_vec[:] += to_remove_dot_vec[:]

                # add on the proposed position
                self._lee.dot_vec(spherical(tuple(npos)), charge, dot_vec)
                
                # apply long range mtl
                L_tmp.fill(0)
                self.lrc(prop_mexp, L_tmp)
                
                # compute long range energy contribution
                new_energy = 0.5 * np.dot(L_tmp, dot_vec)

                arr[px, movxi] += old_energy - new_energy