From bc2c336293eab97f3d34b23544b87f8fcb24b7fe Mon Sep 17 00:00:00 2001 From: Paul Dechamps <paul.dechamps@uliege.be> Date: Thu, 14 Dec 2023 15:03:54 +0100 Subject: [PATCH] (test) Added Agard wing test case --- blast/models/dart/agard445_visc.geo | 229 ++++++++++++++++++++++++++++ blast/validation/agardValidation.py | 174 +++++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 blast/models/dart/agard445_visc.geo create mode 100644 blast/validation/agardValidation.py diff --git a/blast/models/dart/agard445_visc.geo b/blast/models/dart/agard445_visc.geo new file mode 100644 index 0000000..c657f6c --- /dev/null +++ b/blast/models/dart/agard445_visc.geo @@ -0,0 +1,229 @@ +/* AGARD 445 wing */ +// Initially generated by unsRgridWingGen.m + +// Parameters +// domain and mesh +DefineConstant[ nSpan = { 20, Name "Spanwise number of elements" } ]; +DefineConstant[ nLe = { 5, Name "LE chordwise number of elements" } ]; +DefineConstant[ nTe = { 5, Name "TE chordwise number of elements" } ]; +DefineConstant[ nMid = { 10, Name "Mid chordwise number of elements" } ]; +DefineConstant[ nWake = { 15, Name "Wake number of elements" } ]; +DefineConstant[ progSpan = { 1, Name "Spanwise progression" } ]; +DefineConstant[ progLe = { 1, Name "LE progression" } ]; +DefineConstant[ progTe = { 1, Name "TE progression" } ]; +DefineConstant[ progMid = { 1, Name "Mid progression" } ]; +DefineConstant[ progWake = { 1.0, Name "Wake progression" } ]; +DefineConstant[ xO = { -3, Name "Box origin (x)" } ]; +DefineConstant[ zO = { -3, Name "Box origin (z)" } ]; +DefineConstant[ xL = { 7, Name "Box length" } ]; +DefineConstant[ yL = { 3, Name "Box width" } ]; +DefineConstant[ zL = { 6, Name "Box height" } ]; + +//// GEOMETRY + + +/// Points + +// Airfoil 1: agard445, 51 points +Point(1) = {0.559000,0.000000,0.000000}; +Point(2) = {0.531050,0.000000,0.001398}; +Point(3) = {0.503100,0.000000,0.002739}; +Point(4) = {0.475150,0.000000,0.004075}; +Point(5) = {0.447200,0.000000,0.005406}; +Point(6) = {0.419250,0.000000,0.006680}; +Point(7) = {0.391300,0.000000,0.007837}; +Point(8) = {0.363350,0.000000,0.008866}; +Point(9) = {0.335400,0.000000,0.009743}; +Point(10) = {0.307450,0.000000,0.010442}; +Point(11) = {0.279500,0.000000,0.010923}; +Point(12) = {0.251550,0.000000,0.011158}; +Point(13) = {0.223600,0.000000,0.011163}; +Point(14) = {0.195650,0.000000,0.010968}; +Point(15) = {0.167700,0.000000,0.010576}; +Point(16) = {0.139750,0.000000,0.009995}; +Point(17) = {0.111800,0.000000,0.009196}; +Point(18) = {0.083850,0.000000,0.008156}; +Point(19) = {0.055900,0.000000,0.006781}; +Point(20) = {0.041925,0.000000,0.005920}; +Point(21) = {0.027950,0.000000,0.004891}; +Point(22) = {0.013975,0.000000,0.003617}; +Point(23) = {0.006988,0.000000,0.002622}; +Point(24) = {0.004193,0.000000,0.002057}; +Point(25) = {0.002795,0.000000,0.001699}; +Point(26) = {0.000000,0.000000,0.000000}; +Point(27) = {0.002795,0.000000,-0.001699}; +Point(28) = {0.004193,0.000000,-0.002057}; +Point(29) = {0.006988,0.000000,-0.002622}; +Point(30) = {0.013975,0.000000,-0.003617}; +Point(31) = {0.027950,0.000000,-0.004891}; +Point(32) = {0.041925,0.000000,-0.005920}; +Point(33) = {0.055900,0.000000,-0.006781}; +Point(34) = {0.083850,0.000000,-0.008156}; +Point(35) = {0.111800,0.000000,-0.009196}; +Point(36) = {0.139750,0.000000,-0.009995}; +Point(37) = {0.167700,0.000000,-0.010576}; +Point(38) = {0.195650,0.000000,-0.010968}; +Point(39) = {0.223600,0.000000,-0.011163}; +Point(40) = {0.251550,0.000000,-0.011158}; +Point(41) = {0.279500,0.000000,-0.010923}; +Point(42) = {0.307450,0.000000,-0.010442}; +Point(43) = {0.335400,0.000000,-0.009743}; +Point(44) = {0.363350,0.000000,-0.008866}; +Point(45) = {0.391300,0.000000,-0.007837}; +Point(46) = {0.419250,0.000000,-0.006680}; +Point(47) = {0.447200,0.000000,-0.005406}; +Point(48) = {0.475150,0.000000,-0.004075}; +Point(49) = {0.503100,0.000000,-0.002739}; +Point(50) = {0.531050,0.000000,-0.001398}; + +// Airfoil 2: agard445, 51 points +Point(52) = {1.178128,0.762000,0.000000}; +Point(53) = {1.159709,0.762000,0.000921}; +Point(54) = {1.141290,0.762000,0.001805}; +Point(55) = {1.122870,0.762000,0.002685}; +Point(56) = {1.104451,0.762000,0.003562}; +Point(57) = {1.086032,0.762000,0.004402}; +Point(58) = {1.067613,0.762000,0.005165}; +Point(59) = {1.049194,0.762000,0.005843}; +Point(60) = {1.030775,0.762000,0.006421}; +Point(61) = {1.012356,0.762000,0.006881}; +Point(62) = {0.993937,0.762000,0.007198}; +Point(63) = {0.975518,0.762000,0.007353}; +Point(64) = {0.957099,0.762000,0.007357}; +Point(65) = {0.938680,0.762000,0.007228}; +Point(66) = {0.920261,0.762000,0.006970}; +Point(67) = {0.901842,0.762000,0.006587}; +Point(68) = {0.883423,0.762000,0.006060}; +Point(69) = {0.865004,0.762000,0.005375}; +Point(70) = {0.846585,0.762000,0.004468}; +Point(71) = {0.837375,0.762000,0.003901}; +Point(72) = {0.828166,0.762000,0.003223}; +Point(73) = {0.818956,0.762000,0.002383}; +Point(74) = {0.814351,0.762000,0.001728}; +Point(75) = {0.812509,0.762000,0.001356}; +Point(76) = {0.811589,0.762000,0.001120}; +Point(77) = {0.809747,0.762000,0.000000}; +Point(78) = {0.811589,0.762000,-0.001120}; +Point(79) = {0.812509,0.762000,-0.001356}; +Point(80) = {0.814351,0.762000,-0.001728}; +Point(81) = {0.818956,0.762000,-0.002383}; +Point(82) = {0.828166,0.762000,-0.003223}; +Point(83) = {0.837375,0.762000,-0.003901}; +Point(84) = {0.846585,0.762000,-0.004468}; +Point(85) = {0.865004,0.762000,-0.005375}; +Point(86) = {0.883423,0.762000,-0.006060}; +Point(87) = {0.901842,0.762000,-0.006587}; +Point(88) = {0.920261,0.762000,-0.006970}; +Point(89) = {0.938680,0.762000,-0.007228}; +Point(90) = {0.957099,0.762000,-0.007357}; +Point(91) = {0.975518,0.762000,-0.007353}; +Point(92) = {0.993937,0.762000,-0.007198}; +Point(93) = {1.012356,0.762000,-0.006881}; +Point(94) = {1.030775,0.762000,-0.006421}; +Point(95) = {1.049194,0.762000,-0.005843}; +Point(96) = {1.067613,0.762000,-0.005165}; +Point(97) = {1.086032,0.762000,-0.004402}; +Point(98) = {1.104451,0.762000,-0.003562}; +Point(99) = {1.122870,0.762000,-0.002685}; +Point(100) = {1.141290,0.762000,-0.001805}; +Point(101) = {1.159709,0.762000,-0.000921}; + + +// Midplane: +Point(5351) = {xO+xL,0.000000,0.000000}; +Point(5352) = {xO+xL,0.762000,0.000000}; + +/// Lines + +// Airfoil 1: +Spline(1) = {1,2,3}; +Spline(2) = {3,4,5,6,7,8,9,10,11,12,13,14,15}; +Spline(3) = {15,16,17,18,19,20,21,22,23,24,25,26}; +Spline(4) = {26,27,28,29,30,31,32,33,34,35,36,37}; +Spline(5) = {37,38,39,40,41,42,43,44,45,46,47,48,49}; +Spline(6) = {49,50,1}; + +// Airfoil 2: +Spline(7) = {52,53,54}; +Spline(8) = {54,55,56,57,58,59,60,61,62,63,64,65,66}; +Spline(9) = {66,67,68,69,70,71,72,73,74,75,76,77}; +Spline(10) = {77,78,79,80,81,82,83,84,85,86,87,88}; +Spline(11) = {88,89,90,91,92,93,94,95,96,97,98,99,100}; +Spline(12) = {100,101,52}; + + +// Airfoil 1 to airfoil 2: +Line(61) = {1,52}; +Line(62) = {3,54}; +Line(63) = {15,66}; +Line(64) = {26,77}; +Line(65) = {37,88}; +Line(66) = {49,100}; + +// Midplane: +Line(131) = {5351,5352}; + +// Wing to midplane: +Line(161) = {1,5351}; +Line(162) = {52,5352}; +/// Line loops & Surfaces + +// Wing 1: +Line Loop(11) = {1,62,-7,-61}; +Line Loop(12) = {2,63,-8,-62}; +Line Loop(13) = {3,64,-9,-63}; +Line Loop(14) = {4,65,-10,-64}; +Line Loop(15) = {5,66,-11,-65}; +Line Loop(16) = {6,61,-12,-66}; +Surface(11) = {-11}; +Surface(12) = {-12}; +Surface(13) = {-13}; +Surface(14) = {-14}; +Surface(15) = {-15}; +Surface(16) = {-16}; + + +// Wake: +Line Loop(81) = {161,131,-162,-61}; +Surface(81) = {81}; + +/// Surface loops & Volumes + + +//// MESHING ALGORITHM + + +//// PHYSICAL GROUPS + +// Trailing edge and wake tip +Physical Line("wakeTip") = {162}; +Physical Line("te") = {61}; + +// Wing: +Physical Surface("wing") = {11,12,13}; +Physical Surface("wing_") = {14,15,16}; + +// Wake: +Physical Surface("wake") = {81}; + +Coherence; +Transfinite Curve {161, 162} = nWake Using Progression progWake; +Transfinite Curve {131, 61, 62, 66, 63, 65, 64} = nSpan Using Progression progSpan; +Transfinite Curve {-3, 4, -9, 10} = nLe Using Progression progLe; +Transfinite Curve {7, -12, 1, -6} = nTe Using Progression progTe; +Transfinite Curve {2, 5, 8, 11} = nMid Using Progression progMid; +Transfinite Surface {81}; +Transfinite Surface {12}; +Transfinite Surface {15}; +Transfinite Surface {13}; +Transfinite Surface {14}; +Transfinite Surface {11}; +Transfinite Surface {16}; + +Recombine Surface {81}; +Recombine Surface {12}; +Recombine Surface {15}; +Recombine Surface {13}; +Recombine Surface {14}; +Recombine Surface {11}; +Recombine Surface {16}; diff --git a/blast/validation/agardValidation.py b/blast/validation/agardValidation.py new file mode 100644 index 0000000..0b887fa --- /dev/null +++ b/blast/validation/agardValidation.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright 2022 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. + + +# @author Paul Dechamps +# @date 2022 +# Test the blast implementation. The test case is a compressible attached transitional flow. +# Tested functionalities; +# - Time integration. +# - Two time-marching techniques (agressive and safe). +# - Transition routines. +# - Forced transition. +# - Compressible flow routines. +# - Laminar and turbulent flow. +# +# Untested functionalities. +# - Separation routines. +# - Multiple failure case at one iteration. +# - Response to unconverged inviscid solver. + +# Imports. + +import blast.utils as viscUtils +import numpy as np +import os.path + +from fwk.wutils import parseargs +import fwk +from fwk.testing import * +from fwk.coloring import ccolors + +import math + +def cfgInviscid(nthrds, verb): + # Parameters + return { + # Options + 'scenario' : 'aerodynamic', + 'task' : 'analysis', + 'Threads' : nthrds, # number of threads + 'Verb' : verb, # verbosity + # Model (geometry or mesh) + 'File' : os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/modules/dartflo/dart/models/agard445.geo', # Input file containing the model + 'Pars' : {'xL': 7., 'yL': 3., 'zL': 6., 'xO': -3, 'zO': -3, 'msLeRt': 0.0028, 'msTeRt': 0.0056, 'msLeTp': 0.0018, 'msTeTp': 0.0036, 'msF': 1.0}, # parameters for input file model + 'Dim' : 3, # problem dimension + 'Format' : 'vtk', # save format (vtk or gmsh) + # Markers + 'Fluid' : 'field', # name of physical group containing the fluid + 'Farfield' : ['upstream', 'farfield', 'downstream'], # LIST of names of physical groups containing the farfield boundaries (upstream/downstream should be first/last element) + 'Wings' : ['wing'], # LIST of names of physical groups containing the lifting surface boundary + 'Wakes' : ['wake'], # LIST of names of physical group containing the wake + 'WakeTips' : ['wakeTip'], # LIST of names of physical group containing the edge of the wake + 'Tes' : ['te'], # LIST of names of physical group containing the trailing edge + 'dbc' : True, + 'Upstream' : 'upstream', + # Freestream + 'M_inf' : 0.954, # freestream Mach number + 'AoA' : 1, # freestream angle of attack + # Geometry + 'S_ref' : 0.35, # reference surface length + 'c_ref' : 0.47, # reference chord length + 'x_ref' : 0.0, # reference point for moment computation (x) + 'y_ref' : 0.0, # reference point for moment computation (y) + 'z_ref' : 0.0, # reference point for moment computation (z) + # Numerical + 'LSolver' : 'GMRES', # inner solver (Pardiso, MUMPS or GMRES) + 'G_fill' : 2, # fill-in factor for GMRES preconditioner + 'G_tol' : 1e-5, # tolerance for GMRES + 'G_restart' : 50, # restart for GMRES + 'Rel_tol' : 1e-6, # relative tolerance on solver residual + 'Abs_tol' : 1e-8, # absolute tolerance on solver residual + 'Max_it' : 50 # solver maximum number of iterations + } + +def cfgBlast(verb): + return { + 'Re' : 6.7e6, # Freestream Reynolds number + 'Minf' : 0.954, # Freestream Mach number (used for the computation of the time step only) + 'CFL0' : 1, # Inital CFL number of the calculation + + 'sections' : np.linspace(0.026, 0.7, 15), + 'writeSections': np.linspace(0.01, 0.76, 15), + 'Sym':[0.], + 'span': 0.762, + 'interpolator': 'Rbf', + 'rbftype': 'linear', + 'smoothing': 1e-8, + 'degree': 0, + 'neighbors': 10, + 'saveTag': 5, + + 'Verb': verb, # Verbosity level of the solver + 'couplIter': 100, # Maximum number of iterations + 'couplTol' : 1e-3, # Tolerance of the VII methodology + 'iterPrint': 1, # int, number of iterations between outputs + 'resetInv' : True, # bool, flag to reset the inviscid calculation at every iteration. + 'xtrF' : [0., 0.], # Forced transition location + 'nDim' : 3 + } + +def main(): + # Timer. + tms = fwk.Timers() + tms['total'].start() + + args = parseargs() + icfg = cfgInviscid(args.k, args.verb) + vcfg = cfgBlast(args.verb) + + parsViscous = {'nLe': 15, 'nMid': 30, 'nTe': 7, 'nSpan': 60, 'nWake': 30, + 'progLe': 1.07, 'progMid': 1.0, 'progTe': 1.0, 'progSpan': 1.0, 'progWake': 1.15} + vMsh = viscUtils.mesh(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/agard445_visc.geo', parsViscous) + vcfg['vMsh'] = vMsh + + tms['pre'].start() + coupler, iSolverAPI, vSolver = viscUtils.initBlast(icfg, vcfg) + tms['pre'].stop() + + print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET) + tms['solver'].start() + aeroCoeffs = coupler.run() + tms['solver'].stop() + + # 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(vcfg['Re']/1e6, iSolverAPI.getMinf(), iSolverAPI.getAoA()*180/math.pi, iSolverAPI.getCl(), vSolver.Cdt, vSolver.Cdp, vSolver.Cdf, iSolverAPI.getCm())) + + # Write results to file. + vSolution = viscUtils.getSolution(vSolver) + + # Write results to file. + for iSec in range(len(iSolverAPI.cfg['EffSections'])): + vSolution = viscUtils.getSolution(vSolver, iSec) + viscUtils.write(vSolution, vSolver.getRe(), sfx='slice'+str(iSec)) + vSolution['Cdt_int'] = vSolver.Cdf + iSolverAPI.getCd() + + # Save pressure coefficient + iSolverAPI.save(sfx='_viscous') + tms['total'].stop() + + print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET) + print('CPU statistics') + print(tms) + print('SOLVERS statistics') + print(coupler.tms) + + # Test solution + print(ccolors.ANSI_BLUE + 'PyTesting...' + ccolors.ANSI_RESET) + tests = CTests() + tests.add(CTest('Cl', iSolverAPI.getCl(), 0.069, 5e-2)) + tests.add(CTest('Cd wake', vSolution['Cdt_int'], 0.00498, 1e-3, forceabs=True)) + tests.add(CTest('Iterations', len(aeroCoeffs), 8, 0, forceabs=True)) + tests.run() + + # eof + print('') + +if __name__ == "__main__": + main() -- GitLab