diff --git a/src/soap/soapy/kernel.py b/src/soap/soapy/kernel.py
index c13bfdbca2c8c69167ca9934e86942cbdf99d4f3..f257847620c844c6339ded3d8541a85c480d49c9 100644
--- a/src/soap/soapy/kernel.py
+++ b/src/soap/soapy/kernel.py
@@ -190,7 +190,7 @@ class KernelAdaptorSpecificUnique(object):
     def adaptScalar(self, atomic, epsilon=1e-20):
         X = reduce_xnklab_atomic(atomic, self.types)
         X_mag = np.dot(X,X)**0.5
-        if X_mag < epsilon: 
+        if X_mag < epsilon:
             X_mag = 1.
         X_norm = X/X_mag
         return X, X_norm
@@ -223,6 +223,37 @@ class KernelAdaptorSpecific(object):
         X_norm = X/np.dot(X,X)**0.5
         return X, X_norm
 
+class KernelAdaptorGlobalSpecificEnergy(object):
+    def __init__(self, options, types_global):
+        self.types_global = types_global
+        return
+    def adapt(self, espectrum, return_pos_matrix=False, dtype='float64'):
+        dim_linear_ab = None
+        dim_linear_total = None
+        S = len(self.types_global)
+        X = None
+        for sa in self.types_global:
+            for sb in self.types_global:
+                powspec_ab = energy_spectrum.getPowerGlobal(sa, sb)
+                if powspec_ab != None:
+                    xab = powspec_ab.array.real.flatten()
+                    if not dim_linear_ab:
+                        dim_linear_ab = xab.shape[0]
+                        dim_linear_total = S**2*dim_linear_ab
+                        X = np.zeros((S, S*dim_linear_ab), dtype=dtype)
+                    else: assert dim_linear_ab == xab.shape[0]
+                    isa = self.types_global.index(sa)
+                    isb = self.types_global.index(sb)
+                    i0 = isa
+                    i1 = isa+1
+                    j0 = isb*dim_linear_ab
+                    j1 = j0+dim_linear_ab
+                    X[i0:i1,j0:j1] = xab
+        X = X/np.dot(X,X)**0.5
+        if return_pos_matrix:
+            return X, np.array([[0.,0.,0.]]), ["global"]
+        else: return X.flatten()
+
 class KernelAdaptorGlobalSpecific(object):
     def __init__(self, options, types_global=None):
         self.types = types_global
@@ -270,13 +301,13 @@ class KernelAdaptorGeneric(object):
             #    if not pid in pid_list:
             #        logging.debug("Skip, adapt atomic, pid = %d" % pid)
             #        continue
-            
+
             Xi_unnorm, Xi_norm = self.adaptScalar(atomic_i)
             dimX = Xi_norm.shape[0]
             #Xi = np.real(atomic_i.getPower("","").array)
             #dimX = Xi.shape[0]*Xi.shape[1]
             #Xi = Xi.reshape((dimX))
-            
+
             #print "dim(X) =", dimX
             if not IX.any():
                 IX = np.copy(Xi_norm) # TODO Is this necessary?
@@ -299,7 +330,7 @@ class KernelAdaptorGeneric(object):
         dxnkl_pid = atomic.getPowerGradGeneric(nb_pid)
         dX_dx = dxnkl_pid.getArrayGradX()
         dX_dy = dxnkl_pid.getArrayGradY()
-        dX_dz = dxnkl_pid.getArrayGradZ()        
+        dX_dz = dxnkl_pid.getArrayGradZ()
         dimX = dX_dx.shape[0]*dX_dx.shape[1]
         dX_dx = np.real(dX_dx.reshape((dimX)))
         dX_dy = np.real(dX_dy.reshape((dimX)))
@@ -310,7 +341,7 @@ class KernelAdaptorGeneric(object):
         dX_dy = dX_dy/mag_X - np.dot(X, dX_dy)/mag_X**3 * X
         dX_dz = dX_dz/mag_X - np.dot(X, dX_dz)/mag_X**3 * X
         return dX_dx, dX_dy, dX_dz
-        
+
 class KernelAdaptorGlobalGeneric(object):
     def __init__(self, options, types_global=None):
         return
@@ -341,7 +372,7 @@ class KernelAdaptorGlobalGeneric(object):
         dxnkl_pid = atomic.getPowerGradGeneric(nb_pid)
         dX_dx = dxnkl_pid.getArrayGradX()
         dX_dy = dxnkl_pid.getArrayGradY()
-        dX_dz = dxnkl_pid.getArrayGradZ()        
+        dX_dz = dxnkl_pid.getArrayGradZ()
         dimX = dX_dx.shape[0]*dX_dx.shape[1]
         dX_dx = np.real(dX_dx.reshape((dimX)))
         dX_dy = np.real(dX_dy.reshape((dimX)))
@@ -353,7 +384,6 @@ class KernelAdaptorGlobalGeneric(object):
         dX_dz = dX_dz/mag_X - np.dot(X, dX_dz)/mag_X**3 * X
         return dX_dx, dX_dy, dX_dz
 
-
 class KernelFunctionGaussianDiff(object):
     def __init__(self, options):
         self.delta = float(options['kernel.gaussian_delta'])
@@ -393,7 +423,7 @@ class KernelFunctionDot(object):
     def computeDot(self, IX, X, xi, delta):
         return delta**2 * np.dot(IX,X)**xi
     def compute(self, IX, X):
-        return self.computeDot(IX, X, self.xi, self.delta)    
+        return self.computeDot(IX, X, self.xi, self.delta)
     def computeDerivativeOuter(self, IX, X):
         c = self.computeDot(IX, X, self.xi-1, self.delta)
         return self.xi*np.diag(c).dot(IX)
@@ -450,7 +480,7 @@ class KernelFunctionDotHarmonicDist(object):
         D = (1.-C+self.eps)**0.5
         IC = self.kfctdot.computeDerivativeOuter(IX, X)
         return 2*(D-self.d0)*0.5/D*(-1.)*IC
-        
+
 class KernelFunctionDotLj(object):
     def __init__(self, options):
         self.sigma = float(options.get('kernel.lj_sigma'))
@@ -466,7 +496,7 @@ class KernelFunctionDotLj(object):
         IC = self.kfctdot.computeDerivativeOuter(IX, X)
         return (-6.*self.sigma**12*(1./D)**7 + 3.*self.sigma**6*(1./D)**4)*IC
     def computeBlockDot(self, IX, return_distance=False):
-        return self.kfctdot.computeBlock(IX, return_distance)        
+        return self.kfctdot.computeBlock(IX, return_distance)
 
 class KernelFunctionDot3Harmonic(object):
     def __init__(self, options):
@@ -521,21 +551,22 @@ class KernelFunctionDot3HarmonicDist(object):
         return 2*(D_A - D_B)*(0.5/D_A*(-1.)*IC_A - 0.5/D_B*(-1.)*IC_B) + 2*(D_A - D_AB)*0.5/D_A*(-1.)*IC_A + 2*(D_B - D_AB)*0.5/D_B*(-1.)*IC_B + 2*(D_A-self.d0)*1./D_A*(-1.)*IC_A + 2*(D_B-self.d0)*1./D_B*(-1.)*IC_B
 
 KernelAdaptorFactory = {
-'generic': KernelAdaptorGeneric, 
+'generic': KernelAdaptorGeneric,
 'specific': KernelAdaptorSpecific,
 'specific-unique': KernelAdaptorSpecificUnique,
 'global-generic': KernelAdaptorGlobalGeneric,
-'global-specific': KernelAdaptorGlobalSpecific
+'global-specific': KernelAdaptorGlobalSpecific,
+'global-specific-energy': KernelAdaptorGlobalSpecificEnergy
 }
 
-KernelFunctionFactory = { 
+KernelFunctionFactory = {
 'gaussian-diff': KernelFunctionGaussianDiff,
-'dot': KernelFunctionDot, 
+'dot': KernelFunctionDot,
 'dot-shifted': KernelFunctionDotShifted,
-'dot-harmonic': KernelFunctionDotHarmonic, 
+'dot-harmonic': KernelFunctionDotHarmonic,
 'dot-harmonic-dist': KernelFunctionDotHarmonicDist,
 'dot-lj': KernelFunctionDotLj,
-'dot-3-harmonic': KernelFunctionDot3Harmonic, 
+'dot-3-harmonic': KernelFunctionDot3Harmonic,
 'dot-3-harmonic-dist': KernelFunctionDot3HarmonicDist
 }
 
@@ -543,7 +574,7 @@ class KernelPotential(object):
     def __init__(self, options):
         logging.info("Construct kernel potential ...")
         self.basis = soap.Basis(options)
-        self.options = options        
+        self.options = options
         # CORE DATA
         self.IX = None
         self.alpha = None
@@ -551,7 +582,7 @@ class KernelPotential(object):
         self.labels = []
         # KERNEL
         logging.info("Choose kernel function ...")
-        self.kernelfct = KernelFunctionFactory[options.get('kernel.type')](options)   
+        self.kernelfct = KernelFunctionFactory[options.get('kernel.type')](options)
         # ADAPTOR
         logging.info("Choose adaptor ...")
         self.adaptor = KernelAdaptorFactory[options.get('kernel.adaptor')](options)
@@ -562,7 +593,7 @@ class KernelPotential(object):
     def computeKernelMatrix(self, return_distance=False):
         return self.kernelfct.computeBlock(self.IX, return_distance)
     def computeDotKernelMatrix(self, return_distance=False):
-        # Even if the, e.g., dot-harmonic kernel is used for optimization, 
+        # Even if the, e.g., dot-harmonic kernel is used for optimization,
         # the dot-product based kernel matrix may still be relevant
         return self.kernelfct.computeBlockDot(self.IX, return_distance)
     def nConfigs(self):
@@ -635,7 +666,7 @@ class KernelPotential(object):
         # TODO The kernel policy should take care of this:
         if self.use_global_spectrum:
             spectrum.computeGlobal()
-        IX_acqu = self.adaptor.adapt(spectrum)        
+        IX_acqu = self.adaptor.adapt(spectrum)
         n_acqu = IX_acqu.shape[0]
         dim_acqu = IX_acqu.shape[1]
         logging.info("Compute energy from %d atomic environments ..." % n_acqu)
@@ -684,18 +715,18 @@ class KernelPotential(object):
                 # Force on neighbour
                 logging.info("    -> Nb %d" % (nb_pid))
                 dX_dx, dX_dy, dX_dz = self.adaptor.adaptGradients(atomic, nb_pid, X_unnorm)
-                
+
                 force_x = -alpha_dIC.dot(dX_dx)
                 force_y = -alpha_dIC.dot(dX_dy)
                 force_z = -alpha_dIC.dot(dX_dz)
-                
+
                 forces[nb_pid-1][0] += force_x
                 forces[nb_pid-1][1] += force_y
                 forces[nb_pid-1][2] += force_z
                 #print forces
                 #raw_input('...')
         return forces
-        
+
 def restore_positions(structure, positions):
     idx = 0
     for part in structure:
@@ -711,7 +742,7 @@ def perturb_positions(structure, exclude_pid=[]):
         dz = np.random.uniform(-1.,1.)
         part.pos = part.pos + 0.1*np.array([dx,dy,dz])
     return [ part.pos for part in structure ]
-    
+
 def random_positions(structure, exclude_pid=[], b0=-1., b1=1., x=True, y=True, z=True):
     for part in structure:
         if part.id in exclude_pid: continue
@@ -733,7 +764,7 @@ def apply_force_step(structure, forces, scale, constrain_particles=[]):
     idx = -1
     for part in structure:
         idx += 1
-        if part.id in constrain_particles: 
+        if part.id in constrain_particles:
             print "Skip force step, pid =", part.id
             continue
         #if np.random.uniform(0.,1.) > 0.5: continue
@@ -750,7 +781,7 @@ def apply_force_norm_step(structure, forces, scale, constrain_particles=[]):
     idx = -1
     for part in structure:
         idx += 1
-        if part.id in constrain_particles: 
+        if part.id in constrain_particles:
             print "Skip force step, pid =", part.id
             continue
         #if np.random.uniform(0.,1.) > 0.5: continue
@@ -763,8 +794,8 @@ def evaluate_energy(positions, structure, kernelpot, opt_pids, verbose=False, of
     pid_pos = positions.reshape((opt_pids.shape[0],3))
     for pidx, pid in enumerate(opt_pids):
         pos = pid_pos[pidx,:]
-        particle = structure.getParticle(pid)        
-        particle.pos = pos        
+        particle = structure.getParticle(pid)
+        particle.pos = pos
     for part in structure:
         if verbose: print part.id, part.type, part.pos
     # Evaluate energy function
@@ -782,8 +813,8 @@ def evaluate_energy_gradient(positions, structure, kernelpot, opt_pids, verbose=
     pid_pos = positions.reshape((opt_pids.shape[0],3))
     for pidx, pid in enumerate(opt_pids):
         pos = pid_pos[pidx,:]
-        particle = structure.getParticle(pid)        
-        particle.pos = pos        
+        particle = structure.getParticle(pid)
+        particle.pos = pos
     for part in structure:
         if verbose: print part.id, part.type, part.pos
     # Evaluate forces
@@ -797,4 +828,3 @@ def evaluate_energy_gradient(positions, structure, kernelpot, opt_pids, verbose=
     if verbose: print gradients_short
     #forces[2] = 0. # CONSTRAIN TO Z=0 PLANE
     return gradients_short
-