|
| 1 | +*************************** |
| 2 | +Sample generation with CST |
| 3 | +*************************** |
| 4 | + |
| 5 | +This section explains how to use ``AirfoilCST`` module for generating samples. There are typically three |
| 6 | +main steps involved in the process: setting up options and initializing the module, adding design variables |
| 7 | +and generating samples. |
| 8 | + |
| 9 | +Setting up options |
| 10 | +------------------ |
| 11 | + |
| 12 | +First step involves creating options dictionary which is used for initializating the module. The ``airfoilFile`` |
| 13 | +and ``numCST`` are the two mandatory options, rest all are optional, please refer :ref:`options<options>` |
| 14 | +section for more details. Following snippet of the code shows an example:: |
| 15 | + |
| 16 | + from blackbox import AirfoilCST |
| 17 | + from baseclasses import AeroProblem |
| 18 | + import numpy as np |
| 19 | + |
| 20 | + solverOptions = { |
| 21 | + # Common Parameters |
| 22 | + "monitorvariables": ["cl", "cd", "cmz", "yplus"], |
| 23 | + "writeTecplotSurfaceSolution": True, |
| 24 | + "writeSurfaceSolution": False, |
| 25 | + "writeVolumeSolution": False, |
| 26 | + # Physics Parameters |
| 27 | + "equationType": "RANS", |
| 28 | + "smoother": "DADI", |
| 29 | + "MGCycle": "sg", |
| 30 | + "nsubiterturb": 10, |
| 31 | + "nCycles": 7000, |
| 32 | + # ANK Solver Parameters |
| 33 | + "useANKSolver": True, |
| 34 | + "ANKSubspaceSize": 400, |
| 35 | + "ANKASMOverlap": 3, |
| 36 | + "ANKPCILUFill": 4, |
| 37 | + "ANKJacobianLag": 5, |
| 38 | + "ANKOuterPreconIts": 3, |
| 39 | + "ANKInnerPreconIts": 3, |
| 40 | + # NK Solver Parameters |
| 41 | + "useNKSolver": True, |
| 42 | + "NKSwitchTol": 1e-6, |
| 43 | + "NKSubspaceSize": 400, |
| 44 | + "NKASMOverlap": 3, |
| 45 | + "NKPCILUFill": 4, |
| 46 | + "NKJacobianLag": 5, |
| 47 | + "NKOuterPreconIts": 3, |
| 48 | + "NKInnerPreconIts": 3, |
| 49 | + # Termination Criteria |
| 50 | + "L2Convergence": 1e-14 |
| 51 | + } |
| 52 | + |
| 53 | + meshingOptions = { |
| 54 | + # --------------------------- |
| 55 | + # Input Parameters |
| 56 | + # --------------------------- |
| 57 | + "unattachedEdgesAreSymmetry": False, |
| 58 | + "outerFaceBC": "farfield", |
| 59 | + "autoConnect": True, |
| 60 | + "BC": {1: {"jLow": "zSymm", "jHigh": "zSymm"}}, |
| 61 | + "families": "wall", |
| 62 | + # --------------------------- |
| 63 | + # Grid Parameters |
| 64 | + # --------------------------- |
| 65 | + "N": 129, |
| 66 | + "s0": 1e-6, |
| 67 | + "marchDist": 100.0, |
| 68 | + } |
| 69 | + |
| 70 | + # Creating aeroproblem for adflow |
| 71 | + ap = AeroProblem( |
| 72 | + name="ap", alpha=2.0, mach=0.734, reynolds=6.5e6, reynoldsLength=1.0, T=288.15, |
| 73 | + areaRef=1.0, chordRef=1.0, evalFuncs=["cl", "cd", "cmz"], xRef = 0.25, yRef = 0.0, zRef = 0.0 |
| 74 | + ) |
| 75 | + |
| 76 | + # Options for blackbox |
| 77 | + options = { |
| 78 | + "solverOptions": solverOptions, |
| 79 | + "noOfProcessors": 8, |
| 80 | + "aeroProblem": ap, |
| 81 | + "airfoilFile": "rae2822.dat", |
| 82 | + "numCST": [6, 6], |
| 83 | + "meshingOptions": meshingOptions, |
| 84 | + "writeAirfoilCoordinates": True, |
| 85 | + "plotAirfoil": True, |
| 86 | + "writeSliceFile": True, |
| 87 | + "samplingCriterion": "ese" |
| 88 | + } |
| 89 | + |
| 90 | + airfoil = AirfoilCST(options=options) |
| 91 | + |
| 92 | +Firstly, required packages and modules are imported. Then, ``solverOptions`` and ``meshingOptions`` are |
| 93 | +created which determine the solver and meshing settings, refer `ADflow <https://mdolab-adflow.readthedocs-hosted.com/en/latest/options.html>`_ |
| 94 | +and `pyHyp <https://mdolab-pyhyp.readthedocs-hosted.com/en/latest/options.html>`_ options for more details. |
| 95 | +Then, `AeroProblem <https://mdolab-baseclasses.readthedocs-hosted.com/en/latest/pyAero_problem.html>`_ |
| 96 | +object is created which contains details about the flow conditions and the desired output variables are |
| 97 | +defined using ``evalFuncs`` argument. Then, ``options`` dictionary is created, refer :ref:`options<options>` |
| 98 | +section for more details. Finally, the ``AirfoilCST`` module is initialized using the options dictionary. |
| 99 | + |
| 100 | +Adding design variables |
| 101 | +----------------------- |
| 102 | + |
| 103 | +Next step is to add design variables based on which samples will be generated. The ``addDV`` method needs three arguments: |
| 104 | + |
| 105 | +- ``name (str)``: name of the design variable to add. The available design variables are: |
| 106 | + |
| 107 | + - ``upper``: CST coefficients of upper surface. The number of variables will be equal to first entry |
| 108 | + in ``numCST`` list in options dictionary. |
| 109 | + - ``lower``: CST coefficients of lower surface. The number of variables will be equal to second entry |
| 110 | + in ``numCST`` list in options dictionary. |
| 111 | + - ``N1``: First class shape variable for both upper and lower surface. Adds only variable for both surfaces. |
| 112 | + - ``N2``: Second class shape variable for both upper and lower surface. Adds only variable for both surfaces. |
| 113 | + - ``alpha``: Angle of attack for the analysis. |
| 114 | + - ``mach``: Mach number for the analysis. |
| 115 | + - ``altitude``: Altitude for the analysis. |
| 116 | +- ``lowerBound (numpy array or float)``: lower bound for the variable. |
| 117 | +- ``upperBound (numpy array or float)``: upper bound for the variable. |
| 118 | + |
| 119 | + .. note:: |
| 120 | + When ``upper`` or ``lower`` variable are to be added, the lower and upper bound should be a 1D numpy array of the same size |
| 121 | + as the number of CST coefficients for that particular surface mentioned in the ``options`` dictionary. For other cases, lower |
| 122 | + and upper bound should be float. |
| 123 | + |
| 124 | +Following code adds ``alpha``, ``upper`` and ``lower`` as design variables:: |
| 125 | + |
| 126 | + airfoil.addDV("alpha", 2.0, 3.0) |
| 127 | + |
| 128 | + # Adding upper surface CST coeffs as DV |
| 129 | + coeff = airfoil.DVGeo.defaultDV["upper"] # get the fitted CST coeff |
| 130 | + lb = coeff - np.sign(coeff)*0.3*coeff |
| 131 | + ub = coeff + np.sign(coeff)*0.3*coeff |
| 132 | + |
| 133 | + airfoil.addDV("upper", lowerBound=lb, upperBound=ub) |
| 134 | + |
| 135 | + # Adding lower surface CST coeffs as DV |
| 136 | + coeff = airfoil.DVGeo.defaultDV["lower"] # get the fitted CST coeff |
| 137 | + lb = coeff - np.sign(coeff)*0.3*coeff |
| 138 | + ub = coeff + np.sign(coeff)*0.3*coeff |
| 139 | + |
| 140 | + airfoil.addDV("lower", lowerBound=lb, upperBound=ub) |
| 141 | + |
| 142 | +Here, the upper and lower bound for ``lower`` and ``upper`` variable are +30% and -30% of the fitted CST coefficients. |
| 143 | +You can also remove a design variable using ``removeDV`` method. It takes only one input which is the name of the variable. |
| 144 | + |
| 145 | +Generating samples and accessing data |
| 146 | +--------------------------------------- |
| 147 | + |
| 148 | +After adding design variables, generating samples is very easy. You just need to use ``generateSamples`` |
| 149 | +method from the initialized object. This method has two arguments: |
| 150 | + |
| 151 | +- ``numSamples (int)``: number of samples to generate |
| 152 | +- ``doe (numpy array)``: 2D numpy array in which each row represents a specific sample |
| 153 | + |
| 154 | +.. note:: |
| 155 | + You can either provide ``numSamples`` or ``doe`` i.e. both them are mutually exclusive. |
| 156 | + If both are provided, then an error will be raised. |
| 157 | + |
| 158 | +Typically, ``numSamples (int)`` should be used for generating samples. This option will internally generate doe based on the |
| 159 | +options provided while initializating the module and run the analysis. In some cases, you might want to generate samples based on your own doe. In that |
| 160 | +case, you use ``doe (numpy array)`` argument. Following snippet of the code will generate 10 samples:: |
| 161 | + |
| 162 | + airfoil.generateSamples(numSamples=10) |
| 163 | + |
| 164 | +You can see the following output upon successful completion of sample generation process: |
| 165 | + |
| 166 | +- A folder with the name specificed in the ``directory`` option (or the default name - *output*) is created. This folder contains all the generated |
| 167 | + files/folders. |
| 168 | + |
| 169 | +- Within the main output folder, there will be subfolders equal to the number of samples you requested. Each of the folder corresponds to the specific |
| 170 | + analysis performed. It will contain log.txt which contains the output from mesh generation and solver. There will be other files depending on the |
| 171 | + options provided to solver and blackbox. |
| 172 | + |
| 173 | +- ``data.mat`` file which contains: |
| 174 | + |
| 175 | + - **Input variable**: a 2D numpy array ``x`` in which each row represents a specific sample based on which analysis is performed. The number |
| 176 | + of rows will be usually equal to the number of samples argument in the ``generateSamples`` method. But, many times few of the analysis |
| 177 | + fail. It depends a lot on the solver and meshing options, so set those options after some tuning. |
| 178 | + |
| 179 | + .. note:: |
| 180 | + The order of values in each row is based on how you add design variables. In this tutorial, first ``alpha`` is added as |
| 181 | + design variable. Then, lower and upper surface CST coefficients are added. Thus, first value in each row will be alpha, next 6 |
| 182 | + values will be upper surface CST coefficients and last 6 will be lower surface CST coefficients. |
| 183 | + |
| 184 | + - **Output variables**: There are two kinds of output variables - mandatory and user specificed. The ``evalFuncs`` argument in the aero problem |
| 185 | + decides the user desired variables. Along with these variables, `area` of the airfoil is the mandatory objective. |
| 186 | + |
| 187 | + |
| 188 | + Following snippet shows how to access the data.mat file. In this tutorial, ``evalFuncs`` argument contains |
| 189 | + ``cl``, ``cd``, ``cmz``. So, data.mat will contain these variables, along with ``area``:: |
| 190 | + |
| 191 | + from scipy.io import loadmat |
| 192 | + data = loadmat("data.mat") # mention the location of mat file |
| 193 | + |
| 194 | + x = data["x"] |
| 195 | + cl = data["cl"] |
| 196 | + cd = data["cd"] |
| 197 | + cmz = data["cmz"] |
| 198 | + area = data["area"] |
| 199 | + |
| 200 | +- ``description.txt``: contains various informations about the sample generation such as design variables, bounds, number of failed analysis, etc. |
0 commit comments