Output functionals are quantities that define the primary purpose of your simulation. For example, you may like to estimate lift and drag as accurately as possible for a given configuration and flow conditions. Here's how you specify output functionals when using adjoint-based mesh refinement in Cart3D.
You may be interested in many outputs from your simulations. For starters, you may need aerodynamic forces and moments of the entire configuration. Afterwards, you may like to consider aerodynamic performance of specific components in your configuration. While it is OK to have all these outputs drive the adaptation, it may not be necessary. In practice, we found that using the lift and drag functionals (or axial and normal force) with different weights works well for cases that have no side-slip angle. Add the lateral force coefficient when your cases involve side-slip. Loosely speaking, this is sufficient because all our functionals are functions of pressure. The outputs are added to flowCart's input.cntl file in a section called $__Design_Info. Here's an example of our favorite "universal" functional:
$__Force_Moment_Processing: Model_X_axis -Xb Model_Y_axis -Zb Model_Z_axis -Yb Reference_Area 1.0 all Force entire $__Design_Info: # Force Format: # # Name Force Frame J N Target Weight Bound GMP_Comp # (String) (0,1,2) (0,1) (0,1) (int) (dble) (dble) (0) # ------------------------------------------------------------------------------ optForce CD 0 0 0 1 0. 1. 0 entire optForce CL 2 0 0 1 0. 0.2 0 entire
If you simply copy-and-paste the above into your input.cntl file, then you are ready to run. For more advanced users: whenever possible try to take advantage of your GMP configuration hierarchy. For example, your entire configuration may involve wind tunnel hardware and other components that are not part of the surfaces that define your outputs. In other words, use the keyword entire sparingly.
Caution: the setup above is for geometries is in the standard Cart3D orientation (Y-is-up and Z-is-spanwise).
Keep reading if you need the details, otherwise stop.
There are two ways to specify output functionals. The most straightforward approach is to append a $__Design_Info section to the bottom of flowCart's input.cntl file. A more general approach is to specify the outputs via a Functionals.xml file. This approach allows error estimation for multiple outputs, but it requires the solution of multiple adjoints. Both approaches use the same functional syntax described below.
The functionals (J) use one of two general forms that are specified by indices 0 and 1:
| Index | Funtional Form |
|---|---|
| 0 | J = W(P - T)^N |
| 1 | J = W(1 - P / T)^N |
where P is the performance parameter, T is its target value, W is a weight and N is an exponent to allow linear and higher-order functionals. Why is there a target value? This is because these functionals can be also used as objective functions in shape optimization problems. In shape optimization, you may have design goals in mind that you specify as target values, e.g., a desired value of drag. This should not be misinterpreted as a requirement to specify the mesh converged value of drag for the adaptation. The adjoint-based mesh refinement method is not concerned with the value of the functional, instead it focuses on minimizing the discretization errors in the functional. In short, for common functionals you'll most likely specify a target value of zero. For example, if you wish to set drag as the output functional to drive the mesh refinement, select equation (0) and set P to drag, T to zero, W to one and N to one.
As performance parameters, you may select body forces and moments, L/D, and point and line field sensors. For body forces and moments, as well as L/D, you select either the aerodynamic or aircraft (body) reference frame. Use the following indices to select the desired frame:
| Index | Reference Frame |
|---|---|
| 0 | Aerodynamic |
| 1 | Aircraft (body) |
Prerequisites to the use of $__Design_Info are the definitions of the $__Force_Moment_Processing and $__Post_Processing sections. Only forces and moments declared in the $__Force_Moment_Processing section can be used to define output functionals. Similarly, point and line sensors must be first declared in the $__Post_Processing section.
The keyword optForce is used to denote force functionals. Use the following indices to select one of the three force coefficients:
| Index | Force Coefficient |
|---|---|
| 0 | Drag coefficient (CD)
in aerodynamic frame Axial force coefficient (CA) in body frame |
| 1 | Lateral force coefficient
(Cy) in aerodynamic frame Side force coefficient (CY) in body frame |
| 2 | Lift coefficient (CL)
in aerodynamic frame Normal force coefficient (CN) in body frame |
Here is an example of choosing the drag coefficient as an output functional for the component entire:
$__Force_Moment_Processing: Model_X_axis -Xb Model_Y_axis -Zb Model_Z_axis -Yb Reference_Area 1.0 all Force entire $__Design_Info: # Force Format: # # Name Force Frame J N Target Weight Bound GMP_Comp # (String) (0,1,2) (0,1) (0,1) (int) (dble) (dble) (0) # ------------------------------------------------------------------------------ optForce CD 0 0 0 1 0. 1. 0 entire
where Name can be any string and Bound is always set to zero. The key statement in the $__Force_Moment_Processing section is Force entire. This allows us to bind the drag coefficient to the component entire. You may choose any component defined in your GMP Config.xml file. If instead you are interested in the lift coefficient, then you need to change the Force index to 2 and optionally change the Name to CL. A sample case that uses the drag coefficient is the $CART3D/cases/samples_adapt/wing example.
The keyword optMoment_Point is used to denote point-moment functionals. Use the following indices to select one of the three moments:
| Index | Moment Coefficient |
|---|---|
| 0 | CM_ax in aerodynamic
frame Roll (Cl) in body frame |
| 1 | CM_ay in aerodynamic
frame Pitch (Cm) in body frame |
| 2 | CM_az in aerodynamic
frame Yaw (Cn) in body frame Lift |
Here is an example of choosing the pitching moment for the component wing:
$__Force_Moment_Processing: Model_X_axis -Xb Model_Y_axis -Zb Model_Z_axis -Yb Reference_Area 1. all Reference_Length 1. all Moment_Point 0.25 0.0 0.0 wing $__Design_Info: # Point Moment Format: # Index: 0-based index relative to moments defined above per component # # Name Index Moment Frame J N Target Weight Bound GMP_Comp # (String) (int) (0,1,2) (0,1) (0,1) (int) (dble) (dble) (0) # -------------------------------------------------------------------------------------- optMoment_Point MP0 0 1 1 0 1 0. 1. 0 wing
where most fields have already been defined in the Forces section. A new field is Index. This field identifies which Moment_Point the functional binds to. For example, you may have several moments listed for the component wing in the $__Force_Moment_Processing section, each with a different moment center. The Index field is a 0-based index that numbers the moments in the order they are listed for each component.
The keyword optLD is used to denote L/D. Depending on the chosen reference frame, the functional will use either CL and CD, or CN and CA. The performance parameter P in functionals of type 0 or 1 has the following form:
SIGN(CL )*ABS(CL )^A / (CD+Bias)
where Bias is a user specified constant that may be used to account for viscous drag. This formulation allows you to consider endurance factor functionals in the adaptation. Here is an example of choosing L/D for the component airplane:
$__Force_Moment_Processing: Model_X_axis -Xb Model_Y_axis -Zb Model_Z_axis -Yb Reference_Area 1.0 all Force airplane $__Design_Info: # L/D -> SIGN(CL)*ABS(CL)^A/(CD+Bias) in Aero Frame # -> SIGN(CN)*ABS(CN)^A/(CA+Bias) in Body Frame # Format: # # Name Frame J N A Bias Target Weight Bound GMP_Comp # (String) (0,1) (0,1) (int) (dble) (dble) (dble) (dble) (0) # --------------------------------------------------------------------------- optLD LoD 0 0 1 1. 0.001 0. 1. 0 airplane
See Forces for field details. A sample case that shows the specification of the L/D functional is the $CART3D/cases/samples_adapt/naca0012 example.
In this section, we choose a pressure sensor at an arbitrary point or along an arbitrary line in the flowfield as the output functional. For line sensors, you can also request an equivalent area functional. The sensor may lie on the surface of the geometry, however, the algorithm does not check if the sensor is outside the computational domain, i.e., inside the geometry, so be careful. To use a sensor, first define its location in the $__Post_Processing section and then specify the functional form in the $__Design_Info section. Here is an example:
$__Post_Processing: # # Line Sensor # Name Origin X Y Z Destination X Y Z lineSensor LINE1 0. 1.02 0.23 3.1 1.02 0.23 # # Equivalent Area Sensor # Name Origin X Y Z Destination X Y Z Radius eaSensor EA1 0. 1.02 0.23 3.1 1.02 0.23 1.5 # # Point Sensor # Name X Y Z pointSensor PT1 10. 0. 0. $__Design_Info: # Field Sensors # Name J N Target Weight Bound # (String) (0,1) (int) (dble) (dble) (0) # ------------------------------------------------- optSensor PT1 0 2 0. 1.0 0 optSensor LINE1 0 2 0. 1.0 0 optSensor EA1 0 2 0. 1.0 0
Note that the Name field identifies which sensors should be considered as output functionals for the adaptation. You may specify many sensors in the $__Post_Processing section and use their names to pick among them the functionals that drive the adaptation. A sample case that shows how to specify a line sensor is the $CART3D/cases/samples_adapt/cone_cylinder pressure-signature example.
The keyword optMassFlow is used to set mass flow rate through a specified component as the output of interest. First, set up $__Boundary_Conditions with the desired inflow and outflow boundary conditions. Second, make sure the GMP component names in Config.xml file match the numerical ID's of the $__Boundary_Conditions. Last, use the keyword optMassFlow in the $__Design_Info section. Here is an example:
$__Boundary_Conditions: # Inlet boundary condition # Name Comp U_n/c_inf InletVelocityBC 2 0.5 # Nozzle boundary condition # Name Comp m_dot T_t/T_t_inf PowerMFRBC 3 0.07 1.01 $__Design_Info: # Mass Flow Rate output # Name J N Target Weight Bound GMP # (String) (0,1) (int) (dble) (dble) (0) # ------------------------------------------------------------ optMassFlow inlet 0 1 0. 1.0 0 fanFace optMassFlow nozzle 0 1 0. 1.0 0 fanExit
Note that the Name field can be any string and is used to label the output functional.
If using the $__Design_Info section in input.cntl, then list all the functionals (with appropriate declarations in the $__Post_Processing and $__Force_Moment_Processing sections) in this section, one-per-line. The adaptation functional becomes the sum of the specified functionals - the sum is implied by the list. Use the Weight field to specify relative importance of the functionals. The Point and Line Sensors section (in the gray box above) shows an example. Remember that the error estimation and adaptation targets this composite functional and not its individual components.
Functionals.xml
If error estimation in multiple outputs is desired, then use a Functionals.xml file. For example:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Functionals>
<!-- Adapt to 0.1*CL + CD -->
<AeroFun ID="LplusD" Options="Adapt">
# Force Codes: CA=0 CY=1 CN=2 in Aircraft (Body) Frame
# Name Force Frame J N Target Weight Bound GMP
# (String) (0,1,2) (0,1) (0,1,2) (int) (dble) (dble) (-1,0,1)
optForce CL 2 0 0 1 0. 0.1 0 entire
optForce CD 0 0 0 1 0. 1.0 0 entire
</AeroFun>
<!-- Monitor error in CL, up to and including penultimate mesh -->
<AeroFun ID="Lift" Options="Error">
# Force Codes: CD=0 Cy=1 CL=2 in Aerodynamic Frame
# Name Force Frame J N Target Weight Bound GMP
# (String) (0,1,2) (0,1) (0,1,2) (int) (dble) (dble) (-1,0,1)
optForce CL 2 0 0 1 0. 1. 0 entire
</AeroFun>
<!-- Monitor error in CD, up to and including penultimate mesh -->
<AeroFun ID="Drag" Options="Error">
# Force Codes: CA=0 CY=1 CN=2 in Aircraft (Body) Frame
# Name Force Frame J N Target Weight Bound GMP
# (String) (0,1,2) (0,1) (0,1,2) (int) (dble) (dble) (-1,0,1)
optForce CD 0 0 0 1 0. 1. 0 entire
</AeroFun>
<!-- Monitor mesh convergence of pitch, no adjoint or error estimate -->
<AeroFun ID="Pitch">
# Name Index Moment Frame J N Target Weight Bound GMP
# (String) (int) (0,1,2) (0,1) (0,1) (int) (dble) (dble) (0)
optMoment_Point MP0 0 1 1 0 1 0. 1. 0 entire
</AeroFun>
</Functionals>
Each AeroFun element is equivalent to a $__Design_Info section. The value of the Options attribute specifies which functionals require error estimation and of these which one should be used to drive the adaptation. The keywords are as follows:
| Keyword | Meaning |
|---|---|
| Adapt | Functional that drives the adaptation. Implies error computation up to and including the penultimate mesh. Only one AeroFun element can be marked with Adapt. |
| Error | Error computation up to and including the penultimate mesh. No influence on mesh adaptation, but important for assessing if the mesh is good enough for the functional. Generates both fun_con.dat and results.dat files. |
| ErrorAll | Similar to Error, but error computation is done on all meshes, including the finest mesh. Generates both fun_con.dat and results.dat files. |
Options="Adapt, ErrorAll" is valid. If Options are omitted, then functional convergence is reported (fun_con_ID.dat), but errors are not computed.
For sonic-boom analysis problems where the farfield propagation is performed using sBOOM (ver. 2.9 or newer), noise metrics can be specified as output functionals in coupled Cart3D-sBOOM simulations. The mesh adaptation targets the farfield outputs, for example A-SEL, and the computed error estimate reflects the level of discretization error in these outputs. Technical details of the procedure are provided in AIAA-2022-4085. The farfield outputs are specified via the Functionals.xml file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Functionals>
<!-- Adapt to sBOOM noise metrics -->
<!-- Functional is specified in the sBOOM input file -->
<!-- Line-Sensor-Name is defined in input.cntl -->
<AeroFun ID="Any-Unique-String" Options="Adapt">
# Line-Sensor-Name sBOOM-input-file Weight
optSBOOM LINE1 presb.input 1.0
</AeroFun>
</Functionals>
The syntax supports all features of Functionals.xml files, such as the ability to "mix-and-match" functionals:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Functionals>
<AeroFun ID="noise_and_aero" Options="Adapt">
# Name Force Frame J N Target Weight Bound GMP
# (String) (0,1,2) (0,1) (0,1,2) (int) (dble) (dble) (-1,0,1)
optForce CL 2 0 0 1 0. 0.1 0 entire
optForce CD 0 0 0 1 0. 1.0 0 entire
# Line-Sensor-Name sBOOM-input-file Weight
optSBOOM azi_0deg presb_j4_0.input 5.0
optSBOOM azi_10deg presb_j4_10.input 5.0
</AeroFun>
</Functionals>
and error estimation for multiple outputs:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Functionals>
<!-- Each output must be assigned to a different line sensor -->
<!-- The line sensor can be colocated -->
<AeroFun ID="j4" Options="Adapt">
optSBOOM line1 presb_j4.input 1.0
</AeroFun>
<AeroFun ID="j8" Options="Error">
optSBOOM line2 presb_j8.input 1.0
</AeroFun>
<AeroFun ID="j5" Options="Error">
optSBOOM line3 presb_j5.input 1.0
</AeroFun>
</Functionals>
When a $__Design_Info section is specified or a Functionals.xml file is present, the convergence history of the functionals is recorded in an output file called functional.dat. This file is a sibling of the forces.dat and history.dat files, and shows the value of the functionals at each iteration of flowCart. In addition, there is output to flowCart's stdout stream that summarizes the specified functionals.