diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e7210bdc6e1c5b3774871ed7b9604acaecdbe91..c342e270cdbf091f67ca403443ad4792a7009dc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ ENDIF() # SWIG FIND_PACKAGE(SWIG REQUIRED) IF(CMAKE_GENERATOR MATCHES "Visual Studio") # not MSVC because of nmake & jom - SET(CMAKE_SWIG_OUTDIR "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}/") + SET(CMAKE_SWIG_OUTDIR "${EXECUTABLE_OUTPUT_PATH}/$(Configuration)/") ELSE() SET(CMAKE_SWIG_OUTDIR "${EXECUTABLE_OUTPUT_PATH}") ENDIF() @@ -108,8 +108,13 @@ ENABLE_TESTING() # -- INSTALL IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -m site --user-site OUTPUT_VARIABLE PY_SITE OUTPUT_STRIP_TRAILING_WHITESPACE) + STRING(REGEX REPLACE "\\\\" "/" PY_SITE ${PY_SITE}) SET(CMAKE_INSTALL_PREFIX "${PY_SITE}/dartflo" CACHE STRING "Install location" FORCE) SET(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT FALSE) +ELSE() + IF(NOT(CMAKE_INSTALL_PREFIX MATCHES "dartflo$")) + SET(CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/dartflo" CACHE STRING "Install location" FORCE) + ENDIF() ENDIF() IF(UNIX AND NOT APPLE) SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}") diff --git a/dart/_src/CMakeLists.txt b/dart/_src/CMakeLists.txt index 62193a7c9bb59ab44c179729925657056c7a8080..c78c46464f4be1f8f7788ca1f565e3e6e7a5e4ba 100644 --- a/dart/_src/CMakeLists.txt +++ b/dart/_src/CMakeLists.txt @@ -48,5 +48,5 @@ SWIG_LINK_LIBRARIES(dartw dart tbox fwk ${PYTHON_LIBRARIES} ) -INSTALL(FILES ${CMAKE_SWIG_OUTDIR}/dartw.py DESTINATION ${CMAKE_INSTALL_PREFIX}) +INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/\${BUILD_TYPE}/dartw.py DESTINATION ${CMAKE_INSTALL_PREFIX}) INSTALL(TARGETS _dartw DESTINATION ${CMAKE_INSTALL_PREFIX}) diff --git a/dart/_src/dartw.i b/dart/_src/dartw.i index 531a1e5fc5820068259751f0e632049242bf2380..f0583cfe0c0288c4a995913ce920b011cbcdd856 100644 --- a/dart/_src/dartw.i +++ b/dart/_src/dartw.i @@ -79,8 +79,8 @@ threads="1" %immutable dart::Body::Cm; %immutable dart::Body::nLoads; %include "wBody.h" -%include "wBlowing.h" %warnfilter(+509); +%include "wBlowing.h" %immutable dart::Problem::msh; // read-only variable (no setter) %immutable dart::Problem::nDim; diff --git a/dart/api/core.py b/dart/api/core.py index 7da8be7f62f8f1ae029cd8e2210b67f6c210c023..248a6a10a88877f11746837a59529bbc70d447f5 100644 --- a/dart/api/core.py +++ b/dart/api/core.py @@ -19,12 +19,12 @@ ## Initialize DART # Adrien Crovato -def initDart(params, scenario='aerodynamic', task='analysis'): +def initDart(cfg, scenario='aerodynamic', task='analysis'): """Initlialize DART for various API Parameters ---------- - params : dict + cfg : dict Dictionary of parameters to configure DART scenario : string, optional Type of scenario (available: aerodynamic, aerostructural) (default: aerodynamic) @@ -61,31 +61,31 @@ def initDart(params, scenario='aerodynamic', task='analysis'): # Basic checks and config # dimension - if params['Dim'] != 2 and params['Dim'] != 3: - raise RuntimeError('Problem dimension should be 2 or 3, but ' + params['Dim'] + ' was given!\n') + if cfg['Dim'] != 2 and cfg['Dim'] != 3: + raise RuntimeError('Problem dimension should be 2 or 3, but ' + cfg['Dim'] + ' was given!\n') else: - _dim = params['Dim'] + _dim = cfg['Dim'] # aoa and aos - if 'AoA' in params: - alpha = params['AoA'] * math.pi / 180 + if 'AoA' in cfg: + alpha = cfg['AoA'] * math.pi / 180 else: alpha = 0 if _dim == 2: - if 'AoS' in params and params['AoS'] != 0: + if 'AoS' in cfg and cfg['AoS'] != 0: raise RuntimeError('Angle of sideslip (AoS) should be zero for 2D problems!\n') else: beta = 0 - if 'Symmetry' in params: + if 'Symmetry' in cfg: raise RuntimeError('Symmetry boundary condition cannot be used for 2D problems!\n') else: - if 'AoS' in params: - if params['AoS'] != 0 and 'Symmetry' in params: + if 'AoS' in cfg: + if cfg['AoS'] != 0 and 'Symmetry' in cfg: raise RuntimeError('Symmetry boundary condition cannot be used with nonzero angle of sideslip (AoS)!\n') - beta = params['AoS'] * math.pi / 180 + beta = cfg['AoS'] * math.pi / 180 else: beta = 0 # save format - if params['Format'] == 'vtk': + if cfg['Format'] == 'vtk': try: import tboxVtk Writer = tboxVtk.VtkExport @@ -97,14 +97,14 @@ def initDart(params, scenario='aerodynamic', task='analysis'): Writer = tbox.GmshExport print('Results will be saved in gmsh format.\n') # number of threads - if 'Threads' in params: - nthrd = params['Threads'] + if 'Threads' in cfg: + nthrd = cfg['Threads'] else: nthrd = 1 wu.initMKL(nthrd) # initialize threading layer and number of threads # verbosity - if 'Verb' in params: - verb = params['Verb'] + if 'Verb' in cfg: + verb = cfg['Verb'] else: verb = 0 # scenario and task type @@ -114,29 +114,29 @@ def initDart(params, scenario='aerodynamic', task='analysis'): raise RuntimeError('Task should be analysis or optimization, but "' + task + '" was given!\n') # dynamic pressure if scenario == 'aerostructural': - _qinf = params['Q_inf'] + _qinf = cfg['Q_inf'] else: - _qinf = 0 + _qinf = None # Mesh creation - _msh = gmsh.MeshLoader(params['File']).execute(**params['Pars']) + _msh = gmsh.MeshLoader(cfg['File']).execute(**cfg['Pars']) # add the wake if _dim == 2: mshCrck = tbox.MshCrack(_msh, _dim) - mshCrck.setCrack(params['Wake']) - mshCrck.addBoundaries([params['Fluid'], params['Farfield'][-1], params['Wing']]) + mshCrck.setCrack(cfg['Wake']) + mshCrck.addBoundaries([cfg['Fluid'], cfg['Farfield'][-1], cfg['Wing']]) mshCrck.run() else: - for i in range(len(params['Wakes'])): + for i in range(len(cfg['Wakes'])): mshCrck = tbox.MshCrack(_msh, _dim) - mshCrck.setCrack(params['Wakes'][i]) - mshCrck.addBoundaries([params['Fluid'], params['Farfield'][-1], params['Wings'][i]]) - if 'Fuselage' in params: - mshCrck.addBoundaries([params['Fuselage']]) - if 'Symmetry' in params: - mshCrck.addBoundaries([params['Symmetry']]) - if 'WakeTips' in params: - mshCrck.setExcluded(params['WakeTips'][i]) # 2.5D computations + mshCrck.setCrack(cfg['Wakes'][i]) + mshCrck.addBoundaries([cfg['Fluid'], cfg['Farfield'][-1], cfg['Wings'][i]]) + if 'Fuselage' in cfg: + mshCrck.addBoundaries([cfg['Fuselage']]) + if 'Symmetry' in cfg: + mshCrck.addBoundaries([cfg['Symmetry']]) + if 'WakeTips' in cfg: + mshCrck.setExcluded(cfg['WakeTips'][i]) # 3D computations (not excluded for 2.5D) mshCrck.run() # save the updated mesh in native (gmsh) format and then set the writer to the requested format tbox.GmshExport(_msh).save(_msh.name) @@ -146,87 +146,85 @@ def initDart(params, scenario='aerodynamic', task='analysis'): # Mesh morpher creation if scenario == 'aerostructural' or task == 'optimization': - _mrf = tbox.MshDeform(_msh, _dim, nthrds=nthrd) - _mrf.setField(params['Fluid']) - _mrf.addFixed(params['Farfield']) + _mrf = tbox.MshDeform(_msh, tbox.Gmres(1, 1e-6, 30, 1e-8), _dim, nthrds=nthrd) + _mrf.setField(cfg['Fluid']) + _mrf.addFixed(cfg['Farfield']) if _dim == 2: - _mrf.addMoving([params['Wing']]) - _mrf.addInternal([params['Wake'], params['Wake']+'_']) + _mrf.addMoving([cfg['Wing']]) + _mrf.addInternal([cfg['Wake'], cfg['Wake']+'_']) else: - if 'Fuselage' in params: - _mrf.addFixed(params['Fuselage']) - _mrf.setSymmetry(params['Symmetry'], 1) - for i in range(len(params['Wings'])): + if 'Fuselage' in cfg: + _mrf.addFixed(cfg['Fuselage']) + _mrf.setSymmetry(cfg['Symmetry'], 1) + for i in range(len(cfg['Wings'])): if i == 0: - _mrf.addMoving([params['Wings'][i]]) # TODO body of interest (FSI/OPT) is always first given body + _mrf.addMoving([cfg['Wings'][i]]) # TODO body of interest (FSI/OPT) is always first given body else: - _mrf.addFixed([params['Wings'][i]]) - _mrf.addInternal([params['Wakes'][i], params['Wakes'][i]+'_']) + _mrf.addFixed([cfg['Wings'][i]]) + _mrf.addInternal([cfg['Wakes'][i], cfg['Wakes'][i]+'_']) _mrf.initialize() else: _mrf = None # Problem creation - _pbl = dart.Problem(_msh, _dim, alpha, beta, params['M_inf'], params['S_ref'], params['c_ref'], params['x_ref'], params['y_ref'], params['z_ref']) + _pbl = dart.Problem(_msh, _dim, alpha, beta, cfg['M_inf'], cfg['S_ref'], cfg['c_ref'], cfg['x_ref'], cfg['y_ref'], cfg['z_ref']) # add the field - _pbl.set(dart.Fluid(_msh, params['Fluid'], params['M_inf'], _dim, alpha, beta)) + _pbl.set(dart.Fluid(_msh, cfg['Fluid'], cfg['M_inf'], _dim, alpha, beta)) # add the initial condition - _pbl.set(dart.Initial(_msh, params['Fluid'], _dim, alpha, beta)) + _pbl.set(dart.Initial(_msh, cfg['Fluid'], _dim, alpha, beta)) # add farfield boundary conditions (Neumann only, a DOF will be pinned automatically) - for i in range (len(params['Farfield'])): - _pbl.add(dart.Freestream(_msh, params['Farfield'][i], _dim, alpha, beta)) + for i in range (len(cfg['Farfield'])): + _pbl.add(dart.Freestream(_msh, cfg['Farfield'][i], _dim, alpha, beta)) # add solid boundaries if _dim == 2: - bnd = dart.Body(_msh, [params['Wing'], params['Fluid']]) + bnd = dart.Body(_msh, [cfg['Wing'], cfg['Fluid']]) _bnd = bnd _pbl.add(bnd) else: _bnd = None - for bd in params['Wings']: - bnd = dart.Body(_msh, [bd, params['Fluid']]) + for bd in cfg['Wings']: + bnd = dart.Body(_msh, [bd, cfg['Fluid']]) if _bnd is None: _bnd = bnd # TODO body of interest (FSI/OPT) is always first given body _pbl.add(bnd) - if 'Fuselage' in params: - bnd = dart.Body(_msh, [params['Fuselage'], params['Fluid']]) + if 'Fuselage' in cfg: + bnd = dart.Body(_msh, [cfg['Fuselage'], cfg['Fluid']]) _pbl.add(bnd) # add Wake/Kutta boundary conditions + # TODO refactor Wake "exclusion" for 3D? if _dim == 2: - _pbl.add(dart.Wake(_msh, [params['Wake'], params['Wake']+'_', params['Fluid']])) - _pbl.add(dart.Kutta(_msh, [params['Te'], params['Wake']+'_', params['Wing'], params['Fluid']])) + _pbl.add(dart.Wake(_msh, [cfg['Wake'], cfg['Wake']+'_', cfg['Fluid']])) + _pbl.add(dart.Kutta(_msh, [cfg['Te'], cfg['Wake']+'_', cfg['Wing'], cfg['Fluid']])) else: - for i in range(len(params['Wakes'])): - _pbl.add(dart.Wake(_msh, [params['Wakes'][i], params['Wakes'][i]+'_', params['Fluid'], params['TeTips'][i]])) + for i in range(len(cfg['Wakes'])): + if 'WakeExs' in cfg: + _pbl.add(dart.Wake(_msh, [cfg['Wakes'][i], cfg['Wakes'][i]+'_', cfg['Fluid'], cfg['WakeExs'][i]])) # 3D + fuselage + elif 'WakeTips' in cfg: + _pbl.add(dart.Wake(_msh, [cfg['Wakes'][i], cfg['Wakes'][i]+'_', cfg['Fluid'], cfg['WakeTips'][i]])) # 3D + else: + _pbl.add(dart.Wake(_msh, [cfg['Wakes'][i], cfg['Wakes'][i]+'_', cfg['Fluid']])) # 2.5D + _pbl.add(dart.Kutta(_msh, [cfg['Tes'][i], cfg['Wakes'][i]+'_', cfg['Wings'][i], cfg['Fluid']])) # Direct (forward) solver creation # NB: more solvers/options are available but we restrict the user's choice to the most efficient ones # initialize the linear (inner) solver - if params['LSolver'] == 'PARDISO': + if cfg['LSolver'] == 'PARDISO': linsol = tbox.Pardiso() - elif params['LSolver'] == 'MUMPS': + elif cfg['LSolver'] == 'MUMPS': linsol = tbox.Mumps() - elif params['LSolver'] == 'GMRES': - linsol = tbox.Gmres() - linsol.setFillFactor(params['G_fill']) if 'G_fill' in params else linsol.setFillFactor(2) - linsol.setRestart(params['G_restart']) if 'G_restart' in params else linsol.setRestart(50) - linsol.setTolerance(params['G_tol']) if 'G_tol' in params else linsol.setTolerance(1e-5) + elif cfg['LSolver'] == 'GMRES': + gfil = cfg['G_fill'] if 'G_fill' in cfg else 2 + grst = cfg['G_restart'] if 'G_restart' in cfg else 50 + gtol = cfg['G_tol'] if 'G_tol' in cfg else 1e-5 + linsol = tbox.Gmres(gfil, 1e-6, grst, gtol) else: - raise RuntimeError('Available linear solvers: PARDISO, MUMPS or GMRES, but ' + params['LSolver'] + ' was given!\n') + raise RuntimeError('Available linear solvers: PARDISO, MUMPS or GMRES, but ' + cfg['LSolver'] + ' was given!\n') # initialize the nonlinear (outer) solver - _sol = dart.Newton(_pbl, linsol, rTol=params['Rel_tol'], aTol=params['Abs_tol'], mIt=params['Max_it'], nthrds=nthrd, vrb=verb) + _sol = dart.Newton(_pbl, linsol, rTol=cfg['Rel_tol'], aTol=cfg['Abs_tol'], mIt=cfg['Max_it'], nthrds=nthrd, vrb=verb) # Adjoint (reverse) solver creation if task == 'optimization': - if params['LSolver'] == 'PARDISO': - alinsol = tbox.Pardiso() - elif params['LSolver'] == 'MUMPS': - alinsol = tbox.Mumps() - else: - alinsol = tbox.Gmres() - alinsol.setFillFactor(params['G_fill']) if 'G_fill' in params else alinsol.setFillFactor(2) - alinsol.setRestart(params['G_restart']) if 'G_restart' in params else alinsol.setRestart(50) - alinsol.setTolerance(1e-12) - _adj = dart.Adjoint(_sol, _mrf, alinsol) + _adj = dart.Adjoint(_sol, _mrf) else: _adj = None diff --git a/dart/api/internal/trim.py b/dart/api/internal/trim.py index 2555218013c5e20a211ed44fe66de850b985924a..74c0025882f5de8f6be7732433c8500b8a5b109d 100644 --- a/dart/api/internal/trim.py +++ b/dart/api/internal/trim.py @@ -90,8 +90,8 @@ class Trim: self.pbl.update(self.alpha) # run the solver self.tms["solver"].start() - success = self.sol.run() - if not success: + status = self.sol.run() + if status >= 2: raise RuntimeError('Flow solver diverged!\n') self.tms["solver"].stop() # update slope @@ -111,7 +111,7 @@ class Trim: self.sol.save(self.wrtr) # extract Cp if self.dim == 2: - Cp = dU.extract(self.bnd.groups[0].tag.elems, self.solver.Cp) + Cp = dU.extract(self.bnd.groups[0].tag.elems, self.sol.Cp) tU.write(Cp, "Cp_airfoil.dat", "%1.5e", ", ", "x, y, z, Cp", "") elif self.dim == 3 and self.format == 'vtk' and self.slice: dU.writeSlices(self.msh.name, self.slice, self.tag) diff --git a/dart/api/mphys.py b/dart/api/mphys.py index 2edba1ebe352dbcaa57bf879dec24690cdaec229..e59d6130a610c28eca75414bd025c3edf34aaa54 100644 --- a/dart/api/mphys.py +++ b/dart/api/mphys.py @@ -44,6 +44,7 @@ from mphys.builder import Builder class DartMesh(om.IndepVarComp): """Initial surface mesh of moving body For compatibility, the node coordinates of connected surfaces are always 3D + For compatibility, the output is distributed, though it should always be serial Attributes ---------- @@ -63,9 +64,9 @@ class DartMesh(om.IndepVarComp): for i in range(len(self.bnd.nodes)): for j in range(3): x_aero0[3 * i + j] = self.bnd.nodes[i].pos[j] - self.add_output('x_aero0', val=x_aero0, desc='initial aerodynamic surface node coordinates', tags=['mphys_coordinates']) + self.add_output('x_aero0', distributed=True, val=x_aero0, desc='initial aerodynamic surface node coordinates', tags=['mphys_coordinates']) - def mphys_get_triangulated_surface(self): + def get_triangulated_surface(self): """Triangulate the surface Only for 2D surfaces in 3D problems Return a list containing a point and two vectors for each surface element @@ -94,6 +95,7 @@ class DartMesh(om.IndepVarComp): class DartMorpher(om.ImplicitComponent): """Volume mesh morpher For compatibility, the node coordinates of connected surfaces are always 3D, while the volume mesh coordinates (only used internaly) can be 2D or 3D + For compatibility, the input is distributed, though it should always be serial Attributes ---------- @@ -118,7 +120,7 @@ class DartMorpher(om.ImplicitComponent): self.mrf = self.options['mrf'] self.adj = self.options['adj'] # I/O - self.add_input('x_aero', shape_by_conn=True, desc='aerodynamic surface node coordinates', tags=['mphys_coupling']) + self.add_input('x_aero', distributed=True, shape_by_conn=True, desc='aerodynamic surface node coordinates', tags=['mphys_coupling']) self.add_output('xv', val=np.zeros(self.dim * len(self.mrf.msh.nodes)), desc='aerodynamic volume node coordinates', tags=['mphys_coupling']) # volume node coordinates can be 2D or 3D # Partials # self.declare_partials(of=['xv'], wrt=['x_aero']) @@ -174,6 +176,7 @@ class DartDummyMorpher(om.ExplicitComponent): """Dummy volume mesh morpher Allow to define and link the surface mesh coordinates to the volume mesh coordinates, in case the mesh do not deform. For compatibility, the node coordinates of connected surfaces are always 3D, while the volume mesh coordinates (only used internaly) can be 2D or 3D + For compatibility, the input is distributed, though it should always be serial """ def initialize(self): self.options.declare('dim', desc='problem dimension') @@ -188,7 +191,7 @@ class DartDummyMorpher(om.ExplicitComponent): for j in range(dim): xv[dim * i + j] = msh.nodes[i].pos[j] # I/O - self.add_input('x_aero', shape_by_conn=True, desc='aerodynamic surface node coordinates', tags=['mphys_coupling']) + self.add_input('x_aero', distributed=True, shape_by_conn=True, desc='aerodynamic surface node coordinates', tags=['mphys_coupling']) self.add_output('xv', val=xv, desc='aerodynamic volume node coordinates', tags=['mphys_coupling']) def compute(self, inputs, outputs): @@ -215,6 +218,7 @@ class DartSolver(om.ImplicitComponent): def initialize(self): self.options.declare('sol', desc='direct solver', recordable=False) self.options.declare('adj', desc='adjoint solver', recordable=False) + self.options.declare('raiseError', default=False, desc='raise AnalysisError when solver not fully converged') def setup(self): self.sol = self.options['sol'] @@ -234,7 +238,9 @@ class DartSolver(om.ImplicitComponent): self.sol.pbl.update(inputs['aoa'][0]) # Compute self.sol.reset() # resets ICs (slows down convergence, but increases robustness for aero-structural) - self.sol.run() + status = self.sol.run() + if (status == 1 and self.options['raiseError']) or status == 2: # max number of iterations exceeded or NaN in solution + raise om.AnalysisError('DART solver failed to fully converge!\n') # Update outputs outputs['phi'] = self.sol.phi @@ -274,6 +280,7 @@ class DartSolver(om.ImplicitComponent): class DartLoads(om.ExplicitComponent): """Aerodynamic loads on moving body For compatibility, the forces of connected surfaces are always 3D + For compatibility, the output is distributed, though it should always be serial Attributes ---------- @@ -296,7 +303,7 @@ class DartLoads(om.ExplicitComponent): # I/O self.add_input('xv', shape_by_conn=True, desc='aerodynamic volume node coordinates', tags=['mphys_coupling']) self.add_input('phi', shape_by_conn=True, desc='flow variables (potential)', tags=['mphys_coupling']) - self.add_output('f_aero', val=np.zeros(3 * len(self.bnd.nodes)), desc='aerodynamic loads', tags=['mphys_coupling']) + self.add_output('f_aero', distributed=True, val=np.zeros(3 * len(self.bnd.nodes)), desc='aerodynamic loads', tags=['mphys_coupling']) # Partials # self.declare_partials(of=['f_aero'], wrt=['xv', 'phi']) @@ -343,10 +350,11 @@ class DartCoefficients(om.ExplicitComponent): self.options.declare('sol', desc='direct solver', recordable=False) self.options.declare('adj', desc='adjoint solver', recordable=False) self.options.declare('wrtr', desc='data writer', recordable=False) + self.options.declare('iscn', default=0, desc='ID of the scenario') self.options.declare('morph', default=False, desc='whether the mesh can deform or not') def setup(self): - self.iscn = 0 # id of scenario + self.iscn = self.options['iscn'] self.sol = self.options['sol'] self.adj = self.options['adj'] # I/O @@ -358,18 +366,12 @@ class DartCoefficients(om.ExplicitComponent): # Partials self.declare_partials(of=['cl', 'cd'], wrt=['aoa', 'xv', 'phi']) - def mphys_set_iscn(self, iscn): - """Set the id of the scenario - Allow to save the mesh and results in different files - """ - self.iscn = iscn - def compute(self, inputs, outputs): """Get the coefficients for the full aircraft """ # NB: inputs already up-to-date because DartSolver has already been run # Write to disk - if self.options['morph'] and str(type(self.options['wrtr'])) == '<class \'tboxw.GmshExport\'>': + if self.options['morph'] and self.options['wrtr'].type() == 1: if self.iscn == 0: self.options['wrtr'].save(self.sol.pbl.msh.name) else: @@ -412,6 +414,7 @@ class DartGroup(om.Group): self.options.declare('sol', desc='direct solver', recordable=False) self.options.declare('mrf', desc='mesh morpher', recordable=False) self.options.declare('adj', desc='adjoint solver', recordable=False) + self.options.declare('raiseError', default=False, desc='raise AnalysisError when solver not fully converged') def setup(self): # Components @@ -419,8 +422,8 @@ class DartGroup(om.Group): self.add_subsystem('morpher', DartDummyMorpher(dim = self.options['sol'].pbl.nDim, msh = self.options['sol'].pbl.msh), promotes_inputs=['x_aero'], promotes_outputs=['xv']) else: self.add_subsystem('morpher', DartMorpher(dim = self.options['sol'].pbl.nDim, bnd = self.options['bnd'], mrf = self.options['mrf'], adj = self.options['adj']), promotes_inputs=['x_aero'], promotes_outputs=['xv']) - self.add_subsystem('solver', DartSolver(sol = self.options['sol'], adj = self.options['adj']), promotes_inputs=['aoa', 'xv'], promotes_outputs=['phi']) - if self.options['qinf'] != 0: + self.add_subsystem('solver', DartSolver(sol = self.options['sol'], adj = self.options['adj'], raiseError = self.options['raiseError']), promotes_inputs=['aoa', 'xv'], promotes_outputs=['phi']) + if self.options['qinf'] is not None: self.add_subsystem('loads', DartLoads(qinf = self.options['qinf'], bnd = self.options['bnd'], adj = self.options['adj']), promotes_inputs=['xv', 'phi'], promotes_outputs=['f_aero']) # Builder @@ -442,23 +445,60 @@ class DartBuilder(Builder): __adj : dart.Adjoint object Adjoint solver """ - def __init__(self, params, scenario='aerodynamic', task='analysis'): - """Instantiate and initialize all the solver components. - Because we do not use MPI, we do not use the initialize method. + def __init__(self, cfg, scenario='aerodynamic', task='analysis', scenarioId=0, raiseError=False): + """Instantiate the builder and save the parameters and options Parameters ---------- - params : dict + cfg : dict Dictonnary of parameters to configure DART scenario : string, optional Type of scenario (available: aerodynamic, aerostructural) (default: aerodynamic) task : string, optional Type of task (available: analysis, optimization) (default: analysis) + scenarioId : int, optional + ID of the scenario, will be used in the output filename + raiseError : bool, optional + Whether to raise an openMDAO.AnalysisError when the solver does not fully converge (default: False) + As of openMDAO V3.9.2, AnalysisError are only handled by pyOptSparse + """ + self.__cfg = cfg + self.__scn = scenario + self.__tsk = task + self.__sid = scenarioId + self.__raiseError = raiseError + + def initialize(self, comm): + """Instantiate and initialize all the solver components + + Parameters + ---------- + comm: mpi4py.MPI.Comm object + MPI communicator """ - print('*'*31 + 'mphys.DartBuilder' + '*'*31 + '\n') from .core import initDart - self.__dim, self.__qinf, _, self.__wrtr, self.__mrf, _, self.__bnd, self.__sol, self.__adj = initDart(params, scenario=scenario, task=task) - print('*'*31 + 'mphys.DartBuilder' + '*'*31 + '\n') + def _init(): + self.__dim, self.__qinf, _, self.__wrtr, self.__mrf, _, self.__bnd, self.__sol, self.__adj = initDart(self.__cfg, scenario=self.__scn, task=self.__tsk) + # If n MPI processes, init DART on rank=0,...,n-1 sequentially to avoid issues with mesh IO + # If mpi4py is not available or only 1 MPI process, init DART as usual + try: + from mpi4py import MPI + # If several processes are provided by OpenMDAO, DART is requested to run with MPI, which is not supported + if comm.size > 1: + raise RuntimeError('DartBuiler.initialize - DART cannot be run using MPI, except for MultiPoint analysis!\n') + # Else, we are running a MultiPoint analysis and need to ID the actual process + true_comm = MPI.COMM_WORLD + if true_comm.size > 1: + if true_comm.rank != 0: + true_comm.recv(source=true_comm.rank-1) + _init() + if true_comm.rank != true_comm.size-1: + true_comm.send([], dest=true_comm.rank+1) + true_comm.barrier() + else: + _init() + except: + _init() def get_mesh_coordinate_subsystem(self): """Return openMDAO component to get the initial surface mesh coordinates @@ -468,12 +508,12 @@ class DartBuilder(Builder): def get_coupling_group_subsystem(self): """Return openMDAO group containing the morpher, solver and loads """ - return DartGroup(qinf = self.__qinf, bnd = self.__bnd, sol = self.__sol, mrf = self.__mrf, adj = self.__adj) + return DartGroup(qinf = self.__qinf, bnd = self.__bnd, sol = self.__sol, mrf = self.__mrf, adj = self.__adj, raiseError = self.__raiseError) def get_post_coupling_subsystem(self): """Return openMDAO component that computes the aero coefficients and writes data to disk """ - return DartCoefficients(sol = self.__sol, adj = self.__adj, wrtr = self.__wrtr, morph = False if self.__mrf is None else True) + return DartCoefficients(sol = self.__sol, adj = self.__adj, wrtr = self.__wrtr, iscn = self.__sid, morph = False if self.__mrf is None else True) def get_number_of_nodes(self): """Return the number of surface nodes diff --git a/dart/benchmark/onera.py b/dart/benchmark/onera.py index 08e2f85e3d40dcfe2b3e21696f871645d320cf8f..b0f9c2157829c582e57c204ac18d53e18246d80d 100644 --- a/dart/benchmark/onera.py +++ b/dart/benchmark/onera.py @@ -36,11 +36,7 @@ def newton(pbl): try: newton = dart.Newton(pbl, tbox.Pardiso(), nthrds=k, vrb=2) except: - gmres = tbox.Gmres() - gmres.setFillFactor(2) - gmres.setDropTol(1e-6) - gmres.setRestart(50) - gmres.setTolerance(1e-5) + gmres = tbox.Gmres(2, 1e-6, 50, 1e-5) newton = dart.Newton(pbl, gmres, nthrds=k, vrb=2) return newton @@ -66,7 +62,7 @@ def main(): # set the problem and add fluid, initial/boundary conditions tms['pre'].start() - pbl, _, _, _, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'teTip') + pbl, _, _, _, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'wakeTip') tms['pre'].stop() # solve problem diff --git a/dart/benchmark/onera_lfs.msh b/dart/benchmark/onera_lfs.msh index bad883483fd52e1bc2012df01111620350a1d674..b69a99789cfecd7d3db417b14288b4271dc85713 100644 --- a/dart/benchmark/onera_lfs.msh +++ b/dart/benchmark/onera_lfs.msh @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:da782b51f3be6ff2b8d222ed9ad1aba46849b2d018df294ac5f780a0258a74c8 -size 39450759 +oid sha256:c235746b196f5b428da900f56a024eb69c5d1baa2766409c0e1413109c2cd7fb +size 36951138 diff --git a/dart/cases/coyote.py b/dart/cases/coyote.py index 6dda2e0d08de2e3f96136091afd2e83cb368361d..fc493e30324286c0bd5cf268fcb1b797bd2bda72 100644 --- a/dart/cases/coyote.py +++ b/dart/cases/coyote.py @@ -44,7 +44,7 @@ def getParam(): p['Dim'] = 3 # Problem dimension p['Format'] = 'vtk' # Save format (vtk or gmsh) p['Slice'] = [1.8, 3.5, 5.3] # array of (y) coordinates to perform slice along the span (empty if none) - p['TagId'] = 9 # tag number of physical group to be sliced + p['TagId'] = 11 # tag number of physical group to be sliced # Markers p['Fluid'] = 'field' # Name of physical group containing the fluid p['Farfield'] = ['upstream', 'farfield', 'downstream'] # LIST of names of physical groups containing the farfield boundaries (upstream/downstream should be first/last element) @@ -52,7 +52,8 @@ def getParam(): p['Wings'] = ['wing', 'tail'] # LIST of names of physical groups containing the lifting surface body p['Wakes'] = ['wakeW', 'wakeT'] # LIST of names of physical group containing the wake p['WakeTips'] = ['wakeTipW', 'wakeTipT'] # LIST of names of physical group containing the edge of the wake - p['TeTips'] = ['teTipW', 'teTipT'] # LIST of names of physical group containing the edge of the wake and the trailing edge + p['WakeExs'] = ['wakeExW', 'wakeExT'] # LIST of names of physical group containing the edge of the wake and the intersection of lifting surface with fuselage (to be excluded from Wake B.C.) + p['Tes'] = ['teW', 'teT'] # LIST of names of physical group containing the trailing edge # Freestream p['M_inf'] = 0.8 # Freestream Mach number p['AoA_begin'] = 1 # Freestream angle of attack (begin) diff --git a/dart/cases/n0012_3.py b/dart/cases/n0012_3.py deleted file mode 100644 index 57700c2e6cbe4b92065fcc678300cef2369fb776..0000000000000000000000000000000000000000 --- a/dart/cases/n0012_3.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/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. - - -## NACA 0012 wing configuration file for flow polar script -# Adrien Crovato - -def getParam(): - import os.path - from fwk.wutils import parseargs - p = {} - # Specific - span = 1. # span length - # Arguments - args = parseargs() - p['Threads'] = args.k - p['Verb'] = args.verb - # Input/Output - p['File'] = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../models/n0012_3.geo') # Input file containing the model - p['Pars'] = {'spn' : span, 'lgt' : 3., 'wdt' : 3., 'hgt' : 3., 'msLe' : 0.02, 'msTe' : 0.02, 'msF' : 1.} # Parameters for input file model - p['Dim'] = 3 # Problem dimension - p['Format'] = 'vtk' # Save format (vtk or gmsh) - p['Slice'] = [0.01, 0.25, 0.5, 0.75, 0.95] # array of (y) coordinates to perform slice along the span (empty if none) - p['TagId'] = 4 # tag number of physical group to be sliced - # Markers - p['Fluid'] = 'field' # Name of physical group containing the fluid - p['Farfield'] = ['upstream', 'farfield', 'downstream'] # LIST of name of physical groups containing the farfield boundaries (upstream/downstream should be first/last element) - p['Symmetry'] = 'symmetry' # Name of physical group containing the symmetry boundaries - p['Wings'] = ['wing'] # LIST of names of physical groups containing the lifting surface body - p['Wakes'] = ['wake'] # LIST of names of physical group containing the wake - p['WakeTips'] = ['wakeTip'] # LIST of names of physical group containing the edge of the wake - p['TeTips'] = ['teTip'] # LIST of names of physical group containing the edge of the wake and the trailing edge - # Freestream - p['M_inf'] = 0.3 # Freestream Mach number - p['AoA_begin'] = -3. # Freestream angle of attack (begin) - p['AoA_end'] = 3. # Freestream angle of attack (end) - p['AoA_step'] = 1. # Freestream angle of attack (step) - # Geometry - p['S_ref'] = 1.*span # Reference surface length - p['c_ref'] = 1. # Reference chord length - p['x_ref'] = 0.25 # Reference point for moment computation (x) - p['y_ref'] = 0. # Reference point for moment computation (y) - p['z_ref'] = 0. # Reference point for moment computation (z) - # Numerical - p['LSolver'] = 'MUMPS' # Linear solver (PARDISO, GMRES, or MUMPS) - p['Rel_tol'] = 1e-6 # Relative tolerance on solver residual - p['Abs_tol'] = 1e-8 # Absolute tolerance on solver residual - p['Max_it'] = 10 # Solver maximum number of iterations - return p - -def main(): - # Script call - import dart.api.internal.polar as p - polar = p.Polar(getParam()) - polar.run() - polar.disp() - -if __name__ == "__main__": - main() diff --git a/dart/cases/wbht.py b/dart/cases/wbht.py index 4744d14e7fac451e54428a842c6e4b6e37acc4ee..73a8f1daaa682aca82263d5d7027baf1f2ecb3d8 100644 --- a/dart/cases/wbht.py +++ b/dart/cases/wbht.py @@ -56,7 +56,7 @@ def getParam(): p['Dim'] = 3 # Problem dimension p['Format'] = 'vtk' # Save format (vtk or gmsh) p['Slice'] = [0.83, 3.0, 4.0, 6.2, 6.9] # array of (y) coordinates to perform slice along the span (empty if none) - p['TagId'] = 10 # tag number of physical group to be sliced + p['TagId'] = 12 # tag number of physical group to be sliced # Markers p['Fluid'] = 'field' # Name of physical group containing the fluid p['Farfield'] = ['upstream', 'farfield', 'downstream'] # LIST of names of physical groups containing the farfield boundaries (upstream/downstream should be first/last element) @@ -65,9 +65,10 @@ def getParam(): p['Wings'] = ['wing', 'tail'] # LIST of names of physical groups containing the lifting surface body p['Wakes'] = ['wakeW', 'wakeT'] # LIST of names of physical group containing the wake p['WakeTips'] = ['wakeTipW', 'wakeTipT'] # LIST of names of physical group containing the edge of the wake - p['TeTips'] = ['teTipW', 'teTipT'] # LIST of names of physical group containing the edge of the wake and the trailing edge + p['WakeExs'] = ['wakeExW', 'wakeExT'] # LIST of names of physical group containing the edge of the wake and the intersection of lifting surface with fuselage (to be excluded from Wake B.C.) + p['Tes'] = ['teW', 'teT'] # LIST of names of physical group containing the trailing edge # Freestream - p['M_inf'] = 0.75 # Freestream Mach number + p['M_inf'] = 0.72 # Freestream Mach number p['CL'] = 0.4 # Target lift coefficient p['AoA'] = 0. # Freestream angle of attack (guess) p['dCL'] = 7.5 # Slope of CL w.r.t AoA [1/rad] (guess) diff --git a/dart/cases/wht.py b/dart/cases/wht.py index ce7301700cb9d5967ab2f500b323740fe02a7d6d..dd0fc7d10496d2bdafe0eacdc246bbcf7445c00e 100644 --- a/dart/cases/wht.py +++ b/dart/cases/wht.py @@ -59,9 +59,9 @@ def getParam(): p['Wings'] = ['wing', 'tail'] # LIST of names of physical groups containing the lifting surface body p['Wakes'] = ['wakeW', 'wakeT'] # LIST of names of physical group containing the wake p['WakeTips'] = ['wakeTipW', 'wakeTipT'] # LIST of names of physical group containing the edge of the wake - p['TeTips'] = ['teTipW', 'teTipT'] # LIST of names of physical group containing the edge of the wake and the trailing edge + p['Tes'] = ['teW', 'teT'] # LIST of names of physical group containing the trailing edge # Freestream - p['M_inf'] = 0.75 # Freestream Mach number + p['M_inf'] = 0.72 # Freestream Mach number p['CL'] = 0.4 # Target lift coefficient p['AoA'] = 0. # Freestream angle of attack (guess) p['dCL'] = 7.5 # Slope of CL w.r.t AoA [1/rad] (guess) diff --git a/dart/default.py b/dart/default.py index b697a3f92f7ec2386c0d87b922212db0305df4f8..f7909a8f440d60c728e48e88ec5960f37bc66898 100644 --- a/dart/default.py +++ b/dart/default.py @@ -62,7 +62,7 @@ def mesh(dim, file, pars, bnd, wk = 'wake', wktp = None): gmshWriter.save(msh.name) return msh, gmshWriter -def problem(msh, dim, alpha, beta, minf, sref, lref, xref, yref, zref, sur, fld = 'field', upstr = 'upstream', ff = 'farfield', dnstr = 'downstream', wk = 'wake', te = None, tp = None, vsc = False, dbc = False): +def problem(msh, dim, alpha, beta, minf, sref, lref, xref, yref, zref, sur, fld = 'field', upstr = 'upstream', ff = 'farfield', dnstr = 'downstream', wk = 'wake', te = 'te', tp = None, vsc = False, dbc = False): """Initialize problem Parameters @@ -102,7 +102,7 @@ def problem(msh, dim, alpha, beta, minf, sref, lref, xref, yref, zref, sur, fld te : str (optional) name of physical tag contaning the trailing edge tp : str (optional) - name of physical tag contaning the wake tip (and the trailing edge for 3D) + name of physical tag contaning the wake tip (only for 3D) vsc : str (optional) name of physical tag contaning the body to apply transpiration B.C. dbc : bool (optional) @@ -126,15 +126,12 @@ def problem(msh, dim, alpha, beta, minf, sref, lref, xref, yref, zref, sur, fld pbl.add(dart.Freestream(msh, ff, dim, alpha, beta)) pbl.add(dart.Freestream(msh, dnstr, dim, alpha, beta)) # add wake and Kutta conditions - if dim == 2 and te is not None: - wake = dart.Wake(msh, [wk, wk+'_', fld]) - pbl.add(wake) - pbl.add(dart.Kutta(msh, [te, wk+'_', sur, fld])) - elif dim == 3: - wake = dart.Wake(msh, [wk, wk+'_', fld, tp]) - pbl.add(wake) + if tp is None: + wake = dart.Wake(msh, [wk, wk+'_', fld]) # 2 and 2.5D else: - wake = None + wake = dart.Wake(msh, [wk, wk+'_', fld, tp]) # 3D + pbl.add(wake) + pbl.add(dart.Kutta(msh, [te, wk+'_', sur, fld])) # add body of interest bnd = dart.Body(msh, [sur, fld]) pbl.add(bnd) @@ -158,7 +155,7 @@ def picard(pbl): problem formulation """ args = parseargs() - solver = dart.Picard(pbl, tbox.Gmres(), nthrds=args.k, vrb=args.verb+1) + solver = dart.Picard(pbl, tbox.Gmres(1, 1e-6, 30, 1e-8), nthrds=args.k, vrb=args.verb+1) return solver def newton(pbl): @@ -195,7 +192,7 @@ def morpher(msh, dim, mov, fxd = ['upstream', 'farfield', 'downstream'], fld = ' name of physical tag contaning the symmetry plane (y) """ args = parseargs() - mshDef = tbox.MshDeform(msh, dim, nthrds=args.k) + mshDef = tbox.MshDeform(msh, tbox.Gmres(1, 1e-6, 30, 1e-8), dim, nthrds=args.k) mshDef.setField(fld) mshDef.addFixed(fxd) mshDef.addMoving(mov) @@ -215,8 +212,7 @@ def adjoint(solver, morpher): solver : tbox.MshDeform object mesh morpher """ - from tbox.solvers import LinearSolver - adjoint = dart.Adjoint(solver, morpher, LinearSolver().pardiso()) + adjoint = dart.Adjoint(solver, morpher) return adjoint def initViewer(problem): diff --git a/dart/models/agard445.geo b/dart/models/agard445.geo index c7007513110879f3906df863a6c26e1f16dcb322..d26866470a8cb6b02b872b5cb6494022d109d0ff 100644 --- a/dart/models/agard445.geo +++ b/dart/models/agard445.geo @@ -354,7 +354,7 @@ Mesh.SmoothNormals = 1; // Trailing edge and wake tip Physical Line("wakeTip") = {162}; -Physical Line("teTip") = {61, 162}; +Physical Line("te") = {61}; // Internal Field: Physical Volume("field") = {1}; diff --git a/dart/models/coyote.geo b/dart/models/coyote.geo index c9e3615f9aa4efa89c7409c58c96e60ef3679703..bdf9a0cc9fe4ec222421b044ec6bd1a3b1ee3d53 100644 --- a/dart/models/coyote.geo +++ b/dart/models/coyote.geo @@ -61,9 +61,11 @@ Coherence; /* Physical */ // Tips -Physical Line("teTipW") = {155:158, 160:161, 164:167, 169:170}; +Physical Line("wakeExW") = {156:158, 160, 165:167, 169}; +Physical Line("teW") = {155, 161, 164, 170}; Physical Line("wakeTipW") = {160, 169}; -Physical Line("teTipT") = {173:176, 178:181}; +Physical Line("wakeExT") = {173, 175, 176, 178, 180, 181}; +Physical Line("teT") = {174, 179}; Physical Line("wakeTipT") = {173, 178}; // Downstream diff --git a/dart/models/cylinder_2D5.geo b/dart/models/cylinder_2D5.geo deleted file mode 100644 index cc70813611ef7e12c5d07f74371e69da126c9cf4..0000000000000000000000000000000000000000 --- a/dart/models/cylinder_2D5.geo +++ /dev/null @@ -1,161 +0,0 @@ -/* 2D5 Cylinder */ - -// Parameters -// domain -DefineConstant[ dmt = { 1.0, Name "Cylinder diameter" } ]; -DefineConstant[ lgt = { 3.0, Name "Channel length" } ]; -DefineConstant[ wdt = { 2.0, Name "Channel width" } ]; -DefineConstant[ hgt = { 3.0, Name "Channel height" } ]; -DefineConstant[ msN = { 0.1, Min 0.1, Max 1, Step 0.1, Name "Nearfield mesh size" } ]; -DefineConstant[ msF = { 1.0, Min 0.1, Max 1, Step 0.1, Name "Farfield mesh size" } ]; - -// mesh algo -msh3D = 2; -msh2D = 5; - -// Geometry -// cylinder -Point(0) = {0, 0, 0}; -Point(1) = {dmt/2, 0, 0, msN}; -Point(2) = {0, 0, dmt/2, msN}; -Point(3) = {-dmt/2, 0, 0, msN}; -Point(4) = {0, 0, -dmt/2, msN}; -Point(10) = {0, wdt, 0}; -Point(11) = {dmt/2, wdt, 0, msN}; -Point(12) = {0, wdt, dmt/2, msN}; -Point(13) = {-dmt/2, wdt, 0, msN}; -Point(14) = {0, wdt, -dmt/2, msN}; - -// box -Point(31) = {lgt/2, 0, hgt/2, msF}; -Point(32) = {-lgt/2, 0, hgt/2, msF}; -Point(33) = {-lgt/2, 0, -hgt/2, msF}; -Point(34) = {lgt/2, 0, -hgt/2, msF}; -Point(35) = {lgt/2, wdt, hgt/2, msF}; -Point(36) = {-lgt/2, wdt, hgt/2, msF}; -Point(37) = {-lgt/2, wdt, -hgt/2, msF}; -Point(38) = {lgt/2, wdt, -hgt/2, msF}; - -// midplane -Point(41) = {lgt/2, 0, 0, msF}; -Point(42) = {lgt/2, wdt, 0, msF}; -Point(43) = {-lgt/2, wdt, 0, msF}; -Point(44) = {-lgt/2, 0, 0, msF}; - -// wing -Circle(1) = {1, 0, 2}; -Circle(2) = {2, 0, 3}; -Circle(3) = {3, 0, 4}; -Circle(4) = {4, 0, 1}; -Circle(5) = {11, 10, 12}; -Circle(6) = {12, 10, 13}; -Circle(7) = {13, 10, 14}; -Circle(8) = {14, 10, 11}; -Line(9) = {1, 11}; -Line(10) = {2, 12}; -Line(11) = {3, 13}; -Line(12) = {4, 14}; - -// box -Line(21) = {41, 31}; -Line(22) = {31, 32}; -Line(23) = {32, 44}; -Line(24) = {44, 33}; -Line(25) = {33, 34}; -Line(26) = {34, 41}; -Line(27) = {42, 35}; -Line(28) = {35, 36}; -Line(29) = {36, 43}; -Line(30) = {43, 37}; -Line(31) = {37, 38}; -Line(32) = {38, 42}; -Line(33) = {31, 35}; -Line(34) = {32, 36}; -Line(35) = {33, 37}; -Line(36) = {34, 38}; - -// midplane -Line(41) = {1, 41}; -Line(42) = {11, 42}; -Line(43) = {13, 43}; -Line(44) = {3, 44}; -Line(45) = {41, 42}; -Line(46) = {42, 11}; -Line(47) = {13, 43}; -Line(48) = {43, 44}; - -// wing -Line Loop(1) = {1, 10, -5, -9}; -Surface(1) = {-1}; -Line Loop(2) = {2, 11, -6, -10}; -Surface(2) = {-2}; -Line Loop(3) = {3, 12, -7, -11}; -Surface(3) = {-3}; -Line Loop(4) = {4, 9, -8, -12}; -Surface(4) = {-4}; - -// symmetry -Line Loop(5) = {41, 21, 22, 23, -44, -2, -1}; -Plane Surface(5) = {-5}; -Line Loop(12) = {42, 27, 28, 29, -43, -6, -5}; -Plane Surface(12) = {12}; -Line Loop(6) = {44, 24, 25, 26, -41, -4, -3}; -Plane Surface(6) = {-6}; -Line Loop(13) = {43, 30, 31, 32, -42, -8, -7}; -Plane Surface(13) = {13}; - -// upstream -Line Loop(7) = {48, -23, 34, 29}; -Plane Surface(7) = {-7}; -Line Loop(8) = {48, 24, 35, -30}; -Plane Surface(8) = {8}; - -// downstream -Line Loop(9) = {45, 27, -33, -21}; -Plane Surface(9) = {-9}; -Line Loop(10) = {45, -32, -36, 26}; -Plane Surface(10) = {10}; - -// farfield -Line Loop(11) = {22, 34, -28, -33}; -Plane Surface(11) = {11}; -Line Loop(14) = {25, 36, -31, -35}; -Plane Surface(14) = {14}; - -// wake -Line Loop(15) = {41, 45, -42, -9}; -Plane Surface(15) = {15}; - -// internal -Line Loop(16) = {11, 43, 48, -44}; -Plane Surface(16) = {16}; - -// field -Surface Loop(1) = {7, 5, 9, 12, 11, 2, 1, 16, 15}; -Volume(1) = {1}; -Surface Loop(2) = {6, 8, 14, 10, 13, 4, 3, 16, 15}; -Volume(2) = {2}; - -// Mesh -// 2D -MeshAlgorithm Surface{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} = msh2D; -// 3D -Mesh.Algorithm3D = msh3D; -Mesh.OptimizeNetgen = 1; -Mesh.Smoothing = 10; -Mesh.SmoothNormals = 1; - -// Physical -Physical Line("te") = {9}; -Physical Surface("cylinder") = {1, 2}; -Physical Surface("cylinder_") = {3, 4}; -Physical Surface("symmetry") = {5, 12}; -Physical Surface("symmetry_") = {6, 13}; -Physical Surface("upstream") = {7, 8}; -Physical Surface("downstream") = {9}; -Physical Surface("downstream_") = {10}; -Physical Surface("farfield") = {11, 14}; -Physical Surface("wake") = {15}; -Physical Volume("field") = {1}; -Physical Volume("field_") = {2}; - diff --git a/dart/models/cylinder_3.geo b/dart/models/cylinder_3.geo deleted file mode 100644 index f5c9602503fe6c07e9c567eee05ed1ff85f5b568..0000000000000000000000000000000000000000 --- a/dart/models/cylinder_3.geo +++ /dev/null @@ -1,203 +0,0 @@ -/* 3D Cylinder */ - -// Parameters -// domain -DefineConstant[ dmt = { 1.0, Name "Cylinder diameter" } ]; -DefineConstant[ spn = { 2.5, Name "Cylinder span" } ]; -DefineConstant[ tpt = { .05, Name "Cylinder tip thickness" } ]; // percentage of span -DefineConstant[ lgt = { 8.0, Name "Channel length" } ]; -DefineConstant[ wdt = { 4.0, Name "Channel width" } ]; -DefineConstant[ hgt = { 6.0, Name "Channel height" } ]; -DefineConstant[ msN = { 0.1, Min 0.1, Max 1, Step 0.1, Name "Nearfield mesh size" } ]; -DefineConstant[ msF = { 1.0, Min 0.1, Max 1, Step 0.1, Name "Farfield mesh size" } ]; - -// mesh algo -msh3D = 2; -msh2D = 5; - -// Geometry -// cylinder -Point(0) = {0, 0, 0}; -Point(1) = {dmt/2, 0, 0, msN}; -Point(2) = {0, 0, dmt/2, msN}; -Point(3) = {-dmt/2, 0, 0, msN}; -Point(4) = {0, 0, -dmt/2, msN}; -Point(10) = {0, spn, 0}; -Point(11) = {dmt/2, spn, 0, msN}; -Point(12) = {0, spn, dmt/2, msN}; -Point(13) = {-dmt/2, spn, 0, msN}; -Point(14) = {0, spn, -dmt/2, msN}; - -// tip -Point(21) = {0, spn+tpt*spn, 0, msN}; - -// box -Point(31) = {lgt/2, 0, hgt/2, msF}; -Point(32) = {-lgt/2, 0, hgt/2, msF}; -Point(33) = {-lgt/2, 0, -hgt/2, msF}; -Point(34) = {lgt/2, 0, -hgt/2, msF}; -Point(35) = {lgt/2, wdt, hgt/2, msF}; -Point(36) = {-lgt/2, wdt, hgt/2, msF}; -Point(37) = {-lgt/2, wdt, -hgt/2, msF}; -Point(38) = {lgt/2, wdt, -hgt/2, msF}; - -// midplane -Point(41) = {lgt/2, 0, 0, msF}; -Point(42) = {lgt/2, spn, 0, msF}; -Point(43) = {lgt/2, wdt, 0, msF}; -Point(44) = {dmt/2, wdt, 0, msF}; -Point(45) = {0, wdt, 0, msF}; -Point(46) = {-dmt/2, wdt, 0, msF}; -Point(47) = {-lgt/2, wdt, 0, msF}; -Point(48) = {-lgt/2, spn, 0, msF}; -Point(49) = {-lgt/2, 0, 0, msF}; - -// wing -Circle(1) = {1, 0, 2}; -Circle(2) = {2, 0, 3}; -Circle(3) = {3, 0, 4}; -Circle(4) = {4, 0, 1}; -Circle(11) = {11, 10, 12}; -Circle(12) = {12, 10, 13}; -Circle(13) = {13, 10, 14}; -Circle(14) = {14, 10, 11}; -Line(21) = {1, 11}; -Line(22) = {2, 12}; -Line(23) = {3, 13}; -Line(24) = {4, 14}; - -// tip -Ellipse(31) = {11, 10, 10, 21}; -Ellipse(32) = {12, 10, 10, 21}; -Ellipse(33) = {13, 10, 10, 21}; -Ellipse(34) = {14, 10, 10, 21}; - -// box -Line(41) = {41, 31}; -Line(42) = {31, 32}; -Line(43) = {32, 49}; -Line(44) = {49, 33}; -Line(45) = {33, 34}; -Line(46) = {34, 41}; -Line(47) = {43, 35}; -Line(48) = {35, 36}; -Line(49) = {36, 47}; -Line(50) = {47, 37}; -Line(51) = {37, 38}; -Line(52) = {38, 43}; -Line(53) = {31, 35}; -Line(54) = {32, 36}; -Line(55) = {33, 37}; -Line(56) = {34, 38}; - -// midplane -Line(61) = {1, 41}; -Line(62) = {11, 42}; -Line(63) = {11, 44}; -Line(64) = {21, 45}; -Line(65) = {13, 46}; -Line(66) = {13, 48}; -Line(67) = {3, 49}; -Line(68) = {41, 42}; -Line(69) = {42, 43}; -Line(70) = {43, 44}; -Line(71) = {44, 45}; -Line(72) = {45, 46}; -Line(73) = {46, 47}; -Line(74) = {47, 48}; -Line(75) = {48, 49}; - -// cylinder -Line Loop(1) = {1, 22, -11, -21}; -Surface(1) = {-1}; -Line Loop(2) = {2, 23, -12, -22}; -Surface(2) = {-2}; -Line Loop(3) = {3, 24, -13, -23}; -Surface(3) = {-3}; -Line Loop(4) = {4, 21, -14, -24}; -Surface(4) = {-4}; -//tip -Line Loop(5) = {11, 32, -31}; -Surface(5) = {-5}; -Line Loop(6) = {12, 33, -32}; -Surface(6) = {-6}; -Line Loop(7) = {13, 34, -33}; -Surface(7) = {-7}; -Line Loop(8) = {14, 31, -34}; -Surface(8) = {-8}; - -// symmetry -Line Loop(9) = {61, 41, 42, 43, -67, -2, -1}; -Plane Surface(9) = {-9}; -Line Loop(10) = {4, 61, -46, -45, -44, -67, 3}; -Plane Surface(10) = {10}; - -// upstream -Line Loop(11) = {43, -75, -74, -49, -54}; -Plane Surface(11) = {11}; -Line Loop(12) = {75, 44, 55, -50, 74}; -Plane Surface(12) = {12}; - -// downstream -Line Loop(13) = {41, 53, -47, -69, -68}; -Plane Surface(13) = {13}; -Line Loop(14) = {68, 69, -52, -56, 46}; -Plane Surface(14) = {14}; - -// farfield -Line Loop(15) = {42, 54, -48, -53}; -Plane Surface(15) = {15}; -Line Loop(16) = {47, 48, 49, -73, -72, -71, -70}; -Plane Surface(16) = {16}; -Line Loop(17) = {51, 52, 70, 71, 72, 73, 50}; -Plane Surface(17) = {17}; -Line Loop(18) = {45, 56, -51, -55}; -Plane Surface(18) = {18}; - -// wake -Line Loop(19) = {61, 68, -62, -21}; -Surface(19) = {19}; - -// internal -Line Loop(20) = {62, 69, 70, -63}; -Surface(20) = {20}; -Line Loop(21) = {64, -71, -63, 31}; -Surface(21) = {-21}; -Line Loop(22) = {65, -72, -64, -33}; -Surface(22) = {-22}; -Line Loop(23) = {74, -66, 65, 73}; -Surface(23) = {23}; -Line Loop(24) = {75, -67, 23, 66}; -Surface(24) = {24}; - -// field -Surface Loop(1) = {15, 9, 13, 16, 11, 2, 6, 5, 1, 24, 23, 22, 21, 20, 19}; -Volume(1) = {1}; -Surface Loop(2) = {10, 4, 8, 7, 3, 14, 17, 18, 12, 24, 23, 22, 21, 20, 19}; -Volume(2) = {2}; - -// Mesh -// cylinder, farfield, symmetry, midplane -MeshAlgorithm Surface{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24} = msh2D; -// 3D -Mesh.Algorithm3D = msh3D; -Mesh.OptimizeNetgen = 1; -Mesh.Smoothing = 10; -Mesh.SmoothNormals = 1; - -// Physical -Physical Line("teTip") = {21, 62}; -Physical Line("wakeTip") = {62}; -Physical Surface("cylinder") = {1, 2}; -Physical Surface("cylinder_") = {3, 4}; -Physical Surface("tip") = {5, 6, 7, 8}; -Physical Surface("symmetry") = {9}; -Physical Surface("symmetry_") = {10}; -Physical Surface("upstream") = {11, 12}; -Physical Surface("downstream") = {13}; -Physical Surface("downstream_") = {14}; -Physical Surface("farfield") = {15, 16, 17, 18}; -Physical Surface("wake") = {19}; -Physical Volume("field") = {1}; -Physical Volume("field_") = {2}; - diff --git a/dart/models/n0012_3.geo b/dart/models/n0012_3.geo deleted file mode 100644 index c8b02ca41949324232d062a0b5289585c7198591..0000000000000000000000000000000000000000 --- a/dart/models/n0012_3.geo +++ /dev/null @@ -1,442 +0,0 @@ -/* Rectangular NACA0012 wing */ -// Initially generated by unsRgridWingGen.m -// For gmsh 4, use line 334 instead of line 335 (Bezier <- BSpline) - -// Parameters -// domain and mesh -DefineConstant[ spn = { 2.0, Name "Wing span" } ]; -DefineConstant[ lgt = { 3.0, Name "Channel length" } ]; -DefineConstant[ wdt = { 3.0, Name "Channel width" } ]; -DefineConstant[ hgt = { 3.0, Name "Channel height" } ]; -DefineConstant[ msLe = { 0.05, Name "Leading edge mesh size" } ]; -DefineConstant[ msTe = { 0.05, Name "Trailing edge mesh size" } ]; -DefineConstant[ msF = { 1.0, Name "Farfield mesh size" } ]; - -//// GEOMETRY - - -/// Points - -// Airfoil 1: naca0012, 101 points -Point(1) = {1.000000,0.000000,0.000000,msTe}; -Point(2) = {0.999013,0.000000,0.000143}; -Point(3) = {0.996057,0.000000,0.000572}; -Point(4) = {0.991144,0.000000,0.001280}; -Point(5) = {0.984292,0.000000,0.002260}; -Point(6) = {0.975528,0.000000,0.003501}; -Point(7) = {0.964888,0.000000,0.004990}; -Point(8) = {0.952414,0.000000,0.006710}; -Point(9) = {0.938153,0.000000,0.008643}; -Point(10) = {0.922164,0.000000,0.010770}; -Point(11) = {0.904508,0.000000,0.013071,msTe}; -Point(12) = {0.885257,0.000000,0.015523}; -Point(13) = {0.864484,0.000000,0.018106}; -Point(14) = {0.842274,0.000000,0.020795}; -Point(15) = {0.818712,0.000000,0.023569}; -Point(16) = {0.793893,0.000000,0.026405}; -Point(17) = {0.767913,0.000000,0.029279}; -Point(18) = {0.740877,0.000000,0.032168}; -Point(19) = {0.712890,0.000000,0.035048}; -Point(20) = {0.684062,0.000000,0.037896}; -Point(21) = {0.654508,0.000000,0.040686}; -Point(22) = {0.624345,0.000000,0.043394}; -Point(23) = {0.593691,0.000000,0.045992}; -Point(24) = {0.562667,0.000000,0.048455}; -Point(25) = {0.531395,0.000000,0.050754}; -Point(26) = {0.500000,0.000000,0.052862}; -Point(27) = {0.468605,0.000000,0.054749}; -Point(28) = {0.437333,0.000000,0.056390}; -Point(29) = {0.406309,0.000000,0.057755}; -Point(30) = {0.375655,0.000000,0.058819}; -Point(31) = {0.345492,0.000000,0.059557}; -Point(32) = {0.315938,0.000000,0.059947}; -Point(33) = {0.287110,0.000000,0.059971,msTe}; -Point(34) = {0.259123,0.000000,0.059614}; -Point(35) = {0.232087,0.000000,0.058863}; -Point(36) = {0.206107,0.000000,0.057712}; -Point(37) = {0.181288,0.000000,0.056159}; -Point(38) = {0.157726,0.000000,0.054206}; -Point(39) = {0.135516,0.000000,0.051862}; -Point(40) = {0.114743,0.000000,0.049138}; -Point(41) = {0.095492,0.000000,0.046049}; -Point(42) = {0.077836,0.000000,0.042615}; -Point(43) = {0.061847,0.000000,0.038859}; -Point(44) = {0.047586,0.000000,0.034803}; -Point(45) = {0.035112,0.000000,0.030473}; -Point(46) = {0.024472,0.000000,0.025893}; -Point(47) = {0.015708,0.000000,0.021088}; -Point(48) = {0.008856,0.000000,0.016078}; -Point(49) = {0.003943,0.000000,0.010884}; -Point(50) = {0.000987,0.000000,0.005521}; -Point(51) = {0.000000,0.000000,0.000000,msLe}; -Point(52) = {0.000987,0.000000,-0.005521}; -Point(53) = {0.003943,0.000000,-0.010884}; -Point(54) = {0.008856,0.000000,-0.016078}; -Point(55) = {0.015708,0.000000,-0.021088}; -Point(56) = {0.024472,0.000000,-0.025893}; -Point(57) = {0.035112,0.000000,-0.030473}; -Point(58) = {0.047586,0.000000,-0.034803}; -Point(59) = {0.061847,0.000000,-0.038859}; -Point(60) = {0.077836,0.000000,-0.042615}; -Point(61) = {0.095492,0.000000,-0.046049}; -Point(62) = {0.114743,0.000000,-0.049138}; -Point(63) = {0.135516,0.000000,-0.051862}; -Point(64) = {0.157726,0.000000,-0.054206}; -Point(65) = {0.181288,0.000000,-0.056159}; -Point(66) = {0.206107,0.000000,-0.057712}; -Point(67) = {0.232087,0.000000,-0.058863}; -Point(68) = {0.259123,0.000000,-0.059614}; -Point(69) = {0.287110,0.000000,-0.059971,msTe}; -Point(70) = {0.315938,0.000000,-0.059947}; -Point(71) = {0.345492,0.000000,-0.059557}; -Point(72) = {0.375655,0.000000,-0.058819}; -Point(73) = {0.406309,0.000000,-0.057755}; -Point(74) = {0.437333,0.000000,-0.056390}; -Point(75) = {0.468605,0.000000,-0.054749}; -Point(76) = {0.500000,0.000000,-0.052862}; -Point(77) = {0.531395,0.000000,-0.050754}; -Point(78) = {0.562667,0.000000,-0.048455}; -Point(79) = {0.593691,0.000000,-0.045992}; -Point(80) = {0.624345,0.000000,-0.043394}; -Point(81) = {0.654508,0.000000,-0.040686}; -Point(82) = {0.684062,0.000000,-0.037896}; -Point(83) = {0.712890,0.000000,-0.035048}; -Point(84) = {0.740877,0.000000,-0.032168}; -Point(85) = {0.767913,0.000000,-0.029279}; -Point(86) = {0.793893,0.000000,-0.026405}; -Point(87) = {0.818712,0.000000,-0.023569}; -Point(88) = {0.842274,0.000000,-0.020795}; -Point(89) = {0.864484,0.000000,-0.018106}; -Point(90) = {0.885257,0.000000,-0.015523}; -Point(91) = {0.904508,0.000000,-0.013071,msTe}; -Point(92) = {0.922164,0.000000,-0.010770}; -Point(93) = {0.938153,0.000000,-0.008643}; -Point(94) = {0.952414,0.000000,-0.006710}; -Point(95) = {0.964888,0.000000,-0.004990}; -Point(96) = {0.975528,0.000000,-0.003501}; -Point(97) = {0.984292,0.000000,-0.002260}; -Point(98) = {0.991144,0.000000,-0.001280}; -Point(99) = {0.996057,0.000000,-0.000572}; -Point(100) = {0.999013,0.000000,-0.000143,msTe}; - -// Airfoil 2: naca0012, 101 points -Point(102) = {1.000000,spn,0.000000,msTe}; -Point(103) = {0.999013,spn,0.000143}; -Point(104) = {0.996057,spn,0.000572}; -Point(105) = {0.991144,spn,0.001280}; -Point(106) = {0.984292,spn,0.002260}; -Point(107) = {0.975528,spn,0.003501}; -Point(108) = {0.964888,spn,0.004990}; -Point(109) = {0.952414,spn,0.006710}; -Point(110) = {0.938153,spn,0.008643}; -Point(111) = {0.922164,spn,0.010770}; -Point(112) = {0.904508,spn,0.013071,msTe}; -Point(113) = {0.885257,spn,0.015523}; -Point(114) = {0.864484,spn,0.018106}; -Point(115) = {0.842274,spn,0.020795}; -Point(116) = {0.818712,spn,0.023569}; -Point(117) = {0.793893,spn,0.026405}; -Point(118) = {0.767913,spn,0.029279}; -Point(119) = {0.740877,spn,0.032168}; -Point(120) = {0.712890,spn,0.035048}; -Point(121) = {0.684062,spn,0.037896}; -Point(122) = {0.654508,spn,0.040686}; -Point(123) = {0.624345,spn,0.043394}; -Point(124) = {0.593691,spn,0.045992}; -Point(125) = {0.562667,spn,0.048455}; -Point(126) = {0.531395,spn,0.050754}; -Point(127) = {0.500000,spn,0.052862}; -Point(128) = {0.468605,spn,0.054749}; -Point(129) = {0.437333,spn,0.056390}; -Point(130) = {0.406309,spn,0.057755}; -Point(131) = {0.375655,spn,0.058819}; -Point(132) = {0.345492,spn,0.059557}; -Point(133) = {0.315938,spn,0.059947}; -Point(134) = {0.287110,spn,0.059971,msTe}; -Point(135) = {0.259123,spn,0.059614}; -Point(136) = {0.232087,spn,0.058863}; -Point(137) = {0.206107,spn,0.057712}; -Point(138) = {0.181288,spn,0.056159}; -Point(139) = {0.157726,spn,0.054206}; -Point(140) = {0.135516,spn,0.051862}; -Point(141) = {0.114743,spn,0.049138}; -Point(142) = {0.095492,spn,0.046049}; -Point(143) = {0.077836,spn,0.042615}; -Point(144) = {0.061847,spn,0.038859}; -Point(145) = {0.047586,spn,0.034803}; -Point(146) = {0.035112,spn,0.030473}; -Point(147) = {0.024472,spn,0.025893}; -Point(148) = {0.015708,spn,0.021088}; -Point(149) = {0.008856,spn,0.016078}; -Point(150) = {0.003943,spn,0.010884}; -Point(151) = {0.000987,spn,0.005521}; -Point(152) = {0.000000,spn,0.000000,msLe}; -Point(153) = {0.000987,spn,-0.005521}; -Point(154) = {0.003943,spn,-0.010884}; -Point(155) = {0.008856,spn,-0.016078}; -Point(156) = {0.015708,spn,-0.021088}; -Point(157) = {0.024472,spn,-0.025893}; -Point(158) = {0.035112,spn,-0.030473}; -Point(159) = {0.047586,spn,-0.034803}; -Point(160) = {0.061847,spn,-0.038859}; -Point(161) = {0.077836,spn,-0.042615}; -Point(162) = {0.095492,spn,-0.046049}; -Point(163) = {0.114743,spn,-0.049138}; -Point(164) = {0.135516,spn,-0.051862}; -Point(165) = {0.157726,spn,-0.054206}; -Point(166) = {0.181288,spn,-0.056159}; -Point(167) = {0.206107,spn,-0.057712}; -Point(168) = {0.232087,spn,-0.058863}; -Point(169) = {0.259123,spn,-0.059614}; -Point(170) = {0.287110,spn,-0.059971,msTe}; -Point(171) = {0.315938,spn,-0.059947}; -Point(172) = {0.345492,spn,-0.059557}; -Point(173) = {0.375655,spn,-0.058819}; -Point(174) = {0.406309,spn,-0.057755}; -Point(175) = {0.437333,spn,-0.056390}; -Point(176) = {0.468605,spn,-0.054749}; -Point(177) = {0.500000,spn,-0.052862}; -Point(178) = {0.531395,spn,-0.050754}; -Point(179) = {0.562667,spn,-0.048455}; -Point(180) = {0.593691,spn,-0.045992}; -Point(181) = {0.624345,spn,-0.043394}; -Point(182) = {0.654508,spn,-0.040686}; -Point(183) = {0.684062,spn,-0.037896}; -Point(184) = {0.712890,spn,-0.035048}; -Point(185) = {0.740877,spn,-0.032168}; -Point(186) = {0.767913,spn,-0.029279}; -Point(187) = {0.793893,spn,-0.026405}; -Point(188) = {0.818712,spn,-0.023569}; -Point(189) = {0.842274,spn,-0.020795}; -Point(190) = {0.864484,spn,-0.018106}; -Point(191) = {0.885257,spn,-0.015523}; -Point(192) = {0.904508,spn,-0.013071,msTe}; -Point(193) = {0.922164,spn,-0.010770}; -Point(194) = {0.938153,spn,-0.008643}; -Point(195) = {0.952414,spn,-0.006710}; -Point(196) = {0.964888,spn,-0.004990}; -Point(197) = {0.975528,spn,-0.003501}; -Point(198) = {0.984292,spn,-0.002260}; -Point(199) = {0.991144,spn,-0.001280}; -Point(200) = {0.996057,spn,-0.000572}; -Point(201) = {0.999013,spn,-0.000143,msTe}; - -// Tip: -Point(5101) = {0.999013,spn,0.000000}; -Point(5102) = {0.996057,spn+0.000125,0.000000}; -Point(5103) = {0.991144,spn+0.000331,0.000000}; -Point(5104) = {0.984292,spn+0.000620,0.000000}; -Point(5105) = {0.975528,spn+0.000989,0.000000}; -Point(5106) = {0.964888,spn+0.001437,0.000000}; -Point(5107) = {0.952414,spn+0.001963,0.000000}; -Point(5108) = {0.938153,spn+0.002563,0.000000}; -Point(5109) = {0.922164,spn+0.003237,0.000000}; -Point(5110) = {0.904508,spn+0.003981,0.000000,msTe}; -Point(5111) = {0.885257,spn+0.004791,0.000000}; -Point(5112) = {0.864484,spn+0.005666,0.000000}; -Point(5113) = {0.842274,spn+0.006602,0.000000}; -Point(5114) = {0.818712,spn+0.007594,0.000000}; -Point(5115) = {0.793893,spn+0.008640,0.000000}; -Point(5116) = {0.767913,spn+0.009734,0.000000}; -Point(5117) = {0.740877,spn+0.010873,0.000000}; -Point(5118) = {0.712890,spn+0.012052,0.000000}; -Point(5119) = {0.684062,spn+0.013266,0.000000}; -Point(5120) = {0.654508,spn+0.014511,0.000000}; -Point(5121) = {0.624345,spn+0.015781,0.000000}; -Point(5122) = {0.593691,spn+0.017072,0.000000}; -Point(5123) = {0.562667,spn+0.018379,0.000000}; -Point(5124) = {0.531395,spn+0.019696,0.000000}; -Point(5125) = {0.500000,spn+0.021019,0.000000}; -Point(5126) = {0.468605,spn+0.022341,0.000000}; -Point(5127) = {0.437333,spn+0.023658,0.000000}; -Point(5128) = {0.406309,spn+0.024965,0.000000}; -Point(5129) = {0.375655,spn+0.026256,0.000000}; -Point(5130) = {0.345492,spn+0.027526,0.000000}; -Point(5131) = {0.315938,spn+0.028771,0.000000}; -Point(5132) = {0.287110,spn+0.029985,0.000000,msTe}; -Point(5133) = {0.019492,spn+0.041801,0.000000}; - -// Dummy tip center: -Point(5349) = {0.904508,spn,0.000000}; -Point(5350) = {0.287110,spn,0.000000}; - -// Box -Point(10001) = {1+lgt, 0, 0, msF}; -Point(10002) = {1+lgt, 0, hgt, msF}; -Point(10003) = {-lgt, 0, hgt, msF}; -Point(10004) = {-lgt, 0, -hgt, msF}; -Point(10005) = {1+lgt, 0, -hgt, msF}; -Point(10011) = {1+lgt, wdt, hgt, msF}; -Point(10012) = {-lgt, wdt, hgt, msF}; -Point(10013) = {-lgt, wdt, -hgt, msF}; -Point(10014) = {1+lgt, wdt, -hgt, msF}; - -// Wake -Point(10021) = {1+lgt, spn, 0, msF}; - -/// Lines - -// Airfoil 1: -Spline(1) = {1,2,3,4,5,6,7,8,9,10,11}; -Spline(2) = {11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33}; -Spline(3) = {33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; -Spline(4) = {51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69}; -Spline(5) = {69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91}; -Spline(6) = {91,92,93,94,95,96,97,98,99,100,1}; - -// Airfoil 2: -Spline(7) = {102,103,104,105,106,107,108,109,110,111,112}; -Spline(8) = {112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134}; -Spline(9) = {134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152}; -Spline(10) = {152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170}; -Spline(11) = {170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192}; -Spline(12) = {192,193,194,195,196,197,198,199,200,201,102}; - -// Airfoil 1 to airfoil 2: -Line(61) = {1,102}; -Line(62) = {11,112}; -Line(63) = {33,134}; -Line(64) = {51,152}; -Line(65) = {69,170}; -Line(66) = {91,192}; - -// Tip: -Spline(121) = {102,5101,5102,5103,5104,5105,5106,5107,5108,5109,5110}; -Spline(122) = {5110,5111,5112,5113,5114,5115,5116,5117,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132}; -If(GMSH_MAJOR_VERSION >= 4) - Bezier(123) = {5132,5133,152}; -Else - BSpline(123) = {5132,5133,152}; -EndIf -Ellipse(124) = {112,5349,112,5110}; -Ellipse(125) = {134,5350,134,5132}; -Ellipse(126) = {170,5350,170,5132}; -Ellipse(127) = {192,5349,192,5110}; - -// Box -Line(201) = {10001,10002}; -Line(202) = {10002,10003}; -Line(203) = {10003,10004}; -Line(204) = {10004,10005}; -Line(205) = {10005,10001}; -Line(211) = {10011,10012}; -Line(212) = {10012,10013}; -Line(213) = {10013,10014}; -Line(214) = {10014,10011}; -Line(221) = {1, 10001}; -Line(222) = {102, 10021}; -Line(231) = {10002,10011}; -Line(232) = {10003,10012}; -Line(233) = {10004,10013}; -Line(234) = {10005,10014}; - -// Wake -Line(241) = {10001, 10021}; - -/// Line loops & Surfaces - -// Wing 1: -Line Loop(1) = {1,62,-7,-61}; -Line Loop(2) = {2,63,-8,-62}; -Line Loop(3) = {3,64,-9,-63}; -Line Loop(4) = {4,65,-10,-64}; -Line Loop(5) = {5,66,-11,-65}; -Line Loop(6) = {6,61,-12,-66}; -Surface(1) = {-1}; -Surface(2) = {-2}; -Surface(3) = {-3}; -Surface(4) = {-4}; -Surface(5) = {-5}; -Surface(6) = {-6}; - -// Wingtip: -Line Loop(11) = {7,124,-121}; -Line Loop(12) = {8,125,-122,-124}; -Line Loop(13) = {9,-123,-125}; -Line Loop(14) = {10,126,123}; -Line Loop(15) = {11,127,122,-126}; -Line Loop(16) = {12,121,-127}; -Surface(11) = {-11}; -Surface(12) = {-12}; -Surface(13) = {-13}; -Surface(14) = {-14}; -Surface(15) = {-15}; -Surface(16) = {-16}; - -// Symmetry -Line Loop(21) = {201, 202, 203, 204, 205}; -Line Loop(22) = {1, 2, 3, 4, 5, 6}; -Plane Surface(21) = {-21, 22}; - -// Downsteam -Line Loop(31) = {201, 231, -214, -234, 205}; -Plane Surface(31) = {31}; - -// Farfield -Line Loop(41) = {233, -212, -232, 203}; -Plane Surface(41) = {41}; -Line Loop(42) = {204, 234, -213, -233}; -Plane Surface(42) = {42}; -Line Loop(43) = {202, 232, -211, -231}; -Plane Surface(43) = {43}; -Line Loop(44) = {213, 214, 211, 212}; -Plane Surface(44) = {44}; - -// Wake -Line Loop(51) = {221, 241, -222, -61}; -Surface(51) = {51}; - -/// Volume -Surface Loop(1) = {1,2,3,4,5,6,11,12,13,14,15,16,21,31,41,42,43,44}; -Volume(1) = {1}; - -/// Embbeded -Line{221} In Surface{21}; -Line{241} In Surface{31}; -Surface{51} In Volume{1}; - -//// MESHING ALGORITHM - -/// 2D: - -///Wing, farfield and symmetry plane: -MeshAlgorithm Surface{1,2,3,4,5,6,21,31,41,42,43,44,51} = 5; - -///Tip: -MeshAlgorithm Surface{11,12,13,14,15,16} = 1; - -/// 3D: - -Mesh.Algorithm3D = 2; -//Mesh.OptimizeNetgen = 1; -Mesh.Optimize = 1; -Mesh.Smoothing = 10; -Mesh.SmoothNormals = 1; - - - -//// PHYSICAL GROUPS - -// Trailing edge and wake tip -Physical Line("wakeTip") = {222}; -Physical Line("teTip") = {61, 222}; - -// Internal Field: -Physical Volume("field") = {1}; - -// Wing: -Physical Surface("wing") = {1,2,3,11,12,13}; -Physical Surface("wing_") = {4,5,6,14,15,16}; - -// Symmetry: -Physical Surface("symmetry") = {21}; - -// Downstream: -Physical Surface("downstream") = {31}; - -// Farfield: -Physical Surface("upstream") = {41}; -Physical Surface("farfield") = {42,43,44}; - -// Wake: -Physical Surface("wake") = {51}; diff --git a/dart/models/oneraM6.geo b/dart/models/oneraM6.geo index 6c14627beea6c5588ab593509a2b95cf405377c6..25b777bf212557af77618346ac2a17f4690748bd 100644 --- a/dart/models/oneraM6.geo +++ b/dart/models/oneraM6.geo @@ -559,7 +559,7 @@ Mesh.SmoothNormals = 1; // Trailing edge and wake tip Physical Line("wakeTip") = {162}; -Physical Line("teTip") = {61, 162}; +Physical Line("te") = {61}; // Internal Field: Physical Volume("field") = {1}; diff --git a/dart/models/rae_25.geo b/dart/models/rae_25.geo new file mode 100644 index 0000000000000000000000000000000000000000..1deee3cd4c47b1440c640a1be8d462993215b809 --- /dev/null +++ b/dart/models/rae_25.geo @@ -0,0 +1,400 @@ +/* 2.5D extruded RAE 2822 wing */ + +// Parameters +// domain +DefineConstant[ spn = { 1.0, Name "Wing span" }, + lgt = { 6.0, Name "Channel length" }, + hgt = { 6.0, Name "Channel height" }, + msN = { 0.05, Min 0.1, Max 1, Step 0.1, Name "Nearfield mesh size" }, + msF = { 1.0, Min 0.1, Max 1, Step 0.1, Name "Farfield mesh size" } ]; + +// Geometry +// wing +Point(1) = {1.000000, -spn/2, 0.000000, msN}; +Point(2) = {0.999398, -spn/2, 0.000128, msN}; +Point(3) = {0.997592, -spn/2, 0.000510, msN}; +Point(4) = {0.994588, -spn/2, 0.001137, msN}; +Point(5) = {0.990393, -spn/2, 0.002001, msN}; +Point(6) = {0.985016, -spn/2, 0.003092, msN}; +Point(7) = {0.978470, -spn/2, 0.004401, msN}; +Point(8) = {0.970772, -spn/2, 0.005915, msN}; +Point(9) = {0.961940, -spn/2, 0.007622, msN}; +Point(10) = {0.951995, -spn/2, 0.009508, msN}; +Point(11) = {0.940961, -spn/2, 0.011562, msN}; +Point(12) = {0.928864, -spn/2, 0.013769, msN}; +Point(13) = {0.915735, -spn/2, 0.016113, msN}; +Point(14) = {0.901604, -spn/2, 0.018580, msN}; +Point(15) = {0.886505, -spn/2, 0.021153, msN}; +Point(16) = {0.870476, -spn/2, 0.023817, msN}; +Point(17) = {0.853553, -spn/2, 0.026554, msN}; +Point(18) = {0.835779, -spn/2, 0.029347, msN}; +Point(19) = {0.817197, -spn/2, 0.032176, msN}; +Point(20) = {0.797850, -spn/2, 0.035017, msN}; +Point(21) = {0.777785, -spn/2, 0.037847, msN}; +Point(22) = {0.757051, -spn/2, 0.040641, msN}; +Point(23) = {0.735698, -spn/2, 0.043377, msN}; +Point(24) = {0.713778, -spn/2, 0.046029, msN}; +Point(25) = {0.691342, -spn/2, 0.048575, msN}; +Point(26) = {0.668445, -spn/2, 0.050993, msN}; +Point(27) = {0.645142, -spn/2, 0.053258, msN}; +Point(28) = {0.621490, -spn/2, 0.055344, msN}; +Point(29) = {0.597545, -spn/2, 0.057218, msN}; +Point(30) = {0.573365, -spn/2, 0.058845, msN}; +Point(31) = {0.549009, -spn/2, 0.060194, msN}; +Point(32) = {0.524534, -spn/2, 0.061254, msN}; +Point(33) = {0.500000, -spn/2, 0.062029, msN}; +Point(34) = {0.475466, -spn/2, 0.062530, msN}; +Point(35) = {0.450991, -spn/2, 0.062774, msN}; +Point(36) = {0.426635, -spn/2, 0.062779, msN}; +Point(37) = {0.402455, -spn/2, 0.062562, msN}; +Point(38) = {0.378510, -spn/2, 0.062133, msN}; +Point(39) = {0.354858, -spn/2, 0.061497, msN}; +Point(40) = {0.331555, -spn/2, 0.060660, msN}; +Point(41) = {0.308658, -spn/2, 0.059629, msN}; +Point(42) = {0.286222, -spn/2, 0.058414, msN}; +Point(43) = {0.264302, -spn/2, 0.057026, msN}; +Point(44) = {0.242949, -spn/2, 0.055470, msN}; +Point(45) = {0.222215, -spn/2, 0.053753, msN}; +Point(46) = {0.202150, -spn/2, 0.051885, msN}; +Point(47) = {0.182803, -spn/2, 0.049874, msN}; +Point(48) = {0.164221, -spn/2, 0.047729, msN}; +Point(49) = {0.146447, -spn/2, 0.045457, msN}; +Point(50) = {0.129524, -spn/2, 0.043071, msN}; +Point(51) = {0.113495, -spn/2, 0.040585, msN}; +Point(52) = {0.098396, -spn/2, 0.038011, msN}; +Point(53) = {0.084265, -spn/2, 0.035360, msN}; +Point(54) = {0.071136, -spn/2, 0.032644, msN}; +Point(55) = {0.059039, -spn/2, 0.029874, msN}; +Point(56) = {0.048005, -spn/2, 0.027062, msN}; +Point(57) = {0.038060, -spn/2, 0.024219, msN}; +Point(58) = {0.029228, -spn/2, 0.021348, msN}; +Point(59) = {0.021530, -spn/2, 0.018441, msN}; +Point(60) = {0.014984, -spn/2, 0.015489, msN}; +Point(61) = {0.009607, -spn/2, 0.012480, msN}; +Point(62) = {0.005412, -spn/2, 0.009416, msN}; +Point(63) = {0.002408, -spn/2, 0.006306, msN}; +Point(64) = {0.000602, -spn/2, 0.003165, msN}; +Point(65) = {0.000000, -spn/2, 0.000000, msN}; +Point(66) = {0.000602, -spn/2, -0.003160, msN}; +Point(67) = {0.002408, -spn/2, -0.006308, msN}; +Point(68) = {0.005412, -spn/2, -0.009443, msN}; +Point(69) = {0.009607, -spn/2, -0.012559, msN}; +Point(70) = {0.014984, -spn/2, -0.015649, msN}; +Point(71) = {0.021530, -spn/2, -0.018707, msN}; +Point(72) = {0.029228, -spn/2, -0.021722, msN}; +Point(73) = {0.038060, -spn/2, -0.024685, msN}; +Point(74) = {0.048005, -spn/2, -0.027586, msN}; +Point(75) = {0.059039, -spn/2, -0.030416, msN}; +Point(76) = {0.071136, -spn/2, -0.033170, msN}; +Point(77) = {0.084265, -spn/2, -0.035843, msN}; +Point(78) = {0.098396, -spn/2, -0.038431, msN}; +Point(79) = {0.113495, -spn/2, -0.040929, msN}; +Point(80) = {0.129524, -spn/2, -0.043326, msN}; +Point(81) = {0.146447, -spn/2, -0.045610, msN}; +Point(82) = {0.164221, -spn/2, -0.047773, msN}; +Point(83) = {0.182803, -spn/2, -0.049805, msN}; +Point(84) = {0.202150, -spn/2, -0.051694, msN}; +Point(85) = {0.222215, -spn/2, -0.053427, msN}; +Point(86) = {0.242949, -spn/2, -0.054994, msN}; +Point(87) = {0.264302, -spn/2, -0.056376, msN}; +Point(88) = {0.286222, -spn/2, -0.057547, msN}; +Point(89) = {0.308658, -spn/2, -0.058459, msN}; +Point(90) = {0.331555, -spn/2, -0.059046, msN}; +Point(91) = {0.354858, -spn/2, -0.059236, msN}; +Point(92) = {0.378510, -spn/2, -0.058974, msN}; +Point(93) = {0.402455, -spn/2, -0.058224, msN}; +Point(94) = {0.426635, -spn/2, -0.056979, msN}; +Point(95) = {0.450991, -spn/2, -0.055257, msN}; +Point(96) = {0.475466, -spn/2, -0.053099, msN}; +Point(97) = {0.500000, -spn/2, -0.050563, msN}; +Point(98) = {0.524534, -spn/2, -0.047719, msN}; +Point(99) = {0.549009, -spn/2, -0.044642, msN}; +Point(100) = {0.573365, -spn/2, -0.041397, msN}; +Point(101) = {0.597545, -spn/2, -0.038043, msN}; +Point(102) = {0.621490, -spn/2, -0.034631, msN}; +Point(103) = {0.645142, -spn/2, -0.031207, msN}; +Point(104) = {0.668445, -spn/2, -0.027814, msN}; +Point(105) = {0.691342, -spn/2, -0.024495, msN}; +Point(106) = {0.713778, -spn/2, -0.021289, msN}; +Point(107) = {0.735698, -spn/2, -0.018232, msN}; +Point(108) = {0.757051, -spn/2, -0.015357, msN}; +Point(109) = {0.777785, -spn/2, -0.012690, msN}; +Point(110) = {0.797850, -spn/2, -0.010244, msN}; +Point(111) = {0.817197, -spn/2, -0.008027, msN}; +Point(112) = {0.835779, -spn/2, -0.006048, msN}; +Point(113) = {0.853553, -spn/2, -0.004314, msN}; +Point(114) = {0.870476, -spn/2, -0.002829, msN}; +Point(115) = {0.886505, -spn/2, -0.001592, msN}; +Point(116) = {0.901604, -spn/2, -0.000600, msN}; +Point(117) = {0.915735, -spn/2, 0.000157, msN}; +Point(118) = {0.928864, -spn/2, 0.000694, msN}; +Point(119) = {0.940961, -spn/2, 0.001033, msN}; +Point(120) = {0.951995, -spn/2, 0.001197, msN}; +Point(121) = {0.961940, -spn/2, 0.001212, msN}; +Point(122) = {0.970772, -spn/2, 0.001112, msN}; +Point(123) = {0.978470, -spn/2, 0.000935, msN}; +Point(124) = {0.985016, -spn/2, 0.000719, msN}; +Point(125) = {0.990393, -spn/2, 0.000497, msN}; +Point(126) = {0.994588, -spn/2, 0.000296, msN}; +Point(127) = {0.997592, -spn/2, 0.000137, msN}; +Point(128) = {0.999398, -spn/2, 0.000035, msN}; + +Point(301) = {1.000000, spn/2, 0.000000, msN}; +Point(302) = {0.999398, spn/2, 0.000128, msN}; +Point(303) = {0.997592, spn/2, 0.000510, msN}; +Point(304) = {0.994588, spn/2, 0.001137, msN}; +Point(305) = {0.990393, spn/2, 0.002001, msN}; +Point(306) = {0.985016, spn/2, 0.003092, msN}; +Point(307) = {0.978470, spn/2, 0.004401, msN}; +Point(308) = {0.970772, spn/2, 0.005915, msN}; +Point(309) = {0.961940, spn/2, 0.007622, msN}; +Point(310) = {0.951995, spn/2, 0.009508, msN}; +Point(311) = {0.940961, spn/2, 0.011562, msN}; +Point(312) = {0.928864, spn/2, 0.013769, msN}; +Point(313) = {0.915735, spn/2, 0.016113, msN}; +Point(314) = {0.901604, spn/2, 0.018580, msN}; +Point(315) = {0.886505, spn/2, 0.021153, msN}; +Point(316) = {0.870476, spn/2, 0.023817, msN}; +Point(317) = {0.853553, spn/2, 0.026554, msN}; +Point(318) = {0.835779, spn/2, 0.029347, msN}; +Point(319) = {0.817197, spn/2, 0.032176, msN}; +Point(320) = {0.797850, spn/2, 0.035017, msN}; +Point(321) = {0.777785, spn/2, 0.037847, msN}; +Point(322) = {0.757051, spn/2, 0.040641, msN}; +Point(323) = {0.735698, spn/2, 0.043377, msN}; +Point(324) = {0.713778, spn/2, 0.046029, msN}; +Point(325) = {0.691342, spn/2, 0.048575, msN}; +Point(326) = {0.668445, spn/2, 0.050993, msN}; +Point(327) = {0.645142, spn/2, 0.053258, msN}; +Point(328) = {0.621490, spn/2, 0.055344, msN}; +Point(329) = {0.597545, spn/2, 0.057218, msN}; +Point(330) = {0.573365, spn/2, 0.058845, msN}; +Point(331) = {0.549009, spn/2, 0.060194, msN}; +Point(332) = {0.524534, spn/2, 0.061254, msN}; +Point(333) = {0.500000, spn/2, 0.062029, msN}; +Point(334) = {0.475466, spn/2, 0.062530, msN}; +Point(335) = {0.450991, spn/2, 0.062774, msN}; +Point(336) = {0.426635, spn/2, 0.062779, msN}; +Point(337) = {0.402455, spn/2, 0.062562, msN}; +Point(338) = {0.378510, spn/2, 0.062133, msN}; +Point(339) = {0.354858, spn/2, 0.061497, msN}; +Point(340) = {0.331555, spn/2, 0.060660, msN}; +Point(341) = {0.308658, spn/2, 0.059629, msN}; +Point(342) = {0.286222, spn/2, 0.058414, msN}; +Point(343) = {0.264302, spn/2, 0.057026, msN}; +Point(344) = {0.242949, spn/2, 0.055470, msN}; +Point(345) = {0.222215, spn/2, 0.053753, msN}; +Point(346) = {0.202150, spn/2, 0.051885, msN}; +Point(347) = {0.182803, spn/2, 0.049874, msN}; +Point(348) = {0.164221, spn/2, 0.047729, msN}; +Point(349) = {0.146447, spn/2, 0.045457, msN}; +Point(350) = {0.129524, spn/2, 0.043071, msN}; +Point(351) = {0.113495, spn/2, 0.040585, msN}; +Point(352) = {0.098396, spn/2, 0.038011, msN}; +Point(353) = {0.084265, spn/2, 0.035360, msN}; +Point(354) = {0.071136, spn/2, 0.032644, msN}; +Point(355) = {0.059039, spn/2, 0.029874, msN}; +Point(356) = {0.048005, spn/2, 0.027062, msN}; +Point(357) = {0.038060, spn/2, 0.024219, msN}; +Point(358) = {0.029228, spn/2, 0.021348, msN}; +Point(359) = {0.021530, spn/2, 0.018441, msN}; +Point(360) = {0.014984, spn/2, 0.015489, msN}; +Point(361) = {0.009607, spn/2, 0.012480, msN}; +Point(362) = {0.005412, spn/2, 0.009416, msN}; +Point(363) = {0.002408, spn/2, 0.006306, msN}; +Point(364) = {0.000602, spn/2, 0.003165, msN}; +Point(365) = {0.000000, spn/2, 0.000000, msN}; +Point(366) = {0.000602, spn/2, -0.003160, msN}; +Point(367) = {0.002408, spn/2, -0.006308, msN}; +Point(368) = {0.005412, spn/2, -0.009443, msN}; +Point(369) = {0.009607, spn/2, -0.012559, msN}; +Point(370) = {0.014984, spn/2, -0.015649, msN}; +Point(371) = {0.021530, spn/2, -0.018707, msN}; +Point(372) = {0.029228, spn/2, -0.021722, msN}; +Point(373) = {0.038060, spn/2, -0.024685, msN}; +Point(374) = {0.048005, spn/2, -0.027586, msN}; +Point(375) = {0.059039, spn/2, -0.030416, msN}; +Point(376) = {0.071136, spn/2, -0.033170, msN}; +Point(377) = {0.084265, spn/2, -0.035843, msN}; +Point(378) = {0.098396, spn/2, -0.038431, msN}; +Point(379) = {0.113495, spn/2, -0.040929, msN}; +Point(380) = {0.129524, spn/2, -0.043326, msN}; +Point(381) = {0.146447, spn/2, -0.045610, msN}; +Point(382) = {0.164221, spn/2, -0.047773, msN}; +Point(383) = {0.182803, spn/2, -0.049805, msN}; +Point(384) = {0.202150, spn/2, -0.051694, msN}; +Point(385) = {0.222215, spn/2, -0.053427, msN}; +Point(386) = {0.242949, spn/2, -0.054994, msN}; +Point(387) = {0.264302, spn/2, -0.056376, msN}; +Point(388) = {0.286222, spn/2, -0.057547, msN}; +Point(389) = {0.308658, spn/2, -0.058459, msN}; +Point(390) = {0.331555, spn/2, -0.059046, msN}; +Point(391) = {0.354858, spn/2, -0.059236, msN}; +Point(392) = {0.378510, spn/2, -0.058974, msN}; +Point(393) = {0.402455, spn/2, -0.058224, msN}; +Point(394) = {0.426635, spn/2, -0.056979, msN}; +Point(395) = {0.450991, spn/2, -0.055257, msN}; +Point(396) = {0.475466, spn/2, -0.053099, msN}; +Point(397) = {0.500000, spn/2, -0.050563, msN}; +Point(398) = {0.524534, spn/2, -0.047719, msN}; +Point(399) = {0.549009, spn/2, -0.044642, msN}; +Point(400) = {0.573365, spn/2, -0.041397, msN}; +Point(401) = {0.597545, spn/2, -0.038043, msN}; +Point(402) = {0.621490, spn/2, -0.034631, msN}; +Point(403) = {0.645142, spn/2, -0.031207, msN}; +Point(404) = {0.668445, spn/2, -0.027814, msN}; +Point(405) = {0.691342, spn/2, -0.024495, msN}; +Point(406) = {0.713778, spn/2, -0.021289, msN}; +Point(407) = {0.735698, spn/2, -0.018232, msN}; +Point(408) = {0.757051, spn/2, -0.015357, msN}; +Point(409) = {0.777785, spn/2, -0.012690, msN}; +Point(410) = {0.797850, spn/2, -0.010244, msN}; +Point(411) = {0.817197, spn/2, -0.008027, msN}; +Point(412) = {0.835779, spn/2, -0.006048, msN}; +Point(413) = {0.853553, spn/2, -0.004314, msN}; +Point(414) = {0.870476, spn/2, -0.002829, msN}; +Point(415) = {0.886505, spn/2, -0.001592, msN}; +Point(416) = {0.901604, spn/2, -0.000600, msN}; +Point(417) = {0.915735, spn/2, 0.000157, msN}; +Point(418) = {0.928864, spn/2, 0.000694, msN}; +Point(419) = {0.940961, spn/2, 0.001033, msN}; +Point(420) = {0.951995, spn/2, 0.001197, msN}; +Point(421) = {0.961940, spn/2, 0.001212, msN}; +Point(422) = {0.970772, spn/2, 0.001112, msN}; +Point(423) = {0.978470, spn/2, 0.000935, msN}; +Point(424) = {0.985016, spn/2, 0.000719, msN}; +Point(425) = {0.990393, spn/2, 0.000497, msN}; +Point(426) = {0.994588, spn/2, 0.000296, msN}; +Point(427) = {0.997592, spn/2, 0.000137, msN}; +Point(428) = {0.999398, spn/2, 0.000035, msN}; + +// box +Point(631) = {1+lgt/2, -spn/2, hgt/2, msF}; +Point(632) = {-lgt/2, -spn/2, hgt/2, msF}; +Point(633) = {-lgt/2, -spn/2, -hgt/2, msF}; +Point(634) = {1+lgt/2, -spn/2, -hgt/2, msF}; +Point(635) = {1+lgt/2, spn/2, hgt/2, msF}; +Point(636) = {-lgt/2, spn/2, hgt/2, msF}; +Point(637) = {-lgt/2, spn/2, -hgt/2, msF}; +Point(638) = {1+lgt/2, spn/2, -hgt/2, msF}; + +// midplane +Point(641) = {1+lgt/2, -spn/2, 0, msF}; +Point(642) = {1+lgt/2, spn/2, 0, msF}; +Point(643) = {-lgt/2, spn/2, 0, msF}; +Point(644) = {-lgt/2, -spn/2, 0, msF}; + +// wing +Spline(1) = {1:44}; +Spline(2) = {44:65}; +Spline(3) = {65:86}; +Spline(4) = {86:128,1}; +Spline(5) = {301:344}; +Spline(6) = {344:365}; +Spline(7) = {365:386}; +Spline(8) = {386:428,301}; +Line(9) = {1, 301}; +Line(10) = {44, 344}; +Line(11) = {65, 365}; +Line(12) = {86, 386}; + +// box +Line(21) = {641, 631}; +Line(22) = {631, 632}; +Line(23) = {632, 644}; +Line(24) = {644, 633}; +Line(25) = {633, 634}; +Line(26) = {634, 641}; +Line(27) = {642, 635}; +Line(28) = {635, 636}; +Line(29) = {636, 643}; +Line(30) = {643, 637}; +Line(31) = {637, 638}; +Line(32) = {638, 642}; +Line(33) = {631, 635}; +Line(34) = {632, 636}; +Line(35) = {633, 637}; +Line(36) = {634, 638}; + +// midplane +Line(41) = {1, 641}; +Line(42) = {301, 642}; +Line(43) = {365, 643}; +Line(44) = {65, 644}; +Line(45) = {641, 642}; +Line(46) = {643, 644}; + +// wing +Line Loop(1) = {1, 10, -5, -9}; +Surface(1) = {-1}; +Line Loop(2) = {2, 11, -6, -10}; +Surface(2) = {-2}; +Line Loop(3) = {3, 12, -7, -11}; +Surface(3) = {-3}; +Line Loop(4) = {4, 9, -8, -12}; +Surface(4) = {-4}; + +// symmetry +Line Loop(5) = {41, 21, 22, 23, -44, -2, -1}; +Plane Surface(5) = {-5}; +Line Loop(12) = {42, 27, 28, 29, -43, -5, -6}; +Plane Surface(12) = {12}; +Line Loop(6) = {44, 24, 25, 26, -41, -4, -3}; +Plane Surface(6) = {-6}; +Line Loop(13) = {43, 30, 31, 32, -42, -8, -7}; +Plane Surface(13) = {13}; + +// upstream +Line Loop(7) = {46, -23, 34, 29}; +Plane Surface(7) = {-7}; +Line Loop(8) = {46, 24, 35, -30}; +Plane Surface(8) = {8}; + +// downstream +Line Loop(9) = {45, 27, -33, -21}; +Plane Surface(9) = {-9}; +Line Loop(10) = {45, -32, -36, 26}; +Plane Surface(10) = {10}; + +// farfield +Line Loop(11) = {22, 34, -28, -33}; +Plane Surface(11) = {11}; +Line Loop(14) = {25, 36, -31, -35}; +Plane Surface(14) = {14}; + +// wake +Line Loop(15) = {41, 45, -42, -9}; +Plane Surface(15) = {15}; + +// internal +Line Loop(16) = {11, 43, 46, -44}; +Plane Surface(16) = {16}; + +// field +Surface Loop(1) = {7, 5, 9, 12, 11, 1, 2, 16, 15}; +Volume(1) = {1}; +Surface Loop(2) = {6, 8, 14, 10, 13, 3, 4, 16, 15}; +Volume(2) = {2}; + +// Mesh +// 2D +MeshAlgorithm Surface{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} = 5; +// 3D +Mesh.Algorithm3D = 2; +Mesh.OptimizeNetgen = 1; +Mesh.Smoothing = 10; +Mesh.SmoothNormals = 1; + +// Physical +Physical Line("te") = {9}; +Physical Surface("wing") = {1, 2}; +Physical Surface("wing_") = {3, 4}; +Physical Surface("symmetry") = {5, 12}; +Physical Surface("symmetry_") = {6, 13}; +Physical Surface("upstream") = {7, 8}; +Physical Surface("downstream") = {9}; +Physical Surface("downstream_") = {10}; +Physical Surface("farfield") = {11, 14}; +Physical Surface("wake") = {15}; +Physical Volume("field") = {1}; +Physical Volume("field_") = {2}; diff --git a/dart/models/rae_3.geo b/dart/models/rae_3.geo new file mode 100644 index 0000000000000000000000000000000000000000..2c76facfc85fe7c42ea4173652badb3f87d5b6d7 --- /dev/null +++ b/dart/models/rae_3.geo @@ -0,0 +1,430 @@ +/* RAE 2822 rectangular wing */ + +// Parameters +// domain and mesh +DefineConstant[ spn = { 1.0, Name "Wing span" }, + lgt = { 6.0, Name "Channel length" }, + wdt = { 3.0, Name "Channel width" }, + hgt = { 6.0, Name "Channel height" }, + msN = { 0.05, Name "Leading edge mesh size" }, + msF = { 1.0, Name "Farfield mesh size" } ]; + +//// GEOMETRY + + +/// Points + +// Airfoil 1 +Point(1) = {1.000000, 0.0000, 0.000000, msN}; +Point(2) = {0.999398, 0.0000, 0.000128, msN}; +Point(3) = {0.997592, 0.0000, 0.000510, msN}; +Point(4) = {0.994588, 0.0000, 0.001137, msN}; +Point(5) = {0.990393, 0.0000, 0.002001, msN}; +Point(6) = {0.985016, 0.0000, 0.003092, msN}; +Point(7) = {0.978470, 0.0000, 0.004401, msN}; +Point(8) = {0.970772, 0.0000, 0.005915, msN}; +Point(9) = {0.961940, 0.0000, 0.007622, msN}; +Point(10) = {0.951995, 0.0000, 0.009508, msN}; +Point(11) = {0.940961, 0.0000, 0.011562, msN}; +Point(12) = {0.928864, 0.0000, 0.013769, msN}; +Point(13) = {0.915735, 0.0000, 0.016113, msN}; +Point(14) = {0.901604, 0.0000, 0.018580, msN}; +Point(15) = {0.886505, 0.0000, 0.021153, msN}; +Point(16) = {0.870476, 0.0000, 0.023817, msN}; +Point(17) = {0.853553, 0.0000, 0.026554, msN}; +Point(18) = {0.835779, 0.0000, 0.029347, msN}; +Point(19) = {0.817197, 0.0000, 0.032176, msN}; +Point(20) = {0.797850, 0.0000, 0.035017, msN}; +Point(21) = {0.777785, 0.0000, 0.037847, msN}; +Point(22) = {0.757051, 0.0000, 0.040641, msN}; +Point(23) = {0.735698, 0.0000, 0.043377, msN}; +Point(24) = {0.713778, 0.0000, 0.046029, msN}; +Point(25) = {0.691342, 0.0000, 0.048575, msN}; +Point(26) = {0.668445, 0.0000, 0.050993, msN}; +Point(27) = {0.645142, 0.0000, 0.053258, msN}; +Point(28) = {0.621490, 0.0000, 0.055344, msN}; +Point(29) = {0.597545, 0.0000, 0.057218, msN}; +Point(30) = {0.573365, 0.0000, 0.058845, msN}; +Point(31) = {0.549009, 0.0000, 0.060194, msN}; +Point(32) = {0.524534, 0.0000, 0.061254, msN}; +Point(33) = {0.500000, 0.0000, 0.062029, msN}; +Point(34) = {0.475466, 0.0000, 0.062530, msN}; +Point(35) = {0.450991, 0.0000, 0.062774, msN}; +Point(36) = {0.426635, 0.0000, 0.062779, msN}; +Point(37) = {0.402455, 0.0000, 0.062562, msN}; +Point(38) = {0.378510, 0.0000, 0.062133, msN}; +Point(39) = {0.354858, 0.0000, 0.061497, msN}; +Point(40) = {0.331555, 0.0000, 0.060660, msN}; +Point(41) = {0.308658, 0.0000, 0.059629, msN}; +Point(42) = {0.286222, 0.0000, 0.058414, msN}; +Point(43) = {0.264302, 0.0000, 0.057026, msN}; +Point(44) = {0.242949, 0.0000, 0.055470, msN}; +Point(45) = {0.222215, 0.0000, 0.053753, msN}; +Point(46) = {0.202150, 0.0000, 0.051885, msN}; +Point(47) = {0.182803, 0.0000, 0.049874, msN}; +Point(48) = {0.164221, 0.0000, 0.047729, msN}; +Point(49) = {0.146447, 0.0000, 0.045457, msN}; +Point(50) = {0.129524, 0.0000, 0.043071, msN}; +Point(51) = {0.113495, 0.0000, 0.040585, msN}; +Point(52) = {0.098396, 0.0000, 0.038011, msN}; +Point(53) = {0.084265, 0.0000, 0.035360, msN}; +Point(54) = {0.071136, 0.0000, 0.032644, msN}; +Point(55) = {0.059039, 0.0000, 0.029874, msN}; +Point(56) = {0.048005, 0.0000, 0.027062, msN}; +Point(57) = {0.038060, 0.0000, 0.024219, msN}; +Point(58) = {0.029228, 0.0000, 0.021348, msN}; +Point(59) = {0.021530, 0.0000, 0.018441, msN}; +Point(60) = {0.014984, 0.0000, 0.015489, msN}; +Point(61) = {0.009607, 0.0000, 0.012480, msN}; +Point(62) = {0.005412, 0.0000, 0.009416, msN}; +Point(63) = {0.002408, 0.0000, 0.006306, msN}; +Point(64) = {0.000602, 0.0000, 0.003165, msN}; +Point(65) = {0.000000, 0.0000, 0.000000, msN}; +Point(66) = {0.000602, 0.0000, -0.003160, msN}; +Point(67) = {0.002408, 0.0000, -0.006308, msN}; +Point(68) = {0.005412, 0.0000, -0.009443, msN}; +Point(69) = {0.009607, 0.0000, -0.012559, msN}; +Point(70) = {0.014984, 0.0000, -0.015649, msN}; +Point(71) = {0.021530, 0.0000, -0.018707, msN}; +Point(72) = {0.029228, 0.0000, -0.021722, msN}; +Point(73) = {0.038060, 0.0000, -0.024685, msN}; +Point(74) = {0.048005, 0.0000, -0.027586, msN}; +Point(75) = {0.059039, 0.0000, -0.030416, msN}; +Point(76) = {0.071136, 0.0000, -0.033170, msN}; +Point(77) = {0.084265, 0.0000, -0.035843, msN}; +Point(78) = {0.098396, 0.0000, -0.038431, msN}; +Point(79) = {0.113495, 0.0000, -0.040929, msN}; +Point(80) = {0.129524, 0.0000, -0.043326, msN}; +Point(81) = {0.146447, 0.0000, -0.045610, msN}; +Point(82) = {0.164221, 0.0000, -0.047773, msN}; +Point(83) = {0.182803, 0.0000, -0.049805, msN}; +Point(84) = {0.202150, 0.0000, -0.051694, msN}; +Point(85) = {0.222215, 0.0000, -0.053427, msN}; +Point(86) = {0.242949, 0.0000, -0.054994, msN}; +Point(87) = {0.264302, 0.0000, -0.056376, msN}; +Point(88) = {0.286222, 0.0000, -0.057547, msN}; +Point(89) = {0.308658, 0.0000, -0.058459, msN}; +Point(90) = {0.331555, 0.0000, -0.059046, msN}; +Point(91) = {0.354858, 0.0000, -0.059236, msN}; +Point(92) = {0.378510, 0.0000, -0.058974, msN}; +Point(93) = {0.402455, 0.0000, -0.058224, msN}; +Point(94) = {0.426635, 0.0000, -0.056979, msN}; +Point(95) = {0.450991, 0.0000, -0.055257, msN}; +Point(96) = {0.475466, 0.0000, -0.053099, msN}; +Point(97) = {0.500000, 0.0000, -0.050563, msN}; +Point(98) = {0.524534, 0.0000, -0.047719, msN}; +Point(99) = {0.549009, 0.0000, -0.044642, msN}; +Point(100) = {0.573365, 0.0000, -0.041397, msN}; +Point(101) = {0.597545, 0.0000, -0.038043, msN}; +Point(102) = {0.621490, 0.0000, -0.034631, msN}; +Point(103) = {0.645142, 0.0000, -0.031207, msN}; +Point(104) = {0.668445, 0.0000, -0.027814, msN}; +Point(105) = {0.691342, 0.0000, -0.024495, msN}; +Point(106) = {0.713778, 0.0000, -0.021289, msN}; +Point(107) = {0.735698, 0.0000, -0.018232, msN}; +Point(108) = {0.757051, 0.0000, -0.015357, msN}; +Point(109) = {0.777785, 0.0000, -0.012690, msN}; +Point(110) = {0.797850, 0.0000, -0.010244, msN}; +Point(111) = {0.817197, 0.0000, -0.008027, msN}; +Point(112) = {0.835779, 0.0000, -0.006048, msN}; +Point(113) = {0.853553, 0.0000, -0.004314, msN}; +Point(114) = {0.870476, 0.0000, -0.002829, msN}; +Point(115) = {0.886505, 0.0000, -0.001592, msN}; +Point(116) = {0.901604, 0.0000, -0.000600, msN}; +Point(117) = {0.915735, 0.0000, 0.000157, msN}; +Point(118) = {0.928864, 0.0000, 0.000694, msN}; +Point(119) = {0.940961, 0.0000, 0.001033, msN}; +Point(120) = {0.951995, 0.0000, 0.001197, msN}; +Point(121) = {0.961940, 0.0000, 0.001212, msN}; +Point(122) = {0.970772, 0.0000, 0.001112, msN}; +Point(123) = {0.978470, 0.0000, 0.000935, msN}; +Point(124) = {0.985016, 0.0000, 0.000719, msN}; +Point(125) = {0.990393, 0.0000, 0.000497, msN}; +Point(126) = {0.994588, 0.0000, 0.000296, msN}; +Point(127) = {0.997592, 0.0000, 0.000137, msN}; +Point(128) = {0.999398, 0.0000, 0.000035, msN}; + +// Airfoil 2 +Point(301) = {1.000000, spn, 0.000000, msN}; +Point(302) = {0.999398, spn, 0.000128, msN}; +Point(303) = {0.997592, spn, 0.000510, msN}; +Point(304) = {0.994588, spn, 0.001137, msN}; +Point(305) = {0.990393, spn, 0.002001, msN}; +Point(306) = {0.985016, spn, 0.003092, msN}; +Point(307) = {0.978470, spn, 0.004401, msN}; +Point(308) = {0.970772, spn, 0.005915, msN}; +Point(309) = {0.961940, spn, 0.007622, msN}; +Point(310) = {0.951995, spn, 0.009508, msN}; +Point(311) = {0.940961, spn, 0.011562, msN}; +Point(312) = {0.928864, spn, 0.013769, msN}; +Point(313) = {0.915735, spn, 0.016113, msN}; +Point(314) = {0.901604, spn, 0.018580, msN}; +Point(315) = {0.886505, spn, 0.021153, msN}; +Point(316) = {0.870476, spn, 0.023817, msN}; +Point(317) = {0.853553, spn, 0.026554, msN}; +Point(318) = {0.835779, spn, 0.029347, msN}; +Point(319) = {0.817197, spn, 0.032176, msN}; +Point(320) = {0.797850, spn, 0.035017, msN}; +Point(321) = {0.777785, spn, 0.037847, msN}; +Point(322) = {0.757051, spn, 0.040641, msN}; +Point(323) = {0.735698, spn, 0.043377, msN}; +Point(324) = {0.713778, spn, 0.046029, msN}; +Point(325) = {0.691342, spn, 0.048575, msN}; +Point(326) = {0.668445, spn, 0.050993, msN}; +Point(327) = {0.645142, spn, 0.053258, msN}; +Point(328) = {0.621490, spn, 0.055344, msN}; +Point(329) = {0.597545, spn, 0.057218, msN}; +Point(330) = {0.573365, spn, 0.058845, msN}; +Point(331) = {0.549009, spn, 0.060194, msN}; +Point(332) = {0.524534, spn, 0.061254, msN}; +Point(333) = {0.500000, spn, 0.062029, msN}; +Point(334) = {0.475466, spn, 0.062530, msN}; +Point(335) = {0.450991, spn, 0.062774, msN}; +Point(336) = {0.426635, spn, 0.062779, msN}; +Point(337) = {0.402455, spn, 0.062562, msN}; +Point(338) = {0.378510, spn, 0.062133, msN}; +Point(339) = {0.354858, spn, 0.061497, msN}; +Point(340) = {0.331555, spn, 0.060660, msN}; +Point(341) = {0.308658, spn, 0.059629, msN}; +Point(342) = {0.286222, spn, 0.058414, msN}; +Point(343) = {0.264302, spn, 0.057026, msN}; +Point(344) = {0.242949, spn, 0.055470, msN}; +Point(345) = {0.222215, spn, 0.053753, msN}; +Point(346) = {0.202150, spn, 0.051885, msN}; +Point(347) = {0.182803, spn, 0.049874, msN}; +Point(348) = {0.164221, spn, 0.047729, msN}; +Point(349) = {0.146447, spn, 0.045457, msN}; +Point(350) = {0.129524, spn, 0.043071, msN}; +Point(351) = {0.113495, spn, 0.040585, msN}; +Point(352) = {0.098396, spn, 0.038011, msN}; +Point(353) = {0.084265, spn, 0.035360, msN}; +Point(354) = {0.071136, spn, 0.032644, msN}; +Point(355) = {0.059039, spn, 0.029874, msN}; +Point(356) = {0.048005, spn, 0.027062, msN}; +Point(357) = {0.038060, spn, 0.024219, msN}; +Point(358) = {0.029228, spn, 0.021348, msN}; +Point(359) = {0.021530, spn, 0.018441, msN}; +Point(360) = {0.014984, spn, 0.015489, msN}; +Point(361) = {0.009607, spn, 0.012480, msN}; +Point(362) = {0.005412, spn, 0.009416, msN}; +Point(363) = {0.002408, spn, 0.006306, msN}; +Point(364) = {0.000602, spn, 0.003165, msN}; +Point(365) = {0.000000, spn, 0.000000, msN}; +Point(366) = {0.000602, spn, -0.003160, msN}; +Point(367) = {0.002408, spn, -0.006308, msN}; +Point(368) = {0.005412, spn, -0.009443, msN}; +Point(369) = {0.009607, spn, -0.012559, msN}; +Point(370) = {0.014984, spn, -0.015649, msN}; +Point(371) = {0.021530, spn, -0.018707, msN}; +Point(372) = {0.029228, spn, -0.021722, msN}; +Point(373) = {0.038060, spn, -0.024685, msN}; +Point(374) = {0.048005, spn, -0.027586, msN}; +Point(375) = {0.059039, spn, -0.030416, msN}; +Point(376) = {0.071136, spn, -0.033170, msN}; +Point(377) = {0.084265, spn, -0.035843, msN}; +Point(378) = {0.098396, spn, -0.038431, msN}; +Point(379) = {0.113495, spn, -0.040929, msN}; +Point(380) = {0.129524, spn, -0.043326, msN}; +Point(381) = {0.146447, spn, -0.045610, msN}; +Point(382) = {0.164221, spn, -0.047773, msN}; +Point(383) = {0.182803, spn, -0.049805, msN}; +Point(384) = {0.202150, spn, -0.051694, msN}; +Point(385) = {0.222215, spn, -0.053427, msN}; +Point(386) = {0.242949, spn, -0.054994, msN}; +Point(387) = {0.264302, spn, -0.056376, msN}; +Point(388) = {0.286222, spn, -0.057547, msN}; +Point(389) = {0.308658, spn, -0.058459, msN}; +Point(390) = {0.331555, spn, -0.059046, msN}; +Point(391) = {0.354858, spn, -0.059236, msN}; +Point(392) = {0.378510, spn, -0.058974, msN}; +Point(393) = {0.402455, spn, -0.058224, msN}; +Point(394) = {0.426635, spn, -0.056979, msN}; +Point(395) = {0.450991, spn, -0.055257, msN}; +Point(396) = {0.475466, spn, -0.053099, msN}; +Point(397) = {0.500000, spn, -0.050563, msN}; +Point(398) = {0.524534, spn, -0.047719, msN}; +Point(399) = {0.549009, spn, -0.044642, msN}; +Point(400) = {0.573365, spn, -0.041397, msN}; +Point(401) = {0.597545, spn, -0.038043, msN}; +Point(402) = {0.621490, spn, -0.034631, msN}; +Point(403) = {0.645142, spn, -0.031207, msN}; +Point(404) = {0.668445, spn, -0.027814, msN}; +Point(405) = {0.691342, spn, -0.024495, msN}; +Point(406) = {0.713778, spn, -0.021289, msN}; +Point(407) = {0.735698, spn, -0.018232, msN}; +Point(408) = {0.757051, spn, -0.015357, msN}; +Point(409) = {0.777785, spn, -0.012690, msN}; +Point(410) = {0.797850, spn, -0.010244, msN}; +Point(411) = {0.817197, spn, -0.008027, msN}; +Point(412) = {0.835779, spn, -0.006048, msN}; +Point(413) = {0.853553, spn, -0.004314, msN}; +Point(414) = {0.870476, spn, -0.002829, msN}; +Point(415) = {0.886505, spn, -0.001592, msN}; +Point(416) = {0.901604, spn, -0.000600, msN}; +Point(417) = {0.915735, spn, 0.000157, msN}; +Point(418) = {0.928864, spn, 0.000694, msN}; +Point(419) = {0.940961, spn, 0.001033, msN}; +Point(420) = {0.951995, spn, 0.001197, msN}; +Point(421) = {0.961940, spn, 0.001212, msN}; +Point(422) = {0.970772, spn, 0.001112, msN}; +Point(423) = {0.978470, spn, 0.000935, msN}; +Point(424) = {0.985016, spn, 0.000719, msN}; +Point(425) = {0.990393, spn, 0.000497, msN}; +Point(426) = {0.994588, spn, 0.000296, msN}; +Point(427) = {0.997592, spn, 0.000137, msN}; +Point(428) = {0.999398, spn, 0.000035, msN}; + +// Box +Point(10001) = {1+lgt/2, 0, 0, msF}; +Point(10002) = {1+lgt/2, 0, hgt/2, msF}; +Point(10003) = {-lgt/2, 0, hgt/2, msF}; +Point(10004) = {-lgt/2, 0, -hgt/2, msF}; +Point(10005) = {1+lgt/2, 0, -hgt/2, msF}; +Point(10011) = {1+lgt/2, wdt, hgt/2, msF}; +Point(10012) = {-lgt/2, wdt, hgt/2, msF}; +Point(10013) = {-lgt/2, wdt, -hgt/2, msF}; +Point(10014) = {1+lgt/2, wdt, -hgt/2, msF}; + +// Wake +Point(10021) = {1+lgt/2, spn, 0, msF}; + +/// Lines + +// Airfoil 1: +Spline(1) = {1:14}; +Spline(2) = {14:46}; +Spline(3) = {46:65}; +Spline(4) = {65:84}; +Spline(5) = {84:116}; +Spline(6) = {116:128,1}; + +// Airfoil 2: +Spline(7) = {301:314}; +Spline(8) = {314:346}; +Spline(9) = {346:365}; +Spline(10) = {365:384}; +Spline(11) = {384:416}; +Spline(12) = {416:428,301}; + +// Airfoil 1 to airfoil 2: +Line(61) = {1,301}; +Line(62) = {14,314}; +Line(63) = {46,346}; +Line(64) = {65,365}; +Line(65) = {84,384}; +Line(66) = {116,416}; + +// Box +Line(201) = {10001,10002}; +Line(202) = {10002,10003}; +Line(203) = {10003,10004}; +Line(204) = {10004,10005}; +Line(205) = {10005,10001}; +Line(211) = {10011,10012}; +Line(212) = {10012,10013}; +Line(213) = {10013,10014}; +Line(214) = {10014,10011}; +Line(221) = {1, 10001}; +Line(222) = {301, 10021}; +Line(231) = {10002,10011}; +Line(232) = {10003,10012}; +Line(233) = {10004,10013}; +Line(234) = {10005,10014}; + +// Wake +Line(241) = {10001, 10021}; + +/// Line loops & Surfaces + +// Wing 1: +Line Loop(1) = {1,62,-7,-61}; +Line Loop(2) = {2,63,-8,-62}; +Line Loop(3) = {3,64,-9,-63}; +Line Loop(4) = {4,65,-10,-64}; +Line Loop(5) = {5,66,-11,-65}; +Line Loop(6) = {6,61,-12,-66}; +Surface(1) = {-1}; +Surface(2) = {-2}; +Surface(3) = {-3}; +Surface(4) = {-4}; +Surface(5) = {-5}; +Surface(6) = {-6}; + +// Wingtip: +Line Loop(11) = {7:12}; +Plane Surface(11) = {-11}; + +// Symmetry +Line Loop(21) = {201, 202, 203, 204, 205}; +Line Loop(22) = {1, 2, 3, 4, 5, 6}; +Plane Surface(21) = {-21, 22}; + +// Downsteam +Line Loop(31) = {201, 231, -214, -234, 205}; +Plane Surface(31) = {31}; + +// Farfield +Line Loop(41) = {233, -212, -232, 203}; +Plane Surface(41) = {41}; +Line Loop(42) = {204, 234, -213, -233}; +Plane Surface(42) = {42}; +Line Loop(43) = {202, 232, -211, -231}; +Plane Surface(43) = {43}; +Line Loop(44) = {213, 214, 211, 212}; +Plane Surface(44) = {44}; + +// Wake +Line Loop(51) = {221, 241, -222, -61}; +Surface(51) = {51}; + +/// Volume +Surface Loop(1) = {1,2,3,4,5,6,11,21,31,41,42,43,44}; +Volume(1) = {1}; + +/// Embbeded +Line{221} In Surface{21}; +Line{241} In Surface{31}; +Surface{51} In Volume{1}; + +//// MESHING ALGORITHM + +/// 2D: + +///Wing, farfield and symmetry plane: +MeshAlgorithm Surface{1,2,3,4,5,6,11,21,31,41,42,43,44,51} = 5; + +/// 3D: + +Mesh.Algorithm3D = 2; +//Mesh.OptimizeNetgen = 1; +Mesh.Optimize = 1; +Mesh.Smoothing = 10; +Mesh.SmoothNormals = 1; + + + +//// PHYSICAL GROUPS + +// Trailing edge and wake tip +Physical Line("wakeTip") = {222}; +Physical Line("te") = {61}; + +// Internal Field: +Physical Volume("field") = {1}; + +// Wing: +Physical Surface("wing") = {1,2,3,11}; +Physical Surface("wing_") = {4,5,6}; + +// Symmetry: +Physical Surface("symmetry") = {21}; + +// Downstream: +Physical Surface("downstream") = {31}; + +// Farfield: +Physical Surface("upstream") = {41}; +Physical Surface("farfield") = {42,43,44}; + +// Wake: +Physical Surface("wake") = {51}; diff --git a/dart/models/wbht.geo b/dart/models/wbht.geo index 0e79a8e9f93db547430c2e713af28971313e8708..9f252d80dc453d9c0f44d661fd8b2facf94c3dd5 100644 --- a/dart/models/wbht.geo +++ b/dart/models/wbht.geo @@ -950,9 +950,9 @@ Line(3026) = {3049, 3149}; /// Wake // Wing -Point(4001) = {25, 0, -2.26}; -Point(4002) = {25, 6.1, -0.66}; -Point(4003) = {25, 7, -0.41}; +Point(4001) = {25, 0, -0.534}; +Point(4002) = {25, 6.1, 0.01642}; +Point(4003) = {25, 7, 0.2577}; Line(4001) = {2001, 4001}; Line(4002) = {2301, 4002}; @@ -1213,10 +1213,12 @@ Mesh.SmoothNormals = 1; /* Physical */ // Tips: -Physical Line("teTipW") = {4092,4091,4094,2041,4003}; +Physical Line("teW") = {4094,2041}; Physical Line("wakeTipW") = {4003}; -Physical Line("teTipT") = {4103,4102,4101,4100,4105,4106}; +Physical Line("wakeExW") = {4092, 4091, 4003}; +Physical Line("teT") = {4105}; Physical Line("wakeTipT") = {4106}; +Physical Line("wakeExT") = {4102,4101,4100, 4103, 4106}; // Symmetry: Physical Surface("symmetry") = {1}; diff --git a/dart/models/wht.geo b/dart/models/wht.geo index 53a64ea4da10f4f750a2dcfc12cdd35e66ceee8a..4fb94de3675ce307bef1b05c6334ba0bce12b3b5 100644 --- a/dart/models/wht.geo +++ b/dart/models/wht.geo @@ -30,7 +30,7 @@ zOfst = 0.56; // Domain Point(1) = {-10, 0, -10}; Point(2) = {17, 0, -10}; -Point(4001) = {17, 0, -1.39}; +Point(4001) = {17, 0, -0.03763}; Point(4011) = {17, 0, 1.06}; Point(3) = {17, 0, 10}; Point(4) = {-10, 0, 10}; @@ -833,8 +833,8 @@ Line(3026) = {3049, 3149}; /// Wake // Wing -Point(4002) = {17, 6.1, 0.09}; -Point(4003) = {17, 7, 0.29}; +Point(4002) = {17, 6.1, 0.5764}; +Point(4003) = {17, 7, 0.8177}; Line(4001) = {2001, 4001}; Line(4002) = {2301, 4002}; @@ -988,9 +988,9 @@ Mesh.SmoothNormals = 1; /* Physical */ // Tips: -Physical Line("teTipW") = {2031, 2041, 4003}; +Physical Line("teW") = {2031, 2041}; Physical Line("wakeTipW") = {4003}; -Physical Line("teTipT") = {3021, 4012}; +Physical Line("teT") = {3021}; Physical Line("wakeTipT") = {4012}; // Symmetry: diff --git a/dart/pyVII/vCoupler.py b/dart/pyVII/vCoupler.py index 8876da98e6c69e93d94be93a506df41a93652c8c..fb95ffc4afc2e7b39656d89d9ea8852acd35e597 100644 --- a/dart/pyVII/vCoupler.py +++ b/dart/pyVII/vCoupler.py @@ -36,6 +36,9 @@ class Coupler: self.iSolver=iSolver self.vSolver=vSolver + self.vSolver.verbose = self.iSolver.verbose + #self.vSolver.verbose = 0 + self.maxCouplIter = 150 self.couplTol = 1e-4 @@ -55,8 +58,8 @@ class Coupler: # Initilize meshes in c++ objects - self.iSolver.printOn = False - self.vSolver.printOn = False + #self.iSolver.printOn = False + #self.vSolver.printOn = False dragIter = np.zeros((0,2)) @@ -87,6 +90,9 @@ class Coupler: self.tms['viscous'].stop() # print('Viscous ops terminated with exit code ', exitCode) + #plt.xlim([0, 2]) + #plt.show() + self.tms['processing'].start() self.__ImposeBlwVel(couplIter) self.tms['processing'].stop() @@ -107,11 +113,18 @@ class Coupler: xtr = [1, 1] xtr[0]=self.vSolver.Getxtr(0,0) xtr[1]=self.vSolver.Getxtr(0,1) - print(' {:>4.0f}| {:>10.10f} {:>10.10f} | {:>10.4f} {:>8.4f} {:>8.3f}'.format(couplIter, + print(' {:>4.0f}| {:>10.4f} {:>10.4f} | {:>10.4f} {:>8.4f} {:>8.3f}'.format(couplIter, self.iSolver.Cl, self.vSolver.Cdt, xtr[0], xtr[1], np.log10(error))) couplIter += 1 self.tms['processing'].stop() + + self.sln = np.asarray(self.vSolver.GetSolution(0)) + """if couplIter==1: + + #plt.plot(sln[16], sln[1], 'x-') + #plt.plot(self.fMeshDict['globCoord'][:self.fMeshDict['bNodes'][1]], self.fMeshDict['vx'][:self.fMeshDict['bNodes'][1]], 'x-') + return dragIter""" else: print(ccolors.ANSI_RED, 'Maximum number of {:<.0f} coupling iterations reached'.format(self.maxCouplIter), ccolors.ANSI_RESET) return dragIter @@ -182,8 +195,8 @@ class Coupler: dataIn=[None,None] for n in range(0,len(self.group)): self.group[n].connectListNodes, self.group[n].connectListElems, dataIn[n] = self.group[n].connectList(couplIter) - fMeshDict, _, _ = GroupConstructor().mergeVectors(dataIn, 0, 1) - + self.fMeshDict, _, _ = GroupConstructor().mergeVectors(dataIn, 0, 1) + fMeshDict = self.fMeshDict.copy() if ((len(fMeshDict['locCoord'][:fMeshDict['bNodes'][1]]) != self.nElmUpperPrev) or couplIter==0): print('STAG POINT MOVED') diff --git a/dart/pyVII/vCoupler2.py b/dart/pyVII/vCoupler2.py index 6292c256f5cbc200e0730e9678032a55bfe53c5d..fe8baee16b8302c0fb8d3f49062a2eddc0e37541 100644 --- a/dart/pyVII/vCoupler2.py +++ b/dart/pyVII/vCoupler2.py @@ -19,20 +19,18 @@ ## VII Coupler # Paul Dechamps -from dart.viscous.Drivers.DGroupConstructor import GroupConstructor - +import fwk from fwk.coloring import ccolors -import math -import fwk -import dart.pyVII.vUtils as viscU +from math import pi as M_PI import numpy as np -from matplotlib import pyplot as plt class Coupler: def __init__(self, _iSolverAPI, vSolver) -> None: self.iSolverAPI = _iSolverAPI self.vSolver = vSolver + + self.vSolver.verbose = self.iSolverAPI.iSolver.verbose self.maxCouplIter = 150 self.couplTol = 1e-4 @@ -52,7 +50,7 @@ class Coupler: couplIter = 0 cdPrev = 0 print('- AoA: {:<2.2f} Mach: {:<1.1f} Re: {:<2.1f}e6' - .format(self.iSolverAPI.GetAlpha()*180/math.pi, self.iSolverAPI.GetMinf(), self.vSolver.GetRe()/1e6)) + .format(self.iSolverAPI.GetAlpha()*180/M_PI, self.iSolverAPI.GetMinf(), self.vSolver.GetRe()/1e6)) print('{:>5s}| {:>10s} {:>10s} | {:>8s} {:>6s} {:>8s}'.format('It', 'Cl', 'Cd', 'xtrT', 'xtrB', 'Error')) print(' --------------------------------------------------------') while couplIter < self.maxCouplIter: @@ -118,7 +116,7 @@ class Coupler: coeffTable[0,:] = alphaSeq for ind, alpha in enumerate(alphaSeq): - self.iSolver.pbl.update(alpha*math.pi/180) + self.iSolver.pbl.update(alpha*M_PI/180) self.Run() diff --git a/dart/pyVII/vInterpolator.py b/dart/pyVII/vInterpolator.py index 22a289f474638e401a66712ca6ac8c4bed803be7..f4b39489883fdcb2787c2968df1b51eaa0e3f76a 100644 --- a/dart/pyVII/vInterpolator.py +++ b/dart/pyVII/vInterpolator.py @@ -2,21 +2,12 @@ import numpy as np from matplotlib import pyplot as plt from fwk.coloring import ccolors +import dart.pyVII.vUtils as blxU + # 3D spline with Bézier curves from scipy.interpolate import bisplrep from scipy.interpolate import bisplev -# 2D spline with Bézier curves -from scipy.interpolate import splprep -from scipy.interpolate import splev -from scipy.integrate import cumtrapz - -from scipy.interpolate import NearestNDInterpolator -from scipy.interpolate import griddata -from scipy.interpolate import CloughTocher2DInterpolator - -from dart.pyVII import vRbf as RbfInterpol - from scipy.interpolate import interp1d from scipy.interpolate import RBFInterpolator @@ -31,13 +22,14 @@ class Interpolator: self.bndWing = bnd_wing self.bndWake = bnd_wake - self.invStruct, self.viscStruct = self.__GetWing(bnd_wing, bnd_wake, _cfg) + self.nodesList, self.transformedCoord, self.wakeCoord, self.viscStruct, self.viscStruct_tr = self.__GetWing(bnd_wing, bnd_wake, _cfg) print('Sections created') self.config = _cfg - self.xxPrev = [[np.zeros(0) for iReg in range(3)] for iSec in range(len(self.viscStruct))] - self.uePrev = [[np.zeros(len(self.viscStruct[iSec][iReg][:,0])) for iReg in range(2)] for iSec in range(len(self.viscStruct))] - self.DeltaStarPrev = [[np.zeros(len(self.viscStruct[iSec][iReg][:,0])) for iReg in range(2)] for iSec in range(len(self.viscStruct))] + self.xxPrev = [[np.zeros(0) for iReg in range(3)] for iSec in range(1)] + #self.uePrev = [[np.zeros(len(self.viscStruct[iSec][iReg][:,0])) for iReg in range(3)] for iSec in range(len(self.viscStruct))] + self.DeltaStarPrev = [[np.zeros(0 + ) for iReg in range(3)] for iSec in range(1)] self.tms = fwk.Timers() def GetInvBC(self, vSolver, couplIter): @@ -49,9 +41,9 @@ class Interpolator: # Wing - nElm = len(self.bndWing.nodes) + nElm = len(self.nodesList) U_wg, M_wg, Rho_wg = np.zeros((nElm, 3)), np.zeros(nElm), np.zeros(nElm) - for iNode, n in enumerate(self.bndWing.nodes): + 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] @@ -64,6 +56,7 @@ class Interpolator: U_wk =np.zeros((nElm, 3)) M_wk = np.zeros(nElm) Rho_wk = np.zeros(nElm) + 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] @@ -73,66 +66,73 @@ class Interpolator: 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]] + U_wk[:, [1,2]] = U_wk[:,[2,1]] - Ux = self.__RbfToSections(U_wg[:,0], U_wk[:,0]) - Uy = self.__RbfToSections(U_wg[:,1], U_wk[:,1]) - Uz = self.__RbfToSections(U_wg[:,2], U_wk[:,2]) + 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], 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], 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], 1)] - Me = self.__RbfToSections(M_wg, M_wk) - Rho = self.__RbfToSections(Rho_wg, Rho_wk) + 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], 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], 1)] # Find stagnation point for iSec in range(len(self.viscStruct)): - #if couplIter == 0: - self.stgPt = np.argmin(Ux[iSec][0]**2+Uy[iSec][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) - - vSolver.SetGlobMesh(iSec, 0, xUp, yUp, zUp) - vSolver.SetGlobMesh(iSec, 1, xLw, yLw, zLw) - vSolver.SetGlobMesh(iSec, 2, self.viscStruct[iSec][1][:,0], - self.viscStruct[iSec][1][:,1], - self.viscStruct[iSec][1][:,2]) + if couplIter == 0: + self.stgPt = np.argmin(Ux[0]**2+Uy[0]**2) - UxUp, UxLw = self.__Remesh(Ux[iSec][0], self.stgPt) - UyUp, UyLw = self.__Remesh(Uy[iSec][0], self.stgPt) - UzUp, UzLw = self.__Remesh(Uz[iSec][0], self.stgPt) - + 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) + + vSolver.SetGlobMesh(iSec, 0, xUp, yUp, zUp) + vSolver.SetGlobMesh(iSec, 1, xLw, yLw, zLw) + vSolver.SetGlobMesh(iSec, 2, self.viscStruct[iSec][1][:,0], + 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.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) vSolver.SetVelocities(iSec, 0, UxUp, UyUp, UzUp) vSolver.SetVelocities(iSec, 1, UxLw, UyLw, UzLw) - vSolver.SetVelocities(iSec, 2, Ux[iSec][1], Uy[iSec][1], Uz[iSec][1]) + vSolver.SetVelocities(iSec, 2, Ux[1], Uy[1], Uz[1]) - MeUp, MeLw = self.__Remesh(Me[iSec][0], self.stgPt) + MeUp, MeLw = self.__Remesh(Me[0], self.stgPt) vSolver.SetMe(iSec, 0, MeUp) vSolver.SetMe(iSec, 1, MeLw) - vSolver.SetMe(iSec, 2, Me[iSec][1]) + vSolver.SetMe(iSec, 2, Me[1]) - RhoUp, RhoLw = self.__Remesh(Rho[iSec][0], self.stgPt) + RhoUp, RhoLw = self.__Remesh(Rho[0], self.stgPt) vSolver.SetRhoe(iSec, 0, RhoUp) vSolver.SetRhoe(iSec, 1, RhoLw) - vSolver.SetRhoe(iSec, 2, Rho[iSec][1]) + vSolver.SetRhoe(iSec, 2, Rho[1]) - DeltaStarPrevUp, DeltaStarPrevLw = self.__Remesh(self.DeltaStarPrev[iSec][0], self.stgPt) - vSolver.SetDeltaStarExt(iSec, 0, DeltaStarPrevUp) - vSolver.SetDeltaStarExt(iSec, 1, DeltaStarPrevLw) - vSolver.SetDeltaStarExt(iSec, 2, self.DeltaStarPrev[iSec][1]) + #DeltaStarPrevUp, DeltaStarPrevLw = self.__Remesh(self.DeltaStarPrev[iSec][0], self.stgPt) + vSolver.SetDeltaStarExt(iSec, 0, self.DeltaStarPrev[0][0]) + vSolver.SetDeltaStarExt(iSec, 1, self.DeltaStarPrev[0][1]) + vSolver.SetDeltaStarExt(iSec, 2, self.DeltaStarPrev[0][2]) - xxPrevUp, xxPrevLw = self.__Remesh(self.xxPrev[iSec][0], self.stgPt) - vSolver.SetxxExt(iSec, 0, xxPrevUp) - vSolver.SetxxExt(iSec, 1, xxPrevLw) - vSolver.SetxxExt(iSec, 2, self.xxPrev[iSec][1]) + #xxPrevUp, xxPrevLw = self.__Remesh(self.xxPrev[iSec][0], self.stgPt) + vSolver.SetxxExt(iSec, 0, self.xxPrev[0][0]) + vSolver.SetxxExt(iSec, 1, self.xxPrev[0][1]) + vSolver.SetxxExt(iSec, 2, self.xxPrev[0][2]) - uePrevUp, uePrevLw = self.__Remesh(self.uePrev[iSec][0], self.stgPt) + """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]) + vSolver.SetUeOld(iSec, 2, self.uePrev[iSec][1])""" @@ -141,17 +141,20 @@ class Interpolator: 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] - self.DeltaStarPrev[iSec][0] = np.concatenate((np.asarray(vSolver.ExtractDeltaStar(iSec, 0))[::-1], np.asarray(vSolver.ExtractDeltaStar(iSec, 1))[1:]), axis=None) + """self.DeltaStarPrev[iSec][0] = np.concatenate((np.asarray(vSolver.ExtractDeltaStar(iSec, 0))[::-1], np.asarray(vSolver.ExtractDeltaStar(iSec, 1))[1:]), axis=None) self.DeltaStarPrev[iSec][1] = np.asarray(vSolver.ExtractDeltaStar(iSec, 2)) self.xxPrev[iSec][0] = np.concatenate((np.asarray(vSolver.Extractxx(iSec, 0))[::-1], np.asarray(vSolver.Extractxx(iSec, 1))[1:]), axis=None) self.xxPrev[iSec][1] = np.asarray(vSolver.Extractxx(iSec, 2)) self.uePrev[iSec][0] = np.concatenate((np.asarray(vSolver.ExtractUe(iSec, 0))[::-1], np.asarray(vSolver.ExtractUe(iSec, 1))[1:]), axis=None) - self.uePrev[iSec][1] = np.asarray(vSolver.ExtractUe(iSec, 2)) + self.uePrev[iSec][1] = np.asarray(vSolver.ExtractUe(iSec, 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)) @@ -160,6 +163,7 @@ class Interpolator: 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): @@ -175,6 +179,11 @@ class Interpolator: invCgWing[iElm, 1] +=n.pos[1] invCgWing[iElm, 2] +=n.pos[2] invCgWing[iElm, :] /= e.nodes.size() + + invCgWing[invCgWing[:,1]<meany, 0] *= -1 + + # Wake + invCgWake = np.zeros((len(self.bndWake.tag.elems), 3)) for iElm, e in enumerate(self.bndWake.tag.elems): for n in e.nodes: @@ -188,35 +197,21 @@ class Interpolator: invCgWake[:,[1,2]] = invCgWake[:,[2,1]] self.tms['Interpolation'].start() - invCgUp = invCgWing[invCgWing[:,1]>0, :] - invCgLw = invCgWing[invCgWing[:,1]<0, :] - #mappedBlwWing = np.zeros(len(invCgWing)) - mappedBlwWing = RBFInterpolator(viscCgWing[:,:2], BlwWing, neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=self.config['smoothing'], degree=self.config['degree'])(invCgWing[:,:2]) - #mappedBlwWing[:self.config['nPoints'][0]] = RBFInterpolator(viscCgWing[:self.config['nPoints'][0],:], BlwWing[:self.config['nPoints'][0]], neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=1e-6, degree=self.config['degree'])(invCgWingUp) - #mappedBlwWing[self.config['nPoints'][0]:] = RBFInterpolator(viscCgWing[self.config['nPoints'][0]:, :], BlwWing[self.config['nPoints'][0]:], neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=1e-6, degree=self.config['degree'])(invCgWingLw) - # Following lines (interp1d) will not work. - #mappedBlwWing[:self.config['nPoints'][0]] = interp1d(viscCgWing[:self.config['nPoints'][0],0], BlwWing[:self.config['nPoints'][0]])(invCgUp[:, 0]) - #mappedBlwWing[self.config['nPoints'][0]:] = interp1d(viscCgWing[self.config['nPoints'][0]:, 0], BlwWing[self.config['nPoints'][0]:])(invCgLw[:, 0]) - #mappedBlwWake = RBFInterpolator(viscCgWake, BlwWake, neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=self.config['smoothing'], degree=self.config['degree'])(invCgWake) - mappedBlwWake = RBFInterpolator(viscCgWake[:, :2], BlwWake, neighbors=1, kernel='linear', smoothing=1e-6, degree=0)(invCgWake[:, :2]) - - """plt.plot(invCgWing[:,0], invCgWing[:,1]) - plt.show()""" - """plt.plot(invCgWing[:, 0], mappedBlwWing, 'o') - plt.plot(viscCgWing[:,0], BlwWing, 'x') - #plt.xlim([0.8, 1.2]) - plt.show()""" - - """interpWing = NearestNDInterpolator(list(zip(viscCgWing[:,0], viscCgWing[:,1], viscCgWing[:,2])), BlwWing) - mappedBlwWing = interpWing(invCgWing[:,0], invCgWing[:,1], invCgWing[:,2]) - interpWake = NearestNDInterpolator(list(zip(viscCgWake[:,0], viscCgWake[:,1], viscCgWake[:,2])), BlwWake) - mappedBlwWake = interpWake(invCgWake[:,0], invCgWake[:,1], invCgWake[:,2])""" + + mappedBlw = [self.__RbfToSections(viscCgWing[:, :2], BlwWing, invCgWing[:,:2]), self.__RbfToSections(viscCgWake[:, :1], BlwWake, invCgWake[:, :1])] + + #mappedBlwWing = RBFInterpolator(viscCgWing[:,:2], BlwWing, neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=self.config['smoothing'], degree=self.config['degree'])(invCgWing[:,:2]) + #mappedBlwWake = RBFInterpolator(viscCgWake[:, :2], BlwWake, neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=self.config['smoothing'], degree=self.config['degree'])(invCgWake[:, :2]) + + sln = blxU.GetSolution(0, vSolver) self.tms['Interpolation'].stop() for iElm in range(len(self.bndWing.tag.elems)): - self.bndWing.setU(iElm, mappedBlwWing[iElm]) + self.bndWing.setU(iElm, mappedBlw[0][iElm]) for iElm in range(len(self.bndWake.tag.elems)): - self.bndWake.setU(iElm, mappedBlwWake[iElm]) + self.bndWake.setU(iElm, mappedBlw[1][iElm]) + + def RunSolver(self): @@ -250,127 +245,167 @@ class Interpolator: xLw = vec[idx_stag:] return xUp, xLw - def __RbfToSections(self, var, varWk): - varWk = np.reshape(varWk, [len(varWk), 1]) - completeWake = np.hstack((self.invStruct[1], varWk)) - _, idx = np.unique(completeWake[:,:3], axis=0, return_index=True) + def __RbfToSections(self, x, var, xs, wake=0): - saveWake = np.where(completeWake[:,0]==1) - saveWake = saveWake[0] - completeWake = completeWake[np.sort(idx)] + if wake==0: + return RBFInterpolator(x, var, neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=self.config['smoothing'], degree=self.config['degree'])(xs) + else: + return RBFInterpolator(x, var, neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=self.config['smoothing'], degree=self.config['degree'])(xs) - var = np.reshape(var, [len(var), 1]) - completeWing = np.hstack((self.invStruct[0], var)) + def __GetWing(self, bnd_wing, bnd_wake, config): - delIdx = np.where(completeWing[:,0]==1.0) - delIdx = delIdx[0] - save = completeWing[delIdx, 3] + if config['nDim'] == 2 and config['nSections'] != 1: + raise RuntimeError('Cannot create more than 1 section on 2D geometry. Specified:', config['nSections']) - completeWing[delIdx[0], 3] = (completeWing[delIdx[0], 3] + completeWing[delIdx[1], 3]) / 2 - completeWing = np.delete(completeWing, delIdx[1], axis = 0) + 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(2)] for _ in range(config['nSections'])] - mappedVar = [[np.zeros(0) for _ in range(3)] for _ in range(len(self.viscStruct))] + # 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]])) - for iSec in range(len(mappedVar)): - for iReg in range(len(mappedVar[iSec])): - if iReg==0: # Wing + if config['nDim'] == 2: + spanDistri = np.zeros(1) + spanDistri[0] = nodesCoord[0,2] # Span direction is the z direction + + 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 - mappedVar[iSec][iReg] = RBFInterpolator(completeWing[:,:2], completeWing[:,3], neighbors=self.config['neighbors'], kernel=self.config['rbftype'], smoothing=self.config['smoothing'], degree=self.config['degree'])(self.viscStruct[iSec][0][:,:2]) + else: + raise RuntimeError("Number of dimensions not recognized", config['nDim']) - if iReg==1: # Wake - - mappedVar[iSec][iReg] = RBFInterpolator(completeWake[:,:3], completeWake[:,3], neighbors=1, kernel='linear', smoothing=1e-6, degree=0)(self.viscStruct[iSec][1]) + wingSpan = max(nodesCoord[:,2]) - min(nodesCoord[:,2]) - #mappedVar[iSec][0][0] = save[0] - #mappedVar[iSec][0][-1] = save[-1] - #mappedVar[iSec][1][0] = saveWake[0] - """fig = plt.figure() - ax = fig.add_subplot(projection='3d') - ax.scatter(completeWing[:,0], completeWing[:,1], completeWing[:,2], completeWing[:,3], s=0.2) - ax.set_ylim([-0.5, 0.5]) - ax.set_xlabel('x') - ax.set_ylabel('y') - ax.set_zlabel('z') - plt.show()""" - #plt.plot(completeWing[:,0], completeWing[:,3], 'x') - #plt.plot(completeWake[:,0], completeWake[:,3], 'x') - """plt.plot(self.viscStruct[0][0][:,0], mappedVar[0][0]) - plt.plot(self.viscStruct[0][1][:,0], mappedVar[0][1]) - plt.show()""" - return mappedVar + 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] - def __GetWing(self, bnd_wing, bnd_wake, config): + # Find te elements + te_elems = [] + for e in bnd_wing.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 config['nDim'] == 2 and config['nSections'] != 1: - raise RuntimeError('Cannot create more than 1 section on 2D geometry. Specified:', config['nSections']) + 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 - viscStruct = [[np.zeros((config['nPoints'][1] if i==1 else 2*config['nPoints'][0], 3)) for i in range(2)] for _ in range(config['nSections'])] + viscStruct[iSec][0][:,0] = np.concatenate((xDistri[:-1], xDistri[::-1]), axis=None) + viscStruct[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0])) - invStruct = [np.zeros((len(bnd_wake.nodes) if iReg==1 else len(bnd_wing.nodes), 3)) for iReg in range(2)] + 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])) - for iNode, n in enumerate(bnd_wing.nodes): - invStruct[0][iNode, 0] = n.pos[0] - invStruct[0][iNode, 1] = n.pos[1] - invStruct[0][iNode, 2] = n.pos[2] - for iNode, n in enumerate(bnd_wake.nodes): - invStruct[1][iNode, 0] = n.pos[0] - invStruct[1][iNode, 1] = n.pos[2] - invStruct[1][iNode, 2] = n.pos[1] - - """xy = invStruct[0][abs(invStruct[0][:,1]-0.5) <= 5e-2, :] - fig = plt.figure() - ax = fig.add_subplot(projection='3d') - ax.scatter(xy[:,0], xy[:,1], xy[:,2], s=0.2) - ax.set_ylim([-0.5, 0.5]) - ax.set_xlabel('x') - ax.set_ylabel('y') - ax.set_zlabel('z') - plt.show() - - plt.plot(xy[:,0], xy[:,2], 'x') - plt.show()""" + # Interpolation in the transformed space. + 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'] == 2: - spanDistri = np.zeros(1) - spanDistri[0] = invStruct[0][0,2] # Span direction is the z direction + # 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]) - elif config['nDim'] == 3: - invStruct[0][:,[1,2]] = invStruct[0][:,[2,1]] # Inverse y and z so that spanwise direction is in z - invStruct[1][:,[1,2]] = invStruct[1][:,[2,1]] # Inverse y and z so that spanwise direction is in z - spanDistri = np.linspace(min(invStruct[0][:,2]), max(invStruct[0][:,2]), config['nSections']) - spanDistri[0] +=0.1 - spanDistri[-1] -=0.1 + - for iSec, z in enumerate(spanDistri): + return nodesList, transformedCoord, wakeCoord, viscStruct, viscStruct_tr + + """for iSec, z in enumerate(spanDistri): # Create x distribution at the corresponding span position - minX = min(invStruct[0][abs(invStruct[0][:,2]-z)<=config['eps'], 0]) - chordLength = max(invStruct[0][abs(invStruct[0][:,2]-z)<=config['eps'], 0]) - minX + minX = min(upperCoord[abs(upperCoord[:,2]-z)<=config['eps'], 0]) + chordLength = max(upperWing[abs(upperWing[:,2]-z)<=config['eps'], 0]) - minX xDistri = minX + 1/2*(1 + np.cos(np.linspace(0, np.pi, config['nPoints'][0])))*chordLength nElmSide = len(xDistri) viscStruct[iSec][0][:,0] = np.concatenate((xDistri, xDistri[::-1]), axis=None) viscStruct[iSec][0][:,2] = z*np.ones(len(viscStruct[iSec][0][:,0])) - wakeLength = np.max(invStruct[1][:,0]) - np.max(viscStruct[iSec][0][:,0]) + 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])) if config['nDim'] == 2: - upper, lower = self.__SeparateArf(invStruct[0][:,0], invStruct[0][:,1]) + transformedViscCoord = np.zeros((np.shape(viscStruct[iSec][0]))) + transformedCoord + transformedViscCoord[:, 1] = interp1d(transformedCoord[:,0], transformedCoord[:,1])(transformedCoord[:,0]) viscStruct[iSec][0][:nElmSide,1] = interp1d(upper[:,0], upper[:,1])(viscStruct[iSec][0][:nElmSide,0]) viscStruct[iSec][0][nElmSide:,1] = interp1d(lower[:,0], lower[:,1])(viscStruct[iSec][0][nElmSide:,0]) viscStruct[iSec][0] = np.delete(viscStruct[iSec][0], nElmSide, axis=0) viscStruct[iSec][1][:,1] = interp1d(invStruct[1][:,0], invStruct[1][:,1])(viscStruct[iSec][1][:,0]) - """plt.plot(viscStruct[iSec][0][:,0], viscStruct[iSec][0][:,1], '-') + plt.plot(viscStruct[iSec][0][:,0], viscStruct[iSec][0][:,1], '-') plt.plot(viscStruct[iSec][0][:nElmSide,0], viscStruct[iSec][0][:nElmSide,1], 'x') plt.plot(viscStruct[iSec][0][nElmSide:,0], viscStruct[iSec][0][nElmSide:,1], 'o') plt.plot(viscStruct[iSec][1][:,0], np.zeros(len(viscStruct[iSec][1][:,0])), 'x-') plt.xlim([-0.5,2]) plt.ylim([-0.5, 0.5]) - plt.show()""" + plt.show() elif config['nDim'] == 3: nPointsMin = (config['k'][0]+1) * (config['k'][1]+1) # See Scipy bisplrep doc @@ -400,7 +435,7 @@ class Interpolator: for iPoint in range(nElmSide, len(viscStruct[iSec][0][:,0])): viscStruct[iSec][0][iPoint,1] = bisplev(viscStruct[iSec][0][iPoint,0], viscStruct[iSec][0][iPoint,2], tckWingUp) - """invStruct[1] = invStruct[1][invStruct[1][:, 0].argsort()] + invStruct[1] = invStruct[1][invStruct[1][:, 0].argsort()] fig = plt.figure() ax = fig.add_subplot(projection='3d') ax.scatter(invStruct[1][:,0], invStruct[1][:,1], invStruct[1][:,2], s=0.2) @@ -408,10 +443,10 @@ class Interpolator: ax.set_xlabel('x') ax.set_ylabel('y') ax.set_zlabel('z') - plt.show()""" + plt.show() # Wake - """sWake = (len(invStruct[1][:,0])-np.sqrt(2*len(invStruct[1][:,0])) + len(invStruct[1][:,0])+np.sqrt(2*len(invStruct[1][:,0])))/2 - tckWake = bisplrep(invStruct[1][:,0], invStruct[1][:,2], invStruct[1][:,1], kx=config['k'][0], ky=config['k'][1], s=sWake)""" + sWake = (len(invStruct[1][:,0])-np.sqrt(2*len(invStruct[1][:,0])) + len(invStruct[1][:,0])+np.sqrt(2*len(invStruct[1][:,0])))/2 + tckWake = bisplrep(invStruct[1][:,0], invStruct[1][:,2], invStruct[1][:,1], kx=config['k'][0], ky=config['k'][1], s=sWake) for iPoint in range(len(viscStruct[iSec][1][:,0])): #viscStruct[iSec][1][iPoint,1] = bisplev(viscStruct[iSec][1][iPoint,0], viscStruct[iSec][1][iPoint,2], tckWake) viscStruct[iSec][1][iPoint,1] = 0 @@ -427,7 +462,7 @@ class Interpolator: ax.set_ylabel('y') ax.set_zlabel('z') plt.show() - return invStruct, viscStruct + return invStruct, viscStruct""" def __SeparateArf(self, xInp, yInp, zInp=None): if zInp is None: diff --git a/dart/pyVII/vUtils.py b/dart/pyVII/vUtils.py index af3336d01337783f35a432c095b454cc338475b4..32410ed2bba5f7da2902faa08263e32c1f51afb9 100644 --- a/dart/pyVII/vUtils.py +++ b/dart/pyVII/vUtils.py @@ -5,6 +5,36 @@ def initBL(Re, Minf, CFL0, nSections): return solver +def GetSolution(iSec, vSolver): + if iSec<0: + raise RuntimeError("dart::viscU Invalid section number", iSec) + + brutSln = vSolver.GetSolution(iSec) + + sln = {'theta' : brutSln[0], + 'H' : brutSln[1], + 'N' : brutSln[2], + 'ue' : brutSln[3], + 'Ct' : brutSln[4], + 'deltaStar': brutSln[5], + 'Ret' : brutSln[6], + 'Cd' : brutSln[7], + 'Cf' : brutSln[8], + 'Hstar' : brutSln[9], + 'Hstar2' : brutSln[10], + 'Hk' : brutSln[11], + 'Cteq' : brutSln[12], + 'Us' : brutSln[13], + 'delta' : brutSln[14], + 'x/c' : brutSln[15], + 'xtrT' : vSolver.Getxtr(iSec, 0), + 'xtrB' : vSolver.Getxtr(iSec, 1), + 'Cdt' : vSolver.Cdt, + 'Cdf' : vSolver.Cdf, + 'Cdp' : vSolver.Cdp} + return sln + + def Dictionary(blScalars, blVectors, xtr): """Create dictionary with the coordinates and the boundary layer parameters """ diff --git a/dart/src/dart.h b/dart/src/dart.h index 91c6427dec6eb5197e9ad39e54d651666c3c9fc0..f242f898daa4f09861f38f5b6d778a6d3b4ec5a2 100644 --- a/dart/src/dart.h +++ b/dart/src/dart.h @@ -79,12 +79,16 @@ class InvBnd; class F0Ps; class F0El; class F0ElC; +class F0ElRhoBase; class F0ElRho; -class F0ElRhoL; +class F0ElRhoClamp; +class F0ElRhoLin; class F0ElMach; -class F0ElMachL; +class F0ElMachClamp; +class F0ElMachLin; class F0ElCp; -class F0ElCpL; +class F0ElCpClamp; +class F0ElCpLin; class F1El; class F1ElVi; class F1Ct; diff --git a/dart/src/wAdjoint.cpp b/dart/src/wAdjoint.cpp index c3a534016cec1e2b928bed802151dd13a617f5a5..40b3b60b40afb7c74b3dbbc366e29bf1535737da 100644 --- a/dart/src/wAdjoint.cpp +++ b/dart/src/wAdjoint.cpp @@ -32,6 +32,7 @@ #include "wNode.h" #include "wElement.h" #include "wLinearSolver.h" +#include "wGmres.h" #include "wMshDeform.h" #include "wResults.h" #include "wMshExport.h" @@ -51,12 +52,24 @@ using namespace dart; /** * @brief Initialize the adjoint solver */ -Adjoint::Adjoint(std::shared_ptr<Newton> _sol, std::shared_ptr<tbox::MshDeform> _morph, std::shared_ptr<tbox::LinearSolver> _linsol) : sol(_sol), morph(_morph), linsol(_linsol) +Adjoint::Adjoint(std::shared_ptr<Newton> _sol, std::shared_ptr<tbox::MshDeform> _morph) : sol(_sol), morph(_morph) { // Default parameters nthreads = sol->nthreads; verbose = sol->verbose; + // Linear solvers + if (sol->linsol->type() == LSOLTYPE::GMRES_ILUT) + { + // Use the same GMRES, but with a thighter tolerance + std::shared_ptr<Gmres> gmres = std::make_shared<Gmres>(*dynamic_cast<Gmres *>(sol->linsol.get())); + gmres->setTolerance(1e-8); + alinsol = gmres; + } + else + alinsol = sol->linsol; + mlinsol = morph->linsol; + // Update element gradients sol->pbl->initGradElems(); @@ -67,6 +80,13 @@ Adjoint::Adjoint(std::shared_ptr<Newton> _sol, std::shared_ptr<tbox::MshDeform> dCdMsh.resize(sol->pbl->msh->nodes.size(), Eigen::Vector3d::Zero()); dClAoa = 0; dCdAoa = 0; + + // Display solver parameters + std::cout << "--- Adjoint solver ---\n" + << "Aero inner solver: " << *alinsol + << "Mesh inner solver: " << *mlinsol + << "Number of threads: " << nthreads << "\n" + << std::endl; } /** @@ -81,11 +101,6 @@ void Adjoint::run() // Init tbb::global_control control(tbb::global_control::max_allowed_parallelism, nthreads); - // Display solver parameters - std::cout << "--- Adjoint solver ---\n" - << "Number of threads: " << nthreads << "\n" - << std::endl; - // Compute partial gradients of flow residuals and solve flow adjoint tms["0-AdjFlo"].start(); this->linearizeFlow(); // dRu/dU, dRu/dA, dRu/dX @@ -117,8 +132,8 @@ void Adjoint::run() dCf_X[1][i] -= dCd_XU[i]; // dCd/dX - dRu/dX^T * lambdaCdU } // compute mesh adjoint (totals) - std::vector<double> lamClMsh = this->solveMesh(dCf_X[0]); // lambdaClX = dRx/dX^T * (dCl/dX - dRu/dX^T * lambdaClU) - std::vector<double> lamCdMsh = this->solveMesh(dCf_X[1]); // lambdaCdX = dRx/dX^T * (dCd/dX - dRu/dX^T * lambdaCdU) + std::vector<double> lamClMsh = this->solveMesh(dCf_X[0]); // lambdaClX = dRx/dX^-T * (dCl/dX - dRu/dX^T * lambdaClU) + std::vector<double> lamCdMsh = this->solveMesh(dCf_X[1]); // lambdaCdX = dRx/dX^-T * (dCd/dX - dRu/dX^T * lambdaCdU) // store solution for (auto n : sol->pbl->msh->nodes) { @@ -194,7 +209,7 @@ std::vector<double> Adjoint::solveMesh(std::vector<double> const &dX) Eigen::Map<Eigen::VectorXd> dR_(dR.data(), dR.size()); Eigen::VectorXd dX_ = Eigen::Map<const Eigen::VectorXd>(dX.data(), dX.size()); // Solve - linsol->compute(dRx_X.transpose(), Eigen::Map<Eigen::VectorXd>(dX_.data(), dX_.size()), dR_); + mlinsol->compute(dRx_X.transpose(), Eigen::Map<Eigen::VectorXd>(dX_.data(), dX_.size()), dR_); return std::vector<double>(dR.data(), dR.data() + dR.size()); } @@ -242,7 +257,7 @@ std::vector<double> Adjoint::solveFlow(std::vector<double> const &dU) Eigen::Map<Eigen::VectorXd> dR_(dR.data(), dR.size()); Eigen::VectorXd dU_ = Eigen::Map<const Eigen::VectorXd>(dU.data(), dU.size()); // Solve - linsol->compute(dRu_U.transpose(), Eigen::Map<Eigen::VectorXd>(dU_.data(), dU_.size()), dR_); + alinsol->compute(dRu_U.transpose(), Eigen::Map<Eigen::VectorXd>(dU_.data(), dU_.size()), dR_); return std::vector<double>(dR.data(), dR.data() + dR.size()); } @@ -332,18 +347,7 @@ std::vector<std::vector<double>> Adjoint::computeGradientCoefficientsFlow() // Compute gradients of lift and drag Eigen::RowVectorXd dCl = Eigen::RowVectorXd::Zero(sol->pbl->msh->nodes.size()), dCd = Eigen::RowVectorXd::Zero(sol->pbl->msh->nodes.size()); for (auto bnd : sol->pbl->bodies) - { - // gradients of loads - Eigen::SparseMatrix<double, Eigen::RowMajor> dL = Eigen::SparseMatrix<double, Eigen::RowMajor>(3 * bnd->nodes.size(), sol->pbl->msh->nodes.size()); - this->buildGradientLoadsFlow(dL, *bnd); - // project to lift and drag directions - Eigen::RowVector3d dirL = sol->pbl->dirL.eval().transpose(), dirD = sol->pbl->dirD.eval().transpose(); - for (size_t i = 0; i < bnd->nodes.size(); ++i) - { - dCl += dirL * dL.middleRows(i * 3, 3); - dCd += dirD * dL.middleRows(i * 3, 3); - } - } + this->buildGradientCoefficientsFlow(dCl, dCd, *bnd); return std::vector<std::vector<double>>{std::vector<double>(dCl.data(), dCl.data() + dCl.size()), std::vector<double>(dCd.data(), dCd.data() + dCd.size())}; } @@ -369,23 +373,12 @@ std::vector<std::vector<double>> Adjoint::computeGradientCoefficientsMesh() // Compute the gradients of the lift and drag Eigen::RowVectorXd dCl = Eigen::RowVectorXd::Zero(sol->pbl->nDim * sol->pbl->msh->nodes.size()), dCd = Eigen::RowVectorXd::Zero(sol->pbl->nDim * sol->pbl->msh->nodes.size()); for (auto bnd : sol->pbl->bodies) - { - // gradients of loads - Eigen::SparseMatrix<double, Eigen::RowMajor> dL = Eigen::SparseMatrix<double, Eigen::RowMajor>(3 * bnd->nodes.size(), sol->pbl->nDim * sol->pbl->msh->nodes.size()); - this->buildGradientLoadsMesh(dL, *bnd); - // project to lift and drag directions - Eigen::RowVector3d dirL = sol->pbl->dirL.eval().transpose(), dirD = sol->pbl->dirD.eval().transpose(); - for (size_t i = 0; i < bnd->nodes.size(); ++i) - { - dCl += dirL * dL.middleRows(i * 3, 3); - dCd += dirD * dL.middleRows(i * 3, 3); - } - } + this->buildGradientCoefficientsMesh(dCl, dCd, *bnd); return std::vector<std::vector<double>>{std::vector<double>(dCl.data(), dCl.data() + dCl.size()), std::vector<double>(dCd.data(), dCd.data() + dCd.size())}; } /** - * @brief Build the gradients of the loads with respect to the flow variables one a given body + * @brief Build gradients of the loads with respect to the flow variables on a given body */ void Adjoint::buildGradientLoadsFlow(Eigen::SparseMatrix<double, Eigen::RowMajor> &dL, Body const &bnd) { @@ -404,7 +397,7 @@ void Adjoint::buildGradientLoadsFlow(Eigen::SparseMatrix<double, Eigen::RowMajor tbb::spin_mutex::scoped_lock lock(mutex); for (size_t i = 0; i < e->nodes.size(); ++i) { - int rowi = bnd.nMap.at(e->nodes[i]); + int rowi = static_cast<int>(bnd.nMap.at(e->nodes[i])); for (int m = 0; m < 3; ++m) { for (size_t j = 0; j < eV->nodes.size(); ++j) @@ -421,7 +414,43 @@ void Adjoint::buildGradientLoadsFlow(Eigen::SparseMatrix<double, Eigen::RowMajor } /** - * @brief Compute gradients of the residual with respect to angle of attack + * @brief Build gradients of the load coefficients with respect to the flow variables on a given body + * + * Note: this is essentially the same as buildGradientLoadsFlow, but with an additional projection performed inside the loop for performance + */ +void Adjoint::buildGradientCoefficientsFlow(Eigen::RowVectorXd &dCl, Eigen::RowVectorXd &dCd, Body const &bnd) +{ + // Multithread + tbb::global_control control(tbb::global_control::max_allowed_parallelism, nthreads); + tbb::spin_mutex mutex; + + // Build gradients + Eigen::RowVector3d dirL = sol->pbl->dirL.eval().transpose(), dirD = sol->pbl->dirD.eval().transpose(); + tbb::parallel_for_each(bnd.groups[0]->tag->elems.begin(), bnd.groups[0]->tag->elems.end(), [&](Element *e) { + // Associated volume element + Element *eV = bnd.svMap.at(e); + // Build + Eigen::MatrixXd Ae = LoadFunctional::buildGradientFlow(*e, *eV, sol->phi, *sol->pbl->fluid->cP); + // Project + Eigen::RowVectorXd dCle = Eigen::RowVectorXd::Zero(eV->nodes.size()), dCde = Eigen::RowVectorXd::Zero(eV->nodes.size()); + for (size_t i = 0; i < e->nodes.size(); ++i) + { + dCle += dirL * Ae.middleRows(i * 3, 3); + dCde += dirD * Ae.middleRows(i * 3, 3); + } + // Assembly + tbb::spin_mutex::scoped_lock lock(mutex); + for (size_t j = 0; j < eV->nodes.size(); ++j) + { + int rowj = eV->nodes[j]->row; + dCl(rowj) += dCle(j); + dCd(rowj) += dCde(j); + } + }); +} + +/** + * @brief Build gradients of the residual with respect to angle of attack */ void Adjoint::buildGradientResidualAoa(Eigen::VectorXd &dR) { @@ -451,7 +480,7 @@ void Adjoint::buildGradientResidualAoa(Eigen::VectorXd &dR) } /** - * @brief Compute gradients of the lift and drag with respect to angle of attack + * @brief Build gradients of the lift and drag with respect to angle of attack */ void Adjoint::buildGradientLoadsAoa(double &dCl, double &dCd) { @@ -466,7 +495,7 @@ void Adjoint::buildGradientLoadsAoa(double &dCl, double &dCd) } /** - * @brief Compute gradients of the residual with respect to mesh coordinates + * @brief Build gradients of the residual with respect to mesh coordinates */ void Adjoint::buildGradientResidualMesh(Eigen::SparseMatrix<double, Eigen::RowMajor> &dR) { @@ -585,7 +614,7 @@ void Adjoint::buildGradientResidualMesh(Eigen::SparseMatrix<double, Eigen::RowMa } /** - * @brief Compute gradients of the loads with respect to mesh coordinates, on a given body + * @brief Build gradients of the loads with respect to mesh coordinates on a given body */ void Adjoint::buildGradientLoadsMesh(Eigen::SparseMatrix<double, Eigen::RowMajor> &dL, Body const &bnd) { @@ -605,7 +634,7 @@ void Adjoint::buildGradientLoadsMesh(Eigen::SparseMatrix<double, Eigen::RowMajor tbb::spin_mutex::scoped_lock lock(mutex); for (size_t i = 0; i < e->nodes.size(); ++i) { - int rowi = bnd.nMap.at(e->nodes[i]); + int rowi = static_cast<int>(bnd.nMap.at(e->nodes[i])); for (int m = 0; m < 3; ++m) { // surface @@ -618,7 +647,7 @@ void Adjoint::buildGradientLoadsMesh(Eigen::SparseMatrix<double, Eigen::RowMajor // volume for (size_t j = 0; j < eV->nodes.size(); ++j) { - size_t rowj = eV->nodes[j]->row; + int rowj = eV->nodes[j]->row; for (int n = 0; n < sol->pbl->nDim; ++n) T.push_back(Eigen::Triplet<double>(3 * rowi + m, sol->pbl->nDim * rowj + n, Aev(3 * i + m, sol->pbl->nDim * j + n))); } @@ -630,6 +659,60 @@ void Adjoint::buildGradientLoadsMesh(Eigen::SparseMatrix<double, Eigen::RowMajor dL.makeCompressed(); } +/** + * @brief Build gradients of the loads with respect to mesh coordinates on a given body + * + * Note: this is essentially the same as buildGradientLoadsMesh, but with an additional projection performed inside the loop for performance + */ +void Adjoint::buildGradientCoefficientsMesh(Eigen::RowVectorXd &dCl, Eigen::RowVectorXd &dCd, Body const &bnd) +{ + // Multithread + tbb::global_control control(tbb::global_control::max_allowed_parallelism, nthreads); + tbb::spin_mutex mutex; + + // Build gradients + Eigen::RowVector3d dirL = sol->pbl->dirL.eval().transpose(), dirD = sol->pbl->dirD.eval().transpose(); + tbb::parallel_for_each(bnd.groups[0]->tag->elems.begin(), bnd.groups[0]->tag->elems.end(), [&](Element *e) { + // Associated volume element + Element *eV = bnd.svMap.at(e); + // Build + Eigen::MatrixXd Aes, Aev; + std::tie(Aes, Aev) = LoadFunctional::buildGradientMesh(*e, *eV, sol->phi, *sol->pbl->fluid->cP, sol->pbl->nDim); + // Project + Eigen::RowVectorXd dCles = Eigen::RowVectorXd::Zero(sol->pbl->nDim * e->nodes.size()), dCdes = Eigen::RowVectorXd::Zero(sol->pbl->nDim * e->nodes.size()); + Eigen::RowVectorXd dClev = Eigen::RowVectorXd::Zero(sol->pbl->nDim * eV->nodes.size()), dCdev = Eigen::RowVectorXd::Zero(sol->pbl->nDim * eV->nodes.size()); + for (size_t i = 0; i < e->nodes.size(); ++i) + { + dCles += dirL * Aes.middleRows(i * 3, 3); + dCdes += dirD * Aes.middleRows(i * 3, 3); + dClev += dirL * Aev.middleRows(i * 3, 3); + dCdev += dirD * Aev.middleRows(i * 3, 3); + } + // Assembly + tbb::spin_mutex::scoped_lock lock(mutex); + // surface + for (size_t j = 0; j < e->nodes.size(); ++j) + { + int rowj = e->nodes[j]->row; + for (int n = 0; n < sol->pbl->nDim; ++n) + { + dCl(sol->pbl->nDim * rowj + n) += dCles(sol->pbl->nDim * j + n); + dCd(sol->pbl->nDim * rowj + n) += dCdes(sol->pbl->nDim * j + n); + } + } + // volume + for (size_t j = 0; j < eV->nodes.size(); ++j) + { + int rowj = eV->nodes[j]->row; + for (int n = 0; n < sol->pbl->nDim; ++n) + { + dCl(sol->pbl->nDim * rowj + n) += dClev(sol->pbl->nDim * j + n); + dCd(sol->pbl->nDim * rowj + n) += dCdev(sol->pbl->nDim * j + n); + } + } + }); +} + /** * @brief Write the results */ diff --git a/dart/src/wAdjoint.h b/dart/src/wAdjoint.h index a38c2706e9cac8a4a7af8acb20eda63c095f78c2..a33efb11100d5775f064e882e91b57d56ea63de0 100644 --- a/dart/src/wAdjoint.h +++ b/dart/src/wAdjoint.h @@ -37,9 +37,10 @@ namespace dart class DART_API Adjoint : public fwk::wSharedObject { public: - std::shared_ptr<Newton> sol; ///< Newton solver - std::shared_ptr<tbox::MshDeform> morph; ///< mesh morpher - std::shared_ptr<tbox::LinearSolver> linsol; ///< linear solver + std::shared_ptr<Newton> sol; ///< Newton solver + std::shared_ptr<tbox::MshDeform> morph; ///< mesh morpher + std::shared_ptr<tbox::LinearSolver> alinsol; ///< linear solver (adjoint aero) + std::shared_ptr<tbox::LinearSolver> mlinsol; ///< linear solver (adjoint mesh) int nthreads; ///< number of threads for the assembly int verbose; ///< display more info @@ -61,7 +62,7 @@ private: fwk::Timers tms; ///< internal timers public: - Adjoint(std::shared_ptr<Newton> _sol, std::shared_ptr<tbox::MshDeform> _morph, std::shared_ptr<tbox::LinearSolver> _linsol); + Adjoint(std::shared_ptr<Newton> _sol, std::shared_ptr<tbox::MshDeform> _morph); virtual ~Adjoint() { std::cout << "~Adjoint()\n"; } void run(); @@ -93,12 +94,14 @@ public: private: // Partial gradients wrt with respect to flow variables void buildGradientLoadsFlow(Eigen::SparseMatrix<double, Eigen::RowMajor> &dL, Body const &bnd); + void buildGradientCoefficientsFlow(Eigen::RowVectorXd &dCl, Eigen::RowVectorXd &dCd, Body const &bnd); // Partial gradients with respect to angle of attack void buildGradientResidualAoa(Eigen::VectorXd &dR); void buildGradientLoadsAoa(double &dCl, double &dCd); // Partial gradients with respect to mesh coordinates void buildGradientResidualMesh(Eigen::SparseMatrix<double, Eigen::RowMajor> &dR); void buildGradientLoadsMesh(Eigen::SparseMatrix<double, Eigen::RowMajor> &dL, Body const &bnd); + void buildGradientCoefficientsMesh(Eigen::RowVectorXd &dCl, Eigen::RowVectorXd &dCd, Body const &bnd); }; } // namespace dart diff --git a/dart/src/wF0El.cpp b/dart/src/wF0El.cpp index 8a2deeff8928c06485be0ff76c480a0adfada464..bea283450ec26deed8a6dabad98b08af6feddddc 100644 --- a/dart/src/wF0El.cpp +++ b/dart/src/wF0El.cpp @@ -28,153 +28,249 @@ void F0ElC::update(double _v) /** * @brief Evaluate the constant */ -double F0ElC::eval(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElC::eval(Element const &e, std::vector<double> const &phi, size_t k) const { return v; } /** * @brief Evaluate the gradient of the constant */ -double F0ElC::evalGrad(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElC::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const { return 0; } /** - * @brief Evaluate the nonlinear density (constant over element) + * @brief Precompute values for Padé approximation + * + * The input _mC2 is the square of the critical Mach number (used to compute + * the critical velocity). */ -double F0ElRho::eval(Element const &e, std::vector<double> const &u, size_t k) const +F0ElRhoBase::F0ElRhoBase(double _mInf, double _mC2) : F0El(), gamma(1.4), mInf(_mInf) { - double gradU = e.computeGradient(u, k).norm(); // norm of velocity - - if (gradU < gradUC) // true density - { - // particularized: pow(1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2), 1 / (gamma - 1)); - double a = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU * gradU); - return sqrt(a * a * a * a * a); - } + uC = sqrt(_mC2 * (1 / (mInf * mInf) + (gamma - 1) / 2) / (1 + (gamma - 1) / 2 * _mC2)); // critical velocity + rC = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - uC * uC); // r(uC) + beta = ((gamma - 1) * mInf * mInf * uC) / rC; // dr/du(uC) / -r(uC) +} +/** + * @brief Evaluate the base of the isentropic density + * + * r = [1 + (gamma-1)/2*Mi^2*(1-u^2)], u <= uC + * r = r(uC) / (1-(dr/du(uC)/f(uC))*(u/uC-1)), u > uC + */ +double F0ElRhoBase::eval(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double u = e.computeGradient(phi, k).norm(); // norm of velocity + if (u <= uC) + return 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - u * u); else - { - double a = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradUC * gradUC); - double beta = mInf * mInf * gradUC / a; - return sqrt(a * a * a * a * a) / (1 + beta * (gradU / gradUC - 1)); // limited density - } + return rC / (1 + beta * (u / uC - 1)); } /** - * @brief Evaluate the nonlinear density derivative (constant over element) + * @brief Evaluate the gradient of the base of the isentropic density + * + * dr = -(gamma-1)*Mi^2 * u, u <= uC + * dr = -r(uC) / (1-(dr/du(uC)/f(uC))*(u/uC-1))^2 * (dr/du(uC)/f(uC)) / uC, u > uC + * Computed value has to be multiplied by u to recover actual gradient */ -double F0ElRho::evalGrad(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElRhoBase::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const { - double gradU = e.computeGradient(u, k).norm(); // norm of velocity + double u = e.computeGradient(phi, k).norm(); // norm of velocity + if (u <= uC) + return -(gamma - 1) * mInf * mInf; + else + return -rC / ((1 + beta * (u / uC - 1)) * (1 + beta * (u / uC - 1))) * beta / uC / u; +} - if (gradU < gradUC) // true density - { - //particularized: -mInf * mInf * pow(rho, 2 - gamma); - double a = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU * gradU); - return -mInf * mInf * sqrt(a * a * a); // has to be multiplied by grad u to recover true derivative - } - else // limited density - { - double a = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradUC * gradUC); - double beta = mInf * mInf * gradUC / a; - return -sqrt(a * a * a * a * a) / ((1 + beta * (gradU / gradUC - 1)) * (1 + beta * (gradU / gradUC - 1))) * beta / gradUC / gradU; // has to be multiplied by grad u to recover true derivative - } +/** + * @brief Evaluate the isentropic density + * + * rho = (1 + (gamma-1)/2*Mi^2*(1-u^2))^(1/(gamma-1)) + */ +double F0ElRho::eval(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double u = e.computeGradient(phi, k).norm(); // norm of velocity + double r = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - u * u); + return sqrt(r * r * r * r * r); // particularized to gamma=1.4 +} +/** + * @brief Evaluate the isentropic density gradient + * + * drho = -Mi^2 * rho^(2-gamma) * u + * Computed value has to be multiplied by u to recover actual gradient + */ +double F0ElRho::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double u = e.computeGradient(phi, k).norm(); // norm of velocity + double r = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - u * u); + return -mInf * mInf * sqrt(r * r * r); // particularized to gamma=1.4 } /** - * @brief Evaluate the linear density (constant over element) + * @brief Evaluate the (clamped) isentropic density + * + * rho = r^(1/(gamma-1)) */ -double F0ElRhoL::eval(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElRhoClamp::eval(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double r = F0ElRhoBase::eval(e, phi, k); + return sqrt(r * r * r * r * r); // particularized to gamma=1.4 +} +/** + * @brief Evaluate the (clamped) isentropic density gradient + * + * drho = 1/(gamma-1) * r^(2-gamma) * dr + * Computed value has to be multiplied by u to recover actual gradient + */ +double F0ElRhoClamp::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double r = F0ElRhoBase::eval(e, phi, k); + double dr = F0ElRhoBase::evalGrad(e, phi, k); + return 1 / (gamma - 1) * sqrt(r * r * r) * dr; // particularized to gamma=1.4 +} + +/** + * @brief Evaluate the linear density + */ +double F0ElRhoLin::eval(Element const &e, std::vector<double> const &phi, size_t k) const { return 1.; } /** - * @brief Evaluate the linear density derivative (constant over element) + * @brief Evaluate the linear density gradient */ -double F0ElRhoL::evalGrad(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElRhoLin::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const { return 0.; } /** - * @brief Evaluate the nonlinear Mach number (constant over element) + * @brief Evaluate the isentropic Mach number + * + * M = u / sqrt(1/mi^2 + (gamma-1)/2*(1-u^2)) + */ +double F0ElMach::eval(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double u2 = e.computeGradient(phi, k).squaredNorm(); // velocity squared + double a2 = 1 / (mInf * mInf) + 0.5 * (gamma - 1) * (1 - u2); // speed of sound squared + return sqrt(u2) / sqrt(a2); +} +/** + * @brief Evaluate the isentropic Mach number gradient + * + * dM = (1/(u*a) + (gamma-1)/2*u/a^3) * u + * Computed value has to be multiplied by u to recover actual gradient */ -double F0ElMach::eval(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElMach::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const { - Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity - double gradU2 = gradU.squaredNorm(); // velocity squared - double a2 = 1 / (mInf * mInf) + 0.5 * (gamma - 1) * (1 - gradU2); // speed of sound squared + double u2 = e.computeGradient(phi, k).squaredNorm(); // velocity squared + double a2 = 1 / (mInf * mInf) + 0.5 * (gamma - 1) * (1 - u2); // speed of sound squared + return 1 / sqrt(u2 * a2) + 0.5 * (gamma - 1) * sqrt(u2) / sqrt(a2 * a2 * a2); +} - return sqrt(gradU2) / sqrt(a2); +/** + * @brief Evaluate the (clamped) isentropic Mach number + * + * M = u / sqrt(r/Mi^2) + */ +double F0ElMachClamp::eval(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double u = e.computeGradient(phi, k).norm(); // norm of velocity + double r = F0ElRhoBase::eval(e, phi, k); + return mInf * u / sqrt(r); } /** - * @brief Evaluate the nonlinear Mach number derivative (constant over element) + * @brief Evaluate the (clamped) isentropic Mach number gradient + * + * dM = 1 / sqrt(r/Mi^2) + u / sqrt(r^3/Mi^2) * dr + * Computed value has to be multiplied by u to recover actual gradient */ -double F0ElMach::evalGrad(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElMachClamp::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const { - Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity - double gradU2 = gradU.squaredNorm(); // velocity squared - double a2 = 1 / (mInf * mInf) + 0.5 * (gamma - 1) * (1 - gradU2); - - return 1 / sqrt(gradU2 * a2) + 0.5 * (gamma - 1) * sqrt(gradU2) / sqrt(a2 * a2 * a2); // has to be multiplied by grad u to recover true derivative + double u = e.computeGradient(phi, k).norm(); // norm of velocity + double r = F0ElRhoBase::eval(e, phi, k); + double dr = F0ElRhoBase::evalGrad(e, phi, k); + return mInf * (1 / sqrt(r) / u - 0.5 * u / sqrt(r * r * r) * dr); } /** - * @brief Evaluate the linear Mach number (constant over element) + * @brief Evaluate the linear Mach number */ -double F0ElMachL::eval(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElMachLin::eval(Element const &e, std::vector<double> const &phi, size_t k) const { return 0.; } /** - * @brief Evaluate the linear Mach number derivative (constant over element) + * @brief Evaluate the linear Mach number gradient */ -double F0ElMachL::evalGrad(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElMachLin::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const { return 0.; } /** - * @brief Evaluate the nonlinear pressure coefficient (constant over element) + * @brief Evaluate the isentropic pressure coefficient + * + * Cp = 2/(gamma*Mi^2) * ((1 + (gamma-1)/2*Mi^2*(1-u^2))^(gamma/(gamma-1)) - 1) */ -double F0ElCp::eval(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElCp::eval(Element const &e, std::vector<double> const &phi, size_t k) const { - Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity - double gradU2 = gradU.squaredNorm(); // velocity squared - //particularized: 2 / (gamma * mInf * mInf) * (pow(1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2), gamma / (gamma - 1)) - 1); - double a = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2); - - if (a <= 0) - return -2 / (gamma * mInf * mInf); // limit the pressure coefficient when vacuum conditions are reached - else - return 2 / (gamma * mInf * mInf) * (sqrt(a * a * a * a * a * a * a) - 1); + double u2 = e.computeGradient(phi, k).squaredNorm(); // velocity squared + double r = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - u2); + return 2 / (gamma * mInf * mInf) * (sqrt(r * r * r * r * r * r * r) - 1); // particularized to gamma=1.4 } /** - * @brief Evaluate the nonlinear pressure coefficient derivative (constant over element) + * @brief Evaluate the isentropic pressure coefficient gradient + * + * dCp = -2*(1 + (gamma-1)/2*Mi^2*(1-u^2))^(1/(gamma-1)) * u + * Computed value has to multiplied by u to recover actual gradient */ -double F0ElCp::evalGrad(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElCp::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const { - Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity - double gradU2 = gradU.squaredNorm(); // velocity squared - //particularized: -2 * pow(1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2), 1 / (gamma - 1)); - double a = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - gradU2); + double u2 = e.computeGradient(phi, k).squaredNorm(); // velocity squared + double r = 1 + 0.5 * (gamma - 1) * mInf * mInf * (1 - u2); + return -2 * sqrt(r * r * r * r * r); // particularized to gamma=1.4 +} - if (a <= 0) - return 0; // limit the gradient when vacuum conditions are reached - else - return -2 * sqrt(a * a * a * a * a); // has to be multiplied by grad u to recover true derivative +/** + * @brief Evaluate the (clamped) isentropic pressure coefficient + * + * Cp = 2/(gamma*Mi^2) * (r^(gamma/(gamma-1)) - 1) + */ +double F0ElCpClamp::eval(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double r = F0ElRhoBase::eval(e, phi, k); + return 2 / (gamma * mInf * mInf) * (sqrt(r * r * r * r * r * r * r) - 1); // particularized to gamma=1.4 +} +/** + * @brief Evaluate the (clamped) isentropic pressure coefficient gradient + * + * dCp = 2/((gamma-1)*Mi^2) * r^(1/(gamma-1)) * dr + * Computed value has to multiplied by u to recover actual gradient + */ +double F0ElCpClamp::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const +{ + double r = F0ElRhoBase::eval(e, phi, k); + double dr = F0ElRhoBase::evalGrad(e, phi, k); + return 2 / ((gamma - 1) * mInf * mInf) * sqrt(r * r * r * r * r) * dr; // particularized to gamma=1.4 } /** - * @brief Evaluate the linear pressure coefficient (constant over element) + * @brief Evaluate the linear pressure coefficient + * + * Cp = 1-u^2 */ -double F0ElCpL::eval(Element const &e, std::vector<double> const &u, size_t k) const +double F0ElCpLin::eval(Element const &e, std::vector<double> const &phi, size_t k) const { - Eigen::VectorXd gradU = e.computeGradient(u, k); // velocity - double gradU2 = gradU.squaredNorm(); // velocity squared - return 1 - gradU2; + return 1 - e.computeGradient(phi, k).squaredNorm(); } -double F0ElCpL::evalGrad(Element const &e, std::vector<double> const &u, size_t k) const +/** + * @brief Evaluate the linear pressure coefficient gradient + * + * dCp = -2*u + * Computed value has to multiplied by u to recover actual gradient + */ +double F0ElCpLin::evalGrad(Element const &e, std::vector<double> const &phi, size_t k) const { - return -2.; // has to be multiplied by grad u to recover true derivative + return -2.; } \ No newline at end of file diff --git a/dart/src/wF0El.h b/dart/src/wF0El.h index fc4850c98f6f0cc5f071820edc5c3ed222c08904..4f4a7746936380ce1910b1122b0985ef04a203e0 100644 --- a/dart/src/wF0El.h +++ b/dart/src/wF0El.h @@ -34,9 +34,9 @@ public: F0El() : Observer() {} virtual ~F0El() {} - virtual double eval(tbox::Element const &e, std::vector<double> const &u, + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, size_t k) const = 0; - virtual double evalGrad(tbox::Element const &e, std::vector<double> const &u, + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, size_t k) const = 0; }; @@ -51,55 +51,93 @@ public: F0ElC(double _v) : F0El(), v(_v) {} virtual void update(double _v) override; - virtual double eval(tbox::Element const &e, std::vector<double> const &u, + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; - virtual double evalGrad(tbox::Element const &e, std::vector<double> const &u, + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; }; /** - * @brief Nonlinear density + * @brief Base of isentropic density * - * The density is limited (Padé approximation) for large value of velocity and - * particularized for diatomic gas. The input _mC2 is the square of the critical - * Mach number used to compute the critical velocity. + * This function computes the base of the isentropic density, and is then used + * to compute the actual density, Mach number and pressure coefficient. This + * function is clamped for large velocities using a Padé approximation and + * particularized to diatomic gas. + */ +class DART_API F0ElRhoBase : public F0El +{ +protected: + double gamma; ///< heat capacity ratio (diatomic gas only) + double mInf; ///< freestream Mach number +private: + double uC; ///< critical velocity + double rC; ///< critical density base + double beta; ///< ratio for Padé + +public: + F0ElRhoBase(double _mInf, double _mC2 = 5); + + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, + size_t k) const override; + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, + size_t k) const override; +}; + +/** + * @brief Isentropic density + * + * The density is particularized to diatomic gas. */ class DART_API F0ElRho : public F0El { - double gamma; ///< heat capacity ratio (diatomic gas only) - double mInf; ///< freestream Mach number - double gradUC; ///< critical velocity + double gamma; ///< heat capacity ratio (diatomic gas only) + double mInf; ///< freestream Mach number public: - F0ElRho(double _mInf, double _mC2 = 5) : F0El(), gamma(1.4), mInf(_mInf) - { - gradUC = sqrt(_mC2 * (1 / (mInf * mInf) + (gamma - 1) / 2) / (1 + (gamma - 1) / 2 * _mC2)); - } + F0ElRho(double _mInf) : F0El(), gamma(1.4), mInf(_mInf) {} + + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, + size_t k) const override; + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, + size_t k) const override; +}; + +/** + * @brief Isentropic clamped density + * + * The density is clamped (Padé approximation) for large values of velocity and + * particularized to diatomic gas. + */ +class DART_API F0ElRhoClamp : public F0ElRhoBase +{ +public: + F0ElRhoClamp(double _mInf, double _mC2 = 5) : F0ElRhoBase(_mInf, _mC2) {} - virtual double eval(tbox::Element const &e, std::vector<double> const &u, + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; - virtual double evalGrad(tbox::Element const &e, std::vector<double> const &u, + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; }; /** * @brief Linear density (constant) */ -class DART_API F0ElRhoL : public F0El +class DART_API F0ElRhoLin : public F0El { public: - F0ElRhoL() : F0El() {} + F0ElRhoLin() : F0El() {} - virtual double eval(tbox::Element const &e, std::vector<double> const &u, + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; - virtual double evalGrad(tbox::Element const &e, std::vector<double> const &u, + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; }; /** - * @brief Nonlinear Mach number + * @brief Isentropic Mach number * - * Particularized for diatomic gas + * The Mach number is particularized to diatomic gas. */ class DART_API F0ElMach : public F0El { @@ -109,30 +147,47 @@ class DART_API F0ElMach : public F0El public: F0ElMach(double _mInf) : F0El(), gamma(1.4), mInf(_mInf) {} - virtual double eval(tbox::Element const &e, std::vector<double> const &u, + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, + size_t k) const override; + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, + size_t k) const override; +}; + +/** + * @brief Isentropic clamped Mach number + * + * The Mach number is clamped (Padé approximation) for large values of velocity + * and particularized to diatomic gas. + */ +class DART_API F0ElMachClamp : public F0ElRhoBase +{ +public: + F0ElMachClamp(double _mInf, double _mC2 = 5) : F0ElRhoBase(_mInf, _mC2) {} + + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; - virtual double evalGrad(tbox::Element const &e, std::vector<double> const &u, + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; }; /** * @brief Linear Mach number (constant) */ -class DART_API F0ElMachL : public F0El +class DART_API F0ElMachLin : public F0El { public: - F0ElMachL() : F0El() {} + F0ElMachLin() : F0El() {} - virtual double eval(tbox::Element const &e, std::vector<double> const &u, + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; - virtual double evalGrad(tbox::Element const &e, std::vector<double> const &u, + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; }; /** - * @brief Nonlinear pressure coefficient + * @brief Isentropic pressure coefficient * - * Particularized for diatomic gas + * The pressure coefficient is particularized to diatomic gas. */ class DART_API F0ElCp : public F0El { @@ -142,27 +197,43 @@ class DART_API F0ElCp : public F0El public: F0ElCp(double _mInf) : F0El(), gamma(1.4), mInf(_mInf) {} - virtual double eval(tbox::Element const &e, std::vector<double> const &u, + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; - virtual double evalGrad(tbox::Element const &e, std::vector<double> const &u, + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; }; /** - * @brief Linear pressure coefficient + * @brief Isentropic clamped pressure coefficient + * + * The pressure coefficient is clamped (Padé approximation) for large values of + * velocity and particularized to diatomic gas. */ -class DART_API F0ElCpL : public F0El +class DART_API F0ElCpClamp : public F0ElRhoBase { +public: + F0ElCpClamp(double _mInf, double _mC2 = 5) : F0ElRhoBase(_mInf, _mC2) {} + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, + size_t k) const override; + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, + size_t k) const override; +}; + +/** + * @brief Linear pressure coefficient + */ +class DART_API F0ElCpLin : public F0El +{ public: - F0ElCpL() : F0El() {} + F0ElCpLin() : F0El() {} - virtual double eval(tbox::Element const &e, std::vector<double> const &u, + virtual double eval(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; - virtual double evalGrad(tbox::Element const &e, std::vector<double> const &u, + virtual double evalGrad(tbox::Element const &e, std::vector<double> const &phi, size_t k) const override; }; } // namespace dart -#endif //WF0EL_H +#endif // WF0EL_H diff --git a/dart/src/wFluid.cpp b/dart/src/wFluid.cpp index 1713078fab68347424c8dd63e80c0623bda924f2..a209f4bb15b8b27bbbd7425d09cd0bc1fdcbf83c 100644 --- a/dart/src/wFluid.cpp +++ b/dart/src/wFluid.cpp @@ -54,15 +54,15 @@ void Fluid::initFun(double mInf, int dim, double alpha, double beta) { if (mInf == 0) { - rho = new F0ElRhoL(); - mach = new F0ElMachL(); - cP = new F0ElCpL(); + rho = new F0ElRhoLin(); + mach = new F0ElMachLin(); + cP = new F0ElCpLin(); } else { - rho = new F0ElRho(mInf); - mach = new F0ElMach(mInf); - cP = new F0ElCp(mInf); + rho = new F0ElRhoClamp(mInf); + mach = new F0ElMachClamp(mInf); + cP = new F0ElCpClamp(mInf); } phiInf = new F0PsPhiInf(dim, alpha, beta); } diff --git a/dart/src/wInvBnd.cpp b/dart/src/wInvBnd.cpp index 9b19d860a6f3b0dceb4a14a54a36dc6f656cff98..d3ed14efc1670f0c92d7e709f7c6447ade862ccf 100644 --- a/dart/src/wInvBnd.cpp +++ b/dart/src/wInvBnd.cpp @@ -16,6 +16,8 @@ #include <unordered_set> #include <iomanip> #include <fstream> +#include <iostream> +#include <iomanip> /* --- Namespaces -------------------------------------------------------------------- */ @@ -26,3 +28,17 @@ using namespace dart; InvBnd::InvBnd(){} InvBnd::~InvBnd(){} + +double InvBnd::GetMaxMach() const +{ + if (Me.size() <= 0) + { + throw std::runtime_error("dart::InvBnd Invalid Mach number vector."); + } + double Mmax = 0.0; + for (size_t i=0; i<Me.size(); ++i) + { + if (Me[i]>Mmax){Mmax = Me[i];} + } + return Mmax; +} diff --git a/dart/src/wInvBnd.h b/dart/src/wInvBnd.h index c14f2e19e797babd547d75fc5f952e2dd875aaf9..d7f42990548a4a81baf65210df6ff6cbbb50e83b 100644 --- a/dart/src/wInvBnd.h +++ b/dart/src/wInvBnd.h @@ -37,6 +37,8 @@ class DART_API InvBnd void SetDeltaStar(std::vector<double> _DeltaStar) {DeltaStar.resize(_DeltaStar.size(), 0.); DeltaStar = _DeltaStar;}; void SetVtOld(std::vector<double> _VtOld) {VtOld.resize(_VtOld.size(), 0.); VtOld = _VtOld;}; + double GetMaxMach() const; + }; } // namespace dart #endif //WINVBND_H \ No newline at end of file diff --git a/dart/src/wKuttaElement.cpp b/dart/src/wKuttaElement.cpp index c66a8de5ddd78f4c6dc934f6c9af502b473dae9a..360efa5eb6a1e738558a3818c7024e5a20ede6d3 100644 --- a/dart/src/wKuttaElement.cpp +++ b/dart/src/wKuttaElement.cpp @@ -28,26 +28,57 @@ KuttaElement::KuttaElement(size_t _no, Element *&_surE, Element *&_volE, // Sanity checks if (surE->type() == ELTYPE::LINE2) nDim = 2; + else if (surE->type() == ELTYPE::TRI3) + nDim = 3; else { std::stringstream err; err << "KuttaElement only implemented for surface elements of type " - << ELTYPE::LINE2 << " (" << surE->type() << " was given)!\n"; + << ELTYPE::LINE2 << " or " << ELTYPE::TRI3 + << " (" << surE->type() << " was given)!\n"; throw std::runtime_error(err.str()); } - if (volE->type() == ELTYPE::TRI3) + if (volE->type() == ELTYPE::TRI3 || volE->type() == ELTYPE::TETRA4) nCol = volE->nodes.size(); else { std::stringstream err; err << "KuttaElement only implemented for volume elements of type " - << ELTYPE::TRI3 << " (" << volE->type() << " was given)!\n"; + << ELTYPE::TRI3 << " or " << ELTYPE::TETRA4 + << " (" << volE->type() << " was given)!\n"; throw std::runtime_error(err.str()); } // Count TE nodes + mapNodes(); nRow = teN.size(); } +/** + * @brief Map the wake nodes to their local volume node indices + */ +void KuttaElement::mapNodes() +{ + // Find local volume index of contributing surface nodes + for (auto p : teN) + { + for (size_t i = 0; i < volE->nodes.size(); ++i) + { + if (surE->nodes[p.first] == volE->nodes[i]) + { + vsMap[p.first] = i; + break; + } + } + } + // Check that all contributing surface nodes have been mapped + if (vsMap.size() != teN.size()) + { + std::stringstream err; + err << "dart::KuttaElement: could not map some contributing nodes from surface element " << *surE << " to " << *volE << " (number of mapped nodes: " << vsMap.size() << ")!\n"; + throw std::runtime_error(err.str()); + } +} + void KuttaElement::write(std::ostream &out) const { out << "KuttaElement #" << no diff --git a/dart/src/wKuttaElement.h b/dart/src/wKuttaElement.h index b48c48c952139c0e5e722dcab6c24ec9b50fc5c6..f3fe8d8e27f873b399378dc0095cfe878b8873a5 100644 --- a/dart/src/wKuttaElement.h +++ b/dart/src/wKuttaElement.h @@ -21,6 +21,7 @@ #include "wObject.h" #include "wElement.h" #include <vector> +#include <map> namespace dart { @@ -29,16 +30,12 @@ namespace dart * @brief Super-element to apply Kutta condition * * Made up of one surface element at the trailing edge and the connected volume - * element. Only Line2 (surface) and Tri3 (volume) elements are curently - * implemented. - * Since Tri3 are used, the evaluation of the volume integrals is performed at - * dummy Gauss point #0. If volume elements with non-constant shape function - * derivatives are used, those derivates should be recomputed at the true - * surface element Gauss points. - * Kutta works well in 2D, but fails in 3D unless the geometry follows strict - * restrictions (thin and sharp TE, simple planform, same mesh elements on TE - * suction and pressure side, ...). Kutta contribution is therefore disabled for - * 3D cases. + * element. Only Line2/Tri3 (surface) and Tri3/Tetra4 (volume) elements are + * currently implemented. + * Since Tri3 or Tetra4 are used, the evalutaion of the volume integrals is + * performed at dummy Gauss point #0. If volume elements with non-constant shape + * function derivatives are used, those derivates should be recomputed at the + * true surface element Gauss points. * @authors Adrien Crovato */ class DART_API KuttaElement : public fwk::wObject @@ -54,12 +51,16 @@ public: size_t nDim; ///< dimension of volume element std::vector<std::pair<size_t, tbox::Node *>> teN; ///< Map of local node indices and trailing edge nodes + std::map<size_t, size_t> vsMap; ///< map between surface node and volume node indices int sign; ///< +1 if upper element, -1 if lower element KuttaElement(size_t _no, tbox::Element *&_surE, tbox::Element *&_volE, std::vector<std::pair<size_t, tbox::Node *>> &_teN, int _sign); virtual void write(std::ostream &out) const override; #endif + +private: + void mapNodes(); }; } // namespace dart diff --git a/dart/src/wKuttaResidual.cpp b/dart/src/wKuttaResidual.cpp index cbca6a696e549756a1c58bb41224f1222691120e..8884b5f7b7aa76db48ada9e9107c9df13935f608 100644 --- a/dart/src/wKuttaResidual.cpp +++ b/dart/src/wKuttaResidual.cpp @@ -27,18 +27,33 @@ using namespace dart; /** * @brief Build the residual matrix for a fixed-point iteration, on one Kutta element * - * A = \int psi * v_u*grad_phi dS + * A = 1/S * \int (psi + grad_psi*v_inf) * v*grad_phi dS + * NB: v_inf = [1, 0, 0] */ Eigen::MatrixXd KuttaResidual::buildFixed(KuttaElement const &ke, std::vector<double> const &phi) { - // Get shape functions, Jacobian and Gauss points + // Get shape functions and Gauss points Cache &sCache = ke.surE->getVCache(); Gauss &sGauss = sCache.getVGauss(); + Eigen::MatrixXd const &dSfV = ke.volE->getVCache().getDsf(0); + // Get Jacobian + Eigen::MatrixXd const &iJ = ke.volE->getJinv(0); // Get size size_t nRow = ke.nRow; + size_t nDim = ke.nDim; + // Stabilization (disabled in 2D) + Eigen::VectorXd dSfp = Eigen::VectorXd::Zero(nRow); + if (nDim == 3) + { + Eigen::MatrixXd dSf(nRow, nDim); + for (size_t i = 0; i < nRow; ++i) + for (size_t j = 0; j < nDim; ++j) + dSf(i, j) = dSfV(j, ke.vsMap.at(ke.teN[i].first)); + dSfp = 0.5 * sqrt(ke.surE->getVol()) * dSf * iJ.transpose() * Eigen::Vector3d(1, 0, 0).middleRows(0, nDim); + } // Velocity - Eigen::RowVectorXd Aup = ke.volE->computeGradient(phi, 0).transpose() * ke.volE->getJinv(0) * ke.volE->getVCache().getDsf(0); + Eigen::RowVectorXd Aup = 1 / ke.surE->getVol() * ke.volE->computeGradient(phi, 0).transpose() * iJ * dSfV; // Build Eigen::MatrixXd A = Eigen::MatrixXd::Zero(nRow, ke.nCol); @@ -48,7 +63,7 @@ Eigen::MatrixXd KuttaResidual::buildFixed(KuttaElement const &ke, std::vector<do Eigen::VectorXd const &sf = sCache.getSf(k); Eigen::VectorXd sfp(nRow); for (size_t i = 0; i < nRow; ++i) - sfp(i) = sf(ke.teN[i].first); + sfp(i) = sf(ke.teN[i].first) + dSfp(i); // wake contribution A += ke.sign * sfp * Aup * sGauss.getW(k) * ke.surE->getDetJ(k); } @@ -58,19 +73,33 @@ Eigen::MatrixXd KuttaResidual::buildFixed(KuttaElement const &ke, std::vector<do /** * @brief Build the residual vector, on one Kutta element * - * b = \int psi * (grad_phi)^2 dS + * b = 1/S * \int (psi + grad_psi*v_inf) * (grad_phi)^2 dS + * NB: v_inf = [1, 0, 0] */ Eigen::VectorXd KuttaResidual::build(KuttaElement const &ke, std::vector<double> const &phi) { - // Get shape functions, Jacobian and Gauss points + // Get shape functions and Gauss points Cache &sCache = ke.surE->getVCache(); Gauss &sGauss = sCache.getVGauss(); + Eigen::MatrixXd const &dSfV = ke.volE->getVCache().getDsf(0); + // Get Jacobian + Eigen::MatrixXd const &iJ = ke.volE->getJinv(0); // Get size size_t nRow = ke.nRow; + size_t nDim = ke.nDim; + // Stabilization (disabled in 2D) + Eigen::VectorXd dSfp = Eigen::VectorXd::Zero(nRow); + if (nDim == 3) + { + Eigen::MatrixXd dSf(nRow, nDim); + for (size_t i = 0; i < nRow; ++i) + for (size_t j = 0; j < nDim; ++j) + dSf(i, j) = dSfV(j, ke.vsMap.at(ke.teN[i].first)); + dSfp = 0.5 * sqrt(ke.surE->getVol()) * dSf * iJ.transpose() * Eigen::Vector3d(1, 0, 0).middleRows(0, nDim); + } // Velocity - Eigen::VectorXd dPhi = ke.volE->computeGradient(phi, 0); - double dPhi2 = dPhi.squaredNorm(); + double dPhi2 = 1 / ke.surE->getVol() * ke.volE->computeGradient(phi, 0).squaredNorm(); // Build Eigen::VectorXd b = Eigen::VectorXd::Zero(nRow); @@ -80,7 +109,7 @@ Eigen::VectorXd KuttaResidual::build(KuttaElement const &ke, std::vector<double> Eigen::VectorXd const &sf = sCache.getSf(k); Eigen::VectorXd sfp(nRow); for (size_t i = 0; i < nRow; ++i) - sfp(i) = sf(ke.teN[i].first); + sfp(i) = sf(ke.teN[i].first) + dSfp(i); // wake contribution b += ke.sign * sfp * dPhi2 * sGauss.getW(k) * ke.surE->getDetJ(k); } @@ -90,7 +119,8 @@ Eigen::VectorXd KuttaResidual::build(KuttaElement const &ke, std::vector<double> /** * @brief Build the gradient of the residual vector with respect to the flow variable (jacobian), on one Kutta element * - * A = \int psi * 2*(grad_phi_u)*dgrad_phi_u dS + * A = 1/S * \int (psi + grad_psi*v_inf) * 2*(grad_phi_u)*dgrad_phi_u dS + * NB: v_inf = [1, 0, 0] */ Eigen::MatrixXd KuttaResidual::buildGradientFlow(KuttaElement const &ke, std::vector<double> const &phi) { @@ -101,27 +131,68 @@ Eigen::MatrixXd KuttaResidual::buildGradientFlow(KuttaElement const &ke, std::ve /** * @brief Build the gradient of the residual vector with respect to the nodes, on one Kutta element - * - * A = d( \int psi * (grad_phi)^2 dS ) - * = \int psi * d(grad_phi)^2 dS - * + \int psi * (grad_phi)^2 ddS + * + * A = d( 1/S * \int (psi + grad_psi*v_inf) * (grad_phi)^2 dS ) + * = d1/S * \int (psi + grad_psi*v_inf) * (grad_phi)^2 dS + * + 1/S * \int dgrad_psi*v_inf * (grad_phi)^2 dS + * + 1/S * \int (psi + grad_psi*v_inf) * d(grad_phi)^2 dS + * + 1/S * \int (psi + grad_psi*v_inf) * (grad_phi)^2 ddS + * NB: v_inf = [1, 0, 0] */ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> KuttaResidual::buildGradientMesh(KuttaElement const &ke, std::vector<double> const &phi) { // Get shape functions and Gauss points Cache &surCache = ke.surE->getVCache(); Gauss &surGauss = surCache.getVGauss(); + Eigen::MatrixXd const &dSfV = ke.volE->getVCache().getDsf(0); // Get Jacobian Eigen::MatrixXd const &iJ = ke.volE->getJinv(0); std::vector<Eigen::MatrixXd> const &dJ = ke.volE->getGradJ(0); + // Get surface and gradient + double surf = ke.surE->getVol(); + std::vector<double> const &dSurf = ke.surE->getGradVol(); // Get size size_t nRow = ke.nRow; size_t nDim = ke.nDim; size_t nCol = ke.nCol; size_t nSur = ke.surE->nodes.size(); - // velocity + // Stabilization (disabled in 2D) + Eigen::VectorXd gradSfp = Eigen::VectorXd::Zero(nRow); + std::vector<Eigen::VectorXd> dGradSfV(nDim * nCol, Eigen::VectorXd::Zero(nRow)); + std::vector<Eigen::VectorXd> dGradSfS(nDim * nSur, Eigen::VectorXd::Zero(nRow)); + if (nDim == 3) + { + // term + Eigen::VectorXd vi = Eigen::Vector3d(1, 0, 0).middleRows(0, nDim); + double sqSurf = sqrt(surf); + Eigen::MatrixXd dSf(nRow, nDim); + for (size_t i = 0; i < nRow; ++i) + for (size_t m = 0; m < nDim; ++m) + dSf(i, m) = dSfV(m, ke.vsMap.at(ke.teN[i].first)); + gradSfp = 0.5 * sqSurf * dSf * iJ.transpose() * vi; + // volume gradient + for (size_t i = 0; i < nCol; ++i) + { + for (size_t m = 0; m < nDim; ++m) + { + size_t idx = i * nDim + m; + dGradSfV[idx] = 0.5 * sqSurf * dSf * (-iJ * dJ[idx] * iJ).transpose() * vi; // S * dgrad_psi + } + } + // surface gradient + for (size_t i = 0; i < nSur; ++i) + { + for (size_t m = 0; m < nDim; ++m) + { + size_t idx = i * nDim + m; + dGradSfS[idx] = 0.5 * 0.5 / sqSurf * dSurf[idx] * dSf * iJ.transpose() * vi; // dS * grad_psi + } + } + } + // Velocity and normalization Eigen::VectorXd dPhi = ke.volE->computeGradient(phi, 0); + double nrm = 1 / surf; // Build Eigen::MatrixXd Av = Eigen::MatrixXd::Zero(nRow, nDim * nCol); @@ -136,7 +207,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> KuttaResidual::buildGradientMesh(Ku Eigen::VectorXd const &sf = surCache.getSf(k); Eigen::VectorXd sfp(nRow); for (size_t i = 0; i < nRow; ++i) - sfp(i) = sf(ke.teN[i].first); + sfp(i) = sf(ke.teN[i].first) + gradSfp(i); // Volume for (size_t i = 0; i < nCol; ++i) @@ -145,7 +216,9 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> KuttaResidual::buildGradientMesh(Ku { size_t idx = i * nDim + m; // gradient of velocity jump - Av.col(idx) += ke.sign * w * sfp * 2 * dPhi.transpose() * (-iJ * dJ[idx] * dPhi) * detJ; // psi * dgrad_phi^2 + Av.col(idx) += ke.sign * nrm * w * sfp * 2 * dPhi.transpose() * (-iJ * dJ[idx] * dPhi) * detJ; // 1/S * (psi + grad_psi) * dgrad_phi^2 * detJ + // gradient of stabilization term (volume) + Av.col(idx) += ke.sign * nrm * w * dGradSfV[idx] * dPhi.dot(dPhi) * detJ; // 1/S * dgrad_psi * grad_phi^2 * detJ } } // Surface @@ -154,8 +227,12 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> KuttaResidual::buildGradientMesh(Ku for (size_t m = 0; m < nDim; ++m) { size_t idx = i * nDim + m; + // gradient of normalization + As.col(idx) -= ke.sign * nrm * nrm * dSurf[idx] * w * sfp * dPhi.dot(dPhi) * detJ; // d1/S * (psi + grad_psi) * grad_phi^2 * detJ + // gradient of stabilization term (surface) + As.col(idx) += ke.sign * nrm * w * dGradSfS[idx] * dPhi.dot(dPhi) * detJ; // 1/S * dgrad_psi * grad_phi^2 * detJ // gradient of jacobian determinant - As.col(idx) += ke.sign * w * sfp * dPhi.dot(dPhi) * dDetJ[idx]; // psi * grad_phi^2 * ddetJ + As.col(idx) += ke.sign * nrm * w * sfp * dPhi.dot(dPhi) * dDetJ[idx]; // 1/S * (psi + grad_psi) * grad_phi^2 * ddetJ } } } diff --git a/dart/src/wNewton.cpp b/dart/src/wNewton.cpp index 993095bb097df8f7d136967d86bb3a910f431902..23ab5bf6689496c0918338882c5fb92d497ea847 100644 --- a/dart/src/wNewton.cpp +++ b/dart/src/wNewton.cpp @@ -41,6 +41,7 @@ #include <tbb/global_control.h> #include <tbb/parallel_for_each.h> #include <tbb/spin_mutex.h> +#include <tbb/combinable.h> #include <iomanip> #include <deque> @@ -81,7 +82,7 @@ Newton::Newton(std::shared_ptr<Problem> _pbl, std::shared_ptr<tbox::LinearSolver * * Solve the steady transonic Full Potential Equation */ -bool Newton::run() +STATUS Newton::run() { // Multithread tbb::global_control control(tbb::global_control::max_allowed_parallelism, nthreads); @@ -243,15 +244,12 @@ bool Newton::run() // Check the solution if (relRes < relTol || absRes < absTol) { - if (printOn) - { - std::cout << ANSI_COLOR_GREEN << "Newton solver converged!" << ANSI_COLOR_RESET << std::endl; - if (verbose > 1) - std::cout << "Newton solver CPU" << std::endl - << tms; - std::cout << std::endl; - } - return true; + if (printOn) {std::cout << ANSI_COLOR_GREEN << "Newton solver converged!" << ANSI_COLOR_RESET << std::endl;} + if (verbose > 1) + std::cout << "Newton solver CPU" << std::endl + << tms; + std::cout << std::endl; + return STATUS::CONVERGED; } else if (std::isnan(relRes)) { @@ -260,16 +258,16 @@ bool Newton::run() std::cout << "Newton solver CPU" << std::endl << tms; std::cout << std::endl; - return false; + return STATUS::FAILED; } else { - std::cout << ANSI_COLOR_YELLOW << "Newton solver not fully converged!" << ANSI_COLOR_RESET << std::endl; + if (printOn) {std::cout << ANSI_COLOR_YELLOW << "Newton solver not fully converged!" << ANSI_COLOR_RESET << std::endl;} if (verbose > 1) std::cout << "Newton solver CPU" << std::endl << tms; std::cout << std::endl; - return true; + return STATUS::MAXIT; } } @@ -280,11 +278,8 @@ bool Newton::run() */ void Newton::buildJac(Eigen::SparseMatrix<double, Eigen::RowMajor> &J) { - // Multithread - tbb::spin_mutex mutex; - - // List of triplets to build Jacobian matrix - std::deque<Eigen::Triplet<double>> T; + // List of (thead-safe) triplets to build Jacobian matrix + tbb::combinable<std::deque<Eigen::Triplet<double>>> cmbT; // Full Potential Equation with upwind bias: analytical derivatives tms["0-Jbase"].start(); @@ -299,14 +294,14 @@ void Newton::buildJac(Eigen::SparseMatrix<double, Eigen::RowMajor> &J) std::tie(Ae1, Ae2) = PotentialResidual::buildGradientFlow(*e, *eU, phi, *fluid, muCv, mCOv); // Assembly (subsonic) - tbb::spin_mutex::scoped_lock lock(mutex); + std::deque<Eigen::Triplet<double>> &locT = cmbT.local(); for (size_t ii = 0; ii < e->nodes.size(); ++ii) { Node *nodi = e->nodes[ii]; for (size_t jj = 0; jj < e->nodes.size(); ++jj) { Node *nodj = e->nodes[jj]; - T.push_back(Eigen::Triplet<double>(rows[nodi->row], nodj->row, Ae1(ii, jj))); + locT.push_back(Eigen::Triplet<double>(rows[nodi->row], nodj->row, Ae1(ii, jj))); } } // Assembly (supersonic) @@ -319,7 +314,7 @@ void Newton::buildJac(Eigen::SparseMatrix<double, Eigen::RowMajor> &J) for (size_t jj = 0; jj < eU->nodes.size(); ++jj) { Node *nodj = eU->nodes[jj]; - T.push_back(Eigen::Triplet<double>(rows[nodi->row], nodj->row, Ae2(ii, jj))); + locT.push_back(Eigen::Triplet<double>(rows[nodi->row], nodj->row, Ae2(ii, jj))); } } } @@ -337,19 +332,19 @@ void Newton::buildJac(Eigen::SparseMatrix<double, Eigen::RowMajor> &J) Eigen::MatrixXd Aue, Ale; std::tie(Aue, Ale) = WakeResidual::buildGradientFlow(*we, phi); // Assembly - tbb::spin_mutex::scoped_lock lock(mutex); + std::deque<Eigen::Triplet<double>> &locT = cmbT.local(); for (size_t ii = 0; ii < we->nRow; ++ii) { Node *nodi = we->wkN[ii].second; for (size_t jj = 0; jj < we->nColUp; ++jj) { Node *nodj = we->volUpE->nodes[jj]; - T.push_back(Eigen::Triplet<double>(nodi->row, nodj->row, Aue(ii, jj))); + locT.push_back(Eigen::Triplet<double>(nodi->row, nodj->row, Aue(ii, jj))); } for (size_t jj = 0; jj < we->nColLw; ++jj) { Node *nodj = we->volLwE->nodes[jj]; - T.push_back(Eigen::Triplet<double>(nodi->row, nodj->row, -Ale(ii, jj))); + locT.push_back(Eigen::Triplet<double>(nodi->row, nodj->row, -Ale(ii, jj))); } } }); @@ -363,14 +358,14 @@ void Newton::buildJac(Eigen::SparseMatrix<double, Eigen::RowMajor> &J) // Build K Eigen::MatrixXd Ae = KuttaResidual::buildGradientFlow(*ke, phi); // Assembly - tbb::spin_mutex::scoped_lock lock(mutex); + std::deque<Eigen::Triplet<double>> &locT = cmbT.local(); for (size_t ii = 0; ii < ke->nRow; ++ii) { Node *nodi = ke->teN[ii].second; for (size_t jj = 0; jj < ke->nCol; ++jj) { Node *nodj = ke->volE->nodes[jj]; - T.push_back(Eigen::Triplet<double>(nodi->row, nodj->row, Ae(ii, jj))); + locT.push_back(Eigen::Triplet<double>(nodi->row, nodj->row, Ae(ii, jj))); } } }); @@ -378,6 +373,10 @@ void Newton::buildJac(Eigen::SparseMatrix<double, Eigen::RowMajor> &J) tms["1-Jkutta"].stop(); // Build Jacobian matrix without BCs + std::deque<Eigen::Triplet<double>> T = cmbT.combine([&](std::deque<Eigen::Triplet<double>> x, std::deque<Eigen::Triplet<double>> const &y) { + x.insert(x.begin(), y.begin(), y.end()); + return x; + }); J.setFromTriplets(T.begin(), T.end()); // Apply Dirichlet BCs diff --git a/dart/src/wNewton.h b/dart/src/wNewton.h index 3b6f403b067810009b57ede374a1eb37aa01253b..b729e28272aa474fe9fd8f639e966b0470cd3004 100644 --- a/dart/src/wNewton.h +++ b/dart/src/wNewton.h @@ -51,7 +51,7 @@ private: public: Newton(std::shared_ptr<Problem> _pbl, std::shared_ptr<tbox::LinearSolver> _linsol, double rTol = 1e-6, double aTol = 1e-8, int mIt = 25, int nthrds = 1, int vrb = 1); - virtual bool run() override; + virtual STATUS run() override; #ifndef SWIG virtual void write(std::ostream &out) const override; diff --git a/dart/src/wPicard.cpp b/dart/src/wPicard.cpp index ea218f7d4c02d3dd4e14c3816776fef51755279b..5d567514923b835699a796af894a5b5b32ace767 100644 --- a/dart/src/wPicard.cpp +++ b/dart/src/wPicard.cpp @@ -75,7 +75,7 @@ Picard::Picard(std::shared_ptr<Problem> _pbl, std::shared_ptr<tbox::LinearSolver * * Solve the steady subsonic Full Potential Equation */ -bool Picard::run() +STATUS Picard::run() { // Multithread tbb::global_control control(tbb::global_control::max_allowed_parallelism, nthreads); @@ -173,7 +173,7 @@ bool Picard::run() std::cout << "Picard solver CPU" << std::endl << tms; std::cout << std::endl; - return true; + return STATUS::CONVERGED; } else if (std::isnan(relRes)) { @@ -182,7 +182,7 @@ bool Picard::run() std::cout << "Picard solver CPU" << std::endl << tms; std::cout << std::endl; - return false; + return STATUS::FAILED; } else { @@ -191,7 +191,7 @@ bool Picard::run() std::cout << "Picard solver CPU" << std::endl << tms; std::cout << std::endl; - return true; + return STATUS::MAXIT; } } diff --git a/dart/src/wPicard.h b/dart/src/wPicard.h index 42a4580529f1822b6df2cd16a8719cb2c0d7cc97..0a8a27d10a6b539d07d6066027e33b1a203483a6 100644 --- a/dart/src/wPicard.h +++ b/dart/src/wPicard.h @@ -40,7 +40,7 @@ public: public: Picard(std::shared_ptr<Problem> _pbl, std::shared_ptr<tbox::LinearSolver> _linsol, double rTol = 1e-6, double aTol = 1e-8, int mIt = 25, int nthrds = 1, int vrb = 1); - virtual bool run() override; + virtual STATUS run() override; #ifndef SWIG virtual void write(std::ostream &out) const override; diff --git a/dart/src/wProblem.cpp b/dart/src/wProblem.cpp index 164dd47af954f2690e156752fafb42e106675406..2337085deb068e6730ff6fa03d888defb12acd33 100644 --- a/dart/src/wProblem.cpp +++ b/dart/src/wProblem.cpp @@ -194,63 +194,42 @@ void Problem::check() const // Sanity checks if (fluid == NULL) throw std::runtime_error("No Fluid provided!\n"); + if (bodies.empty()) + throw std::runtime_error("No Body provided!\n"); if (iIC == NULL) throw std::runtime_error("No Initial Condition provided!\n"); if (fBCs.empty()) throw std::runtime_error("No Freestream B.C. provided!\n"); if (wBCs.empty()) throw std::runtime_error("No Wake B.C. provided!\n"); + if (kSCs.empty()) + throw std::runtime_error("No Kutta condition provided!\n"); // Three-dimension problem if (nDim == 3) { // Volume element type for (auto e : fluid->tag->elems) - { if (e->type() != ELTYPE::TETRA4) - { - std::stringstream err; - err << "3D solver is only implemented for volume elements of type " - << ELTYPE::TETRA4 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } - } + throwUnsupElType(e, "3", "volume", ELTYPE::TETRA4); + // Surface element type (Body) + for (auto surf : bodies) + for (auto e : surf->groups[0]->tag->elems) + if (e->type() != ELTYPE::TRI3) + throwUnsupElType(e, "3", "surface", ELTYPE::TRI3); // Surface element type (Freestream B.C.) for (auto surf : fBCs) - { for (auto e : surf->tag->elems) - { if (e->type() != ELTYPE::TRI3) - { - std::stringstream err; - err << "3D solver is only implemented for surface elements of type " - << ELTYPE::TRI3 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } - } - } + throwUnsupElType(e, "3", "surface", ELTYPE::TRI3); // Surface element type (Wake B.C.) for (auto surf : wBCs) { for (auto e : surf->groups[0]->tag->elems) - { if (e->type() != ELTYPE::TRI3) - { - std::stringstream err; - err << "3D solver is only implemented for surface elements of type " - << ELTYPE::TRI3 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } - } + throwUnsupElType(e, "3", "surface", ELTYPE::TRI3); for (auto e : surf->groups[1]->tag->elems) - { if (e->type() != ELTYPE::TRI3) - { - std::stringstream err; - err << "3D solver is only implemented for surface elements of type " - << ELTYPE::TRI3 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } - } + throwUnsupElType(e, "3", "surface", ELTYPE::TRI3); } // Blowing B.C. /*if (!bBCs.empty()) @@ -261,52 +240,27 @@ void Problem::check() const { // Volume element type for (auto e : fluid->tag->elems) - { if (e->type() != ELTYPE::TRI3) - { - std::stringstream err; - err << "2D solver is only implemented for volume elements of type " - << ELTYPE::TRI3 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } - } + throwUnsupElType(e, "2", "volume", ELTYPE::TRI3); + // Surface element type (Body) + for (auto surf : bodies) + for (auto e : surf->groups[0]->tag->elems) + if (e->type() != ELTYPE::LINE2) + throwUnsupElType(e, "2", "surface", ELTYPE::LINE2); // Surface element type (Freestream B.C.) for (auto surf : fBCs) - { for (auto e : surf->tag->elems) - { if (e->type() != ELTYPE::LINE2) - { - std::stringstream err; - err << "2D solver is only implemented for surface elements of type " - << ELTYPE::LINE2 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } - } - } + throwUnsupElType(e, "2", "surface", ELTYPE::LINE2); // Surface element type (Wake B.C.) for (auto surf : wBCs) { for (auto e : surf->groups[0]->tag->elems) - { if (e->type() != ELTYPE::LINE2) - { - std::stringstream err; - err << "2D solver is only implemented for surface elements of type " - << ELTYPE::LINE2 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } - } + throwUnsupElType(e, "2", "surface", ELTYPE::LINE2); for (auto e : surf->groups[1]->tag->elems) - { if (e->type() != ELTYPE::LINE2) - { - std::stringstream err; - err << "2D solver is only implemented for surface elements of type " - << ELTYPE::LINE2 << " (" << e->type() << " was given)!\n"; - throw std::runtime_error(err.str()); - } - } + throwUnsupElType(e, "2", "surface", ELTYPE::LINE2); } } else @@ -318,6 +272,15 @@ void Problem::check() const } } +void Problem::throwUnsupElType(Element const *e, std::string const &pdim, std::string const &edim, ELTYPE type) const +{ + std::stringstream err; + err << pdim << "D solver is only implemented for " + << edim << " elements of type " << type + << " (" << e->type() << " was given)!\n"; + throw std::runtime_error(err.str()); +} + void Problem::write(std::ostream &out) const { out << "dart::Problem parameters" diff --git a/dart/src/wProblem.h b/dart/src/wProblem.h index 3ba02003b099911f8da965d56dd85c4401f50e17..d59911e6863d6db28eafc223371731f2095517b5 100644 --- a/dart/src/wProblem.h +++ b/dart/src/wProblem.h @@ -19,6 +19,7 @@ #include "dart.h" #include "wObject.h" +#include "wElement.h" #include "wF1Ct.h" #include <memory> #include <iostream> @@ -87,6 +88,9 @@ public: void initGradElems(); virtual void write(std::ostream &out) const override; #endif + +private: + void throwUnsupElType(tbox::Element const *e, std::string const &pdim, std::string const &edim, tbox::ELTYPE type) const; }; } // namespace dart diff --git a/dart/src/wSolver.cpp b/dart/src/wSolver.cpp index 7f69f841eb1f6c7357f6c3ef3a2c0f2be733ec97..68d2b6119cc09b811844dcab4e8a681db8149d2f 100644 --- a/dart/src/wSolver.cpp +++ b/dart/src/wSolver.cpp @@ -21,6 +21,7 @@ #include "wAssign.h" #include "wBody.h" #include "wWake.h" +#include "wKutta.h" #include "wLoadFunctional.h" #include "wMshData.h" @@ -63,9 +64,9 @@ Solver::Solver(std::shared_ptr<Problem> _pbl, << "** _ /_/ /_ ___ | __ _/_ / **\n" << "** /_____/ /_/ |_/_/ |_| /_/ **\n" << "*******************************************************************************\n" - << "** Hi! My name is DART v1.1.0-21.09 **\n" + << "** Hi! My name is DART v1.2.0-22.04 **\n" << "** Adrien Crovato **\n" - << "** ULiege 2018-2021 **\n" + << "** ULiege 2018-2022 **\n" << "*******************************************************************************\n" << std::endl; @@ -110,6 +111,8 @@ Solver::Solver(std::shared_ptr<Problem> _pbl, std::cout << "Dirichlet on " << *bnd->tag << "\n"; for (auto bnd : pbl->wBCs) std::cout << "Wake on " << *bnd->groups[0]->tag << "\n"; + for (auto bnd : pbl->kSCs) + std::cout << "Kutta on " << *bnd->groups[0]->tag << "\n"; for (auto bnd : pbl->bodies) std::cout << "Body on " << *bnd->groups[0]->tag << "\n"; std::cout << "--- Freestream conditions ---\n" @@ -150,7 +153,7 @@ void Solver::reset() /** * @brief Dummy run */ -bool Solver::run() +STATUS Solver::run() { throw std::runtime_error("dart::Solver::run not implemented!\n"); } diff --git a/dart/src/wSolver.h b/dart/src/wSolver.h index d48fc3a7369c6d56293665e730ec0504abd6b4f7..aab40ad17beb65aaee05537c73ab5bad693dc710 100644 --- a/dart/src/wSolver.h +++ b/dart/src/wSolver.h @@ -29,6 +29,16 @@ namespace dart { +/** + * @brief Exit code of DART solver + */ +enum class STATUS +{ + CONVERGED = 0, // fully converged to prescribed (relative or absolute) tolerance + MAXIT = 1, // not fully converged (max. number of iterations exceeded) + FAILED = 2 // NaN in the solution vector +}; + /** * @brief Base class for full potential solvers * @authors Adrien Crovato @@ -67,7 +77,7 @@ public: virtual ~Solver(); void reset(); - virtual bool run(); + virtual STATUS run(); void save(tbox::MshExport *mshWriter, int n = 0); protected: diff --git a/dart/src/wTimeSolver.cpp b/dart/src/wTimeSolver.cpp index 42870daaa5e9435325f9206bc66279198135eb3c..1c3534fdc035ef86d44e99603e496ca0147e2c83 100644 --- a/dart/src/wTimeSolver.cpp +++ b/dart/src/wTimeSolver.cpp @@ -124,10 +124,7 @@ int TimeSolver::Integration(size_t iPoint, BLRegion *bl) } bl->U[iPoint * nVar + 0] = std::max(bl->U[iPoint * nVar + 0], 1e-6); bl->U[iPoint * nVar + 1] = std::max(bl->U[iPoint * nVar + 1], 1.0005); - if (std::isnan(bl->U[iPoint * nVar + 1])) - { - std::cout << iPoint << " nan at it " << innerIters << std::endl; - } + SysRes = SysMatrix->ComputeFluxes(iPoint, bl); normSysRes = (SysRes + slnIncr / timeStep).norm(); @@ -140,8 +137,6 @@ int TimeSolver::Integration(size_t iPoint, BLRegion *bl) IMatrix = MatrixXd::Identity(5,5) / timeStep; normSysRes = (SysRes + slnIncr / timeStep).norm(); itFrozenJac = 1; - std::cout << "normSysRes is nan " << std::endl; - //throw; } if (normSysRes <= tol * normSysRes0) diff --git a/dart/src/wViscFluxes.cpp b/dart/src/wViscFluxes.cpp index 34334a53c3a14ce279693cac4255142bdf2e6867..9ffd72a4a86d718f82f310c971bc0ab192a9dce4 100644 --- a/dart/src/wViscFluxes.cpp +++ b/dart/src/wViscFluxes.cpp @@ -230,7 +230,7 @@ VectorXd ViscFluxes::BLlaws(size_t iPoint, BLRegion *bl, std::vector<double> u) timeMatrix(4, 4) = 1.0; } - Vector<double, 5> result = timeMatrix.partialPivLu().solve(spaceVector); + /*Vector<double, 5> result = timeMatrix.partialPivLu().solve(spaceVector); if (std::isnan(result.norm())) { std::cout << "Point " << iPoint << " det " << timeMatrix.determinant() << std::endl; @@ -239,7 +239,7 @@ VectorXd ViscFluxes::BLlaws(size_t iPoint, BLRegion *bl, std::vector<double> u) std::cout << dT_dx << " " << (2 + u[1] - Mea * Mea) * (u[0] / u[3]) * due_dx << " " << " cf " << - Cfa / 2 << std::endl; std::cout << " u[0] " << u[0] << " u[1] " << u[1] << " u[2] " << u[2] << " u[3] " << u[3] << " u[4] " << u[4] << " Usa " << Usa << std::endl; throw; - } + }*/ return timeMatrix.partialPivLu().solve(spaceVector); } diff --git a/dart/src/wViscSolver.cpp b/dart/src/wViscSolver.cpp index 6e06caa149238cbce6692e940a6c0e7fff26c7b9..65cbe38b7b5a31693ccb5892f40c940b6dbba836 100644 --- a/dart/src/wViscSolver.cpp +++ b/dart/src/wViscSolver.cpp @@ -35,16 +35,16 @@ ViscSolver::ViscSolver(double _Re, double _Minf, double _CFL0, unsigned int nSec /* Freestream parameters */ - Re = _Re; /* Freestream Reynolds number */ - + Re = _Re; CFL0 = _CFL0; - Cdt = 0.; - Cdf = 0.; - Cdp = 0.; - solverExitCode = 0; + Cdt = 0.; Cdf = 0.; Cdp = 0.; + + verbose = 1; + /* Initialzing boundary layer */ + Sections.resize(nSections); for (size_t iSec=0; iSec < nSections; ++iSec) { @@ -58,6 +58,9 @@ ViscSolver::ViscSolver(double _Re, double _Minf, double _CFL0, unsigned int nSec Sections[iSec][2]->name = "wake"; } + /* Pre/post processing flags */ + + solverExitCode = 0; stagPtMvmt.resize(Sections.size(), false); /* Temporal solver initialization */ @@ -90,8 +93,6 @@ ViscSolver::~ViscSolver() } delete tSolver; - //PrintBanner(); - std::cout << "~ViscSolver()\n"; } // end ~ViscSolver @@ -103,24 +104,27 @@ int ViscSolver::Run(unsigned int couplIter) { bool lockTrans=false; int pointExitCode = 0; + solverExitCode = 0; for (size_t iSec=0; iSec<Sections.size(); ++iSec) { - //std::cout << "\n - Sec " << iSec << " stagPtMvmt " << stagPtMvmt[iSec] << Sections[iSec][0]->mesh->GetDiffnElm(); + + if (verbose>0){std::cout << "Sec " << iSec << " ";} + if (verbose>1){std::cout << "Mmax " << std::max(Sections[iSec][0]->invBnd->GetMaxMach(), Sections[iSec][1]->invBnd->GetMaxMach());} /* Check for stagnation point movement */ if (couplIter != 0 && (Sections[iSec][0]->mesh->GetDiffnElm())) { stagPtMvmt[iSec] = true; - if (printOn){std::cout << "Stagnation point moved by " << Sections[iSec][0]->mesh->GetDiffnElm() << " elements." << std::endl;} + if (verbose>1){std::cout << "Stagnation point moved by " << Sections[iSec][0]->mesh->GetDiffnElm() << " elements." << std::endl;} } else { stagPtMvmt[iSec] = false; } - /* Set boundary condition */ + /* Set boundary conditions */ Sections[iSec][0]->xtr = 1.; /* Upper side initial xtr */ Sections[iSec][1]->xtr = 1.; /* Lower side initial xtr */ @@ -129,25 +133,15 @@ int ViscSolver::Run(unsigned int couplIter) Sections[iSec][0]->SetStagBC(Re); Sections[iSec][1]->SetStagBC(Re); - - bool reset = false; - if (solverExitCode != 0) - { - reset = true; - } - solverExitCode = 0; - - - /* Loop over the regions */ + /* Loop over the regions (upper, lower and wake) */ for (size_t iRegion = 0; iRegion < Sections[iSec].size(); ++iRegion) { - /* Output region name */ - if (printOn){std::cout << Sections[iSec][iRegion]->name << " ";} + if (verbose>0){std::cout << Sections[iSec][iRegion]->name << " ";} /* Check if we need to enter safe mode */ - if (couplIter == 0 || Sections[iSec][iRegion]->mesh->GetDiffnElm() != 0 || stagPtMvmt[iSec] == true || reset) + if (couplIter == 0 || Sections[iSec][iRegion]->mesh->GetDiffnElm() != 0 || stagPtMvmt[iSec] == true || solverExitCode != 0) { tSolver->SetCFL0(1); tSolver->SetitFrozenJac(1); @@ -173,7 +167,7 @@ int ViscSolver::Run(unsigned int couplIter) Sections[iSec][iRegion]->invBnd->SetVtOld(ueOld); } - if (printOn){std::cout << "restart. ";} + if (verbose>1){std::cout << "restart. ";} } else @@ -181,6 +175,8 @@ int ViscSolver::Run(unsigned int couplIter) tSolver->SetCFL0(CFL0); tSolver->SetitFrozenJac(5); tSolver->SetinitSln(false); + + if (verbose>1){std::cout << "update. ";} } /* Save number of points in each regions */ @@ -190,14 +186,14 @@ int ViscSolver::Run(unsigned int couplIter) /* Reset regime */ lockTrans = false; - if (iRegion < 2) + if (iRegion < 2) // Airfoil { for (size_t k = 0; k < Sections[iSec][iRegion]->mesh->GetnMarkers(); k++) { Sections[iSec][iRegion]->Regime[k] = 0; } } - else + else // Wake { for (size_t k = 0; k < Sections[iSec][iRegion]->mesh->GetnMarkers(); k++) { @@ -214,6 +210,7 @@ int ViscSolver::Run(unsigned int couplIter) } Sections[iSec][iRegion]->SetWakeBC(Re, UpperCond, LowerCond); lockTrans = true; + if (verbose>2){std::cout << "Wake BC imposed." <<std::endl;} } /* Loop over points */ @@ -223,51 +220,60 @@ int ViscSolver::Run(unsigned int couplIter) /* Initialize solution at point */ tSolver->InitialCondition(iPoint, Sections[iSec][iRegion]); - + pointExitCode = tSolver->Integration(iPoint, Sections[iSec][iRegion]); + //Sections[iSec][iRegion]->U[iPoint * Sections[iSec][iRegion]->GetnVar() + 2] = 10.0; + /* Unsucessfull convergence output */ if (pointExitCode != 0) { - if (printOn){std::cout << "Point " << iPoint << ": Convergence terminated with exitcode " << pointExitCode << std::endl;} + if (verbose>1){std::cout << "Point " << iPoint << ": Convergence terminated with exitcode " << pointExitCode << std::endl;} solverExitCode = -1; // Convergence failed - //std::cout << " NC " << iPoint << " "; - + } + else + { + if (verbose>2){std::cout << "Point " << iPoint << ": Successful convergence.\n";} } /* Transition */ if (!lockTrans) { + /* Check if perturbation waves are growing or not. */ + CheckWaves(iPoint, Sections[iSec][iRegion]); - // Free transition. + /* Amplification factor is compared to critical amplification factor. */ + if (Sections[iSec][iRegion]->U[iPoint * Sections[iSec][iRegion]->GetnVar() + 2] >= Sections[iSec][iRegion]->GetnCrit()) { AverageTransition(iPoint, Sections[iSec][iRegion], 0); - if (printOn) + if (verbose>0) { std::cout << std::fixed; std::cout << std::setprecision(2); std::cout << Sections[iSec][iRegion]->xtr << " (" << Sections[iSec][iRegion]->transMarker << ") "; } + if (verbose>2){std::cout << "" << std::endl;} lockTrans = true; } // End if } // End if (!lockTrans). } // End for iPoints + Sections[iSec][iRegion]->ComputeBlwVel(); + if (verbose>2){"Blowing velocities of " + Sections[iSec][iRegion]->name + " side computed.";} + } // End for iRegion } // End for iSections ComputeDrag(Sections[0]); - if (solverExitCode != 0) - { - std::cout << "some points did not converge. "; - } - if (printOn){std::cout << "\n" << std::endl;} + + if (solverExitCode != 0 && verbose>1){std::cout << "some points did not converge. ";} + if (verbose>0){std::cout << "\n" << std::endl;} return solverExitCode; // exit code } @@ -336,10 +342,11 @@ void ViscSolver::AverageTransition(size_t iPoint, BLRegion *bl, int forced) /* Solve point in turbulent configuration */ int exitCode = tSolver->Integration(iPoint, bl); - if (exitCode != 0) + if (exitCode != 0 && verbose>1) { std::cout << "Warning: Transition point turbulent computation terminated with exit code " << exitCode << std::endl; } + else if(verbose>2){std::cout << "Sucessfull transition point turbulent computation.";} /* Average both solutions (Now solution @ iPoint is the turbulent solution) */ bl->U[iPoint * nVar + 0] = avLam * lamSol[0] + avTurb * bl->U[(iPoint)*nVar + 0]; /* Theta */ @@ -422,7 +429,9 @@ void ViscSolver::ComputeDrag(std::vector<BLRegion *> const &bl) void ViscSolver::SetGlobMesh(size_t iSec, size_t iRegion, std::vector<double> _x, std::vector<double> _y, std::vector<double> _z) { + if (verbose>1){std::cout << "Mesh of " << _x.size() << " elements on " << Sections[iSec][iRegion]->name << " side. ";} Sections[iSec][iRegion]->SetMesh(_x, _y, _z); + if (verbose>1){std::cout << "Mesh mapped to local frame of reference." << std::endl;} } void ViscSolver::SetVelocities(size_t iSec, size_t iRegion, std::vector<double> vx, std::vector<double> vy, std::vector<double> vz) @@ -530,6 +539,94 @@ void ViscSolver::SetUeOld(size_t iSec, size_t iRegion, std::vector<double> _ue) Sections[iSec][iRegion]->invBnd->SetVtOld(_ue); } +std::vector<std::vector<double>> ViscSolver::GetSolution(size_t iSec) +{ + size_t nMarkersUp = Sections[iSec][0]->mesh->GetnMarkers(); + size_t nMarkersLw = Sections[iSec][1]->mesh->GetnMarkers() - 1; /* No stagnation point doublon */ + unsigned int nVar = Sections[iSec][0]->GetnVar(); + + std::vector<std::vector<double>> Sln(16); + for (size_t iVector=0; iVector<Sln.size(); ++iVector) + { + Sln[iVector].resize(nMarkersUp + nMarkersLw + Sections[iSec][2]->mesh->GetnMarkers(), 0.); + } + /* Upper side */ + size_t revPoint = nMarkersUp - 1; + for (size_t iPoint=0; iPoint<nMarkersUp; ++iPoint) + { + Sln[0][iPoint] = Sections[iSec][0]->U[revPoint*nVar + 0]; + Sln[1][iPoint] = Sections[iSec][0]->U[revPoint*nVar + 1]; + Sln[2][iPoint] = Sections[iSec][0]->U[revPoint*nVar + 2]; + Sln[3][iPoint] = Sections[iSec][0]->U[revPoint*nVar + 3]; + Sln[4][iPoint] = Sections[iSec][0]->U[revPoint*nVar + 4]; + Sln[5][iPoint] = Sections[iSec][0]->DeltaStar[revPoint]; + + Sln[6][iPoint] = Sections[iSec][0]->Ret[revPoint]; + Sln[7][iPoint] = Sections[iSec][0]->Cd[revPoint]; + Sln[8][iPoint] = Sections[iSec][0]->Cf[revPoint]; + Sln[9][iPoint] = Sections[iSec][0]->Hstar[revPoint]; + Sln[10][iPoint] = Sections[iSec][0]->Hstar2[revPoint]; + Sln[11][iPoint] = Sections[iSec][0]->Hk[revPoint]; + Sln[12][iPoint] = Sections[iSec][0]->Cteq[revPoint]; + Sln[13][iPoint] = Sections[iSec][0]->Us[revPoint]; + Sln[14][iPoint] = Sections[iSec][0]->Delta[revPoint]; + + Sln[15][iPoint] = Sections[iSec][0]->mesh->Getx(revPoint); + --revPoint; + } + /* Lower side */ + for (size_t iPoint=0; iPoint<Sections[iSec][1]->mesh->GetnMarkers(); ++iPoint) + { + Sln[0][nMarkersUp + iPoint] = Sections[iSec][1]->U[iPoint*nVar + 0]; + Sln[1][nMarkersUp + iPoint] = Sections[iSec][1]->U[iPoint*nVar + 1]; + Sln[2][nMarkersUp + iPoint] = Sections[iSec][1]->U[iPoint*nVar + 2]; + Sln[3][nMarkersUp + iPoint] = Sections[iSec][1]->U[iPoint*nVar + 3]; + Sln[4][nMarkersUp + iPoint] = Sections[iSec][1]->U[iPoint*nVar + 4]; + Sln[5][nMarkersUp + iPoint] = Sections[iSec][1]->DeltaStar[iPoint]; + + Sln[6][nMarkersUp + iPoint] = Sections[iSec][1]->Ret[iPoint]; + Sln[7][nMarkersUp + iPoint] = Sections[iSec][1]->Cd[iPoint]; + Sln[8][nMarkersUp + iPoint] = Sections[iSec][1]->Cf[iPoint]; + Sln[9][nMarkersUp + iPoint] = Sections[iSec][1]->Hstar[iPoint]; + Sln[10][nMarkersUp + iPoint] = Sections[iSec][1]->Hstar2[iPoint]; + Sln[11][nMarkersUp + iPoint] = Sections[iSec][1]->Hk[iPoint]; + Sln[12][nMarkersUp + iPoint] = Sections[iSec][1]->Cteq[iPoint]; + Sln[13][nMarkersUp + iPoint] = Sections[iSec][1]->Us[iPoint]; + Sln[14][nMarkersUp + iPoint] = Sections[iSec][1]->Delta[iPoint]; + + Sln[15][nMarkersUp + iPoint] = Sections[iSec][1]->mesh->Getx(iPoint); + + } + /* Wake */ + for (size_t iPoint=0; iPoint<Sections[iSec][2]->mesh->GetnMarkers(); ++iPoint) + { + Sln[0][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->U[iPoint*nVar + 0]; + Sln[1][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->U[iPoint*nVar + 1]; + Sln[2][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->U[iPoint*nVar + 2]; + Sln[3][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->U[iPoint*nVar + 3]; + Sln[4][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->U[iPoint*nVar + 4]; + Sln[5][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->DeltaStar[iPoint]; + + Sln[6][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Ret[iPoint]; + Sln[7][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Cd[iPoint]; + Sln[8][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Cf[iPoint]; + Sln[9][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Hstar[iPoint]; + Sln[10][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Hstar2[iPoint]; + Sln[11][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Hk[iPoint]; + Sln[12][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Cteq[iPoint]; + Sln[13][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Us[iPoint]; + Sln[14][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->Delta[iPoint]; + + Sln[15][nMarkersUp + nMarkersLw + iPoint] = Sections[iSec][2]->mesh->Getx(iPoint); + + } + + if (verbose>2){std::cout << "Solution structure sent." << std::endl;} + + return Sln; + +} + void ViscSolver::PrintBanner() const { diff --git a/dart/src/wViscSolver.h b/dart/src/wViscSolver.h index 85f32929c33a485a0dd11774b7ac2ccb74ed9852..d56aabeb3a16738c062ca55a92d6d86a77e40979 100644 --- a/dart/src/wViscSolver.h +++ b/dart/src/wViscSolver.h @@ -12,11 +12,11 @@ public: double Cdt, Cdf, Cdp; - - bool printOn = true; std::vector<std::vector<BLRegion *>> Sections; + unsigned int verbose; + private: double Re, CFL0; @@ -52,6 +52,9 @@ public: double Getxtr(size_t iSec, size_t iRegion) const {return Sections[iSec][iRegion]->xtr;}; + std::vector<std::vector<double>> GetSolution(size_t iSec); + + private: void CheckWaves(size_t iPoint, BLRegion *bl); void AverageTransition(size_t iPoint, BLRegion *bl, int forced); diff --git a/dart/src/wWakeElement.h b/dart/src/wWakeElement.h index 0cf0a30cb76206fad57a05296069a4fa4ff18b2b..43ead69dca1bbbef7c1d4651addf02801baf0d72 100644 --- a/dart/src/wWakeElement.h +++ b/dart/src/wWakeElement.h @@ -30,8 +30,8 @@ namespace dart * @brief Super-element to apply wake boundary conditions * * Made up of two surface elements on the wake and the connected volume - * elements. Only Line2 (surface) and Tri3 (volume) elements are curently - * implemented. + * elements. Only Line2/Tri3 (surface) and Tri3/Tetra4 (volume) elements are + * currently implemented. * Since Tri3 or Tetra4 are used, the evalutaion of the volume integrals is * performed at dummy Gauss point #0. If volume elements with non-constant shape * function derivatives are used, those derivates should be recomputed at the diff --git a/dart/src/wWakeResidual.cpp b/dart/src/wWakeResidual.cpp index 671eb02674d119592d428eb2959ba23f74edd740..4af31768ca2f18c7370533247264bdba82f190e2 100644 --- a/dart/src/wWakeResidual.cpp +++ b/dart/src/wWakeResidual.cpp @@ -66,7 +66,7 @@ std::tuple<Eigen::MatrixXd, Eigen::MatrixXd> WakeResidual::buildFixed(WakeElemen Eigen::VectorXd const &sf = sCache.getSf(k); Eigen::VectorXd sfp(nRow); for (size_t i = 0; i < nRow; ++i) - sfp(i) = dSfp(i) + sf(we.wkN[i].first); + sfp(i) = sf(we.wkN[i].first) + dSfp(i); // wake contribution Au += sfp * Aup * sGauss.getW(k) * we.surUpE->getDetJ(k); Al += sfp * Alw * sGauss.getW(k) * we.surUpE->getDetJ(k); @@ -99,10 +99,8 @@ std::tuple<Eigen::VectorXd, Eigen::VectorXd> WakeResidual::build(WakeElement con Eigen::VectorXd dSfp(nRow); dSfp = 0.5 * sqrt(we.surUpE->getVol()) * dSf * we.volUpE->getJinv(0).transpose() * Eigen::Vector3d(1, 0, 0).middleRows(0, nDim); // Velocity squared - Eigen::VectorXd dPhiU = we.volUpE->computeGradient(phi, 0); - Eigen::VectorXd dPhiL = we.volLwE->computeGradient(phi, 0); - double dPhi2u = dPhiU.squaredNorm(); - double dPhi2l = dPhiL.squaredNorm(); + double dPhi2u = we.volUpE->computeGradient(phi, 0).squaredNorm(); + double dPhi2l = we.volLwE->computeGradient(phi, 0).squaredNorm(); // Build Eigen::VectorXd bu = Eigen::VectorXd::Zero(nRow); @@ -113,7 +111,7 @@ std::tuple<Eigen::VectorXd, Eigen::VectorXd> WakeResidual::build(WakeElement con Eigen::VectorXd const &sf = sCache.getSf(k); Eigen::VectorXd sfp(nRow); for (size_t i = 0; i < nRow; ++i) - sfp(i) = dSfp(i) + sf(we.wkN[i].first); + sfp(i) = sf(we.wkN[i].first) + dSfp(i); // wake contribution bu += sfp * dPhi2u * sGauss.getW(k) * we.surUpE->getDetJ(k); bl += sfp * dPhi2l * sGauss.getW(k) * we.surUpE->getDetJ(k); diff --git a/dart/tests/adjoint.py b/dart/tests/adjoint.py index 3d3932a85195fe4d8199e67ff40562b8f3ef51ef..5788fe27441057128a222cd330e4d421add55673 100644 --- a/dart/tests/adjoint.py +++ b/dart/tests/adjoint.py @@ -55,7 +55,7 @@ def main(): # set the problem and add fluid, initial/boundary conditions tms['pre'].start() - pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, c_ref, c_ref, 0.25, 0., 0., 'airfoil', te = 'te') + pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, c_ref, c_ref, 0.25, 0., 0., 'airfoil') tms['pre'].stop() # solve problem @@ -114,15 +114,15 @@ def main(): if M_inf == 0. and alpha == 0*np.pi/180: tests.add(CTest('dCl_dAoA', adjoint.dClAoa, 6.9, 1e-2)) tests.add(CTest('dCd_dAoA', adjoint.dCdAoa, 0.0, 1e-3)) - tests.add(CTest('dCl_dMsh', dClX, 55.439, 1e-3)) - tests.add(CTest('dCd_dMsh', dCdX, 0.482, 1e-3)) + tests.add(CTest('dCl_dMsh', dClX, 36.9, 1e-2)) + tests.add(CTest('dCd_dMsh', dCdX, 0.482, 1e-2)) tests.add(CTest('dCl_dAoA (msh)', dClAoA, 6.9, 1e-2)) tests.add(CTest('dCd_dAoA (msh)', dCdAoA, 0.0, 1e-3)) elif M_inf == 0.7 and alpha == 2*np.pi/180: tests.add(CTest('dCl_dAoA', adjoint.dClAoa, 11.8, 1e-2)) # FD 11.835 (step = 1e-5) tests.add(CTest('dCd_dAoA', adjoint.dCdAoa, 0.127, 1e-2)) # 0.12692 (step = 1e-5) - tests.add(CTest('dCl_dMsh', dClX, 82.67, 1e-3)) - tests.add(CTest('dCd_dMsh', dCdX, 0.908, 1e-3)) + tests.add(CTest('dCl_dMsh', dClX, 61.2, 1e-2)) + tests.add(CTest('dCd_dMsh', dCdX, 0.830, 1e-2)) tests.add(CTest('dCl_dAoA (msh)', dClAoA, 11.8, 1e-2)) tests.add(CTest('dCd_dAoA (msh)', dCdAoA, 0.127, 1e-2)) else: diff --git a/dart/tests/bli_lowLift.py b/dart/tests/bli_lowLift.py index 908c5edbaf285ac22b547e905cb69716e0a7a3ef..9272fcadb82e381fc7296cf0f49698ee9f1857de 100644 --- a/dart/tests/bli_lowLift.py +++ b/dart/tests/bli_lowLift.py @@ -39,8 +39,6 @@ import dart.default as floD #import dart.viscUtils as viscU import dart.pyVII.vCoupler as floVC -import dart.pyVII.vCoupler2 as viscC # Rbf coupler -import dart.pyVII.vInterpolator as Interpol # Rbf interpolator import numpy as np import tbox @@ -60,69 +58,74 @@ def main(): # define flow variables Re = 1e7 - alpha = 12*math.pi/180 - #alphaSeq = np.arange(-5, 5.5, 0.5) + alpha = 0*math.pi/180 M_inf = 0. - meshFactor = 1 CFL0 = 1 - plotVar = 'H' - nSections = 1 - rbf = 0 - + # ======================================================================================== 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.0001} - msh, gmshWriter = floD.mesh(dim, 'models/n0012.geo', pars, ['field', 'airfoil', 'downstream']) - tms['msh'].stop() + nRel = 5 - # 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() + nomDeVariableDePorc_x = [None for _ in range(nRel)] + nomDeVariableDePorc_var = [None for _ in range(nRel)] + nomDeVariableDePorc_Uin = [None for _ in range(nRel)] - # solve viscous problem + for i in range(nRel): + # mesh the geometry + print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET) + tms['msh'].start() - print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) - tms['solver'].start() - - isolver = floD.newton(pbl) - vsolver = floD.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} + pars = {'xLgt' : 5, 'yLgt' : 5, 'msF' : 1, 'msTe' : 0.01, 'msLe' : 0.01} + msh, gmshWriter = floD.mesh(dim, 'models/n0012.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 = floD.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} - if rbf: - iSolverAPI = Interpol.Interpolator(isolver, blw[0], blw[1], config) - coupler = viscC.Coupler(iSolverAPI, vsolver) - aeroCoeff = coupler.Run() - isolver.reset() - axs[0].plot(aeroCoeff[:,0], 'x-') - axs[1].plot(aeroCoeff[:,1], 'x-') - axs[0].set(xlabel='iters', ylabel='$c_l$') - axs[1].set(xlabel='iters', ylabel='$c_d$') - plt.show() - else: coupler = floVC.Coupler(isolver, vsolver) coupler.CreateProblem(blw[0], blw[1]) - fig, axs = plt.subplots(2) - for i in range(1): - aeroCoeff = coupler.Run() - isolver.reset() - axs[0].plot(aeroCoeff[:,0], 'x-') - axs[1].plot(aeroCoeff[:,1], 'x-') - axs[0].set(xlabel='iters', ylabel='$c_l$') - axs[1].set(xlabel='iters', ylabel='$c_d$') - plt.show() - #coupler.Run() - + #fig, axs = plt.subplots(2) + aeroCoeff = coupler.Run() + #isolver.reset() + + nomDeVariableDePorc_x[i] = coupler.sln[15].copy() + nomDeVariableDePorc_var[i] = coupler.sln[2].copy() + nomDeVariableDePorc_Uin[i] = coupler.fMeshDict['vx'].copy() + print(len(nomDeVariableDePorc_x), len(nomDeVariableDePorc_var)) + for i in range(len(nomDeVariableDePorc_Uin)): + plt.plot(nomDeVariableDePorc_Uin[i] - nomDeVariableDePorc_Uin[0], 'x-') + plt.show() + for i in range(len(nomDeVariableDePorc_var)): + plt.plot(nomDeVariableDePorc_x[i], nomDeVariableDePorc_var[i] - nomDeVariableDePorc_var[0], 'x-') + plt.show() + + for i in range(len(nomDeVariableDePorc_var)): + plt.plot(nomDeVariableDePorc_x[i], nomDeVariableDePorc_var[i], '-') + plt.show() + + """sln = np.asarray(vsolver.GetSolution(0)) + + print(sln[8][sln[8]>0.1]) + plt.plot(sln[16], sln[1]) + plt.xlim([0, 2]) + plt.show()""" #coupler.RunPolar(alphaSeq) tms['solver'].stop() diff --git a/dart/tests/bli_lowLift2.py b/dart/tests/bli_lowLift2.py new file mode 100644 index 0000000000000000000000000000000000000000..7e738fa3d47cb5785a2f970e325c730de8ee0685 --- /dev/null +++ b/dart/tests/bli_lowLift2.py @@ -0,0 +1,154 @@ +#!/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.vCoupler2 as viscC # Rbf coupler +import dart.pyVII.vInterpolator as Interpol # Rbf interpolator +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 = 0*math.pi/180 + M_inf = 0. + + 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.01} + msh, gmshWriter = floD.mesh(dim, 'models/n0012.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 = floD.initBL(Re, M_inf, CFL0, nSections) + config = {'nDim': dim, 'nSections':nSections, 'nPoints':[103, 25], 'eps':0.02, 'rbftype': 'cubic', 'smoothing': 0.0, 'degree': 1, 'neighbors': 20} + + iSolverAPI = Interpol.Interpolator(isolver, blw[0], blw[1], config) + coupler = viscC.Coupler(iSolverAPI, vsolver) + aeroCoeff = coupler.Run() + #coupler.RunPolar(alphaSeq) + tms['solver'].stop() + + # extract Cp + Cp = floU.extract(bnd.groups[0].tag.elems, isolver.Cp) + tboxU.write(Cp, 'Cp_airfoil.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)) + + # 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/blipython.py b/dart/tests/blipython.py index d52d07bc4f7bce543d812c2ad8be37cbe540a159..8f40e54b6a12f47ae5f2a5e2b7138ece58af3091 100755 --- a/dart/tests/blipython.py +++ b/dart/tests/blipython.py @@ -93,7 +93,7 @@ def main(): # 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) + pbl, _, _, bnd, blw = floD.problem(msh, dim, alpha, 0., M_inf, c_ref, c_ref, 0.25, 0., 0., 'airfoil', vsc = True, dbc=True) tms['pre'].stop() # solve viscous problem diff --git a/dart/tests/cylinder.py b/dart/tests/cylinder.py index 88dc36af29ef3ae7e7955fb12e128d880625c8d8..07d43117a1d25ebf38f3f0e24cdbb843fc383762 100644 --- a/dart/tests/cylinder.py +++ b/dart/tests/cylinder.py @@ -59,19 +59,19 @@ def main(): # set the problem and add fluid, initial/boundary conditions tms['pre'].start() - pbl, dirichlet, wake, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, l_ref, l_ref, 0., 0., 0., 'cylinder', te = 'te', dbc=True) + pbl, dirichlet, wake, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, l_ref, l_ref, 0., 0., 0., 'cylinder', dbc=True) tms['pre'].stop() # solve problem print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) tms['picard'].start() solver0 = floD.picard(pbl) - cnvrgd0 = solver0.run() + solver0.run() solver0.save(gmshWriter) tms['picard'].stop() tms['newton'].start() solver1 = floD.newton(pbl) - cnvrgd1 = solver1.run() + solver1.run() solver1.save(gmshWriter) tms['newton'].stop() @@ -126,8 +126,6 @@ def main(): # check results print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) - if not cnvrgd0 or not cnvrgd1: - raise Exception(ccolors.ANSI_RED + 'Flow solver failed to converge!' + ccolors.ANSI_RESET) tests = CTests() tests.add(CTest('Picard: iteration count', solver0.nIt, 12, 1, forceabs=True)) tests.add(CTest('Picard: Neumann B.C. mean error', errNeu0, 0., 1e-2)) diff --git a/dart/tests/cylinder2D5.py b/dart/tests/cylinder2D5.py deleted file mode 100644 index 107e6a4c8867a1ce083a9b647300ba4250ff18cb..0000000000000000000000000000000000000000 --- a/dart/tests/cylinder2D5.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/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 the (non)linear flow around extruded 2D cylinder, with various B.C. -# Adrien Crovato -# -# Test solver convergence and boundary conditions -# -# CAUTION -# This test is provided to ensure that the solver works properly. -# Mesh refinement may have to be performed to obtain physical results. - -import math -import dart.default as floD -import fwk -from fwk.testing import * -from fwk.coloring import ccolors - -def main(): - # timer - tms = fwk.Timers() - tms['total'].start() - - # define flow variables - alpha = 3*math.pi/180 - U_inf = [math.cos(alpha), 0., math.sin(alpha)] # norm should be 1 - M_inf = 0.1 - dim = 3 - - # define dimension and mesh size - dmt = 1.0 # cylinder diameter - lgt = 8.0 # channel length - hgt = 6.0 # channel height - wdt = 3.0 # channel width - l_ref = dmt # reference length - S_ref = dmt*wdt # reference area - fms = 0.5 # farfield mesh size - nms = 0.1 # nearfield mesh size - - # mesh the geometry - print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET) - tms["msh"].start() - pars = {'dmt' : dmt, 'lgt' : lgt, 'wdt' : wdt, 'hgt' : hgt, 'msN' : nms, 'msF' : fms} - msh, gmshWriter = floD.mesh(dim, 'models/cylinder_2D5.geo', pars, ['field', 'cylinder', 'symmetry', 'downstream']) - tms["msh"].stop() - - # set the problem and add fluid, initial/boundary conditions - tms['pre'].start() - pbl, dirichlet, wake, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, l_ref, 0., 0., 0., 'cylinder', tp = 'te', dbc=True) - tms['pre'].stop() - - # solve problem - print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) - tms['solver'].start() - solver = floD.newton(pbl) - cnvrgd = solver.run() - solver.save(gmshWriter) - tms['solver'].stop() - - # compute mean error in Body, Neumann boundary condition (works only for Tri3 elements) - gradn = [] - for e in bnd.groups[0].tag.elems: - gradx = 0 - grady = 0 - gradz = 0 - ux = e.nodes[1].pos[0] - e.nodes[0].pos[0] - uy = e.nodes[1].pos[1] - e.nodes[0].pos[1] - uz = e.nodes[1].pos[2] - e.nodes[0].pos[2] - vx = e.nodes[2].pos[0] - e.nodes[0].pos[0] - vy = e.nodes[2].pos[1] - e.nodes[0].pos[1] - vz = e.nodes[2].pos[2] - e.nodes[0].pos[2] - nx = uy*vz - uz*vy - ny = uz*vx - ux*vz - nz = ux*vy - uy*vx - for n in e.nodes: - gradx += solver.U[n.row][0] / e.nodes.size() - grady += solver.U[n.row][1] / e.nodes.size() - gradz += solver.U[n.row][2] / e.nodes.size() - gradn_ = gradx * nx + grady * ny + gradz * nz - gradn.append(gradn_) - errNeu = sum(gradn) / len(gradn) - # compute largest error in Dirichlet boundary condition - errDir = 0. - for n in dirichlet.nodes: - errCur = solver.phi[n.row] - (n.pos[0]*U_inf[0] + n.pos[1]*U_inf[1] + n.pos[2]*U_inf[2]) - if (abs(errCur) > errDir): - errDir = abs(errCur) - # compute largest error in Wake boundary condition - errWak = 0. - for n in wake.nodMap: - errCur = solver.Cp[n.row] - solver.Cp[wake.nodMap[n].row] - if (abs(errCur) > errWak): - errWak = abs(errCur) - - # display timers - tms['total'].stop() - print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET) - print('CPU statistics') - print(tms) - - # visualize solution - floD.initViewer(pbl) - - # check results - print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) - if (not cnvrgd): - raise Exception(ccolors.ANSI_RED + 'Flow solver failed to converge!' + ccolors.ANSI_RESET) - tests = CTests() - tests.add(CTest('iteration count', solver.nIt, 3, 1, forceabs=True)) - tests.add(CTest('Neumann B.C. mean error', errNeu, 0., 1e-2)) - tests.add(CTest('Dirichlet B.C. max error', errDir, 0., 1e-12)) - tests.add(CTest('Wake/Kutta B.C. max error', errWak, 0., 1e-1)) - tests.run() - - # eof - print('') - -if __name__ == "__main__": - main() diff --git a/dart/tests/cylinder3.py b/dart/tests/cylinder3.py deleted file mode 100644 index 869eca38e59673a42dd7db4e238425c57fc6dcdf..0000000000000000000000000000000000000000 --- a/dart/tests/cylinder3.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/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 the (non)linear flow around 3D cylinder, with various B.C. -# Adrien Crovato -# -# Test solver convergence and boundary conditions -# -# CAUTION -# This test is provided to ensure that the solver works properly. -# Mesh refinement may have to be performed to obtain physical results. - -import math -import dart.utils as floU -import dart.default as floD -import fwk -from fwk.testing import * -from fwk.coloring import ccolors - -def main(): - # timer - tms = fwk.Timers() - tms['total'].start() - - # define flow variables - alpha = 3*math.pi/180 - U_inf = [math.cos(alpha), 0., math.sin(alpha)] # norm should be 1 - M_inf = 0.1 - dim = 3 - - # define dimension and mesh size - dmt = 1.0 # cylinder diameter - spn = 2.0 # cylinder span - tpt = 5e-2 # cylinder tip thickness (ratio wrt span) - lgt = 8.0 # channel length - hgt = 6.0 # channel height - wdt = 3.0 # channel width - l_ref = dmt # reference length - S_ref = dmt*spn # reference area - fms = 0.5 # farfield mesh size - nms = 0.1 # nearfield mesh size - - # mesh the geometry - print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET) - tms['msh'].start() - pars = {'dmt' : dmt, 'spn' : spn, 'tpt' : tpt, 'lgt' : lgt, 'wdt' : wdt, 'hgt' : hgt, 'msN' : nms, 'msF' : fms} - msh, gmshWriter = floD.mesh(dim, 'models/cylinder_3.geo', pars, ['field', 'cylinder', 'symmetry', 'downstream'], wktp = 'wakeTip') - tms['msh'].stop() - - # set the problem and add fluid, initial/boundary conditions - tms['pre'].start() - pbl, dirichlet, wake, bnd,_ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, l_ref, 0., 0., 0., 'cylinder', tp = 'teTip', dbc=True) - tms['pre'].stop() - - # solve problem - print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) - tms['solver'].start() - solver = floD.newton(pbl) - cnvrgd = solver.run() - solver.save(gmshWriter) - tms['solver'].stop() - - # compute mean error in Body, Neumann boundary condition (works only for Tri3 elements) - gradn = [] - for e in bnd.groups[0].tag.elems: - gradx = 0 - grady = 0 - gradz = 0 - ux = e.nodes[1].pos[0] - e.nodes[0].pos[0] - uy = e.nodes[1].pos[1] - e.nodes[0].pos[1] - uz = e.nodes[1].pos[2] - e.nodes[0].pos[2] - vx = e.nodes[2].pos[0] - e.nodes[0].pos[0] - vy = e.nodes[2].pos[1] - e.nodes[0].pos[1] - vz = e.nodes[2].pos[2] - e.nodes[0].pos[2] - nx = uy*vz - uz*vy - ny = uz*vx - ux*vz - nz = ux*vy - uy*vx - for n in e.nodes: - gradx += solver.U[n.row][0] / e.nodes.size() - grady += solver.U[n.row][1] / e.nodes.size() - gradz += solver.U[n.row][2] / e.nodes.size() - gradn_ = gradx * nx + grady * ny + gradz * nz - gradn.append(gradn_) - errNeu = sum(gradn) / len(gradn) - # compute largest error in Dirichlet boundary condition - errDir = 0. - for n in dirichlet.nodes: - errCur = solver.phi[n.row] - (n.pos[0]*U_inf[0] + n.pos[1]*U_inf[1] + n.pos[2]*U_inf[2]) - if (abs(errCur) > errDir): - errDir = abs(errCur) - # compute largest error in Wake boundary condition - errWak = 0. - for n in wake.nodMap: - errCur = solver.Cp[n.row] - solver.Cp[wake.nodMap[n].row] - if (abs(errCur) > errWak): - errWak = abs(errCur) - - # display timers - tms['total'].stop() - print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET) - print('CPU statistics') - print(tms) - - # visualize solution - floD.initViewer(pbl) - - # check results - print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) - if (not cnvrgd): - raise Exception(ccolors.ANSI_RED + 'Flow solver failed to converge!' + ccolors.ANSI_RESET) - tests = CTests() - tests.add(CTest('iteration count', solver.nIt, 4, 1, forceabs=True)) - tests.add(CTest('Neumann B.C. mean error', errNeu, 0., 1e-2)) - tests.add(CTest('Dirichlet B.C. max error', errDir, 0., 1e-12)) - tests.add(CTest('Wake/Kutta B.C. max error', errWak, 0., 1e-1)) - tests.run() - - # eof - print('') - -if __name__ == "__main__": - main() diff --git a/dart/tests/lift.py b/dart/tests/lift.py index 9f598bb2df4eee4c020850e6fad71b53f8a580a7..daa9b6eb2ed31cdfbddb45f0e9b5448b7eb46210 100644 --- a/dart/tests/lift.py +++ b/dart/tests/lift.py @@ -54,7 +54,7 @@ def main(): # set the problem and add fluid, initial/boundary conditions tms['pre'].start() - pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, c_ref, c_ref, 0.25, 0., 0., 'airfoil', te = 'te') + pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, c_ref, c_ref, 0.25, 0., 0., 'airfoil') tms['pre'].stop() # solve problem @@ -107,6 +107,7 @@ def main(): tests.add(CTest('iteration count', solver.nIt, 12, 3, forceabs=True)) tests.add(CTest('min(Cp)', min(Cp[:,3]), -1.28, 5e-2)) tests.add(CTest('Cl', solver.Cl, 0.388, 5e-2)) + tests.add(CTest('Cd', solver.Cd, 0.0013, 5e-4, forceabs=True)) tests.add(CTest('Cm', solver.Cm, 0.0, 1e-2)) else: raise Exception('Test not defined for this flow') diff --git a/dart/tests/lift3.py b/dart/tests/lift3.py deleted file mode 100644 index 67c2ad3d74fdf53c8ed07166138bf2363f95ac80..0000000000000000000000000000000000000000 --- a/dart/tests/lift3.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/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) potential flow around a NACA 0012 rectangular wing -# Adrien Crovato -# -# Test the nonlinear shock-capturing capability and the Kutta condition -# -# CAUTION -# This test is provided to ensure that the solver works properly. -# Mesh refinement may have to be performed to obtain physical results. - -import math -import dart.utils as floU -import dart.default as floD -import fwk -from fwk.testing import * -from fwk.coloring import ccolors - -def main(): - # timer - tms = fwk.Timers() - tms['total'].start() - - # define flow variables - alpha = 3*math.pi/180 - M_inf = 0.3 - dim = 3 - - # define dimension and mesh size - spn = 1.0 # wing span - lgt = 3.0 # channel half length - hgt = 3.0 # channel half height - wdt = 3.0 # channel width - S_ref = 1.*spn # reference area - c_ref = 1 # reference chord - fms = 1.0 # farfield mesh size - nms = 0.02 # nearfield mesh size - - # mesh the geometry - print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET) - tms['msh'].start() - pars = {'spn' : spn, 'lgt' : lgt, 'wdt' : wdt, 'hgt' : hgt, 'msLe' : nms, 'msTe' : nms, 'msF' : fms} - msh, gmshWriter = floD.mesh(dim, 'models/n0012_3.geo', pars, ['field', 'wing', 'symmetry', 'downstream'], wktp = 'wakeTip') - 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 = 'teTip') - tms['pre'].stop() - - # solve problem - print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) - tms['solver'].start() - solver = floD.newton(pbl) - solver.run() - solver.save(gmshWriter) - tms['solver'].stop() - - # display timers - tms['total'].stop() - print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET) - print('CPU statistics') - print(tms) - - # visualize solution - floD.initViewer(pbl) - - # check results - print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) - tests = CTests() - if alpha == 3*math.pi/180 and M_inf == 0.3 and spn == 1.0: - tests.add(CTest('iteration count', solver.nIt, 3, 1, forceabs=True)) - tests.add(CTest('CL', solver.Cl, 0.135, 5e-2)) - tests.add(CTest('CD', solver.Cd, 0.0062, 1e-2)) # Tranair (NF=0.0062, FF=0.0030), Panair 0.0035 - tests.add(CTest('CS', solver.Cs, 0.0121, 5e-2)) - tests.add(CTest('CM', solver.Cm, -0.0278, 1e-2)) - else: - raise Exception('Test not defined for this flow') - tests.run() - - # eof - print('') - -if __name__ == "__main__": - main() diff --git a/dart/tests/meshDef3.py b/dart/tests/meshDef3.py deleted file mode 100644 index d571ee61ffbcd3b53f3dce91e427d21e49a2e55a..0000000000000000000000000000000000000000 --- a/dart/tests/meshDef3.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/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 the flow around a NACA 0012 wing on a deformed mesh -# Adrien Crovato -# -# Test the mesh deformation process -# -# CAUTION -# This test is provided to ensure that the solver works properly. -# Mesh refinement may have to be performed to obtain physical results. - -import numpy as np -import dart.utils as floU -import dart.default as floD -import fwk -from fwk.testing import * -from fwk.coloring import ccolors - -def main(): - # timer - tms = fwk.Timers() - tms['total'].start() - - # define flow variables - alpha0 = 0 # must be zero for this testfile - M_inf = 0.3 - dim = 3 - - # define dimension and mesh size - spn = 1.0 # wing span - lgt = 3.0 # channel half length - hgt = 3.0 # channel half height - wdt = 3.0 # channel width - S_ref = 1.*spn # reference area - c_ref = 1 # reference chord - fms = 1.0 # farfield mesh size - nms = 0.05 # nearfield mesh size - - # parameters for mesh deformation - alfa = 3*np.pi/180 - xc = 0.25 - dz_max = 0.2*spn - - # mesh an airfoil - print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET) - tms['msh'].start() - pars = {'spn' : spn, 'lgt' : lgt, 'wdt' : wdt, 'hgt' : hgt, 'msLe' : nms, 'msTe' : nms, 'msF' : fms} - msh, gmshWriter = floD.mesh(dim, 'models/n0012_3.geo', pars, ['field', 'wing', 'symmetry', 'downstream'], wktp = 'wakeTip') - tms['msh'].stop() - # create mesh deformation handler - mshDef = floD.morpher(msh, dim, ['wing']) - - # set the problem and add fluid, initial/boundary conditions - tms['pre'].start() - pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha0, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'teTip') - tms['pre'].stop() - - # solver problem for 0°AOA - print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) - tms['solver0'].start() - solver = floD.newton(pbl) - solver.run() - tms['solver0'].stop() - - # deform the mesh (dummy rotation + bending) - print(ccolors.ANSI_BLUE + 'PyDeforming...' + ccolors.ANSI_RESET) - tms['deform'].start() - mshDef.savePos() - rMat = np.matrix([[np.cos(alfa), np.sin(alfa)], [-np.sin(alfa), np.cos(alfa)]]) - vNods = {} - for e in bnd.groups[0].tag.elems: - for n in e.nodes: - if n.no not in vNods: - vNods[n.no] = n - for no in vNods: - nod = np.matrix([[vNods[no].pos[0]-xc], [vNods[no].pos[2]]]) - new = rMat * nod - vNods[no].pos[0] = new[0,0] - vNods[no].pos[2] = new[1,0] + dz_max/(spn*spn)*(vNods[no].pos[1]*vNods[no].pos[1]) - # deform the mesh - mshDef.deform() - gmshWriter.save(msh.name+"_def") - tms['deform'].stop() - - # solve problem for alfa AOA - print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) - tms['solver1'].start() - solver.run() - solver.save(gmshWriter) - tms['solver1'].stop() - - # display results - print(ccolors.ANSI_BLUE + 'PyRes...' + ccolors.ANSI_RESET) - print(' case M alpha Cl Cd Cm') - print(' true {0:8.2f} {1:8.1f} {2:8.4f} {3:8.4f} {4:8.4f}'.format(M_inf, alfa*180/np.pi, solver.Cl, solver.Cd, solver.Cm)) - - # display timers - tms['total'].stop() - print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET) - print('CPU statistics') - print(tms) - - # check results - print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) - tests = CTests() - if alfa == 3*np.pi/180 and M_inf == 0.3 and spn == 1.0: - tests.add(CTest('iteration count', solver.nIt, 3, 1, forceabs=True)) - tests.add(CTest('CL', solver.Cl, 0.135, 5e-1)) - tests.add(CTest('CD', solver.Cd, 0.0062, 1e-2)) # Tranair (NF=0.0062, FF=0.0030), Panair 0.0035 - tests.add(CTest('CS', solver.Cs, -0.011, 5e-2)) - tests.add(CTest('CM', solver.Cm, 0.0061, 1e-2)) - tests.run() - - # eof - print('') - -if __name__ == "__main__": - main() diff --git a/dart/tests/meshDef.py b/dart/tests/morpher.py similarity index 96% rename from dart/tests/meshDef.py rename to dart/tests/morpher.py index c50e5af78d270351db7117ae710d3cb81246839f..c82f27719227c722d27d4db4d80d0d17d546d4d3 100644 --- a/dart/tests/meshDef.py +++ b/dart/tests/morpher.py @@ -55,7 +55,7 @@ def main(): pars = {'xLgt' : 5, 'yLgt' : 5, 'msF' : 1., 'msTe' : 0.01, 'msLe' : 0.01} msh, gmshWriter = floD.mesh(dim, 'models/n0012.geo', pars, ['field', 'airfoil', 'downstream']) # create mesh deformation handler - mshDef = floD.morpher(msh, dim, ['airfoil']) + morpher = floD.morpher(msh, dim, ['airfoil']) # mesh the reference geometry pars = {'xLgt' : 5, 'yLgt' : 5, 'msF' : 1., 'msTe' : 0.01, 'msLe' : 0.01, 'angle' : alfa, 'xRot' : xc} msh_ref, gmshWriter_ref = floD.mesh(dim, 'models/n0012.geo', pars, ['field', 'airfoil', 'downstream']) @@ -63,9 +63,9 @@ def main(): # set the problem and add fluid, initial/boundary conditions tms['pre'].start() - pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha0, 0., M_inf, c_ref, c_ref, xc+dx, dy, 0., 'airfoil', te = 'te') + pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha0, 0., M_inf, c_ref, c_ref, xc+dx, dy, 0., 'airfoil') # set the refrence problem and add fluid, initial/boundary conditions - pbl_ref, _, _, bnd_ref, _ = floD.problem(msh_ref, dim, alpha0, 0., M_inf, c_ref, c_ref, xc, 0., 0., 'airfoil', te = 'te') + pbl_ref, _, _, bnd_ref, _ = floD.problem(msh_ref, dim, alpha0, 0., M_inf, c_ref, c_ref, xc, 0., 0., 'airfoil') tms['pre'].stop() # solver problem for 0°AOA @@ -78,7 +78,7 @@ def main(): # deform the mesh (dummy rotation + translation) print(ccolors.ANSI_BLUE + 'PyDeforming...' + ccolors.ANSI_RESET) tms['deform'].start() - mshDef.savePos() + morpher.savePos() rMat = np.matrix([[np.cos(alfa), np.sin(alfa)], [-np.sin(alfa), np.cos(alfa)]]) vNods = {} for e in bnd.groups[0].tag.elems: @@ -91,7 +91,7 @@ def main(): vNods[no].pos[0] = new[0,0] + dx + xc vNods[no].pos[1] = new[1,0] + dy # deform the mesh - mshDef.deform() + morpher.deform() gmshWriter.save("n0012_def") tms['deform'].stop() diff --git a/dart/tests/nonlift.py b/dart/tests/nonlift.py index 06136600610981edca7e4fa6350b10172aafdb0e..223aa336b3ccd995c20e0bfa83e1c344e00ddded 100644 --- a/dart/tests/nonlift.py +++ b/dart/tests/nonlift.py @@ -29,6 +29,7 @@ import math import dart.utils as floU import dart.default as floD +from matplotlib import pyplot as plt import tbox.utils as tboxU import fwk from fwk.testing import * @@ -41,7 +42,7 @@ def main(): # define flow variables alpha = 0*math.pi/180 # must be zero for this testfile - M_inf = 0.8 + M_inf = 0. c_ref = 1 dim = 2 @@ -54,19 +55,26 @@ def main(): # set the problem and add fluid, initial/boundary conditions tms['pre'].start() - pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, c_ref, c_ref, 0.25, 0., 0., 'airfoil', te = 'te') + pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, c_ref, c_ref, 0.25, 0., 0., 'airfoil') tms['pre'].stop() # solve problem print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) tms['solver'].start() solver = floD.newton(pbl) - solver.run() - solver.save(gmshWriter) - tms['solver'].stop() + nRel = 10 + Cp = [None for _ in range(nRel)] + for i in range(nRel): + solver.run() + solver.save(gmshWriter) + tms['solver'].stop() - # extract Cp - Cp = floU.extract(bnd.groups[0].tag.elems, solver.Cp) + # extract Cp + Cp[i] = floU.extract(bnd.groups[0].tag.elems, solver.U) + plt.plot(Cp[i][:,0], Cp[i][:,3]-Cp[0][:,3], 'x') + solver.reset() + plt.show() + quit() tboxU.write(Cp, 'Cp_airfoil.dat', '%1.5e', ', ', 'x, y, z, Cp', '') # display results print(ccolors.ANSI_BLUE + 'PyRes...' + ccolors.ANSI_RESET) @@ -93,6 +101,7 @@ def main(): elif M_inf == 0.8: tests.add(CTest('iteration count', solver.nIt, 15, 3, forceabs=True)) tests.add(CTest('min(Cp)', min(Cp[:,3]), -0.89, 5e-2)) + tests.add(CTest('Cd', solver.Cd, 0.0049, 5e-4, forceabs=True)) else: raise Exception('Test not defined for this flow') tests.add(CTest('Cl', solver.Cl, 0., 1e-2)) diff --git a/dart/tests/adjoint3.py b/dart/tests/rae_25.py similarity index 62% rename from dart/tests/adjoint3.py rename to dart/tests/rae_25.py index a9bb5a768a233508a06f76d13f278033695c75e6..cc656c11f7211fad86603d24ea9b253615b57698 100644 --- a/dart/tests/adjoint3.py +++ b/dart/tests/rae_25.py @@ -2,13 +2,13 @@ # -*- 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. @@ -16,22 +16,20 @@ # limitations under the License. -## Compute adjoint solution of lifting (linear or nonlinear) potential flow around a NACA 0012 +## Compute the nonlinear flow around extruded 2D rae2822 # Adrien Crovato # -# Test the adjoint solver +# Test transonic capabilities and kutta condition # # CAUTION # This test is provided to ensure that the solver works properly. # Mesh refinement may have to be performed to obtain physical results. import numpy as np -import dart.utils as floU import dart.default as floD -import tbox.utils as tboxU import fwk from fwk.testing import * -from fwk.coloring import ccolors +from fwk.coloring import ccolors def main(): # timer @@ -39,31 +37,38 @@ def main(): tms['total'].start() # define flow variables - alpha = 3*np.pi/180 - M_inf = 0.3 - c_ref = 1 - span = 1 + alpha = 1*np.pi/180 + M_inf = 0.72 dim = 3 + # define dimension and mesh size + spn = 0.2 # wing span + lgt = 6.0 # channel length + hgt = 6.0 # channel height + wdt = 3.0 # channel width + c_ref = 1.0 # reference length + S_ref = spn # reference area + fms = 1.0 # farfield mesh size + nms = 0.01 # nearfield mesh size + # mesh the geometry print(ccolors.ANSI_BLUE + 'PyMeshing...' + ccolors.ANSI_RESET) - tms['msh'].start() - pars = {'spn' : span, 'lgt' : 3, 'wdt' : 3, 'hgt' : 3, 'msLe' : 0.02, 'msTe' : 0.02, 'msF' : 1.} - msh, gmshWriter = floD.mesh(dim, 'models/n0012_3.geo', pars, ['field', 'wing', 'symmetry', 'downstream'], wktp = 'wakeTip') - # create mesh deformation handler + tms["msh"].start() + pars = {'spn' : spn, 'lgt' : lgt, 'wdt' : wdt, 'hgt' : hgt, 'msN' : nms, 'msF' : fms} + msh, gmshWriter = floD.mesh(dim, 'models/rae_25.geo', pars, ['field', 'wing', 'symmetry', 'downstream']) morpher = floD.morpher(msh, dim, ['wing']) - tms['msh'].stop() + 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, span*c_ref, c_ref, 0., 0., 0., 'wing', tp = 'teTip') + pbl, _, _, bnd, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0.25, 0., 0., 'wing') tms['pre'].stop() # solve problem print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) tms['solver'].start() solver = floD.newton(pbl) - solver.run() + status = solver.run() solver.save(gmshWriter) tms['solver'].stop() @@ -83,7 +88,6 @@ def main(): dCdX += np.array([adjoint.dCdMsh[n.row][0], adjoint.dCdMsh[n.row][1], adjoint.dCdMsh[n.row][2]]).dot(np.array([adjoint.dCdMsh[n.row][0], adjoint.dCdMsh[n.row][1], adjoint.dCdMsh[n.row][2]])) dClX = np.sqrt(dClX) dCdX = np.sqrt(dCdX) - # recover gradient wrt to AoA from mesh gradient drot = np.array([[-np.sin(alpha), 0, np.cos(alpha)], [0, 0, 0], [-np.cos(alpha), 0, -np.sin(alpha)]]) dClAoA = 0 @@ -95,8 +99,8 @@ def main(): # display results print(ccolors.ANSI_BLUE + 'PyRes...' + ccolors.ANSI_RESET) - print(' M alpha Cl Cd dCl_da dCd_da') - print('{0:8.2f} {1:8.1f} {2:8.4f} {3:8.4f} {4:8.4f} {5:8.4f}'.format(M_inf, alpha*180/np.pi, solver.Cl, solver.Cd, adjoint.dClAoa, adjoint.dCdAoa)) + print(' M alpha Cl Cd Cm') + print('{0:8.2f} {1:8.1f} {2:8.4f} {3:8.4f} {4:8.4f}'.format(M_inf, alpha*180/np.pi, solver.Cl, solver.Cd, solver.Cm)) # display timers tms['total'].stop() @@ -104,25 +108,25 @@ def main(): print('CPU statistics') print(tms) + # visualize solution + floD.initViewer(pbl) + # check results print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) + if status > 0: + raise Exception(ccolors.ANSI_RED + 'Solver failed to converge!' + ccolors.ANSI_RESET) tests = CTests() - if M_inf == 0.3 and alpha == 3*np.pi/180 and span == 1: - tests.add(CTest('dCl/dAoA', adjoint.dClAoa, 2.5, 5e-2)) # FD 2.526 (step 1e-5) - tests.add(CTest('dCd/dAoA', adjoint.dCdAoa, 0.146, 5e-2)) # FD 0.1460 (step 1e-5) - tests.add(CTest('dCl_dMsh', dClX, 2.016, 5e-2)) - tests.add(CTest('dCd_dMsh', dCdX, 0.133, 5e-2)) - tests.add(CTest('dCl/dAoA (msh)', dClAoA, 2.5, 5e-2)) - tests.add(CTest('dCd/dAoA (msh)', dCdAoA, 0.146, 5e-2)) - elif M_inf == 0.7 and alpha == 5*np.pi/180 and span == 2: - tests.add(CTest('dCl/dAoA', adjoint.dClAoa, 4.9, 5e-2)) - tests.add(CTest('dCd/dAoA', adjoint.dCdAoa, 0.454, 5e-2)) - tests.add(CTest('dCl_dMsh', dClX, 2.571, 5e-2)) - tests.add(CTest('dCd_dMsh', dCdX, 0.204, 5e-2)) - tests.add(CTest('dCl/dAoA (msh)', dClAoA, 4.9, 5e-2)) - tests.add(CTest('dCd/dAoA (msh)', dCdAoA, 0.454, 5e-2)) - else: - raise Exception('Test not defined for this flow') + tests.add(CTest('iteration count', solver.nIt, 6, 1, forceabs=True)) + tests.add(CTest('CL', solver.Cl, 0.60, 5e-2)) # 2D, 0.62 + tests.add(CTest('CD', solver.Cd, 0.0015, 1e-2)) # 2D 0.0009 (3D refined 0.0006) + tests.add(CTest('CS', solver.Cs, 0.0000, 1e-3, forceabs=True)) + tests.add(CTest('CM', solver.Cm, -0.113, 5e-2)) # 2D -0.117 + tests.add(CTest('dCl/dAoA', adjoint.dClAoa, 12.7, 5e-2)) # 2D 12.7, FD 12.73 (1e-6) + tests.add(CTest('dCd/dAoA', adjoint.dCdAoa, 0.059, 5e-3, forceabs=True)) # 2D 0.051, FD 0.0557 (1e-6) + tests.add(CTest('dCl_dMsh', dClX, 22.0, 5e-2)) + tests.add(CTest('dCd_dMsh', dCdX, 1.0, 5e-2)) + tests.add(CTest('dCl/dAoA (msh)', dClAoA, 12.9, 5e-2)) # 2D 12.9 + tests.add(CTest('dCd/dAoA (msh)', dCdAoA, 0.058, 5e-3, forceabs=True)) # 2D 0.051 tests.run() # eof diff --git a/dart/tests/rae_3.py b/dart/tests/rae_3.py new file mode 100644 index 0000000000000000000000000000000000000000..f720dc466c16e848e45f3157fb25c6ec0a1f417a --- /dev/null +++ b/dart/tests/rae_3.py @@ -0,0 +1,179 @@ +#!/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 the nonlinear flow around rectangular 3D rae2822 +# Adrien Crovato +# +# Test the direct and adjoint solvers, and the mesh morpher in 3D +# +# CAUTION +# This test is provided to ensure that the solver works properly. +# Mesh refinement may have to be performed to obtain physical results. + +import numpy as np +import dart.default as floD +import dart.utils as floU +from matplotlib import pyplot as plt +import fwk +from fwk.testing import * +from fwk.coloring import ccolors + +def main(): + # timer + tms = fwk.Timers() + tms['total'].start() + + # define flow variables + alpha = 0.*np.pi/180 + M_inf = 0. + dim = 3 + + # define dimension and mesh size + spn = 1.0 # wing span + lgt = 6.0 # channel length + hgt = 6.0 # channel height + wdt = 3.0 # channel width + c_ref = 1.0 # reference length + S_ref = spn # reference area + fms = 1.0 # farfield mesh size + nms = 0.02 # nearfield mesh size + + # parameters for mesh deformation + alfa = 1*np.pi/180 + xc = 0.25 + dz_max = 0.2*spn + + # mesh the geometry and create mesh deformation handler + 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') + 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') + + span = 0.5 + elemPlot = [] + for e in bnd.groups[0].tag.elems: + if abs(e.nodes[0].pos[1] - span) <= 1e-3: + elemPlot = np.append(elemPlot, e) + print('here', len(elemPlot)) + nRel = 5 + Cp = [None for _ in range(nRel)] + for i in range(nRel): + + solver = floD.newton(pbl) # create the solver now so element memory is up to date + tms['pre'].stop() + + """# deform the mesh (dummy rotation + bending) + print(ccolors.ANSI_BLUE + 'PyDeforming...' + ccolors.ANSI_RESET) + tms['deform'].start() + morpher.savePos() + rMat = np.matrix([[np.cos(alfa), np.sin(alfa)], [-np.sin(alfa), np.cos(alfa)]]) + vNods = {} + for e in bnd.groups[0].tag.elems: + for n in e.nodes: + if n.no not in vNods: + vNods[n.no] = n + for no in vNods: + nod = np.matrix([[vNods[no].pos[0]-xc], [vNods[no].pos[2]]]) + new = rMat * nod + vNods[no].pos[0] = new[0,0] + vNods[no].pos[2] = new[1,0] + dz_max/(spn*spn)*(vNods[no].pos[1]*vNods[no].pos[1]) + # deform the mesh + morpher.deform() + gmshWriter.save(msh.name+"_def") + tms['deform'].stop()""" + + # solve problem + print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) + tms['solver'].start() + status = solver.run() + Cp[i] = floU.extract(elemPlot, solver.U) + plt.plot(Cp[i][:,0], Cp[i][:,3] - Cp[0][:,3], 'x') + solver.reset() + plt.show() + quit() + solver.save(gmshWriter) + tms['solver'].stop() + + # solve adjoint problem + print(ccolors.ANSI_BLUE + 'PyGradient...' + ccolors.ANSI_RESET) + tms['adjoint'].start() + adjoint = floD.adjoint(solver, morpher) + adjoint.run() + adjoint.save(gmshWriter) + tms['adjoint'].stop() + + # compute norm of gradient wrt to mesh + dClX = 0 + dCdX = 0 + for n in msh.nodes: + dClX += np.array([adjoint.dClMsh[n.row][0], adjoint.dClMsh[n.row][1], adjoint.dClMsh[n.row][2]]).dot(np.array([adjoint.dClMsh[n.row][0], adjoint.dClMsh[n.row][1], adjoint.dClMsh[n.row][2]])) + dCdX += np.array([adjoint.dCdMsh[n.row][0], adjoint.dCdMsh[n.row][1], adjoint.dCdMsh[n.row][2]]).dot(np.array([adjoint.dCdMsh[n.row][0], adjoint.dCdMsh[n.row][1], adjoint.dCdMsh[n.row][2]])) + dClX = np.sqrt(dClX) + dCdX = np.sqrt(dCdX) + # recover gradient wrt to AoA from mesh gradient + drot = np.array([[-np.sin(alfa), 0, np.cos(alfa)], [0, 0, 0], [-np.cos(alfa), 0, -np.sin(alfa)]]) + dClAoA = 0 + dCdAoA = 0 + for n in bnd.nodes: + dx = drot.dot(np.array([n.pos[0] - 0.25, n.pos[1], n.pos[2]])) + dClAoA += np.array([adjoint.dClMsh[n.row][0], adjoint.dClMsh[n.row][1], adjoint.dClMsh[n.row][2]]).dot(dx) + dCdAoA += np.array([adjoint.dCdMsh[n.row][0], adjoint.dCdMsh[n.row][1], adjoint.dCdMsh[n.row][2]]).dot(dx) + + # display results + print(ccolors.ANSI_BLUE + 'PyRes...' + ccolors.ANSI_RESET) + print(' M alpha Cl Cd dCl_da dCd_da') + print('{0:8.2f} {1:8.1f} {2:8.4f} {3:8.4f} {4:8.4f} {5:8.4f}'.format(M_inf, alfa*180/np.pi, solver.Cl, solver.Cd, adjoint.dClAoa, adjoint.dCdAoa)) + + # display timers + tms['total'].stop() + print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET) + print('CPU statistics') + print(tms) + + # visualize solution + floD.initViewer(pbl) + + # check results + print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) + if status > 0: + raise Exception(ccolors.ANSI_RED + 'Solver failed to converge!' + ccolors.ANSI_RESET) + tests = CTests() + tests.add(CTest('iteration count', solver.nIt, 7, 1, forceabs=True)) + tests.add(CTest('CL', solver.Cl, 0.21, 5e-2)) + tests.add(CTest('CD', solver.Cd, 0.008, 1e-2)) + tests.add(CTest('CS', solver.Cs, -0.020, 5e-2)) + tests.add(CTest('CM', solver.Cm, -0.080, 5e-2)) + tests.add(CTest('dCl/dAoA', adjoint.dClAoa, 3.0, 5e-2)) # FD 3.0144 (1e-6) + tests.add(CTest('dCd/dAoA', adjoint.dCdAoa, 0.2, 5e-2)) # FD 0.2007 (1e-6) + tests.add(CTest('dCl_dMsh', dClX, 2.3, 5e-2)) + tests.add(CTest('dCd_dMsh', dCdX, 0.2, 5e-2)) + tests.add(CTest('dCl/dAoA (msh)', dClAoA, 3.0, 5e-2)) + tests.add(CTest('dCd/dAoA (msh)', dCdAoA, 0.2, 5e-2)) + tests.run() + + # eof + print('') + +if __name__ == "__main__": + main() diff --git a/dart/utils.py b/dart/utils.py index 012b86c2fa0d113660640d6d6c24b5ddceada94d..9691f77b6a302af2dae89a2e4b80398af2bd8f63 100644 --- a/dart/utils.py +++ b/dart/utils.py @@ -97,17 +97,17 @@ def extract(vElems, vData): else: raise RuntimeError('dart.utils.extract: 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)) + data = np.zeros((len(vElems)+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] + while i < len(vElems)+1: + data[i,0] = vElems[i%len(vElems)].nodes[0].pos[0] + data[i,1] = vElems[i%len(vElems)].nodes[0].pos[1] + data[i,2] = vElems[i%len(vElems)].nodes[0].pos[2] if size == 1: - data[i,3] = vData[vElems[i%vElems.size()].nodes[0].row] + data[i,3] = vData[vElems[i%len(vElems)].nodes[0].row] else: for j in range(size): - data[i,3+j] = vData[vElems[i%vElems.size()].nodes[0].row][j] + data[i,3+j] = vData[vElems[i%len(vElems)].nodes[0].row][j] i += 1 return data diff --git a/dart/validation/agard.py b/dart/validation/agard.py index 3e048c0585be28f3cc6d914508771f2d17e46ca4..86d5b9b767a88ab9107adba31809b85365a4d772 100644 --- a/dart/validation/agard.py +++ b/dart/validation/agard.py @@ -69,7 +69,7 @@ def main(): # set the problem and add fluid, initial/boundary conditions tms['pre'].start() - pbl, _, _, _, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'teTip') + pbl, _, _, _, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'wakeTip') tms['pre'].stop() # solve problem diff --git a/dart/validation/onera.py b/dart/validation/onera.py index 5739b25dceff469f07aecee6a60399e5ab805ad3..6957094a6f26428f4bc3814c8ca757320c9cc1eb 100644 --- a/dart/validation/onera.py +++ b/dart/validation/onera.py @@ -67,7 +67,7 @@ def main(): # set the problem and add fluid, initial/boundary conditions tms['pre'].start() - pbl, _, _, _, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'teTip') + pbl, _, _, _, _ = floD.problem(msh, dim, alpha, 0., M_inf, S_ref, c_ref, 0., 0., 0., 'wing', tp = 'wakeTip') tms['pre'].stop() # solve problem diff --git a/dart/viscous/Solvers/Steady/StdCoupler.py b/dart/viscous/Solvers/Steady/StdCoupler.py index 5b6613218b129faa5283516e7ff825e62b2eaa03..d4cfb2a5e07970655d7fbe85c62f81ed68290ae5 100755 --- a/dart/viscous/Solvers/Steady/StdCoupler.py +++ b/dart/viscous/Solvers/Steady/StdCoupler.py @@ -44,7 +44,7 @@ class Coupler: # run inviscid solver self.isolver.run() print('--- Viscous solver parameters ---') - print('Tolerance (drag count):', self.tol * 1000) + print('Tolerance (drag count):', self.tol * 1e4) print('--- Viscous problem definition ---') print('Reynolds number:', self.vsolver.Re) print('') diff --git a/ext/amfe b/ext/amfe index 87212cfb034a92cc83acfeea751f076a84c12779..8a20b0f157021fc286fa14bb9099fba81092da5c 160000 --- a/ext/amfe +++ b/ext/amfe @@ -1 +1 @@ -Subproject commit 87212cfb034a92cc83acfeea751f076a84c12779 +Subproject commit 8a20b0f157021fc286fa14bb9099fba81092da5c