diff --git a/CMake/FindCODI.cmake b/CMake/FindCODI.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..4e3551cf73d49ee5e7929acf7eab4b0d0504c760
--- /dev/null
+++ b/CMake/FindCODI.cmake
@@ -0,0 +1,75 @@
+# Copyright 2023 University of Liège
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Try to find CoDiPack headers
+# ----------------------------------------------------------------------------   
+# output:
+#    CODI_FOUND             : whether the packae was found
+#    CODI_INCLUDE_DIRS      : where the headers are [cached]
+#    CODI_VERSION           : version number
+# ----------------------------------------------------------------------------
+# autodetection:
+#    use "CMAKE_PREFIX_PATH=/path/to/package/"
+#    or  "CMAKE_INCLUDE_PATH=/path/to/package/include"
+#    or  "INCLUDE=/path/to/package/include"
+# ----------------------------------------------------------------------------   
+
+# Check version
+macro(_check_version)
+    file(READ "${CODI_INCLUDE_DIRS}/codi.hpp" _version_header)
+
+    string(REGEX MATCH "define[ \t]+CODI_MAJOR_VERSION[ \t]+([0-9]+)" major_version_match "${_version_header}")
+    set(CODI_MAJOR_VERSION "${CMAKE_MATCH_1}")                        
+    string(REGEX MATCH "define[ \t]+CODI_MINOR_VERSION[ \t]+([0-9]+)" minor_version_match "${_version_header}")
+    set(CODI_MINOR_VERSION "${CMAKE_MATCH_1}")                        
+    string(REGEX MATCH "define[ \t]+CODI_BUILD_VERSION[ \t]+([0-9]+)" build_version_match "${_version_header}")
+    set(CODI_BUILD_VERSION "${CMAKE_MATCH_1}")
+
+    set(CODI_VERSION ${CODI_MAJOR_VERSION}.${CODI_MINOR_VERSION}.${CODI_BUILD_VERSION})
+
+    if(${CODI_VERSION} VERSION_LESS ${CODI_FIND_VERSION})
+        message(FATAL_ERROR "CoDiPack version ${CODI_VERSION} found in ${CODI_INCLUDE_DIRS}, but at least version ${CODI_FIND_VERSION} is required!")
+    endif()
+endmacro()
+
+# Set a dummy version if not provided
+if(NOT CODI_FIND_VERSION)
+    if(NOT CODI_FIND_VERSION_MAJOR)
+        set(CODI_FIND_VERSION_MAJOR 2)
+    endif()
+    if(NOT CODI_FIND_VERSION_MINOR)
+        set(CODI_FIND_VERSION_MINOR 0)
+    endif()
+    if(NOT CODI_FIND_VERSION_BUILD)
+        set(CODI_FIND_VERSION_BUILD 2)
+    endif()
+
+    set(CODI_FIND_VERSION "${CODI_FIND_VERSION_MAJOR}.${CODI_FIND_VERSION_MINOR}.${CODI_FIND_VERSION_BUILD}")
+endif()
+
+# Find the header and check the version
+find_path(CODI_INCLUDE_DIRS "codi.hpp")
+if (CODI_INCLUDE_DIRS)
+    _check_version()
+else()
+    message(FATAL_ERROR "CoDiPack headers not found! Define the path in the INCLUDE environment variable.")
+endif()
+
+# handle the QUIETLY and REQUIRED arguments and set EIGEN_FOUND to TRUE
+# if all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CODI
+                                  FOUND_VAR CODI_FOUND
+                                  REQUIRED_VARS CODI_INCLUDE_DIRS
+                                  VERSION_VAR CODI_VERSION)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 03edcc4736eda7a6192931ff055e8bfb4f592861..b916eb53c6c6efddc4d4248a95ba804b9ff3c1b9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,6 +54,8 @@ ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
     #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything") # add verbosity
 ENDIF()
 
+OPTION(USE_CODI         "Compile with CoDiPack"         OFF)
+
 # -- DEPENDENCIES
 # Python
 # use Python3_ROOT_DIR if wrong python found (e.g. anaconda)
@@ -61,7 +63,14 @@ FIND_PACKAGE(Python3 COMPONENTS Interpreter Development)
 SET(PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
 SET(PYTHON_LIBRARIES ${Python3_LIBRARIES})
 SET(PYTHON_INCLUDE_PATH ${Python3_INCLUDE_DIRS}) 
-SET(PYTHONLIBS_VERSION_STRING ${Python3_VERSION})     
+SET(PYTHONLIBS_VERSION_STRING ${Python3_VERSION}) 
+
+# CoDiPack
+IF(USE_CODI)
+    FIND_PACKAGE(CODI 2.1.0 REQUIRED)
+    MESSAGE(STATUS "CODI_INCLUDE_DIRS: ${CODI_INCLUDE_DIRS}")
+ENDIF()
+
 
 # SWIG
 FIND_PACKAGE(SWIG REQUIRED)
@@ -74,6 +83,10 @@ ENDIF()
 # -- DEFINE (for SWIG to detect definitions)
 INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) # to find "amfe_def.h"
 
+# -- DEFINE (for SWIG to detect definitions)
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/blaster_def.h.in ${CMAKE_BINARY_DIR}/blaster_def.h)
+INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) # pass to the most top-level build dir to find "sdpm_def.h"
+
 # -- CTest
 ENABLE_TESTING()
 
@@ -109,3 +122,4 @@ MESSAGE(STATUS "* BUILD TYPE: ${CMAKE_BUILD_TYPE}")
 MESSAGE(STATUS "* VTK SUPPORT: ${USE_VTK}")
 MESSAGE(STATUS "* MKL SUPPORT: ${USE_MKL}")
 MESSAGE(STATUS "* MUMPS SUPPORT: ${USE_MUMPS}")
+MESSAGE(STATUS "* CoDiPack SUPPORT: ${USE_CODI}")
diff --git a/blast/_src/blastw.i b/blast/_src/blastw.i
index 7938cd7f1ffda01b03e9a21d929dceb40670685c..58432beb1fc04e8bc5faf87b4b5cbe1379be8bb2 100644
--- a/blast/_src/blastw.i
+++ b/blast/_src/blastw.i
@@ -37,6 +37,39 @@ threads="1"
 
 %}
 
+%include "std_vector.i"
+
+%include "blaster_def.h" // needed to access USE_CODI in SWIG interface
+#ifndef USE_CODI
+typedef double bldouble; // needed so that SWIG does not convert bldouble to double
+#endif
+%typemap(in) bldouble* (bldouble temp) {
+    if (PyFloat_Check($input)) {
+        temp = bldouble(PyFloat_AsDouble($input));
+        $1 = &temp;
+    } else if (PyObject_TypeCheck($input, &PyCapsule_Type)) {
+        $1 = (bldouble *) PyCapsule_GetPointer($input, NULL);
+    } else if (SWIG_IsOK(SWIG_ConvertPtr($input, (void **)&$1, SWIGTYPE_p_bldouble, 0))) {
+        // Successfully converted to bldouble*
+    } else {
+        PyErr_SetString(PyExc_TypeError, "Expected a float or bldouble");
+        return NULL;
+    }
+}
+%typemap(out) bldouble {
+#ifndef USE_CODI
+    $result = PyFloat_FromDouble($1);
+#else
+    $result = PyFloat_FromDouble(($1).getValue());
+#endif
+}
+#ifndef USE_CODI
+%rename(std_vector_double) std::vector<bldouble>;
+%rename(std_vector_vector_double) std::vector<std::vector<bldouble>>;
+#else
+%template(std_vector_bldouble) std::vector<bldouble>;
+%template(std_vector_vector_bldouble) std::vector<std::vector<bldouble>>;
+#endif
 
 %include "fwkw.swg"
 
@@ -78,6 +111,74 @@ threads="1"
 %template(std_vector_blSection) std::vector<std::shared_ptr<blast::Section>>;
 %template(std_vector_blBoundaryLayer) std::vector<std::shared_ptr<blast::BoundaryLayer>>;
 
+#ifdef USE_CODI
+class bldouble {};
+%extend bldouble {
+    double __float__()
+    {
+        return (*self).getValue();
+    }
+    bldouble __add__(bldouble const &other)
+    {
+        return *self + other;
+    }
+    bldouble __sub__(bldouble const &other)
+    {
+        return *self - other;
+    }
+    bldouble __mul__(bldouble const &other)
+    {
+        return *self * other;
+    }
+    bldouble __div__(bldouble const &other)
+    {
+        return *self / other;
+    }
+    // use repr instead of str so that iterables also print nicely
+    std::string __repr__()
+    {
+        std::ostringstream out; out << *self;
+        return out.str();
+    }
+}
+#endif
+
+class blVector3d {};
+%extend blVector3d {
+	blVector3d(double x, double y, double z)
+	{
+		blVector3d *v = new blVector3d();
+		*v << x,y,z;
+		return v;
+	}
+    double __getitem__(int i)
+    {
+        if (i > 2)
+            throw std::runtime_error("blVector3d: index out of range (size 3)!\n");
+#ifndef USE_CODI
+        return (*self)(i);
+#else
+        return (*self)(i).getValue();
+#endif
+    }
+    // use repr instead of str so that iterables also print nicely
+    std::string __repr__()
+    {
+        std::ostringstream out; out << *self;
+        return out.str();
+    }
+}
+
+%extend std::vector<bldouble> {
+    void __setitem__(size_t i, double val) {
+#ifndef USE_CODI
+        (*$self)[i] = val;
+#else
+        (*$self)[i] = static_cast<bldouble>(val);  // Explicit conversion
+#endif
+    }
+}
+
 %extend blast::Section {
     %pythoncode {
         def __iter__(self):
@@ -92,4 +193,4 @@ threads="1"
             else:
                 raise StopIteration
     }
-}
\ No newline at end of file
+}
diff --git a/blast/blCoupler.py b/blast/blCoupler.py
index e03334f74613283abe2e922fe5a64cfcc57c9dfd..8810afbcda88b786f2731b785c84c7a0e8f17cf0 100644
--- a/blast/blCoupler.py
+++ b/blast/blCoupler.py
@@ -113,12 +113,12 @@ class Coupler:
             self.isol.getBlowingBoundary(couplIter+1)
 
             aeroCoeffs['Cl'].append(self.isol.getCl())
-            aeroCoeffs['Cd'].append(self.isol.getCd() + self.vsol.Cdf)
-            aeroCoeffs['Cdwake'].append(self.vsol.Cdt)
+            aeroCoeffs['Cd'].append(self.isol.getCd() + self.vsol.getCdf())
+            aeroCoeffs['Cdwake'].append(self.vsol.getCdt())
 
             # Check convergence status.
-            cd = self.vsol.Cdf + self.isol.getCd()
-            #cd = self.vsol.Cdt if self.vsol.Cdt != 0 else self.vsol.Cdf + self.isol.getCd()
+            cd = self.vsol.getCdf() + self.isol.getCd()
+            #cd = self.vsol.getCdt() if self.vsol.getCdt() != 0 else self.vsol.getCdf() + self.isol.getCd()
             error = abs((cd - cdPrev) / cd) if cd != 0 else 1
 
             # Save restart file
@@ -127,7 +127,7 @@ class Coupler:
                 self.isol.save_restart(cd, sfx=_sfx)
 
             if error <= self.tol:
-                print(ccolors.ANSI_GREEN, '{:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>6.4f} | {:>5.0f} {:>5.0f} | {:>6.3f}\n'.format(couplIter, self.isol.getCl(), self.isol.getTotalDrag(), self.vsol.Cdt, self.vsol.bodies[0].getAvgxtr(0), self.vsol.bodies[0].getAvgxtr(1), iEc, vEc, np.log10(error)), ccolors.ANSI_RESET)
+                print(ccolors.ANSI_GREEN, '{:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>6.4f} | {:>5.0f} {:>5.0f} | {:>6.3f}\n'.format(couplIter, self.isol.getCl(), self.isol.getTotalDrag(), self.vsol.getCdt(), self.vsol.bodies[0].getAvgxtr(0), self.vsol.bodies[0].getAvgxtr(1), iEc, vEc, np.log10(error)), ccolors.ANSI_RESET)
                 if iEc != 0 or vEc != 0:
                     print(ccolors.ANSI_RED, 'Warning: Solver(s) did not converge', ccolors.ANSI_RESET)
                 if write:
@@ -143,7 +143,7 @@ class Coupler:
                 print('{:>5s}| {:>7s} {:>7s} {:>7s} | {:>6s} {:>6s} | {:>5s} {:>5s} | {:>6s}'.format('It', 'Cl', 'Cd', 'Cdwake', 'xtrT', 'xtrB', 'iOut', 'vOut', 'Error'))
                 print('  --------------------------------------------------------------------')
             if couplIter % self.iterPrint == 0:
-                print(' {:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>6.4f} | {:>5.0f} {:>5.0f} | {:>6.3f}'.format(couplIter, self.isol.getCl(), self.isol.getTotalDrag(), self.vsol.Cdt, self.vsol.bodies[0].getAvgxtr(0), self.vsol.bodies[0].getAvgxtr(1), iEc, vEc, np.log10(error)))
+                print(' {:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>6.4f} | {:>5.0f} {:>5.0f} | {:>6.3f}'.format(couplIter, self.isol.getCl(), self.isol.getTotalDrag(), self.vsol.getCdt(), self.vsol.bodies[0].getAvgxtr(0), self.vsol.bodies[0].getAvgxtr(1), iEc, vEc, np.log10(error)))
                 if self.isol.getVerbose() != 0 or self.vsol.verbose != 0:
                     print('')
             couplIter += 1
@@ -152,7 +152,7 @@ class Coupler:
             print('')
             print('{:>5s}| {:>7s} {:>7s} {:>7s} | {:>6s} {:>8s} | {:>6s}'.format('It', 'Cl', 'Cd', 'Cdwake', 'xtrT', 'xtrB', 'Error'))
             print('  --------------------------------------------------------------------')
-            print(ccolors.ANSI_RED, '{:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>7.4f} | {:>6.3f}\n'.format(couplIter-1, self.isol.getCl(), self.isol.getTotalDrag(), self.vsol.Cdt, self.vsol.bodies[0].getAvgxtr(0), self.vsol.bodies[0].getAvgxtr(1), np.log10(error)), ccolors.ANSI_RESET)
+            print(ccolors.ANSI_RED, '{:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>7.4f} | {:>6.3f}\n'.format(couplIter-1, self.isol.getCl(), self.isol.getTotalDrag(), self.vsol.getCdt(), self.vsol.bodies[0].getAvgxtr(0), self.vsol.bodies[0].getAvgxtr(1), np.log10(error)), ccolors.ANSI_RESET)
             if write:
                 self.isol.writeCp(sfx='_viscous'+self.filesfx)
                 for i, body in enumerate(self.vsol.bodies):
diff --git a/blast/blUtils.py b/blast/blUtils.py
index 2b4e24858dd22d491f3423f43bc7c183374470d5..1bfe4d7f05372bb107200173ec2d06fb23d22b49 100644
--- a/blast/blUtils.py
+++ b/blast/blUtils.py
@@ -267,9 +267,9 @@ def save(sections, **kwargs):
                     region_points.append([nod.pos[0], nod.pos[1], nod.pos[2]])
 
                     for var in solution_dict.keys():
-                        value = getattr(reg, var)[inod]
+                        value = float(getattr(reg, var)[inod])
                         if var == "cf" or var == "cd":
-                            value *= reg.vt[inod] * reg.vt[inod]
+                            value *= float(reg.vt[inod]) * float(reg.vt[inod])
                         region_solution[var].append(value)
 
                 region_points = np.array(region_points)
diff --git a/blast/interfaces/blSolversInterface.py b/blast/interfaces/blSolversInterface.py
index ced73ad27bf6d8725957a3d16a415d69b76852d7..66cec4131f6dd3ef12499bf9337b6df5da1fac71 100644
--- a/blast/interfaces/blSolversInterface.py
+++ b/blast/interfaces/blSolversInterface.py
@@ -122,7 +122,7 @@ class SolversInterface:
         float
             Total drag coefficient.
         """
-        return self.getCd() + self.vSolver.Cdf
+        return self.getCd() + self.vSolver.getCdf()
 
     def getBlowingBoundary(self, couplIter:int):
         """Get blowing boundary condition from the viscous solver.
@@ -361,7 +361,7 @@ class SolversInterface:
                     # Create node
                     nodes = blast.std_vector_blNode()
                     for inod, nod in enumerate(pystruct.getNodes(reg.getName())):
-                        pos = tbox.Vector3d(nod[xIdx], nod[yIdx], nod[zIdx])
+                        pos = blast.blVector3d(nod[xIdx], nod[yIdx], nod[zIdx])
                         row = int(pystruct.getNodeConnectList(reg.getName())[inod]) if self.cfg['interpolator'] == 'Matching' else inod
                         nodes.push_back(blast.blNode(inod, pos, row))
                     # Set nodes
diff --git a/blast/src/CMakeLists.txt b/blast/src/CMakeLists.txt
index cd3f09b324b535c8eaa3e422df8faa6af56dfd51..9d3617aaf25beeedb3888b3607037f1592e986a2 100644
--- a/blast/src/CMakeLists.txt
+++ b/blast/src/CMakeLists.txt
@@ -23,6 +23,11 @@ TARGET_INCLUDE_DIRECTORIES(blast PUBLIC ${PROJECT_SOURCE_DIR}/blast/src
                                         ${PROJECT_SOURCE_DIR}/modules/dartflo/ext/amfe/fwk/src
                                         ${PROJECT_SOURCE_DIR}/modules/dartflo/dart/src
                                         ${PYTHON_INCLUDE_PATH})
+IF(USE_CODI)
+    TARGET_INCLUDE_DIRECTORIES(blast PUBLIC ${CODI_INCLUDE_DIRS})
+    TARGET_COMPILE_DEFINITIONS(blast PUBLIC CODI_EnableEigen)
+ENDIF()
+
 TARGET_LINK_LIBRARIES(blast dart fwk tbox)
 
 INSTALL(TARGETS blast DESTINATION ${CMAKE_INSTALL_PREFIX})
diff --git a/blast/src/blBody.cpp b/blast/src/blBody.cpp
index 63c91210a7773c37b95e79e7a2c2c8c48661fdde..d56b5820190e4e01021c1da1e4d4f33cc3719b6f 100644
--- a/blast/src/blBody.cpp
+++ b/blast/src/blBody.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
+#include "blast.h"
 #include "blBody.h"
-#include <Eigen/Dense>
 
 using namespace blast;
 
@@ -27,15 +27,15 @@ void Body::add(std::shared_ptr<Section> section)
     sections.push_back(section);
 }
 
-double Body::getAvgxtr(size_t iregion) const
+bldouble Body::getAvgxtr(size_t iregion) const
 {
     // Return the average transition location of a region.
-    double sum = 0.0;
+    bldouble sum = 0.0;
     for (auto &section : sections)
     {
         sum += section->regions[iregion]->getxoctr();
     }
-    return sum / static_cast<double>(sections.size());
+    return sum / static_cast<bldouble>(sections.size());
 }
 
 void Body::computeDrag()
@@ -48,7 +48,7 @@ void Body::computeDrag()
     for (size_t isection = 1; isection < sections.size(); isection++)
     {
         sections[isection]->computeDrag();
-        double dz = sections[isection]->regions[0]->nodes[0]->pos[2] - sections[isection - 1]->regions[0]->nodes[0]->pos[2];
+        bldouble dz = sections[isection]->regions[0]->nodes[0]->pos[2] - sections[isection - 1]->regions[0]->nodes[0]->pos[2];
         Cdt += sections[isection]->getCdt() * dz;
         Cdf += sections[isection]->getCdf() * dz;
         Cdp += sections[isection]->getCdp() * dz;
diff --git a/blast/src/blBody.h b/blast/src/blBody.h
index c868597e8ae60c4de7433e2710fab9a24e9b071f..c029eac4c7c7bd526bc274741cd7310444caa170 100644
--- a/blast/src/blBody.h
+++ b/blast/src/blBody.h
@@ -19,22 +19,22 @@ class BLAST_API Body : public fwk::wSharedObject
 {
 private:
     std::string name; ///< Name of the body.
-    double span;      ///< Body span. Used for drag computation.
+    bldouble span;      ///< Body span. Used for drag computation.
 
 public:
-    double Cdt; ///< Total drag coefficient of the body
-    double Cdf; ///< Friction drag coefficient of the body
-    double Cdp; ///< Pressure drag coefficient of the body
+    bldouble Cdt; ///< Total drag coefficient of the body
+    bldouble Cdf; ///< Friction drag coefficient of the body
+    bldouble Cdp; ///< Pressure drag coefficient of the body
 
     Body(std::string name, double span = 1.0);
     ~Body() { std::cout << "~blast::Body()" << std::endl; };
     std::vector<std::shared_ptr<Section>> sections; ///< Boundary layer sections.
 
     void add(std::shared_ptr<Section> section);
-    double getAvgxtr(size_t iregion) const;
+    bldouble getAvgxtr(size_t iregion) const;
     void computeDrag();
     std::string getName() const { return name; }
-    double getSpan() const { return span; }
+    bldouble getSpan() const { return span; }
     bool hasWake() const;
 };
 } // namespace blast
diff --git a/blast/src/blBoundaryLayer.cpp b/blast/src/blBoundaryLayer.cpp
index b30b1e931ddd48dc0e293c190a9ce2ed7a66a2de..9e3ca6e65839236c12bb2e2842f1d1ecfd2325d2 100644
--- a/blast/src/blBoundaryLayer.cpp
+++ b/blast/src/blBoundaryLayer.cpp
@@ -1,3 +1,4 @@
+#include "blast.h"
 #include "blBoundaryLayer.h"
 #include "blClosures.h"
 #include "blNode.h"
@@ -74,9 +75,9 @@ void BoundaryLayer::reset()
  *
  * @param Re Freestream Reynolds number.
  */
-void BoundaryLayer::setStagnationBC(double Re)
+void BoundaryLayer::setStagnationBC(bldouble Re)
 {
-    double dv0 = std::abs((vt[1] - vt[0]) / (nodes[1]->xi - nodes[0]->xi));
+    bldouble dv0 = std::abs((vt[1] - vt[0]) / (nodes[1]->xi - nodes[0]->xi));
     if (dv0 > 0)
         u[0] = sqrt(0.075 / (Re * dv0)); // Theta
     else
@@ -94,7 +95,7 @@ void BoundaryLayer::setStagnationBC(double Re)
     }
     deltaStar[0] = u[0] * u[1];
 
-    std::vector<double> lamParam(8, 0.);
+    std::vector<bldouble> lamParam(8, 0.);
     closSolver->laminarClosures(lamParam, u[0], u[1], Ret[0], Me[0], name);
 
     Hstar[0] = lamParam[0];
@@ -114,7 +115,7 @@ void BoundaryLayer::setStagnationBC(double Re)
  * @param UpperCond Variables at the last point on the upper side.
  * @param LowerCond Variables at the last point on the lower side.
  */
-void BoundaryLayer::setWakeBC(double Re, std::vector<std::vector<double>> &teConditions)
+void BoundaryLayer::setWakeBC(bldouble Re, std::vector<std::vector<bldouble>> &teConditions)
 {
     if (name != "wake")
         std::cout << "Warning: Imposing wake boundary condition on " << name
@@ -155,7 +156,7 @@ void BoundaryLayer::setWakeBC(double Re, std::vector<std::vector<double>> &teCon
     deltaStar[0] = u[0] * u[1];
 
     // Laminar closures.
-    std::vector<double> lamParam(8, 0.);
+    std::vector<bldouble> lamParam(8, 0.);
     closSolver->laminarClosures(lamParam, u[0], u[1], Ret[0], Me[0], name);
     Hstar[0] = lamParam[0];
     Hstar2[0] = lamParam[1];
@@ -202,10 +203,10 @@ void BoundaryLayer::computeBlowingVelocity()
     }
 }
 
-std::vector<std::vector<double>> BoundaryLayer::evalGradwrtDeltaStar()
+std::vector<std::vector<bldouble>> BoundaryLayer::evalGradwrtDeltaStar()
 {
-    std::vector<std::vector<double>> gradVe =
-        std::vector<std::vector<double>>(getnElms());
+    std::vector<std::vector<bldouble>> gradVe =
+        std::vector<std::vector<bldouble>>(getnElms());
     for (auto &vec : gradVe)
         vec.resize(getnNodes(), 0.);
 
@@ -218,10 +219,10 @@ std::vector<std::vector<double>> BoundaryLayer::evalGradwrtDeltaStar()
     return gradVe;
 }
 
-std::vector<std::vector<double>> BoundaryLayer::evalGradwrtVt()
+std::vector<std::vector<bldouble>> BoundaryLayer::evalGradwrtVt()
 {
-    std::vector<std::vector<double>> gradVe =
-        std::vector<std::vector<double>>(getnElms());
+    std::vector<std::vector<bldouble>> gradVe =
+        std::vector<std::vector<bldouble>>(getnElms());
     for (auto &vec : gradVe)
         vec.resize(getnNodes(), 0.);
 
@@ -234,10 +235,10 @@ std::vector<std::vector<double>> BoundaryLayer::evalGradwrtVt()
     return gradVe;
 }
 
-std::vector<std::vector<double>> BoundaryLayer::evalGradwrtRho()
+std::vector<std::vector<bldouble>> BoundaryLayer::evalGradwrtRho()
 {
-    std::vector<std::vector<double>> gradVe =
-        std::vector<std::vector<double>>(getnElms());
+    std::vector<std::vector<bldouble>> gradVe =
+        std::vector<std::vector<bldouble>>(getnElms());
     for (auto &vec : gradVe)
         vec.resize(getnNodes(), 0.);
 
@@ -260,25 +261,25 @@ std::vector<std::vector<double>> BoundaryLayer::evalGradwrtRho()
  *
  * dVe_dx = dVe_dloc * dloc_dx
  *
- * @return std::vector<double> Gradient of the velocity with respect to the x
+ * @return std::vector<bldouble> Gradient of the velocity with respect to the x
  * coordinate.
  */
-std::vector<std::vector<double>> BoundaryLayer::evalGradwrtX()
+std::vector<std::vector<bldouble>> BoundaryLayer::evalGradwrtX()
 {
-    std::vector<std::vector<double>> gradVe =
-        std::vector<std::vector<double>>(getnElms());
+    std::vector<std::vector<bldouble>> gradVe =
+        std::vector<std::vector<bldouble>>(getnElms());
     for (auto &vec : gradVe)
         vec.resize(getnNodes(), 0.);
 
     // Compute dVe/dloc
-    std::vector<std::vector<double>> gradVe_loc =
-        std::vector<std::vector<double>>(getnElms());
+    std::vector<std::vector<bldouble>> gradVe_loc =
+        std::vector<std::vector<bldouble>>(getnElms());
     for (auto &vec : gradVe_loc)
         vec.resize(getnNodes(), 0.);
 
     for (size_t i = 1; i < getnNodes(); ++i)
     {
-        double val = 1 / rhoe[i] *
+        bldouble val = 1 / rhoe[i] *
                      (rhoe[i] * vt[i] * deltaStar[i] -
                       rhoe[i - 1] * vt[i - 1] * deltaStar[i - 1]) /
                      ((nodes[i]->xi - nodes[i - 1]->xi) * (nodes[i]->xi - nodes[i - 1]->xi));
@@ -292,8 +293,8 @@ std::vector<std::vector<double>> BoundaryLayer::evalGradwrtX()
     // (y_j - y_j-1)^2) = - dloc/dx_j For loc_i, there are two contributions of
     // x_j except if j = i. loc_n = sqrt((xn-xn-1)^2) + sqrt((xn-1-xn-2)^2) + ...
     // + sqrt((x1-x0)^2)
-    std::vector<std::vector<double>> gradloc_x =
-        std::vector<std::vector<double>>(getnNodes());
+    std::vector<std::vector<bldouble>> gradloc_x =
+        std::vector<std::vector<bldouble>>(getnNodes());
     for (auto &vec : gradloc_x)
         vec.resize(getnNodes(), 0.);
 
@@ -318,22 +319,22 @@ std::vector<std::vector<double>> BoundaryLayer::evalGradwrtX()
     return gradVe;
 }
 
-std::vector<std::vector<double>> BoundaryLayer::evalGradwrtY()
+std::vector<std::vector<bldouble>> BoundaryLayer::evalGradwrtY()
 {
-    std::vector<std::vector<double>> gradVe =
-        std::vector<std::vector<double>>(getnElms());
+    std::vector<std::vector<bldouble>> gradVe =
+        std::vector<std::vector<bldouble>>(getnElms());
     for (auto &vec : gradVe)
         vec.resize(getnNodes(), 0.);
 
     // Compute dVe/dloc
-    std::vector<std::vector<double>> gradVe_loc =
-        std::vector<std::vector<double>>(getnElms());
+    std::vector<std::vector<bldouble>> gradVe_loc =
+        std::vector<std::vector<bldouble>>(getnElms());
     for (auto &vec : gradVe_loc)
         vec.resize(getnNodes(), 0.);
 
     for (size_t i = 1; i < getnNodes(); ++i)
     {
-        double val = 1 / rhoe[i] *
+        bldouble val = 1 / rhoe[i] *
                      (rhoe[i] * vt[i] * deltaStar[i] -
                       rhoe[i - 1] * vt[i - 1] * deltaStar[i - 1]) /
                      ((nodes[i]->xi - nodes[i - 1]->xi) * (nodes[i]->xi - nodes[i - 1]->xi));
@@ -347,8 +348,8 @@ std::vector<std::vector<double>> BoundaryLayer::evalGradwrtY()
     // (y_j - y_j-1)^2) = - dloc/dy_j For loc_i, there are two contributions of
     // y_j except if j = i. loc_n = sqrt((yn-yn-1)^2) + sqrt((yn-1-yn-2)^2) + ...
     // + sqrt((y1-y0)^2)
-    std::vector<std::vector<double>> gradloc_y =
-        std::vector<std::vector<double>>(getnNodes());
+    std::vector<std::vector<bldouble>> gradloc_y =
+        std::vector<std::vector<bldouble>>(getnNodes());
     for (auto &vec : gradloc_y)
         vec.resize(getnNodes(), 0.);
 
@@ -373,11 +374,11 @@ std::vector<std::vector<double>> BoundaryLayer::evalGradwrtY()
     return gradVe;
 }
 
-std::vector<double> BoundaryLayer::getTeConditions() const
+std::vector<bldouble> BoundaryLayer::getTeConditions() const
 {
     // Return [theta, H, N, ue, Ct] at the last node.
     size_t nodeId = getnNodes() - 1;
-    std::vector<double> teCond;
+    std::vector<bldouble> teCond;
     for (size_t ivar = 0; ivar < getnVar(); ++ivar)
         teCond.push_back(u[nodeId * getnVar() + ivar]);
     return teCond;
diff --git a/blast/src/blBoundaryLayer.h b/blast/src/blBoundaryLayer.h
index 04ab90ceea0f7b730433c7c0acfafc8dbb9d24ca..f89f57cc96da4c9e8cd96883ab551e8a99a2c40b 100644
--- a/blast/src/blBoundaryLayer.h
+++ b/blast/src/blBoundaryLayer.h
@@ -22,7 +22,7 @@ class BLAST_API BoundaryLayer : public fwk::wSharedObject
 private:
     unsigned int const nVar =
         5;              ///< Number of variables of the partial differential problem.
-    double nCrit = 9.0; ///< Critical amplification factor.
+    bldouble nCrit = 9.0; ///< Critical amplification factor.
     std::string name;   ///< Name of the region.
 
 public:
@@ -33,38 +33,38 @@ public:
     std::vector<int> no;
 
     // Boundary layer variables.
-    std::vector<double> u; ///< Solution vector (theta, H, N, ue, Ct).
-    std::vector<double>
+    std::vector<bldouble> u; ///< Solution vector (theta, H, N, ue, Ct).
+    std::vector<bldouble>
         Ret;                ///< Reynolds number based on the momentum thickness (theta).
-    std::vector<double> cd; ///< Local dissipation coefficient.
-    std::vector<double> cf; ///< Local friction coefficient.
-    std::vector<double>
+    std::vector<bldouble> cd; ///< Local dissipation coefficient.
+    std::vector<bldouble> cf; ///< Local friction coefficient.
+    std::vector<bldouble>
         Hstar; ///< Kinetic energy shape parameter (thetaStar/theta).
-    std::vector<double>
+    std::vector<bldouble>
         Hstar2;             ///< Density shape parameter (deltaStarStar/theta).
-    std::vector<double> Hk; ///< Kinematic shape parameter (int(1-u/ue d_eta)).
-    std::vector<double>
+    std::vector<bldouble> Hk; ///< Kinematic shape parameter (int(1-u/ue d_eta)).
+    std::vector<bldouble>
         ctEq;                  ///< Equilibrium shear stress coefficient (turbulent BL).
-    std::vector<double> us;    ///< Equivalent normalized wall slip velocity.
-    std::vector<double> delta; ///< Boundary layer thickness.
-    std::vector<double>
+    std::vector<bldouble> us;    ///< Equivalent normalized wall slip velocity.
+    std::vector<bldouble> delta; ///< Boundary layer thickness.
+    std::vector<bldouble>
         deltaStar; ///< Displacement thickness (int(1-rho*u/rhoe*ue d_eta)).
 
-    std::vector<double> Me;           ///< Mach number.
-    std::vector<double> vt;           ///< Velocity.
-    std::vector<double> rhoe;         ///< Density.
-    std::vector<double> deltaStarExt; ///< Displacement thickness.
-    std::vector<double> vtExt;        ///< Previous velocity.
+    std::vector<bldouble> Me;           ///< Mach number.
+    std::vector<bldouble> vt;           ///< Velocity.
+    std::vector<bldouble> rhoe;         ///< Density.
+    std::vector<bldouble> deltaStarExt; ///< Displacement thickness.
+    std::vector<bldouble> vtExt;        ///< Previous velocity.
 
-    std::vector<double> blowingVelocity; ///< Blowing velocity.
+    std::vector<bldouble> blowingVelocity; ///< Blowing velocity.
 
     // Transition related variables.
     size_t transitionNode; ///< Node id of the transition location.
 
 private:
-    double xtrF; ///< Forced transition location in the local frame of reference
+    bldouble xtrF; ///< Forced transition location in the local frame of reference
                  ///< (x/c).
-    double xtr;  ///< Transition location in the local frame of reference (x/c).
+    bldouble xtr;  ///< Transition location in the local frame of reference (x/c).
 
     void reset();
 
@@ -75,34 +75,34 @@ public:
     std::string getName() const { return name; }
     size_t getnNodes() const { return nodes.size(); }
     size_t getnElms() const { return nodes.size() - 1; }
-    double getxtr() const { return xtr; }
-    double getxoctr() const { return nodes[transitionNode]->xoc; }
-    double getxitr() const { return nodes[transitionNode]->xi; }
-    double getxtrF() const { return xtrF; }
-    double getMaxMach() const { return *std::max_element(Me.begin(), Me.end()); }
+    bldouble getxtr() const { return xtr; }
+    bldouble getxoctr() const { return nodes[transitionNode]->xoc; }
+    bldouble getxitr() const { return nodes[transitionNode]->xi; }
+    bldouble getxtrF() const { return xtrF; }
+    bldouble getMaxMach() const { return *std::max_element(Me.begin(), Me.end()); }
     size_t getnVar() const { return nVar; }
-    double getnCrit() const { return nCrit; }
-    std::vector<double> getTeConditions() const;
+    bldouble getnCrit() const { return nCrit; }
+    std::vector<bldouble> getTeConditions() const;
 
     // Setters
     void setMesh(std::vector<std::shared_ptr<blNode>> const &_nodes);
     void setElementsId(std::vector<int> &nos);
-    void setxtrF(double const _xtrF) { xtrF = _xtrF; }
-    void setxtr(double const _xtr) { xtr = _xtr; }
-    void setnCrit(double const _nCrit) { nCrit = _nCrit; }
+    void setxtrF(bldouble const _xtrF) { xtrF = _xtrF; }
+    void setxtr(bldouble const _xtr) { xtr = _xtr; }
+    void setnCrit(bldouble const _nCrit) { nCrit = _nCrit; }
 
     // Boundary conditions.
-    void setStagnationBC(double Re);
-    void setWakeBC(double Re, std::vector<std::vector<double>> &teConditions);
+    void setStagnationBC(bldouble Re);
+    void setWakeBC(bldouble Re, std::vector<std::vector<bldouble>> &teConditions);
 
     // Others
     void printSolution(size_t inod) const;
     void computeBlowingVelocity();
-    std::vector<std::vector<double>> evalGradwrtRho();
-    std::vector<std::vector<double>> evalGradwrtVt();
-    std::vector<std::vector<double>> evalGradwrtDeltaStar();
-    std::vector<std::vector<double>> evalGradwrtX();
-    std::vector<std::vector<double>> evalGradwrtY();
+    std::vector<std::vector<bldouble>> evalGradwrtRho();
+    std::vector<std::vector<bldouble>> evalGradwrtVt();
+    std::vector<std::vector<bldouble>> evalGradwrtDeltaStar();
+    std::vector<std::vector<bldouble>> evalGradwrtX();
+    std::vector<std::vector<bldouble>> evalGradwrtY();
 };
 } // namespace blast
 #endif // BLBOUNDARYLAYER_H
diff --git a/blast/src/blClosures.cpp b/blast/src/blClosures.cpp
index e2a4f2ab098bb2fc8a9818de261e20183a832cd7..249b15391a194d87dec0742ddf3cb72f97e14787 100644
--- a/blast/src/blClosures.cpp
+++ b/blast/src/blClosures.cpp
@@ -1,3 +1,4 @@
+#include "blast.h"
 #include "blClosures.h"
 #include <cmath>
 #include <iostream>
@@ -14,27 +15,27 @@ using namespace blast;
  * @param Me Local Mach number.
  * @param name Name of the region.
  */
-void Closures::laminarClosures(std::vector<double> &closureVars, double theta,
-                               double H, double Ret, const double Me,
+void Closures::laminarClosures(std::vector<bldouble> &closureVars, bldouble theta,
+                               bldouble H, bldouble Ret, const bldouble Me,
                                const std::string name)
 {
     H = std::max(H, 1.00005);
 
     // Kinematic shape factor H*.
-    double Hk = (H - 0.29 * Me * Me) / (1.0 + 0.113 * Me * Me);
+    bldouble Hk = (H - 0.29 * Me * Me) / (1.0 + 0.113 * Me * Me);
     if (name == "wake")
         Hk = std::max(Hk, 1.00005);
     else
         Hk = std::max(Hk, 1.05000);
 
     // Density shape parameter.
-    double Hstar2 = (0.064 / (Hk - 0.8) + 0.251) * Me * Me;
+    bldouble Hstar2 = (0.064 / (Hk - 0.8) + 0.251) * Me * Me;
 
     // Boundary layer thickness.
-    double delta = std::min((3.15 + H + (1.72 / (Hk - 1.0))) * theta, 12.0 * theta);
+    bldouble delta = std::min((3.15 + H + (1.72 / (Hk - 1.0))) * theta, 12.0 * theta);
 
-    double Hstar = 0.0;
-    double Hks = Hk - 4.35;
+    bldouble Hstar = 0.0;
+    bldouble Hks = Hk - 4.35;
     if (Hk <= 4.35)
         Hstar = 0.0111 * Hks * Hks / (Hk + 1.0) -
                 0.0278 * Hks * Hks * Hks / (Hk + 1.0) + 1.528 -
@@ -46,8 +47,8 @@ void Closures::laminarClosures(std::vector<double> &closureVars, double theta,
     Hstar = (Hstar + 0.028 * Me * Me) / (1.0 + 0.014 * Me * Me);
 
     // Friction coefficient.
-    double tmp = 0.0;
-    double cf = 0.0;
+    bldouble tmp = 0.0;
+    bldouble cf = 0.0;
     if (Hk < 5.5)
     {
         tmp = (5.5 - Hk) * (5.5 - Hk) * (5.5 - Hk) / (Hk + 1.0);
@@ -60,13 +61,13 @@ void Closures::laminarClosures(std::vector<double> &closureVars, double theta,
     }
 
     // Dissipation coefficient.
-    double Cd = 0.0;
+    bldouble Cd = 0.0;
     if (Hk < 4.0)
         Cd = (0.00205 * std::pow(4.0 - Hk, 5.5) + 0.207) * (Hstar / (2.0 * Ret));
     else
     {
-        double HkCd = (Hk - 4.0) * (Hk - 4.0);
-        double denCd = 1.0 + 0.02 * HkCd;
+        bldouble HkCd = (Hk - 4.0) * (Hk - 4.0);
+        bldouble denCd = 1.0 + 0.02 * HkCd;
         Cd = (-0.0016 * HkCd / denCd + 0.207) * (Hstar / (2.0 * Ret));
     }
 
@@ -78,8 +79,8 @@ void Closures::laminarClosures(std::vector<double> &closureVars, double theta,
         cf = 0.0;
     }
 
-    double us = 0.;
-    double ctEq = 0.;
+    bldouble us = 0.;
+    bldouble ctEq = 0.;
 
     closureVars = {Hstar, Hstar2, Hk, cf, Cd, delta, ctEq, us};
 }
@@ -95,25 +96,25 @@ void Closures::laminarClosures(std::vector<double> &closureVars, double theta,
  * @param Me Local Mach number.
  * @param name Name of the region.
  */
-void Closures::turbulentClosures(std::vector<double> &closureVars, double theta,
-                                 double H, double Ct, double Ret,
-                                 const double Me, const std::string name)
+void Closures::turbulentClosures(std::vector<bldouble> &closureVars, bldouble theta,
+                                 bldouble H, bldouble Ct, bldouble Ret,
+                                 const bldouble Me, const std::string name)
 {
     H = std::max(H, 1.00005);
     Ct = std::min(Ct, 0.3);
     // Ct = std::max(std::min(Ct, 0.30), 0.0000001);
 
-    double Hk = (H - 0.29 * Me * Me) / (1. + 0.113 * Me * Me);
+    bldouble Hk = (H - 0.29 * Me * Me) / (1. + 0.113 * Me * Me);
     if (name == "wake")
         Hk = std::max(Hk, 1.00005);
     else
         Hk = std::max(Hk, 1.05000);
 
-    double Hstar2 = ((0.064 / (Hk - 0.8)) + 0.251) * Me * Me;
-    double gamma = 1.4 - 1.;
-    double Fc = std::sqrt(1. + 0.5 * gamma * Me * Me);
+    bldouble Hstar2 = ((0.064 / (Hk - 0.8)) + 0.251) * Me * Me;
+    bldouble gamma = 1.4 - 1.;
+    bldouble Fc = std::sqrt(1. + 0.5 * gamma * Me * Me);
 
-    double H0 = 0.;
+    bldouble H0 = 0.;
     if (Ret <= 400.)
         H0 = 4.0;
     else
@@ -121,7 +122,7 @@ void Closures::turbulentClosures(std::vector<double> &closureVars, double theta,
     if (Ret <= 200.)
         Ret = 200.;
 
-    double Hstar = 0.;
+    bldouble Hstar = 0.;
     if (Hk <= H0)
         Hstar =
             ((0.5 - 4. / Ret) * ((H0 - Hk) / (H0 - 1.)) * ((H0 - Hk) / (H0 - 1.))) *
@@ -138,32 +139,32 @@ void Closures::turbulentClosures(std::vector<double> &closureVars, double theta,
     // Whitfield's minor additional compressibility correction.
     Hstar = (Hstar + 0.028 * Me * Me) / (1. + 0.014 * Me * Me);
 
-    double logRt = std::log(Ret / Fc);
+    bldouble logRt = std::log(Ret / Fc);
     logRt = std::max(logRt, 3.0);
-    double arg = std::max(-1.33 * Hk, -20.0);
+    bldouble arg = std::max(-1.33 * Hk, -20.0);
 
     // Equivalent normalized wall slip velocity.
-    double us = (Hstar / 2.) * (1. - 4. * (Hk - 1.) / (3. * H));
+    bldouble us = (Hstar / 2.) * (1. - 4. * (Hk - 1.) / (3. * H));
 
     // Boundary layer thickness.
-    double delta = std::min((3.15 + H + (1.72 / (Hk - 1.))) * theta, 12. * theta);
+    bldouble delta = std::min((3.15 + H + (1.72 / (Hk - 1.))) * theta, 12. * theta);
 
-    double Ctcon = 0.5 / (6.7 * 6.7 * 0.75);
-    double Hkc = 0.;
-    double Cdw = 0.;
-    double Cdd = 0.;
-    double Cdl = 0.;
+    bldouble Ctcon = 0.5 / (6.7 * 6.7 * 0.75);
+    bldouble Hkc = 0.;
+    bldouble Cdw = 0.;
+    bldouble Cdd = 0.;
+    bldouble Cdl = 0.;
 
-    double Hmin = 0.;
-    double Fl = 0.;
-    double Dfac = 0.;
+    bldouble Hmin = 0.;
+    bldouble Fl = 0.;
+    bldouble Dfac = 0.;
 
-    double cf = 0.;
-    double Cd = 0.;
+    bldouble cf = 0.;
+    bldouble Cd = 0.;
 
-    double n = 1.0;
+    bldouble n = 1.0;
 
-    double ctEq = 0.;
+    bldouble ctEq = 0.;
 
     if (name == "wake")
     {
@@ -221,20 +222,20 @@ void Closures::turbulentClosures(std::vector<double> &closureVars, double theta,
  * @param Me Local Mach number.
  * @param name Name of the region.
  */
-void Closures::turbulentClosures(double &closureVars, double theta, double H,
-                                 double Ct, double Ret, const double Me,
+void Closures::turbulentClosures(bldouble &closureVars, bldouble theta, bldouble H,
+                                 bldouble Ct, bldouble Ret, const bldouble Me,
                                  const std::string name)
 {
     H = std::max(H, 1.00005);
     Ct = std::min(Ct, 0.3);
 
-    double Hk = (H - 0.29 * Me * Me) / (1 + 0.113 * Me * Me);
+    bldouble Hk = (H - 0.29 * Me * Me) / (1 + 0.113 * Me * Me);
     if (name == "wake")
         Hk = std::max(Hk, 1.00005);
     else
         Hk = std::max(Hk, 1.05000);
 
-    double H0 = 0.0;
+    bldouble H0 = 0.0;
     if (Ret <= 400.)
         H0 = 4.0;
     else
@@ -242,7 +243,7 @@ void Closures::turbulentClosures(double &closureVars, double theta, double H,
     if (Ret <= 200.0)
         Ret = 200.0;
 
-    double Hstar = 0.0;
+    bldouble Hstar = 0.0;
     if (Hk <= H0)
         Hstar =
             ((0.5 - 4.0 / Ret) * ((H0 - Hk) / (H0 - 1.)) * ((H0 - Hk) / (H0 - 1.))) *
@@ -260,12 +261,12 @@ void Closures::turbulentClosures(double &closureVars, double theta, double H,
     Hstar = (Hstar + 0.028 * Me * Me) / (1.0 + 0.014 * Me * Me);
 
     // Equivalent normalized wall slip velocity.
-    double us = (Hstar / 2.0) * (1.0 - 4 * (Hk - 1.0) / (3.0 * H));
+    bldouble us = (Hstar / 2.0) * (1.0 - 4 * (Hk - 1.0) / (3.0 * H));
 
-    double Ctcon = 0.5 / (6.7 * 6.7 * 0.75);
+    bldouble Ctcon = 0.5 / (6.7 * 6.7 * 0.75);
 
-    double Hkc = 0.0;
-    double ctEq = 0.0;
+    bldouble Hkc = 0.0;
+    bldouble ctEq = 0.0;
 
     if (name == "wake")
     {
diff --git a/blast/src/blClosures.h b/blast/src/blClosures.h
index 42d48ecfcc1d61bf3267c3240ca156294b360a7a..7fd6f4cc3e70bdb1d067810f2dd641f16df3f83d 100644
--- a/blast/src/blClosures.h
+++ b/blast/src/blClosures.h
@@ -16,14 +16,14 @@ class BLAST_API Closures
 {
 
 public:
-    static void laminarClosures(std::vector<double> &closureVars, double theta,
-                                double H, double Ret, const double Me,
+    static void laminarClosures(std::vector<bldouble> &closureVars, bldouble theta,
+                                bldouble H, bldouble Ret, const bldouble Me,
                                 const std::string name);
-    static void turbulentClosures(std::vector<double> &closureVars, double theta,
-                                  double H, double Ct, double Ret, double Me,
+    static void turbulentClosures(std::vector<bldouble> &closureVars, bldouble theta,
+                                  bldouble H, bldouble Ct, bldouble Ret, bldouble Me,
                                   const std::string name);
-    static void turbulentClosures(double &closureVars, double theta, double H,
-                                  double Ct, double Ret, const double Me,
+    static void turbulentClosures(bldouble &closureVars, bldouble theta, bldouble H,
+                                  bldouble Ct, bldouble Ret, const bldouble Me,
                                   const std::string name);
 };
 } // namespace blast
diff --git a/blast/src/blCoupledAdjoint.cpp b/blast/src/blCoupledAdjoint.cpp
index 55421a7c5da2607c924db5911344f77d9a5602a8..1e8867fbadb54dfa0fc7388d3c34cf16b8eb0b54 100644
--- a/blast/src/blCoupledAdjoint.cpp
+++ b/blast/src/blCoupledAdjoint.cpp
@@ -576,97 +576,97 @@ void CoupledAdjoint::gradientswrtMachNumber()
     //**************************************************************************//
     dRM_M.setIdentity();
 
-    //**************************************************************************//
-    //                                 dRdStar_M                                //
-    //--------------------------------------------------------------------------//
-    //                         Central finite-difference                        //
-    //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T;
-    double delta = 1e-6;
-    size_t i = 0;
-    double saveM = 0.;
-    std::vector<Eigen::VectorXd> ddStar(2,
-                                        Eigen::VectorXd::Zero(dRdStar_M.cols()));
-    std::vector<double> dCdf(2, 0.);
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                for (size_t j = 0; j < reg->getnNodes(); ++j)
-                {
-                    saveM = reg->Me[j];
-
-                    reg->Me[j] = saveM + delta;
-                    ddStar[0] = this->runViscous();
-                    dCdf[0] = vsol->Cdf;
-                    reg->Me[j] = saveM - delta;
-                    ddStar[1] = this->runViscous();
-                    dCdf[1] = vsol->Cdf;
-
-                    reg->Me[j] = saveM;
-
-                    for (int k = 0; k < ddStar[0].size(); ++k)
-                        T.push_back(Eigen::Triplet<double>(
-                            k, i, -(ddStar[0][k] - ddStar[1][k]) / (2. * delta)));
-                    // Collect Cd gradients
-                    dCd_M(i) = (dCdf[0] - dCdf[1]) / (2. * delta);
-                    ++i;
-                }
-            }
-        }
-        dRdStar_M.setFromTriplets(T.begin(), T.end());
-        dRdStar_M.prune(0.);
-    }
+//     //**************************************************************************//
+//     //                                 dRdStar_M                                //
+//     //--------------------------------------------------------------------------//
+//     //                         Central finite-difference                        //
+//     //**************************************************************************//
+//     std::deque<Eigen::Triplet<double>> T;
+//     double delta = 1e-6;
+//     size_t i = 0;
+//     double saveM = 0.;
+//     std::vector<Eigen::VectorXd> ddStar(2,
+//                                         Eigen::VectorXd::Zero(dRdStar_M.cols()));
+//     std::vector<double> dCdf(2, 0.);
+//     for (auto &body : vsol->bodies)
+//     {
+//         for (auto &section : body->sections)
+//         {
+//             for (auto &reg : section->regions)
+//             {
+//                 for (size_t j = 0; j < reg->getnNodes(); ++j)
+//                 {
+//                     saveM = reg->Me[j];
+
+//                     reg->Me[j] = saveM + delta;
+//                     ddStar[0] = this->runViscous();
+//                     dCdf[0] = vsol->Cdf;
+//                     reg->Me[j] = saveM - delta;
+//                     ddStar[1] = this->runViscous();
+//                     dCdf[1] = vsol->Cdf;
+
+//                     reg->Me[j] = saveM;
+
+//                     for (int k = 0; k < ddStar[0].size(); ++k)
+//                         T.push_back(Eigen::Triplet<double>(
+//                             k, i, -(ddStar[0][k] - ddStar[1][k]) / (2. * delta)));
+//                     // Collect Cd gradients
+//                     dCd_M(i) = (dCdf[0] - dCdf[1]) / (2. * delta);
+//                     ++i;
+//                 }
+//             }
+//         }
+//         dRdStar_M.setFromTriplets(T.begin(), T.end());
+//         dRdStar_M.prune(0.);
+//     }
 }
 
-/**
- * @brief Compute all the gradients wrt the density on the surface
- * Non-zero are: dRrho_rho, dRblw_rho
- * Zeros are: dRphi_rho, dRM_rho, dRv_rho, dRdStar_rho, dRx_rho
- */
+// /**
+//  * @brief Compute all the gradients wrt the density on the surface
+//  * Non-zero are: dRrho_rho, dRblw_rho
+//  * Zeros are: dRphi_rho, dRM_rho, dRv_rho, dRdStar_rho, dRx_rho
+//  */
 void CoupledAdjoint::gradientswrtDensity()
 {
-    size_t nNs = 0;
-    for (auto bBC : isol->pbl->bBCs)
-        nNs += bBC->nodes.size(); // Number of surface nodes
-    nNs += 1;                     // Duplicate stagnation point
-    size_t nEs = 0;
-    for (auto bBC : isol->pbl->bBCs)
-        nEs += bBC->uE.size(); // Number of blowing elements
-
-    //**************************************************************************//
-    //                                 dRrho_rho                                //
-    //**************************************************************************//
-    dRrho_rho.setIdentity();
-
-    //**************************************************************************//
-    //                                 dRblw_rho                                //
-    //--------------------------------------------------------------------------//
-    //                               Analytical                                 //
-    //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T_blw;
-    int offSetElms = 0;
-    int offSetNodes = 0;
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                std::vector<std::vector<double>> grad = reg->evalGradwrtRho();
-                for (size_t i = 0; i < grad.size(); ++i)
-                    for (size_t j = 0; j < grad[i].size(); ++j)
-                        T_blw.push_back(Eigen::Triplet<double>(i + offSetElms, j + offSetNodes,
-                                                               -grad[i][j]));
-                offSetElms += reg->getnElms();
-                offSetNodes += reg->getnNodes();
-            }
-        }
-    }
-    dRblw_rho.setFromTriplets(T_blw.begin(), T_blw.end());
-    dRblw_rho.prune(0.);
+//     size_t nNs = 0;
+//     for (auto bBC : isol->pbl->bBCs)
+//         nNs += bBC->nodes.size(); // Number of surface nodes
+//     nNs += 1;                     // Duplicate stagnation point
+//     size_t nEs = 0;
+//     for (auto bBC : isol->pbl->bBCs)
+//         nEs += bBC->uE.size(); // Number of blowing elements
+
+//     //**************************************************************************//
+//     //                                 dRrho_rho                                //
+//     //**************************************************************************//
+//     dRrho_rho.setIdentity();
+
+//     //**************************************************************************//
+//     //                                 dRblw_rho                                //
+//     //--------------------------------------------------------------------------//
+//     //                               Analytical                                 //
+//     //**************************************************************************//
+//     std::deque<Eigen::Triplet<double>> T_blw;
+//     int offSetElms = 0;
+//     int offSetNodes = 0;
+//     for (auto &body : vsol->bodies)
+//     {
+//         for (auto &section : body->sections)
+//         {
+//             for (auto &reg : section->regions)
+//             {
+//                 std::vector<std::vector<double>> grad = reg->evalGradwrtRho();
+//                 for (size_t i = 0; i < grad.size(); ++i)
+//                     for (size_t j = 0; j < grad[i].size(); ++j)
+//                         T_blw.push_back(Eigen::Triplet<double>(i + offSetElms, j + offSetNodes,
+//                                                                -grad[i][j]));
+//                 offSetElms += reg->getnElms();
+//                 offSetNodes += reg->getnNodes();
+//             }
+//         }
+//     }
+//     dRblw_rho.setFromTriplets(T_blw.begin(), T_blw.end());
+//     dRblw_rho.prune(0.);
 }
 
 /**
@@ -676,168 +676,168 @@ void CoupledAdjoint::gradientswrtDensity()
  */
 void CoupledAdjoint::gradientswrtVelocity()
 {
-    size_t nDim = isol->pbl->nDim; // Number of dimensions of the problem
-    size_t nNs = 0;
-    for (auto bBC : isol->pbl->bBCs)
-        nNs += bBC->nodes.size(); // Number of surface nodes
-    nNs += 1;                     // Duplicate stagnation point
-    size_t nEs = 0;
-    for (auto bBC : isol->pbl->bBCs)
-        nEs += bBC->uE.size(); // Number of blowing elements
-
-    //**************************************************************************//
-    //                                   dRv_v                                  //
-    //**************************************************************************//
-    dRv_v.setIdentity();
-
-    //**** Get velocity****/
-    Eigen::MatrixXd v = Eigen::MatrixXd::Zero(nNs, nDim);
-    size_t i = 0;
-    int iReg = -1;
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                if (reg->getName() == "wake")
-                    iReg = 1;
-                else if (reg->getName() == "upper" || reg->getName() == "lower")
-                    iReg = 0;
-                else
-                    throw std::runtime_error("Unknown section name");
-                for (size_t j = 0; j < reg->getnNodes(); ++j)
-                {
-                    for (size_t idim = 0; idim < nDim; ++idim)
-                        v(i, idim) =
-                            isol->U[isol->pbl->bBCs[iReg]->nodes[reg->nodes[j]->row]->row](idim);
-                    ++i;
-                }
-            }
-        }
-    }
-
-    //**************************************************************************//
-    //                                 dvt_v                                    //
-    //--------------------------------------------------------------------------//
-    //                               Analytical                                 //
-    //**************************************************************************//
-    Eigen::SparseMatrix<double, Eigen::RowMajor> dVt_v(nNs, nNs * nDim);
-    std::deque<Eigen::Triplet<double>> T_vt;
-
-    i = 0;
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                for (size_t j = 0; j < reg->getnNodes(); ++j)
-                {
-                    for (size_t idim = 0; idim < nDim; ++idim)
-                    {
-                        T_vt.push_back(Eigen::Triplet<double>(
-                            i, i * nDim + idim,
-                            1 / std::sqrt(v(i, 0) * v(i, 0) + v(i, 1) * v(i, 1)) * v(i, idim)));
-                    }
-                    ++i;
-                }
-            }
-        }
-    }
-    dVt_v.setFromTriplets(T_vt.begin(), T_vt.end());
-    dVt_v.prune(0.);
-
-    //**************************************************************************//
-    //                                 dRdStar_vt                               //
-    //--------------------------------------------------------------------------//
-    //                          Central finite-difference                       //
-    //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T;
-    double delta = 1e-6;
-    i = 0;
-    double saveM = 0.;
-    std::vector<Eigen::VectorXd> dvt(2, Eigen::VectorXd::Zero(dRdStar_M.cols()));
-    std::vector<double> dCdf(2, 0.);
-    Eigen::VectorXd dCd_vt = Eigen::VectorXd::Zero(dRM_M.cols());
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                for (size_t j = 0; j < reg->getnNodes(); ++j)
-                {
-                    saveM = reg->vt[j];
-
-                    reg->vt[j] = saveM + delta;
-                    dvt[0] = this->runViscous();
-                    dCdf[0] = vsol->Cdf;
-                    reg->vt[j] = saveM - delta;
-                    dvt[1] = this->runViscous();
-                    dCdf[1] = vsol->Cdf;
-
-                    reg->vt[j] = saveM;
-
-                    for (int k = 0; k < dvt[0].size(); ++k)
-                        T.push_back(Eigen::Triplet<double>(
-                            k, i, -(dvt[0][k] - dvt[1][k]) / (2. * delta)));
-                    dCd_vt(i) = (dCdf[0] - dCdf[1]) / (2. * delta);
-                    ++i;
-                }
-            }
-        }
-    }
-    Eigen::SparseMatrix<double, Eigen::RowMajor> dRdStar_vt(dRdStar_M.rows(),
-                                                            dRdStar_M.cols());
-    dRdStar_vt.setFromTriplets(T.begin(), T.end());
-    dRdStar_vt.prune(0.);
-
-    //**************************************************************************//
-    //                                 dRdStar_v                                //
-    //**************************************************************************//
-    dRdStar_v = dRdStar_vt * dVt_v;
-    dRdStar_v.prune(0.);
-
-    //**************************************************************************//
-    //                                   dCdf_v                                 //
-    //**************************************************************************//
-    dCd_v =
-        dCd_vt.transpose() * dVt_v; // [1xnNs] x [nNs x nNs*nDim] = [1 x nNs*nDim]
-
-    //**************************************************************************//
-    //                                 dRblw_vt                                 //
-    //--------------------------------------------------------------------------//
-    //                                 Analytical                               //
-    //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T_blw;
-    int offSetElms = 0;
-    int offSetNodes = 0;
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                std::vector<std::vector<double>> grad = reg->evalGradwrtVt();
-                for (size_t i = 0; i < grad.size(); ++i)
-                    for (size_t j = 0; j < grad[i].size(); ++j)
-                        T_blw.push_back(Eigen::Triplet<double>(i + offSetElms, j + offSetNodes,
-                                                               -grad[i][j]));
-                offSetElms += reg->getnElms();
-                offSetNodes += reg->getnNodes();
-            }
-        }
-    }
-    Eigen::SparseMatrix<double, Eigen::RowMajor> dRblw_vt(nEs, nNs);
-    dRblw_vt.setFromTriplets(T_blw.begin(), T_blw.end());
-    dRblw_vt.prune(0.);
-
-    //**************************************************************************//
-    //                                   dRblw_v                                //
-    //**************************************************************************//
-    dRblw_v = dRblw_vt * dVt_v;
-    dRblw_v.prune(0.);
+    // size_t nDim = isol->pbl->nDim; // Number of dimensions of the problem
+    // size_t nNs = 0;
+    // for (auto bBC : isol->pbl->bBCs)
+    //     nNs += bBC->nodes.size(); // Number of surface nodes
+    // nNs += 1;                     // Duplicate stagnation point
+    // size_t nEs = 0;
+    // for (auto bBC : isol->pbl->bBCs)
+    //     nEs += bBC->uE.size(); // Number of blowing elements
+
+    // //**************************************************************************//
+    // //                                   dRv_v                                  //
+    // //**************************************************************************//
+    // dRv_v.setIdentity();
+
+    // //**** Get velocity****/
+    // Eigen::MatrixXd v = Eigen::MatrixXd::Zero(nNs, nDim);
+    // size_t i = 0;
+    // int iReg = -1;
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             if (reg->getName() == "wake")
+    //                 iReg = 1;
+    //             else if (reg->getName() == "upper" || reg->getName() == "lower")
+    //                 iReg = 0;
+    //             else
+    //                 throw std::runtime_error("Unknown section name");
+    //             for (size_t j = 0; j < reg->getnNodes(); ++j)
+    //             {
+    //                 for (size_t idim = 0; idim < nDim; ++idim)
+    //                     v(i, idim) =
+    //                         isol->U[isol->pbl->bBCs[iReg]->nodes[reg->nodes[j]->row]->row](idim);
+    //                 ++i;
+    //             }
+    //         }
+    //     }
+    // }
+
+    // //**************************************************************************//
+    // //                                 dvt_v                                    //
+    // //--------------------------------------------------------------------------//
+    // //                               Analytical                                 //
+    // //**************************************************************************//
+    // Eigen::SparseMatrix<double, Eigen::RowMajor> dVt_v(nNs, nNs * nDim);
+    // std::deque<Eigen::Triplet<double>> T_vt;
+
+    // i = 0;
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             for (size_t j = 0; j < reg->getnNodes(); ++j)
+    //             {
+    //                 for (size_t idim = 0; idim < nDim; ++idim)
+    //                 {
+    //                     T_vt.push_back(Eigen::Triplet<double>(
+    //                         i, i * nDim + idim,
+    //                         1 / std::sqrt(v(i, 0) * v(i, 0) + v(i, 1) * v(i, 1)) * v(i, idim)));
+    //                 }
+    //                 ++i;
+    //             }
+    //         }
+    //     }
+    // }
+    // dVt_v.setFromTriplets(T_vt.begin(), T_vt.end());
+    // dVt_v.prune(0.);
+
+    // //**************************************************************************//
+    // //                                 dRdStar_vt                               //
+    // //--------------------------------------------------------------------------//
+    // //                          Central finite-difference                       //
+    // //**************************************************************************//
+    // std::deque<Eigen::Triplet<double>> T;
+    // double delta = 1e-6;
+    // i = 0;
+    // double saveM = 0.;
+    // std::vector<Eigen::VectorXd> dvt(2, Eigen::VectorXd::Zero(dRdStar_M.cols()));
+    // std::vector<double> dCdf(2, 0.);
+    // Eigen::VectorXd dCd_vt = Eigen::VectorXd::Zero(dRM_M.cols());
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             for (size_t j = 0; j < reg->getnNodes(); ++j)
+    //             {
+    //                 saveM = reg->vt[j];
+
+    //                 reg->vt[j] = saveM + delta;
+    //                 dvt[0] = this->runViscous();
+    //                 dCdf[0] = vsol->Cdf;
+    //                 reg->vt[j] = saveM - delta;
+    //                 dvt[1] = this->runViscous();
+    //                 dCdf[1] = vsol->Cdf;
+
+    //                 reg->vt[j] = saveM;
+
+    //                 for (int k = 0; k < dvt[0].size(); ++k)
+    //                     T.push_back(Eigen::Triplet<double>(
+    //                         k, i, -(dvt[0][k] - dvt[1][k]) / (2. * delta)));
+    //                 dCd_vt(i) = (dCdf[0] - dCdf[1]) / (2. * delta);
+    //                 ++i;
+    //             }
+    //         }
+    //     }
+    // }
+    // Eigen::SparseMatrix<double, Eigen::RowMajor> dRdStar_vt(dRdStar_M.rows(),
+    //                                                         dRdStar_M.cols());
+    // dRdStar_vt.setFromTriplets(T.begin(), T.end());
+    // dRdStar_vt.prune(0.);
+
+    // //**************************************************************************//
+    // //                                 dRdStar_v                                //
+    // //**************************************************************************//
+    // dRdStar_v = dRdStar_vt * dVt_v;
+    // dRdStar_v.prune(0.);
+
+    // //**************************************************************************//
+    // //                                   dCdf_v                                 //
+    // //**************************************************************************//
+    // dCd_v =
+    //     dCd_vt.transpose() * dVt_v; // [1xnNs] x [nNs x nNs*nDim] = [1 x nNs*nDim]
+
+    // //**************************************************************************//
+    // //                                 dRblw_vt                                 //
+    // //--------------------------------------------------------------------------//
+    // //                                 Analytical                               //
+    // //**************************************************************************//
+    // std::deque<Eigen::Triplet<double>> T_blw;
+    // int offSetElms = 0;
+    // int offSetNodes = 0;
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             std::vector<std::vector<double>> grad = reg->evalGradwrtVt();
+    //             for (size_t i = 0; i < grad.size(); ++i)
+    //                 for (size_t j = 0; j < grad[i].size(); ++j)
+    //                     T_blw.push_back(Eigen::Triplet<double>(i + offSetElms, j + offSetNodes,
+    //                                                            -grad[i][j]));
+    //             offSetElms += reg->getnElms();
+    //             offSetNodes += reg->getnNodes();
+    //         }
+    //     }
+    // }
+    // Eigen::SparseMatrix<double, Eigen::RowMajor> dRblw_vt(nEs, nNs);
+    // dRblw_vt.setFromTriplets(T_blw.begin(), T_blw.end());
+    // dRblw_vt.prune(0.);
+
+    // //**************************************************************************//
+    // //                                   dRblw_v                                //
+    // //**************************************************************************//
+    // dRblw_v = dRblw_vt * dVt_v;
+    // dRblw_v.prune(0.);
 }
 
 /**
@@ -852,77 +852,77 @@ void CoupledAdjoint::gradientswrtDeltaStar()
     //--------------------------------------------------------------------------//
     //                        Central finite-difference                         //
     //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T;
-    double delta = 1e-6;
-    double saveDStar = 0.;
-    std::vector<Eigen::VectorXd> ddstar(
-        2, Eigen::VectorXd::Zero(dRdStar_dStar.cols()));
-    std::vector<double> dCdf(2, 0.);
-    size_t i = 0;
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                for (size_t j = 0; j < reg->getnNodes(); ++j)
-                {
-                    saveDStar = reg->deltaStarExt[j];
-
-                    reg->deltaStarExt[j] = saveDStar + delta;
-                    ddstar[0] = this->runViscous();
-                    dCdf[0] = vsol->Cdf;
-                    reg->deltaStarExt[j] = saveDStar - delta;
-                    ddstar[1] = this->runViscous();
-                    dCdf[1] = vsol->Cdf;
-
-                    reg->deltaStarExt[j] = saveDStar;
-
-                    for (int k = 0; k < ddstar[0].size(); ++k)
-                        T.push_back(Eigen::Triplet<double>(
-                            k, i, (ddstar[0][k] - ddstar[1][k]) / (2. * delta)));
-                    dCd_dStar(i) = (dCdf[0] - dCdf[1]) / (2. * delta);
-                    ++i;
-                }
-            }
-        }
-    }
-    Eigen::SparseMatrix<double, Eigen::RowMajor> dRdStar_dStar_dum(
-        dRdStar_dStar.rows(), dRdStar_dStar.cols());
-    // RdStar = dStar - f(dStar) = 0
-    // dRdStar_dStar = 1 - df_dStar (minus is 3 lines below and not in the
-    // triplets)
-    dRdStar_dStar_dum.setFromTriplets(T.begin(), T.end());
-    dRdStar_dStar.setIdentity();
-    dRdStar_dStar -= dRdStar_dStar_dum;
-    dRdStar_dStar.prune(0.);
-
-    //**************************************************************************//
-    //                                 dRblw_dStar                              //
-    //--------------------------------------------------------------------------//
-    //                                 Analytical                               //
-    //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T_blw;
-    int offSetElms = 0;
-    int offSetNodes = 0;
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                std::vector<std::vector<double>> grad = reg->evalGradwrtDeltaStar();
-                for (size_t i = 0; i < grad.size(); ++i)
-                    for (size_t j = 0; j < grad[i].size(); ++j)
-                        T_blw.push_back(Eigen::Triplet<double>(i + offSetElms, j + offSetNodes,
-                                                               -grad[i][j]));
-                offSetElms += reg->getnElms();
-                offSetNodes += reg->getnNodes();
-            }
-        }
-    }
-    dRblw_dStar.setFromTriplets(T_blw.begin(), T_blw.end());
-    dRblw_dStar.prune(0.);
+    // std::deque<Eigen::Triplet<double>> T;
+    // double delta = 1e-6;
+    // double saveDStar = 0.;
+    // std::vector<Eigen::VectorXd> ddstar(
+    //     2, Eigen::VectorXd::Zero(dRdStar_dStar.cols()));
+    // std::vector<double> dCdf(2, 0.);
+    // size_t i = 0;
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             for (size_t j = 0; j < reg->getnNodes(); ++j)
+    //             {
+    //                 saveDStar = reg->deltaStarExt[j];
+
+    //                 reg->deltaStarExt[j] = saveDStar + delta;
+    //                 ddstar[0] = this->runViscous();
+    //                 dCdf[0] = vsol->Cdf;
+    //                 reg->deltaStarExt[j] = saveDStar - delta;
+    //                 ddstar[1] = this->runViscous();
+    //                 dCdf[1] = vsol->Cdf;
+
+    //                 reg->deltaStarExt[j] = saveDStar;
+
+    //                 for (int k = 0; k < ddstar[0].size(); ++k)
+    //                     T.push_back(Eigen::Triplet<double>(
+    //                         k, i, (ddstar[0][k] - ddstar[1][k]) / (2. * delta)));
+    //                 dCd_dStar(i) = (dCdf[0] - dCdf[1]) / (2. * delta);
+    //                 ++i;
+    //             }
+    //         }
+    //     }
+    // }
+    // Eigen::SparseMatrix<double, Eigen::RowMajor> dRdStar_dStar_dum(
+    //     dRdStar_dStar.rows(), dRdStar_dStar.cols());
+    // // RdStar = dStar - f(dStar) = 0
+    // // dRdStar_dStar = 1 - df_dStar (minus is 3 lines below and not in the
+    // // triplets)
+    // dRdStar_dStar_dum.setFromTriplets(T.begin(), T.end());
+    // dRdStar_dStar.setIdentity();
+    // dRdStar_dStar -= dRdStar_dStar_dum;
+    // dRdStar_dStar.prune(0.);
+
+    // //**************************************************************************//
+    // //                                 dRblw_dStar                              //
+    // //--------------------------------------------------------------------------//
+    // //                                 Analytical                               //
+    // //**************************************************************************//
+    // std::deque<Eigen::Triplet<double>> T_blw;
+    // int offSetElms = 0;
+    // int offSetNodes = 0;
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             std::vector<std::vector<double>> grad = reg->evalGradwrtDeltaStar();
+    //             for (size_t i = 0; i < grad.size(); ++i)
+    //                 for (size_t j = 0; j < grad[i].size(); ++j)
+    //                     T_blw.push_back(Eigen::Triplet<double>(i + offSetElms, j + offSetNodes,
+    //                                                            -grad[i][j]));
+    //             offSetElms += reg->getnElms();
+    //             offSetNodes += reg->getnNodes();
+    //         }
+    //     }
+    // }
+    // dRblw_dStar.setFromTriplets(T_blw.begin(), T_blw.end());
+    // dRblw_dStar.prune(0.);
 }
 
 /**
@@ -937,44 +937,44 @@ void CoupledAdjoint::gradientswrtBlowingVelocity()
     //--------------------------------------------------------------------------//
     //                                 Analytical                               //
     //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T;
-
-    size_t jj = 0;
-    int iReg = 0;
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                if (reg->getName() == "wake")
-                    iReg = 1;
-                else if (reg->getName() == "upper" || reg->getName() == "lower")
-                    iReg = 0;
-                else
-                    throw std::runtime_error("Unknown section name");
-                for (size_t iElm = 0; iElm < reg->getnElms(); ++iElm)
-                {
-                    auto blowingElement = isol->pbl->bBCs[iReg]->uE[reg->no[iElm]].first;
-                    Eigen::VectorXd be =
-                        dart::BlowingResidual::buildGradientBlowing(*blowingElement);
-                    for (size_t ii = 0; ii < blowingElement->nodes.size(); ii++)
-                    {
-                        tbox::Node *nodi = blowingElement->nodes[ii];
-                        T.push_back(
-                            Eigen::Triplet<double>(isol->getRow(nodi->row), jj, be(ii)));
-                    }
-                    ++jj;
-                }
-            }
-        }
-    }
-    dRphi_blw.setFromTriplets(T.begin(), T.end());
-    dRphi_blw.prune(0.);
-    dRphi_blw.makeCompressed();
-
-    /**** dRblw_blw ****/
-    dRblw_blw.setIdentity();
+    // std::deque<Eigen::Triplet<double>> T;
+
+    // size_t jj = 0;
+    // int iReg = 0;
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             if (reg->getName() == "wake")
+    //                 iReg = 1;
+    //             else if (reg->getName() == "upper" || reg->getName() == "lower")
+    //                 iReg = 0;
+    //             else
+    //                 throw std::runtime_error("Unknown section name");
+    //             for (size_t iElm = 0; iElm < reg->getnElms(); ++iElm)
+    //             {
+    //                 auto blowingElement = isol->pbl->bBCs[iReg]->uE[reg->no[iElm]].first;
+    //                 Eigen::VectorXd be =
+    //                     dart::BlowingResidual::buildGradientBlowing(*blowingElement);
+    //                 for (size_t ii = 0; ii < blowingElement->nodes.size(); ii++)
+    //                 {
+    //                     tbox::Node *nodi = blowingElement->nodes[ii];
+    //                     T.push_back(
+    //                         Eigen::Triplet<double>(isol->getRow(nodi->row), jj, be(ii)));
+    //                 }
+    //                 ++jj;
+    //             }
+    //         }
+    //     }
+    // }
+    // dRphi_blw.setFromTriplets(T.begin(), T.end());
+    // dRphi_blw.prune(0.);
+    // dRphi_blw.makeCompressed();
+
+    // /**** dRblw_blw ****/
+    // dRblw_blw.setIdentity();
 }
 
 /**
@@ -989,16 +989,16 @@ void CoupledAdjoint::gradientwrtAoA()
     //--------------------------------------------------------------------------//
     //                                 Analytical                               //
     //**************************************************************************//
-    std::vector<double> dCx_AoA = iadjoint->computeGradientCoefficientsAoa();
-    dCl_AoA = dCx_AoA[0];
-    dCd_AoA = dCx_AoA[1];
-
-    //**************************************************************************//
-    //                                 dRphi_Aoa                                //
-    //--------------------------------------------------------------------------//
-    //                                 Analytical                               //
-    //**************************************************************************//
-    dRphi_AoA = iadjoint->getRu_A();
+    // std::vector<double> dCx_AoA = iadjoint->computeGradientCoefficientsAoa();
+    // dCl_AoA = dCx_AoA[0];
+    // dCd_AoA = dCx_AoA[1];
+
+    // //**************************************************************************//
+    // //                                 dRphi_Aoa                                //
+    // //--------------------------------------------------------------------------//
+    // //                                 Analytical                               //
+    // //**************************************************************************//
+    // dRphi_AoA = iadjoint->getRu_A();
 }
 
 /**
@@ -1009,228 +1009,228 @@ void CoupledAdjoint::gradientwrtAoA()
 void CoupledAdjoint::gradientwrtMesh()
 {
 
-    int nDim = isol->pbl->nDim;
-
-    //**************************************************************************//
-    //                               dCl_x, dCd_x                               //
-    //--------------------------------------------------------------------------//
-    //                                 Analytical                               //
-    //**************************************************************************//
-    std::vector<std::vector<double>> dCx_x =
-        iadjoint->computeGradientCoefficientsMesh();
-    dCl_x = Eigen::Map<Eigen::VectorXd>(dCx_x[0].data(), dCx_x[0].size());
-    dCdp_x = Eigen::Map<Eigen::VectorXd>(dCx_x[1].data(), dCx_x[1].size());
-
-    //**************************************************************************//
-    //                                  dRphi_x                                 //
-    //--------------------------------------------------------------------------//
-    //                                 Analytical                               //
-    //**************************************************************************//
-    dRphi_x = iadjoint->getRu_X();
-    //**************************************************************************//
-    //                                   dRx_x                                  //
-    //--------------------------------------------------------------------------//
-    //                                 Analytical                               //
-    //**************************************************************************//
-    dRx_x = iadjoint->getRx_X();
-
-    //**************************************************************************//
-    //                            dRdStar_x, dCdf_dx                            //
-    //--------------------------------------------------------------------------//
-    //                         Central finite-difference                        //
-    //--------------------------------------------------------------------------//
-    // We don't do dRdStar_x = dRdStar_loc * dloc_dx because Cdf = f(xi(x), x)  //
-    // and we would have to compute dCdf/dx and dCdf/dloc. Same for deltaStar.  //
-    // It is more computationally expansive to compute                          //
-    // ddeltaStar/dx, ddeltaStar/dloc than ddeltaStar_dx, ddeltaStar_dy         //
-    //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T_dStar_x;
-    double delta = 1e-8;
-    int iReg = 0;
-    std::vector<Eigen::VectorXd> ddStar(2,
-                                        Eigen::VectorXd::Zero(dRdStar_M.cols()));
-    std::vector<double> dCdf(2, 0.);
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                if (reg->getName() == "wake")
-                    iReg = 1;
-                else if (reg->getName() == "upper" || reg->getName() == "lower")
-                    iReg = 0;
-                else
-                    throw std::runtime_error("Unknown section name");
-                for (size_t j = 0; j < reg->getnNodes(); ++j)
-                {
-                    int rowj = isol->pbl->bBCs[iReg]->nodes[reg->nodes[j]->row]->row;
-                    // x
-                    double saveX = reg->nodes[j]->pos[0];
-
-                    reg->nodes[j]->pos[0] = saveX + delta;
-                    section->computeLocalCoordinates(reg);
-                    for (auto &nod : reg->nodes)
-                        nod->xiExt = nod->xi;
-                    ddStar[0] = this->runViscous();
-                    dCdf[0] = vsol->Cdf;
-                    reg->nodes[j]->pos[0] = saveX - delta;
-                    section->computeLocalCoordinates(reg);
-                    for (auto &nod : reg->nodes)
-                        nod->xiExt = nod->xi;
-                    ddStar[1] = this->runViscous();
-                    dCdf[1] = vsol->Cdf;
-
-                    reg->nodes[j]->pos[0] = saveX;
-                    section->computeLocalCoordinates(reg);
-                    for (auto &nod : reg->nodes)
-                        nod->xiExt = nod->xi;
-
-                    for (int k = 0; k < ddStar[0].size(); ++k)
-                        T_dStar_x.push_back(Eigen::Triplet<double>(
-                            k, rowj * isol->pbl->nDim + 0,
-                            -(ddStar[0][k] - ddStar[1][k]) / (2. * delta)));
-                    dCdf_x(rowj * isol->pbl->nDim + 0) += (dCdf[0] - dCdf[1]) / (2. * delta);
-                    // y
-                    double saveY = reg->nodes[j]->pos[1];
-
-                    reg->nodes[j]->pos[1] = saveY + delta;
-                    section->computeLocalCoordinates(reg);
-                    for (auto &nod : reg->nodes)
-                        nod->xiExt = nod->xi;
-                    ddStar[0] = this->runViscous();
-                    dCdf[0] = vsol->Cdf;
-                    reg->nodes[j]->pos[1] = saveY - delta;
-                    section->computeLocalCoordinates(reg);
-                    for (auto &nod : reg->nodes)
-                        nod->xiExt = nod->xi;
-                    ddStar[1] = this->runViscous();
-                    dCdf[1] = vsol->Cdf;
-
-                    reg->nodes[j]->pos[1] = saveY;
-                    section->computeLocalCoordinates(reg);
-                    for (auto &nod : reg->nodes)
-                        nod->xiExt = nod->xi;
-
-                    for (int k = 0; k < ddStar[0].size(); ++k)
-                        T_dStar_x.push_back(Eigen::Triplet<double>(
-                            k, rowj * isol->pbl->nDim + 1,
-                            -(ddStar[0][k] - ddStar[1][k]) / (2. * delta)));
-                    dCdf_x(rowj * isol->pbl->nDim + 1) += (dCdf[0] - dCdf[1]) / (2. * delta);
-                }
-            }
-        }
-    }
-    dRdStar_x.setFromTriplets(T_dStar_x.begin(), T_dStar_x.end());
-    dRdStar_x.prune(0.);
-
-    //**************************************************************************//
-    //                                dRblw_x                                   //
-    //--------------------------------------------------------------------------//
-    //                               Analytical                                 //
-    //**************************************************************************//
-    std::deque<Eigen::Triplet<double>> T_blw_x;
-    int offSetElms = 0;
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                if (reg->getName() == "wake")
-                    iReg = 1;
-                else if (reg->getName() == "upper" || reg->getName() == "lower")
-                    iReg = 0;
-                else
-                    throw std::runtime_error("Unknown section name");
-                std::vector<std::vector<double>> gradX = reg->evalGradwrtX();
-                std::vector<std::vector<double>> gradY = reg->evalGradwrtY();
-                for (size_t i = 0; i < gradX.size(); ++i)
-                    for (size_t j = 0; j < gradX[i].size(); ++j)
-                    {
-                        int rowj = isol->pbl->bBCs[iReg]->nodes[reg->nodes[j]->row]->row;
-                        T_blw_x.push_back(Eigen::Triplet<double>(
-                            i + offSetElms, rowj * isol->pbl->nDim + 0, -gradX[i][j]));
-                        T_blw_x.push_back(Eigen::Triplet<double>(
-                            i + offSetElms, rowj * isol->pbl->nDim + 1, -gradY[i][j]));
-                    }
-                offSetElms += reg->getnElms();
-            }
-        }
-    }
-    dRblw_x.setFromTriplets(T_blw_x.begin(), T_blw_x.end());
-    dRblw_x.prune(0.);
-
-    //**************************************************************************//
-    //                         dRM_x, dRrho_x, dRv_x                            //
-    //--------------------------------------------------------------------------//
-    //                              Analytical                                  //
-    //**************************************************************************//
-    auto pbl = isol->pbl;
-
-    std::deque<Eigen::Triplet<double>> T_dM_x;
-    std::deque<Eigen::Triplet<double>> T_drho_x;
-    std::deque<Eigen::Triplet<double>> T_dv_x;
-
-    int jj = 0;
-    iReg = 0;
-
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (auto &reg : section->regions)
-            {
-                if (reg->getName() == "wake")
-                    iReg = 1;
-                else if (reg->getName() == "upper" || reg->getName() == "lower")
-                    iReg = 0;
-                else
-                    throw std::runtime_error(
-                        "gradientswrtInviscidFlow: Unknown section name");
-                for (size_t iNode = 0; iNode < reg->getnNodes(); ++iNode)
-                {
-                    tbox::Node *srfNode = pbl->bBCs[iReg]->nodes[reg->nodes[iNode]->row];
-                    double nAdjElms = static_cast<double>(pbl->fluid->neMap[srfNode].size());
-                    for (auto e : pbl->fluid->neMap[srfNode])
-                    {
-                        // dv/dx = dv/dgradPhi * dgradPhi/dx = dgradPhi/dx = (-J^(-1) *
-                        // dJ/dx_j)*grad_xPhi dM/dx = dM/dgradPhi * dgradPhi/dx = dM/dgradPhi *
-                        // gradPhi * dv/dx drho/dx = drho/dgradPhi * dgradPhi/dx = drho/dgradPhi
-                        // * gradPhi * dv/dx
-                        for (size_t inodOnElm = 0; inodOnElm < e->nodes.size(); inodOnElm++)
-                            for (int idim = 0; idim < nDim; ++idim)
-                            {
-                                Eigen::VectorXd gradV = (-e->getJinv(0)) *
-                                                        e->getGradJ(0)[inodOnElm * nDim + idim] *
-                                                        e->computeGradient(isol->phi, 0);
-                                double gradM = pbl->fluid->mach->evalGrad(*e, isol->phi, 0) *
-                                               e->computeGradient(isol->phi, 0).transpose() * gradV;
-                                double gradrho = pbl->fluid->rho->evalGrad(*e, isol->phi, 0) *
-                                                 e->computeGradient(isol->phi, 0).transpose() *
-                                                 gradV;
-                                T_dM_x.push_back(Eigen::Triplet<double>(
-                                    jj, e->nodes[inodOnElm]->row * nDim + idim, -gradM / nAdjElms));
-                                T_drho_x.push_back(Eigen::Triplet<double>(
-                                    jj, e->nodes[inodOnElm]->row * nDim + idim,
-                                    -gradrho / nAdjElms));
-                                for (int idim2 = 0; idim2 < nDim; idim2++)
-                                    T_dv_x.push_back(Eigen::Triplet<double>(
-                                        jj * nDim + idim2, e->nodes[inodOnElm]->row * nDim + idim,
-                                        -gradV(idim2) / nAdjElms));
-                            }
-                    }
-                    ++jj;
-                }
-            }
-        }
-    }
-    dRM_x.setFromTriplets(T_dM_x.begin(), T_dM_x.end());
-    dRrho_x.setFromTriplets(T_drho_x.begin(), T_drho_x.end());
-    dRv_x.setFromTriplets(T_dv_x.begin(), T_dv_x.end());
-    dRM_x.prune(0.);
-    dRrho_x.prune(0.);
-    dRv_x.prune(0.);
+    // int nDim = isol->pbl->nDim;
+
+    // //**************************************************************************//
+    // //                               dCl_x, dCd_x                               //
+    // //--------------------------------------------------------------------------//
+    // //                                 Analytical                               //
+    // //**************************************************************************//
+    // std::vector<std::vector<double>> dCx_x =
+    //     iadjoint->computeGradientCoefficientsMesh();
+    // dCl_x = Eigen::Map<Eigen::VectorXd>(dCx_x[0].data(), dCx_x[0].size());
+    // dCdp_x = Eigen::Map<Eigen::VectorXd>(dCx_x[1].data(), dCx_x[1].size());
+
+    // //**************************************************************************//
+    // //                                  dRphi_x                                 //
+    // //--------------------------------------------------------------------------//
+    // //                                 Analytical                               //
+    // //**************************************************************************//
+    // dRphi_x = iadjoint->getRu_X();
+    // //**************************************************************************//
+    // //                                   dRx_x                                  //
+    // //--------------------------------------------------------------------------//
+    // //                                 Analytical                               //
+    // //**************************************************************************//
+    // dRx_x = iadjoint->getRx_X();
+
+    // //**************************************************************************//
+    // //                            dRdStar_x, dCdf_dx                            //
+    // //--------------------------------------------------------------------------//
+    // //                         Central finite-difference                        //
+    // //--------------------------------------------------------------------------//
+    // // We don't do dRdStar_x = dRdStar_loc * dloc_dx because Cdf = f(xi(x), x)  //
+    // // and we would have to compute dCdf/dx and dCdf/dloc. Same for deltaStar.  //
+    // // It is more computationally expansive to compute                          //
+    // // ddeltaStar/dx, ddeltaStar/dloc than ddeltaStar_dx, ddeltaStar_dy         //
+    // //**************************************************************************//
+    // std::deque<Eigen::Triplet<double>> T_dStar_x;
+    // double delta = 1e-8;
+    // int iReg = 0;
+    // std::vector<Eigen::VectorXd> ddStar(2,
+    //                                     Eigen::VectorXd::Zero(dRdStar_M.cols()));
+    // std::vector<double> dCdf(2, 0.);
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             if (reg->getName() == "wake")
+    //                 iReg = 1;
+    //             else if (reg->getName() == "upper" || reg->getName() == "lower")
+    //                 iReg = 0;
+    //             else
+    //                 throw std::runtime_error("Unknown section name");
+    //             for (size_t j = 0; j < reg->getnNodes(); ++j)
+    //             {
+    //                 int rowj = isol->pbl->bBCs[iReg]->nodes[reg->nodes[j]->row]->row;
+    //                 // x
+    //                 double saveX = reg->nodes[j]->pos[0];
+
+    //                 reg->nodes[j]->pos[0] = saveX + delta;
+    //                 section->computeLocalCoordinates(reg);
+    //                 for (auto &nod : reg->nodes)
+    //                     nod->xiExt = nod->xi;
+    //                 ddStar[0] = this->runViscous();
+    //                 dCdf[0] = vsol->Cdf;
+    //                 reg->nodes[j]->pos[0] = saveX - delta;
+    //                 section->computeLocalCoordinates(reg);
+    //                 for (auto &nod : reg->nodes)
+    //                     nod->xiExt = nod->xi;
+    //                 ddStar[1] = this->runViscous();
+    //                 dCdf[1] = vsol->Cdf;
+
+    //                 reg->nodes[j]->pos[0] = saveX;
+    //                 section->computeLocalCoordinates(reg);
+    //                 for (auto &nod : reg->nodes)
+    //                     nod->xiExt = nod->xi;
+
+    //                 for (int k = 0; k < ddStar[0].size(); ++k)
+    //                     T_dStar_x.push_back(Eigen::Triplet<double>(
+    //                         k, rowj * isol->pbl->nDim + 0,
+    //                         -(ddStar[0][k] - ddStar[1][k]) / (2. * delta)));
+    //                 dCdf_x(rowj * isol->pbl->nDim + 0) += (dCdf[0] - dCdf[1]) / (2. * delta);
+    //                 // y
+    //                 double saveY = reg->nodes[j]->pos[1];
+
+    //                 reg->nodes[j]->pos[1] = saveY + delta;
+    //                 section->computeLocalCoordinates(reg);
+    //                 for (auto &nod : reg->nodes)
+    //                     nod->xiExt = nod->xi;
+    //                 ddStar[0] = this->runViscous();
+    //                 dCdf[0] = vsol->Cdf;
+    //                 reg->nodes[j]->pos[1] = saveY - delta;
+    //                 section->computeLocalCoordinates(reg);
+    //                 for (auto &nod : reg->nodes)
+    //                     nod->xiExt = nod->xi;
+    //                 ddStar[1] = this->runViscous();
+    //                 dCdf[1] = vsol->Cdf;
+
+    //                 reg->nodes[j]->pos[1] = saveY;
+    //                 section->computeLocalCoordinates(reg);
+    //                 for (auto &nod : reg->nodes)
+    //                     nod->xiExt = nod->xi;
+
+    //                 for (int k = 0; k < ddStar[0].size(); ++k)
+    //                     T_dStar_x.push_back(Eigen::Triplet<double>(
+    //                         k, rowj * isol->pbl->nDim + 1,
+    //                         -(ddStar[0][k] - ddStar[1][k]) / (2. * delta)));
+    //                 dCdf_x(rowj * isol->pbl->nDim + 1) += (dCdf[0] - dCdf[1]) / (2. * delta);
+    //             }
+    //         }
+    //     }
+    // }
+    // dRdStar_x.setFromTriplets(T_dStar_x.begin(), T_dStar_x.end());
+    // dRdStar_x.prune(0.);
+
+    // //**************************************************************************//
+    // //                                dRblw_x                                   //
+    // //--------------------------------------------------------------------------//
+    // //                               Analytical                                 //
+    // //**************************************************************************//
+    // std::deque<Eigen::Triplet<double>> T_blw_x;
+    // int offSetElms = 0;
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             if (reg->getName() == "wake")
+    //                 iReg = 1;
+    //             else if (reg->getName() == "upper" || reg->getName() == "lower")
+    //                 iReg = 0;
+    //             else
+    //                 throw std::runtime_error("Unknown section name");
+    //             std::vector<std::vector<double>> gradX = reg->evalGradwrtX();
+    //             std::vector<std::vector<double>> gradY = reg->evalGradwrtY();
+    //             for (size_t i = 0; i < gradX.size(); ++i)
+    //                 for (size_t j = 0; j < gradX[i].size(); ++j)
+    //                 {
+    //                     int rowj = isol->pbl->bBCs[iReg]->nodes[reg->nodes[j]->row]->row;
+    //                     T_blw_x.push_back(Eigen::Triplet<double>(
+    //                         i + offSetElms, rowj * isol->pbl->nDim + 0, -gradX[i][j]));
+    //                     T_blw_x.push_back(Eigen::Triplet<double>(
+    //                         i + offSetElms, rowj * isol->pbl->nDim + 1, -gradY[i][j]));
+    //                 }
+    //             offSetElms += reg->getnElms();
+    //         }
+    //     }
+    // }
+    // dRblw_x.setFromTriplets(T_blw_x.begin(), T_blw_x.end());
+    // dRblw_x.prune(0.);
+
+    // //**************************************************************************//
+    // //                         dRM_x, dRrho_x, dRv_x                            //
+    // //--------------------------------------------------------------------------//
+    // //                              Analytical                                  //
+    // //**************************************************************************//
+    // auto pbl = isol->pbl;
+
+    // std::deque<Eigen::Triplet<double>> T_dM_x;
+    // std::deque<Eigen::Triplet<double>> T_drho_x;
+    // std::deque<Eigen::Triplet<double>> T_dv_x;
+
+    // int jj = 0;
+    // iReg = 0;
+
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (auto &reg : section->regions)
+    //         {
+    //             if (reg->getName() == "wake")
+    //                 iReg = 1;
+    //             else if (reg->getName() == "upper" || reg->getName() == "lower")
+    //                 iReg = 0;
+    //             else
+    //                 throw std::runtime_error(
+    //                     "gradientswrtInviscidFlow: Unknown section name");
+    //             for (size_t iNode = 0; iNode < reg->getnNodes(); ++iNode)
+    //             {
+    //                 tbox::Node *srfNode = pbl->bBCs[iReg]->nodes[reg->nodes[iNode]->row];
+    //                 double nAdjElms = static_cast<double>(pbl->fluid->neMap[srfNode].size());
+    //                 for (auto e : pbl->fluid->neMap[srfNode])
+    //                 {
+    //                     // dv/dx = dv/dgradPhi * dgradPhi/dx = dgradPhi/dx = (-J^(-1) *
+    //                     // dJ/dx_j)*grad_xPhi dM/dx = dM/dgradPhi * dgradPhi/dx = dM/dgradPhi *
+    //                     // gradPhi * dv/dx drho/dx = drho/dgradPhi * dgradPhi/dx = drho/dgradPhi
+    //                     // * gradPhi * dv/dx
+    //                     for (size_t inodOnElm = 0; inodOnElm < e->nodes.size(); inodOnElm++)
+    //                         for (int idim = 0; idim < nDim; ++idim)
+    //                         {
+    //                             Eigen::VectorXd gradV = (-e->getJinv(0)) *
+    //                                                     e->getGradJ(0)[inodOnElm * nDim + idim] *
+    //                                                     e->computeGradient(isol->phi, 0);
+    //                             double gradM = pbl->fluid->mach->evalGrad(*e, isol->phi, 0) *
+    //                                            e->computeGradient(isol->phi, 0).transpose() * gradV;
+    //                             double gradrho = pbl->fluid->rho->evalGrad(*e, isol->phi, 0) *
+    //                                              e->computeGradient(isol->phi, 0).transpose() *
+    //                                              gradV;
+    //                             T_dM_x.push_back(Eigen::Triplet<double>(
+    //                                 jj, e->nodes[inodOnElm]->row * nDim + idim, -gradM / nAdjElms));
+    //                             T_drho_x.push_back(Eigen::Triplet<double>(
+    //                                 jj, e->nodes[inodOnElm]->row * nDim + idim,
+    //                                 -gradrho / nAdjElms));
+    //                             for (int idim2 = 0; idim2 < nDim; idim2++)
+    //                                 T_dv_x.push_back(Eigen::Triplet<double>(
+    //                                     jj * nDim + idim2, e->nodes[inodOnElm]->row * nDim + idim,
+    //                                     -gradV(idim2) / nAdjElms));
+    //                         }
+    //                 }
+    //                 ++jj;
+    //             }
+    //         }
+    //     }
+    // }
+    // dRM_x.setFromTriplets(T_dM_x.begin(), T_dM_x.end());
+    // dRrho_x.setFromTriplets(T_drho_x.begin(), T_drho_x.end());
+    // dRv_x.setFromTriplets(T_dv_x.begin(), T_dv_x.end());
+    // dRM_x.prune(0.);
+    // dRrho_x.prune(0.);
+    // dRv_x.prune(0.);
 }
 
 /**
@@ -1241,41 +1241,41 @@ void CoupledAdjoint::gradientwrtMesh()
  */
 Eigen::VectorXd CoupledAdjoint::runViscous()
 {
-    int exitCode = vsol->run();
-    if (exitCode != 0 && vsol->verbose > 0)
-        std::cout << "vsol terminated with exit code " << exitCode << std::endl;
-
-    // Extract deltaStar
-    std::vector<Eigen::VectorXd> dStar_p;
-
-    // Extract parts in a loop
-    for (auto &body : vsol->bodies)
-    {
-        for (auto &section : body->sections)
-        {
-            for (size_t i = 0; i < section->regions.size(); ++i)
-            {
-                std::vector<double> deltaStar_vec = section->regions[i]->deltaStar;
-                Eigen::VectorXd deltaStar_eigen =
-                    Eigen::Map<Eigen::VectorXd>(deltaStar_vec.data(), deltaStar_vec.size());
-                dStar_p.push_back(deltaStar_eigen);
-            }
-        }
-    }
-    // Calculate the total size
-    int nNs = 0;
-    for (const auto &p : dStar_p)
-        nNs += p.size();
-
-    // Concatenate the vectors
-    Eigen::VectorXd deltaStar(nNs);
-    int idx = 0;
-    for (const auto &p : dStar_p)
-    {
-        deltaStar.segment(idx, p.size()) = p;
-        idx += p.size();
-    }
-    return deltaStar;
+    // int exitCode = vsol->run();
+    // if (exitCode != 0 && vsol->verbose > 0)
+    //     std::cout << "vsol terminated with exit code " << exitCode << std::endl;
+
+    // // Extract deltaStar
+    // std::vector<Eigen::VectorXd> dStar_p;
+
+    // // Extract parts in a loop
+    // for (auto &body : vsol->bodies)
+    // {
+    //     for (auto &section : body->sections)
+    //     {
+    //         for (size_t i = 0; i < section->regions.size(); ++i)
+    //         {
+    //             std::vector<double> deltaStar_vec = section->regions[i]->deltaStar;
+    //             Eigen::VectorXd deltaStar_eigen =
+    //                 Eigen::Map<Eigen::VectorXd>(deltaStar_vec.data(), deltaStar_vec.size());
+    //             dStar_p.push_back(deltaStar_eigen);
+    //         }
+    //     }
+    // }
+    // // Calculate the total size
+    // int nNs = 0;
+    // for (const auto &p : dStar_p)
+    //     nNs += p.size();
+
+    // // Concatenate the vectors
+    // Eigen::VectorXd deltaStar(nNs);
+    // int idx = 0;
+    // for (const auto &p : dStar_p)
+    // {
+    //     deltaStar.segment(idx, p.size()) = p;
+    //     idx += p.size();
+    // }
+    // return deltaStar;
 }
 
 /**
diff --git a/blast/src/blDriver.cpp b/blast/src/blDriver.cpp
index a23f3dc416bb9a5f71b1e40335156a9c9fcde417..ba33f166d20497813e3c07f486c72ec65fff3c29 100644
--- a/blast/src/blDriver.cpp
+++ b/blast/src/blDriver.cpp
@@ -1,3 +1,4 @@
+#include "blast.h"
 #include "blDriver.h"
 #include "blBoundaryLayer.h"
 #include "blSolver.h"
@@ -64,7 +65,7 @@ int Driver::run()
                             // unsuccessful, failed; >0: unsuccessful nb iter).
 
     int numberFailedPerBody = 0;
-    double maxMach = 0.;
+    bldouble maxMach = 0.;
 
     solverExitCode = 0;
 
@@ -109,7 +110,7 @@ int Driver::run()
                     for (auto &nod : reg->nodes)
                         nod->setRegime(1);
                     // Impose wake boundary condition.
-                    std::vector<std::vector<double>> teConditions;
+                    std::vector<std::vector<bldouble>> teConditions;
                     for (auto &iregion : section->regions)
                         if (iregion->getName() == "upper" || iregion->getName() == "lower")
                             teConditions.push_back(iregion->getTeConditions());
@@ -200,7 +201,7 @@ int Driver::run()
 void Driver::checkWaves(size_t inod, std::shared_ptr<BoundaryLayer> &bl)
 {
 
-    double logRet_crit =
+    bldouble logRet_crit =
         2.492 * std::pow(1. / (bl->Hk[inod] - 1), 0.43) +
         0.7 * (std::tanh(14 * (1. / (bl->Hk[inod] - 1)) - 9.24) + 1.0);
 
@@ -229,7 +230,7 @@ void Driver::averageTransition(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
     size_t nVar = bl->getnVar();
 
     // Save laminar solution.
-    std::vector<double> lamSol(nVar, 0.0);
+    std::vector<bldouble> lamSol(nVar, 0.0);
     for (size_t k = 0; k < lamSol.size(); ++k)
         lamSol[k] = bl->u[inod * nVar + k];
 
@@ -245,16 +246,16 @@ void Driver::averageTransition(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
                     (bl->u[inod * nVar + 2] - bl->u[(inod - 1) * nVar + 2])) +
                bl->nodes[inod - 1]->xoc);
 
-    double avTurb =
+    bldouble avTurb =
         (bl->nodes[inod]->xoc - bl->getxtr()) / (bl->nodes[inod]->xoc - bl->nodes[inod - 1]->xoc);
     if (avTurb < 0. - 1e-12)
         avTurb = 0.;
     if (avTurb > 1. + 1e-12)
         avTurb = 1.;
-    double avLam = 1. - avTurb;
+    bldouble avLam = 1. - avTurb;
 
     // Impose boundary condition.
-    double Cteq_trans;
+    bldouble Cteq_trans;
     bl->closSolver->turbulentClosures(Cteq_trans, bl->u[(inod - 1) * nVar + 0],
                                       bl->u[(inod - 1) * nVar + 1], 0.03,
                                       bl->Ret[inod - 1], bl->Me[inod - 1],
@@ -295,7 +296,7 @@ void Driver::averageTransition(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
 
     // Recompute closures. (The turbulent BC @ inod - 1 does not influence
     // laminar closure relations).
-    std::vector<double> lamParam(8, 0.);
+    std::vector<bldouble> lamParam(8, 0.);
     bl->closSolver->laminarClosures(
         lamParam, bl->u[(inod - 1) * nVar + 0], bl->u[(inod - 1) * nVar + 1],
         bl->Ret[inod - 1], bl->Me[inod - 1], bl->getName());
@@ -308,7 +309,7 @@ void Driver::averageTransition(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
     bl->ctEq[inod - 1] = lamParam[6];
     bl->us[inod - 1] = lamParam[7];
 
-    std::vector<double> turbParam(8, 0.);
+    std::vector<bldouble> turbParam(8, 0.);
     bl->closSolver->turbulentClosures(
         turbParam, bl->u[(inod)*nVar + 0], bl->u[(inod)*nVar + 1],
         bl->u[(inod)*nVar + 4], bl->Ret[inod], bl->Me[inod], bl->getName());
diff --git a/blast/src/blDriver.h b/blast/src/blDriver.h
index 7c5ffd70ae2d99eb2d36eeaaf856316e09473c42..79356e9e8ba26688c3046522ed66ba6d6c00e2eb 100644
--- a/blast/src/blDriver.h
+++ b/blast/src/blDriver.h
@@ -23,18 +23,16 @@ public:
     std::vector<std::shared_ptr<Body>> bodies; ///< Boundary layer regions sorted by body and section.
     unsigned int verbose;                      ///< Verbosity level of the solver 0<=verbose<=1.
 
-    double Cdt;
-    double Cdf;
-    double Cdp;
-
 private:
-    double Re;                 ///< Freestream Reynolds number.
-    double CFL0;               ///< Initial CFL number for pseudo time integration.
-    std::vector<double> spans; ///< Wing Span (Used only for drag computation, not used if 2D
-                               ///< case).
+    bldouble Re;                 ///< Freestream Reynolds number.
+    bldouble CFL0;               ///< Initial CFL number for pseudo time integration.
     Solver *tSolver;           ///< Pseudo-time solver.
     int solverExitCode;        ///< Exit code of viscous calculations.
 
+    bldouble Cdt;
+    bldouble Cdf;
+    bldouble Cdp;
+
 protected:
     fwk::Timers tms; ///< Internal timers
 
@@ -47,8 +45,11 @@ public:
     void add(std::shared_ptr<Body> body);
 
     // Getters.
-    double getRe() const { return Re; }
-    double getMinf() const { return tSolver->getMinf(); }
+    bldouble getRe() const { return Re; }
+    bldouble getMinf() const { return tSolver->getMinf(); }
+    bldouble getCdf() const { return Cdf; }
+    bldouble getCdt() const { return Cdt; }
+    bldouble getCdp() const { return Cdp; }
 
     // Setters.
     void setVerbose(unsigned int _verbose) { verbose = _verbose; }
diff --git a/blast/src/blFluxes.cpp b/blast/src/blFluxes.cpp
index 2578f52d04862edd5428d6bef9692ac051b1ac56..8b974ba90330a5bebac1b8a533a4b18c2bcef64d 100644
--- a/blast/src/blFluxes.cpp
+++ b/blast/src/blFluxes.cpp
@@ -1,53 +1,87 @@
+#include "blast.h"
 #include "blFluxes.h"
 #include "blBoundaryLayer.h"
 #include "blNode.h"
-#include <Eigen/Dense>
+
+#ifdef USE_CODI
+#include "codi.hpp"
+#endif
 
 using namespace blast;
-using namespace Eigen;
 
 /**
  * @brief Compute residual vector of the integral boundary layer equations.
  *
  * @param inod Marker id.
  * @param bl Boundary layer region.
- * @return VectorXd
+ * @return blVectorXd
  */
-VectorXd Fluxes::computeResiduals(size_t inod, std::shared_ptr<BoundaryLayer> &bl)
+blVectorXd Fluxes::computeResiduals(size_t inod, std::shared_ptr<BoundaryLayer> &bl)
 {
     size_t nVar = bl->getnVar();
-    std::vector<double> u(nVar, 0.);
+    std::vector<bldouble> u(nVar, 0.);
     for (size_t k = 0; k < nVar; ++k)
         u[k] = bl->u[inod * nVar + k];
     return blLaws(inod, bl, u);
 }
 
 /**
- * @brief Compute Jacobian of the integral boundary layer equations.
+ * @brief Compute Jacobian of the integral boundary layer equations using 
+ * automatic differentiation or finite differences.
  *
  * @param inod Marker id.
  * @param bl Boundary layer region.
  * @param sysRes Residual of the IBL at point inod.
  * @param eps Pertubation from current solution used to compute the Jacobian.
- * @return MatrixXd
+ * @return blMatrixXd
  */
-MatrixXd Fluxes::computeJacobian(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
-                                 VectorXd const &sysRes, double eps)
+blMatrixXd Fluxes::computeJacobian(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
+                                 blVectorXd const &sysRes, bldouble eps)
 {
     size_t nVar = bl->getnVar();
-    MatrixXd JacMatrix = MatrixXd::Zero(5, 5);
-    std::vector<double> uUp(nVar, 0.);
+    blMatrixXd JacMatrix = blMatrixXd::Zero(nVar, nVar);
+    std::vector<bldouble> sol(nVar, 0.);
     for (size_t k = 0; k < nVar; ++k)
-        uUp[k] = bl->u[inod * nVar + k];
+        sol[k] = bl->u[inod * nVar + k];
 
-    double varSave = 0.;
-    for (size_t iVar = 0; iVar < nVar; ++iVar)
-    {
-        varSave = uUp[iVar];
-        uUp[iVar] += eps;
-        JacMatrix.col(iVar) = (blLaws(inod, bl, uUp) - sysRes) / eps;
-        uUp[iVar] = varSave;
-    }
+    #ifdef USE_CODI
+        // Compute the Jacobian using automatic differentiation.
+        bltape &tape = bldouble::getTape();
+        tape.reset();
+        tape.setActive();
+        // Register inputs
+        for (auto &ui : sol)
+            tape.registerInput(ui);
+        // Compute residuals
+        blVectorXd res = blLaws(inod, bl, sol);
+        // Register outputs
+        for (auto& ri : res)
+            tape.registerOutput(ri);
+        // Desactivate tape
+        tape.setPassive();
+
+        // Form the Jacobian
+        for (size_t i = 0; i < 5; ++i)
+        {
+            res[i].gradient() = 1.0;
+
+            tape.evaluate();
+            for(size_t j = 0; j < 5; ++j) {
+                JacMatrix(i, j) = sol[j].getGradient();
+            }
+            tape.clearAdjoints();
+        }
+    #else
+        // Compute the Jacobian using finite differences.
+        bldouble varSave = 0.;
+        for (size_t iVar = 0; iVar < nVar; ++iVar)
+        {
+            varSave = sol[iVar];
+            sol[iVar] += eps;
+            JacMatrix.col(iVar) = (blLaws(inod, bl, sol) - sysRes) / eps;
+            sol[iVar] = varSave;
+        }
+    #endif
     return JacMatrix;
 }
 
@@ -57,17 +91,17 @@ MatrixXd Fluxes::computeJacobian(size_t inod, std::shared_ptr<BoundaryLayer> &bl
  * @param inod Node number.
  * @param bl Boundary layer region.
  * @param u Solution vector at point inod.
- * @return VectorXd
+ * @return blVectorXd
  */
-VectorXd Fluxes::blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
-                        std::vector<double> u)
+blVectorXd Fluxes::blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
+                        std::vector<bldouble> &u)
 {
     size_t nVar = bl->getnVar();
     auto &currNode = bl->nodes[inod];
     auto &prevNode = bl->nodes[inod - 1];
 
     // Dissipation ratio.
-    double dissipRatio = 0.;
+    bldouble dissipRatio = 0.;
     if (bl->getName() == "wake")
         dissipRatio = 0.9;
     else
@@ -81,7 +115,7 @@ VectorXd Fluxes::blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
     if (currNode->getRegime() == 0)
     {
         // Laminar closure relations.
-        std::vector<double> lamParam(8, 0.);
+        std::vector<bldouble> lamParam(8, 0.);
         bl->closSolver->laminarClosures(lamParam, u[0], u[1], bl->Ret[inod],
                                         bl->Me[inod], bl->getName());
         bl->Hstar[inod] = lamParam[0];
@@ -96,7 +130,7 @@ VectorXd Fluxes::blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
     else if (currNode->getRegime() == 1)
     {
         // Turbulent closure relations.
-        std::vector<double> turbParam(8, 0.);
+        std::vector<bldouble> turbParam(8, 0.);
         bl->closSolver->turbulentClosures(
             turbParam, u[0], u[1], u[4], bl->Ret[inod], bl->Me[inod], bl->getName());
         bl->Hstar[inod] = turbParam[0];
@@ -112,24 +146,24 @@ VectorXd Fluxes::blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
         throw std::runtime_error("Wrong regime");
 
     // Gradients computation.
-    double dx = (currNode->xi - prevNode->xi);
-    double dxExt = (currNode->xiExt - prevNode->xiExt);
-    double dt_dx = (u[0] - bl->u[(inod - 1) * nVar + 0]) / dx;
-    double dH_dx = (u[1] - bl->u[(inod - 1) * nVar + 1]) / dx;
-    double due_dx = (u[3] - bl->u[(inod - 1) * nVar + 3]) / dx;
-    double dct_dx = (u[4] - bl->u[(inod - 1) * nVar + 4]) / dx;
-    double dHstar_dx = (bl->Hstar[inod] - bl->Hstar[inod - 1]) / dx;
+    bldouble dx = (currNode->xi - prevNode->xi);
+    bldouble dxExt = (currNode->xiExt - prevNode->xiExt);
+    bldouble dt_dx = (u[0] - bl->u[(inod - 1) * nVar + 0]) / dx;
+    bldouble dH_dx = (u[1] - bl->u[(inod - 1) * nVar + 1]) / dx;
+    bldouble due_dx = (u[3] - bl->u[(inod - 1) * nVar + 3]) / dx;
+    bldouble dct_dx = (u[4] - bl->u[(inod - 1) * nVar + 4]) / dx;
+    bldouble dHstar_dx = (bl->Hstar[inod] - bl->Hstar[inod - 1]) / dx;
 
-    double dueExt_dx = (bl->vt[inod] - bl->vt[inod - 1]) / dxExt;
-    double ddeltaStarExt_dx =
+    bldouble dueExt_dx = (bl->vt[inod] - bl->vt[inod - 1]) / dxExt;
+    bldouble ddeltaStarExt_dx =
         (bl->deltaStarExt[inod] - bl->deltaStarExt[inod - 1]) / dxExt;
 
-    double c = 4. / (M_PI * dx);
-    double cExt = 4. / (M_PI * dxExt);
+    bldouble c = 4. / (M_PI * dx);
+    bldouble cExt = 4. / (M_PI * dxExt);
 
     // Amplification routine.
-    double dN_dx = 0.0;
-    double ax = 0.0;
+    bldouble dN_dx = 0.0;
+    bldouble ax = 0.0;
     if (bl->getxtrF() == -1.0 && currNode->getRegime() == 0)
     {
         // No forced transition and laminar regime.
@@ -137,15 +171,15 @@ VectorXd Fluxes::blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
         dN_dx = (u[2] - bl->u[(inod - 1) * nVar + 2]) / dx;
     }
 
-    double Mea = bl->Me[inod];
-    double Hstara = bl->Hstar[inod];
-    double Hstar2a = bl->Hstar2[inod];
-    double Hka = bl->Hk[inod];
-    double cfa = bl->cf[inod];
-    double cda = bl->cd[inod];
-    double deltaa = bl->delta[inod];
-    double ctEqa = bl->ctEq[inod];
-    double usa = bl->us[inod];
+    bldouble Mea = bl->Me[inod];
+    bldouble Hstara = bl->Hstar[inod];
+    bldouble Hstar2a = bl->Hstar2[inod];
+    bldouble Hka = bl->Hk[inod];
+    bldouble cfa = bl->cf[inod];
+    bldouble cda = bl->cd[inod];
+    bldouble deltaa = bl->delta[inod];
+    bldouble ctEqa = bl->ctEq[inod];
+    bldouble usa = bl->us[inod];
 
     //--------------------------------------------------------------------------------//
     // Integral boundary layer equations. //
@@ -187,7 +221,7 @@ VectorXd Fluxes::blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
     //     timeMatrix(4, 4) = 1.0;
     //--------------------------------------------------------------------------------//
 
-    VectorXd result = VectorXd::Zero(5);
+    blVectorXd result = blVectorXd::Zero(5);
 
     if (currNode->getRegime() == 0)
     {
@@ -298,28 +332,28 @@ VectorXd Fluxes::blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
  * @param Hk Kinematic shape parameter.
  * @param Ret Reynolds number based on the momentum thickness.
  * @param theta Momentum thickness.
- * @return double
+ * @return bldouble
  */
-double Fluxes::amplificationRoutine(double Hk, double Ret, double theta) const
+bldouble Fluxes::amplificationRoutine(bldouble Hk, bldouble Ret, bldouble theta) const
 {
-    double dgr = 0.08;
-    double Hk1 = 3.5;
-    double Hk2 = 4.;
-    double Hmi = (1 / (Hk - 1));
-    double logRet_crit =
+    bldouble dgr = 0.08;
+    bldouble Hk1 = 3.5;
+    bldouble Hk2 = 4.;
+    bldouble Hmi = (1 / (Hk - 1));
+    bldouble logRet_crit =
         2.492 * std::pow(1. / (Hk - 1.), 0.43) +
         0.7 * (std::tanh(14. * Hmi - 9.24) +
                1.0); // value at which the amplification starts to grow
 
-    double ax = 0.;
+    bldouble ax = 0.;
     if (Ret <= 0.)
         Ret = 1.;
     if (std::log10(Ret) < logRet_crit - dgr)
         ax = 0.;
     else
     {
-        double rNorm = (std::log10(Ret) - (logRet_crit - dgr)) / (2. * dgr);
-        double Rfac = 0.;
+        bldouble rNorm = (std::log10(Ret) - (logRet_crit - dgr)) / (2. * dgr);
+        bldouble Rfac = 0.;
         if (rNorm <= 0)
             Rfac = 0.;
         if (rNorm >= 1)
@@ -328,25 +362,25 @@ double Fluxes::amplificationRoutine(double Hk, double Ret, double theta) const
             Rfac = 3. * rNorm * rNorm - 2. * rNorm * rNorm * rNorm;
 
         // Normal envelope amplification rate
-        double m = -0.05 + 2.7 * Hmi - 5.5 * Hmi * Hmi + 3. * Hmi * Hmi * Hmi +
+        bldouble m = -0.05 + 2.7 * Hmi - 5.5 * Hmi * Hmi + 3. * Hmi * Hmi * Hmi +
                    0.1 * std::exp(-20. * Hmi);
-        double arg = 3.87 * Hmi - 2.52;
-        double dndRet = 0.028 * (Hk - 1.) - 0.0345 * std::exp(-(arg * arg));
+        bldouble arg = 3.87 * Hmi - 2.52;
+        bldouble dndRet = 0.028 * (Hk - 1.) - 0.0345 * std::exp(-(arg * arg));
         ax = (m * dndRet / theta) * Rfac;
 
         // Set correction for separated profiles
         if (Hk > Hk1)
         {
-            double Hnorm = (Hk - Hk1) / (Hk2 - Hk1);
-            double Hfac = 0.;
+            bldouble Hnorm = (Hk - Hk1) / (Hk2 - Hk1);
+            bldouble Hfac = 0.;
             if (Hnorm >= 1.)
                 Hfac = 1.;
             else
                 Hfac = 3. * Hnorm * Hnorm - 2. * Hnorm * Hnorm * Hnorm;
-            double ax1 = ax;
-            double gro = 0.3 + 0.35 * std::exp(-0.15 * (Hk - 5.));
-            double tnr = std::tanh(1.2 * (std::log10(Ret) - gro));
-            double ax2 = (0.086 * tnr - 0.25 / std::pow((Hk - 1.), 1.5)) / theta;
+            bldouble ax1 = ax;
+            bldouble gro = 0.3 + 0.35 * std::exp(-0.15 * (Hk - 5.));
+            bldouble tnr = std::tanh(1.2 * (std::log10(Ret) - gro));
+            bldouble ax2 = (0.086 * tnr - 0.25 / std::pow((Hk - 1.), 1.5)) / theta;
             if (ax2 < 0.)
                 ax2 = 0.;
             ax = Hfac * ax2 + (1. - Hfac) * ax1;
diff --git a/blast/src/blFluxes.h b/blast/src/blFluxes.h
index 4e8d5b12932ed1d276fefa9975ab5ee3cdff4e1c..dee71ab5b46e1ad4101ed88136bf2cb1c33ca83b 100644
--- a/blast/src/blFluxes.h
+++ b/blast/src/blFluxes.h
@@ -3,8 +3,6 @@
 
 #include "blBoundaryLayer.h"
 #include "blast.h"
-#include <Eigen/Dense>
-
 #include <memory>
 
 namespace blast
@@ -18,19 +16,19 @@ namespace blast
 class BLAST_API Fluxes
 {
 public:
-    double Re; ///< Freestream Reynolds number.
+    bldouble Re; ///< Freestream Reynolds number.
 
 public:
-    Fluxes(double _Re) : Re(_Re) {}
+    Fluxes(bldouble _Re) : Re(_Re) {}
     ~Fluxes() {}
-    Eigen::VectorXd computeResiduals(size_t inod, std::shared_ptr<BoundaryLayer> &bl);
-    Eigen::MatrixXd computeJacobian(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
-                                    Eigen::VectorXd const &sysRes, double eps);
+    blVectorXd computeResiduals(size_t inod, std::shared_ptr<BoundaryLayer> &bl);
+    blMatrixXd computeJacobian(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
+                                    blVectorXd const &sysRes, bldouble eps);
 
 private:
-    Eigen::VectorXd blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
-                           std::vector<double> u);
-    double amplificationRoutine(double Hk, double Ret, double theta) const;
+    blVectorXd blLaws(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
+                           std::vector<bldouble> &u);
+    bldouble amplificationRoutine(bldouble Hk, bldouble Ret, bldouble theta) const;
 };
 } // namespace blast
 #endif // BLFLUXES_H
diff --git a/blast/src/blNode.cpp b/blast/src/blNode.cpp
index dd110d525a84394c91fd5761a2111f7bc58ea722..2628aa78330694dd33999e7b51f86cca19ce0771 100644
--- a/blast/src/blNode.cpp
+++ b/blast/src/blNode.cpp
@@ -16,6 +16,7 @@
 
 // Adapted from tbox wNode by Romain Boman.
 
+#include "blast.h"
 #include "blNode.h"
 #include <Eigen/Dense>
 
@@ -26,7 +27,7 @@ void blNode::write(std::ostream &out) const
     out << "node #" << no << " = " << pos.transpose() << " row=" << row;
 }
 
-blNode::blNode(int n, Eigen::Vector3d const &p, int r) : wObject(), no(n), pos(p), row(r)
+blNode::blNode(int n, blVector3d const &p, int r) : wObject(), no(n), pos(p), row(r)
 {
     xoc = 0.0;
     xi = 0.0;
diff --git a/blast/src/blNode.h b/blast/src/blNode.h
index 026c068acf6f24ccd0b4b305132baf8c4d5f997c..84d16040895ce450202b9fda3b483d739a0f4884 100644
--- a/blast/src/blNode.h
+++ b/blast/src/blNode.h
@@ -24,7 +24,6 @@
 #include <vector>
 #include <algorithm>
 #include <memory>
-#include <Eigen/Dense>
 
 namespace blast
 {
@@ -36,18 +35,18 @@ class BLAST_API blNode : public fwk::wObject
 {
 public:
     int no;
-    Eigen::Vector3d pos;
+    blVector3d pos;
     int row;
 
-    double xoc;   ///< x/c coordinate in the global frame of reference.
-    double xi;    ///< coordinate in the local frame of reference.
-    double xiExt; ///< coordinate in the local frame of reference, at the edge of the boundary layer.
+    bldouble xoc;   ///< x/c coordinate in the global frame of reference.
+    bldouble xi;    ///< coordinate in the local frame of reference.
+    bldouble xiExt; ///< coordinate in the local frame of reference, at the edge of the boundary layer.
 
 private:
     int regime; ///< Regime of the boundary layer (0=laminar, 1=turbulent).
 
 public:
-    blNode(int n, Eigen::Vector3d const &p, int r);
+    blNode(int n, blVector3d const &p, int r);
     void setRegime(int const r) { regime = r; }
     int getRegime() const { return regime; }
 
diff --git a/blast/src/blSection.cpp b/blast/src/blSection.cpp
index bcae644e5a8495f764c458432e646ae918eca142..3de8e6dc422ab18b5609e1848427808b33b9f237 100644
--- a/blast/src/blSection.cpp
+++ b/blast/src/blSection.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
+#include "blast.h"
 #include "blSection.h"
 #include "blBoundaryLayer.h"
-#include <Eigen/Dense>
 
 using namespace blast;
 
@@ -32,8 +32,8 @@ void Section::add(std::shared_ptr<BoundaryLayer> bl)
 void Section::computeLocalCoordinates()
 {
     // Compute minimum x and local chord
-    double xmin = 0.0;
-    double xmax = 0.0;
+    bldouble xmin = 0.0;
+    bldouble xmax = 0.0;
     for (auto &bl : regions)
     {
         if (bl->getName() == "wake")
@@ -46,7 +46,7 @@ void Section::computeLocalCoordinates()
                 xmax = node->pos[0];
         }
     }
-    double chord = xmax - xmin;
+    bldouble chord = xmax - xmin;
     if (chord <= 0.)
         throw std::runtime_error("Chord length is zero or negative.");
 
@@ -58,7 +58,7 @@ void Section::computeLocalCoordinates()
         {
             auto &nod1 = bl->nodes[ielm + 1];
             auto &nod2 = bl->nodes[ielm];
-            double dx = std::sqrt((nod1->pos[0] - nod2->pos[0]) * (nod1->pos[0] - nod2->pos[0]) + (nod1->pos[1] - nod2->pos[1]) * (nod1->pos[1] - nod2->pos[1]));
+            bldouble dx = std::sqrt((nod1->pos[0] - nod2->pos[0]) * (nod1->pos[0] - nod2->pos[0]) + (nod1->pos[1] - nod2->pos[1]) * (nod1->pos[1] - nod2->pos[1]));
             nod1->xi = nod2->xi + dx;
             nod1->xiExt = nod1->xi;
         }
@@ -71,8 +71,8 @@ void Section::computeLocalCoordinates()
 void Section::computeLocalCoordinates(std::shared_ptr<BoundaryLayer> &reg)
 {
     // Compute minimum x and local chord
-    double xmin = 0.0;
-    double xmax = 0.0;
+    bldouble xmin = 0.0;
+    bldouble xmax = 0.0;
     for (auto &bl : regions)
     {
         if (bl->getName() == "wake")
@@ -85,7 +85,7 @@ void Section::computeLocalCoordinates(std::shared_ptr<BoundaryLayer> &reg)
                 xmax = node->pos[0];
         }
     }
-    double chord = xmax - xmin;
+    bldouble chord = xmax - xmin;
     if (chord <= 0.)
         throw std::runtime_error("Chord length is zero or negative.");
 
@@ -95,7 +95,7 @@ void Section::computeLocalCoordinates(std::shared_ptr<BoundaryLayer> &reg)
     {
         auto &nod1 = reg->nodes[ielm + 1];
         auto &nod2 = reg->nodes[ielm];
-        double dx = std::sqrt((nod1->pos[0] - nod2->pos[0]) * (nod1->pos[0] - nod2->pos[0]) + (nod1->pos[1] - nod2->pos[1]) * (nod1->pos[1] - nod2->pos[1]));
+        bldouble dx = std::sqrt((nod1->pos[0] - nod2->pos[0]) * (nod1->pos[0] - nod2->pos[0]) + (nod1->pos[1] - nod2->pos[1]) * (nod1->pos[1] - nod2->pos[1]));
         nod1->xi = nod2->xi + dx;
         // nod1->xiExt = nod1->xi;
     }
@@ -122,7 +122,7 @@ void Section::computeDrag()
     Cdf = 0.0;
     for (auto &reg : regions)
     {
-        std::vector<double> cf_side(reg->getnNodes(), 0.0);
+        std::vector<bldouble> cf_side(reg->getnNodes(), 0.0);
         for (size_t k = 0; k < reg->getnNodes(); ++k)
             cf_side[k] = reg->vt[k] * reg->vt[k] * reg->cf[k];
         // Integrate cf_side over reg->nodes[i]->pos[0] and pos[1]
diff --git a/blast/src/blSection.h b/blast/src/blSection.h
index 5039f4902ad2544f72abff03b942c3c922ca19c1..0c8c7ea8fd35c0d82478005751dc08404e63eb0c 100644
--- a/blast/src/blSection.h
+++ b/blast/src/blSection.h
@@ -19,9 +19,9 @@ class BLAST_API Section : public fwk::wSharedObject
 {
 
 private:
-    double Cdt = 0.0; ///< Total drag coefficient.
-    double Cdf = 0.0; ///< Friction drag coefficient.
-    double Cdp = 0.0; ///< Pressure drag coefficient.
+    bldouble Cdt = 0.0; ///< Total drag coefficient.
+    bldouble Cdf = 0.0; ///< Friction drag coefficient.
+    bldouble Cdp = 0.0; ///< Pressure drag coefficient.
 
 public:
     Section();
@@ -32,9 +32,9 @@ public:
     void computeLocalCoordinates();
     void computeLocalCoordinates(std::shared_ptr<BoundaryLayer> &reg);
     void computeDrag();
-    double getCdt() const { return Cdt; }
-    double getCdf() const { return Cdf; }
-    double getCdp() const { return Cdp; }
+    bldouble getCdt() const { return Cdt; }
+    bldouble getCdf() const { return Cdf; }
+    bldouble getCdp() const { return Cdp; }
     int getRegionIdByName(std::string name) const;
     bool hasWake() const;
 };
diff --git a/blast/src/blSolver.cpp b/blast/src/blSolver.cpp
index c34e7c02ddc735efa2af561a9dcc42bb40d83568..f0fb70dbad074c56f34db3ab10bd58720ba759e2 100644
--- a/blast/src/blSolver.cpp
+++ b/blast/src/blSolver.cpp
@@ -1,10 +1,9 @@
+#include "blast.h"
 #include "blSolver.h"
 #include "blBoundaryLayer.h"
 #include "blFluxes.h"
-#include <Eigen/Dense>
 #include <iostream>
 
-using namespace Eigen;
 using namespace tbox;
 using namespace blast;
 
@@ -19,8 +18,8 @@ using namespace blast;
  * @param _itFrozenJac Number of iterations between which the Jacobian is
  * frozen.
  */
-Solver::Solver(double _CFL0, double _Minf, double Re, unsigned int _maxIt,
-               double _tol, unsigned int _itFrozenJac)
+Solver::Solver(bldouble _CFL0, bldouble _Minf, bldouble Re, unsigned int _maxIt,
+               bldouble _tol, unsigned int _itFrozenJac)
 {
     CFL0 = _CFL0;
     maxIt = _maxIt;
@@ -81,27 +80,27 @@ int Solver::integration(size_t inod, std::shared_ptr<BoundaryLayer> &bl)
     auto prevNode = bl->nodes[inod - 1];
 
     // Save initial condition.
-    std::vector<double> sln0(nVar, 0.);
+    std::vector<bldouble> sln0(nVar, 0.);
     for (size_t i = 0; i < nVar; ++i)
         sln0[i] = bl->u[inod * nVar + i];
 
     // Initialize time integration variables.
-    double dx = currNode->xi - prevNode->xi;
+    bldouble dx = currNode->xi - prevNode->xi;
 
     // Initial time step.
-    double CFL = CFL0;
+    bldouble CFL = CFL0;
     unsigned int itFrozenJac = itFrozenJac0;
-    double timeStep = setTimeStep(CFL, dx, bl->vt[inod]);
-    MatrixXd IMatrix(5, 5);
-    IMatrix = MatrixXd::Identity(5, 5) / timeStep;
+    bldouble timeStep = setTimeStep(CFL, dx, bl->vt[inod]);
+    blMatrixXd IMatrix(5, 5);
+    IMatrix = blMatrixXd::Identity(5, 5) / timeStep;
 
     // Initial system residuals.
-    VectorXd sysRes = sysMatrix->computeResiduals(inod, bl);
-    double normSysRes0 = sysRes.norm();
-    double normSysRes = normSysRes0;
+    blVectorXd sysRes = sysMatrix->computeResiduals(inod, bl);
+    bldouble normSysRes0 = sysRes.norm();
+    bldouble normSysRes = normSysRes0;
 
-    MatrixXd JacMatrix = MatrixXd::Zero(5, 5);
-    VectorXd slnIncr = VectorXd::Zero(5);
+    blMatrixXd JacMatrix = blMatrixXd::Zero(5, 5);
+    blVectorXd slnIncr = blVectorXd::Zero(5);
 
     unsigned int innerIters = 0; // Inner (non-linear) iterations
 
@@ -129,7 +128,7 @@ int Solver::integration(size_t inod, std::shared_ptr<BoundaryLayer> &bl)
         // CFL adaptation.
         CFL = std::max(CFL0 * pow(normSysRes0 / normSysRes, 0.7), 0.1);
         timeStep = setTimeStep(CFL, dx, bl->vt[inod]);
-        IMatrix = MatrixXd::Identity(5, 5) / timeStep;
+        IMatrix = blMatrixXd::Identity(5, 5) / timeStep;
 
         innerIters++;
     }
@@ -149,16 +148,16 @@ int Solver::integration(size_t inod, std::shared_ptr<BoundaryLayer> &bl)
  * @param CFL CFL number.
  * @param dx Cell size.
  * @param invVel Inviscid velocity.
- * @return double
+ * @return bldouble
  */
-double Solver::setTimeStep(double CFL, double dx, double invVel) const
+bldouble Solver::setTimeStep(bldouble CFL, bldouble dx, bldouble invVel) const
 {
     // Speed of sound.
-    double gradU2 = (invVel * invVel);
-    double soundSpeed = computeSoundSpeed(gradU2);
+    bldouble gradU2 = (invVel * invVel);
+    bldouble soundSpeed = computeSoundSpeed(gradU2);
 
     // Velocity of the fastest traveling wave.
-    double advVel = soundSpeed + invVel;
+    bldouble advVel = soundSpeed + invVel;
 
     // Time step computation.
     return CFL * dx / advVel;
@@ -168,9 +167,9 @@ double Solver::setTimeStep(double CFL, double dx, double invVel) const
  * @brief Compute the speed of sound in a cell.
  *
  * @param gradU2 Inviscid velocity squared in the cell.
- * @return double
+ * @return bldouble
  */
-double Solver::computeSoundSpeed(double gradU2) const
+bldouble Solver::computeSoundSpeed(bldouble gradU2) const
 {
     return sqrt(1. / (Minf * Minf) + 0.5 * (gamma - 1.) * (1. - gradU2));
 }
@@ -185,7 +184,7 @@ double Solver::computeSoundSpeed(double gradU2) const
  * @param usePrevPoint if 1, use the solution at previous point instead of sln0.
  */
 void Solver::resetSolution(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
-                           std::vector<double> sln0, bool usePrevPoint)
+                           std::vector<bldouble> sln0, bool usePrevPoint)
 {
     size_t nVar = bl->getnVar();
 
@@ -206,7 +205,7 @@ void Solver::resetSolution(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
 
     if (bl->nodes[inod]->getRegime() == 0)
     {
-        std::vector<double> lamParam(8, 0.);
+        std::vector<bldouble> lamParam(8, 0.);
         bl->closSolver->laminarClosures(lamParam, bl->u[inod * nVar + 0],
                                         bl->u[inod * nVar + 1], bl->Ret[inod],
                                         bl->Me[inod], bl->getName());
@@ -221,7 +220,7 @@ void Solver::resetSolution(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
     }
     else if (bl->nodes[inod]->getRegime() == 1)
     {
-        std::vector<double> turbParam(8, 0.);
+        std::vector<bldouble> turbParam(8, 0.);
         bl->closSolver->turbulentClosures(
             turbParam, bl->u[inod * nVar + 0], bl->u[inod * nVar + 1],
             bl->u[inod * nVar + 4], bl->Ret[inod], bl->Me[inod], bl->getName());
@@ -236,7 +235,7 @@ void Solver::resetSolution(size_t inod, std::shared_ptr<BoundaryLayer> &bl,
     }
 }
 
-void Solver::setCFL0(double _CFL0)
+void Solver::setCFL0(bldouble _CFL0)
 {
     if (_CFL0 > 0)
         CFL0 = _CFL0;
diff --git a/blast/src/blSolver.h b/blast/src/blSolver.h
index 5e1753e1ceb38fe5fb06adf835b4a45b0bc10f80..b882fb96e9eec7db17d2dd8630da19c9f8dbf70b 100644
--- a/blast/src/blSolver.h
+++ b/blast/src/blSolver.h
@@ -17,31 +17,31 @@ class BLAST_API Solver
 {
 
 private:
-    double CFL0;               ///< Initial CFL number.
+    bldouble CFL0;               ///< Initial CFL number.
     unsigned int maxIt;        ///< Maximum number of iterations.
-    double tol;                ///< Convergence tolerance.
+    bldouble tol;                ///< Convergence tolerance.
     unsigned int itFrozenJac0; ///< Number of iterations between which the
                                ///< Jacobian is frozen.
-    double const gamma = 1.4;  ///< Air heat capacity ratio.
-    double Minf;               ///< Freestream Mach number.
+    bldouble const gamma = 1.4;  ///< Air heat capacity ratio.
+    bldouble Minf;               ///< Freestream Mach number.
 
     Fluxes *sysMatrix;
 
 public:
-    Solver(double _CFL0, double _Minf, double Re, unsigned int _maxIt = 100,
-           double _tol = 1e-8, unsigned int _itFrozenJac = 1);
+    Solver(bldouble _CFL0, bldouble _Minf, bldouble Re, unsigned int _maxIt = 100,
+           bldouble _tol = 1e-8, unsigned int _itFrozenJac = 1);
     ~Solver();
     void initialCondition(size_t inod, std::shared_ptr<BoundaryLayer> &bl);
     int integration(size_t inod, std::shared_ptr<BoundaryLayer> &bl);
 
     // Getters.
-    double getCFL0() const { return CFL0; }
-    double getMinf() const { return Minf; }
+    bldouble getCFL0() const { return CFL0; }
+    bldouble getMinf() const { return Minf; }
     unsigned int getmaxIt() const { return maxIt; }
     unsigned int getitFrozenJac() const { return itFrozenJac0; }
 
     // Setters.
-    void setCFL0(double _CFL0);
+    void setCFL0(bldouble _CFL0);
     void setmaxIt(unsigned int _maxIt) { maxIt = _maxIt; };
     void setitFrozenJac(unsigned int _itFrozenJac)
     {
@@ -49,9 +49,9 @@ public:
     }
 
 private:
-    double setTimeStep(double CFL, double dx, double invVel) const;
-    double computeSoundSpeed(double gradU2) const;
-    void resetSolution(size_t inod, std::shared_ptr<BoundaryLayer> &bl, std::vector<double> Sln0,
+    bldouble setTimeStep(bldouble CFL, bldouble dx, bldouble invVel) const;
+    bldouble computeSoundSpeed(bldouble gradU2) const;
+    void resetSolution(size_t inod, std::shared_ptr<BoundaryLayer> &bl, std::vector<bldouble> Sln0,
                        bool usePrevPoint = false);
 };
 } // namespace blast
diff --git a/blast/src/blast.h b/blast/src/blast.h
index 42b50f849775ecf7ade8d1e49a8690ca2bb3ed86..239c65fac8c8767324e5eed99021ce489cabce5a 100644
--- a/blast/src/blast.h
+++ b/blast/src/blast.h
@@ -30,6 +30,23 @@
 #endif
 
 #include "tbox.h"
+#include "blaster_def.h"
+#include <Eigen/Dense>
+
+#ifndef SWIG
+#ifndef USE_CODI
+using bldouble = double;
+#else // USE_CODI
+#include "codi.hpp"
+using bldouble = codi::RealReverse;
+using bltape = bldouble::Tape;
+#endif // USE_CODI
+
+using blMatrixXd = Eigen::Matrix<bldouble, Eigen::Dynamic, Eigen::Dynamic>;
+using blVectorXd = Eigen::Matrix<bldouble, Eigen::Dynamic, 1>;
+using blMatrix3d = Eigen::Matrix<bldouble, 3, 3>;
+using blVector3d = Eigen::Matrix<bldouble, 3, 1>;
+#endif // SWIG
 
 /**
  * @brief Namespace for blast module
diff --git a/blast/tests/dart/t_naca0012_2D.py b/blast/tests/dart/t_naca0012_2D.py
index b31c31d4d44a7699027636c45f7e59cde75ebd6a..2d169708ea564fa9e3a5ae1d2b2e4ffd53d8c1bc 100644
--- a/blast/tests/dart/t_naca0012_2D.py
+++ b/blast/tests/dart/t_naca0012_2D.py
@@ -121,7 +121,7 @@ def main():
     # Display results.
     print(ccolors.ANSI_BLUE + 'PyRes...' + ccolors.ANSI_RESET)
     print('      Re        M    alpha       Cl       Cd      Cdp      Cdf       Cm')
-    print('{0:6.1f}e6 {1:8.2f} {2:8.1f} {3:8.4f} {4:8.4f} {5:8.4f} {6:8.4f} {7:8.4f}'.format(vcfg['Re']/1e6, isol.getMinf(), isol.getAoA()*180/math.pi, isol.getCl(), vsol.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
+    print('{0:6.1f}e6 {1:8.2f} {2:8.1f} {3:8.4f} {4:8.4f} {5:8.4f} {6:8.4f} {7:8.4f}'.format(vcfg['Re']/1e6, isol.getMinf(), isol.getAoA()*180/math.pi, isol.getCl(), vsol.getCdt(), vsol.getCdp(), vsol.getCdf(), isol.getCm()))
     tms['total'].stop()
 
     print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
@@ -136,9 +136,9 @@ def main():
     print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET)
     tests = CTests()
     tests.add(CTest('Cl', isol.getCl(), 0.230, 5e-2)) # XFOIL 0.2325
-    tests.add(CTest('Cd wake', vsol.Cdt, 0.0057, 1e-3, forceabs=True)) # XFOIL 0.00531
-    tests.add(CTest('Cd integral', vsol.Cdf + isol.getCd(), 0.0058, 1e-3, forceabs=True)) # XFOIL 0.00531
-    tests.add(CTest('Cdf', vsol.Cdf, 0.0047, 1e-3, forceabs=True)) # XFOIL 0.00084, Cdf = 0.00447
+    tests.add(CTest('Cd wake', vsol.getCdt(), 0.0057, 1e-3, forceabs=True)) # XFOIL 0.00531
+    tests.add(CTest('Cd integral', vsol.getCdf() + isol.getCd(), 0.0058, 1e-3, forceabs=True)) # XFOIL 0.00531
+    tests.add(CTest('Cdf', vsol.getCdf(), 0.0047, 1e-3, forceabs=True)) # XFOIL 0.00084, Cdf = 0.00447
     tests.add(CTest('xtr_top', vsol.bodies[0].getAvgxtr(0), 0.196, 0.03, forceabs=True)) # XFOIL 0.1877
     tests.add(CTest('xtr_bot', vsol.bodies[0].getAvgxtr(1), 0.40, 0.01, forceabs=True)) # XFOIL 0.4998
     tests.add(CTest('error dStar', np.linalg.norm(bl_solution['deltaStar'] - bl_solution['theta']*bl_solution['H']), 0., 0., forceabs=True))
diff --git a/blast/tests/dart/t_rae2822_3D.py b/blast/tests/dart/t_rae2822_3D.py
index b4018f567d9e44e42ed613a50b34ddf37826efa9..1bf4253032e9b757df58ef3d4f0d79f2e14b516a 100644
--- a/blast/tests/dart/t_rae2822_3D.py
+++ b/blast/tests/dart/t_rae2822_3D.py
@@ -143,7 +143,7 @@ def main():
     # Display results.
     print(ccolors.ANSI_BLUE + 'PyRes...' + ccolors.ANSI_RESET)
     print('      Re        M    alpha       Cl       Cd  Cd_wake      Cdp      Cdf       Cm')
-    print('{0:6.1f}e6 {1:8.2f} {2:8.1f} {3:8.4f} {4:8.4f} {5:8.4f} {6:8.4f} {7:8.4f} {8:8.4f}'.format(vcfg['Re']/1e6, isol.getMinf(), isol.getAoA()*180/math.pi, isol.getCl(), vsol.Cdf + isol.getCd(), vsol.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
+    print('{0:6.1f}e6 {1:8.2f} {2:8.1f} {3:8.4f} {4:8.4f} {5:8.4f} {6:8.4f} {7:8.4f} {8:8.4f}'.format(vcfg['Re']/1e6, isol.getMinf(), isol.getAoA()*180/math.pi, isol.getCl(), vsol.getCdf() + isol.getCd(), vsol.getCdt(), vsol.getCdp(), vsol.getCdf(), isol.getCm()))
 
     # Save results
     isol.save(sfx='_viscous')
@@ -159,9 +159,9 @@ def main():
     print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET)
     tests = CTests()
     tests.add(CTest('Cl', isol.getCl(), 0.1305, 5e-2))
-    tests.add(CTest('Cd wake', vsol.Cdt, 0.0113, 1e-3, forceabs=True))
-    tests.add(CTest('Cd integral', vsol.Cdf + isol.getCd(), 0.0172, 1e-3, forceabs=True))
-    tests.add(CTest('Cdf', vsol.Cdf, 0.0115, 1e-3, forceabs=True))
+    tests.add(CTest('Cd wake', vsol.getCdt(), 0.0113, 1e-3, forceabs=True))
+    tests.add(CTest('Cd integral', vsol.getCdf() + isol.getCd(), 0.0172, 1e-3, forceabs=True))
+    tests.add(CTest('Cdf', vsol.getCdf(), 0.0115, 1e-3, forceabs=True))
     tests.add(CTest('Iterations', len(aeroCoeffs['Cl']), 4, 0, forceabs=True))
     tests.run()
 
diff --git a/blaster_def.h.in b/blaster_def.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..4d1fa8efc88a470e528b8a0146bcfc5b17ea07b6
--- /dev/null
+++ b/blaster_def.h.in
@@ -0,0 +1 @@
+#cmakedefine USE_CODI