diff --git a/examples/scipy/LagrangeSweep.py b/examples/scipy/LagrangeSweep.py
index 7c18cc1..7194251 100644
--- a/examples/scipy/LagrangeSweep.py
+++ b/examples/scipy/LagrangeSweep.py
@@ -1,65 +1,85 @@
 from copy import copy
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
 from rrompy.hfengines.scipy import HelmholtzBoxScatteringProblemEngine as HBSPE
 from rrompy.reduction_methods.lagrange import ApproximantLagrangePade as Pade
 from rrompy.reduction_methods.lagrange import ApproximantLagrangeRB as RB
 from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
 from rrompy.utilities.parameter_sampling import QuadratureSampler as QS
 
+verb = 0
 testNo = 1
-npoints = 11
+npoints = 100
+homog = True
+homog = False
 
 if testNo == 1:
-    ks = np.power([4 + .5j, 14 + .5j], .5)
-    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 20)
+    ks = np.power([24 + 5.j, 34 + 5.j], .5)
+    solver = HSBPE(kappa = 32 ** .5, theta = np.pi / 3, n = 15)
     solver.omega = np.real(np.mean(ks))
-    mutars = np.linspace(0**.5, 21**.5, npoints)
-    filenamebase = '../data/output/HelmholtzBubbleLagrange'
+    mutars = np.linspace(21**.5, 42**.5, npoints)
+    filenamebase = '../data/output/HelmholtzBubbleSHIFTLSweep'
+    homog = False
 elif testNo == 2:
-    ks = [10 + .25j, 14 + .25j]
+    ks = [10 + 0.j, 14 + 0.j]
     solver = HBSPE(R = 5, kappa = 3, theta = - np.pi * 75 / 180, n = 10)
     solver.omega = np.real(np.mean(ks))
-    mutars = np.linspace(9, 14, npoints)
-    filenamebase = '../data/output/HelmholtzBoxLagrange'
+    mutars = np.linspace(9, 15, npoints)
+    homogMSG = ""
+    if not homog: homogMSG = "Non"
+    filenamebase = '../data/output/HelmholtzBoxLSweep' + homogMSG + "Homog"
 
 k0 = np.mean(ks)
 shift = 6
-nsets = 2
+nsets = 5
 stride = 3
 Smax = stride * (nsets - 1) + shift + 2
 
 rescaling = lambda x: np.power(x, 2.)
 rescalingInv = lambda x: np.power(x, .5)
 paramsPade = {'S':Smax, 'POD':True,
               'sampler':QS(ks, "CHEBYSHEV", rescaling, rescalingInv)}    
 paramsRB = copy(paramsPade)
+paramsPoly = copy(paramsPade)
 paramsSetsPade = [None] * nsets
 paramsSetsRB = [None] * nsets
+paramsSetsPoly = [None] * nsets
 for i in range(nsets):
-    paramsSetsPade[i] = {'N': stride * i + shift + 1, 'M': stride * i + shift,
+    paramsSetsPade[i] = {'N': stride * i + shift + 1,
+                         'M': stride * i + shift + 1,
+                         'S': stride * i + shift + 2}
+    paramsSetsRB[i] = {'R': stride * i + shift + 2,
+                       'S': stride * i + shift + 2}
+    paramsSetsPoly[i] = {'N': 0,
+                         'M': stride * i + shift + 1,
                          'S': stride * i + shift + 2}
-    paramsSetsRB[i] = {'R': stride * i + shift + 1, 'S': stride * i + shift + 2}
 
-appPade = Pade(solver, mu0 = k0, approxParameters = paramsPade)
-appRB = RB(solver, mu0 = k0, approxParameters = paramsRB)
+appPade = Pade(solver, mu0 = k0, approxParameters = paramsPade,
+               verbosity = verb, homogeneize = homog)
+appRB = RB(solver, mu0 = k0, approxParameters = paramsRB, 
+           verbosity = verb, homogeneize = homog)
+appPoly = Pade(solver, mu0 = k0, approxParameters = paramsPoly,
+               verbosity = verb, homogeneize = homog)
 
 sweeper = Sweeper(mutars = mutars, mostExpensive = 'Approx')
 sweeper.ROMEngine = appPade
 sweeper.params = paramsSetsPade
-filenamePade = sweeper.sweep(filenamebase + 'PadeFE.dat', outputs = 'ALL')
-
+filenamePade = sweeper.sweep(filenamebase + 'Pade.dat')
 sweeper.ROMEngine = appRB
 sweeper.params = paramsSetsRB
-filenameRB = sweeper.sweep(filenamebase + 'RBFE.dat', outputs = 'ALL')
+filenameRB = sweeper.sweep(filenamebase + 'RB.dat')
+sweeper.ROMEngine = appPoly
+sweeper.params = paramsSetsPoly
+filenamePoly = sweeper.sweep(filenamebase + 'Poly.dat')
+
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normHF', 'normApp'], ['S'], onePlot = True,
+                    save = filenamebase + 'Norm',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normResRel'], ['S'], save = filenamebase + 'Res',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normErrRel'], ['S'], save = filenamebase + 'Err',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
 
-print("Pade'")
-sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['S'],
-             onePlot = True)
-print("RB")
-sweeper.plot(filenameRB, ['muRe'], ['normHF', 'normApp'], ['S'],
-             onePlot = True)
-print("Pade'")
-sweeper.plot(filenamePade, ['muRe'], ['normErr'], ['S'])
-print("RB")
-sweeper.plot(filenameRB, ['muRe'], ['normErr'], ['S'])
diff --git a/examples/scipy/LagrangeSweepUnstable.py b/examples/scipy/LagrangeSweepUnstable.py
index 18c7033..242b57d 100644
--- a/examples/scipy/LagrangeSweepUnstable.py
+++ b/examples/scipy/LagrangeSweepUnstable.py
@@ -1,42 +1,75 @@
 from copy import copy
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
 from rrompy.reduction_methods.lagrange import ApproximantLagrangePade as Pade
 from rrompy.reduction_methods.lagrange import ApproximantLagrangeRB as RB
 from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
 from rrompy.utilities.parameter_sampling import ManualSampler as MS
 
-npoints = 11
+npoints = 50
 
-solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 20)
+solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 30, verbosity = 0)
 mutars = np.linspace(6**.5, 16**.5, npoints)
-filenamebase = '../data/output/HelmholtzBubbleLagrangeUnstable'
+filenamebase = '../data/output/HelmholtzBubbleLagrange'
 
 k0 = np.mean(mutars)
 
 rescaling = lambda x: np.power(x, 2.)
 rescalingInv = lambda x: np.power(x, .5)
-paramsPade = {'S':4, 'POD':True, 'sampler':MS([6**.5, 16**.5], [[14**.5], [12**.5], [9**.5], [11**.5]])}
-paramsPade = {'S':4, 'POD':True, 'sampler':MS([6**.5, 16**.5], [[8**.5], [10**.5], [13**.5], [11**.5]])}
-paramsRB = copy(paramsPade)
-paramsSetsPade = [{'N': 3, 'M': 3}]
-paramsSetsRB = [{'R': 4}]
 
-appPade = Pade(solver, mu0 = k0, approxParameters = paramsPade)
-appRB = RB(solver, mu0 = k0, approxParameters = paramsRB)
+paramsChoices = {
+    'Stable':
+    {'S':4, 'POD':True,
+     'sampler':MS([6**.5, 16**.5], [[14**.5], [12**.5], [9**.5], [11**.5]])},
+    'Unstable':
+    {'S':4, 'POD':True,
+     'sampler':MS([6**.5, 16**.5], [[8**.5], [10**.5], [13**.5], [11**.5]])}
+                }
 
-sweeper = Sweeper(mutars = mutars, mostExpensive = 'Approx')
-sweeper.ROMEngine = appPade
-sweeper.params = paramsSetsPade
-filenamePade = sweeper.sweep(filenamebase + 'PadeFE.dat')
-
-sweeper.ROMEngine = appRB
-sweeper.params = paramsSetsRB
-filenameRB = sweeper.sweep(filenamebase + 'RBFE.dat')
-
-sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['S'],
-             onePlot = True)
-sweeper.plot(filenameRB, ['muRe'], ['normHF', 'normApp'], ['S'],
-             onePlot = True)
-sweeper.plot(filenamePade, ['muRe'], ['normErr'], ['S'])
-sweeper.plot(filenameRB, ['muRe'], ['normErr'], ['S'])
+j = 0
+filenamePade = [None] * len(paramsChoices.keys())
+filenameRB = [None] * len(paramsChoices.keys())
+for typeP in paramsChoices.keys():
+    paramsPade = paramsChoices[typeP]
+    paramsRB = copy(paramsPade)
+    paramsSetsPade = [{'N': 3, 'M': 3}]
+    paramsSetsRB = [{'R': 4}]
+    
+    appPade = Pade(solver, mu0 = k0, approxParameters = paramsPade,
+                   verbosity = 0)
+    appRB = RB(solver, mu0 = k0, approxParameters = paramsRB,
+               verbosity = 0)
+    
+    sweeper = Sweeper(mutars = mutars, mostExpensive = 'Approx')
+    sweeper.ROMEngine = appPade
+    sweeper.params = paramsSetsPade
+    filenamePade[j] = sweeper.sweep(filenamebase + 'Pade{}.dat'.format(typeP),
+                                    verbose = 0)
+    sweeper.ROMEngine = appRB
+    sweeper.params = paramsSetsRB
+    filenameRB[j] = sweeper.sweep(filenamebase + 'RB{}.dat'.format(typeP),
+                                  verbose = 0)
+    j += 1
+    
+print("Pade'")
+sweeper.plotCompare(filenamePade, ['muRe'],
+                    ['normHF', 'normApp'], ['S'], onePlot = True,
+                    save = filenamebase + 'PadeNorm', saveFormat = "png",
+                    labels = list(paramsChoices.keys()))
+sweeper.plotCompare(filenamePade, ['muRe'], ['normResRel'],
+                    ['S'], save = filenamebase + 'PadeRes', saveFormat = "png",
+                    labels = list(paramsChoices.keys()))
+sweeper.plotCompare(filenamePade, ['muRe'], ['normErrRel'],
+                    ['S'], save = filenamebase + 'PadeErr', saveFormat = "png", 
+                    labels = list(paramsChoices.keys()))
+print("RB")
+sweeper.plotCompare(filenameRB, ['muRe'],
+                    ['normHF', 'normApp'], ['S'], onePlot = True,
+                    save = filenamebase + 'RBNorm', saveFormat = "png",
+                    labels = list(paramsChoices.keys()))
+sweeper.plotCompare(filenameRB, ['muRe'], ['normResRel'],
+                    ['S'], save = filenamebase + 'RBRes', saveFormat = "png",
+                    labels = list(paramsChoices.keys()))
+sweeper.plotCompare(filenameRB, ['muRe'], ['normErrRel'],
+                    ['S'], save = filenamebase + 'RBErr', saveFormat = "png", 
+                    labels = list(paramsChoices.keys()))
diff --git a/examples/scipy/PadeLagrange.py b/examples/scipy/PadeLagrange.py
index bbd16d1..6fdcec3 100644
--- a/examples/scipy/PadeLagrange.py
+++ b/examples/scipy/PadeLagrange.py
@@ -1,86 +1,107 @@
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
 from rrompy.hfengines.scipy import HelmholtzSquareTransmissionProblemEngine as HSTPE
 from rrompy.hfengines.scipy import HelmholtzBoxScatteringProblemEngine as HBSPE
 from rrompy.reduction_methods.lagrange import ApproximantLagrangePade as Pade
 from rrompy.utilities.parameter_sampling import QuadratureSampler as QS
 
-testNo = 3
+testNo = 2
+verb = 0
+homog = True
+homog = False
 
 if testNo == 1:
     k0s = np.power([10 + 0.j, 14 + 0.j], .5)
     k0 = np.mean(k0s)
     ktar = (11 + .5j) ** .5
 
     rescaling = lambda x: np.power(x, 2.)
     rescalingInv = lambda x: np.power(x, .5)
     params = {'N':4, 'M':3, 'S':5, 'POD':True,
               'sampler':QS(k0s, "CHEBYSHEV", rescaling, rescalingInv)}    
 
-    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40)
+    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = Pade(solver, mu0 = k0, approxParameters = params)
+    approx = Pade(solver, mu0 = k0, approxParameters = params,
+                  verbosity = verb)
     
     approx.setupApprox()
 #    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_Pade''')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
     print('\nPoles Pade'':')
     print(approx.getPoles())
 
 ############
 elif testNo == 2:
     k0s = [3.85 + 0.j, 4.15 + 0.j]
     k0 = np.mean(k0s)
     ktar = 4 + .15j
 
     rescaling = lambda x: np.power(x, 2.)
     rescalingInv = lambda x: np.power(x, .5)
-    params = {'N':9, 'M':8, 'S':10, 'POD':True,
+    params = {'N':8, 'M':9, 'S':10, 'POD':True,
               'sampler':QS(k0s, "CHEBYSHEV", rescaling, rescalingInv)}    
 
-    solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50)
+    solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = Pade(solver, mu0 = k0, approxParameters = params)
+    approx = Pade(solver, mu0 = k0, approxParameters = params,
+                  verbosity = verb, homogeneize = homog)
     
     approx.setupApprox()
     approx.plotSamples()
     approx.plotApp(ktar, name = 'u_Pade''')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
     print('\nPoles Pade'':')
     print(approx.getPoles())
 
 ############
 elif testNo == 3:
     k0s = [2, 5]
     k0 = np.mean(k0s)
     ktar = 4.5 - 0.j
-    params = {'N':10, 'M':9, 'S':15, 'POD':True,
+    params = {'N':10, 'M':11, 'S':15, 'POD':True,
               'sampler':QS(k0s, "CHEBYSHEV")}
     
-    solver = HBSPE(R = 7, kappa = 3, theta = - np.pi * 75 / 180, n = 40)
+    solver = HBSPE(R = 7, kappa = 3, theta = - np.pi * 75 / 180, n = 40,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = Pade(solver, mu0 = k0, approxParameters = params)
+    approx = Pade(solver, mu0 = k0, approxParameters = params,
+                  verbosity = verb, homogeneize = homog)
     
     approx.setupApprox()
-#    approx.plotSamples()
+    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_Pade''')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
-
+    approx.plotRes(ktar, name = 'res')
+    
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
     print('\nPoles Pade'':')
     print(approx.getPoles())
     
diff --git a/examples/scipy/PadeTaylor.py b/examples/scipy/PadeTaylor.py
index cae5981..7bae70c 100644
--- a/examples/scipy/PadeTaylor.py
+++ b/examples/scipy/PadeTaylor.py
@@ -1,75 +1,97 @@
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
-from rrompy.hfengines.scipy import HelmholtzSquareTransmissionProblemEngine as HSTPE
+from rrompy.hfengines.scipy import (
+                             HelmholtzSquareTransmissionProblemEngine as HSTPE)
 from rrompy.hfengines.scipy import HelmholtzBoxScatteringProblemEngine as HBSPE
 from rrompy.reduction_methods.taylor import ApproximantTaylorPade as Pade
 
-testNo = 1
+testNo = 4
+verb = 0
+homog = True
+#homog = False
 
 if testNo == 1:
     params = {'N':4, 'M':3, 'E':4, 'sampleType':'Arnoldi', 'POD':True}
     k0 = 12 ** .5
     ktar = 10.5 ** .5
     
-    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40)
+    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = Pade(solver, mu0 = k0, approxParameters = params)
+    approx = Pade(solver, mu0 = k0, approxParameters = params,
+                  verbosity = verb)
     
     approx.setupApprox()
+#    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_Pade''')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
     print('\nPoles Pade'':')
     print(approx.getPoles())
 
 ############
 elif testNo == 2:
-    params = {'N':7, 'M':6, 'E':7, 'sampleType':'Arnoldi', 'POD':True}
+    params = {'N':6, 'M':7, 'E':7, 'sampleType':'Arnoldi', 'POD':True}
     k0 = 16 ** .5
-    ktar = 14 ** .5
+    ktar = 15 ** .5
     
-    solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50)
+    solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = Pade(solver, mu0 = k0, approxParameters = params)
+    approx = Pade(solver, mu0 = k0, approxParameters = params,
+                  verbosity = verb, homogeneize = homog)
     
     approx.setupApprox()
-    approx.plotSamples()
+#    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_Pade''')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
     print('\nPoles Pade'':')
     print(approx.getPoles())
 
 ############
 elif testNo in [3, 4]:
     if testNo == 3:
-        params = {'N':8, 'M':7, 'E':8, 'sampleType':'Krylov', 'POD':True}
+        params = {'N':7, 'M':8, 'E':8, 'sampleType':'Krylov', 'POD':True}
     else:
-        params = {'N':8, 'M':7, 'E':8, 'sampleType':'Arnoldi', 'POD':True}
+        params = {'N':7, 'M':8, 'E':8, 'sampleType':'Arnoldi', 'POD':True}
     k0 = 3
-    ktar = 4.25+.5j
+    ktar = 4.+0.j
 
-    solver = HBSPE(R = 5, kappa = 3, theta = - np.pi * 75 / 180, n = 30)
+    solver = HBSPE(R = 5, kappa = 3, theta = - np.pi * 75 / 180, n = 30,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = Pade(solver, mu0 = k0, approxParameters = params)
+    approx = Pade(solver, mu0 = k0, approxParameters = params,
+                  verbosity = verb, homogeneize = homog)
 
     approx.setupApprox()
     approx.plotSamples()
     approx.plotApp(ktar, name = 'u_Pade''')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
     print('\nPoles Pade'':')
     print(approx.getPoles())
-    
diff --git a/examples/scipy/RBLagrange.py b/examples/scipy/RBLagrange.py
index a8e07c0..bbfe2bc 100644
--- a/examples/scipy/RBLagrange.py
+++ b/examples/scipy/RBLagrange.py
@@ -1,85 +1,99 @@
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
 from rrompy.hfengines.scipy import HelmholtzSquareTransmissionProblemEngine as HSTPE
 from rrompy.hfengines.scipy import HelmholtzBoxScatteringProblemEngine as HBSPE
 from rrompy.reduction_methods.lagrange import ApproximantLagrangeRB as RB
 from rrompy.utilities.parameter_sampling import QuadratureSampler as QS
 
 testNo = 3
+verb = 0
+homog = True
+homog = False
 
 if testNo == 1:
     k0s = np.power([10 + 0.j, 14 + 0.j], .5)
     k0 = np.mean(k0s)
     ktar = (11 + .5j) ** .5
     
     rescaling = lambda x: np.power(x, 2.)
     rescalingInv = lambda x: np.power(x, .5)
     params = {'S':5, 'R':4, 'POD':True,
               'sampler':QS(k0s, "CHEBYSHEV", rescaling, rescalingInv)}    
 
-    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40)
+    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = RB(solver, mu0 = k0, approxParameters = params)
+    approx = RB(solver, mu0 = k0, approxParameters = params,
+                verbosity = verb)
     
     approx.setupApprox()
 #    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_RB')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
-    print('\nPoles RB:')
-    print(approx.getPoles())
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
 
 ############
 elif testNo == 2:
     k0s = [3.85 + 0.j, 4.15 + 0.j]
     k0 = np.mean(k0s)
     ktar = 4 + .15j
 
     rescaling = lambda x: np.power(x, 2.)
     rescalingInv = lambda x: np.power(x, .5)
     params = {'S':10, 'R':9, 'POD':True,
               'sampler':QS(k0s, "CHEBYSHEV", rescaling, rescalingInv)}    
 
-    solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50)
+    solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = RB(solver, mu0 = k0, approxParameters = params)
+    approx = RB(solver, mu0 = k0, approxParameters = params,
+                verbosity = verb, homogeneize = homog)
     
     approx.setupApprox()
-    approx.plotSamples()
+#    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_RB')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
-    print('\nPoles RB:')
-    print(approx.getPoles())
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
 
 ############
 elif testNo == 3:
     k0s = [2, 5]
     k0 = np.mean(k0s)
-    ktar = 4.5 - .2j
+    ktar = 4.5 - 0.j
     params = {'S':15, 'R':10, 'POD':True, 'sampler':QS(k0s, "CHEBYSHEV")}
     
-    solver = HBSPE(R = 7, kappa = 3, theta = - np.pi * 75 / 180, n = 40)
+    solver = HBSPE(R = 7, kappa = 3, theta = - np.pi * 75 / 180, n = 40,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = RB(solver, mu0 = k0, approxParameters = params)
+    approx = RB(solver, mu0 = k0, approxParameters = params,
+                verbosity = verb, homogeneize = homog)
 
     approx.setupApprox()
 #    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_RB')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
-
+    approx.plotRes(ktar, name = 'res')
+    
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
-    print('\nPoles RB:')
-    print(approx.getPoles())
-    
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
diff --git a/examples/scipy/RBTaylor.py b/examples/scipy/RBTaylor.py
index aa2c384..b95241c 100644
--- a/examples/scipy/RBTaylor.py
+++ b/examples/scipy/RBTaylor.py
@@ -1,75 +1,90 @@
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
 from rrompy.hfengines.scipy import HelmholtzSquareTransmissionProblemEngine as HSTPE
 from rrompy.hfengines.scipy import HelmholtzBoxScatteringProblemEngine as HBSPE
 from rrompy.reduction_methods.taylor import ApproximantTaylorRB as RB
 
-testNo = 3
+testNo = 4
+verb = 0
+homog = True
+#homog = False
 
 if testNo == 1:
     params = {'E':4, 'R':4, 'sampleType':'Arnoldi', 'POD':True}
     k0 = 12 ** .5
     ktar = 10.5 ** .5
     
-    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40)
+    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40,
+                   verbosity = verb)
     solver.omega = np.real(k0)
-    approx = RB(solver, mu0 = k0, approxParameters = params)
+    approx = RB(solver, mu0 = k0, approxParameters = params,
+                verbosity = verb)
     
     approx.setupApprox()
+#    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_RB')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
-    print('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}'.format(solNorm, appErr,
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
+    print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
-    print('\nPoles RB:')
-    print(approx.getPoles())
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
 
 ############
 elif testNo == 2:
     params = {'E':7, 'R':7, 'sampleType':'Arnoldi', 'POD':True}
     k0 = 16**.5
-    ktar = 14**.5
+    ktar = 15**.5
     
-    solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 4., n = 50)
+    solver = HSTPE(nT = 2, nB = 1, theta = np.pi * 45/180, kappa = 3.,
+                   n = 50, verbosity = verb)
     solver.omega = np.real(k0)
-    approx = RB(solver, mu0 = k0, approxParameters = params)
+    approx = RB(solver, mu0 = k0, approxParameters = params,
+                verbosity = verb, homogeneize = homog)
     
     approx.setupApprox()
-    approx.plotSamples()
+#    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_RB')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
-    print('\nPoles RB:')
-    print(approx.getPoles())
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))
 
 ############
 elif testNo in [3, 4]:
     if testNo == 3:
-        params = {'R':8, 'E':8, 'sampleType':'Krylov', 'POD':True}
+        params = {'E':8, 'sampleType':'Krylov', 'POD':True}
     else:
-        params = {'R':8, 'E':8, 'sampleType':'Arnoldi', 'POD':True}
+        params = {'E':8, 'sampleType':'Arnoldi', 'POD':True}
     k0 = 3
     ktar = 4.25+.5j
 
-    solver = HBSPE(R = 5, kappa = 3, theta = - np.pi * 75 / 180, n = 30)
+    solver = HBSPE(R = 5, kappa = 3, theta = - np.pi * 75 / 180,
+                   n = 30, verbosity = verb)
     solver.omega = np.real(k0)
-    approx = RB(solver, mu0 = k0, approxParameters = params)
+    approx = RB(solver, mu0 = k0, approxParameters = params,
+                verbosity = verb, homogeneize = homog)
     
     approx.setupApprox()
-    approx.plotSamples()
+#    approx.plotSamples()
     approx.plotApp(ktar, name = 'u_RB')
     approx.plotHF(ktar, name = 'u_HF')
     approx.plotErr(ktar, name = 'err')
+    approx.plotRes(ktar, name = 'res')
     
     appErr, solNorm = approx.normErr(ktar), approx.normHF(ktar)
+    resNorm, RHSNorm = approx.normRes(ktar), approx.normRHS(ktar)
     print(('SolNorm:\t{}\nErr:\t{}\nErrRel:\t{}').format(solNorm, appErr,
                                                    np.divide(appErr, solNorm)))
-    print('\nPoles RB:')
-    print(approx.getPoles())
-    
+    print(('RHSNorm:\t{}\nRes:\t{}\nResRel:\t{}').format(RHSNorm, resNorm,
+                                                  np.divide(resNorm, RHSNorm)))    
diff --git a/examples/scipy/TaylorPoles.py b/examples/scipy/TaylorPoles.py
index 2b7f3d5..d59d092 100644
--- a/examples/scipy/TaylorPoles.py
+++ b/examples/scipy/TaylorPoles.py
@@ -1,61 +1,68 @@
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
 from rrompy.reduction_methods.taylor import ApproximantTaylorPade as Pade
 from rrompy.reduction_methods.taylor import ApproximantTaylorRB as RB
-from rrompy.utilities import squareResonances
+from rrompy.utilities.base import squareResonances
 
-k0 = (12+1.j) ** .5
+verb = 0
+
+k0 = (12+0.j) ** .5
 Nmin, Nmax = 2, 10
 Nvals = np.arange(Nmin, Nmax + 1, 2)
 
 params = {'N':Nmin, 'M':0, 'Emax':Nmax, 'POD':True, 'sampleType':'Arnoldi'}
 #, 'robustTol':1e-14}
 
-#boolCon = lambda x : np.abs(np.imag(x)) < 1e-1 * np.abs(np.real(x) - np.real(z0))
+#boolCon = lambda x : np.abs(np.imag(x)) < 1e-1 * np.abs(np.real(x)
+#                                                      - np.real(z0))
 #cleanupParameters = {'boolCondition':boolCon, 'residueCheck':True}
 
-solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 25)
+solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 25, verbosity = verb)
 solver.omega = np.real(k0)
-approxP = Pade(solver, mu0 = k0, approxParameters = params)#,
+approxP = Pade(solver, mu0 = k0, approxParameters = params, verbosity = verb)#,
 #               equilibration = True, cleanupParameters = cleanupParameters)
-approxR = RB(solver, mu0 = k0, approxParameters = params)
+approxR = RB(solver, mu0 = k0, approxParameters = params, verbosity = verb)
 
 rP, rE = [None] * len(Nvals), [None] * len(Nvals)
 
 verbose = 1
 for j, N in enumerate(Nvals):
     if verbose > 0:
         print('N = E = {}'.format(N))
     approxP.approxParameters = {'N':N, 'E':N}
     approxR.approxParameters = {'R':N, 'E':N}
     if verbose > 1:
         print(approxP.approxParameters)
         print(approxR.approxParameters)
 
     rP[j] = approxP.getPoles()
     rE[j] = approxR.getPoles()
     if verbose > 2:
         print(rP)
         print(rE)
 
 from matplotlib import pyplot as plt
 plotRows = int(np.ceil(len(Nvals) / 3))
 fig, axes = plt.subplots(plotRows, 3, figsize = (15, 3.5 * plotRows))
 for j, N in enumerate(Nvals):
     i1, i2 = int(np.floor(j / 3)), j % 3
     axes[i1, i2].set_title('N = E = {}'.format(N))
     axes[i1, i2].plot(np.real(rP[j]), np.imag(rP[j]), 'Xb',
                       label="Pade'", markersize = 8)
-    axes[i1, i2].plot(np.real(rE[j]), np.imag(rE[j]), '*r',
-                      label="RB", markersize = 10)
+    axes[i1, i2].plot(np.real(rE[j]), np.imag(rE[j]), 'Pr',
+                      label="RB", markersize = 8)
     axes[i1, i2].axhline(linewidth=1, color='k')
     xmin, xmax = axes[i1, i2].get_xlim()
-    res = np.array(squareResonances(xmin**2., xmax**2., False), .5)
+    height = (xmax - xmin) / 2.
+    res = np.power(squareResonances(xmin**2., xmax**2., False), .5)
     axes[i1, i2].plot(res, np.zeros_like(res), 'ok', markersize = 4)
+    axes[i1, i2].plot(np.real(k0), np.imag(k0), 'om', markersize = 5)
+    axes[i1, i2].plot(np.real(k0) * np.ones(2),
+                      1.5 * height * np.arange(-1, 3, 2), '--m')
     axes[i1, i2].grid()
     axes[i1, i2].set_xlim(xmin, xmax)
-    axes[i1, i2].axis('equal')
+    axes[i1, i2].set_ylim(- height, height)
     p = axes[i1, i2].legend()
 plt.tight_layout()
 for j in range((len(Nvals) - 1) % 3 + 1, 3):
     axes[plotRows - 1, j].axis('off')
diff --git a/examples/scipy/TaylorSweep.py b/examples/scipy/TaylorSweep.py
index 9edac3e..9e9c8a3 100644
--- a/examples/scipy/TaylorSweep.py
+++ b/examples/scipy/TaylorSweep.py
@@ -1,64 +1,77 @@
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
 from rrompy.hfengines.scipy import HelmholtzBoxScatteringProblemEngine as HBSPE
 from rrompy.reduction_methods.taylor import ApproximantTaylorPade as Pade
 from rrompy.reduction_methods.taylor import ApproximantTaylorRB as RB
 from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
 
 testNo = 1
+verb = 0
+homog = True
+homog = False
 
 k0 = (12 + 0.j) ** .5
-npoints = 101
+npoints = 100
 
 shift = 5
-nsets = 3
+nsets = 2
 stride = 2
 Emax = stride * (nsets - 1) + shift + 1
 
 if testNo == 1:
-    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 10)
+    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 15,
+                   verbosity = verb)
     solver.omega = np.real(k0)
     params = {'Emax':Emax, 'sampleType':'ARNOLDI', 'POD':True}
     ktars = np.linspace(7**.5, 16**.5, npoints)
-    filenamebase = '../data/output/HelmholtzBubbleTaylor'
+    filenamebase = '../data/output/HelmholtzBubbleTSweep'
+    homog = False
 elif testNo == 2:
-    solver = HBSPE(R = 5, kappa = 3, theta = - np.pi * 75 / 180, n = 10)
+    solver = HBSPE(R = 5, kappa = 3, theta = - np.pi * 75 / 180, n = 10,
+                   verbosity = verb)
     solver.omega = np.real(k0)
     params = {'Emax':Emax, 'sampleType':'Arnoldi', 'POD':True}
-    ktars = np.linspace(11**.5, 13**.5, npoints)
-    filenamebase = '../data/output/HelmholtzBoxTaylor'
+    ktars = np.linspace(7**.5, 17**.5, npoints)
+    homogMSG = ""
+    if not homog: homogMSG = "Non"
+    filenamebase = '../data/output/HelmholtzBoxTSweep' + homogMSG + "Homog"
 
 paramsSetsPade = [None] * nsets
 paramsSetsRB = [None] * nsets
+paramsSetsPoly = [None] * nsets
 for i in range(nsets):
     paramsSetsPade[i] = {'N':stride*i+shift+1, 'M':stride*i+shift+1,
                          'E':stride*i+shift+1}
     paramsSetsRB[i] = {'E':stride*i+shift+1,'R':stride*i+shift+2}
+    paramsSetsPoly[i] = {'N':0, 'M':stride*i+shift+1,
+                         'E':stride*i+shift+1}
 
-appPade = Pade(solver, mu0 = k0, approxParameters = params)
-appRB = RB(solver, mu0 = k0, approxParameters = params)
+appPade = Pade(solver, mu0 = k0, approxParameters = params,
+               verbosity = verb, homogeneize = homog)
+appRB = RB(solver, mu0 = k0, approxParameters = params,
+           verbosity = verb, homogeneize = homog)
+appPoly = Pade(solver, mu0 = k0, approxParameters = params,
+               verbosity = verb, homogeneize = homog)
 
 sweeper = Sweeper(mutars = ktars, mostExpensive = 'Approx')
 sweeper.ROMEngine = appPade
 sweeper.params = paramsSetsPade
-filenamePade = sweeper.sweep(filenamebase + 'PadeFE.dat')
-
+filenamePade = sweeper.sweep(filenamebase + 'Pade.dat')
 sweeper.ROMEngine = appRB
 sweeper.params = paramsSetsRB
-filenameRB = sweeper.sweep(filenamebase + 'RBFE.dat')
+filenameRB = sweeper.sweep(filenamebase + 'RB.dat')
+sweeper.ROMEngine = appPoly
+sweeper.params = paramsSetsPoly
+filenamePoly = sweeper.sweep(filenamebase + 'Poly.dat')
 
-print('Pade''')
-sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['E'],
-             onePlot = True)
-print('RB')
-sweeper.plot(filenameRB, ['muRe'], ['normHF', 'normApp'], ['E'],
-             onePlot = True)
-print('Pade''')
-sweeper.plot(filenamePade, ['muRe'], ['normResRel'], ['E'])
-print('RB')
-sweeper.plot(filenameRB, ['muRe'], ['normResRel'], ['E'])
-print('Pade''')
-sweeper.plot(filenamePade, ['muRe'], ['normErrRel'], ['E'])
-print('RB')
-sweeper.plot(filenameRB, ['muRe'], ['normErrRel'], ['E'])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normHF', 'normApp'], ['E'], onePlot = True,
+                    save = filenamebase + 'Norm',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normResRel'], ['E'], save = filenamebase + 'Res',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normErrRel'], ['E'], save = filenamebase + 'Err',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
 
diff --git a/examples/scipy/airfoil.py b/examples/scipy/airfoil.py
index e8eaf25..498aa50 100644
--- a/examples/scipy/airfoil.py
+++ b/examples/scipy/airfoil.py
@@ -1,192 +1,212 @@
-from copy import copy
-import fenics as fen
+from copy import deepcopy as copy
 import numpy as np
-import sympy as sp
-from rrompy.hfengines.scipy import ScatteringProblemEngine as SPE
+import fenics as fen
+import ufl
+from rrompy.hfengines.scipy import HelmholtzBoxScatteringProblemEngine as HSP
 from rrompy.reduction_methods.taylor import ApproximantTaylorPade as TP
 from rrompy.reduction_methods.taylor import ApproximantTaylorRB as TRB
 from rrompy.reduction_methods.lagrange import ApproximantLagrangePade as LP
 from rrompy.reduction_methods.lagrange import ApproximantLagrangeRB as LRB
 from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
 from rrompy.utilities.parameter_sampling import QuadratureSampler as QS
+from rrompy.utilities.base.fenics import fenONE
 from operator import itemgetter
 def subdict(d, ks):
     return dict(zip(ks, itemgetter(*ks)(d)))
 
+verb = 0
+
+####################
+
+homog = True
+#homog = False
+
 ####################
 
 test = "solve"
 test = "Taylor"
 test = "Lagrange"
-#test = "TaylorSweep"
-#test = "LagrangeSweep"
+test = "TaylorSweep"
+test = "LagrangeSweep"
 
 plotSamples = True
 
-k0 = 10 + 1.j
-kLeft, kRight = 8 + 1.j, 12 + 1.j
+k0 = 10
+kLeft, kRight = 8 + 0.j, 12 + 0.j
 ktar = 11
-ktars = np.linspace(8, 12, 33) - .5j
+ktars = np.linspace(8, 12, 21) + 0.j
 
 PI = np.pi
 R = 2
 def Dboundary(x, on_boundary):
     return on_boundary and (x[0]**2+x[1]**2)**.5 < .95 * R
 
 kappa = 10
 theta = PI * - 45 / 180.
 mu = 1.1
 epsilon = .1
+mesh = fen.Mesh('../data/mesh/airfoil.xml')
 
-x, y = sp.symbols('x[0] x[1]', real=True)
-phiex = kappa * (x * np.cos(theta) + y * np.sin(theta))
-u0ex = - sp.exp(1.j * phiex)
+c, s = np.cos(theta), np.sin(theta)
+x, y = fen.SpatialCoordinate(mesh)[:]
+u0R = - fen.cos(kappa * (c * x + s * y))
+u0I = - fen.sin(kappa * (c * x + s * y))
 
 checkReal = x**2-x+y**2
-rhoroot = ((x**2+y**2)/((x-1)**2+y**2))**.25
-phiroot1 = sp.atan(-y/(x**2-x+y**2)) / 2
-phiroot2 = sp.atan(-y/(x**2-x+y**2)) / 2 - PI * sp.sign(-y/(x**2-x+y**2)) / 2
-kappam1 = (((rhoroot*sp.cos(phiroot1)+.5)**2.+(rhoroot*sp.sin(phiroot1))**2.)/
-           ((rhoroot*sp.cos(phiroot1)-1.)**2.+(rhoroot*sp.sin(phiroot1))**2.)
+rhop5 = ((x**2+y**2)/((x-1)**2+y**2))**.25
+phiroot1 = fen.atan(-y/(x**2-x+y**2)) / 2
+phiroot2 = fen.atan(-y/(x**2-x+y**2)) / 2 - PI * ufl.sign(-y/(x**2-x+y**2)) / 2
+kappam1 = (((rhop5*fen.cos(phiroot1)+.5)**2.+(rhop5*fen.sin(phiroot1))**2.)/
+           ((rhop5*fen.cos(phiroot1)-1.)**2.+(rhop5*fen.sin(phiroot1))**2.)
           )**.5 - mu
-kappam2 = (((rhoroot*sp.cos(phiroot2)+.5)**2.+(rhoroot*sp.sin(phiroot2))**2.)/
-           ((rhoroot*sp.cos(phiroot2)-1.)**2.+(rhoroot*sp.sin(phiroot2))**2.)
+kappam2 = (((rhop5*fen.cos(phiroot2)+.5)**2.+(rhop5*fen.sin(phiroot2))**2.)/
+           ((rhop5*fen.cos(phiroot2)-1.)**2.+(rhop5*fen.sin(phiroot2))**2.)
           )**.5 - mu
-Heps1 = .9 * .5 * (1 + kappam1/epsilon + sp.sin(PI*kappam1/epsilon) / PI) + .1
-Heps2 = .9 * .5 * (1 + kappam2/epsilon + sp.sin(PI*kappam2/epsilon) / PI) + .1
-
-mesh = fen.Mesh('../data/mesh/airfoil.xml')
-
-a = fen.Expression(('{0}>=0 ? ({2}>=-{1} ? ({2}<={1} ? {4} : 1) : .1) : '
-                    '({3}>=-{1} ? ({3}<={1} ? {5} : 1) : .1)')\
-                    .format(sp.printing.ccode(checkReal), str(epsilon), 
-                            sp.printing.ccode(kappam1),
-                            sp.printing.ccode(kappam2), 
-                            sp.printing.ccode(Heps1),
-                            sp.printing.ccode(Heps2)), degree = 3)
-
-DirichletTerm = [sp.printing.ccode(sp.simplify(sp.re(u0ex))),
-                 sp.printing.ccode(sp.simplify(sp.im(u0ex)))]
-
-solver = SPE()
-solver.omega = k0
+Heps1 = .9 * .5 * (1 + kappam1/epsilon + fen.sin(PI*kappam1/epsilon) / PI) + .1
+Heps2 = .9 * .5 * (1 + kappam2/epsilon + fen.sin(PI*kappam2/epsilon) / PI) + .1
+
+cTT = ufl.conditional(ufl.le(kappam1, epsilon), Heps1, fenONE)
+c_F = fen.Constant(.1)
+cFT = ufl.conditional(ufl.le(kappam2, epsilon), Heps2, fenONE)
+c_F = fen.Constant(.1)
+cT = ufl.conditional(ufl.ge(kappam1, - epsilon), cTT, c_F)
+cF = ufl.conditional(ufl.ge(kappam2, - epsilon), cFT, c_F)
+a = ufl.conditional(ufl.ge(checkReal, 0.), cT, cF)
+
+###
+solver = HSP(R, np.abs(k0), theta, n = 1, verbosity = verb,
+             degree_threshold = 8)
 solver.V = fen.FunctionSpace(mesh, "P", 3)
 solver.diffusivity = a
 solver.DirichletBoundary = Dboundary
-solver.RobinBoundary = 'rest'
-solver.DirichletDatum = [fen.Expression(x, degree = 3)\
-                                                    for x in DirichletTerm]
-
-baseRe, baseIm = solver.DirichletDatum
-baseRe = fen.project(baseRe, solver.V)
-baseIm = fen.project(baseIm, solver.V)
-uinc = np.array(baseRe.vector()) + 1.j * np.array(baseIm.vector())
+solver.RobinBoundary = "REST"
+solver.DirichletDatum = [u0R, u0I]
+###
     
 if test == "solve":
-    aF = fen.interpolate(a, solver.V)
-    av = aF.vector()
-    uh = solver.solve(k0)
+    uinc = solver.liftDirichletData(k0)
+    if homog:
+        uhtot = solver.solve(k0, homogeneized = homog)
+        uh = uhtot + uinc
+    else:
+        uh = solver.solve(k0, homogeneized = homog)
+        uhtot = uh - uinc
     print(solver.norm(uh))
-    uhtot = uh - uinc
     print(solver.norm(uhtot))
-    solver.plot(av, what = 'Real', name = 'a')
-    solver.plot(uhtot - uh, what = 'Real', name = 'u_inc')
+    solver.plot(fen.project(a, solver.V).vector(), what = 'Real',
+                name = 'a')
+    solver.plot(uinc, what = 'Real', name = 'u_inc')
     solver.plot(uh, what = 'ABS')
     solver.plot(uhtot, what = 'ABS', name = 'u + u_inc')
 
 elif test in ["Taylor", "Lagrange"]:
     if test == "Taylor":
-        params = {'N':8, 'M':7, 'R':8, 'E':8, 'sampleType':'Krylov', 'POD':False}
-        params = {'N':8, 'M':7, 'R':8, 'E':8, 'sampleType':'Arnoldi', 'POD':False}
+        params = {'N':8, 'M':8, 'R':8, 'E':8,
+                  'sampleType':'Arnoldi', 'POD':True}
         parPade = subdict(params, ['N', 'M', 'E', 'sampleType', 'POD'])
         parRB = subdict(params, ['R', 'E', 'sampleType', 'POD'])
-        approxPade = TP(solver, mu0 = k0, approxParameters = parPade)
-        approxRB = TRB(solver, mu0 = k0, approxParameters = parRB)
+        approxPade = TP(solver, mu0 = k0, approxParameters = parPade,
+                        verbosity = verb, homogeneize = homog)
+        approxRB = TRB(solver, mu0 = k0, approxParameters = parRB,
+                       verbosity = verb, homogeneize = homog)
     else:
-        params = {'N':8, 'M':7, 'R':9, 'S':9, 'POD':True,
+        params = {'N':8, 'M':8, 'R':9, 'S':9, 'POD':True,
                   'sampler':QS([kLeft, kRight], "CHEBYSHEV")}
         parPade = subdict(params, ['N', 'M', 'S', 'POD', 'sampler'])
         parRB = subdict(params, ['R', 'S', 'POD', 'sampler'])
         approxPade = LP(solver, mu0 = np.mean([kLeft, kRight]),
-                        approxParameters = parPade)
+                        approxParameters = parPade, verbosity = verb,
+                        homogeneize = homog)
         approxRB = LRB(solver, mu0 = np.mean([kLeft, kRight]),
-                       approxParameters = parRB)
+                       approxParameters = parRB, verbosity = verb,
+                       homogeneize = homog)
 
     approxPade.setupApprox()
     approxRB.setupApprox()
     if plotSamples:
         approxPade.plotSamples()
-    PadeErr, solNorm = approxPade.normErr(ktar), approxPade.normHF(ktar)
-    RBErr = approxRB.normErr(ktar)
-    print(('SolNorm:\t{}\nErrPade:\t{}\nErrRelPade:\t{}\nErrRB:\t\t{}'
-           '\nErrRelRB:\t{}').format(solNorm, PadeErr,
-                                     np.divide(PadeErr, solNorm), RBErr,
-                                     np.divide(RBErr, solNorm)))
+    approxPade.plotHF(ktar, name = 'u_HF')
+    approxPade.plotApp(ktar, name = 'u_Pade''')
+    approxPade.plotErr(ktar, name = 'err_Pade''')
+    approxPade.plotRes(ktar, name = 'res_Pade''')
+    approxRB.plotApp(ktar, name = 'u_RB')
+    approxRB.plotErr(ktar, name = 'err_RB')
+    approxRB.plotRes(ktar, name = 'res_RB')
+    
+    HFNorm, RHSNorm = approxPade.normHF(ktar), approxPade.normRHS(ktar)
+    PadeRes, PadeErr = approxPade.normRes(ktar), approxPade.normErr(ktar)
+    RBRes, RBErr = approxRB.normRes(ktar), approxRB.normErr(ktar)
+    print('HFNorm:\t{}\nRHSNorm:\t{}'.format(HFNorm, RHSNorm))
+    print('PadeRes:\t{}\nPadeErr:\t{}'.format(PadeRes, PadeErr))
+    print('RBRes:\t{}\nRBErr:\t{}'.format(RBRes, RBErr))
 
     print('\nPoles Pade'':')
     print(approxPade.getPoles())
-    print('\nPoles RB:')
-    print(approxRB.getPoles())
-
-    uHF = approxPade.getHF(ktar)
-    solver.plot(uHF, name = 'u_ex')
-    approxPade.plotApp(ktar, name = 'u_Pade''')
-    approxRB.plotApp(ktar, name = 'u_RB')
-    approxPade.plotErr(ktar, name = 'errPade''')
-    approxRB.plotErr(ktar, name = 'errRB')
 
 elif test in ["TaylorSweep", "LagrangeSweep"]:
     if test == "TaylorSweep":
         shift = 10
-        nsets = 3
+        nsets = 2
         stride = 3
         Emax = stride * (nsets - 1) + shift + 1
-        params = {'Emax':Emax, 'sampleType':'Krylov', 'POD':False}
-        params = {'Emax':Emax, 'sampleType':'Arnoldi', 'POD':False}
+        params = {'Emax':Emax, 'sampleType':'Arnoldi', 'POD':True}
         paramsSetsPade = [None] * nsets
         paramsSetsRB = [None] * nsets
         for i in range(nsets):
-            paramsSetsPade[i] = {'N':stride*i+shift + 1, 'M':stride*i+shift,
+            paramsSetsPade[i] = {'N':stride*i+shift + 1, 'M':stride*i+shift+1,
                                  'E':stride*i+shift + 1}
-            paramsSetsRB[i] = {'E':stride*i+shift + 1,'R':stride*i+shift + 1}
-        approxPade = TP(solver, mu0 = kappa,approxParameters = params)
-        approxRB = TRB(solver, mu0 = kappa, approxParameters = params)
+            paramsSetsRB[i] = {'E':stride*i+shift + 1,'R':stride*i+shift + 2}
+        approxPade = TP(solver, mu0 = kappa,approxParameters = params,
+                        verbosity = verb, homogeneize = homog)
+        approxRB = TRB(solver, mu0 = kappa, approxParameters = params,
+                       verbosity = verb, homogeneize = homog)
     else:
         shift = 10
-        nsets = 3
+        nsets = 2
         stride = 3
         Smax = stride * (nsets - 1) + shift + 2
         paramsPade = {'S':Smax, 'POD':True,
                       'sampler':QS([kLeft, kRight], "CHEBYSHEV")}
         paramsRB = copy(paramsPade)
         paramsSetsPade = [None] * nsets
         paramsSetsRB = [None] * nsets
         for i in range(nsets):
-            paramsSetsPade[i] = {'N': stride*i+shift+1, 'M': stride*i+shift,
+            paramsSetsPade[i] = {'N': stride*i+shift+1, 'M': stride*i+shift+1,
                                  'S': stride*i+shift+2}
-            paramsSetsRB[i] = {'R': stride*i+shift+1, 'S': stride*i+shift+2}
+            paramsSetsRB[i] = {'R': stride*i+shift+2, 'S': stride*i+shift+2}
         approxPade = LP(solver, mu0 = np.mean([kLeft, kRight]),
-                        approxParameters = paramsPade)
+                        approxParameters = paramsPade, verbosity = verb,
+                        homogeneize = homog)
         approxRB = LRB(solver, mu0 = np.mean([kLeft, kRight]),
-                       approxParameters = paramsRB)
+                       approxParameters = paramsRB, verbosity = verb,
+                       homogeneize = homog)
     
     sweeper = Sweeper(mutars = ktars, mostExpensive = 'Approx')
 
+    homogMSG = ""
+    if not homog: homogMSG = "Non"
+    filenamebase = '../data/output/airfoil' + test[:-5] + homogMSG + "Homog"
+    
     sweeper.ROMEngine = approxPade
     sweeper.params = paramsSetsPade
-    filenamePade = sweeper.sweep('../data/output/airfoil'+test[:-5]+'Pade.dat')
+    filenamePade = sweeper.sweep(filenamebase +'Pade.dat')
     
     sweeper.ROMEngine = approxRB
     sweeper.params = paramsSetsRB
-    filenameRB = sweeper.sweep('../data/output/airfoil'+test[:-5]+'RB.dat')
+    filenameRB = sweeper.sweep(filenamebase +'RB.dat')
     
     if test == "TaylorSweep":
         constr = ['E']
     else:
         constr = ['S']
-    sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], constr,
-                 onePlot = True)
-    sweeper.plot(filenameRB, ['muRe'], ['normHF', 'normApp'], constr,
-                 onePlot = True)
-    sweeper.plot(filenamePade, ['muRe'], ['normErr'], constr)
-    sweeper.plot(filenameRB, ['muRe'], ['normErr'], constr)
+    sweeper.plotCompare([filenamePade, filenameRB], ['muRe'],
+                        ['normHF', 'normApp'], constr, onePlot = True,
+                        save = filenamebase + 'Norm',
+                        saveFormat = "png", labels = ["Pade'", "RB"])
+    sweeper.plotCompare([filenamePade, filenameRB], ['muRe'], ['normResRel'],
+                        constr, save = filenamebase + 'Res',
+                        saveFormat = "png", labels = ["Pade'", "RB"])    
+    sweeper.plotCompare([filenamePade, filenameRB], ['muRe'], ['normErrRel'],
+                        constr, save = filenamebase + 'Err',
+                        saveFormat = "png", labels = ["Pade'", "RB"])
+
diff --git a/examples/scipy/domainCrack.py b/examples/scipy/domainCrack.py
deleted file mode 100644
index a3ae673..0000000
--- a/examples/scipy/domainCrack.py
+++ /dev/null
@@ -1,109 +0,0 @@
-import fenics as fen
-import numpy as np
-import sympy as sp
-from rrompy.hfengines.scipy import HelmholtzProblemEngine as HPE
-from rrompy.reduction_methods.taylor import ApproximantTaylorPade as TP
-from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
-
-test = "poles"
-#test = "error"
-#test = "norm"
-
-k0 = 10
-ktars = np.power([80, 95, 98], .5)
-ktarsNorm = np.linspace(78**.5, 122**.5, 250)
-
-def boundaryNeumann(x, on_boundary):
-    return on_boundary and x[1] > .25 and x[0] > 0.995 and x[0] < 1.005
-
-x0, y0 = .5, .5
-Rr, Ri = .1, .1
-x, y = sp.symbols('x[0] x[1]', real=True)
-fex = sp.exp(- ((x - x0)**2 + (y - y0)**2) / 2 / Rr**2)
-
-meshname = '../data/mesh/crack_coarse.xml'
-#meshname = '../data/mesh/crack_fine.xml'
-mesh = fen.Mesh(meshname)
-forcingTerm = fen.Expression(sp.printing.ccode(sp.simplify(fex)), degree = 3)
-
-solver = HPE()
-solver.omega = np.real(k0)
-solver.V = fen.FunctionSpace(mesh, "P", 3)
-solver.forcingTerm = forcingTerm
-solver.NeumannBoundary = boundaryNeumann
-solver.DirichletBoundary = 'rest'
-
-if test == "poles":
-    appPoles = {}
-    Emax = 13
-    params = {'N':6, 'M':0, 'E':6, 'Emax':Emax, 'sampleType':'Arnoldi',
-              'POD':True}
-
-    approxPade = TP(solver, mu0 = k0, approxParameters = params)
-    for E in range(6, Emax + 1):
-        approxPade.E = E
-        appPoles[E] = np.sort(approxPade.getPoles())
-
-    a = fen.dot(fen.grad(solver.u), fen.grad(solver.v)) * fen.dx
-    A = fen.assemble(a)
-    fen.DirichletBC(solver.V, fen.Constant(0.),
-                    solver.DirichletBoundary).apply(A)
-    AMat = fen.as_backend_type(A).mat()
-    Ar, Ac, Av = AMat.getValuesCSR()
-    import scipy.sparse as scsp
-    A = scsp.csr_matrix((Av, Ac, Ar), shape = AMat.size)
-
-    m = fen.dot(solver.u, solver.v) * fen.dx
-    M = fen.assemble(m)
-    fen.DirichletBC(solver.V, fen.Constant(0.),
-                    solver.DirichletBoundary).apply(M)
-    MMat = fen.as_backend_type(M).mat()
-    Mr, Mc, Mv = MMat.getValuesCSR()
-    import scipy.sparse as scsp
-    M = scsp.csr_matrix((Mv, Mc, Mr), shape = MMat.size)
-
-    poles = scsp.linalg.eigs(A, k = 7, M = M, sigma = 100.,
-                             return_eigenvectors = False)
-    II = np.argsort(np.abs(poles - k0))
-    poles = poles[II]
-    print('Exact', end = ': ')
-    [print('{},{}'.format(np.real(x), np.imag(x)), end = ',') for x in poles]
-    print()
-    
-    for E in range(6, Emax + 1):
-        print(E, end = ': ')
-        [print('{},{}'.format(np.real(x), np.imag(x)), end = ',')\
-                                                 for x in np.sort(appPoles[E])]
-        print()
-    
-elif test == "error":
-    M0 = 5
-    Emax = 13
-    params = {'Emax':Emax, 'sampleType':'Arnoldi', 'POD':True}
-    paramsSetsPade = [None] * (Emax - M0 + 1)
-    for M in range(M0, Emax + 1):
-        paramsSetsPade[M - M0] = {'N':M0 + 1, 'M':M, 'E':max(M, M0 + 1)}
-    approxPade = TP(solver, mu0 = k0, approxParameters = params)
-    
-    sweeper = Sweeper(mutars = ktars, mostExpensive = 'Approx')
-    sweeper.ROMEngine = approxPade
-    sweeper.params = paramsSetsPade
-    filenamePade = sweeper.sweep('../data/output/membrane_error.dat', 
-                                 outputs = 'ALL')
-    sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['E'],
-                 onePlot = True)
-    sweeper.plot(filenamePade, ['muRe'], ['normErr'], ['E'])
-
-elif test == "norm":
-    params = [{'N':6, 'M':10, 'E':10, 'sampleType':'Arnoldi', 'POD':True}]
-    approxPade = TP(solver, mu0 = k0, approxParameters = params[0])
-    
-    sweeper = Sweeper(mutars = ktarsNorm, mostExpensive = 'Approx')
-    sweeper.ROMEngine = approxPade
-    sweeper.params = params
-    filenamePade = sweeper.sweep('../data/output/membrane_norm.dat',
-                                 outputs = ["normHF", "normApp", "normErr"])
-    sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['E'],
-                 onePlot = True)
-    sweeper.plot(filenamePade, ['muRe'], ['normErr'], ['E'])
-
diff --git a/examples/scipy/laplaceGaussianTaylor.py b/examples/scipy/laplaceGaussianTaylor.py
new file mode 100644
index 0000000..bd16914
--- /dev/null
+++ b/examples/scipy/laplaceGaussianTaylor.py
@@ -0,0 +1,100 @@
+import numpy as np
+from rrompy.hfengines.scipy import LaplaceDiskGaussian as LDG
+from rrompy.reduction_methods.taylor import ApproximantTaylorPade as Pade
+from rrompy.reduction_methods.taylor import ApproximantTaylorRB as RB
+from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
+from operator import itemgetter
+def subdict(d, ks):
+    return dict(zip(ks, itemgetter(*ks)(d)))
+
+testNo = 3
+verb = 0
+
+if testNo == 1:
+    mu = 4.
+    solver = LDG(n = 40, verbosity = verb)
+
+    uh = solver.solve(mu)
+    solver.plotmesh()
+    print(solver.norm(uh))
+    solver.plot(uh)
+    
+############
+if testNo == 2:
+    params = {'N':8, 'M':8, 'E':8, 'sampleType':'Arnoldi', 'POD':True}
+#    params = {'N':8, 'M':8, 'E':8, 'sampleType':'Krylov', 'POD':True}
+    mu0 = 0.
+    solver = LDG(n = 20, degree_threshold = 15, verbosity = verb)
+    approxP = Pade(solver, mu0 = mu0, approxParameters = params,
+                   verbosity = verb)
+    paramsRB = subdict(params, ['E', 'sampleType', 'POD'])
+    approxR = RB(solver, mu0 = mu0, approxParameters = paramsRB,
+                 verbosity = verb)
+    
+    approxP.setupApprox()
+    approxR.setupApprox()
+#    approxP.plotSamples()
+
+    mutar = 3.25
+    approxP.plotHF(mutar, name = 'u_HF')
+    approxP.plotApp(mutar, name = 'u_Pade''')
+    approxR.plotApp(mutar, name = 'u_RB')
+    approxP.plotErr(mutar, name = 'err_Pade''')
+    approxR.plotErr(mutar, name = 'err_RB')
+    
+    solNorm = approxP.normHF(mutar)
+    appPErr = approxP.normErr(mutar)
+    appRErr = approxR.normErr(mutar)
+    print(('SolNorm:\t{}\nErrRelP:\t{}\nErrRelR:\t{}').format(solNorm,
+                                         appPErr / solNorm, appRErr / solNorm))
+
+############
+elif testNo == 3:
+    mu0 = 0.
+    mutars = np.linspace(0., 4., 60)
+    solver = LDG(n = 10, degree_threshold = 15, verbosity = verb)
+    shift = 2
+    nsets = 6
+    stride = 2
+    Emax = stride * (nsets - 1) + shift
+    params = {'Emax':Emax, 'sampleType':'Arnoldi', 'POD':True}
+    params = {'Emax':Emax, 'sampleType':'Krylov', 'POD':False}
+    paramsSetsPade = [None] * nsets
+    paramsSetsRB = [None] * nsets
+    paramsSetsPoly = [None] * nsets
+    for i in range(nsets):
+        paramsSetsPade[i] = {'N':stride*i+shift, 'M':stride*i+shift,
+                             'E':stride*i+shift}
+        paramsSetsRB[i] = {'E':stride*i+shift}
+        paramsSetsPoly[i] = {'N':0, 'M':stride*i+shift,
+                             'E':stride*i+shift}
+    approxPade = Pade(solver, mu0 = mu0, approxParameters = params,
+                      verbosity = verb)
+    approxRB = RB(solver, mu0 = mu0, approxParameters = params,
+                  verbosity = verb)
+    approxPoly = Pade(solver, mu0 = mu0, approxParameters = params,
+                      verbosity = verb)
+
+    filenamebase = '../data/output/LapGTaylor'
+    
+    sweeper = Sweeper(mutars = mutars, mostExpensive = 'Approx')
+    sweeper.ROMEngine = approxPade
+    sweeper.params = paramsSetsPade
+    filenamePade = sweeper.sweep(filenamebase + 'Pade.dat')
+    sweeper.ROMEngine = approxRB
+    sweeper.params = paramsSetsRB
+    filenameRB = sweeper.sweep(filenamebase + 'RB.dat')
+    sweeper.ROMEngine = approxPoly
+    sweeper.params = paramsSetsPoly
+    filenamePoly = sweeper.sweep(filenamebase + 'Poly.dat')
+
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normHF', 'normApp'], ['E'], onePlot = True,
+                    save = filenamebase + 'Norm',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normResRel'], ['E'], save = filenamebase + 'Res',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normErrRel'], ['E'], save = filenamebase + 'Err',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
diff --git a/examples/scipy/membraneTaylor.py b/examples/scipy/membraneTaylor.py
index a3ae673..dee9594 100644
--- a/examples/scipy/membraneTaylor.py
+++ b/examples/scipy/membraneTaylor.py
@@ -1,109 +1,96 @@
 import fenics as fen
 import numpy as np
-import sympy as sp
-from rrompy.hfengines.scipy import HelmholtzProblemEngine as HPE
+from rrompy.hfengines.base import HelmholtzProblemEngine as HPE
 from rrompy.reduction_methods.taylor import ApproximantTaylorPade as TP
 from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
 
+verb = 0
+
 test = "poles"
-#test = "error"
-#test = "norm"
+test = "error"
 
 k0 = 10
-ktars = np.power([80, 95, 98], .5)
-ktarsNorm = np.linspace(78**.5, 122**.5, 250)
+ktars = np.linspace(78**.5, 122**.5, 50)
 
 def boundaryNeumann(x, on_boundary):
     return on_boundary and x[1] > .25 and x[0] > 0.995 and x[0] < 1.005
 
-x0, y0 = .5, .5
-Rr, Ri = .1, .1
-x, y = sp.symbols('x[0] x[1]', real=True)
-fex = sp.exp(- ((x - x0)**2 + (y - y0)**2) / 2 / Rr**2)
-
 meshname = '../data/mesh/crack_coarse.xml'
 #meshname = '../data/mesh/crack_fine.xml'
 mesh = fen.Mesh(meshname)
-forcingTerm = fen.Expression(sp.printing.ccode(sp.simplify(fex)), degree = 3)
 
-solver = HPE()
+x, y = fen.SpatialCoordinate(mesh)[:]
+x0, y0 = .5, .5
+Rr, Ri = .1, .1
+forcingTerm = fen.exp(- ((x - x0)**2 + (y - y0)**2) / 2 / Rr**2)
+
+solver = HPE(verbosity = verb)
 solver.omega = np.real(k0)
 solver.V = fen.FunctionSpace(mesh, "P", 3)
 solver.forcingTerm = forcingTerm
 solver.NeumannBoundary = boundaryNeumann
 solver.DirichletBoundary = 'rest'
 
 if test == "poles":
     appPoles = {}
     Emax = 13
     params = {'N':6, 'M':0, 'E':6, 'Emax':Emax, 'sampleType':'Arnoldi',
               'POD':True}
 
-    approxPade = TP(solver, mu0 = k0, approxParameters = params)
+    approxPade = TP(solver, mu0 = k0, approxParameters = params,
+                    verbosity = verb)
     for E in range(6, Emax + 1):
         approxPade.E = E
         appPoles[E] = np.sort(approxPade.getPoles())
 
     a = fen.dot(fen.grad(solver.u), fen.grad(solver.v)) * fen.dx
     A = fen.assemble(a)
     fen.DirichletBC(solver.V, fen.Constant(0.),
                     solver.DirichletBoundary).apply(A)
     AMat = fen.as_backend_type(A).mat()
     Ar, Ac, Av = AMat.getValuesCSR()
     import scipy.sparse as scsp
     A = scsp.csr_matrix((Av, Ac, Ar), shape = AMat.size)
 
     m = fen.dot(solver.u, solver.v) * fen.dx
     M = fen.assemble(m)
     fen.DirichletBC(solver.V, fen.Constant(0.),
                     solver.DirichletBoundary).apply(M)
     MMat = fen.as_backend_type(M).mat()
     Mr, Mc, Mv = MMat.getValuesCSR()
     import scipy.sparse as scsp
     M = scsp.csr_matrix((Mv, Mc, Mr), shape = MMat.size)
 
     poles = scsp.linalg.eigs(A, k = 7, M = M, sigma = 100.,
                              return_eigenvectors = False)
     II = np.argsort(np.abs(poles - k0))
     poles = poles[II]
     print('Exact', end = ': ')
     [print('{},{}'.format(np.real(x), np.imag(x)), end = ',') for x in poles]
     print()
     
     for E in range(6, Emax + 1):
         print(E, end = ': ')
         [print('{},{}'.format(np.real(x), np.imag(x)), end = ',')\
                                                  for x in np.sort(appPoles[E])]
         print()
     
 elif test == "error":
     M0 = 5
-    Emax = 13
+    Emax = 8
     params = {'Emax':Emax, 'sampleType':'Arnoldi', 'POD':True}
     paramsSetsPade = [None] * (Emax - M0 + 1)
     for M in range(M0, Emax + 1):
         paramsSetsPade[M - M0] = {'N':M0 + 1, 'M':M, 'E':max(M, M0 + 1)}
-    approxPade = TP(solver, mu0 = k0, approxParameters = params)
+    approxPade = TP(solver, mu0 = k0, approxParameters = params,
+                    verbosity = verb)
     
     sweeper = Sweeper(mutars = ktars, mostExpensive = 'Approx')
     sweeper.ROMEngine = approxPade
     sweeper.params = paramsSetsPade
     filenamePade = sweeper.sweep('../data/output/membrane_error.dat', 
                                  outputs = 'ALL')
-    sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['E'],
-                 onePlot = True)
-    sweeper.plot(filenamePade, ['muRe'], ['normErr'], ['E'])
-
-elif test == "norm":
-    params = [{'N':6, 'M':10, 'E':10, 'sampleType':'Arnoldi', 'POD':True}]
-    approxPade = TP(solver, mu0 = k0, approxParameters = params[0])
-    
-    sweeper = Sweeper(mutars = ktarsNorm, mostExpensive = 'Approx')
-    sweeper.ROMEngine = approxPade
-    sweeper.params = params
-    filenamePade = sweeper.sweep('../data/output/membrane_norm.dat',
-                                 outputs = ["normHF", "normApp", "normErr"])
-    sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['E'],
+    sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['M'],
                  onePlot = True)
-    sweeper.plot(filenamePade, ['muRe'], ['normErr'], ['E'])
+    sweeper.plot(filenamePade, ['muRe'], ['normErr'], ['M'])
 
diff --git a/examples/scipy/parametricDomain.py b/examples/scipy/parametricDomain.py
index 6c953c5..f5c5dc4 100644
--- a/examples/scipy/parametricDomain.py
+++ b/examples/scipy/parametricDomain.py
@@ -1,89 +1,103 @@
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleDomainProblemEngine as HSBDPE
 from rrompy.reduction_methods.taylor import ApproximantTaylorPade as Pade
 from rrompy.reduction_methods.taylor import ApproximantTaylorRB as RB
 from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
 from operator import itemgetter
 def subdict(d, ks):
     return dict(zip(ks, itemgetter(*ks)(d)))
 
 testNo = 3
+verb = 0
 
 if testNo == 1:
     mu = 7 ** .5
-    solver = HSBDPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40)
+    solver = HSBDPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40, mu0 = mu,
+                    degree_threshold = 15, verbosity = verb)
 
     uh = solver.solve(mu)
     solver.plotmesh()
     print(solver.norm(uh))
     solver.plot(uh)
     
 ############
 if testNo == 2:
-    params = {'N':7, 'M':8, 'E':8, 'sampleType':'Arnoldi', 'POD':True}
+    params = {'N':8, 'M':8, 'E':8, 'sampleType':'Arnoldi', 'POD':True}
 #    params = {'N':7, 'M':8, 'E':8, 'sampleType':'Krylov', 'POD':True}
     mu0 = 7 ** .5
-    mutar = (7.5 + .5j) ** .5
-    solver = HSBDPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40)
-    approxP = Pade(solver, mu0 = mu0, approxParameters = params)
+    mutar = (7. + .1j) ** .5
+    solver = HSBDPE(kappa = 12 ** .5, theta = np.pi / 3, n = 40, mu0 = mu0,
+                    degree_threshold = 15, verbosity = verb)
+    approxP = Pade(solver, mu0 = mu0, approxParameters = params,
+                   verbosity = verb)
     paramsRB = subdict(params, ['E', 'sampleType', 'POD'])
-    approxR = RB(solver, mu0 = mu0, approxParameters = paramsRB)
+    approxR = RB(solver, mu0 = mu0, approxParameters = paramsRB,
+                 verbosity = verb)
     
     approxP.setupApprox()
     approxR.setupApprox()
 #    approxP.plotSamples()
     approxP.plotHF(mutar, name = 'u_HF')
     approxP.plotApp(mutar, name = 'u_Pade''')
     approxR.plotApp(mutar, name = 'u_RB')
     approxP.plotErr(mutar, name = 'err_Pade''')
     approxR.plotErr(mutar, name = 'err_RB')
     
     solNorm = approxP.normHF(mutar)
     appPErr = approxP.normErr(mutar)
     appRErr = approxR.normErr(mutar)
     print(('SolNorm:\t{}\nErrRelP:\t{}\nErrRelR:\t{}').format(solNorm,
                                          appPErr / solNorm, appRErr / solNorm))
     print('\nPoles Pade'':')
     print(approxP.getPoles())
-    print('\nPoles RB:')
-    print(approxR.getPoles())
 
 ############
 elif testNo == 3:
     mu0 = 14 ** .5
-    mutars = np.linspace(9**.5, 19**.5, 250)
-#    mutars = np.linspace(9**.5, 19**.5, 20)
-    solver = HSBDPE(kappa = 12 ** .5, theta = np.pi / 3, n = 20)
+    mutars = np.linspace(9**.5, 19**.5, 100)
+    solver = HSBDPE(kappa = 12 ** .5, theta = np.pi / 3, n = 20, mu0 = mu0,
+                    degree_threshold = 15, verbosity = verb)
     shift = 10
     nsets = 1
     stride = 2
     Emax = stride * (nsets - 1) + shift
     params = {'Emax':Emax, 'sampleType':'Arnoldi', 'POD':True}
     paramsSetsPade = [None] * nsets
     paramsSetsRB = [None] * nsets
+    paramsSetsPoly = [None] * nsets
     for i in range(nsets):
-        paramsSetsPade[i] = {'N':stride*i+shift, 'M':stride*i+shift, 'E':stride*i+shift}
+        paramsSetsPade[i] = {'N':stride*i+shift, 'M':stride*i+shift,
+                             'E':stride*i+shift}
         paramsSetsRB[i] = {'E':stride*i+shift}
-    approxPade = Pade(solver, mu0 = mu0, approxParameters = params)
-    approxRB = RB(solver, mu0 = mu0, approxParameters = params)
+        paramsSetsPoly[i] = {'N':0, 'M':stride*i+shift,
+                             'E':stride*i+shift}
+    approxPade = Pade(solver, mu0 = mu0, approxParameters = params,
+                      verbosity = verb)
+    approxRB = RB(solver, mu0 = mu0, approxParameters = params,
+                  verbosity = verb)
+    approxPoly = Pade(solver, mu0 = mu0, approxParameters = params,
+                      verbosity = verb)
+    
+    filenamebase = '../data/output/domainTaylor'
     
     sweeper = Sweeper(mutars = mutars, mostExpensive = 'Approx')
     sweeper.ROMEngine = approxPade
     sweeper.params = paramsSetsPade
-    filenamePade = sweeper.sweep('../data/output/domain_errorPade.dat', 
-                                 outputs = 'ALL')
+    filenamePade = sweeper.sweep(filenamebase + 'Pade.dat')
     sweeper.ROMEngine = approxRB
     sweeper.params = paramsSetsRB
-    filenameRB = sweeper.sweep('../data/output/domain_errorRB.dat', 
-                               outputs = 'ALL')
+    filenameRB = sweeper.sweep(filenamebase + 'RB.dat')
+    sweeper.ROMEngine = approxPoly
+    sweeper.params = paramsSetsPoly
+    filenamePoly = sweeper.sweep(filenamebase + 'Poly.dat')
 
-    print('Pade''')
-    sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], ['E'],
-                 onePlot = True)
-    print('RB')
-    sweeper.plot(filenameRB, ['muRe'], ['normHF', 'normApp'], ['E'],
-                 onePlot = True)
-    print('Pade''')
-    sweeper.plot(filenamePade, ['muRe'], ['normErrRel'], ['E'])
-    print('RB')
-    sweeper.plot(filenameRB, ['muRe'], ['normErrRel'], ['E'])
+    sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                        ['normHF', 'normApp'], ['E'], onePlot = True,
+                        save = filenamebase + 'Norm',
+                        saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+    sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                        ['normResRel'], ['E'], save = filenamebase + 'Res',
+                        saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+    sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                        ['normErrRel'], ['E'], save = filenamebase + 'Err',
+                        saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
diff --git a/examples/scipy/scatteringSquare.py b/examples/scipy/scatteringSquare.py
index d4b00e8..ffb92c7 100644
--- a/examples/scipy/scatteringSquare.py
+++ b/examples/scipy/scatteringSquare.py
@@ -1,140 +1,166 @@
 from copy import copy
 import numpy as np
-from rrompy.hfengines.scipy import HelmholtzCavityScatteringProblemEngine as CSPE
+from rrompy.hfengines.scipy import (
+                                HelmholtzCavityScatteringProblemEngine as CSPE)
 from rrompy.reduction_methods.taylor import ApproximantTaylorPade as TP
 from rrompy.reduction_methods.lagrange import ApproximantLagrangePade as LP
 from rrompy.reduction_methods.taylor import ApproximantTaylorRB as TRB
 from rrompy.reduction_methods.lagrange import ApproximantLagrangeRB as LRB
 from rrompy.utilities.parameter_sweeper import ParameterSweeper as Sweeper
 from rrompy.utilities.parameter_sampling import QuadratureSampler as QS
 from operator import itemgetter
 def subdict(d, ks):
     return dict(zip(ks, itemgetter(*ks)(d)))
 
+verb = 0
+
 ####################
 
 test = "solve"
 test = "Taylor"
 test = "Lagrange"
-#test = "TaylorSweep"
+test = "TaylorSweep"
 #test = "LagrangeSweep"
 
 plotSamples = True
 
 k0 = 10
 kLeft, kRight = 9, 11
 ktar = 9.5
 ktars = np.linspace(8.5, 11.5, 125)
 #ktars = np.array([k0])
 
 kappa = 5
 n = 50
 
-solver = CSPE(kappa = kappa, n = n)
+solver = CSPE(kappa = kappa, n = n, verbosity = verb)
 solver.omega = k0
 
 if test == "solve":
     uh = solver.solve(k0)
     print(solver.norm(uh))
     solver.plot(uh, what = ['ABS', 'REAL'])
 
 elif test in ["Taylor", "Lagrange"]:
     if test == "Taylor":
         params = {'N':8, 'M':7, 'R':8, 'E':8, 'sampleType':'Krylov', 'POD':True}
         params = {'N':8, 'M':7, 'R':8, 'E':8, 'sampleType':'Arnoldi', 'POD':True}
         parPade = subdict(params, ['N', 'M', 'E', 'sampleType', 'POD'])
         parRB = subdict(params, ['R', 'E', 'sampleType', 'POD'])
-        approxPade = TP(solver, mu0 = k0, approxParameters = parPade)
-        approxRB = TRB(solver, mu0 = k0, approxParameters = parRB)
+        approxPade = TP(solver, mu0 = k0, approxParameters = parPade,
+                        verbosity = verb)
+        approxRB = TRB(solver, mu0 = k0, approxParameters = parRB,
+                       verbosity = verb)
     else:
         params = {'N':8, 'M':8, 'R':9, 'S':9, 'POD':True,
                   'sampler':QS([kLeft, kRight], "CHEBYSHEV")}
         parPade = subdict(params, ['N', 'M', 'S', 'POD', 'sampler'])
         parRB = subdict(params, ['R', 'S', 'POD', 'sampler'])
         approxPade = LP(solver, mu0 = np.mean([kLeft, kRight]),
-                        approxParameters = parPade)
+                        approxParameters = parPade,
+                        verbosity = verb)
         approxRB = LRB(solver, mu0 = np.mean([kLeft, kRight]),
-                       approxParameters = parRB)
+                       approxParameters = parRB,
+                       verbosity = verb)
 
     approxPade.setupApprox()
     approxRB.setupApprox()
     if plotSamples:
         approxPade.plotSamples()
     
     PadeErr, solNorm = approxPade.normErr(ktar), approxPade.normHF(ktar)
     RBErr = approxRB.normErr(ktar)
     print(('SolNorm:\t{}\nErrPade:\t{}\nErrRelPade:\t{}\nErrRB:\t\t{}'
            '\nErrRelRB:\t{}').format(solNorm, PadeErr,
                                      np.divide(PadeErr, solNorm), RBErr,
                                      np.divide(RBErr, solNorm)))
 
     print('\nPoles Pade'':')
     print(approxPade.getPoles())
     print('\nPoles RB:')
     print(approxRB.getPoles())
 
     approxPade.plotHF(ktar, name = 'u_ex')
     approxPade.plotApp(ktar, name = 'u_Pade''')
     approxRB.plotApp(ktar, name = 'u_RB')
     approxPade.plotErr(ktar, name = 'errPade''')
     approxRB.plotErr(ktar, name = 'errRB')
 
 elif test in ["TaylorSweep", "LagrangeSweep"]:
     if test == "TaylorSweep":
         shift = 5
         nsets = 4
         stride = 3
         Emax = stride * (nsets - 1) + shift + 1
         params = {'Emax':Emax, 'sampleType':'Krylov', 'POD':True}
         params = {'Emax':Emax, 'sampleType':'Arnoldi', 'POD':True}
         paramsSetsPade = [None] * nsets
         paramsSetsRB = [None] * nsets
         for i in range(nsets):
             paramsSetsPade[i] = {'N': stride*i+shift+1,
                                  'M': stride*i+shift,#+1,
                                  'E': stride*i+shift+1}
             paramsSetsRB[i] = {'R': stride*i+shift+1,#+1,
                                'E': stride*i+shift+1}
-        approxPade = TP(solver, mu0 = k0,approxParameters = params)
-        approxRB = TRB(solver, mu0 = k0, approxParameters = params)
+        approxPade = TP(solver, mu0 = k0,approxParameters = params,
+                        verbosity = verb)
+        approxRB = TRB(solver, mu0 = k0, approxParameters = params,
+                       verbosity = verb)
     else:
         shift = 7
         nsets = 4
         stride = 3
         Smax = stride * (nsets - 1) + shift + 2
         paramsPade = {'S':Smax, 'POD':True,
                       'sampler':QS([kLeft, kRight], "CHEBYSHEV")}
         paramsRB = copy(paramsPade)
+        paramsPoly = copy(paramsPade)
         paramsSetsPade = [None] * nsets
         paramsSetsRB = [None] * nsets
+        paramsSetsPoly = [None] * nsets
         for i in range(nsets):
             paramsSetsPade[i] = {'N': stride*i+shift+1,
-                                 'M': stride*i+shift,#+1,
+                                 'M': stride*i+shift+1,
                                  'S': stride*i+shift+2}
-            paramsSetsRB[i] = {'R': stride*i+shift+1,#+1,
+            paramsSetsRB[i] = {'R': stride*i+shift+2,
                                'S': stride*i+shift+2}
+            paramsSetsPoly[i] = {'N': 0,
+                                 'M': stride*i+shift+1,
+                                 'S': stride*i+shift+2}
         approxPade = LP(solver, mu0 = np.mean([kLeft, kRight]),
-                        approxParameters = paramsPade)
+                        approxParameters = paramsPade,
+                        verbosity = verb)
         approxRB = LRB(solver, mu0 = np.mean([kLeft, kRight]),
-                       approxParameters = paramsRB)
+                       approxParameters = paramsRB,
+                       verbosity = verb)
+        approxPoly = LP(solver, mu0 = np.mean([kLeft, kRight]),
+                        approxParameters = paramsPoly,
+                        verbosity = verb)
+        
+    filenamebase = '../data/output/scatSquare' + test[:-5]
     
     sweeper = Sweeper(mutars = ktars, mostExpensive = 'Approx')
-
     sweeper.ROMEngine = approxPade
     sweeper.params = paramsSetsPade
-    filenamePade = sweeper.sweep('../data/output/ssquare'+test[:-5]+'Pade.dat')
-    
+    filenamePade = sweeper.sweep(filenamebase + 'Pade.dat')
     sweeper.ROMEngine = approxRB
     sweeper.params = paramsSetsRB
-    filenameRB = sweeper.sweep('../data/output/ssquare'+test[:-5]+'RB.dat')
+    filenameRB = sweeper.sweep(filenamebase + 'RB.dat')
+    sweeper.ROMEngine = approxPoly
+    sweeper.params = paramsSetsPoly
+    filenamePoly = sweeper.sweep(filenamebase + 'Poly.dat')
     
     if test == "TaylorSweep":
         constr = ['E']
     else:
         constr = ['S']
-    sweeper.plot(filenamePade, ['muRe'], ['normHF', 'normApp'], constr,
-                 onePlot = True)
-    sweeper.plot(filenameRB, ['muRe'], ['normHF', 'normApp'], constr,
-                 onePlot = True)
-    sweeper.plot(filenamePade, ['muRe'], ['normApp'], constr)
-    sweeper.plot(filenameRB, ['muRe'], ['normApp'], constr)
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normHF', 'normApp'], constr, onePlot = True,
+                    save = filenamebase + 'Norm',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normResRel'], constr, save = filenamebase + 'Res',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
+sweeper.plotCompare([filenamePade, filenameRB, filenamePoly], ['muRe'],
+                    ['normErrRel'], constr, save = filenamebase + 'Err',
+                    saveFormat = "png", labels = ["Pade'", "RB", "Poly"])
diff --git a/examples/scipy/solver.py b/examples/scipy/solver.py
index f71387f..b34ceae 100644
--- a/examples/scipy/solver.py
+++ b/examples/scipy/solver.py
@@ -1,38 +1,72 @@
 import numpy as np
 from rrompy.hfengines.scipy import HelmholtzSquareBubbleProblemEngine as HSBPE
-from rrompy.hfengines.scipy import HelmholtzSquareTransmissionProblemEngine as HSTPE
+from rrompy.hfengines.scipy import (
+                             HelmholtzSquareTransmissionProblemEngine as HSTPE)
 from rrompy.hfengines.scipy import HelmholtzBoxScatteringProblemEngine as HBSPE
+from rrompy.hfengines.scipy import (
+                               HelmholtzCavityScatteringProblemEngine as HCSPE)
 
 testNo = 3
+verb = 0
 
 if testNo == 1:
-    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 20)
-
+    solver = HSBPE(kappa = 12 ** .5, theta = np.pi / 3, n = 20,
+                   verbosity = verb)
+    
     mu = 12.**.5
     uh = solver.solve(mu)
-    solver.plotmesh(save = False)
+    solver.plotmesh()
     print(solver.norm(uh))
-    solver.plot(uh, save = False)
-    solver.plot(solver.residual(uh, mu))
+    solver.plot(uh)
+    solver.plot(solver.residual(uh, mu), 'res')
 
 ###########
-elif testNo == 2:
-    solver = HSTPE(nT = 1, nB = 2, theta = np.pi * 20 / 180,
-                   kappa = 4., n = 50)
+elif testNo == [2, -2]:
+    solver = HSTPE(nT = 1, nB = 2, theta = np.pi * 20 / 180, kappa = 4.,
+                   n = 50, verbosity = verb)
 
     mu = 4.
-    uh = solver.solve(mu)
+    uref = solver.liftDirichletData(mu)
+    if testNo > 0:
+        uh = solver.solve(mu)
+        utot = uh - uref
+    else:
+        utot = solver.solve(mu, homogeneized = True)
+        uh = utot + uref
+    print(solver.norm(uh))
+    print(solver.norm(uref))
+    solver.plot(uh)
+    solver.plot(uref, name = 'u_Dir')
+    solver.plot(utot, name = 'u_tot')
+    solver.plot(solver.residual(uh, mu), 'res')
+    solver.plot(solver.residual(utot, mu, homogeneized = True), 'res_tot')
+
+###########
+elif testNo in [3, -3]:
+    solver = HBSPE(R = 5, kappa = 12**.5, theta = - np.pi * 60 / 180, n = 30,
+                   verbosity = verb)
+    mu = 12**.5
+    uref = solver.liftDirichletData(mu)
+    if testNo > 0:
+        uh = solver.solve(mu)
+        utot = uh - uref
+    else:
+        utot = solver.solve(mu, homogeneized = True)
+        uh = utot + uref
+    solver.plotmesh()
     print(solver.norm(uh))
+    print(solver.norm(utot))
     solver.plot(uh)
-    solver.plot(solver.residual(uh, mu))
+    solver.plot(utot, name = 'u_tot')
+    solver.plot(solver.residual(uh, mu), 'res')
+    solver.plot(solver.residual(utot, mu, homogeneized = True), 'res_tot')
 
 ###########
-elif testNo == 3:
-    solver = HBSPE(R = 5, kappa = 12**.5, theta = - np.pi * 60 / 180, n = 30)
-    uinc = - solver.liftDirichletData()
-    uh = solver.solve(12**.5)
+elif testNo == 4:
+    solver = HCSPE(kappa = 5, n = 30, verbosity = verb)
+    mu = 10
+    uh = solver.solve(mu)
     solver.plotmesh()
     print(solver.norm(uh))
-    print(solver.norm(uh + uinc))
     solver.plot(uh)
-    solver.plot(uh + uinc, name = 'u_tot')
+    solver.plot(solver.residual(uh, mu), 'res')
diff --git a/rrompy/hfengines/base/__init__.py b/rrompy/hfengines/base/__init__.py
index febe1c9..de93c79 100644
--- a/rrompy/hfengines/base/__init__.py
+++ b/rrompy/hfengines/base/__init__.py
@@ -1,28 +1,34 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.hfengines.base.problem_engine_base import ProblemEngineBase
-from rrompy.hfengines.base.boundary_conditions import BoundaryConditions
+from .problem_engine_base import ProblemEngineBase
+from .boundary_conditions import BoundaryConditions
+from .laplace_base_problem_engine import LaplaceBaseProblemEngine
+from .helmholtz_problem_engine import HelmholtzProblemEngine
+from .scattering_problem_engine import ScatteringProblemEngine
 
 __all__ = [
         'ProblemEngineBase',
-        'BoundaryConditions'
+        'BoundaryConditions',
+        'LaplaceBaseProblemEngine',
+        'HelmholtzProblemEngine',
+        'ScatteringProblemEngine'
           ]
 
 
 
diff --git a/rrompy/hfengines/base/boundary_conditions.py b/rrompy/hfengines/base/boundary_conditions.py
index fb35b41..48bebb9 100644
--- a/rrompy/hfengines/base/boundary_conditions.py
+++ b/rrompy/hfengines/base/boundary_conditions.py
@@ -1,106 +1,110 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from rrompy.utilities.base.types import GenExpr
 from rrompy.utilities.base.fenics import bdrTrue, bdrFalse
 
 __all__ = ['BoundaryConditions']
 
 class BoundaryConditions:
     """Boundary conditions manager."""
 
     allowedKinds = ["Dirichlet", "Neumann", "Robin"]
 
     def __init__(self, kind : str = None):
         if kind is None: return
         kind = kind[0].upper() + kind[1:].lower()
         if kind in self.allowedKinds:
             getattr(self.__class__, kind + "Boundary", None).fset(self, "ALL")
         else:
             raise Exception("BC kind not recognized.")
 
     def name(self) -> str:
         return self.__class__.__name__
 
     def __str__(self) -> str:
         return self.name()
     
     def _generalManagement(self, kind:str, value:GenExpr):
         if isinstance(value, (str,)):
             value = value.upper()
             if value.upper() == "ALL":
                 self._complementaryManagementAll(kind)
             elif value.upper() == "REST":
                 self._complementaryManagementRest(kind)
             else:
                 raise Exception("Wildcard not recognized.")
         elif callable(value):
             self._standardManagement(kind, value)
         else:
             raise Exception(kind + "Boundary type not recognized.")
 
     def _complementaryManagementAll(self, kind:str):
         if kind not in self.allowedKinds:
             raise Exception("BC kind not recognized.")
         for k in self.allowedKinds:
             if k != kind:
                 getattr(self.__class__, k + "Boundary").fset(self, bdrFalse)
         super().__setattr__("_" + kind + "Boundary", bdrTrue)
         if hasattr(self, "_" + kind + "Rest"):
             super().__delattr__("_" + kind + "Rest")
 
     def _complementaryManagementRest(self, kind:str):
         if kind not in self.allowedKinds:
             raise Exception("BC kind not recognized.")
+        otherBCs = []
         for k in self.allowedKinds:
-            if k != kind and hasattr(self, "_" + k + "Rest"):
-                raise Exception("Only 1 'REST' wildcard can be specified.")
+            if k != kind:
+                if hasattr(self, "_" + k + "Rest"):
+                    raise Exception("Only 1 'REST' wildcard can be specified.")
+                otherBCs += [getattr(self, k + "Boundary")]
         def restCall(x, on_boundary):
             return (on_boundary
-                and not any([getattr(self, k + "Boundary")(x, on_boundary)]))
+                and not any([bc(x, on_boundary) for bc in otherBCs]))
         super().__setattr__("_" + kind + "Boundary", restCall)
         super().__setattr__("_" + kind + "Rest", 1)
 
     def _standardManagement(self, kind:str, bc:callable):
         super().__setattr__("_" + kind + "Boundary", bc)
         if hasattr(self, "_" + kind + "Rest"):
             super().__delattr__("_" + kind + "Rest")
 
     @property
     def DirichletBoundary(self):
         """Function handle to DirichletBoundary."""
         return self._DirichletBoundary
     @DirichletBoundary.setter
     def DirichletBoundary(self, DirichletBoundary):
         self._generalManagement("Dirichlet", DirichletBoundary)
         
     @property
     def NeumannBoundary(self):
         """Function handle to NeumannBoundary."""
         return self._NeumannBoundary
     @NeumannBoundary.setter
     def NeumannBoundary(self, NeumannBoundary):
         self._generalManagement("Neumann", NeumannBoundary)
 
     @property
     def RobinBoundary(self):
         """Function handle to RobinBoundary."""
         return self._RobinBoundary
     @RobinBoundary.setter
     def RobinBoundary(self, RobinBoundary):
         self._generalManagement("Robin", RobinBoundary)
+
diff --git a/rrompy/hfengines/scipy/helmholtz_problem_engine.py b/rrompy/hfengines/base/helmholtz_problem_engine.py
similarity index 54%
rename from rrompy/hfengines/scipy/helmholtz_problem_engine.py
rename to rrompy/hfengines/base/helmholtz_problem_engine.py
index e3a0b12..33a0b8d 100644
--- a/rrompy/hfengines/scipy/helmholtz_problem_engine.py
+++ b/rrompy/hfengines/base/helmholtz_problem_engine.py
@@ -1,149 +1,154 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 import scipy.sparse as scsp
 import fenics as fen
-from rrompy.utilities.base.types import Np1D, Np2D, Tuple, List
-from rrompy.hfengines.scipy.helmholtz_base_problem_engine import HelmholtzBaseProblemEngine, fenZERO
+from .laplace_base_problem_engine import LaplaceBaseProblemEngine
+from rrompy.utilities.base.types import Np1D, ScOp
+from rrompy.utilities.base.fenics import fenZERO, fenONE
+from rrompy.utilities.base import verbosityDepth
 
 __all__ = ['HelmholtzProblemEngine']
 
-class HelmholtzProblemEngine(HelmholtzBaseProblemEngine):
+class HelmholtzProblemEngine(LaplaceBaseProblemEngine):
     """
-    Solver for Helmholtz problems with parametric wavenumber.
+    Solver for generic Helmholtz problems with parametric wavenumber.
         - \nabla \cdot (a \nabla u) - omega^2 * n**2 * u = f in \Omega
         u = u0                                               on \Gamma_D
         \partial_nu = g1                                     on \Gamma_N
         \partial_nu + h u = g2                               on \Gamma_R
 
     Attributes:
         omega: Value of omega.
         diffusivity: Value of a.
         refractionIndex: Value of n.
         forcingTerm: Value of f.
         DirichletDatum: Value of u0.
         NeumannDatum: Value of g1.
-        RobinDatumH: Value of h.
         RobinDatumG: Value of g2.
+        RobinDatumH: Value of h.
         DirichletBoundary: Function handle to \Gamma_D.
         NeumannBoundary: Function handle to \Gamma_N.
         RobinBoundary: Function handle to \Gamma_R.
         V: Real FE space.
         u: Generic trial functions for variational form evaluation.
         v: Generic test functions for variational form evaluation.
         ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
         A0: Scipy sparse array representation (in CSC format) of A0.
         A1: Scipy sparse array representation (in CSC format) of A1.
         b0: Numpy array representation of b0.
         As: Scipy sparse array representation (in CSC format) of As.
         bs: Numpy array representation of bs.
     """
-    _RobinDatumH = [fenZERO, fenZERO]
 
-    def __init__(self):
-        super().__init__()
-        self.V = fen.FunctionSpace(fen.UnitSquareMesh(10, 10), "P", 1)
-        self.DirichletBoundary = "ALL"
+    nAs = 2
 
-    @property
-    def RobinDatumH(self):
-        """Value of h."""
-        return self._RobinDatumH
-    @RobinDatumH.setter
-    def RobinDatumH(self, RobinDatumH):
-        if hasattr(self, "A0"): del self.A0
-        if not isinstance(RobinDatumH, (list, tuple,)):
-            RobinDatumH = [RobinDatumH, fenZERO]
-        self._RobinDatumH = RobinDatumH
+    def __init__(self, degree_threshold : int = np.inf, verbosity : int = 10):
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
+        self.omega = 1.
+        self.refractionIndex = fenONE
 
+    @property
+    def refractionIndex(self):
+        """Value of n."""
+        return self._refractionIndex
+    @refractionIndex.setter
+    def refractionIndex(self, refractionIndex):
+        self.resetAs()
+        if not isinstance(refractionIndex, (list, tuple,)):
+            refractionIndex = [refractionIndex, fenZERO]
+        self._refractionIndex = refractionIndex
+    
     def rescaling(self, x:Np1D) -> Np1D:
         """Rescaling in parameter dependence."""
         return np.power(x, 2.)
 
     def rescalingInv(self, x:Np1D) -> Np1D:
         """Inverse rescaling in parameter dependence."""
         return np.power(x, .5)
 
-    def A(self, mu:complex, der : int = 0) -> Np2D:
+    def A(self, mu:complex, der : int = 0) -> ScOp:
         """Assemble (derivative of) operator of linear system."""
-        if der > 1 or der < 0:
-            d = self.V.dim()
-            return scsp.csr_matrix((np.zeros(0), np.zeros(0), np.zeros(d + 1)),
-                                   shape = (d, d), dtype = np.complex)
+        Anull = self.checkAInBounds(der)
+        if Anull is not None: return Anull
         self.autoSetDS()
-        if der <= 0 and not hasattr(self, "A0"):
+        if der <= 0 and self.As[0] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling operator term A0.")
             DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
                                            self.DirichletBoundary)
             aRe, aIm = self.diffusivity
             hRe, hIm = self.RobinDatumH
+            termNames = ["diffusivity", "RobinDatumH"]
+            parsRe = self.iterReduceQuadratureDegree(zip(
+                                              [aRe, hRe],
+                                              [x + "Real" for x in termNames]))
+            parsIm = self.iterReduceQuadratureDegree(zip(
+                                              [aIm, hIm],
+                                              [x + "Imag" for x in termNames]))
             a0Re = (aRe * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
                   + hRe * fen.dot(self.u, self.v) * self.ds(1))
             a0Im = (aIm * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
                   + hIm * fen.dot(self.u, self.v) * self.ds(1))
-            A0Re = fen.assemble(a0Re)
-            A0Im = fen.assemble(a0Im)
+            A0Re = fen.assemble(a0Re, form_compiler_parameters = parsRe)
+            A0Im = fen.assemble(a0Im, form_compiler_parameters = parsIm)
             DirichletBC0.apply(A0Re)
             DirichletBC0.zero(A0Im)
             A0ReMat = fen.as_backend_type(A0Re).mat()
             A0ImMat = fen.as_backend_type(A0Im).mat()
             A0Rer, A0Rec, A0Rev = A0ReMat.getValuesCSR()
             A0Imr, A0Imc, A0Imv = A0ImMat.getValuesCSR()
-            self.A0 = (scsp.csr_matrix((A0Rev, A0Rec, A0Rer),
-                                       shape = A0ReMat.size)
-               + 1.j * scsp.csr_matrix((A0Imv, A0Imc, A0Imr),
-                                       shape = A0ImMat.size))
-        if der <= 1 and not hasattr(self, "A1"):
+            self.As[0] = (scsp.csr_matrix((A0Rev, A0Rec, A0Rer),
+                                          shape = A0ReMat.size)
+                  + 1.j * scsp.csr_matrix((A0Imv, A0Imc, A0Imr),
+                                          shape = A0ImMat.size))
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling operator term.")
+        if der <= 1 and self.As[1] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling operator term A1.")
             DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
                                            self.DirichletBoundary)
             nRe, nIm = self.refractionIndex
             n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
+            parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
+                                               ["refractionIndexSquaredReal"]))
+            parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
+                                               ["refractionIndexSquaredImag"]))
             a1Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
             a1Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
-            A1Re = fen.assemble(a1Re)
-            A1Im = fen.assemble(a1Im)
+            A1Re = fen.assemble(a1Re, form_compiler_parameters = parsRe)
+            A1Im = fen.assemble(a1Im, form_compiler_parameters = parsIm)
             DirichletBC0.zero(A1Re)
             DirichletBC0.zero(A1Im)
             A1ReMat = fen.as_backend_type(A1Re).mat()
             A1ImMat = fen.as_backend_type(A1Im).mat()
             A1Rer, A1Rec, A1Rev = A1ReMat.getValuesCSR()
             A1Imr, A1Imc, A1Imv = A1ImMat.getValuesCSR()
-            self.A1 = (scsp.csr_matrix((A1Rev, A1Rec, A1Rer),
-                                       shape = A1ReMat.size)
-               + 1.j * scsp.csr_matrix((A1Imv, A1Imc, A1Imr),
-                                       shape = A1ImMat.size))
+            self.As[1] = (scsp.csr_matrix((A1Rev, A1Rec, A1Rer),
+                                          shape = A1ReMat.size)
+                  + 1.j * scsp.csr_matrix((A1Imv, A1Imc, A1Imr),
+                                          shape = A1ImMat.size))
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling operator term.")
         if der == 0:
-            return self.A0 + mu**2 * self.A1
-        return self.A1
-
-    def affineBlocksA(self, mu : complex = 0.) -> Tuple[List[Np2D], callable]:
-        """Assemble affine blocks of operator of linear system."""
-        def lambdas(x, j):
-            if j == 0: return np.ones(np.size(x))
-            if j == 1: return self.rescaling(x) - self.rescaling(mu)
-            raise Exception("Wrong j value.")
-        A0 = self.A(mu, 0)
-        return [A0, self.A1], lambdas
+            return self.As[0] + mu**2 * self.As[1]
+        return self.As[1]
 
-    def affineBlocksb(self, mu : complex = 0.) -> Tuple[List[Np1D], callable]:
-        """Assemble affine blocks of RHS of linear system."""
-        def lambdas(x, j):
-            if j == 0: return np.ones(np.size(x))
-            raise Exception("Wrong j value.")
-        self.b(mu, 0)
-        return [self.b0], lambdas
diff --git a/rrompy/hfengines/base/laplace_base_problem_engine.py b/rrompy/hfengines/base/laplace_base_problem_engine.py
new file mode 100644
index 0000000..6265459
--- /dev/null
+++ b/rrompy/hfengines/base/laplace_base_problem_engine.py
@@ -0,0 +1,315 @@
+# Copyright (C) 2018 by the RROMPy authors
+#
+# This file is part of RROMPy.
+#
+# RROMPy is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# RROMPy is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import numpy as np
+import scipy.sparse as scsp
+import fenics as fen
+from .problem_engine_base import ProblemEngineBase
+from rrompy.utilities.base.types import Np1D, ScOp
+from rrompy.utilities.base.fenics import fenZERO, fenONE
+from rrompy.utilities.base import verbosityDepth
+
+__all__ = ['LaplaceBaseProblemEngine']
+
+class LaplaceBaseProblemEngine(ProblemEngineBase):
+    """
+    Solver for generic Laplace problems.
+        - \nabla \cdot (a \nabla u) = f in \Omega
+        u = u0                          on \Gamma_D
+        \partial_nu = g1                on \Gamma_N
+        \partial_nu + h u = g2          on \Gamma_R
+
+    Attributes:
+        omega: Value of omega.
+        diffusivity: Value of a.
+        forcingTerm: Value of f.
+        DirichletDatum: Value of u0.
+        NeumannDatum: Value of g1.
+        RobinDatumG: Value of g2.
+        RobinDatumH: Value of h.
+        DirichletBoundary: Function handle to \Gamma_D.
+        NeumannBoundary: Function handle to \Gamma_N.
+        RobinBoundary: Function handle to \Gamma_R.
+        V: Real FE space.
+        u: Generic trial functions for variational form evaluation.
+        v: Generic test functions for variational form evaluation.
+        ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
+        A0: Scipy sparse array representation (in CSC format) of A0.
+        b0: Numpy array representation of b0.
+        As: Scipy sparse array representation (in CSC format) of As.
+        bs: Numpy array representation of bs.
+    """
+
+    def __init__(self, degree_threshold : int = np.inf, verbosity : int = 10):
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
+        self.omega = 0.
+        self.diffusivity = fenONE
+        self.forcingTerm = fenZERO
+        self.DirichletDatum = fenZERO
+        self.NeumannDatum = fenZERO
+        self.RobinDatumG = fenZERO
+        self.RobinDatumH = fenZERO
+
+    @property
+    def V(self):
+        """Value of V."""
+        return self._V
+    @V.setter
+    def V(self, V):
+        self.As = [None] * self.nAs
+        self.bs = [None] * self.nbs
+        if not type(V).__name__ == 'FunctionSpace':
+            raise Exception("V type not recognized.")
+        self._V = V
+        self.u = fen.TrialFunction(V)
+        self.v = fen.TestFunction(V)
+        self.dsToBeSet = True
+
+    @property
+    def diffusivity(self):
+        """Value of a."""
+        return self._diffusivity
+    @diffusivity.setter
+    def diffusivity(self, diffusivity):
+        self.resetAs()
+        if not isinstance(diffusivity, (list, tuple,)):
+            diffusivity = [diffusivity, fenZERO]
+        self._diffusivity = diffusivity
+
+    @property
+    def forcingTerm(self):
+        """Value of f."""
+        return self._forcingTerm
+    @forcingTerm.setter
+    def forcingTerm(self, forcingTerm):
+        self.resetbs()
+        if not isinstance(forcingTerm, (list, tuple,)):
+            forcingTerm = [forcingTerm, fenZERO]
+        self._forcingTerm = forcingTerm
+
+    @property
+    def DirichletDatum(self):
+        """Value of u0."""
+        return self._DirichletDatum
+    @DirichletDatum.setter
+    def DirichletDatum(self, DirichletDatum):
+        self.resetbs()
+        if not isinstance(DirichletDatum, (list, tuple,)):
+            DirichletDatum = [DirichletDatum, fenZERO]
+        self._DirichletDatum = DirichletDatum
+
+    @property
+    def NeumannDatum(self):
+        """Value of g1."""
+        return self._NeumannDatum
+    @NeumannDatum.setter
+    def NeumannDatum(self, NeumannDatum):
+        self.resetbs()
+        if not isinstance(NeumannDatum, (list, tuple,)):
+            NeumannDatum = [NeumannDatum, fenZERO]
+        self._NeumannDatum = NeumannDatum
+
+    @property
+    def RobinDatumG(self):
+        """Value of g2."""
+        return self._RobinDatumG
+    @RobinDatumG.setter
+    def RobinDatumG(self, RobinDatumG):
+        self.resetbs()
+        if not isinstance(RobinDatumG, (list, tuple,)):
+            RobinDatumG = [RobinDatumG, fenZERO]
+        self._RobinDatumG = RobinDatumG
+
+    @property
+    def RobinDatumH(self):
+        """Value of h."""
+        return self._RobinDatumH
+    @RobinDatumH.setter
+    def RobinDatumH(self, RobinDatumH):
+        self.resetAs()
+        if not isinstance(RobinDatumH, (list, tuple,)):
+            RobinDatumH = [RobinDatumH, fenZERO]
+        self._RobinDatumH = RobinDatumH
+
+    @property
+    def DirichletBoundary(self):
+        """Function handle to DirichletBoundary."""
+        return self.BCManager.DirichletBoundary
+    @DirichletBoundary.setter
+    def DirichletBoundary(self, DirichletBoundary):
+        self.resetAs()
+        self.resetbs()
+        self.BCManager.DirichletBoundary = DirichletBoundary
+
+    @property
+    def NeumannBoundary(self):
+        """Function handle to NeumannBoundary."""
+        return self.BCManager.NeumannBoundary
+    @NeumannBoundary.setter
+    def NeumannBoundary(self, NeumannBoundary):
+        self.resetAs()
+        self.resetbs()
+        self.dsToBeSet = True
+        self.BCManager.NeumannBoundary = NeumannBoundary
+
+    @property
+    def RobinBoundary(self):
+        """Function handle to RobinBoundary."""
+        return self.BCManager.RobinBoundary
+    @RobinBoundary.setter
+    def RobinBoundary(self, RobinBoundary):
+        self.resetAs()
+        self.resetbs()
+        self.dsToBeSet = True
+        self.BCManager.RobinBoundary = RobinBoundary
+    
+    def autoSetDS(self):
+        """Set FEniCS boundary measure based on boundary function handles."""
+        if self.dsToBeSet:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Initializing boundary measures.",
+                               end = "")
+            NB = self.NeumannBoundary
+            RB = self.RobinBoundary
+            class NBoundary(fen.SubDomain):
+                def inside(self, x, on_boundary):
+                    return NB(x, on_boundary)
+            class RBoundary(fen.SubDomain):
+                def inside(self, x, on_boundary):
+                    return RB(x, on_boundary)
+            boundary_markers = fen.MeshFunction("size_t", self.V.mesh(),
+                                            self.V.mesh().topology().dim() - 1)
+            NBoundary().mark(boundary_markers, 0)
+            RBoundary().mark(boundary_markers, 1)
+            self.ds = fen.Measure("ds", domain = self.V.mesh(),
+                                  subdomain_data = boundary_markers)
+            self.dsToBeSet = False
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", " Done.", inline = True)
+
+    def buildEnergyNormForm(self):
+        """
+        Build sparse matrix (in CSR format) representative of scalar product.
+        """
+        if self.verbosity >= 20:
+            verbosityDepth("INIT", "Assembling energy matrix.", end = "")
+        normMatFen = fen.assemble((fen.dot(fen.grad(self.u), fen.grad(self.v))
+                    + np.abs(self.omega)**2 * fen.dot(self.u, self.v)) *fen.dx)
+        normMat = fen.as_backend_type(normMatFen).mat()
+        self.energyNormMatrix = scsp.csr_matrix(normMat.getValuesCSR()[::-1],
+                                                shape = normMat.size)
+        if self.verbosity >= 20:
+            verbosityDepth("DEL", " Done.", inline = True)
+
+    def A(self, mu:complex, der : int = 0) -> ScOp:
+        """Assemble (derivative of) operator of linear system."""
+        Anull = self.checkAInBounds(der)
+        if Anull is not None: return Anull
+        self.autoSetDS()
+        if self.As[0] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling operator term A0.")
+            DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+                                           self.DirichletBoundary)
+            aRe, aIm = self.diffusivity
+            hRe, hIm = self.RobinDatumH
+            termNames = ["diffusivity", "RobinDatumH"]
+            parsRe = self.iterReduceQuadratureDegree(zip(
+                                              [aRe, hRe],
+                                              [x + "Real" for x in termNames]))
+            parsIm = self.iterReduceQuadratureDegree(zip(
+                                              [aIm, hIm],
+                                              [x + "Imag" for x in termNames]))
+            a0Re = (aRe * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+                  + hRe * fen.dot(self.u, self.v) * self.ds(1))
+            a0Im = (aIm * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
+                  + hIm * fen.dot(self.u, self.v) * self.ds(1))
+            A0Re = fen.assemble(a0Re, form_compiler_parameters = parsRe)
+            A0Im = fen.assemble(a0Im, form_compiler_parameters = parsIm)
+            DirichletBC0.apply(A0Re)
+            DirichletBC0.zero(A0Im)
+            A0ReMat = fen.as_backend_type(A0Re).mat()
+            A0ImMat = fen.as_backend_type(A0Im).mat()
+            A0Rer, A0Rec, A0Rev = A0ReMat.getValuesCSR()
+            A0Imr, A0Imc, A0Imv = A0ImMat.getValuesCSR()
+            self.As[0] = (scsp.csr_matrix((A0Rev, A0Rec, A0Rer),
+                                          shape = A0ReMat.size)
+                  + 1.j * scsp.csr_matrix((A0Imv, A0Imc, A0Imr),
+                                          shape = A0ImMat.size))
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling operator term.")
+        return self.As[0]
+
+    def b(self, mu:complex, der : int = 0,
+          homogeneized : bool = False) -> Np1D:
+        """Assemble (derivative of) RHS of linear system."""
+        bnull = self.checkbInBounds(der, homogeneized)
+        if bnull is not None: return bnull
+        if homogeneized and not np.isclose(self.mu0BC, mu):
+            self.u0BC = self.liftDirichletData(mu)
+        if not np.isclose(self.bsmu, mu):
+            self.bsmu = mu
+            self.resetbs()
+        if self.bs[homogeneized][der] is None:
+            self.autoSetDS()
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling forcing term b{}."\
+                                                                  .format(der))
+            if der < self.nbs:
+                fRe, fIm = self.forcingTerm
+                g1Re, g1Im = self.NeumannDatum
+                g2Re, g2Im = self.RobinDatumG
+            else:
+                fRe, fIm = fenZERO, fenZERO
+                g1Re, g1Im = fenZERO, fenZERO
+                g2Re, g2Im = fenZERO, fenZERO
+            termNames = ["forcingTerm", "NeumannDatum", "RobinDatumG"]
+            parsRe = self.iterReduceQuadratureDegree(zip(
+                                          [fRe, g1Re, g2Re],
+                                          [x + "Real" for x in termNames]))
+            parsIm = self.iterReduceQuadratureDegree(zip(
+                                          [fIm, g1Im, g2Im],
+                                          [x + "Imag" for x in termNames]))
+            L0Re = (fen.dot(fRe, self.v) * fen.dx
+                  + fen.dot(g1Re, self.v) * self.ds(0)
+                  + fen.dot(g2Re, self.v) * self.ds(1))
+            L0Im = (fen.dot(fIm, self.v) * fen.dx
+                  + fen.dot(g1Im, self.v) * self.ds(0)
+                  + fen.dot(g2Im, self.v) * self.ds(1))
+            b0Re = fen.assemble(L0Re, form_compiler_parameters = parsRe)
+            b0Im = fen.assemble(L0Im, form_compiler_parameters = parsIm)
+            if homogeneized:
+                Ader = self.A(mu, der)
+                b0Re[:] -= np.real(Ader.dot(self.u0BC))
+                b0Im[:] -= np.imag(Ader.dot(self.u0BC))
+                DBCR = fen.DirichletBC(self.V, fenZERO, self.DirichletBoundary)
+                DBCI = fen.DirichletBC(self.V, fenZERO, self.DirichletBoundary)
+            else:
+                DBCR = fen.DirichletBC(self.V, self.DirichletDatum[0],
+                                       self.DirichletBoundary)
+                DBCI = fen.DirichletBC(self.V, self.DirichletDatum[1],
+                                       self.DirichletBoundary)
+            DBCR.apply(b0Re)
+            DBCI.apply(b0Im)
+            self.bs[homogeneized][der] = np.array(b0Re[:]
+                                        + 1.j * b0Im[:], dtype = np.complex)
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling forcing term.")
+        return self.bs[homogeneized][der]
+
diff --git a/rrompy/hfengines/base/problem_engine_base.py b/rrompy/hfengines/base/problem_engine_base.py
index 817304e..fd909ab 100644
--- a/rrompy/hfengines/base/problem_engine_base.py
+++ b/rrompy/hfengines/base/problem_engine_base.py
@@ -1,109 +1,333 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from abc import abstractmethod
-from numpy import abs
-from rrompy.utilities.base.types import Np1D, HS1D, HSOp, strLst
+import fenics as fen
+import numpy as np
+from scipy.sparse import csr_matrix
+import scipy.sparse as scsp
+import scipy.sparse.linalg as scspla
+from matplotlib import pyplot as plt
+from rrompy.utilities.base.types import (Np1D, ScOp, strLst, FenFunc,
+                                         Tuple, List)
+from rrompy.utilities.base import purgeList, getNewFilename, verbosityDepth
 from .boundary_conditions import BoundaryConditions
 
 __all__ = ['ProblemEngineBase']
 
 class ProblemEngineBase:
     """
     Generic solver for parametric problems.
     """
+
+    nAs, nbs = 1, 1
     functional = lambda self, u: 0.
 
-    def __init__(self):
+    def __init__(self, degree_threshold : int = np.inf, verbosity : int = 10):
         self.BCManager = BoundaryConditions("Dirichlet")
+        self.V = fen.FunctionSpace(fen.UnitSquareMesh(10, 10), "P", 1)
+        self.verbosity = verbosity
+        self.resetAs()
+        self.resetbs()
+        self.bsmu = np.nan
+        self.liftDirichletDatamu = np.nan
+        self.mu0BC = np.nan
+        self.degree_threshold = degree_threshold
     
     def name(self) -> str:
         return self.__class__.__name__
         
     def __str__(self) -> str:
         return self.name()
 
-    @abstractmethod
-    def innerProduct(self, u:HS1D, v:HS1D) -> float:
+    def __dir_base__(self):
+        return [x for x in self.__dir__() if x[:2] != "__"]
+
+    def innerProduct(self, u:Np1D, v:Np1D) -> float:
         """Hilbert space scalar product."""
-        pass
+        if not hasattr(self, "energyNormMatrix"):
+            self.buildEnergyNormForm()
+        return v.conj().T.dot(self.energyNormMatrix.dot(u))
 
-    def norm(self, u:HS1D) -> float:
-        return abs(self.innerProduct(u, u)) ** .5
+    def buildEnergyNormForm(self):
+        """
+        Build sparse matrix (in CSR format) representative of scalar product.
+        """
+        if self.verbosity >= 20:
+            verbosityDepth("INIT", "Assembling energy matrix.", end = "")
+        normMat = fen.assemble(fen.dot(self.u, self.v) * fen.dx)
+        normMatFen = fen.as_backend_type(normMat).mat()
+        self.energyNormMatrix = csr_matrix(normMatFen.getValuesCSR()[::-1],
+                                           shape = normMat.size)
+        if self.verbosity >= 20:
+            verbosityDepth("DEL", " Done.", inline = True)
+
+    def norm(self, u:Np1D) -> float:
+        return np.abs(self.innerProduct(u, u)) ** .5
 
     def rescaling(self, x:Np1D) -> Np1D:
         """Rescaling in parameter dependence."""
         return x
 
     def rescalingInv(self, x:Np1D) -> Np1D:
         """Inverse rescaling in parameter dependence."""
         return x
 
+    def checkAInBounds(self, der : int = 0):
+        """Check if derivative index is oob for operator of linear system."""
+        if der < 0 or der >= self.nAs:
+            d = self.V.dim()
+            return scsp.csr_matrix((np.zeros(0), np.zeros(0), np.zeros(d + 1)),
+                                   shape = (d, d), dtype = np.complex)
+
+    def checkbInBounds(self, der : int = 0, homogeneized : bool = False):
+        """Check if derivative index is oob for RHS of linear system."""
+        if der < 0 or der >= max(self.nbs, self.nAs * homogeneized):
+            return np.zeros(self.V.dim(), dtype = np.complex)
+
+    def setDirichletDatum(self, mu:complex):
+        """Set Dirichlet datum if parametric."""
+        if hasattr(self, "liftedDirichletDatum"):
+            self.liftDirichletDatamu = mu
+
+    def liftDirichletData(self, mu:complex) -> Np1D:
+        """Lift Dirichlet datum."""
+        self.setDirichletDatum(mu)
+        if not np.isclose(self.liftDirichletDatamu, mu):
+            try:
+                liftRe = fen.interpolate(self.DirichletDatum[0], self.V)
+            except:
+                liftRe = fen.project(self.DirichletDatum[0], self.V)
+            try:
+                liftIm = fen.interpolate(self.DirichletDatum[1], self.V)
+            except:
+                liftIm = fen.project(self.DirichletDatum[1], self.V)
+            self.liftedDirichletDatum = (np.array(liftRe.vector())
+                                 + 1.j * np.array(liftIm.vector()))
+        return self.liftedDirichletDatum
+
+    def resetAs(self):
+        """Reset (derivatives of) operator of linear system."""
+        self.As = [None] * self.nAs
+
+    def resetbs(self):
+        """Reset (derivatives of) RHS of linear system."""
+        self.bs = {True: [None] * max(self.nbs, self.nAs),
+                   False: [None] * self.nbs}
+
+    def reduceQuadratureDegree(self, fun:FenFunc, name:str):
+        """Check whether to reduce compiler parameters to degree threshold."""
+        if not np.isinf(self.degree_threshold):
+            from ufl.algorithms.estimate_degrees import (
+                                      estimate_total_polynomial_degree as ETPD)
+            try:
+                deg = ETPD(fun)
+            except:
+                return False
+            if deg > self.degree_threshold:
+                if self.verbosity >= 15:
+                    verbosityDepth("MAIN", ("Reducing quadrature degree from "
+                                            "{} to {} for {}.").format(
+                                                         deg,
+                                                         self.degree_threshold,
+                                                         name))
+                return True
+        return False
+
+    def iterReduceQuadratureDegree(self, funsNames:List[Tuple[FenFunc, str]]):
+        """
+        Iterate reduceQuadratureDegree over list and define reduce compiler
+            parameters.
+        """
+        if funsNames is not None:
+            for fun, name in funsNames:
+                if self.reduceQuadratureDegree(fun, name):
+                    return {"quadrature_degree" : self.degree_threshold}
+        return {}
+
     @abstractmethod
-    def A(self, mu:complex, der : int = 0) -> HSOp:
+    def A(self, mu:complex, der : int = 0) -> ScOp:
         """Assemble (derivative of) operator of linear system."""
-        pass
+        Anull = self.checkAInBounds(der)
+        if Anull is not None: return Anull
+        if self.As[der] is None:
+            self.As[der] = 0.
+        return self.As[der]
 
     @abstractmethod
-    def b(self, mu:complex, der : int = 0) -> HS1D:
+    def b(self, mu:complex, der : int = 0,
+          homogeneized : bool = False) -> Np1D:
         """Assemble (derivative of) RHS of linear system."""
-        pass
+        bnull = self.checkbInBounds(der, homogeneized)
+        if bnull is not None: return bnull
+        if self.bs[homogeneized][der] is None:
+            self.bs[homogeneized][der] = 0.
+        return self.bs[homogeneized][der]
 
-    @abstractmethod
-    def solve(self, mu:complex, RHS : HS1D = None) -> HS1D:
-        """Find solution of linear system."""
-        pass
+    def affineBlocksA(self, mu : complex = 0.) -> Tuple[List[Np1D], callable]:
+        """Assemble affine blocks of operator of linear system."""
+        def lambdas(x, j):
+            if j == 0: return np.ones(np.size(x))
+            if j in range(1, self.nAs): return np.power(self.rescaling(x)
+                                                      - self.rescaling(mu), j)
+            raise Exception("Wrong j value.")
+        As = [None] * self.nAs
+        for j in range(self.nAs):
+            As[j] = self.A(mu, j)
+        return As, lambdas
 
-    @abstractmethod
-    def residual(self, u:HS1D, mu:complex) -> HS1D:
-        """Find residual of linear system for given approximate solution."""
-        pass
+    def affineBlocksb(self, mu : complex = 0., homogeneized : bool = False)\
+                                                -> Tuple[List[Np1D], callable]:
+        """Assemble affine blocks of RHS of linear system."""
+        def lambdas(x, j):
+            if j == 0: return np.ones(np.size(x))
+            if j in range(1, self.nbsEff): return np.power(self.rescaling(x)
+                                                         - self.rescaling(mu),
+                                                           j)
+            raise Exception("Wrong j value.")
+        if homogeneized:
+            self.nbsEff = max(self.nAs, self.nbs)
+        else:
+            self.nbsEff = self.nbs
+        bs = [None] * self.nbsEff
+        for j in range(self.nbsEff):
+            bs[j] = self.b(mu, j, homogeneized)
+        return bs, lambdas
 
-    @abstractmethod
-    def plot(self, u:HS1D, name : str = "u", save : bool = False,
-             what : strLst = 'all', **figspecs):
+    def solve(self, mu:complex, RHS : Np1D = None,
+              homogeneized : bool = False) -> Np1D:
+        """
+        Find solution of linear system.
+
+        Args:
+            mu: parameter value.
+            RHS: RHS of linear system. If None, defaults to that of parametric
+                system. Defaults to None.
+        """
+        A = self.A(mu)
+        if RHS is None: RHS = self.b(mu, 0, homogeneized)
+        return scspla.spsolve(A, RHS)
+
+    def residual(self, u:Np1D, mu:complex,
+                 homogeneized : bool = False) -> Np1D:
+        """
+        Find residual of linear system for given approximate solution.
+
+        Args:
+            u: numpy complex array with function dofs. If None, set to 0.
+            mu: parameter value.
+        """
+        A = self.A(mu)
+        RHS = self.b(mu, 0, homogeneized)
+        if u is None: return RHS
+        return RHS - A.dot(u)
+
+    def plot(self, u:Np1D, name : str = "u", save : str = None,
+             what : strLst = 'all', saveFormat : str = "eps",
+             saveDPI : int = 100, **figspecs):
         """
         Do some nice plots of the complex-valued function with given dofs.
 
         Args:
-            u: Hilbert space element.
+            u: numpy complex array with function dofs.
             name(optional): Name to be shown as title of the plots. Defaults to
                 'u'.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
             what(optional): Which plots to do. If list, can contain 'ABS',
                 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
                 Defaults to 'ALL'.
-            save(optional): Whether to save plot(s). Defaults to False.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
             figspecs(optional key args): Optional arguments for matplotlib
                 figure creation.
         """
-        pass
+        if isinstance(what, (str,)):
+            if what.upper() == 'ALL':
+                what = ['ABS', 'PHASE', 'REAL', 'IMAG']
+            else:
+                what = [what]
+        what = purgeList(what, ['ABS', 'PHASE', 'REAL', 'IMAG'],
+                         listname = self.name() + ".what", baselevel = 1)
+        if len(what) == 0: return
+        if 'figsize' not in figspecs.keys():
+            figspecs['figsize'] = (13. * len(what) / 4, 3)
+        subplotcode = 100 + len(what) * 10
 
-    @abstractmethod
-    def plotmesh(self, name : str = "mesh", save : bool = False, **figspecs):
+        plt.figure(**figspecs)
+        plt.jet()
+        if 'ABS' in what:
+            uAb = fen.Function(self.V)
+            uAb.vector()[:] = np.array(np.abs(u), dtype = float)
+            subplotcode = subplotcode + 1
+            plt.subplot(subplotcode)
+            p = fen.plot(uAb, title = "|{0}|".format(name))
+            plt.colorbar(p)
+        if 'PHASE' in what:
+            uPh = fen.Function(self.V)
+            uPh.vector()[:] = np.array(np.angle(u), dtype = float)
+            subplotcode = subplotcode + 1
+            plt.subplot(subplotcode)
+            p = fen.plot(uPh, title = "phase({0})".format(name))
+            plt.colorbar(p)
+        if 'REAL' in what:
+            uRe = fen.Function(self.V)
+            uRe.vector()[:] = np.array(np.real(u), dtype = float)
+            subplotcode = subplotcode + 1
+            plt.subplot(subplotcode)
+            p = fen.plot(uRe, title = "Re({0})".format(name))
+            plt.colorbar(p)
+        if 'IMAG' in what:
+            uIm = fen.Function(self.V)
+            uIm.vector()[:] = np.array(np.imag(u), dtype = float)
+            subplotcode = subplotcode + 1
+            plt.subplot(subplotcode)
+            p = fen.plot(uIm, title = "Im({0})".format(name))
+            plt.colorbar(p)
+        if save is not None:
+            save = save.strip()
+            plt.savefig(getNewFilename("{}_fig_".format(save), saveFormat),
+                        format = saveFormat, dpi = saveDPI)
+        plt.show()
+        plt.close()
+
+    def plotmesh(self, name : str = "Mesh", save : str = None,
+                 saveFormat : str = "eps", saveDPI : int = 100, **figspecs):
         """
         Do a nice plot of the mesh.
 
         Args:
-            u: Hilbert space element.
+            u: numpy complex array with function dofs.
             name(optional): Name to be shown as title of the plots. Defaults to
-                'mesh'.
-            save(optional): Whether to save plot(s). Defaults to False.
+                'u'.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
             figspecs(optional key args): Optional arguments for matplotlib
                 figure creation.
         """
-        pass
+        plt.figure(**figspecs)
+        fen.plot(self.V.mesh())
+        if save is not None:
+            save = save.strip()
+            plt.savefig(getNewFilename("{}_msh_".format(save), saveFormat),
+                        format = saveFormat, dpi = saveDPI)
+        plt.show()
+        plt.close()
+
diff --git a/rrompy/hfengines/scipy/scattering_problem_engine.py b/rrompy/hfengines/base/scattering_problem_engine.py
similarity index 51%
rename from rrompy/hfengines/scipy/scattering_problem_engine.py
rename to rrompy/hfengines/base/scattering_problem_engine.py
index 6b9deef..2b51334 100644
--- a/rrompy/hfengines/scipy/scattering_problem_engine.py
+++ b/rrompy/hfengines/base/scattering_problem_engine.py
@@ -1,139 +1,167 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-import numpy as np
+from numpy import inf
 import scipy.sparse as scsp
 import fenics as fen
-from rrompy.utilities.base.types import Np1D, Np2D, Tuple, List
+from rrompy.utilities.base.types import Np1D, ScOp
 from rrompy.utilities.base.fenics import fenZERO
-from .helmholtz_base_problem_engine import HelmholtzBaseProblemEngine
+from rrompy.utilities.base import verbosityDepth
+from .helmholtz_problem_engine import HelmholtzProblemEngine
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['ScatteringProblemEngine']
 
-class ScatteringProblemEngine(HelmholtzBaseProblemEngine):
+class ScatteringProblemEngine(HelmholtzProblemEngine):
     """
     Solver for scattering problems with parametric wavenumber.
         - \nabla \cdot (a \nabla u) - omega^2 * n**2 * u = f in \Omega
         u = u0                                               on \Gamma_D
         \partial_nu = g1                                     on \Gamma_N
-        \partial_nu +- i k u = g2                            on \Gamma_R
+        \partial_nu +- i omega u = g2                        on \Gamma_R
 
     Attributes:
         signR: Sign in ABC.
         omega: Value of omega.
         diffusivity: Value of a.
         refractionIndex: Value of n.
         forcingTerm: Value of f.
         DirichletDatum: Value of u0.
         NeumannDatum: Value of g1.
         RobinDatumG: Value of g2.
         DirichletBoundary: Function handle to \Gamma_D.
         NeumannBoundary: Function handle to \Gamma_N.
         RobinBoundary: Function handle to \Gamma_R.
         V: Real FE space.
         u: Generic trial functions for variational form evaluation.
         v: Generic test functions for variational form evaluation.
         ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
         A0: Scipy sparse array representation (in CSC format) of A0.
         A1: Scipy sparse array representation (in CSC format) of A1.
         A2: Scipy sparse array representation (in CSC format) of A1.
         b0: Numpy array representation of b0.
         As: Scipy sparse array representation (in CSC format) of As.
         bs: Numpy array representation of bs.
     """
+
+    nAs = 3
     signR = - 1.
 
-    def A(self, mu:complex, der : int = 0) -> Np2D:
+    def __init__(self, degree_threshold : int = inf, verbosity : int = 10):
+        self.silenceWarnings = True
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
+        del self.silenceWarnings
+
+    def rescaling(self, x:Np1D) -> Np1D:
+        """Rescaling in parameter dependence."""
+        return x
+
+    def rescalingInv(self, x:Np1D) -> Np1D:
+        """Inverse rescaling in parameter dependence."""
+        return x
+
+    @property
+    def RobinDatumH(self):
+        """Value of h."""
+        return self.signR * self.omega
+    @RobinDatumH.setter
+    def RobinDatumH(self, RobinDatumH):
+        if not hasattr(self, "silenceWarnings"):
+            warn(("Scattering problems do not allow changes of h. Ignoring "
+                  "assignment."))
+        return
+
+    def A(self, mu:complex, der : int = 0) -> ScOp:
         """Assemble (derivative of) operator of linear system."""
-        if der > 2 or der < 0:
-            d = self.V.dim()
-            return scsp.csr_matrix((np.zeros(0), np.zeros(0), np.zeros(d + 1)),
-                                   shape = (d, d), dtype = np.complex)
+        Anull = self.checkAInBounds(der)
+        if Anull is not None: return Anull
         self.autoSetDS()
-        if der <= 0 and not hasattr(self, "A0"):
+        if der <= 0 and self.As[0] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling operator term A0.")
             DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
                                            self.DirichletBoundary)
             aRe, aIm = self.diffusivity
+            parsRe = self.iterReduceQuadratureDegree(zip([aRe],
+                                                         ["diffusivityReal"]))
+            parsIm = self.iterReduceQuadratureDegree(zip([aIm],
+                                                         ["diffusivityImag"]))
             a0Re = aRe * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
             a0Im = aIm * fen.dot(fen.grad(self.u), fen.grad(self.v)) * fen.dx
-            A0Re = fen.assemble(a0Re)
-            A0Im = fen.assemble(a0Im)
+            A0Re = fen.assemble(a0Re, form_compiler_parameters = parsRe)
+            A0Im = fen.assemble(a0Im, form_compiler_parameters = parsIm)
             DirichletBC0.apply(A0Re)
             DirichletBC0.zero(A0Im)
             A0ReMat = fen.as_backend_type(A0Re).mat()
             A0ImMat = fen.as_backend_type(A0Im).mat()
             A0Rer, A0Rec, A0Rev = A0ReMat.getValuesCSR()
             A0Imr, A0Imc, A0Imv = A0ImMat.getValuesCSR()
-            self.A0 = (scsp.csr_matrix((A0Rev, A0Rec, A0Rer),
-                                       shape = A0ReMat.size)
-               + 1.j * scsp.csr_matrix((A0Imv, A0Imc, A0Imr),
-                                       shape = A0ImMat.size))
-        if der <= 1 and not hasattr(self, "A1"):
+            self.As[0] = (scsp.csr_matrix((A0Rev, A0Rec, A0Rer),
+                                          shape = A0ReMat.size)
+                  + 1.j * scsp.csr_matrix((A0Imv, A0Imc, A0Imr),
+                                          shape = A0ImMat.size))
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling operator term.")
+        if der <= 1 and self.As[1] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling operator term A1.")
             DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
                                            self.DirichletBoundary)
             a1 = fen.dot(self.u, self.v) * self.ds(1)
             A1 = fen.assemble(a1)
             DirichletBC0.zero(A1)
             A1Mat = fen.as_backend_type(A1).mat()
             A1r, A1c, A1v = A1Mat.getValuesCSR()
-            self.A1 = self.signR * 1.j * scsp.csr_matrix((A1v, A1c, A1r),
-                                                         shape = A1Mat.size)
-        if der <= 2 and not hasattr(self, "A2"):
+            self.As[1] = self.signR * 1.j * scsp.csr_matrix((A1v, A1c, A1r),
+                                                            shape = A1Mat.size)
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling operator term.")
+        if der <= 2 and self.As[2] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling operator term A2.")
             DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
                                            self.DirichletBoundary)
             nRe, nIm = self.refractionIndex
             n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
+            parsRe = self.iterReduceQuadratureDegree(zip([n2Re],
+                                               ["refractionIndexSquaredReal"]))
+            parsIm = self.iterReduceQuadratureDegree(zip([n2Im],
+                                               ["refractionIndexSquaredImag"]))
             a2Re = - n2Re * fen.dot(self.u, self.v) * fen.dx
             a2Im = - n2Im * fen.dot(self.u, self.v) * fen.dx
-            A2Re = fen.assemble(a2Re)
-            A2Im = fen.assemble(a2Im)
+            A2Re = fen.assemble(a2Re, form_compiler_parameters = parsRe)
+            A2Im = fen.assemble(a2Im, form_compiler_parameters = parsIm)
             DirichletBC0.zero(A2Re)
             DirichletBC0.zero(A2Im)
             A2ReMat = fen.as_backend_type(A2Re).mat()
             A2ImMat = fen.as_backend_type(A2Im).mat()
             A2Rer, A2Rec, A2Rev = A2ReMat.getValuesCSR()
             A2Imr, A2Imc, A2Imv = A2ImMat.getValuesCSR()
-            self.A2 = (scsp.csr_matrix((A2Rev, A2Rec, A2Rer),
-                                       shape = A2ReMat.size)
-               + 1.j * scsp.csr_matrix((A2Imv, A2Imc, A2Imr),
-                                       shape = A2ImMat.size))
+            self.As[2] = (scsp.csr_matrix((A2Rev, A2Rec, A2Rer),
+                                          shape = A2ReMat.size)
+                  + 1.j * scsp.csr_matrix((A2Imv, A2Imc, A2Imr),
+                                          shape = A2ImMat.size))
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling operator term.")
         if der == 0:
-            return self.A0 + mu * self.A1 + mu**2. * self.A2
+            return self.As[0] + mu * self.As[1] + mu**2. * self.As[2]
         if der == 1:
-            return self.A1 + 2 * mu * self.A2
-        return self.A2
-
-    def affineBlocksA(self, mu : complex = 0.) -> Tuple[List[Np2D], callable]:
-        """Assemble affine blocks of operator of linear system."""
-        def lambdas(x, j):
-            if j == 0: return np.ones(np.size(x))
-            if j in [1, 2]: return np.power(self.rescaling(x)
-                                          - self.rescaling(mu), j)
-            raise Exception("Wrong j value.")
-        A0 = self.A(mu, 0)
-        A1 = self.A(mu, 1)
-        return [A0, A1, self.A2], lambdas
-
-    def affineBlocksb(self, mu : complex = 0.) -> Tuple[List[Np1D], callable]:
-        """Assemble affine blocks of RHS of linear system."""
-        def lambdas(x, j):
-            if j == 0: return np.ones(np.size(x))
-            raise Exception("Wrong j value.")
-        self.b(mu, 0)
-        return [self.b0], lambdas
+            return self.As[1] + 2 * mu * self.As[2]
+        return self.As[2]
 
diff --git a/rrompy/hfengines/scipy/__init__.py b/rrompy/hfengines/scipy/__init__.py
index 870f0a5..7bd5728 100644
--- a/rrompy/hfengines/scipy/__init__.py
+++ b/rrompy/hfengines/scipy/__init__.py
@@ -1,47 +1,42 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from .generic_problem_engine import GenericProblemEngine
-from .helmholtz_base_problem_engine import HelmholtzBaseProblemEngine
 from .helmholtz_box_scattering_problem_engine import (
                                            HelmholtzBoxScatteringProblemEngine)
 from .helmholtz_cavity_scattering_problem_engine import (
                                         HelmholtzCavityScatteringProblemEngine)
-from .helmholtz_problem_engine import HelmholtzProblemEngine
 from .helmholtz_square_bubble_problem_engine import (
                                             HelmholtzSquareBubbleProblemEngine)
 from .helmholtz_square_bubble_domain_problem_engine import (
                                       HelmholtzSquareBubbleDomainProblemEngine)
 from .helmholtz_square_transmission_problem_engine import (
                                       HelmholtzSquareTransmissionProblemEngine)
-from .scattering_problem_engine import ScatteringProblemEngine
+from .laplace_disk_gaussian import (
+                                      LaplaceDiskGaussian)
 
 __all__ = [
-        'GenericProblemEngine',
-        'HelmholtzBaseProblemEngine',
         'HelmholtzBoxScatteringProblemEngine',
         'HelmholtzCavityScatteringProblemEngine',
-        'HelmholtzProblemEngine',
         'HelmholtzSquareBubbleProblemEngine',
         'HelmholtzSquareBubbleDomainProblemEngine',
         'HelmholtzSquareTransmissionProblemEngine',
-        'ScatteringProblemEngine'
+        'LaplaceDiskGaussian'
           ]
 
 
 
diff --git a/rrompy/hfengines/scipy/generic_problem_engine.py b/rrompy/hfengines/scipy/generic_problem_engine.py
deleted file mode 100644
index 0ef4250..0000000
--- a/rrompy/hfengines/scipy/generic_problem_engine.py
+++ /dev/null
@@ -1,185 +0,0 @@
-# Copyright (C) 2018 by the RROMPy authors
-#
-# This file is part of RROMPy.
-#
-# RROMPy is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# RROMPy is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from abc import abstractmethod
-import fenics as fen
-import numpy as np
-from scipy.sparse import csr_matrix
-import scipy.sparse.linalg as scspla
-from matplotlib import pyplot as plt
-from rrompy.hfengines.base import ProblemEngineBase
-from rrompy.utilities.base.types import Np1D, Np2D, strLst, Tuple, List
-from rrompy.utilities.base import purgeList, getNewFilename
-
-__all__ = ['GenericProblemEngine']
-
-class GenericProblemEngine(ProblemEngineBase):
-    """
-    Generic solver for parametric problems.
-    """
-    
-    def __init__(self):
-        super().__init__()
-        self.V = fen.FunctionSpace(fen.UnitSquareMesh(10, 10), "P", 1)
-    
-    def name(self) -> str:
-        return self.__class__.__name__
-        
-    def __str__(self) -> str:
-        return self.name()
-
-    def innerProduct(self, u:Np1D, v:Np1D) -> float:
-        """Hilbert space scalar product."""
-        if not hasattr(self, "energyNormMatrix"):
-            self.buildEnergyNormForm()
-        return v.conj().T.dot(self.energyNormMatrix.dot(u))
-
-    def buildEnergyNormForm(self):
-        """
-        Build sparse matrix (in CSR format) representative of scalar product.
-        """
-        normMat = fen.assemble(fen.dot(self.u, self.v) * fen.dx)
-        normMatFen = fen.as_backend_type(normMat).mat()
-        self.energyNormMatrix = csr_matrix(normMatFen.getValuesCSR()[::-1],
-                                           shape = normMat.size)
-
-    def solve(self, mu:complex, RHS : Np1D = None) -> Np1D:
-        """
-        Find solution of linear system.
-
-        Args:
-            mu: parameter value.
-            RHS: RHS of linear system. If None, defaults to that of parametric
-                system. Defaults to None.
-        """
-        if RHS is None: RHS = self.b(mu)
-        return scspla.spsolve(self.A(mu), RHS)
-
-    def residual(self, u:Np1D, mu:complex) -> Np1D:
-        """
-        Find residual of linear system for given approximate solution.
-
-        Args:
-            u: numpy complex array with function dofs. If None, set to 0.
-            mu: parameter value.
-        """
-        RHS = self.b(mu)
-        if u is None: return RHS
-        return RHS - self.A(mu).dot(u)
-
-    def plot(self, u:Np1D, name : str = "u", save : bool = False,
-             what : strLst = 'all', **figspecs):
-        """
-        Do some nice plots of the complex-valued function with given dofs.
-
-        Args:
-            u: numpy complex array with function dofs.
-            name(optional): Name to be shown as title of the plots. Defaults to
-                'u'.
-            what(optional): Which plots to do. If list, can contain 'ABS',
-                'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
-                Defaults to 'ALL'.
-            save(optional): Whether to save plot(s). Defaults to False.
-            figspecs(optional key args): Optional arguments for matplotlib
-                figure creation.
-        """
-        if isinstance(what, (str,)):
-            if what.upper() == 'ALL':
-                what = ['ABS', 'PHASE', 'REAL', 'IMAG']
-            else:
-                what = [what]
-        what = purgeList(what, ['ABS', 'PHASE', 'REAL', 'IMAG'],
-                         listname = self.name() + ".what", baselevel = 1)
-        if len(what) == 0: return
-        if 'figsize' not in figspecs.keys():
-            figspecs['figsize'] = (13. * len(what) / 4, 3)
-        subplotcode = 100 + len(what) * 10
-
-        plt.figure(**figspecs)
-        plt.jet()
-        if 'ABS' in what:
-            uAb = fen.Function(self.V)
-            uAb.vector()[:] = np.array(np.abs(u), dtype = float)
-            subplotcode = subplotcode + 1
-            plt.subplot(subplotcode)
-            p = fen.plot(uAb, title = "|{0}|".format(name))
-            plt.colorbar(p)
-        if 'PHASE' in what:
-            uPh = fen.Function(self.V)
-            uPh.vector()[:] = np.array(np.angle(u), dtype = float)
-            subplotcode = subplotcode + 1
-            plt.subplot(subplotcode)
-            p = fen.plot(uPh, title = "phase({0})".format(name))
-            plt.colorbar(p)
-        if 'REAL' in what:
-            uRe = fen.Function(self.V)
-            uRe.vector()[:] = np.array(np.real(u), dtype = float)
-            subplotcode = subplotcode + 1
-            plt.subplot(subplotcode)
-            p = fen.plot(uRe, title = "Re({0})".format(name))
-            plt.colorbar(p)
-        if 'IMAG' in what:
-            uIm = fen.Function(self.V)
-            uIm.vector()[:] = np.array(np.imag(u), dtype = float)
-            subplotcode = subplotcode + 1
-            plt.subplot(subplotcode)
-            p = fen.plot(uIm, title = "Im({0})".format(name))
-            plt.colorbar(p)
-        if save:
-            plt.savefig(getNewFilename("fig", "eps"), format='eps', dpi=1000)
-        plt.show()
-        plt.close()
-    
-    def plotmesh(self, name : str = "Mesh", save : bool = False, **figspecs):
-        """
-        Do a nice plot of the mesh.
-
-        Args:
-            u: numpy complex array with function dofs.
-            name(optional): Name to be shown as title of the plots. Defaults to
-                'u'.
-            save(optional): Whether to save plot(s). Defaults to False.
-            figspecs(optional key args): Optional arguments for matplotlib
-                figure creation.
-        """
-        plt.figure(**figspecs)
-        fen.plot(self.V.mesh())
-        if save:
-            plt.savefig(getNewFilename("msh", "eps"), format='eps', dpi=1000)
-        plt.show()
-        plt.close()
-
-    @abstractmethod
-    def A(self, mu:complex, der : int = 0) -> Np2D:
-        """Assemble (derivative of) operator of linear system."""
-        pass
-
-    @abstractmethod
-    def b(self, mu:complex, der : int = 0) -> Np1D:
-        """Assemble (derivative of) RHS of linear system."""
-        pass
-
-    @abstractmethod
-    def affineBlocksA(self, mu : complex = 0.) -> Tuple[List[Np2D], callable]:
-        """Assemble affine blocks of operator of linear system."""
-        pass
-
-    @abstractmethod
-    def affineBlocksb(self, mu : complex = 0.) -> Tuple[List[Np1D], callable]:
-        """Assemble affine blocks of RHS of linear system."""
-        pass
diff --git a/rrompy/hfengines/scipy/helmholtz_base_problem_engine.py b/rrompy/hfengines/scipy/helmholtz_base_problem_engine.py
deleted file mode 100644
index e097221..0000000
--- a/rrompy/hfengines/scipy/helmholtz_base_problem_engine.py
+++ /dev/null
@@ -1,311 +0,0 @@
-# Copyright (C) 2018 by the RROMPy authors
-#
-# This file is part of RROMPy.
-#
-# RROMPy is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# RROMPy is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
-#
-
-import numpy as np
-import scipy.sparse as scsp
-import fenics as fen
-from .generic_problem_engine import GenericProblemEngine
-from rrompy.utilities.base.types import Np1D
-from rrompy.utilities.base.fenics import fenZERO, fenONE, bdrTrue, bdrFalse
-
-__all__ = ['HelmholtzBaseProblemEngine']
-
-class HelmholtzBaseProblemEngine(GenericProblemEngine):
-    """
-    ABSTRACT
-    Solver for generic Helmholtz problems with parametric wavenumber.
-        - \nabla \cdot (a \nabla u) - omega^2 * n**2 * u = f in \Omega
-        u = u0                                               on \Gamma_D
-        \partial_nu = g1                                     on \Gamma_N
-        \partial_nu + h u = g2                               on \Gamma_R
-
-    Attributes:
-        omega: Value of omega.
-        diffusivity: Value of a.
-        refractionIndex: Value of n.
-        forcingTerm: Value of f.
-        DirichletDatum: Value of u0.
-        NeumannDatum: Value of g1.
-        RobinDatumG: Value of g2.
-        DirichletBoundary: Function handle to \Gamma_D.
-        NeumannBoundary: Function handle to \Gamma_N.
-        RobinBoundary: Function handle to \Gamma_R.
-        V: Real FE space.
-        u: Generic trial functions for variational form evaluation.
-        v: Generic test functions for variational form evaluation.
-        ds: Boundary measure 2-tuple (resp. for Neumann and Robin boundaries).
-        A0: Scipy sparse array representation (in CSC format) of A0.
-        A1: Scipy sparse array representation (in CSC format) of A1.
-        b0: Numpy array representation of b0.
-        As: Scipy sparse array representation (in CSC format) of As.
-        bs: Numpy array representation of bs.
-    """
-    omega = 1.
-
-    def __init__(self):
-        super().__init__()
-        self.diffusivity = fenONE
-        self.refractionIndex = fenONE
-        self.forcingTerm = fenZERO
-        self.DirichletDatum = fenZERO
-        self.NeumannDatum = fenZERO
-        self.RobinDatumG = fenZERO
-
-    @property
-    def V(self):
-        """Value of V."""
-        return self._V
-    @V.setter
-    def V(self, V):
-        if hasattr(self, "A0"): del self.A0
-        if hasattr(self, "A1"): del self.A1
-        if hasattr(self, "b0"): del self.b0
-        if not type(V).__name__ == 'FunctionSpace':
-            raise Exception("V type not recognized.")
-        self._V = V
-        self.u = fen.TrialFunction(V)
-        self.v = fen.TestFunction(V)
-        self.dsToBeSet = True
-
-    @property
-    def diffusivity(self):
-        """Value of a."""
-        return self._diffusivity
-    @diffusivity.setter
-    def diffusivity(self, diffusivity):
-        if hasattr(self, "A0"): del self.A0
-        if not isinstance(diffusivity, (list, tuple,)):
-            diffusivity = [diffusivity, fenZERO]
-        self._diffusivity = diffusivity
-
-    @property
-    def refractionIndex(self):
-        """Value of n."""
-        return self._refractionIndex
-    @refractionIndex.setter
-    def refractionIndex(self, refractionIndex):
-        if hasattr(self, "A1"): del self.A1
-        if not isinstance(refractionIndex, (list, tuple,)):
-            refractionIndex = [refractionIndex, fenZERO]
-        self._refractionIndex = refractionIndex
-    
-    @property
-    def forcingTerm(self):
-        """Value of f."""
-        return self._forcingTerm
-    @forcingTerm.setter
-    def forcingTerm(self, forcingTerm):
-        if hasattr(self, "b0"): del self.b0
-        if not isinstance(forcingTerm, (list, tuple,)):
-            forcingTerm = [forcingTerm, fenZERO]
-        self._forcingTerm = forcingTerm
-
-    @property
-    def DirichletDatum(self):
-        """
-        Value of u0. Its assignment changes u0Re, u0Im, DirichletBCRe and
-            DirichletBCIm.
-        """
-        return self._DirichletDatum
-    @DirichletDatum.setter
-    def DirichletDatum(self, DirichletDatum):
-        if hasattr(self, "b0"): del self.b0
-        if not isinstance(DirichletDatum, (list, tuple,)):
-            DirichletDatum = [DirichletDatum, fenZERO]
-        self._DirichletDatum = DirichletDatum
-
-    @property
-    def NeumannDatum(self):
-        """Value of g1."""
-        return self._NeumannDatum
-    @NeumannDatum.setter
-    def NeumannDatum(self, NeumannDatum):
-        if hasattr(self, "b0"): del self.b0
-        if not isinstance(NeumannDatum, (list, tuple,)):
-            NeumannDatum = [NeumannDatum, fenZERO]
-        self._NeumannDatum = NeumannDatum
-
-    @property
-    def RobinDatumG(self):
-        """Value of g2."""
-        return self._RobinDatumG
-    @RobinDatumG.setter
-    def RobinDatumG(self, RobinDatumG):
-        if hasattr(self, "b0"): del self.b0
-        if not isinstance(RobinDatumG, (list, tuple,)):
-            RobinDatumG = [RobinDatumG, fenZERO]
-        self._RobinDatumG = RobinDatumG
-
-    @property
-    def DirichletBoundary(self):
-        """Function handle to DirichletBoundary."""
-        return self._DirichletBoundary
-    @DirichletBoundary.setter
-    def DirichletBoundary(self, DirichletBoundary):
-        if hasattr(self, "A0"): del self.A0
-        if hasattr(self, "A1"): del self.A1
-        if isinstance(DirichletBoundary, (str,)):
-            if DirichletBoundary.upper() == "NONE":
-                self._DirichletBoundary = bdrFalse
-                self.DREST = 0
-            elif DirichletBoundary.upper() == "ALL":
-                self._DirichletBoundary = bdrTrue
-                self.NeumannBoundary = "NONE"
-                self.RobinBoundary = "NONE"
-                self.DREST = 0
-            elif DirichletBoundary.upper() == "REST":
-                if self.NREST + self.RREST > 0:
-                    raise Exception("Only 1 'REST' wildcard can be specified.")
-                self._DirichletBoundary = lambda x, on_boundary : (on_boundary
-                                   and not self.NeumannBoundary(x, on_boundary)
-                                   and not self.RobinBoundary(x, on_boundary))
-                self.DREST = 1
-            else:
-                raise Exception("DirichletBoundary label not recognized.")
-        elif callable(DirichletBoundary):
-            self._DirichletBoundary = DirichletBoundary
-            self.DREST = 0
-        else:
-            raise Exception("DirichletBoundary type not recognized.")
-
-    @property
-    def NeumannBoundary(self):
-        """Function handle to NeumannBoundary."""
-        return self._NeumannBoundary
-    @NeumannBoundary.setter
-    def NeumannBoundary(self, NeumannBoundary):
-        if hasattr(self, "b0"): del self.b0
-        self.dsToBeSet = True
-        if isinstance(NeumannBoundary, (str,)):
-            if NeumannBoundary.upper() == "NONE":
-                self._NeumannBoundary = bdrFalse
-                self.NREST = 0
-            elif NeumannBoundary.upper() == "ALL":
-                self._NeumannBoundary = bdrTrue
-                self.DirichletBoundary = "NONE"
-                self.RobinBoundary = "NONE"
-                self.NREST = 0
-            elif NeumannBoundary.upper() == "REST":
-                if self.DREST + self.RREST > 0:
-                    raise Exception("Only 1 'REST' wildcard can be specified.")
-                self._NeumannBoundary = lambda x, on_boundary : (on_boundary
-                                 and not self.DirichletBoundary(x, on_boundary)
-                                 and not self.RobinBoundary(x, on_boundary))
-                self.NREST = 1
-            else:
-                raise Exception("NeumannBoundary label not recognized.")
-        elif callable(NeumannBoundary):
-            self._NeumannBoundary = NeumannBoundary
-            self.NREST = 0
-        else:
-            raise Exception("DirichletBoundary type not recognized.")
-
-    @property
-    def RobinBoundary(self):
-        """Function handle to RobinBoundary."""
-        return self._RobinBoundary
-    @RobinBoundary.setter
-    def RobinBoundary(self, RobinBoundary):
-        if hasattr(self, "A0"): del self.A0
-        if hasattr(self, "A1"): del self.A1
-        self.dsToBeSet = True
-        if isinstance(RobinBoundary, (str,)):
-            if RobinBoundary.upper() == "NONE":
-                self._RobinBoundary = bdrFalse
-                self.RREST = 0
-            elif RobinBoundary.upper() == "ALL":
-                self._RobinBoundary = bdrTrue
-                self.DirichletBoundary = "NONE"
-                self.NeumannBoundary = "NONE"
-                self.RREST = 0
-            elif RobinBoundary.upper() == "REST":
-                if self.DREST + self.NREST > 0:
-                    raise Exception("Only 1 'REST' wildcard can be specified.")
-                self._RobinBoundary = lambda x, on_boundary : (on_boundary
-                                 and not self.DirichletBoundary(x, on_boundary)
-                                 and not self.NeumannBoundary(x, on_boundary))
-                self.RREST = 1
-            else:
-                raise Exception("RobinBoundary label not recognized.")
-            return
-        elif callable(RobinBoundary):
-            self._RobinBoundary = RobinBoundary
-            self.RREST = 0
-        else:
-            raise Exception("RobinBoundary type not recognized.")
-    
-    def autoSetDS(self):
-        """Set FEniCS boundary measure based on boundary function handles."""
-        if self.dsToBeSet:
-            NB = self.NeumannBoundary
-            RB = self.RobinBoundary
-            class NBoundary(fen.SubDomain):
-                def inside(self, x, on_boundary):
-                    return NB(x, on_boundary)
-            class RBoundary(fen.SubDomain):
-                def inside(self, x, on_boundary):
-                    return RB(x, on_boundary)
-            boundary_markers = fen.MeshFunction("size_t", self.V.mesh(),
-                                            self.V.mesh().topology().dim() - 1)
-            NBoundary().mark(boundary_markers, 0)
-            RBoundary().mark(boundary_markers, 1)
-            self.ds = fen.Measure("ds", domain = self.V.mesh(),
-                                  subdomain_data = boundary_markers)
-            self.dsToBeSet = False
-
-    def buildEnergyNormForm(self):
-        """
-        Build sparse matrix (in CSR format) representative of scalar product.
-        """
-        normMatFen = fen.assemble((fen.dot(fen.grad(self.u), fen.grad(self.v))
-                    + np.abs(self.omega)**2 * fen.dot(self.u, self.v)) *fen.dx)
-        normMat = fen.as_backend_type(normMatFen).mat()
-        self.energyNormMatrix = scsp.csr_matrix(normMat.getValuesCSR()[::-1],
-                                                shape = normMat.size)
-
-    def liftDirichletData(self) -> Np1D:
-        """Lift Dirichlet datum."""
-        solLRe = fen.interpolate(self.DirichletDatum[0], self.V)
-        solLIm = fen.interpolate(self.DirichletDatum[1], self.V)
-        return np.array(solLRe.vector()) + 1.j * np.array(solLIm.vector())
-
-    def b(self, mu:complex, der : int = 0) -> Np1D:
-        """Assemble (derivative of) RHS of linear system."""
-        if der != 0:
-            return np.zeros(self.V.dim(), dtype = np.complex)
-        self.autoSetDS()
-        if not hasattr(self, "b0"):
-            fRe, fIm = self.forcingTerm
-            g1Re, g1Im = self.NeumannDatum
-            g2Re, g2Im = self.RobinDatumG
-            L0Re = (fen.dot(fRe, self.v) * fen.dx
-                  + fen.dot(g1Re, self.v) * self.ds(0)
-                  + fen.dot(g2Re, self.v) * self.ds(1))
-            L0Im = (fen.dot(fIm, self.v) * fen.dx
-                  + fen.dot(g1Im, self.v) * self.ds(0)
-                  + fen.dot(g2Im, self.v) * self.ds(1))
-            b0Re = fen.assemble(L0Re)
-            b0Im = fen.assemble(L0Im)
-            fen.DirichletBC(self.V, self.DirichletDatum[0],
-                            self.DirichletBoundary).apply(b0Re)
-            fen.DirichletBC(self.V, self.DirichletDatum[1],
-                            self.DirichletBoundary).apply(b0Im)
-            self.b0 = np.array(b0Re[:] + 1.j * b0Im[:], dtype = np.complex)
-        return self.b0
-
-
diff --git a/rrompy/hfengines/scipy/helmholtz_box_scattering_problem_engine.py b/rrompy/hfengines/scipy/helmholtz_box_scattering_problem_engine.py
index ca6c830..3bb09c2 100644
--- a/rrompy/hfengines/scipy/helmholtz_box_scattering_problem_engine.py
+++ b/rrompy/hfengines/scipy/helmholtz_box_scattering_problem_engine.py
@@ -1,59 +1,58 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 import fenics as fen
-from rrompy.hfengines.scipy.scattering_problem_engine import ScatteringProblemEngine
+from rrompy.hfengines.base.scattering_problem_engine import (
+                                                       ScatteringProblemEngine)
 
 __all__ = ['HelmholtzBoxScatteringProblemEngine']
 
 class HelmholtzBoxScatteringProblemEngine(ScatteringProblemEngine):
     """
     Solver for scattering problem outside a box with parametric wavenumber.
         - \Delta u - omega^2 * n^2 * u = 0 in \Omega
         u = 0                              on \Gamma_D
         \partial_nu - i k u = 0            on \Gamma_R
         with exact solution a transmitted plane wave.
     """
-    def __init__(self, R:float, kappa:float, theta:float, n:int):
-        super().__init__()
+    def __init__(self, R:float, kappa:float, theta:float, n:int,
+                 degree_threshold : int = np.inf, verbosity : int = 10):
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
         
         self.omega = kappa
         
         import mshr
         scatterer = mshr.Polygon([fen.Point(-1, -.5), fen.Point(1, -.5),
                                   fen.Point(1, .5), fen.Point(.8, .5),
                                   fen.Point(.8, -.3), fen.Point(-.8, -.3),
                                   fen.Point(-.8, .5), fen.Point(-1, .5),])
         mesh = mshr.generate_mesh(mshr.Circle(fen.Point(0, 0), R)-scatterer, n)
         self.V = fen.FunctionSpace(mesh, "P", 3)
         
         self.DirichletBoundary = (lambda x, on_boundary:
                                on_boundary and (x[0]**2+x[1]**2)**.5 < .95 * R)
-        self.RobinBoundary = (lambda x, on_boundary:
-                               on_boundary and (x[0]**2+x[1]**2)**.5 > .95 * R)
+        self.RobinBoundary = "REST"
     
-        import sympy as sp
-        x, y = sp.symbols('x[0] x[1]', real=True)
-        phiex = kappa * (x * np.cos(theta) + y * np.sin(theta))
-        u0ex = - sp.exp(1.j * phiex)
-        u0 = [sp.printing.ccode(sp.simplify(sp.re(u0ex))),
-              sp.printing.ccode(sp.simplify(sp.im(u0ex)))]
-        self.DirichletDatum = [fen.Expression(x, degree = 3) for x in u0]
-        
+        c, s = np.cos(theta), np.sin(theta)
+        x, y = fen.SpatialCoordinate(mesh)[:]
+        u0R = - fen.cos(kappa * (c * x + s * y))
+        u0I = - fen.sin(kappa * (c * x + s * y))
+        self.DirichletDatum = [u0R, u0I]
         
diff --git a/rrompy/hfengines/scipy/helmholtz_cavity_scattering_problem_engine.py b/rrompy/hfengines/scipy/helmholtz_cavity_scattering_problem_engine.py
index 3535b3b..f9263b0 100644
--- a/rrompy/hfengines/scipy/helmholtz_cavity_scattering_problem_engine.py
+++ b/rrompy/hfengines/scipy/helmholtz_cavity_scattering_problem_engine.py
@@ -1,54 +1,60 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 import fenics as fen
-from rrompy.hfengines.scipy.scattering_problem_engine import ScatteringProblemEngine
+from rrompy.hfengines.base.scattering_problem_engine import (
+                                                       ScatteringProblemEngine)
 
 __all__ = ['HelmholtzCavityScatteringProblemEngine']
 
 class HelmholtzCavityScatteringProblemEngine(ScatteringProblemEngine):
     """
     Solver for scattering problem inside a cavity with parametric wavenumber.
         - \Delta u - omega^2 * n^2 * u = 0 in \Omega
         u = 0                              on \Gamma_D
         \partial_nu - i k u = 0            on \Gamma_R
         with exact solution a transmitted plane wave.
     """
     def __init__(self, kappa:float, n:int, gamma : float = 0.,
-                 signR : int = -1):
-        super().__init__()
+                 signR : int = -1, degree_threshold : int = np.inf,
+                 verbosity : int = 10):
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
         
+        self.signR = signR
         self.omega = kappa
         
-        mesh = fen.RectangleMesh(fen.Point(0,0), fen.Point(np.pi,np.pi), n, n)
+        pi = np.pi
+        mesh = fen.RectangleMesh(fen.Point(0, 0), fen.Point(pi, pi), n, n)
         self.V = fen.FunctionSpace(mesh, "P", 3)
         
         self.RobinBoundary = (lambda x, on_boundary: on_boundary 
                                                  and np.isclose(x[1], np.pi))
         self.DirichletBoundary = "REST"
     
-        import sympy as sp
-        x, y = sp.symbols('x[0] x[1]', real=True)
-        wex = 4/np.pi**4 * x * y * (x - np.pi) * (y - 2 * np.pi)
-        phiex = signR * kappa * (x * gamma + y)
-        uex = wex * sp.exp(-1.j * phiex)
-        fex = - uex.diff(x, 2) - uex.diff(y, 2) - kappa**2 * uex
-        forcingTerm = [sp.printing.ccode(sp.simplify(sp.re(fex))),
-                       sp.printing.ccode(sp.simplify(sp.im(fex)))]
-        self.forcingTerm = [fen.Expression(x, degree = 3) for x in forcingTerm]
+        x, y = fen.SpatialCoordinate(mesh)[:]
+        C = 4. / pi ** 4.
+        bR = C * (2 * (x * (pi - x) + y * (2 * pi - y))
+                + (kappa * gamma) ** 2. * x * (pi - x) * y * (2 * pi - y))
+        bI = C * signR * 2 * kappa * (gamma * (pi - 2 * x) * y * (pi - y)
+                                    + 2 * x * (pi - x) * (pi - y))
+        wR = fen.cos(kappa * signR * (gamma * x + y))
+        wI = fen.sin(kappa * signR * (gamma * x + y))
+        self.forcingTerm = [bR * wR + bI * wI, bI * wR - bR * wI]
+
diff --git a/rrompy/hfengines/scipy/helmholtz_square_bubble_domain_problem_engine.py b/rrompy/hfengines/scipy/helmholtz_square_bubble_domain_problem_engine.py
index 8c73294..3a54b7b 100644
--- a/rrompy/hfengines/scipy/helmholtz_square_bubble_domain_problem_engine.py
+++ b/rrompy/hfengines/scipy/helmholtz_square_bubble_domain_problem_engine.py
@@ -1,185 +1,243 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 import scipy.sparse as scsp
 import fenics as fen
-from rrompy.utilities.base.types import Np1D, Np2D, Tuple, List, FenExpr
-from rrompy.hfengines.scipy.helmholtz_problem_engine import (
-                                               HelmholtzProblemEngine, fenZERO)
+from rrompy.utilities.base.types import Np1D, ScOp, Tuple, List, FenExpr
+from rrompy.utilities.base.fenics import fenZERO
+from rrompy.hfengines.base.helmholtz_problem_engine import (
+                                                        HelmholtzProblemEngine)
+from rrompy.utilities.base import verbosityDepth
 
 __all__ = ['HelmholtzSquareBubbleDomainProblemEngine']
 
 class HelmholtzSquareBubbleDomainProblemEngine(HelmholtzProblemEngine):
     """
     Solver for square bubble Helmholtz problems with parametric domain heigth.
         - \Delta u - kappa^2 * u = f in \Omega_mu = [0,\pi] x [0,\mu\pi]
         u = 0                        on \Gamma_mu = \partial\Omega_mu
         with exact solution square bubble times plane wave.
     """
     
-    def __init__(self, kappa:float, theta:float, n:int):
-        super().__init__()
-        
+    nAs, nbs = 3, 20
+
+    def __init__(self, kappa:float, theta:float, n:int, mu0 : np.complex = 1.,
+                 degree_threshold : int = np.inf, verbosity : int = 10):
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
         self.omega = kappa
         self.kappa = kappa
         self.theta = theta
-        
-        self.derMaxB = 20
-        self.bs = [None] * self.derMaxB
+        self.mu0 = mu0
+        self.forcingTermMu = np.nan
         
         mesh = fen.RectangleMesh(fen.Point(0,0), fen.Point(np.pi,np.pi), n, n)
         self.V = fen.FunctionSpace(mesh, "P", 3)
         
+    def buildEnergyNormForm(self):
+        """
+        Build sparse matrix (in CSR format) representative of scalar product.
+        """
+        if self.verbosity >= 20:
+            verbosityDepth("INIT", "Assembling energy matrix.", end = "")
+        mudx = np.abs(self.mu0) * fen.dot(self.u.dx(0), self.v.dx(0)) * fen.dx
+        muM = np.abs(self.mu0) * fen.dot(self.u, self.v) * fen.dx
+        imudy = 1. / np.abs(self.mu0) * (fen.dot(self.u.dx(1), self.v.dx(1))
+                                       * fen.dx)
+        normMatFen = fen.assemble(mudx + imudy + muM)
+        normMat = fen.as_backend_type(normMatFen).mat()
+        self.energyNormMatrix = scsp.csr_matrix(normMat.getValuesCSR()[::-1],
+                                                shape = normMat.size)
+        if self.verbosity >= 20:
+            verbosityDepth("DEL", " Done.", inline = True)
+
     def getForcingTerm(self, mu:complex) -> Tuple[FenExpr, FenExpr]:
         """Compute forcing term."""
-        if (not hasattr(self, "forcingTermMu")
-         or not np.isclose(mu, self.forcingTermMu)):
-            import sympy as sp
-            x, y = sp.symbols('x[0] x[1]', real=True)
-            wex = 16/np.pi**4 * x * y * (x - np.pi) * (y - np.pi)
-            phiex = self.kappa * (x * np.cos(self.theta) + y * mu * np.sin(self.theta))
-            uex = wex * sp.exp(-1.j * phiex)
-            fex = - uex.diff(x, 2) - uex.diff(y, 2) - self.kappa**2 * uex
-            forcingTerm = [sp.printing.ccode(sp.simplify(sp.re(fex))),
-                           sp.printing.ccode(sp.simplify(sp.im(fex)))]
-            self.forcingTerm = [fen.Expression(x, degree = 3) for x in forcingTerm]
+        if not np.isclose(mu, self.forcingTermMu):
+            if self.verbosity >= 25:
+                verbosityDepth("INIT",
+                               "Assembling base expression for forcing term.",
+                               end = "")
+            pi = np.pi
+            c, s = np.cos(self.theta), np.sin(self.theta)
+            x, y = fen.SpatialCoordinate(self.V.mesh())[:]
+            muR, muI = np.real(mu), np.imag(mu)
+            mu2R, mu2I = np.real(mu ** 2.), np.imag(mu ** 2.)
+            C = 16. / pi ** 4.
+            bR = C * (2 * (x * (pi - x) + y * (pi - y))
+                    + (self.kappa * s) ** 2. * (mu2R - 1.)
+                                                 * x * (pi - x) * y * (pi - y))
+            bI = C * (2 * self.kappa * (c * (pi - 2 * x) * y * (pi - y)
+                                      + s * x * (pi - x) * (pi - 2 * y))
+                    + (self.kappa * s) ** 2. * mu2I
+                                                 * x * (pi - x) * y * (pi - y))
+            wR = (fen.cos(self.kappa * (c * x + s * muR * y))
+                * fen.exp(self.kappa * s * muI * y))
+            wI = (fen.sin(self.kappa * (c * x + s * muR * y))
+                * fen.exp(self.kappa * s * muI * y))
+            self.forcingTerm = [bR * wR + bI * wI, bI * wR - bR * wI]
             self.forcingTermMu = mu
+            if self.verbosity >= 25:
+                verbosityDepth("DEL", " Done.", inline = True)
         return self.forcingTerm
     
     def getExtraFactorB(self, mu:complex, der:int) -> Tuple[FenExpr, FenExpr]:
         """Compute extra expression in RHS."""
-        import sympy as sp
+        def getPowMinusj(x, power):
+            powR = x ** power
+            powI = fenZERO
+            if power % 2 == 1:
+                powR, powI = powI, powR
+            if (power + 3) % 4 < 2:
+                powR, powI = - powR, - powI
+            return powR, powI
+        if self.verbosity >= 25:
+            verbosityDepth("INIT", ("Assembling auxiliary expression for "
+                                    "forcing term derivative."), end = "")
         from math import factorial as fact
-        y = sp.symbols('x[1]', real=True)
-        expr = mu**2.*np.power(-1.j * self.kappa * np.sin(self.theta) * y, der)
+        y = fen.SpatialCoordinate(self.V.mesh())[1]
+        powR, powI = [(self.kappa * np.sin(self.theta)) ** der * k\
+                                                 for k in getPowMinusj(y, der)]
+        mu2R, mu2I = np.real(mu ** 2.), np.imag(mu ** 2.)
+        exprR = mu2R * powR - mu2I * powI
+        exprI = mu2I * powR + mu2R * powI
         if der >= 1:
-            expr += 2.*mu*np.power(-1.j * self.kappa * np.sin(self.theta) * y, 
-                                   der - 1) * der
+            muR, muI = np.real(2. * mu), np.imag(2. * mu)
+            powR, powI = [(self.kappa * np.sin(self.theta)) ** (der - 1) * k\
+                                       * der for k in getPowMinusj(y, der - 1)]
+            exprR += muR * powR - muI * powI
+            exprI += muI * powR + muR * powI
         if der >= 2:
-            expr += np.power(-1.j * self.kappa * np.sin(self.theta) * y, 
-                             der - 2) * der * (der - 1)
-        extraTerm = [sp.printing.ccode(sp.simplify(sp.re(expr / fact(der)))),
-                     sp.printing.ccode(sp.simplify(sp.im(expr / fact(der))))]
-        return [fen.Expression(x, degree = 3) for x in extraTerm]
+            powR, powI = [(self.kappa * np.sin(self.theta)) ** (der - 2) * k\
+                           * der * (der - 1) for k in getPowMinusj(y, der - 2)]
+            exprR += powR
+            exprI += powI
+        fac = fact(der)
+        if self.verbosity >= 25:
+            verbosityDepth("DEL", " Done.", inline = True)
+        return [exprR / fac, exprI / fac]
 
     def rescaling(self, x:Np1D) -> Np1D:
         """Rescaling in parameter dependence."""
         return x
 
     def rescalingInv(self, x:Np1D) -> Np1D:
         """Inverse rescaling in parameter dependence."""
         return x
 
-    def A(self, mu:complex, der : int = 0) -> Np2D:
+    def A(self, mu:complex, der : int = 0) -> ScOp:
         """Assemble (derivative of) operator of linear system."""
-        if der > 2 or der < 0:
-            d = self.V.dim()
-            return scsp.csr_matrix((np.zeros(0), np.zeros(0), np.zeros(d + 1)),
-                                   shape = (d, d), dtype = np.complex)
+        Anull = self.checkAInBounds(der)
+        if Anull is not None: return Anull
         self.autoSetDS()
-        if der <= 0 and not hasattr(self, "A0"):
+        if der <= 0 and self.As[0] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling operator term A0.")
             DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
                                            self.DirichletBoundary)
             a0Re = fen.dot(self.u.dx(1), self.v.dx(1)) * fen.dx
             A0Re = fen.assemble(a0Re)
             DirichletBC0.apply(A0Re)
             A0ReMat = fen.as_backend_type(A0Re).mat()
             A0Rer, A0Rec, A0Rev = A0ReMat.getValuesCSR()
-            self.A0 = scsp.csr_matrix((A0Rev, A0Rec, A0Rer),
-                                      shape = A0ReMat.size,
-                                      dtype = np.complex)
-        if der <= 2 and not hasattr(self, "A2"):
+            self.As[0] = scsp.csr_matrix((A0Rev, A0Rec, A0Rer),
+                                         shape = A0ReMat.size,
+                                         dtype = np.complex)
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling operator term.")
+        if der <= 2 and self.As[2] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT", "Assembling operator term A2.")
             DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
                                            self.DirichletBoundary)
             nRe, nIm = self.refractionIndex
             n2Re, n2Im = nRe * nRe - nIm * nIm, 2 * nRe * nIm
             k2Re, k2Im = np.real(self.omega ** 2), np.imag(self.omega ** 2)
             k2n2Re = k2Re * n2Re - k2Im * n2Im
             k2n2Im = k2Re * n2Im + k2Im * n2Re
+            parsRe = self.iterReduceQuadratureDegree(zip([k2n2Re],
+                                   ["kappaSquaredRefractionIndexSquaredReal"]))
+            parsIm = self.iterReduceQuadratureDegree(zip([k2n2Im],
+                                   ["kappaSquaredRefractionIndexSquaredImag"]))
             a2Re = (fen.dot(self.u.dx(0), self.v.dx(0))
                   - k2n2Re * fen.dot(self.u, self.v)) * fen.dx
             a2Im = - k2n2Im * fen.dot(self.u, self.v) * fen.dx
-            A2Re = fen.assemble(a2Re)
-            A2Im = fen.assemble(a2Im)
+            A2Re = fen.assemble(a2Re, form_compiler_parameters = parsRe)
+            A2Im = fen.assemble(a2Im, form_compiler_parameters = parsIm)
             DirichletBC0.zero(A2Re)
             DirichletBC0.zero(A2Im)
             A2ReMat = fen.as_backend_type(A2Re).mat()
             A2ImMat = fen.as_backend_type(A2Im).mat()
             A2Rer, A2Rec, A2Rev = A2ReMat.getValuesCSR()
             A2Imr, A2Imc, A2Imv = A2ImMat.getValuesCSR()
-            self.A2 = (scsp.csr_matrix((A2Rev, A2Rec, A2Rer),
-                                       shape = A2ReMat.size)
-               + 1.j * scsp.csr_matrix((A2Imv, A2Imc, A2Imr),
-                                       shape = A2ImMat.size))
+            self.As[2] = (scsp.csr_matrix((A2Rev, A2Rec, A2Rer),
+                                          shape = A2ReMat.size)
+                  + 1.j * scsp.csr_matrix((A2Imv, A2Imc, A2Imr),
+                                          shape = A2ImMat.size))
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling operator term.")
         if der == 0:
-            return self.A0 + mu ** 2 * self.A2
+            return self.As[0] + mu ** 2 * self.As[2]
         if der == 1:
-            return 2. * mu * self.A2
-        return self.A2
+            return 2. * mu * self.As[2]
+        return self.As[2]
 
-    def b(self, mu:complex, der : int = 0) -> Np1D:
+    def b(self, mu:complex, der : int = 0,
+          homogeneized : bool = False) -> Np1D:
         """Assemble (derivative of) RHS of linear system."""
-        if der < 0 or der >= self.derMaxB:
-            return np.zeros(self.V.dim(), dtype = np.complex)
-        if self.bs[der] is None:
-            fRe, fIm = self.getForcingTerm(mu)
-            cRe, cIm = self.getExtraFactorB(mu, der)
-            cfRe = cRe * fRe - cIm * fIm
-            cfIm = cRe * fIm + cIm * fRe
+        bnull = self.checkbInBounds(der, homogeneized)
+        if bnull is not None: return bnull
+        if homogeneized and not np.isclose(self.mu0BC, mu):
+            self.u0BC = self.liftDirichletData(mu)
+        if not np.isclose(self.bsmu, mu):
+            self.bsmu = mu
+            self.resetbs()
+        if self.bs[homogeneized][der] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT",
+                               "Assembling forcing term b{}.".format(der))
+            if der < self.nbs:
+                fRe, fIm = self.getForcingTerm(mu)
+                cRe, cIm = self.getExtraFactorB(mu, der)
+                cfRe = cRe * fRe - cIm * fIm
+                cfIm = cRe * fIm + cIm * fRe
+            else:
+                cfRe, cfIm = fenZERO, fenZERO
+            parsRe = self.iterReduceQuadratureDegree(zip([cfRe],
+                                         ["forcingTermDer{}Real".format(der)]))
+            parsIm = self.iterReduceQuadratureDegree(zip([cfIm],
+                                         ["forcingTermDer{}Imag".format(der)]))
             L0Re = fen.dot(cfRe, self.v) * fen.dx
             L0Im = fen.dot(cfIm, self.v) * fen.dx
-            b0Re = fen.assemble(L0Re)
-            b0Im = fen.assemble(L0Im)
-            if der == 0:
-                DirichletBCRe = fen.DirichletBC(self.V, self.DirichletDatum[0],
-                                                self.DirichletBoundary)
-                DirichletBCIm = fen.DirichletBC(self.V, self.DirichletDatum[1],
-                                                self.DirichletBoundary)
-            else:
-                DirichletBCRe = fen.DirichletBC(self.V, fenZERO,
-                                                self.DirichletBoundary)
-                DirichletBCIm = DirichletBCRe
-            DirichletBCRe.apply(b0Re)
-            DirichletBCIm.apply(b0Im)
-            self.bs[der] = np.array(b0Re[:] + 1.j * b0Im[:], dtype = np.complex)
-        return self.bs[der]
-
-    def affineBlocksA(self, mu : complex = 0.) -> Tuple[List[Np2D], callable]:
-        """Assemble affine blocks of operator of linear system."""
-        def lambdas(x, j):
-            if j == 0: return np.ones(np.size(x))
-            if j in [1, 2]: return np.power(self.rescaling(x)
-                                          - self.rescaling(mu), j)
-            raise Exception("Wrong j value.")
-        A0 = self.A(mu, 0)
-        A1 = self.A(mu, 1)
-        return [A0, A1, self.A2], lambdas
-
-    def affineBlocksb(self, mu : complex = 0.) -> Tuple[List[Np1D], callable]:
-        """Assemble affine blocks of RHS of linear system."""
-        def lambdas(x, j):
-            if j == 0: return np.ones(np.size(x))
-            if j in range(1, self.derMaxB): return np.power(self.rescaling(x)
-                                                          - self.rescaling(mu),
-                                                            j)
-            raise Exception("Wrong j value.")
-        for j in range(self.derMaxB):
-            self.b(mu, j)
-        return self.bs, lambdas
+            b0Re = fen.assemble(L0Re, form_compiler_parameters = parsRe)
+            b0Im = fen.assemble(L0Im, form_compiler_parameters = parsIm)
+            if homogeneized:
+                Ader = self.A(mu, der)
+                b0Re[:] -= np.real(Ader.dot(self.u0BC))
+                b0Im[:] -= np.imag(Ader.dot(self.u0BC))
+            DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+                                           self.DirichletBoundary)
+            DirichletBC0.apply(b0Re)
+            DirichletBC0.apply(b0Im)
+            self.bs[homogeneized][der] = np.array(b0Re[:]
+                                          + 1.j * b0Im[:], dtype = np.complex)
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling forcing term.")
+        return self.bs[homogeneized][der]
 
diff --git a/rrompy/hfengines/scipy/helmholtz_square_bubble_problem_engine.py b/rrompy/hfengines/scipy/helmholtz_square_bubble_problem_engine.py
index 4dbcbff..7e6035f 100644
--- a/rrompy/hfengines/scipy/helmholtz_square_bubble_problem_engine.py
+++ b/rrompy/hfengines/scipy/helmholtz_square_bubble_problem_engine.py
@@ -1,50 +1,53 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 import fenics as fen
-from rrompy.hfengines.scipy.helmholtz_problem_engine import (
+from rrompy.hfengines.base.helmholtz_problem_engine import (
                                                         HelmholtzProblemEngine)
 
 __all__ = ['HelmholtzSquareBubbleProblemEngine']
 
 class HelmholtzSquareBubbleProblemEngine(HelmholtzProblemEngine):
     """
     Solver for square bubble Helmholtz problems with parametric wavenumber.
         - \Delta u - omega^2 * u = f in \Omega
         u = 0                        on \Gamma_D
         with exact solution square bubble times plane wave.
     """
-    def __init__(self, kappa:float, theta:float, n:int):
-        super().__init__()
+    def __init__(self, kappa:float, theta:float, n:int,
+                 degree_threshold : int = np.inf, verbosity : int = 10):
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
         
         self.omega = kappa
         
-        mesh = fen.RectangleMesh(fen.Point(0,0), fen.Point(np.pi,np.pi), n, n)
+        pi = np.pi
+        mesh = fen.RectangleMesh(fen.Point(0, 0), fen.Point(pi, pi), n, n)
         self.V = fen.FunctionSpace(mesh, "P", 3)
         
-        import sympy as sp
-        x, y = sp.symbols('x[0] x[1]', real=True)
-        wex = 16/np.pi**4 * x * y * (x - np.pi) * (y - np.pi)
-        phiex = kappa * (x * np.cos(theta) + y * np.sin(theta))
-        uex = wex * sp.exp(-1.j * phiex)
-        fex = - uex.diff(x, 2) - uex.diff(y, 2) - kappa**2 * uex
-        forcingTerm = [sp.printing.ccode(sp.simplify(sp.re(fex))),
-                       sp.printing.ccode(sp.simplify(sp.im(fex)))]
-        self.forcingTerm = [fen.Expression(x, degree = 3) for x in forcingTerm]
+        c, s = np.cos(theta), np.sin(theta)
+        x, y = fen.SpatialCoordinate(mesh)[:]
+        C = 16. / pi ** 4.
+        bR = C * 2 * (x * (pi - x) + y * (pi - y))
+        bI = C * 2 * kappa * (c * (pi - 2 * x) * y * (pi - y)
+                            + s * x * (pi - x) * (pi - 2 * y))
+        wR = fen.cos(kappa * (c * x + s * y))
+        wI = fen.sin(kappa * (c * x + s * y))
+        self.forcingTerm = [bR * wR + bI * wI, bI * wR - bR * wI]
         
diff --git a/rrompy/hfengines/scipy/helmholtz_square_transmission_problem_engine.py b/rrompy/hfengines/scipy/helmholtz_square_transmission_problem_engine.py
index fbcca0f..dc5cce5 100644
--- a/rrompy/hfengines/scipy/helmholtz_square_transmission_problem_engine.py
+++ b/rrompy/hfengines/scipy/helmholtz_square_transmission_problem_engine.py
@@ -1,62 +1,78 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 import fenics as fen
-from .helmholtz_problem_engine import HelmholtzProblemEngine
+import ufl
+from rrompy.hfengines.base.helmholtz_problem_engine import (
+                                                        HelmholtzProblemEngine)
 
 __all__ = ['HelmholtzSquareTransmissionProblemEngine']
 
 class HelmholtzSquareTransmissionProblemEngine(HelmholtzProblemEngine):
     """
     Solver for square transmission Helmholtz problems with parametric
         wavenumber.
         - \Delta u - omega^2 * n^2 * u = 0 in \Omega
         u = 0                              on \Gamma_D
         with exact solution a transmitted plane wave.
     """
-    def __init__(self, nT:float, nB:float, kappa:float, theta:float, n:int):
-        super().__init__()
+    def __init__(self, nT:float, nB:float, kappa:float, theta:float, n:int,
+                 degree_threshold : int = np.inf, verbosity : int = 10):
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
         
         self.omega = kappa
         
         mesh = fen.RectangleMesh(fen.Point(-np.pi/2, -np.pi/2),
                                  fen.Point(np.pi/2, np.pi/2), n, n)
         self.V = fen.FunctionSpace(mesh, "P", 3)
         
-        import sympy as sp    
         dx, dy = np.cos(theta), np.sin(theta)
         Kx = kappa * nB * dx
         Ky = kappa * (nT**2. - (nB * dx)**2. + 0.j)**.5
         T = 2 * kappa * nB * dy / (Ky + kappa * nB * dy)
-        x, y = sp.symbols('x[0] x[1]', real=True)
-        uT = T * sp.exp(1.j * (Kx*x + Ky*y))
-        uB = (          sp.exp(1.j * kappa * nB * (dx*x + dy*y))
-            + (T - 1) * sp.exp(1.j * kappa * nB * (dx*x - dy*y)))
-        uRe = fen.Expression('x[1]>=0 ? {} : {}'.format(
-                                                 sp.printing.ccode(sp.re(uT)),
-                                                 sp.printing.ccode(sp.re(uB))),
-                                                 degree = 3)
-        uIm = fen.Expression('x[1]>=0 ? {} : {}'.format(
-                                                 sp.printing.ccode(sp.im(uT)),
-                                                 sp.printing.ccode(sp.im(uB))),
-                                                 degree = 3)
 
-        self.refractionIndex = fen.Expression('x[1] >= 0 ? nT : nB',
-                                              nT = nT, nB = nB, degree = 0)
-        self.DirichletDatum = [uRe, uIm]
+        x, y = fen.SpatialCoordinate(mesh)[:]
+        TR, TI = np.real(T), np.imag(T)
+        if np.isclose(np.imag(Ky), 0.):
+            u0RT = (TR * fen.cos(Kx * x + np.real(Ky) * y)
+                  - TI * fen.sin(Kx * x + np.real(Ky) * y))
+            u0IT = (TR * fen.sin(Kx * x + np.real(Ky) * y)
+                  + TI * fen.cos(Kx * x + np.real(Ky) * y))
+        else:
+            u0RT = fen.exp(- np.imag(Ky) * y) * (TR * fen.cos(Kx * x)
+                                               - TI * fen.sin(Kx * x))
+            u0IT = fen.exp(- np.imag(Ky) * y) * (TR * fen.sin(Kx * x)
+                                               + TI * fen.cos(Kx * x))
+        u0RB = (fen.cos(kappa * nB * (dx * x + dy * y))
+              + (TR - 1) * fen.cos(kappa * nB * (dx*x - dy*y))
+              - TI * fen.sin(kappa * nB * (dx*x - dy*y)))
+        u0IB = (fen.sin(kappa * nB * (dx * x + dy * y))
+              + (TR - 1) * fen.sin(kappa * nB * (dx*x - dy*y))
+              + TI * fen.cos(kappa * nB * (dx*x - dy*y)))
+        u0R = ufl.conditional(ufl.ge(y, 0.), u0RT, u0RB)
+        u0I = ufl.conditional(ufl.ge(y, 0.), u0IT, u0IB)
+        self.refractionIndex = ufl.conditional(ufl.ge(y, 0.),
+                                               fen.Constant(nT),
+                                               fen.Constant(nB))
+        self.DirichletDatum = [u0R, u0I]
+        
+
+
+
diff --git a/rrompy/hfengines/scipy/laplace_disk_gaussian.py b/rrompy/hfengines/scipy/laplace_disk_gaussian.py
new file mode 100644
index 0000000..277fe8d
--- /dev/null
+++ b/rrompy/hfengines/scipy/laplace_disk_gaussian.py
@@ -0,0 +1,150 @@
+# Copyright (C) 2018 by the RROMPy authors
+#
+# This file is part of RROMPy.
+#
+# RROMPy is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# RROMPy is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import numpy as np
+import fenics as fen
+from rrompy.utilities.base.types import Np1D, Tuple, List, FenExpr
+from rrompy.hfengines.base.laplace_base_problem_engine import (
+                                                      LaplaceBaseProblemEngine)
+from rrompy.utilities.base.fenics import fenZERO, fenONE
+from rrompy.utilities.base import verbosityDepth
+
+__all__ = ['LaplaceDiskGaussian']
+
+class LaplaceDiskGaussian(LaplaceBaseProblemEngine):
+    """
+    Solver for disk Laplace problems with parametric forcing term center.
+        - \Delta u = C exp(-.5 * ||\cdot - (mu, 0)||^2) in \Omega = B(0, 5)
+        u = 0                                           on \partial\Omega.
+    """
+    
+    nbs = 20
+
+    def __init__(self, n:int, degree_threshold : int = np.inf,
+                 verbosity : int = 10):
+        super().__init__(degree_threshold = degree_threshold,
+                         verbosity = verbosity)
+        self.computebsFactors()
+        self.forcingTermMu = np.nan
+        
+        import mshr
+        mesh = mshr.generate_mesh(mshr.Circle(fen.Point(0., 0.), 5.), n)
+        self.V = fen.FunctionSpace(mesh, "P", 3)
+        
+    def getForcingTerm(self, mu:complex) -> Tuple[FenExpr, FenExpr]:
+        """Compute forcing term."""
+        if not np.isclose(mu, self.forcingTermMu):
+            if self.verbosity >= 25:
+                verbosityDepth("INIT",
+                               "Assembling base expression for forcing term.",
+                               end = "")
+            x, y = fen.SpatialCoordinate(self.V.mesh())[:]
+            C = np.exp(-.5 * mu ** 2.)
+            CR, CI = np.real(C), np.imag(C)
+            f0 = (2 * np.pi) ** -.5 * fen.exp(-.5 * (x ** 2. + y ** 2.))
+            muR, muI = np.real(mu), np.imag(mu)
+            f1R = fen.exp(muR * x) * fen.cos(muI * x)
+            f1I = fen.exp(muR * x) * fen.sin(muI * x)
+            self.forcingTerm = [f0 * (CR * f1R - CI * f1I), 
+                                f0 * (CR * f1I + CI * f1R)]
+            self.forcingTermMu = mu
+            if self.verbosity >= 25:
+                verbosityDepth("DEL", " Done.", inline = True)
+        return self.forcingTerm
+    
+    def computebsFactors(self):
+        self.bsFactors = np.zeros((self.nbs, self.nbs), dtype = float)
+        self.bsFactors[0, 0] = 1.
+        self.bsFactors[1, 1] = 1.
+        for j in range(2, self.nbs):
+            l = (j + 1) % 2 + 1
+            J = np.arange(l, j + 1, 2)
+            self.bsFactors[j, J] = self.bsFactors[j - 1, J - 1]
+            if l == 2:
+                l = 0
+            J = np.arange(l, j, 2)
+            self.bsFactors[j, J] += np.multiply(- 1 - J,
+                                                self.bsFactors[j - 1, J + 1])
+            self.bsFactors[j, l : j + 2 : 2] /= j
+    
+    def getExtraFactorB(self, mu:complex, der:int) -> Tuple[FenExpr, FenExpr]:
+        """Compute extra expression in RHS."""
+        if self.verbosity >= 25:
+            verbosityDepth("INIT", ("Assembling auxiliary expression for "
+                                    "forcing term derivative."), end = "")
+        muR, muI = np.real(mu), np.imag(mu)
+        x = fen.SpatialCoordinate(self.V.mesh())[0]
+        l = der % 2
+        if l == 0:
+            powR, powI = fenONE, fenZERO
+        else:
+            powR, powI = x - muR, fen.Constant(muI)
+        exprR, exprI = [self.bsFactors[der, l] * k for k in [powR, powI]]
+        for j in range(l + 2, der + 1, 2):
+            for _ in range(2):
+                powR, powI = (powR * (x - muR) - powI * muI,
+                              powR * muI + powI * (x - muR))
+            exprR += self.bsFactors[der, j] * powR
+            exprI += self.bsFactors[der, j] * powI
+        if self.verbosity >= 25:
+            verbosityDepth("DEL", " Done.", inline = True)
+        return[exprR, exprI]
+
+    def b(self, mu:complex, der : int = 0,
+          homogeneized : bool = False) -> Np1D:
+        """Assemble (derivative of) RHS of linear system."""
+        bnull = self.checkbInBounds(der, homogeneized)
+        if bnull is not None: return bnull
+        if homogeneized and not np.isclose(self.mu0BC, mu):
+            self.u0BC = self.liftDirichletData(mu)
+        if not np.isclose(self.bsmu, mu):
+            self.bsmu = mu
+            self.resetbs()
+        if self.bs[homogeneized][der] is None:
+            if self.verbosity >= 20:
+                verbosityDepth("INIT",
+                               "Assembling forcing term b{}.".format(der))
+            if der < self.nbs:
+                fRe, fIm = self.getForcingTerm(mu)
+                cRe, cIm = self.getExtraFactorB(mu, der)
+                cfRe = cRe * fRe - cIm * fIm
+                cfIm = cRe * fIm + cIm * fRe
+            else:
+                cfRe, cfIm = fenZERO, fenZERO
+            parsRe = self.iterReduceQuadratureDegree(zip([cfRe],
+                                         ["forcingTermDer{}Real".format(der)]))
+            parsIm = self.iterReduceQuadratureDegree(zip([cfIm],
+                                         ["forcingTermDer{}Imag".format(der)]))
+            L0Re = fen.dot(cfRe, self.v) * fen.dx
+            L0Im = fen.dot(cfIm, self.v) * fen.dx
+            b0Re = fen.assemble(L0Re, form_compiler_parameters = parsRe)
+            b0Im = fen.assemble(L0Im, form_compiler_parameters = parsIm)
+            if homogeneized:
+                Ader = self.A(mu, der)
+                b0Re[:] -= np.real(Ader.dot(self.u0BC))
+                b0Im[:] -= np.imag(Ader.dot(self.u0BC))
+            DirichletBC0 = fen.DirichletBC(self.V, fenZERO,
+                                           self.DirichletBoundary)
+            DirichletBC0.apply(b0Re)
+            DirichletBC0.apply(b0Im)
+            self.bs[homogeneized][der] = np.array(b0Re[:]
+                                          + 1.j * b0Im[:], dtype = np.complex)
+            if self.verbosity >= 20:
+                verbosityDepth("DEL", "Done assembling forcing term.")
+        return self.bs[homogeneized][der]
+
diff --git a/rrompy/reduction_methods/base/__init__.py b/rrompy/reduction_methods/base/__init__.py
index 1c37f64..fdc4ada 100644
--- a/rrompy/reduction_methods/base/__init__.py
+++ b/rrompy/reduction_methods/base/__init__.py
@@ -1,25 +1,25 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.reduction_methods.base.generic_approximant import GenericApproximant
+from .generic_approximant import GenericApproximant
 
 __all__ = [
         'GenericApproximant'
           ]
 
 
diff --git a/rrompy/reduction_methods/base/generic_approximant.py b/rrompy/reduction_methods/base/generic_approximant.py
index 64e2624..924764e 100644
--- a/rrompy/reduction_methods/base/generic_approximant.py
+++ b/rrompy/reduction_methods/base/generic_approximant.py
@@ -1,384 +1,499 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from abc import abstractmethod
 import numpy as np
 from copy import copy
 from rrompy.sampling.base.sampling_engine_base import SamplingEngineBase
-from rrompy.utilities.base.types import Np1D, HS1D, DictAny, HFEng, strLst
+from rrompy.utilities.base.types import Np1D, DictAny, HFEng, sampleEng, strLst
 from rrompy.utilities.base import purgeDict, verbosityDepth
 
 __all__ = ['GenericApproximant']
 
 class GenericApproximant:
     """
     ABSTRACT
     ROM approximant computation for parametric problems.
     
     Args:
         HFEngine: HF problem solver.
         mu0(optional): Default parameter. Defaults to 0.
         approxParameters(optional): Dictionary containing values for main
             parameters of approximant. Recognized keys are:
             - 'POD': whether to compute POD of snapshots; defaults to True.
             Defaults to empty dict.
         verbosity(optional): Verbosity level. Defaults to 10.
 
     Attributes:
         HFEngine: HF problem solver.
         mu0: Default parameter.
         w: Weight for norm computation.
         approxParameters: Dictionary containing values for main parameters of
             approximant. Recognized keys are in parameterList.
         parameterList: Recognized keys of approximant parameters:
             - 'POD': whether to compute POD of snapshots.
         verbosity: Verbosity level.
         POD: Whether to compute POD of snapshots.
         samplingEngine: Sampling engine.
         uHF: High fidelity solution with wavenumber lastSolvedHF as numpy
             complex vector.
         lastSolvedHF: Wavenumber corresponding to last computed high fidelity
             solution.
-        solLifting: Lifting of Dirichlet boundary data as numpy vector.
         uApp: Last evaluated approximant as numpy complex vector.
         lastApproxParameters: List of parameters corresponding to last
             computed approximant.
     """
 
     def __init__(self, HFEngine:HFEng, mu0 : complex = 0,
-                 approxParameters : DictAny = {}, verbosity : int = 10):
+                 approxParameters : DictAny = {}, homogeneize : bool = False,
+                 verbosity : int = 10):
         self._preInit()
         self.verbosity = verbosity
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT", ("Initializing approximant engine of "
                                     "type {}.").format(self.name()))
         self.HFEngine = HFEngine
         self._HFEngine0 = copy(HFEngine)
         if not hasattr(self, "parameterList"):
             self.parameterList = []
         self.parameterList += ["POD"]
 
-        self.solLifting = self.HFEngine.liftDirichletData()
         self.mu0 = mu0
+        self.homogeneize = homogeneize
         self.approxParameters = approxParameters
         self._postInit()
 
     def _preInit(self):
         if not hasattr(self, "depth"): self.depth = 0
         else: self.depth += 1
 
     def _postInit(self):
         if self.depth == 0:
-            if self.verbosity >= 5:
+            if self.verbosity >= 10:
                 verbosityDepth("DEL", "Done initializing.\n")
             del self.depth
         else: self.depth -= 1
 
     def name(self) -> str:
         return self.__class__.__name__
         
     def __str__(self) -> str:
         return self.name()
 
-    def setupSampling(self):
+    def setupSampling(self, SamplingEngine : sampleEng = SamplingEngineBase):
         """Setup sampling engine."""
-        self.samplingEngine = SamplingEngineBase(self.HFEngine,
-                                                 verbosity = self.verbosity)
+        self.samplingEngine = SamplingEngine(self.HFEngine,
+                                             verbosity = self.verbosity)
 
     @property
     def approxParameters(self):
         """Value of approximant parameters."""
         return self._approxParameters
     @approxParameters.setter
     def approxParameters(self, approxParams):
         if not hasattr(self, "approxParameters"):
             self._approxParameters = {}
         approxParameters = purgeDict(approxParams, self.parameterList,
                                   dictname = self.name() + ".approxParameters",
                                   baselevel = 1)
         keyList = list(approxParameters.keys())
         if "POD" in keyList:
             self.POD = approxParameters["POD"]
         elif hasattr(self, "POD"):
             self.POD = self.POD
         else:
             self.POD = True
 
     @property
     def POD(self):
         """Value of POD."""
         return self._POD
     @POD.setter
     def POD(self, POD):
         if hasattr(self, "POD"): PODold = self.POD
         else: PODold = -1
         self._POD = POD
         self._approxParameters["POD"] = self.POD
         if PODold != self.POD:
             self.setupSampling()
             self.resetSamples()
 
+    @property
+    def homogeneize(self):
+        """Value of homogeneize."""
+        return self._homogeneize
+    @homogeneize.setter
+    def homogeneize(self, homogeneize):
+        if not hasattr(self, "_homogeneize"):
+            self._homogeneize = None
+        if homogeneize != self.homogeneize:
+            self._homogeneize = homogeneize
+            self.resetSamples()
+
     def solveHF(self, mu : complex = None):
         """
         Find high fidelity solution with original parameters and arbitrary
             parameter.
 
         Args:
             mu: Target parameter.
         """
         if mu is None: mu = self.mu0
         if (not hasattr(self, "lastSolvedHF")
          or not np.isclose(self.lastSolvedHF, mu)):
-            self.uHF = self.samplingEngine.solveLS(mu)
+            self.uHF = self.samplingEngine.solveLS(mu,
+                                               homogeneized = self.homogeneize)
             self.lastSolvedHF = mu
 
     def resetSamples(self):
         """Reset samples."""
         if hasattr(self, "samplingEngine"):
             self.samplingEngine.resetHistory()
         else:
             self.setupSampling()
 
-    def plotSamples(self, name : str = "u", save : bool = False,
-                    what : strLst = 'all', **figspecs):
+    def plotSamples(self, name : str = "u", save : str = None,
+                    what : strLst = 'all', saveFormat : str = "eps",
+                    saveDPI : int = 100, **figspecs):
         """
         Do some nice plots of the samples.
 
         Args:
             name(optional): Name to be shown as title of the plots. Defaults to
                 'u'.
             what(optional): Which plots to do. If list, can contain 'ABS',
                 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
                 Defaults to 'ALL'.
-            save(optional): Whether to save plot(s). Defaults to False.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
             figspecs(optional key args): Optional arguments for matplotlib
                 figure creation.
         """
         self.samplingEngine.plotSamples(name = name, save = save, what = what,
+                                        saveFormat = saveFormat,
+                                        saveDPI = saveDPI,
                                         **figspecs)
         
     @abstractmethod
     def setupApprox(self):
         """
         Setup approximant. (ABSTRACT)
 
         Any specialization should include something like
             self.computeDerivatives()
             if not self.checkComputedApprox():
                 ...
                 self.lastApproxParameters = copy(self.approxParameters)
         """
         pass
 
     def checkComputedApprox(self) -> bool:
         """
         Check if setup of new approximant is not needed.
 
         Returns:
             True if new setup is not needed. False otherwise.
         """
         return (hasattr(self, "lastApproxParameters")
             and self.approxParameters == self.lastApproxParameters)
 
     @abstractmethod
     def evalApprox(self, mu:complex):
         """
         Evaluate approximant at arbitrary parameter. (ABSTRACT)
 
         Any specialization should include something like
             self.setupApprox()
             self.uApp = ...
 
         Args:
             mu: Target parameter.
         """
         pass
 
-    def getHF(self, mu:complex) -> HS1D:
+    def getHF(self, mu:complex, homogeneized : bool = False) -> Np1D:
         """
         Get HF solution at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             HFsolution.
         """
         self.solveHF(mu)
+        if self.homogeneize and not homogeneized:
+            return self.uHF + self.HFEngine.liftDirichletData(mu)
+        if not self.homogeneize and homogeneized:
+            return self.uHF - self.HFEngine.liftDirichletData(mu)
         return self.uHF
 
-    def getRHS(self, mu:complex) -> HS1D:
+    def getRHS(self, mu:complex, homogeneized : bool = False) -> Np1D:
         """
         Get linear system RHS at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Linear system RHS.
         """
-        return self.HFEngine.residual(None, mu)
+        return self.HFEngine.residual(None, mu, homogeneized = homogeneized)
 
-    def getApp(self, mu:complex) -> HS1D:
+    def getApp(self, mu:complex, homogeneized : bool = False) -> Np1D:
         """
         Get approximant at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Approximant.
         """
         self.evalApprox(mu)
+        if self.homogeneize and not homogeneized:
+            return self.uApp + self.HFEngine.liftDirichletData(mu)
+        if not self.homogeneize and homogeneized:
+            return self.uApp - self.HFEngine.liftDirichletData(mu)
         return self.uApp
 
-    def getRes(self, mu:complex) -> HS1D:
+    def getRes(self, mu:complex, homogeneized : bool = False) -> Np1D:
         """
         Get residual at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Approximant residual.
         """
-        return self.HFEngine.residual(self.getApp(mu), mu)
+        return self.HFEngine.residual(self.getApp(mu, homogeneized), mu,
+                                      homogeneized = homogeneized)
 
-    def getErr(self, mu:complex) -> HS1D:
+    def getErr(self, mu:complex, homogeneized : bool = False) -> Np1D:
         """
         Get error at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Approximant error.
         """
-        return self.getApp(mu) - self.getHF(mu)
+        return self.getApp(mu, homogeneized) - self.getHF(mu, homogeneized)
 
     @abstractmethod
     def getPoles(self) -> Np1D:
         """
         Obtain approximant poles.
 
         Returns:
             Numpy complex vector of poles.
         """
         pass
 
-    def normHF(self, mu:complex) -> float:
+    def normHF(self, mu:complex, homogeneized : bool = False) -> float:
         """
         Compute norm of HF solution at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Target norm of HFsolution.
         """
-        return self.HFEngine.norm(self.getHF(mu))
+        return self.HFEngine.norm(self.getHF(mu, homogeneized))
 
-    def normRHS(self, mu:complex) -> HS1D:
+    def normRHS(self, mu:complex, homogeneized : bool = False) -> Np1D:
         """
         Compute norm of linear system RHS at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Norm of linear system RHS.
         """
-        return self.HFEngine.norm(self.getRHS(mu))
+        return self.HFEngine.norm(self.getRHS(mu, homogeneized))
 
-    def normApp(self, mu:complex) -> float:
+    def normApp(self, mu:complex, homogeneized : bool = False) -> float:
         """
         Compute norm of (translated) approximant at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Target norm of approximant.
         """
-        return self.HFEngine.norm(self.getApp(mu))
+        return self.HFEngine.norm(self.getApp(mu, homogeneized))
 
-    def normRes(self, mu:complex) -> float:
+    def normRes(self, mu:complex, homogeneized : bool = False) -> float:
         """
         Compute norm of approximant residual at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Target norm of (A(mu)app(mu) - f(mu)).
         """
-        return self.HFEngine.norm(self.getRes(mu))
+        return self.HFEngine.norm(self.getRes(mu, homogeneized))
 
-    def normErr(self, mu:complex) -> float:
+    def normErr(self, mu:complex, homogeneized : bool = False) -> float:
         """
         Compute norm of approximant error at arbitrary parameter.
 
         Args:
             mu: Target parameter.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
 
         Returns:
             Target norm of (approximant - HFsolution).
         """
-        return self.HFEngine.norm(self.getErr(mu))
+        return self.HFEngine.norm(self.getErr(mu, homogeneized))
 
-    def plotHF(self, mu:complex, name : str = "u", **figspecs):
+    def plotHF(self, mu:complex, name : str = "uHF", save : str = None,
+               what : strLst = 'all', saveFormat : str = "eps",
+               saveDPI : int = 100, homogeneized : bool = False, **figspecs):
         """
         Do some nice plots of the HF solution at arbitrary parameter.
 
         Args:
             mu: Target parameter.
             name(optional): Name to be shown as title of the plots. Defaults to
                 'u'.
+            what(optional): Which plots to do. If list, can contain 'ABS',
+                'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
+                Defaults to 'ALL'.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
             figspecs(optional key args): Optional arguments for matplotlib
                 figure creation.
         """
-        uHF = self.getHF(mu)
-        self.HFEngine.plot(uHF, name = name, **figspecs)
+        uHF = self.getHF(mu, homogeneized)
+        self.HFEngine.plot(uHF, name = name, save = save, what = what,
+                           saveFormat = saveFormat, saveDPI = saveDPI,
+                           **figspecs)
 
-    def plotApp(self, mu:complex, name : str = "u", **figspecs):
+    def plotApp(self, mu:complex, name : str = "uApp", save : str = None,
+                what : strLst = 'all', saveFormat : str = "eps",
+                saveDPI : int = 100, homogeneized : bool = False, **figspecs):
         """
         Do some nice plots of approximant at arbitrary parameter.
 
         Args:
             mu: Target parameter.
             name(optional): Name to be shown as title of the plots. Defaults to
                 'u'.
+            what(optional): Which plots to do. If list, can contain 'ABS',
+                'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
+                Defaults to 'ALL'.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
+            figspecs(optional key args): Optional arguments for matplotlib
+                figure creation.
+        """
+        uApp = self.getApp(mu, homogeneized)
+        self.HFEngine.plot(uApp, name = name, save = save, what = what,
+                           saveFormat = saveFormat, saveDPI = saveDPI,
+                           **figspecs)
+
+    def plotRes(self, mu:complex, name : str = "res", save : str = None,
+                what : strLst = 'all', saveFormat : str = "eps",
+                saveDPI : int = 100, homogeneized : bool = False, **figspecs):
+        """
+        Do some nice plots of approximation residual at arbitrary parameter.
+
+        Args:
+            mu: Target parameter.
+            name(optional): Name to be shown as title of the plots. Defaults to
+                'u'.
+            what(optional): Which plots to do. If list, can contain 'ABS',
+                'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
+                Defaults to 'ALL'.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
             figspecs(optional key args): Optional arguments for matplotlib
                 figure creation.
         """
-        uApp = self.getApp(mu)
-        self.HFEngine.plot(uApp, name = name, **figspecs)
+        uRes = self.getRes(mu, homogeneized)
+        self.HFEngine.plot(uRes, name = name, save = save, what = what,
+                           saveFormat = saveFormat, saveDPI = saveDPI,
+                           **figspecs)
 
-    def plotErr(self, mu:complex, name : str = "u", **figspecs):
+    def plotErr(self, mu:complex, name : str = "err", save : str = None,
+                what : strLst = 'all', saveFormat : str = "eps",
+                saveDPI : int = 100, homogeneized : bool = False, **figspecs):
         """
         Do some nice plots of approximation error at arbitrary parameter.
 
         Args:
             mu: Target parameter.
             name(optional): Name to be shown as title of the plots. Defaults to
                 'u'.
+            what(optional): Which plots to do. If list, can contain 'ABS',
+                'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
+                Defaults to 'ALL'.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
+            homogeneized(optional): Whether to remove Dirichlet BC. Defaults to
+                False.
             figspecs(optional key args): Optional arguments for matplotlib
                 figure creation.
         """
-        uErr = self.getErr(mu)
-        self.HFEngine.plot(uErr, name = name, **figspecs)
+        uErr = self.getErr(mu, homogeneized)
+        self.HFEngine.plot(uErr, name = name, save = save, what = what,
+                           saveFormat = saveFormat, saveDPI = saveDPI,
+                           **figspecs)
+
diff --git a/rrompy/reduction_methods/lagrange/__init__.py b/rrompy/reduction_methods/lagrange/__init__.py
index 24a3521..822bd2a 100644
--- a/rrompy/reduction_methods/lagrange/__init__.py
+++ b/rrompy/reduction_methods/lagrange/__init__.py
@@ -1,29 +1,29 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.reduction_methods.lagrange.generic_approximant_lagrange import GenericApproximantLagrange
-from rrompy.reduction_methods.lagrange.approximant_lagrange_pade import ApproximantLagrangePade
-from rrompy.reduction_methods.lagrange.approximant_lagrange_rb import ApproximantLagrangeRB
+from .generic_approximant_lagrange import GenericApproximantLagrange
+from .approximant_lagrange_pade import ApproximantLagrangePade
+from .approximant_lagrange_rb import ApproximantLagrangeRB
 
 __all__ = [
         'GenericApproximantLagrange',
         'ApproximantLagrangePade',
         'ApproximantLagrangeRB'
           ]
 
 
diff --git a/rrompy/reduction_methods/lagrange/approximant_lagrange_pade.py b/rrompy/reduction_methods/lagrange/approximant_lagrange_pade.py
index b3d7cda..438501f 100644
--- a/rrompy/reduction_methods/lagrange/approximant_lagrange_pade.py
+++ b/rrompy/reduction_methods/lagrange/approximant_lagrange_pade.py
@@ -1,365 +1,358 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from copy import copy
-import warnings
 import numpy as np
-from rrompy.reduction_methods.lagrange.generic_approximant_lagrange import (
-                                                    GenericApproximantLagrange)
+from .generic_approximant_lagrange import GenericApproximantLagrange
 from rrompy.utilities.base.types import Np1D, DictAny, HFEng
 from rrompy.utilities.base import purgeDict, verbosityDepth
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['ApproximantLagrangePade']
 
 class ApproximantLagrangePade(GenericApproximantLagrange):
     """
     ROM Lagrange Pade' interpolant computation for parametric problems.
 
     Args:
         HFEngine: HF problem solver.
         mu0(optional): Default parameter. Defaults to 0.
         approxParameters(optional): Dictionary containing values for main
             parameters of approximant. Recognized keys are:
             - 'POD': whether to compute POD of snapshots; defaults to True;
             - 'S': total number of samples current approximant relies upon;
                 defaults to 2;
             - 'sampler': sample point generator; defaults to uniform sampler on
                 [0, 1];
             - 'M': degree of Pade' interpolant numerator; defaults to 0;
             - 'N': degree of Pade' interpolant denominator; defaults to 0.
             Defaults to empty dict.
             
     Attributes:
         HFEngine: HF problem solver.
         mu0: Default parameter.
         mus: Array of snapshot parameters.
         ws: Array of snapshot weigths.
         approxParameters: Dictionary containing values for main parameters of
             approximant. Recognized keys are in parameterList.
         parameterList: Recognized keys of approximant parameters:
             - 'POD': whether to compute POD of snapshots; 
             - 'S': total number of samples current approximant relies upon;
             - 'sampler': sample point generator;
             - 'M': degree of Pade' interpolant numerator;
             - 'N': degree of Pade' interpolant denominator;
             - 'robustTol': tolerance for robust Pade' denominator management.
         extraApproxParameters: List of approxParameters keys in addition to
             mother class's.
         S: Number of solution snapshots over which current approximant is
             based upon.
         sampler: Sample point generator.
         M: Numerator degree of approximant.
         N: Denominator degree of approximant.
         POD: Whether to compute POD of snapshots.
         robustTol: Tolerance for robust Pade' denominator management.
         samplingEngine: Sampling engine.
         uHF: High fidelity solution with wavenumber lastSolvedHF as numpy
             complex vector.
         lastSolvedHF: Wavenumber corresponding to last computed high fidelity
             solution.
-        solLifting: Lifting of Dirichlet boundary data as numpy vector.
         Q: Numpy 1D vector containing complex coefficients of approximant
             denominator.
         P: Numpy 2D vector whose columns are FE dofs of coefficients of
             approximant numerator.
         uApp: Last evaluated approximant as numpy complex vector.
         lastApproxParameters: List of parameters corresponding to last
             computed approximant.
     """
     
     def __init__(self, HFEngine:HFEng, mu0 : complex = 0.,
-                 approxParameters : DictAny = {}, verbosity : int = 10):
+                 approxParameters : DictAny = {}, homogeneize : bool = False,
+                 verbosity : int = 10):
         self._preInit()
         if not hasattr(self, "parameterList"):
             self.parameterList = []
         self.parameterList += ["M", "N", "robustTol"]
         super().__init__(HFEngine = HFEngine, mu0 = mu0,
                          approxParameters = approxParameters,
+                         homogeneize = homogeneize,
                          verbosity = verbosity)
         self._postInit()
 
     @property
     def approxParameters(self):
         """
         Value of approximant parameters. Its assignment may change M, N and S.
         """
         return self._approxParameters
     @approxParameters.setter
     def approxParameters(self, approxParams):
         approxParameters = purgeDict(approxParams, self.parameterList,
                                   dictname = self.name() + ".approxParameters",
                                   baselevel = 1)
         approxParametersCopy = purgeDict(approxParameters, ["M", "N"],
                                          True, True, baselevel = 1)
         GenericApproximantLagrange.approxParameters.fset(self,
                                                          approxParametersCopy)
         keyList = list(approxParameters.keys())
         if "robustTol" in keyList:
             self.robustTol = approxParameters["robustTol"]
         elif hasattr(self, "robustTol"):
             self.robustTol = self.robustTol
         else:
             self.robustTol = 0
         if "M" in keyList:
             self.M = approxParameters["M"]
         elif hasattr(self, "M"):
             self.M = self.M
         else:
             self.M = 0
         if "N" in keyList:
             self.N = approxParameters["N"]
         elif hasattr(self, "N"):
             self.N = self.N
         else:
             self.N = 0
 
     @property
     def M(self):
         """Value of M. Its assignment may change S."""
         return self._M
     @M.setter
     def M(self, M):
         if M < 0: raise ArithmeticError("M must be non-negative.")
         self._M = M
         self._approxParameters["M"] = self.M
         if hasattr(self, "S") and self.S < self.M + 1:
-            warnings.warn("Prescribed S is too small. Updating S to M + 1.",
-                          stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Prescribed S is too small. Updating S to M + 1.")
             self.S = self.M + 1
 
     @property
     def N(self):
         """Value of N. Its assignment may change S."""
         return self._N
     @N.setter
     def N(self, N):
         if N < 0: raise ArithmeticError("N must be non-negative.")
         self._N = N
         self._approxParameters["N"] = self.N
         if hasattr(self, "S") and self.S < self.N + 1:
-            warnings.warn("Prescribed S is too small. Updating S to N + 1.",
-                          stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Prescribed S is too small. Updating S to N + 1.")
             self.S = self.N + 1
 
     @property
     def robustTol(self):
         """Value of tolerance for robust Pade' denominator management."""
         return self._robustTol
     @robustTol.setter
     def robustTol(self, robustTol):
         if robustTol < 0.:
-            warnings.warn(("Overriding prescribed negative robustness "
-                          "tolerance to 0."), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Overriding prescribed negative robustness tolerance to 0.")
             robustTol = 0.
         self._robustTol = robustTol
         self._approxParameters["robustTol"] = self.robustTol
 
     @property
     def S(self):
         """Value of S."""
         return self._S
     @S.setter
     def S(self, S):
         if S <= 0: raise ArithmeticError("S must be positive.")
         if hasattr(self, "S"): Sold = self.S
         else: Sold = -1
         vals, label = [0] * 2, {0:"M", 1:"N"}
         if hasattr(self, "M"): vals[0] = self.M
         if hasattr(self, "N"): vals[1] = self.N
         idxmax = np.argmax(vals)
         if vals[idxmax] + 1 > S:
-            warnings.warn("Prescribed S is too small. Updating S to {} + 1."\
-                          .format(label[idxmax]), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Prescribed S is too small. Updating S to {} + 1."\
+                                                        .format(label[idxmax]))
             self.S = vals[idxmax] + 1
         else:
             self._S = S
             self._approxParameters["S"] = self.S
             if Sold != self.S:
                 self.resetSamples()
 
     def setupApprox(self):
         """
         Compute Pade' interpolant.
         SVD-based robust eigenvalue management.
         """
         if not self.checkComputedApprox():
             if self.verbosity >= 5:
                 verbosityDepth("INIT", "Setting up {}.". format(self.name()))
+            self.computeSnapshots()
+            if self.verbosity >= 7:
                 verbosityDepth("INIT", "Starting computation of denominator.")
             while True:
                 self.computeSnapshots()
                 TN = np.vander(self.radiusPade(self.mus), N = self.N + 1,
                                increasing = True)
                 if self.POD:
                     data = self.samplingEngine.RPOD.T
                 else:
                     data = self.samplingEngine.samples.T
                 RHSFull = np.empty((self.S, data.shape[1] * (self.N + 1)),
                                    dtype = np.complex)
                 for j in range(self.S):
                     RHSFull[j, :] = np.kron(TN[j, :], data[j, :])
                 G = np.polyfit(self.radiusPade(self.mus), RHSFull,
                                deg = self.N, w = self.ws)[0, :].reshape(
                                                  (self.N + 1, data.shape[1])).T
                 if self.POD:
-                    if self.verbosity >= 5:
+                    if self.verbosity >= 7:
                         verbosityDepth("INIT", ("Solving svd for square root "
                                                 "of gramian matrix."),
                                        end = "")
                     _, ev, V = np.linalg.svd(G, full_matrices = False)
                     ev = ev[::-1]
                     eV = V[::-1, :].conj().T
                 else:
-                    if self.verbosity >= 5:
+                    if self.verbosity >= 10:
                         verbosityDepth("INIT", "Building gramian matrix.",
                                        end = "")
                     G2 = self.HFEngine.innerProduct(G, G)
-                    if self.verbosity >= 5:
+                    if self.verbosity >= 10:
                         verbosityDepth("DEL", "Done building gramian.",
                                        inline = True)
+                    if self.verbosity >= 7:
                         verbosityDepth("INIT", ("Solving eigenvalue problem "
                                                 "for gramian matrix."),
                                        end = "")
                     ev, eV = np.linalg.eigh(G2)
-                if self.verbosity >= 5:
+                if self.verbosity >= 7:
                     verbosityDepth("DEL", " Done.", inline = True)
                 ts = self.robustTol * np.linalg.norm(ev)
                 Nnew = np.sum(np.abs(ev) >= ts)
                 diff = self.N - Nnew
                 if diff <= 0: break
                 Snew = self.S - diff
                 Mnew = min(self.M, Snew - 1)
                 if Mnew == self.M:
                     strM = ""
                 else:
                     strM = ", M from {0} to {1},".format(self.M, Mnew)
                 print(("Smallest {0} eigenvalues below tolerance.\n"
                        "Reducing N from {1} to {2}{5} and S from {3} to {4}.")\
                            .format(diff + 1, self.N, Nnew, self.S, Snew, strM))
                 newParameters = {"N" : Nnew, "M" : Mnew, "S" : Snew}
                 self.approxParameters = newParameters
             self.Q = eV[:, 0]
-            if self.verbosity >= 5:
+            if self.verbosity >= 7:
                 verbosityDepth("DEL", "Done computing denominator.")
                 verbosityDepth("INIT", "Starting computation of numerator.")
             TNQ = TN.dot(self.Q).reshape((self.S, 1))
             if self.POD:
                 data = self.samplingEngine.samples.dot(
                                                       self.samplingEngine.RPOD)
             else:
                 data = self.samplingEngine.samples
             RHS = np.multiply(data.T, TNQ)
             self.P = np.polyfit(self.radiusPade(self.mus), RHS, deg = self.M,
                                 w = self.ws)[::-1, :].T
-            if self.verbosity >= 5:
+            if self.verbosity >= 7:
                 verbosityDepth("DEL", "Done computing numerator.")
             self.lastApproxParameters = copy(self.approxParameters)
             if hasattr(self, "lastSolvedApp"): del self.lastSolvedApp
             if self.verbosity >= 5:
                 verbosityDepth("DEL", "Done setting up approximant.\n")
 
     def radiusPade(self, mu:Np1D, mu0 : float = None) -> float:
         """
         Compute translated radius to be plugged into Pade' approximant.
 
         Args:
             mu: Parameter(s) 1.
             mu0: Parameter(s) 2. If None, set to self.mu0.
 
         Returns:
             Translated radius to be plugged into Pade' approximant.
         """
         if mu0 is None: mu0 = self.mu0
         return self.HFEngine.rescaling(mu) - self.HFEngine.rescaling(mu0)
 
     def getPVal(self, mu:complex):
         """
         Evaluate Pade' numerator at arbitrary parameter.
 
         Args:
             mu: Target parameter.
         """
         self.setupApprox()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT",
                            "Evaluating numerator at mu = {}.".format(mu),
                            end = "")
         powerlist = np.power(self.radiusPade(mu), np.arange(self.M + 1))
         p = self.P.dot(powerlist)
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("DEL", " Done.", inline = True)
         return p
 
     def getQVal(self, mu:complex):
         """
         Evaluate Pade' denominator at arbitrary parameter.
 
         Args:
             mu: Target parameter.
         """
         self.setupApprox()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT",
                            "Evaluating denominator at mu = {}.".format(mu),
                            end = "")
         powerlist = np.power(self.radiusPade(mu), np.arange(self.N + 1))
         q = self.Q.dot(powerlist)
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("DEL", " Done.", inline = True)
         return q
 
     def evalApprox(self, mu:complex):
         """
         Evaluate Pade' approximant at arbitrary parameter.
 
         Args:
             mu: Target parameter.
         """
         self.setupApprox()
         if (not hasattr(self, "lastSolvedApp")
          or not np.isclose(self.lastSolvedApp, mu)):
+            if self.verbosity >= 5:
+                verbosityDepth("INIT",
+                               "Evaluating approximant at mu = {}.".format(mu))
             try:
                 self.uApp = self.getPVal(mu) / self.getQVal(mu)
             except:
                 self.uApp = np.empty(self.P.shape[0])
                 self.uApp[:] = np.nan
             self.lastSolvedApp = mu
+            if self.verbosity >= 5:
+                verbosityDepth("DEL", "Done evaluating approximant.")
 
     def getPoles(self) -> Np1D:
         """
         Obtain approximant poles.
         
         Returns:
             Numpy complex vector of poles.
         """
         self.setupApprox()
         return self.HFEngine.rescalingInv(np.roots(self.Q[::-1])
                                         + self.HFEngine.rescaling(self.mu0))
         
diff --git a/rrompy/reduction_methods/lagrange/approximant_lagrange_rb.py b/rrompy/reduction_methods/lagrange/approximant_lagrange_rb.py
index 4ccfff7..cfdc6d2 100644
--- a/rrompy/reduction_methods/lagrange/approximant_lagrange_rb.py
+++ b/rrompy/reduction_methods/lagrange/approximant_lagrange_rb.py
@@ -1,276 +1,282 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from copy import copy
-import warnings
 import numpy as np
 import scipy as sp
-from rrompy.reduction_methods.lagrange.generic_approximant_lagrange import GenericApproximantLagrange
+from .generic_approximant_lagrange import GenericApproximantLagrange
 from rrompy.utilities.base.types import Np1D, DictAny, HFEng
 from rrompy.utilities.base import purgeDict, verbosityDepth
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['ApproximantLagrangeRB']
 
 class ApproximantLagrangeRB(GenericApproximantLagrange):
     """
     ROM RB approximant computation for parametric problems.
 
     Args:
         HFEngine: HF problem solver.
         mu0(optional): Default parameter. Defaults to 0.
         approxParameters(optional): Dictionary containing values for main
             parameters of approximant. Recognized keys are:
             - 'POD': whether to compute POD of snapshots; defaults to True;
             - 'S': total number of samples current approximant relies upon;
                 defaults to 2;
             - 'sampler': sample point generator; defaults to uniform sampler on
                 [0, 1];
             - 'R': rank for Galerkin projection; defaults to S.
             Defaults to empty dict.
             
     Attributes:
         HFEngine: HF problem solver.
         mu0: Default parameter.
         mus: Array of snapshot parameters.
         ws: Array of snapshot weigths (unused).
         approxRadius: Dummy radius of approximant (i.e. distance from mu0 to
             farthest sample point).
         approxParameters: Dictionary containing values for main parameters of
             approximant. Recognized keys are in parameterList.
         parameterList: Recognized keys of approximant parameters:
             - 'POD': whether to compute POD of snapshots; 
             - 'S': total number of samples current approximant relies upon;
             - 'sampler': sample point generator;
             - 'R': rank for Galerkin projection.
         extraApproxParameters: List of approxParameters keys in addition to
             mother class's.
         S: Number of solution snapshots over which current approximant is
             based upon.
         sampler: Sample point generator.
         R: Rank for Galerkin projection.
         POD: Whether to compute POD of snapshots.
         samplingEngine: Sampling engine.
         projMat: Projection matrix for RB system assembly.
         uHF: High fidelity solution with wavenumber lastSolvedHF as numpy
             complex vector.
         lastSolvedHF: Wavenumber corresponding to last computed high fidelity
             solution.
-        solLifting: Lifting of Dirichlet boundary data as numpy vector.
         uApp: Last evaluated approximant as numpy complex vector.
         lastApproxParameters: List of parameters corresponding to last
             computed approximant.
         As: List of sparse matrices (in CSC format) representing coefficients
             of linear system matrix wrt theta(mu).
         bs: List of numpy vectors representing coefficients of linear system
            RHS wrt theta(mu).
         thetaAs: List of callables representing coefficients of linear system
             matrix wrt mu.
         thetabs: List of callables representing coefficients of linear system
             RHS wrt mu.
         ARBs: List of sparse matrices (in CSC format) representing coefficients
             of compressed linear system matrix wrt theta(mu).
         bRBs: List of numpy vectors representing coefficients of compressed 
             linear system RHS wrt theta(mu).
     """
     
     def __init__(self, HFEngine:HFEng, mu0 : complex = 0.,
-                 approxParameters : DictAny = {}, verbosity : int = 10):
+                 approxParameters : DictAny = {}, homogeneize : bool = False,
+                 verbosity : int = 10):
         self._preInit()
         if not hasattr(self, "parameterList"):
             self.parameterList = []
         self.parameterList += ["R"]
         super().__init__(HFEngine = HFEngine, mu0 = mu0,
                          approxParameters = approxParameters,
+                         homogeneize = homogeneize,
                          verbosity = verbosity)
+        if self.verbosity >= 10:
+            verbosityDepth("INIT", "Computing affine blocks of system.")
         self.As, self.thetaAs = self.HFEngine.affineBlocksA(self.mu0)
-        self.bs, self.thetabs = self.HFEngine.affineBlocksb(self.mu0)
+        self.bs, self.thetabs = self.HFEngine.affineBlocksb(self.mu0,
+                                                            self.homogeneize)
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done computing affine blocks.")
         self._postInit()
 
     def resetSamples(self):
         """Reset samples."""
         super().resetSamples()
         self.projMat = None
 
     @property
     def approxParameters(self):
         """
         Value of approximant parameters. Its assignment may change M, N and S.
         """
         return self._approxParameters
     @approxParameters.setter
     def approxParameters(self, approxParams):
         approxParameters = purgeDict(approxParams, self.parameterList,
                                   dictname = self.name() + ".approxParameters",
                                   baselevel = 1)
         approxParametersCopy = purgeDict(approxParameters, ["R"], True, True,
                                          baselevel = 1)
         GenericApproximantLagrange.approxParameters.fset(self,
                                                          approxParametersCopy)
         keyList = list(approxParameters.keys())
         if "R" in keyList:
             self.R = approxParameters["R"]
         elif hasattr(self, "R"):
             self.R = self.R
         else:
             self.R = self.S
 
     @property
     def R(self):
         """Value of R. Its assignment may change S."""
         return self._R
     @R.setter
     def R(self, R):
         if R < 0: raise ArithmeticError("R must be non-negative.")
         self._R = R
         self._approxParameters["R"] = self.R
         if hasattr(self, "S") and self.S < self.R:
-            warnings.warn("Prescribed S is too small. Updating S to R.",
-                          stacklevel = 2)
+            warn("Prescribed S is too small. Updating S to R.")
             self.S = self.R
 
     def checkComputedApprox(self) -> bool:
         """
         Check if setup of new approximant is not needed.
 
         Returns:
             True if new setup is not needed. False otherwise.
         """
         return (self.projMat is not None and super().checkComputedApprox())
 
     def setupApprox(self):
         """Compute RB projection matrix."""
         if not self.checkComputedApprox():
             if self.verbosity >= 5:
                 verbosityDepth("INIT", "Setting up {}.". format(self.name()))
             self.computeSnapshots()
-            if self.verbosity >= 5:
+            if self.verbosity >= 7:
                 verbosityDepth("INIT", "Computing projection matrix.",
                                end = "")
             if self.POD:
                 U, _, _ = np.linalg.svd(self.samplingEngine.RPOD,
                                         full_matrices = False)
                 self.projMat = self.samplingEngine.samples.dot(U[:, : self.R])
             else:
                 self.projMat = self.samplingEngine.samples[:, : self.R]
-            if self.verbosity >= 5:
+            if self.verbosity >= 7:
                 verbosityDepth("DEL", " Done.", inline = True)
             self.lastApproxParameters = copy(self.approxParameters)
             if hasattr(self, "lastSolvedApp"): del self.lastSolvedApp
             self.assembleReducedSystem()
             if self.verbosity >= 5:
                 verbosityDepth("DEL", "Done setting up approximant.\n")
 
     def assembleReducedSystem(self):
         """Build affine blocks of RB linear system through projections."""
         self.setupApprox()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT", "Projecting affine terms of HF model.",
                            end = "")
         projMatH = self.projMat.T.conjugate()
         self.ARBs = [None] * len(self.As)
         self.bRBs = [None] * len(self.bs)
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("MAIN", ".", end = "", inline = True)
         for j in range(len(self.As)):
             self.ARBs[j] = projMatH.dot(self.As[j].dot(self.projMat))
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("MAIN", ".", end = "", inline = True)
         for j in range(len(self.bs)):
             self.bRBs[j] = projMatH.dot(self.bs[j])
-        if self.verbosity >= 5:
-            verbosityDepth("DEL", " Done.", inline = True)
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done.", inline = True)
 
     def solveReducedSystem(self, mu:complex) -> Np1D:
         """
         Solve RB linear system.
 
         Args:
             mu: Target parameter.
 
         Returns:
             Solution of RB linear system.
         """
         self.setupApprox()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT",
                            "Assembling reduced model for mu = {}.".format(mu),
                            end = "")
         ARBmu = self.thetaAs(mu, 0) * self.ARBs[0][:self.R,:self.R]
         bRBmu = self.thetabs(mu, 0) * self.bRBs[0][:self.R]
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("MAIN", ".", end = "", inline = True)
         for j in range(1, len(self.ARBs)):
             ARBmu += self.thetaAs(mu, j) * self.ARBs[j][:self.R, :self.R]
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("MAIN", ".", end = "", inline = True)
         for j in range(1, len(self.bRBs)):
             bRBmu += self.thetabs(mu, j) * self.bRBs[j][:self.R]
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done.", inline = True)
         if self.verbosity >= 5:
-            verbosityDepth("DEL", " Done.", inline = True)
             verbosityDepth("INIT", 
                            "Solving reduced model for mu = {}.".format(mu),
                            end = "")
         uRB = self.projMat[:, :self.R].dot(np.linalg.solve(ARBmu, bRBmu))
         if self.verbosity >= 5:
             verbosityDepth("DEL", " Done.", inline = True)
         return uRB
 
     def evalApprox(self, mu:complex):
         """
         Evaluate RB approximant at arbitrary wavenumber.
 
         Args:
             mu: Target parameter.
         """
         self.setupApprox()
         if (not hasattr(self, "lastSolvedApp")
          or not np.isclose(self.lastSolvedApp, mu)):
+            if self.verbosity >= 5:
+                verbosityDepth("INIT",
+                               "Computing RB solution at mu = {}.".format(mu))
             self.uApp = self.solveReducedSystem(mu)
             self.lastSolvedApp = mu
+            if self.verbosity >= 5:
+                verbosityDepth("DEL", "Done computing RB solution.")
 
     def getPoles(self) -> Np1D:
         """
         Obtain approximant poles.
 
         Returns:
             Numpy complex vector of poles.
         """
-        warnings.warn(("Impossible to compute poles in general affine "
-                       "parameter dependence. Results subject to "
-                       "interpretation/rescaling, or possibly completely "
-                       "wrong."), stacklevel = 2)
+        warn(("Impossible to compute poles in general affine parameter "
+              "dependence. Results subject to interpretation/rescaling, or "
+              "possibly completely wrong."))
         self.setupApprox()
+        if len(self.ARBs) < 2:
+            return
         A = np.eye(self.ARBs[0].shape[0] * (len(self.ARBs) - 1),
                    dtype = np.complex)
         B = np.zeros_like(A)
         A[: self.ARBs[0].shape[0], : self.ARBs[0].shape[0]] = - self.ARBs[0]
         for j in range(len(self.ARBs) - 1):
             Aj = self.ARBs[j + 1]
             B[: Aj.shape[0], j * Aj.shape[0] : (j + 1) * Aj.shape[0]] = Aj
         II = np.arange(self.ARBs[0].shape[0],
                        self.ARBs[0].shape[0] * (len(self.ARBs) - 1))
         B[II, II - self.ARBs[0].shape[0]] = 1.
-        try:
-            return sp.linalg.eigvals(A, B)
-        except:
-            warnings.warn("Generalized eig algorithm did not converge.",
-                          stacklevel = 2)
-            x = np.empty(A.shape[0])
-            x[:] = np.NaN
-            return x
+        return self.HFEngine.rescalingInv(sp.linalg.eigvals(A, B)
+                                        + self.HFEngine.rescaling(self.mu0))
 
diff --git a/rrompy/reduction_methods/lagrange/generic_approximant_lagrange.py b/rrompy/reduction_methods/lagrange/generic_approximant_lagrange.py
index 88bba75..446a6fc 100644
--- a/rrompy/reduction_methods/lagrange/generic_approximant_lagrange.py
+++ b/rrompy/reduction_methods/lagrange/generic_approximant_lagrange.py
@@ -1,199 +1,202 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
-from rrompy.reduction_methods.base.generic_approximant import GenericApproximant
+from rrompy.reduction_methods.base.generic_approximant import (
+                                                            GenericApproximant)
 from rrompy.utilities.base.types import DictAny, HFEng
 from rrompy.utilities.base import purgeDict, verbosityDepth
 
 __all__ = ['GenericApproximantLagrange']
 
 class GenericApproximantLagrange(GenericApproximant):
     """
     ROM Lagrange interpolant computation for parametric problems (ABSTRACT).
 
     Args:
         HFEngine: HF problem solver.
         mu0(optional): Default parameter. Defaults to 0.
         approxParameters(optional): Dictionary containing values for main
             parameters of approximant. Recognized keys are:
             - 'POD': whether to compute POD of snapshots; defaults to True;
             - 'S': total number of samples current approximant relies upon;
             - 'sampler': sample point generator; defaults to uniform sampler on
                 [0, 1].
             Defaults to empty dict.
 
     Attributes:
         HFEngine: HF problem solver.
         mu0: Default parameter.
         mus: Array of snapshot parameters.
         ws: Array of snapshot weigths.
         approxParameters: Dictionary containing values for main parameters of
             approximant. Recognized keys are in parameterList.
         parameterList: Recognized keys of approximant parameters:
             - 'POD': whether to compute POD of snapshots;
             - 'S': total number of snapshots current approximant relies upon;
             - 'sampler': sample point generator.
         extraApproxParameters: List of approxParameters keys in addition to
             mother class's.
         S: Number of solution snapshots over which current approximant is
             based upon.
         sampler: Sample point generator.
         POD: Whether to compute POD of snapshots.
         samplingEngine: Sampling engine.
         uHF: High fidelity solution with wavenumber lastSolvedHF as numpy
             complex vector.
         lastSolvedHF: Wavenumber corresponding to last computed high fidelity
             solution.
-        solLifting: Lifting of Dirichlet boundary data as numpy vector.
         uApp: Last evaluated approximant as numpy complex vector.
         lastApproxParameters: List of parameters corresponding to last
             computed approximant.
     """
 
     def __init__(self, HFEngine:HFEng, mu0 : complex = 0.,
-                 approxParameters : DictAny = {}, verbosity : int = 10):
+                 approxParameters : DictAny = {}, homogeneize : bool = False,
+                 verbosity : int = 10):
         self._preInit()
         if not hasattr(self, "parameterList"):
             self.parameterList = []
         self.parameterList += ["S", "sampler"]
         super().__init__(HFEngine = HFEngine, mu0 = mu0,
                          approxParameters = approxParameters,
+                         homogeneize = homogeneize,
                          verbosity = verbosity)
         self._postInit()
 
     def setupSampling(self):
         """Setup sampling engine."""
         if not hasattr(self, "POD"): return
         if self.POD:
             from rrompy.sampling.scipy.sampling_engine_lagrange_pod import (
-                                   SamplingEngineLagrangePOD as SamplingEngine)
+                                                     SamplingEngineLagrangePOD)
+            super().setupSampling(SamplingEngineLagrangePOD)
         else:
             from rrompy.sampling.scipy.sampling_engine_lagrange import (
-                                      SamplingEngineLagrange as SamplingEngine)
-        self.samplingEngine = SamplingEngine(self.HFEngine,
-                                             verbosity = self.verbosity)
+                                                        SamplingEngineLagrange)
+            super().setupSampling(SamplingEngineLagrange)
 
     @property
     def mus(self):
         """Value of mus. Its assignment may reset snapshots."""
         return self._mus
     @mus.setter
     def mus(self, mus):
         musOld = self.mus if hasattr(self, 'mus') else None
         self._mus = np.array(mus)
         _, musCounts = np.unique(self._mus, return_counts = True)
         if len(np.where(musCounts > 1)[0]) > 0:
             raise Exception("Repeated sample points not allowed.")
         if (musOld is None or len(self.mus) != len(musOld)
             or not np.allclose(self.mus, musOld, 1e-14)):
             self.resetSamples()
             self.autoNode = None
 
     @property
     def approxParameters(self):
         """Value of approximant parameters. Its assignment may change S."""
         return self._approxParameters
     @approxParameters.setter
     def approxParameters(self, approxParams):
         approxParameters = purgeDict(approxParams, self.parameterList,
                                   dictname = self.name() + ".approxParameters",
                                   baselevel = 1)
         approxParametersCopy = purgeDict(approxParameters, ["S", "sampler"],
                                          True, True, baselevel = 1)
         GenericApproximant.approxParameters.fset(self, approxParametersCopy)
         keyList = list(approxParameters.keys())
         if "S" in keyList:
             self.S = approxParameters["S"]
         elif hasattr(self, "S"):
             self.S = self.S
         else:
             self.S = 2
         if "sampler" in keyList:
             self.sampler = approxParameters["sampler"]
         elif not hasattr(self, "S"):
             from rrompy.utilities.parameter_sampling import QuadratureSampler
             self.sampler = QuadratureSampler([0., 1.], "UNIFORM")
             del QuadratureSampler
             
     @property
     def POD(self):
         """Value of POD."""
         return self._POD
     @POD.setter
     def POD(self, POD):
         if hasattr(self, "POD"): PODold = self.POD
         else: PODold = -1
         self._POD = POD
         self._approxParameters["POD"] = self.POD
         if PODold != self.POD:
             self.setupSampling()
             self.resetSamples()
 
     @property
     def S(self):
         """Value of S."""
         return self._S
     @S.setter
     def S(self, S):
         if S <= 0: raise ArithmeticError("S must be positive.")
         if hasattr(self, "S"): Sold = self.S
         else: Sold = -1
         self._S = S
         self._approxParameters["S"] = self.S
         if Sold != self.S:
             self.resetSamples()
 
     @property
     def sampler(self):
         """Value of sampler."""
         return self._sampler
     @sampler.setter
     def sampler(self, sampler):
         if 'generatePoints' not in dir(sampler):
             raise Exception("Sampler type not recognized.")
         if hasattr(self, '_sampler'):
             samplerOld = self.sampler
         self._sampler = sampler
         self._approxParameters["sampler"] = self.sampler
         if not 'samplerOld' in locals() or samplerOld != self.sampler:
             self.resetSamples()
     
     def computeSnapshots(self):
         """
         Compute snapshots of solution map.
         """
         if self.samplingEngine.samples is None:
             if self.verbosity >= 5:
                 verbosityDepth("INIT", "Starting computation of snapshots.")
             self.mus, self.ws = self.sampler.generatePoints(self.S)
             self.mus = np.array([x[0] for x in self.mus])
-            self.samplingEngine.iterSample(self.mus)
+            self.samplingEngine.iterSample(self.mus,
+                                           homogeneize = self.homogeneize)
             if self.verbosity >= 5:
                 verbosityDepth("DEL", "Done computing snapshots.")
 
     def checkComputedApprox(self) -> bool:
         """
         Check if setup of new approximant is not needed.
 
         Returns:
             True if new setup is not needed. False otherwise.
         """
         return (self.samplingEngine.samples is not None
             and super().checkComputedApprox())
 
diff --git a/rrompy/reduction_methods/taylor/__init__.py b/rrompy/reduction_methods/taylor/__init__.py
index 9c0745a..09d9bec 100644
--- a/rrompy/reduction_methods/taylor/__init__.py
+++ b/rrompy/reduction_methods/taylor/__init__.py
@@ -1,29 +1,29 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.reduction_methods.taylor.generic_approximant_taylor import GenericApproximantTaylor
-from rrompy.reduction_methods.taylor.approximant_taylor_pade import ApproximantTaylorPade
-from rrompy.reduction_methods.taylor.approximant_taylor_rb import ApproximantTaylorRB
+from .generic_approximant_taylor import GenericApproximantTaylor
+from .approximant_taylor_pade import ApproximantTaylorPade
+from .approximant_taylor_rb import ApproximantTaylorRB
 
 __all__ = [
         'GenericApproximantTaylor',
         'ApproximantTaylorPade',
         'ApproximantTaylorRB'
           ]
 
 
diff --git a/rrompy/reduction_methods/taylor/approximant_taylor_pade.py b/rrompy/reduction_methods/taylor/approximant_taylor_pade.py
index 08b1dbb..9095d2a 100644
--- a/rrompy/reduction_methods/taylor/approximant_taylor_pade.py
+++ b/rrompy/reduction_methods/taylor/approximant_taylor_pade.py
@@ -1,577 +1,563 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from copy import copy
-import warnings
 import numpy as np
-from rrompy.reduction_methods.taylor.generic_approximant_taylor import (
-                                                      GenericApproximantTaylor)
-from rrompy.sampling.scipy.pod_engine import PODEngine
+from .generic_approximant_taylor import GenericApproximantTaylor
+from rrompy.sampling.base.pod_engine import PODEngine
 from rrompy.utilities.base.types import Np1D, Np2D, Tuple, DictAny
 from rrompy.utilities.base.types import HFEng
 from rrompy.utilities.base import purgeDict, verbosityDepth
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['ApproximantTaylorPade']
 
 class ApproximantTaylorPade(GenericApproximantTaylor):
     """
     ROM single-point fast Pade' approximant computation for parametric
         problems.
 
     Args:
         HFEngine: HF problem solver.
         mu0(optional): Default parameter. Defaults to 0.
         approxParameters(optional): Dictionary containing values for main
             parameters of approximant. Recognized keys are:
             - 'POD': whether to compute POD of snapshots; defaults to True;
             - 'rho': weight for computation of original Pade' approximant;
                 defaults to np.inf, i.e. fast approximant;
             - 'M': degree of Pade' approximant numerator; defaults to 0;
             - 'N': degree of Pade' approximant denominator; defaults to 0;
             - 'E': total number of derivatives current approximant relies upon;
                 defaults to Emax;
             - 'Emax': total number of derivatives of solution map to be
                 computed; defaults to E;
             - 'robustTol': tolerance for robust Pade' denominator management;
                 defaults to 0;
             - 'rescaleParam': whether to rescale parameter during denominator
                 computation; defaults to True;
             - 'sampleType': label of sampling type; available values are:
                 - 'ARNOLDI': orthogonalization of solution derivatives through
                     Arnoldi algorithm;
                 - 'KRYLOV': standard computation of solution derivatives.
                 Defaults to 'KRYLOV'.
             Defaults to empty dict.
 
     Attributes:
         HFEngine: HF problem solver.
         mu0: Default parameter.
         approxParameters: Dictionary containing values for main parameters of
             approximant. Recognized keys are in parameterList.
         parameterList: Recognized keys of approximant parameters:
             - 'POD': whether to compute POD of snapshots; 
             - 'rho': weight for computation of original Pade' approximant;
             - 'M': degree of Pade' approximant numerator;
             - 'N': degree of Pade' approximant denominator;
             - 'E': total number of derivatives current approximant relies upon;
             - 'Emax': total number of derivatives of solution map to be
                 computed;
             - 'robustTol': tolerance for robust Pade' denominator management;
             - 'rescaleParam': whether to rescale parameter during denominator
                 computation;
             - 'sampleType': label of sampling type.
         POD: Whether to compute QR factorization of derivatives.
         rho: Weight of approximant.
         M: Numerator degree of approximant.
         N: Denominator degree of approximant.
         E: Number of solution derivatives over which current approximant is
             based upon.
         Emax: Total number of solution derivatives to be computed.
         robustTol: Tolerance for robust Pade' denominator management.
         sampleType: Label of sampling type.
         initialHFData: HF problem initial data.
         uHF: High fidelity solution with wavenumber lastSolvedHF as numpy
             complex vector.
         lastSolvedHF: Wavenumber corresponding to last computed high fidelity
             solution.
-        solLifting: Lifting of Dirichlet boundary data as numpy vector.
         G: Square Numpy 2D vector of size (N+1) corresponding to Pade'
             denominator matrix (see paper).
         Q: Numpy 1D vector containing complex coefficients of approximant
             denominator.
         P: Numpy 2D vector whose columns are FE dofs of coefficients of
             approximant numerator.
         uApp: Last evaluated approximant as numpy complex vector.
         lastApproxParameters: List of parameters corresponding to last
             computed approximant.
     """
     
     def __init__(self, HFEngine:HFEng, mu0 : complex = 0,
-                 approxParameters : DictAny = {}, verbosity : int = 10):
+                 approxParameters : DictAny = {}, homogeneize : bool = False,
+                 verbosity : int = 10):
         self._preInit()
         if not hasattr(self, "parameterList"):
             self.parameterList = []
         self.parameterList += ["M", "N", "robustTol", "rho", "rescaleParam"]
         super().__init__(HFEngine = HFEngine, mu0 = mu0,
                          approxParameters = approxParameters,
+                         homogeneize = homogeneize,
                          verbosity = verbosity)
         self._postInit()
 
     @property
     def approxParameters(self):
         """Value of approximant parameters."""
         return self._approxParameters
     @approxParameters.setter
     def approxParameters(self, approxParams):
         approxParameters = purgeDict(approxParams, self.parameterList,
                                   dictname = self.name() + ".approxParameters",
                                   baselevel = 1)
         approxParametersCopy = purgeDict(approxParameters, 
                                          ["M", "N", "robustTol", "rho"],
                                          True, True, baselevel = 1)
         keyList = list(approxParameters.keys())
         if "rho" in keyList:
             self._rho = approxParameters["rho"]
         elif hasattr(self, "rho"):
             self._rho = self.rho
         else:
             self._rho = np.inf
         GenericApproximantTaylor.approxParameters.fset(self,
                                                        approxParametersCopy)
         self.rho = self._rho
         if "robustTol" in keyList:
             self.robustTol = approxParameters["robustTol"]
         elif hasattr(self, "robustTol"):
             self.robustTol = self.robustTol
         else:
             self.robustTol = 0
         if "rescaleParam" in keyList:
             self.rescaleParam = approxParameters["rescaleParam"]
         elif hasattr(self, "rescaleParam"):
             self.rescaleParam = self.rescaleParam
         else:
             self.rescaleParam = True
         self._ignoreParWarnings = True
         if "M" in keyList:
             self.M = approxParameters["M"]
         elif hasattr(self, "M"):
             self.M = self.M
         else:
             self.M = 0
         del self._ignoreParWarnings
         if "N" in keyList:
             self.N = approxParameters["N"]
         elif hasattr(self, "N"):
             self.N = self.N
         else:
             self.N = 0
 
     @property
     def rho(self):
         """Value of rho."""
         return self._rho
     @rho.setter
     def rho(self, rho):
         self._rho = np.abs(rho)
         self._approxParameters["rho"] = self.rho
 
     @property
     def M(self):
         """Value of M. Its assignment may change Emax and E."""
         return self._M
     @M.setter
     def M(self, M):
         if M < 0: raise ArithmeticError("M must be non-negative.")
         self._M = M
         self._approxParameters["M"] = self.M
         if not hasattr(self, "_ignoreParWarnings"):
             self.checkMNEEmax()
 
     @property
     def N(self):
         """Value of N. Its assignment may change Emax."""
         return self._N
     @N.setter
     def N(self, N):
         if N < 0: raise ArithmeticError("N must be non-negative.")
         self._N = N
         self._approxParameters["N"] = self.N
         self.checkMNEEmax()
 
     def checkMNEEmax(self):
         """Check consistency of M, N, E, and Emax."""
         M = self.M if hasattr(self, "_M") else 0
         N = self.N if hasattr(self, "_N") else 0
         E = self.E if hasattr(self, "_E") else M + N
         Emax = self.Emax if hasattr(self, "_Emax") else M + N
         if self.rho == np.inf:
             if Emax < max(N, M):
-                warnings.warn(("Prescribed Emax is too small. Updating Emax "
-                               "to max(M, N)."), stacklevel = 3)
-                from sys.stderr import flush
-                flush()
-                del flush
+                warn(("Prescribed Emax is too small. Updating Emax to "
+                      "max(M, N)."))
                 self.Emax = max(N, M)
             if E < max(N, M):
-                warnings.warn(("Prescribed E is too small. Updating E to "
-                               "max(M, N)."), stacklevel = 3)
-                from sys.stderr import flush
-                flush()
-                del flush
+                warn("Prescribed E is too small. Updating E to max(M, N).")
                 self.E = max(N, M)
         else:
             if Emax < N + M:
-                warnings.warn(("Prescribed Emax is too small. Updating "
-                               "Emax to M + N."), stacklevel = 3)
-                from sys.stderr import flush
-                flush()
-                del flush
+                warn("Prescribed Emax is too small. Updating Emax to M + N.")
                 self.Emax = self.N + M
             if E < N + M:
-                warnings.warn(("Prescribed E is too small. Updating E to "
-                               "M + N."), stacklevel = 3)
-                from sys.stderr import flush
-                flush()
-                del flush
+                warn("Prescribed E is too small. Updating E to M + N.")
                 self.E = self.N + M
 
     @property
     def robustTol(self):
         """Value of tolerance for robust Pade' denominator management."""
         return self._robustTol
     @robustTol.setter
     def robustTol(self, robustTol):
         if robustTol < 0.:
-            warnings.warn(("Overriding prescribed negative robustness "
-                          "tolerance to 0."), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Overriding prescribed negative robustness tolerance to 0.")
             robustTol = 0.
         self._robustTol = robustTol
         self._approxParameters["robustTol"] = self.robustTol
 
     @property
     def rescaleParam(self):
         """Value of parameter rescaling during denominator computation."""
         return self._rescaleParam
     @rescaleParam.setter
     def rescaleParam(self, rescaleParam):
         if not isinstance(rescaleParam, (bool,)):
-            warnings.warn(("Prescribed rescaleParam not recognized. "
-                          "Overriding to True."), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Prescribed rescaleParam not recognized. Overriding to True.")
             rescaleParam = True
         self._rescaleParam = rescaleParam
         self._approxParameters["rescaleParam"] = self.rescaleParam
 
     @property
     def E(self):
         """Value of E. Its assignment may change Emax."""
         return self._E
     @E.setter
     def E(self, E):
         if E < 0: raise ArithmeticError("E must be non-negative.")
         self._E = E
         self.checkMNEEmax()
         self._approxParameters["E"] = self.E
         if hasattr(self, "Emax") and self.Emax < self.E:
-            warnings.warn(("Prescribed Emax is too small. Updating Emax "
-                           "to E."), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Prescribed Emax is too small. Updating Emax to E.")
             self.Emax = self.E
 
     @property
     def Emax(self):
         """Value of Emax. Its assignment may reset computed derivatives."""
         return self._Emax
     @Emax.setter
     def Emax(self, Emax):
         if Emax < 0: raise ArithmeticError("Emax must be non-negative.")
         if hasattr(self, "Emax"): EmaxOld = self.Emax
         else: EmaxOld = -1
         if hasattr(self, "_N"): N = self.N
         else: N = 0
         if hasattr(self, "_M"): M = self.M
         else: M = 0
         if hasattr(self, "_E"): E = self.E
         else: E = 0
         if self.rho == np.inf:
             if max(N, M, E) > Emax:
-                warnings.warn(("Prescribed Emax is too small. Updating Emax "
-                               "to max(N, M, E)."), stacklevel = 2)
-                from sys.stderr import flush
-                flush()
-                del flush
+                warn(("Prescribed Emax is too small. Updating Emax to "
+                      "max(N, M, E)."))
                 Emax = max(N, M, E)
         else:
             if max(N + M, E) > Emax:
-                warnings.warn(("Prescribed Emax is too small. Updating Emax "
-                               "to max(N + M, E)."), stacklevel = 2)
-                from sys.stderr import flush
-                flush()
-                del flush
+                warn(("Prescribed Emax is too small. Updating Emax to "
+                      "max(N + M, E)."))
                 Emax = max(N + M, E)
         self._Emax = Emax
         self._approxParameters["Emax"] = Emax
         if EmaxOld >= self.Emax and self.samplingEngine.samples is not None:
             self.samplingEngine.samples = self.samplingEngine.samples[:,
                                                           : self.Emax + 1]
             if (self.sampleType == "ARNOLDI"
                 and self.samplingEngine.HArnoldi is not None):
                 self.samplingEngine.HArnoldi = self.samplingEngine.HArnoldi[
                                                            : self.Emax + 1,
                                                            : self.Emax + 1]
                 self.samplingEngine.RArnoldi = self.samplingEngine.RArnoldi[
                                                            : self.Emax + 1,
                                                            : self.Emax + 1]
 
     def setupApprox(self):
         """
         Compute Pade' approximant. SVD-based robust eigenvalue management.
         """
         if not self.checkComputedApprox():
             if self.verbosity >= 5:
                 verbosityDepth("INIT", "Setting up {}.". format(self.name()))
             self.computeDerivatives()
-            if self.verbosity >= 5:
-                verbosityDepth("INIT", "Starting computation of denominator.")
-            while True:
-                if self.POD:
-                    ev, eV = self.findeveVGQR()
-                else:
-                    ev, eV = self.findeveVGExplicit()
-                ts = self.robustTol * np.linalg.norm(ev)
-                Nnew = np.sum(np.abs(ev) >= ts)
-                diff = self.N - Nnew
-                if diff <= 0: break
-                Enew = self.E - diff
-                Mnew = min(self.M, Enew)
-                if Mnew == self.M:
-                    strM = ""
-                else:
-                    strM = ", M from {0} to {1},".format(self.M, Mnew)
-                print(("Smallest {0} eigenvalues below tolerance.\n"
-                       "Reducing N from {1} to {2}{5} and E from {3} to {4}.")\
-                           .format(diff + 1, self.N, Nnew, self.E, Enew, strM))
-                newParameters = {"N" : Nnew, "M" : Mnew, "E" : Enew}
-                self.approxParameters = newParameters
-            self.Q = eV[::-1, 0]
-            if self.verbosity >= 5:
-                verbosityDepth("DEL", "Done computing denominator.")
+            if self.N > 0:
+                if self.verbosity >= 7:
+                    verbosityDepth("INIT", ("Starting computation of "
+                                            "denominator."))
+                while True:
+                    if self.N == 0:
+                        if self.verbosity >= 7:
+                            verbosityDepth("DEL",
+                                           "Done computing denominator.")
+                        self.Q = np.ones(1)
+                        break
+                    if self.POD:
+                        ev, eV = self.findeveVGQR()
+                    else:
+                        ev, eV = self.findeveVGExplicit()
+                    ts = self.robustTol * np.linalg.norm(ev)
+                    Nnew = np.sum(np.abs(ev) >= ts)
+                    diff = self.N - Nnew
+                    if diff <= 0: break
+                    Enew = self.E - diff
+                    Mnew = min(self.M, Enew)
+                    if Mnew == self.M:
+                        strM = ""
+                    else:
+                        strM = ", M from {0} to {1},".format(self.M, Mnew)
+                    print(("Smallest {0} eigenvalues below tolerance.\n"
+                           "Reducing N from {1} to {2}{5} and E from {3} to "
+                           "{4}.").format(diff + 1, self.N, Nnew, self.E,
+                                          Enew, strM))
+                    newParameters = {"N" : Nnew, "M" : Mnew, "E" : Enew}
+                    self.approxParameters = newParameters
+                self.Q = eV[::-1, 0]
+                if self.verbosity >= 7:
+                    verbosityDepth("DEL", "Done computing denominator.")
+            else:
+                self.Q = np.ones(1)
+            if self.verbosity >= 7:
                 verbosityDepth("INIT", "Starting computation of numerator.")
             QToeplitz = np.zeros((self.Emax + 1, self.M + 1),
                                  dtype = np.complex)
             for i in range(len(self.Q)):
                 rng = np.arange(self.M + 1 - i)
                 QToeplitz[rng, rng + i] = self.Q[i]
             if self.sampleType == "ARNOLDI":
                 QToeplitz = self.samplingEngine.RArnoldi.dot(QToeplitz)
             self.P = self.samplingEngine.samples.dot(QToeplitz)
-            if self.verbosity >= 5:
+            if self.verbosity >= 7:
                 verbosityDepth("DEL", "Done computing numerator.")
             self.lastApproxParameters = copy(self.approxParameters)
             if hasattr(self, "lastSolvedApp"): del self.lastSolvedApp
             if self.verbosity >= 5:
                 verbosityDepth("DEL", "Done setting up approximant.\n")
 
     def rescaleParameter(self, R:Np2D, A : Np2D = None,
                          exponent : float = 1.) -> Np2D:
         """
         Prepare parameter rescaling.
         
         Args:
             R: Matrix whose columns need rescaling.
             A(optional): Matrix whose diagonal defines scaling factor. If None,
                 previous value of scaleFactor is used. Defaults to None.
             exponent(optional): Exponent of scaling factor in matrix diagonal.
                 Defaults to 1.
 
         Returns:
             Rescaled matrix.
         """
         if A is not None:
             aDiag = np.diag(A)
             scaleCoeffs = np.polyfit(np.arange(A.shape[1]),
                                      np.log(aDiag), 1)
             self.scaleFactor = np.exp(- scaleCoeffs[0] / exponent)
         return np.multiply(R, np.power(self.scaleFactor,np.arange(R.shape[1])))
 
     def buildG(self):
         """Assemble Pade' denominator matrix."""
         self.computeDerivatives()
         if self.rho == np.inf:
             Nmin = self.E - self.N
         else:
             Nmin = self.M - self.N + 1
         if self.sampleType == "KRYLOV":
             DerE = self.samplingEngine.samples[:, Nmin : self.E + 1]
             G = self.HFEngine.innerProduct(DerE, DerE)
             if self.rescaleParam:
                 DerE = self.rescaleParameter(DerE, G, 2.)
                 G = self.HFEngine.innerProduct(DerE, DerE)
         else:
             RArnE = self.samplingEngine.RArnoldi[: self.E + 1,
                                                  Nmin : self.E + 1]
             if self.rescaleParam:
                 RArnE = self.rescaleParameter(RArnE, RArnE[Nmin :, :])
             G = RArnE.conj().T.dot(RArnE)
         if self.rho == np.inf:
             self.G = G
         else:
             Gbig = G
             self.G = np.zeros((self.N + 1, self.N + 1), dtype = np.complex)
             for k in range(self.E - self.M):
                 self.G += self.rho ** (2 * k) * Gbig[k : k + self.N + 1,
                                                      k : k + self.N + 1]
             
     def findeveVGExplicit(self) -> Tuple[Np1D, Np2D]:
         """
         Compute explicitly eigenvalues and eigenvectors of Pade' denominator
             matrix.
         """
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT", "Building gramian matrix.")
         self.buildG()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("DEL", "Done building gramian.")
+        if self.verbosity >= 7:
             verbosityDepth("INIT", 
                            "Solving eigenvalue problem for gramian matrix.")
         ev, eV = np.linalg.eigh(self.G)
         if self.rescaleParam:
             eV = self.rescaleParameter(eV.T).T
-        if self.verbosity >= 5:
+        if self.verbosity >= 7:
             verbosityDepth("DEL", "Done solving eigenvalue problem.")
         return ev, eV
 
     def findeveVGQR(self) -> Tuple[Np1D, Np2D]:
         """
         Compute eigenvalues and eigenvectors of Pade' denominator matrix
             through SVD of R factor. See ``Householder triangularization of a
             quasimatrix'', L.Trefethen, 2008 for QR algorithm.
 
         Returns:
             Eigenvalues in ascending order and corresponding eigenvector
                 matrix.
         """
         self.computeDerivatives()
         if self.rho == np.inf:
             Nmin = self.E - self.N
         else:
             Nmin = self.M - self.N + 1
         if self.sampleType == "KRYLOV":
             A = copy(self.samplingEngine.samples[:, Nmin : self.E + 1])
             self.PODEngine = PODEngine(self.HFEngine)
-            if self.verbosity >= 5:
+            if self.verbosity >= 10:
                 verbosityDepth("INIT", "Orthogonalizing samples.", end = "")
             R = self.PODEngine.QRHouseholder(A, only_R = True)
-            if self.verbosity >= 5:
+            if self.verbosity >= 10:
                 verbosityDepth("DEL", " Done.", inline = True)
         else:
             R = self.samplingEngine.RArnoldi[: self.E + 1, Nmin : self.E + 1]
         if self.rescaleParam:
             R = self.rescaleParameter(R, R[Nmin :, :])
         if self.rho == np.inf:
-            if self.verbosity >= 5:
+            if self.verbosity >= 10:
                 verbosityDepth("INIT", ("Solving svd for square root of "
                                         "gramian matrix."), end = "")
             _, s, V = np.linalg.svd(R, full_matrices = False)
         else:
-            if self.verbosity >= 5:
+            if self.verbosity >= 10:
                 verbosityDepth("INIT", ("Building matrix stack for square "
                                         "root of gramian."), end = "")
             Rtower = np.zeros((R.shape[0] * (self.E - self.M), self.N + 1),
                               dtype = np.complex)
             for k in range(self.E - self.M):
                 Rtower[k * R.shape[0] : (k + 1) * R.shape[0], :] = (
                                 self.rho ** k
                               * R[:, self.M - self.N + 1 + k : self.M + 1 + k])
-            if self.verbosity >= 5:
+            if self.verbosity >= 10:
                 verbosityDepth("DEL", " Done.", inline = True)
+            if self.verbosity >= 7:
                 verbosityDepth("INIT", ("Solving svd for square root of "
                                         "gramian matrix."), end = "")
             _, s, V = np.linalg.svd(Rtower, full_matrices = False)
         eV = V.conj().T[:, ::-1]
         if self.rescaleParam:
             eV = self.rescaleParameter(eV.T).T
-        if self.verbosity >= 5:
+        if self.verbosity >= 7:
             verbosityDepth("DEL", " Done.", inline = True)
         return s[::-1], eV
             
     def radiusPade(self, mu:Np1D, mu0 : float = None) -> float:
         """
         Compute translated radius to be plugged into Pade' approximant.
 
         Args:
             mu: Parameter(s) 1.
             mu0: Parameter(s) 2. If None, set to self.mu0.
 
         Returns:
             Translated radius to be plugged into Pade' approximant.
         """
         if mu0 is None: mu0 = self.mu0
         return self.HFEngine.rescaling(mu) - self.HFEngine.rescaling(mu0)
 
     def getPVal(self, mu:complex):
         """
         Evaluate Pade' numerator at arbitrary parameter.
 
         Args:
             mu: Target parameter.
         """
         self.setupApprox()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT",
                            "Evaluating numerator at mu = {}.".format(mu),
                            end = "")
         powerlist = np.power(self.radiusPade(mu), np.arange(self.M + 1))
         p = self.P.dot(powerlist)
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("DEL", " Done.", inline = True)
         return p
 
     def getQVal(self, mu:complex):
         """
         Evaluate Pade' denominator at arbitrary parameter.
 
         Args:
             mu: Target parameter.
         """
         self.setupApprox()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT",
                            "Evaluating denominator at mu = {}.".format(mu),
                            end = "")
         powerlist = np.power(self.radiusPade(mu), np.arange(self.N + 1))
         q = self.Q.dot(powerlist)
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("DEL", " Done.", inline = True)
         return q
 
     def evalApprox(self, mu:complex):
         """
         Evaluate Pade' approximant at arbitrary parameter.
 
         Args:
             mu: Target parameter.
         """
         self.setupApprox()
         if (not hasattr(self, "lastSolvedApp")
          or not np.isclose(self.lastSolvedApp, mu)):
+            if self.verbosity >= 5:
+                verbosityDepth("INIT",
+                               "Evaluating approximant at mu = {}.".format(mu))
             try:
                 self.uApp = self.getPVal(mu) / self.getQVal(mu)
             except:
                 self.uApp = np.empty(self.P.shape[0])
                 self.uApp[:] = np.nan
             self.lastSolvedApp = mu
+            if self.verbosity >= 5:
+                verbosityDepth("DEL", "Done evaluating approximant.")
 
     def getPoles(self) -> Np1D:
         """
         Obtain approximant poles.
 
         Returns:
             Numpy complex vector of poles.
         """
         self.setupApprox()
         return self.HFEngine.rescalingInv(np.roots(self.Q[::-1])
                                         + self.HFEngine.rescaling(self.mu0))
         
diff --git a/rrompy/reduction_methods/taylor/approximant_taylor_rb.py b/rrompy/reduction_methods/taylor/approximant_taylor_rb.py
index 4e81634..6e1044c 100644
--- a/rrompy/reduction_methods/taylor/approximant_taylor_rb.py
+++ b/rrompy/reduction_methods/taylor/approximant_taylor_rb.py
@@ -1,312 +1,302 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from copy import copy
-import warnings
 import numpy as np
 import scipy as sp
-from rrompy.reduction_methods.taylor.generic_approximant_taylor import GenericApproximantTaylor
-from rrompy.sampling.scipy.pod_engine import PODEngine
+from .generic_approximant_taylor import GenericApproximantTaylor
+from rrompy.sampling.base.pod_engine import PODEngine
 from rrompy.utilities.base.types import Np1D, DictAny, HFEng
 from rrompy.utilities.base import purgeDict, verbosityDepth
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['ApproximantTaylorRB']
 
 class ApproximantTaylorRB(GenericApproximantTaylor):
     """
     ROM single-point fast RB approximant computation for parametric problems
         with polynomial dependence up to degree 2.
 
     Args:
         HFEngine: HF problem solver.
         mu0(optional): Default parameter. Defaults to 0.
         approxParameters(optional): Dictionary containing values for main
             parameters of approximant. Recognized keys are:
             - 'POD': whether to compute POD of snapshots; defaults to True;
             - 'R': rank for Galerkin projection; defaults to E + 1;
             - 'E': total number of derivatives current approximant relies upon;
                 defaults to Emax;
             - 'Emax': total number of derivatives of solution map to be
                 computed; defaults to E;
             - 'sampleType': label of sampling type; available values are:
                 - 'ARNOLDI': orthogonalization of solution derivatives through
                     Arnoldi algorithm;
                 - 'KRYLOV': standard computation of solution derivatives.
                 Defaults to 'KRYLOV'.
             Defaults to empty dict.
 
     Attributes:
         HFEngine: HF problem solver.
         mu0: Default parameter.
         approxParameters: Dictionary containing values for main parameters of
             approximant. Recognized keys are in parameterList.
         parameterList: Recognized keys of approximant parameters:
             - 'POD': whether to compute POD of snapshots;
             - 'R': rank for Galerkin projection;
             - 'E': total number of derivatives current approximant relies upon;
             - 'Emax': total number of derivatives of solution map to be
                 computed;
             - 'sampleType': label of sampling type.
         POD: Whether to compute QR factorization of derivatives.
         R: Rank for Galerkin projection.
         E: Number of solution derivatives over which current approximant is
             based upon.
         Emax: Total number of solution derivatives to be computed.
         sampleType: Label of sampling type, i.e. 'KRYLOV'.
         uHF: High fidelity solution with wavenumber lastSolvedHF as numpy
             complex vector.
         lastSolvedHF: Wavenumber corresponding to last computed high fidelity
             solution.
         uApp: Last evaluated approximant as numpy complex vector.
         lastApproxParameters: List of parameters corresponding to last
             computed approximant.
-        solLifting: Numpy complex vector with lifting of real part of Dirichlet
-            boundary datum.
         projMat: Numpy matrix representing projection onto RB space.
         projMat: Numpy matrix representing projection onto RB space.
         As: List of sparse matrices (in CSC format) representing coefficients
             of linear system matrix wrt mu.
         bs: List of numpy vectors representing coefficients of linear system
            RHS wrt mu.
         ARBs: List of sparse matrices (in CSC format) representing RB
             coefficients of linear system matrix wrt mu.
         bRBs: List of numpy vectors representing RB coefficients of linear
             system RHS wrt mu.
     """
 
     def __init__(self, HFEngine:HFEng, mu0 : complex = 0,
-                 approxParameters : DictAny = {}, verbosity : int = 10):
+                 approxParameters : DictAny = {}, homogeneize : bool = False,
+                 verbosity : int = 10):
         self._preInit()
         if not hasattr(self, "parameterList"):
             self.parameterList = []
         self.parameterList += ["R"]
         super().__init__(HFEngine = HFEngine, mu0 = mu0,
                          approxParameters = approxParameters,
+                         homogeneize = homogeneize,
                          verbosity = verbosity)
+        if self.verbosity >= 10:
+            verbosityDepth("INIT", "Computing affine blocks of system.")
         self.As, self.thetaAs = self.HFEngine.affineBlocksA(self.mu0)
-        self.bs, self.thetabs = self.HFEngine.affineBlocksb(self.mu0)
+        self.bs, self.thetabs = self.HFEngine.affineBlocksb(self.mu0,
+                                                            self.homogeneize)
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done computing affine blocks.")
         self._postInit()
 
     def resetSamples(self):
         """Reset samples."""
         super().resetSamples()
         self.projMat = None
 
     @property
     def approxParameters(self):
         """
         Value of approximant parameters. Its assignment may change M, N and S.
         """
         return self._approxParameters
     @approxParameters.setter
     def approxParameters(self, approxParams):
         approxParameters = purgeDict(approxParams, self.parameterList,
                                   dictname = self.name() + ".approxParameters",
                                   baselevel = 1)
         approxParametersCopy = purgeDict(approxParameters, ["R"],
                                          True, True, baselevel = 1)
         GenericApproximantTaylor.approxParameters.fset(self,
                                                        approxParametersCopy)
         keyList = list(approxParameters.keys())
         if "R" in keyList:
             self.R = approxParameters["R"]
         else:
             self.R = self.E + 1
 
     @property
     def POD(self):
         """Value of POD."""
         return self._POD
     @POD.setter
     def POD(self, POD):
         GenericApproximantTaylor.POD.fset(self, POD)
         if (hasattr(self, "sampleType") and self.sampleType == "ARNOLDI"
                                         and not self.POD):
-            warnings.warn(("Arnoldi sampling implicitly forces POD-type "
-                           "derivative management."), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn(("Arnoldi sampling implicitly forces POD-type derivative "
+                  "management."))
 
     @property
     def sampleType(self):
         """Value of sampleType."""
         return self._sampleType
     @sampleType.setter
     def sampleType(self, sampleType):
         GenericApproximantTaylor.sampleType.fset(self, sampleType)
         if (hasattr(self, "POD") and not self.POD
                                  and self.sampleType == "ARNOLDI"):
-            warnings.warn(("Arnoldi sampling implicitly forces POD-type "
-                           "derivative management."), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn(("Arnoldi sampling implicitly forces POD-type derivative "
+                  "management."))
 
     @property
     def R(self):
         """Value of R. Its assignment may change S."""
         return self._R
     @R.setter
     def R(self, R):
         if R < 0: raise ArithmeticError("R must be non-negative.")
         self._R = R
         self._approxParameters["R"] = self.R
         if hasattr(self, "E") and self.E + 1 < self.R:
-            warnings.warn("Prescribed E is too small. Updating E to R - 1.",
-                          stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Prescribed E is too small. Updating E to R - 1.")
             self.E = self.R - 1
 
     def setupApprox(self):
         """Setup RB system."""
         if not self.checkComputedApprox():
             if self.verbosity >= 5:
                 verbosityDepth("INIT", "Setting up {}.". format(self.name()))
             self.computeDerivatives()
-            if self.verbosity >= 5:
+            if self.verbosity >= 7:
                 verbosityDepth("INIT", "Computing projection matrix.",
                                end = "")
             if self.POD and not self.sampleType == "ARNOLDI":
                 self.PODEngine = PODEngine(self.HFEngine)
                 self.projMatQ, self.projMatR = self.PODEngine.QRHouseholder(
                                                    self.samplingEngine.samples)
             if self.POD:
                 if self.sampleType == "ARNOLDI":
                     self.projMatR = self.samplingEngine.RArnoldi
                     self.projMatQ = self.samplingEngine.samples
                 U, _, _ = np.linalg.svd(self.projMatR[: self.E + 1, : self.E + 1])                                                           
                 self.projMat = self.projMatQ[:, : self.E + 1].dot(U[:, : self.R])
             else:
                 self.projMat = self.samplingEngine.samples[:, : self.R + 1]
-            if self.verbosity >= 5:
+            if self.verbosity >= 7:
                 verbosityDepth("DEL", " Done.", inline = True)
             self.lastApproxParameters = copy(self.approxParameters)
             if hasattr(self, "lastSolvedApp"): del self.lastSolvedApp
             self.assembleReducedSystem()
             if self.verbosity >= 5:
                 verbosityDepth("DEL", "Done setting up approximant.\n")
 
     def assembleReducedSystem(self):
         """Build affine blocks of RB linear system through projections."""
         if not self.checkComputedApprox():
             self.setupApprox()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT", "Projecting affine terms of HF model.",
                            end = "")
         projMatH = self.projMat.T.conj()
         self.ARBs = [None] * len(self.As)
         self.bRBs = [None] * len(self.bs)
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("MAIN", ".", end = "", inline = True)
         for j in range(len(self.As)):
             self.ARBs[j] = projMatH.dot(self.As[j].dot(self.projMat))
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("MAIN", ".", end = "", inline = True)
         for j in range(len(self.bs)):
             self.bRBs[j] = projMatH.dot(self.bs[j])
-        if self.verbosity >= 5:
-            verbosityDepth("DEL", " Done.", inline = True)
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done.", inline = True)
 
     def solveReducedSystem(self, mu:complex) -> Np1D:
         """
         Solve RB linear system.
 
         Args:
             mu: Target parameter.
 
         Returns:
             Solution of RB linear system.
         """
         self.setupApprox()
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT",
                            "Assembling reduced model for mu = {}.".format(mu),
                            end = "")
         ARBmu = self.thetaAs(mu, 0) * self.ARBs[0][:self.R,:self.R]
         bRBmu = self.thetabs(mu, 0) * self.bRBs[0][:self.R]
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("MAIN", ".", end = "", inline = True)
         for j in range(1, len(self.ARBs)):
             ARBmu += self.thetaAs(mu, j) * self.ARBs[j][:self.R, :self.R]
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("MAIN", ".", end = "", inline = True)
         for j in range(1, len(self.bRBs)):
             bRBmu += self.thetabs(mu, j) * self.bRBs[j][:self.R]
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done.", inline = True)
         if self.verbosity >= 5:
-            verbosityDepth("DEL", " Done.", inline = True)
             verbosityDepth("INIT", 
                            "Solving reduced model for mu = {}.".format(mu),
                            end = "")
         uRB = self.projMat[:, :self.R].dot(np.linalg.solve(ARBmu, bRBmu))
         if self.verbosity >= 5:
             verbosityDepth("DEL", " Done.", inline = True)
         return uRB
 
     def evalApprox(self, mu:complex):
         """
         Evaluate RB approximant at arbitrary wavenumber.
 
         Args:
             mu: Target parameter.
         """
         self.setupApprox()
         if (not hasattr(self, "lastSolvedApp")
          or not np.isclose(self.lastSolvedApp, mu)):
+            if self.verbosity >= 5:
+                verbosityDepth("INIT",
+                               "Computing RB solution at mu = {}.".format(mu))
             self.uApp = self.solveReducedSystem(mu)
             self.lastSolvedApp = mu
+            if self.verbosity >= 5:
+                verbosityDepth("DEL", "Done computing RB solution.")
 
     def getPoles(self) -> Np1D:
         """
         Obtain approximant poles.
 
         Returns:
             Numpy complex vector of poles.
         """
-        warnings.warn(("Impossible to compute poles in general affine "
-                       "parameter dependence. Results subject to "
-                       "interpretation/rescaling, or possibly completely "
-                       "wrong."), stacklevel = 2)
-        from sys.stderr import flush
-        flush()
-        del flush
+        warn(("Impossible to compute poles in general affine parameter "
+              "dependence. Results subject to interpretation/rescaling, or "
+              "possibly completely wrong."))
         self.setupApprox()
+        if len(self.ARBs) < 2:
+            return
         A = np.eye(self.ARBs[0].shape[0] * (len(self.ARBs) - 1),
                    dtype = np.complex)
         B = np.zeros_like(A)
         A[: self.ARBs[0].shape[0], : self.ARBs[0].shape[0]] = - self.ARBs[0]
         for j in range(len(self.ARBs) - 1):
             Aj = self.ARBs[j + 1]
             B[: Aj.shape[0], j * Aj.shape[0] : (j + 1) * Aj.shape[0]] = Aj
         II = np.arange(self.ARBs[0].shape[0],
                        self.ARBs[0].shape[0] * (len(self.ARBs) - 1))
         B[II, II - self.ARBs[0].shape[0]] = 1.
-        try:
-            return sp.linalg.eigvals(A, B)
-        except:
-            warnings.warn("Generalized eig algorithm did not converge.",
-                          stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
-            x = np.empty(A.shape[0])
-            x[:] = np.NaN
-            return x
+        return self.HFEngine.rescalingInv(sp.linalg.eigvals(A, B)
+                                        + self.HFEngine.rescaling(self.mu0))
 
diff --git a/rrompy/reduction_methods/taylor/generic_approximant_taylor.py b/rrompy/reduction_methods/taylor/generic_approximant_taylor.py
index c8b1f6c..a8e5c55 100644
--- a/rrompy/reduction_methods/taylor/generic_approximant_taylor.py
+++ b/rrompy/reduction_methods/taylor/generic_approximant_taylor.py
@@ -1,235 +1,227 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-import warnings
-from rrompy.reduction_methods.base.generic_approximant import GenericApproximant
+from rrompy.reduction_methods.base.generic_approximant import (
+                                                            GenericApproximant)
 from rrompy.utilities.base.types import DictAny, HFEng
 from rrompy.utilities.base import purgeDict, verbosityDepth
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['GenericApproximantTaylor']
 
 class GenericApproximantTaylor(GenericApproximant):
     """
     ROM single-point approximant computation for parametric problems
         (ABSTRACT).
     
     Args:
         HFEngine: HF problem solver.
         mu0(optional): Default parameter. Defaults to 0.
         approxParameters(optional): Dictionary containing values for main
             parameters of approximant. Recognized keys are:
             - 'POD': whether to compute POD of snapshots; defaults to True;
             - 'E': total number of derivatives current approximant relies upon;
                 defaults to Emax;
             - 'Emax': total number of derivatives of solution map to be
                 computed; defaults to E;
             - 'sampleType': label of sampling type; available values are:
                 - 'ARNOLDI': orthogonalization of solution derivatives through
                     Arnoldi algorithm;
                 - 'KRYLOV': standard computation of solution derivatives.
                 Defaults to 'KRYLOV'.
             Defaults to empty dict.
 
     Attributes:
         HFEngine: HF problem solver.
         mu0: Default parameter.
         approxParameters: Dictionary containing values for main parameters of
             approximant. Recognized keys are in parameterList.
         parameterList: Recognized keys of approximant parameters:
             - 'POD': whether to compute POD of snapshots;
             - 'E': total number of derivatives current approximant relies upon;
             - 'Emax': total number of derivatives of solution map to be
                 computed;
             - 'sampleType': label of sampling type.
         POD: Whether to compute QR factorization of derivatives.
         E: Number of solution derivatives over which current approximant is
             based upon.
         Emax: Total number of solution derivatives to be computed.
         sampleType: Label of sampling type.
         initialHFData: HF problem initial data.
         samplingEngine: Sampling engine.
         uHF: High fidelity solution with wavenumber lastSolvedHF as numpy
             complex vector.
         lastSolvedHF: Wavenumber corresponding to last computed high fidelity
             solution.
-        solLifting: Lifting of Dirichlet boundary data as numpy vector.
         uApp: Last evaluated approximant as numpy complex vector.
         lastApproxParameters: List of parameters corresponding to last
             computed approximant.
     """
 
     def __init__(self, HFEngine:HFEng, mu0 : complex = 0,
-                 approxParameters : DictAny = {}, verbosity : int = 10):
+                 approxParameters : DictAny = {}, homogeneize : bool = False,
+                 verbosity : int = 10):
         self._preInit()
         if not hasattr(self, "parameterList"):
             self.parameterList = []
         self.parameterList += ["E", "Emax", "sampleType"]
         super().__init__(HFEngine = HFEngine, mu0 = mu0,
                          approxParameters = approxParameters,
+                         homogeneize = homogeneize,
                          verbosity = verbosity)
         self._postInit()
 
     def setupSampling(self):
         """Setup sampling engine."""
         if not hasattr(self, "sampleType"): return
         if self.sampleType == "ARNOLDI":
             from rrompy.sampling.scipy.sampling_engine_arnoldi import (
-                                       SamplingEngineArnoldi as SamplingEngine)
+                                                         SamplingEngineArnoldi)
+            super().setupSampling(SamplingEngineArnoldi)
         elif self.sampleType == "KRYLOV":
             from rrompy.sampling.scipy.sampling_engine_krylov import (
-                                        SamplingEngineKrylov as SamplingEngine)
+                                                          SamplingEngineKrylov)
+            super().setupSampling(SamplingEngineKrylov)
         else:
             raise Exception("Sample type not recognized.")
-        self.samplingEngine = SamplingEngine(self.HFEngine,
-                                             verbosity = self.verbosity)
 
     @property
     def approxParameters(self):
         """
         Value of approximant parameters. Its assignment may change E and Emax.
         """
         return self._approxParameters
     @approxParameters.setter
     def approxParameters(self, approxParams):
         approxParameters = purgeDict(approxParams, self.parameterList,
                                   dictname = self.name() + ".approxParameters",
                                   baselevel = 1)
         approxParametersCopy = purgeDict(approxParameters,
                                          ["E", "Emax", "sampleType"],
                                          True, True, baselevel = 1)
         GenericApproximant.approxParameters.fset(self, approxParametersCopy)
         keyList = list(approxParameters.keys())
         if "E" in keyList:
             self._E = approxParameters["E"]
             self._approxParameters["E"] = self.E
             if "Emax" in keyList:
                 self.Emax = approxParameters["Emax"]
             else:
                 if not hasattr(self, "Emax"):
                     self.Emax = self.E
                 else:
                     self.Emax = self.Emax
         else:
             if "Emax" in keyList:
                 self._E = approxParameters["Emax"]
                 self._approxParameters["E"] = self.E
                 self.Emax = self.E
             else:
                 if not (hasattr(self, "Emax") and hasattr(self, "E")):
                     raise Exception("At least one of E and Emax must be set.")
         if "sampleType" in keyList:
             self.sampleType = approxParameters["sampleType"]
         elif hasattr(self, "sampleType"):
             self.sampleType = self.sampleType
         else:
             self.sampleType = "KRYLOV"
 
     @property
     def E(self):
         """Value of E. Its assignment may change Emax."""
         return self._E
     @E.setter
     def E(self, E):
         if E < 0: raise ArithmeticError("E must be non-negative.")
         self._E = E
         self._approxParameters["E"] = self.E
         if hasattr(self, "Emax") and self.Emax < self.E:
-            warnings.warn("Prescribed E is too large. Updating Emax to E.",
-                          stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Prescribed E is too large. Updating Emax to E.")
             self.Emax = self.E
 
     @property
     def Emax(self):
         """Value of Emax. Its assignment may reset computed derivatives."""
         return self._Emax
     @Emax.setter
     def Emax(self, Emax):
         if Emax < 0: raise ArithmeticError("Emax must be non-negative.")
         if hasattr(self, "Emax"): EmaxOld = self.Emax
         else: EmaxOld = -1
         self._Emax = Emax
         if hasattr(self, "E") and self.Emax < self.E:
-            warnings.warn("Prescribed Emax is too small. Updating Emax to E.",
-                          stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn("Prescribed Emax is too small. Updating Emax to E.")
             self.Emax = self.E
         else:
             self._approxParameters["Emax"] = self.Emax
             if (EmaxOld >= self.Emax
             and self.samplingEngine.samples is not None):
                 self.samplingEngine.samples = self.samplingEngine.samples[:,
                                                                : self.Emax + 1]
                 if (self.sampleType == "ARNOLDI"
                     and self.samplingEngine.HArnoldi is not None):
                     self.samplingEngine.HArnoldi= self.samplingEngine.HArnoldi[
                                                                : self.Emax + 1,
                                                                : self.Emax + 1]
                     self.samplingEngine.RArnoldi= self.samplingEngine.RArnoldi[
                                                                : self.Emax + 1,
                                                                : self.Emax + 1]
             else:
                 self.resetSamples()
 
     @property
     def sampleType(self):
         """Value of sampleType."""
         return self._sampleType
     @sampleType.setter
     def sampleType(self, sampleType):
         if hasattr(self, "sampleType"): sampleTypeOld = self.sampleType
         else: sampleTypeOld = -1
         try:
             sampleType = sampleType.upper().strip().replace(" ","")
             if sampleType not in ["ARNOLDI", "KRYLOV"]: 
                 raise Exception("Sample type not recognized.")
             self._sampleType = sampleType
         except:
-            warnings.warn(("Prescribed sampleType not recognized. Overriding "
-                           "to 'KRYLOV'."), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn(("Prescribed sampleType not recognized. Overriding to "
+                  "'KRYLOV'."))
             self._sampleType = "KRYLOV"
         self._approxParameters["sampleType"] = self.sampleType
         if sampleTypeOld != self.sampleType:
             self.resetSamples()
 
     def computeDerivatives(self):
         """Compute derivatives of solution map starting from order 0."""
         if self.samplingEngine.samples is None:
             if self.verbosity >= 5:
                 verbosityDepth("INIT", "Starting computation of derivatives.")
-            self.samplingEngine.iterSample(self.mu0, self.Emax + 1)
+            self.samplingEngine.iterSample(self.mu0, self.Emax + 1,
+                                           homogeneize = self.homogeneize)
             if self.verbosity >= 5:
                 verbosityDepth("DEL", "Done computing derivatives.")
             
     def checkComputedApprox(self) -> bool:
         """
         Check if setup of new approximant is not needed.
 
         Returns:
             True if new setup is not needed. False otherwise.
         """
         return (self.samplingEngine.samples is not None
             and super().checkComputedApprox())
 
diff --git a/rrompy/sampling/base/__init__.py b/rrompy/sampling/base/__init__.py
index a8d83f1..09e673f 100644
--- a/rrompy/sampling/base/__init__.py
+++ b/rrompy/sampling/base/__init__.py
@@ -1,27 +1,27 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.sampling.base.pod_engine_base import PODEngineBase
-from rrompy.sampling.base.sampling_engine_base import SamplingEngineBase
+from .pod_engine import PODEngine
+from .sampling_engine_base import SamplingEngineBase
 
 __all__ = [
-        'PODEngineBase',
+        'PODEngine',
         'SamplingEngineBase'
           ]
 
 
diff --git a/rrompy/sampling/scipy/pod_engine.py b/rrompy/sampling/base/pod_engine.py
similarity index 94%
rename from rrompy/sampling/scipy/pod_engine.py
rename to rrompy/sampling/base/pod_engine.py
index b8a5474..a376ea7 100644
--- a/rrompy/sampling/scipy/pod_engine.py
+++ b/rrompy/sampling/base/pod_engine.py
@@ -1,140 +1,147 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 from copy import copy
-from rrompy.sampling.base.pod_engine_base import PODEngineBase
 from rrompy.utilities.base.types import Np1D, Np2D, Tuple, HFEng
 
 __all__ = ['PODEngine']
 
-class PODEngine(PODEngineBase):
+class PODEngine:
     """
     POD engine for general matrix orthogonalization.
-    
-    Args/Attributes:
-        HFEngine: HF problem solver.
     """
 
     def __init__(self, HFEngine:HFEng):
         self.HFEngine = HFEngine
 
+    def name(self) -> str:
+        return self.__class__.__name__
+        
+    def __str__(self) -> str:
+        return self.name()
+        
+    def norm(self, a:Np1D) -> float:
+        """Compute norm of a Hilbert space object."""
+        pass
+
     def GS(self, a:Np1D, Q:Np2D, n : int = None,
            aA:Np1D = None, QA:Np2D = None) -> Tuple[Np1D, Np1D, Np1D]:
         """
         Compute 1 Gram-Schmidt step with given projector.
         
         Args:
             a: vector to be projected;
             Q: orthogonal projection matrix;
             n: number of columns of Q to be considered;
             aA: augmented components of vector to be projected;
             QA: augmented components of projection matrix.
 
         Returns:
             Resulting normalized vector, coefficients of a wrt the updated 
                 basis.
         """
         if n is None:
             n = Q.shape[1]
         if aA is None != QA is None:
             raise Exception(("Either both or none of augmented components "
                              "must be provided."))
         r = np.zeros((n + 1,), dtype = a.dtype)
         if n > 0:
             Q = Q[:, : n]
             for j in range(2): # twice is enough!
                 nu = self.HFEngine.innerProduct(a, Q)
                 a = a - Q.dot(nu)
                 if aA is not None:
                     aA = aA - QA.dot(nu)
                 r[:-1] = r[:-1] + nu
         r[-1] = self.HFEngine.norm(a)
         if np.isclose(np.abs(r[-1]), 0.):
             r[-1] = 1.
         a = a / r[-1]
         if aA is not None:
             aA = aA / r[-1]
         return a, r, aA
 
     def QRGramSchmidt(self, A:Np2D,
                       only_R : bool = False) -> Tuple[Np1D, Np1D]:
         """
         Compute QR decomposition of a matrix through Gram-Schmidt method.
         
         Args:
             A: matrix to be decomposed;
             only_R(optional): whether to skip reconstruction of Q; defaults to
                 False.
 
         Returns:
             Resulting orthogonal and upper-triangular factors.
         """
         N = A.shape[1]
         Q = np.zeros_like(A, dtype = A.dtype)
         R = np.zeros((N, N), dtype = A.dtype)
         for k in range(N):
             Q[:, k], R[: k + 1, k], _ = self.GS(A[:, k], Q, k)
         if only_R:
             return R
         return Q, R
     
     def QRHouseholder(self, A:Np2D, Q0 : Np2D = None,
                       only_R : bool = False) -> Tuple[Np1D, Np1D]:
         """
         Compute QR decomposition of a matrix through Householder method.
         
         Args:
             A: matrix to be decomposed;
             Q0(optional): initial orthogonal guess for Q; defaults to random;
             only_R(optional): whether to skip reconstruction of Q; defaults to
                 False.
 
         Returns:
             Resulting (orthogonal and )upper-triangular factor(s).
         """
         B = copy(A)
         N = B.shape[1]
         V = np.zeros_like(B, dtype = B.dtype)
         R = np.zeros((N, N), dtype = B.dtype)
         if Q0 is None:
             Q = np.zeros_like(B, dtype = B.dtype) + np.random.randn(*(B.shape))
         else:
             Q = copy(Q0)
         for k in range(N):
             if Q0 is None:
                 Q[:, k], _, _ = self.GS(Q[:, k], Q, k)
             a = B[:, k]
             R[k, k] = self.HFEngine.norm(a)
             alpha = self.HFEngine.innerProduct(a, Q[:, k])
             if np.isclose(np.abs(alpha), 0.): s = 1.
             else: s = - alpha / np.abs(alpha)
             Q[:, k] = s * Q[:, k]
             V[:, k], _, _ = self.GS(R[k, k] * Q[:, k] - a, Q, k) 
             J = np.arange(k + 1, N)
             vtB = self.HFEngine.innerProduct(B[:, J], V[:, k])
             B[:, J] = B[:, J] - 2 * np.outer(V[:, k], vtB)
             R[k, J] = self.HFEngine.innerProduct(B[:, J], Q[:, k])
             B[:, J] = B[:, J] - np.outer(Q[:, k], R[k, J])
         if only_R:
             return R
         for k in range(N - 1, -1, -1):
             J = np.arange(k, N)
             vtQ = self.HFEngine.innerProduct(Q[:, J], V[:, k])
             Q[:, J] = Q[:, J] - 2 * np.outer(V[:, k], vtQ)
         return Q, R
+        
diff --git a/rrompy/sampling/base/pod_engine_base.py b/rrompy/sampling/base/pod_engine_base.py
deleted file mode 100644
index 9356768..0000000
--- a/rrompy/sampling/base/pod_engine_base.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright (C) 2018 by the RROMPy authors
-#
-# This file is part of RROMPy.
-#
-# RROMPy is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# RROMPy is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
-#
-
-from rrompy.utilities.base.types import HS1D, HS2D, Tuple
-
-__all__ = ['PODEngineBase']
-
-class PODEngineBase:
-    """
-    POD engine for general matrix orthogonalization. ABSTRACT.
-    """
-
-    def name(self) -> str:
-        return self.__class__.__name__
-        
-    def __str__(self) -> str:
-        return self.name()
-        
-    def norm(self, a:HS1D) -> float:
-        """Compute norm of a Hilbert space object."""
-        pass
-
-    def GS(self, a:HS1D, Q:HS2D, n : int = None,
-           aA:HS1D = None, QA:HS2D = None) -> Tuple[HS1D, HS1D, HS1D]:
-        """
-        Compute 1 Gram-Schmidt step with given projector.
-        
-        Args:
-            a: Hilbert space object to be projected;
-            Q: orthogonal projection Hilbert space quasi-matrix;
-            n: number of columns of Q to be considered;
-            aA: augmented components of Hilbert space object to be projected;
-            QA: augmented components of Hilbert space object projection
-                quasi-matrix.
-
-        Returns:
-            Resulting normalized Hilbert space object, coefficients of a wrt
-                the updated basis.
-        """
-        pass
-
-    def QRGramSchmidt(self, A:HS2D,
-                      only_R : bool = False) -> Tuple[HS1D, HS1D]:
-        """
-        Compute QR decomposition of a matrix through Gram-Schmidt method.
-        
-        Args:
-            A: Hilbert space quasi-matrix to be decomposed;
-            only_R(optional): whether to skip reconstruction of Q; defaults to
-                False.
-
-        Returns:
-            Resulting orthogonal and upper-triangular quasi-factors.
-        """
-        pass
-    
-    def QRHouseholder(self, A:HS2D, Q0 : HS2D = None,
-                      only_R : bool = False) -> Tuple[HS1D, HS1D]:
-        """
-        Compute QR decomposition of a matrix through Householder method.
-        
-        Args:
-            A: Hilbert space quasi-matrix to be decomposed;
-            Q0(optional): initial orthogonal guess for Q; defaults to random;
-            only_R(optional): whether to skip reconstruction of Q; defaults to
-                False.
-
-        Returns:
-            Resulting (orthogonal and )upper-triangular quasi-factor(s).
-        """
-        pass
-        
diff --git a/rrompy/sampling/base/sampling_engine_base.py b/rrompy/sampling/base/sampling_engine_base.py
index ab1c51a..b5c6066 100644
--- a/rrompy/sampling/base/sampling_engine_base.py
+++ b/rrompy/sampling/base/sampling_engine_base.py
@@ -1,97 +1,102 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.utilities.base.types import HS1D, HFEng, strLst
+from rrompy.utilities.base.types import Np1D, HFEng, strLst
 from rrompy.utilities.base import verbosityDepth
 
 __all__ = ['SamplingEngineBase']
 
 class SamplingEngineBase:
     """HERE"""
     
     nameBase = 0
 
     def __init__(self, HFEngine:HFEng, verbosity : int = 10):
         self.verbosity = verbosity
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT",
                            "Initializing sampling engine of type {}.".format(
                                                                   self.name()),
                            end = "")
         self.HFEngine = HFEngine
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("DEL", " Done.", inline = True)
             
     def name(self) -> str:
         return self.__class__.__name__
         
     def __str__(self) -> str:
         return self.name()
         
     def resetHistory(self):
         self.samples = None
         self.nsamples = 0
         
     @property
     def HFEngine(self):
         """Value of HFEngine. Its assignment resets history."""
         return self._HFEngine
     @HFEngine.setter
     def HFEngine(self, HFEngine):
         self._HFEngine = HFEngine
         self.resetHistory()
     
-    def solveLS(self, mu:complex, RHS : HS1D = None) -> HS1D:
+    def solveLS(self, mu:complex, RHS : Np1D = None,
+                homogeneized : bool = False) -> Np1D:
         """
         Solve linear system.
 
         Args:
             mu: Parameter value.
         
         Returns:
             Solution of system.
         """
         if self.verbosity >= 5:
-            verbosityDepth("INIT", "Solving HF model for mu = {}.".format(mu),
-                           end = "")
-        u = self.HFEngine.solve(mu, RHS)
+            verbosityDepth("INIT", "Solving HF model for mu = {}.".format(mu))
+        u = self.HFEngine.solve(mu, RHS, homogeneized)
         if self.verbosity >= 5:
-            verbosityDepth("DEL", " Done.", inline = True)
+            verbosityDepth("DEL", "Done solving HF model.")
         return u
 
-    def plotSamples(self, name : str = "u", save : bool = False,
-                    what : strLst = 'all', **figspecs):
+    def plotSamples(self, name : str = "u", save : str = None,
+                    what : strLst = 'all', saveFormat : str = "eps",
+                    saveDPI : int = 100, **figspecs):
         """
         Do some nice plots of the samples.
 
         Args:
             name(optional): Name to be shown as title of the plots. Defaults to
                 'u'.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
             what(optional): Which plots to do. If list, can contain 'ABS',
                 'PHASE', 'REAL', 'IMAG'. If str, same plus wildcard 'ALL'.
                 Defaults to 'ALL'.
-            save(optional): Whether to save plot(s). Defaults to False.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
             figspecs(optional key args): Optional arguments for matplotlib
                 figure creation.
         """
         for j in range(self.nsamples):
             self.HFEngine.plot(self.samples[:, j],
                                name = "{}_{}".format(name, j + self.nameBase),
-                               what = what, **figspecs)
-                               
+                               save = save, what = what,
+                               saveFormat = saveFormat, saveDPI = saveDPI,
+                               **figspecs)
 
diff --git a/rrompy/sampling/scipy/__init__.py b/rrompy/sampling/scipy/__init__.py
index 1c1b986..31e0790 100644
--- a/rrompy/sampling/scipy/__init__.py
+++ b/rrompy/sampling/scipy/__init__.py
@@ -1,33 +1,31 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.sampling.scipy.sampling_engine_krylov import SamplingEngineKrylov
-from rrompy.sampling.scipy.sampling_engine_arnoldi import SamplingEngineArnoldi
-from rrompy.sampling.scipy.sampling_engine_lagrange import SamplingEngineLagrange
-from rrompy.sampling.scipy.sampling_engine_lagrange_pod import SamplingEngineLagrangePOD
-from rrompy.sampling.scipy.pod_engine import PODEngine
+from .sampling_engine_krylov import SamplingEngineKrylov
+from .sampling_engine_arnoldi import SamplingEngineArnoldi
+from .sampling_engine_lagrange import SamplingEngineLagrange
+from .sampling_engine_lagrange_pod import SamplingEngineLagrangePOD
 
 __all__ = [
         'SamplingEngineKrylov',
         'SamplingEngineArnoldi',
         'SamplingEngineLagrange',
-        'SamplingEngineLagrangePOD',
-        'PODEngine'
+        'SamplingEngineLagrangePOD'
           ]
 
 
diff --git a/rrompy/sampling/scipy/sampling_engine_arnoldi.py b/rrompy/sampling/scipy/sampling_engine_arnoldi.py
index d2247fd..d50de53 100644
--- a/rrompy/sampling/scipy/sampling_engine_arnoldi.py
+++ b/rrompy/sampling/scipy/sampling_engine_arnoldi.py
@@ -1,128 +1,129 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from copy import copy
 import numpy as np
-from rrompy.sampling.scipy.pod_engine import PODEngine
-from rrompy.sampling.scipy.sampling_engine_krylov import SamplingEngineKrylov
+from rrompy.sampling.base.pod_engine import PODEngine
+from .sampling_engine_krylov import SamplingEngineKrylov
 from rrompy.utilities.base.types import Np1D
 from rrompy.utilities.base import verbosityDepth
 
 __all__ = ['SamplingEngineArnoldi']
 
 class SamplingEngineArnoldi(SamplingEngineKrylov):
     """HERE"""
 
     def resetHistory(self):
         super().resetHistory()
         self.HArnoldi = None
         self.RArnoldi = None
         self.RHSs = None
         self.samplesAug = None
 
     @property
     def HFEngine(self):
         """Value of HFEngine. Its assignment resets history."""
         return self._HFEngine
     @HFEngine.setter
     def HFEngine(self, HFEngine):
         self._HFEngine = HFEngine
         self.resetHistory()
         self.PODEngine = PODEngine(self._HFEngine)
     
     def preprocesssamples(self):
         ns = self.nsamples
         if ns <= 0: return
         return self.samplesAug[:, ns - 1].reshape((-1,self.HFEngine.V.dim())).T
         
-    def preprocessb(self, mu:complex, overwrite : bool = False):
+    def preprocessb(self, mu:complex, overwrite : bool = False,
+                    homogeneize : bool = False):
         ns = self.nsamples
-        r = self.HFEngine.b(mu, ns)
+        r = super().preprocessb(mu, overwrite, homogeneize)
         if ns == 0:
             return r
         elif ns == 1:
             r = r / self.RArnoldi[0, 0]
         else:
             r = ((r - self.RHSs[:, :ns-1].dot(self.RArnoldi[:ns-1, ns-1]))
                                             / self.RArnoldi[ns-1, ns-1])
         if overwrite:
             self.RHSs[:, ns - 1] = r
         else:
             if ns == 1:
                 self.RHSs = r.reshape((- 1, 1))
             else:
                 self.RHSs = np.hstack((self.RHSs, r[:, None]))
         return r
         
     def postprocessu(self, u:Np1D, overwrite : bool = False):
-        if self.verbosity >= 5:
-            verbosityDepth("INIT", "Starting orthogonalization.", end = "")
+        if self.verbosity >= 10:
+            verbosityDepth("INIT", "Starting orthogonalization.")
         ns = self.nsamples
         nsAug = (ns + 1) * self.HFEngine.V.dim()
         if ns == 0:
             u, h, _ = self.PODEngine.GS(u, np.empty((0, 0)))
             r = h[0]
             uAug = copy(u)
         else:
             uAug = np.concatenate((self.samplesAug[self.HFEngine.V.dim()
                                                  - nsAug :, ns - 1],
                                    u), axis = None)
             u, h, uAug = self.PODEngine.GS(u, self.samples[:, : ns], ns, uAug,
                                            self.samplesAug[- nsAug :, : ns])
         if overwrite:
             self.HArnoldi[: ns + 1, ns] = h
             if ns > 0:
                 r = self.HArnoldi[: ns + 1, 1 : ns + 1].dot(
                                                    self.RArnoldi[: ns, ns - 1])
             self.RArnoldi[: ns + 1, ns] = r
             self.samplesAug[- nsAug :, ns] = uAug
         else:
             if ns == 0:
                 self.HArnoldi = h.reshape((1, 1))
                 self.RArnoldi = r.reshape((1, 1))
                 self.samplesAug = uAug.reshape((-1, 1))
             else:
                 self.HArnoldi=np.block([[    self.HArnoldi, h[:-1, None]],
                                         [np.zeros((1, ns)),        h[-1]]])
                 if ns > 0:
                     r = self.HArnoldi[: ns + 1, 1 : ns + 1].dot(
                                                    self.RArnoldi[: ns, ns - 1])
                 self.RArnoldi=np.block([[    self.RArnoldi, r[:-1, None]],
                                         [np.zeros((1, ns)),        r[-1]]])
                 self.samplesAug=np.vstack((np.zeros((self.HFEngine.V.dim(),
                                                      ns)),
                                            self.samplesAug))
                 self.samplesAug = np.hstack((self.samplesAug, uAug[:, None]))
-        if self.verbosity >= 5:
-            verbosityDepth("DEL", " Done.", inline = True)
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done orthogonalizing.")
         return u
         
     def preallocateSamples(self, u:Np1D, n:int):
         super().preallocateSamples(u, n)
         h = self.HArnoldi
         r = self.RArnoldi
         saug = self.samplesAug
         self.HArnoldi = np.zeros((n, n), dtype = u.dtype)
         self.HArnoldi[0, 0] = h[0, 0]
         self.RArnoldi = np.zeros((n, n), dtype = u.dtype)
         self.RArnoldi[0, 0] = r[0, 0]
         self.RHSs = np.empty((u.size, n - 1), dtype = u.dtype)
         self.samplesAug = np.zeros((self.HFEngine.V.dim() * (n + 1), n),
                                    dtype = u.dtype)
         self.samplesAug[- self.HFEngine.V.dim() :, 0] = saug[:, 0]
 
diff --git a/rrompy/sampling/scipy/sampling_engine_krylov.py b/rrompy/sampling/scipy/sampling_engine_krylov.py
index 059cfed..253d543 100644
--- a/rrompy/sampling/scipy/sampling_engine_krylov.py
+++ b/rrompy/sampling/scipy/sampling_engine_krylov.py
@@ -1,85 +1,87 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 from rrompy.sampling.base.sampling_engine_base import SamplingEngineBase
 from rrompy.utilities.base.types import Np1D, Np2D
 from rrompy.utilities.base import verbosityDepth
 
 __all__ = ['SamplingEngineKrylov']
 
 class SamplingEngineKrylov(SamplingEngineBase):
     """HERE"""
 
     def preprocesssamples(self):
         if self.samples is None: return
         return self.samples[:, : self.nsamples]
         
-    def preprocessb(self, mu:complex, overwrite : bool = False):
-        return self.HFEngine.b(mu, self.nsamples)
+    def preprocessb(self, mu:complex, overwrite : bool = False,
+                    homogeneize : bool = False):
+        return self.HFEngine.b(mu, self.nsamples, homogeneized = homogeneize)
         
     def postprocessu(self, u:Np1D, overwrite : bool = False):
         return u
 
     def preallocateSamples(self, u:Np1D, n:int):
         self.samples = np.empty((u.size, n), dtype = u.dtype)
         self.samples[:, 0] = u
             
-    def nextSample(self, mu:complex, overwrite : bool = False) -> Np1D:
+    def nextSample(self, mu:complex, overwrite : bool = False,
+                   homogeneize : bool = False) -> Np1D:
         ns = self.nsamples
-        if self.verbosity >= 5:
+        if self.verbosity >= 10:
             verbosityDepth("INIT", ("Setting up computation of {}-th Taylor "
-                                    "coefficient.").format(ns), end = "")
+                                    "coefficient.").format(ns))
         samplesOld = self.preprocesssamples()
-        if self.verbosity >= 5:
-            verbosityDepth("MAIN", ".", end = "", inline = True)
-        RHS = self.preprocessb(mu, overwrite = overwrite)
-        if self.verbosity >= 5:
-            verbosityDepth("MAIN", ".", end = "", inline = True)
+        RHS = self.preprocessb(mu, overwrite = overwrite,
+                               homogeneize = homogeneize)
         for i in range(1, ns + 1):
             RHS -= self.HFEngine.A(mu, i).dot(samplesOld[:, - i])
-        if self.verbosity >= 5:
-            verbosityDepth("DEL", " Done.", inline = True)
-        u = self.postprocessu(self.solveLS(mu, RHS = RHS),
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done setting up for Taylor coefficient.")
+        u = self.postprocessu(self.solveLS(mu, RHS = RHS,
+                                           homogeneized = homogeneize),
                               overwrite = overwrite)
         if overwrite:
             self.samples[:, ns] = u
         else:
             if ns == 0:
                 self.samples = u[:, None]
             else:
                 self.samples = np.hstack((self.samples, u[:, None]))
         self.nsamples += 1
         return u
 
-    def iterSample(self, mu:complex, n:int) -> Np2D:
+    def iterSample(self, mu:complex, n:int,
+                   homogeneize : bool = False) -> Np2D:
         if self.verbosity >= 5:
             verbosityDepth("INIT", "Starting sampling iterations at mu = {}."\
                                                                    .format(mu))
         if n <= 0:
             raise Exception(("Number of Krylov iterations must be positive."))
         self.resetHistory()
-        u = self.nextSample(mu)
+        u = self.nextSample(mu, homogeneize = homogeneize)
         if n > 1:
             self.preallocateSamples(u, n)
             for _ in range(1, n):
-                self.nextSample(mu, overwrite = True)
+                self.nextSample(mu, overwrite = True,
+                                homogeneize = homogeneize)
         if self.verbosity >= 5:
             verbosityDepth("DEL", "Finished sampling iterations.")
         return self.samples
 
diff --git a/rrompy/sampling/scipy/sampling_engine_lagrange.py b/rrompy/sampling/scipy/sampling_engine_lagrange.py
index f4af0e9..81bf598 100644
--- a/rrompy/sampling/scipy/sampling_engine_lagrange.py
+++ b/rrompy/sampling/scipy/sampling_engine_lagrange.py
@@ -1,66 +1,69 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
 from rrompy.sampling.base.sampling_engine_base import SamplingEngineBase
 from rrompy.utilities.base.types import Np1D, Np2D
 from rrompy.utilities.base import verbosityDepth
 
 __all__ = ['SamplingEngineLagrange']
 
 class SamplingEngineLagrange(SamplingEngineBase):
     """HERE"""
 
     nameBase = 1
 
     def postprocessu(self, u:Np1D, overwrite : bool = False):
         return u
 
     def preallocateSamples(self, u:Np1D, n:int):
         self.samples = np.empty((u.size, n), dtype = u.dtype)
         self.samples[:, 0] = u
             
-    def nextSample(self, mu:complex, overwrite : bool = False) -> Np1D:
+    def nextSample(self, mu:complex, overwrite : bool = False,
+                   homogeneize : bool = False) -> Np1D:
         ns = self.nsamples
-        u = self.postprocessu(self.solveLS(mu), overwrite = overwrite)
+        u = self.postprocessu(self.solveLS(mu, homogeneized = homogeneize),
+                              overwrite = overwrite)
         if overwrite:
             self.samples[:, ns] = u
         else:
             if ns == 0:
                 self.samples = u[:, None]
             else:
                 self.samples = np.hstack((self.samples, u[:, None]))
         self.nsamples += 1
         return u
 
-    def iterSample(self, mu:Np1D) -> Np2D:
+    def iterSample(self, mu:Np1D, homogeneize : bool = False) -> Np2D:
         if self.verbosity >= 5:
             verbosityDepth("INIT", "Starting sampling iterations.")
         n = mu.size
         if n <= 0:
             raise Exception(("Number of samples must be positive."))
         self.resetHistory()
-        u = self.nextSample(mu[0])
+        u = self.nextSample(mu[0], homogeneize = homogeneize)
         if n > 1:
             self.preallocateSamples(u, n)
             for j in range(1, n):
-                self.nextSample(mu[j], overwrite = True)
+                self.nextSample(mu[j], overwrite = True,
+                                homogeneize = homogeneize)
         if self.verbosity >= 5:
             verbosityDepth("DEL", "Finished sampling iterations.")
         return self.samples
 
diff --git a/rrompy/sampling/scipy/sampling_engine_lagrange_pod.py b/rrompy/sampling/scipy/sampling_engine_lagrange_pod.py
index e9ea0ad..b239295 100644
--- a/rrompy/sampling/scipy/sampling_engine_lagrange_pod.py
+++ b/rrompy/sampling/scipy/sampling_engine_lagrange_pod.py
@@ -1,70 +1,70 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 import numpy as np
-from rrompy.sampling.scipy.pod_engine import PODEngine
-from rrompy.sampling.scipy.sampling_engine_lagrange import SamplingEngineLagrange
+from rrompy.sampling.base.pod_engine import PODEngine
+from .sampling_engine_lagrange import SamplingEngineLagrange
 from rrompy.utilities.base.types import Np1D
 from rrompy.utilities.base import verbosityDepth
 
 __all__ = ['SamplingEngineLagrangePOD']
 
 class SamplingEngineLagrangePOD(SamplingEngineLagrange):
     """HERE"""
 
     def resetHistory(self):
         super().resetHistory()
         self.RPOD = None
 
     @property
     def HFEngine(self):
         """Value of HFEngine. Its assignment resets history."""
         return self._HFEngine
     @HFEngine.setter
     def HFEngine(self, HFEngine):
         self._HFEngine = HFEngine
         self.resetHistory()
         self.PODEngine = PODEngine(self._HFEngine)
     
     def postprocessu(self, u:Np1D, overwrite : bool = False):
-        if self.verbosity >= 5:
-            verbosityDepth("INIT", "Starting orthogonalization.", end = "")
+        if self.verbosity >= 10:
+            verbosityDepth("INIT", "Starting orthogonalization.")
         ns = self.nsamples
         if ns == 0:
             u, r, _ = self.PODEngine.GS(u, np.empty((0, 0)))
             r = r[0]
         else:
             u, r, _ = self.PODEngine.GS(u, self.samples[:, : ns], ns)
         if overwrite:
             self.RPOD[: ns + 1, ns] = r
         else:
             if ns == 0:
                 self.RPOD = r.reshape((1, 1))
             else:
                 self.RPOD=np.block([[        self.RPOD, r[:-1, None]],
                                     [np.zeros((1, ns)),        r[-1]]])
-        if self.verbosity >= 5:
-            verbosityDepth("DEL", " Done.", inline = True)
+        if self.verbosity >= 10:
+            verbosityDepth("DEL", "Done orthogonalizing.")
         return u
         
     def preallocateSamples(self, u:Np1D, n:int):
         super().preallocateSamples(u, n)
         r = self.RPOD
         self.RPOD = np.zeros((n, n), dtype = u.dtype)
         self.RPOD[0, 0] = r[0, 0]
 
diff --git a/rrompy/utilities/base/__init__.py b/rrompy/utilities/base/__init__.py
index 5b77131..99a448d 100644
--- a/rrompy/utilities/base/__init__.py
+++ b/rrompy/utilities/base/__init__.py
@@ -1,43 +1,43 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.utilities.base.find_dict_str_key import findDictStrKey
-from rrompy.utilities.base.get_new_filename import getNewFilename
-from rrompy.utilities.base.purge_dict import purgeDict
-from rrompy.utilities.base.purge_list import purgeList
-from rrompy.utilities.base.number_theory import squareResonances, primeFactorize, getLowestPrimeFactor
-from rrompy.utilities.base.sobol import sobolGenerate
-from rrompy.utilities.base import types as Types
-from rrompy.utilities.base import fenics as Fenics
-from rrompy.utilities.base.verbosity_depth import verbosityDepth
+from .find_dict_str_key import findDictStrKey
+from .get_new_filename import getNewFilename
+from .purge_dict import purgeDict
+from .purge_list import purgeList
+from .number_theory import squareResonances, primeFactorize, getLowestPrimeFactor
+from .sobol import sobolGenerate
+from . import types as Types
+from . import fenics as Fenics
+from .verbosity_depth import verbosityDepth
 
 __all__ = [
         'findDictStrKey',
         'getNewFilename',
         'purgeDict',
         'purgeList',
         'squareResonances',
         'primeFactorize',
         'getLowestPrimeFactor',
         'sobolGenerate',
         'Types',
         'Fenics',
         'verbosityDepth'
            ]
 
 
diff --git a/rrompy/utilities/base/purge_dict.py b/rrompy/utilities/base/purge_dict.py
index 9a41612..dcb2108 100644
--- a/rrompy/utilities/base/purge_dict.py
+++ b/rrompy/utilities/base/purge_dict.py
@@ -1,45 +1,43 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-import warnings
 from rrompy.utilities.base.find_dict_str_key import findDictStrKey
 from rrompy.utilities.base.types import ListAny, DictAny
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['purgeDict']
 
 def purgeDict(dct:DictAny, allowedKeys : ListAny = [], silent : bool = False,
               complement : bool = False, dictname : str = "", 
               baselevel : int = 0) -> DictAny:
     if dictname != "":
         dictname = " in " + dictname
     dctcp = {}
     for key in dct.keys():
         akey = findDictStrKey(key, allowedKeys)
         if (akey is None) != complement:
             if not silent:
-                warnings.warn("Ignoring key {0}{2} with value {1}."\
-                              .format(key, dct[key], dictname),
-                              stacklevel = baselevel + 2)
-                from sys.stderr import flush
-                flush()
-                del flush
+                warn("Ignoring key {0}{2} with value {1}.".format(key,
+                                                                  dct[key],
+                                                                  dictname),
+                     baselevel)
         else:
             if akey is None:
                 akey = key
             dctcp[akey] = dct[key]
     return dctcp
diff --git a/rrompy/utilities/base/purge_list.py b/rrompy/utilities/base/purge_list.py
index 92cd744..70cf5c0 100644
--- a/rrompy/utilities/base/purge_list.py
+++ b/rrompy/utilities/base/purge_list.py
@@ -1,43 +1,39 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-import warnings
 from rrompy.utilities.base.find_dict_str_key import findDictStrKey
 from rrompy.utilities.base.types import ListAny
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['purgeList']
 
 def purgeList(lst:ListAny, allowedEntries : ListAny = [],
               silent : bool = False, complement : bool = False,
               listname : str = "", baselevel : int = 0) -> ListAny:
     if listname != "":
         listname = " in " + listname
     lstcp = []
     for x in lst:
         ax = findDictStrKey(x, allowedEntries)
         if (ax is None) != complement:
             if not silent:
-                warnings.warn("Ignoring entry {0}{1}.".format(x, listname),
-                              stacklevel = baselevel + 2)
-                from sys.stderr import flush
-                flush()
-                del flush
+                warn("Ignoring entry {0}{1}.".format(x, listname), baselevel)
         else:
             lstcp = lstcp + [ax]
     return lstcp
 
diff --git a/rrompy/utilities/base/types.py b/rrompy/utilities/base/types.py
index fe26a19..e93358d 100644
--- a/rrompy/utilities/base/types.py
+++ b/rrompy/utilities/base/types.py
@@ -1,51 +1,51 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from typing import TypeVar, List, Tuple, Dict, Any
 
-__all__ = ['TupleAny','ListAny','DictAny','HS1D','HS2D','HSOp','Np1D','Np2D',
-           'Np1DLst','N2FSExpr','FenExpr','HFEng','ROMEng','GenExpr','strLst',
-           'BfSExpr']
+__all__ = ['TupleAny','ListAny','DictAny','ScOp','Np1D','Np2D','Np1DLst',
+           'N2FSExpr','FenExpr','FenFunc','HFEng','ROMEng','sampleEng',
+           'GenExpr','strLst','BfSExpr']
 
 # ANY
 TupleAny = Tuple[Any]
 ListAny = List[Any]
 DictAny = Dict[Any, Any]
 
-# GENERIC
-HS1D = TypeVar("Hilbert space element")
-HS2D = TypeVar("Hilbert space quasi-matrix")
-HSOp = TypeVar("Hilbert space operator")
+# SCIPY
+ScOp = TypeVar("Scipy sparse matrix for space operator")
 
 # NUMPY
 Np1D = TypeVar("NumPy 1D array")
 Np2D = TypeVar("NumPy 2D array")
 Np1DLst = TypeVar("NumPy 1D array or list of NumPy 1D array")
 N2FSExpr = TypeVar("NumPy 2D array, float or str")
 
 # FENICS
 FenExpr = TypeVar("FEniCS expression")
+FenFunc = TypeVar("FEniCS function")
 
 # ENGINES
 HFEng = TypeVar("High fidelity engine")
 ROMEng = TypeVar("ROM engine")
+sampleEng = TypeVar("Sampling engine")
 
 # OTHERS
 GenExpr = TypeVar("Generic expression")
 strLst = TypeVar("str or list of str")
 BfSExpr = TypeVar("Boolean function or string")
diff --git a/rrompy/utilities/parameter_sampling/__init__.py b/rrompy/utilities/parameter_sampling/__init__.py
index cdf181b..fe293d3 100644
--- a/rrompy/utilities/parameter_sampling/__init__.py
+++ b/rrompy/utilities/parameter_sampling/__init__.py
@@ -1,33 +1,33 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.utilities.parameter_sampling.generic_sampler import GenericSampler
-from rrompy.utilities.parameter_sampling.quadrature_sampler import QuadratureSampler
-from rrompy.utilities.parameter_sampling.random_sampler import RandomSampler
-from rrompy.utilities.parameter_sampling.fft_sampler import FFTSampler
-from rrompy.utilities.parameter_sampling.manual_sampler import ManualSampler
+from .generic_sampler import GenericSampler
+from .quadrature_sampler import QuadratureSampler
+from .random_sampler import RandomSampler
+from .fft_sampler import FFTSampler
+from .manual_sampler import ManualSampler
 
 __all__ = [
         'GenericSampler',
         'QuadratureSampler',
         'RandomSampler',
         'FFTSampler',
         'ManualSampler'
           ]
 
 
diff --git a/rrompy/utilities/parameter_sweeper/__init__.py b/rrompy/utilities/parameter_sweeper/__init__.py
index 1571153..03ca6b3 100644
--- a/rrompy/utilities/parameter_sweeper/__init__.py
+++ b/rrompy/utilities/parameter_sweeper/__init__.py
@@ -1,25 +1,25 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.utilities.parameter_sweeper.parameter_sweeper import ParameterSweeper
+from .parameter_sweeper import ParameterSweeper
 
 __all__ = [
         'ParameterSweeper'
           ]
 
 
diff --git a/rrompy/utilities/parameter_sweeper/parameter_sweeper.py b/rrompy/utilities/parameter_sweeper/parameter_sweeper.py
index 88fadaa..a4d9167 100644
--- a/rrompy/utilities/parameter_sweeper/parameter_sweeper.py
+++ b/rrompy/utilities/parameter_sweeper/parameter_sweeper.py
@@ -1,361 +1,489 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
 from copy import copy
 import itertools
 import csv
-import warnings
 import numpy as np
 from matplotlib import pyplot as plt
 from rrompy.utilities.base.types import Np1D, DictAny, List, ROMEng
 from rrompy.utilities.base import purgeList, getNewFilename, verbosityDepth
+from rrompy.utilities.warning_manager import warn
 
 __all__ = ['ParameterSweeper']
 
 def C2R2csv(x):
     x = np.ravel(x)
     y = np.concatenate((np.real(x), np.imag(x)))
     z = np.ravel(np.reshape(y, [2, np.size(x)]).T)
     return np.array2string(z, separator = '_', suppress_small = False,
                            max_line_width = np.inf, sign = '+',
                            formatter = {'all' : lambda x : "{:.15E}".format(x)}
                           )[1 : -1]
 
 class ParameterSweeper:
     """
     ROM approximant parameter sweeper.
     
     Args:
         ROMEngine(optional): Generic approximant class. Defaults to None.
         mutars(optional): Array of parameter values to sweep. Defaults to empty
             array.
         params(optional): List of parameter settings (each as a dict) to
             explore. Defaults to single empty set.
         mostExpensive(optional): String containing label of most expensive
             step, to be executed fewer times. Allowed options are 'HF' and
             'Approx'. Defaults to 'HF'.
 
     Attributes:
         ROMEngine: Generic approximant class.
         mutars: Array of parameter values to sweep.
         params: List of parameter settings (each as a dict) to explore.
         mostExpensive: String containing label of most expensive step, to be
             executed fewer times.
     """
     
     allowedOutputsStandard = ["normHF", "normApp", "normRes", "normResRel",
                               "normErr", "normErrRel"]
     allowedOutputs = allowedOutputsStandard + ["HFFunc", "AppFunc",
                                                "ErrFunc", "ErrFuncRel"]
     allowedOutputsFull = allowedOutputs + ["poles"]
 
     def __init__(self, ROMEngine : ROMEng = None, mutars : Np1D = np.array([]),
                  params : List[DictAny] = [{}], mostExpensive : str = "HF"):
         self.ROMEngine = ROMEngine
         self.mutars = mutars
         self.params = params
         self.mostExpensive = mostExpensive
 
     def name(self) -> str:
         return self.__class__.__name__
         
     def __str__(self) -> str:
         return self.name()
 
     @property
     def mostExpensive(self):
         """Value of mostExpensive."""
         return self._mostExpensive
     @mostExpensive.setter
     def mostExpensive(self, mostExpensive:str):
         mostExpensive = mostExpensive.upper()
         if mostExpensive not in ["HF", "APPROX"]:
-            warnings.warn(("Value of mostExpensive not recognized. Overriding "
-                           "to 'APPROX'."), stacklevel = 2)
-            from sys.stderr import flush
-            flush()
-            del flush
+            warn(("Value of mostExpensive not recognized. Overriding to "
+                  "'APPROX'."))
             mostExpensive = "APPROX"
         self._mostExpensive = mostExpensive
 
     def checkValues(self) -> bool:
         """Check if sweep can be performed."""
         if self.ROMEngine is None:
             raise Exception("ROMEngine is missing. Aborting.")
         if len(self.mutars) == 0:
             raise Exception("Empty target parameter vector. Aborting.")
         if len(self.params) == 0:
             raise Exception("Empty method parameters vector. Aborting.")
 
     def sweep(self, filename : str = "out.dat", outputs : List[str] = [],
-              verbose : int = 1):
+              verbose : int = 10):
         self.checkValues()
         try:
             if outputs.upper() == "ALL":
                 outputs = self.allowedOutputsFull
         except:
             if len(outputs) == 0:
                 outputs = self.allowedOutputsStandard
         outputs = purgeList(outputs, self.allowedOutputsFull,
                             listname = self.name() + ".outputs",
                             baselevel = 1)
         poles = ("poles" in outputs)
         if len(outputs) == 0:
             raise Exception("Empty outputs. Aborting.")
         outParList = self.ROMEngine.parameterList
         Nparams = len(self.params)
         if poles: polesCheckList = []
         allowedParams = self.ROMEngine.parameterList
         
         dotPos = filename.rfind('.')
         if dotPos in [-1, len(filename) - 1]:
             filename = getNewFilename(filename[:dotPos])
         else:
             filename = getNewFilename(filename[:dotPos], filename[dotPos + 1:])
             
         append_write = "w"
         initial_row = (outParList + ["muRe", "muIm"]
                      + [x for x in self.allowedOutputs if x in outputs]
                      + ["type"] + ["poles"] * poles)
         with open(filename, append_write, buffering = 1) as fout:
             writer = csv.writer(fout, delimiter=",")
             writer.writerow(initial_row)
 
             if self.mostExpensive == "HF":
                 outerSet = self.mutars
                 innerSet = self.params
             elif self.mostExpensive == "APPROX":
                 outerSet = self.params
                 innerSet = self.mutars
     
             for outerIdx, outerPar in enumerate(outerSet):
                 if self.mostExpensive == "HF":
                     i, mutar = outerIdx, outerPar
                 elif self.mostExpensive == "APPROX":
                     j, par = outerIdx, outerPar
                     self.ROMEngine.approxParameters = {k: par[k] for k in\
                                                     par.keys() & allowedParams}
                     self.ROMEngine.setupApprox()
     
                 for innerIdx, innerPar in enumerate(innerSet):
                     if self.mostExpensive == "APPROX":
                         i, mutar = innerIdx, innerPar
                     elif self.mostExpensive == "HF":
                         j, par = innerIdx, innerPar
                         self.ROMEngine.approxParameters = {k: par[k] for k in\
                                                     par.keys() & allowedParams}
                         self.ROMEngine.setupApprox()
         
-                    if verbose >= 1:
+                    if verbose >= 5:
                         verbosityDepth("INIT", "Set {}/{}\tmu_{} = {:.10f}"\
                                              .format(j + 1, Nparams, i, mutar))
     
                     outData = []
                     if "normHF" in outputs:
                         valNorm = self.ROMEngine.normHF(mutar)
                         outData = outData + [valNorm]
                     if "normApp" in outputs:
                         val = self.ROMEngine.normApp(mutar)
                         outData = outData + [val]
                     if "normRes" in outputs:
                         valNRes = self.ROMEngine.normRes(mutar)
                         outData = outData + [valNRes]
                     if "normResRel" in outputs:
                         if "normRes" not in outputs:
                             valNRes = self.ROMEngine.normRes(mutar)
                         val = self.ROMEngine.normRHS(mutar)
                         outData = outData + [valNRes / val]
                     if "normErr" in outputs:
                         valNErr = self.ROMEngine.normErr(mutar)
                         outData = outData + [valNErr]
                     if "normErrRel" in outputs:
                         if "normHF" not in outputs:
                             valNorm = self.ROMEngine.normHF(mutar)
                         if "normErr" not in outputs:
                             valNErr = self.ROMEngine.normErr(mutar)
                         outData = outData + [valNErr / valNorm]
                     if "HFFunc" in outputs:
                         valFunc = self.ROMEngine.HFEngine.functional(
                                                    self.ROMEngine.getHF(mutar))
                         outData = outData + [valFunc]
                     if "AppFunc" in outputs:
                         valFApp = self.ROMEngine.HFEngine.functional(
                                                   self.ROMEngine.getApp(mutar))
                         outData = outData + [valFApp]
                     if "ErrFunc" in outputs:
                         if "HFFunc" not in outputs:
                             valFunc = self.ROMEngine.HFEngine.functional(
                                                    self.ROMEngine.getHF(mutar))
                         if "AppFunc" not in outputs:
                             valFApp = self.ROMEngine.HFEngine.functional(
                                                   self.ROMEngine.getApp(mutar))
                         valFErr = np.abs(valFApp - valFunc)
                         outData = outData + [valFErr]
                     if "ErrFuncRel" in outputs:
                         if not ("HFFunc" in outputs or "ErrFunc" in outputs):
                             valFunc = self.ROMEngine.HFEngine.functional(
                                                    self.ROMEngine.getHF(mutar))
                         if not ("AppFunc" in outputs or "ErrFunc" in outputs):
                             valFApp = self.ROMEngine.HFEngine.functional(
                                                   self.ROMEngine.getApp(mutar))
                         val = np.nan
                         if not np.isclose(valFunc, 0.):
                             val = valFApp / valFunc
                         outData = outData + [val]
                     writeData = []
                     for parn in outParList:
                         writeData = (writeData
                                    + [self.ROMEngine.approxParameters[parn]])
                     writeData = (writeData + [mutar.real, mutar.imag]
                                + outData + [self.ROMEngine.name()])
                     if poles:
                         if j not in polesCheckList:
                             polesCheckList += [j]
                             writeData = writeData + [C2R2csv(
                                                     self.ROMEngine.getPoles())]
                         else:
                             writeData = writeData + [""]
                     writer.writerow(str(x) for x in writeData)
-                    if verbose >= 1:
+                    if verbose >= 5:
                         verbosityDepth("DEL", "", end = "", inline = "")
         
-                if verbose >= 1:
+                if verbose >= 5:
                     if self.mostExpensive == "APPROX":
                         out = "Set {}/{}\tdone.\n".format(j + 1, Nparams)
                     elif self.mostExpensive == "HF":
                         out = "Point mu_{} = {:.10f}\tdone.\n".format(i, mutar)
                     verbosityDepth("INIT", out)
                     verbosityDepth("DEL", "", end = "", inline = "")
         self.filename = filename
         return self.filename
             
     def read(self, filename:str, restrictions : DictAny = {},
              outputs : List[str] = []) -> DictAny:
         """
         Execute a query on a custom format CSV.
     
         Args:
             filename: CSV filename.
             restrictions(optional): Parameter configurations to output.
                 Defaults to empty dictionary, i.e. output all.
             outputs(optional):  Values to output. Defaults to empty list, i.e.
                 no output.
     
         Returns:
             Dictionary of desired results, with a key for each entry of
                 outputs, and a numpy 1D array as corresponding value.
         """
         with open(filename, 'r') as f:
             reader = csv.reader(f, delimiter=',')
             header = next(reader)
             restrIndices, outputIndices, outputData = {}, {}, {}
             for key in restrictions.keys():
                 try:
                     restrIndices[key] = header.index(key)
                     if not isinstance(restrictions[key], list):
                         restrictions[key] = [restrictions[key]]
                     restrictions[key] = copy(restrictions[key])
                 except:
-                    warnings.warn("Ignoring key {} from restrictions"\
-                                  .format(key), stacklevel = 2)
-                    from sys.stderr import flush
-                    flush()
-                    del flush
+                    warn("Ignoring key {} from restrictions.".format(key))
             for key in outputs:
                 try:
                     outputIndices[key] = header.index(key)
                     outputData[key] = np.array([])
                 except:
-                    warnings.warn("Ignoring key {} from outputs".format(key),
-                                  stacklevel = 2)
-                    from sys.stderr import flush
-                    flush()
-                    del flush
-    
+                    warn("Ignoring key {} from outputs.".format(key))
+
             for row in reader:
                 restrTrue = True
                 for key in restrictions.keys():
                     if row[restrIndices[key]] == restrictions[key]:
                         continue
                     try:
                         if np.any(np.isclose(float(row[restrIndices[key]]),
                                   [float(x) for x in restrictions[key]])):
                             continue
                     except: pass
                     restrTrue = False
                 if restrTrue:
                     for key in outputIndices.keys():
                         try:
                             val = row[outputIndices[key]]
                             val = float(val)
                         finally:
                             outputData[key] = np.append(outputData[key], val)
         return outputData
-            
+
     def plot(self, filename:str, xs:List[str], ys:List[str], zs:List[str],
-             onePlot : bool = False):
+             onePlot : bool = False, save : str = None,
+             saveFormat : str = "eps", saveDPI : int = 100, **figspecs):
         """
         Perform plots from data in filename.
     
         Args:
             filename: CSV filename.
             xs: Values to put on x axes.
             ys: Values to put on y axes.
             zs: Meta-values for constraints.
-            onePlot: Whether to create a single figure per x. Defaults to
-                False.
+            onePlot(optional): Whether to create a single figure per x.
+                Defaults to False.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
+            figspecs(optional key args): Optional arguments for matplotlib
+                figure creation.
         """
+        if save is not None:
+            save = save.strip()
         zsVals = self.read(filename, outputs = zs)
         zs = list(zsVals.keys())
         zss = None
         for key in zs:
             vals = np.unique(zsVals[key])
             if zss is None:
                 zss = copy(vals)
             else:
                 zss = list(itertools.product(zss, vals))
         lzs = len(zs)
         for z in zss:
             if lzs <= 1:
                 constr = {zs[0] : z}
             else:
                 constr = {zs[j] : z[j] for j in range(len(zs))}
             data = self.read(filename, restrictions = constr, outputs = xs+ys)
             if onePlot:
                 for x in xs:
                     xVals = data[x]
-                    plt.figure()
+                    p = plt.figure(**figspecs)
+                    logScale = False
                     for y in ys:
                         yVals = data[y]
                         label = '{} vs {} for {}'.format(y, x, constr)
-                        plt.semilogy(xVals, yVals, label = label)
+                        if np.min(yVals) <= - np.finfo(float).eps:
+                            plt.plot(xVals, yVals, label = label)
+                        else:
+                            plt.plot(xVals, yVals, label = label)
+                            if np.log10(np.max(yVals) / np.min(yVals)) > 1.:
+                                logScale = True
+                    if logScale:
+                        ax = p.get_axes()[0]
+                        ax.set_yscale('log')
                     plt.legend()
                     plt.grid()
+                    if save is not None:
+                        prefix = "{}_{}_vs_{}_{}".format(save, ys, x, constr)
+                        plt.savefig(getNewFilename(prefix, saveFormat),
+                                    format = saveFormat, dpi = saveDPI)
                     plt.show()
                     plt.close()
             else:
                 for x, y in itertools.product(xs, ys):
                     xVals, yVals = data[x], data[y]
                     label = '{} vs {} for {}'.format(y, x, constr)
-                    plt.figure()
-                    plt.semilogy(xVals, yVals, label = label)
+                    p = plt.figure(**figspecs)
+                    if np.min(yVals) <= - np.finfo(float).eps:
+                        plt.plot(xVals, yVals, label = label)
+                    else:
+                        plt.plot(xVals, yVals, label = label)
+                        if np.log10(np.max(yVals) / np.min(yVals)) > 1.:
+                            ax = p.get_axes()[0]
+                            ax.set_yscale('log')
+                    plt.legend()
+                    plt.grid()
+                    if save is not None:
+                        prefix = "{}_{}_vs_{}_{}".format(save, y, x, constr)
+                        plt.savefig(getNewFilename(prefix, saveFormat),
+                                    format = saveFormat, dpi = saveDPI)
+                    plt.show()
+                    plt.close()
+
+    def plotCompare(self, filenames:List[str], xs:List[str], ys:List[str],
+                    zs:List[str], onePlot : bool = False, save : str = None,
+                    saveFormat : str = "eps", saveDPI : int = 100,
+                    labels : List[str] = None, **figspecs):
+        """
+        Perform plots from data in filename1 and filename2.
+    
+        Args:
+            filenames: CSV filenames.
+            xs: Values to put on x axes.
+            ys: Values to put on y axes.
+            zs: Meta-values for constraints.
+            onePlot(optional): Whether to create a single figure per x.
+                Defaults to False.
+            save(optional): Where to save plot(s). Defaults to None, i.e. no
+                saving.
+            saveFormat(optional): Format for saved plot(s). Defaults to "eps".
+            saveDPI(optional): DPI for saved plot(s). Defaults to 100.
+            labels: Label for each dataset.
+            figspecs(optional key args): Optional arguments for matplotlib
+                figure creation.
+        """
+        nfiles = len(filenames)
+        if save is not None:
+            save = save.strip()
+        if labels is None:
+            labels = ["{}".format(j + 1) for j in range(nfiles)]
+        zsVals = self.read(filenames[0], outputs = zs)
+        zs = list(zsVals.keys())
+        zss = None
+        for key in zs:
+            vals = np.unique(zsVals[key])
+            if zss is None:
+                zss = copy(vals)
+            else:
+                zss = list(itertools.product(zss, vals))
+        lzs = len(zs)
+        for z in zss:
+            if lzs <= 1:
+                constr = {zs[0] : z}
+            else:
+                constr = {zs[j] : z[j] for j in range(len(zs))}
+            data = [None] * nfiles
+            for j in range(nfiles):
+                data[j] = self.read(filenames[j], restrictions = constr,
+                                    outputs = xs + ys)
+            if onePlot:
+                for x in xs:
+                    xVals = [None] * nfiles
+                    for j in range(nfiles):
+                        try:
+                            xVals[j] = data[j][x]
+                        except:
+                            pass
+                    p = plt.figure(**figspecs)
+                    logScale = False
+                    for y in ys:
+                        for j in range(nfiles):
+                            try:
+                                yVals = data[j][y]
+                            except:
+                                pass
+                            l = '{} vs {} for {}, {}'.format(y, x, constr,
+                                                             labels[j])
+                            if np.min(yVals) <= - np.finfo(float).eps:
+                                plt.plot(xVals[j], yVals, label = l)
+                            else:
+                                plt.plot(xVals[j], yVals, label = l)
+                                if np.log10(np.max(yVals)/np.min(yVals)) > 1.:
+                                    logScale = True
+                    if logScale:
+                        ax = p.get_axes()[0]
+                        ax.set_yscale('log')
+                    plt.legend()
+                    plt.grid()
+                    if save is not None:
+                        prefix = "{}_{}_vs_{}_{}".format(save, ys, x, constr)
+                        plt.savefig(getNewFilename(prefix, saveFormat),
+                                    format = saveFormat, dpi = saveDPI)
+                    plt.show()
+                    plt.close()
+            else:
+                for x, y in itertools.product(xs, ys):
+                    p = plt.figure(**figspecs)
+                    logScale = False
+                    for j in range(nfiles):
+                        xVals, yVals = data[j][x], data[j][y]
+                        l = '{} vs {} for {}, {}'.format(y, x, constr,
+                                                         labels[j])
+                        if np.min(yVals) <= - np.finfo(float).eps:
+                            plt.plot(xVals, yVals, label = l)
+                        else:
+                            plt.plot(xVals, yVals, label = l)
+                            if np.log10(np.max(yVals)/np.min(yVals)) > 1.:
+                                logScale = True
+                    if logScale:
+                        ax = p.get_axes()[0]
+                        ax.set_yscale('log')
                     plt.legend()
                     plt.grid()
+                    if save is not None:
+                        prefix = "{}_{}_vs_{}_{}".format(save, y, x, constr)
+                        plt.savefig(getNewFilename(prefix, saveFormat),
+                                    format = saveFormat, dpi = saveDPI)
                     plt.show()
                     plt.close()
 
diff --git a/rrompy/utilities/parameter_sweeper/__init__.py b/rrompy/utilities/warning_manager/__init__.py
similarity index 87%
copy from rrompy/utilities/parameter_sweeper/__init__.py
copy to rrompy/utilities/warning_manager/__init__.py
index 1571153..7138de5 100644
--- a/rrompy/utilities/parameter_sweeper/__init__.py
+++ b/rrompy/utilities/warning_manager/__init__.py
@@ -1,25 +1,25 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.utilities.parameter_sweeper.parameter_sweeper import ParameterSweeper
+from .warning_manager import warn
 
 __all__ = [
-        'ParameterSweeper'
+        'warn'
           ]
 
 
diff --git a/rrompy/hfengines/base/__init__.py b/rrompy/utilities/warning_manager/warning_manager.py
similarity index 53%
copy from rrompy/hfengines/base/__init__.py
copy to rrompy/utilities/warning_manager/warning_manager.py
index febe1c9..2443872 100644
--- a/rrompy/hfengines/base/__init__.py
+++ b/rrompy/utilities/warning_manager/warning_manager.py
@@ -1,28 +1,34 @@
 # Copyright (C) 2018 by the RROMPy authors
 #
 # This file is part of RROMPy.
 #
 # RROMPy is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # RROMPy is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public License
 # along with RROMPy. If not, see <http://www.gnu.org/licenses/>.
 #
 
-from rrompy.hfengines.base.problem_engine_base import ProblemEngineBase
-from rrompy.hfengines.base.boundary_conditions import BoundaryConditions
-
-__all__ = [
-        'ProblemEngineBase',
-        'BoundaryConditions'
-          ]
-
+import traceback as tb
 
+__all__ = ['warn']
 
+def warn(msg : str = "", stacklevel : int = 0):
+    frameSummary = tb.extract_stack()[- 3 - stacklevel]
+    if frameSummary.name == "<module>":
+        name = ""
+    else:
+        name = ", within {}".format(frameSummary.name)
+    print("\n\x1b[3m  Warning at {}:{}{}:\x1b[0m".format(frameSummary.filename,
+                                                         frameSummary.lineno,
+                                                         name))
+    print(">   \x1b[31m{}\x1b[0m".format(frameSummary.line))
+    if len(msg) > 0:
+        print("\x1b[3m  {}\x1b[0m\n".format(msg))