Skip to content

Instantly share code, notes, and snippets.

@talbring
Last active April 21, 2020 15:04
Show Gist options
  • Save talbring/cfd26e25218a15b8788ce4e047f97ed6 to your computer and use it in GitHub Desktop.
Save talbring/cfd26e25218a15b8788ce4e047f97ed6 to your computer and use it in GitHub Desktop.
Technical Specification User Defined Functions in SU2

Technical Specification User Defined Functions in SU2

Introduction

User-defined functions enable to customize certain elements of the code. This can include for example the definition of boundary conditions, initial conditions or output fields. The idea is that users can write small code snippets to define the desired behavior. Up to now adding new capabilities to the code required modification of the C++ code and a subsequent compilation. Most users are, however, not familiar with this process.

Proposed behavior for user-defined output

At the first step, only user-defined output functions will be supported. There are two modes of operation, inline expressions and function definitions in a separate file.

Inline Expressions

Inline expressions can be used to directly specify a custom output field as values for config options SCREEN_OUTPUT, HISTORY_OUTPUT and VOLUME_OUTPUT. For example to define the ratio of drag and lift:

SCREEN_OUTPUT = INNER_ITER, RMS_DENSITY, {DRAG/LIFT}

An expression is defined in the config file using curly braces "{}". Any output field defined in the code can be used as a variable in the expression. Furthermore, there are some basic functions available, e.g. sqrt, pow, sin, cos, tan, abs.

General Function definition

It is also possible to define more complex functions in a separate file (called functions.su2x). A basic function definition looks like the following:

def DragOverLift(){
    return DRAG/LIFT;
}

A function can then be used in an inline expression, e.g:

SCREEN_OUTPUT = INNER_ITER, RMS_DENSITY, {DragOverLift()}

It is also possible to pass arguments to a function:

def MachNumber(gamma){
    return sqrt(gamma*PRESSURE/DENSITY);
}

Then a value for that argument can be passed in the inline expression:

VOLUME_OUTPUT= COORDINATES, SOLUTION, {MachNumber(1.4)}

Special function definition

A function can be declared as a certain type. These functions are used by the code to perform some additional tasks. Currently, for the output we have three function types:

  • historyfield
  • surfaceintegral

Defining a history field using historyfield

A history field can be defined using the keyword historyfield, e.g.

def historyfield DragOverLift(){
    return DRAG/LIFT;
}

Once defined, you can simply use it without an expression:

SCREEN_OUTPUT = INNER_ITER, RMS_DENSITY, DragOverLift

Note: No arguments are allowed for functions defined as type historyfield.

Defining a surface integral value using surfaceintegral

If a definition is of type surfaceintegral, the value returned is integrated over all surface markers defined in the mesh and available in the history scope. Lets consider massflow as an example. We first define a surface integral (which is nothing but a sum of the returned value over all boundary elements):

def surfaceintegral Massflow(){
  return MASSFLOW;
}

This implicitely creates new history output fields Massflow@markerName, where markerName can be replaced with any of the markers in your mesh. For example to monitor the massflow at the OUTLET marker we would use

SCREEN_OUTPUT = INNER_ITER, RMS_DENSITY, Massflow@OUTLET

For convenience also a function Massflow() defined in the history scope, which accepts a name of a marker as its argument. This enables to easily define for example massflow or area averaged quantities, i.e.:


# Integrate area
def surfaceintegral Area(){
  return AREA;
}

# Integrate total pressure times area
def surfaceintegral PtotArea(){
  return TOTAL_PRESSURE*AREA;
}

# define area averaged total pressure as a function
def AreaAveragedPtotFunction (marker){
  return PtotArea(marker)/Area(marker);
}

# define area averaged total pressure as a output field
def historyfield AreaAveragedPtotField (){
  return PtotArea@OUTLET/Area@OUTLET;
}

In the config file we can then use the function in an expression or directly the defined field (both ways are equivalent):

SCREEN_OUTPUT = INNER_ITER, RMS_DENSITY, {AreaAveragedPTotFunction(OUTLET)}, AreaAveragedPtotField

Parser definition

The current proposal is based on the C++ parser cparse. The code is released under MIT license. Small modifications where necessary. Code is added to the externals directory. The reasons for using this implementation are the following:

  • Easy to use and to customize
  • Differentiable using CoDiPack
  • Permissive license
  • Documentation

Reasons against the library:

  • Code is not very well written
  • Performance unkown for large scale applications
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment