diff --git a/blast/interfaces/blSolversInterface.py b/blast/interfaces/blSolversInterface.py index 05e23dde69032394225ad42e634ab246a2736c23..724bdffc6bbccd9fa71bb7bdba0a1881b44d4d97 100644 --- a/blast/interfaces/blSolversInterface.py +++ b/blast/interfaces/blSolversInterface.py @@ -70,7 +70,7 @@ class SolversInterface: else: raise RuntimeError('Incorrect interpolator specified in config.') - self.interpolator = interp(self.cfg, self.getnDim()) + self.interpolator = interp(self.getnDim(), **self.cfg) # Initialize transfer quantities self.deltaStarExt = [[np.zeros(0) for iReg in range(3)]\ diff --git a/blast/interfaces/interpolators/blInterpolator.py b/blast/interfaces/interpolators/blInterpolator.py new file mode 100644 index 0000000000000000000000000000000000000000..4a03f4df792a986e0ae79c642e5bfb5d7ca1eb76 --- /dev/null +++ b/blast/interfaces/interpolators/blInterpolator.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright 2024 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. + + +# Abstract interpolator class +# Paul Dechamps + +class Interpolator: + """ + Abstract interpolator class + + Attributes: + ---------- + ndim : int + Number of dimensions (must be 2 or 3). + """ + def __init__(self, _ndim): + """ + Initialize the Interpolator. + + Parameters: + ---------- + ndim : int + Number of dimensions (must be 2 or 3). + """ + if _ndim != 2 and _ndim != 3: + raise ValueError('Number of dimensions must be 2 or 3 but {} was given'.format(ndim)) + self.ndim = _ndim + + def inviscidToViscous(self, iDict, vDict): + """ + Interpolate data from the inviscid mesh to the viscous mesh. + + Parameters: + ---------- + iDict : list + List blDataStructure objects for the inviscid part. + vDict : list + List blDataStructure objects for the viscous part. + """ + raise NotImplementedError('inviscidToViscous method not implemented') + + def viscousToInviscid(self, iDict, vDict): + """ + Interpolate data from the viscous mesh to the inviscid mesh. + + Parameters: + ---------- + iDict : list + List blDataStructure objects for the inviscid part. + vDict : list + List blDataStructure objects for the viscous part. + """ + raise NotImplementedError('viscousToInviscid method not implemented') diff --git a/blast/interfaces/interpolators/blMatchingInterpolator.py b/blast/interfaces/interpolators/blMatchingInterpolator.py index 1dd052ee183750fa0812c9917f4db79e43e95421..f795585f6c967f6ba5ae6988ed25965e8a20d414 100644 --- a/blast/interfaces/interpolators/blMatchingInterpolator.py +++ b/blast/interfaces/interpolators/blMatchingInterpolator.py @@ -1,28 +1,52 @@ -import numpy as np -class MatchingInterpolator: +# Copyright 2024 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. + + +# Matching interpolator class +# Paul Dechamps + +from blast.interfaces.interpolators.blInterpolator import Interpolator + +class MatchingInterpolator(Interpolator): """ Matching Interpolator for inviscid and viscous data. Attributes: ---------- - cfg : dict - Configuration dictionary. - nDim : int - Number of dimensions. + _sections : list + List of boundary layers sections. """ - def __init__(self, cfg, ndim): + def __init__(self, ndim, **kwargs): """ Initialize the MatchingInterpolator. Parameters: ---------- - _cfg : dict - Configuration dictionary. - _nDim : int + ndim : int Number of dimensions. + kwargs : dict + Optional arguments. + + Optional arguments: + ------------------- + sections : list + List of sections for 3D cases. """ - self._cfg = cfg - self._ndim = ndim + super().__init__(ndim) + self._sections = kwargs.get('sections') + if self.ndim == 2 and len(self._sections) > 1: + raise RuntimeError('Multiple sections are not supported in 2D') def inviscidToViscous(self, iDict, vDict): """ @@ -35,11 +59,11 @@ class MatchingInterpolator: vDict : dict Viscous data dictionary. """ - if self._ndim == 2: + if self.ndim == 2: for iReg in range(len(iDict)): 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']): + elif self.ndim == 3: + for iSec, ysec in enumerate(self._sections): for iReg in range(2): print(iDict[iReg].nodesCoord[iDict[iReg].nodesCoord[:,1] == ysec]) print(iDict[iReg].V[iDict[iReg].nodesCoord[:,1] == ysec]) @@ -56,8 +80,8 @@ class MatchingInterpolator: vDict : dict Viscous data dictionary. """ - if self._ndim == 2: + if self.ndim == 2: for iReg in range(2): iDict[iReg].blowingVel = vDict[0][iReg].blowingVel else: - raise RuntimeError('Incorrect number of dimensions', self._ndim) \ No newline at end of file + 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 1a203feb49c34f5076b98bca7ed100233b306b04..694953675c403f8015e28c09901d6939292567b6 100644 --- a/blast/interfaces/interpolators/blRbfInterpolator.py +++ b/blast/interfaces/interpolators/blRbfInterpolator.py @@ -1,33 +1,69 @@ +# Copyright 2024 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. +# RBF interpolator class +# Paul Dechamps + +from blast.interfaces.interpolators.blInterpolator import Interpolator import numpy as np from scipy.interpolate import RBFInterpolator -class RbfInterpolator: +class RbfInterpolator(Interpolator): """ Radial Basis Function (RBF) Interpolator for inviscid and viscous data. Attributes: ---------- - _cfg : dict - Configuration dictionary. - _ndim : int - Number of dimensions (2 or 3). + _neighbors : int + Number of neighbors to use for interpolation. + _rbftype : str + Type of RBF kernel to use. + _smoothing : float + Smoothing factor. + _degree : int + Degree of the polynomial kernel. + _sym : list + List of symmetry planes. """ - def __init__(self, cfg, ndim): + def __init__(self, ndim, **kwargs): """ Initialize the RbfInterpolator. Parameters: ---------- - cfg : dict - Configuration dictionary. ndim : int Number of dimensions (must be 2 or 3). + kwargs : dict + Optional arguments. + + Optional arguments: + ------------------- + nneighbors : int + Number of neighbors to use for interpolation. Default is 10. + rbftype : str + Type of RBF kernel to use. Default is 'linear'. + smoothing : float + Smoothing factor. Default is 0.0. + degree : int + Degree of the polynomial kernel. Default is 0. """ - self._cfg = cfg - if ndim != 2 and ndim != 3: - raise ValueError('Number of dimensions must be 2 or 3 but {} was given'.format(ndim)) - self._ndim = ndim + super().__init__(ndim) + self._neighbors = kwargs.get('neighbors', 10) + self._rbftype = kwargs.get('rbftype', 'linear') + self._smoothing = kwargs.get('smoothing', 0.0) + self._degree = kwargs.get('degree', 0) + self._sym = kwargs.get('Sym', []) def inviscidToViscous(self, iDict, vDict): """ @@ -48,9 +84,9 @@ class RbfInterpolator: M = np.zeros(reg.nodesCoord.shape[0]) rho = np.zeros(reg.nodesCoord.shape[0]) for iDim in range(3): - v[:,iDim] = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self._ndim if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].V[:,iDim], reg.nodesCoord[:,:(self._ndim if 'vAirfoil' in reg.name else 1)]) - M = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self._ndim if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].M, reg.nodesCoord[:,:(self._ndim if 'vAirfoil' in reg.name else 1)]) - rho = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self._ndim if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].Rho, reg.nodesCoord[:,:(self._ndim if 'vAirfoil' in reg.name else 1)]) + v[:,iDim] = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self.ndim if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].V[:,iDim], reg.nodesCoord[:,:(self.ndim if 'vAirfoil' in reg.name else 1)]) + M = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self.ndim if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].M, reg.nodesCoord[:,:(self.ndim if 'vAirfoil' in reg.name else 1)]) + rho = self.__rbfToSection(iDict[iReg].nodesCoord[:,:(self.ndim if iDict[iReg].name == 'iWing' else 1)], iDict[iReg].Rho, reg.nodesCoord[:,:(self.ndim if 'vAirfoil' in reg.name else 1)]) vDict[iSec][iReg].updateVars(v, M, rho) def viscousToInviscid(self, iDict, vDict): @@ -64,22 +100,21 @@ class RbfInterpolator: vDict : dict Viscous data dictionary. """ - if self._ndim == 2: + if self.ndim == 2: for iReg, reg in enumerate(iDict): - iDict[iReg].blowingVel = self.__rbfToSection(vDict[0][iReg].elemsCoordTr[:,:(self._ndim-1 if 'vAirfoil' in reg.name else 1)], vDict[0][iReg].blowingVel, reg.elemsCoordTr[:,:(self._ndim-1 if reg.name == 'iWing' else 1)]) - elif self._ndim == 3: + iDict[iReg].blowingVel = self.__rbfToSection(vDict[0][iReg].elemsCoordTr[:,:(self.ndim-1 if 'vAirfoil' in reg.name else 1)], vDict[0][iReg].blowingVel, reg.elemsCoordTr[:,:(self.ndim-1 if reg.name == 'iWing' else 1)]) + elif self.ndim == 3: for iReg, reg in enumerate(iDict): viscElemsCoord = np.zeros((0,3)) viscBlowing = np.zeros(0) for iSec, sec in enumerate(vDict): viscElemsCoord = np.row_stack((viscElemsCoord, sec[iReg].elemsCoord[:,:3])) viscBlowing = np.concatenate((viscBlowing, sec[iReg].blowingVel)) - if 'Sym' in self._cfg: - for s in self._cfg['Sym']: - dummy = viscElemsCoord.copy() - dummy[:,1] = (dummy[:,1] - s)*(-1) + s - viscElemsCoord = np.row_stack((viscElemsCoord, dummy)) - viscBlowing = np.concatenate((viscBlowing, viscBlowing)) + 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]) def __rbfToSection(self, x, var, xs): @@ -103,5 +138,5 @@ class RbfInterpolator: if np.all(var == var[0]): varOut = RBFInterpolator(x, var, neighbors=1, kernel='linear', smoothing=0.0, degree=0)(xs) else: - varOut = RBFInterpolator(x, var, neighbors=self._cfg['neighbors'], kernel=self._cfg['rbftype'], smoothing=self._cfg['smoothing'], degree=self._cfg['degree'])(xs) + varOut = RBFInterpolator(x, var, neighbors=self._neighbors, kernel=self._rbftype, smoothing=self._smoothing, degree=self._degree)(xs) return varOut \ No newline at end of file