Skip to content
Snippets Groups Projects
Verified Commit 6b4c2c31 authored by Paul Dechamps's avatar Paul Dechamps :speech_balloon:
Browse files

(refactor) Update validation cases

parent 727915b8
No related branches found
No related tags found
1 merge request!1BLASTER v1.0
Pipeline #50747 passed
......@@ -22,7 +22,7 @@
# Imports.
import blast.utils as viscUtils
import blast.utils as vutils
import numpy as np
import os.path
......@@ -53,7 +53,6 @@ def cfgInviscid(nthrds, verb):
'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.96, # freestream Mach number
......@@ -120,11 +119,11 @@ def main():
parsViscous = {'nLe': 30, 'nMid': 45, 'nTe': 10, 'nSpan': 60, 'nWake': 25,
'progLe': 1.1, 'progMid': 1.0, 'progTe': 1.0, 'progSpan': 1.0, 'progWake': 1.2}
vMsh = viscUtils.mesh(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/agard445_visc.geo', parsViscous)
vMsh = vutils.mesh(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/agard445_visc.geo', parsViscous)
vcfg['vMsh'] = vMsh
tms['pre'].start()
coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
coupler, isol, vsol = vutils.initBlast(icfg, vcfg)
tms['pre'].stop()
print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
......@@ -139,7 +138,7 @@ def main():
# Write results to file.
isol.save(sfx='_viscous'+sfxVec[i])
vSolution = viscUtils.getSolution(isol.sec, write=True, toW='all')
vSolution = vutils.getSolution(isol.sec, write=True, toW='all')
print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
print('CPU statistics')
......
#!/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 2024
# Imports.
import blast.utils as vutils
import numpy as np
from fwk.wutils import parseargs
import fwk
from fwk.testing import *
from fwk.coloring import ccolors
import math
def cfgInviscid(nthrds, verb):
import os.path
# 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.abspath(__file__)) + '/../models/dart/n0012.geo', # Input file containing the model
'Pars' : {'xLgt' : 50, 'yLgt' : 50, 'growthRatio': 1.3, 'msTe' : 0.008, 'msLe': 0.00008}, # parameters for input file model
'Dim' : 2, # problem dimension
'Format' : 'gmsh', # 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)
'Wing' : 'airfoil', # LIST of names of physical groups containing the lifting surface boundary
'Wake' : 'wake', # LIST of names of physical group containing the wake
'WakeTip' : 'wakeTip', # LIST of names of physical group containing the edge of the wake
'Te' : 'te', # LIST of names of physical group containing the trailing edge
'Upstream' : 'upstream',
# Freestream
'M_inf' : 0.16, # freestream Mach number
'AoA' : 15., # freestream angle of attack
# Geometry
'S_ref' : 1., # reference surface length
'c_ref' : 1., # reference chord length
'x_ref' : .25, # 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' : 'SparseLU', # inner solver (Pardiso, MUMPS or GMRES)
'Rel_tol' : 1e-8, # relative tolerance on solver residual
'Abs_tol' : 1e-6, # absolute tolerance on solver residual
'Max_it' : 30 # solver maximum number of iterations
}
def cfgBlast(verb):
return {
'Re' : 3e6, # Freestream Reynolds number
'Minf' : 0.16, # Freestream Mach number (used for the computation of the time step only)
'CFL0' : 0.1, # Inital CFL number of the calculation
'Verb': verb, # Verbosity level of the solver
'couplIter': 150, # Maximum number of iterations
'couplTol' : 1e-3, # Tolerance of the VII methodology
'iterPrint': 1, # int, number of iterations between outputs
'resetInv' : False, # bool, flag to reset the inviscid calculation at every iteration.
'sections' : [0], # List of sections for boundary layer calculation
'xtrF' : [None, None], # Forced transition locations
'interpolator' : 'Matching' # Interpolator for the coupling
}
def main():
# Timer.
tms = fwk.Timers()
tms['total'].start()
args = parseargs()
icfg = cfgInviscid(args.k, args.verb)
vcfg = cfgBlast(args.verb)
tms['pre'].start()
coupler, isol, vsol = vutils.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, isol.getMinf(), isol.getAoA()*180/math.pi, isol.getCl(), vsol.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
# Write results to file.
bl_solution = vutils.getSolution(isol.sec, write=False)[0]
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', isol.getCl(), 0.230, 5e-2)) # XFOIL 0.2325
tests.add(CTest('Cd wake', vsol.Cdt, 0.0057, 1e-3, forceabs=True)) # XFOIL 0.00531
tests.add(CTest('Cd integral', vsol.Cdf + isol.getCd(), 0.0058, 1e-3, forceabs=True)) # XFOIL 0.00531
tests.add(CTest('Cdf', vsol.Cdf, 0.0047, 1e-3, forceabs=True)) # XFOIL 0.00084, Cdf = 0.00447
tests.add(CTest('xtr_top', vsol.getAverageTransition(0), 0.196, 0.03, forceabs=True)) # XFOIL 0.1877
tests.add(CTest('xtr_bot', vsol.getAverageTransition(1), 0.40, 0.01, forceabs=True)) # XFOIL 0.4998
tests.add(CTest('Iterations', len(aeroCoeffs['Cl']), 20, 0, forceabs=True))
#tests.run()
# Plot results
if not args.nogui:
cpv = np.loadtxt('Cp_viscous.dat', skiprows=1, delimiter=',')
cpi = np.loadtxt('Cp_inviscid.dat', skiprows=1, delimiter=',')
cpv_xf = np.loadtxt('/'.join(__file__.split('/')[:-2])+'/models/references/n0012_15deg_xf_cpVisc.dat', skiprows=1)
bl_xf = np.loadtxt('/'.join(__file__.split('/')[:-2])+'/models/references/n0012_15deg_xf_bl.dat', skiprows=1)
from matplotlib import pyplot as plt
plt.figure()
plt.plot(cpv[:, 0], cpv[:, 3], color='firebrick', lw=2, label='BLASTER - viscous')
plt.plot(cpv_xf[:, 0], cpv_xf[:, 1], color='royalblue', lw=2, label='XFOIL - viscous')
plt.plot(cpi[:, 0], cpi[:, 3], color='firebrick', lw=1, label='BLASTER - inviscid', linestyle='--')
plt.gca().invert_yaxis()
plt.legend(frameon=False)
plt.xlabel('$x/c$')
plt.ylabel('$c_p$')
plt.draw()
plt.figure()
plt.plot(bl_solution['x'], bl_solution['cf']*bl_solution['ue']*bl_solution['ue'], color='firebrick', lw=2, label='BLASTER')
plt.plot(bl_xf[:, 1], bl_xf[:, 6], color='royalblue', lw=2, label='XFOIL')
plt.legend(frameon=False)
plt.xlim([0, 1])
plt.xlabel('$x/c$')
plt.ylabel('$c_f$')
plt.draw()
plt.show()
# eof
print('')
if __name__ == "__main__":
main()
......@@ -22,7 +22,7 @@
# Imports.
import blast.utils as viscUtils
import blast.utils as vutils
import numpy as np
import os.path
......@@ -53,7 +53,6 @@ def cfgInviscid(nthrds, verb):
'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.771, # freestream Mach number
......@@ -112,11 +111,11 @@ def main():
parsViscous = {'spn': 1.,
'nLe': 25, 'nMid': 50, 'nTe': 10, 'nSpan': 60, 'nWake': 25,
'progLe': 1.1, '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/lann_visc.msh', parsViscous)
vMsh = vutils.mesh(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/lann_visc.msh', parsViscous)
vcfg['vMsh'] = vMsh
tms['pre'].start()
coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
coupler, isol, vsol = vutils.initBlast(icfg, vcfg)
tms['pre'].stop()
print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
......@@ -130,7 +129,7 @@ def main():
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, isol.getMinf(), isol.getAoA()*180/math.pi, isol.getCl(), vsol.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
# Write results to file.
vSolution = viscUtils.getSolution(isol.sec, write=True, toW='all')
vSolution = vutils.getSolution(isol.sec, write=True, toW='all')
# Save pressure coefficient
isol.save(sfx='_viscous')
......
......@@ -22,7 +22,7 @@
# Imports.
import blast.utils as viscUtils
import blast.utils as vutils
import numpy as np
import os.path
......@@ -53,7 +53,6 @@ def cfgInviscid(nthrds, verb):
'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.839, # freestream Mach number
......@@ -110,11 +109,11 @@ def main():
vcfg = cfgBlast(args.verb)
parsViscous = {'nLe': 20, 'nTe': 8, 'nMid': 40, 'nSpan': 60, 'nWake': 20}
vMsh = viscUtils.mesh(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/onera_visc.geo', parsViscous)
vMsh = vutils.mesh(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/onera_visc.geo', parsViscous)
vcfg['vMsh'] = vMsh
tms['pre'].start()
coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
coupler, isol, vsol = vutils.initBlast(icfg, vcfg)
tms['pre'].stop()
print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
......@@ -128,7 +127,7 @@ def main():
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, isol.getMinf(), isol.getAoA()*180/math.pi, isol.getCl(), vsol.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
# Write results to file.
vSolution = viscUtils.getSolution(isol.sec, write=True, toW='all', sfx='onera')
vSolution = vutils.getSolution(isol.sec, write=True, toW='all', sfx='onera')
# Save pressure coefficient
isol.save(sfx='_viscous')
......
......@@ -18,10 +18,11 @@
# @author Paul Dechamps
# @date 2022
# Farfield mesh size is 4.547 which corresponds to a growth ratio of 1.1
# Imports.
import blast.utils as viscUtils
import blast.utils as vutils
import numpy as np
from fwk.wutils import parseargs
......@@ -43,7 +44,7 @@ def cfgInviscid(nthrds, verb):
'Verb' : verb, # verbosity
# Model (geometry or mesh)
'File' : os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/dart/rae_2.geo', # Input file containing the model
'Pars' : {'xLgt' : 50, 'yLgt' : 50, 'msF': 10, 'msTe' : 0.008, 'msLe' : 0.002}, # parameters for input file model
'Pars' : {'xLgt' : 50, 'yLgt' : 50, 'msF': 4.547, 'msTe' : 0.008, 'msLe' : 0.002}, # parameters for input file model
'Dim' : 2, # problem dimension
'Format' : 'gmsh', # save format (vtk or gmsh)
# Markers
......@@ -53,7 +54,6 @@ def cfgInviscid(nthrds, verb):
'Wake' : 'wake', # LIST of names of physical group containing the wake
'WakeTip' : 'wakeTip', # LIST of names of physical group containing the edge of the wake
'Te' : 'te', # LIST of names of physical group containing the trailing edge
'dbc' : True,
'Upstream' : 'upstream',
# Freestream
'M_inf' : 0.729, # freestream Mach number
......@@ -82,7 +82,7 @@ def cfgBlast(verb):
'Verb': verb, # Verbosity level of the solver
'couplIter': 50, # Maximum number of iterations
'couplTol' : 1e-4, # Tolerance of the VII methodology
'iterPrint': 5, # int, number of iterations between outputs
'iterPrint': 1, # int, number of iterations between outputs
'resetInv' : True, # bool, flag to reset the inviscid calculation at every iteration.
'sections' : [0],
'xtrF' : [0.03, 0.03],# Forced transition location
......@@ -103,17 +103,10 @@ def main():
_ = tbox.Pardiso()
except:
print('PARDISO not found, using SparseLu')
icfg['LSolver'] = 'SparseLu'
gr = 1.1
if gr == 1.0:
icfg['Pars']['msF'] = icfg['Pars']['msLe']
else:
n = np.log10(1-(1-gr)*icfg['Pars']['xLgt']/icfg['Pars']['msLe'])/np.log10(gr)
icfg['Pars']['msF'] = icfg['Pars']['msLe']*gr**(n-1)
icfg['LSolver'] = 'SparseLU'
tms['pre'].start()
coupler, isol, vsol = viscUtils.initBlast(icfg, vcfg)
coupler, isol, vsol = vutils.initBlast(icfg, vcfg)
tms['pre'].stop()
print(ccolors.ANSI_BLUE + 'PySolving...' + ccolors.ANSI_RESET)
......@@ -127,7 +120,7 @@ def main():
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, isol.getMinf(), isol.getAoA()*180/math.pi, isol.getCl(), vsol.Cdt, vsol.Cdp, vsol.Cdf, isol.getCm()))
# Write results to file.
vSolution = viscUtils.getSolution(isol.sec)
vSolution = vutils.getSolution(isol.sec)
tms['total'].stop()
print(ccolors.ANSI_BLUE + 'PyTiming...' + ccolors.ANSI_RESET)
......@@ -144,44 +137,27 @@ def main():
tests.add(CTest('Cd integral', isol.getCd() + vsol.Cdf, 0.0126, 1e-3, forceabs=True))
tests.add(CTest('Cdf', vsol.Cdf, 0.0067, 1e-3, forceabs=True))
tests.add(CTest('Iterations', len(aeroCoeffs['Cl']), 34, 0, forceabs=True))
tests.run()
expResults = np.loadtxt(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/models/references/rae2822_AR138_case6.dat')
expResults[:,1] *= -1
#tests.run()
# Show results
# Plot results
if not args.nogui:
iCp = viscUtils.read('Cp_inviscid.dat')
vCp = viscUtils.read('Cp_viscous.dat')
plotcp = {'curves': [np.column_stack((vCp[:,0], vCp[:,3])),
np.column_stack((iCp[:,0], iCp[:,3])),
expResults],
'labels': ['Blast (VII)', 'DART (inviscid)', 'Experimental'],
'lw': [3, 3, 2, 2],
'color': ['darkblue', 'darkblue', 'black'],
'ls': ['-', '--', 'o'],
'reverse': True,
'xlim':[0, 1],
'yreverse': True,
'legend': True,
'xlabel': '$x/c$',
'ylabel': '$c_p$'
}
viscUtils.plot(plotcp)
plotcf = {'curves': [np.column_stack((vSolution[0]['x'], vSolution[0]['cf']))],
'labels': ['Blast'],
'lw': [3, 3],
'color': ['darkblue'],
'ls': ['-'],
'reverse': True,
'xlim':[0, 1],
'ylim':[0, 0.008],
'legend': True,
'xlabel': '$x/c$',
'ylabel': '$c_f$'
}
viscUtils.plot(plotcf)
cpv = np.loadtxt('Cp_viscous.dat', skiprows=1, delimiter=',')
cpi = np.loadtxt('Cp_inviscid.dat', skiprows=1, delimiter=',')
expResults = np.loadtxt('/'.join(__file__.split('/')[:-2])+'/models/references/rae2822_AR138_case6.dat')
expResults[:,1] *= -1
from matplotlib import pyplot as plt
plt.figure()
plt.plot(cpv[:, 0], cpv[:, 3], color='firebrick', lw=2, label='BLASTER - viscous')
plt.plot(expResults[:, 0], expResults[:, 1], color='black', ls='', marker='s', markerfacecolor='none', label='Experimental')
plt.plot(cpi[:, 0], cpi[:, 3], color='firebrick', lw=1, label='BLASTER - inviscid', linestyle='--')
plt.gca().invert_yaxis()
plt.legend(frameon=False)
plt.xlabel('$x/c$')
plt.ylabel('$c_p$')
plt.draw()
plt.show()
# eof
print('')
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment