diff --git a/integrators/_details/interfaces/tpsPreconditioner.py b/integrators/_details/interfaces/tpsPreconditioner.py
index 4328fe603826958101c392d20c1f0c629d70cb10..bb252a7d82f1867be552cf36a6c11e7f0fc4d012 100644
--- a/integrators/_details/interfaces/tpsPreconditioner.py
+++ b/integrators/_details/interfaces/tpsPreconditioner.py
@@ -108,6 +108,7 @@ class TPSPreconditioner(_preconditionerInterface._PreconditionerInterface):
     import scipy.sparse.linalg
     import scipy.sparse as sp
     import numpy as np
+    import pyamg
 
     if(self.parameters.alphaPreconditioner == None):
       A = self._A_stat[:self._A_stat.shape[0]//3, :self._A_stat.shape[0]//3]
@@ -115,16 +116,34 @@ class TPSPreconditioner(_preconditionerInterface._PreconditionerInterface):
       A = self._A_stat_precond[:self._A_stat_precond.shape[0]//3 \
         , :self._A_stat_precond.shape[0]//3]
 
-    
     self._Compute_Q()
-    metaPre = 1.0 / A.diagonal()
-    metaP = lambda x: metaPre*x
-    P = scipy.sparse.linalg.LinearOperator(A.shape, matvec=metaP)
-    self._prePractical = lambda y: np.concatenate(( \
-      scipy.sparse.linalg.cg(A, y[:y.size//3], tol=self._solvetol/10, M=P)[0], \
-      scipy.sparse.linalg.cg(A, y[y.size//3:2*y.size//3], tol=self._solvetol/10, M=P)[0], \
-      scipy.sparse.linalg.cg(A, y[2*y.size//3:], tol=self._solvetol/10, M=P)[0]))
 
+    # trying ML, SPLU, CG preconditioner, ML as default
+    # (CG not working well for h << lex)
+    # it seems ML faster, but SPLU less iterations
+    # way faster than true inverse, especially for large NV
+    opt = "ml" # "ml", "splu"
+    if opt == "ml":
+      ml = pyamg.ruge_stuben_solver(A)
+      pre = ml.aspreconditioner()
+      
+      self._prePractical = lambda y: np.concatenate(( \
+        (pre * y[:y.size//3], pre * y[y.size//3:2*y.size//3], pre * y[2*y.size//3:])))
+    elif opt == "splu":
+      cgs = pyamg.coarse_grid_solver("splu")
+      self._prePractical = lambda y: np.concatenate(( \
+        (cgs(A, y[:y.size//3]), \
+        cgs(A, y[y.size//3:2*y.size//3]), \
+        cgs(A, y[2*y.size//3:]))))
+    elif opt == "cg":
+      metaPre = 1.0 / A.diagonal()
+      metaP = lambda x: metaPre*x
+      P = scipy.sparse.linalg.LinearOperator(A.shape, matvec=metaP)
+      self._prePractical = lambda y: np.concatenate(( \
+        scipy.sparse.linalg.cg(A, y[:y.size//3], tol=self._solvetol/10, M=P)[0], \
+        scipy.sparse.linalg.cg(A, y[y.size//3:2*y.size//3], tol=self._solvetol/10, M=P)[0], \
+        scipy.sparse.linalg.cg(A, y[2*y.size//3:], tol=self._solvetol/10, M=P)[0]))
+  
     practical2D = lambda x: \
       self._Q.dot(self._prePractical(self._Q.transpose().dot(x)))
 
@@ -147,9 +166,11 @@ class TPSPreconditioner(_preconditionerInterface._PreconditionerInterface):
       A = self._A_stat_precond[:self._A_stat_precond.shape[0]//3 \
         , :self._A_stat_precond.shape[0]//3]
 
-    # trying AMG, SPLU, CG preconditioner, CG as default. 
+    # trying ML, SPLU, CG preconditioner, ML as default
+    # (CG not working well for h << lex)
+    # it seems ML faster, but SPLU less iterations
     # way faster than true inverse, especially for large NV
-    opt = "cg" # "ml", "splu"
+    opt = "ml" # "ml", "splu"
     if opt == "ml":
       ml = pyamg.ruge_stuben_solver(A)
       pre = ml.aspreconditioner()