From 4dc69103ff3760329be31991239257e6d1b12c86 Mon Sep 17 00:00:00 2001
From: Paul Dechamps <paul.dechamps@uliege.be>
Date: Thu, 25 Apr 2024 11:28:18 +0200
Subject: [PATCH] (feat) Refactor of the solver interface

Boundary layer c++ objects are created in python with swig and are manipulated by the interface. The initial condition of the viscous solver was changed. All test cases have been adapted. A decrease in the number of iterations is globally observed. Results are slightly improved especially for the RAE validation case.
---
 blast/_src/blastw.h                           |   3 +-
 blast/_src/blastw.i                           |   5 +-
 blast/coupler.py                              |  94 ++--
 blast/interfaces/DDataStructure.py            | 179 +++++--
 blast/interfaces/DSolversInterface.py         | 242 ++++-----
 blast/interfaces/dart/DartInterface.py        |  54 +-
 .../interpolators/DMatchingInterpolator.py    |  19 +-
 .../interpolators/DRbfInterpolator.py         |  13 +-
 .../models/references/rae2822_AR138_case6.dat | 103 ++++
 blast/src/CMakeLists.txt                      |   2 +-
 blast/src/DBoundaryLayer.cpp                  | 143 +++---
 blast/src/DBoundaryLayer.h                    |  68 ++-
 blast/src/DDiscretization.cpp                 |  79 ---
 blast/src/DDiscretization.h                   |  54 --
 blast/src/DDriver.cpp                         | 469 +++++-------------
 blast/src/DDriver.h                           |  26 +-
 blast/src/DEdge.cpp                           |  59 ---
 blast/src/DEdge.h                             |  44 --
 blast/src/DFluxes.cpp                         |  14 +-
 blast/src/DSolver.cpp                         |  56 +--
 blast/src/DSolver.h                           |   2 -
 blast/src/blast.h                             |   2 -
 blast/tests/dart/naca0012_2D.py               |  34 +-
 blast/tests/dart/rae2822_3D.py                |  28 +-
 blast/utils.py                                | 172 ++++---
 blast/validation/lannValidation.py            |  21 +-
 blast/validation/oneraValidation.py           |  21 +-
 blast/validation/raeValidation.py             |  47 +-
 28 files changed, 950 insertions(+), 1103 deletions(-)
 create mode 100644 blast/models/references/rae2822_AR138_case6.dat
 delete mode 100644 blast/src/DDiscretization.cpp
 delete mode 100644 blast/src/DDiscretization.h
 delete mode 100644 blast/src/DEdge.cpp
 delete mode 100644 blast/src/DEdge.h

diff --git a/blast/_src/blastw.h b/blast/_src/blastw.h
index ec45463..f0b51a2 100644
--- a/blast/_src/blastw.h
+++ b/blast/_src/blastw.h
@@ -14,4 +14,5 @@
  * limitations under the License.
  */
 
-#include "DDriver.h"
\ No newline at end of file
+#include "DDriver.h"
+#include "DBoundaryLayer.h"
\ No newline at end of file
diff --git a/blast/_src/blastw.i b/blast/_src/blastw.i
index ab103f1..a28e208 100644
--- a/blast/_src/blastw.i
+++ b/blast/_src/blastw.i
@@ -21,12 +21,12 @@
 %module(docstring=
 "'blastw' module: Viscous inviscid interaction for blast 2021-2022
 (c) ULiege - A&M",
-directors="0",
 threads="1"
 ) blastw
 %{
 
 #include "blast.h"
+#include "DBoundaryLayer.h"
 
 #include "fwkw.h"
 #include "tboxw.h"
@@ -44,6 +44,9 @@ threads="1"
 %include "blast.h"
 
 %shared_ptr(blast::Driver);
+%shared_ptr(blast::BoundaryLayer);
+%include "DBoundaryLayer.h"
+
 
 %immutable blast::Driver::Re; // read-only variable (no setter)
 %immutable blast::Driver::Cdt;
diff --git a/blast/coupler.py b/blast/coupler.py
index b94e05e..91ecd93 100644
--- a/blast/coupler.py
+++ b/blast/coupler.py
@@ -25,78 +25,108 @@ import numpy as np
 
 class Coupler:
     def __init__(self, iSolverAPI, vSolver, _maxCouplIter=150, _couplTol=1e-4, _iterPrint=1, _resetInv=False, sfx=''):
-        self.iSolverAPI = iSolverAPI
-        self.vSolver = vSolver
-        self.maxCouplIter = _maxCouplIter
-        self.couplTol = _couplTol
-        self.resetInv = _resetInv
-        self.iterPrint = _iterPrint if self.iSolverAPI.getVerbose() == 0 and self.vSolver.verbose == 0 else 1
+        self.isol = iSolverAPI
+        self.vsol = vSolver
+        self.maxIter = _maxCouplIter
+        self.tol = _couplTol
+        self.resetInviscid = _resetInv
+        self.iterPrint = _iterPrint if self.isol.getVerbose() == 0 and self.vsol.verbose == 0 else 1
         self.tms = fwk.Timers()
         self.filesfx = sfx
 
     def run(self):
+        print('')
+        print(' ######################################################## ')
+        print('|            ___  __   ___   _________________           |')
+        print('|           / _ )/ /  / _ | / __/_  __/ __/ _ \          |')
+        print('|          / _  / /__/ __ |_\ \  / / / _// , _/          |')
+        print('|         /____/____/_/ |_/___/ /_/ /___/_/|_|           |')
+        print('|                                                        |')
+        print('| 2021-2024 University of Liege                          |')
+        print('| Paul Dechamps (gitlab.uliege.be/pdechamps)             |')
+        print(' ######################################################## ')
+        print('')
+        print('-- Case definition --')
+        print('{:<6s} {:<4.2f} (deg)\n{:<6s} {:<6.2f}\n{:<6s} {:<4.2f}e6'.format('AoA:', self.isol.getAoA()*180/math.pi, 'Mach:', self.isol.getMinf(), 'Re:', self.vsol.getRe()/1e6))
+        print('Transitions: [{:<.2f}, {:<.2f}]'.format(self.isol.cfg['xtrF'][0], self.isol.cfg['xtrF'][1]))
+        print('nDim:', self.isol.getnDim())
+        print('nSections:', self.isol.cfg['nSections'])
+        print('Interpolator:', self.isol.cfg['interpolator'])
+        print('')
+        print('-- Coupler parameters --') 
+        print('MaxIter:{:>3.0f}'.format(self.maxIter))
+        print('Tolerance:{:>6.2f}'.format(np.log10(self.tol)))
+        print('IterPrint:{:>2.0f}'.format(self.iterPrint))
+        print('ResetInv:{:>5s}'.format(str(self.resetInviscid)))
+        print('Verb:{:>2.0f}'.format(self.isol.getVerbose()))
+        print('')
+
         # Aerodynamic coefficients.
-        aeroCoeffs = np.zeros((0, 4))
+        aeroCoeffs = {'Cl':[], 'Cd': [], 'Cdwake': []}
 
         # Convergence parameters.
         couplIter = 0
         cdPrev = 0.0
 
-        while couplIter < self.maxCouplIter:
+        while couplIter < self.maxIter:
+            # Impose blowing boundary condition in the inviscid solver.
+            self.tms['processing'].start()
+            self.isol.getBlowingBoundary(couplIter)
+            self.isol.setBlowingVelocity()
+            self.tms['processing'].stop()
+
             # Run inviscid solver.
             self.tms['inviscid'].start()
-            if self.resetInv:
-                self.iSolverAPI.reset()
-            self.iSolverAPI.run()
+            if self.resetInviscid:
+                self.isol.reset()
+            self.isol.run()
             self.tms['inviscid'].stop()
 
             # Write inviscid Cp distribution.
             if couplIter == 0:
-                self.iSolverAPI.writeCp(sfx='_inviscid'+self.filesfx)
+                self.isol.initializeViscousSolver()
+                self.isol.writeCp(sfx='_inviscid'+self.filesfx)
 
             # Impose inviscid boundary in the viscous solver.
             self.tms['processing'].start()
-            self.iSolverAPI.imposeInvBC(couplIter)
+            self.isol.getInviscidBC()
+            self.isol.setViscousSolver()
             self.tms['processing'].stop()
 
             # Run viscous solver.
             self.tms['viscous'].start()
-            exitCode = self.vSolver.run(couplIter)
+            exitCode = self.vsol.run()
             self.tms['viscous'].stop()
 
-            # Impose blowing boundary condition in the inviscid solver.
-            self.tms['processing'].start()
-            self.iSolverAPI.imposeBlwVel()
-            self.tms['processing'].stop()
-
-            aeroCoeffs = np.vstack((aeroCoeffs, [self.iSolverAPI.getCl(), self.vSolver.Cdt, self.vSolver.Cdf + self.iSolverAPI.getCd(), self.vSolver.Cdf]))
+            aeroCoeffs['Cl'].append(self.isol.getCl())
+            aeroCoeffs['Cd'].append(self.isol.getCd() + self.vsol.Cdf)
+            aeroCoeffs['Cdwake'].append(self.vsol.Cdt)
 
             # Check convergence status.
-            #cd = self.vSolver.Cdf + self.iSolverAPI.getCd()
-            cd = self.vSolver.Cdt if self.vSolver.Cdt != 0 else self.vSolver.Cdf + self.iSolverAPI.getCd()
+            cd = self.vsol.Cdf + self.isol.getCd()
+            #cd = self.vsol.Cdt if self.vsol.Cdt != 0 else self.vsol.Cdf + self.isol.getCd()
             error = abs((cd - cdPrev) / cd) if cd != 0 else 1
 
-            if error <= self.couplTol:
-                print(ccolors.ANSI_GREEN, '{:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>6.4f} | {:>6.3f}\n'.format(couplIter, self.iSolverAPI.getCl(), self.iSolverAPI.getCd()+self.vSolver.Cdf, self.vSolver.Cdt, self.vSolver.getxoctr(0, 0), self.vSolver.getxoctr(0, 1), np.log10(error)), ccolors.ANSI_RESET)
-                self.iSolverAPI.writeCp(sfx='_viscous'+self.filesfx)
+            if error <= self.tol:
+                print(ccolors.ANSI_GREEN, '{:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>6.4f} | {:>6.3f}\n'.format(couplIter, self.isol.getCl(), self.isol.getCd()+self.vsol.Cdf, self.vsol.Cdt, self.vsol.getAverageTransition(0), self.vsol.getAverageTransition(1), np.log10(error)), ccolors.ANSI_RESET)
+                self.isol.writeCp(sfx='_viscous'+self.filesfx)
                 return aeroCoeffs
             cdPrev = cd
 
             if couplIter == 0:
-                print('- AoA: {:<2.2f} Mach: {:<1.1f} Re: {:<2.1f}e6'.format(self.iSolverAPI.getAoA()*180/math.pi, self.iSolverAPI.getMinf(), self.vSolver.getRe()/1e6))
+                print('')
                 print('{:>5s}| {:>7s} {:>7s} {:>7s} | {:>6s} {:>6s} | {:>6s}'.format('It', 'Cl', 'Cd', 'Cdwake', 'xtrT', 'xtrB', 'Error'))
                 print('  ----------------------------------------------------------')
             if couplIter % self.iterPrint == 0:
-                print(' {:>4.0f}| {:>7.4f} {:>7.4f} {:>7.4f} | {:>6.4f} {:>6.4f} | {:>6.3f}'.format(couplIter, self.iSolverAPI.getCl(), self.iSolverAPI.getCd()+self.vSolver.Cdf, self.vSolver.Cdt, self.vSolver.getAvrgxoctr(0), self.vSolver.getAvrgxoctr(1), np.log10(error)))
-                if self.iSolverAPI.getVerbose() != 0 or self.vSolver.verbose != 0:
+                print(' {:>4.0f}| {:>7.5f} {:>7.5f} {:>7.5f} | {:>6.4f} {:>6.4f} | {:>6.3f}'.format(couplIter, self.isol.getCl(), self.isol.getCd()+self.vsol.Cdf, self.vsol.Cdt, self.vsol.getAverageTransition(0), self.vsol.getAverageTransition(1), np.log10(error)))
+                if self.isol.getVerbose() != 0 or self.vsol.verbose != 0:
                     print('')
             couplIter += 1
-            self.tms['processing'].stop()
         else:
-            print(ccolors.ANSI_RED, 'Maximum number of {:<.0f} coupling iterations reached'.format(self.maxCouplIter), ccolors.ANSI_RESET)
+            print(ccolors.ANSI_RED, 'Maximum number of {:<.0f} coupling iterations reached'.format(self.maxIter), ccolors.ANSI_RESET)
             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, self.iSolverAPI.getCl(), self.iSolverAPI.getCd()+self.vSolver.Cdf, self.vSolver.Cdt, self.vSolver.getAvrgxoctr(0), self.vSolver.getAvrgxoctr(1), np.log10(error)), ccolors.ANSI_RESET)
-            self.iSolverAPI.writeCp(sfx='_viscous'+self.filesfx)
+            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.getCd()+self.vsol.Cdf, self.vsol.Cdt, self.vsol.getAverageTransition(0), self.vsol.getAverageTransition(1), np.log10(error)), ccolors.ANSI_RESET)
+            self.isol.writeCp(sfx='_viscous'+self.filesfx)
             return aeroCoeffs
diff --git a/blast/interfaces/DDataStructure.py b/blast/interfaces/DDataStructure.py
index c1eec30..8fa91c0 100644
--- a/blast/interfaces/DDataStructure.py
+++ b/blast/interfaces/DDataStructure.py
@@ -1,11 +1,27 @@
 import numpy as np
 class Group:
-    def __init__(self, _name):
+    def __init__(self, _name, _nDim):
+        """Initialize the group.
+        
+        args:
+        ----
+            _name: str
+                Name of the group
+            _nDim: int
+            Number of dimensions
+        """
         self.name = _name
-        self.nUpperPrev = 0
+        self.nDim = _nDim
         self.stagPoint = None
 
     def initStructures(self, nPoints):
+        """Initialize the data structures.
+        
+        args:
+        ----
+            nPoints: int
+                Number of points in the region
+        """
         self.nPoints = nPoints
         self.nElems = nPoints - 1
         self.nodesCoord = np.zeros((self.nPoints,4))
@@ -19,70 +35,141 @@ class Group:
         self.deltaStarExt = np.zeros(self.nPoints)
         self.xxExt = np.zeros(self.nPoints)
 
-    def updateVars(self, nodes, _V, _M, _Rho):
-        self.nodesCoord = nodes
-        self.nPoints = len(self.nodesCoord[:,0])
-        self.nElems = self.nPoints - 1
+    def updateVars(self, _V, _M, _Rho):
+        """Update the velocity, Mach number and density of the boundary layer.
+        
+        args:
+        ----
+            _V: np.ndarray
+                Velocity
+            _M: np.ndarray
+                Mach number
+            _Rho: np.ndarray
+                Density
+        """
         self.V = _V
         self.M = _M
         self.Rho = _Rho
-        self.computeStagPoint()
 
-    def getXUpper(self):
-        return np.flip(self.nodesCoord[:self.stagPoint+1,0])
-    def getXLower(self):
-        return self.nodesCoord[self.stagPoint:, 0]
-    def getYUpper(self):
-        return np.flip(self.nodesCoord[:self.stagPoint+1,1])
-    def getYLower(self):
-        return self.nodesCoord[self.stagPoint:, 1]
-    def getZUpper(self):
-        return np.flip(self.nodesCoord[:self.stagPoint+1,2])
-    def getZLower(self):
-        return self.nodesCoord[self.stagPoint:, 2]
+    def getNodesCoord(self, reg:str, dim:int):
+        """Return the coordinates of the nodes in the direction dim
+        
+        args:
+        ----
+            reg: str
+                Region of the boundary layer (upper, lower, wake)
+            dim: int
+                Direction of the coordinates (x, y, z)
+        """
+        if reg == "wake":
+            return self.nodesCoord[:,dim]
+        elif reg == "upper":
+            return np.flip(self.nodesCoord[:self.stagPoint+1,dim])
+        elif reg == "lower":
+            return self.nodesCoord[self.stagPoint:,dim]
+        else:
+            raise RuntimeError('Invalid region', reg)
+    
+    def getVelocity(self, reg:str, dim:int):
+        """Return the velocity in the direction dim
+
+        args:
+        ----
+            reg: str
+                Region of the boundary layer (upper, lower, wake)
+            dim: int
+                Direction of the velocity
+        """
+        if reg == "wake":
+            return self.V[:,dim]
+        elif reg == "upper":
+            return np.flip(self.V[:self.stagPoint+1,dim])
+        elif reg == "lower":
+            return self.V[self.stagPoint:,dim]
+        else:
+            raise RuntimeError('Invalid region', reg)
     
-    def getVelocityXUpper(self):
-        return np.flip(self.V[:self.stagPoint+1,0])
-    def getVelocityXLower(self):
-        return self.V[self.stagPoint:, 0]
-    def getVelocityYUpper(self):
-        return np.flip(self.V[:self.stagPoint+1,1])
-    def getVelocityYLower(self):
-        return self.V[self.stagPoint:, 1]
-    def getVelocityZUpper(self):
-        return np.flip(self.V[:self.stagPoint+1,2])
-    def getVelocityZLower(self):
-        return self.V[self.stagPoint:, 2]
+    def getVt(self, reg:str):
+        """Return the velocity in the direction tangential
+        to the boundary layer
 
-    def getMachUpper(self):
-        return np.flip(self.M[:self.stagPoint+1])
-    def getMachLower(self):
-        return self.M[self.stagPoint:]
+        args:
+        ----
+            reg: str
+                Region of the boundary layer (upper, lower, wake)
+        """
+        vt = np.sqrt(self.V[:,0]**2 + self.V[:,self.nDim-1]**2)
+        if reg == "wake":
+            return vt
+        elif reg == "upper":
+            return np.flip(vt[:self.stagPoint+1])
+        elif reg == "lower":
+            return vt[self.stagPoint:]
+        else:
+            raise RuntimeError('Invalid region', reg)
+        
+    def getMach(self, reg:str):
+        """Return the Mach number at the edge of the boundary layer
+
+        args:
+        ----
+            reg: str
+                Region of the boundary layer (upper, lower, wake)
+        """
+        if reg == "wake":
+            return self.M
+        elif reg == "upper":
+            return np.flip(self.M[:self.stagPoint+1])
+        elif reg == "lower":
+            return self.M[self.stagPoint:]
+        else:
+            raise RuntimeError('Invalid region', reg)
+    
+    def getRho(self, reg:str):
+        """Return the density at the edge of the boundary layer
 
-    def getRhoUpper(self):
-        return np.flip(self.Rho[:self.stagPoint+1])
-    def getRhoLower(self):
-        return self.Rho[self.stagPoint:]
+        args:
+        ----
+            reg: str
+                Region of the boundary layer (upper, lower, wake)
+        """
+        if reg == "wake":
+            return self.Rho
+        elif reg == "upper":
+            return np.flip(self.Rho[:self.stagPoint+1])
+        elif reg == "lower":
+            return self.Rho[self.stagPoint:]
+        else:
+            raise RuntimeError('Invalid region', reg)
 
-    def setBlowingVelocity(self, blwVel):
-        self.blowingVel = blwVel
     def setConnectList(self, _connectListNodes, _connectListElems):
+        """Set connectivity lists for viscous structures.
+
+        args:
+        ----
+            _connectListNodes: np.ndarray
+                Connectivity list for nodes
+            _connectListElems: np.ndarray
+                Connectivity list for elements
+        """
         if self.name != 'iWing' and self.name != 'iWake':
             raise RuntimeError('Cannot set connectivity lists for viscous structures', self.name)
         self.connectListNodes = _connectListNodes
         self.connectListElems = _connectListElems
+
     def connectBlowingVel(self):
+        """Connect blowing velocities for viscous structures
+        using the connectivity list.
+        """
         if self.name != 'iWing' and self.name != 'iWake':
             raise RuntimeWarning('Can not connect blowing velocities for viscous structure. Maybe it was not set.', self.name)
         self.blowingVel = self.blowingVel[self.connectListElems.argsort()]
 
-    def isMeshChanged(self):
-        return self.nPoints - self.nUpperPrev
-    def updatePrev(self):
-        self.nUpperPrev = self.nPoints
     def computeStagPoint(self):
+        """Compute the stagnation point of the boundary layer.
+        """
         if 'iWake' in self.name or 'vWake' in self.name:
             self.stagPoint = None
         else:
             if self.stagPoint is None:
-                self.stagPoint = np.argmin(np.sqrt(self.V[:,0]**2 + self.V[:,1]**2))
\ No newline at end of file
+                self.stagPoint = np.argmin(np.sqrt(self.V[:,0]**2 + self.V[:,self.nDim-1]**2))
\ No newline at end of file
diff --git a/blast/interfaces/DSolversInterface.py b/blast/interfaces/DSolversInterface.py
index 5722230..c1f9ed1 100644
--- a/blast/interfaces/DSolversInterface.py
+++ b/blast/interfaces/DSolversInterface.py
@@ -1,5 +1,5 @@
 import numpy as np
-from scipy.interpolate import interp1d
+import blast
 from blast.interfaces.DDataStructure import Group
 import time
 
@@ -10,133 +10,157 @@ class SolversInterface:
 
         if 'nSections' not in self.cfg:
             self.cfg['nSections'] = len(self.cfg['sections'])
-        
-        if 'sweep' not in self.cfg:
-            self.cfg['sweep'] = False
 
         # Initialize data structures.
-        self.iBnd = [Group('iWing' if iReg == 0 else 'iWake') for iReg in range(2)]
-        self.vBnd = [[Group('vAirfoil'+str(k) if iReg == 0 else 'vWake'+str(k)) for iReg in range(2)] for k in range(self.cfg['nSections'])]
+        self.iBnd = [Group('iWing' if iReg == 0 else 'iWake', self.getnDim()) for iReg in range(2)]
+        self.vBnd = [[Group('vAirfoil'+str(k) if iReg == 0 else 'vWake'+str(k), self.getnDim()) for iReg in range(2)] for k in range(self.cfg['nSections'])]
         
+        # Initialize interpolator and meshes
+        initialTime = time.time()
+        self.setMesh()
         if self.cfg['interpolator'] == 'Matching':
             from blast.interfaces.interpolators.DMatchingInterpolator import MatchingInterpolator as interp
+            # Initialize viscous structures for matching computations
+            for iSec in range(len(self.vBnd)):
+                for iReg, reg in enumerate(self.vBnd[iSec]):
+                    reg.initStructures(self.iBnd[iReg].nPoints)
+                    self.vBnd[iSec][iReg].nodesCoord = self.iBnd[iReg].nodesCoord
+
         elif self.cfg['interpolator'] == 'Rbf':
             from blast.interfaces.interpolators.DRbfInterpolator import RbfInterpolator as interp
             print('RBF interpolator initialized.')
             print('Loading viscous mesh... ', end='')
-            initialTime = time.time()
-            if self.cfg['nDim'] == 2:
-                self.getVAirfoil()
-            elif self.cfg['nDim'] == 3:
-                self.getVWing()
+            self.getVWing()
             print('done in {:.2f}s.'.format(time.time()-initialTime))
         else:
             raise RuntimeError('Incorrect interpolator specified in config.')
-        self.interpolator = interp(self.cfg)
-
-        print('Loading inviscid mesh... ', end='')
-        initialTime = time.time()
-        self.setMesh()
-        print('done in {:.2f}s.'.format(time.time()-initialTime))
 
-        #self.interpolator.ilwIdx = self.ilwIdx
-        #self.interpolator.vlwIdx = self.vlwIdx
+        self.interpolator = interp(self.cfg, self.getnDim())
 
+        # Initialize transfer quantities
         self.deltaStarExt = [[np.zeros(0) for iReg in range(3)]\
                              for iSec in range(self.cfg['nSections'])]
         self.xxExt        = [[np.zeros(0) for iReg in range(3)]\
                              for iSec in range(self.cfg['nSections'])]
-        #self.vtOld = [[np.zeros(0) for iReg in range(3)] for iSec in range(self.cfg['nSections'])]
+        self.vtExt        = [[np.zeros(0) for iReg in range(3)]\
+                             for iSec in range(self.cfg['nSections'])]
     
-    def setViscousSolver(self, couplIter):
+    def setViscousSolver(self, adjoint=False):
         """Interpolate solution to viscous mesh and sets the inviscid boundary in the viscous solver.
         """
-        self.interpolator.inviscidToViscous(self.iBnd, self.vBnd, couplIter)
+        self.interpolator.inviscidToViscous(self.iBnd, self.vBnd)
+        
         for iSec in range(self.cfg['nSections']):
-            ## Mesh
-            if (self.vBnd[iSec][0].isMeshChanged()):
-                for reg in self.vBnd[iSec]:
+            for i, reg in enumerate(self.sec[iSec]):
+                if reg.name == 'wake':
+                    iReg = 1
+                elif reg.name == 'lower' or reg.name == 'upper':
+                    iReg = 0
+                else:
+                    raise RuntimeError('Invalid region', reg.name)
+
+                reg.setMe(self.vBnd[iSec][iReg].getMach(reg.name))
+                reg.setRhoe(self.vBnd[iSec][iReg].getRho(reg.name))
+                reg.setVt(self.vBnd[iSec][iReg].getVt(reg.name))
+
+                if adjoint == False:
+                    reg.setDeltaStarExt(self.deltaStarExt[iSec][i])
+                    reg.setxxExt(self.xxExt[iSec][i])
+
+    def getBlowingBoundary(self, couplIter):
+        """ Get blowing boundary condition from the viscous solver.
+        args:
+        ----
+            couplIter: int
+                Current iteration of the coupling loop.
+        """
+        if couplIter != 0:
+            for iSec in range(len(self.vBnd)):
+                for iReg, reg in enumerate(self.vBnd[iSec]):
                     if 'vWake' in reg.name:
-                        iReg = 2
-                        self.vSolver.setGlobMesh(iSec, iReg,
-                                                 reg.nodesCoord[:,0],
-                                                 reg.nodesCoord[:,1],
-                                                 reg.nodesCoord[:,2])
-                        # External variables
-                        self.xxExt[iSec][2] = np.zeros(reg.nPoints)
-                        self.deltaStarExt[iSec][2] = np.zeros(reg.nPoints)
-                        #self.vtOld[iSec][2] = np.zeros(reg.nPoints)
+                        reg.blowingVel = np.asarray(self.sec[iSec][2].blowingVelocity)
                     elif 'vAirfoil' in reg.name:
-                        self.vSolver.setGlobMesh(iSec, 0,
-                                                 reg.getXUpper(),
-                                                 reg.getYUpper(),
-                                                 reg.getZUpper())
-                        self.vSolver.setGlobMesh(iSec, 1,
-                                                 abs(reg.getXLower()),
-                                                 reg.getYLower(),
-                                                 reg.getZLower())
-                        # External variables
-                        self.xxExt[iSec][0]        = np.zeros(reg.stagPoint+1)
-                        self.deltaStarExt[iSec][0] = np.zeros(reg.stagPoint+1)
-                        #self.vtOld[iSec][0]        = np.zeros(reg.stagPoint+1)
-                        self.xxExt[iSec][1]        = np.zeros(reg.nPoints
-                                                              - reg.stagPoint)
-                        self.deltaStarExt[iSec][1] = np.zeros(reg.nPoints
-                                                              - reg.stagPoint)
-                        #self.vtOld[iSec][1]        = np.zeros(reg.nPoints
-                        #                                     - reg.stagPoint)
-                    else:
-                        raise RuntimeError('Tried to initialized viscous\
-                                           struture but name was', reg.name)
-            ## Inviscid variables
+                        reg.blowingVel = np.concatenate((np.flip(np.asarray(self.sec[iSec][0].blowingVelocity)),
+                                                        np.asarray(self.sec[iSec][1].blowingVelocity)))
+                for i in range(len(self.sec[iSec])):
+                    self.xxExt[iSec][i] = np.asarray(self.sec[iSec][i].loc)
+                    self.deltaStarExt[iSec][i] = np.asarray(self.sec[iSec][i].deltaStar)
+                
+        self.interpolator.viscousToInviscid(self.iBnd, self.vBnd)
+    
+    def initializeViscousSolver(self):
+        """Initialize the viscous sections in the viscous solver.
+        """
+        self.sec = [[] for _ in range(self.cfg['nSections'])]
+        self.vSolver.reset()
+        for i in range(self.cfg['nSections']):
+            # TODO: Add functionality to initialize sections without wake.
+            for j in range(3):
+                if j == 2:
+                    name = "wake"
+                    xtrF = -1
+                elif j == 1:
+                    name = "lower"
+                    xtrF = self.cfg['xtrF'][j]
+                elif j ==0:
+                    name = "upper"
+                    xtrF = self.cfg['xtrF'][j]
+
+
+                self.sec[i].append(blast.BoundaryLayer(xtrF, name))
+                self.vSolver.addSection(i, self.sec[i][j])
+
+        self.getInviscidBC()
+        self.interpolator.inviscidToViscous(self.iBnd, self.vBnd)
+
+        # Compute stagnation points
+        for iSec in range(self.cfg['nSections']):
             for reg in self.vBnd[iSec]:
-                reg.updatePrev()
-                if 'vWake' in reg.name:
-                    iReg = 2
-                    self.vSolver.setVelocities(iSec, iReg,
-                                               reg.V[:,0],
-                                               reg.V[:,1],
-                                               reg.V[:,2])
-                    self.vSolver.setMe(iSec, iReg, reg.M)
-                    self.vSolver.setRhoe(iSec, iReg, reg.Rho)
-                elif 'vAirfoil' in reg.name:
-                    iReg = 0 # Upper side
-                    self.vSolver.setVelocities(iSec, iReg,
-                                               reg.getVelocityXUpper(),
-                                               reg.getVelocityYUpper(),
-                                               reg.getVelocityZUpper())
-                    self.vSolver.setMe(iSec, iReg, reg.getMachUpper())
-                    self.vSolver.setRhoe(iSec, iReg, reg.getRhoUpper())
-                    iReg = 1 # Lower side
-                    self.vSolver.setVelocities(iSec, iReg,
-                                               reg.getVelocityXLower(),
-                                               reg.getVelocityYLower(),
-                                               reg.getVelocityZLower())
-                    self.vSolver.setMe(iSec, iReg, reg.getMachLower())
-                    self.vSolver.setRhoe(iSec, iReg, reg.getRhoLower())
+                reg.computeStagPoint()
+
+        # Set mesh
+        for iSec in range(self.cfg['nSections']):
+            # Compute section chord
+            xMin = np.min(self.vBnd[iSec][0].nodesCoord[:,0])
+            xMax = np.max(self.vBnd[iSec][0].nodesCoord[:,0])
+            chord = xMax - xMin
+            for reg in self.sec[iSec]:
+                if reg.name == 'wake':
+                    iReg = 1
+                elif reg.name == 'lower' or reg.name == 'upper':
+                    iReg = 0
                 else:
-                    raise RuntimeError('Tried to initialize a viscous\
-                                       struture but name was', reg.name)
-            ## External variables
-            for iRegv in range(3):
-                self.vSolver.setxxExt(iSec, iRegv, self.xxExt[iSec][iRegv])
-                self.vSolver.setDeltaStarExt(iSec, iRegv,
-                                             self.deltaStarExt[iSec][iRegv])
-                #self.vSolver.setVtOld(iSec, iRegv, self.vtOld[iSec][iRegv])
-    def getBlowingBoundary(self):
-        for iSec in range(len(self.vBnd)):
-            for reg in self.vBnd[iSec]:
-                if 'vWake' in reg.name:
-                    reg.blowingVel = np.asarray(self.vSolver.extractBlowingVel(iSec, 2))
-                elif 'vAirfoil' in reg.name:
-                    reg.blowingVel = np.concatenate((np.flip(np.asarray(self.vSolver.extractBlowingVel(iSec, 0))),
-                                                     np.asarray(self.vSolver.extractBlowingVel(iSec, 1))))
-            for iRegv in range(3):
-                self.xxExt[iSec][iRegv] = self.vSolver.extractxx(iSec, iRegv)
-                self.deltaStarExt[iSec][iRegv] = self.vSolver.extractDeltaStar(iSec, iRegv)
-                #self.vtOld[iSec][iRegv] = self.vSolver.extractUe(iSec, iRegv)
+                    raise RuntimeError('Invalid region', reg.name)
                 
-        self.interpolator.viscousToInviscid(self.iBnd, self.vBnd)
+                xIdx = 0
+                if self.getnDim() == 2:
+                    yIdx = 1
+                    zIdx = 2
+                elif self.getnDim() == 3:
+                    yIdx = 2
+                    zIdx = 1
+                else:
+                    raise RuntimeError('Incorrect number of dimensions', self.getnDim())
+
+                reg.setMesh(self.vBnd[iSec][iReg].getNodesCoord(reg.name, xIdx),
+                            self.vBnd[iSec][iReg].getNodesCoord(reg.name, yIdx),
+                            self.vBnd[iSec][iReg].getNodesCoord(reg.name, zIdx),
+                            chord,
+                            xMin)
+
+            # External variables
+            for i, reg in enumerate(self.sec[iSec]):
+                if reg.name == 'wake':
+                    iReg = 1
+                elif reg.name == 'lower' or reg.name == 'upper':
+                    iReg = 0
+                else:
+                    raise RuntimeError('Invalid region', reg.name)
+                loc = np.zeros(reg.getnNodes())
+                for iPoint in range(reg.getnNodes()):
+                    loc[iPoint] = reg.loc[iPoint]
+                self.xxExt[iSec][i] = loc
+                self.deltaStarExt[iSec][i] = np.zeros(reg.getnNodes())
 
     def getVWing(self):
         """Obtain the nodes' location and row and cg of all elements.
@@ -147,11 +171,7 @@ class SolversInterface:
         """
 
         data = [np.zeros((0,4)) for _ in range(2)]
-
-        leNodes = np.zeros((0, 3))
         lwRows = []
-        ctlw = 0
-
         for e in self.cfg['vMsh'].elems:
             if e.ptag.name == 'wing' or e.ptag.name == 'wing_'\
                 or e.ptag.name == 'leadingEdge':
@@ -165,8 +185,8 @@ class SolversInterface:
             for nw in e.nodes:
                 if nw.row not in data[iRegion][:,3]:
                     data[iRegion] = np.vstack((data[iRegion], [nw.pos[0],\
-                                                                nw.pos[2],\
                                                                 nw.pos[1],\
+                                                                nw.pos[2],\
                                                                 nw.row]))
                     # If wing_ exists, the lower side is identifiable.
                     if e.ptag.name == 'wing_':
@@ -188,16 +208,16 @@ class SolversInterface:
             for iy, y in enumerate(self.cfg['sections']):
                 # Find nearest value in the mesh
                 try:
-                    idx = (np.abs(reg[:,2]-y).argmin())
+                    idx = (np.abs(reg[:,1]-y).argmin())
                 except:
-                    print('Region', reg[:,2], 'cannot be found through\
+                    print('Region', reg[:,1], 'cannot be found through\
                           config input', y)
                     raise RuntimeError("Could not identify section.\
                                        Possibly a missing tag")
-                section = reg[idx,2]
+                section = reg[idx,1]
                 if iReg == 0:
                     self.cfg['EffSections'] = np.append(self.cfg['EffSections'], section)
-                nodesSec = reg[abs(reg[:,2]-section)<1e-3, :]
+                nodesSec = reg[abs(reg[:,1]-section)<1e-3, :]
 
                 # Separate points on upper and lower side
                 if iReg == 0:
@@ -225,4 +245,4 @@ class SolversInterface:
 
                 self.vBnd[iy][iReg].initStructures(nodesSec.shape[0])
                 self.vBnd[iy][iReg].nodesCoord = nodesSec
-                self.vBnd[iy][iReg].elemsCoord = cgSec
+                self.vBnd[iy][iReg].elemsCoord = cgSec
\ No newline at end of file
diff --git a/blast/interfaces/dart/DartInterface.py b/blast/interfaces/dart/DartInterface.py
index da0809b..9c6f040 100644
--- a/blast/interfaces/dart/DartInterface.py
+++ b/blast/interfaces/dart/DartInterface.py
@@ -28,9 +28,9 @@ class DartInterface(SolversInterface):
     def __init__(self, dartCfg, vSolver, _cfg):
         try:
             from modules.dartflo.dart.api.core import initDart
-            self.argOut = initDart(dartCfg, viscous=True)
-            self.solver = self.argOut.get('sol') # Solver
-            self.blw = [self.argOut.get('blwb'), self.argOut.get('blww')]
+            self.inviscidObjects = initDart(dartCfg, viscous=True)
+            self.solver = self.inviscidObjects.get('sol') # Solver
+            self.blw = [self.inviscidObjects.get('blwb'), self.inviscidObjects.get('blww')]
             print('Dart successfully loaded.')
         except:
             print(ccolors.ANSI_RED, 'Could not load DART. Make sure it is installed.', ccolors.ANSI_RESET)
@@ -50,7 +50,7 @@ class DartInterface(SolversInterface):
         # Extract Cp on elements
         self.save(sfx=sfx)
         # 2D Case
-        if self.cfg['nDim'] == 2:
+        if self.getnDim() == 2:
             vElems = self.blw[0].tag.elems
             vData = self.solver.Cp
             if isinstance(vData[0], float):
@@ -75,25 +75,22 @@ class DartInterface(SolversInterface):
             print('writing data file ' + 'Cp' +sfx + '.dat')
             np.savetxt('Cp'+sfx+'.dat', data, fmt='%1.6e', delimiter=', ', header='x, y, z, Cp', comments='')
         
-        elif self.cfg['nDim'] == 3:
+        elif self.getnDim() == 3:
                 # Save surface cp
-                data = np.zeros((self.argOut['bnd'].nodes.size(), 4))
-                for i, n in enumerate(self.argOut['bnd'].nodes):
+                data = np.zeros((self.inviscidObjects['bnd'].nodes.size(), 4))
+                for i, n in enumerate(self.inviscidObjects['bnd'].nodes):
                     data[i,0] = n.pos[0]
                     data[i,1] = n.pos[1]
                     data[i,2] = n.pos[2]
                     data[i,3] = self.solver.Cp[n.row]
-                np.savetxt(self.argOut['msh'].name+'_Cp_surface'+sfx+'.dat', data, fmt='%1.6e', delimiter=', ', header='x, y, z, Cp', comments='')
+                np.savetxt(self.inviscidObjects['msh'].name+'_Cp_surface'+sfx+'.dat', data, fmt='%1.6e', delimiter=', ', header='x, y, z, Cp', comments='')
                 import modules.dartflo.dart.utils as invUtils
                 if self.cfg['Format'] == 'vtk':
-                    import os
-                    if not os.path.exists('cpSlices'+sfx):
-                        os.makedirs('cpSlices'+sfx)
-                    print('Saving Cp files in vtk format. Msh {:s}, Tag {:.0f}'.format(self.argOut['msh'].name, self.cfg['saveTag']))
-                    invUtils.writeSlices(self.argOut['msh'].name, self.cfg['writeSections'], self.cfg['saveTag'], sfx=sfx)
+                    print('Saving Cp files in vtk format. Msh {:s}, Tag {:.0f}'.format(self.inviscidObjects['msh'].name, self.cfg['saveTag']))
+                    invUtils.writeSlices(self.inviscidObjects['msh'].name, self.cfg['writeSections'], self.cfg['saveTag'], sfx=sfx)
     
     def save(self, sfx='inviscid'):
-        self.solver.save(self.argOut['wrt'], sfx)
+        self.solver.save(self.inviscidObjects['wrt'], sfx)
 
     def getAoA(self):
         return self.solver.pbl.alpha
@@ -113,10 +110,13 @@ class DartInterface(SolversInterface):
     def getVerbose(self):
         return self.solver.verbose
     
+    def getnDim(self):
+        return self.inviscidObjects['pbl'].nDim
+    
     def reset(self):
         self.solver.reset()
     
-    def imposeInvBC(self, couplIter):
+    def getInviscidBC(self):
         """ Extract the inviscid paramaters at the edge of the boundary layer
         and use it as a boundary condition in the viscous solver.
 
@@ -132,27 +132,23 @@ class DartInterface(SolversInterface):
                     self.iBnd[n].V[iRow,iDim] = self.solver.U[row][iDim]
                 self.iBnd[n].M[iRow] = self.solver.M[row]
                 self.iBnd[n].Rho[iRow] = self.solver.rho[row]
-            if self.cfg['nDim']==3:
-                self.iBnd[n].V[:,[1,2]] = self.iBnd[n].V[:,[2,1]]
-        self.setViscousSolver(couplIter)
 
-    def imposeBlwVel(self):
+    def setBlowingVelocity(self):
         """ Extract the solution of the viscous calculation (blowing velocity)
         and use it as a boundary condition in the inviscid solver.
         """
-        self.getBlowingBoundary()
+
         # Impose blowing velocities.
         for n in range(len(self.iBnd)):
-            if self.cfg['nDim'] == 2:
+            if self.getnDim() == 2:
                 self.iBnd[n].connectBlowingVel()
             for i, blw in enumerate(self.iBnd[n].blowingVel):
                 self.blw[n].setU(i, blw)
 
     def setMesh(self):
-
-        if self.cfg['nDim'] == 2:
+        if self.getnDim() == 2:
             self.getAirfoil()
-        elif self.cfg['nDim'] == 3:
+        elif self.getnDim() == 3:
             self.getWing()
         else:
             raise RuntimeError('dartInterface::Could not resolve how to set\
@@ -326,11 +322,11 @@ class DartInterface(SolversInterface):
                 # Compute cg position
                 cg_pt = np.zeros(3)
                 for nw in e.nodes:
-                    cg_pt += [nw.pos[0], nw.pos[2], nw.pos[1]]
+                    cg_pt += [nw.pos[0], nw.pos[1], nw.pos[2]]
                     if nw.row not in data[iRegion][:,3]:
                         data[iRegion] = np.vstack((data[iRegion], [nw.pos[0],\
-                                                                   nw.pos[2],\
                                                                    nw.pos[1],\
+                                                                   nw.pos[2],\
                                                                    nw.row]))
                 cg_pt/=e.nodes.size()
                 cg_pt = np.hstack((cg_pt, e.no))
@@ -341,9 +337,9 @@ class DartInterface(SolversInterface):
             for s in self.cfg['Sym']:
                 for iReg in range(len(data)):
                     dummy = data[iReg].copy()
-                    dummy[:,2] -= s
-                    dummy[:,2] *= -1
-                    dummy[:,2] += s
+                    dummy[:,1] -= s
+                    dummy[:,1] *= -1
+                    dummy[:,1] += s
                     data[iReg] = np.row_stack((data[iReg], dummy))
 
         for n in range(len(data)):
diff --git a/blast/interfaces/interpolators/DMatchingInterpolator.py b/blast/interfaces/interpolators/DMatchingInterpolator.py
index a801890..3a42cd6 100644
--- a/blast/interfaces/interpolators/DMatchingInterpolator.py
+++ b/blast/interfaces/interpolators/DMatchingInterpolator.py
@@ -1,23 +1,22 @@
 import numpy as np
 class MatchingInterpolator:
-    def __init__(self, cfg):
-        self.cfg = cfg
+    def __init__(self, _cfg, _nDim):
+        self.cfg = _cfg
+        self.nDim = _nDim
 
-    def inviscidToViscous(self, iDict, vDict, couplIter):
-        ## Airfoil
-        # Find stagnation point
-        if self.cfg['nDim'] == 2:
+    def inviscidToViscous(self, iDict, vDict):
+        if self.nDim == 2:
             for iReg in range(len(iDict)):
-                vDict[0][iReg].updateVars(iDict[iReg].nodesCoord, iDict[iReg].V, iDict[iReg].M, iDict[iReg].Rho)
-        elif self.cfg['nDim'] == 3:
+                vDict[0][iReg].updateVars(iDict[iReg].V, iDict[iReg].M, iDict[iReg].Rho)
+        elif self.nDim == 3:
             for iSec, ysec in enumerate(self.cfg['sections']):
                 for iReg in range(2):
                     print(iDict[iReg].nodesCoord[iDict[iReg].nodesCoord[:,1] == ysec])
                     print(iDict[iReg].V[iDict[iReg].nodesCoord[:,1] == ysec])
-                    vDict[iSec][iReg].updateVars(iDict[iReg].nodesCoord[iDict[iReg].nodesCoord[:,1] == ysec], iDict[iReg].V[iDict[iReg].nodesCoord[:,1] == ysec], iDict[iReg].Rho[iDict[iReg].nodesCoord[:,1] == ysec])
+                    vDict[iSec][iReg].updateVars(iDict[iReg].V[iDict[iReg].nodesCoord[:,1] == ysec], iDict[iReg].Rho[iDict[iReg].nodesCoord[:,1] == ysec])
 
     def viscousToInviscid(self, iDict, vDict):
-        if self.cfg['nDim'] == 2:
+        if self.nDim == 2:
             for iReg in range(2):
                 iDict[iReg].blowingVel = vDict[0][iReg].blowingVel
         else:
diff --git a/blast/interfaces/interpolators/DRbfInterpolator.py b/blast/interfaces/interpolators/DRbfInterpolator.py
index 081ccc9..1eda4a3 100644
--- a/blast/interfaces/interpolators/DRbfInterpolator.py
+++ b/blast/interfaces/interpolators/DRbfInterpolator.py
@@ -3,10 +3,11 @@
 import numpy as np
 from scipy.interpolate import RBFInterpolator
 class RbfInterpolator:
-    def __init__(self, _cfg):
+    def __init__(self, _cfg, _nDim):
         self.cfg = _cfg
+        self.nDim = _nDim
 
-    def inviscidToViscous(self, iDict, vDict, couplIter):
+    def inviscidToViscous(self, iDict, vDict):
         ## Airfoil
         # Find stagnation point
         for iSec in range(len(vDict)):
@@ -18,13 +19,13 @@ class RbfInterpolator:
                     v[:,iDim] = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self.cfg['nDim'] if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].V[:,iDim], reg.nodesCoord[:,:(self.cfg['nDim'] if 'vAirfoil' in reg.name else 1)])
                 M = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self.cfg['nDim'] if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].M, reg.nodesCoord[:,:(self.cfg['nDim'] if 'vAirfoil' in reg.name else 1)])
                 rho = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self.cfg['nDim'] if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].Rho, reg.nodesCoord[:,:(self.cfg['nDim'] if 'vAirfoil' in reg.name else 1)])
-                vDict[iSec][iReg].updateVars(vDict[iSec][iReg].nodesCoord, v, M, rho)
+                vDict[iSec][iReg].updateVars(v, M, rho)
 
     def viscousToInviscid(self, iDict, vDict):
-        if self.cfg['nDim'] == 2:
+        if self.nDim == 2:
             for iReg, reg in enumerate(iDict):
                 iDict[iReg].blowingVel = self.__rbfToSection(vDict[0][iReg].elemsCoordTr[:,:(self.cfg['nDim']-1 if 'vAirfoil' in reg.name else 1)], vDict[0][iReg].blowingVel, reg.elemsCoordTr[:,:(self.cfg['nDim']-1 if reg.name == 'iWing' else 1)])
-        elif self.cfg['nDim'] == 3:
+        elif self.nDim == 3:
             for iReg, reg in enumerate(iDict):
                 viscElemsCoord = np.zeros((0,3))
                 viscBlowing = np.zeros(0)
@@ -34,7 +35,7 @@ class RbfInterpolator:
                 if 'Sym' in self.cfg:
                     for s in self.cfg['Sym']:
                         dummy = viscElemsCoord.copy()
-                        dummy[:,2] = (dummy[:,2] - s)*(-1) + s
+                        dummy[:,1] = (dummy[:,1] - s)*(-1) + s
                         viscElemsCoord = np.row_stack((viscElemsCoord, dummy))
                         viscBlowing = np.concatenate((viscBlowing, viscBlowing))
                 reg.blowingVel = self.__rbfToSection(viscElemsCoord, viscBlowing, reg.elemsCoord[:,:3])
diff --git a/blast/models/references/rae2822_AR138_case6.dat b/blast/models/references/rae2822_AR138_case6.dat
new file mode 100644
index 0000000..9fc6aa3
--- /dev/null
+++ b/blast/models/references/rae2822_AR138_case6.dat
@@ -0,0 +1,103 @@
+0.9938 -0.1432
+0.9875 -0.1318                                                            
+0.9750 -0.1082                                                            
+0.9500 -0.0592                                                            
+0.9250 -0.0115                                                            
+0.9000  0.0365                                                            
+0.8750  0.0808                                                            
+0.8500  0.1296                                                            
+0.8250  0.1746                                                            
+0.8000  0.2186
+0.7750  0.2702                                                            
+0.7500  0.3029                                                            
+0.7000  0.3913                                                            
+0.6771  0.4263                                                            
+0.6500  0.4778                                                            
+0.6196  0.5361                                                            
+0.6000  0.5798                                                            
+0.5750  0.6769                                                            
+0.5500  0.9137                                                            
+0.5250  1.2201                                                            
+0.5000  1.2164                                                            
+0.4750  1.2038                                                            
+0.4500  1.1940                                                            
+0.4250  1.1819                                                            
+0.4000  1.1601                                                            
+0.3750  1.1490                                                            
+0.3500  1.1273                                                            
+0.3250  1.1168                                                            
+0.3000  1.1091                                                            
+0.2800  1.1010                                                            
+0.2500  1.0736                                                            
+0.2208  1.0456                                                            
+0.2000  1.0433                                                            
+0.1500  1.0096                                                            
+0.1000  0.9886                                                            
+0.0750  1.0432                                                            
+0.0625  1.0730                                                            
+0.0500  1.0923                                                            
+0.0375  1.0820                                                            
+0.0271  1.0435                                                            
+0.0187  1.0362                                                            
+0.0146  0.9204                                                            
+0.0125  0.8680                                                            
+0.0104  0.8041                                                            
+0.0087  0.7658                                                            
+0.0073  0.7250                                                            
+0.0060  0.6269                                                            
+0.0048  0.5309                                                            
+0.0036  0.4667                                                            
+0.0026  0.2746                                                            
+0.0016  0.0521                                                            
+0.0008 -0.1042                                                            
+0.0002  0.4219                                                            
+0.0000 -0.8328                                                            
+0.0002 -1.0396                                                            
+0.0008 -1.1053                                                            
+0.0016 -1.1338                                                            
+0.0026 -1.1223                                                            
+0.0036 -1.0823                                                            
+0.0048 -1.0273                                                            
+0.0060 -0.9736                                                            
+0.0073 -0.9148                                                            
+0.0087 -0.8703                                                            
+0.0104 -0.8148                                                            
+0.0125 -0.7537                                                            
+0.0146 -0.6980                                                            
+0.0186 -0.6159                                                            
+0.0271 -0.5444                                                            
+0.0375 -0.4040                                                            
+0.0500 -0.3088                                                            
+0.0625 -0.2454                                                            
+0.0750 -0.1926                                                            
+0.1000 -0.1042                                                            
+0.1500  0.0081                                                            
+0.2000  0.0940                                                            
+0.2500  0.1754                                                            
+0.3000  0.2506                                                            
+0.3250  0.2904                                                            
+0.3500  0.3214                                                            
+0.3750  0.3406                                                            
+0.4000  0.3403                                                            
+0.4250  0.3194                                                            
+0.4500  0.2881                                                            
+0.4750  0.2469                                                            
+0.5000  0.2079                                                            
+0.5250  0.1657                                                            
+0.5500  0.1169                                                            
+0.5750  0.0731                                                            
+0.6000  0.0301                                                            
+0.6196  0.0003                                                            
+0.6500 -0.0431                                                            
+0.6771 -0.0836                                                            
+0.7000 -0.1134                                                            
+0.7500 -0.1731                                                            
+0.7750 -0.1988                                                            
+0.8500 -0.2618                                                            
+0.8750 -0.2778                                                            
+0.9000 -0.2907                                                            
+0.9250 -0.2972                                                            
+0.9500 -0.2937                                                            
+0.9750 -0.2676                                                            
+0.9875 -0.2396                                                            
+0.9938 -0.2146  
\ No newline at end of file
diff --git a/blast/src/CMakeLists.txt b/blast/src/CMakeLists.txt
index 394f4cb..96caacb 100644
--- a/blast/src/CMakeLists.txt
+++ b/blast/src/CMakeLists.txt
@@ -20,7 +20,7 @@ ADD_LIBRARY(blast SHARED ${SRCS})
 MACRO_DebugPostfix(blast)
 TARGET_INCLUDE_DIRECTORIES(blast PUBLIC ${PROJECT_SOURCE_DIR}/blast/src)
 
-TARGET_LINK_LIBRARIES(blast tbox)
+TARGET_LINK_LIBRARIES(blast dart fwk tbox)
 
 INSTALL(TARGETS blast DESTINATION ${CMAKE_INSTALL_PREFIX})
 
diff --git a/blast/src/DBoundaryLayer.cpp b/blast/src/DBoundaryLayer.cpp
index 9886a79..86fc294 100644
--- a/blast/src/DBoundaryLayer.cpp
+++ b/blast/src/DBoundaryLayer.cpp
@@ -1,9 +1,8 @@
 #include "DBoundaryLayer.h"
 #include "DClosures.h"
-#include "DDiscretization.h"
-#include "DEdge.h"
 #include <cmath>
 #include <iomanip>
+#include <iostream>
 
 using namespace blast;
 
@@ -12,55 +11,80 @@ using namespace blast;
  *
  * @param _xtrF Forced transition location (default=-1; free transition).
  */
-BoundaryLayer::BoundaryLayer(double _xtrF)
+BoundaryLayer::BoundaryLayer(double _xtrF, std::string _name)
 {
     xtrF = _xtrF;
+    name = _name;
     xtr = 1.0;
-    xoctr = 1.0;
     closSolver = new Closures();
-    mesh = new Discretization();
-    blEdge = new Edge();
-    transMarker = 0;
+    transitionNode = 0;
 }
 
 BoundaryLayer::~BoundaryLayer()
 {
     delete closSolver;
-    delete mesh;
-    delete blEdge;
-    // std::cout << "~blast::BoundaryLayer()\n";
 }
 
-/**
- * @brief Set the mesh and resize all boundary layer quantities accordingly.
- *
- * @param x Position x in the global frame of reference.
- * @param y Position y in the global frame of reference.
- * @param z Position z in the global frame of reference.
- */
-void BoundaryLayer::setMesh(std::vector<double> x,
-                            std::vector<double> y,
-                            std::vector<double> z)
+void BoundaryLayer::setMesh(std::vector<double> _x, std::vector<double> _y, std::vector<double> _z, double _chord, double xMin)
 {
-    size_t nMarkers = x.size();
-    mesh->setGlob(x, y, z);
-
-    // Resize and reset all variables if needed.
-    if (mesh->getDiffnElm() != 0)
+    if (_x.size() != _y.size() || _x.size() != _z.size())
+        throw std::runtime_error("Mesh coordinates are not consistent.");
+    nNodes = _x.size();
+    nElms = nNodes - 1;
+    x = _x;
+    y = _y;
+    z = _z;
+    chord = _chord;
+
+    // Compute the local coordinate.
+    loc.resize(nNodes, 0.);
+    alpha.resize(nElms, 0.);
+    dx.resize(nElms, 0.);
+
+    for (size_t iPoint = 0; iPoint < nElms; ++iPoint)
     {
-        u.resize(nVar * nMarkers, 0.);
-        Ret.resize(nMarkers, 0.);
-        cd.resize(nMarkers, 0.);
-        cf.resize(nMarkers, 0.);
-        Hstar.resize(nMarkers, 0.);
-        Hstar2.resize(nMarkers, 0.);
-        Hk.resize(nMarkers, 0.);
-        ctEq.resize(nMarkers, 0.);
-        us.resize(nMarkers, 0.);
-        deltaStar.resize(nMarkers, 0.);
-        delta.resize(nMarkers, 0.);
-        regime.resize(nMarkers, 0);
+        alpha[iPoint] = std::atan2(y[iPoint + 1] - y[iPoint], x[iPoint + 1] - x[iPoint]);
+        // dx = sqrt(delta x ^2 + delta y ^2).
+        dx[iPoint] = std::sqrt((x[iPoint + 1] - x[iPoint]) * (x[iPoint + 1] - x[iPoint]) + (y[iPoint + 1] - y[iPoint]) * (y[iPoint + 1] - y[iPoint]));
+        loc[iPoint + 1] = loc[iPoint] + dx[iPoint];
     }
+
+    // Compute the x/c coordinate.
+    if (chord <= 0)
+        throw std::runtime_error("Chord length is zero or negative.");
+    xoc.resize(nNodes, 0.);
+    for (size_t iPoint = 0; iPoint < nNodes; ++iPoint)
+        xoc[iPoint] = (x[iPoint] - xMin) / chord;
+
+    this->reset();
+}
+
+void BoundaryLayer::reset()
+{
+    u.resize(nNodes*getnVar(), 0.);
+    Ret.resize(nNodes, 0.);
+    cd.resize(nNodes, 0.);
+    cf.resize(nNodes, 0.);
+    Hstar.resize(nNodes, 0.);
+    Hstar2.resize(nNodes, 0.);
+    Hk.resize(nNodes, 0.);
+    ctEq.resize(nNodes, 0.);
+    us.resize(nNodes, 0.);
+    deltaStar.resize(nNodes, 0.);
+    delta.resize(nNodes, 0.);
+    deltaStar.resize(nNodes, 0.);
+    regime.resize(nNodes, 0);
+    blowingVelocity.resize(nElms, 0.);
+
+    Me.resize(nNodes, 0.);
+    vt.resize(nNodes, 0.);
+    rhoe.resize(nNodes, 0.);
+    deltaStarExt.resize(nNodes, 0.);
+    vtExt.resize(nNodes, 0.);
+    xxExt.resize(nNodes, 0.);
+
+    transitionNode = 0;
+    xtr = 1.0;
 }
 
 /**
@@ -68,16 +92,16 @@ void BoundaryLayer::setMesh(std::vector<double> x,
  *
  * @param Re Freestream Reynolds number.
  */
-void BoundaryLayer::setStagBC(double Re)
+void BoundaryLayer::setStagnationBC(double Re)
 {
-    double dv0 = (blEdge->getVt(1) - blEdge->getVt(0)) / (mesh->getLoc(1) - mesh->getLoc(0));
+    double dv0 = (vt[1] - vt[0]) / (loc[1] - loc[0]);
     if (dv0 > 0)
         u[0] = sqrt(0.075 / (Re * dv0)); // Theta
     else
         u[0] = 1e-6;         // Theta
     u[1] = 2.23;             // H
     u[2] = 0.;               // N
-    u[3] = blEdge->getVt(0); // ue
+    u[3] = vt[0];            // ue
     u[4] = 0.;               // Ctau
 
     Ret[0] = u[3] * u[0] * Re;
@@ -89,7 +113,7 @@ void BoundaryLayer::setStagBC(double Re)
     deltaStar[0] = u[0] * u[1];
 
     std::vector<double> lamParam(8, 0.);
-    closSolver->laminarClosures(lamParam, u[0], u[1], Ret[0], blEdge->getMe(0), name);
+    closSolver->laminarClosures(lamParam, u[0], u[1], Ret[0], Me[0], name);
 
     Hstar[0] = lamParam[0];
     Hstar2[0] = lamParam[1];
@@ -115,7 +139,7 @@ void BoundaryLayer::setWakeBC(double Re, std::vector<double> UpperCond, std::vec
     u[0] = UpperCond[0] + LowerCond[0];                                        // (Theta_up+Theta_low).
     u[1] = (UpperCond[0] * UpperCond[1] + LowerCond[0] * LowerCond[1]) / u[0]; // ((Theta*H)_up+(Theta*H)_low)/(Theta_up+Theta_low).
     u[2] = 9.;                                                                 // Amplification factor.
-    u[3] = blEdge->getVt(0);                                                   // Inviscid velocity.
+    u[3] = vt[0];                                                              // Inviscid velocity.
     u[4] = (UpperCond[0] * UpperCond[4] + LowerCond[0] * LowerCond[4]) / u[0]; // ((Ct*Theta)_up+(Theta)_low)/(Ct*Theta_up+Theta_low).
 
     Ret[0] = u[3] * u[0] * Re; // Reynolds number based on the momentum thickness.
@@ -129,7 +153,7 @@ void BoundaryLayer::setWakeBC(double Re, std::vector<double> UpperCond, std::vec
 
     // Laminar closures.
     std::vector<double> lamParam(8, 0.);
-    closSolver->laminarClosures(lamParam, u[0], u[1], Ret[0], blEdge->getMe(0), name);
+    closSolver->laminarClosures(lamParam, u[0], u[1], Ret[0], Me[0], name);
     Hstar[0] = lamParam[0];
     Hstar2[0] = lamParam[1];
     Hk[0] = lamParam[2];
@@ -139,7 +163,7 @@ void BoundaryLayer::setWakeBC(double Re, std::vector<double> UpperCond, std::vec
     ctEq[0] = lamParam[6];
     us[0] = lamParam[7];
 
-    for (size_t k = 0; k < mesh->getnMarkers(); ++k)
+    for (size_t k = 0; k < nNodes; ++k)
         regime[k] = 1;
 }
 
@@ -147,20 +171,20 @@ void BoundaryLayer::setWakeBC(double Re, std::vector<double> UpperCond, std::vec
  * @brief Compute the blowing velocity in each station of the region.
  *
  */
-void BoundaryLayer::computeBlwVel()
+void BoundaryLayer::computeBlowingVelocity()
 {
     deltaStar[0] = u[0] * u[1];
-    blowingVelocity.resize(mesh->getnMarkers() - 1, 0.);
-    for (size_t iPoint = 1; iPoint < mesh->getnMarkers(); ++iPoint)
+    blowingVelocity.resize(nNodes - 1, 0.);
+    for (size_t iPoint = 1; iPoint < nNodes; ++iPoint)
     {
         deltaStar[iPoint] = u[iPoint * nVar + 0] * u[iPoint * nVar + 1];
-        blowingVelocity[iPoint - 1] = (blEdge->getRhoe(iPoint) * blEdge->getVt(iPoint) * deltaStar[iPoint] - blEdge->getRhoe(iPoint - 1) * blEdge->getVt(iPoint - 1) * deltaStar[iPoint - 1]) / (blEdge->getRhoe(iPoint) * (mesh->getLoc(iPoint) - mesh->getLoc(iPoint - 1)));
+        blowingVelocity[iPoint - 1] = (rhoe[iPoint] * vt[iPoint] * deltaStar[iPoint] - rhoe[iPoint-1] * vt[iPoint-1] * deltaStar[iPoint - 1]) / (rhoe[iPoint] * (loc[iPoint] - loc[iPoint-1]));
         if (std::isnan(blowingVelocity[iPoint - 1]))
         {
-            if (blEdge->getRhoe(iPoint) == 0.)
+            if (rhoe[iPoint] == 0.)
                 std::cout << "Density is zero at point " << iPoint << std::endl;
-            if ((mesh->getLoc(iPoint) - mesh->getLoc(iPoint - 1)) == 0.)
-                std::cout << "Points " << iPoint -1 << " and " << iPoint << " are at the same position " << mesh->getLoc(iPoint) << ", resulting in an infinite gradient." << std::endl;
+            if ((loc[iPoint] - loc[iPoint-1]) == 0.)
+                std::cout << "Points " << iPoint -1 << " and " << iPoint << " are at the same position " << loc[iPoint] << ", resulting in an infinite gradient." << std::endl;
             if (std::isnan(deltaStar[iPoint]))
                 std::cout << "Displacement thickness is nan at position " << iPoint << std::endl;
             if (std::isnan(deltaStar[iPoint - 1]))
@@ -173,15 +197,16 @@ void BoundaryLayer::computeBlwVel()
 /**
  * @brief Print solution at a given station.
  *
- * @param iPoint Marker id.
+ * @param iPoint Node id.
  * @note Function used for debugging.
  */
 void BoundaryLayer::printSolution(size_t iPoint) const
 {
-    if (iPoint < 0 || iPoint > mesh->getnMarkers()-1)
+    if (iPoint < 0 || iPoint > nNodes-1)
         throw std::runtime_error("Tried to access element outside of region size.");
-    std::cout << "Pt " << iPoint << "Reg " << regime[iPoint] << std::endl;
-    std::cout << "x " << mesh->getx(iPoint) << "xx " << mesh->getLoc(iPoint) << "xxExt " << mesh->getExt(iPoint) << std::endl;
+    std::cout << "Pt " << iPoint << "Reg " << name << " Turb " << regime[iPoint] << std::endl;
+    std::cout << std::setprecision(5) << "x " << x[iPoint] << ", xoc " << xoc[iPoint] <<
+    ", xx " << loc[iPoint] << "xxExt " << xxExt[iPoint] << std::endl;
     std::cout << std::scientific << std::setprecision(15);
     std::cout << std::setw(10) << "T " << u[iPoint * nVar + 0] << "\n"
               << std::setw(10) << "H " << u[iPoint * nVar + 1] << "\n"
@@ -189,8 +214,8 @@ void BoundaryLayer::printSolution(size_t iPoint) const
               << std::setw(10) << "ue " << u[iPoint * nVar + 3] << "\n"
               << std::setw(10) << "Ct " << u[iPoint * nVar + 4] << "\n"
               << std::setw(10) << "dStar (BL) " << deltaStar[iPoint] << "\n"
-              << std::setw(10) << "dStar (old) " << blEdge->getDeltaStar(iPoint) << "\n"
-              << std::setw(10) << "vt " << blEdge->getVt(iPoint) << "\n"
-              << std::setw(10) << "Me " << blEdge->getMe(iPoint) << "\n"
-              << std::setw(10) << "rhoe " << blEdge->getRhoe(iPoint) << std::endl;
+              << std::setw(10) << "dStar (ext) " << deltaStarExt[iPoint] << "\n"
+              << std::setw(10) << "vt " << vt[iPoint] << "\n"
+              << std::setw(10) << "Me " << Me[iPoint] << "\n"
+              << std::setw(10) << "rhoe " << rhoe[iPoint] << std::endl;
 }
\ No newline at end of file
diff --git a/blast/src/DBoundaryLayer.h b/blast/src/DBoundaryLayer.h
index d56795e..8fbe4af 100644
--- a/blast/src/DBoundaryLayer.h
+++ b/blast/src/DBoundaryLayer.h
@@ -2,9 +2,8 @@
 #define DBOUNDARYLAYER_H
 
 #include "blast.h"
+#include "wObject.h"
 #include "DClosures.h"
-#include "DDiscretization.h"
-#include "DEdge.h"
 
 namespace blast
 {
@@ -13,7 +12,7 @@ namespace blast
  * @brief Boundary layer region upper/lower side or wake.
  * @author Paul Dechamps
  */
-class BLAST_API BoundaryLayer
+class BLAST_API BoundaryLayer : public fwk::wSharedObject
 {
 
 private:
@@ -21,11 +20,21 @@ private:
     double nCrit = 9.0;          ///< Critical amplification factor.
 
 public:
-    Discretization *mesh; ///< 1D surface boundary layer mesh.
-    Edge *blEdge;         ///< Quantites at the inviscid boundary (edge of the boundary layer).
     Closures *closSolver; ///< Closure relations class.
     std::string name;     ///< Name of the region.
 
+    // Mesh
+    size_t nNodes;             ///< Number of points in the domain.
+    size_t nElms;              ///< Number of cells in the domain.
+    std::vector<double> x;     ///< x coordinate in the global frame of reference.
+    std::vector<double> y;     ///< y coordinate in the global frame of reference.
+    std::vector<double> z;     ///< z coordinate in the global frame of reference.
+    std::vector<double> xoc;   ///< x/c coordinate in the global frame of reference.
+    std::vector<double> loc;   ///< xi coordinate in the local frame of reference.
+    std::vector<double> dx;    ///< Cell size.
+    std::vector<double> alpha; ///< Angle of the cell wrt the x axis of the global frame of reference.
+    double chord;              ///< Chord of the section.
+
     // Boundary layer variables.
     std::vector<double> u;         ///< Solution vector (theta, H, N, ue, Ct).
     std::vector<double> Ret;       ///< Reynolds number based on the momentum thickness (theta).
@@ -37,33 +46,58 @@ public:
     std::vector<double> 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> deltaStar; ///< Dispacement thickness (int(1-rho*u/rhoe*ue d_eta)).
+    std::vector<double> 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> xxExt;          ///< xi coordinate in the local frame of reference, at the edge of the boundary layer.
+    std::vector<double> deltaStarExt;   ///< Displacement thickness.
+    std::vector<double> vtExt;          ///< Previous velocity.
+
+    std::vector<double> blowingVelocity; ///< Blowing velocity.
 
     // Transition related variables.
     std::vector<int> regime;             ///< Laminar (0) or turbulent (1) regime.
-    std::vector<double> blowingVelocity; ///< Blowing velocity.
-    size_t transMarker;                  ///< Marker id of the transition location.
-    double xtrF;                         ///< Forced transition location in the global frame of reference.
-    double xtr;                          ///< Transition location in the global frame of reference.
-    double xoctr;                        ///< Transition location in % of the chord.
+    size_t transitionNode;               ///< Node id of the transition location.
+    double xtrF;                         ///< Forced transition location in the local frame of reference (x/c).
+    double xtr;                          ///< Transition location in the local frame of reference (x/c).
 
-    BoundaryLayer(double _xtrF = -1.0);
+    BoundaryLayer(double _xtrF = -1.0, std::string _name = "None");
     ~BoundaryLayer();
 
+    void reset();
+
+    // Getters
+    std::string getName() const { return name; };
+    size_t getnNodes() const { return nNodes; };
+    size_t getnElms() const { return nElms; };
+
+    std::vector<double> getDeltaStar() const { return deltaStar; };
+    std::vector<double> getUe() const {std::vector<double > ue(nNodes, 0.); for (size_t i = 0; i < nNodes; ++i) ue[i] = u[i * nVar + 3]; return ue;};
+    std::vector<double> getBlowing() const { return blowingVelocity; };
+
+    // Setters
+    void setMesh(std::vector<double> const _x, std::vector<double> const y, std::vector<double> const z, double const _chord, double const xMin);
+    void setMe(std::vector<double> const _Me) {if (_Me.size() != nNodes) throw std::runtime_error("Mach number vector is not consistent."); Me = _Me;};
+    void setVt(std::vector<double> const _vt) {if (_vt.size() != nNodes) throw std::runtime_error("Velocity vector is not consistent."); vt = _vt;};
+    void setRhoe(std::vector<double> const _rhoe) {if (_rhoe.size() != nNodes) throw std::runtime_error("Density vector is not consistent."); rhoe = _rhoe;};
+    void setxxExt(std::vector<double> const _xxExt) {if (_xxExt.size() != nNodes) throw std::runtime_error("External mesh vector is not consistent."); xxExt = _xxExt;};
+    void setDeltaStarExt(std::vector<double> const _deltaStarExt) {if (_deltaStarExt.size() != nNodes) throw std::runtime_error("Displacement thickness vector is not consistent."); deltaStarExt = _deltaStarExt;};
+    void setVtExt(std::vector<double> const _vtExt) {if (_vtExt.size() != nNodes) throw std::runtime_error("Velocity vector is not consistent."); vtExt = _vtExt;};
+
     // Boundary conditions.
-    void setStagBC(double Re);
+    void setStagnationBC(double Re);
     void setWakeBC(double Re, std::vector<double> upperConditions, std::vector<double> lowerConditions);
-    void setMesh(std::vector<double> x,
-                 std::vector<double> y,
-                 std::vector<double> z);
 
     // Getters.
     size_t getnVar() const { return nVar; };
     double getnCrit() const { return nCrit; };
+    void setnCrit(double const _nCrit) {nCrit = _nCrit;};
 
     // Others
     void printSolution(size_t iPoint) const;
-    void computeBlwVel();
+    void computeBlowingVelocity();
 };
 } // namespace blast
 #endif // DBOUNDARYLAYER_H
diff --git a/blast/src/DDiscretization.cpp b/blast/src/DDiscretization.cpp
deleted file mode 100644
index 9a6796b..0000000
--- a/blast/src/DDiscretization.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "DDiscretization.h"
-#include <cmath>
-#include <algorithm>
-
-using namespace blast;
-
-Discretization::Discretization()
-{
-    nMarkers = 0;
-    nElm = 0;
-    prevnMarkers = 0;
-}
-
-Discretization::~Discretization() {}
-
-void Discretization::setGlob(std::vector<double> &_x, std::vector<double> &_y, std::vector<double> &_z)
-{
-    if (_x.size() != _y.size() || _y.size() != _z.size() || _x.size() != _z.size())
-        throw std::runtime_error("blast::Discretization Wrong mesh sizes.\n");
-    if (_x.size() < 2 || _y.size() < 2 || _z.size() < 2)
-        throw std::runtime_error("blast::Discretization Mesh too small.\n");
-
-    nMarkers = _x.size();
-    x.resize(nMarkers, 0.);
-    y.resize(nMarkers, 0.);
-    z.resize(nMarkers, 0.);
-    nElm = nMarkers - 1;
-    x = _x;
-    y = _y;
-    z = _z;
-
-    computeBLcoord();
-    computeOCcoord();
-}
-
-/**
- * @brief Compute nodes coordinates in the local frame of reference.
- */
-void Discretization::computeBLcoord()
-{
-    loc.resize(nMarkers, 0.);
-    alpha.resize(nElm, 0.);
-    dx.resize(nElm, 0.);
-
-    for (size_t iPoint = 0; iPoint < nElm; ++iPoint)
-    {
-        alpha[iPoint] = std::atan2(y[iPoint + 1] - y[iPoint], x[iPoint + 1] - x[iPoint]);
-        // dx = sqrt(delta x ^2 + delta y ^2).
-        dx[iPoint] = std::sqrt((x[iPoint + 1] - x[iPoint]) * (x[iPoint + 1] - x[iPoint]) + (y[iPoint + 1] - y[iPoint]) * (y[iPoint + 1] - y[iPoint]));
-        loc[iPoint + 1] = loc[iPoint] + dx[iPoint];
-    }
-}
-
-/**
- * @brief Compute x/chord coordinate.
-*/
-void Discretization::computeOCcoord()
-{
-    xoc.resize(nMarkers, 0.);
-
-    // Find min and max of array x
-    auto min_it = std::min_element(x.begin(), x.end());
-    double xMin = *min_it;
-    auto max_it = std::max_element(x.begin(), x.end());
-    double xMax = *max_it;
-
-    // Compute xoc
-    chord = xMax - xMin;
-    if (chord <= 0)
-        throw;
-    for (size_t iPoint = 0; iPoint < x.size(); ++iPoint)
-        xoc[iPoint] = (x[iPoint] - xMin) / chord;
-}
-
-void Discretization::setExt(std::vector<double> extM)
-{
-    ext.resize(extM.size(), 0.);
-    ext = extM;
-};
diff --git a/blast/src/DDiscretization.h b/blast/src/DDiscretization.h
deleted file mode 100644
index 1f4d534..0000000
--- a/blast/src/DDiscretization.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef DDISCRETIZATION_H
-#define DDISCRETIZATION_H
-
-#include "blast.h"
-#include "DBoundaryLayer.h"
-
-namespace blast
-{
-
-/**
- * @brief Boundary layer mesh.
- * @author Paul Dechamps
- */
-class BLAST_API Discretization
-{
-private:
-    std::vector<double> x;     ///< x coordinate in the global frame of reference.
-    std::vector<double> y;     ///< y coordinate in the global frame of reference.
-    std::vector<double> z;     ///< z coordinate in the global frame of reference.
-    std::vector<double> xoc;   ///< x/c coordinate in the global frame of reference.
-    std::vector<double> loc;   ///< xi coordinate in the local frame of reference.
-    std::vector<double> ext;   ///< xi coordinate in the local frame of reference, at the edge of the boundary layer.
-    std::vector<double> dx;    ///< Cell size.
-    std::vector<double> alpha; ///< Angle of the cell wrt the x axis of the global frame of reference.
-    size_t nMarkers;           ///< Number of points in the domain.
-    size_t nElm;               ///< Number of cells in the domain.
-    double chord;              ///< Chord of the section.
-
-public:
-    size_t prevnMarkers; ///< Number of points in the domain at the previous iteration.
-
-    Discretization();
-    ~Discretization();
-
-    // Getters.
-    size_t getnMarkers() const { return nMarkers; };
-    double getLoc(size_t iPoint) const { return loc[iPoint]; };
-    double getx(size_t iPoint) const { return x[iPoint]; };
-    double gety(size_t iPoint) const { return y[iPoint]; };
-    double getz(size_t iPoint) const { return z[iPoint]; };
-    double getxoc(size_t iPoint) const { return xoc[iPoint]; };
-    double getExt(size_t iPoint) const { return ext[iPoint]; };
-    double getAlpha(size_t iElm) const { return alpha[iElm]; };
-    size_t getDiffnElm() const { return nMarkers - prevnMarkers; };
-    double getChord() const { return chord; };
-
-    // Setters.
-    void setGlob(std::vector<double> &_x, std::vector<double> &_y, std::vector<double> &_z);
-    void setExt(std::vector<double> extM);
-    void computeBLcoord();
-    void computeOCcoord();
-};
-} // namespace blast
-#endif // WDISCRETIZATION_H
diff --git a/blast/src/DDriver.cpp b/blast/src/DDriver.cpp
index a1fcba0..a03cf59 100644
--- a/blast/src/DDriver.cpp
+++ b/blast/src/DDriver.cpp
@@ -32,19 +32,10 @@ Driver::Driver(double _Re, double _Minf, double _CFL0, size_t nSections,
 
     // Initialzing boundary layer
     sections.resize(nSections);
+    solverExitCode = 0;
     convergenceStatus.resize(nSections);
     for (size_t iSec = 0; iSec < nSections; ++iSec)
-    {
         convergenceStatus[iSec].resize(3);
-        for (size_t i = 0; i < 3; ++i)
-        {
-            BoundaryLayer *region = new BoundaryLayer(xtrF[i]);
-            sections[iSec].push_back(region);
-        }
-        sections[iSec][0]->name = "upper";
-        sections[iSec][1]->name = "lower";
-        sections[iSec][2]->name = "wake";
-    }
 
     Cdt_sec.resize(sections.size(), 0.);
     Cdf_sec.resize(sections.size(), 0.);
@@ -54,9 +45,6 @@ Driver::Driver(double _Re, double _Minf, double _CFL0, size_t nSections,
     Cdp = 0.;
     span = _span;
 
-    // Pre/post processing flags.
-    stagPtMvmt.resize(sections.size(), false);
-
     // Time solver initialization.
     tSolver = new Solver(_CFL0, _Minf, Re);
 
@@ -74,138 +62,89 @@ Driver::Driver(double _Re, double _Minf, double _CFL0, size_t nSections,
  */
 Driver::~Driver()
 {
-    for (size_t iSec = 0; iSec < sections.size(); ++iSec)
-        for (size_t i = 0; i < sections[iSec].size(); ++i)
-            delete sections[iSec][i];
     delete tSolver;
     std::cout << "~blast::Driver()\n";
 } // end ~Driver
 
+void Driver::reset()
+{
+    size_t nSections = sections.size();
+    for (size_t iSec = 0; iSec < sections.size(); ++iSec)
+        sections[iSec].resize(0);
+    sections.resize(nSections);
+}
+
 /**
  * @brief Runs viscous operations. Temporal solver parametrisation is first adapted,
  * Solutions are initialized than time marched towards steady state successively for each points.
  *
- * @param couplIter Current coupling iteration.
  * @return int Solver exit code.
  */
-int Driver::run(unsigned int const couplIter)
+int Driver::run()
 {
-    bool lockTrans = false; // Flagging activation of transition routines.
+    bool lockTrans = false; // Flag activation of transition routines.
     int pointExitCode;      // Output of pseudo time integration (0: converged; -1: unsuccessful, failed; >0: unsuccessful nb iter).
 
     double maxMach = 0.;
 
     for (size_t iSec = 0; iSec < sections.size(); ++iSec)
     {
-        tms["0-CheckIn"].start();
         if (verbose > 1)
             std::cout << "Sec " << iSec << " ";
 
-        // Check for stagnation point movement.
-        if (couplIter != 0 && (sections[iSec][0]->mesh->getDiffnElm()))
-        {
-            stagPtMvmt[iSec] = true;
-            if (verbose > 2)
-                std::cout << "Stagnation point moved by " << sections[iSec][0]->mesh->getDiffnElm() << " elements." << std::endl;
-        }
-        else
-            stagPtMvmt[iSec] = false;
-
-        // Set boundary conditions.
-        sections[iSec][0]->xtr = 1.; // Upper side initial xtr.
-        sections[iSec][1]->xtr = 1.; // Lower side initial xtr.
-        sections[iSec][2]->xtr = 0.; // Wake initial xtr (fully turbulent).
-        sections[iSec][0]->setStagBC(Re);
-        sections[iSec][1]->setStagBC(Re);
-        tms["0-CheckIn"].stop();
-
         // Loop over the regions (upper, lower and wake).
-        for (size_t iRegion = 0; iRegion < sections[iSec].size(); ++iRegion)
+        int iRegion = 0;
+        for (auto reg: sections[iSec])
         {
             convergenceStatus[iSec][iRegion].resize(0);
 
-            // Maximum Mach number in the region.
-            if (sections[iSec][iRegion]->blEdge->getMaxMach() > maxMach)
-                maxMach = sections[iSec][iRegion]->blEdge->getMaxMach();
-
-            if (verbose > 1)
-                std::cout << sections[iSec][iRegion]->name << " ";
-
-            // Check if safe mode is required.
-            if (couplIter == 0 || sections[iSec][iRegion]->mesh->getDiffnElm() != 0 || stagPtMvmt[iSec] == true || solverExitCode != 0)
-            {
-                tSolver->setCFL0(1);
-                tSolver->setitFrozenJac(1);
-                tSolver->setinitSln(true);
-
-                if (sections[iSec][iRegion]->mesh->getDiffnElm())
-                {
-                    std::vector<double> xxExtCurr(sections[iSec][iRegion]->mesh->getnMarkers(), 0.);
-                    for (size_t iPoint = 0; iPoint < xxExtCurr.size(); ++iPoint)
-                        xxExtCurr[iPoint] = sections[iSec][iRegion]->mesh->getLoc(iPoint);
-                    sections[iSec][iRegion]->mesh->setExt(xxExtCurr);
-
-                    std::vector<double> DeltaStarZeros(sections[iSec][iRegion]->mesh->getnMarkers(), 0.0);
-                    sections[iSec][iRegion]->blEdge->setDeltaStar(DeltaStarZeros);
-
-                    std::vector<double> ueOld(sections[iSec][iRegion]->mesh->getnMarkers(), 0.0);
-                    for (size_t iPoint = 0; iPoint < ueOld.size(); ++iPoint)
-                        ueOld[iPoint] = sections[iSec][iRegion]->blEdge->getVt(iPoint);
-                    sections[iSec][iRegion]->blEdge->setVtOld(ueOld);
-                }
-
-                // Keyword annoncing iteration safety level.
-                if (verbose > 1)
-                    std::cout << "restart. ";
-            }
+            // Reset transition
+            if (reg->name == "wake")
+                reg->xtr = 0.;
+            else if (reg-> name == "upper" || reg->name == "lower")
+                reg->xtr = 1.;
             else
             {
-                tSolver->setCFL0(CFL0);
-                tSolver->setitFrozenJac(5);
-                tSolver->setinitSln(false);
-
-                // Keyword annoncing iteration safety level.
-                if (verbose > 1)
-                    std::cout << "update. ";
+                std::cout << "reg->name " << reg->name << std::endl;
+                throw std::runtime_error("Wrong region name\n");
             }
 
-            // Save number of points in each regions.
-            sections[iSec][iRegion]->mesh->prevnMarkers = sections[iSec][iRegion]->mesh->getnMarkers();
-
             // Reset regime.
             lockTrans = false;
-            if (iRegion < 2) // Airfoil
-                for (size_t k = 0; k < sections[iSec][iRegion]->mesh->getnMarkers(); k++)
-                    sections[iSec][iRegion]->regime[k] = 0;
-            else if (iRegion == 2) // Wake
+            if (reg->name == "upper" || reg->name == "lower")
+            {
+                for (size_t k = 0; k < reg->nNodes; k++)
+                    reg->regime[k] = 0;
+                reg->setStagnationBC(Re);
+            }
+
+            else if (reg->name == "wake") // Wake
             {
-                for (size_t k = 0; k < sections[iSec][iRegion]->mesh->getnMarkers(); k++)
-                    sections[iSec][iRegion]->regime[k] = 1;
+                for (size_t k = 0; k < reg->nNodes; k++)
+                    reg->regime[k] = 1;
 
                 // Impose wake boundary condition.
-                std::vector<double> upperConditions(sections[iSec][iRegion]->getnVar(), 0.);
-                std::vector<double> lowerConditions(sections[iSec][iRegion]->getnVar(), 0.);
+                std::vector<double> upperConditions(reg->getnVar(), 0.);
+                std::vector<double> lowerConditions(reg->getnVar(), 0.);
                 for (size_t k = 0; k < upperConditions.size(); ++k)
                 {
-                    upperConditions[k] = sections[iSec][0]->u[(sections[iSec][0]->mesh->getnMarkers() - 1) * sections[iSec][0]->getnVar() + k];
-                    lowerConditions[k] = sections[iSec][1]->u[(sections[iSec][1]->mesh->getnMarkers() - 1) * sections[iSec][1]->getnVar() + k];
+                    upperConditions[k] = sections[iSec][0]->u[(sections[iSec][0]->nNodes - 1) * sections[iSec][0]->getnVar() + k];
+                    lowerConditions[k] = sections[iSec][1]->u[(sections[iSec][1]->nNodes - 1) * sections[iSec][1]->getnVar() + k];
                 }
-                sections[iSec][iRegion]->setWakeBC(Re, upperConditions, lowerConditions);
+                reg->setWakeBC(Re, upperConditions, lowerConditions);
                 lockTrans = true;
             }
             else
-                throw;
+                throw std::runtime_error("Wrong region name\n");
 
             // Loop over points
-            for (size_t iPoint = 1; iPoint < sections[iSec][iRegion]->mesh->getnMarkers(); ++iPoint)
+            for (size_t iPoint = 1; iPoint < reg->nNodes; ++iPoint)
             {
                 // Initialize solution at point
-                tSolver->initialCondition(iPoint, sections[iSec][iRegion]);
+                tSolver->initialCondition(iPoint, reg);
                 // Solve equations
                 tms["1-Solver"].start();
-                pointExitCode = tSolver->integration(iPoint, sections[iSec][iRegion]);
-                if (sections[iSec][iRegion]->xtrF != -1 && sections[iSec][iRegion]->mesh->getxoc(iPoint) >= sections[iSec][iRegion]->xtrF)
-                    sections[iSec][iRegion]->u[iPoint * sections[iSec][iRegion]->getnVar()+2] = 9.;
+                pointExitCode = tSolver->integration(iPoint, reg);
                 tms["1-Solver"].stop();
 
                 if (pointExitCode != 0)
@@ -215,29 +154,47 @@ int Driver::run(unsigned int const couplIter)
                 tms["2-Transition"].start();
                 if (!lockTrans)
                 {
-                    // Check if perturbation waves are growing or not.
-                    if (sections[iSec][iRegion]->xtrF != -1 && sections[iSec][iRegion]->mesh->getxoc(iPoint) <= sections[iSec][iRegion]->xtrF)
-                        checkWaves(iPoint, sections[iSec][iRegion]);
-
-                    // Amplification factor is compared to critical amplification factor.
-                    if (sections[iSec][iRegion]->u[iPoint * sections[iSec][iRegion]->getnVar() + 2] >= sections[iSec][iRegion]->getnCrit())
+                    // Forced transition
+                    if (reg->xtrF != -1 && reg->xoc[iPoint] >= reg->xtrF)
                     {
-                        averageTransition(iPoint, sections[iSec][iRegion], 0);
+                        reg->u[iPoint * reg->getnVar() + 2] = reg->getnCrit();
+                        averageTransition(iPoint, reg, true);
                         if (verbose > 1)
                         {
                             std::cout << std::fixed;
                             std::cout << std::setprecision(2);
-                            std::cout << sections[iSec][iRegion]->xoctr
-                                      << " (" << sections[iSec][iRegion]->transMarker << ") ";
+                            std::cout << reg->xtr
+                                    << " (" << reg->transitionNode << ") ";
                         }
                         lockTrans = true;
                     }
+                    // Free transtion
+                    else if (reg->xtrF == -1)
+                    {
+                        // Check if perturbation waves are growing or not.
+                        checkWaves(iPoint, reg);
+
+                        // Amplification factor is compared to critical amplification factor.
+                        if (reg->u[iPoint * reg->getnVar() + 2] >= reg->getnCrit())
+                        {
+                            averageTransition(iPoint, reg, false);
+                            if (verbose > 1)
+                            {
+                                std::cout << std::fixed;
+                                std::cout << std::setprecision(2);
+                                std::cout << reg->xtr
+                                        << " (" << reg->transitionNode << ") ";
+                            }
+                            lockTrans = true;
+                        }
+                    }
                 }
                 tms["2-Transition"].stop();
             }
             tms["3-Blowing"].start();
-            sections[iSec][iRegion]->computeBlwVel();
+            reg->computeBlowingVelocity();
             tms["3-Blowing"].stop();
+            iRegion++;
         }
         if (verbose > 1)
             std::cout << std::endl;
@@ -280,7 +237,7 @@ void Driver::checkWaves(size_t iPoint, BoundaryLayer *bl)
  * @param bl BoundaryLayer region.
  * @param forced Flag for forced transition.
  */
-void Driver::averageTransition(size_t iPoint, BoundaryLayer *bl, int forced)
+void Driver::averageTransition(size_t iPoint, BoundaryLayer *bl, bool forced)
 {
     // Averages solution on transition marker.
     size_t nVar = bl->getnVar();
@@ -291,23 +248,37 @@ void Driver::averageTransition(size_t iPoint, BoundaryLayer *bl, int forced)
         lamSol[k] = bl->u[iPoint * nVar + k];
 
     // Set up turbulent portion boundary condition.
-    bl->transMarker = iPoint; // Save transition marker.
+    bl->transitionNode = iPoint; // Save transition marker.
 
     // Loop over remaining points in the region.
-    for (size_t k = iPoint; k < bl->mesh->getnMarkers(); ++k)
+    for (size_t k = iPoint; k < bl->nNodes; ++k)
         bl->regime[k] = 1; // Set Turbulent regime.
 
     // Compute transition location.
-    bl->xtr = (bl->getnCrit() - bl->u[(iPoint - 1) * nVar + 2]) * ((bl->mesh->getx(iPoint) - bl->mesh->getx(iPoint - 1)) / (bl->u[iPoint * nVar + 2] - bl->u[(iPoint - 1) * nVar + 2])) + bl->mesh->getx(iPoint - 1);
-    bl->xoctr = (bl->getnCrit() - bl->u[(iPoint - 1) * nVar + 2]) * ((bl->mesh->getxoc(iPoint) - bl->mesh->getxoc(iPoint - 1)) / (bl->u[iPoint * nVar + 2] - bl->u[(iPoint - 1) * nVar + 2])) + bl->mesh->getxoc(iPoint - 1);
+    // if (forced)
+    //     bl->xtr = bl->xtrF;
+    // else
+    bl->xtr = (bl->getnCrit() - bl->u[(iPoint - 1) * nVar + 2]) * ((bl->x[iPoint] - bl->x[iPoint-1]) / (bl->u[iPoint * nVar + 2] - bl->u[(iPoint - 1) * nVar + 2])) + bl->x[iPoint-1];
 
-    // Percentage of the subsection corresponding to a turbulent flow.
-    double avTurb = (bl->mesh->getx(iPoint) - bl->xtr) / (bl->mesh->getx(iPoint) - bl->mesh->getx(iPoint - 1));
+    double avTurb = (bl->x[iPoint] - bl->xtr) / (bl->x[iPoint] - bl->x[iPoint-1]);
     double avLam = 1. - avTurb;
 
+    //std::cout << "avTurb " << avTurb << " avLam " << avLam << std::endl;
+    if (avTurb < 0. || avTurb > 1. || avLam < 0. || avLam > 1.)
+    {
+        bl->printSolution(iPoint);
+        bl->printSolution(iPoint - 1);
+        std::cout << "dx " << std::abs(bl->xoc[iPoint] - bl->xoc[iPoint - 1]) << std::endl;
+        std::cout << " (bl->u[iPoint * nVar + 2] - bl->u[(iPoint - 1) * nVar + 2]) " << (bl->u[iPoint * nVar + 2] - bl->u[(iPoint - 1) * nVar + 2]) << std::endl;
+        std::cout << " bl->getnCrit() - bl->u[(iPoint - 1) * nVar + 2] " << bl->getnCrit() - bl->u[(iPoint - 1) * nVar + 2] << std::endl;
+        std::cout << "xtr " << bl->xtr << std::endl;
+        std::cout << "avTurb " << avTurb << " avLam " << avLam << std::endl;
+        throw std::runtime_error("Transition location out of bounds.");
+    }
+
     // Impose boundary condition.
     double Cteq_trans;
-    bl->closSolver->turbulentClosures(Cteq_trans, bl->u[(iPoint - 1) * nVar + 0], bl->u[(iPoint - 1) * nVar + 1], 0.03, bl->Ret[iPoint - 1], bl->blEdge->getMe(iPoint - 1), bl->name);
+    bl->closSolver->turbulentClosures(Cteq_trans, bl->u[(iPoint - 1) * nVar + 0], bl->u[(iPoint - 1) * nVar + 1], 0.03, bl->Ret[iPoint - 1], bl->Me[iPoint-1], bl->name);
     bl->ctEq[iPoint - 1] = Cteq_trans;
     bl->u[(iPoint - 1) * nVar + 4] = 0.7 * bl->ctEq[iPoint - 1];
 
@@ -331,7 +302,7 @@ void Driver::averageTransition(size_t iPoint, BoundaryLayer *bl, int forced)
 
     // Recompute closures. (The turbulent BC @ iPoint - 1 does not influence laminar closure relations).
     std::vector<double> lamParam(8, 0.);
-    bl->closSolver->laminarClosures(lamParam, bl->u[(iPoint - 1) * nVar + 0], bl->u[(iPoint - 1) * nVar + 1], bl->Ret[iPoint - 1], bl->blEdge->getMe(iPoint - 1), bl->name);
+    bl->closSolver->laminarClosures(lamParam, bl->u[(iPoint - 1) * nVar + 0], bl->u[(iPoint - 1) * nVar + 1], bl->Ret[iPoint - 1], bl->Me[iPoint-1], bl->name);
     bl->Hstar[iPoint - 1] = lamParam[0];
     bl->Hstar2[iPoint - 1] = lamParam[1];
     bl->Hk[iPoint - 1] = lamParam[2];
@@ -342,7 +313,7 @@ void Driver::averageTransition(size_t iPoint, BoundaryLayer *bl, int forced)
     bl->us[iPoint - 1] = lamParam[7];
 
     std::vector<double> turbParam(8, 0.);
-    bl->closSolver->turbulentClosures(turbParam, bl->u[(iPoint)*nVar + 0], bl->u[(iPoint)*nVar + 1], bl->u[(iPoint)*nVar + 4], bl->Ret[iPoint], bl->blEdge->getMe(iPoint), bl->name);
+    bl->closSolver->turbulentClosures(turbParam, bl->u[(iPoint)*nVar + 0], bl->u[(iPoint)*nVar + 1], bl->u[(iPoint)*nVar + 4], bl->Ret[iPoint], bl->Me[iPoint], bl->name);
     bl->Hstar[iPoint] = turbParam[0];
     bl->Hstar2[iPoint] = turbParam[1];
     bl->Hk[iPoint] = turbParam[2];
@@ -363,41 +334,41 @@ void Driver::averageTransition(size_t iPoint, BoundaryLayer *bl, int forced)
  * @param bl BoundaryLayer region.
  * @param i Considered section.
  */
-void Driver::computeSectionalDrag(std::vector<BoundaryLayer *> const &bl, size_t i)
+void Driver::computeSectionalDrag(std::vector<BoundaryLayer *> const &sec, size_t i)
 {
-    size_t nVar = bl[0]->getnVar();
-    size_t lastWkPt = (bl[2]->mesh->getnMarkers() - 1) * nVar;
+    size_t nVar = sec[0]->getnVar();
+    size_t lastWkPt = (sec[2]->nNodes - 1) * nVar;
 
     // Normalize friction and dissipation coefficients.
-    std::vector<double> frictioncoeff_upper(bl[0]->mesh->getnMarkers(), 0.0);
+    std::vector<double> frictioncoeff_upper(sec[0]->nNodes, 0.0);
     for (size_t k = 0; k < frictioncoeff_upper.size(); ++k)
-        frictioncoeff_upper[k] = bl[0]->blEdge->getVt(k) * bl[0]->blEdge->getVt(k) * bl[0]->cf[k];
+        frictioncoeff_upper[k] = sec[0]->vt[k] * sec[0]->vt[k] * sec[0]->cf[k];
 
-    std::vector<double> frictioncoeff_lower(bl[1]->mesh->getnMarkers(), 0.0);
+    std::vector<double> frictioncoeff_lower(sec[1]->nNodes, 0.0);
     for (size_t k = 0; k < frictioncoeff_lower.size(); ++k)
-        frictioncoeff_lower[k] = bl[1]->blEdge->getVt(k) * bl[1]->blEdge->getVt(k) * bl[1]->cf[k];
+        frictioncoeff_lower[k] = sec[1]->vt[k] * sec[1]->vt[k] * sec[1]->cf[k];
 
     // Compute friction drag coefficient.
     double Cdf_upper = 0.0;
-    for (size_t k = 1; k < bl[0]->mesh->getnMarkers(); ++k)
-        Cdf_upper += (frictioncoeff_upper[k] + frictioncoeff_upper[k - 1]) * (bl[0]->mesh->getx(k) - bl[0]->mesh->getx(k - 1)) / 2;
+    for (size_t k = 1; k < sec[0]->nNodes; ++k)
+        Cdf_upper += (frictioncoeff_upper[k] + frictioncoeff_upper[k - 1]) * (sec[0]->x[k] - sec[0]->x[k-1]) / 2;
     double Cdf_lower = 0.0;
-    for (size_t k = 1; k < bl[1]->mesh->getnMarkers(); ++k)
-        Cdf_lower += (frictioncoeff_lower[k] + frictioncoeff_lower[k - 1]) * (bl[1]->mesh->getx(k) - bl[1]->mesh->getx(k - 1)) / 2;
+    for (size_t k = 1; k < sec[1]->nNodes; ++k)
+        Cdf_lower += (frictioncoeff_lower[k] + frictioncoeff_lower[k - 1]) * (sec[1]->x[k] - sec[1]->x[k-1]) / 2;
 
     // Friction drag coefficient.
     Cdf_sec[i] = Cdf_upper + Cdf_lower; // No friction in the wake
     // Total drag coefficient.
-    Cdt_sec[i] = 2 * bl[2]->u[lastWkPt + 0] * pow(bl[2]->u[lastWkPt + 3], (bl[2]->u[lastWkPt + 1] + 5) / 2);
+    Cdt_sec[i] = 2 * sec[2]->u[lastWkPt + 0] * pow(sec[2]->u[lastWkPt + 3], (sec[2]->u[lastWkPt + 1] + 5) / 2);
     // Pressure drag coefficient.
     Cdp_sec[i] = Cdt_sec[i] - Cdf_sec[i];
 }
 
-double Driver::getAvrgxoctr(size_t const iRegion) const
+double Driver::getAverageTransition(size_t const iRegion) const
 {
     double xtr = 0.0;
     for (size_t iSec = 0; iSec < sections.size(); ++iSec)
-        xtr += sections[iSec][iRegion]->xoctr;
+        xtr += sections[iSec][iRegion]->xtr;
     xtr /= sections.size();
     return xtr;
 }
@@ -421,13 +392,13 @@ void Driver::computeTotalDrag()
     }
     else
     {
-        Cdt += (sections[0][0]->mesh->getz(0) - 0) * Cdt_sec[0];
-        Cdp += (sections[0][0]->mesh->getz(0) - 0) * Cdp_sec[0];
-        Cdf += (sections[0][0]->mesh->getz(0) - 0) * Cdf_sec[0];
+        Cdt += (sections[0][0]->z[0] - 0) * Cdt_sec[0];
+        Cdp += (sections[0][0]->z[0] - 0) * Cdp_sec[0];
+        Cdf += (sections[0][0]->z[0] - 0) * Cdf_sec[0];
         double dz = 0.;
         for (size_t k = 1; k < sections.size(); ++k)
         {
-            dz = (sections[k][0]->mesh->getz(0) - sections[k - 1][0]->mesh->getz(0));
+            dz = (sections[k][0]->z[0] - sections[k - 1][0]->z[0]);
             Cdt += dz * Cdt_sec[k];
             Cdp += dz * Cdp_sec[k];
             Cdf += dz * Cdf_sec[k];
@@ -472,7 +443,7 @@ int Driver::outputStatus(double maxMach) const
                 if (convergenceStatus[iSec][iReg].size() != 0)
                     for (size_t iPoint = 0; iPoint < convergenceStatus[iSec][iReg].size(); ++iPoint)
                     {
-                        std::cout << convergenceStatus[iSec][iReg][iPoint] << " (" << sections[iSec][iReg]->mesh->getx(convergenceStatus[iSec][iReg][iPoint]) << "), ";
+                        std::cout << convergenceStatus[iSec][iReg][iPoint] << " (" << sections[iSec][iReg]->x[convergenceStatus[iSec][iReg][iPoint]] << "), ";
                         ++count;
                     }
                 std::cout << "\n";
@@ -488,7 +459,7 @@ int Driver::outputStatus(double maxMach) const
         std::vector<double> meanTransitions(2, 0.);
         for (size_t iSec = 0; iSec < sections.size(); ++iSec)
             for (size_t iReg = 0; iReg < 2; ++iReg)
-                meanTransitions[iReg] += sections[iSec][iReg]->xoctr;
+                meanTransitions[iReg] += sections[iSec][iReg]->xtr;
         for (size_t iReg = 0; iReg < meanTransitions.size(); ++iReg)
             meanTransitions[iReg] /= sections.size();
 
@@ -526,184 +497,6 @@ int Driver::outputStatus(double maxMach) const
     return solverExitCode;
 }
 
-/**
- * @brief Set nodes coordinates in the global frame of reference.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @param _x Vector of x coordinates of the nodes in the region.
- * @param _y Vector of y coordinates of the nodes in the region.
- * @param _z Vector of z coordinates of the nodes in the region.
- */
-void Driver::setGlobMesh(size_t iSec, size_t iRegion, std::vector<double> _x, std::vector<double> _y, std::vector<double> _z)
-{
-    if (iSec > sections.size() || iRegion > sections[iSec].size())
-        throw std::runtime_error("blast::Driver Wrong section or region id.");
-    sections[iSec][iRegion]->setMesh(_x, _y, _z);
-}
-
-/**
- * @brief Set the velocity at the nodes in the global frame of reference.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @param vx Vector of velocities projected on the x axis of the global frame of reference.
- * @param vy Vector of velocities projected on the y axis of the global frame of reference.
- * @param vz Vector of velocities projected on the z axis of the global frame of reference.
- */
-void Driver::setVelocities(size_t iSec, size_t iRegion, std::vector<double> vx, std::vector<double> vy, std::vector<double> vz)
-{
-    if (vx.size() != vy.size() || vy.size() != vz.size() || vx.size() != vz.size())
-        throw std::runtime_error("blast::Driver Wrong velocity vector sizes.");
-    if (vx.size() != sections[iSec][iRegion]->mesh->getnMarkers())
-        throw std::runtime_error("blast::Driver Velocity vector is not coherent with the mesh.");
-
-    std::vector<double> vt(vx.size(), 0.0);
-
-    for (size_t iPoint = 0; iPoint < vx.size() - 1; ++iPoint)
-    {
-        vt[iPoint] = vx[iPoint] * std::cos(sections[iSec][iRegion]->mesh->getAlpha(iPoint)) + vy[iPoint] * std::sin(sections[iSec][iRegion]->mesh->getAlpha(iPoint));
-        vt[iPoint + 1] = vx[iPoint + 1] * std::cos(sections[iSec][iRegion]->mesh->getAlpha(iPoint)) + vy[iPoint + 1] * std::sin(sections[iSec][iRegion]->mesh->getAlpha(iPoint));
-    }
-
-    sections[iSec][iRegion]->blEdge->setVt(vt);
-}
-
-/**
- * @brief Set the Mach number at the nodes.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @param _Me Vector of Mach numbers at the nodes.
- */
-void Driver::setMe(size_t iSec, size_t iRegion, std::vector<double> _Me)
-{
-    if (_Me.size() != sections[iSec][iRegion]->mesh->getnMarkers())
-        throw std::runtime_error("blast::Driver Mach number vector is not coherent with the mesh.");
-    sections[iSec][iRegion]->blEdge->setMe(_Me);
-}
-
-/**
- * @brief Set the density at the nodes.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @param _Rhoe Vector of density at the nodes.
- */
-void Driver::setRhoe(size_t iSec, size_t iRegion, std::vector<double> _Rhoe)
-{
-    if (_Rhoe.size() != sections[iSec][iRegion]->mesh->getnMarkers())
-        throw std::runtime_error("blast::Driver Density vector is not coherent with the mesh.");
-    sections[iSec][iRegion]->blEdge->setRhoe(_Rhoe);
-}
-
-/**
- * @brief Set the nodes coordinates in the local frame of reference at the edge of the boundary layer.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @param _xxExt Vector of coordinates of the nodes.
- */
-void Driver::setxxExt(size_t iSec, size_t iRegion, std::vector<double> _xxExt)
-{
-    if (_xxExt.size() != sections[iSec][iRegion]->mesh->getnMarkers())
-        throw std::runtime_error("blast::Driver External mesh vector is not coherent with the mesh.");
-    sections[iSec][iRegion]->mesh->setExt(_xxExt);
-}
-
-/**
- * @brief Set the displacement thickness (previous iteration).
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @param _DeltaStarExt Vector of displacement thicknesses at the nodes.
- */
-void Driver::setDeltaStarExt(size_t iSec, size_t iRegion, std::vector<double> _DeltaStarExt)
-{
-    if (_DeltaStarExt.size() != sections[iSec][iRegion]->mesh->getnMarkers())
-    {
-        std::cout << "size DeltaStar: " << _DeltaStarExt.size() << ". nMarkers: " << sections[iSec][iRegion]->mesh->getnMarkers() << std::endl;
-        throw std::runtime_error("blast::Driver External delta star vector is not coherent with the mesh.");
-    }
-    sections[iSec][iRegion]->blEdge->setDeltaStar(_DeltaStarExt);
-}
-
-/**
- * @brief Returns x coordinates of the nodes in the local frame of reference in the considered region.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @return std::vector<double>
- */
-std::vector<double> Driver::extractxCoord(size_t iSec, size_t iRegion) const
-{
-    std::vector<double> xCoord(sections[iSec][iRegion]->mesh->getnMarkers(), 0.);
-    for (size_t iPoint = 0; iPoint < xCoord.size(); ++iPoint)
-        xCoord[iPoint] = sections[iSec][iRegion]->mesh->getx(iPoint);
-    return xCoord;
-}
-
-/**
- * @brief Returns blowing velocities (defined on the cells' cg) in the considered region.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @return std::vector<double>
- */
-std::vector<double> Driver::extractBlowingVel(size_t iSec, size_t iRegion) const
-{
-    return sections[iSec][iRegion]->blowingVelocity;
-}
-std::vector<double> Driver::extractxx(size_t iSec, size_t iRegion) const
-{
-    std::vector<double> xx(sections[iSec][iRegion]->mesh->getnMarkers(), 0.);
-    for (size_t iPoint = 0; iPoint < xx.size(); ++iPoint)
-        xx[iPoint] = sections[iSec][iRegion]->mesh->getLoc(iPoint);
-    return xx;
-}
-
-/**
- * @brief Returns the displacement thickness in the considered region.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @return std::vector<double>
- */
-std::vector<double> Driver::extractDeltaStar(size_t iSec, size_t iRegion) const
-{
-    return sections[iSec][iRegion]->deltaStar;
-}
-
-/**
- * @brief Returns the velocity of the interaction law in the considered region.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @return std::vector<double>
- */
-std::vector<double> Driver::extractUe(size_t iSec, size_t iRegion) const
-{
-    std::vector<double> ueCurr(sections[iSec][iRegion]->mesh->getnMarkers(), 0.0);
-    for (size_t i = 0; i < ueCurr.size(); ++i)
-        ueCurr[i] = sections[iSec][iRegion]->u[i * sections[iSec][iRegion]->getnVar() + 3];
-    return ueCurr;
-}
-
-/**
- * @brief Set the velocity at the edge of the BL at the previous iteration in the considered region.
- *
- * @param iSec id of the considered section.
- * @param iRegion id of the considered region.
- * @param _ue Velocity vector.
- * @return std::vector<double>
- */
-void Driver::setUeOld(size_t iSec, size_t iRegion, std::vector<double> _ue)
-{
-    if (_ue.size() != sections[iSec][iRegion]->mesh->getnMarkers())
-        throw std::runtime_error("blast::Driver External velocity vector is not coherent with the mesh.");
-    sections[iSec][iRegion]->blEdge->setVtOld(_ue);
-}
-
 /**
  * @brief Returns the integral boundary layer solution in a section (sorted from upper Te to lower Te than wake).
  *
@@ -712,13 +505,13 @@ void Driver::setUeOld(size_t iSec, size_t iRegion, std::vector<double> _ue)
  */
 std::vector<std::vector<double>> Driver::getSolution(size_t iSec)
 {
-    size_t nMarkersUp = sections[iSec][0]->mesh->getnMarkers();
-    size_t nMarkersLw = sections[iSec][1]->mesh->getnMarkers(); // No stagnation point doublon.
+    size_t nMarkersUp = sections[iSec][0]->nNodes;
+    size_t nMarkersLw = sections[iSec][1]->nNodes; // No stagnation point doublon.
     size_t nVar = sections[iSec][0]->getnVar();
 
     std::vector<std::vector<double>> Sln(20);
     for (size_t iVector = 0; iVector < Sln.size(); ++iVector)
-        Sln[iVector].resize(nMarkersUp + nMarkersLw + sections[iSec][2]->mesh->getnMarkers(), 0.);
+        Sln[iVector].resize(nMarkersUp + nMarkersLw + sections[iSec][2]->nNodes, 0.);
     // Upper side.
     size_t revPoint = nMarkersUp - 1;
     for (size_t iPoint = 0; iPoint < nMarkersUp; ++iPoint)
@@ -740,15 +533,15 @@ std::vector<std::vector<double>> Driver::getSolution(size_t iSec)
         Sln[13][iPoint] = sections[iSec][0]->us[revPoint];
         Sln[14][iPoint] = sections[iSec][0]->delta[revPoint];
 
-        Sln[15][iPoint] = sections[iSec][0]->mesh->getx(revPoint);
-        Sln[16][iPoint] = sections[iSec][0]->mesh->getxoc(revPoint);
-        Sln[17][iPoint] = sections[iSec][0]->mesh->gety(revPoint);
-        Sln[18][iPoint] = sections[iSec][0]->mesh->getz(revPoint);
-        Sln[19][iPoint] = sections[iSec][0]->blEdge->getVt(revPoint);
+        Sln[15][iPoint] = sections[iSec][0]->x[revPoint];
+        Sln[16][iPoint] = sections[iSec][0]->xoc[revPoint];
+        Sln[17][iPoint] = sections[iSec][0]->y[revPoint];
+        Sln[18][iPoint] = sections[iSec][0]->z[revPoint];
+        Sln[19][iPoint] = sections[iSec][0]->vt[revPoint];
         --revPoint;
     }
     // Lower side.
-    for (size_t iPoint = 0; iPoint < sections[iSec][1]->mesh->getnMarkers(); ++iPoint)
+    for (size_t iPoint = 0; iPoint < sections[iSec][1]->nNodes; ++iPoint)
     {
         Sln[0][nMarkersUp + iPoint] = sections[iSec][1]->u[iPoint * nVar + 0];
         Sln[1][nMarkersUp + iPoint] = sections[iSec][1]->u[iPoint * nVar + 1];
@@ -767,14 +560,14 @@ std::vector<std::vector<double>> Driver::getSolution(size_t iSec)
         Sln[13][nMarkersUp + iPoint] = sections[iSec][1]->us[iPoint];
         Sln[14][nMarkersUp + iPoint] = sections[iSec][1]->delta[iPoint];
 
-        Sln[15][nMarkersUp + iPoint] = sections[iSec][1]->mesh->getx(iPoint);
-        Sln[16][nMarkersUp + iPoint] = sections[iSec][1]->mesh->getxoc(iPoint);
-        Sln[17][nMarkersUp + iPoint] = sections[iSec][1]->mesh->gety(iPoint);
-        Sln[18][nMarkersUp + iPoint] = sections[iSec][1]->mesh->getz(iPoint);
-        Sln[19][nMarkersUp + iPoint] = sections[iSec][1]->blEdge->getVt(iPoint);
+        Sln[15][nMarkersUp + iPoint] = sections[iSec][1]->x[iPoint];
+        Sln[16][nMarkersUp + iPoint] = sections[iSec][1]->xoc[iPoint];
+        Sln[17][nMarkersUp + iPoint] = sections[iSec][1]->y[iPoint];
+        Sln[18][nMarkersUp + iPoint] = sections[iSec][1]->z[iPoint];
+        Sln[19][nMarkersUp + iPoint] = sections[iSec][1]->vt[iPoint];
     }
     // Wake.
-    for (size_t iPoint = 0; iPoint < sections[iSec][2]->mesh->getnMarkers(); ++iPoint)
+    for (size_t iPoint = 0; iPoint < sections[iSec][2]->nNodes; ++iPoint)
     {
         Sln[0][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->u[iPoint * nVar + 0];
         Sln[1][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->u[iPoint * nVar + 1];
@@ -793,11 +586,11 @@ std::vector<std::vector<double>> Driver::getSolution(size_t iSec)
         Sln[13][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->us[iPoint];
         Sln[14][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->delta[iPoint];
 
-        Sln[15][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->mesh->getx(iPoint);
-        Sln[16][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->mesh->getxoc(iPoint);
-        Sln[17][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->mesh->gety(iPoint);
-        Sln[18][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->mesh->getz(iPoint);
-        Sln[19][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->blEdge->getVt(iPoint);
+        Sln[15][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->x[iPoint];
+        Sln[16][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->xoc[iPoint];
+        Sln[17][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->y[iPoint];
+        Sln[18][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->z[iPoint];
+        Sln[19][nMarkersUp + nMarkersLw + iPoint] = sections[iSec][2]->vt[iPoint];
     }
 
     if (verbose > 2)
diff --git a/blast/src/DDriver.h b/blast/src/DDriver.h
index 2937d3d..ed598aa 100644
--- a/blast/src/DDriver.h
+++ b/blast/src/DDriver.h
@@ -28,7 +28,6 @@ private:
     double Re;                                                       ///< Freestream Reynolds number.
     double CFL0;                                                     ///< Initial CFL number for pseudo time integration.
     double span;                                                     ///< Wing Span (Used only for drag computation, not used if 2D case).
-    std::vector<bool> stagPtMvmt;                                    ///< Flag to account for stagnation point movements.
     Solver *tSolver;                                                 ///< Pseudo-time solver.
     int solverExitCode;                                              ///< Exit code of viscous calculations.
     std::vector<std::vector<std::vector<size_t>>> convergenceStatus; ///< Vector containing points that did not converged.
@@ -40,34 +39,19 @@ public:
     Driver(double _Re, double _Minf, double _CFL0, size_t nSections,
            double xtrF_top=-1., double xtrF_bot=-1.,  double _span = 0., unsigned int _verbose = 1);
     ~Driver();
-    int run(unsigned int const couplIter);
+    int run();
+    void reset();
 
     // Getters.
-    double getxtr(size_t iSec, size_t iRegion) const { return sections[iSec][iRegion]->xtr; };
-    double getxoctr(size_t iSec, size_t iRegion) const { return sections[iSec][iRegion]->xoctr; };
-    double getAvrgxoctr(size_t const iRegion) const;
+    double getAverageTransition(size_t const iRegion) const;
     double getRe() const { return Re; };
     std::vector<std::vector<double>> getSolution(size_t iSec);
 
-    // Setters.
-    void setGlobMesh(size_t iSec, size_t iRegion, std::vector<double> _x, std::vector<double> _y, std::vector<double> _z);
-    void setVelocities(size_t iSec, size_t iRegion, std::vector<double> _vx, std::vector<double> _vy, std::vector<double> _vz);
-    void setMe(size_t iSec, size_t iRegion, std::vector<double> _Me);
-    void setRhoe(size_t iSec, size_t iRegion, std::vector<double> _rhoe);
-    void setxxExt(size_t iSec, size_t iRegion, std::vector<double> _xxExt);
-    void setDeltaStarExt(size_t iSec, size_t iRegion, std::vector<double> _deltaStarExt);
-    void setUeOld(size_t iSec, size_t iRegion, std::vector<double> _ue);
-
-    // Extractors.
-    std::vector<double> extractBlowingVel(size_t iSec, size_t iRegion) const;
-    std::vector<double> extractxx(size_t iSec, size_t iRegion) const;
-    std::vector<double> extractDeltaStar(size_t iSec, size_t iRegion) const;
-    std::vector<double> extractxCoord(size_t iSec, size_t iRegion) const;
-    std::vector<double> extractUe(size_t iSec, size_t iRegion) const;
+    void addSection(size_t iSec, BoundaryLayer * &bl){sections[iSec].push_back(bl);};
 
 private:
     void checkWaves(size_t iPoint, BoundaryLayer *bl);
-    void averageTransition(size_t iPoint, BoundaryLayer *bl, int forced);
+    void averageTransition(size_t iPoint, BoundaryLayer *bl, bool forced);
     void computeSectionalDrag(std::vector<BoundaryLayer *> const &bl, size_t i);
     void computeTotalDrag();
     void computeBlwVel();
diff --git a/blast/src/DEdge.cpp b/blast/src/DEdge.cpp
deleted file mode 100644
index 762d63c..0000000
--- a/blast/src/DEdge.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#include "DEdge.h"
-
-using namespace blast;
-
-/**
- * @brief Construct a new Edge::Edge object.
- *
- */
-Edge::Edge()
-{
-    Me.resize(0, 0.);
-    vt.resize(0, 0.);
-    rhoe.resize(0, 0.);
-    deltaStar.resize(0, 0.);
-    vtOld.resize(0, 0.);
-}
-
-/**
- * @brief Return the maximum inviscid Mach number in the region.
- *
- * @return double
- */
-double Edge::getMaxMach() const
-{
-    if (Me.size() <= 0)
-        throw std::runtime_error("blast::Edge Invalid Mach number vector.");
-    double Mmax = 0.0;
-    for (size_t i = 0; i < Me.size(); ++i)
-        if (Me[i] > Mmax)
-            Mmax = Me[i];
-    return Mmax;
-}
-
-// Setters.
-void Edge::setMe(std::vector<double> const _Me)
-{
-    Me.resize(_Me.size(), 0.);
-    Me = _Me;
-}
-void Edge::setVt(std::vector<double> const _vt)
-{
-    vt.resize(_vt.size(), 0.);
-    vt = _vt;
-}
-void Edge::setRhoe(std::vector<double> const _rhoe)
-{
-    rhoe.resize(_rhoe.size(), 0.);
-    rhoe = _rhoe;
-}
-void Edge::setDeltaStar(std::vector<double> const _deltaStar)
-{
-    deltaStar.resize(_deltaStar.size(), 0.);
-    deltaStar = _deltaStar;
-}
-void Edge::setVtOld(std::vector<double> const _vtOld)
-{
-    vtOld.resize(_vtOld.size(), 0.);
-    vtOld = _vtOld;
-}
diff --git a/blast/src/DEdge.h b/blast/src/DEdge.h
deleted file mode 100644
index 0833564..0000000
--- a/blast/src/DEdge.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef DEDGE_H
-#define DEDGE_H
-
-#include "blast.h"
-#include <vector>
-#include <iostream>
-
-namespace blast
-{
-
-/**
- * @brief Inviscid quantities at the edge of the boundary layer of a BoundaryLayer region.
- * @author Paul Dechamps
- */
-class BLAST_API Edge
-{
-private:
-    std::vector<double> Me;        ///< Mach number.
-    std::vector<double> vt;        ///< Velocity.
-    std::vector<double> rhoe;      ///< Density.
-    std::vector<double> deltaStar; ///< Displacement thickness.
-    std::vector<double> vtOld;     ///< Previous velocity.
-
-public:
-    Edge();
-    ~Edge(){};
-
-    // Getters.
-    double getMe(size_t iPoint) const { return Me[iPoint]; };
-    double getVt(size_t iPoint) const { return vt[iPoint]; };
-    double getRhoe(size_t iPoint) const { return rhoe[iPoint]; };
-    double getDeltaStar(size_t iPoint) const { return deltaStar[iPoint]; };
-    double getVtOld(size_t iPoint) const { return vtOld[iPoint]; };
-    double getMaxMach() const;
-
-    // Setters.
-    void setMe(std::vector<double> const _Me);
-    void setVt(std::vector<double> const _vt);
-    void setRhoe(std::vector<double> const _rhoe);
-    void setDeltaStar(std::vector<double> const _deltaStar);
-    void setVtOld(std::vector<double> const _vtOld);
-};
-} // namespace blast
-#endif // DEDGE_H
diff --git a/blast/src/DFluxes.cpp b/blast/src/DFluxes.cpp
index c3beca0..3cf81cc 100644
--- a/blast/src/DFluxes.cpp
+++ b/blast/src/DFluxes.cpp
@@ -79,7 +79,7 @@ VectorXd Fluxes::blLaws(size_t iPoint, BoundaryLayer *bl, std::vector<double> u)
     {
         // Laminar closure relations.
         std::vector<double> lamParam(8, 0.);
-        bl->closSolver->laminarClosures(lamParam, u[0], u[1], bl->Ret[iPoint], bl->blEdge->getMe(iPoint), bl->name);
+        bl->closSolver->laminarClosures(lamParam, u[0], u[1], bl->Ret[iPoint], bl->Me[iPoint], bl->name);
         bl->Hstar[iPoint] = lamParam[0];
         bl->Hstar2[iPoint] = lamParam[1];
         bl->Hk[iPoint] = lamParam[2];
@@ -94,7 +94,7 @@ VectorXd Fluxes::blLaws(size_t iPoint, BoundaryLayer *bl, std::vector<double> u)
     {
         // Turbulent closure relations.
         std::vector<double> turbParam(8, 0.);
-        bl->closSolver->turbulentClosures(turbParam, u[0], u[1], u[4], bl->Ret[iPoint], bl->blEdge->getMe(iPoint), bl->name);
+        bl->closSolver->turbulentClosures(turbParam, u[0], u[1], u[4], bl->Ret[iPoint], bl->Me[iPoint], bl->name);
         bl->Hstar[iPoint] = turbParam[0];
         bl->Hstar2[iPoint] = turbParam[1];
         bl->Hk[iPoint] = turbParam[2];
@@ -112,16 +112,16 @@ VectorXd Fluxes::blLaws(size_t iPoint, BoundaryLayer *bl, std::vector<double> u)
     }
 
     // Gradients computation.
-    double dx = (bl->mesh->getLoc(iPoint) - bl->mesh->getLoc(iPoint - 1));
-    double dxExt = (bl->mesh->getExt(iPoint) - bl->mesh->getExt(iPoint - 1));
+    double dx = (bl->loc[iPoint] - bl->loc[iPoint-1]);
+    double dxExt = (bl->xxExt[iPoint] - bl->xxExt[iPoint-1]);
     double dt_dx = (u[0] - bl->u[(iPoint - 1) * nVar + 0]) / dx;
     double dH_dx = (u[1] - bl->u[(iPoint - 1) * nVar + 1]) / dx;
     double due_dx = (u[3] - bl->u[(iPoint - 1) * nVar + 3]) / dx;
     double dct_dx = (u[4] - bl->u[(iPoint - 1) * nVar + 4]) / dx;
     double dHstar_dx = (bl->Hstar[iPoint] - bl->Hstar[iPoint - 1]) / dx;
 
-    double dueExt_dx = (bl->blEdge->getVt(iPoint) - bl->blEdge->getVt(iPoint - 1)) / dxExt;
-    double ddeltaStarExt_dx = (bl->blEdge->getDeltaStar(iPoint) - bl->blEdge->getDeltaStar(iPoint - 1)) / dxExt;
+    double dueExt_dx = (bl->vt[iPoint] - bl->vt[iPoint-1]) / dxExt;
+    double ddeltaStarExt_dx = (bl->deltaStarExt[iPoint] - bl->deltaStarExt[iPoint-1]) / dxExt;
 
     double c = 4 / (M_PI * dx);
     double cExt = 4 / (M_PI * dxExt);
@@ -136,7 +136,7 @@ VectorXd Fluxes::blLaws(size_t iPoint, BoundaryLayer *bl, std::vector<double> u)
         dN_dx = (u[2] - bl->u[(iPoint - 1) * nVar + 2]) / dx;
     }
 
-    double Mea = bl->blEdge->getMe(iPoint);
+    double Mea = bl->Me[iPoint];
     double Hstara = bl->Hstar[iPoint];
     double Hstar2a = bl->Hstar2[iPoint];
     double Hka = bl->Hk[iPoint];
diff --git a/blast/src/DSolver.cpp b/blast/src/DSolver.cpp
index fc3b94d..541a799 100644
--- a/blast/src/DSolver.cpp
+++ b/blast/src/DSolver.cpp
@@ -2,6 +2,7 @@
 #include "DBoundaryLayer.h"
 #include "DFluxes.h"
 #include <Eigen/Dense>
+#include <iostream>
 
 using namespace Eigen;
 using namespace tbox;
@@ -24,7 +25,6 @@ Solver::Solver(double _CFL0, double _Minf, double Re, unsigned int _maxIt, doubl
     tol = _tol;
     itFrozenJac0 = _itFrozenJac;
     Minf = std::max(_Minf, 0.1);
-    initSln = true;
     sysMatrix = new Fluxes(Re);
 }
 
@@ -47,25 +47,20 @@ Solver::~Solver()
 void Solver::initialCondition(size_t iPoint, BoundaryLayer *bl)
 {
     size_t nVar = bl->getnVar();
-    if (initSln)
-    {
-        bl->u[iPoint * nVar + 0] = bl->u[(iPoint - 1) * nVar + 0];
-        bl->u[iPoint * nVar + 1] = bl->u[(iPoint - 1) * nVar + 1];
-        bl->u[iPoint * nVar + 2] = bl->u[(iPoint - 1) * nVar + 2];
-        bl->u[iPoint * nVar + 3] = bl->blEdge->getVt(iPoint);
-        bl->u[iPoint * nVar + 4] = bl->u[(iPoint - 1) * nVar + 4];
-
-        bl->Ret[iPoint] = bl->Ret[iPoint - 1];
-        bl->cd[iPoint] = bl->cd[iPoint - 1];
-        bl->cf[iPoint] = bl->cf[iPoint - 1];
-        bl->Hstar[iPoint] = bl->Hstar[iPoint - 1];
-        bl->Hstar2[iPoint] = bl->Hstar2[iPoint - 1];
-        bl->Hk[iPoint] = bl->Hk[iPoint - 1];
-        bl->ctEq[iPoint] = bl->ctEq[iPoint - 1];
-        bl->us[iPoint] = bl->us[iPoint - 1];
-        bl->delta[iPoint] = bl->delta[iPoint - 1];
-        bl->deltaStar[iPoint] = bl->deltaStar[iPoint - 1];
-    }
+    for (auto k = 0; k < nVar; ++k)
+        bl->u[iPoint * nVar + k] = bl->u[(iPoint - 1) * nVar + k];
+    bl->u[iPoint * nVar + 3] = bl->vt[iPoint];
+
+    bl->Ret[iPoint] = bl->Ret[iPoint - 1];
+    bl->cd[iPoint] = bl->cd[iPoint - 1];
+    bl->cf[iPoint] = bl->cf[iPoint - 1];
+    bl->Hstar[iPoint] = bl->Hstar[iPoint - 1];
+    bl->Hstar2[iPoint] = bl->Hstar2[iPoint - 1];
+    bl->Hk[iPoint] = bl->Hk[iPoint - 1];
+    bl->ctEq[iPoint] = bl->ctEq[iPoint - 1];
+    bl->us[iPoint] = bl->us[iPoint - 1];
+    bl->delta[iPoint] = bl->delta[iPoint - 1];
+    bl->deltaStar[iPoint] = bl->deltaStar[iPoint - 1];
     if (bl->regime[iPoint] == 1 && bl->u[iPoint * nVar + 4] <= 0)
         bl->u[iPoint * nVar + 4] = 0.03;
 }
@@ -87,12 +82,12 @@ int Solver::integration(size_t iPoint, BoundaryLayer *bl)
         sln0[i] = bl->u[iPoint * nVar + i];
 
     // Initialize time integration variables.
-    double dx = bl->mesh->getLoc(iPoint) - bl->mesh->getLoc(iPoint - 1);
+    double dx = bl->loc[iPoint] - bl->loc[iPoint-1];
 
     // Initial time step.
     double CFL = CFL0;
     unsigned int itFrozenJac = itFrozenJac0;
-    double timeStep = setTimeStep(CFL, dx, bl->blEdge->getVt(iPoint));
+    double timeStep = setTimeStep(CFL, dx, bl->vt[iPoint]);
     MatrixXd IMatrix(5, 5);
     IMatrix = MatrixXd::Identity(5, 5) / timeStep;
 
@@ -124,23 +119,12 @@ int Solver::integration(size_t iPoint, BoundaryLayer *bl)
         sysRes = sysMatrix->computeResiduals(iPoint, bl);
         normSysRes = (sysRes + slnIncr / timeStep).norm();
 
-        if (std::isnan(normSysRes))
-        {
-            resetSolution(iPoint, bl, sln0, true);
-            sysRes = sysMatrix->computeResiduals(iPoint, bl);
-            CFL = 1.0;
-            timeStep = setTimeStep(CFL, dx, bl->blEdge->getVt(iPoint));
-            IMatrix = MatrixXd::Identity(5, 5) / timeStep;
-            normSysRes = (sysRes + slnIncr / timeStep).norm();
-            itFrozenJac = 1;
-        }
-
         if (normSysRes <= tol * normSysRes0)
             return 0; // Successfull exit.
 
         // CFL adaptation.
         CFL = std::max(CFL0 * pow(normSysRes0 / normSysRes, 0.7), 0.1);
-        timeStep = setTimeStep(CFL, dx, bl->blEdge->getVt(iPoint));
+        timeStep = setTimeStep(CFL, dx, bl->vt[iPoint]);
         IMatrix = MatrixXd::Identity(5, 5) / timeStep;
 
         innerIters++;
@@ -213,7 +197,7 @@ void Solver::resetSolution(size_t iPoint, BoundaryLayer *bl, std::vector<double>
     if (bl->regime[iPoint] == 0)
     {
         std::vector<double> lamParam(8, 0.);
-        bl->closSolver->laminarClosures(lamParam, bl->u[iPoint * nVar + 0], bl->u[iPoint * nVar + 1], bl->Ret[iPoint], bl->blEdge->getMe(iPoint), bl->name);
+        bl->closSolver->laminarClosures(lamParam, bl->u[iPoint * nVar + 0], bl->u[iPoint * nVar + 1], bl->Ret[iPoint], bl->Me[iPoint], bl->name);
         bl->Hstar[iPoint] = lamParam[0];
         bl->Hstar2[iPoint] = lamParam[1];
         bl->Hk[iPoint] = lamParam[2];
@@ -226,7 +210,7 @@ void Solver::resetSolution(size_t iPoint, BoundaryLayer *bl, std::vector<double>
     else if (bl->regime[iPoint] == 1)
     {
         std::vector<double> turbParam(8, 0.);
-        bl->closSolver->turbulentClosures(turbParam, bl->u[iPoint * nVar + 0], bl->u[iPoint * nVar + 1], bl->u[iPoint * nVar + 4], bl->Ret[iPoint], bl->blEdge->getMe(iPoint), bl->name);
+        bl->closSolver->turbulentClosures(turbParam, bl->u[iPoint * nVar + 0], bl->u[iPoint * nVar + 1], bl->u[iPoint * nVar + 4], bl->Ret[iPoint], bl->Me[iPoint], bl->name);
         bl->Hstar[iPoint] = turbParam[0];
         bl->Hstar2[iPoint] = turbParam[1];
         bl->Hk[iPoint] = turbParam[2];
diff --git a/blast/src/DSolver.h b/blast/src/DSolver.h
index f6ce735..16c73ba 100644
--- a/blast/src/DSolver.h
+++ b/blast/src/DSolver.h
@@ -19,7 +19,6 @@ private:
     unsigned int maxIt;        ///< Maximum number of iterations.
     double tol;                ///< Convergence tolerance.
     unsigned int itFrozenJac0; ///< Number of iterations between which the Jacobian is frozen.
-    bool initSln;              ///< Flag to initialize the solution at the point.
     double const gamma = 1.4;  ///< Air heat capacity ratio.
     double Minf;               ///< Freestream Mach number.
 
@@ -40,7 +39,6 @@ public:
     void setCFL0(double _CFL0);
     void setmaxIt(unsigned int _maxIt) { maxIt = _maxIt; };
     void setitFrozenJac(unsigned int _itFrozenJac) { itFrozenJac0 = _itFrozenJac; };
-    void setinitSln(bool _initSln) { initSln = _initSln; };
 
 private:
     double setTimeStep(double CFL, double dx, double invVel) const;
diff --git a/blast/src/blast.h b/blast/src/blast.h
index 71cdab8..382e040 100644
--- a/blast/src/blast.h
+++ b/blast/src/blast.h
@@ -43,8 +43,6 @@ class Solver;
 
 // Data structures
 class BoundaryLayer;
-class Discretization;
-class Edge;
 
 // Other
 class Closures;
diff --git a/blast/tests/dart/naca0012_2D.py b/blast/tests/dart/naca0012_2D.py
index 4bdfc11..361b760 100644
--- a/blast/tests/dart/naca0012_2D.py
+++ b/blast/tests/dart/naca0012_2D.py
@@ -55,7 +55,7 @@ def cfgInviscid(nthrds, verb):
     'Verb' : verb, # verbosity
     # Model (geometry or mesh)
     'File' : os.path.dirname(os.path.abspath(__file__)) + '/../../models/dart/n0012.geo', # Input file containing the model
-    'Pars' : {'xLgt' : 5, 'yLgt' : 5, 'msF' : 1, 'msTe' : 0.01, 'msLe' : 0.001}, # parameters for input file model
+    'Pars' : {'xLgt' : 50, 'yLgt' : 50, 'msF' : 8.33, 'msTe' : 0.01, 'msLe' : 0.001}, # parameters for input file model
     'Dim' : 2, # problem dimension
     'Format' : 'gmsh', # save format (vtk or gmsh)
     # Markers
@@ -92,14 +92,13 @@ def cfgBlast(verb):
         'Minf' : 0.2,     # Freestream Mach number (used for the computation of the time step only)
         'CFL0' : 1,         # Inital CFL number of the calculation
         'Verb': verb,       # Verbosity level of the solver
-        'couplIter': 25,    # Maximum number of iterations
+        'couplIter': 50,    # Maximum number of iterations
         'couplTol' : 1e-4,  # Tolerance of the VII methodology
         'iterPrint': 5,     # int, number of iterations between outputs
         'resetInv' : True,  # bool, flag to reset the inviscid calculation at every iteration.
         'sections' : [0],
         'xtrF' : [None, 0.4],# Forced transition location
-        'interpolator' : 'Matching',
-        'nDim' : 2
+        'interpolator' : 'Matching'
     }
 
 def main():
@@ -112,7 +111,7 @@ def main():
     vcfg = cfgBlast(args.verb)
 
     tms['pre'].start()
-    coupler, iSolverAPI, vSolver = viscUtils.initBlast(icfg, vcfg)
+    coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
     tms['pre'].stop()
 
     print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
@@ -123,11 +122,10 @@ 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, iSolverAPI.getMinf(), iSolverAPI.getAoA()*180/math.pi, iSolverAPI.getCl(), vSolver.Cdt, vSolver.Cdp, vSolver.Cdf, iSolverAPI.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.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
 
      # Write results to file.
-    vSolution = viscUtils.getSolution(vSolver)
-    vSolution['Cdt_int'] = vSolution['Cdf'] + iSolverAPI.getCd()
+    vSolution = viscUtils.getSolution(isol.sec, write=True, toW='all')
     tms['total'].stop()
 
     print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
@@ -139,13 +137,13 @@ def main():
     # Test solution
     print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET)
     tests = CTests()
-    tests.add(CTest('Cl', iSolverAPI.getCl(), 0.230, 5e-2)) # XFOIL 0.2325
-    tests.add(CTest('Cd wake', vSolution['Cdt_w'], 0.0056, 1e-3, forceabs=True)) # XFOIL 0.00531
-    tests.add(CTest('Cd integral', vSolution['Cdt_int'], 0.0059, 1e-3, forceabs=True)) # XFOIL 0.00531
-    tests.add(CTest('Cdf', vSolution['Cdf'], 0.00465, 1e-3, forceabs=True)) # XFOIL 0.00084, Cdf = 0.00447
-    tests.add(CTest('xtr_top', vSolution['xtrT'], 0.20, 0.03, forceabs=True)) # XFOIL 0.1877
-    tests.add(CTest('xtr_bot', vSolution['xtrB'], 0.40, 0.01, forceabs=True)) # XFOIL 0.4998
-    tests.add(CTest('Iterations', len(aeroCoeffs), 17, 0, forceabs=True))
+    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('xtr_top', vsol.getAverageTransition(0), 0.196, 0.03, forceabs=True)) # XFOIL 0.1877
+    tests.add(CTest('xtr_bot', vsol.getAverageTransition(1), 0.40, 0.01, forceabs=True)) # XFOIL 0.4998
+    tests.add(CTest('Iterations', len(aeroCoeffs['Cl']), 19, 0, forceabs=True))
     tests.run()
 
     # Show results
@@ -158,7 +156,7 @@ def main():
                             np.column_stack((xfoilCp[:,0], xfoilCp[:,1])),
                             np.column_stack((iCp[:,0], iCp[:,3])),
                             np.column_stack((xfoilCpInv[:,0], xfoilCpInv[:,1]))],
-                    'labels': ['Blast (VII)', 'XFOIL VII', 'DART (inviscid)', 'XFOIL (inviscid)'],
+                    'labels': ['Blaster (VII)', 'XFOIL (VII)', 'DART (inviscid)', 'XFOIL (inviscid)'],
                     'lw': [3, 3, 2, 2],
                     'color': ['firebrick', 'darkblue', 'firebrick', 'darkblue'],
                     'ls': ['-', '-', '--', '--'],
@@ -172,9 +170,9 @@ def main():
         viscUtils.plot(plotcp)
 
         xfoilBl = viscUtils.read('../../blast/models/references/blXfoil_n0012.dat', delim=None, skip = 1)
-        plotcf = {'curves': [np.column_stack((vSolution['x'], vSolution['Cf'])),
+        plotcf = {'curves': [np.column_stack((vSolution[0]['x'], vSolution[0]['cf']*vSolution[0]['ue']*vSolution[0]['ue'])),
                             np.column_stack((xfoilBl[:,1], xfoilBl[:,6]))],
-                'labels': ['Blast', 'XFOIL'],
+                'labels': ['Blaster', 'XFOIL'],
                 'lw': [3, 3],
                 'color': ['firebrick', 'darkblue'],
                 'ls': ['-', '-'],
diff --git a/blast/tests/dart/rae2822_3D.py b/blast/tests/dart/rae2822_3D.py
index 92add20..3e3a32f 100644
--- a/blast/tests/dart/rae2822_3D.py
+++ b/blast/tests/dart/rae2822_3D.py
@@ -93,7 +93,7 @@ def cfgBlast(verb):
         'Minf' : 0.8,     # Freestream Mach number (used for the computation of the time step only)
         'CFL0' : 1,       # Inital CFL number of the calculation
 
-        'sections' : np.linspace(0.01, 0.95, 30),
+        'sections' : np.linspace(0.01, 0.95, 3),
         'writeSections': [0.2, 0.4, 0.6, 0.8, 1.0],
         'Sym':[0.],
         'span': 1.,
@@ -105,7 +105,7 @@ def cfgBlast(verb):
         'saveTag': 4,
 
         'Verb': verb,       # Verbosity level of the solver
-        'couplIter': 50,    # Maximum number of iterations
+        'couplIter': 5,    # Maximum number of iterations
         'couplTol' : 5e-2,  # Tolerance of the VII methodology
         'iterPrint': 1,     # int, number of iterations between outputs
         'resetInv' : False, # bool, flag to reset the inviscid calculation at every iteration.
@@ -131,7 +131,7 @@ def main():
     vcfg['vMsh'] = vMsh
 
     tms['pre'].start()
-    coupler, iSolverAPI, vSolver = viscUtils.initBlast(icfg, vcfg)
+    coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
     tms['pre'].stop()
 
     print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
@@ -142,19 +142,13 @@ 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, iSolverAPI.getMinf(), iSolverAPI.getAoA()*180/math.pi, iSolverAPI.getCl(), vSolver.Cdf + iSolverAPI.getCd(), vSolver.Cdt, vSolver.Cdp, vSolver.Cdf, iSolverAPI.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.Cdf + isol.getCd(), vsol.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
 
      # Write results to file.
-    vSolution = viscUtils.getSolution(vSolver)
+    vSolution = viscUtils.getSolution(isol.sec, write=True, toW='all')
 
-    # Write results to file.
-    for iSec in range(len(iSolverAPI.cfg['EffSections'])):
-        vSolution = viscUtils.getSolution(vSolver, iSec)
-        viscUtils.write(vSolution, vSolver.getRe(), sfx='slice'+str(iSec))
-    vSolution['Cdt_int'] = vSolver.Cdf + iSolverAPI.getCd()
-
-    # Save pressure coefficient
-    iSolverAPI.save(sfx='_viscous')
+    # Save results
+    isol.save(sfx='_viscous')
     tms['total'].stop()
 
     print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
@@ -166,9 +160,11 @@ def main():
     # Test solution
     print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET)
     tests = CTests()
-    tests.add(CTest('Cl', iSolverAPI.getCl(), 0.128, 5e-2))
-    tests.add(CTest('Cd wake', vSolution['Cdt_int'], 0.0132, 1e-3, forceabs=True))
-    tests.add(CTest('Iterations', len(aeroCoeffs), 5, 0, forceabs=True))
+    tests.add(CTest('Cl', isol.getCl(), 0.135, 5e-2))
+    tests.add(CTest('Cd wake', vsol.Cdt, 0.0074, 1e-3, forceabs=True))
+    tests.add(CTest('Cd integral', vsol.Cdf + isol.getCd(), 0.0140, 1e-3, forceabs=True))
+    tests.add(CTest('Cdf', vsol.Cdf, 0.0061, 1e-3, forceabs=True))
+    tests.add(CTest('Iterations', len(aeroCoeffs), 3, 0, forceabs=True))
     tests.run()
 
     # eof
diff --git a/blast/utils.py b/blast/utils.py
index 91a0aa4..b32492a 100644
--- a/blast/utils.py
+++ b/blast/utils.py
@@ -101,77 +101,109 @@ def mesh(file, pars):
     return msh
 
 
-def getSolution(vSolver, iSec=0):
-    """Extract viscous solution.
-    Args
-    ----
-    - vSolver: blast::Driver class. Driver of the viscous calculations
-    - iSec (int): Marker of the section (default: 0)
-    """
-    if iSec<0:
-        raise RuntimeError("blast::viscU Invalid section number", iSec)
+def getSolution(sections, write=False, toW=['x', 'xelm', 'theta', 'H', 'deltaStar', 'Cf', 'blowingVelocity'], sfx=''):
+    """ Extract viscous solution.
+    
+    Parameters
+    ----------
+    
+        - sections: list of blast::BoundaryLayer class. Sections of the boundary layer solver.
+        - write: bool. Flag to write the results in a file.
+        - sfx: str. Suffix to add to the file name.
     
-    solverOutput = vSolver.getSolution(iSec)
-
-    sln = { 'theta'    : solverOutput[0],
-            'H'        : solverOutput[1],
-            'N'        : solverOutput[2],
-            'ue'       : solverOutput[3],
-            'Ct'       : solverOutput[4],
-            'deltaStar': solverOutput[5],
-            'Ret'      : solverOutput[6],
-            'Cd'       : solverOutput[7],
-            'Cf'       : np.asarray(solverOutput[8])*np.asarray(solverOutput[3])**2,
-            'Hstar'    : solverOutput[9],
-            'Hstar2'   : solverOutput[10],
-            'Hk'       : solverOutput[11],
-            'Cteq'     : solverOutput[12],
-            'Us'       : solverOutput[13],
-            'delta'    : solverOutput[14],
-            'x'        : solverOutput[15],
-            'xoc'      : solverOutput[16],
-            'y'        : solverOutput[17],
-            'z'        : solverOutput[18],
-            'ueInv'    : solverOutput[19],
-            'xtrT'     : vSolver.getAvrgxoctr(0),
-            'xtrB'     : vSolver.getAvrgxoctr(1),
-            'Cdt_w'    : vSolver.Cdt_sec[iSec],
-            'Cdf'      : vSolver.Cdf_sec[iSec],
-            'Cdp'      : vSolver.Cdp_sec[iSec]
-            }
-    return sln
-
-def write(wData, Re, toW=['deltaStar', 'H', 'Hstar', 'Cf', 'Ct', 'ue', 'ueInv', 'delta'], sfx=''):
-    """Write the results in bl files
+    Return
+    ------
+    
+        - sol: list[dicts]. Dictionary containing the boundary layer solution.
     """
-    import os
-    if not os.path.exists('blSlices'):
-        os.makedirs('blSlices')
-    # Write
-    print('Writing file: /blSlices/bl'+sfx+'.dat...', end = '')
-    f = open('blSlices/bl'+sfx+'.dat', 'w+')
-
-    f.write('$Sectional aerodynamic coefficients\n')
-    f.write('             Re             Cdw             Cdp             Cdf         xtr_top         xtr_bot\n')
-    f.write('{0:15.6f} {1:15.6f} {2:15.6f} {3:15.6f} {4:15.6f} {5:15.6f}\n'.format(Re, wData['Cdt_w'], wData['Cdp'],
-                                                                                   wData['Cdf'], wData['xtrT'],
-                                                                                   wData['xtrB']))
-    f.write('$Boundary layer variables\n')
-    f.write('{0:>15s} {1:>15s} {2:>15s} {3:>15s}'.format('x','y', 'z', 'xoc'))
-
-
-    for s in toW:
-        f.write(' {0:>15s}'.format(s))
-    f.write('\n')
-
-    for i in range(len(wData['x'])):
-        f.write('{0:>15.6f} {1:>15.6f} {2:>15.6f} {3:>15.6f}'.format(wData['x'][i], wData['y'][i], wData['z'][i], (wData['x'][i] - min(wData['x'])) / (max(wData['x']) - min(wData['x']))))
-        for s in toW:
-            f.write(' {0:15.6f}'.format(wData[s][i]))
-        f.write('\n')
-
-    f.close()
-    print('done.')
+
+    nVar = sections[0][0].getnVar()
+    sol = []
+
+    varKeys = ['theta', 'H', 'N', 'ue', 'Ct']
+    attrKeys = ['x', 'y', 'z', 'xoc', 'deltaStar', \
+               'cd', 'cf', 'Hstar', 'Hstar2', 'Hk', 'ctEq', 'us', 'delta',\
+                'vt', 'Ret']
+    elemsKeys = ['xelm', 'yelm', 'zelm']
+
+    for iSec, sec in enumerate(sections):
+        nNodes = 0
+        for side in sec:
+            nNodes += len(side.x)
+        
+        sol.append({})
+
+        for key in elemsKeys:
+            sol[iSec][key] = np.zeros(nNodes-len(sec))
+        for key in varKeys + attrKeys:
+            sol[iSec][key] = np.zeros(nNodes)
+
+        for side in sec:
+            nNodes_side = side.nNodes
+            if side.name == "upper":
+                for key in attrKeys:
+                    sol[iSec][key][:nNodes_side] = np.flip(getattr(side, key))
+                for k, key in enumerate(varKeys):
+                    sol[iSec][key][:nNodes_side] = np.flip(side.u[k::nVar])
+            else:
+                if side.name == "lower":
+                    slicer = np.s_[sec[0].x.size():sec[0].x.size()+sec[1].x.size()]
+                elif side.name == "wake":
+                    slicer = np.s_[sec[0].x.size()+sec[1].x.size():]
+
+                for key in attrKeys:
+                    sol[iSec][key][slicer] = getattr(side, key)
+                for k, key in enumerate(varKeys):
+                    sol[iSec][key][slicer] = side.u[k::nVar]
+        
+            # Compute elements cgs
+            elemsCoord = np.zeros((nNodes_side-1, 3))
+            for k, key in enumerate(elemsKeys):
+                elemsCoord[:,k] = 0.5 * (np.array(getattr(side, key[0]))[1:] + np.array(getattr(side, key[0]))[:-1])
+            if side.name == "upper":
+                for k, key in enumerate(elemsKeys):
+                    sol[iSec][key][:nNodes_side-1] = np.flip(elemsCoord[:,k])
+            else:
+                if side.name == "lower":
+                    slicer = np.s_[(sec[0].x.size()-1):(sec[0].x.size()-1)+(sec[1].x.size()-1)]
+                elif side.name == "wake":
+                    slicer = np.s_[(sec[0].x.size()-1)+(sec[1].x.size()-1):]
+                for k, key in enumerate(elemsKeys):
+                    sol[iSec][key][slicer] = elemsCoord[:,k]
+        sol[iSec]['blowingVelocity'] = np.concatenate((np.flip(sec[0].blowingVelocity),\
+                                                       sec[1].blowingVelocity, sec[2].blowingVelocity))
+
+    if write:
+        import datetime
+        if toW == 'all':
+            toW = varKeys + attrKeys
+        import os
+        if not os.path.exists('blSlices'):
+            os.makedirs('blSlices')
+        print('Writing file: /blSlices/bl'+sfx+'.dat...', end = '')
+        for iSec, sec in enumerate(sections):
+            f = open('blSlices/bl'+str(iSec)+sfx+'.dat', 'w+')
+            f.write('# BLASTER boundary layer output file\n')
+            f.write('# Generated on '+datetime.datetime.now().strftime('%Y-%m-%d %H:%M')+'\n')
+            f.write('\n')
+            f.write('# Section '+str(iSec)+'\n')
+            f.write('# ')
+            for side in sec:
+                f.write('xtr_'+side.name+' = '+str(round(side.xtr,6))+' ')
+            f.write('\n')
+            f.write('# Stagnation point at index '+str(sec[0].x.size()-1)+'\n')
+            f.write('# Wake at index '+str(sec[0].x.size()+sec[1].x.size())+'\n')
+        
+            for key in toW:
+                f.write(' {0:>21s}'.format(key))
+            f.write('\n')
+            for i in range(len(sol[iSec]['x'])):
+                for key in toW:
+                    f.write(' {0:21.16f}'.format(sol[iSec][key][i]))
+                f.write('\n')
+            f.close()
+        print('done.')
+    return sol
 
 def read(filename, delim=',', skip=1):
     """Read from file and store in data array
@@ -193,7 +225,7 @@ def plot(cfg):
     if 'xreverse' in cfg and cfg['xreverse'] is True: plt.gca().invert_xaxis()
     if 'title' in cfg: plt.title(cfg['title'])
     if 'xlim' in cfg: plt.xlim(cfg['xlim'])
-    if 'ylim' in cfg: plt.xlim(cfg['ylim'])
+    if 'ylim' in cfg: plt.ylim(cfg['ylim'])
     if 'legend' in cfg and cfg['legend'] is True: plt.legend(frameon=False)
     if 'xlabel' in cfg: plt.xlabel(cfg['xlabel'])
     if 'ylabel' in cfg: plt.ylabel(cfg['ylabel'])
diff --git a/blast/validation/lannValidation.py b/blast/validation/lannValidation.py
index f5e8659..9833f14 100644
--- a/blast/validation/lannValidation.py
+++ b/blast/validation/lannValidation.py
@@ -116,7 +116,7 @@ def main():
     vcfg['vMsh'] = vMsh
 
     tms['pre'].start()
-    coupler, iSolverAPI, vSolver = viscUtils.initBlast(icfg, vcfg)
+    coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
     tms['pre'].stop()
 
     print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
@@ -127,19 +127,13 @@ 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, iSolverAPI.getMinf(), iSolverAPI.getAoA()*180/math.pi, iSolverAPI.getCl(), vSolver.Cdt, vSolver.Cdp, vSolver.Cdf, iSolverAPI.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.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
 
      # Write results to file.
-    vSolution = viscUtils.getSolution(vSolver)
-
-    # Write results to file.
-    for iSec in range(len(iSolverAPI.cfg['EffSections'])):
-        vSolution = viscUtils.getSolution(vSolver, iSec)
-        viscUtils.write(vSolution, vSolver.getRe(), sfx='slice'+str(iSec))
-    vSolution['Cdt_int'] = vSolver.Cdf + iSolverAPI.getCd()
+    vSolution = viscUtils.getSolution(isol.sec, write=True, toW='all')
 
     # Save pressure coefficient
-    iSolverAPI.save(sfx='_viscous')
+    isol.save(sfx='_viscous')
     tms['total'].stop()
 
     print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
@@ -151,9 +145,10 @@ def main():
     # Test solution
     print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET)
     tests = CTests()
-    tests.add(CTest('Cl', iSolverAPI.getCl(), 0.6007, 5e-2))
-    tests.add(CTest('Cd wake', vSolution['Cdt_int'], 0.02756, 1e-3, forceabs=True))
-    tests.add(CTest('Iterations', len(aeroCoeffs), 19, 0, forceabs=True))
+    tests.add(CTest('Cl', isol.getCl(), 0.6007, 5e-2))
+    tests.add(CTest('Cd wake', vsol.Cdt, 0.00348, 1e-3, forceabs=True))
+    tests.add(CTest('Cd int', isol.getCd() + vsol.Cdf, 0.0279, 1e-3, forceabs=True))
+    tests.add(CTest('Iterations', len(aeroCoeffs['Cl']), 4, 0, forceabs=True))
     tests.run()
 
     # eof
diff --git a/blast/validation/oneraValidation.py b/blast/validation/oneraValidation.py
index cb9af04..8a41eab 100644
--- a/blast/validation/oneraValidation.py
+++ b/blast/validation/oneraValidation.py
@@ -114,7 +114,7 @@ def main():
     vcfg['vMsh'] = vMsh
 
     tms['pre'].start()
-    coupler, iSolverAPI, vSolver = viscUtils.initBlast(icfg, vcfg)
+    coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
     tms['pre'].stop()
 
     print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
@@ -125,19 +125,13 @@ 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, iSolverAPI.getMinf(), iSolverAPI.getAoA()*180/math.pi, iSolverAPI.getCl(), vSolver.Cdt, vSolver.Cdp, vSolver.Cdf, iSolverAPI.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.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
 
      # Write results to file.
-    vSolution = viscUtils.getSolution(vSolver)
-
-    # Write results to file.
-    for iSec in range(len(iSolverAPI.cfg['EffSections'])):
-        vSolution = viscUtils.getSolution(vSolver, iSec)
-        viscUtils.write(vSolution, vSolver.getRe(), sfx='slice'+str(iSec))
-    vSolution['Cdt_int'] = vSolver.Cdf + iSolverAPI.getCd()
+    vSolution = viscUtils.getSolution(isol.sec, write=True, toW='all', sfx='onera')
 
     # Save pressure coefficient
-    iSolverAPI.save(sfx='_viscous')
+    isol.save(sfx='_viscous')
     tms['total'].stop()
 
     print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
@@ -149,9 +143,10 @@ def main():
     # Test solution
     print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET)
     tests = CTests()
-    tests.add(CTest('Cl', iSolverAPI.getCl(), 0.279, 5e-2))
-    tests.add(CTest('Cd wake', vSolution['Cdt_int'], 0.0168, 1e-3, forceabs=True))
-    tests.add(CTest('Iterations', len(aeroCoeffs), 19, 0, forceabs=True))
+    tests.add(CTest('Cl', isol.getCl(), 0.279, 5e-2))
+    tests.add(CTest('Cd wake', vsol.Cdt, 0.00471, 1e-3, forceabs=True))
+    tests.add(CTest('Cd int', isol.getCd() + vsol.Cdf, 0.01519, 1e-3, forceabs=True))
+    tests.add(CTest('Iterations', len(aeroCoeffs['Cl']), 13, 0, forceabs=True))
     tests.run()
 
     # eof
diff --git a/blast/validation/raeValidation.py b/blast/validation/raeValidation.py
index 9a99c22..8265822 100644
--- a/blast/validation/raeValidation.py
+++ b/blast/validation/raeValidation.py
@@ -28,11 +28,11 @@ from fwk.wutils import parseargs
 import fwk
 from fwk.testing import *
 from fwk.coloring import ccolors
+import os.path
 
 import math
 
 def cfgInviscid(nthrds, verb):
-    import os.path
     # Parameters
     return {
     # Options
@@ -42,13 +42,13 @@ def cfgInviscid(nthrds, verb):
     'Verb' : verb, # verbosity
     # Model (geometry or mesh)
     'File' : os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/rae_2.geo', # Input file containing the model
-    'Pars' : {'xLgt' : 5, 'yLgt' : 5, 'msF' : 1, 'msTe' : 0.01, 'msLe' : 0.002}, # parameters for input file model
+    'Pars' : {'xLgt' : 50, 'yLgt' : 50, 'msF': 10, 'msTe' : 0.01, 'msLe' : 0.001}, # parameters for input file model
     'Dim' : 2, # problem dimension
     'Format' : 'gmsh', # save format (vtk or gmsh)
     # Markers
     'Fluid' : 'field', # name of physical group containing the fluid
     'Farfield' : ['upstream', 'farfield', 'downstream'], # LIST of names of physical groups containing the farfield boundaries (upstream/downstream should be first/last element)
-    'Wing' : 'airfoil', # LIST of names of physical groups containing the lifting surface boundary
+    'Wing' : 'airfoil', # LIST of names of physical groups containing the lifting surface boundaryk
     'Wake' : 'wake', # LIST of names of physical group containing the wake
     'WakeTip' : 'wakeTip', # LIST of names of physical group containing the edge of the wake
     'Te' : 'te', # LIST of names of physical group containing the trailing edge
@@ -64,7 +64,7 @@ def cfgInviscid(nthrds, verb):
     'y_ref' : 0.0, # reference point for moment computation (y)
     'z_ref' : 0.0, # reference point for moment computation (z)
     # Numerical
-    'LSolver' : 'GMRES', # inner solver (Pardiso, MUMPS or GMRES)
+    'LSolver' : 'SparseLu', # inner solver (Pardiso, MUMPS or GMRES)
     'G_fill' : 2, # fill-in factor for GMRES preconditioner
     'G_tol' : 1e-5, # tolerance for GMRES
     'G_restart' : 50, # restart for GMRES
@@ -98,8 +98,15 @@ def main():
     icfg = cfgInviscid(args.k, args.verb)
     vcfg = cfgBlast(args.verb)
 
+    gr = 1.1
+    if gr == 1.0:
+        icfg['Pars']['msF'] = icfg['Pars']['msLe']
+    else:
+        n = np.log10(1-(1-gr)*icfg['Pars']['xLgt']/icfg['Pars']['msLe'])/np.log10(gr)
+        icfg['Pars']['msF'] = icfg['Pars']['msLe']*gr**(n-1)
+    print('msF =', icfg['Pars']['msF'])
     tms['pre'].start()
-    coupler, iSolverAPI, vSolver = viscUtils.initBlast(icfg, vcfg)
+    coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
     tms['pre'].stop()
 
     print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
@@ -110,11 +117,10 @@ 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, iSolverAPI.getMinf(), iSolverAPI.getAoA()*180/math.pi, iSolverAPI.getCl(), vSolver.Cdt, vSolver.Cdp, vSolver.Cdf, iSolverAPI.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.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
 
      # Write results to file.
-    vSolution = viscUtils.getSolution(vSolver)
-    vSolution['Cdt_int'] = vSolution['Cdf'] + iSolverAPI.getCd()
+    vSolution = viscUtils.getSolution(isol.sec)
     tms['total'].stop()
 
     print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
@@ -126,23 +132,27 @@ def main():
     # Test solution
     print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET)
     tests = CTests()
-    tests.add(CTest('Cl', iSolverAPI.getCl(), 0.752, 5e-2)) # XFOIL 0.2325
-    tests.add(CTest('Cd wake', vSolution['Cdt_w'], 0.0094, 1e-3, forceabs=True)) # XFOIL 0.00531
-    tests.add(CTest('Cd integral', vSolution['Cdt_int'], 0.0145, 1e-3, forceabs=True)) # XFOIL 0.00531
-    tests.add(CTest('Cdf', vSolution['Cdf'], 0.0069, 1e-3, forceabs=True)) # XFOIL 0.00084, Cdf = 0.00447
-    tests.add(CTest('Iterations', len(aeroCoeffs), 35, 0, forceabs=True))
+    tests.add(CTest('Cl', isol.getCl(), 0.766, 5e-2))
+    tests.add(CTest('Cd wake', vsol.Cdt, 0.0093, 1e-3, forceabs=True))
+    tests.add(CTest('Cd integral', isol.getCd() + vsol.Cdf, 0.0138, 1e-3, forceabs=True))
+    tests.add(CTest('Cdf', vsol.Cdf, 0.0069, 1e-3, forceabs=True))
+    tests.add(CTest('Iterations', len(aeroCoeffs['Cl']), 42, 0, forceabs=True))
     tests.run()
 
+    expResults = np.loadtxt(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/references/rae2822_AR138_case6.dat')
+    expResults[:,1] *= -1
+
     # Show results
     if not args.nogui:
         iCp = viscUtils.read('Cp_inviscid.dat')
         vCp = viscUtils.read('Cp_viscous.dat')
         plotcp = {'curves': [np.column_stack((vCp[:,0], vCp[:,3])),
-                            np.column_stack((iCp[:,0], iCp[:,3]))],
-                    'labels': ['Blast (VII)', 'DART (inviscid)'],
+                            np.column_stack((iCp[:,0], iCp[:,3])),
+                            expResults],
+                    'labels': ['Blast (VII)', 'DART (inviscid)', 'Experimental'],
                     'lw': [3, 3, 2, 2],
-                    'color': ['darkblue', 'darkblue'],
-                    'ls': ['-', '--'],
+                    'color': ['darkblue', 'darkblue', 'black'],
+                    'ls': ['-', '--', 'o'],
                     'reverse': True,
                     'xlim':[0, 1],
                     'yreverse': True,
@@ -152,13 +162,14 @@ def main():
                     }
         viscUtils.plot(plotcp)
 
-        plotcf = {'curves': [np.column_stack((vSolution['x'], vSolution['Cf']))],
+        plotcf = {'curves': [np.column_stack((vSolution[0]['x'], vSolution[0]['cf']))],
                 'labels': ['Blast'],
                 'lw': [3, 3],
                 'color': ['darkblue'],
                 'ls': ['-'],
                 'reverse': True,
                 'xlim':[0, 1],
+                'ylim':[0, 0.008],
                 'legend': True,
                 'xlabel': '$x/c$',
                 'ylabel': '$c_f$'
-- 
GitLab