Issue:
cell.precision for 2D systems changed in 2.1

We have some tests failing downstream since 2.1, which seem to suddenly require a much lower `cell.precision` to pass.
This affects a 3x2x1 supercell of a square lattice of He atoms (example script below).

With version 2.0 the results are:
```
k-HF:  converged=  True  E=-2.855155880475
G-HF:  converged=  True  E=-2.855155880468
```

With version 2.1 the results are:

```
k-HF:  converged=  True  E=-2.855155880613
G-HF:  converged= False  E=-2.855140202195
```
with the following warning for the Gamma-point supercell calculation:

> WARN: 0.008379 error found in overlap integrals. cell.precision  or  cell.rcut  can be adjusted to improve accuracy.

Only when lowering `cell.precision` to `1e-15` will this warning dissappear, and I get

```
k-HF:  converged=  True  E=-2.855155880468
G-HF:  converged=  True  E=-2.855155880468
```

It appears that some truncation or resolution parameter is now underestimated in this 2D supercell system, since we shouldn't need to go to such a low precision.
 
This doesn't appear to be an issue when using 3D PBC.
(edit: although possibly related to #1409)
 
 Script:
 [run.py.txt](https://github.com/pyscf/pyscf/files/9557081/run.py.txt)

---

ke_guess from estimate_ke_cutoff_for_eta too low

In the PBC calculation below the nuclear potential has an imaginary part at k-points which are self-conjugated (i.e. k = G-k) for some inverse lattice vector G). At these k-points the nuclear potential should be real.

This is however not the case, even with a `cell.precision` of `1e-11`. To remove the imaginary part one has to use `1e-12`, which seems really quite low.  

It seems that the kinetic energy cutoff [here](https://github.com/pyscf/pyscf/blob/2bd16d760ddcbbcec4ca5d7b7b480b953743459b/pyscf/pbc/df/aft.py#L160) is not estimated conservatively enough.

This may be related to the fact that the unit cell below us quite "sharp", with lattice vectors far from being orthogonal (I don't know if a cubic cell was assumed for the ke estimate, just a guess).

```
import numpy as np
import pyscf
import pyscf.pbc
import pyscf.pbc.df
import pyscf.lib


cell = pyscf.pbc.gto.Cell()
a  = 4.1705
cell.a = a * np.asarray([
    [1, 0.5, 0.5],
    [0.5, 1, 0.5],
    [0.5, 0.5, 1.0]])
cell.atom = [
        ['Ni', [0, 0, 0]],
        ['Ni', [a, a, a]]]
cell.basis = 'def2-svp'
cell.output = 'pyscf.txt'
cell.verbose = 10
cell.exp_to_discard = 0.1
cell.precision = 1e-10
#cell.precision = 1e-12
cell.build()

kmesh = [2,1,1]
kpts = cell.make_kpts(kmesh)

df = pyscf.pbc.df.GDF(cell, kpts)
vnuc = pyscf.lib.asarray(df.get_nuc(kpts))
for k in range(len(kpts)):
    im = np.linalg.norm(vnuc[k].imag)
    print("Imaginary part of V(nuc) at kpt= %3d:  %.3e" % (k, im))
```

Fix patch:
diff --git a/pyscf/dft/gks.py b/pyscf/dft/gks.py
index 9fbb8f60ae..9c701f3968 100644
--- a/pyscf/dft/gks.py
+++ b/pyscf/dft/gks.py
@@ -120,6 +120,7 @@ def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
 
         if ground_state:
             exc -= numpy.einsum('ij,ji', dm, vk).real * .5
+
     if ground_state:
         ecoul = numpy.einsum('ij,ji', dm, vj).real * .5
     else:
diff --git a/pyscf/gto/mole.py b/pyscf/gto/mole.py
index 2bb541f328..a65c0aca77 100644
--- a/pyscf/gto/mole.py
+++ b/pyscf/gto/mole.py
@@ -2361,9 +2361,10 @@ def __getattr__(self, key):
         else:
             mf = scf.HF(self)
 
+        if not hasattr(mf.__class__, key):
+            raise AttributeError('Mole object does not have method %s' % key)
+
         method = getattr(mf, key, None)
-        if method is None:
-            raise AttributeError('Mole object has no attribute %s' % key)
 
         # Initialize SCF object for post-SCF methods if applicable
         if self.nelectron != 0:
diff --git a/pyscf/pbc/df/gdf_builder.py b/pyscf/pbc/df/gdf_builder.py
index d25ec524e3..dd54d017bb 100644
--- a/pyscf/pbc/df/gdf_builder.py
+++ b/pyscf/pbc/df/gdf_builder.py
@@ -599,7 +599,7 @@ def _guess_eta(cell, kpts=None, mesh=None):
     a = cell.lattice_vectors()
     eta_min = aft.estimate_eta(cell, cell.precision*1e-2)
     ke_min = aft.estimate_ke_cutoff_for_eta(cell, eta_min, cell.precision)
-    mesh_min = pbctools.cutoff_to_mesh(a, ke_min) + 1
+    mesh_min = _round_off_to_odd_mesh(pbctools.cutoff_to_mesh(a, ke_min))
 
     if mesh is None:
         nimgs = (8 * cell.rcut**3 / cell.vol) ** (cell.dimension / 3)
diff --git a/pyscf/pbc/df/incore.py b/pyscf/pbc/df/incore.py
index 3f75f79b9a..02f1f09ef0 100644
--- a/pyscf/pbc/df/incore.py
+++ b/pyscf/pbc/df/incore.py
@@ -115,7 +115,12 @@ def wrap_int3c(cell, auxcell, intor='int3c2e', aosym='s1', comp=1,
         wherej = kptij_idx[len(kpti):]
         nkpts = len(kpts)
         kptij_idx = wherei * nkpts + wherej
-    dfbuilder = _Int3cBuilder(cell, auxcell, kpts)
+    dfbuilder = _Int3cBuilder(cell, auxcell, kpts).build()
+    # Reduce the size of supmol based on the 3-center overlaps. Otherwise the
+    # dfbuilder.supmol oftens two large for the calculations.
+    # TODO: strip supmol basis based on the intor type.
+    eta = np.hstack(auxcell.bas_exps()).min()
+    dfbuilder.supmol = _strip_basis(dfbuilder.supmol, eta)
     int3c = dfbuilder.gen_int3c_kernel(intor, aosym, comp, j_only,
                                        kptij_idx, return_complex=True)
     return int3c
@@ -176,16 +181,11 @@ def build(self):
         self.rs_cell = rs_cell = ft_ao._RangeSeparatedCell.from_cell(
             cell, self.ke_cutoff, RCUT_THRESHOLD, verbose=log)
 
-        rcut = cell.rcut
-        if False:
-            # FIXME: Is it necessary to increase rcut?
-            exp_min = np.hstack(cell.bas_exps()).min()
-            eij = exp_min / 2
-            # Approximate with only s functions for the lattice-sum boundary
-            rcut = abs(-np.log(cell.precision) / eij)**.5 * 2
-            log.debug1('exp_min = %g, rcut = %g', exp_min, rcut)
-
-        supmol = ft_ao._ExtendedMole.from_cell(rs_cell, kmesh, rcut, verbose=log)
+        supmol = ft_ao._ExtendedMole.from_cell(rs_cell, kmesh, cell.rcut,
+                                               verbose=log)
+        if self.auxcell is not None:
+            eta = np.hstack(self.auxcell.bas_exps()).min()
+            supmol = _strip_basis(supmol, eta)
         self.supmol = supmol
         log.debug('sup-mol nbas = %d cGTO = %d pGTO = %d',
                   supmol.nbas, supmol.nao, supmol.npgto_nr())
@@ -584,17 +584,21 @@ def get_pp_loc_part2(self):
         if self.rs_cell is None:
             self.build()
         cell = self.cell
-        supmol = self.supmol
-        if supmol.nbas == supmol.bas_mask.size:  # supmol not stripped
-            supmol = self.supmol.strip_basis(inplace=False)
         kpts = self.kpts
         nkpts = len(kpts)
         intors = ('int3c2e', 'int3c1e', 'int3c1e_r2_origk',
                   'int3c1e_r4_origk', 'int3c1e_r6_origk')
+        fake_cells = [pp_int.fake_cell_vloc(cell, cn) for cn in range(1, 5)]
+
+        supmol = self.supmol
+        if supmol.nbas == supmol.bas_mask.size:  # supmol not stripped
+            eta = min([np.hstack(c.bas_exps()).min()
+                       for c in fake_cells if c.nbas > 0])
+            supmol = _strip_basis(supmol, eta, inplace=False)
+
         bufR = 0
         bufI = 0
-        for cn in range(1, 5):
-            fake_cell = pp_int.fake_cell_vloc(cell, cn)
+        for cn, fake_cell in enumerate(fake_cells, start=1):
             if fake_cell.nbas > 0:
                 int3c = self.gen_int3c_kernel(intors[cn], 's2', comp=1, j_only=True,
                                               auxcell=fake_cell, supmol=supmol)
diff --git a/pyscf/pbc/df/rsdf_builder.py b/pyscf/pbc/df/rsdf_builder.py
index 2ec983c391..8a931ab3ed 100644
--- a/pyscf/pbc/df/rsdf_builder.py
+++ b/pyscf/pbc/df/rsdf_builder.py
@@ -347,9 +347,7 @@ def get_2c2e(self, uniq_kpts):
         rs_auxcell = self.rs_auxcell
         auxcell_c = rs_auxcell.compact_basis_cell()
         if auxcell_c.nbas > 0:
-            rcut_sr = auxcell_c.rcut
-            rcut_sr = (-2*np.log(
-                .225*precision * omega**4 * rcut_sr**2))**.5 / omega
+            rcut_sr = (-np.log(precision * auxcell_c.rcut**2 * omega))**.5 / omega
             auxcell_c.rcut = rcut_sr
             logger.debug1(self, 'auxcell_c  rcut_sr = %g', rcut_sr)
             with auxcell_c.with_short_range_coulomb(omega):
@@ -1159,7 +1157,7 @@ def _guess_omega(cell, kpts, mesh=None):
     # enough to truncate the interaction.
     omega_min = aft.estimate_omega(cell, cell.precision*1e-2)
     ke_min = aft.estimate_ke_cutoff_for_omega(cell, omega_min, cell.precision)
-    mesh_min = pbctools.cutoff_to_mesh(a, ke_min) + 1
+    mesh_min = _round_off_to_odd_mesh(pbctools.cutoff_to_mesh(a, ke_min))
 
     if mesh is None:
         nao = cell.npgto_nr()
diff --git a/pyscf/pbc/dft/gen_grid.py b/pyscf/pbc/dft/gen_grid.py
index 0b99ff3ca1..51aa9a6156 100644
--- a/pyscf/pbc/dft/gen_grid.py
+++ b/pyscf/pbc/dft/gen_grid.py
@@ -107,14 +107,11 @@ def build(self, cell=None, with_non0tab=False):
         else:
             self.cell = cell
 
-        coords = self.coords
-        weights = self.weights
-
         if with_non0tab:
-            self.non0tab = self.make_mask(cell, coords)
+            self.non0tab = self.make_mask(cell, self.coords)
         else:
             self.non0tab = None
-        return coords, weights
+        return self
 
     def reset(self, cell=None):
         if cell is not None:
@@ -130,7 +127,8 @@ def dump_flags(self, verbose=None):
 
     def kernel(self, cell=None, with_non0tab=False):
         self.dump_flags()
-        return self.build(cell, with_non0tab)
+        self.build(cell, with_non0tab)
+        return self.coords, self.weights
 
     @lib.with_doc(make_mask.__doc__)
     def make_mask(self, cell=None, coords=None, relativity=0, shls_slice=None,
@@ -174,28 +172,28 @@ def get_becke_grids(cell, atom_grid={}, radi_method=dft.radi.gauss_chebyshev,
             coords, vol = atom_grids_tab[cell.atom_symbol(ia)]
             coords = coords + atm_coords[iL,ia]
             # search for grids in unit cell
-            c = b.dot(coords.T).round(8)
+            c = b.dot(coords.T)
 
             mask = np.ones(c.shape[1], dtype=bool)
             if dimension >= 1:
-                mask &= (c[0]>=0) & (c[0]<=1)
+                mask &= (c[0]>=-.5) & (c[0]<=.5)
             if dimension >= 2:
-                mask &= (c[1]>=0) & (c[1]<=1)
+                mask &= (c[1]>=-.5) & (c[1]<=.5)
             if dimension == 3:
-                mask &= (c[2]>=0) & (c[2]<=1)
+                mask &= (c[2]>=-.5) & (c[2]<=.5)
 
             vol = vol[mask]
             if vol.size > 8:
                 c = c[:,mask]
                 if dimension >= 1:
-                    vol[c[0]==0] *= .5
-                    vol[c[0]==1] *= .5
+                    vol[c[0]==-.5] *= .5
+                    vol[c[0]== .5] *= .5
                 if dimension >= 2:
-                    vol[c[1]==0] *= .5
-                    vol[c[1]==1] *= .5
+                    vol[c[1]==-.5] *= .5
+                    vol[c[1]== .5] *= .5
                 if dimension == 3:
-                    vol[c[2]==0] *= .5
-                    vol[c[2]==1] *= .5
+                    vol[c[2]==-.5] *= .5
+                    vol[c[2]== .5] *= .5
                 coords = coords[mask]
                 coords_all.append(coords)
                 weights_all.append(vol)
@@ -251,7 +249,7 @@ def build(self, cell=None, with_non0tab=False):
         logger.info(self, 'tot grids = %d', len(self.weights))
         logger.info(self, 'cell vol = %.9g  sum(weights) = %.9g',
                     cell.vol, self.weights.sum())
-        return self.coords, self.weights
+        return self
 
     @lib.with_doc(make_mask.__doc__)
     def make_mask(self, cell=None, coords=None, relativity=0, shls_slice=None,
diff --git a/pyscf/pbc/dft/gks.py b/pyscf/pbc/dft/gks.py
index 7313bc2595..6ade248edc 100644
--- a/pyscf/pbc/dft/gks.py
+++ b/pyscf/pbc/dft/gks.py
@@ -69,8 +69,9 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
         t0 = logger.timer(ks, 'setting up grids', *t0)
 
     # vxc = (vxc_aa, vxc_bb). vxc_ab is neglected in collinear DFT.
+    max_memory = ks.max_memory - lib.current_memory()[0]
     n, exc, vxc = ks._numint.nr_uks(cell, ks.grids, ks.xc, (dm_a,dm_b), 0,
-                                    kpt, kpts_band)
+                                    kpt, kpts_band, max_memory=max_memory)
     logger.debug(ks, 'nelec by numeric integration = %s', n)
     t0 = logger.timer(ks, 'vxc', *t0)
     # vxc = (vxc_aa,   0   )
@@ -81,7 +82,16 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
         vj = ks.get_j(cell, dm, hermi, kpt, kpts_band)
         vxc += vj
     else:
-        raise NotImplementedError
+        vj, vk = ks.get_jk(cell, dm, hermi, kpt, kpts_band)
+        vk *= hyb
+        if abs(omega) > 1e-10:
+            vklr = ks.get_k(cell, dm, hermi, kpt, kpts_band, omega=omega)
+            vklr *= (alpha - hyb)
+            vk += vklr
+        vxc += vj - vk
+
+        if ground_state:
+            exc -= numpy.einsum('ij,ji', dm, vk).real * .5
 
     if ground_state:
         ecoul = numpy.einsum('ij,ji', dm, vj).real * .5
diff --git a/pyscf/pbc/dft/kgks.py b/pyscf/pbc/dft/kgks.py
index 5c70888559..69a7bf21c7 100644
--- a/pyscf/pbc/dft/kgks.py
+++ b/pyscf/pbc/dft/kgks.py
@@ -82,8 +82,9 @@ def get_veff(ks, cell=None, dm_kpts=None, dm_last=0, vhf_last=0, hermi=1,
         t0 = logger.timer(ks, 'setting up grids', *t0)
 
     # vxc_spblk = (vxc_aa, vxc_bb), vxc_aa = (nkpts, nao, nao), vxc_bb = (nkpts, nao, nao)
+    max_memory = ks.max_memory - lib.current_memory()[0]
     n, exc, vxc_spblk = ks._numint.nr_uks(cell, ks.grids, ks.xc, (dm_a,dm_b), hermi,
-                                          kpts, kpts_band)
+                                          kpts, kpts_band, max_memory=max_memory)
     logger.debug(ks, 'nelec by numeric integration = %s', n)
     t0 = logger.timer(ks, 'vxc', *t0)
 
@@ -98,10 +99,23 @@ def get_veff(ks, cell=None, dm_kpts=None, dm_last=0, vhf_last=0, hermi=1,
 
     weight = 1./len(kpts)
     if not hybrid:
+        ks.with_df._j_only = False
         vj = ks.get_j(cell, dm_kpts, hermi, kpts, kpts_band)
         vxc += vj
     else:
-        raise NotImplementedError
+        if getattr(ks.with_df, '_j_only', False):  # for GDF and MDF
+            logger.warn(ks, 'df.j_only cannot be used with hybrid functional')
+            ks.with_df._j_only = False
+        vj, vk = ks.get_jk(cell, dm_kpts, hermi, kpts, kpts_band)
+        vk *= hyb
+        if abs(omega) > 1e-10:
+            vklr = ks.get_k(cell, dm_kpts, hermi, kpts, kpts_band, omega=omega)
+            vklr *= (alpha - hyb)
+            vk += vklr
+        vxc += vj - vk
+
+        if ground_state:
+            exc -= np.einsum('Kij,Kji', dm_kpts, vk).real * .5
 
     if ground_state:
         ecoul = np.einsum('Kij,Kji', dm_kpts, vj).real * .5 * weight
diff --git a/pyscf/pbc/dft/krks.py b/pyscf/pbc/dft/krks.py
index 0df82bf2d8..8cfb330c6a 100644
--- a/pyscf/pbc/dft/krks.py
+++ b/pyscf/pbc/dft/krks.py
@@ -86,17 +86,20 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
     if hermi == 2:  # because rho = 0
         n, exc, vxc = 0, 0, 0
     else:
+        max_memory = ks.max_memory - lib.current_memory()[0]
         n, exc, vxc = ks._numint.nr_rks(cell, ks.grids, ks.xc, dm, hermi,
-                                        kpts, kpts_band)
+                                        kpts, kpts_band, max_memory=max_memory)
         logger.debug(ks, 'nelec by numeric integration = %s', n)
         t0 = logger.timer(ks, 'vxc', *t0)
 
     weight = 1./len(kpts)
     if not hybrid:
+        ks.with_df._j_only = False
         vj = ks.get_j(cell, dm, hermi, kpts, kpts_band)
         vxc += vj
     else:
         if getattr(ks.with_df, '_j_only', False):  # for GDF and MDF
+            logger.warn(ks, 'df.j_only cannot be used with hybrid functional')
             ks.with_df._j_only = False
         vj, vk = ks.get_jk(cell, dm, hermi, kpts, kpts_band)
         vk *= hyb
diff --git a/pyscf/pbc/dft/krks_ksymm.py b/pyscf/pbc/dft/krks_ksymm.py
index 3a7e6290d9..d3d63bacff 100644
--- a/pyscf/pbc/dft/krks_ksymm.py
+++ b/pyscf/pbc/dft/krks_ksymm.py
@@ -70,8 +70,10 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
     if hermi == 2:  # because rho = 0
         n, exc, vxc = 0, 0, 0
     else:
+        max_memory = ks.max_memory - lib.current_memory()[0]
         n, exc, vxc = ks._numint.nr_rks(cell, ks.grids, ks.xc, dm_bz,
-                                        kpts=kpts.kpts, kpts_band=kpts_band)
+                                        kpts=kpts.kpts, kpts_band=kpts_band,
+                                        max_memory=max_memory)
         logger.debug(ks, 'nelec by numeric integration = %s', n)
         t0 = logger.timer(ks, 'vxc', *t0)
 
diff --git a/pyscf/pbc/dft/kuks.py b/pyscf/pbc/dft/kuks.py
index 7c374e0454..23dfba2487 100644
--- a/pyscf/pbc/dft/kuks.py
+++ b/pyscf/pbc/dft/kuks.py
@@ -69,18 +69,21 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
     if hermi == 2:  # because rho = 0
         n, exc, vxc = (0,0), 0, 0
     else:
+        max_memory = ks.max_memory - lib.current_memory()[0]
         n, exc, vxc = ks._numint.nr_uks(cell, ks.grids, ks.xc, dm, hermi,
-                                        kpts, kpts_band)
+                                        kpts, kpts_band, max_memory=max_memory)
         logger.debug(ks, 'nelec by numeric integration = %s', n)
         t0 = logger.timer(ks, 'vxc', *t0)
 
     weight = 1./len(kpts)
 
     if not hybrid:
+        ks.with_df._j_only = False
         vj = ks.get_j(cell, dm[0]+dm[1], hermi, kpts, kpts_band)
         vxc += vj
     else:
         if getattr(ks.with_df, '_j_only', False):  # for GDF and MDF
+            logger.warn(ks, 'df.j_only cannot be used with hybrid functional')
             ks.with_df._j_only = False
         vj, vk = ks.get_jk(cell, dm, hermi, kpts, kpts_band)
         vj = vj[0] + vj[1]
diff --git a/pyscf/pbc/dft/kuks_ksymm.py b/pyscf/pbc/dft/kuks_ksymm.py
index 5e5a5f0823..a842305c55 100644
--- a/pyscf/pbc/dft/kuks_ksymm.py
+++ b/pyscf/pbc/dft/kuks_ksymm.py
@@ -69,8 +69,10 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
     if hermi == 2:  # because rho = 0
         n, exc, vxc = (0,0), 0, 0
     else:
+        max_memory = ks.max_memory - lib.current_memory()[0]
         n, exc, vxc = ks._numint.nr_uks(cell, ks.grids, ks.xc, dm_bz,
-                                        kpts=kpts.kpts, kpts_band=kpts_band)
+                                        kpts=kpts.kpts, kpts_band=kpts_band,
+                                        max_memory=max_memory)
         logger.debug(ks, 'nelec by numeric integration = %s', n)
         t0 = logger.timer(ks, 'vxc', *t0)
 
diff --git a/pyscf/pbc/dft/numint.py b/pyscf/pbc/dft/numint.py
index 578d86db1d..8ad4bff044 100644
--- a/pyscf/pbc/dft/numint.py
+++ b/pyscf/pbc/dft/numint.py
@@ -969,7 +969,7 @@ def block_loop(self, cell, grids, nao=None, deriv=0, kpt=numpy.zeros(3),
 # NOTE to index grids.non0tab, the blksize needs to be the integer multiplier of BLKSIZE
         if blksize is None:
             blksize = int(max_memory*1e6/(comp*2*nao*16*BLKSIZE))*BLKSIZE
-            blksize = max(BLKSIZE, min(blksize, ngrids, BLKSIZE*1200))
+            blksize = max(BLKSIZE, min(blksize, ngrids, BLKSIZE*2400))
         if non0tab is None:
             non0tab = grids.non0tab
         if non0tab is None:
@@ -1155,7 +1155,7 @@ def block_loop(self, cell, grids, nao=None, deriv=0, kpts=numpy.zeros((1,3)),
 # NOTE to index grids.non0tab, the blksize needs to be the integer multiplier of BLKSIZE
         if blksize is None:
             blksize = int(max_memory*1e6/(comp*2*len(kpts_all)*nao*16*BLKSIZE))*BLKSIZE
-            blksize = max(BLKSIZE, min(blksize, ngrids, BLKSIZE*1200))
+            blksize = max(BLKSIZE, min(blksize, ngrids, BLKSIZE*2400))
         if non0tab is None:
             non0tab = grids.non0tab
         if non0tab is None:
diff --git a/pyscf/pbc/dft/rks.py b/pyscf/pbc/dft/rks.py
index bf172f6a64..15c9fc6069 100644
--- a/pyscf/pbc/dft/rks.py
+++ b/pyscf/pbc/dft/rks.py
@@ -91,8 +91,9 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
     if hermi == 2:  # because rho = 0
         n, exc, vxc = 0, 0, 0
     else:
+        max_memory = ks.max_memory - lib.current_memory()[0]
         n, exc, vxc = ks._numint.nr_rks(cell, ks.grids, ks.xc, dm, hermi,
-                                        kpt, kpts_band)
+                                        kpt, kpts_band, max_memory=max_memory)
         logger.debug(ks, 'nelec by numeric integration = %s', n)
         t0 = logger.timer(ks, 'vxc', *t0)
 
@@ -100,8 +101,6 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
         vj = ks.get_j(cell, dm, hermi, kpt, kpts_band)
         vxc += vj
     else:
-        if getattr(ks.with_df, '_j_only', False):  # for GDF and MDF
-            ks.with_df._j_only = False
         vj, vk = ks.get_jk(cell, dm, hermi, kpt, kpts_band)
         vk *= hyb
         if abs(omega) > 1e-10:
diff --git a/pyscf/pbc/dft/uks.py b/pyscf/pbc/dft/uks.py
index c7eb940845..dcdd87a661 100644
--- a/pyscf/pbc/dft/uks.py
+++ b/pyscf/pbc/dft/uks.py
@@ -75,8 +75,9 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
     if hermi == 2:  # because rho = 0
         n, exc, vxc = (0,0), 0, 0
     else:
+        max_memory = ks.max_memory - lib.current_memory()[0]
         n, exc, vxc = ks._numint.nr_uks(cell, ks.grids, ks.xc, dm, hermi,
-                                        kpt, kpts_band)
+                                        kpt, kpts_band, max_memory=max_memory)
         logger.debug(ks, 'nelec by numeric integration = %s', n)
         t0 = logger.timer(ks, 'vxc', *t0)
 
@@ -84,8 +85,6 @@ def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1,
         vj = ks.get_j(cell, dm[0]+dm[1], hermi, kpt, kpts_band)
         vxc += vj
     else:
-        if getattr(ks.with_df, '_j_only', False):  # for GDF and MDF
-            ks.with_df._j_only = False
         vj, vk = ks.get_jk(cell, dm, hermi, kpt, kpts_band)
         vj = vj[0] + vj[1]
         vk *= hyb
diff --git a/pyscf/pbc/gto/cell.py b/pyscf/pbc/gto/cell.py
index ccb1ff49fa..f1c0d9d572 100644
--- a/pyscf/pbc/gto/cell.py
+++ b/pyscf/pbc/gto/cell.py
@@ -382,7 +382,11 @@ def intor_cross(intor, cell1, cell2, comp=None, hermi=0, kpts=None, kpt=None,
     fintor = getattr(moleintor.libcgto, intor)
     cintopt = lib.c_null_ptr()
 
-    Ls = cell1.get_lattice_Ls(rcut=max(cell1.rcut, cell2.rcut))
+    rcut = max(cell1.rcut, cell2.rcut)
+    if cell1.dimension < 2 or cell1.low_dim_ft_type == 'inf_vacuum':
+        Ls = cell1.get_lattice_Ls(rcut=rcut, dimension=cell1.dimension)
+    else:
+        Ls = cell1.get_lattice_Ls(rcut=rcut, dimension=3)
     expkL = np.asarray(np.exp(1j*np.dot(kpts_lst, Ls.T)), order='C')
     drv = libpbc.PBCnr2c_drv
 
@@ -735,25 +739,26 @@ def get_ewald_params(cell, precision=None, mesh=None):
         ew_cut = cell.rcut
         ew_eta = np.sqrt(max(np.log(4*np.pi*ew_cut**2/precision)/ew_cut**2, .1))
     else:
-        if mesh is None:
-            mesh = cell.mesh
         mesh = _cut_mesh_for_ewald(cell, mesh)
-        Gmax = min(np.asarray(mesh)//2 * lib.norm(cell.reciprocal_vectors(), axis=1))
-        log_precision = np.log(precision/(4*np.pi*(Gmax+1e-100)**2))
-        ew_eta = np.sqrt(-Gmax**2/(4*log_precision)) + 1e-100
+        ke_cutoff = pbctools.mesh_to_cutoff(cell.lattice_vectors(), mesh).min()
+        log_precision = np.log(precision / (cell.atom_charges().sum()*16*np.pi**2))
+        ew_eta = np.sqrt(-ke_cutoff/(2*log_precision))
         ew_cut = _estimate_rcut(ew_eta**2, 0, 1., precision)
     return ew_eta, ew_cut
 
+MESH_FOR_EWALD = np.array([15] * 3)
+
 def _cut_mesh_for_ewald(cell, mesh):
-    mesh = np.copy(mesh)
-    mesh_max = np.asarray(np.linalg.norm(cell.lattice_vectors(), axis=1) * 2,
-                          dtype=int)  # roughly 2 grids per bohr
+    if cell.dimension == 3:
+        return MESH_FOR_EWALD
+
+    mesh = MESH_FOR_EWALD.copy()
     if (cell.dimension < 2 or
         (cell.dimension == 2 and cell.low_dim_ft_type == 'inf_vacuum')):
-        mesh_max[cell.dimension:] = mesh[cell.dimension:]
-
-    mesh_max[mesh_max<80] = 80
-    mesh[mesh>mesh_max] = mesh_max[mesh>mesh_max]
+        mesh[cell.dimension:] = cell.mesh[cell.dimension:]
+    else:  # dimension == 2
+        # roughly 2 grids per bohr
+        mesh[2] = int(np.linalg.norm(cell.lattice_vectors()[2])) * 2 + 1
     return mesh
 
 def ewald(cell, ew_eta=None, ew_cut=None):
@@ -776,9 +781,17 @@ def ewald(cell, ew_eta=None, ew_cut=None):
     if cell.natm == 0:
         return 0
 
-    if ew_eta is None: ew_eta = cell.get_ewald_params()[0]
-    if ew_cut is None: ew_cut = cell.get_ewald_params()[1]
     chargs = cell.atom_charges()
+
+    if ew_eta is None or ew_cut is None:
+        ew_eta, ew_cut = cell.get_ewald_params()
+        mesh = _cut_mesh_for_ewald(cell, cell.mesh)
+    else:
+        log_precision = np.log(cell.precision / (chargs.sum()*16*np.pi**2))
+        ke_cutoff = -2*ew_eta**2*log_precision
+        mesh = pbctools.cutoff_to_mesh(cell.lattice_vectors(), ke_cutoff)
+        logger.debug1(cell, 'mesh for ewald %s', mesh)
+
     coords = cell.atom_coords()
     Lall = cell.get_lattice_Ls(rcut=ew_cut)
 
@@ -802,10 +815,10 @@ def ewald(cell, ew_eta=None, ew_cut=None):
     # where
     #   ZS_I(G) = \sum_a Z_a exp (i G.R_a)
 
-    mesh = _cut_mesh_for_ewald(cell, cell.mesh)
     Gv, Gvbase, weights = cell.get_Gv_weights(mesh)
     absG2 = np.einsum('gi,gi->g', Gv, Gv)
     absG2[absG2==0] = 1e200
+
     if cell.dimension != 2 or cell.low_dim_ft_type == 'inf_vacuum':
         coulG = 4*np.pi / absG2
         coulG *= weights
@@ -909,7 +922,7 @@ def make_kpts(cell, nks, wrap_around=WRAP_AROUND, with_gamma_point=WITH_GAMMA,
         kpts = libkpts.make_kpts(cell, kpts, space_group_symmetry, time_reversal_symmetry, symmorphic)
     return kpts
 
-def get_uniform_grids(cell, mesh=None, **kwargs):
+def get_uniform_grids(cell, mesh=None, wrap_around=True):
     '''Generate a uniform real-space grid consistent w/ samp thm; see MH (3.19).
 
     Args:
@@ -921,14 +934,18 @@ def get_uniform_grids(cell, mesh=None, **kwargs):
 
     '''
     if mesh is None: mesh = cell.mesh
-    if 'gs' in kwargs:
-        warnings.warn('cell.gs is deprecated.  It is replaced by cell.mesh,'
-                      'the number of PWs (=2*gs+1) along each direction.')
-        mesh = [2*n+1 for n in kwargs['gs']]
-    mesh = np.asarray(mesh, dtype=np.double)
-    qv = lib.cartesian_prod([np.arange(x) for x in mesh])
-    a_frac = np.einsum('i,ij->ij', 1./mesh, cell.lattice_vectors())
-    coords = np.dot(qv, a_frac)
+
+    if wrap_around:
+        # wrap the coordinates around the origin. If coordinates are generated
+        # inside the primitive cell without wrap-around, an extra layer would be
+        # needed in function get_lattice_Ls for 2D calculations.
+        qv = lib.cartesian_prod([np.fft.fftfreq(x) for x in mesh])
+        coords = np.dot(qv, cell.lattice_vectors())
+    else:
+        mesh = np.asarray(mesh, dtype=np.double)
+        qv = lib.cartesian_prod([np.arange(x) for x in mesh])
+        a_frac = np.einsum('i,ij->ij', 1./mesh, cell.lattice_vectors())
+        coords = np.dot(qv, a_frac)
     return coords
 gen_uniform_grids = get_uniform_grids
 
@@ -1207,9 +1224,10 @@ def __getattr__(self, key):
             else:
                 mf = scf.HF(self)
 
-        method = getattr(mf, key, None)
-        if method is None:
-            raise AttributeError('Cell object has no attribute %s' % key)
+        if not hasattr(mf.__class__, key):
+            raise AttributeError('Cell object does not have method %s' % key)
+
+        method = getattr(mf, key)
 
         mf.run()
         return method
diff --git a/pyscf/pbc/gto/ecp.py b/pyscf/pbc/gto/ecp.py
index 15e7ae5c33..f04d23fc4d 100644
--- a/pyscf/pbc/gto/ecp.py
+++ b/pyscf/pbc/gto/ecp.py
@@ -52,7 +52,8 @@ def ecp_int(cell, kpts=None):
     # shls_slice of auxiliary index (0,1) corresponds to the fictitious s function
     shls_slice = (0, cell.nbas, 0, cell.nbas, 0, 1)
 
-    dfbuilder = incore._Int3cBuilder(cell, ecpcell, kpts_lst)
+    dfbuilder = incore._Int3cBuilder(cell, ecpcell, kpts_lst).build()
+    print(dfbuilder.supmol.nbas)
     int3c = dfbuilder.gen_int3c_kernel('ECPscalar', aosym='s2', comp=1,
                                        j_only=True, return_complex=True)
     buf = int3c(shls_slice)
diff --git a/pyscf/pbc/scf/hf.py b/pyscf/pbc/scf/hf.py
index e18a753a76..ce1a41e998 100644
--- a/pyscf/pbc/scf/hf.py
+++ b/pyscf/pbc/scf/hf.py
@@ -237,27 +237,30 @@ def dip_moment(cell, dm, unit='Debye', verbose=logger.NOTE,
 
     if grids is None:
         grids = gen_grid.UniformGrids(cell)
-        #? FIXME: Less requirements on the density accuracy.
-        #ke_cutoff = gto.estimate_ke_cutoff(cell, 1e-5)
-        #grids.mesh = tools.cutoff_to_mesh(a, ke_cutoff)
+
     if rho is None:
         rho = numint.NumInt().get_rho(cell, dm, grids, kpt, cell.max_memory)
 
+    # With the optimal origin of the unti cell, the net dipole in the unit
+    # cell should be strictly zero. However, the integral grids are often not
+    # enough to produce the zero dipole. Errors are caused by the sub-optimal
+    # origin and the numerial integration.
     if origin is None:
         origin = _search_dipole_gauge_origin(cell, grids, rho, log)
 
-    # Move the cell to the position around the origin.
     def shift_grids(r):
-        r_frac = lib.dot(r - origin, b.T)
-        # Grids on the boundary (r_frac == +/-0.5) of the new cell may lead to
-        # unbalanced contributions to the dipole moment. Exclude them from the
-        # dipole and quadrupole
-        r_frac[r_frac== 0.5] = 0
-        r_frac[r_frac==-0.5] = 0
-        r_frac[r_frac > 0.5] -= 1
-        r_frac[r_frac <-0.5] += 1
+        r_frac = (r - origin).dot(b.T)
+        r_frac5 = r_frac.round(5)
+        # With origin at the center of the unit cell Grids on the edge
+        # (r_frac == +/-0.5) of the new cell may lead to unbalanced
+        # contributions to the dipole moment.
+        r_frac[r_frac5== 0.5] = 0
+        r_frac[r_frac5==-0.5] = 0
+        r_frac[r_frac5 > 0.5] -= 1
+        r_frac[r_frac5 <-0.5] += 1
         r = lib.dot(r_frac, a)
         return r
+
     r = shift_grids(grids.coords)
     e_dip = np.einsum('g,g,gx->x', rho, grids.weights, r)
 
@@ -275,94 +278,105 @@ def shift_grids(r):
 
 def _search_dipole_gauge_origin(cell, grids, rho, log):
     '''Optimize the position of the unit cell in crystal. With a proper unit
-    cell, the nuclear charge center and the electron density center are at the
-    same point. This function returns the origin of such unit cell.
+    cell, the nuclear charge center and the electron density center can be
+    placed at the same point (zero net dipole). This function returns the
+    coordinates of the center of the unit cell.
     '''
     from pyscf.pbc.dft import gen_grid
     a = cell.lattice_vectors()
     b = np.linalg.inv(a).T
     charges = cell.atom_charges()
     coords  = cell.atom_coords()
-
-    origin = np.einsum('i,ix->x', charges, coords) / charges.sum()
-    log.debug1('Initial guess of origin center %s', origin)
     nelec = np.dot(rho, grids.weights)
 
     # The dipole moment in the crystal is not uniquely defined. Depending on
     # the position and the shape of the unit cell, the value of dipole moment
-    # can be very different. The optimization below searches the boundary of
+    # can be very different. The optimization below searches the origin of a
     # cell inside which the nuclear charge center and electron density charge
-    # center locate at the same point. The gauge origin will be chosen at the
-    # center of unit cell.
+    # center locate at the same point.
     if (cell.dimension == 3 and
         # For orthogonal lattice only
         abs(np.diag(a.diagonal())).max() and
         isinstance(grids, gen_grid.UniformGrids)):
-        gridxyz = grids.coords.T.reshape(3, *grids.mesh)
-        gridbase = (gridxyz[0,:,0,0], gridxyz[1,0,:,0], gridxyz[2,0,0,:])
+
+        r_nuc_frac = coords.dot(b.T)
+        grid_frac = [np.fft.fftfreq(x) for x in grids.mesh]
         wxyz = grids.weights.reshape(grids.mesh)
         rhoxyz = rho.reshape(grids.mesh)
 
-        def search_orig(ix, origin):
+        def search_orig(ix):
             nx = grids.mesh[ix]
-            Lx = a[ix,ix]
-            g = gridbase[ix] - origin
-            g_frac = (g * b[ix,ix]).round(6)
-            g[g_frac == .5]  = 0
-            g[g_frac ==-.5]  = 0
-            g[g_frac >  .5] -= Lx
-            g[g_frac < -.5] += Lx
-            meanx = np.einsum('xyz,xyz->'+('xyz'[ix]), rhoxyz, wxyz) / nelec
-            ex = meanx * g
-
-            r_nuc = coords[:,ix] - origin
-            r_frac = (r_nuc * b[ix,ix]).round(6)
-            r_nuc[r_frac == .5]  = 0
-            r_nuc[r_frac ==-.5]  = 0
-            r_nuc[r_frac >  .5] -= Lx
-            r_nuc[r_frac < -.5] += Lx
-            nuc_dip = np.dot(charges, r_nuc) / charges.sum()
-
-            # ex.sum() ~ electron dipole wrt the given origin
-            dipx = nuc_dip - ex.sum()
-
-            g = gridbase[ix] - origin
-            sorted_meanx = np.hstack((meanx[g >= Lx/2],
-                                      meanx[(g < Lx/2) & (g >= -Lx/2)],
-                                      meanx[g < -Lx/2]))
-            if abs(dipx) < 1e-3:
-                offx = 0
-            elif dipx > 0:
-                # To cancel the positive dipole, move electrons to the right side
-                rcum_dip = np.append(0, np.cumsum(sorted_meanx * Lx))
-                idx = np.where(rcum_dip > dipx)[0][0]
-                dx = (rcum_dip[idx] - dipx) / (rcum_dip[idx] - rcum_dip[idx-1])
-                offx = (idx - dx) * Lx/nx
-            else:
-                # To cancel the negative dipole, move electrons to the left side
-                lcum_dip = np.append(0, np.cumsum(sorted_meanx[::-1] * Lx))
-                idx = np.where(lcum_dip > -dipx)[0][0]
-                dx = (lcum_dip[idx] - -dipx) / (lcum_dip[idx] - lcum_dip[idx-1])
-                offx = -(idx - dx) * Lx/nx
-            return origin + offx
-
-        wbar = grids.weights[0]**(1./3)
-        for i in range(4):
-            orig_last = origin
-            origin[0] = search_orig(0, origin[0])
-            origin[1] = search_orig(1, origin[1])
-            origin[2] = search_orig(2, origin[2])
-            if abs(origin - orig_last).max() < wbar:
-                break
-            log.debug1('iter %d: origin %s', i, origin)
+            den = np.einsum('xyz,xyz->'+('xyz'[ix]), rhoxyz, wxyz)
+
+            nuc_x = r_nuc_frac[:,ix]
+            grid_x = grid_frac[ix]
+            # possible origin of the unit cell
+            possible_orig = grid_x
+
+            # shifts the unit cell
+            possible_x = grid_x - possible_orig[:,None]
+            possible_x[possible_x < 0] += 1
+            possible_nuc_x = nuc_x - possible_orig[:,None]
+            possible_nuc_x[possible_nuc_x < 0] += 1
+
+            # Handle the grids on the edge of a unit cell.
+            possible_nuc_x[possible_nuc_x==0] = .5
+            possible_nuc_x[possible_nuc_x==1] = .5
+            possible_x[possible_x==0] = .5
+            possible_x[possible_x==1] = .5
+
+            # dip in fractional coordinates
+            dip  = np.einsum('sx,x->s', possible_nuc_x, charges)
+            dip -= np.einsum('sx,x->s', possible_x, den)
+            # Put the net charge at the center of the unit cell
+            dip -= .5 * (charges.sum() - nelec)
+
+            idx = abs(dip).argmin()
+            dip_min = dip[idx]
+
+            if abs(dip_min) > 1e-4:
+                dip_nearest1 = dip[idx-1]
+                dip_nearest2 = dip[(idx+1)%nx]
+                if dip_nearest1 * dip_nearest2 > 0:
+                    if dip_nearest1 * dip_min > dip_nearest2 * dip_min:
+                        idx_nearest = idx - 1
+                    else:
+                        idx_nearest = idx + 1
+                else:
+                    if dip_nearest1 * dip_min < dip_nearest2 * dip_min:
+                        idx_nearest = idx - 1
+                    else:
+                        idx_nearest = idx + 1
+
+                dip_nearest = dip[idx_nearest%nx]
+                if dip_nearest * dip_min < 0:
+                    # extrapolation
+                    idx = (idx_nearest*dip_min-idx*dip_nearest) / (dip_min-dip_nearest)
+
+            # wraparound
+            if idx >= nx // 2:
+                idx -= nx
+            shift = idx / nx * a[ix]
+            return shift
+
+        orig_x = search_orig(0)
+        orig_y = search_orig(1)
+        orig_z = search_orig(2)
+        origin = orig_x + orig_y + orig_z
+        log.debug1('optimized cell origin = %s', origin)
+        log.debug1('  origin_x %s', orig_x)
+        log.debug1('  origin_y %s', orig_y)
+        log.debug1('  origin_z %s', orig_z)
+        center = origin + .5 * a.sum(axis=0)
+        log.debug1('gauge origin = %s', center)
     else:
         # If the grids are non-cubic grids, regenerating the grids is expensive if
         # the position or the shape of the unit cell is changed. The position of
         # the unit cell is not optimized. The gauge origin is set to the nuclear
         # charge center of the original unit cell.
-        pass
+        center = np.einsum('i,ix->x', charges, coords) / charges.sum()
 
-    return origin
+    return center
 
 def get_rho(mf, dm=None, grids=None, kpt=None):
     '''Compute density in real space
@@ -711,11 +725,13 @@ def energy_nuc(self):
     @lib.with_doc(dip_moment.__doc__)
     def dip_moment(self, cell=None, dm=None, unit='Debye', verbose=logger.NOTE,
                    **kwargs):
+        if cell is None:
+            cell = self.cell
+        if dm is None:
+            dm = self.make_rdm1()
         rho = kwargs.pop('rho', None)
         if rho is None:
             rho = self.get_rho(dm)
-        if cell is None:
-            cell = self.cell
         return dip_moment(cell, dm, unit, verbose, rho=rho, kpt=self.kpt, **kwargs)
 
     def _finalize(self):
diff --git a/pyscf/pbc/scf/krohf.py b/pyscf/pbc/scf/krohf.py
index fdfecd4e57..1866086528 100644
--- a/pyscf/pbc/scf/krohf.py
+++ b/pyscf/pbc/scf/krohf.py
@@ -429,15 +429,7 @@ def mulliken_meta(self, cell=None, dm=None, verbose=logger.DEBUG,
         return mulliken_meta(cell, dm, s=s, verbose=verbose,
                              pre_orth_method=pre_orth_method)
 
-    @lib.with_doc(dip_moment.__doc__)
-    def dip_moment(self, cell=None, dm=None, unit='Debye', verbose=logger.NOTE,
-                   **kwargs):
-        if cell is None: cell = self.cell
-        if dm is None: dm = self.make_rdm1()
-        rho = kwargs.pop('rho', None)
-        if rho is None:
-            rho = self.get_rho(dm)
-        return dip_moment(cell, dm, unit, verbose, rho=rho, kpts=self.kpts, **kwargs)
+    dip_moment = khf.KSCF.dip_moment
 
     spin_square = pbcrohf.ROHF.spin_square
 
diff --git a/pyscf/pbc/scf/rohf.py b/pyscf/pbc/scf/rohf.py
index 970ddcd78b..92b7d1ac75 100644
--- a/pyscf/pbc/scf/rohf.py
+++ b/pyscf/pbc/scf/rohf.py
@@ -120,15 +120,7 @@ def get_bands(self, kpts_band, cell=None, dm=None, kpt=None):
         '''
         raise NotImplementedError
 
-    @lib.with_doc(dip_moment.__doc__)
-    def dip_moment(self, cell=None, dm=None, unit='Debye', verbose=logger.NOTE,
-                   **kwargs):
-        if cell is None: cell = self.cell
-        if dm is None: dm = self.make_rdm1()
-        rho = kwargs.pop('rho', None)
-        if rho is None:
-            rho = self.get_rho(dm)
-        return dip_moment(cell, dm, unit, verbose, rho=rho, kpt=self.kpt, **kwargs)
+    dip_moment = pbchf.SCF.dip_moment
 
     def get_init_guess(self, cell=None, key='minao'):
         if cell is None: cell = self.cell
diff --git a/pyscf/pbc/scf/uhf.py b/pyscf/pbc/scf/uhf.py
index b6e8658b74..82e69b8980 100644
--- a/pyscf/pbc/scf/uhf.py
+++ b/pyscf/pbc/scf/uhf.py
@@ -212,8 +212,10 @@ def get_bands(self, kpts_band, cell=None, dm=None, kpt=None):
     @lib.with_doc(dip_moment.__doc__)
     def dip_moment(self, cell=None, dm=None, unit='Debye', verbose=logger.NOTE,
                    **kwargs):
-        if cell is None: cell = self.cell
-        if dm is None: dm = self.make_rdm1()
+        if cell is None:
+            cell = self.cell
+        if dm is None:
+            dm = self.make_rdm1()
         rho = kwargs.pop('rho', None)
         if rho is None:
             rho = self.get_rho(dm)
diff --git a/pyscf/pbc/tools/pbc.py b/pyscf/pbc/tools/pbc.py
index ea6ecee86f..397a0d9a28 100644
--- a/pyscf/pbc/tools/pbc.py
+++ b/pyscf/pbc/tools/pbc.py
@@ -405,7 +405,7 @@ def precompute_exx(cell, kpts):
     #alpha = 3./Rin * np.sqrt(0.5)
     #kcell.mesh = (4*alpha*np.linalg.norm(kcell.a,axis=1)).astype(int)
     log.debug("# kcell.mesh FFT = %s", kcell.mesh)
-    rs = gen_grid.gen_uniform_grids(kcell)
+    rs = kcell.get_uniform_grids(wrap_around=False)
     kngs = len(rs)
     log.debug("# kcell kngs = %d", kngs)
     corners_coord = lib.cartesian_prod(([0, 1], [0, 1], [0, 1]))
@@ -451,10 +451,7 @@ def madelung(cell, kpts):
     ecell.mesh = np.asarray(cell.mesh) * Nk
 
     if cell.omega == 0:
-        ew_eta, ew_cut = ecell.get_ewald_params(cell.precision, ecell.mesh)
-        lib.logger.debug1(cell, 'Monkhorst pack size %s ew_eta %s ew_cut %s',
-                          Nk, ew_eta, ew_cut)
-        return -2*ecell.ewald(ew_eta, ew_cut)
+        return -2*ecell.ewald()
 
     else:
         # cell.ewald function does not use the Coulomb kernel function
@@ -512,10 +509,10 @@ def get_lattice_Ls(cell, nimgs=None, rcut=None, dimension=None, discard=True):
                              np.arange(-nimgs[2], nimgs[2]+1)))
     Ls = np.dot(Ts, a)
     if discard:
-        Ls = _discard_edge_images(cell, Ls, rcut)
+        Ls = _discard_edge_images(cell, Ls, rcut, dimension)
     return np.asarray(Ls, order='C')
 
-def _discard_edge_images(cell, Ls, rcut):
+def _discard_edge_images(cell, Ls, rcut, dimension):
     '''
     Discard images if no basis in the image would contribute to lattice sum.
     '''
@@ -524,8 +521,8 @@ def _discard_edge_images(cell, Ls, rcut):
 
     a = cell.lattice_vectors()
     scaled_atom_coords = np.linalg.solve(a.T, cell.atom_coords().T).T
-    atom_boundary_max = scaled_atom_coords[:cell.dimension].max(axis=0)
-    atom_boundary_min = scaled_atom_coords[:cell.dimension].min(axis=0)
+    atom_boundary_max = scaled_atom_coords[:,:dimension].max(axis=0)
+    atom_boundary_min = scaled_atom_coords[:,:dimension].min(axis=0)
     if (np.any(atom_boundary_max > 1) or np.any(atom_boundary_min < -1)):
         logger.warn(cell, 'Atoms found very far from the primitive cell. '
                     'Atom coordinates may be error.')
@@ -538,9 +535,16 @@ def _discard_edge_images(cell, Ls, rcut):
     # of the primitive cell converged
     boundary_max = np.ceil(np.max([atom_boundary_max  ,  ovlp_penalty], axis=0)).astype(int)
     boundary_min = np.floor(np.min([atom_boundary_min-1, -ovlp_penalty], axis=0)).astype(int)
-    penalty_x = np.arange(boundary_min[0], boundary_max[0]+1)
-    penalty_y = np.arange(boundary_min[1], boundary_max[1]+1)
-    penalty_z = np.arange(boundary_min[2], boundary_max[2]+1)
+    penalty_x = penalty_y = penalty_z = [0]
+    if dimension == 1:
+        penalty_x = np.arange(boundary_min[0], boundary_max[0]+1)
+    elif dimension == 2:
+        penalty_x = np.arange(boundary_min[0], boundary_max[0]+1)
+        penalty_y = np.arange(boundary_min[1], boundary_max[1]+1)
+    else:
+        penalty_x = np.arange(boundary_min[0], boundary_max[0]+1)
+        penalty_y = np.arange(boundary_min[1], boundary_max[1]+1)
+        penalty_z = np.arange(boundary_min[2], boundary_max[2]+1)
     shifts = lib.cartesian_prod([penalty_x, penalty_y, penalty_z]).dot(a)
     Ls_mask = (np.linalg.norm(Ls + shifts[:,None,:], axis=2) < rcut).any(axis=0)
     # cell0 (Ls == 0) should always be included.
@@ -659,34 +663,40 @@ def cutoff_to_mesh(a, cutoff):
     Returns:
         mesh : (3,) array
     '''
+    # Let E(mesh_x) = min_{y, z}(|mesh_x*b[0]+y*b[1]+z*b[2]|^2)
+    # Search largest mesh_x requiring E(mesh_x) <= 2*cutoff
     b = 2 * np.pi * np.linalg.inv(a.T)
-    cutoff = cutoff * _cubic2nonorth_factor(a)
-    mesh = np.ceil(np.sqrt(2*cutoff)/lib.norm(b, axis=1) * 2).astype(int)
+    c = b.dot(b.T)
+    # r is the ratio between G of each direction when E(mesh) reaches minimum
+    r = np.linalg.inv(c) / np.linalg.det(c)
+    r /= r.diagonal()[:,None]
+    Gmax = (2*cutoff / (np.linalg.norm(r.dot(b), axis=1)**2))**.5
+    # off-diagonal r may be > 1, means that the ke_cutoff is limited by the
+    # off-diagonal part
+    # e.g r[:,2] = [1, .5, 1.2], Gx = max(Gx, Gy*.5, Gz*1.2)
+    Gmax = (r * Gmax[:,None]).max(axis=0)
+    mesh = np.ceil(Gmax).astype(int) * 2 + 1
     return mesh
 
 def mesh_to_cutoff(a, mesh):
     '''
     Convert #grid points to KE cutoff
     '''
+    # Let E(mesh_x) = min_{y, z}(|mesh_x*b[0]+y*b[1]+z*b[2]|^2)
+    # Search min(E(mesh_x)/2) subject to mesh_x > mesh
     b = 2 * np.pi * np.linalg.inv(a.T)
-    Gmax = lib.norm(b, axis=1) * np.asarray(mesh) * .5
-    ke_cutoff = Gmax**2/2
-    # scale down Gmax to get the real energy cutoff for non-orthogonal lattice
-    return ke_cutoff / _cubic2nonorth_factor(a)
-
-def _cubic2nonorth_factor(a):
-    '''The factors to transform the energy cutoff from cubic lattice to
-    non-orthogonal lattice. Energy cutoff is estimated based on cubic lattice.
-    It needs to be rescaled for the non-orthogonal lattice to ensure that the
-    minimal Gv vector in the reciprocal space is larger than the required
-    energy cutoff.
-    '''
-    # Using ke_cutoff to set up a sphere, the sphere needs to be completely
-    # inside the box defined by Gv vectors
-    abase = a / np.linalg.norm(a, axis=1)[:,None]
-    bbase = np.linalg.inv(abase.T)
-    overlap = np.einsum('ix,ix->i', abase, bbase)
-    return 1./overlap**2
+    c = b.dot(b.T)
+    # r is the ratio between G of each direction when E(mesh) reaches minimum
+    r = np.linalg.inv(c) / np.linalg.det(c)
+    r /= r.diagonal()[:,None]
+    gs = (np.asarray(mesh) - 1) // 2
+    # off-diagonal r may be > 1, means that the ke_cutoff is limited by the
+    # off-diagonal part
+    # e.g r[2] = [1.2, 1.2, 1], ke_cutoff_z = min(Gx/1.2, Gy/1.2, Gz)
+    gs_eff = (gs / (r + 1e-100)).min(axis=1)
+    Gmax = gs_eff * np.linalg.norm(r.dot(b), axis=1)
+    ke_cutoff = Gmax**2 / 2
+    return ke_cutoff
 
 def cutoff_to_gs(a, cutoff):
     '''Deprecated.  Replaced by function cutoff_to_mesh.'''


Test patch:
diff --git a/pyscf/lib/test/test_numint_uniform_grid.py b/pyscf/lib/test/test_numint_uniform_grid.py
index 6e81852afb..4551300995 100644
--- a/pyscf/lib/test/test_numint_uniform_grid.py
+++ b/pyscf/lib/test/test_numint_uniform_grid.py
@@ -58,8 +58,10 @@ def setUpModule():
     # FIXME when kpts != 0 and dm is not hermitian
     dm_kpts = cell_orth.pbc_intor('int1e_ovlp', kpts=kpts)
 
-    grids_orth = gen_grid.UniformGrids(cell_orth)
-    grids_north = gen_grid.UniformGrids(cell_north)
+    grids_orth = gen_grid.UniformGrids(cell_orth).run()
+    grids_north = gen_grid.UniformGrids(cell_north).run()
+    grids_orth.coords = cell_orth.get_uniform_grids(wrap_around=False)
+    grids_north.coords = cell_north.get_uniform_grids(wrap_around=False)
 
     ao_kpts_orth = cell_orth.pbc_eval_gto('GTOval_sph_deriv1', grids_orth.coords, kpts=kpts)
     ao_kpts_north = cell_north.pbc_eval_gto('GTOval_sph_deriv1', grids_north.coords, kpts=kpts)
@@ -213,7 +215,7 @@ def test_pbc_orth_lda_rho_submesh(self):
                   unit='B',
                   mesh=[7,6,5],
                   a=numpy.eye(3)*8)
-        grids = cell.get_uniform_grids()
+        grids = cell.get_uniform_grids(wrap_around=False)
         ao = cell.pbc_eval_gto('GTOval', grids)
         nao = cell.nao_nr()
         dm = numpy.random.random((nao,nao))
@@ -230,7 +232,7 @@ def test_pbc_nonorth_lda_rho_submesh(self):
                   unit='B',
                   mesh=[7,6,5],
                   a=numpy.eye(3)*8+numpy.random.rand(3,3))
-        grids = cell.get_uniform_grids()
+        grids = cell.get_uniform_grids(wrap_around=False)
         ao = cell.pbc_eval_gto('GTOval', grids)
         nao = cell.nao_nr()
         dm = numpy.random.random((nao,nao))
diff --git a/pyscf/pbc/cc/test/test_eom_kgccsd.py b/pyscf/pbc/cc/test/test_eom_kgccsd.py
index b493db11a8..53f369e12a 100644
--- a/pyscf/pbc/cc/test/test_eom_kgccsd.py
+++ b/pyscf/pbc/cc/test/test_eom_kgccsd.py
@@ -31,24 +31,6 @@ def test_n3_diffuse(self):
         cell = make_test_cell.test_cell_n3_diffuse()
 
         nmp = [1,1,2]
-        '''
-        # treating 1*1*2 supercell at gamma point
-        supcell = super_cell(cell,nmp)
-        gmf  = scf.GHF(supcell,exxdiv=None)
-        ehf  = gmf.kernel()
-        gcc  = cc.GCCSD(gmf)
-        gcc.conv_tol=1e-12
-        gcc.conv_tol_normt=1e-10
-        gcc.max_cycle=250
-        ecc, t1, t2 = gcc.kernel()
-        print('GHF energy (supercell) %.7f \n' % (float(ehf)/2.))
-        print('GCCSD correlation energy (supercell) %.7f \n' % (float(ecc)/2.))
-
-        eom = eom_gccsd.EOMIP(gcc)
-        e1, v = eom.ipccsd(nroots=6)
-        eom = eom_gccsd.EOMEA(gcc)
-        e2, v = eom.eaccsd(nroots=6, left=True, koopmans=True)
-        '''
         # Running HF and CCSD with 1x1x2 Monkhorst-Pack k-point mesh
         ehf2 = kmf.e_tot
         self.assertAlmostEqual(ehf2, -6.1870676561725695, 6)
@@ -150,24 +132,6 @@ def test_n3_diffuse_star(self):
         cell = make_test_cell.test_cell_n3_diffuse()
 
         nmp = [1,1,2]
-        '''
-        # treating 1*1*2 supercell at gamma point
-        supcell = super_cell(cell,nmp)
-        gmf  = scf.GHF(supcell,exxdiv=None)
-        ehf  = gmf.kernel()
-        gcc  = cc.GCCSD(gmf)
-        gcc.conv_tol=1e-12
-        gcc.conv_tol_normt=1e-10
-        gcc.max_cycle=250
-        ecc, t1, t2 = gcc.kernel()
-        print('GHF energy (supercell) %.7f \n' % (float(ehf)/2.))
-        print('GCCSD correlation energy (supercell) %.7f \n' % (float(ecc)/2.))
-
-        #eom = eom_gccsd.EOMIP(gcc)
-        #e1, v = eom.ipccsd_star(nroots=6, koopmans=True)
-        eom = eom_gccsd.EOMEA(gcc)
-        e2, v = eom.eaccsd_star(nroots=9, koopmans=True)
-        '''
         ehf2 = kmf.e_tot
         self.assertAlmostEqual(ehf2, -6.1870676561725695, 6)
 
@@ -192,26 +156,6 @@ def test_n3_diffuse_Ta(self):
         cell = make_test_cell.test_cell_n3_diffuse()
 
         nmp = [1,1,2]
-        '''
-        # treating 1*1*2 supercell at gamma point
-        supcell = super_cell(cell,nmp)
-        gmf  = scf.GHF(supcell,exxdiv=None)
-        gmf.conv_tol = 1e-10
-        gmf.conv_tol_grad = gmf.conv_tol * 10**2
-        ehf  = gmf.kernel()
-        gcc  = cc.GCCSD(gmf)
-        gcc.conv_tol=1e-12
-        gcc.conv_tol_normt=1e-10
-        gcc.max_cycle=250
-        ecc, t1, t2 = gcc.kernel()
-        print('GHF energy (supercell) %.7f \n' % (float(ehf)/2.))
-        print('GCCSD correlation energy (supercell) %.7f \n' % (float(ecc)/2.))
-
-        eom = eom_gccsd.EOMIP_Ta(gcc)
-        e1 = eom.ipccsd_star(nroots=6, koopmans=True)
-        eom = eom_gccsd.EOMEA_Ta(gcc)
-        e2 = eom.eaccsd_star(nroots=6, koopmans=True)
-        '''
         # Running HF and CCSD with 1x1x2 Monkhorst-Pack k-point mesh
         ehf2 = kmf.e_tot
         self.assertAlmostEqual(ehf2, -6.1870676561725695, 6)
@@ -248,3 +192,6 @@ def test_n3_diffuse_Ta(self):
         self.assertAlmostEqual(e2_obt[0][1], 1.2229050426609025, 6)
         self.assertAlmostEqual(e2_obt[0][2], 1.374851059956632, 6)
 
+if __name__ == '__main__':
+    print("eom_kccsd_rhf tests")
+    unittest.main()
diff --git a/pyscf/pbc/cc/test/test_eom_kgccsd_diag.py b/pyscf/pbc/cc/test/test_eom_kgccsd_diag.py
index 15292a9d4e..3508f8300e 100644
--- a/pyscf/pbc/cc/test/test_eom_kgccsd_diag.py
+++ b/pyscf/pbc/cc/test/test_eom_kgccsd_diag.py
@@ -27,8 +27,9 @@ def setUpModule():
     3.370137329, 0.000000000, 3.370137329
     3.370137329, 3.370137329, 0.000000000'''
     cell.unit = 'B'
-    #cell.verbose = 7
-    #cell.output = '/dev/null'
+    cell.verbose = 7
+    cell.output = '/dev/null'
+    cell.mesh = [15] * 3
     cell.build()
 
     KGCCSD_TEST_NMP = [1,1,2]
@@ -36,6 +37,7 @@ def setUpModule():
 
 def tearDownModule():
     global cell, KGCCSD_TEST_NMP, KGCCSD_TEST_THRESHOLD
+    cell.stdout.close()
     del cell, KGCCSD_TEST_NMP, KGCCSD_TEST_THRESHOLD
 
 def get_idx_r2(nkpts,nocc,nvir,ki,kj,i,j,a):
diff --git a/pyscf/pbc/cc/test/test_eom_krccsd.py b/pyscf/pbc/cc/test/test_eom_krccsd.py
index 4d5a555a06..8f364db947 100644
--- a/pyscf/pbc/cc/test/test_eom_krccsd.py
+++ b/pyscf/pbc/cc/test/test_eom_krccsd.py
@@ -87,7 +87,22 @@ def make_rand_kmf(nkpts=3):
     return kmf
 
 def setUpModule():
-    global cell_n3d, kmf, rand_kmf, rand_kmf1, rand_kmf2
+    global cell, cell_n3d, kmf, rand_kmf, rand_kmf1, rand_kmf2
+    cell = gto.Cell()
+    cell.atom = '''
+    He 0.000000000000   0.000000000000   0.000000000000
+    He 1.685068664391   1.685068664391   1.685068664391
+    '''
+    cell.basis = [[0, (1., 1.)], [0, (.5, 1.)]]
+    cell.a = '''
+    0.000000000, 3.370137329, 3.370137329
+    3.370137329, 0.000000000, 3.370137329
+    3.370137329, 3.370137329, 0.000000000'''
+    cell.unit = 'B'
+    cell.precision = 1e-8
+    cell.mesh = [15] * 3
+    cell.build()
+
     cell_n3d = make_test_cell.test_cell_n3_diffuse()
     kmf = pbcscf.KRHF(cell_n3d, cell_n3d.make_kpts((1,1,2), with_gamma_point=True), exxdiv=None)
     kmf.conv_tol = 1e-10
@@ -98,9 +113,9 @@ def setUpModule():
     rand_kmf2 = make_rand_kmf(nkpts=2)
 
 def tearDownModule():
-    global cell_n3d, kmf, rand_kmf, rand_kmf1, rand_kmf2
+    global cell, cell_n3d, kmf, rand_kmf, rand_kmf1, rand_kmf2
     cell_n3d.stdout.close()
-    del cell_n3d, kmf, rand_kmf, rand_kmf1, rand_kmf2
+    del cell, cell_n3d, kmf, rand_kmf, rand_kmf1, rand_kmf2
 
 class KnownValues(unittest.TestCase):
     def test_n3_diffuse(self):
@@ -312,9 +327,9 @@ def test_t3p2_imds_complex_slow(self):
         rand_cc.t1, rand_cc.t2, rand_cc.eris = t1, t2, eris
 
         e, pt1, pt2, Wmcik, Wacek = kintermediates_rhf.get_t3p2_imds_slow(rand_cc, t1, t2)
-        self.assertAlmostEqual(lib.fp(e),47165803.39384298, 3)
+        self.assertAlmostEqual(lib.fp(e),47165803.39384298, 2)
         self.assertAlmostEqual(lib.fp(pt1),10444.351837617747+20016.35108560657j, 4)
-        self.assertAlmostEqual(lib.fp(pt2),5481819.3905677245929837+-8012159.8432002812623978j, 3)
+        self.assertAlmostEqual(lib.fp(pt2),5481819.3905677245929837+-8012159.8432002812623978j, 2)
         self.assertAlmostEqual(lib.fp(Wmcik),-4401.1631306775143457+-10002.8851650238902948j, 4)
         self.assertAlmostEqual(lib.fp(Wacek),2057.9135114790879015+1970.9887693509299424j, 4)
 
@@ -334,9 +349,9 @@ def test_t3p2_imds_complex(self):
         rand_cc.t1, rand_cc.t2, rand_cc.eris = t1, t2, eris
 
         e, pt1, pt2, Wmcik, Wacek = kintermediates_rhf.get_t3p2_imds(rand_cc, t1, t2)
-        self.assertAlmostEqual(lib.fp(e), 47165803.393840045, 3)
+        self.assertAlmostEqual(lib.fp(e), 47165803.393840045, 2)
         self.assertAlmostEqual(lib.fp(pt1),10444.3518376177471509+20016.3510856065695407j, 4)
-        self.assertAlmostEqual(lib.fp(pt2),5481819.3905677245929837+-8012159.8432002812623978j, 3)
+        self.assertAlmostEqual(lib.fp(pt2),5481819.3905677245929837+-8012159.8432002812623978j, 2)
         self.assertAlmostEqual(lib.fp(Wmcik),-4401.1631306775143457+-10002.8851650238902948j, 4)
         self.assertAlmostEqual(lib.fp(Wacek),2057.9135114790879015+1970.9887693509299424j, 4)
 
@@ -429,20 +444,6 @@ def test_t3p2_imds_complex_against_so_frozen(self):
         self.assertAlmostEqual(lib.fp(gWacek[:,:,:,::2,1::2,::2,1::2]), lib.fp(Wacek), 8)
 
     def test_eomea_matvec(self):
-        cell = gto.Cell()
-        cell.atom = '''
-        He 0.000000000000   0.000000000000   0.000000000000
-        He 1.685068664391   1.685068664391   1.685068664391
-        '''
-        cell.basis = [[0, (1., 1.)], [0, (.5, 1.)]]
-        cell.a = '''
-        0.000000000, 3.370137329, 3.370137329
-        3.370137329, 0.000000000, 3.370137329
-        3.370137329, 3.370137329, 0.000000000'''
-        cell.unit = 'B'
-        cell.precision = 1e-8
-        cell.build()
-
         np.random.seed(2)
 # Running HF and CCSD with 1x1x2 Monkhorst-Pack k-point mesh
         kmf = pbcscf.KRHF(cell, kpts=cell.make_kpts([1, 1, 3]), exxdiv=None)
@@ -496,20 +497,6 @@ def test_eomea_matvec(self):
         self.assertAlmostEqual(lib.fp(hc), (-3.5273812229833275-0.10165584293391894j), 7)
 
     def test_eomea_l_matvec(self):
-        cell = gto.Cell()
-        cell.atom = '''
-        He 0.000000000000   0.000000000000   0.000000000000
-        He 1.685068664391   1.685068664391   1.685068664391
-        '''
-        cell.basis = [[0, (1., 1.)], [0, (.5, 1.)]]
-        cell.a = '''
-        0.000000000, 3.370137329, 3.370137329
-        3.370137329, 0.000000000, 3.370137329
-        3.370137329, 3.370137329, 0.000000000'''
-        cell.unit = 'B'
-        cell.precision = 1e-8
-        cell.build()
-
         np.random.seed(2)
 # Running HF and CCSD with 1x1x2 Monkhorst-Pack k-point mesh
         kmf = pbcscf.KRHF(cell, kpts=cell.make_kpts([1, 1, 3]), exxdiv=None)
diff --git a/pyscf/pbc/cc/test/test_eom_kuccsd.py b/pyscf/pbc/cc/test/test_eom_kuccsd.py
index 4605b61294..929d341243 100644
--- a/pyscf/pbc/cc/test/test_eom_kuccsd.py
+++ b/pyscf/pbc/cc/test/test_eom_kuccsd.py
@@ -26,24 +26,6 @@ def tearDownModule():
 class KnownValues(unittest.TestCase):
     def test_n3_diffuse(self):
         self.assertAlmostEqual(kmf.e_tot, -6.1870676561721227, 6)
-        '''
-        nmp = [1,1,2]
-        # treating 1*1*2 supercell at gamma point
-        supcell = super_cell(cell_n3d,nmp)
-        gmf  = scf.UHF(supcell,exxdiv=None)
-        ehf  = gmf.kernel()
-        gcc  = cc.UCCSD(gmf)
-        gcc.conv_tol=1e-12
-        gcc.conv_tol_normt=1e-10
-        gcc.max_cycle=250
-        ecc, t1, t2 = gcc.kernel()
-        print('UHF energy (supercell) %.7f \n' % (float(ehf)/2.))
-        print('UCCSD correlation energy (supercell) %.7f \n' % (float(ecc)/2.))
-        #eom = eom_uccsd.EOMIP(gcc)
-        #e1, v = eom.ipccsd(nroots=2)
-        #eom = eom_uccsd.EOMEA(gcc)
-        #e2, v = eom.eaccsd(nroots=2, koopmans=True)
-        '''
         mycc = pbcc.KUCCSD(kmf)
         mycc.conv_tol = 1e-7
         mycc.conv_tol_normt = 1e-7
diff --git a/pyscf/pbc/cc/test/test_kgccsd.py b/pyscf/pbc/cc/test/test_kgccsd.py
index c180b9f51f..b550350361 100644
--- a/pyscf/pbc/cc/test/test_kgccsd.py
+++ b/pyscf/pbc/cc/test/test_kgccsd.py
@@ -48,8 +48,9 @@ def setUpModule():
     3.370137329, 0.000000000, 3.370137329
     3.370137329, 3.370137329, 0.000000000'''
     cell.unit = 'B'
-    #cell.verbose = 7
+    cell.verbose = 7
     cell.output = '/dev/null'
+    cell.mesh = [15] * 3
     cell.build()
 
     rand_kmf = make_rand_kmf()
diff --git a/pyscf/pbc/cc/test/test_krccsd.py b/pyscf/pbc/cc/test/test_krccsd.py
index 36777b1ff2..52e6e8e586 100644
--- a/pyscf/pbc/cc/test/test_krccsd.py
+++ b/pyscf/pbc/cc/test/test_krccsd.py
@@ -50,6 +50,7 @@ def setUpModule():
     cell.unit = 'B'
     #cell.verbose = 7
     cell.output = '/dev/null'
+    cell.mesh = [15] * 3
     cell.build()
 
     rand_kmf = make_rand_kmf()
diff --git a/pyscf/pbc/df/test/test_df_jk.py b/pyscf/pbc/df/test/test_df_jk.py
index 804fec0fb8..94ee9229f5 100644
--- a/pyscf/pbc/df/test/test_df_jk.py
+++ b/pyscf/pbc/df/test/test_df_jk.py
@@ -95,8 +95,8 @@ def test_jk_single_kpt_high_cost(self):
         k_ref = 32.30441176447805   # rsjk result
         self.assertAlmostEqual(ej1, j_ref, 2)
         self.assertAlmostEqual(ek1, k_ref, 2)
-        self.assertAlmostEqual(ej1, 48.283745538383684, 7)
-        self.assertAlmostEqual(ek1, 32.30260871417842 , 7)
+        self.assertAlmostEqual(ej1, 48.283745538383684, 6)
+        self.assertAlmostEqual(ek1, 32.30260871417842 , 6)
 
         numpy.random.seed(12)
         nao = cell.nao_nr()
@@ -105,8 +105,8 @@ def test_jk_single_kpt_high_cost(self):
         vj1, vk1 = mf.get_jk(cell, dm, hermi=0)
         ej1 = numpy.einsum('ij,ji->', vj1, dm)
         ek1 = numpy.einsum('ij,ji->', vk1, dm)
-        self.assertAlmostEqual(ej1, 242.04678235140264, 5)
-        self.assertAlmostEqual(ek1, 280.15934926575903, 5)
+        self.assertAlmostEqual(ej1, 242.04678235140264, 6)
+        self.assertAlmostEqual(ek1, 280.15934926575903, 6)
 
         numpy.random.seed(1)
         kpt = numpy.random.random(3)
@@ -118,11 +118,11 @@ def test_jk_single_kpt_high_cost(self):
         vj, vk = mydf.get_jk(dm, 1, kpt, exxdiv=None)
         ej1 = numpy.einsum('ij,ji->', vj, dm)
         ek1 = numpy.einsum('ij,ji->', vk, dm)
-        self.assertAlmostEqual(ej1, 241.15121903857556+0j, 5)
-        self.assertAlmostEqual(ek1, 279.64649194057051+0j, 5)
+        self.assertAlmostEqual(ej1, 241.15121903857556+0j, 6)
+        self.assertAlmostEqual(ek1, 279.64649194057051+0j, 6)
         vj, vk = mydf.get_jk(dm, 1, kpt, with_j=False, exxdiv='ewald')
         ek1 = numpy.einsum('ij,ji->', vk, dm)
-        self.assertAlmostEqual(ek1, 691.64624456329909+0j, 5)
+        self.assertAlmostEqual(ek1, 691.64624456329909+0j, 6)
 
     def test_jk_hermi0(self):
         numpy.random.seed(12)
diff --git a/pyscf/pbc/df/test/test_gdf_builder.py b/pyscf/pbc/df/test/test_gdf_builder.py
index 2180216d96..2c70e1833a 100644
--- a/pyscf/pbc/df/test/test_gdf_builder.py
+++ b/pyscf/pbc/df/test/test_gdf_builder.py
@@ -195,7 +195,7 @@ def test_make_j3c_gamma_0d(self):
         with tempfile.NamedTemporaryFile() as tmpf:
             dfbuilder.make_j3c(tmpf.name)
             v2 = load(tmpf.name, kpts[[0, 0]])
-            self.assertAlmostEqual(lib.fp(v2), 2.4133985606622783, 7)
+            self.assertAlmostEqual(lib.fp(v2), 2.4119378731259946, 7)
 
         ref = cholesky_eri(cell, auxmol=auxcell)
         self.assertAlmostEqual(abs(v2-ref).max(), 0, 2)
diff --git a/pyscf/pbc/df/test/test_mdf.py b/pyscf/pbc/df/test/test_mdf.py
index e0f771a7c1..aa9f8e7d1a 100644
--- a/pyscf/pbc/df/test/test_mdf.py
+++ b/pyscf/pbc/df/test/test_mdf.py
@@ -88,38 +88,38 @@ def test_get_eri_gamma_high_cost(self):
         eri0000 = odf.get_eri()
         self.assertTrue(eri0000.dtype == numpy.double)
         self.assertAlmostEqual(eri0000.real.sum(), 140.52553833398147, 7)
-        self.assertAlmostEqual(lib.fp(eri0000), -1.2234059928846319, 7)
+        self.assertAlmostEqual(lib.fp(eri0000), -1.2234059928846319, 6)
 
         eri1111 = kmdf.get_eri((kpts[0],kpts[0],kpts[0],kpts[0]))
         self.assertTrue(eri1111.dtype == numpy.double)
-        self.assertAlmostEqual(eri1111.real.sum(), 140.52553833398147, 7)
+        self.assertAlmostEqual(eri1111.real.sum(), 140.52553833398147, 6)
         self.assertAlmostEqual(eri1111.imag.sum(), 0, 7)
-        self.assertAlmostEqual(lib.fp(eri1111), -1.2234059928846319, 7)
-        self.assertTrue(numpy.allclose(eri1111, eri0000))
+        self.assertAlmostEqual(lib.fp(eri1111), -1.2234059928846319, 6)
+        self.assertAlmostEqual(abs(eri1111-eri0000).max(), 0, 6)
 
         eri4444 = kmdf.get_eri((kpts[4],kpts[4],kpts[4],kpts[4]))
         self.assertTrue(eri4444.dtype == numpy.complex128)
-        self.assertAlmostEqual(eri4444.real.sum(), 259.46539833377523, 7)
+        self.assertAlmostEqual(eri4444.real.sum(), 259.46539833377523, 6)
         self.assertAlmostEqual(abs(eri4444.imag).sum(), 0.00010425699058702189, 9)
-        self.assertAlmostEqual(lib.fp(eri4444), 1.9705270829923354-3.6097479693720031e-07j, 6)
+        self.assertAlmostEqual(lib.fp(eri4444), 1.9705270829923354-3.6097479693720031e-07j, 5)
         eri0000 = ao2mo.restore(1, eri0000, cell.nao_nr()).reshape(eri4444.shape)
-        self.assertTrue(numpy.allclose(eri0000, eri4444, atol=1e-7))
+        self.assertAlmostEqual(abs(eri0000-eri4444).max(), 0, 6)
 
     def test_get_eri_1111_high_cost(self):
         eri1111 = kmdf.get_eri((kpts[1],kpts[1],kpts[1],kpts[1]))
         self.assertTrue(eri1111.dtype == numpy.complex128)
         self.assertAlmostEqual(eri1111.real.sum(), 258.81872464108312, 6)
         self.assertAlmostEqual(abs(eri1111.imag).sum(), 16.275864968641145, 7)
-        self.assertAlmostEqual(lib.fp(eri1111), 2.2339104732873363+0.10954687420327755j, 7)
+        self.assertAlmostEqual(lib.fp(eri1111), 2.2339104732873363+0.10954687420327755j, 5)
         check2 = kmdf.get_eri((kpts[1]+5e-9,kpts[1]+5e-9,kpts[1],kpts[1]))
         self.assertTrue(numpy.allclose(eri1111, check2, atol=1e-7))
 
     def test_get_eri_0011_high_cost(self):
         eri0011 = kmdf.get_eri((kpts[0],kpts[0],kpts[1],kpts[1]))
         self.assertTrue(eri0011.dtype == numpy.complex128)
-        self.assertAlmostEqual(eri0011.real.sum(), 259.13073670793142, 7)
-        self.assertAlmostEqual(abs(eri0011.imag).sum(), 8.4042424538275426, 7)
-        self.assertAlmostEqual(lib.fp(eri0011), 2.1374953278715552+0.12350314965485282j, 7)
+        self.assertAlmostEqual(eri0011.real.sum(), 259.13073670793142, 6)
+        self.assertAlmostEqual(abs(eri0011.imag).sum(), 8.4042424538275426, 6)
+        self.assertAlmostEqual(lib.fp(eri0011), 2.1374953278715552+0.12350314965485282j, 5)
 
     def test_get_eri_0110_high_cost(self):
         eri0110 = kmdf.get_eri((kpts[0],kpts[1],kpts[1],kpts[0]))
@@ -135,7 +135,7 @@ def test_get_eri_0123_high_cost(self):
         eri0123 = kmdf.get_eri(kpts[:4])
         self.assertTrue(eri0123.dtype == numpy.complex128)
         self.assertAlmostEqual(eri0123.real.sum(), 410.40005228006925, 6)
-        self.assertAlmostEqual(abs(eri0123.imag.sum()), 0.18510643194748144, 8)
+        self.assertAlmostEqual(abs(eri0123.imag.sum()), 0.18510643194748144, 7)
         self.assertAlmostEqual(lib.fp(eri0123), 1.764025947503265+0.3084202485153878j, 6)
 
     def test_get_eri_gamma_1(self):
diff --git a/pyscf/pbc/df/test/test_mdf_builder.py b/pyscf/pbc/df/test/test_mdf_builder.py
index 6caceafb09..1140c3d241 100644
--- a/pyscf/pbc/df/test/test_mdf_builder.py
+++ b/pyscf/pbc/df/test/test_mdf_builder.py
@@ -178,7 +178,6 @@ def test_ccmdf_vs_fft(self):
         )
 
         dfbuilder = mdf._CCMDFBuilder(cell, auxcell, kpts)
-        dfbuilder.mesh = [7] * 3
         dfbuilder.build()
         j2c = dfbuilder.get_2c2e(np.zeros((1, 3)))
 
@@ -205,26 +204,26 @@ def test_ccmdf_vs_fft(self):
     def test_rsmdf_get_2c2e_gamma(self):
         dfbuilder = mdf._RSMDFBuilder(cell, auxcell).set(mesh=mesh).build()
         j2c = dfbuilder.get_2c2e(np.zeros((1, 3)))
-        self.assertAlmostEqual(lib.fp(j2c), 0.010615787015170507, 9)
+        self.assertAlmostEqual(lib.fp(j2c), 0.010615787015170507, 7)
 
     def test_rsmdf_get_2c2e(self):
         dfbuilder = mdf._RSMDFBuilder(cell, auxcell, kpts).set(mesh=mesh).build()
         j2c = dfbuilder.get_2c2e(kpts)
-        self.assertAlmostEqual(lib.fp(j2c), 0.09006694627014439+0.014552394902466072j, 9)
-        self.assertAlmostEqual(lib.fp(j2c[0]), 0.010615787015170507, 9)
+        self.assertAlmostEqual(lib.fp(j2c), 0.09006694627014439+0.014552394902466072j, 7)
+        self.assertAlmostEqual(lib.fp(j2c[0]), 0.010615787015170507, 7)
 
     def test_rsmdf_get_2c2e_cart(self):
         with lib.temporary_env(cell, cart=True):
             dfbuilder = mdf._RSMDFBuilder(cell, auxcell, kpts).set(mesh=mesh).build()
             j2c = dfbuilder.get_2c2e(kpts)
-        self.assertAlmostEqual(lib.fp(j2c), 0.09006694627014439+0.014552394902466072j, 9)
+        self.assertAlmostEqual(lib.fp(j2c), 0.09006694627014439+0.014552394902466072j, 7)
 
     def test_rsmdf_make_j3c_gamma(self):
         dfbuilder = mdf._RSMDFBuilder(cell, auxcell).set(mesh=mesh).build()
         with tempfile.NamedTemporaryFile() as tmpf:
             dfbuilder.make_j3c(tmpf.name, aosym='s2')
             v2 = load(tmpf.name, kpts[[0, 0]])
-            self.assertAlmostEqual(lib.fp(v2), 0.01486794482668373, 7)
+            self.assertAlmostEqual(lib.fp(v2), 0.01486794482668373, 6)
 
             dfbuilder.make_j3c(tmpf.name, aosym='s1')
             v1 = load(tmpf.name, kpts[[0, 0]])
@@ -235,19 +234,19 @@ def test_rsmdf_make_j3c_gamma(self):
             dfbuilder.exclude_d_aux = False
             dfbuilder.make_j3c(tmpf.name, aosym='s2')
             v2 = load(tmpf.name, kpts[[0, 0]])
-            self.assertAlmostEqual(lib.fp(v2), 0.01486794482668373, 7)
+            self.assertAlmostEqual(lib.fp(v2), 0.01486794482668373, 6)
 
             dfbuilder.fft_dd_block = False
             dfbuilder.exclude_d_aux = True
             dfbuilder.make_j3c(tmpf.name, aosym='s2')
             v2 = load(tmpf.name, kpts[[0, 0]])
-            self.assertAlmostEqual(lib.fp(v2), 0.01486794482668373, 7)
+            self.assertAlmostEqual(lib.fp(v2), 0.01486794482668373, 6)
 
             dfbuilder.fft_dd_block = False
             dfbuilder.exclude_d_aux = False
             dfbuilder.make_j3c(tmpf.name, aosym='s2')
             v2 = load(tmpf.name, kpts[[0, 0]])
-            self.assertAlmostEqual(lib.fp(v2), 0.01486794482668373, 7)
+            self.assertAlmostEqual(lib.fp(v2), 0.01486794482668373, 6)
 
     def test_rsmdf_make_j3c(self):
         dfbuilder = mdf._RSMDFBuilder(cell, auxcell, kpts).set(mesh=mesh).build()
@@ -257,9 +256,9 @@ def test_rsmdf_make_j3c(self):
             for ki in range(nkpts):
                 for kj in range(nkpts):
                     v_s2.append(load(tmpf.name, kpts[[ki, kj]]))
-            self.assertAlmostEqual(lib.fp(v_s2[0]), 0.01486794482668373, 7)
-            self.assertAlmostEqual(lib.fp(v_s2[2*nkpts+4]), 0.0009656916277807118+0.011048147592950475j, 7)
-            self.assertAlmostEqual(lib.fp(v_s2[2*nkpts+2]), 0.01509142892728263+0j, 7)
+            self.assertAlmostEqual(lib.fp(v_s2[0]), 0.01486794482668373, 6)
+            self.assertAlmostEqual(lib.fp(v_s2[2*nkpts+4]), 0.0009656916277807118+0.011048147592950475j, 6)
+            self.assertAlmostEqual(lib.fp(v_s2[2*nkpts+2]), 0.01509142892728263+0j, 6)
 
             dfbuilder.make_j3c(tmpf.name, aosym='s1')
             idx, idy = np.tril_indices(cell.nao)
@@ -278,8 +277,8 @@ def test_rsmdf_make_j3c_j_only(self):
             v_s2 = []
             for ki in range(nkpts):
                 v_s2.append(load(tmpf.name, kpts[[ki, ki]]))
-            self.assertAlmostEqual(lib.fp(v_s2[0]), 0.01486794482668373, 7)
-            self.assertAlmostEqual(lib.fp(v_s2[2]), 0.01509142892728263+0j, 7)
+            self.assertAlmostEqual(lib.fp(v_s2[0]), 0.01486794482668373, 6)
+            self.assertAlmostEqual(lib.fp(v_s2[2]), 0.01509142892728263+0j, 6)
 
             dfbuilder.make_j3c(tmpf.name, aosym='s1', j_only=True)
             idx, idy = np.tril_indices(cell.nao)
@@ -501,7 +500,6 @@ def test_ccmdf_vs_fft_sr(self):
         )
 
         dfbuilder = mdf._CCMDFBuilder(cell_sr, auxcell_sr, kpts)
-        dfbuilder.mesh = [7] * 3
         dfbuilder.build()
         j2c = dfbuilder.get_2c2e(np.zeros((1, 3)))
 
@@ -525,26 +523,26 @@ def test_ccmdf_vs_fft_sr(self):
         with tempfile.NamedTemporaryFile() as tmpf:
             dfbuilder.make_j3c(tmpf.name, aosym='s2', j_only=True)
             v1 = load(tmpf.name, kpts[[0, 0]])
-            self.assertAlmostEqual(abs(ref - v1).max(), 0, 7)
+            self.assertAlmostEqual(abs(ref - v1).max(), 0, 8)
 
 #### Test _RSMDFBuilder with omega < 0 ####
 
     def test_rsmdf_get_2c2e_gamma_sr(self):
         dfbuilder = mdf._RSMDFBuilder(cell_sr, auxcell_sr).set(mesh=mesh).build()
         j2c = dfbuilder.get_2c2e(np.zeros((1, 3)))
-        self.assertAlmostEqual(lib.fp(j2c), 0.010646767031704538, 9)
+        self.assertAlmostEqual(lib.fp(j2c), 0.010646767031704538, 6)
 
     def test_rsmdf_get_2c2e_sr(self):
         dfbuilder = mdf._RSMDFBuilder(cell_sr, auxcell_sr, kpts).set(mesh=mesh).build()
         j2c = dfbuilder.get_2c2e(kpts)
-        self.assertAlmostEqual(lib.fp(j2c), 0.0902078021182187+0.01449234991201075j, 9)
-        self.assertAlmostEqual(lib.fp(j2c[0]), 0.010646767031704538, 9)
+        self.assertAlmostEqual(lib.fp(j2c), 0.0902078021182187+0.01449234991201075j, 6)
+        self.assertAlmostEqual(lib.fp(j2c[0]), 0.010646767031704538, 6)
 
     def test_rsmdf_get_2c2e_cart_sr(self):
         with lib.temporary_env(cell_sr, cart=True):
             dfbuilder = mdf._RSMDFBuilder(cell_sr, auxcell_sr, kpts).set(mesh=mesh).build()
             j2c = dfbuilder.get_2c2e(kpts)
-        self.assertAlmostEqual(lib.fp(j2c), 0.0902078021182187+0.01449234991201075j, 9)
+        self.assertAlmostEqual(lib.fp(j2c), 0.0902078021182187+0.01449234991201075j, 6)
 
     def test_rsmdf_make_j3c_gamma_sr(self):
         dfbuilder = mdf._RSMDFBuilder(cell_sr, auxcell_sr).set(mesh=mesh).build()
diff --git a/pyscf/pbc/df/test/test_mdf_jk.py b/pyscf/pbc/df/test/test_mdf_jk.py
index 2ce03363da..04f97b740d 100644
--- a/pyscf/pbc/df/test/test_mdf_jk.py
+++ b/pyscf/pbc/df/test/test_mdf_jk.py
@@ -82,7 +82,7 @@ def test_jk_single_kpt(self):
         ej1 = numpy.einsum('ij,ji->', vj1, dm)
         ek1 = numpy.einsum('ij,ji->', vk1, dm)
         self.assertAlmostEqual(ej1, 25.81378242361819, 6)
-        self.assertAlmostEqual(ek1, 72.6092971275962 , 6)
+        self.assertAlmostEqual(ek1, 72.6092971275962 , 5)
 
     def test_jk_single_kpt_high_cost(self):
         mf = mdf_jk.density_fit(mf0, auxbasis='weigend', mesh=(11,)*3)
@@ -104,7 +104,7 @@ def test_jk_single_kpt_high_cost(self):
         ej1 = numpy.einsum('ij,ji->', vj1, dm)
         ek1 = numpy.einsum('ij,ji->', vk1, dm)
         self.assertAlmostEqual(ej1, 242.19379703364774, 6)
-        self.assertAlmostEqual(ek1, 280.28450527230103, 6)
+        self.assertAlmostEqual(ek1, 280.28450527230103, 5)
 
         numpy.random.seed(1)
         kpt = numpy.random.random(3)
@@ -116,7 +116,7 @@ def test_jk_single_kpt_high_cost(self):
         ej1 = numpy.einsum('ij,ji->', vj, dm)
         ek1 = numpy.einsum('ij,ji->', vk, dm)
         self.assertAlmostEqual(ej1, 241.29955504573206+0j, 6)
-        self.assertAlmostEqual(ek1, 691.76854602384913+0j, 6)
+        self.assertAlmostEqual(ek1, 691.76854602384913+0j, 5)
 
     def test_jk_hermi0(self):
         numpy.random.seed(12)
@@ -148,7 +148,7 @@ def test_jk_hermi0_high_cost(self):
         ej0 = numpy.einsum('ij,ji->', vj0, dm)
         ek0 = numpy.einsum('ij,ji->', vk0, dm)
         self.assertAlmostEqual(ej0, 242.18855706416096, 6)
-        self.assertAlmostEqual(ek0, 280.70982164657647, 6)
+        self.assertAlmostEqual(ek0, 280.70982164657647, 5)
 
     def test_j_kpts(self):
         numpy.random.seed(1)
diff --git a/pyscf/pbc/df/test/test_rsdf_scf.py b/pyscf/pbc/df/test/test_rsdf_scf.py
index eaf1b644ef..b7e1e09f22 100644
--- a/pyscf/pbc/df/test/test_rsdf_scf.py
+++ b/pyscf/pbc/df/test/test_rsdf_scf.py
@@ -55,14 +55,14 @@ def test_h2_jonly_k211(self):
         mf = pscf.KRKS(cell,kpts).rs_density_fit()
         mf.xc = "pbe"
         mf.kernel()
-        self.assertAlmostEqual(mf.e_tot, -1.0021023542499443, 7)
+        self.assertAlmostEqual(mf.e_tot, -1.0021025295489245, 7)
 
     def test_h2_jonly_k211_shiftedcenter(self):
         kpts = cell.make_kpts([2,1,1],scaled_center=scaled_center)
         mf = pscf.KRKS(cell,kpts).rs_density_fit()
         mf.xc = "pbe"
         mf.kernel()
-        self.assertAlmostEqual(mf.e_tot, -1.0047041613565, 7)
+        self.assertAlmostEqual(mf.e_tot, -1.004704372120814, 7)
 
     def test_h2_jk_k211(self):
         kpts = cell.make_kpts([2,1,1])
diff --git a/pyscf/pbc/dft/test/test_gen_grid.py b/pyscf/pbc/dft/test/test_gen_grid.py
index 0d60736cdd..aa3ee8f890 100644
--- a/pyscf/pbc/dft/test/test_gen_grid.py
+++ b/pyscf/pbc/dft/test/test_gen_grid.py
@@ -53,8 +53,8 @@ def test_becke_grids(self):
         grids.build()
         s1 = get_ovlp(cell, grids)
         s2 = cell.pbc_intor('int1e_ovlp_sph')
-        self.assertAlmostEqual(numpy.linalg.norm(s1-s2), 0, 5)
-        self.assertEqual(grids.weights.size, 15416)
+        self.assertAlmostEqual(numpy.linalg.norm(s1-s2), 0, 4)
+        self.assertEqual(grids.weights.size, 14742)
 
     def test_becke_grids_2d(self):
         L = 4.
@@ -76,7 +76,7 @@ def test_becke_grids_2d(self):
         s1 = get_ovlp(cell, grids)
         s2 = cell.pbc_intor('int1e_ovlp_sph')
         self.assertAlmostEqual(numpy.linalg.norm(s1-s2), 0, 5)
-        self.assertEqual(grids.weights.size, 8374)
+        self.assertEqual(grids.weights.size, 7624)
 
     def test_becke_grids_1d(self):
         L = 4.
@@ -105,7 +105,7 @@ def test_becke_grids_2d_low_dim_ft_type(self):
         cell = pgto.Cell()
         cell.a = numpy.eye(3)*L
         cell.a[1,0] = cell.a[1,1] = L / 2
-        cell.a[2] *= 2
+        cell.a[2,2] = L * 2
         cell.mesh = numpy.array([n,n,n])
 
         cell.atom = 'He 1 0 1'
@@ -119,11 +119,13 @@ def test_becke_grids_2d_low_dim_ft_type(self):
         s1 = get_ovlp(cell, grids)
         s2 = cell.pbc_intor('int1e_ovlp_sph')
         self.assertAlmostEqual(numpy.linalg.norm(s1-s2), 0, 5)
-        self.assertEqual(grids.weights.size, 8347)
+        self.assertEqual(grids.weights.size, 7560)
+
+        grids = gen_grid.UniformGrids(cell)
+        s1 = get_ovlp(cell, grids)
+        self.assertAlmostEqual(numpy.linalg.norm(s1-s2), 0, 5)
 
 
 if __name__ == '__main__':
     print("Full Tests for Becke grids")
     unittest.main()
-
-
diff --git a/pyscf/pbc/dft/test/test_kgks.py b/pyscf/pbc/dft/test/test_kgks.py
index 61031a25b4..21fbf9dbde 100644
--- a/pyscf/pbc/dft/test/test_kgks.py
+++ b/pyscf/pbc/dft/test/test_kgks.py
@@ -36,6 +36,7 @@ def setUpModule():
     cell.basis = 'gth-dzvp'
     cell.pseudo = 'gth-pade'
     cell.verbose = 0
+    cell.mesh = [29] * 3
     cell.build()
     kmesh = [2, 1, 1]
     kpts = cell.make_kpts(kmesh, wrap_around=True)
@@ -90,7 +91,7 @@ def test_KGKS_sfx2c1e_high_cost(self):
                 mf.conv_tol = 1e-10
                 e_kgks = mf.kernel()
                 print(e_kgks)
-            self.assertAlmostEqual(e_kgks, -75.67071562222077, 5)
+            self.assertAlmostEqual(e_kgks, -75.67071562222077, 4)
 
     def test_KGKS_x2c1e_high_cost(self):
         with lib.light_speed(10) as c:
@@ -101,7 +102,7 @@ def test_KGKS_x2c1e_high_cost(self):
                 mf.conv_tol = 1e-10
                 e_kgks = mf.kernel()
                 print(e_kgks)
-            self.assertAlmostEqual(e_kgks, -75.66883793093882, 5)
+            self.assertAlmostEqual(e_kgks, -75.66883793093882, 4)
 
 
 if __name__ == '__main__':
diff --git a/pyscf/pbc/dft/test/test_krkspu.py b/pyscf/pbc/dft/test/test_krkspu.py
index d4e00064fd..9904f92523 100644
--- a/pyscf/pbc/dft/test/test_krkspu.py
+++ b/pyscf/pbc/dft/test/test_krkspu.py
@@ -23,20 +23,29 @@
 from pyscf.pbc import gto as pgto
 from pyscf.pbc import dft as pdft
 
+def setUpModule():
+    global cell
+    cell = pgto.Cell()
+    cell.unit = 'A'
+    cell.atom = 'C 0.,  0.,  0.; C 0.8917,  0.8917,  0.8917'
+    cell.a = '''0.      1.7834  1.7834
+                1.7834  0.      1.7834
+                1.7834  1.7834  0.    '''
+
+    cell.basis = 'gth-dzvp'
+    cell.pseudo = 'gth-pade'
+    cell.verbose = 7
+    cell.output = '/dev/null'
+    cell.mesh = [29]*3
+    cell.build()
+
+def tearDownModule():
+    global cell
+    cell.stdout.close()
+    del cell
+
 class KnownValues(unittest.TestCase):
     def test_KRKSpU_high_cost(self):
-        cell = pgto.Cell()
-        cell.unit = 'A'
-        cell.atom = 'C 0.,  0.,  0.; C 0.8917,  0.8917,  0.8917'
-        cell.a = '''0.      1.7834  1.7834
-                    1.7834  0.      1.7834
-                    1.7834  1.7834  0.    '''
-
-        cell.basis = 'gth-dzvp'
-        cell.pseudo = 'gth-pade'
-        cell.verbose = 7
-        cell.output = '/dev/null'
-        cell.build()
         kmesh = [2, 1, 1]
         kpts = cell.make_kpts(kmesh, wrap_around=True)
         U_idx = ["1 C 2p"]
@@ -49,18 +58,6 @@ def test_KRKSpU_high_cost(self):
         self.assertAlmostEqual(e1, -10.694460059491741, 8)
 
     def test_KRKSpU_ksymm(self):
-        cell = pgto.Cell()
-        cell.unit = 'A'
-        cell.atom = 'C 0.,  0.,  0.; C 0.8917,  0.8917,  0.8917'
-        cell.a = '''0.      1.7834  1.7834
-                    1.7834  0.      1.7834
-                    1.7834  1.7834  0.    '''
-
-        cell.basis = 'gth-dzvp'
-        cell.pseudo = 'gth-pade'
-        cell.verbose = 7
-        cell.output = '/dev/null'
-        cell.build()
         U_idx = ["1 C 2p"]
         U_val = [5.0]
         kmesh = [2, 2, 1]
@@ -73,18 +70,6 @@ def test_KRKSpU_ksymm(self):
         self.assertAlmostEqual(e1, -11.0115546012593, 8)
 
     def test_get_veff(self):
-        cell = pgto.Cell()
-        cell.unit = 'A'
-        cell.atom = 'C 0.,  0.,  0.; C 0.8917,  0.8917,  0.8917'
-        cell.a = '''0.      1.7834  1.7834
-                    1.7834  0.      1.7834
-                    1.7834  1.7834  0.    '''
-
-        cell.basis = 'gth-dzvp'
-        cell.pseudo = 'gth-pade'
-        cell.verbose = 7
-        cell.output = '/dev/null'
-        cell.build()
         kmesh = [2, 1, 1]
         kpts = cell.make_kpts(kmesh, wrap_around=True)
         U_idx = ["1 C 2p"]
diff --git a/pyscf/pbc/dft/test/test_kukspu.py b/pyscf/pbc/dft/test/test_kukspu.py
index 74e8ad8ee1..b6b9bceefc 100644
--- a/pyscf/pbc/dft/test/test_kukspu.py
+++ b/pyscf/pbc/dft/test/test_kukspu.py
@@ -23,20 +23,29 @@
 from pyscf.pbc import gto as pgto
 from pyscf.pbc import dft as pdft
 
+def setUpModule():
+    global cell
+    cell = pgto.Cell()
+    cell.unit = 'A'
+    cell.atom = 'C 0.,  0.,  0.; C 0.8917,  0.8917,  0.8917'
+    cell.a = '''0.      1.7834  1.7834
+                1.7834  0.      1.7834
+                1.7834  1.7834  0.    '''
+
+    cell.basis = 'gth-dzvp'
+    cell.pseudo = 'gth-pade'
+    cell.verbose = 7
+    cell.output = '/dev/null'
+    cell.mesh = [29]*3
+    cell.build()
+
+def tearDownModule():
+    global cell
+    cell.stdout.close()
+    del cell
+
 class KnownValues(unittest.TestCase):
     def test_KUKSpU_high_cost(self):
-        cell = pgto.Cell()
-        cell.unit = 'A'
-        cell.atom = 'C 0.,  0.,  0.; C 0.8917,  0.8917,  0.8917'
-        cell.a = '''0.      1.7834  1.7834
-                    1.7834  0.      1.7834
-                    1.7834  1.7834  0.    '''
-
-        cell.basis = 'gth-dzvp'
-        cell.pseudo = 'gth-pade'
-        cell.verbose = 7
-        cell.output = '/dev/null'
-        cell.build()
         kmesh = [2, 1, 1]
         kpts = cell.make_kpts(kmesh, wrap_around=True)
         U_idx = ["1 C 2p"]
@@ -49,18 +58,6 @@ def test_KUKSpU_high_cost(self):
         self.assertAlmostEqual(e1, -10.694460059491741, 8)
 
     def test_KUKSpU_ksymm(self):
-        cell = pgto.Cell()
-        cell.unit = 'A'
-        cell.atom = 'C 0.,  0.,  0.; C 0.8917,  0.8917,  0.8917'
-        cell.a = '''0.      1.7834  1.7834
-                    1.7834  0.      1.7834
-                    1.7834  1.7834  0.    '''
-
-        cell.basis = 'gth-dzvp'
-        cell.pseudo = 'gth-pade'
-        cell.verbose = 7
-        cell.output = '/dev/null'
-        cell.build()
         U_idx = ["1 C 2p"]
         U_val = [5.0]
         kmesh = [2, 2, 1]
@@ -73,18 +70,6 @@ def test_KUKSpU_ksymm(self):
         self.assertAlmostEqual(e1, -11.0115546012593, 8)
 
     def test_get_veff(self):
-        cell = pgto.Cell()
-        cell.unit = 'A'
-        cell.atom = 'C 0.,  0.,  0.; C 0.8917,  0.8917,  0.8917'
-        cell.a = '''0.      1.7834  1.7834
-                    1.7834  0.      1.7834
-                    1.7834  1.7834  0.    '''
-
-        cell.basis = 'gth-dzvp'
-        cell.pseudo = 'gth-pade'
-        cell.verbose = 7
-        cell.output = '/dev/null'
-        cell.build()
         kmesh = [2, 1, 1]
         kpts = cell.make_kpts(kmesh, wrap_around=True)
         U_idx = ["1 C 2p"]
diff --git a/pyscf/pbc/dft/test/test_multigrid.py b/pyscf/pbc/dft/test/test_multigrid.py
index ed953a388e..01614eb7e2 100644
--- a/pyscf/pbc/dft/test/test_multigrid.py
+++ b/pyscf/pbc/dft/test/test_multigrid.py
@@ -119,7 +119,7 @@ def test_orth_rks_lda_kpts(self):
         n, exc0, ref = ni.nr_rks(cell_orth, mydf.grids, xc, dm, 1, kpts=kpts)
         mydf = multigrid.MultiGridFFTDF(cell_orth)
         n, exc1, vxc = multigrid.nr_rks(mydf, xc, dm, kpts=kpts)
-        self.assertAlmostEqual(float(abs(ref-vxc).max()), 0, 8)
+        self.assertAlmostEqual(float(abs(ref-vxc).max()), 0, 7)
         self.assertAlmostEqual(abs(exc0-exc1).max(), 0, 7)
 
     def test_multigrid_kuks(self):
@@ -127,18 +127,18 @@ def test_multigrid_kuks(self):
         mf.xc = 'lda,'
         ref = mf.get_veff(cell_he, numpy.array((dm_he,dm_he)), kpts=kpts)
         out = multigrid.multigrid(mf).get_veff(cell_he, (dm_he,dm_he), kpts=kpts)
-        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 9)
-        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 9)
-        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 9)
+        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 8)
+        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 8)
+        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 8)
 
     def test_multigrid_krks(self):
         mf = dft.KRKS(cell_he)
         mf.xc = 'lda,'
         ref = mf.get_veff(cell_he, dm_he, kpts=kpts)
         out = multigrid.multigrid(mf).get_veff(cell_he, dm_he, kpts=kpts)
-        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 9)
-        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 9)
-        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 9)
+        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 8)
+        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 8)
+        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 8)
 
     def test_multigrid_kroks(self):
         mf = dft.KROKS(cell_he)
@@ -151,27 +151,27 @@ def test_multigrid_kroks(self):
                             mo_occ=mo_occ*2)
         ref = mf.get_veff(cell_he, dm1, kpts=kpts)
         out = multigrid.multigrid(mf).get_veff(cell_he, dm1, kpts=kpts)
-        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 9)
-        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 9)
-        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 9)
+        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 7)
+        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 7)
+        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 7)
 
     def test_multigrid_uks(self):
         mf = dft.UKS(cell_he)
         mf.xc = 'lda,'
         ref = mf.get_veff(cell_he, numpy.array((dm_he[0],dm_he[0])))
         out = multigrid.multigrid(mf).get_veff(cell_he, (dm_he[0], dm_he[0]))
-        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 9)
-        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 9)
-        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 9)
+        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 7)
+        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 7)
+        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 7)
 
     def test_multigrid_rks(self):
         mf = dft.RKS(cell_he)
         mf.xc = 'lda,'
         ref = mf.get_veff(cell_he, dm_he[0])
         out = multigrid.multigrid(mf).get_veff(cell_he, dm_he[0])
-        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 9)
-        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 9)
-        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 9)
+        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 7)
+        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 7)
+        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 7)
 
     def test_multigrid_roks(self):
         mf = dft.ROKS(cell_he)
@@ -184,9 +184,9 @@ def test_multigrid_roks(self):
                             mo_occ=mo_occ*2)
         ref = mf.get_veff(cell_he, dm1)
         out = multigrid.multigrid(mf).get_veff(cell_he, dm1)
-        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 9)
-        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 9)
-        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 8)
+        self.assertAlmostEqual(float(abs(ref-out).max()), 0, 7)
+        self.assertAlmostEqual(abs(ref.exc-out.exc).max(), 0, 7)
+        self.assertAlmostEqual(abs(ref.ecoul-out.ecoul).max(), 0, 7)
 
     def test_orth_rks_gga_kpts(self):
         xc = 'b88,'
@@ -196,9 +196,9 @@ def test_orth_rks_gga_kpts(self):
         ref += mydf.get_jk(dm, hermi=1, with_k=False, kpts=kpts)[0]
         mydf = multigrid.MultiGridFFTDF(cell_orth)
         n, exc1, vxc = multigrid.nr_rks(mydf, xc, dm, hermi=1, kpts=kpts, with_j=True)
-        self.assertAlmostEqual(abs(ref-vxc).max(), 0, 8)
+        self.assertAlmostEqual(abs(ref-vxc).max(), 0, 7)
         self.assertAlmostEqual(abs(exc0-exc1).max(), 0, 7)
-        self.assertAlmostEqual(lib.fp(ref), -0.05697304864467462+0.6990367789096609j, 8)
+        self.assertAlmostEqual(lib.fp(ref), -0.05697304864467462+0.6990367789096609j, 7)
 
     def test_eval_rhoG_orth_kpts(self):
         numpy.random.seed(9)
@@ -262,7 +262,7 @@ def test_gen_rhf_response(self):
         v = multigrid._gen_rhf_response(mf, dm_he, hermi=1)(dm1)
         self.assertEqual(ref.dtype, v.dtype)
         self.assertEqual(ref.shape, v.shape)
-        self.assertAlmostEqual(abs(v-ref).max(), 0, 9)
+        self.assertAlmostEqual(abs(v-ref).max(), 0, 8)
 
         mf.xc = 'b88,'
         ref = dft.numint.nr_rks_fxc(ni, cell_he, mydf.grids, mf.xc, dm_he, dm1,
@@ -380,7 +380,7 @@ def test_gen_uhf_response(self):
         v = multigrid._gen_uhf_response(mf, dm_he, with_j=True, hermi=1)(dm1)
         self.assertEqual(ref.dtype, v.dtype)
         self.assertEqual(ref.shape, v.shape)
-        self.assertAlmostEqual(abs(v-ref).max(), 0, 9)
+        self.assertAlmostEqual(abs(v-ref).max(), 0, 7)
 
         mf.xc = 'b88,'
         ref = dft.numint.nr_uks_fxc(ni, cell_he, mydf.grids, mf.xc, dm_he, dm1, hermi=1)
@@ -448,7 +448,7 @@ def test_rcut_vs_ke_cut(self):
             mg_df = multigrid.MultiGridFFTDF(cell_orth)
             n2, exc2, v2 = multigrid.nr_rks(mg_df, xc, dm1, kpts=kpts)
             self.assertEqual(len(mg_df.tasks), 6)
-        self.assertAlmostEqual(n1, n2, 7)
+        self.assertAlmostEqual(n1, n2, 6)
         self.assertAlmostEqual(exc1, exc2, 7)
         self.assertAlmostEqual(abs(v1-v2).max(), 0, 7)
 
diff --git a/pyscf/pbc/dft/test/test_numint.py b/pyscf/pbc/dft/test/test_numint.py
index 6a3dab0de8..75a40fe514 100644
--- a/pyscf/pbc/dft/test/test_numint.py
+++ b/pyscf/pbc/dft/test/test_numint.py
@@ -45,6 +45,14 @@ def eval_ao(cell, coords, kpt=numpy.zeros(3), deriv=0, relativity=0, shls_slice=
                                             shls_slice, non0tab, out, verbose) * factor
     return numpy.asarray(aoR)
 
+def coords_wrap_around_phase(cell, coords, kpts):
+    ngrids = coords.shape[0]
+    fac = np.exp(1j*cell.lattice_vectors().dot(kpts.T))
+    fac = np.repeat(fac[None,:,:], ngrids, axis=0)
+    fac[coords>=0] = 1
+    fac = np.prod(fac, axis=1)
+    return fac
+
 def make_grids(mesh):
     L = 60
     cell = pbcgto.Cell()
@@ -131,7 +139,17 @@ def test_eval_ao_kpts(self):
         np.random.seed(1)
         kpts = np.random.random((4,3))
         ni = numint.KNumInt(kpts)
-        ao1 = ni.eval_ao(cell, grids.coords, kpts)
+        coords = grids.coords
+        ao1 = ni.eval_ao(cell, coords, kpts)
+        fac = coords_wrap_around_phase(cell, coords, kpts)
+
+        self.assertAlmostEqual(lib.fp(ao1[0]*fac[:,0:1]), (-2.4066959390326477-0.98044994099240701j), 8)
+        self.assertAlmostEqual(lib.fp(ao1[1]*fac[:,1:2]), (-0.30643153325360639+0.1571658820483913j), 8)
+        self.assertAlmostEqual(lib.fp(ao1[2]*fac[:,2:3]), (-1.1937974302337684-0.39039259235266233j), 8)
+        self.assertAlmostEqual(lib.fp(ao1[3]*fac[:,3:4]), (0.17701966968272009-0.20232879692603079j), 8)
+
+        coords = cell.get_uniform_grids(wrap_around=False)
+        ao1 = ni.eval_ao(cell, coords, kpts)
         self.assertAlmostEqual(lib.fp(ao1[0]), (-2.4066959390326477-0.98044994099240701j), 8)
         self.assertAlmostEqual(lib.fp(ao1[1]), (-0.30643153325360639+0.1571658820483913j), 8)
         self.assertAlmostEqual(lib.fp(ao1[2]), (-1.1937974302337684-0.39039259235266233j), 8)
@@ -156,7 +174,8 @@ def test_eval_ao_kpt(self):
         ao0 = eval_ao(cell, grids.coords, kpt)
         ao1 = ni.eval_ao(cell, grids.coords, kpt)
         self.assertAlmostEqual(abs(ao0 - ao1).max(), 0, 10)
-        self.assertAlmostEqual(lib.fp(ao1), (-2.4066959390326477-0.98044994099240701j), 8)
+        fac = coords_wrap_around_phase(cell, grids.coords, kpt[None])
+        self.assertAlmostEqual(lib.fp(ao1*fac), (-2.4066959390326477-0.98044994099240701j), 8)
 
     def test_nr_rks(self):
         cell = pbcgto.Cell()
@@ -177,8 +196,7 @@ def test_nr_rks(self):
         dms = np.random.random((2,nao,nao))
         dms = (dms + dms.transpose(0,2,1)) * .5
         ni = numint.NumInt()
-        with lib.temporary_env(pbcgto.eval_gto, EXTRA_PREC=1e-5):
-            ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', dms[0], 1, kpts[0])
+        ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', dms[0], 1, kpts[0])
         self.assertAlmostEqual(ne, 5.0499199224525153, 8)
         self.assertAlmostEqual(exc, -3.8870579114663886, 8)
         self.assertAlmostEqual(lib.fp(vmat), 0.42538491159934377+0.14139753327162483j, 8)
@@ -188,15 +206,15 @@ def test_nr_rks(self):
             ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', dms, 1, kpts)
         self.assertAlmostEqual(ne, 6.0923292346269742, 8)
         self.assertAlmostEqual(exc, -3.9899423803106466, 8)
-        self.assertAlmostEqual(lib.fp(vmat[0]), -2348.9577179701278-60.733087913116719j, 7)
-        self.assertAlmostEqual(lib.fp(vmat[1]), -2353.0350086740673-117.74811536967495j, 7)
+        self.assertAlmostEqual(lib.fp(vmat[0]), -2348.9577179701278-60.733087913116719j, 6)
+        self.assertAlmostEqual(lib.fp(vmat[1]), -2353.0350086740673-117.74811536967495j, 6)
 
         with lib.temporary_env(pbcgto.eval_gto, EXTRA_PREC=1e-5):
             ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', [dms,dms], 1, kpts)
         self.assertAlmostEqual(ne[1], 6.0923292346269742, 8)
         self.assertAlmostEqual(exc[1], -3.9899423803106466, 8)
-        self.assertAlmostEqual(lib.fp(vmat[1][0]), -2348.9577179701278-60.733087913116719j, 7)
-        self.assertAlmostEqual(lib.fp(vmat[1][1]), -2353.0350086740673-117.74811536967495j, 7)
+        self.assertAlmostEqual(lib.fp(vmat[1][0]), -2348.9577179701278-60.733087913116719j, 6)
+        self.assertAlmostEqual(lib.fp(vmat[1][1]), -2353.0350086740673-117.74811536967495j, 6)
 
     def test_eval_rho(self):
         cell, grids = make_grids([61]*3)
@@ -275,6 +293,7 @@ def test_2d_rho(self):
         cell.build()
         grids = gen_grid.UniformGrids(cell)
         grids.build()
+        grids.coords = cell.get_uniform_grids(wrap_around=False)
         numpy.random.seed(10)
         nao = cell.nao_nr()
         dm = numpy.random.random((nao,nao))
@@ -296,6 +315,7 @@ def test_1d_rho(self):
         cell.build()
         grids = gen_grid.UniformGrids(cell)
         grids.build()
+        grids.coords = cell.get_uniform_grids(wrap_around=False)
         numpy.random.seed(10)
         nao = cell.nao_nr()
         dm = numpy.random.random((nao,nao))
@@ -304,6 +324,29 @@ def test_1d_rho(self):
         rho = numint.get_rho(ni, cell, dm, grids)
         self.assertAlmostEqual(lib.fp(rho), 1.1624587519868457, 9)
 
+    def test_3d_rho(self):
+        cell = pbcgto.Cell()
+        cell.a = '3 0 0; 0 3 0; 0 0 3'
+        cell.unit = 'B'
+        cell.atom = 'He     1.    0.       1.'
+        cell.basis = {'He': '321g'}
+        cell.verbose = 0
+        cell.mesh = [20,20,20]
+        cell.build()
+        grids = gen_grid.UniformGrids(cell)
+        grids.build()
+        numpy.random.seed(10)
+        nao = cell.nao_nr()
+        dm = numpy.random.random((nao,nao))
+        dm = dm + dm.T
+        ni = numint.NumInt()
+        rho = numint.get_rho(ni, cell, dm, grids)
+        self.assertAlmostEqual(lib.fp(rho), 1.4639787098513968, 9)
+
+        grids.coords = cell.get_uniform_grids(wrap_around=False)
+        rho1 = numint.get_rho(ni, cell, dm, grids)
+        self.assertAlmostEqual(abs(rho - rho1).max(), 0, 9)
+
 if __name__ == '__main__':
     print("Full Tests for pbc.dft.numint")
     unittest.main()
diff --git a/pyscf/pbc/dft/test/test_rks.py b/pyscf/pbc/dft/test/test_rks.py
index 7fe5ff8f62..04730c18bf 100644
--- a/pyscf/pbc/dft/test/test_rks.py
+++ b/pyscf/pbc/dft/test/test_rks.py
@@ -137,7 +137,22 @@ def test_density_fit(self):
         cell.build()
         mf = pbcdft.RKS(cell).density_fit()
         mf.kernel()
-        self.assertAlmostEqual(mf.e_tot, -4.717699891018736, 7)
+        self.assertAlmostEqual(mf.e_tot, -4.717699891018736, 6)
+
+    def test_density_fit_2d(self):
+        L = 4.
+        cell = pbcgto.Cell()
+        cell.a = np.eye(3)*L
+        cell.a[2,2] = 12
+        cell.dimension = 2
+        cell.unit = 'B'
+        cell.atom = 'H 0 0 0; H .8 .8 0'
+        cell.basis = {'H': [[0, (4.0, 1.0)], [0, (1.0, 1.0)]]}
+        cell.build()
+        mf = pbcdft.RKS(cell).run()
+        self.assertAlmostEqual(mf.e_tot, -0.6252695697315944, 7)
+        mf = pbcdft.RKS(cell).density_fit().run()
+        self.assertAlmostEqual(mf.e_tot, -0.635069614773985, 5)
 
     def test_rsh_fft(self):
         mf = pbcdft.RKS(cell)
diff --git a/pyscf/pbc/gto/test/test_cell.py b/pyscf/pbc/gto/test/test_cell.py
index 226eda810f..4f20093e56 100644
--- a/pyscf/pbc/gto/test/test_cell.py
+++ b/pyscf/pbc/gto/test/test_cell.py
@@ -24,6 +24,7 @@
 from pyscf import lib
 from pyscf.pbc import gto as pgto
 from pyscf.pbc.gto import ecp
+from pyscf.pbc.tools import pbc as pbctools
 
 
 def setUpModule():
@@ -121,20 +122,8 @@ def test_ewald(self):
         cell.output = '/dev/null'
         cell.build()
 
-        ew_cut = (20,20,20)
-        self.assertAlmostEqual(cell.ewald(.05, 100), -0.468640671931, 9)
-        self.assertAlmostEqual(cell.ewald(0.1, 100), -0.468640671931, 9)
-        self.assertAlmostEqual(cell.ewald(0.2, 100), -0.468640671931, 9)
-        self.assertAlmostEqual(cell.ewald(1  , 100), -0.468640671931, 9)
-
-        def check(precision, eta_ref, ewald_ref):
-            ew_eta0, ew_cut0 = cell.get_ewald_params(precision, mesh=[41]*3)
-            self.assertAlmostEqual(ew_eta0, eta_ref)
-            self.assertAlmostEqual(cell.ewald(ew_eta0, ew_cut0), ewald_ref, 9)
-        check(0.001, 3.15273336976, -0.468640679947)
-        check(1e-05, 2.77596886114, -0.468640671968)
-        check(1e-07, 2.50838938833, -0.468640671931)
-        check(1e-09, 2.30575091612, -0.468640671931)
+        self.assertAlmostEqual(cell.ewald(0.2, 30), -0.468640671931, 9)
+        self.assertAlmostEqual(cell.ewald(1  , 30), -0.468640671931, 9)
 
         cell = pgto.Cell()
         numpy.random.seed(10)
@@ -151,6 +140,32 @@ def check(precision, eta_ref, ewald_ref):
         self.assertAlmostEqual(cell.ewald(2, 10), -2.3711356723457615, 9)
         self.assertAlmostEqual(cell.ewald(2,  5), -2.3711356723457615, 9)
 
+    def test_ewald_vs_supercell(self):
+        a  = 4.1705
+        cell = pgto.Cell()
+        cell.a = a * np.asarray([
+            [1, 0.5, 0.5],
+            [0.5, 1, 0.5],
+            [0.5, 0.5, 1.0]])
+
+        cell.atom = [
+                ['Ni', [0, 0, 0]],
+                ['Ni', [a, a, a]]]
+        cell.precision = 1e-8
+        cell.build()
+        e_nuc_1 = cell.energy_nuc()
+        self.assertAlmostEqual(e_nuc_1, -456.0950359594, 8)
+
+        celldims = [2, 1, 1]
+        scell = pbctools.super_cell(cell, celldims)
+        e_nuc_2 = scell.energy_nuc() / np.product(celldims)
+        self.assertAlmostEqual(e_nuc_1, e_nuc_2, 8)
+
+        celldims = [2, 2, 1]
+        scell = pbctools.super_cell(cell, celldims)
+        e_nuc_2 = scell.energy_nuc() / np.product(celldims)
+        self.assertAlmostEqual(e_nuc_1, e_nuc_2, 8)
+
     def test_ewald_2d_inf_vacuum(self):
         cell = pgto.Cell()
         cell.a = numpy.eye(3) * 4
@@ -176,7 +191,7 @@ def test_ewald_1d_inf_vacuum(self):
         cell.low_dim_ft_type = 'inf_vacuum'
         cell.rcut = 3.6
         cell.build()
-        self.assertAlmostEqual(cell.ewald(), 70.875156940393225, 7)
+        self.assertAlmostEqual(cell.ewald(), 70.875156940393225, 4)
 
     def test_ewald_0d_inf_vacuum(self):
         cell = pgto.Cell()
diff --git a/pyscf/pbc/mp/test/test_kpoint.py b/pyscf/pbc/mp/test/test_kpoint.py
index 0596fe20d8..3633cfdc82 100644
--- a/pyscf/pbc/mp/test/test_kpoint.py
+++ b/pyscf/pbc/mp/test/test_kpoint.py
@@ -85,7 +85,7 @@ class KnownValues(unittest.TestCase):
     def test_111(self):
         nk = (1, 1, 1)
         escf, emp = run_kcell(cell,nk)
-        self.assertAlmostEqual(escf, -1.2061049658473704, 9)
+        self.assertAlmostEqual(escf, -1.2061049658473704, 7)
         self.assertAlmostEqual(emp, -5.44597932944397e-06, 9)
         escf, emp = run_kcell_complex(cell,nk)
         self.assertAlmostEqual(emp, -5.44597932944397e-06, 9)
@@ -93,7 +93,7 @@ def test_111(self):
     def test_311_high_cost(self):
         nk = (3, 1, 1)
         escf, emp = run_kcell(cell,nk)
-        self.assertAlmostEqual(escf, -1.0585001200928885, 9)
+        self.assertAlmostEqual(escf, -1.0585001200928885, 7)
         self.assertAlmostEqual(emp, -7.9832274354253814e-06, 9)
 
     def test_h4_fcc_k2_frozen_high_cost(self):
diff --git a/pyscf/pbc/mp/test/test_padding.py b/pyscf/pbc/mp/test/test_padding.py
index 78c5fe07bf..2062d93b15 100644
--- a/pyscf/pbc/mp/test/test_padding.py
+++ b/pyscf/pbc/mp/test/test_padding.py
@@ -38,6 +38,7 @@ def setUpModule():
                        ke_cutoff=ke_cutoff)
     cell.verbose = 4
     cell.output = '/dev/null'
+    cell.mesh = [17] * 3
     cell.build()
 
 def tearDownModule():
@@ -55,9 +56,20 @@ def run_kcell(cell, nk):
     return ekpt, mp.e_corr
 
 class KnownValues(unittest.TestCase):
-    def test_221(self):
+    def test_211(self):
         cell1 = cell.copy()
         cell1.basis = 'gth-dzv'
+        cell1.mesh = [17] * 3
+        cell1.build()
+        nk = [2, 1, 1]
+        escf, emp = run_kcell(cell1, nk)
+        self.assertAlmostEqual(escf, -10.551651367521986, 7)
+        self.assertAlmostEqual(emp , -0.1514005714425273, 7)
+
+    def test_221_high_cost(self):
+        cell1 = cell.copy()
+        cell1.basis = 'gth-dzv'
+        cell1.mesh = [17] * 3
         cell1.build()
 
         nk = [2, 2, 1]
diff --git a/pyscf/pbc/scf/test/test_hf.py b/pyscf/pbc/scf/test/test_hf.py
index 8054cab85a..9ad48a9a58 100644
--- a/pyscf/pbc/scf/test/test_hf.py
+++ b/pyscf/pbc/scf/test/test_hf.py
@@ -474,23 +474,23 @@ def test_init(self):
         self.assertTrue(isinstance(pscf.KHF  (cell  ), pscf.khf.KRHF   ))
         self.assertTrue(isinstance(pscf.KHF  (cell_u), pscf.kuhf.KUHF  ))
 
-    def test_dipole_moment(self):
-        dip = mf.dip_moment()
-        self.assertAlmostEqual(lib.fp(dip), 0.03847620192010277, 8)
-
-        # For test cover only. Results for low-dimesion system are not
-        # implemented.
-        with lib.temporary_env(cell, dimension=1):
-            kdm = kmf.get_init_guess(key='minao')
-            dip = kmf.dip_moment(cell, kdm)
-        #self.assertAlmostEqual(lib.fp(dip), 0, 9)
-
     def test_makov_payne_correction(self):
+        from pyscf.pbc.dft import gen_grid
         de = pbchf.makov_payne_correction(mf)
-        self.assertAlmostEqual(de[0], -0.1490687416177664, 7)
+        self.assertAlmostEqual(de[0], -0.1490687416177664, 2)
         self.assertAlmostEqual(de[0], de[1], 7)
         self.assertAlmostEqual(de[0], de[2], 7)
 
+        dm = mf.make_rdm1()
+        grids = gen_grid.UniformGrids(cell)
+        rho = pscf.hf.get_rho(mf, dm, grids)
+        log = lib.logger.new_logger(mf)
+        center = pscf.hf._search_dipole_gauge_origin(cell, grids, rho, log)
+        self.assertAlmostEqual(abs(center - [1.75, 2, 2]).max(), 0, 2)
+
+        dip = mf.dip_moment(cell, dm)
+        self.assertAlmostEqual(abs(dip).max(), 0, 1)
+
     def test_init_guess_by_1e(self):
         dm = mf.get_init_guess(key='1e')
         self.assertAlmostEqual(lib.fp(dm), 0.025922864381755062, 8)
diff --git a/pyscf/pbc/scf/test/test_khf.py b/pyscf/pbc/scf/test/test_khf.py
index d2405ac621..484e1210db 100644
--- a/pyscf/pbc/scf/test/test_khf.py
+++ b/pyscf/pbc/scf/test/test_khf.py
@@ -258,10 +258,6 @@ def occ_vir(nocc, nvir):
         self.assertAlmostEqual(f[0], 3, 9)
         self.assertAlmostEqual(f[1], 1.5, 9)
 
-    def test_dipole_moment(self):
-        dip = kmf.dip_moment()
-        self.assertAlmostEqual(lib.fp(dip), 0.729751581497479, 5)
-
     def test_krhf_vs_rhf(self):
         np.random.seed(1)
         k = np.random.random(3)
diff --git a/pyscf/pbc/scf/test/test_khf_ksym.py b/pyscf/pbc/scf/test/test_khf_ksym.py
index cf85b5fcd3..5586a3d52c 100644
--- a/pyscf/pbc/scf/test/test_khf_ksym.py
+++ b/pyscf/pbc/scf/test/test_khf_ksym.py
@@ -221,20 +221,6 @@ def test_get_rho(self):
         error = np.amax(np.absolute(rho - kumf0.get_rho()))
         self.assertAlmostEqual(error, 0., 7)
 
-    def test_dip_moment(self):
-        kpts = cell.make_kpts(nk,space_group_symmetry=True,time_reversal_symmetry=True)
-        kmf = pscf.KRHF(cell, kpts)
-        kmf.kernel()
-        dip = kmf.dip_moment()
-        error = np.amax(np.absolute(dip - kmf0.dip_moment()))
-        self.assertAlmostEqual(error, 0., 6)
-
-        kmf = pscf.KUHF(cell, kpts)
-        kmf.kernel()
-        dip = kmf.dip_moment()
-        error = np.amax(np.absolute(dip - kumf0.dip_moment()))
-        self.assertAlmostEqual(error, 0., 6)
-
     def test_transform_fock(self):
         kpts = cell.make_kpts(nk,space_group_symmetry=True,time_reversal_symmetry=True)
         kmf = pscf.KRHF(cell, kpts)
diff --git a/pyscf/pbc/scf/test/test_rohf.py b/pyscf/pbc/scf/test/test_rohf.py
index 9173a3fe35..17262cbcb3 100644
--- a/pyscf/pbc/scf/test/test_rohf.py
+++ b/pyscf/pbc/scf/test/test_rohf.py
@@ -90,12 +90,13 @@ def test_init_guess_by_chkfile(self):
         self.assertAlmostEqual(e1, -3.4190632006601662, 9)
         self.assertTrue(mf1.mo_coeff[0].dtype == np.double)
 
+    @unittest.skip('mesh not enough for density')
     def test_dipole_moment(self):
         dip = mf.dip_moment()
-        self.assertAlmostEqual(lib.fp(dip), 1.6424482249196493, 7)
+        self.assertAlmostEqual(abs(dip).max(), 0, 2)
 
         dip = kmf.dip_moment()
-        self.assertAlmostEqual(lib.fp(dip), 0.7361493256233677, 7)
+        self.assertAlmostEqual(abs(dip).max(), 0, 2)
 
     def test_get_init_guess(self):
         cell1 = cell.copy()
diff --git a/pyscf/pbc/scf/test/test_uhf.py b/pyscf/pbc/scf/test/test_uhf.py
index d44fbdd7c3..0eded3c1d8 100644
--- a/pyscf/pbc/scf/test/test_uhf.py
+++ b/pyscf/pbc/scf/test/test_uhf.py
@@ -90,12 +90,13 @@ def test_init_guess_by_chkfile(self):
         self.assertAlmostEqual(e1, -3.4272925247351256, 9)
         self.assertTrue(mf1.mo_coeff[0].dtype == np.double)
 
+    @unittest.skip('mesh not enough for density')
     def test_dipole_moment(self):
         dip = mf.dip_moment()
-        self.assertAlmostEqual(lib.fp(dip), 1.644379056097664, 7)
+        self.assertAlmostEqual(abs(dip).max(), 0, 2)
 
         dip = kmf.dip_moment()
-        self.assertAlmostEqual(lib.fp(dip), 0.6934317735537686, 6)
+        self.assertAlmostEqual(abs(dip).max(), 0, 2)
 
     def test_spin_square(self):
         ss = kmf.spin_square()[0]
diff --git a/pyscf/pbc/tools/make_test_cell.py b/pyscf/pbc/tools/make_test_cell.py
index 76a8148383..867e8bbab0 100644
--- a/pyscf/pbc/tools/make_test_cell.py
+++ b/pyscf/pbc/tools/make_test_cell.py
@@ -125,6 +125,7 @@ def test_cell_n3_diffuse():
     cell.pseudo = "gth-pade"
 
     cell.verbose = 7
+    cell.mesh = [5] * 3
     cell.output = '/dev/null'
     cell.build()
     return cell
diff --git a/pyscf/pbc/tools/test/test_pbc.py b/pyscf/pbc/tools/test/test_pbc.py
index 6a13b88697..68ef8b2c53 100644
--- a/pyscf/pbc/tools/test/test_pbc.py
+++ b/pyscf/pbc/tools/test/test_pbc.py
@@ -206,6 +206,27 @@ def test_ifft(self):
         v = tools.ifft(a, [8,n,8]).ravel()
         self.assertAlmostEqual(abs(ref-v).max(), 0, 10)
 
+    def test_mesh_to_cutoff(self):
+        a = numpy.array([
+            [0.  , 3.37, 3.37],
+            [3.37, 0.  , 3.37],
+            [3.37, 3.37, 0.  ],])
+
+        ke = tools.mesh_to_cutoff(a, [15]*3)
+        self.assertAlmostEqual(ke.min(), 42.58297736648015, 9)
+        mesh = tools.cutoff_to_mesh(a, ke.min())
+        self.assertAlmostEqual(abs(mesh - [15]*3).max(), 0, 9)
+
+        a = numpy.array([
+            [0.  ,10.11, 10.11],
+            [3.37, 0.  , 3.37],
+            [3.37, 3.37, 0.  ],])
+        ke = tools.mesh_to_cutoff(a, [15]*3)
+        self.assertAlmostEqual(ke.min(), 4.7314419296089065, 9)
+        mesh = tools.cutoff_to_mesh(a, ke.min())
+        k1 = tools.mesh_to_cutoff(a, mesh)
+        self.assertAlmostEqual(ke.min(), k1.min(), 9)
+
 
 if __name__ == '__main__':
     print("Full Tests for pbc.tools")