From 1f95c6a3ca0c95a7d9187b480a30a5f5d525d7fe Mon Sep 17 00:00:00 2001
From: Paul Dechamps <paul.dechamps@uliege.be>
Date: Thu, 27 Feb 2025 18:38:45 +0100
Subject: [PATCH] (feat) Modify interpolators for new data structures

---
 .../interpolators/blMatchingInterpolator.py   |  16 +-
 .../interpolators/blRbfInterpolator.py        | 275 +++++++++---------
 2 files changed, 151 insertions(+), 140 deletions(-)

diff --git a/blast/interfaces/interpolators/blMatchingInterpolator.py b/blast/interfaces/interpolators/blMatchingInterpolator.py
index 5f90c89..4fd0ada 100644
--- a/blast/interfaces/interpolators/blMatchingInterpolator.py
+++ b/blast/interfaces/interpolators/blMatchingInterpolator.py
@@ -61,15 +61,11 @@ class MatchingInterpolator(Interpolator):
         """
         if self.ndim == 2:
             for ibody in range(len(iDict)):
-                for ireg in range(len(iDict[ibody])):
-                    vDict[ibody][0][ireg].updateVars(iDict[ibody][ireg].V, iDict[ibody][ireg].M, iDict[ibody][ireg].Rho)
-        elif self.ndim == 3:
-            for ibody in range(len(iDict)):
-                for isec, ysec in enumerate(self._sections):
-                    for ireg in range(2):
-                        print(iDict[ibody][ireg].nodesCoord[iDict[ireg].nodesCoord[:,1] == ysec])
-                        print(iDict[ibody][ireg].V[iDict[ireg].nodesCoord[:,1] == ysec])
-                        vDict[ibody][isec][ireg].updateVars(iDict[ibody][ireg].V[iDict[ibody][ireg].nodesCoord[:,1] == ysec], iDict[ibody][ireg].Rho[iDict[ibody][ireg].nodesCoord[:,1] == ysec])
+                for i, ireg in enumerate(iDict[ibody]):
+                    vreg = vDict[ibody][0][i]
+                    vreg.updateVariables(ireg.getMach('all'), ireg.getVelocity('all'), ireg.getDensity('all'))
+        else:
+            raise RuntimeError('Incorrect number of dimensions', self.ndim)
 
     def viscousToInviscid(self, iDict, vDict):
         """
@@ -85,6 +81,6 @@ class MatchingInterpolator(Interpolator):
         if self.ndim == 2:
             for ibody in range(len(iDict)):
                 for iReg in range(len(iDict[ibody])):
-                    iDict[ibody][iReg].blowingVel = vDict[ibody][0][iReg].blowingVel
+                    iDict[ibody][iReg].setBlowingVelocity(vDict[ibody][0][iReg].getBlowingVelocity())
         else:
             raise RuntimeError('Incorrect number of dimensions', self.ndim)
\ No newline at end of file
diff --git a/blast/interfaces/interpolators/blRbfInterpolator.py b/blast/interfaces/interpolators/blRbfInterpolator.py
index 35b8535..5f2d0a6 100644
--- a/blast/interfaces/interpolators/blRbfInterpolator.py
+++ b/blast/interfaces/interpolators/blRbfInterpolator.py
@@ -34,157 +34,172 @@ class RbfInterpolator(Interpolator):
     def inviscidToViscous(self, iDict, vDict):
 
         self.tms['tot'].start()
-        for ibody in range(len(iDict)):
-            if iDict[ibody][0].sidesIdentified and iDict[ibody][0].type == 'wing':
+        for ibody, inviscid_regions in enumerate(iDict):
+            inviscid_airfoil = inviscid_regions[0]
+            inviscid_wake = inviscid_regions[1]
+
+            if inviscid_airfoil.sidesIdentified and inviscid_airfoil.getType() == 'wing':
                 self.tms['getIdict'].start()
-                xi_up = iDict[ibody][0].getUpperNodes()
-                Mi_up = iDict[ibody][0].getUpperMach()
-                rhoi_up = iDict[ibody][0].getUpperDensity()
-                vi_up = iDict[ibody][0].getUpperVelocity()
-
-                # lower side
-                xi_lw = iDict[ibody][0].getLowerNodes()
-                Mi_lw = iDict[ibody][0].getLowerMach()
-                rhoi_lw = iDict[ibody][0].getLowerDensity()
-                vi_lw = iDict[ibody][0].getLowerVelocity()
-
-                # wake
-                xi_wk = iDict[ibody][1].nodesCoord[:, :self.ndim]
-                Mi_wk = iDict[ibody][1].M
-                rhoi_wk = iDict[ibody][1].Rho
-                vi_wk = iDict[ibody][1].V[:,:self.ndim]
-                self.tms['getIdict'].stop()
 
+                # Extract inviscid data for interpolation
+                xi_up, Mi_up, rhoi_up, vi_up = (
+                    inviscid_airfoil.getNodes('upper_fromLE')[:, :self.ndim],
+                    inviscid_airfoil.getMach('upper_fromLE'),
+                    inviscid_airfoil.getDensity('upper_fromLE'),
+                    inviscid_airfoil.getVelocity('upper_fromLE')[:, :self.ndim],
+                )
+
+                xi_lw, Mi_lw, rhoi_lw, vi_lw = (
+                    inviscid_airfoil.getNodes('lower_fromLE')[:, :self.ndim],
+                    inviscid_airfoil.getMach('lower_fromLE'),
+                    inviscid_airfoil.getDensity('lower_fromLE'),
+                    inviscid_airfoil.getVelocity('lower_fromLE')[:, :self.ndim],
+                )
+
+                xi_wk, Mi_wk, rhoi_wk, vi_wk = (
+                    inviscid_wake.getNodes('wake')[:, :self.ndim],
+                    inviscid_wake.getMach('wake'),
+                    inviscid_wake.getDensity('wake'),
+                    inviscid_wake.getVelocity('wake')[:, :self.ndim],
+                )
+
+                self.tms['getIdict'].stop()
                 self.tms['getVdict'].start()
-                # Viscous side
-                xv_up = np.empty((0, self.ndim), dtype=float)
-                xv_lw = np.empty((0, self.ndim), dtype=float)
-                xv_wk = np.empty((0, self.ndim), dtype=float)
-                for iSec in range(len(vDict[ibody])):
-                    xv_up = np.row_stack((xv_up, vDict[ibody][iSec][0].getUpperNodes()))
-                    xv_lw = np.row_stack((xv_lw, vDict[ibody][iSec][0].getLowerNodes()))
-                    xv_wk = np.row_stack((xv_wk, vDict[ibody][iSec][1].nodesCoord[:,:self.ndim]))
+
+                # Get viscous node
+                xv_up = np.vstack([sec[0].getNodes('upper_fromLE')[:, :self.ndim] for sec in vDict[ibody]])
+                xv_lw = np.vstack([sec[0].getNodes('lower_fromLE')[:, :self.ndim] for sec in vDict[ibody]])
+                xv_wk = np.vstack([sec[1].getNodes('wake')[:, :self.ndim] for sec in vDict[ibody]])
+
                 self.tms['getVdict'].stop()
-                # Interpolation
                 self.tms['rbf'].start()
-                Mv_up = self.__rbfToSection(xi_up, Mi_up, xv_up)
-                rhov_up = self.__rbfToSection(xi_up, rhoi_up, xv_up)
-                vv_up = np.zeros((xv_up.shape[0], self.ndim))
-                for idim in range(self.ndim):
-                    vv_up[:,idim] = self.__rbfToSection(xi_up, vi_up[:,idim], xv_up)
-
-                Mv_lw = self.__rbfToSection(xi_lw, Mi_lw, xv_lw)
-                rhov_lw = self.__rbfToSection(xi_lw, rhoi_lw, xv_lw)
-                vv_lw = np.zeros((xv_lw.shape[0], self.ndim))
-                for idim in range(self.ndim):
-                    vv_lw[:,idim] = self.__rbfToSection(xi_lw, vi_lw[:,idim], xv_lw)
-
-                Mv_wk = self.__rbfToSection(xi_wk, Mi_wk, xv_wk)
-                rhov_wk = self.__rbfToSection(xi_wk, rhoi_wk, xv_wk)
-                vv_wk = np.zeros((xv_wk.shape[0], self.ndim))
-                for idim in range(self.ndim):
-                    vv_wk[:,idim] = self.__rbfToSection(xi_wk, vi_wk[:,idim], xv_wk)
-                self.tms['rbf'].stop()
 
-                # The viscous structure is sorted in selig format.
-                # Here, upper and lower side are 'opposite' (upper is from TE to LE
-                # while lower is from LE to TE). It is important that it always stays
-                # this way for this concatenation operation.
+                # Perform vectorized RBF interpolation
+                Mv_up, rhov_up = self.__rbfToSection(xi_up, Mi_up, xv_up), self.__rbfToSection(xi_up, rhoi_up, xv_up)
+                Mv_lw, rhov_lw = self.__rbfToSection(xi_lw, Mi_lw, xv_lw), self.__rbfToSection(xi_lw, rhoi_lw, xv_lw)
+                Mv_wk, rhov_wk = self.__rbfToSection(xi_wk, Mi_wk, xv_wk), self.__rbfToSection(xi_wk, rhoi_wk, xv_wk)
+
+                vv_up = np.column_stack([self.__rbfToSection(xi_up, vi_up[:, dim], xv_up) for dim in range(self.ndim)])
+                vv_lw = np.column_stack([self.__rbfToSection(xi_lw, vi_lw[:, dim], xv_lw) for dim in range(self.ndim)])
+                vv_wk = np.column_stack([self.__rbfToSection(xi_wk, vi_wk[:, dim], xv_wk) for dim in range(self.ndim)])
+
+                self.tms['rbf'].stop()
                 self.tms['setting'].start()
-                cpt_up = 0
-                cpt_lw = 0
-                cpt_wk = 0
-                from matplotlib import pyplot as plt
+
+                # Assign values to each viscous section
+                cpt_up, cpt_lw, cpt_wk = 0, 0, 0
                 for sec in vDict[ibody]:
-                    M_airfoil = np.empty(sec[0].nPoints, dtype=float)
-                    M_wake = np.empty(sec[1].nPoints, dtype=float)
-                    rho_airfoil = np.empty(sec[0].nPoints, dtype=float)
-                    rho_wake = np.empty(sec[1].nPoints, dtype=float)
-                    v_airfoil = np.zeros((sec[0].nPoints, self.ndim), dtype=float)
-                    v_wake = np.zeros((sec[1].nPoints, self.ndim), dtype=float)
-
-                    # Mach number
-                    M_airfoil = np.concatenate((Mv_up[cpt_up:cpt_up+sec[0].getUpperNodes().shape[0]],
-                                                Mv_lw[cpt_lw:cpt_lw+sec[0].getLowerNodes().shape[0]]))
-                    M_wake = Mv_wk[cpt_wk:cpt_wk+sec[1].nPoints]
-                    # Density
-                    rho_airfoil = np.concatenate((rhov_up[cpt_up:cpt_up+sec[0].getUpperNodes().shape[0]],
-                                                rhov_lw[cpt_lw:cpt_lw+sec[0].getLowerNodes().shape[0]]))
-                    rho_wake = rhov_wk[cpt_wk:cpt_wk+sec[1].nPoints]
-
-                    # Velocity
-                    for idim in range(self.ndim):
-                        v_airfoil[:,idim] = np.concatenate((vv_up[cpt_up:cpt_up+sec[0].getUpperNodes().shape[0],idim],
-                                                        vv_lw[cpt_lw:cpt_lw+sec[0].getLowerNodes().shape[0],idim]))
-                        v_wake[:,idim] = vv_wk[cpt_wk:cpt_wk+sec[1].nPoints,idim]
-                    cpt_up += sec[0].getUpperNodes().shape[0]
-                    cpt_lw += sec[0].getLowerNodes().shape[0]
-                    cpt_wk += sec[1].nPoints
-
-                    sec[0].updateVars(v_airfoil, M_airfoil, rho_airfoil)
-                    sec[1].updateVars(v_wake, M_wake, rho_wake)
+                    n_up = sec[0].getNodes('upper_fromLE').shape[0]
+                    n_lw = sec[0].getNodes('lower_fromLE').shape[0]
+                    n_wk = sec[1].getnNodes()
+
+                    # Concatenate Mach number and density
+                    M_airfoil = np.concatenate((Mv_up[cpt_up:cpt_up + n_up], Mv_lw[cpt_lw:cpt_lw + n_lw]))
+                    rho_airfoil = np.concatenate((rhov_up[cpt_up:cpt_up + n_up], rhov_lw[cpt_lw:cpt_lw + n_lw]))
+                    M_wake, rho_wake = Mv_wk[cpt_wk:cpt_wk + n_wk], rhov_wk[cpt_wk:cpt_wk + n_wk]
+
+                    # Concatenate velocity
+                    v_airfoil = np.column_stack([
+                        np.concatenate((vv_up[cpt_up:cpt_up + n_up, dim], vv_lw[cpt_lw:cpt_lw + n_lw, dim]))
+                        for dim in range(self.ndim)
+                    ])
+                    v_wake = vv_wk[cpt_wk:cpt_wk + n_wk]
+
+                    # Update the variables
+                    sec[0].updateVariables(M_airfoil, v_airfoil, rho_airfoil)
+                    sec[1].updateVariables(M_wake, v_wake, rho_wake)
+
+                    # Update counters
+                    cpt_up += n_up
+                    cpt_lw += n_lw
+                    cpt_wk += n_wk
+
                 self.tms['setting'].stop()
+
             else:
-                for iSec in range(len(vDict[ibody])):
-                    for iReg, reg in enumerate(vDict[ibody][iSec]):
-                        v = np.zeros((reg.nodesCoord.shape[0], 3))
-                        M = np.zeros(reg.nodesCoord.shape[0])
-                        rho = np.zeros(reg.nodesCoord.shape[0])
-                        for iDim in range(self.ndim):
-                            v[:,iDim] = self.__rbfToSection(iDict[ibody][iReg].nodesCoord[:,:(self.ndim if iDict[ibody][iReg].name == 'iWing' else 1)], iDict[ibody][iReg].V[:,iDim], reg.nodesCoord[:,:(self.ndim if 'vAirfoil' in reg.name else 1)])
-                        M = self.__rbfToSection(iDict[ibody][iReg].nodesCoord[:,:(self.ndim if iDict[ibody][iReg].name == 'iWing' else 1)], iDict[ibody][iReg].M, reg.nodesCoord[:,:(self.ndim if 'vAirfoil' in reg.name else 1)])
-                        rho = self.__rbfToSection(iDict[ibody][iReg].nodesCoord[:,:(self.ndim if iDict[ibody][iReg].name == 'iWing' else 1)], iDict[ibody][iReg].Rho, reg.nodesCoord[:,:(self.ndim if 'vAirfoil' in reg.name else 1)])
-                        vDict[ibody][iSec][iReg].updateVars(v, M, rho)
+                # General case
+                for iSec, sections in enumerate(vDict[ibody]):
+                    for iReg, reg in enumerate(sections):
+                        n_nodes = reg.getnNodes()
+
+                        slice_dim = self.ndim if 'vAirfoil' in reg._name else 1
+                        xi = iDict[ibody][iReg].getNodes('all')[:, :slice_dim]
+                        xv = reg.getNodes('all')[:, :slice_dim]
+
+                        # Perform RBF interpolation
+                        v = np.column_stack([
+                            self.__rbfToSection(xi, iDict[ibody][iReg].getVelocity(reg='all')[:,dim], xv)
+                            for dim in range(self.ndim)
+                        ])
+                        M = self.__rbfToSection(xi, iDict[ibody][iReg].getMach('all'), xv)
+                        rho = self.__rbfToSection(xi, iDict[ibody][iReg].getDensity('all'), xv)
+
+                        # Update the variables
+                        reg.updateVariables(M, v, rho)
+        self.tms['tot'].stop()
 
     def viscousToInviscid(self, iDict, vDict):
 
         for ibody in range(len(iDict)):
             if iDict[ibody][0].sidesIdentified:
-                # Viscous side
-                xv_up = np.zeros((0, self.ndim))
-                xv_lw = np.zeros((0, self.ndim))
-                xv_wk = np.zeros((0, self.ndim))
-                blwv_up = np.zeros(0)
-                blwv_lw = np.zeros(0)
-                blwv_wk = np.zeros(0)
-                for iSec, sec in enumerate(vDict[ibody]):
-                    xv_up = np.row_stack((xv_up, sec[0].getUpperElems()))
-                    xv_lw = np.row_stack((xv_lw, sec[0].getLowerElems()))
-                    xv_wk = np.row_stack((xv_wk, sec[1].elemsCoord[:,:self.ndim]))
-                    blwv_up = np.concatenate((blwv_up, sec[0].getUpperBlowingVel()))
-                    blwv_lw = np.concatenate((blwv_lw, sec[0].getLowerBlowingVel()))
-                    blwv_wk = np.concatenate((blwv_wk, sec[1].blowingVel))
-
-                # Inviscid side
-                xi_up = iDict[ibody][0].getUpperElems()
-                xi_lw = iDict[ibody][0].getLowerElems()
-                xi_wk = iDict[ibody][1].elemsCoord[:,:self.ndim]
-
-                blwi_up = self.__rbfToSection(xv_up, blwv_up, xi_up[:,:self.ndim])
-                blwi_lw = self.__rbfToSection(xv_lw, blwv_lw, xi_lw[:,:self.ndim])
-                blwi_wk = self.__rbfToSection(xv_wk, blwv_wk, xi_wk[:,:self.ndim])
-
-                iDict[ibody][0].blowingVel = np.concatenate((blwi_up, blwi_lw))
-                iDict[ibody][1].blowingVel = blwi_wk
+                # Extract elements and blowing velocity for the viscous side
+                xv_up, xv_lw, xv_wk = [], [], []
+                blwv_up, blwv_lw, blwv_wk = [], [], []
+
+                for sec in vDict[ibody]:
+                    xv_up.append(sec[0].getElms('upper_fromLE')[:, :self.ndim])
+                    xv_lw.append(sec[0].getElms('lower_fromLE')[:, :self.ndim])
+                    xv_wk.append(sec[1].getElms('wake')[:, :self.ndim])
+
+                    blwv_up.append(sec[0].getBlowingVelocity('upper_fromLE'))
+                    blwv_lw.append(sec[0].getBlowingVelocity('lower_fromLE'))
+                    blwv_wk.append(sec[1].getBlowingVelocity('wake'))
+
+                xv_up, xv_lw, xv_wk = map(np.vstack, [xv_up, xv_lw, xv_wk])
+                blwv_up, blwv_lw, blwv_wk = map(np.concatenate, [blwv_up, blwv_lw, blwv_wk])
+
+                # Extract elements for the inviscid side
+                xi_up = iDict[ibody][0].getElms('upper_fromLE')[:, :self.ndim]
+                xi_lw = iDict[ibody][0].getElms('lower_fromLE')[:, :self.ndim]
+                xi_wk = iDict[ibody][1].getElms('wake')[:, :self.ndim]
+
+                # Perform RBF interpolation
+                blwi_up = self.__rbfToSection(xv_up, blwv_up, xi_up)
+                blwi_lw = self.__rbfToSection(xv_lw, blwv_lw, xi_lw)
+                blwi_wk = self.__rbfToSection(xv_wk, blwv_wk, xi_wk)
+
+                # Set interpolated blowing velocity for inviscid side
+                iDict[ibody][0].setBlowingVelocity(np.concatenate((blwi_up, blwi_lw)))
+                iDict[ibody][1].setBlowingVelocity(blwi_wk)
+
             else:
                 if self.ndim == 2:
                     raise RuntimeError('2D not implemented')
-                    for iReg, reg in enumerate(iDict[ibody]):
-                        iDict[iReg].blowingVel = self.__rbfToSection(vDict[ibody][0][iReg].elemsCoord[:,:(self.ndim-1 if 'vAirfoil' in reg.name else 1)], vDict[0][iReg].blowingVel, reg.elemsCoord[:,:(self.ndim-1 if reg.name == 'iWing' else 1)])
+
                 elif self.ndim == 3:
                     for iReg, reg in enumerate(iDict[ibody]):
-                        viscElemsCoord = np.zeros((0,3))
-                        viscBlowing = np.zeros(0)
-                        for iSec, sec in enumerate(vDict[ibody]):
-                            viscElemsCoord = np.row_stack((viscElemsCoord, sec[iReg].elemsCoord[:,:3]))
-                            viscBlowing = np.concatenate((viscBlowing, sec[iReg].blowingVel))
-                        if len(self._sym) > 0:
+                        # Collect elements and blowing velocity
+                        viscElemsCoord, viscBlowing = [], []
+                        for sec in vDict[ibody]:
+                            viscElemsCoord.append(sec[iReg].getElms('all'))
+                            viscBlowing.append(sec[iReg].getBlowingVelocity('all'))
+
+                        # Apply symmetry transformations if needed
+                        if self._sym:
                             for s in self._sym:
-                                dummy = viscElemsCoord.copy()
-                                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])
+                                mirrored = np.copy(np.vstack(viscElemsCoord))
+                                mirrored[:, 1] = (mirrored[:, 1] - s) * (-1) + s
+                                viscElemsCoord.append(mirrored)
+                                viscBlowing.append(np.concatenate(viscBlowing))
+
+                        # Convert to numpy arrays efficiently
+                        viscElemsCoord = np.vstack(viscElemsCoord)
+                        viscBlowing = np.concatenate(viscBlowing)
+
+                        # Apply interpolation and update
+                        blw = self.__rbfToSection(viscElemsCoord, viscBlowing, reg.getElms('all'))
+                        reg.setBlowingVelocity(blw)
+
                 else:
                     raise RuntimeError('Incorrect number of dimensions', self.cfg['nDim'])
 
-- 
GitLab