From 2e2e93bd6e56353dc4bcf7b925f698381de1be80 Mon Sep 17 00:00:00 2001 From: Paul Dechamps <paul.dechamps@uliege.be> Date: Mon, 4 Dec 2023 21:51:28 +0100 Subject: [PATCH] (feat) Added vtk support Added vtk support in Dart api. Modified writing of boundary layer slices and introduced new argument of blast - writeSlices - which indicates vtk where to extract cps. The feature is not yet available for the boundary layer slices as this would require interpolation in the viscous solver. --- blast/interfaces/dart/DartInterface.py | 66 +++++++++++++++----------- blast/utils.py | 7 ++- blast/validation/oneraValidation.py | 34 ++++++------- 3 files changed, 62 insertions(+), 45 deletions(-) diff --git a/blast/interfaces/dart/DartInterface.py b/blast/interfaces/dart/DartInterface.py index 92c7919..7b3752c 100644 --- a/blast/interfaces/dart/DartInterface.py +++ b/blast/interfaces/dart/DartInterface.py @@ -28,15 +28,15 @@ class DartInterface(SolversInterface): def __init__(self, dartCfg, vSolver, _cfg): try: from modules.dartflo.dart.api.core import initDart - argOut = initDart(dartCfg, viscous=True) - self.solver = argOut.get('sol') # Solver - self.wrt = argOut.get('wrt') # Writer - self.blw = [argOut.get('blwb'), argOut.get('blww')] + self.argOut = initDart(dartCfg, viscous=True) + self.solver = self.argOut.get('sol') # Solver + self.blw = [self.argOut.get('blwb'), self.argOut.get('blww')] print('Dart successfully loaded.') except: print(ccolors.ANSI_RED, 'Could not load DART. Make sure it is installed.', ccolors.ANSI_RESET) raise RuntimeError('Import error') + _cfg['Format'] = dartCfg['Format'] if 'iMsh' not in _cfg: _cfg['iMsh'] = self.blw SolversInterface.__init__(self, vSolver, _cfg) @@ -48,32 +48,44 @@ class DartInterface(SolversInterface): """ Write Cp distribution around the airfoil on file. """ # Extract Cp on elements - vElems = self.blw[0].tag.elems - vData = self.solver.Cp - if isinstance(vData[0], float): - size = 1 - elif vData[0].size() == 3: - size = 3 - else: - raise RuntimeError('unrecognized format for vData!') - # store data (not efficient, but OK since only meant for small 2D cases) - data = np.zeros((vElems.size()+1,3+size)) - i = 0 - while i < vElems.size()+1: - data[i,0] = vElems[i%vElems.size()].nodes[0].pos[0] - data[i,1] = vElems[i%vElems.size()].nodes[0].pos[1] - data[i,2] = vElems[i%vElems.size()].nodes[0].pos[2] - if size == 1: - data[i,3] = vData[vElems[i%vElems.size()].nodes[0].row] + self.save(sfx=sfx) + # 2D Case + if self.cfg['nDim'] == 2: + vElems = self.blw[0].tag.elems + vData = self.solver.Cp + if isinstance(vData[0], float): + size = 1 + elif vData[0].size() == 3: + size = 3 else: - for j in range(size): - data[i,3+j] = vData[vElems[i%vElems.size()].nodes[0].row][j] - i += 1 - print('writing data file ' + 'Cp' +sfx + '.dat') - np.savetxt('Cp'+sfx+'.dat', data, fmt='%1.6e', delimiter=', ', header='x, y, z, Cp', comments='') + raise RuntimeError('unrecognized format for vData!') + # store data (not efficient, but OK since only meant for small 2D cases) + data = np.zeros((vElems.size()+1,3+size)) + i = 0 + while i < vElems.size()+1: + data[i,0] = vElems[i%vElems.size()].nodes[0].pos[0] + data[i,1] = vElems[i%vElems.size()].nodes[0].pos[1] + data[i,2] = vElems[i%vElems.size()].nodes[0].pos[2] + if size == 1: + data[i,3] = vData[vElems[i%vElems.size()].nodes[0].row] + else: + for j in range(size): + data[i,3+j] = vData[vElems[i%vElems.size()].nodes[0].row][j] + i += 1 + print('writing data file ' + 'Cp' +sfx + '.dat') + np.savetxt('Cp'+sfx+'.dat', data, fmt='%1.6e', delimiter=', ', header='x, y, z, Cp', comments='') + + elif self.cfg['nDim'] == 3: + import modules.dartflo.dart.utils as invUtils + if self.cfg['Format'] == 'vtk': + import os + if not os.path.exists('cpSlices'+sfx): + os.makedirs('cpSlices'+sfx) + print('Saving Cp files in vtk format. Msh {:s}, Tag {:.0f}'.format(self.argOut['msh'].name, self.cfg['saveTag'])) + invUtils.writeSlices(self.argOut['msh'].name, self.cfg['writeSections'], self.cfg['saveTag'], sfx=sfx) def save(self, sfx='inviscid'): - self.solver.save(self.wrt, sfx) + self.solver.save(self.argOut['wrt'], sfx) def getAoA(self): return self.solver.pbl.alpha diff --git a/blast/utils.py b/blast/utils.py index b07f83c..80ac5bb 100644 --- a/blast/utils.py +++ b/blast/utils.py @@ -142,9 +142,12 @@ def getSolution(vSolver, iSec=0): def write(wData, Re, toW=['deltaStar', 'H', 'Hstar', 'Cf', 'Ct', 'ue', 'ueInv', 'delta'], sfx=''): """Write the results in bl files """ + import os + if not os.path.exists('blSlices'): + os.makedirs('blSlices') # Write - print('Writing file: bl_'+sfx+'.dat...', end = '') - f = open('bl'+sfx+'.dat', 'w+') + print('Writing file: /blSlices/bl'+sfx+'.dat...', end = '') + f = open('blSlices/bl'+sfx+'.dat', 'w+') f.write('$Sectional aerodynamic coefficients\n') f.write(' Re Cdw Cdp Cdf xtr_top xtr_bot\n') diff --git a/blast/validation/oneraValidation.py b/blast/validation/oneraValidation.py index 1fb9785..3c0d239 100644 --- a/blast/validation/oneraValidation.py +++ b/blast/validation/oneraValidation.py @@ -57,7 +57,7 @@ def cfgInviscid(nthrds, verb): 'File' : os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/onera_lfs.msh', # Input file containing the model 'Pars' : {}, # parameters for input file model 'Dim' : 3, # problem dimension - 'Format' : 'gmsh', # save format (vtk or gmsh) + 'Format' : 'vtk', # save format (vtk or gmsh) # Markers 'Fluid' : 'field', # name of physical group containing the fluid 'Farfield' : ['upstream', 'farfield', 'downstream'], # LIST of names of physical groups containing the farfield boundaries (upstream/downstream should be first/last element) @@ -68,31 +68,32 @@ def cfgInviscid(nthrds, verb): 'dbc' : True, 'Upstream' : 'upstream', # Freestream - 'M_inf' : 0.839, # freestream Mach number - 'AoA' : 3.06, # freestream angle of attack + 'M_inf' : 0.839, # freestream Mach number + 'AoA' : 3.06, # freestream angle of attack # Geometry - 'S_ref' : 0.7528, # reference surface length - 'c_ref' : 0.64, # reference chord length - 'x_ref' : 0.0, # reference point for moment computation (x) - 'y_ref' : 0.0, # reference point for moment computation (y) - 'z_ref' : 0.0, # reference point for moment computation (z) + 'S_ref' : 0.7528, # reference surface length + 'c_ref' : 0.64, # reference chord length + 'x_ref' : 0.0, # reference point for moment computation (x) + 'y_ref' : 0.0, # reference point for moment computation (y) + 'z_ref' : 0.0, # reference point for moment computation (z) # Numerical 'LSolver' : 'GMRES', # inner solver (Pardiso, MUMPS or GMRES) - 'G_fill' : 2, # fill-in factor for GMRES preconditioner - 'G_tol' : 1e-5, # tolerance for GMRES - 'G_restart' : 50, # restart for GMRES - 'Rel_tol' : 1e-6, # relative tolerance on solver residual - 'Abs_tol' : 1e-8, # absolute tolerance on solver residual - 'Max_it' : 50 # solver maximum number of iterations + 'G_fill' : 2, # fill-in factor for GMRES preconditioner + 'G_tol' : 1e-5, # tolerance for GMRES + 'G_restart' : 50, # restart for GMRES + 'Rel_tol' : 1e-6, # relative tolerance on solver residual + 'Abs_tol' : 1e-8, # absolute tolerance on solver residual + 'Max_it' : 50 # solver maximum number of iterations } def cfgBlast(verb): return { - 'Re' : 1e7, # Freestream Reynolds number - 'Minf' : 0.2, # Freestream Mach number (used for the computation of the time step only) + 'Re' : 11.72*10e6, # Freestream Reynolds number + 'Minf' : 0.839, # Freestream Mach number (used for the computation of the time step only) 'CFL0' : 1, # Inital CFL number of the calculation 'sections' : np.linspace(0.026, 1.15, 20), + 'writeSections': [0.20, 0.44, 0.80], 'Sym':[0.], 'span':1.196, 'interpolator': 'Rbf', @@ -100,6 +101,7 @@ def cfgBlast(verb): 'smoothing': 1e-8, 'degree': 0, 'neighbors': 10, + 'saveTag': 5, 'Verb': verb, # Verbosity level of the solver 'couplIter': 50, # Maximum number of iterations -- GitLab