diff --git a/libhreels/calcHREELS3.py b/libhreels/calcHREELS3.py
new file mode 100644
index 0000000000000000000000000000000000000000..785ecd6f7713f0bbbcb1ebd9344726cb0b59d2ab
--- /dev/null
+++ b/libhreels/calcHREELS3.py
@@ -0,0 +1,206 @@
+#!/usr/bin/env python3
+import numpy as np
+import json
+import sys, re, os
+from libhreels.HREELS import myPath
+from copy import deepcopy
+
+libDir = os.path.dirname(os.path.realpath(__file__)) 
+
+if not (sys.version.startswith('3.6') or sys.version.startswith('3.8')):
+    print('''Make sure the Fortran routines 'myEels2' and 'myBoson' 
+    have been complied with the proper f2py3 for the right 
+    python version!!''') 
+try:
+    from . import myEels3 as LambinEELS   # wrapper for myEels3.f90
+    from libhreels import myBoson as LambinBoson  # wrapper for myBoson.f90
+except:
+    print('myEels2 and MyBoson are not available here (Check your version)')			
+
+# Experimental setup as dictionary:
+setup = {
+    "e0": 4.0,
+    "theta": 60.,
+    "phia": 0.33,
+    "phib": 2.0,
+    "temperature": 298.,
+    "debug": False
+}
+# Instrumental function describing elastic peak shape:
+instrument = {
+    "width": 18.,
+    "intensity": 100000.,
+    "asym": 0.01,
+    "gauss": 0.88
+}
+
+	
+def importMaterials(string='', path=libDir):
+    ''' Returns a dictionary with all phonon parameters for the material provided 
+    as string argument. If the string is empty or not matching, a list of all available 
+    materials is printed.
+    '''
+    file = os.path.join(myPath(path),'materials.json')
+    with open(file) as json_file:
+        materials = json.load(json_file)
+        try:
+            mat = materials[string]
+        except:
+            print('No data for material >>{}<< found in {} materials.json!!'.format(string, path))
+            print('Available materials:\n{}\n'.format(materials.keys()))
+            mat = 'None'
+    return mat
+
+
+def addDrude(wPlasma, gPlasma, material):
+    ''' Adds a simple Drude response to the materials properties (which are provided 
+    as 3rd argument) and returns a new materials dictionary with all phonon parameters. Note 
+    that at least the eps_infinity has to given before.
+    '''
+    newMaterial = deepcopy(material)
+    # To select the Drude response, the Lambin Fortran code requires a negative first oscillator frequency
+    # which is then interpreted as plasma frequency.
+    # The values of the former LO parameter are irrelevant (but need to be provided). 
+    if not wPlasma > 0:
+        print('Cannot add Drude to material',material)
+        return material
+    try:
+        if len(newMaterial['wTO']) > 0:
+            newMaterial['wTO'] += [-1*wPlasma]
+            newMaterial['gTO'] += [-1*gPlasma]
+            newMaterial['wLO'] += [0]
+            newMaterial['gLO'] += [0]
+            return newMaterial
+    except:
+        print('Cannot add Drude to material',material)
+    return material
+
+################################################################################
+################################################################################
+class lambin:
+    def __init__(self, film, setup=setup, instrument=instrument):
+        self.e0 = setup['e0']
+        self.theta = setup['theta']
+        self.phia = setup['phia']
+        self.phib = setup['phib']
+        self.temperature = setup['temperature']
+        self.debug = setup['debug']
+        self.width = instrument['width']
+        self.gauss = instrument['gauss']
+        self.intensity = instrument['intensity']
+        self.asym = instrument['asym']
+        self.layers = len(film)          # number of layers
+        self.neps = self.layers
+        name_size = self.layers
+        self.name = []; self.thick=[]; self.listNOsci=[]; self.epsinf =[]; Q = []
+        allTO=[]; allgTO=[];  allgLO=[]; nDrude=0
+        name2 = []
+        for layer in film:
+            try:
+                a = layer[0]['name']
+            except:
+                a = 'None'
+            self.name.append('{:<10}'.format(a[:10]))        # film name and material
+            name2.append(a)
+            try:
+                a = layer[1]
+            except:
+                a = 10000.
+            self.thick.append(a)
+            self.epsinf.append(layer[0]['eps'])
+            nTO = 2 * len(layer[0]['wTO'])
+            allTO.extend(layer[0]['wTO'])
+            allgTO.extend(layer[0]['gTO'])
+            allTO.extend(layer[0]['wLO'])
+            allgTO.extend(layer[0]['gLO'])
+            Q.extend(2*len(layer[0]['wTO'])*[10.])
+            self.listNOsci.append(nTO)
+        
+        if len(allTO)!=sum(self.listNOsci) or len(allgTO)!=sum(self.listNOsci):
+            print('Error in materials: ', layer[0])
+        self.wOsc = np.array(allTO)
+        self.gOsc = np.array(allgTO)
+        self.osc = np.array([self.wOsc, np.array(Q), self.gOsc])
+        return
+
+    def calcSurfaceLoss(self,x):
+        ''' Calculate the surface loss spectrum for the array of x, which needs to be an equidistant array. 
+        All parameters are defined in the class __init__() call.'''
+        wmin = min(x)
+        wmax = max(x)-0.001
+        dw = (wmax-wmin)/(len(x)-1)     # assumes that x is an equidistant array
+        wn_array_size = len(x)     # size of array for x and epsilon (wn_array, loss_array)
+        nper = 1.
+        contrl = '{:<10}'.format('None'[:10])   # Can be 'image' to include image charge
+        mode = '{:<10}'.format('kurosawa'[:10])           
+        wn_array,loss_array = LambinEELS.mod_doeels.doeels(self.e0,self.theta,self.phia,self.phib,
+            wmin,wmax,dw,self.layers,self.neps,nper,self.name,
+            self.thick,self.epsinf,self.listNOsci,self.osc,contrl,mode,wn_array_size)
+        i=0
+        for item in wn_array:
+            if item > 0: break
+            i += 1
+        return wn_array[i-1:], loss_array[i-1:]
+
+    def calcHREELS(self,x, normalized=True):
+        emin = min(x)
+        emax = max(x)-0.001
+        norm = 1
+        xLoss,loss_array = self.calcSurfaceLoss(x)
+        wmin = min(xLoss)
+        wmax = max(xLoss)
+        xOut,spectrum,n = LambinBoson.doboson3(self.temperature,self.width,self.gauss,self.asym,
+            emin,emax,wmin,wmax,loss_array,self.debug,len(loss_array))
+        if normalized:
+            norm = max(spectrum[:n])
+        # return xOut[:n], spectrum[:n]/norm
+        return xOut[:len(x)], spectrum[:len(x)]/norm
+
+    def calcEps(self, x):
+        epsArray = []
+        nOsci = len(self.wOsc)
+        for wn in x:
+            yn = LambinEELS.mod_doeels.seteps(self.listNOsci,nOsci,self.osc,self.epsinf,wn,self.layers)
+            epsArray.append(yn)
+        return np.transpose(np.array(epsArray))
+
+####################################################################################
+def myMain():
+    import matplotlib.pyplot as plt
+    import numpy as np
+    from copy import deepcopy
+    import os
+
+    x = np.linspace(-100.,900,1100)
+
+    material = {'eps': 4.,
+                'wTO': [0],  'gTO': [20], 'wLO': [598.7], 'gLO': [20],
+                }
+
+    film1 = lambin(film=[[material,10000.]])
+    film1.temperature = 100
+    xs, spectrum = film1.calcSurfaceLoss(x)
+    plt.plot(xs,spectrum)
+
+    # pureDrude = {'eps': 4.,
+    #             'wTO': [-400],  'gTO': [-20], 'wLO': [0], 'gLO': [0],
+    #             }
+    # film2 = lambin(film=[[pureDrude,10000.]])
+    # film2.temperature = 100
+    # xs, spectrum = film2.calcSurfaceLoss(x)
+    # plt.plot(xs,spectrum,'g-.', label='pure Drude 400')
+
+
+    plt.ylabel('Surface Loss')
+    plt.xlabel('Energy Loss (cm$^{-1}$)')
+    plt.legend(title=r'Plasma frequency')
+
+    plt.text(0.99, 0.01,os.path.basename(__file__), fontsize=10, ha='right', va='bottom', transform=plt.gcf().transFigure)
+    output_filename = os.path.splitext(__file__)[0] + '.png'
+    plt.savefig(output_filename)
+
+    plt.show()
+
+
+if __name__ == '__main__':
+	myMain()
\ No newline at end of file
diff --git a/libhreels/myEels3.cpython-38-x86_64-linux-gnu.so b/libhreels/myEels3.cpython-38-x86_64-linux-gnu.so
index cccb9a7fbf263a6a0d26891cd36aa2b661034fe8..3ffd40c9d643a0d986f4095e567dbc4dc813ff7a 100644
Binary files a/libhreels/myEels3.cpython-38-x86_64-linux-gnu.so and b/libhreels/myEels3.cpython-38-x86_64-linux-gnu.so differ
diff --git a/libhreels/myEels3.f90 b/libhreels/myEels3.f90
index bf5e57645764f591a6bab7a92043a59ddc8bc121..c250a8e1403756f0be2175e81560656d56414201 100644
--- a/libhreels/myEels3.f90
+++ b/libhreels/myEels3.f90
@@ -975,16 +975,19 @@ subroutine seteps(nos, osc_size, osc, epsinf, wn, nLayer, eps)
     wn2 = wn**2
     do k = 1, m     ! loop over all TO modes
       j = j + 1
-      if (osc(1,j) > 0.) then     ! positive TO mode: 'Kurosa' form
+
+      if (osc(1,j) > 0.) then     ! positive TO mode: 'Kurosawa' form: _Multiplicative_ phonon mode
         b = wn/osc(1, j+m)
         nomi = nomi * osc(1, j+m)**2 * (1.0 - b * dcmplx(b, osc(3,j+m)/osc(1, j+m)) )
         deno =deno * (osc(1,j)**2 - wn * dcmplx( wn, osc(3,j) ) )
-      else if (osc(1,j) < 0.) then! Negative TO mode means: treat as term added to epsilon
+      
+      else if (osc(1,j) < 0.) then! Negative TO mode means: _Additive_ Lorentz oscillator with Q
         addeps = addeps + osc(1,j)**2 * osc(2,j) /dcmplx(osc(1,j)**2 + wn2, wn*osc(3,j))
+      
       else                      ! osc(1,j) = 0   -> it is a Drude term
-            ! addeps = addeps - osc(1,j)**2/dcmplx(wn2, -1*wn*osc(3,j))
-        addeps = addeps - dcmplx(osc(1,j+m)**2, wn*(osc(3,j+m)-osc(3,j))) /dcmplx(wn2, -1*wn*osc(3,j))
+        addeps = addeps - dcmplx(osc(1,j+m)**2, wn*(osc(3,j)-osc(3,j+m))) /dcmplx(wn2, wn*osc(3,j))
       end if
+
     enddo
     j = j+m     ! we have already looped over the LO modes, therefore increase the index
     eps(l) = epsinf(l) * nomi / deno + addeps