diff --git a/codes/tool.py b/codes/tool.py
new file mode 100644
index 0000000000000000000000000000000000000000..b536607c02dba0e88deea1611f1d8acf0fc4c730
--- /dev/null
+++ b/codes/tool.py
@@ -0,0 +1,144 @@
+import numpy as np
+import os
+import ase
+import ase.io
+from ase import Atoms, Atom
+from ase.io import Trajectory
+from ase.constraints import FixScaled,FixAtoms
+from sklearn.metrics import mean_squared_error
+from dscribe.descriptors import SOAP
+from scipy.interpolate import UnivariateSpline
+from sklearn.gaussian_process import GaussianProcessRegressor
+from sklearn.gaussian_process.kernels import RBF
+from sklearn.model_selection import GridSearchCV
+from joblib import Parallel, delayed
+from ase import neighborlist 
+from sklearn.preprocessing import StandardScaler
+from create_descriptor import *
+
+
+
+def sign(x):
+    if x<0:
+        return -1
+    else:
+        return 1
+
+def get_train_data(traj,data_folder,train_pos_indices):  
+        sys=Trajectory(traj)
+        ind_slab=sys[0].constraints[1].index
+        ind_free=np.delete(np.arange(len(sys[0])),ind_slab)
+        species=[]
+        elem=sys[0].get_chemical_symbols() 
+        #identification des espèces
+        for el in range(len(elem)): 
+            if elem[el] not in species:
+                species.append(elem[el])   
+        y_ini=np.load(data_folder+'/E.npy')
+        index_pos=np.load(data_folder+'/ind_pos.npy')
+        ind_train=[]
+        #select only 3 config per position
+        for i in range(len(index_pos)):
+            if i in train_pos_indices:
+                ind_train.append(index_pos[i,0])
+                ind_train.append((index_pos[i,1]-index_pos[i,0]+1)//2)
+                ind_train.append(index_pos[i,1])
+
+        y_train=np.array([y_ini[i] for i in ind_train])
+        return [sys[i] for i in ind_train],y_train,species
+
+def pos_to_relax(poscar_file,n=20):    
+        poscar=ase.io.read(poscar_file)
+        #position à relaxer
+        cell=poscar.get_cell()
+        a=cell[0,0]
+        b=cell[1,1]
+        c=cell[2,2]
+        #maillage
+        n=20
+        Xpos=[i*a/n for i in range(n)]
+        Ypos=[i*b/n for i in range(n)]
+        
+        pos=np.array([[i/n,j/n,0] for i in range(n) for j in range(n)])
+        pos=pos@cell       
+        xx,yy=pos[:,0],pos[:,1]
+        zz=np.empty(len(xx))
+        #zpos
+        atom_top=poscar.get_positions()
+        for i in range(len(xx)):        
+            dx = atom_top[:,0] - xx[i] 
+            dy = atom_top[:,1] - yy[i] 
+            dz = atom_top[:,2] - 18 
+            dxy=np.linalg.norm([dx,dy,dz],axis=0)
+            indice=np.where(dxy==np.min(dxy))[0][0]    
+            zz[i]=atom_top[indice,2]+1.6
+        return xx,yy,zz
+
+def searchEminzgrid(desc,p,ind=0,atomseul='H',poscar='POSCAR'):   
+            pos=p.copy()        
+            zetap=[]
+            traj_tot=[]
+            NB=False
+            try:
+                traj_ini=ase.io.read(poscar,format='vasp')
+            except:
+                traj_ini=poscar.copy()
+            cell=traj_ini.get_cell()
+            while NB is False:
+                traj=traj_ini+Atoms(atomseul,[pos],pbc=True,cell=cell)             
+                traj_tot.append(traj)
+                zetap.append(pos[2])
+                cutoffs=neighborlist.natural_cutoffs(traj)
+                nl = neighborlist.NeighborList(cutoffs,skin=0,bothways=True,self_interaction=False)
+                nl.update(traj)
+                indices, offsets = nl.get_neighbors(-1)
+                pos[2]-=0.1
+                if len(indices)>0:
+                    NB=True
+            zlim=pos[2]+0.1    
+            for _ in range(5):
+                traj=traj_ini+Atoms(atomseul,[pos],pbc=True,cell=cell)
+                traj_tot.append(traj)
+                zetap.append(pos[2])
+                pos[2]-=0.1
+            #print(traj,traj[0])   
+            print(len(zetap)) 
+            x_pred=desc.create(traj_tot)
+            return x_pred,zetap,ind,zlim
+        
+        
+    
+    
+def pos_reduc(zetap,Eetap,Estd,ind,zlim,xpos,ypos): 
+        y_spl = UnivariateSpline(np.flip(zetap),np.flip(Eetap),s=0,k=3)
+        y_spl_2d = y_spl.derivative(n=2)
+        y_spl_1d = y_spl.derivative(n=1)
+        minis=[]
+        yspld2m1=y_spl_2d(zetap[2])
+        yspld1m1=y_spl_1d(zetap[2])
+        for it in range(200):
+            zz=zetap[0]+it/200*(zetap[-1]-zetap[0])           
+            if y_spl_2d(zz)>0:
+                         if sign(y_spl_1d(zz))!=sign(yspld1m1):
+                                 j=np.where(abs(zetap-zz)==min(abs(zetap-zz)))[0][0]
+                                 minis.append(j)
+            yspld2m1=y_spl_2d(zz)
+            yspld1m1=y_spl_1d(zz)
+        try:
+            minE=Eetap[minis[np.argsort(Eetap[minis]+Estd[minis])[0]]]
+        except:
+            minE=Eetap[np.argsort(Eetap+Estd)[0]]
+            print('no min for i=',ind)
+        E=minE
+        z=zetap[np.where(Eetap==minE)[0][0]]
+        Estd=Estd[np.where(Eetap==minE)[0][0]]                
+        
+        with open('resultat.txt', 'a') as f:
+                  f.write('indice: '+str(ind)+' pos: '+str(xpos)+' '+str(ypos)+' zlim: '+str(zlim)+' zpred: '+str(z)+' Epred: '+str(E)+' Estd: '+str(Estd)+'\n')
+        f.close()
+
+def run_para(p,ind,desc,scaler,g_search,poscar='POSCAR'):
+        x_pred,zetap,ind,zlim=searchEminzgrid(desc,p,ind=ind,atomseul='H',poscar=poscar)  
+        x_pred=scaler.transform(x_pred)          
+        Eprd,Estd=g_search.best_estimator_.predict(x_pred,return_std=True)
+        pos_reduc(np.array(zetap),Eprd,Estd,ind,zlim,p[0],p[1])
\ No newline at end of file