From fcd2945e14ec65e6a94a4d378a991b79d95a884d Mon Sep 17 00:00:00 2001
From: Paul Dechamps <paulzer@sentinelle.local>
Date: Thu, 12 May 2022 13:55:21 +0200
Subject: [PATCH] Separating upper lower sides with normals

---
 dart/default.py             |   1 +
 dart/pyVII/vCoupler.py      |  12 +-
 dart/pyVII/vCoupler2.py     |   3 +-
 dart/pyVII/vInterpolator.py | 623 ++++++++++++++++--------------------
 dart/pyVII/vStructures.py   |  46 ---
 dart/pyVII/vUtils.py        |  54 +---
 dart/src/wBody.cpp          |   4 +
 dart/src/wClosures.cpp      |  35 +-
 dart/src/wViscFluxes.cpp    |   1 -
 dart/src/wViscSolver.cpp    |   2 +
 dart/tests/bli2.py          | 156 +++++++++
 dart/tests/bli3.py          |  20 +-
 dart/tests/bli_lowLift.py   |   4 +-
 dart/tests/bli_lowLift2.py  |  29 +-
 dart/tests/rae_3.py         |  27 +-
 15 files changed, 510 insertions(+), 507 deletions(-)
 delete mode 100644 dart/pyVII/vStructures.py
 create mode 100644 dart/tests/bli2.py

diff --git a/dart/default.py b/dart/default.py
index caf91dc..878ed74 100644
--- a/dart/default.py
+++ b/dart/default.py
@@ -42,6 +42,7 @@ def mesh(dim, file, pars, bnd, wk = 'wake', wktp = None):
         name of crack (wake) tip physical tag
     """
     import tbox.gmsh as gmsh
+    import copy
     # load the mesh
     msh = gmsh.MeshLoader(file,__file__).execute(**pars)
     # crack the mesh
diff --git a/dart/pyVII/vCoupler.py b/dart/pyVII/vCoupler.py
index cde32fe..f74cd4c 100644
--- a/dart/pyVII/vCoupler.py
+++ b/dart/pyVII/vCoupler.py
@@ -19,6 +19,9 @@
 ## VII Coupler
 # Paul Dechamps
 
+import dart.utils as floU
+import tbox.utils as tboxU
+
 from dart.viscous.Master.DAirfoil import Airfoil
 from dart.viscous.Master.DWake import Wake
 from dart.viscous.Drivers.DGroupConstructor import GroupConstructor
@@ -39,7 +42,7 @@ class Coupler:
     self.vSolver.verbose = self.iSolver.verbose
     #self.vSolver.verbose = 0
 
-    self.maxCouplIter = 1
+    self.maxCouplIter = 150
     self.couplTol = 1e-4
 
     self.tms=fwk.Timers()
@@ -79,6 +82,11 @@ class Coupler:
       self.iSolver.run()
       self.tms['inviscid'].stop()
 
+      if couplIter == 0:
+        # Write inviscid Cp distribution
+        Cp = floU.extract(self.group[0].boundary.tag.elems, self.iSolver.Cp)
+        tboxU.write(Cp, 'Cp_Inviscid.dat', '%1.5e', ', ', 'x, y, z, Cp', '')
+
       # Extract inviscid boundary
       self.tms['processing'].start()
       self.__ImposeInvBC(couplIter)
@@ -101,7 +109,7 @@ class Coupler:
 
       dragIter = np.vstack((dragIter, [self.iSolver.Cl, self.vSolver.Cdt]))
       
-      if error  <= self.couplTol and exitCode==0:
+      if error  <= self.couplTol:
         print('{:>5s}| {:>10s} {:>10s} | {:>10s} {:>8s} {:>8s}'.format('It', 'Cl', 'Cd', 'xtrT', 'xtrB', 'Error'))
         print(ccolors.ANSI_GREEN,'{:>4.0f}| {:>10.5f} {:>10.5f} | {:>10.4f} {:>8.4f} {:>8.2f}\n'.format(couplIter,
         self.iSolver.Cl, self.vSolver.Cdt, xtr[0], xtr[1], np.log10(error)),ccolors.ANSI_RESET)
diff --git a/dart/pyVII/vCoupler2.py b/dart/pyVII/vCoupler2.py
index 1d86205..1699635 100644
--- a/dart/pyVII/vCoupler2.py
+++ b/dart/pyVII/vCoupler2.py
@@ -35,8 +35,6 @@ class Coupler:
 
     self.tms=fwk.Timers()
     self.resetInv = False
-
-    self.iSolverAPI.iSolver.printOn=False
     pass
 
   def Run(self):
@@ -58,6 +56,7 @@ class Coupler:
       # Run inviscid solver
       self.tms['inviscid'].start()
       if self.resetInv:
+        print('Inviscid solver reset')
         self.iSolverAPI.ResetSolver()
       self.iSolverAPI.RunSolver()
       self.tms['inviscid'].stop()
diff --git a/dart/pyVII/vInterpolator.py b/dart/pyVII/vInterpolator.py
index 1304404..7323c2f 100644
--- a/dart/pyVII/vInterpolator.py
+++ b/dart/pyVII/vInterpolator.py
@@ -1,9 +1,11 @@
+from gc import isenabled
+from xmlrpc.client import INVALID_ENCODING_CHAR
 import numpy as np
 from matplotlib import pyplot as plt
 from fwk.coloring import ccolors
 
 import dart.pyVII.vUtils as blxU
-import dart.pyVII.vStructures as vStruct
+#import dart.pyVII.vStructures as vStruct
 
 # 3D spline with Bézier curves
 from scipy.interpolate import bisplrep
@@ -19,26 +21,25 @@ import fwk
 
 
 class Interpolator:
-    def __init__(self, _dartSolver, bnd_wing, bnd_wake, _cfg):
-        self.iSolver = _dartSolver
-
-        self.invStruct = vStruct.invStruct()
-        self.viscStruct = vStruct.viscStruct()
-
-        self.bndWing = bnd_wing
-        self.bndWake = bnd_wake
-        self.config = _cfg
-        if self.config['nDim'] == 2:
-            self.nodesList, self.transformedCoord, self.wakeCoord, self.viscStruct, self.viscStruct_tr = self.__GetAirfoil(bnd_wing, bnd_wake, _cfg)
-        elif self.config['nDim'] == 3:
-            
+    def __init__(self, _dartAPI, _blw, _cfg):
+        
+        self.iSolver = _dartAPI
+        self.blw = _blw
 
-        print('Sections created')
+        # Create data structures for interpolation
+        self.tms = fwk.Timers()
+        self.tms['GetWing'].start()
+        self.__GetWing(_blw, _cfg)
+        self.tms['GetWing'].stop()
+        print(self.tms)
+        self.cfg = _cfg
 
-        self.xxPrev = [[None for iReg in range(3)] for iSec in range(1)]
+        self.stgPt=np.zeros(self.cfg['nSections'], dtype=int)
+
+        self.xxPrev = [[np.zeros(0) for iReg in range(3)] for iSec in range(self.cfg['nSections'])]
         #self.uePrev = [[np.zeros(len(self.viscStruct[iSec][iReg][:,0])) for iReg in range(3)] for iSec in range(len(self.viscStruct))]
-        self.DeltaStarPrev = [[None for iReg in range(3)] for iSec in range(1)] 
-        self.tms = fwk.Timers()
+        self.DeltaStarPrev = [[np.zeros(0) for iReg in range(3)] for iSec in range(self.cfg['nSections'])]
+
 
     def GetInvBC(self, vSolver, couplIter):
         self.tms['InvToVisc'].start()
@@ -49,50 +50,36 @@ class Interpolator:
 
         # Wing
 
-        U_wg = np.zeros((len(self.nodesList), 3))
-        M_wg = np.zeros(len(self.nodesList))
-        Rho_wg = np.zeros(len(self.nodesList))
-        for iNode, n in enumerate(self.nodesList):
-            U_wg[iNode,0] = self.iSolver.U[n.row][0]
-            U_wg[iNode,1] = self.iSolver.U[n.row][1]
-            U_wg[iNode,2] = self.iSolver.U[n.row][2]
-            M_wg[iNode] = self.iSolver.M[n.row]
-            Rho_wg[iNode] = self.iSolver.rho[n.row]
-        
-        # Wake
+        U = [np.zeros((len(self.invStruct[i][:,0]), 3)) for i in range(len(self.invStruct))]
+        M = [np.zeros(len(self.invStruct[i][:,0])) for i in range(len(self.invStruct))]
+        Rho = [np.zeros(len(self.invStruct[i][:,0])) for i in range(len(self.invStruct))]
 
-        U_wk =np.zeros((len(self.bndWake.nodes), 3))
-        M_wk = np.zeros(len(self.bndWake.nodes))
-        Rho_wk = np.zeros(len(self.bndWake.nodes))
+        # Extract variables.
+
+        for iReg in range(len(self.invStruct)):
+            for iNode, row in enumerate(self.invStruct[iReg][:,3]):
+                row = int(row)
+                U[iReg][iNode,:] = [self.iSolver.U[row][0], self.iSolver.U[row][1], self.iSolver.U[row][2]]
+                M[iReg][iNode] = self.iSolver.M[row]
+                Rho[iReg][iNode] = self.iSolver.rho[row]
         
-        for iNode, n in enumerate(self.bndWake.nodes):
-            U_wk[iNode,0] = self.iSolver.U[n.row][0]
-            U_wk[iNode,1] = self.iSolver.U[n.row][1]
-            U_wk[iNode,2] = self.iSolver.U[n.row][2]
-            M_wk[iNode] = self.iSolver.M[n.row]
-            Rho_wk[iNode] = self.iSolver.rho[n.row]
-
-        if self.config['nDim'] == 3:  # x and y inverted in 3d
-            U_wg[:, [1,2]] = U_wg[:,[2,1]]
-            U_wk[:, [1,2]] = U_wk[:,[2,1]] 
+            if self.cfg['nDim'] == 3:
+                U[iReg][:,[1,2]] = U[iReg][:,[2,1]]
         
-        Ux = [self.__RbfToSections(self.transformedCoord[:,:2], U_wg[:,0], self.viscStruct_tr[0][0][:,:2]), self.__RbfToSections(self.wakeCoord[:, :1], U_wk[:,0], self.viscStruct[0][1][:,:1])]
-        Uy = [self.__RbfToSections(self.transformedCoord[:,:2], U_wg[:,1], self.viscStruct_tr[0][0][:,:2]), self.__RbfToSections(self.wakeCoord[:, :1], U_wk[:,1], self.viscStruct[0][1][:,:1])]
-        Uz = [self.__RbfToSections(self.transformedCoord[:,:2], U_wg[:,2], self.viscStruct_tr[0][0][:,:2]), self.__RbfToSections(self.wakeCoord[:, :1], U_wk[:,2], self.viscStruct[0][1][:,:1])]
-
-        Me = [self.__RbfToSections(self.transformedCoord[:,:2], M_wg, self.viscStruct_tr[0][0][:,:2]), self.__RbfToSections(self.wakeCoord[:, :1], M_wk, self.viscStruct[0][1][:,:1])]
-
-        Rho = [self.__RbfToSections(self.transformedCoord[:,:2], Rho_wg, self.viscStruct_tr[0][0][:,:2]), self.__RbfToSections(self.wakeCoord[:, :1], Rho_wk, self.viscStruct[0][1][:,:1])]
-
         # Find stagnation point
-        for iSec in range(len(self.viscStruct)):
-
+        nD = self.cfg['nDim']
+        for iSec in range(len(self.viscStruct_tr)):
+            Ux = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], U[0][:,0], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], U[1][:,0], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])]
+            Uy = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], U[0][:,1], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], U[1][:,1], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])]
+            Uz = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], U[0][:,2], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], U[1][:,2], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])]
+            Me = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], M[0], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], M[1], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])]
+            Rhoe = [self.__RbfToSections(self.invStruct_tr[0][:,:nD], Rho[0], self.viscStruct_tr[iSec][0][:,:nD]), self.__RbfToSections(self.invStruct_tr[1][:, [0,2] if nD==3 else 0], Rho[1], self.viscStruct[iSec][1][:,[0,2] if nD==3 else 0])]
             if couplIter == 0:
-                self.stgPt = np.argmin(Ux[0]**2+Uy[0]**2)
+                self.stgPt[iSec] = np.argmin(Ux[0]**2+Uy[0]**2)
             
-                xUp, xLw = self.__Remesh(self.viscStruct[iSec][0][:,0], self.stgPt)
-                yUp, yLw = self.__Remesh(self.viscStruct[iSec][0][:,1], self.stgPt)
-                zUp, zLw = self.__Remesh(self.viscStruct[iSec][0][:,2], self.stgPt)
+                xUp, xLw = self.__Remesh(self.viscStruct[iSec][0][:,0], self.stgPt[iSec])
+                yUp, yLw = self.__Remesh(self.viscStruct[iSec][0][:,1], self.stgPt[iSec])
+                zUp, zLw = self.__Remesh(self.viscStruct[iSec][0][:,2], self.stgPt[iSec])
 
                 vSolver.SetGlobMesh(iSec, 0, xUp, yUp, zUp)
                 vSolver.SetGlobMesh(iSec, 1, xLw, yLw, zLw)
@@ -100,122 +87,87 @@ class Interpolator:
                                             self.viscStruct[iSec][1][:,1],
                                             self.viscStruct[iSec][1][:,2])
 
-                self.DeltaStarPrev[0][0] = np.zeros(len(xUp))
-                self.DeltaStarPrev[0][1] = np.zeros(len(xLw))
-                self.DeltaStarPrev[0][2] = np.zeros(len(self.viscStruct[iSec][1][:,0]))
+                self.DeltaStarPrev[iSec][0] = np.zeros(len(xUp))
+                self.DeltaStarPrev[iSec][1] = np.zeros(len(xLw))
+                self.DeltaStarPrev[iSec][2] = np.zeros(len(self.viscStruct[iSec][1][:,0]))
                 
-                self.xxPrev[0][0] = np.zeros(len(xUp))
-                self.xxPrev[0][1] = np.zeros(len(xLw))
-                self.xxPrev[0][2] = np.zeros(len(self.viscStruct[iSec][1][:,0]))
-            
-            UxUp, UxLw = self.__Remesh(Ux[0], self.stgPt)
-            UyUp, UyLw = self.__Remesh(Uy[0], self.stgPt)
-            UzUp, UzLw = self.__Remesh(Uz[0], self.stgPt)
+                self.xxPrev[iSec][0] = np.zeros(len(xUp))
+                self.xxPrev[iSec][1] = np.zeros(len(xLw))
+                self.xxPrev[iSec][2] = np.zeros(len(self.viscStruct[iSec][1][:,0]))
 
-            if couplIter == 0:
-                plt.plot(self.__Remesh(self.viscStruct[iSec][0][:,0], self.stgPt)[0], UxUp)
-                plt.plot(self.__Remesh(self.viscStruct[iSec][0][:,0], self.stgPt)[1], UxLw)
-                plt.show()
+            UxUp, UxLw = self.__Remesh(Ux[0], self.stgPt[iSec])
+            UyUp, UyLw = self.__Remesh(Uy[0], self.stgPt[iSec])
+            UzUp, UzLw = self.__Remesh(Uz[0], self.stgPt[iSec])
 
             vSolver.SetVelocities(iSec, 0, UxUp, UyUp, UzUp)
             vSolver.SetVelocities(iSec, 1, UxLw, UyLw, UzLw)
             vSolver.SetVelocities(iSec, 2, Ux[1], Uy[1], Uz[1])
 
-            MeUp, MeLw = self.__Remesh(Me[0], self.stgPt)
+            MeUp, MeLw = self.__Remesh(Me[0], self.stgPt[iSec])
 
             vSolver.SetMe(iSec, 0, MeUp)
             vSolver.SetMe(iSec, 1, MeLw)
             vSolver.SetMe(iSec, 2, Me[1])
 
-            RhoUp, RhoLw = self.__Remesh(Rho[0], self.stgPt)
+            RhoUp, RhoLw = self.__Remesh(Rhoe[0], self.stgPt[iSec])
 
             vSolver.SetRhoe(iSec, 0, RhoUp)
             vSolver.SetRhoe(iSec, 1, RhoLw)
-            vSolver.SetRhoe(iSec, 2, Rho[1])
-
-            vSolver.SetDeltaStarExt(iSec, 0, self.DeltaStarPrev[0][0])
-            vSolver.SetDeltaStarExt(iSec, 1, self.DeltaStarPrev[0][1])
-            vSolver.SetDeltaStarExt(iSec, 2, self.DeltaStarPrev[0][2])
-
-            vSolver.SetxxExt(iSec, 0, self.xxPrev[0][0])
-            vSolver.SetxxExt(iSec, 1, self.xxPrev[0][1])
-            vSolver.SetxxExt(iSec, 2, self.xxPrev[0][2])
+            vSolver.SetRhoe(iSec, 2, Rhoe[1])
 
-            """uePrevUp, uePrevLw = self.__Remesh(self.uePrev[iSec][0], self.stgPt)
-            vSolver.SetUeOld(iSec, 0, uePrevUp)
-            vSolver.SetUeOld(iSec, 1, uePrevLw)
-            vSolver.SetUeOld(iSec, 2, self.uePrev[iSec][1])"""
+            for iReg in range(3):
+                vSolver.SetDeltaStarExt(iSec, iReg, self.DeltaStarPrev[iSec][iReg])
+                vSolver.SetxxExt(iSec, iReg, self.xxPrev[iSec][iReg])
             
             
 
     def SetBlowingVel(self, vSolver, couplIter):
-        BlowingVel = [[np.zeros(0) for iReg in range(3)] for iSec in range(len(self.viscStruct))]
+
         for iSec in range(len(self.viscStruct)):
-            for iRegion in range(3):
-                BlowingVel[iSec][iRegion] = np.asarray(vSolver.ExtractBlowingVel(iSec, iRegion))
-                self.DeltaStarPrev[iSec][iRegion] = np.asarray(vSolver.ExtractDeltaStar(iSec, iRegion))
-                self.xxPrev[iSec][iRegion] = np.asarray(vSolver.Extractxx(iSec, iRegion))
-
-        if self.config['nDim'] == 2:
-            BlwWing = np.concatenate((BlowingVel[0][0][::-1], BlowingVel[0][1]))
-            BlwWake = BlowingVel[0][2]
-            
-            meany = (self.viscStruct[0][0][np.argmin(self.viscStruct[0][0][:,0]), 1] - self.viscStruct[0][0][np.argmax(self.viscStruct[0][0][:,0]), 1]) / 2
-
-            # Compute cell centers
-            viscCgWing = np.zeros((len(self.viscStruct[0][0][:,0]) - 1, 3))
-            for iElm in range(len(self.viscStruct[0][0][:,0]) - 1):
-                viscCgWing[iElm, 0] = self.viscStruct[0][0][iElm, 0] + self.viscStruct[0][0][iElm + 1, 0]
-                viscCgWing[iElm, 1] = self.viscStruct[0][0][iElm, 1] + self.viscStruct[0][0][iElm + 1, 1]
-                viscCgWing[iElm, 2] = self.viscStruct[0][0][iElm, 2] + self.viscStruct[0][0][iElm + 1, 2]
-            viscCgWing/=2
-            viscCgWing[viscCgWing[:,1]<meany, 0] *= -1
-
-            viscCgWake = np.zeros((len(self.viscStruct[0][1][:,0]) - 1, 3))
-            for iElm in range(len(self.viscStruct[0][1][:,0]) - 1):
-                viscCgWake[iElm, 0] = self.viscStruct[0][1][iElm, 0] + self.viscStruct[0][1][iElm + 1, 0]
-                viscCgWake[iElm, 1] = self.viscStruct[0][1][iElm, 1] + self.viscStruct[0][1][iElm + 1, 1]
-                viscCgWake[iElm, 2] = self.viscStruct[0][1][iElm, 2] + self.viscStruct[0][1][iElm + 1, 2]
-            viscCgWake/=2
-
-            invCgWing = np.zeros((len(self.bndWing.tag.elems), 3))
-            for iElm, e in enumerate(self.bndWing.tag.elems):
-                for n in e.nodes:
-                    invCgWing[iElm, 0] +=n.pos[0]
-                    invCgWing[iElm, 1] +=n.pos[1]
-                    invCgWing[iElm, 2] +=n.pos[2]
-                invCgWing[iElm, :] /= e.nodes.size()
-            
-            invCgWing[invCgWing[:,1]<meany, 0] *= -1
+            for iReg in range(3):
+                self.DeltaStarPrev[iSec][iReg] = vSolver.ExtractDeltaStar(iSec, iReg)
+                self.xxPrev[iSec][iReg] = vSolver.Extractxx(iSec, iReg)
 
-            # Wake 
+        x = [np.zeros((0,3)) for _ in range(2)]
+        blw = [np.zeros(0) for _ in range(2)]
 
-            invCgWake = np.zeros((len(self.bndWake.tag.elems), 3))
-            for iElm, e in enumerate(self.bndWake.tag.elems):
-                for n in e.nodes:
-                    invCgWake[iElm, 0] +=n.pos[0]
-                    invCgWake[iElm, 1] +=n.pos[1]
-                    invCgWake[iElm, 2] +=n.pos[2]
-                invCgWake[iElm, :] /= e.nodes.size()
-            
-            if self.config['nDim'] == 3:
-                invCgWing[:,[1,2]] = invCgWing[:,[2,1]]
-                invCgWake[:,[1,2]] = invCgWake[:,[2,1]]
+        for iSec in range(len(self.viscStruct)):
+            for iReg in range(2):
+                if iReg == 0:
+                    x[iReg] = np.vstack((x[iReg], self.viscCg_tr[iSec][iReg][:,:3]))
+                    blwUp = vSolver.ExtractBlowingVel(iSec, 0)
+                    blwLw = vSolver.ExtractBlowingVel(iSec, 1)
+                    plt.plot(blwLw)
+                    plt.show()
+                    blw[iReg] = np.concatenate((blw[iReg], blwUp[::-1] , blwLw))
+                    plt.plot(self.viscCg_tr[iSec][iReg][:,0],np.concatenate((blwUp[::-1] , blwLw)))
+                    plt.title(iSec)
+                    plt.show()
+                elif iReg == 1:
+                    x[iReg] = np.vstack((x[iReg], self.viscCg_tr[iSec][iReg][:,:3]))
+                    blw[iReg] = np.concatenate((blw[iReg], vSolver.ExtractBlowingVel(iSec, 2)))
 
         self.tms['Interpolation'].start()
-
-        mappedBlw = [self.__RbfToSections(viscCgWing[:, :2], BlwWing, invCgWing[:,:2]), self.__RbfToSections(viscCgWake[:, :1], BlwWake, invCgWake[:, :1])]
-
-        sln = blxU.GetSolution(0, vSolver)
-
-        self.tms['Interpolation'].stop()
-        for iElm in range(len(self.bndWing.tag.elems)):
-            self.bndWing.setU(iElm, mappedBlw[0][iElm])
-        for iElm in range(len(self.bndWake.tag.elems)):
-            self.bndWake.setU(iElm, mappedBlw[1][iElm])
-
+        nD = self.cfg['nDim']
+        mappedBlw = [self.__RbfToSections(x[0], blw[0], self.invCg_tr[0][:,:3], forceLin=1), self.__RbfToSections(x[1][:, [0,2] if nD==3 else 0], blw[1], self.invCg_tr[1][:, [0,2] if nD==3 else 0], forceLin=1)]
         
 
+        fig = plt.figure()
+        ax = fig.add_subplot(projection='3d')
+        ax.scatter(self.invCg_tr[0][:,0], self.invCg_tr[0][:,2], mappedBlw[0], s=0.3)
+        #ax.scatter(abs(invCg_tr[0][:,0]), invCg_tr[0][:,2], invCg_tr[0][:,1], s=0.3)
+        for sec in range(len(self.viscStruct_tr)):
+            ax.scatter(x[0][:,0], x[0][:,2], blw[0], color = 'red')
+        #ax.set_zlim([-0.5, 0.5])
+        ax.set_xlabel('x')
+        ax.set_ylabel('y')
+        ax.set_zlabel('z')
+        plt.show()
+        self.tms['Interpolation'].stop()
+        for iElm in range(len(self.invCg_tr[0][:,0])):
+            self.blw[0].setU(iElm, mappedBlw[0][iElm])
+        for iElm in range(len(self.invCg_tr[1][:,0])):
+            self.blw[1].setU(iElm, mappedBlw[1][iElm])
 
     def RunSolver(self):
         self.iSolver.run()
@@ -240,82 +192,116 @@ class Interpolator:
     def GetCm(self):
         return self.iSolver.Cm
 
-    def __Remesh(self, vec, idx_stag):
-        xUp = vec[:idx_stag+1]
+    def __Remesh(self, vec, stgPt):
+        xUp = vec[:stgPt+1]
         xUp = xUp[::-1]
 
-        xLw = vec[idx_stag:]
+        xLw = vec[stgPt:]
         return xUp, xLw
 
-    def __RbfToSections(self, x, var, xs):
+    def __RbfToSections(self, x, var, xs, forceLin=0):
         if np.all(var == var[0]):
             varOut = RBFInterpolator(x, var, neighbors=1, kernel='linear', smoothing=0.0, degree=0)(xs)
+        elif forceLin==1:
+            varOut = RBFInterpolator(x, var, neighbors=50, kernel='linear', smoothing=0.1, degree=0)(xs)
         else:
-            varOut = RBFInterpolator(x, var, neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=self.config['smoothing'], degree=self.config['degree'])(xs)
+            varOut = RBFInterpolator(x, var, neighbors=self.cfg['neighbors'], kernel=self.cfg['rbftype'], smoothing=self.cfg['smoothing'], degree=self.cfg['degree'])(xs)
         return varOut
-        
-    def __GetWing(self, bnd_wing, bnd_wake, config):
 
-        if config['nDim'] == 2 and config['nSections'] != 1:
-            raise RuntimeError('Cannot create more than 1 section on 2D geometry. Specified:', config['nSections'])
+
+    def __GetWing(self, blw, config):
 
         viscStruct = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(2)] for _ in range(config['nSections'])]
-        viscStruct_tr = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(1)] for _ in range(config['nSections'])]
+        viscStruct_tr = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(2)] for _ in range(config['nSections'])]
+
+        
+        invStruct = [np.zeros((len(blw[i].nodes), 4)) for i in range(len(blw))]
+        invStruct_tr = [np.zeros((len(blw[i].nodes), 4)) for i in range(len(blw))]
+
+        # Wing
+        upperNodes = np.zeros((0,4))
+        lowerNodes = np.zeros((0,4))
+
+        self.tms['ElmLoop'].start()
+        # Compute reference normal
+        nVec = [np.zeros(0) for _ in range(blw[1].tag.elems[0].nodes.size())]
+        for iNode, n in enumerate(blw[1].tag.elems[0].nodes):
+            nVec[iNode] = np.array([n.pos[0], n.pos[1], n.pos[2]])
+        normalRef = np.cross(nVec[1] - nVec[0], nVec[2] - nVec[0])
+        normalRef/=np.linalg.norm(normalRef)
+            
+        for e in blw[0].tag.elems:
+            nVec = [np.zeros(0) for _ in range(e.nodes.size())]
+            for iNode, n in enumerate(e.nodes):
+                nVec[iNode] = np.array([n.pos[0], n.pos[1], n.pos[2]])
+            normal = np.cross(nVec[1] - nVec[0], nVec[2] - nVec[0])
+            normal/=np.linalg.norm(normalRef)
+            if np.dot(normal, normalRef) >= 0:
+                for n in e.nodes:
+                    if n.row not in upperNodes[:,3] and n.row not in lowerNodes[:,3]:
+                        upperNodes = np.vstack((upperNodes, [n.pos[0], n.pos[1], n.pos[2], n.row]))
+            if np.dot(normal, normalRef) < 0:
+                for n in e.nodes:
+                    if n.row not in lowerNodes[:,3] and n.row not in upperNodes[:,3]:
+                        lowerNodes = np.vstack((lowerNodes, [n.pos[0], n.pos[1], n.pos[2], n.row]))
+
+        self.tms['ElmLoop'].stop()
+
+        dummyLower = lowerNodes.copy()
+        dummyLower[:,0] *= -1
+
+        invStruct_tr[0] = np.vstack((upperNodes, dummyLower))
+        invStruct[0] = np.vstack((upperNodes, lowerNodes))
 
-        # Create node list
-        nodesCoord = np.zeros((0, 3))
-        for n in bnd_wing.nodes:
-            nodesCoord = np.vstack((nodesCoord, [n.pos[0], n.pos[1], n.pos[2]]))
+        # Remove duplicates
+        invStruct_tr[0] = np.unique(invStruct_tr[0], axis=0)
 
+        # Wake part
+        for iNode, n in enumerate(blw[1].nodes):
+            invStruct_tr[1][iNode, :] = [n.pos[0], n.pos[1], n.pos[2], n.row]
+        invStruct[1] = invStruct_tr[1].copy()
+
+        # Create spanwise distribution
         if config['nDim'] == 2:
             spanDistri = np.zeros(1)
-            spanDistri[0] = nodesCoord[0,2] # Span direction is the z direction
+            spanDistri[0] = invStruct[0][0,2] # Span direction is the z direction
 
+            wingSpan = 0.
+            fInterp = interp1d(invStruct_tr[0][:,0], invStruct_tr[0][:,1])
 
-        
         elif config['nDim'] == 3:
-            nodesCoord[:, [1,2]] = nodesCoord[:, [2, 1]]
-            spanDistri = np.linspace(min(nodesCoord[:,2]), max(nodesCoord[:,2]), config['nSections'])
+            invStruct[0][:, [1,2]] = invStruct[0][:, [2, 1]]
+            invStruct[1][:, [1,2]] = invStruct[1][:, [2, 1]]
+            invStruct_tr[0][:, [1,2]] = invStruct_tr[0][:, [2, 1]]
+            invStruct_tr[1][:, [1,2]] = invStruct_tr[1][:, [2, 1]]
+            spanDistri = np.linspace(min(invStruct[0][:,2]), max(invStruct[0][:,2]), config['nSections'])
             spanDistri[0] +=0.1
             spanDistri[-1] -=0.1
-            print('spanDistri', spanDistri)
-
-        else:
-            raise RuntimeError("Number of dimensions not recognized", config['nDim'])
-
-        fig = plt.figure()
-        ax = fig.add_subplot(projection='3d')
-        ax.scatter(nodesCoord[:,0], nodesCoord[:,1], nodesCoord[:,2], s=0.3)
-        #ax.scatter(wake[:,0], wake[:,1], wake[:,2], s=0.3)
-        #ax.set_zlim([-0.5, 0.5])
-        ax.set_xlabel('x')
-        ax.set_ylabel('y')
-        ax.set_zlabel('z')
-        plt.show()
-
-        wingSpan = max(nodesCoord[:,2]) - min(nodesCoord[:,2])
 
-        upperNodes, lowerNodes = self.__SeparateWing(nodesCoord)
+            print('spanDistri', spanDistri)
+        
+            # Spline wing
+            # Point in the wing tip region are not accounted for during Bezier curve spline
+            #xUp = upperNodes[upperNodes[:,0]<config['span'], :]
+            #xLw = lowerNodes[lowerNodes[:,0]<config['span'], :]
 
-        lowerNodes[:,0] *= -1
-        transformedCoord = np.vstack((upperNodes, lowerNodes))
+            #xUp[:,[1,2]] = xUp[:,[2,1]]
+            #xLw[:,[1,2]] = xLw[:,[2,1]]
 
-        tck_wing = bisplrep(transformedCoord[:,0], transformedCoord[:,2], transformedCoord[:,1], kx=3, ky=3, s=1e-3, quiet=1)
+            #sUp = (len(xUp)-np.sqrt(2*len(xUp)) + len(xUp)+np.sqrt(2*len(xUp)))/2
+            #sLw = (len(xLw)-np.sqrt(2*len(xLw)) + len(xLw)+np.sqrt(2*len(xLw)))/2
+            #tck_wingUp = bisplrep(xUp[:,0], xUp[:,2], xUp[:,1], kx=3, ky=3, s=sUp, quiet=1)
+            #tck_wingLw = bisplrep(xLw[:,0], xLw[:,2], xLw[:,1], kx=3, ky=3, s=sLw, quiet=1)
 
-        wakeCoord = np.zeros((len(bnd_wake.nodes), 3))
-        for iNode, n in enumerate(bnd_wake.nodes):
-            wakeCoord[iNode, 0] = n.pos[0]
-            wakeCoord[iNode, 1] = n.pos[1]
-            wakeCoord[iNode, 2] = n.pos[2]
-        
-        if config['nDim'] == 3:
-            wakeCoord[:, [1,2]] = wakeCoord[:, [1,2]]
+            m = len(invStruct_tr[0][:,0])
+            _s = (m-np.sqrt(2*m) + m+np.sqrt(2*m))/2
+            tck_wing = bisplrep(invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],0], invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],2], invStruct_tr[0][invStruct_tr[0][:,2]<config['span'],1], kx=5, ky=5, s=1e-8)
 
-        #tck_wake = splrep(wakeCoord)
+        # Create sections
+        self.tms['iSecLoop'].start()
 
         for iSec, z in enumerate(spanDistri):
-
-            portion = nodesCoord[abs(nodesCoord[:,2] - z) <= 0.01 * wingSpan,:]
+            portion = invStruct[0][abs(invStruct[0][:,2] - z) <= 0.01 * config['span'],:]
             
             chordLength = max(portion[:, 0]) - min(portion[:, 0])
             xDistri = min(portion[:,0]) + 1/2*(1 + np.cos(np.linspace(0, np.pi, config['nPoints'][0])))*chordLength
@@ -327,180 +313,115 @@ class Interpolator:
             viscStruct_tr[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0]))
 
             # Interpolation in the transformed space.
-            for iPoint in range(len(viscStruct_tr[iSec][0][:,0])):
-                viscStruct_tr[iSec][0][iPoint,1] = bisplev(viscStruct_tr[iSec][0][iPoint,0], viscStruct_tr[iSec][0][iPoint,2], tck_wing)
-            
+            if config['nDim'] == 3:
+                    
+                for iPoint in range(len(viscStruct_tr[iSec][0][:,0])):
+                    viscStruct_tr[iSec][0][iPoint, 1] = bisplev(viscStruct_tr[iSec][0][iPoint,0], viscStruct_tr[iSec][0][iPoint,2], tck_wing)
+
+
+            elif config['nDim'] == 2:
+                viscStruct_tr[iSec][0][:,1] = fInterp(viscStruct_tr[iSec][0][:,0])
+
+            viscStruct_tr[iSec][0][0,1] = 0.
+            viscStruct_tr[iSec][0][-1,1] = 0.
             viscStruct[iSec][0][:,1] = viscStruct_tr[iSec][0][:,1].copy()
 
-            fig = plt.figure()
-            ax = fig.add_subplot(projection='3d')
-            ax.scatter(transformedCoord[:,0], transformedCoord[:,2], transformedCoord[:,1], s=0.3)
-            #ax.scatter(wake[:,0], wake[:,1], wake[:,2], s=0.3)``
-            for iSec in range(len(viscStruct)):
-                ax.scatter(viscStruct_tr[iSec][0][:,0], viscStruct_tr[iSec][0][:,2], viscStruct[iSec][0][:,1], color='red')
-            ax.set_zlim([-0.5, 0.5])
-            ax.set_xlabel('x')
-            ax.set_ylabel('y')
-            ax.set_zlabel('z')
-            plt.show()
-            
-            #viscStruct_tr[iSec][0][:,1] = splev(viscStruct_tr[iSec][0][:,0], spl)
-            #viscStruct_tr[iSec][0][:,1] = interp1d(transformedCoord[:,0], transformedCoord[:,1])(viscStruct_tr[iSec][0][:,0])
-            #viscStruct[iSec][0][:,1] = viscStruct_tr[iSec][0][:,1].copy()
+            # Wake 
+            wakeLength = np.max(invStruct[1][:,0]) - np.max(viscStruct[iSec][0][:,0])
+            viscStruct_tr[iSec][1][:,0] = np.max(viscStruct[iSec][0][:,0]) + (np.max(viscStruct[iSec][0][:,0]) + np.cos(np.linspace(np.pi, np.pi/2, config['nPoints'][1]))) * wakeLength
+            viscStruct_tr[iSec][1][:,2] = z*np.ones(len(viscStruct[iSec][1][:,0]))
+            viscStruct_tr[iSec][1][:,1] = interp1d(invStruct_tr[1][:,0], invStruct_tr[1][:,1], bounds_error=False, fill_value='extrapolate')(viscStruct_tr[iSec][1][:,0])
+
+            viscStruct[iSec][1] = viscStruct_tr[iSec][1].copy()
 
-            """# Wake
-            wakeLength = np.max(wakeCoord[:,0]) - np.max(viscStruct[iSec][0][:,0])
-            viscStruct[iSec][1][:,0] = np.max(viscStruct[iSec][0][:,0]) + (np.max(viscStruct[iSec][0][:,0]) + np.cos(np.linspace(np.pi, np.pi/2, config['nPoints'][1]))) * wakeLength
-            viscStruct[iSec][1][:,2] = z*np.ones(len(viscStruct[iSec][1][:,0]))
-            viscStruct[iSec][1][:,1] = interp1d(wakeCoord[:,0], wakeCoord[:,1])(viscStruct[iSec][1][:,0])"""
+        # Cg positions
+        self.tms['iSecLoop'].stop()
 
         fig = plt.figure()
         ax = fig.add_subplot(projection='3d')
-        ax.scatter(nodesCoord[:,0], nodesCoord[:,2], nodesCoord[:,1], s=0.3)
-        #ax.scatter(wake[:,0], wake[:,1], wake[:,2], s=0.3)
-        for iSec in range(len(viscStruct)):
-            ax.scatter(viscStruct[iSec][0][:,0], viscStruct[iSec][0][:,2], viscStruct[iSec][0][:,1], color='red')
+        ax.scatter(invStruct_tr[0][:,0], invStruct_tr[0][:,2], invStruct_tr[0][:,1], s=0.3)
+        ax.scatter(invStruct_tr[1][:,0], invStruct_tr[1][:,2], invStruct_tr[1][:,1], s=0.3)
+        for sec in viscStruct_tr:
+            ax.scatter(sec[0][:,0], sec[0][:,2], sec[0][:,1], color = 'red')
+            ax.scatter(sec[1][:,0], sec[1][:,2], sec[1][:,1], color = 'red')
         ax.set_zlim([-0.5, 0.5])
         ax.set_xlabel('x')
         ax.set_ylabel('y')
         ax.set_zlabel('z')
         plt.show()
-        return nodesList, transformedCoord, wakeCoord, viscStruct, viscStruct_tr
-
-
-    def __GetAirfoil(self, bnd_wing, bnd_wake, config):
-
-        if config['nSections'] != 1:
-            raise RuntimeError('Cannot create more than 1 section on 2D geometry. Specified:', config['nSections'])
-
-        viscStruct = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(2)] for _ in range(config['nSections'])]
-        viscStruct_tr = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0]-1, 3)) for i in range(1)] for _ in range(config['nSections'])]
-
-        # Create node list
-        nodesCoord = np.zeros((0, 3))
-        for n in bnd_wing.nodes:
-            nodesCoord = np.vstack((nodesCoord, [n.pos[0], n.pos[1], n.pos[2]]))
+        """fig = plt.figure()
+        ax = fig.add_subplot(projection='3d')
+        ax.scatter(invStruct[0][:,0], invStruct[0][:,2], invStruct[0][:,1], s=0.3)
+        for sec in viscStruct:
+            ax.scatter(sec[0][:,0], sec[0][:,2], sec[0][:,1], color = 'red')
+            #ax.scatter(sec[1][:,0], sec[1][:,2], sec[1][:,1], color = 'red')
+        ax.set_zlim([-0.5, 0.5])
+        ax.set_xlabel('x')
+        ax.set_ylabel('y')
+        ax.set_zlabel('z')
+        plt.show()"""
 
-        if config['nDim'] == 2:
-            spanDistri = np.zeros(1)
-            spanDistri[0] = nodesCoord[0,2] # Span direction is the z direction
+        viscCg_tr = [[np.zeros((len(viscStruct[iSec][iReg][:,0]) - 1, 3)) for iReg in range(2)] for iSec in range(len(viscStruct))]
+        invCg_tr = [np.zeros((len(blw[iReg].tag.elems), 3)) for iReg in range(2)]
+        self.tms['CgLoop'].start()
         
-        elif config['nDim'] == 3:
-            nodesCoord[:, [1,2]] = nodesCoord[:, [2, 1]]
-            spanDistri = np.linspace(min(nodesCoord[:,2]), max(nodesCoord[:,2]), config['nSections'])
-            spanDistri[0] +=0.1
-            spanDistri[-1] -=0.1
-            print('spanDistri', spanDistri)
-
-        else:
-            raise RuntimeError("Number of dimensions not recognized", config['nDim'])
-
-        wingSpan = max(nodesCoord[:,2]) - min(nodesCoord[:,2])
-
-        upperNodes, lowerNodes = self.__SeparateWing(nodesCoord)
-
-        for iSec, z in enumerate(spanDistri):
-            
-            portion = nodesCoord[abs(nodesCoord[:,2] - z) <= 0.01 * wingSpan,:]
-
-            le_coord = portion[portion[:,0] == np.min((portion[:,0])), :][0]
-            te_coord = portion[portion[:,0] == np.max((portion[:,0])), :][0]
-
-            # Find te elements
-            te_elems = []
-            for e in bnd_wing.tag.elems:
+        # Viscous
+        for iSec in range(len(viscStruct)):
+            for iReg in range(len(viscStruct[iSec])):
+                for iElm in range(len(viscStruct[iSec][iReg][:,0]) - 1):
+                    for iDir in range(3):
+                        viscCg_tr[iSec][iReg][iElm, iDir] = viscStruct_tr[iSec][iReg][iElm, iDir] + viscStruct_tr[iSec][iReg][iElm + 1, iDir]
+                viscCg_tr[iSec][iReg] /= 2
+
+        # Inviscid
+        for iReg in range(len(blw)):
+            for iElm, e in enumerate(blw[iReg].tag.elems):
                 for n in e.nodes:
-                    if n.pos[0] == te_coord[0]:
-                        te_elems.append(e)
-                        break
-            
-            # Cg of te elements
-            cg_teElems = np.zeros((len(te_elems), 3))
-            for iElm, eTe in enumerate(te_elems):
-                for n in eTe.nodes:
-                    cg_teElems[iElm, 0] += n.pos[0]
-                    cg_teElems[iElm, 1] += n.pos[1]
-                    cg_teElems[iElm, 2] += n.pos[2]
-            
-            # Sort upper side in 0 and lower side in 1
-            if cg_teElems[0, 1] < cg_teElems[1, 1]:
-                save = te_elems[0].copy()
-                te_elems[0] = te_elems[1]
-                te_elems[1] = save
-            
-            # Find te_nodes (sorted [upper, lower])
-            te_nodes = [None, None]
-            for i in range(len(te_elems)):
-                for n in te_elems[i].nodes:
-                    if n.pos[0] == te_coord[0]:
-                        te_nodes[i] = n
-                        break
-            
-            # Find le_node
-            for n in bnd_wing.nodes:
-                if n.pos[0] == le_coord[0]:
-                    le_node = n
-                    break
-                
+                    if n.row in upperNodes[:,3] or iReg == 1:
+                        invCg_tr[iReg][iElm, 0] +=n.pos[0]
+                    elif n.row in lowerNodes[:,3]:
+                        invCg_tr[iReg][iElm, 0] += -n.pos[0]
 
-            meany = (le_coord[1] + te_coord[1]) / 2
-
-            transformedCoord = np.zeros((0, 3))
-            nodesList = []
-
-            for iNode, n in enumerate(bnd_wing.nodes):
-                if n.pos[0] != le_coord[0] and n.pos[0] != te_coord[0]:
-                    if n.pos[1] > meany:
-                        transformedCoord = np.vstack((transformedCoord, [n.pos[0], n.pos[1], n.pos[2]]))
-                        nodesList.append(n)
-
-                    elif n.pos[1] < meany:
-                        transformedCoord = np.vstack((transformedCoord, [-n.pos[0], n.pos[1], n.pos[2]]))
-                        nodesList.append(n)
-
-            transformedCoord = np.vstack((transformedCoord, le_coord))
-            nodesList.append(le_node)
-            transformedCoord = np.vstack((transformedCoord, [te_nodes[0].pos[0], te_nodes[0].pos[1], te_nodes[0].pos[2]]))
-            nodesList.append(te_nodes[0])
-            transformedCoord = np.vstack((transformedCoord, [-te_nodes[1].pos[0], te_nodes[1].pos[1], te_nodes[1].pos[2]]))
-            nodesList.append(te_nodes[1])
-
-            wakeCoord = np.zeros((len(bnd_wake.nodes), 3))
-            for iNode, n in enumerate(bnd_wake.nodes):
-                wakeCoord[iNode, 0] = n.pos[0]
-                wakeCoord[iNode, 1] = n.pos[1]
-                wakeCoord[iNode, 2] = n.pos[2]
-            
-            chordLength = max(portion[:, 0]) - min(portion[:, 0])
-            xDistri = le_coord[0] + 1/2*(1 + np.cos(np.linspace(0, np.pi, config['nPoints'][0])))*chordLength
+                    invCg_tr[iReg][iElm, 1] +=n.pos[1]
+                    invCg_tr[iReg][iElm, 2] +=n.pos[2]
+                invCg_tr[iReg][iElm, :] /= e.nodes.size()
 
-            viscStruct[iSec][0][:,0] = np.concatenate((xDistri[:-1], xDistri[::-1]), axis=None)
-            viscStruct[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0]))
-
-            viscStruct_tr[iSec][0][:,0] = np.concatenate((xDistri[:-1], -xDistri[::-1]), axis=None).copy()
-            viscStruct_tr[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0]))
-
-            # Interpolation in the transformed space.
-            splineTr = transformedCoord.copy()
-            splineTr = splineTr[splineTr[:, 0].argsort()]
-            spl = splrep(splineTr[:,0], splineTr[:,1], k=5)
-            viscStruct_tr[iSec][0][:,1] = splev(viscStruct_tr[iSec][0][:,0], spl)
-            #viscStruct_tr[iSec][0][:,1] = interp1d(transformedCoord[:,0], transformedCoord[:,1])(viscStruct_tr[iSec][0][:,0])
-            viscStruct[iSec][0][:,1] = viscStruct_tr[iSec][0][:,1].copy()
+            if config['nDim'] == 3:
+                invCg_tr[iReg][:,[1,2]] = invCg_tr[iReg][:,[2,1]]
+        self.tms['CgLoop'].stop()
 
-            # Wake
-            wakeLength = np.max(wakeCoord[:,0]) - np.max(viscStruct[iSec][0][:,0])
-            viscStruct[iSec][1][:,0] = np.max(viscStruct[iSec][0][:,0]) + (np.max(viscStruct[iSec][0][:,0]) + np.cos(np.linspace(np.pi, np.pi/2, config['nPoints'][1]))) * wakeLength
-            viscStruct[iSec][1][:,2] = z*np.ones(len(viscStruct[iSec][1][:,0]))
-            viscStruct[iSec][1][:,1] = interp1d(wakeCoord[:,0], wakeCoord[:,1])(viscStruct[iSec][1][:,0])
+        """if config['nDim'] == 3:
+            fig = plt.figure()
+            ax = fig.add_subplot(projection='3d')
+            ax.scatter(invStruct_tr[0][:,0], invStruct_tr[0][:,2], invStruct[0][:,1], s=0.3)
+            #ax.scatter(abs(invCg_tr[0][:,0]), invCg_tr[0][:,2], invCg_tr[0][:,1], s=0.3)
+            for sec in viscStruct_tr:
+                ax.scatter(abs(sec[0][:,0]), sec[0][:,2], sec[0][:,1], color = 'red')
+                ax.scatter(abs(sec[1][:,0]), sec[1][:,2], sec[1][:,1], color = 'red')
+            #ax.set_zlim([-0.5, 0.5])
+            ax.set_xlabel('x')
+            ax.set_ylabel('y')
+            ax.set_zlabel('z')
+            plt.show()
+        elif config['nDim'] == 2:
+            plt.plot(abs(invStruct_tr[0][:,0]), invStruct[0][:,1], 'x', color='blue')
+            plt.plot(abs(invStruct_tr[1][:,0]), invStruct[1][:,1], 'x', color='blue')
+            plt.plot(abs(invCg_tr[0][:,0]), invCg_tr[0][:,1], 'o', color='red')
+            plt.plot(abs(invCg_tr[1][:,0]), invCg_tr[1][:,1], 'o', color='red')
+            plt.title('Inviscid')
+            plt.show()
+            plt.plot(viscStruct_tr[0][0][:,0], viscStruct_tr[0][0][:,1])
+            plt.plot(viscStruct_tr[0][1][:,0], viscStruct_tr[0][1][:,1])
+            plt.plot(invStruct_tr[0][:,0], invStruct[0][:,1], 'o', color='blue')
+            plt.plot(invStruct_tr[1][:,0], invStruct[1][:,1], 'x', color='blue')
+            plt.title('Viscous vs Inviscid')
+            plt.show()"""
 
-            return nodesList, transformedCoord, wakeCoord, viscStruct, viscStruct_tr
 
-    def __SeparateWing(self, nodesCoord):
-        
-        print(np.max(nodesCoord[:,0]))
-        meany = nodesCoord[np.argmax(nodesCoord[:,0]), 1] - nodesCoord[np.argmin(nodesCoord[:,0]), 1]
+        self.invStruct = invStruct
+        self.invStruct_tr = invStruct_tr
+        self.viscStruct = viscStruct
+        self.viscStruct_tr = viscStruct_tr
 
-        upperNodes = nodesCoord[nodesCoord[:,1]>=meany].copy()
-        lowerNodes = nodesCoord[nodesCoord[:,1]<=meany].copy()
-        return upperNodes, lowerNodes
\ No newline at end of file
+        self.invCg_tr = invCg_tr
+        self.viscCg_tr = viscCg_tr
\ No newline at end of file
diff --git a/dart/pyVII/vStructures.py b/dart/pyVII/vStructures.py
deleted file mode 100644
index fd6f7f5..0000000
--- a/dart/pyVII/vStructures.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import numpy as np
-
-class viscStruct:
-    def __init__(self, nPoints_surf, nPoints_wake):
-        self.nSurfNodes = nPoints_surf
-        self.nWakeNodes = nPoints_wake
-
-        self.nodesReal = np.zeros((self.nSurfNodes, 3)) # Coordinates of surface nodes in the real space
-        self.nodesTrans = np.zeros((self.nWakeNodes, 3)) # Coordinates of surface nodes in the transformed space
-
-        # Usefull variables for section representation
-        self.chordLength = 0.
-        self.leCoord = 0.
-
-
-        self.nodesWake = np.zeros((nPoints_wake, 3))
-
-    def GenerateDistri(self):
-        xDistri = self.le_coord + 1/2*(1 + np.cos(np.linspace(0, np.pi, len(self.nSurfNodes))))*self.chordLength
-        self.nodesReal[:,0] = np.concatenate((xDistri[:-1], xDistri[::-1]), axis=None)
-
-class invStruct:
-    def __init__(self, _bndSurf, _bndWake, _nDim):
-        self.nDim = _nDim
-
-        self.bndSurf = _bndSurf
-        self.bndWake = _bndWake
-
-        self.nSurfNodes = self.bndSurf.nodes.size()
-
-        # np matrix of nodes coordinate in the transformed space associated to the c++ structures 'node' in nodesList
-        # (coordinates at indice i in 'nodesTrans' correspond to the node at position i in 'nodesList')
-        self.nodesTrans = np.zeros(self.nSurfNodes,3)
-        self.nodesList = [None for _ in range(self.nSurfNodes)]
-
-    def CreateList(self):
-        
-        nodesReal = np.zeros((self.nSurfNodes, 3))
-        nodeList = [None for _ in range(self.nSurfNodes)]
-        for iNode, n in enumerate(self.bndSurf.nodes):
-            nodesReal[iNode, :] = [n.pos[0], n.pos[1], n.pos[2]]
-            nodeList[iNode] = n
-        
-        
-
-
diff --git a/dart/pyVII/vUtils.py b/dart/pyVII/vUtils.py
index a8423fd..7009f8d 100644
--- a/dart/pyVII/vUtils.py
+++ b/dart/pyVII/vUtils.py
@@ -50,36 +50,7 @@ def GetSolution(iSec, vSolver):
          'Cdp'      : vSolver.Cdp}
   return sln
 
-
-def Dictionary(blScalars, blVectors, xtr):
-  """Create dictionary with the coordinates and the boundary layer parameters
-  """
-
-  wData = {}
-  # [xx, x, deltaStar, theta, H, N, Ue, Hk, Hstar, Hstar2, Cf, Cd, Ct, delta, VtExt, Me, Rhoe]
-  wData['xx']         = blVectors[0]
-  wData['x/c']        = blVectors[1]
-  wData['deltaStar']  = blVectors[2]
-  wData['theta']      = blVectors[3]
-  wData['H']          = blVectors[4]
-  wData['N']          = blVectors[5]
-  wData['Ue']         = blVectors[6]
-  wData['Ct']         = blVectors[7]
-  wData['Hk']         = blVectors[8]
-  wData['Hstar']      = blVectors[9]
-  wData['HStar2']     = blVectors[10]
-  wData['Cf']         = blVectors[11]
-  wData['Cd']         = blVectors[12]
-  wData['delta']      = blVectors[13]
-  wData['VtExt']      = blVectors[14]
-  wData['Me']         = blVectors[15]
-  wData['Rhoe']       = blVectors[16]
-  wData['Blowing']    = blVectors[17]
-  wData['xtrTop']     = xtr[0]
-  wData['xtrBot']     = xtr[1]
-  return wData
-
-def WriteFile(wData, Re, toW=['delta*', 'H', 'Cf', 'Ctau']):
+def WriteFile(wData, Re, toW=['deltaStar', 'H', 'Cf', 'Ct', 'delta']):
   """Write the results in airfoil_viscous.dat
   """
   
@@ -89,18 +60,18 @@ def WriteFile(wData, Re, toW=['delta*', 'H', 'Cf', 'Ctau']):
 
   f.write('$Aerodynamic coefficients\n')
   f.write('             Re              Cd             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['Cd'], wData['Cdp'],
-                                                                                  wData['Cdf'], wData['xtrTop'],
-                                                                                  wData['xtrBot']))
+  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'], wData['Cdp'],
+                                                                                  wData['Cdf'], wData['xtrT'],
+                                                                                  wData['xtrB']))
   f.write('$Boundary layer variables\n')
-  f.write('              x               y               z             x/c')
+  f.write('            x/c')
 
   for s in toW:
     f.write(' {0:>15s}'.format(s))
   f.write('\n')
 
-  for i in range(len(self.data[:,0])):
-    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/c'][i]))
+  for i in range(len(wData['x/c'])):
+    f.write('{0:15.6f}'.format(wData['x/c'][i]))
     for s in toW:
       f.write(' {0:15.6f}'.format(wData[s][i]))
     f.write('\n')
@@ -108,17 +79,6 @@ def WriteFile(wData, Re, toW=['delta*', 'H', 'Cf', 'Ctau']):
   f.close()
   print('done.')
 
-def ExtractVars(viscSolver):
-  import numpy as np
-
-  blScalars = [viscSolver.Cdt, viscSolver.Cdf, viscSolver.Cdp]
-  
-  # [xx, x, deltaStar, theta, H, N, Ue, Hk, Hstar, Hstar2, Cf, Cd, Ct, delta, VtExt, Me, Rhoe, Blowing]
-
-  blVectors = viscSolver.ExtractSolution()
-
-
-  return blScalars, blVectors
 
 def PlotVars(wData, var='H'):
   from matplotlib import pyplot as plt
diff --git a/dart/src/wBody.cpp b/dart/src/wBody.cpp
index 511e9be..f81ef6d 100644
--- a/dart/src/wBody.cpp
+++ b/dart/src/wBody.cpp
@@ -41,6 +41,10 @@ Body::Body(std::shared_ptr<MshData> _msh, std::vector<int> const &nos) : Groups(
 
 Body::Body(std::shared_ptr<MshData> _msh, std::vector<std::string> const &names) : Groups(_msh, names), Cl(0), Cd(0), Cs(0), Cm(0)
 {
+    for (auto i=0; i<names.size(); ++i)
+    {
+        std::cout << names[i] << std::endl;
+    }
     // Sanity check
     if (groups.size() != 2)
     {
diff --git a/dart/src/wClosures.cpp b/dart/src/wClosures.cpp
index f9874c4..7f867be 100644
--- a/dart/src/wClosures.cpp
+++ b/dart/src/wClosures.cpp
@@ -103,14 +103,6 @@ std::vector<double> Closures::LaminarClosures(double theta, double H, double Ret
     ClosureVars[6] = Cteq;
     ClosureVars[7] = Us;
 
-    for (size_t i=0; i<ClosureVars.size(); ++i)
-    {
-        if (std::isnan(ClosureVars[i]))
-        {
-            std::cout << "lam : nan detected in closureVars at position " << i << std::endl;
-            //throw;
-        }
-    }
     return ClosureVars;
 }
 
@@ -135,15 +127,15 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C
     }
 
     double Hstar2 = ((0.064/(Hk-0.8))+0.251)*Me*Me;
-    double gamma = 1.4;
-    double Fc = std::sqrt(1+0.5*gamma*Me*Me);
+    double gamma = 1.4 - 1.;
+    double Fc = std::sqrt(1+0.5*gamma*Me*Me); /* .2 can be used as well replacing .5*gamma */
 
     double H0 = 0.;
     if (Ret <= 400)
     {
         H0 = 4.0;
     }
-    else if (Ret > 400)
+    else
     {
         H0 = 3 + (400/Ret);
     }
@@ -157,7 +149,7 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C
     {
         Hstar = ((0.5-4/Ret)*((H0-Hk)/(H0-1))*((H0-Hk)/(H0-1)))*(1.5/(Hk+0.5))+1.5+4/Ret;
     }
-    else if (Hk > H0)
+    else
     {
         Hstar = (Hk-H0)*(Hk-H0)*(0.007*std::log(Ret)/((Hk-H0+4/std::log(Ret))*(Hk-H0+4/std::log(Ret))) + 0.015/Hk) + 1.5 + 4/Ret;
     }
@@ -166,11 +158,6 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C
 
 
     double logRt = std::log(Ret/Fc);
-    if (std::isnan(logRt))
-    {
-        std::cout << "logRt is nan. Ret= " << Ret << std::endl;
-        //throw;
-    }
     logRt = std::max(logRt, 3.0);
     double arg = std::max(-1.33*Hk, -20.0);
 
@@ -195,6 +182,8 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C
     double Cd = 0.;
 
     double n = 1.0;
+
+    double Cteq = 0.;
     
     if (name == "wake")
     {
@@ -208,6 +197,7 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C
         Cdw = 0.0;  // wall contribution
         Cdd = (0.995-Us)*Ct*Ct; // turbulent outer layer contribution
         Cdl = 0.15*(0.995-Us)*(0.995-Us)/Ret; // laminar stress contribution to outer layer
+        Cteq = std::sqrt(4*Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H)); // Here it is Cteq^0.5
     }
     else
     {
@@ -225,13 +215,14 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C
         Cdw = 0.5*(Cf*Us) * Dfac;
         Cdd = (0.995-Us)*Ct*Ct;
         Cdl = 0.15*(0.995-Us)*(0.995-Us)/Ret;
+        Cteq = std::sqrt(Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H)); // Here it is Cteq^0.5
     }
     if (n*Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H)<0)
     {
         std::cout << "Negative sqrt encountered " << std::endl;
         //throw;
     }
-    double Cteq = std::sqrt(n*Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H));
+    //double Cteq = std::sqrt(n*Hstar*Ctcon*((Hk-1)*Hkc*Hkc)/((1-Us)*(Hk*Hk)*H));
     Cd = n*(Cdw+ Cdd + Cdl);
     // Ueq = 1.25/Hk*(Cf/2-((Hk-1)/(6.432*Hk))**2)
 
@@ -246,13 +237,5 @@ std::vector<double> Closures::TurbulentClosures(double theta, double H, double C
     ClosureVars[6] = Cteq;
     ClosureVars[7] = Us;
 
-    for (size_t i=0; i<ClosureVars.size(); ++i)
-    {
-        if (std::isnan(ClosureVars[i]))
-        {
-            std::cout << "turb : nan detected in closureVars at position " << i << std::endl;
-            //throw;
-        }
-    }
     return ClosureVars;
 }
\ No newline at end of file
diff --git a/dart/src/wViscFluxes.cpp b/dart/src/wViscFluxes.cpp
index 15daf4a..0346a58 100644
--- a/dart/src/wViscFluxes.cpp
+++ b/dart/src/wViscFluxes.cpp
@@ -129,7 +129,6 @@ VectorXd ViscFluxes::BLlaws(size_t iPoint, BLRegion *bl, std::vector<double> u)
     double dHstar_dx = (bl->Hstar[iPoint] - bl->Hstar[iPoint - 1]) / dx;
 
     double dueExt_dx = (bl->invBnd->GetVt(iPoint) - bl->invBnd->GetVt(iPoint - 1)) / dxExt;
-    //std::cout << bl->invBnd->GetVtOld(iPoint) << " " << bl->invBnd->GetVt(iPoint) << std::endl;
     double ddeltaStarExt_dx = (bl->invBnd->GetDeltaStar(iPoint) - bl->invBnd->GetDeltaStar(iPoint - 1)) / dxExt;
 
     double c = 4 / (M_PI * dx);
diff --git a/dart/src/wViscSolver.cpp b/dart/src/wViscSolver.cpp
index a3d0f9b..2a06c2c 100644
--- a/dart/src/wViscSolver.cpp
+++ b/dart/src/wViscSolver.cpp
@@ -268,6 +268,7 @@ int ViscSolver::Run(unsigned int const couplIter)
             if (verbose>2){"Blowing velocities of " + Sections[iSec][iRegion]->name + " side computed.";}
 
         }     // End for iRegion
+        if (verbose>0){std::cout << "\n";}
     } // End for iSections
 
     ComputeDrag(Sections[0]);
@@ -487,6 +488,7 @@ void ViscSolver::SetDeltaStarExt(size_t iSec, size_t iRegion, std::vector<double
 {
     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("dart::ViscSolver External delta star vector is not coherent with the mesh.");
     }
     Sections[iSec][iRegion]->invBnd->SetDeltaStar(_DeltaStarExt);
diff --git a/dart/tests/bli2.py b/dart/tests/bli2.py
new file mode 100644
index 0000000..26c8a75
--- /dev/null
+++ b/dart/tests/bli2.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python3 
+# -*- coding: utf-8 -*-
+
+# Copyright 2020 University of Liège
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+## Compute lifting (linear or nonlinear) viscous flow around a NACA 0012
+# Amaury Bilocq
+#
+# Test the viscous-inviscid interaction scheme
+# Reference to the master's thesis: http://hdl.handle.net/2268/252195
+# Reference test cases with Naca0012 (different from master's thesis):
+# 1) Incompressible: Re = 1e7, M_inf = 0, alpha = 5°, msTE = 0.01, msLE = 0.01
+#    -> nIt = 27, Cl = 0.55, Cd = 0.0058, xtrTop = 0.087, xtrBot = 0.741
+#    -> msLe = 0.001, xtrTop = 0.061
+# 2) Compressible: Re = 1e7, M_inf = 5, alpha = 5°, msTE = 0.01, msLE = 0.01
+#    -> nIt = 33, Cl = 0.65, Cd = 0.0063, xtrTop = 0.057, xtrBot = 0.740
+# 3) Separated: Re = 1e7, M_inf = 0, alpha = 12°, msTE = 0.01, msLE = 0.001
+#    -> nIt = 43, Cl = 1.30 , Cd = 0.0108, xtrTop = 0.010, xtrBot = 1
+#
+# CAUTION
+# This test is provided to ensure that the solver works properly.
+# Mesh refinement may have to be performed to obtain physical results.
+
+import dart.utils as floU
+import dart.default as floD
+#import dart.viscUtils as viscU
+
+import dart.pyVII.vCoupler as floVC
+import dart.pyVII.vUtils as viscU
+import numpy as np
+
+import tbox
+import tbox.utils as tboxU
+import fwk
+from fwk.testing import *
+from fwk.coloring import ccolors
+from matplotlib import pyplot as plt
+
+import math
+
+def main():
+    print('Start')
+    # timer
+    tms = fwk.Timers()
+    tms['total'].start()
+
+    # define flow variables
+    Re = 1e7
+    alpha = 2*math.pi/180
+    M_inf = 0.715
+
+    CFL0 = 1
+
+    nSections = 1
+    
+    # ========================================================================================
+
+    c_ref = 1
+    dim = 2
+
+    # mesh the geometry
+    print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET)
+    tms['msh'].start()
+
+    pars = {'xLgt' : 5, 'yLgt' : 5, 'msF' : 1, 'msTe' : 0.01, 'msLe' : 0.005}
+    msh, gmshWriter = floD.mesh(dim, 'models/rae2822.geo', pars, ['field', 'airfoil', 'downstream'])
+    tms['msh'].stop()
+
+    # set the problem and add medium, initial/boundary conditions
+    tms['pre'].start()
+    pbl, _, _, bnd, blw = floD.problem(msh, dim, alpha, 0., M_inf, c_ref, c_ref, 0.25, 0., 0., 'airfoil', te = 'te', vsc = True, dbc=True)
+    tms['pre'].stop()
+
+    # solve viscous problem
+
+    print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
+    tms['solver'].start()
+    
+    isolver = floD.newton(pbl)
+    vsolver = viscU.initBL(Re, M_inf, CFL0, nSections)
+    config = {'nDim': dim, 'nSections':nSections, 'nPoints':[600, 50], 'eps':0.02, 'rbftype': 'cubic', 'smoothing': 0.0, 'degree': 1, 'neighbors': 10}
+
+    coupler = floVC.Coupler(isolver, vsolver)
+    coupler.CreateProblem(blw[0], blw[1])
+    coupler.Run()
+
+    # extract Cp
+    Cp = floU.extract(bnd.groups[0].tag.elems, isolver.Cp)
+    tboxU.write(Cp, 'Cp.dat', '%1.5e', ', ', 'x, y, z, Cp', '')
+    # 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(Re/1e6, M_inf, alpha*180/math.pi, isolver.Cl, vsolver.Cdt, vsolver.Cdp, vsolver.Cdf, isolver.Cm))
+
+    # Write results to file
+    vSol = viscU.GetSolution(0, vsolver)
+    viscU.WriteFile(vSol, vsolver.GetRe())
+
+    # display timers
+    tms['total'].stop()
+    print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
+    print('CPU statistics')
+    print(tms)
+    print('SOLVERS statistics')
+    print(coupler.tms)
+
+    xtr=vsolver.Getxtr()
+    
+    """# visualize solution and plot results
+    #floD.initViewer(pbl)
+    tboxU.plot(Cp[:,0], Cp[:,3], 'x', 'Cp', 'Cl = {0:.{3}f}, Cd = {1:.{3}f}, Cm = {2:.{3}f}'.format(isolver.Cl, vsolver.Cdt, isolver.Cm, 4), True)
+
+    blScalars, blVectors = viscU.ExtractVars(vsolver)
+    wData = viscU.Dictionary(blScalars, blVectors, xtr)
+    viscU.PlotVars(wData, plotVar)"""
+
+    
+    # check results
+    print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET)
+    tests = CTests()
+    if Re == 1e7 and M_inf == 0. and alpha == 2.*math.pi/180:
+        tests.add(CTest('Cl', isolver.Cl, 0.2208, 5e-3))
+        tests.add(CTest('Cd', vsolver.Cdt, 0.00531, 1e-3, forceabs=True))
+        tests.add(CTest('Cdp', vsolver.Cdp, 0.0009, 1e-3, forceabs=True))
+        tests.add(CTest('xtr_top', xtr[0], 0.20, 0.03, forceabs=True))
+        tests.add(CTest('xtr_bot', xtr[1], 0.50, 0.03, forceabs=True))
+    if Re == 1e7 and M_inf == 0. and alpha == 5.*math.pi/180:
+        tests.add(CTest('Cl', isolver.Cl, 0.5488, 5e-3))
+        tests.add(CTest('Cd', vsolver.Cdt, 0.0062, 1e-3, forceabs=True))
+        tests.add(CTest('Cdp', vsolver.Cdp,0.0018, 1e-3, forceabs=True))
+        tests.add(CTest('xtr_top', xtr[0], 0.06, 0.03, forceabs=True))
+        tests.add(CTest('xtr_bot', xtr[1], 0.74, 0.03, forceabs=True))
+    else:
+        raise Exception('Test not defined for this flow')
+
+    tests.run()
+
+
+    # eof
+    print('')
+
+if __name__ == "__main__":
+    main()
diff --git a/dart/tests/bli3.py b/dart/tests/bli3.py
index 6ef0ad4..792d16b 100644
--- a/dart/tests/bli3.py
+++ b/dart/tests/bli3.py
@@ -30,7 +30,7 @@ import dart.utils as floU
 import dart.default as floD
 
 import dart.pyVII.vUtils as viscU
-import dart.pyVII.vCoupler as viscC
+import dart.pyVII.vCoupler2 as viscC
 import dart.pyVII.vInterpolator as vInterpol
 
 import fwk
@@ -43,9 +43,12 @@ def main():
     tms['total'].start()
 
     # define flow variables
-    Re = 11.72e6
+    """Re = 11.72e6
     alpha = 3.06*math.pi/180
-    M_inf = 0.8395
+    M_inf = 0.8395"""
+    Re = 1e7
+    alpha = 0.*math.pi/180
+    M_inf = 0.
     dim = 3
     CFL0 = 1
 
@@ -74,16 +77,13 @@ def main():
     tms['pre'].stop()
 
     # solve problem
-    config = {'nDim': dim, 'nSections':nSections, 'nPoints':[500, 25], 'eps':0.05, 'k':[5, 5]}
-    iSolverAPI = vInterpol.Interpolator(floD.newton(pbl), blw[0], blw[1], config)
-    vSolver = viscU.initBL(Re, M_inf, CFL0, nSections)
+    config = {'nDim': dim, 'nSections':nSections, 'span':spn, 'nPoints':[200, 25], 'eps':0.02, 'rbftype': 'cubic', 'smoothing': 0.001, 'degree': 1, 'neighbors': 5}
+    iSolverAPI = vInterpol.Interpolator(floD.newton(pbl), blw, config)
+    vSolver = viscU.initBL(Re, M_inf, CFL0, nSections, 2)
     #iSolverAPI = viscAPI.dartAPI(floD.newton(pbl), bnd, wk, nSections, vInterp)
     coupler = viscC.Coupler(iSolverAPI, vSolver)
 
-    try:
-        coupler.Run()
-    except Exception as e:
-        print('VII convergence terminated, ', str(e.args[0]))
+    coupler.Run()
 
     # display timers
     tms['total'].stop()
diff --git a/dart/tests/bli_lowLift.py b/dart/tests/bli_lowLift.py
index 544b06a..10c1ae6 100644
--- a/dart/tests/bli_lowLift.py
+++ b/dart/tests/bli_lowLift.py
@@ -59,7 +59,7 @@ def main():
 
     # define flow variables
     Re = 1e7
-    alpha = 0*math.pi/180
+    alpha = 5*math.pi/180
     M_inf = 0.
 
     CFL0 = 1
@@ -71,7 +71,7 @@ def main():
     c_ref = 1
     dim = 2
 
-    nRel = 5
+    nRel = 1
 
     nomDeVariableDePorc_x = [None for _ in range(nRel)]
     nomDeVariableDePorc_var = [None for _ in range(nRel)]
diff --git a/dart/tests/bli_lowLift2.py b/dart/tests/bli_lowLift2.py
index 7704020..05ab0ab 100644
--- a/dart/tests/bli_lowLift2.py
+++ b/dart/tests/bli_lowLift2.py
@@ -61,22 +61,22 @@ def main():
 
     # define flow variables
     Re = 1e7
-    alpha = 2*math.pi/180
+    alpha = 5*math.pi/180
     M_inf = 0.
 
     CFL0 = 1
 
     nSections = 1
+    verbose = 0
     
     # ========================================================================================
 
     c_ref = 1
     dim = 2
 
-    nPv = [100, 100, 100]
+    nPv = [200]
     aeroCoeff = [np.zeros(2) for i in range(len(nPv))]
 
-    fig, axs = plt.subplots(2,1)
 
     for i in range(len(nPv)):
 
@@ -85,7 +85,7 @@ def main():
         tms['msh'].start()
         
         pars = {'xLgt' : 5, 'yLgt' : 5, 'msF' : 1, 'msTe' : 0.01, 'msLe' : 0.001}
-        msh, gmshWriter = floD.mesh(dim, 'models/n0012.geo', pars, ['field', 'airfoil', 'downstream'])
+        msh, sortElm, gmshWriter = floD.mesh(dim, 'models/n0012.geo', pars, ['field', 'airfoil', 'downstream'])
         tms['msh'].stop()
 
         # set the problem and add medium, initial/boundary conditions
@@ -99,31 +99,24 @@ def main():
         tms['solver'].start()
         
         isolver = floD.newton(pbl)
-        vsolver = viscU.initBL(Re, M_inf, CFL0, nSections, 0)
-        config = {'nDim': dim, 'nSections':nSections, 'nPoints':[nPv[i], 25], 'eps':0.02, 'rbftype': 'cubic', 'smoothing': 0.0, 'degree': 1, 'neighbors': 3}
+        if verbose == 0:
+            isolver.printOn = False
+        vsolver = viscU.initBL(Re, M_inf, CFL0, nSections, verbose)
+        config = {'nDim': dim, 'nSections':nSections, 'nPoints':[nPv[i], 25], 'eps':0.02, 'rbftype': 'cubic', 'smoothing': 0.0, 'degree': 1, 'neighbors': 15}
 
-        iSolverAPI = Interpol.Interpolator(isolver, blw[0], blw[1], config)
+        iSolverAPI = Interpol.Interpolator(isolver, sortElm, blw, config)
 
         coupler = viscC.Coupler(iSolverAPI, vsolver)
         aeroCoeff[i] = coupler.Run()
-        axs[0].plot(aeroCoeff[i][:,0], 'x-')
-        axs[1].plot(aeroCoeff[i][:,1], 'x-')
 
-        del isolver
+        """del isolver
         del vsolver
         del iSolverAPI
         del pbl
         del bnd
         del blw
         del msh
-        del gmshWriter
-
-    axs[0].set_xlabel('x/c')
-    axs[0].set_ylabel('Cl')
-    axs[0].set_ylim([-.1, .1])
-    axs[1].set_xlabel('x/c')
-    axs[1].set_ylabel('Cd')
-    plt.show()
+        del gmshWriter"""
     tms['solver'].stop()
 
     # extract Cp
diff --git a/dart/tests/rae_3.py b/dart/tests/rae_3.py
index f720dc4..f1f8add 100644
--- a/dart/tests/rae_3.py
+++ b/dart/tests/rae_3.py
@@ -62,14 +62,37 @@ def main():
     print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET)
     tms["msh"].start()
     pars = {'spn' : spn, 'lgt' : lgt, 'wdt' : wdt, 'hgt' : hgt, 'msN' : nms, 'msF' : fms}
-    msh, gmshWriter = floD.mesh(dim, 'models/rae_3.geo', pars, ['field', 'wing', 'symmetry', 'downstream'], wktp = 'wakeTip')
+    msh, sortElm, gmshWriter = floD.mesh(dim, 'models/rae_3.geo', pars, ['field', 'wing', 'symmetry', 'downstream'], wktp = 'wakeTip')
     morpher = floD.morpher(msh, dim, ['wing'])
     tms["msh"].stop()
 
     # set the problem and add fluid, initial/boundary conditions
     tms['pre'].start()
-    pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'wakeTip')
+    pbl, _, _, bnd, blw = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'wakeTip', vsc=True)
 
+    upperNodes = np.zeros((0,4))
+    lowerNodes = np.zeros((0,4))
+
+    for e in blw[0].tag.elems:
+        if e.no in sortElm['upper']:
+            for n in e.nodes:
+                if n.row not in upperNodes[:,3]:
+                    upperNodes = np.vstack((upperNodes, [n.pos[0], n.pos[1], n.pos[2], n.row]))
+        elif e.no in sortElm['lower']:
+            for n in e.nodes:
+                if n.row not in lowerNodes[:,3]:
+                    lowerNodes = np.vstack((lowerNodes, [n.pos[0], n.pos[1], n.pos[2], n.row]))
+    
+    fig = plt.figure()
+    ax = fig.add_subplot(projection='3d')
+    ax.scatter(upperNodes[:,0], upperNodes[:,1], upperNodes[:,2], s=0.3, color='red')
+    ax.scatter(lowerNodes[:,0], lowerNodes[:,1], lowerNodes[:,2], s=0.3, color='blue')
+    #ax.scatter(wake[:,0], wake[:,1], wake[:,2], s=0.3)
+    #ax.set_zlim([-0.5, 0.5])
+    ax.set_xlabel('x')
+    ax.set_ylabel('y')
+    ax.set_zlabel('z')
+    plt.show()
     span = 0.5
     elemPlot = []
     for e in bnd.groups[0].tag.elems:
-- 
GitLab