Source code for psdr.demos.naca0012

from __future__ import print_function
import numpy as np

from psdr import Function, BoxDomain

__all__ = ['NACA0012']

[docs]class NACA0012(Function): r""" The lift and drag of a NACA0012 airfoil perturbed by Hicks-Henne bump functions This function computes the lift and drag of a NACA0012 airfoil perturbed by Hicks-Henne bump functions. The lift and drag are computed using [SU2]_ using Euler flow at Mach number 0.8 and angle of attack 1.25. This example slightly modifies the configuration file that appears in the SU2 quickstart folder: (inv_NACA0012.cfg)[https://github.com/su2code/SU2/blob/master/QuickStart/inv_NACA0012.cfg]. Parameters ---------- n_lower: int, optional (default: 10) Number of bump functions for the lower surface n_upper: int, optional (default: 10) Number of bump functions for the upper surface fraction: float, optional (default:0.01) References ---------- .. [SU2] https://su2code.github.io/ """ def __init__(self, n_lower = 10, n_upper = 10, fraction = 0.01, dask_client = None, **kwargs): domain = build_hicks_henne_domain(n_lower, n_upper, fraction = fraction) kwargs.update({'n_lower':n_lower, 'n_upper':n_upper}) Function.__init__(self, naca0012_func, domain, vectorized = False, kwargs = kwargs, dask_client = dask_client, return_grad = True)
def build_hicks_henne_domain(n_lower = 10, n_upper = 10, fraction = 0.1): dom = BoxDomain(-fraction*np.ones(n_lower), fraction*np.ones(n_lower), names = 'lower bump') * \ BoxDomain(-fraction*np.ones(n_upper), fraction*np.ones(n_upper), names = 'upper bump') return dom def naca0012_func(x, version = 'v1', workdir = None, verbose = False, keep_data = False, n_lower = 10, n_upper = 10, return_grad = False, maxiter = 1000, nprocesses = 1): r""" """ # If we use this inside the RedisPool, we need to load the modules # internal to this file import shutil, subprocess, os, tempfile, shlex, platform import numpy as np from subprocess import Popen, PIPE, STDOUT if workdir is None: # Docker cannot access /var by default, so we move the temporary file to # /tmp on MacOS if platform.system() == 'Darwin': workdir = tempfile.mkdtemp(dir = '/tmp') else: workdir = tempfile.mkdtemp() assert keep_data == False, "In order to keep the run, specify a path for a directory" else: workdir = os.path.abspath(workdir) os.makedirs(workdir) # Copy the inputs to a file np.savetxt(workdir + '/my.input', x, fmt = '%.15e') call = "docker run -t --rm --mount type=bind,source='%s',target='/workdir' jeffreyhokanson/naca0012:%s /workdir/my.input" % (workdir, version) call += " --nlower %d --nupper %d" % (n_lower, n_upper) if return_grad: call += " --adjoint discrete" call += ' --maxiter %d' % maxiter call += ' --nprocesses %d' % nprocesses args = shlex.split(call) with open(workdir + '/output.log', 'ab') as log: p = Popen(args, stdout = PIPE, stderr = STDOUT) while True: # Read output from pipe # TODO: this should buffer to end of line rather than fixed size output = p.stdout.readline() log.write(output) if verbose: print(output, end ='') # Check for termination if p.poll() is not None: break if p.returncode != 0: print("exited with error code %d" % p.returncode) fx = np.loadtxt(workdir + '/my.output') if return_grad: grad = np.loadtxt(workdir + '/my_grad.output') if not keep_data: shutil.rmtree(workdir) if return_grad: return fx, grad else: return fx