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.
Run OpenFAST Simulations: Execute OpenFAST simulations under uniform flow conditions over a range of wind speeds to obtain baseline aerodynamic data.
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:
In this case, 50 actuator node points are used along the 120m blade, leading to a spacing of 2.4m or nearly \(\Delta x\).
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.
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.
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.
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.
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
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.
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.
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
A Jupyter notebook for comparing AMR-Wind ALM results to OpenFAST data for the purpose of calibrating \(\epsilon\) can be found on GitHub: https://github.com/gyalla/ALM_Calibrations/blob/main/ALM_Calibration_Notebook.ipynb. This notebook was used to make the figures shown here.
A python script for interpolating AeroDyn OpenFAST .dat files to an arbitrary number of blade points can be on GitHub: https://github.com/gyalla/ALM_Calibrations/blob/main/interpolate_aerodyn.py.