Actuator Line Model Calibration

This walkthrough provides an overview of important considerations for calibrating an Actuator Line Model (ALM) for wind turbine large eddy simulation (LES). The primary focus is on calibrating the \(\epsilon\) parameter, which controls the spreading of turbine aerodynamic forces into body forces, effectively determining how these forces are distributed to the surrounding fluid. Also discussed are considerations regarding the simulation time step \(\Delta t\), the filtered lifting line correction (FLLC), the number of actuator node points, and the near-turbine resolution \(\Delta x\). The IEA-15MW-240 turbine model will be used here as an example.

Calibrating Epsilon

In this tutorial, we will focus on calibrating the epsilon parameter to align the ALM results with those obtained from a stand-alone OpenFAST simulation in uniform flow conditions. These ideal conditions are where OpenFAST turbine models are typically designed and trusted, so the OpenFAST turbine performance can be used to help tune the ALM, despite generally being a lower fidelity model. An overview of the general process is provided below.

  1. Run OpenFAST Simulations: Execute OpenFAST simulations under uniform flow conditions over a range of wind speeds to obtain baseline aerodynamic data.

  2. AMR-Wind Setup: Construct a simple single-turbine mesh in AMR-Wind that can be used to efficiently run several uniform flow simulations over a range of \(\epsilon\) parameters. Refinement zones can be useful for speeding up the calibration process, especially since there is no turbulence in the inflow. The important consideration is the near-turbine mesh size, since the \(\epsilon\) parameter will be tuned according to this resolution. The near-turbine resolution may depend, for example, on computational cost, desired fidelity, or the spacing between actuator node points. Here, an isotropic near-turbine resolution of \(\Delta x= 2.5m\) is used, with four levels of refinement that range from a 20m background mesh to the 2.5m near-turbine mesh, as shown in the following figure:

../_images/calibration_mesh.png

In this case, 50 actuator node points are used along the 120m blade, leading to a spacing of 2.4m or nearly \(\Delta x\).

  1. Adjust Epsilon: Run a series of AMR-Wind simulations over a range of epsilon values and wind speeds. Prior studies may be useful for choosing initial values. For instance, a general rule-of-thumb is that \(\epsilon / \Delta x \approx 2\) seems to perform well for a variety of turbine models, however, this is not always true as seen for the IEA-15MW-240 model here. To adjust epsilon, change the actuator epsilon parameter(s) in the AMR-Wind input file:

Actuator.T0.epsilon                      = 5.0 5.0 5.0

For isotropic values of \(\epsilon\), a single number can be used:

Actuator.T0.epsilon                      = 5.0

Five different wind speeds of 5 m/s, 6.5 m/s, 9 m/s, 11 m/s, and 14 m/s are included in the calibration here to cover regions 1, 2, and 3 performance, and six different epsilon values are tested including \(\epsilon = 1, 2, 3, 4, 5, 10\). The initial calibrations are focused primarily at 9.0m/s, and the optimal epsilon value(s) are then tested at the other wind speeds.

  1. Compare Results: Run the ALM simulations and compare the results with those obtained from OpenFAST. Focus on key performance metrics. The following figures show the results from OpenFAST and the AMR-Wind simulations at six different \(\epsilon\) values for generated power, blade pitch, rotor speed, and rotor torque.

../_images/ALM_Openfast_Comparison.png

The best agreement between the OpenFAST and ALM simulations is found for \(\epsilon = 2.0\), which leads to a 0.3% relative error in generated power at 9.0m/s. This value was also found to perform well at the other wind speeds.

In addition to comparing turbine performance metrics, it is important to make sure the ALM has not introduced non-physical oscillations in the blade loading. The mean axial and tangential blade loading curves are shown below at 9.0m/s and 6.5m/s across a range of different epsilon values. Again, the value of \(\epsilon = 2.0\) agrees well with the OpenFAST curve and does not have significant oscillations along the blade span.

../_images/ALM_Openfast_blade_loading_9.0.png ../_images/ALM_Openfast_blade_loading_6.5.png

5. Iterate: Repeat the process, adjusting epsilon as necessary until the ALM results align closely with the OpenFAST data. Based on the results shown here, \(\epsilon = 2.0\) is the recommended setting for the IEA-15MW-240 turbine model at 2.5m resolutions or equivalently \(\epsilon / \Delta x = 0.8\).

Filtered Lifting Line Correction

It has been shown that accurate predictions of the velocity field and loads along the blades are achieved with \(\epsilon^{opt} / c = 0.25\) where \(c\) is the chord length; however, this value of \(\epsilon\) is typically much finer than can be resolved in a practical LES. To correct potential issues with the ALM for coarse-scale LES that cannot resolve this optimal kernel size, the filtered lifting line correction (FLLC) can be used, as documented in Martínez-Tossas et al. (JFM 2019) and Martínez-Tossas et al. (JFM 2024). There are three steps to turning on FLLC for actuators in AMR-Wind.

  1. Increase number of actuator points: FLLC involves computing gradients along the blade, which typically requires a larger number of actuator points than an ALM without FLLC. Previous studies suggest \(\approx 300\) AeroDyn blade points is appropriate for FLLC, which is the number used here. Therefore, the first step is to increase the number of AeroDyn blade points in the AeroDyn OpenFAST .dat file. This can be done, for example, through interpolation (see Additional Resources). This number of actuator points must also be specified in the AMR-Wind input file:

Actuator.T0.num_points_blade            = 300
  1. Set epsilon_chord and epsilon_min: In addition to epsilon, the epsilon_min and epsilon_chord parameters should be specified in the AMR-Wind input file:

Actuator.T0.epsilon         = 2.0 2.0 2.0
Actuator.T0.epsilon_min     = 2.0 2.0 2.0
Actuator.T0.epsilon_chord   = 0.25 0.25 0.25

Here, epsilon and epsilon_min correspond to the value of \(\epsilon\) for the ALM without FLLC (i.e., the value found in the previous section Calibrating Epsilon). The parameter epsilon_chord corresponds to \(\epsilon^{opt} / c\) and is typically set to 0.25, as mentioned above.

  1. Turn on FLLC: For each actuator to use FLLC, the fllc parameter must be set to true

Actuator.T0.fllc                         = true

As shown in the figures below, FLLC generally improves the representation of the blade loading and maintains the good agreement in turbine performance metrics with OpenFAST.

../_images/FLLC_ALM_Openfast_Comparison.png ../_images/FLLC_ALM_Openfast_blade_loading.png

Note that raising the number of AeroDyn blade points may significantly increase computational cost. In the example here, there was a 1.8 times slowdown in the average solve time per timestep when using FLLC.

Timestep considerations

In addition to the CFL condition, there is a general rule-of-thumb that the timestep, \(\Delta t\), should be set such that the blade(tip) does not rotate more than a grid cell per time step. Below, we verify this criterion is satisfied for the timestep \(\Delta t=0.02\) used here, based on the rotor speed output from OpenFAST.

The mean rotor speed is found to range from 30.0 deg/s to 45.4 deg/s as the wind speed ranged from 5m/s to 14m/s. This means that, based on the mean rotor speeds and AMR-Wind timestep, the blades rotate between 0.60 – 0.91 deg/timesteps on average. The circumference of the rotor disk is \(240\pi\) and, on average, the blades rotate between 0.0016 – 0.0025 rotations/timestep. Therefore, the blades move between 1.25 − 1.90 m/timestep or between 0.5 − 0.76 \(\Delta x\) m/timestep. This distance is indeed less than a grid cell per timestep.

Input File

An example of the AMR-Wind input file used for the ALM calibration with \(\epsilon=2.0\) at a wind speed of 9.0m/s is included below:

  1# --- Simulation time control parameters ---
  2time.stop_time                           = 360.0               # Max (simulated) time to evolve [s]
  3time.max_step                            = -1                  
  4time.fixed_dt                            = 0.02                # Fixed timestep size (in seconds). If negative, then time.cfl is used
  5time.checkpoint_interval                 = 1000                
  6incflo.physics                           = FreeStream Actuator # List of physics models to include in simulation.
  7incflo.verbose                           = 0                   
  8io.check_file                            = chk                 
  9incflo.use_godunov                       = true                
 10incflo.godunov_type                      = weno_z              
 11turbulence.model                         = Laminar             
 12incflo.gravity                           = 0.0 0.0 -9.81       # Gravitational acceleration vector (x,y,z) [m/s^2]
 13incflo.density                           = 1.225               # Fluid density [kg/m^3]
 14transport.viscosity                      = 1.872e-05           # Fluid dynamic viscosity [kg/m-s]
 15transport.laminar_prandtl                = 0.7                 # Laminar prandtl number
 16transport.turbulent_prandtl              = 0.3333              # Turbulent prandtl number
 17ConstValue.density.value                 = 1.225               
 18ConstValue.velocity.value                = 9.0 0.0 0.0         
 19
 20# --- Geometry and Mesh ---
 21geometry.prob_lo                         = -2560.0 -960.0 -960.0
 22geometry.prob_hi                         = 2560.0 960.0 960.0  
 23amr.n_cell                               = 256 96 96           # Number of cells in x, y, and z directions
 24amr.max_level                            = 3                   
 25geometry.is_periodic                     = 0 1 1               
 26xlo.type                                 = mass_inflow         
 27xlo.density                              = 1.225               
 28xlo.velocity                             = 9.0 0.0 0.0         
 29xhi.type                                 = pressure_outflow    
 30
 31# --- ABL parameters ---
 32ICNS.source_terms                        = ActuatorForcing     
 33incflo.velocity                          = 9.0 0.0 0.0         
 34ABLForcing.abl_forcing_height            = 0.0                 
 35time.plot_interval                       = 1000                
 36io.plot_file                             = plt                 
 37io.KE_int                                = -1                  
 38Actuator.type                            = TurbineFastLine     
 39Actuator.TurbineFastLine.epsilon         = 2.0 2.0 2.0         
 40Actuator.TurbineFastLine.epsilon_tower   = 2.0 2.0 2.0         
 41Actuator.TurbineFastLine.fllc            = false               
 42Actuator.TurbineFastLine.density         = 1.225               
 43
 44#---- tagging defs ----
 45tagging.labels                           = Farm_level_0_zone Farm_level_1_zone T0_level_2_zone
 46tagging.Farm_level_0_zone.type           = GeometryRefinement  
 47tagging.Farm_level_0_zone.shapes         = Farm_level_0_zone   
 48tagging.Farm_level_0_zone.level          = 0                   
 49tagging.Farm_level_0_zone.Farm_level_0_zone.type = box                 
 50tagging.Farm_level_0_zone.Farm_level_0_zone.origin = -2400.0 -720.0 -480.0
 51tagging.Farm_level_0_zone.Farm_level_0_zone.xaxis = 4800.0 0.0 0.0      
 52tagging.Farm_level_0_zone.Farm_level_0_zone.yaxis = -0.0 1440.0 -0.0    
 53tagging.Farm_level_0_zone.Farm_level_0_zone.zaxis = 0.0 0.0 960.0       
 54tagging.Farm_level_1_zone.type           = GeometryRefinement  
 55tagging.Farm_level_1_zone.shapes         = Farm_level_1_zone   
 56tagging.Farm_level_1_zone.level          = 1                   
 57tagging.Farm_level_1_zone.Farm_level_1_zone.type = box                 
 58tagging.Farm_level_1_zone.Farm_level_1_zone.origin = -600.0 -600.0 -288.0
 59tagging.Farm_level_1_zone.Farm_level_1_zone.xaxis = 1200.0 0.0 0.0      
 60tagging.Farm_level_1_zone.Farm_level_1_zone.yaxis = -0.0 1200.0 -0.0    
 61tagging.Farm_level_1_zone.Farm_level_1_zone.zaxis = 0.0 0.0 576.0       
 62tagging.T0_level_2_zone.type             = GeometryRefinement  
 63tagging.T0_level_2_zone.shapes           = T0_level_2_zone     
 64tagging.T0_level_2_zone.level            = 2                   
 65tagging.T0_level_2_zone.T0_level_2_zone.type = box                 
 66tagging.T0_level_2_zone.T0_level_2_zone.origin = -240.0 -240.0 -240.0
 67tagging.T0_level_2_zone.T0_level_2_zone.xaxis = 480.0 0.0 0.0       
 68tagging.T0_level_2_zone.T0_level_2_zone.yaxis = -0.0 480.0 -0.0     
 69tagging.T0_level_2_zone.T0_level_2_zone.zaxis = 0.0 0.0 480.0       
 70
 71#---- actuator defs ----
 72Actuator.labels                          = T0                  
 73Actuator.T0.type                         = TurbineFastLine     
 74Actuator.T0.openfast_input_file          = T0_AMR_OpenFAST3p4_IEA15MW/IEA-15-240-RWT-Monopile/IEA-15-240-RWT-Monopile.fst
 75Actuator.T0.base_position                = 0.0 0.0 -150.0      
 76Actuator.T0.rotor_diameter               = 240.0               
 77Actuator.T0.hub_height                   = 150.0               
 78Actuator.T0.num_points_blade             = 50                  
 79Actuator.T0.num_points_tower             = 12                  
 80Actuator.T0.openfast_start_time          = 0.0                 
 81Actuator.T0.openfast_stop_time           = 10000.0             
 82Actuator.T0.fllc                         = false               
 83Actuator.T0.nacelle_drag_coeff           = 0.0                 
 84Actuator.T0.nacelle_area                 = 0.0                 
 85Actuator.T0.yaw                          = 270.0               
 86Actuator.T0.output_frequency             = 10                  
 87Actuator.T0.num_blades                   = 3                   
 88Actuator.T0.use_tip_correction           = true                
 89Actuator.T0.use_root_correction          = true                
 90
 91#---- postprocessing defs ----
 92incflo.post_processing                   = sampling            
 93sampling.type                            = Sampling            
 94sampling.output_frequency                = 100                 
 95sampling.fields                          = velocity            
 96
 97#---- sample defs ----
 98sampling.labels                          = Farm_hh             
 99sampling.Farm_hh.type                    = PlaneSampler        
100sampling.Farm_hh.num_points              = 513 193             
101sampling.Farm_hh.origin                  = -2560.0 -960.0 0.0  
102sampling.Farm_hh.axis1                   = 5120.0 0.0 0.0      
103sampling.Farm_hh.axis2                   = 0.0 1920.0 0.0      
104sampling.Farm_hh.normal                  = 0.0 0.0 0.0         
105
106#---- extra params ----
107#== END AMR-WIND INPUT ==

Additional Resources