"""
This file contains tools for postprocessing airfoil optimizations
from the CMPLXFOIL solver class in CMPLXFOIL_solver.py.
Developers:
-----------
- Eytan Adler (EA)
- Alasdair Gray (AG)
History
-------
v. 1.0 - Initial Class Creation (EA + AG, 2022)
"""
# =============================================================================
# Standard Python modules
# =============================================================================
import os
import pickle as pkl
from glob import glob
# =============================================================================
# External Python modules
# =============================================================================
from baseclasses import AeroProblem
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# =============================================================================
# Extension modules
# =============================================================================
from .CMPLXFOIL import CMPLXFOIL
[docs]
class AnimateAirfoilOpt:
"""
Class for generating animations of airfoil optimization
"""
def __init__(self, dirName, APName):
"""
Initialize the object with the directory and AeroProblem name.
This object assumes that the files are accessible under the name
<dirName>/<APName>_<iteration number>.<dat or pkl>
and that BOTH dat (airfoil shape) and pkl (chordwise data) files
are available.
Parameters
----------
dirName : str
Name of directory that contains the airfoil optimization data files
APName : str
Name of the AeroProblem to be animated.
"""
self.dirName = dirName
self.APName = APName
# Get the list of file names and figure out how many iterations there are to plot
self.fileList = glob(os.path.join(self.dirName, f"{self.APName}_*.dat"))
for i in range(len(self.fileList)):
self.fileList[i] = self.fileList[i][:-4]
self.fileList.sort()
self.iters = len(self.fileList)
# Make sure pickle files are also available
if len(glob(os.path.join(self.dirName, f"{self.APName}_*.pkl"))) != self.iters:
raise FileNotFoundError("There must be a pickle file and dat file for each iteration")
print(f"Found dat and pkl files for {self.iters} iterations")
[docs]
def animate(self, outputFileName="airfoil_opt", ext="mp4", **animKwargs):
"""
Generate an animation of an optimization.
Parameters
----------
outputFileName : str, optional
Movie filename to save to with no extension (default "airfoil_opt")
ext : str, optional
Extension for animation ("mp4" and "gif" are useful ones)
animKwargs : optional
Additional keyword arguments to be passed to matplotlib's
FuncAnimation save method
"""
# If no animation keyword args specified and file type is mp4, set codec
if not animKwargs:
animKwargs = {"fps": 15, "dpi": 200}
if ext.lower() == "mp4":
animKwargs["extra_args"] = ["-vcodec", "libx264"]
# Create initial plot
foil = CMPLXFOIL(self.fileList[0] + ".dat")
foil.curAP = AeroProblem(self.APName, mach=0.5, altitude=0.0)
with open(self.fileList[0] + ".pkl", "rb") as f:
foil.sliceData = pkl.load(f)
fig, axs = foil.plotAirfoil()
CPlim = foil.CPlim
CFlim = foil.CFlim
xlimFoil = foil.xlimFoil
ylimFoil = foil.ylimFoil
coords0 = foil.coords0
def animateFrame(i):
"""
Function to be called by FuncAnimation
"""
print(f"Rendering frame {i} of {self.iters}.....{(i + 1)/self.iters * 100:0.2f}% done", end="\r")
foil = CMPLXFOIL(self.fileList[i] + ".dat")
foil.curAP = AeroProblem(self.APName, mach=0.5, altitude=0.0)
foil.CPlim = CPlim
foil.CFlim = CFlim
foil.xlimFoil = xlimFoil
foil.ylimFoil = ylimFoil
foil.coords0 = coords0
with open(self.fileList[i] + ".pkl", "rb") as f:
foil.sliceData = pkl.load(f)
foil.airfoilFig = fig
foil.airfoilAxs = axs
foil._updateAirfoilPlot(pause=False)
# Call the animator and save the result as a movie file
anim = FuncAnimation(fig, animateFrame, frames=self.iters, interval=66, blit=False)
anim.save(outputFileName + "." + ext, **animKwargs)
# Save the last frame
animateFrame(self.iters - 1)
plt.savefig(outputFileName + ".pdf")