diff --git a/docker/Dockerfile b/docker/Dockerfile
index 70c74e9ca7523fe39cc8441e0f8f3be0639d0cca..bb1d17ace41f02ef11c936c97bc737331da8d376 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -56,6 +56,14 @@ ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:$IPOPT_DIR/lib
 ## Install PyOptSparse
 #COPY docker/install_pyoptsparse.sh /install
 WORKDIR $POSDIR
+
+
+# Replace python 3 incomplatible files from pyoptsparse with files from pyipopt
+RUN git clone https://github.com/xuy/pyipopt.git && \
+    mv ./pyipopt/src/pyipoptcoremodule.c ./pyoptsparse/pyIPOPT/src/pyipoptcoremodule.c && \
+    mv ./pyipopt/src/hook.h ./pyoptsparse/pyIPOPT/src/hook.h && \
+    mv ./pyipopt/src/callback.c ./pyoptsparse/pyIPOPT/src/callback.c
+
 RUN python setup.py install
 
 #RUN mkdir /notebooks
@@ -67,34 +75,36 @@ RUN python setup.py install
 
 # Add Tini. Tini operates as a process subreaper for jupyter. This prevents
 # kernel crashes.
-#ENV TINI_VERSION v0.6.0
-#ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/bin/tini
-#RUN chmod +x /usr/bin/tini
+ENV TINI_VERSION v0.6.0
+ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/bin/tini
+RUN chmod +x /usr/bin/tini
 
 
 # Install the Colonel
 
-RUN mkdir /deb
-WORKDIR /deb
-COPY docker/*.deb /deb/
-RUN dpkg -i *.deb
+#RUN mkdir /deb
+#WORKDIR /deb
+#COPY docker/*.deb /deb/
+#RUN dpkg -i *.deb
 
 RUN apt-get clean \
  && apt-get autoremove -y
 
+RUN apt-get install lazarus -y 
+ 
 #RUN mkdir /install
-RUN mkdir /install/source
-RUN mkdir /install/FugaLib
-WORKDIR   /install
-COPY topfarm/cost_models/fuga/Colonel/source/*.pas /install/source/
-COPY topfarm/cost_models/fuga/Colonel/FugaLib/FugaLib.lpr /install/FugaLib/
-COPY topfarm/cost_models/fuga/Colonel/FugaLib/FugaLib.lpi /install/FugaLib
+#RUN mkdir /install/source
+#RUN mkdir /install/FugaLib
+#WORKDIR   /install
+#COPY topfarm/cost_models/fuga/Colonel/source/*.pas /install/source/
+#COPY topfarm/cost_models/fuga/Colonel/FugaLib/FugaLib.lpr /install/FugaLib/
+#COPY topfarm/cost_models/fuga/Colonel/FugaLib/FugaLib.lpi /install/FugaLib
 
 ## Build
-RUN lazbuild /install/FugaLib/FugaLib.lpr
+RUN lazbuild /install/FugaLib/FugaLib.lpi
 
-#RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
-#RUN apt-get update -y && apt-get install -y nodejs
+RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
+RUN apt-get update -y && apt-get install -y nodejs
 
 
 #RUN jupyter labextension install @jupyter-widgets/jupyterlab-manager \
diff --git a/docker/fpc-src_3.0.4-2_amd64.deb b/docker/fpc-src_3.0.4-2_amd64.deb
deleted file mode 100644
index 0c121d0fa64ace642134c8559cce2c341eb9e6a8..0000000000000000000000000000000000000000
Binary files a/docker/fpc-src_3.0.4-2_amd64.deb and /dev/null differ
diff --git a/docker/fpc_3.0.4-2_amd64.deb b/docker/fpc_3.0.4-2_amd64.deb
deleted file mode 100644
index 986469225241e34ee0228b4d60c5d6eef6cbe4c1..0000000000000000000000000000000000000000
Binary files a/docker/fpc_3.0.4-2_amd64.deb and /dev/null differ
diff --git a/tests/test_fuga/test_pyfuga.py b/tests/test_fuga/test_pyfuga.py
index 3fea940944364ce149b672cfc7b5005ea7395090..2405260e457610c37b8e1e4ea5f2befc32bb33af 100644
--- a/tests/test_fuga/test_pyfuga.py
+++ b/tests/test_fuga/test_pyfuga.py
@@ -23,10 +23,10 @@ def get_fuga():
         check_lib_exists()
         pyFuga = PyFuga()
         pyFuga.setup(farm_name='Horns Rev 1',
-                     turbine_model_path=fuga_path + 'LUT/', turbine_model_name='Vestas_V80_(2_MW_offshore)[h=67.00]',
+                     turbine_model_path=fuga_path + 'LUTs-T/', turbine_model_name='Vestas_V80_(2_MW_offshore)[h=70.00]',
                      tb_x=tb_x, tb_y=tb_y,
-                     mast_position=(0, 0, 70), z0=0.0001, zi=400, zeta0=0,
-                     farms_dir=fuga_path + 'LUT/Farms/', wind_atlas_path='Horns Rev 1/hornsrev_north_only.lib', climate_interpolation=False)
+                     mast_position=(0, 0, 70), z0=0.03, zi=400, zeta0=0,
+                     farms_dir=fuga_path + 'LUTs-T/Farms/', wind_atlas_path='MyFarm/north_pm30_only.lib', climate_interpolation=False)
         return pyFuga
     return _fuga
 
@@ -67,37 +67,39 @@ def testSetup(get_fuga):
 
 def testAEP_one_tb(get_fuga):
     pyFuga = get_fuga([0], [0])
-    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0], [0]]).T), [7.450272, 7.450272, 0.424962, 1.])
+    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0], [0]]).T), [8.2896689155874324, 8.2896689155874324, 0.472841, 1.])
     pyFuga.cleanup()
 
 
 def testAEP(pyFuga):
-    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0, 200], [0, 0]]).T), [14.866138, 14.900544, 0.423981, 0.997691])
-    np.testing.assert_array_almost_equal(pyFuga.get_aep_gradients(np.array([[0, 200], [0, 0]]).T), 0)
-    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0, 0], [0, 200]]).T), [12.124883, 14.900544, 0.3458, 0.813721])
-    np.testing.assert_array_almost_equal(pyFuga.get_aep_gradients(np.array([[0, 0], [0, 200]]).T), [[-0.001794, 0.001794],
-                                                                                                    [-0.008126, 0.008126],
-                                                                                                    [0., 0.]])
-    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0, 200], [0, 200]]).T), [14.864909, 14.900544, 0.423946, 0.997608])
-    np.testing.assert_array_almost_equal(pyFuga.get_aep_gradients(np.array([[0, 200], [0, 200]]).T), [[-5.165553e-06, 5.165553e-06],
-                                                                                                      [1.599768e-06, -1.599768e-06],
-                                                                                                      [0.000000e+00, 0.000000e+00]])
+    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0, 1000], [0, 0]]).T), [
+                                         2 * 8.2896689155874324, 2 * 8.2896689155874324, 0.472841, 1.])
+    np.testing.assert_array_almost_equal(pyFuga.get_aep_gradients(np.array([[0, 1000], [0, 0]]).T), 0)
+    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0, 0], [0, 200]]).T), [14.688347, 16.579338,  0.41891,  0.885943])
+    np.testing.assert_array_almost_equal(pyFuga.get_aep_gradients(np.array([[0, 0], [0, 200]]).T), [[-0.003789,  0.003789],
+                                                                                                    [-0.007204,  0.007204],
+                                                                                                    [0.,  0.]])
+    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0, 200], [0, 200]]).T), [20.352901, 16.579338,  0.580462,  1.227606])
+    np.testing.assert_array_almost_equal(pyFuga.get_aep_gradients(np.array([[0, 200], [0, 200]]).T), [[-2.033273e-05,  2.033273e-05],
+                                                                                                      [7.255895e-06, -7.255895e-06],
+                                                                                                      [0.000000e+00,  0.000000e+00]])
     pyFuga.cleanup()
 
 
 def testLargeOffset(pyFuga):
     o = 1.e16
-    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0 + o, 0 + o], [0 + o, 200 + o]]).T), [12.124883, 14.900544, 0.3458, 0.813721])
-    np.testing.assert_array_almost_equal(pyFuga.get_aep_gradients(), [[-0.001794, 0.001794],
-                                                                      [-0.008126, 0.008126],
-                                                                      [0., 0.]])
+    np.testing.assert_array_almost_equal(pyFuga.get_aep(np.array([[0 + o, 0 + o], [0 + o, 200 + o]]).T), [14.688347, 16.579338,  0.41891,  0.885943])
+    np.testing.assert_array_almost_equal(pyFuga.get_aep_gradients(), [[-0.003789,  0.003789],
+                                                                      [-0.007204,  0.007204],
+                                                                      [0.,  0.]])
+
 
 def testAEP_topfarm(get_fuga):
     pyFuga = get_fuga()
-    init_pos = [[0, 0], [200, 0]]
+    init_pos = [[0, 0], [1000, 0]]
     tf = TopFarm(init_pos, pyFuga.get_TopFarm_cost_component(), 160, init_pos, boundary_type='square')
     tf.evaluate()
-    np.testing.assert_array_almost_equal(tf.get_cost(), -14.866138)
+    np.testing.assert_array_almost_equal(tf.get_cost(), -16.579337831174865)
 
 
 def test_pyfuga_cmd():
diff --git a/tests/topfarm/__init__.py b/tests/topfarm/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/topfarm/test_drivers.py b/tests/topfarm/test_drivers.py
new file mode 100644
index 0000000000000000000000000000000000000000..39faec7ad32a72137e6f1db21140b9b5dd447643
--- /dev/null
+++ b/tests/topfarm/test_drivers.py
@@ -0,0 +1,43 @@
+from topfarm import TopFarm
+import numpy as np
+import pytest
+from topfarm.cost_models.dummy import DummyCost
+from topfarm.plotting import NoPlot
+from topfarm.easy_drivers import EasyScipyOptimizeDriver, EasyPyOptSparseIPOPT
+
+
+initial = [[6, 0], [6, -8], [1, 1]]  # initial turbine layouts
+optimal = np.array([[2.5, -3], [6, -7], [4.5, -3]])  # desired turbine layouts
+boundary = [(0, 0), (6, 0), (6, -10), (0, -10)]  # turbine boundaries
+desired = [[3, -3], [7, -7], [4, -3]]  # desired turbine layouts
+
+
+@pytest.fixture
+def topfarm_generator():
+    def _topfarm_obj(driver):
+        # from topfarm.cost_models.dummy import DummyCostPlotComp
+        # plot_comp = DummyCostPlotComp(desired)
+        plot_comp = NoPlot()
+        return TopFarm(initial, DummyCost(desired), 2, plot_comp=plot_comp, boundary=boundary, driver=driver)
+    return _topfarm_obj
+
+
+@pytest.mark.parametrize('driver,tol', [(EasyScipyOptimizeDriver(), 1e-4),
+                                        (EasyScipyOptimizeDriver(tol=1e-3), 1e-2),
+                                        (EasyScipyOptimizeDriver(maxiter=13), 1e-1),
+                                        (EasyScipyOptimizeDriver(optimizer='COBYLA', tol=1e-3, disp=False), 1e-2),
+                                        (EasyPyOptSparseIPOPT(), 1e-4),
+                                        ][:])
+def test_optimizers(driver, tol, topfarm_generator):
+    if driver.__class__.__name__ == "PyOptSparseMissingDriver":
+        pytest.xfail("reason")
+    tf = topfarm_generator(driver)
+    tf.evaluate()
+    print(driver.__class__.__name__)
+    tf.optimize()
+    tb_pos = tf.turbine_positions
+    # tf.plot_comp.show()
+
+    assert sum((tb_pos[2] - tb_pos[0])**2) > 2**2 - tol  # check min spacing
+    assert tb_pos[1][0] < 6 + tol  # check within border
+    np.testing.assert_array_almost_equal(tb_pos, optimal, -int(np.log10(tol)))
diff --git a/tests/test_topfarm.py b/tests/topfarm/test_topfarm.py
similarity index 97%
rename from tests/test_topfarm.py
rename to tests/topfarm/test_topfarm.py
index a8758a4bb8439799c10af1f5e5892a69fb256825..dd8d02ab137d81ea00ecf5687ecfd98d8b932b93 100644
--- a/tests/test_topfarm.py
+++ b/tests/topfarm/test_topfarm.py
@@ -1,8 +1,3 @@
-'''
-Created on 17. maj 2018
-
-@author: mmpe
-'''
 from topfarm import TopFarm
 
 import numpy as np
diff --git a/topfarm/_topfarm.py b/topfarm/_topfarm.py
index 572c9efaa98d9012bbac72775a39658e9757dd61..1e0e75d8450f5188751db4628a61ec1c956fdefe 100644
--- a/topfarm/_topfarm.py
+++ b/topfarm/_topfarm.py
@@ -19,7 +19,7 @@ class TopFarm(object):
     """
 
     def __init__(self, turbines, cost_comp, min_spacing, boundary, boundary_type='convex_hull', plot_comp=None,
-                 driver_options={'optimizer': 'SLSQP'}):
+                 driver=ScipyOptimizeDriver()):
 
         self.initial_positions = turbines = np.array(turbines)
 
@@ -32,19 +32,18 @@ class TopFarm(object):
         indeps = prob.model.add_subsystem('indeps', IndepVarComp(), promotes=['*'])
         min_x, min_y = self.boundary_comp.vertices.min(0)
         mean_x, mean_y = self.boundary_comp.vertices.mean(0)
-        if driver_options['optimizer'] == 'SLSQP':
+        design_var_kwargs = {}
+
+        if 'optimizer' in driver.options and driver.options['optimizer'] == 'SLSQP':
             min_x, min_y, mean_x, mean_y = 0, 0, 1, 1  # scaling disturbs SLSQP
+            # Default +/- sys.float_info.max does not work for SLSQP
+            design_var_kwargs = {'lower': np.nan, 'upper': np.nan}
         indeps.add_output('turbineX', turbines[:, 0], units='m', ref0=min_x, ref=mean_x)
         indeps.add_output('turbineY', turbines[:, 1], units='m', ref0=min_y, ref=mean_y)
         indeps.add_output('boundary', self.boundary_comp.vertices, units='m')
         prob.model.add_subsystem('cost_comp', cost_comp, promotes=['*'])
-        prob.driver = ScipyOptimizeDriver()
+        prob.driver = driver
 
-        prob.driver.options.update(driver_options)
-        design_var_kwargs = {}
-        if driver_options['optimizer'] == 'SLSQP':
-            # Default +/- sys.float_info.max does not work for SLSQP
-            design_var_kwargs = {'lower': np.nan, 'upper': np.nan}
         prob.model.add_design_var('turbineX', **design_var_kwargs)
         prob.model.add_design_var('turbineY', **design_var_kwargs)
         prob.model.add_objective('cost')
diff --git a/topfarm/cost_models/dummy.py b/topfarm/cost_models/dummy.py
index 777b77f80e09eddd43d4f210541731aead66c4df..77a99f00f423eaccd360346288a56c8013c1dc94 100644
--- a/topfarm/cost_models/dummy.py
+++ b/topfarm/cost_models/dummy.py
@@ -19,9 +19,6 @@ class DummyCost(ExplicitComponent):
         self.optimal = np.array(optimal_positions)
         self.N = self.optimal.shape[0]
 
-    def cost(self, x, y):
-        """Evaluate cost function"""
-
     def setup(self):
         self.add_input('turbineX', val=np.zeros(self.N), units='m')
         self.add_input('turbineY', val=np.zeros(self.N), units='m')
diff --git a/topfarm/cost_models/fuga/Colonel b/topfarm/cost_models/fuga/Colonel
index 01e2b99aa8f7f40d7a020710f9a0374bcfa7f26c..4910e86f1297f55d40f57a62be8f0f287b6e55e7 160000
--- a/topfarm/cost_models/fuga/Colonel
+++ b/topfarm/cost_models/fuga/Colonel
@@ -1 +1 @@
-Subproject commit 01e2b99aa8f7f40d7a020710f9a0374bcfa7f26c
+Subproject commit 4910e86f1297f55d40f57a62be8f0f287b6e55e7
diff --git a/topfarm/cost_models/fuga/py_fuga.py b/topfarm/cost_models/fuga/py_fuga.py
index a82e5036fea6fe8179bcfd5942c2b8c803363202..450307c1a61a2beb1ee70674f384de5e339640a0 100644
--- a/topfarm/cost_models/fuga/py_fuga.py
+++ b/topfarm/cost_models/fuga/py_fuga.py
@@ -130,10 +130,10 @@ def try_me():
     if __name__ == '__main__':
         pyFuga = PyFuga()
         pyFuga.setup(farm_name='Horns Rev 1',
-                     turbine_model_path=fuga_path + 'LUT/', turbine_model_name='Vestas_V80_(2_MW_offshore)[h=67.00]',
+                     turbine_model_path=fuga_path + 'LUTs-T/', turbine_model_name='Vestas_V80_(2_MW_offshore)[h=70.00]',
                      tb_x=[423974, 424033], tb_y=[6151447, 6150889],
-                     mast_position=(0, 0, 70), z0=0.0001, zi=400, zeta0=0,
-                     farms_dir=fuga_path + 'LUT/Farms/', wind_atlas_path='Horns Rev 1\hornsrev.lib')
+                     mast_position=(0, 0, 70), z0=0.03, zi=400, zeta0=0,
+                     farms_dir=fuga_path + 'LUTs-T/Farms/', wind_atlas_path='MyFarm\DEN05JBgr_7.813E_55.489N_7.4_5.lib')
 
         print(pyFuga.get_no_turbines())
         print(pyFuga.get_aep(np.array([[0, 0], [0, 1000]])))
diff --git a/topfarm/easy_drivers.py b/topfarm/easy_drivers.py
new file mode 100644
index 0000000000000000000000000000000000000000..339d244daa71452f4d602dc3cf628b9f3aba40f7
--- /dev/null
+++ b/topfarm/easy_drivers.py
@@ -0,0 +1,48 @@
+from openmdao.drivers.scipy_optimizer import ScipyOptimizeDriver
+
+
+class EasyScipyOptimizeDriver(ScipyOptimizeDriver):
+
+    def __init__(self, optimizer='SLSQP', maxiter=200, tol=1e-6, disp=True):
+        """
+        Parameters
+        ----------
+        optimizer : {'COBYLA', 'SLSQP'}
+            Gradients are only supported by SLSQP
+        maxiter : int
+            Maximum number of iterations.
+        tol : float
+            Tolerance for termination. For detailed control, use solver-specific options.
+        disp : bool
+            Set to False to prevent printing of Scipy convergence messages
+        """
+        ScipyOptimizeDriver.__init__(self)
+        self.options.update({'optimizer': optimizer, 'maxiter': maxiter, 'tol': tol, 'disp': disp})
+
+
+try:
+    from openmdao.drivers.pyoptsparse_driver import pyOptSparseDriver
+
+#     Not working:
+#     capi_return is NULL
+#     Call-back cb_slfunc_in_slsqp__user__routines failed.
+#
+#     class EasyPyOptSparseSLSQP(pyOptSparseDriver):
+#         def __init__(self, maxit=200, acc=1e-6):
+#             pyOptSparseDriver.__init__(self)
+#             self.options.update({'optimizer': 'SLSQP'})
+#             self.opt_settings.update({'MAXIT': maxit, 'ACC': acc})
+
+    class EasyPyOptSparseIPOPT(pyOptSparseDriver):
+        def __init__(self, max_iter=200):
+            pyOptSparseDriver.__init__(self)
+            self.options.update({'optimizer': 'IPOPT'})
+            self.opt_settings.update({'linear_solver': 'ma27', 'max_iter': max_iter})
+
+
+except ModuleNotFoundError:
+    class PyOptSparseMissingDriver(object):
+        options = {}
+
+    EasyPyOptSparseSLSQP = PyOptSparseMissingDriver
+    EasyPyOptSparseIPOPT = PyOptSparseMissingDriver