source: palm/trunk/SOURCE/wind_turbine_model_mod.f90 @ 3049

Last change on this file since 3049 was 3049, checked in by Giersch, 6 years ago

Revision history corrected

  • Property svn:keywords set to Id
File size: 119.1 KB
RevLine 
[1820]1!> @file wind_turbine_model_mod.f90
[1912]2!------------------------------------------------------------------------------!
[2696]3! This file is part of the PALM model system.
[1819]4!
[2000]5! PALM is free software: you can redistribute it and/or modify it under the
6! terms of the GNU General Public License as published by the Free Software
7! Foundation, either version 3 of the License, or (at your option) any later
8! version.
[1819]9!
10! PALM is distributed in the hope that it will be useful, but WITHOUT ANY
11! WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12! A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13!
14! You should have received a copy of the GNU General Public License along with
15! PALM. If not, see <http://www.gnu.org/licenses/>.
16!
[2718]17! Copyright 2009-2018 Carl von Ossietzky Universitaet Oldenburg
18! Copyright 1997-2018 Leibniz Universitaet Hannover
[1912]19!------------------------------------------------------------------------------!
[1819]20!
21! Current revisions:
22! -----------------
[1913]23!
[3049]24!
[1913]25! Former revisions:
26! -----------------
27! $Id: wind_turbine_model_mod.f90 3049 2018-05-29 13:52:36Z Giersch $
[3049]28! Error messages revised
29!
30! 2932 2018-03-26 09:39:22Z Giersch
[2932]31! renamed wind_turbine_par to wind_turbine_parameters
32!
33! 2894 2018-03-15 09:17:58Z Giersch
[2894]34! variable named found has been introduced for checking if restart data was
35! found, reading of restart strings has been moved completely to
36! read_restart_data_mod, wind_turbine_prerun flag has been removed, redundant
37! skipping function has been removed, wtm_read/write_restart_data have been
38! renamed to wtm_r/wrd_global, wtm_rrd_global is called in
39! read_restart_data_mod now, marker *** end wtm *** was removed, strings and
40! their respective lengths are written out and read now in case of restart
41! runs to get rid of prescribed character lengths, CASE DEFAULT was added if
42! restart data is read
43!
44! 2885 2018-03-14 11:02:46Z Giersch
[2836]45! Bugfix in interpolation of lift and drag coefficients on fine grid of radius
46! segments and angles of attack, speed-up of the initialization of the wind
47! turbine model
48!
49! 2792 2018-02-07 06:45:29Z Giersch
[2792]50! omega_rot_l has to be calculated after determining the indices for the hub in
51! case of restart runs
52!
53! 2776 2018-01-31 10:44:42Z Giersch
[2776]54! wind_turbine_prerun flag is used to define if module
55! related parameters were outputted as restart data
56!
57! 2718 2018-01-02 08:49:38Z maronga
[2716]58! Corrected "Former revisions" section
59!
60! 2696 2017-12-14 17:12:51Z kanani
61! Change in file header (GPL part)
62!
63! 2669 2017-12-06 16:03:27Z raasch
[2669]64! filename of turbine output changed to WTM_OUTPUT_DATA. File extension now
65! includes the nest domain number. Turbine extension changed to "_T##"
66!
67! 2576 2017-10-24 13:49:46Z Giersch
[2894]68! Definition of a new function called wtm_skip_global to skip module
[2576]69! parameters during reading restart data
70!
71! 2563 2017-10-19 15:36:10Z Giersch
[2563]72! Restart runs with wind turbine model are possible now. For this purpose, two
73! new subroutines wtm_write_restart_data and wtm_read_restart_data had to be
74! defined
75!
76! 2553 2017-10-18 08:03:45Z Giersch
[2553]77! Bugfix of vertical loop in wtm_tendencies to account for different turbine
78! heights, bugfix of the interpolation of the u-component concerning the
79! vertical index and further small adjustments of the programming style
80!
81! 2410 2017-09-06 08:16:30Z Giersch
[2410]82! Revise error message PA0462
83!
84! 2349 2017-08-10 15:44:04Z Giersch
[2349]85! Add parameter pitch_rate to namelist and revise/add error messages
86!
87! 2343 2017-08-08 11:28:43Z Giersch
[2341]88! Unit correction in Doxygen comments
[2323]89!
[2343]90! 2323 2017-07-26 12:57:38Z Giersch
91! Change unit number of file WTM_DATA from 201 to 90
92
[2323]93! 2322 2017-07-26 08:30:28Z Giersch
[2322]94! Bugfix of error message and assign error numbers
95!
96! 2257 2017-06-07 14:07:05Z witha
[2257]97! Bugfix: turb_cl_tab and turb_cd_tab were set to zero before being allocated
[1844]98!
[2257]99! 2233 2017-05-30 18:08:54Z suehring
100!
[2233]101! 2232 2017-05-30 17:47:52Z suehring
102! Adjustments to new topography concept
103!
[2153]104! 2152 2017-02-17 13:27:24Z lvollmer
105! Bugfix in subroutine wtm_read_blade_tables
106! Addition of a tip loss model
107!
[2016]108! 2015 2016-09-28 08:45:18Z lvollmer
109! Bugfix of pitch control
110!
[2001]111! 2000 2016-08-20 18:09:15Z knoop
112! Forced header and separation lines into 80 columns
113!
[1930]114! 1929 2016-06-09 16:25:25Z suehring
115! Bugfix: added preprocessor directives for parallel and serial mode
116!
[1917]117! 1914 2016-05-26 14:44:07Z witha
[1821]118! Initial revision
119!
[1819]120!
121! Description:
122! ------------
123!> This module calculates the effect of wind turbines on the flow fields. The
124!> initial version contains only the advanced actuator disk with rotation method
125!> (ADM-R).
126!> The wind turbines include the tower effect, can be yawed and tilted.
127!> The wind turbine model includes controllers for rotational speed, pitch and
128!> yaw.
129!> Currently some specifications of the NREL 5 MW reference turbine
130!> are hardcoded whereas most input data comes from separate files (currently
131!> external, planned to be included as namelist which will be read in
132!> automatically).
133!>
134!> @todo Revise code according to PALM Coding Standard
135!> @todo Implement ADM and ALM turbine models
136!> @todo Generate header information
[1917]137!> @todo Implement further parameter checks and error messages
[1819]138!> @todo Revise and add code documentation
139!> @todo Output turbine parameters as timeseries
140!> @todo Include additional output variables
[1864]141!> @todo Revise smearing the forces for turbines in yaw
142!> @todo Revise nacelle and tower parameterization
143!> @todo Allow different turbine types in one simulation
[1819]144!
145!------------------------------------------------------------------------------!
146 MODULE wind_turbine_model_mod
147
148    USE arrays_3d,                                                             &
[2553]149        ONLY:  tend, u, v, w, zu, zw
[1819]150
[2553]151    USE constants,                                                             &
152        ONLY:  pi
[1819]153
154    USE control_parameters,                                                    &
[2669]155        ONLY:  coupling_char, dt_3d, dz, message_string, simulated_time,       &
[2894]156               wind_turbine, initializing_actions
[1819]157
158    USE cpulog,                                                                &
159        ONLY:  cpu_log, log_point_s
160
161    USE grid_variables,                                                        &
162        ONLY:  ddx, dx, ddy, dy
163
164    USE indices,                                                               &
165        ONLY:  nbgp, nx, nxl, nxlg, nxr, nxrg, ny, nyn, nyng, nys, nysg, nz,   &
[2232]166               nzb, nzt, wall_flags_0
[1819]167
168    USE kinds
169
170    USE pegrid
171
172
173    IMPLICIT NONE
174
[1864]175    PRIVATE
[1819]176
177!
178!-- Variables specified in the namelist wind_turbine_par
179
[1864]180    INTEGER(iwp) ::  nairfoils = 8   !< number of airfoils of the used turbine model (for ADM-R and ALM)
[1839]181    INTEGER(iwp) ::  nturbines = 1   !< number of turbines
[1819]182
[1839]183    LOGICAL ::  pitch_control = .FALSE.   !< switch for use of pitch controller
184    LOGICAL ::  speed_control = .FALSE.   !< switch for use of speed controller
185    LOGICAL ::  yaw_control   = .FALSE.   !< switch for use of yaw controller
[2152]186    LOGICAL ::  tl_cor        = .FALSE.    !< switch for use of tip loss correct.
[1819]187
[1839]188    REAL(wp) ::  segment_length  = 1.0_wp          !< length of the segments, the rotor area is divided into
189                                                   !< (in tangential direction, as factor of MIN(dx,dy,dz))
190    REAL(wp) ::  segment_width   = 0.5_wp          !< width of the segments, the rotor area is divided into
191                                                   !< (in radial direction, as factor of MIN(dx,dy,dz))
192    REAL(wp) ::  time_turbine_on = 0.0_wp          !< time at which turbines are started
193    REAL(wp) ::  tilt            = 0.0_wp          !< vertical tilt of the rotor [degree] ( positive = backwards )
[1819]194
[1912]195    REAL(wp), DIMENSION(1:100) ::  dtow             = 0.0_wp  !< tower diameter [m]
[2553]196    REAL(wp), DIMENSION(1:100) ::  omega_rot        = 0.9_wp  !< inital or constant rotor speed [rad/s]
[1912]197    REAL(wp), DIMENSION(1:100) ::  phi_yaw          = 0.0_wp  !< yaw angle [degree] ( clockwise, 0 = facing west )
198    REAL(wp), DIMENSION(1:100) ::  pitch_add        = 0.0_wp  !< constant pitch angle
199    REAL(wp), DIMENSION(1:100) ::  rcx        = 9999999.9_wp  !< position of hub in x-direction
200    REAL(wp), DIMENSION(1:100) ::  rcy        = 9999999.9_wp  !< position of hub in y-direction
201    REAL(wp), DIMENSION(1:100) ::  rcz        = 9999999.9_wp  !< position of hub in z-direction
202    REAL(wp), DIMENSION(1:100) ::  rnac             = 0.0_wp  !< nacelle diameter [m]
203    REAL(wp), DIMENSION(1:100) ::  rr              = 63.0_wp  !< rotor radius [m]
204    REAL(wp), DIMENSION(1:100) ::  turb_cd_nacelle = 0.85_wp  !< drag coefficient for nacelle
205    REAL(wp), DIMENSION(1:100) ::  turb_cd_tower    = 1.2_wp  !< drag coefficient for tower
[1839]206
[1819]207!
208!-- Variables specified in the namelist for speed controller
209!-- Default values are from the NREL 5MW research turbine (Jonkman, 2008)
210
[1912]211    REAL(wp) ::  rated_power    = 5296610.0_wp    !< rated turbine power [W]
[1839]212    REAL(wp) ::  gear_ratio     = 97.0_wp         !< Gear ratio from rotor to generator
[2341]213    REAL(wp) ::  inertia_rot    = 34784179.0_wp   !< Inertia of the rotor [kg*m2]
214    REAL(wp) ::  inertia_gen    = 534.116_wp      !< Inertia of the generator [kg*m2]
[1839]215    REAL(wp) ::  gen_eff        = 0.944_wp        !< Electric efficiency of the generator
216    REAL(wp) ::  gear_eff       = 1.0_wp          !< Loss between rotor and generator
217    REAL(wp) ::  air_dens       = 1.225_wp        !< Air density to convert to W [kg/m3]
218    REAL(wp) ::  rated_genspeed = 121.6805_wp     !< Rated generator speed [rad/s]
[1912]219    REAL(wp) ::  max_torque_gen = 47402.91_wp     !< Maximum of the generator torque [Nm]
[1839]220    REAL(wp) ::  slope2         = 2.332287_wp     !< Slope constant for region 2
221    REAL(wp) ::  min_reg2       = 91.21091_wp     !< Lower generator speed boundary of region 2 [rad/s]
222    REAL(wp) ::  min_reg15      = 70.16224_wp     !< Lower generator speed boundary of region 1.5 [rad/s]
[1912]223    REAL(wp) ::  max_trq_rate   = 15000.0_wp      !< Max generator torque increase [Nm/s]
224    REAL(wp) ::  pitch_rate     = 8.0_wp          !< Max pitch rate [degree/s]
[1839]225
[1912]226
[1819]227!
228!-- Variables specified in the namelist for yaw control
229
[1839]230    REAL(wp) ::  yaw_speed = 0.005236_wp   !< speed of the yaw actuator [rad/s]
231    REAL(wp) ::  max_miss = 0.08726_wp     !< maximum tolerated yaw missalignment [rad]
232    REAL(wp) ::  min_miss = 0.008726_wp    !< minimum yaw missalignment for which the actuator stops [rad]
233
[1819]234!
235!-- Set flag for output files TURBINE_PARAMETERS
236    TYPE file_status
237       LOGICAL ::  opened, opened_before
238    END TYPE file_status
239   
[1912]240    TYPE(file_status), DIMENSION(500) :: openfile_turb_mod =                   &
241                                         file_status(.FALSE.,.FALSE.)
[1819]242
243!
244!-- Variables for initialization of the turbine model
245
[1839]246    INTEGER(iwp) ::  inot         !< turbine loop index (turbine id)
247    INTEGER(iwp) ::  nsegs_max    !< maximum number of segments (all turbines, required for allocation of arrays)
248    INTEGER(iwp) ::  nrings_max   !< maximum number of rings (all turbines, required for allocation of arrays)
249    INTEGER(iwp) ::  ring         !< ring loop index (ring number)
250    INTEGER(iwp) ::  rr_int       !<
251    INTEGER(iwp) ::  upper_end    !<
[1819]252
[1839]253    INTEGER(iwp), DIMENSION(1) ::  lct   !<
[1819]254
[1912]255    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  i_hub     !< index belonging to x-position of the turbine
256    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  i_smear   !< index defining the area for the smearing of the forces (x-direction)
257    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  j_hub     !< index belonging to y-position of the turbine
258    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  j_smear   !< index defining the area for the smearing of the forces (y-direction)
259    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  k_hub     !< index belonging to hub height
260    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  k_smear   !< index defining the area for the smearing of the forces (z-direction)
261    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nrings    !< number of rings per turbine
262    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nsegs_total !< total number of segments per turbine
[1819]263
[1912]264    INTEGER(iwp), DIMENSION(:,:), ALLOCATABLE ::  nsegs   !< number of segments per ring and turbine
[1819]265
[1912]266!
267!-  parameters for the smearing from the rotor to the cartesian grid   
[1864]268    REAL(wp) ::  pol_a            !< parameter for the polynomial smearing fct
269    REAL(wp) ::  pol_b            !< parameter for the polynomial smearing fct
[1912]270    REAL(wp) ::  delta_t_factor   !<
[1864]271    REAL(wp) ::  eps_factor       !< 
[1839]272    REAL(wp) ::  eps_min          !<
273    REAL(wp) ::  eps_min2         !<
274    REAL(wp) ::  sqrt_arg         !<
[1819]275
[1839]276!
277!-- Variables for the calculation of lift and drag coefficients
[1912]278    REAL(wp), DIMENSION(:), ALLOCATABLE  ::  ard     !<
279    REAL(wp), DIMENSION(:), ALLOCATABLE  ::  crd     !<
280    REAL(wp), DIMENSION(:), ALLOCATABLE  ::  delta_r !< radial segment length
281    REAL(wp), DIMENSION(:), ALLOCATABLE  ::  lrd     !<
[1864]282   
[1912]283    REAL(wp) ::  accu_cl_cd_tab = 0.1_wp  !< Accuracy of the interpolation of
284                                          !< the lift and drag coeff [deg]
[1819]285
[1912]286    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: turb_cd_tab   !< table of the blade drag coefficient
287    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: turb_cl_tab   !< table of the blade lift coefficient
[1819]288
[1912]289    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  nac_cd_surf  !< 3d field of the tower drag coefficient
290    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  tow_cd_surf  !< 3d field of the nacelle drag coefficient
[1819]291
292!
293!-- Variables for the calculation of the forces
[1912]294     
[1839]295    REAL(wp) ::  cur_r                       !<
296    REAL(wp) ::  phi_rotor                   !<
297    REAL(wp) ::  pre_factor                  !< 
298    REAL(wp) ::  torque_seg                  !<
299    REAL(wp) ::  u_int_l                     !<
300    REAL(wp) ::  u_int_u                     !<
301    REAL(wp) ::  u_rot                       !<
302    REAL(wp) ::  v_int_l                     !<
303    REAL(wp) ::  v_int_u                     !<
304    REAL(wp) ::  w_int_l                     !<
305    REAL(wp) ::  w_int_u                     !<
[1912]306!
307!-  Tendencies from the nacelle and tower thrust
308    REAL(wp) ::  tend_nac_x = 0.0_wp  !<
309    REAL(wp) ::  tend_tow_x = 0.0_wp  !<
310    REAL(wp) ::  tend_nac_y = 0.0_wp  !<
311    REAL(wp) ::  tend_tow_y = 0.0_wp  !<
[1819]312
[1912]313    REAL(wp), DIMENSION(:), ALLOCATABLE ::  alpha_attack !<
314    REAL(wp), DIMENSION(:), ALLOCATABLE ::  chord        !<
315    REAL(wp), DIMENSION(:), ALLOCATABLE ::  phi_rel      !<
316    REAL(wp), DIMENSION(:), ALLOCATABLE ::  torque_total !<
317    REAL(wp), DIMENSION(:), ALLOCATABLE ::  thrust_rotor !<
318    REAL(wp), DIMENSION(:), ALLOCATABLE ::  turb_cl      !<
319    REAL(wp), DIMENSION(:), ALLOCATABLE ::  turb_cd      !<
320    REAL(wp), DIMENSION(:), ALLOCATABLE ::  vrel         !<
321    REAL(wp), DIMENSION(:), ALLOCATABLE ::  vtheta       !<
322
323    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  rbx, rby, rbz     !< coordinates of the blade elements
324    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  rotx, roty, rotz  !< normal vectors to the rotor coordinates
325
326!
327!-  Fields for the interpolation of velocities on the rotor grid
328    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  u_int       !<
329    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  u_int_1_l   !<
330    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  v_int       !<
331    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  v_int_1_l   !<
332    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  w_int       !<
333    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  w_int_1_l   !<
334   
335!
336!-  rotor tendencies on the segments
337    REAL(wp), DIMENSION(:), ALLOCATABLE :: thrust_seg   !<
338    REAL(wp), DIMENSION(:), ALLOCATABLE :: torque_seg_y !<
339    REAL(wp), DIMENSION(:), ALLOCATABLE :: torque_seg_z !<   
340
341!
342!-  rotor tendencies on the rings
343    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  thrust_ring       !<
344    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  torque_ring_y     !<
345    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  torque_ring_z     !<
346   
347!
348!-  rotor tendencies on rotor grids for all turbines
349    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  thrust      !<
350    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  torque_y    !<
351    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  torque_z    !<
352
353!
354!-  rotor tendencies on coordinate grid
355    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  rot_tend_x  !<
356    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  rot_tend_y  !<
357    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  rot_tend_z  !<
358!   
359!-  variables for the rotation of the rotor coordinates       
360    REAL(wp), DIMENSION(1:100,1:3,1:3) ::  rot_coord_trans  !< matrix for rotation of rotor coordinates
361   
[1839]362    REAL(wp), DIMENSION(1:3) ::  rot_eigen_rad   !<
363    REAL(wp), DIMENSION(1:3) ::  rot_eigen_azi   !<
364    REAL(wp), DIMENSION(1:3) ::  rot_eigen_nor   !<
365    REAL(wp), DIMENSION(1:3) ::  re              !<
366    REAL(wp), DIMENSION(1:3) ::  rea             !<
367    REAL(wp), DIMENSION(1:3) ::  ren             !<
368    REAL(wp), DIMENSION(1:3) ::  rote            !<
369    REAL(wp), DIMENSION(1:3) ::  rota            !<
370    REAL(wp), DIMENSION(1:3) ::  rotn            !<
[1819]371
[1839]372!
373!-- Fixed variables for the speed controller
[1819]374
[1912]375    LOGICAL  ::  start_up = .TRUE.   !<
[1864]376   
[1912]377    REAL(wp) ::  Fcorner             !< corner freq for the controller low pass filter
378    REAL(wp) ::  min_reg25           !< min region 2.5
379    REAL(wp) ::  om_rate             !< rotor speed change
380    REAL(wp) ::  slope15             !< slope in region 1.5
381    REAL(wp) ::  slope25             !< slope in region 2.5
382    REAL(wp) ::  trq_rate            !< torque change
383    REAL(wp) ::  vs_sysp             !<
384    REAL(wp) ::  lp_coeff            !< coeff for the controller low pass filter
[1819]385
[1864]386    REAL(wp), DIMENSION(100) :: omega_rot_l = 0.0_wp !< local rot speed [rad/s]
[2563]387
[1839]388!
389!-- Fixed variables for the yaw controller
[1819]390
[1912]391    REAL(wp), DIMENSION(:)  , ALLOCATABLE ::  yawdir           !< direction to yaw
392    REAL(wp), DIMENSION(:)  , ALLOCATABLE ::  phi_yaw_l        !< local (cpu) yaw angle
393    REAL(wp), DIMENSION(:)  , ALLOCATABLE ::  wd30_l           !< local (cpu) long running avg of the wd
394    REAL(wp), DIMENSION(:)  , ALLOCATABLE ::  wd2_l            !< local (cpu) short running avg of the wd
395    REAL(wp), DIMENSION(:)  , ALLOCATABLE ::  wdir             !< wind direction at hub
396    REAL(wp), DIMENSION(:)  , ALLOCATABLE ::  u_inflow         !< wind speed at hub
397    REAL(wp), DIMENSION(:)  , ALLOCATABLE ::  wdir_l           !<
398    REAL(wp), DIMENSION(:)  , ALLOCATABLE ::  u_inflow_l       !<
399    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  wd30             !<
400    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  wd2              !<
401    LOGICAL,  DIMENSION(1:100)            ::  doyaw = .FALSE.  !<
402    INTEGER(iwp)                          ::  WDLON            !<
403    INTEGER(iwp)                          ::  WDSHO            !<
[1819]404
[2563]405!
406!-- Variables that have to be saved in the binary file for restarts
407    REAL(wp), DIMENSION(1:100) ::  pitch_add_old           = 0.0_wp  !< old constant pitch angle
408    REAL(wp), DIMENSION(1:100) ::  omega_gen               = 0.0_wp  !< curr. generator speed
409    REAL(wp), DIMENSION(1:100) ::  omega_gen_f             = 0.0_wp  !< filtered generator speed
410    REAL(wp), DIMENSION(1:100) ::  omega_gen_old           = 0.0_wp  !< last generator speed
411    REAL(wp), DIMENSION(1:100) ::  omega_gen_f_old         = 0.0_wp  !< last filtered generator speed
412    REAL(wp), DIMENSION(1:100) ::  torque_gen              = 0.0_wp  !< generator torque
413    REAL(wp), DIMENSION(1:100) ::  torque_gen_old          = 0.0_wp  !< last generator torque
[1819]414
[2563]415
[1839]416    SAVE
[1819]417
[1839]418
419    INTERFACE wtm_parin
420       MODULE PROCEDURE wtm_parin
421    END INTERFACE wtm_parin
[2563]422
[2894]423    INTERFACE wtm_wrd_global 
424       MODULE PROCEDURE wtm_wrd_global 
425    END INTERFACE wtm_wrd_global
[2576]426
[2894]427    INTERFACE wtm_rrd_global 
428       MODULE PROCEDURE wtm_rrd_global
429    END INTERFACE wtm_rrd_global 
[1912]430   
431    INTERFACE wtm_check_parameters
432       MODULE PROCEDURE wtm_check_parameters
433    END INTERFACE wtm_check_parameters
[1839]434       
435    INTERFACE wtm_init_arrays
436       MODULE PROCEDURE wtm_init_arrays
437    END INTERFACE wtm_init_arrays
438
439    INTERFACE wtm_init
440       MODULE PROCEDURE wtm_init
441    END INTERFACE wtm_init
442   
[1912]443    INTERFACE wtm_read_blade_tables
444       MODULE PROCEDURE wtm_read_blade_tables
445    END INTERFACE wtm_read_blade_tables
[1839]446           
[1819]447    INTERFACE wtm_forces
448       MODULE PROCEDURE wtm_forces
[2553]449    END INTERFACE wtm_forces
450
451    INTERFACE wtm_yawcontrol
[1839]452       MODULE PROCEDURE wtm_yawcontrol
[2553]453    END INTERFACE wtm_yawcontrol
[1864]454   
455    INTERFACE wtm_rotate_rotor
456       MODULE PROCEDURE wtm_rotate_rotor
457    END INTERFACE wtm_rotate_rotor
458   
459    INTERFACE wtm_speed_control
460       MODULE PROCEDURE wtm_init_speed_control
461       MODULE PROCEDURE wtm_speed_control
462    END INTERFACE wtm_speed_control
[1819]463
464    INTERFACE wtm_tendencies
465       MODULE PROCEDURE wtm_tendencies
466       MODULE PROCEDURE wtm_tendencies_ij
467    END INTERFACE wtm_tendencies
[1864]468   
469   
[1912]470    PUBLIC wtm_check_parameters, wtm_forces, wtm_init, wtm_init_arrays,        &
[2894]471           wtm_parin, wtm_wrd_global, wtm_rrd_global, wtm_tendencies
[1819]472
[2563]473
[1819]474 CONTAINS
475
476
477!------------------------------------------------------------------------------!
478! Description:
479! ------------
[1839]480!> Parin for &wind_turbine_par for wind turbine model
[1819]481!------------------------------------------------------------------------------!
[1839]482    SUBROUTINE wtm_parin
[1819]483
484
485       IMPLICIT NONE
[1912]486       
487       INTEGER(iwp) ::  ierrn       !<
[1819]488
[1839]489       CHARACTER (LEN=80) ::  line  !< dummy string that contains the current line of the parameter file
490
491       NAMELIST /wind_turbine_par/   air_dens, dtow, gear_eff, gear_ratio,     &
[1864]492                                  gen_eff, inertia_gen, inertia_rot, max_miss, &
[1839]493                                  max_torque_gen, max_trq_rate, min_miss,      &
[1864]494                                  min_reg15, min_reg2, nairfoils, nturbines,   &
[1912]495                                  omega_rot, phi_yaw, pitch_add, pitch_control,&
[1839]496                                  rated_genspeed, rated_power, rcx, rcy, rcz,  &
497                                  rnac, rr, segment_length, segment_width,     &
[1864]498                                  slope2, speed_control, tilt, time_turbine_on,&
[2349]499                                  turb_cd_nacelle, turb_cd_tower, pitch_rate,  &
[2152]500                                  yaw_control, yaw_speed, tl_cor
[2932]501                                 
502       NAMELIST /wind_turbine_parameters/                                      &
503                                  air_dens, dtow, gear_eff, gear_ratio,        &
504                                  gen_eff, inertia_gen, inertia_rot, max_miss, &
505                                  max_torque_gen, max_trq_rate, min_miss,      &
506                                  min_reg15, min_reg2, nairfoils, nturbines,   &
507                                  omega_rot, phi_yaw, pitch_add, pitch_control,&
508                                  rated_genspeed, rated_power, rcx, rcy, rcz,  &
509                                  rnac, rr, segment_length, segment_width,     &
510                                  slope2, speed_control, tilt, time_turbine_on,&
511                                  turb_cd_nacelle, turb_cd_tower, pitch_rate,  &
512                                  yaw_control, yaw_speed, tl_cor
[1819]513!
[1839]514!--    Try to find wind turbine model package
515       REWIND ( 11 )
516       line = ' '
[2932]517       DO  WHILE ( INDEX( line, '&wind_turbine_parameters' ) == 0 )
[1839]518          READ ( 11, '(A)', END=10 )  line
519       ENDDO
520       BACKSPACE ( 11 )
521
522!
523!--    Read user-defined namelist
[2932]524       READ ( 11, wind_turbine_parameters, IOSTAT=ierrn )
525
526       IF ( ierrn < 0 )  THEN
527          message_string = 'no wind_turbine_parameters-NAMELIST found: '  //    &
528                           'End of file has reached'
529          CALL message( 'wtm_parin', 'PA0460', 1, 2, 0, 6, 0 )
530       ELSEIF ( ierrn > 0 ) THEN
531          message_string = 'errors in wind_turbine_parameters-NAMELIST: '  //   &
532                           'some variables for steering may not be properly set'
533          CALL message( 'wtm_parin', 'PA0466', 1, 2, 0, 6, 0 )               
534       ENDIF
535       
536!
537!--    Set flag that indicates that the wind turbine model is switched on
538       wind_turbine = .TRUE.
539       
540       GOTO 12
541
542!
543!--    Try to find wind turbine model package
544 10    REWIND ( 11 )
545       line = ' '
546       DO  WHILE ( INDEX( line, '&wind_turbine_par' ) == 0 )
547          READ ( 11, '(A)', END=12 )  line
548       ENDDO
549       BACKSPACE ( 11 )
550
551!
552!--    Read user-defined namelist
[1912]553       READ ( 11, wind_turbine_par, IOSTAT=ierrn )
[2349]554
[1912]555       IF ( ierrn < 0 )  THEN
[2349]556          message_string = 'no wind_turbine_par-NAMELIST found: '  //          &
557                           'End of file has reached'
[2322]558          CALL message( 'wtm_parin', 'PA0460', 1, 2, 0, 6, 0 )
[2349]559       ELSEIF ( ierrn > 0 ) THEN
[2932]560          message_string = 'errors in wind_turbine_par-NAMELIST: '  //         &
[2349]561                           'some variables for steering may not be properly set'
562          CALL message( 'wtm_parin', 'PA0466', 1, 2, 0, 6, 0 )               
[1912]563       ENDIF
[2932]564     
565       message_string = 'namelist wind_tubrine_par is deprecated and will ' // &
[3046]566                        'be removed in near future. &Please use namelist ' //  &
[2932]567                        'wind_turbine_parameters instead' 
568       CALL message( 'wtm_parin', 'PA0487', 0, 1, 0, 6, 0 )     
569     
[1839]570!
571!--    Set flag that indicates that the wind turbine model is switched on
572       wind_turbine = .TRUE.
573
[2932]574 12    CONTINUE   ! TBD Change from continue, mit ierrn machen
[2563]575
[1839]576
577    END SUBROUTINE wtm_parin
578
[2563]579
580!------------------------------------------------------------------------------!
581! Description:
582! ------------
[2894]583!> This routine writes the respective restart data.
[2576]584!------------------------------------------------------------------------------!
[2894]585    SUBROUTINE wtm_wrd_global 
[2576]586
587
[2563]588       IMPLICIT NONE
[2776]589
[2563]590       
[2894]591       CALL wrd_write_string( 'omega_gen' )
[2563]592       WRITE ( 14 )  omega_gen
[2894]593
594       CALL wrd_write_string( 'omega_gen_f' )
[2563]595       WRITE ( 14 )  omega_gen_f
[2894]596
597       CALL wrd_write_string( 'omega_gen_f_old' )
[2563]598       WRITE ( 14 )  omega_gen_f_old
[2894]599
600       CALL wrd_write_string( 'omega_gen_old' )
[2563]601       WRITE ( 14 )  omega_gen_old
[2894]602
603       CALL wrd_write_string( 'omega_rot' )
[2563]604       WRITE ( 14 )  omega_rot
[2894]605
606       CALL wrd_write_string( 'phi_yaw' )
607       WRITE ( 14 )  phi_yaw
608
609       CALL wrd_write_string( 'pitch_add' )
[2563]610       WRITE ( 14 )  pitch_add
[2894]611
612       CALL wrd_write_string( 'pitch_add_old' )
[2563]613       WRITE ( 14 )  pitch_add_old
[2894]614
615       CALL wrd_write_string( 'torque_gen' )
[2563]616       WRITE ( 14 )  torque_gen
[2894]617
618       CALL wrd_write_string( 'torque_gen_old' )
[2563]619       WRITE ( 14 )  torque_gen_old
[2894]620
[2563]621       
[2894]622    END SUBROUTINE wtm_wrd_global   
[2563]623
624
625!------------------------------------------------------------------------------!
626! Description:
627! ------------
628!> This routine reads the respective restart data.
629!------------------------------------------------------------------------------!
[2894]630 SUBROUTINE wtm_rrd_global( found )
[2563]631
632
[2894]633    USE control_parameters,                                                    &
634        ONLY: length, restart_string
635
636
[2563]637    IMPLICIT NONE
638
[2894]639    LOGICAL, INTENT(OUT)  ::  found 
[2563]640
641
[2894]642    found = .TRUE.
[2563]643
644
[2894]645    SELECT CASE ( restart_string(1:length) )
[2563]646
[2894]647       CASE ( 'omega_gen' )
648          READ ( 13 )  omega_gen
649       CASE ( 'omega_gen_f' )
650          READ ( 13 )  omega_gen_f
651       CASE ( 'omega_gen_f_old' )
652          READ ( 13 )  omega_gen_f_old
653       CASE ( 'omega_gen_old' )
654          READ ( 13 )  omega_gen_old
655       CASE ( 'omega_rot' )
656          READ ( 13 )  omega_rot
657       CASE ( 'phi_yaw' )
658          READ ( 13 )  phi_yaw
659       CASE ( 'pitch_add' )
660          READ ( 13 )  pitch_add
661       CASE ( 'pitch_add_old' )
662          READ ( 13 )  pitch_add_old
663       CASE ( 'torque_gen' )
664          READ ( 13 )  torque_gen
665       CASE ( 'torque_gen_old' )
666          READ ( 13 )  torque_gen_old
[2563]667
[2894]668       CASE DEFAULT
[2563]669
[2894]670          found = .FALSE.
[2563]671
[2894]672    END SELECT
673   
[2563]674
[2894]675 END SUBROUTINE wtm_rrd_global
676
677
[2563]678!------------------------------------------------------------------------------!
679! Description:
680! ------------
681!> Check namelist parameter
682!------------------------------------------------------------------------------!
[1912]683    SUBROUTINE wtm_check_parameters
684
685   
686       IMPLICIT NONE
687   
688       IF ( ( .NOT.speed_control ) .AND. pitch_control )  THEN
689          message_string = 'pitch_control = .TRUE. requires '//                &
690                           'speed_control = .TRUE.'
[2322]691          CALL message( 'wtm_check_parameters', 'PA0461', 1, 2, 0, 6, 0 )
[1912]692       ENDIF
693       
[2322]694       IF ( ANY( omega_rot(1:nturbines) < 0.0 ) )  THEN
695          message_string = 'omega_rot < 0.0, Please set omega_rot to '     // &
[2792]696                           'a value equal or larger than zero'
[2322]697          CALL message( 'wtm_check_parameters', 'PA0462', 1, 2, 0, 6, 0 )
[1912]698       ENDIF
699       
700       
701       IF ( ANY( rcx(1:nturbines) == 9999999.9_wp ) .OR.                       &
702            ANY( rcy(1:nturbines) == 9999999.9_wp ) .OR.                       &
703            ANY( rcz(1:nturbines) == 9999999.9_wp ) )  THEN
704         
705          message_string = 'rcx, rcy, rcz '                                 // &
706                           'have to be given for each turbine.'         
[2322]707          CALL message( 'wtm_check_parameters', 'PA0463', 1, 2, 0, 6, 0 )         
[1912]708         
709       ENDIF
710
711 
712    END SUBROUTINE wtm_check_parameters 
713   
714                                       
[1839]715!------------------------------------------------------------------------------!
716! Description:
717! ------------
718!> Allocate wind turbine model arrays
719!------------------------------------------------------------------------------!
720    SUBROUTINE wtm_init_arrays
721
722
723       IMPLICIT NONE
724
[1864]725       REAL(wp) ::  delta_r_factor   !<
726       REAL(wp) ::  delta_r_init     !<
727
[1839]728!
729!--    To be able to allocate arrays with dimension of rotor rings and segments,
[1819]730!--    the maximum possible numbers of rings and segments have to be calculated:
731
732       ALLOCATE( nrings(1:nturbines) )
733       ALLOCATE( delta_r(1:nturbines) )
734
735       nrings(:)  = 0
736       delta_r(:) = 0.0_wp
737
738!
739!--    Thickness (radial) of each ring and length (tangential) of each segment:
740       delta_r_factor = segment_width
741       delta_t_factor = segment_length
742       delta_r_init   = delta_r_factor * MIN( dx, dy, dz)
743
744       DO inot = 1, nturbines
745!
746!--       Determine number of rings:
747          nrings(inot) = NINT( rr(inot) / delta_r_init )
748
749          delta_r(inot) = rr(inot) / nrings(inot)
750
751       ENDDO
752
753       nrings_max = MAXVAL(nrings)
754
755       ALLOCATE( nsegs(1:nrings_max,1:nturbines) )
756       ALLOCATE( nsegs_total(1:nturbines) )
757
758       nsegs(:,:)     = 0
759       nsegs_total(:) = 0
760
761
762       DO inot = 1, nturbines
763          DO ring = 1, nrings(inot)
764!
765!--          Determine number of segments for each ring:
[1839]766             nsegs(ring,inot) = MAX( 8, CEILING( delta_r_factor * pi *         &
767                                                 ( 2.0_wp * ring - 1.0_wp ) /  &
768                                                 delta_t_factor ) )
[1819]769          ENDDO
770!
771!--       Total sum of all rotor segments:
[1839]772          nsegs_total(inot) = SUM( nsegs(:,inot) )
[1819]773
774       ENDDO
775
776!
777!--    Maximum number of segments per ring:
778       nsegs_max = MAXVAL(nsegs)
779
[1864]780!!
781!!--    TODO: Folgendes im Header ausgeben!
782!       IF ( myid == 0 )  THEN
783!          PRINT*, 'nrings(1) = ', nrings(1)
784!          PRINT*, '--------------------------------------------------'
785!          PRINT*, 'nsegs(:,1) = ', nsegs(:,1)
786!          PRINT*, '--------------------------------------------------'
787!          PRINT*, 'nrings_max = ', nrings_max
788!          PRINT*, 'nsegs_max = ', nsegs_max
789!          PRINT*, 'nsegs_total(1) = ', nsegs_total(1)
790!       ENDIF
[1819]791
792
793!
794!--    Allocate 1D arrays (dimension = number of turbines)
795       ALLOCATE( i_hub(1:nturbines) )
796       ALLOCATE( i_smear(1:nturbines) )
797       ALLOCATE( j_hub(1:nturbines) )
798       ALLOCATE( j_smear(1:nturbines) )
799       ALLOCATE( k_hub(1:nturbines) )
800       ALLOCATE( k_smear(1:nturbines) )
801       ALLOCATE( torque_total(1:nturbines) )
[1912]802       ALLOCATE( thrust_rotor(1:nturbines) )
[1819]803
804!
805!--    Allocation of the 1D arrays for yaw control
806       ALLOCATE( yawdir(1:nturbines) )
807       ALLOCATE( u_inflow(1:nturbines) )
808       ALLOCATE( wdir(1:nturbines) )
809       ALLOCATE( u_inflow_l(1:nturbines) )
810       ALLOCATE( wdir_l(1:nturbines) )
811       ALLOCATE( phi_yaw_l(1:nturbines) )
812       
813!
814!--    Allocate 1D arrays (dimension = number of rotor segments)
815       ALLOCATE( alpha_attack(1:nsegs_max) )
816       ALLOCATE( chord(1:nsegs_max) )
817       ALLOCATE( phi_rel(1:nsegs_max) )
818       ALLOCATE( thrust_seg(1:nsegs_max) )
819       ALLOCATE( torque_seg_y(1:nsegs_max) )
820       ALLOCATE( torque_seg_z(1:nsegs_max) )
[1839]821       ALLOCATE( turb_cd(1:nsegs_max) )
822       ALLOCATE( turb_cl(1:nsegs_max) )
[1819]823       ALLOCATE( vrel(1:nsegs_max) )
824       ALLOCATE( vtheta(1:nsegs_max) )
825
826!
827!--    Allocate 2D arrays (dimension = number of rotor rings and segments)
828       ALLOCATE( rbx(1:nrings_max,1:nsegs_max) )
829       ALLOCATE( rby(1:nrings_max,1:nsegs_max) )
830       ALLOCATE( rbz(1:nrings_max,1:nsegs_max) )
831       ALLOCATE( thrust_ring(1:nrings_max,1:nsegs_max) )
832       ALLOCATE( torque_ring_y(1:nrings_max,1:nsegs_max) )
833       ALLOCATE( torque_ring_z(1:nrings_max,1:nsegs_max) )
834
835!
836!--    Allocate additional 2D arrays
837       ALLOCATE( rotx(1:nturbines,1:3) )
838       ALLOCATE( roty(1:nturbines,1:3) )
839       ALLOCATE( rotz(1:nturbines,1:3) )
840
841!
842!--    Allocate 3D arrays (dimension = number of grid points)
[1912]843       ALLOCATE( nac_cd_surf(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
844       ALLOCATE( rot_tend_x(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
845       ALLOCATE( rot_tend_y(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
846       ALLOCATE( rot_tend_z(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
[1819]847       ALLOCATE( thrust(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
848       ALLOCATE( torque_y(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
849       ALLOCATE( torque_z(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
[1912]850       ALLOCATE( tow_cd_surf(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
[1819]851
852!
853!--    Allocate additional 3D arrays
854       ALLOCATE( u_int(1:nturbines,1:nrings_max,1:nsegs_max) )
855       ALLOCATE( u_int_1_l(1:nturbines,1:nrings_max,1:nsegs_max) )
856       ALLOCATE( v_int(1:nturbines,1:nrings_max,1:nsegs_max) )
857       ALLOCATE( v_int_1_l(1:nturbines,1:nrings_max,1:nsegs_max) )
858       ALLOCATE( w_int(1:nturbines,1:nrings_max,1:nsegs_max) )
859       ALLOCATE( w_int_1_l(1:nturbines,1:nrings_max,1:nsegs_max) )
860
861!
862!--    All of the arrays are initialized with a value of zero:
863       i_hub(:)                 = 0
864       i_smear(:)               = 0
865       j_hub(:)                 = 0
866       j_smear(:)               = 0
867       k_hub(:)                 = 0
868       k_smear(:)               = 0
[1912]869       
[1819]870       torque_total(:)          = 0.0_wp
[1912]871       thrust_rotor(:)          = 0.0_wp
[1819]872
[2563]873       IF ( TRIM( initializing_actions ) /= 'read_restart_data' ) THEN
874          omega_gen(:)             = 0.0_wp
875          omega_gen_old(:)         = 0.0_wp
876          omega_gen_f(:)           = 0.0_wp
877          omega_gen_f_old(:)       = 0.0_wp
878          pitch_add_old(:)         = 0.0_wp
879          torque_gen(:)            = 0.0_wp
880          torque_gen_old(:)        = 0.0_wp
881       ENDIF
882
[1819]883       yawdir(:)                = 0.0_wp
884       wdir(:)                  = 0.0_wp
885       u_inflow(:)              = 0.0_wp
886
887!
888!--    Allocate 1D arrays (dimension = number of rotor segments)
889       alpha_attack(:)          = 0.0_wp
890       chord(:)                 = 0.0_wp
891       phi_rel(:)               = 0.0_wp
892       thrust_seg(:)            = 0.0_wp
893       torque_seg_y(:)          = 0.0_wp
894       torque_seg_z(:)          = 0.0_wp
[1864]895       turb_cd(:)               = 0.0_wp
896       turb_cl(:)               = 0.0_wp
[1819]897       vrel(:)                  = 0.0_wp
898       vtheta(:)                = 0.0_wp
899
900       rbx(:,:)                 = 0.0_wp
901       rby(:,:)                 = 0.0_wp
902       rbz(:,:)                 = 0.0_wp
903       thrust_ring(:,:)         = 0.0_wp
904       torque_ring_y(:,:)       = 0.0_wp
905       torque_ring_z(:,:)       = 0.0_wp
906
907       rotx(:,:)                = 0.0_wp
908       roty(:,:)                = 0.0_wp
909       rotz(:,:)                = 0.0_wp
910
[1912]911       nac_cd_surf(:,:,:)       = 0.0_wp
912       rot_tend_x(:,:,:)        = 0.0_wp
913       rot_tend_y(:,:,:)        = 0.0_wp
914       rot_tend_z(:,:,:)        = 0.0_wp
[1819]915       thrust(:,:,:)            = 0.0_wp
916       torque_y(:,:,:)          = 0.0_wp
917       torque_z(:,:,:)          = 0.0_wp
[1912]918       tow_cd_surf(:,:,:)       = 0.0_wp
[1819]919
920       u_int(:,:,:)             = 0.0_wp
921       u_int_1_l(:,:,:)         = 0.0_wp
922       v_int(:,:,:)             = 0.0_wp
923       v_int_1_l(:,:,:)         = 0.0_wp
924       w_int(:,:,:)             = 0.0_wp
925       w_int_1_l(:,:,:)         = 0.0_wp
926
927
[1839]928    END SUBROUTINE wtm_init_arrays
[1819]929
930
931!------------------------------------------------------------------------------!
932! Description:
933! ------------
[1839]934!> Initialization of the wind turbine model
[1819]935!------------------------------------------------------------------------------!
[1839]936    SUBROUTINE wtm_init
[1819]937
[1839]938   
[1819]939       IMPLICIT NONE
940
941       INTEGER(iwp) ::  i  !< running index
942       INTEGER(iwp) ::  j  !< running index
943       INTEGER(iwp) ::  k  !< running index
[1864]944       
[1819]945!
[1864]946!--    Help variables for the smearing function       
947       REAL(wp) ::  eps_kernel       !<       
948       
[1839]949!
[1864]950!--    Help variables for calculation of the tower drag       
951       INTEGER(iwp) ::  tower_n      !<
952       INTEGER(iwp) ::  tower_s      !<
[1839]953!
[1864]954!--    Help variables for the calulaction of the nacelle drag
955       INTEGER(iwp) ::  i_ip         !<
956       INTEGER(iwp) ::  i_ipg        !<
957       
958       REAL(wp) ::  yvalue               
959       REAL(wp) ::  dy_int           !<
960       REAL(wp) ::  dz_int           !<
961       
962       REAL(wp), DIMENSION(:,:), ALLOCATABLE :: circle_points  !<
963             
964       INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: index_nacb       !<
965       INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: index_nacl       !<
966       INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: index_nacr       !<
967       INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: index_nact       !<
968       
969       ALLOCATE( index_nacb(1:nturbines) )
970       ALLOCATE( index_nacl(1:nturbines) )
971       ALLOCATE( index_nacr(1:nturbines) )
972       ALLOCATE( index_nact(1:nturbines) )
[1819]973
[1839]974!
[1819]975!------------------------------------------------------------------------------!
[1839]976!--    Calculation of parameters for the regularization kernel
977!--    (smearing of the forces)
[1819]978!------------------------------------------------------------------------------!
979!
[1839]980!--    In the following, some of the required parameters for the smearing will
981!--    be calculated:
[1819]982
[1839]983!--    The kernel is set equal to twice the grid spacing which has turned out to
984!--    be a reasonable value (see e.g. Troldborg et al. (2013), Wind Energy,
[1819]985!--    DOI: 10.1002/we.1608):
986       eps_kernel = 2.0_wp * dx
987!
[1839]988!--    The zero point (eps_min) of the polynomial function must be the following
989!--    if the integral of the polynomial function (for values < eps_min) shall
990!--    be equal to the integral of the Gaussian function used before:
991       eps_min = ( 105.0_wp / 32.0_wp )**( 1.0_wp / 3.0_wp ) *                 &
992                 pi**( 1.0_wp / 6.0_wp ) * eps_kernel
[1819]993!
994!--    Square of eps_min:
995       eps_min2 = eps_min**2
996!
997!--    Parameters in the polynomial function:
[1864]998       pol_a = 1.0_wp / eps_min**4
999       pol_b = 2.0_wp / eps_min**2
[1819]1000!
[1839]1001!--    Normalization factor which is the inverse of the integral of the smearing
1002!--    function:
1003       eps_factor = 105.0_wp / ( 32.0_wp * pi * eps_min**3 )
1004       
[1864]1005!--    Change tilt angle to rad:
1006       tilt = tilt * pi / 180.0_wp
1007     
[1819]1008!
[1864]1009!--    Change yaw angle to rad:
[2563]1010       IF ( TRIM( initializing_actions ) /= 'read_restart_data' ) THEN
1011          phi_yaw(:) = phi_yaw(:) * pi / 180.0_wp
1012       ENDIF
[1819]1013
[1864]1014
[1819]1015       DO inot = 1, nturbines
1016!
[1864]1017!--       Rotate the rotor coordinates in case yaw and tilt are defined
1018          CALL wtm_rotate_rotor( inot )
[1819]1019         
1020!
1021!--       Determine the indices of the hub height
1022          i_hub(inot) = INT(   rcx(inot)                 / dx )
1023          j_hub(inot) = INT( ( rcy(inot) + 0.5_wp * dy ) / dy )
1024          k_hub(inot) = INT( ( rcz(inot) + 0.5_wp * dz ) / dz )
1025
1026!
1027!--       Determining the area to which the smearing of the forces is applied.
[1839]1028!--       As smearing now is effectively applied only for distances smaller than
1029!--       eps_min, the smearing area can be further limited and regarded as a
1030!--       function of eps_min:
[1819]1031          i_smear(inot) = CEILING( ( rr(inot) + eps_min ) / dx )
1032          j_smear(inot) = CEILING( ( rr(inot) + eps_min ) / dy )
1033          k_smear(inot) = CEILING( ( rr(inot) + eps_min ) / dz )
[1864]1034       
[1819]1035       ENDDO
1036
1037!
[2792]1038!--    Call the wtm_init_speed_control subroutine and calculate the local
1039!--    omega_rot for the respective processor.
1040       IF ( speed_control)  THEN
1041       
1042          CALL wtm_speed_control
1043
1044          IF ( TRIM( initializing_actions ) == 'read_restart_data' ) THEN
1045
1046             DO inot = 1, nturbines
1047
1048                IF ( nxl > i_hub(inot) ) THEN
1049                   torque_gen(inot) = 0.0_wp
1050                   omega_gen_f(inot) = 0.0_wp
1051                   omega_rot_l(inot) = 0.0_wp
1052                ENDIF
1053
1054                IF ( nxr < i_hub(inot) ) THEN
1055                   torque_gen(inot) = 0.0_wp
1056                   omega_gen_f(inot) = 0.0_wp
1057                   omega_rot_l(inot) = 0.0_wp
1058                ENDIF
1059
1060                IF ( nys > j_hub(inot) ) THEN
1061                   torque_gen(inot) = 0.0_wp
1062                   omega_gen_f(inot) = 0.0_wp
1063                   omega_rot_l(inot) = 0.0_wp
1064                ENDIF
1065
1066                IF ( nyn < j_hub(inot) ) THEN
1067                   torque_gen(inot) = 0.0_wp
1068                   omega_gen_f(inot) = 0.0_wp
1069                   omega_rot_l(inot) = 0.0_wp
1070                ENDIF
1071
1072                IF ( ( nxl <= i_hub(inot) ) .AND. ( nxr >= i_hub(inot) ) ) THEN
1073                   IF ( ( nys <= j_hub(inot) ) .AND. ( nyn >= j_hub(inot) ) ) THEN
1074
1075                      omega_rot_l(inot) = omega_gen(inot) / gear_ratio
1076
1077                   ENDIF
1078                ENDIF
1079
1080             END DO
1081
1082          ENDIF
1083
1084       ENDIF
1085
1086!
[1819]1087!------------------------------------------------------------------------------!
[1839]1088!--    Determine the area within each grid cell that overlaps with the area
1089!--    of the nacelle and the tower (needed for calculation of the forces)
[1819]1090!------------------------------------------------------------------------------!
1091!
1092!--    Note: so far this is only a 2D version, in that the mean flow is
1093!--    perpendicular to the rotor area.
1094
1095!
1096!--    Allocation of the array containing information on the intersection points
1097!--    between rotor disk and the numerical grid:
1098       upper_end = ( ny + 1 ) * 10000 
1099
1100       ALLOCATE( circle_points(1:2,1:upper_end) )
[1839]1101       
1102       circle_points(:,:) = 0.0_wp
[1819]1103
[1839]1104       
1105       DO inot = 1, nturbines                     ! loop over number of turbines
[1819]1106!
[1839]1107!--       Determine the grid index (u-grid) that corresponds to the location of
1108!--       the rotor center (reduces the amount of calculations in the case that
1109!--       the mean flow is perpendicular to the rotor area):
[1819]1110          i = i_hub(inot)
1111
1112!
[1839]1113!--       Determine the left and the right edge of the nacelle (corresponding
1114!--       grid point indices):
[1819]1115          index_nacl(inot) = INT( ( rcy(inot) - rnac(inot) + 0.5_wp * dy ) / dy )
1116          index_nacr(inot) = INT( ( rcy(inot) + rnac(inot) + 0.5_wp * dy ) / dy )
1117!
[1839]1118!--       Determine the bottom and the top edge of the nacelle (corresponding
1119!--       grid point indices).The grid point index has to be increased by 1, as
1120!--       the first level for the u-component (index 0) is situated below the
1121!--       surface. All points between z=0 and z=dz/s would already be contained
1122!--       in grid box 1.
[1819]1123          index_nacb(inot) = INT( ( rcz(inot) - rnac(inot) ) / dz ) + 1
1124          index_nact(inot) = INT( ( rcz(inot) + rnac(inot) ) / dz ) + 1
1125
1126!
1127!--       Determine the indices of the grid boxes containing the left and
[1864]1128!--       the right boundaries of the tower:
[1819]1129          tower_n = ( rcy(inot) + 0.5_wp * dtow(inot) - 0.5_wp * dy ) / dy
1130          tower_s = ( rcy(inot) - 0.5_wp * dtow(inot) - 0.5_wp * dy ) / dy
1131
1132!
1133!--       Determine the fraction of the grid box area overlapping with the tower
[1864]1134!--       area and multiply it with the drag of the tower:
[1839]1135          IF ( ( nxlg <= i )  .AND.  ( nxrg >= i ) )  THEN
[1819]1136
1137             DO  j = nys, nyn
1138!
[1839]1139!--             Loop from south to north boundary of tower
1140                IF ( ( j >= tower_s )  .AND.  ( j <= tower_n ) )  THEN
1141
[1819]1142                   DO  k = nzb, nzt
1143
1144                      IF ( k == k_hub(inot) )  THEN
1145                         IF ( tower_n - tower_s >= 1 )  THEN
[1839]1146!
[1819]1147!--                      leftmost and rightmost grid box:
1148                            IF ( j == tower_s )  THEN
[1912]1149                               tow_cd_surf(k,j,i) = ( rcz(inot) -              &
1150                                    ( k_hub(inot) * dz - 0.5_wp * dz ) )  *    & ! extension in z-direction
1151                                  ( ( tower_s + 1.0_wp + 0.5_wp ) * dy    -    &
1152                                    ( rcy(inot) - 0.5_wp * dtow(inot) ) ) *    & ! extension in y-direction
1153                                  turb_cd_tower(inot)
[1819]1154                            ELSEIF ( j == tower_n )  THEN
[1912]1155                               tow_cd_surf(k,j,i) = ( rcz(inot)            -   &
1156                                    ( k_hub(inot) * dz - 0.5_wp * dz ) )  *    & ! extension in z-direction
1157                                  ( ( rcy(inot) + 0.5_wp * dtow(inot) )   -    &
1158                                    ( tower_n + 0.5_wp ) * dy )           *    & ! extension in y-direction
1159                                  turb_cd_tower(inot)
[1819]1160!
1161!--                         grid boxes inbetween
[1912]1162!--                         (where tow_cd_surf = grid box area):
[1819]1163                            ELSE
[1912]1164                               tow_cd_surf(k,j,i) = ( rcz(inot) -              &
1165                                    ( k_hub(inot) * dz - 0.5_wp * dz ) )  *    &
1166                                    dy * turb_cd_tower(inot)
[1819]1167                            ENDIF
1168!
1169!--                      tower lies completely within one grid box:
1170                         ELSE
[1912]1171                            tow_cd_surf(k,j,i) = ( rcz(inot)                 - &
[1839]1172                                       ( k_hub(inot) * dz - 0.5_wp * dz ) ) *  &
[1912]1173                                       dtow(inot) * turb_cd_tower(inot)
[1819]1174                         ENDIF
[1839]1175!
1176!--                  In case that k is smaller than k_hub the following actions
1177!--                  are carried out:
[1819]1178                      ELSEIF ( k < k_hub(inot) )  THEN
1179                     
[1839]1180                         IF ( ( tower_n - tower_s ) >= 1 )  THEN
1181!
[1819]1182!--                         leftmost and rightmost grid box:
1183                            IF ( j == tower_s )  THEN                         
[1912]1184                               tow_cd_surf(k,j,i) = dz * (                     &
[1839]1185                                      ( tower_s + 1 + 0.5_wp ) * dy         -  &
1186                                      ( rcy(inot) - 0.5_wp * dtow(inot) )      &
[1912]1187                                                        ) * turb_cd_tower(inot)
[1819]1188                            ELSEIF ( j == tower_n )  THEN
[1912]1189                               tow_cd_surf(k,j,i) = dz * (                     &
[1839]1190                                      ( rcy(inot) + 0.5_wp * dtow(inot) )   -  &
1191                                      ( tower_n + 0.5_wp ) * dy                &
[1912]1192                                                         ) * turb_cd_tower(inot)
[1839]1193!
1194!--                         grid boxes inbetween
[1912]1195!--                         (where tow_cd_surf = grid box area):
[1819]1196                            ELSE
[1912]1197                               tow_cd_surf(k,j,i) = dz * dy * turb_cd_tower(inot)
[1819]1198                            ENDIF
[1839]1199!
[1819]1200!--                         tower lies completely within one grid box:
1201                         ELSE
[1912]1202                            tow_cd_surf(k,j,i) = dz * dtow(inot) *             &
1203                                                turb_cd_tower(inot)
[1839]1204                         ENDIF ! end if larger than grid box
1205
1206                      ENDIF    ! end if k == k_hub
1207
1208                   ENDDO       ! end loop over k
1209
1210                ENDIF          ! end if inside north and south boundary of tower
1211
1212             ENDDO             ! end loop over j
1213
1214          ENDIF                ! end if hub inside domain + ghostpoints
[1819]1215       
[1839]1216         
[1912]1217          CALL exchange_horiz( tow_cd_surf, nbgp )
[1819]1218
[1839]1219!
[1864]1220!--       Calculation of the nacelle area
1221!--       CAUTION: Currently disabled due to segmentation faults on the FLOW HPC
1222!--                cluster (Oldenburg)
1223!!
1224!!--       Tabulate the points on the circle that are required in the following for
1225!!--       the calculation of the Riemann integral (node points; they are called
1226!!--       circle_points in the following):
1227!
1228!          dy_int = dy / 10000.0_wp
1229!
1230!          DO  i_ip = 1, upper_end
1231!             yvalue   = dy_int * ( i_ip - 0.5_wp ) + 0.5_wp * dy           !<--- segmentation fault
1232!             sqrt_arg = rnac(inot)**2 - ( yvalue - rcy(inot) )**2          !<--- segmentation fault
1233!             IF ( sqrt_arg >= 0.0_wp )  THEN
1234!!
1235!!--             bottom intersection point
1236!                circle_points(1,i_ip) = rcz(inot) - SQRT( sqrt_arg )
1237!!
1238!!--             top intersection point
1239!                circle_points(2,i_ip) = rcz(inot) + SQRT( sqrt_arg )       !<--- segmentation fault
1240!             ELSE
1241!                circle_points(:,i_ip) = -111111                            !<--- segmentation fault
1242!             ENDIF
1243!          ENDDO
1244!
1245!
1246!          DO  j = nys, nyn
1247!!
1248!!--          In case that the grid box is located completely outside the nacelle
1249!!--          (y) it can automatically be stated that there is no overlap between
1250!!--          the grid box and the nacelle and consequently we can set
[1912]1251!!--          nac_cd_surf(:,j,i) = 0.0:
[1864]1252!             IF ( ( j >= index_nacl(inot) )  .AND.  ( j <= index_nacr(inot) ) )  THEN
1253!                DO  k = nzb+1, nzt
1254!!
1255!!--                In case that the grid box is located completely outside the
1256!!--                nacelle (z) it can automatically be stated that there is no
1257!!--                overlap between the grid box and the nacelle and consequently
[1912]1258!!--                we can set nac_cd_surf(k,j,i) = 0.0:
[1864]1259!                   IF ( ( k >= index_nacb(inot) )  .OR.                           &
1260!                        ( k <= index_nact(inot) ) )  THEN
1261!!
1262!!--                   For all other cases Riemann integrals are calculated.
1263!!--                   Here, the points on the circle that have been determined
1264!!--                   above are used in order to calculate the overlap between the
1265!!--                   gridbox and the nacelle area (area approached by 10000
1266!!--                   rectangulars dz_int * dy_int):
1267!                      DO  i_ipg = 1, 10000
1268!                         dz_int = dz
1269!                         i_ip = j * 10000 + i_ipg
1270!!
1271!!--                      Determine the vertical extension dz_int of the circle
1272!!--                      within the current grid box:
1273!                         IF ( ( circle_points(2,i_ip) < zw(k) ) .AND.          &  !<--- segmentation fault
1274!                              ( circle_points(2,i_ip) >= zw(k-1) ) ) THEN
1275!                            dz_int = dz_int -                                  &  !<--- segmentation fault
1276!                                     ( zw(k) - circle_points(2,i_ip) )
1277!                         ENDIF
1278!                         IF ( ( circle_points(1,i_ip) <= zw(k) ) .AND.         &  !<--- segmentation fault
1279!                              ( circle_points(1,i_ip) > zw(k-1) ) ) THEN
1280!                            dz_int = dz_int -                                  &
1281!                                     ( circle_points(1,i_ip) - zw(k-1) )
1282!                         ENDIF
1283!                         IF ( zw(k-1) > circle_points(2,i_ip) ) THEN
1284!                            dz_int = 0.0_wp
1285!                         ENDIF
1286!                         IF ( zw(k) < circle_points(1,i_ip) ) THEN
1287!                            dz_int = 0.0_wp                     
1288!                         ENDIF
1289!                         IF ( ( nxlg <= i ) .AND. ( nxrg >= i ) ) THEN
[1912]1290!                            nac_cd_surf(k,j,i) = nac_cd_surf(k,j,i) +        &  !<--- segmentation fault
1291!                                                  dy_int * dz_int * turb_cd_nacelle(inot)
[1864]1292!                         ENDIF   
1293!                      ENDDO
1294!                   ENDIF
1295!                ENDDO
1296!             ENDIF
[1819]1297!
[1864]1298!          ENDDO
[1819]1299!       
[1912]1300!          CALL exchange_horiz( nac_cd_surf, nbgp )                                !<---  segmentation fault
[1819]1301
[1864]1302       ENDDO   ! end of loop over turbines
[1819]1303
[1912]1304       tow_cd_surf   = tow_cd_surf   / ( dx * dy * dz )      ! Normalize tower drag
1305       nac_cd_surf = nac_cd_surf / ( dx * dy * dz )      ! Normalize nacelle drag
[1819]1306
[1912]1307       CALL wtm_read_blade_tables
[1839]1308 
[1864]1309    END SUBROUTINE wtm_init
1310
1311
[1819]1312!------------------------------------------------------------------------------!
[1864]1313! Description:
1314! ------------
1315!> Read in layout of the rotor blade , the lift and drag tables
1316!> and the distribution of lift and drag tables along the blade
[1819]1317!------------------------------------------------------------------------------!
[1912]1318!
1319    SUBROUTINE wtm_read_blade_tables
[1819]1320
[1839]1321
[1864]1322       IMPLICIT NONE
1323
1324       INTEGER(iwp) ::  ii   !< running index
1325       INTEGER(iwp) ::  jj   !< running index
[1843]1326   
[1864]1327       INTEGER(iwp) ::  ierrn       !<
1328   
1329       CHARACTER(200) :: chmess     !< Read in string
[1839]1330
[1864]1331       INTEGER(iwp) ::  dlen        !< no. rows of local table
1332       INTEGER(iwp) ::  dlenbl      !< no. rows of cd, cl table
1333       INTEGER(iwp) ::  ialpha      !< table position of current alpha value
1334       INTEGER(iwp) ::  iialpha     !<
1335       INTEGER(iwp) ::  iir         !<
1336       INTEGER(iwp) ::  radres      !< radial resolution
1337       INTEGER(iwp) ::  t1          !< no. of airfoil
1338       INTEGER(iwp) ::  t2          !< no. of airfoil
1339       INTEGER(iwp) ::  trow        !<
1340       INTEGER(iwp) ::  dlenbl_int  !< no. rows of interpolated cd, cl tables
[1839]1341   
[1864]1342       REAL(wp) :: alpha_attack_i   !<
1343       REAL(wp) :: weight_a         !<
1344       REAL(wp) :: weight_b         !<
[1839]1345
[1864]1346       INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: ttoint1    !<
1347       INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: ttoint2    !<
[1839]1348   
[1864]1349       REAL(wp), DIMENSION(:), ALLOCATABLE :: turb_cd_sel1   !<
1350       REAL(wp), DIMENSION(:), ALLOCATABLE :: turb_cd_sel2   !<
1351       REAL(wp), DIMENSION(:), ALLOCATABLE :: turb_cl_sel1   !<
1352       REAL(wp), DIMENSION(:), ALLOCATABLE :: turb_cl_sel2   !<
1353       REAL(wp), DIMENSION(:), ALLOCATABLE :: read_cl_cd     !< read in var array
[1839]1354             
[1864]1355       REAL(wp), DIMENSION(:), ALLOCATABLE    :: alpha_attack_tab   !<
1356       REAL(wp), DIMENSION(:), ALLOCATABLE    :: trad1              !<
1357       REAL(wp), DIMENSION(:), ALLOCATABLE    :: trad2              !<         
1358       REAL(wp), DIMENSION(:,:), ALLOCATABLE  :: turb_cd_table      !<
1359       REAL(wp), DIMENSION(:,:), ALLOCATABLE  :: turb_cl_table      !<
[1839]1360                                         
[1864]1361       ALLOCATE ( read_cl_cd(1:2*nairfoils+1) )
[1839]1362
[1864]1363!
1364!--    Read in the distribution of lift and drag tables along the blade, the
1365!--    layout of the rotor blade and the lift and drag tables:
1366
[2323]1367       OPEN ( 90, FILE='WTM_DATA', STATUS='OLD', FORM='FORMATTED', IOSTAT=ierrn )
[1864]1368
1369       IF ( ierrn /= 0 )  THEN
1370          message_string = 'file WTM_DATA does not exist'
[2322]1371          CALL message( 'wtm_init', 'PA0464', 1, 2, 0, 6, 0 )
[1864]1372       ENDIF
1373!
1374!--    Read distribution table:
1375
1376       dlen = 0
1377
[2323]1378       READ ( 90, '(3/)' )
[1864]1379
1380       rloop3: DO
[2323]1381          READ ( 90, *, IOSTAT=ierrn ) chmess
[1864]1382          IF ( ierrn < 0  .OR.  chmess == '#'  .OR.  chmess == '')  EXIT rloop3
1383          dlen = dlen + 1
1384       ENDDO rloop3
1385
1386       ALLOCATE( trad1(1:dlen), trad2(1:dlen), ttoint1(1:dlen), ttoint2(1:dlen))
1387
1388       DO jj = 1,dlen+1
[2323]1389          BACKSPACE ( 90, IOSTAT=ierrn )
[1864]1390       ENDDO
1391
1392       DO jj = 1,dlen
[2323]1393          READ ( 90, * ) trad1(jj), trad2(jj), ttoint1(jj), ttoint2(jj)
[1864]1394       ENDDO
1395
1396!
1397!--    Read layout table:
1398
[1839]1399       dlen = 0 
[1864]1400
[2323]1401       READ ( 90, '(3/)')
[1864]1402
[1843]1403       rloop1: DO
[2323]1404          READ ( 90, *, IOSTAT=ierrn ) chmess
[1864]1405          IF ( ierrn < 0  .OR.  chmess == '#'  .OR.  chmess == '')  EXIT rloop1
1406          dlen = dlen + 1
[1843]1407       ENDDO rloop1
[1864]1408
[1839]1409       ALLOCATE( lrd(1:dlen), ard(1:dlen), crd(1:dlen) )
[1864]1410       DO jj = 1, dlen+1
[2323]1411          BACKSPACE ( 90, IOSTAT=ierrn )
[1864]1412       ENDDO             
1413       DO jj = 1, dlen
[2323]1414          READ ( 90, * ) lrd(jj), ard(jj), crd(jj) 
[1839]1415       ENDDO
[1819]1416
[1864]1417!
1418!--    Read tables (turb_cl(alpha),turb_cd(alpha) for the different profiles:
[1819]1419
[1864]1420       dlen = 0
1421
[2323]1422       READ ( 90, '(3/)' )
[1864]1423
[1843]1424       rloop2: DO
[2323]1425          READ ( 90, *, IOSTAT=ierrn ) chmess
[1864]1426          IF ( ierrn < 0  .OR.  chmess == '#'  .OR.  chmess == '')  EXIT rloop2
1427          dlen = dlen + 1
1428       ENDDO rloop2 
1429
[1912]1430       ALLOCATE( alpha_attack_tab(1:dlen), turb_cl_table(1:dlen,1:nairfoils),  &
[1864]1431                 turb_cd_table(1:dlen,1:nairfoils) )
1432
1433       DO jj = 1,dlen+1
[2323]1434          BACKSPACE ( 90, IOSTAT=ierrn )
[1864]1435       ENDDO 
1436
[1839]1437       DO jj = 1,dlen
[2323]1438          READ ( 90, * ) read_cl_cd
[1864]1439          alpha_attack_tab(jj) = read_cl_cd(1)
1440          DO ii= 1, nairfoils
1441             turb_cl_table(jj,ii) = read_cl_cd(ii*2)
1442             turb_cd_table(jj,ii) = read_cl_cd(ii*2+1)
[1819]1443          ENDDO
[1864]1444
[1839]1445       ENDDO
[1864]1446
1447       dlenbl = dlen 
1448
[2323]1449       CLOSE ( 90 )
[1819]1450
[1864]1451!
[2836]1452!--    For each possible radial position (resolution: 0.1 m --> 631 values if rr(1)=63m)
1453!--    and each possible angle of attack (resolution: 0.1 degrees --> 3601 values!)
[1864]1454!--    determine the lift and drag coefficient by interpolating between the
1455!--    tabulated values of each table (interpolate to current angle of attack)
1456!--    and between the tables (interpolate to current radial position):
[1839]1457
[2836]1458       ALLOCATE( turb_cl_sel1(1:dlenbl) ) 
1459       ALLOCATE( turb_cl_sel2(1:dlenbl) ) 
1460       ALLOCATE( turb_cd_sel1(1:dlenbl) )
1461       ALLOCATE( turb_cd_sel2(1:dlenbl) )
[1819]1462
[1864]1463       radres     = INT( rr(1) * 10.0_wp ) + 1_iwp
1464       dlenbl_int = INT( 360.0_wp / accu_cl_cd_tab ) + 1_iwp
[1839]1465
[2836]1466       ALLOCATE( turb_cl_tab(1:dlenbl_int,1:radres) )
1467       ALLOCATE( turb_cd_tab(1:dlenbl_int,1:radres) )
[1864]1468
[2836]1469       DO iir = 1, radres ! loop over radius
[1864]1470
[2836]1471          cur_r = ( iir - 1_iwp ) * 0.1_wp
1472!
1473!--       Find position in table 1
1474          lct = MINLOC( ABS( trad1 - cur_r ) )
1475!             lct(1) = lct(1)
[1864]1476
[2836]1477          IF ( ( trad1(lct(1)) - cur_r ) .GT. 0.0 )  THEN
1478             lct(1) = lct(1) - 1
1479          ENDIF
[1864]1480
[2836]1481          trow = lct(1)
1482!
1483!--       Calculate weights for radius interpolation
1484          weight_a = ( trad2(trow) - cur_r ) / ( trad2(trow) - trad1(trow) )
1485          weight_b = ( cur_r - trad1(trow) ) / ( trad2(trow) - trad1(trow) )
1486          t1 = ttoint1(trow)
1487          t2 = ttoint2(trow)
[1864]1488
[2836]1489          IF ( t1 .EQ. t2 ) THEN  ! if both are the same, the weights are NaN
1490             weight_a = 0.5_wp    ! then do interpolate in between same twice
1491             weight_b = 0.5_wp    ! using 0.5 as weight
1492          ENDIF
1493
1494          IF ( t1 == 0 .AND. t2 == 0 ) THEN
1495             turb_cd_sel1 = 0.0_wp
1496             turb_cd_sel2 = 0.0_wp
1497             turb_cl_sel1 = 0.0_wp
1498             turb_cl_sel2 = 0.0_wp
1499
1500             turb_cd_tab(1,iir) = 0.0_wp  ! For -180° (iialpha=1) the values   
1501             turb_cl_tab(1,iir) = 0.0_wp  ! for each radius has to be set
1502                                          ! explicitly             
1503          ELSE
1504             turb_cd_sel1 = turb_cd_table(:,t1)
1505             turb_cd_sel2 = turb_cd_table(:,t2)
1506             turb_cl_sel1 = turb_cl_table(:,t1)
1507             turb_cl_sel2 = turb_cl_table(:,t2)
1508!
1509!--          For -180° (iialpha=1) the values for each radius has to be set
1510!--          explicitly
1511             turb_cd_tab(1,iir) = ( weight_a * turb_cd_table(1,t1) + weight_b  & 
1512                                  * turb_cd_table(1,t2) )   
1513             turb_cl_tab(1,iir) = ( weight_a * turb_cl_table(1,t1) + weight_b  & 
1514                                  * turb_cl_table(1,t2) ) 
1515          ENDIF
1516
1517          DO iialpha = 2, dlenbl_int  ! loop over angles
1518             
[1864]1519             alpha_attack_i = -180.0_wp + REAL( iialpha-1 ) * accu_cl_cd_tab
1520             ialpha = 1
[2836]1521             
[2152]1522             DO WHILE ( ( alpha_attack_i > alpha_attack_tab(ialpha) ) .AND. (ialpha <= dlen ) )
[1864]1523                ialpha = ialpha + 1
1524             ENDDO
[1819]1525
[1864]1526!
[1912]1527!--          Interpolation of lift and drag coefficiencts on fine grid of radius
1528!--          segments and angles of attack
1529             turb_cl_tab(iialpha,iir) = ( alpha_attack_tab(ialpha) -           &
1530                                          alpha_attack_i ) /                   &
[1864]1531                                        ( alpha_attack_tab(ialpha) -           &
1532                                          alpha_attack_tab(ialpha-1) ) *       &
1533                                        ( weight_a * turb_cl_sel1(ialpha-1) +  &
1534                                          weight_b * turb_cl_sel2(ialpha-1) ) +&
1535                                        ( alpha_attack_i             -         &
1536                                          alpha_attack_tab(ialpha-1) ) /       &
1537                                        ( alpha_attack_tab(ialpha) -           &
1538                                          alpha_attack_tab(ialpha-1) ) *       &
1539                                        ( weight_a * turb_cl_sel1(ialpha) +    &
1540                                          weight_b * turb_cl_sel2(ialpha) )
[1912]1541             turb_cd_tab(iialpha,iir) = ( alpha_attack_tab(ialpha) -           &
1542                                          alpha_attack_i ) /                   &
[1864]1543                                        ( alpha_attack_tab(ialpha) -           &
1544                                          alpha_attack_tab(ialpha-1) ) *       &
1545                                        ( weight_a * turb_cd_sel1(ialpha-1) +  &
1546                                          weight_b * turb_cd_sel2(ialpha-1) ) +&
1547                                        ( alpha_attack_i             -         &
1548                                          alpha_attack_tab(ialpha-1) ) /       &
1549                                        ( alpha_attack_tab(ialpha) -           &
1550                                          alpha_attack_tab(ialpha-1) ) *       &
1551                                        ( weight_a * turb_cd_sel1(ialpha) +    &
1552                                          weight_b * turb_cd_sel2(ialpha) )
[2836]1553           
[1912]1554          ENDDO   ! end loop over angles of attack
[2836]1555         
1556       ENDDO   ! end loop over radius
[1819]1557
[2836]1558
[1912]1559    END SUBROUTINE wtm_read_blade_tables
[1819]1560
1561
[1864]1562!------------------------------------------------------------------------------!
1563! Description:
1564! ------------
1565!> The projection matrix for the coordinate system of therotor disc in respect
1566!> to the yaw and tilt angle of the rotor is calculated
1567!------------------------------------------------------------------------------!
1568    SUBROUTINE wtm_rotate_rotor( inot )
[1819]1569
[1864]1570
1571       IMPLICIT NONE
1572
1573       INTEGER(iwp) :: inot
1574!
1575!--    Calculation of the rotation matrix for the application of the tilt to
1576!--    the rotors
1577       rot_eigen_rad(1) = SIN( phi_yaw(inot) )    ! x-component of the radial eigenvector
1578       rot_eigen_rad(2) = COS( phi_yaw(inot) )    ! y-component of the radial eigenvector
1579       rot_eigen_rad(3) = 0.0_wp                  ! z-component of the radial eigenvector
1580
1581       rot_eigen_azi(1) = 0.0_wp                  ! x-component of the azimuth eigenvector
1582       rot_eigen_azi(2) = 0.0_wp                  ! y-component of the azimuth eigenvector
1583       rot_eigen_azi(3) = 1.0_wp                  ! z-component of the azimuth eigenvector
1584
1585       rot_eigen_nor(1) =  COS( phi_yaw(inot) )   ! x-component of the normal eigenvector
1586       rot_eigen_nor(2) = -SIN( phi_yaw(inot) )   ! y-component of the normal eigenvector
1587       rot_eigen_nor(3) = 0.0_wp                  ! z-component of the normal eigenvector
[1839]1588   
[1864]1589!
1590!--    Calculation of the coordinate transformation matrix to apply a tilt to
1591!--    the rotor. If tilt = 0, rot_coord_trans is a unit matrix.
[1819]1592
[1912]1593       rot_coord_trans(inot,1,1) = rot_eigen_rad(1)**2                   *     &
[1864]1594                                   ( 1.0_wp - COS( tilt ) ) + COS( tilt ) 
[1912]1595       rot_coord_trans(inot,1,2) = rot_eigen_rad(1) * rot_eigen_rad(2)   *     &
1596                                   ( 1.0_wp - COS( tilt ) )              -     &
[1864]1597                                   rot_eigen_rad(3) * SIN( tilt )
[1912]1598       rot_coord_trans(inot,1,3) = rot_eigen_rad(1) * rot_eigen_rad(3)   *     &
1599                                   ( 1.0_wp - COS( tilt ) )              +     &
[1864]1600                                   rot_eigen_rad(2) * SIN( tilt )
[1912]1601       rot_coord_trans(inot,2,1) = rot_eigen_rad(2) * rot_eigen_rad(1)   *     &
1602                                   ( 1.0_wp - COS( tilt ) )              +     &
[1864]1603                                   rot_eigen_rad(3) * SIN( tilt )
[1912]1604       rot_coord_trans(inot,2,2) = rot_eigen_rad(2)**2                   *     &
[1864]1605                                   ( 1.0_wp - COS( tilt ) ) + COS( tilt ) 
[1912]1606       rot_coord_trans(inot,2,3) = rot_eigen_rad(2) * rot_eigen_rad(3)   *     &
1607                                   ( 1.0_wp - COS( tilt ) )              -     &
[1864]1608                                   rot_eigen_rad(1) * SIN( tilt )
[1912]1609       rot_coord_trans(inot,3,1) = rot_eigen_rad(3) * rot_eigen_rad(1)   *     &
1610                                   ( 1.0_wp - COS( tilt ) )              -     &
[1864]1611                                   rot_eigen_rad(2) * SIN( tilt )
[1912]1612       rot_coord_trans(inot,3,2) = rot_eigen_rad(3) * rot_eigen_rad(2)   *     &
1613                                   ( 1.0_wp - COS( tilt ) )              +     &
[1864]1614                                   rot_eigen_rad(1) * SIN( tilt )
[1912]1615       rot_coord_trans(inot,3,3) = rot_eigen_rad(3)**2                   *     &
[1864]1616                                   ( 1.0_wp - COS( tilt ) ) + COS( tilt )
[1839]1617
[1864]1618!
1619!--    Vectors for the Transformation of forces from the rotor's spheric
1620!--    coordinate system to the cartesian coordinate system
1621       rotx(inot,:) = MATMUL( rot_coord_trans(inot,:,:), rot_eigen_nor )
1622       roty(inot,:) = MATMUL( rot_coord_trans(inot,:,:), rot_eigen_rad )
1623       rotz(inot,:) = MATMUL( rot_coord_trans(inot,:,:), rot_eigen_azi )
1624   
1625    END SUBROUTINE wtm_rotate_rotor
[1839]1626
1627
[1819]1628!------------------------------------------------------------------------------!
1629! Description:
1630! ------------
[1839]1631!> Calculation of the forces generated by the wind turbine
[1819]1632!------------------------------------------------------------------------------!
1633    SUBROUTINE wtm_forces
1634
[1864]1635
[1819]1636       IMPLICIT NONE
1637
[2669]1638       CHARACTER (LEN=4) ::  turbine_id
[1819]1639
[1839]1640       INTEGER(iwp) ::  i, j, k          !< loop indices
1641       INTEGER(iwp) ::  inot             !< turbine loop index (turbine id)
1642       INTEGER(iwp) ::  iialpha, iir     !<
1643       INTEGER(iwp) ::  rseg, rseg_int   !<
1644       INTEGER(iwp) ::  ring, ring_int   !<
1645       INTEGER(iwp) ::  ii, jj, kk       !<
[1912]1646   
[2232]1647       REAL(wp)     ::  flag               !< flag to mask topography grid points
[1839]1648       REAL(wp)     ::  sin_rot, cos_rot   !<
1649       REAL(wp)     ::  sin_yaw, cos_yaw   !<
[1912]1650       
1651       REAL(wp) ::  aa, bb, cc, dd  !< interpolation distances
1652       REAL(wp) ::  gg              !< interpolation volume var 
1653       
1654       REAL(wp) ::  dist_u_3d, dist_v_3d, dist_w_3d  !< smearing distances
1655
1656       
[1839]1657!
[1819]1658!      Variables for pitch control
1659       REAL(wp)     ::  torque_max=0.0_wp
[1839]1660       LOGICAL      ::  pitch_sw=.FALSE.
1661
[1819]1662       INTEGER(iwp), DIMENSION(1) :: lct=0
[1839]1663       REAL(wp), DIMENSION(1)     :: rad_d=0.0_wp
[2152]1664       
1665       REAL(wp) :: tl_factor !< factor for tip loss correction
[1819]1666
1667
[1864]1668       CALL cpu_log( log_point_s(61), 'wtm_forces', 'start' )
[1819]1669
1670
1671       IF ( simulated_time >= time_turbine_on ) THEN
1672
[1864]1673!
[1819]1674!--       Set forces to zero for each new time step:
1675          thrust(:,:,:)         = 0.0_wp
1676          torque_y(:,:,:)       = 0.0_wp
1677          torque_z(:,:,:)       = 0.0_wp
1678          torque_total(:)       = 0.0_wp
[1912]1679          rot_tend_x(:,:,:)     = 0.0_wp
1680          rot_tend_y(:,:,:)     = 0.0_wp
1681          rot_tend_z(:,:,:)     = 0.0_wp
1682          thrust_rotor(:)       = 0.0_wp
[1819]1683!
1684!--       Loop over number of turbines:
1685          DO inot = 1, nturbines
1686
1687             cos_yaw = COS(phi_yaw(inot))
1688             sin_yaw = SIN(phi_yaw(inot))
1689!
[1839]1690!--          Loop over rings of each turbine:
[1819]1691             DO ring = 1, nrings(inot)
1692
1693                thrust_seg(:)   = 0.0_wp
1694                torque_seg_y(:) = 0.0_wp
1695                torque_seg_z(:) = 0.0_wp
1696!
1697!--             Determine distance between each ring (center) and the hub:
1698                cur_r = (ring - 0.5_wp) * delta_r(inot)
1699
1700!
[1839]1701!--             Loop over segments of each ring of each turbine:
[1819]1702                DO rseg = 1, nsegs(ring,inot)
1703!
[1864]1704!--                !-----------------------------------------------------------!
1705!--                !-- Determine coordinates of the ring segments            --!
1706!--                !-----------------------------------------------------------!
[1819]1707!
[1864]1708!--                Determine angle of ring segment towards zero degree angle of
1709!--                rotor system (at zero degree rotor direction vectors aligned
1710!--                with y-axis):
[1819]1711                   phi_rotor = rseg * 2.0_wp * pi / nsegs(ring,inot)
1712                   cos_rot   = COS( phi_rotor )
1713                   sin_rot   = SIN( phi_rotor )
1714
[1864]1715!--                Now the direction vectors can be determined with respect to
1716!--                the yaw and tilt angle:
[1819]1717                   re(1) = cos_rot * sin_yaw
[1839]1718                   re(2) = cos_rot * cos_yaw   
[1819]1719                   re(3) = sin_rot
1720
1721                   rote = MATMUL( rot_coord_trans(inot,:,:), re )
1722!
1723!--                Coordinates of the single segments (center points):
1724                   rbx(ring,rseg) = rcx(inot) + cur_r * rote(1)
1725                   rby(ring,rseg) = rcy(inot) + cur_r * rote(2)
1726                   rbz(ring,rseg) = rcz(inot) + cur_r * rote(3)
1727
[1864]1728!--                !-----------------------------------------------------------!
1729!--                !-- Interpolation of the velocity components from the     --!
1730!--                !-- cartesian grid point to the coordinates of each ring  --!
1731!--                !-- segment (follows a method used in the particle model) --!
1732!--                !-----------------------------------------------------------!
[1819]1733
1734                   u_int(inot,ring,rseg)     = 0.0_wp
1735                   u_int_1_l(inot,ring,rseg) = 0.0_wp
1736
1737                   v_int(inot,ring,rseg)     = 0.0_wp
1738                   v_int_1_l(inot,ring,rseg) = 0.0_wp
1739
1740                   w_int(inot,ring,rseg)     = 0.0_wp
1741                   w_int_1_l(inot,ring,rseg) = 0.0_wp
1742
1743!
1744!--                Interpolation of the u-component:
1745
1746                   ii =   rbx(ring,rseg) * ddx
1747                   jj = ( rby(ring,rseg) - 0.5_wp * dy ) * ddy
[2553]1748                   kk = ( rbz(ring,rseg) + 0.5_wp * dz ) / dz
[1819]1749!
[1864]1750!--                Interpolate only if all required information is available on
1751!--                the current PE:
[1839]1752                   IF ( ( ii >= nxl )  .AND.  ( ii <= nxr ) )  THEN
1753                      IF ( ( jj >= nys )  .AND.  ( jj <= nyn ) )  THEN
[1819]1754
[1839]1755                         aa = ( ( ii + 1          ) * dx - rbx(ring,rseg) ) *  &
1756                              ( ( jj + 1 + 0.5_wp ) * dy - rby(ring,rseg) )
1757                         bb = ( rbx(ring,rseg) - ii * dx )                  *  &
1758                              ( ( jj + 1 + 0.5_wp ) * dy - rby(ring,rseg) )
1759                         cc = ( ( ii+1            ) * dx - rbx(ring,rseg) ) *  &
1760                              ( rby(ring,rseg) - ( jj + 0.5_wp ) * dy )
1761                         dd = ( rbx(ring,rseg) -              ii * dx )     *  &
1762                              ( rby(ring,rseg) - ( jj + 0.5_wp ) * dy ) 
[1819]1763                         gg = dx * dy
1764
[1864]1765                         u_int_l = ( aa * u(kk,jj,ii)     +                    &
1766                                     bb * u(kk,jj,ii+1)   +                    &
1767                                     cc * u(kk,jj+1,ii)   +                    &
1768                                     dd * u(kk,jj+1,ii+1)                      &
[1819]1769                                   ) / gg
1770
[1864]1771                         u_int_u = ( aa * u(kk+1,jj,ii)     +                  &
1772                                     bb * u(kk+1,jj,ii+1)   +                  &
1773                                     cc * u(kk+1,jj+1,ii)   +                  &
1774                                     dd * u(kk+1,jj+1,ii+1)                    &
[1819]1775                                   ) / gg
1776
[1864]1777                         u_int_1_l(inot,ring,rseg) = u_int_l          +        &
1778                                     ( rbz(ring,rseg) - zu(kk) ) / dz *        &
[1819]1779                                     ( u_int_u - u_int_l )
1780
1781                      ELSE
1782                         u_int_1_l(inot,ring,rseg) = 0.0_wp
1783                      ENDIF
1784                   ELSE
1785                      u_int_1_l(inot,ring,rseg) = 0.0_wp
1786                   ENDIF
1787
1788
1789!
1790!--                Interpolation of the v-component:
1791                   ii = ( rbx(ring,rseg) - 0.5_wp * dx ) * ddx
[1839]1792                   jj =   rby(ring,rseg)                 * ddy
[1819]1793                   kk = ( rbz(ring,rseg) + 0.5_wp * dz ) / dz 
1794!
[1864]1795!--                Interpolate only if all required information is available on
1796!--                the current PE:
[1839]1797                   IF ( ( ii >= nxl )  .AND.  ( ii <= nxr ) )  THEN
1798                      IF ( ( jj >= nys )  .AND.  ( jj <= nyn ) )  THEN
[1819]1799
[1839]1800                         aa = ( ( ii + 1 + 0.5_wp ) * dx - rbx(ring,rseg) ) *  &
1801                              ( ( jj + 1 )          * dy - rby(ring,rseg) )
1802                         bb = ( rbx(ring,rseg)     - ( ii + 0.5_wp ) * dx ) *  &
1803                              ( ( jj + 1 ) * dy          - rby(ring,rseg) )
1804                         cc = ( ( ii + 1 + 0.5_wp ) * dx - rbx(ring,rseg) ) *  &
1805                              ( rby(ring,rseg)           -        jj * dy )
1806                         dd = ( rbx(ring,rseg)     - ( ii + 0.5_wp ) * dx ) *  &
1807                              ( rby(ring,rseg)           -        jj * dy )
[1819]1808                         gg = dx * dy
1809
[1864]1810                         v_int_l = ( aa * v(kk,jj,ii)     +                    &
1811                                     bb * v(kk,jj,ii+1)   +                    &
1812                                     cc * v(kk,jj+1,ii)   +                    &
1813                                     dd * v(kk,jj+1,ii+1)                      &
[1819]1814                                   ) / gg
1815
[1864]1816                         v_int_u = ( aa * v(kk+1,jj,ii)     +                  &
1817                                     bb * v(kk+1,jj,ii+1)   +                  &
1818                                     cc * v(kk+1,jj+1,ii)   +                  &
1819                                     dd * v(kk+1,jj+1,ii+1)                    &
[1819]1820                                  ) / gg
1821
[1864]1822                         v_int_1_l(inot,ring,rseg) = v_int_l +                 &
1823                                     ( rbz(ring,rseg) - zu(kk) ) / dz *        &
[1819]1824                                     ( v_int_u - v_int_l )
1825
1826                      ELSE
1827                         v_int_1_l(inot,ring,rseg) = 0.0_wp
1828                      ENDIF
1829                   ELSE
1830                      v_int_1_l(inot,ring,rseg) = 0.0_wp
1831                   ENDIF
1832
1833
1834!
1835!--                Interpolation of the w-component:
1836                   ii = ( rbx(ring,rseg) - 0.5_wp * dx ) * ddx
1837                   jj = ( rby(ring,rseg) - 0.5_wp * dy ) * ddy
[1839]1838                   kk =   rbz(ring,rseg)                 / dz
[1819]1839!
[1864]1840!--                Interpolate only if all required information is available on
1841!--                the current PE:
[1839]1842                   IF ( ( ii >= nxl )  .AND.  ( ii <= nxr ) )  THEN
1843                      IF ( ( jj >= nys )  .AND.  ( jj <= nyn ) )  THEN
[1819]1844
[1839]1845                         aa = ( ( ii + 1 + 0.5_wp ) * dx - rbx(ring,rseg) ) *  &
1846                              ( ( jj + 1 + 0.5_wp ) * dy - rby(ring,rseg) )
1847                         bb = ( rbx(ring,rseg)     - ( ii + 0.5_wp ) * dx ) *  &
1848                              ( ( jj + 1 + 0.5_wp ) * dy - rby(ring,rseg) )
1849                         cc = ( ( ii + 1 + 0.5_wp ) * dx - rbx(ring,rseg) ) *  &
1850                              ( rby(ring,rseg)     - ( jj + 0.5_wp ) * dy )
1851                         dd = ( rbx(ring,rseg)     - ( ii + 0.5_wp ) * dx ) *  &
1852                              ( rby(ring,rseg)     - ( jj + 0.5_wp ) * dy )
[1819]1853                         gg = dx * dy
1854
[1864]1855                         w_int_l = ( aa * w(kk,jj,ii)     +                    &
1856                                     bb * w(kk,jj,ii+1)   +                    &
1857                                     cc * w(kk,jj+1,ii)   +                    &
1858                                     dd * w(kk,jj+1,ii+1)                      &
[1819]1859                                   ) / gg
1860
[1864]1861                         w_int_u = ( aa * w(kk+1,jj,ii)     +                  &
1862                                     bb * w(kk+1,jj,ii+1)   +                  &
1863                                     cc * w(kk+1,jj+1,ii)   +                  &
1864                                     dd * w(kk+1,jj+1,ii+1)                    &
[1819]1865                                    ) / gg
1866
[1864]1867                         w_int_1_l(inot,ring,rseg) = w_int_l +                 &
1868                                     ( rbz(ring,rseg) - zw(kk) ) / dz *        &
[1819]1869                                     ( w_int_u - w_int_l )
1870                      ELSE
1871                         w_int_1_l(inot,ring,rseg) = 0.0_wp
1872                      ENDIF
1873                   ELSE
1874                      w_int_1_l(inot,ring,rseg) = 0.0_wp
1875                   ENDIF
1876
1877                ENDDO
1878             ENDDO
1879
1880          ENDDO
1881
1882!
1883!--       Exchange between PEs (information required on each PE):
1884#if defined( __parallel )
[1839]1885          CALL MPI_ALLREDUCE( u_int_1_l, u_int, nturbines * MAXVAL(nrings) *   &
1886                              MAXVAL(nsegs), MPI_REAL, MPI_SUM, comm2d, ierr )
1887          CALL MPI_ALLREDUCE( v_int_1_l, v_int, nturbines * MAXVAL(nrings) *   &
1888                              MAXVAL(nsegs), MPI_REAL, MPI_SUM, comm2d, ierr )
1889          CALL MPI_ALLREDUCE( w_int_1_l, w_int, nturbines * MAXVAL(nrings) *   &
1890                              MAXVAL(nsegs), MPI_REAL, MPI_SUM, comm2d, ierr )
[1819]1891#else
1892          u_int = u_int_1_l
1893          v_int = v_int_1_l
1894          w_int = w_int_1_l
1895#endif
1896
1897
1898!
1899!--       Loop over number of turbines:
[1912]1900
[1819]1901          DO inot = 1, nturbines
[1912]1902pit_loop: DO
[1819]1903
[1912]1904             IF ( pitch_sw )  THEN
[1839]1905                torque_total(inot) = 0.0_wp
[1912]1906                thrust_rotor(inot) = 0.0_wp
1907                pitch_add(inot)    = pitch_add(inot) + 0.25_wp
1908!                 IF ( myid == 0 ) PRINT*, 'Pitch', inot, pitch_add(inot)
1909             ELSE
1910                cos_yaw = COS(phi_yaw(inot))
1911                sin_yaw = SIN(phi_yaw(inot))
1912                IF ( pitch_control )  THEN
1913                   pitch_add(inot) = MAX(pitch_add_old(inot) - pitch_rate *    &
1914                                         dt_3d , 0.0_wp )
1915                ENDIF
[1819]1916             ENDIF
1917
[1839]1918!
1919!--          Loop over rings of each turbine:
[1819]1920             DO ring = 1, nrings(inot)
1921!
1922!--             Determine distance between each ring (center) and the hub:
1923                cur_r = (ring - 0.5_wp) * delta_r(inot)
[1839]1924!
1925!--             Loop over segments of each ring of each turbine:
[1819]1926                DO rseg = 1, nsegs(ring,inot)
1927!
[1839]1928!--                Determine angle of ring segment towards zero degree angle of
1929!--                rotor system (at zero degree rotor direction vectors aligned
1930!--                with y-axis):
[1819]1931                   phi_rotor = rseg * 2.0_wp * pi / nsegs(ring,inot)
1932                   cos_rot   = COS(phi_rotor)
1933                   sin_rot   = SIN(phi_rotor)
1934!
[1839]1935!--                Now the direction vectors can be determined with respect to
1936!--                the yaw and tilt angle:
[1819]1937                   re(1) = cos_rot * sin_yaw
1938                   re(2) = cos_rot * cos_yaw
1939                   re(3) = sin_rot
1940
[1864]1941!                  The current unit vector in azimuthal direction:                         
[1819]1942                   rea(1) = - sin_rot * sin_yaw
1943                   rea(2) = - sin_rot * cos_yaw
1944                   rea(3) =   cos_rot
1945
1946!
[1864]1947!--                To respect the yawing angle for the calculations of
1948!--                velocities and forces the unit vectors perpendicular to the
1949!--                rotor area in direction of the positive yaw angle are defined:
[1819]1950                   ren(1) =   cos_yaw
1951                   ren(2) = - sin_yaw
1952                   ren(3) = 0.0_wp
1953!
1954!--                Multiplication with the coordinate transformation matrix
[1864]1955!--                gives the final unit vector with consideration of the rotor
1956!--                tilt:
[1819]1957                   rote = MATMUL( rot_coord_trans(inot,:,:), re )
1958                   rota = MATMUL( rot_coord_trans(inot,:,:), rea )
1959                   rotn = MATMUL( rot_coord_trans(inot,:,:), ren )
1960!
1961!--                Coordinates of the single segments (center points):
1962                   rbx(ring,rseg) = rcx(inot) + cur_r * rote(1)
1963
1964                   rby(ring,rseg) = rcy(inot) + cur_r * rote(2)
1965
1966                   rbz(ring,rseg) = rcz(inot) + cur_r * rote(3)
1967
1968!
[1864]1969!--                !-----------------------------------------------------------!
1970!--                !-- Calculation of various angles and relative velocities --!
1971!--                !-----------------------------------------------------------!
[1819]1972!
[1864]1973!--                In the following the 3D-velocity field is projected its
[2553]1974!--                components perpendicular and parallel to the rotor area
[1819]1975!--                The calculation of forces will be done in the rotor-
1976!--                coordinates y' and z.
1977!--                The yaw angle will be reintroduced when the force is applied
1978!--                on the hydrodynamic equations
[1864]1979!
1980!--                Projection of the xy-velocities relative to the rotor area
1981!
[1819]1982!--                Velocity perpendicular to the rotor area:
[1864]1983                   u_rot = u_int(inot,ring,rseg)*rotn(1) +                     &
1984                   v_int(inot,ring,rseg)*rotn(2) +                             &
[1819]1985                   w_int(inot,ring,rseg)*rotn(3)
1986!
[1864]1987!--                Projection of the 3D-velocity vector in the azimuthal
1988!--                direction:
1989                   vtheta(rseg) = rota(1) * u_int(inot,ring,rseg) +            & 
1990                                  rota(2) * v_int(inot,ring,rseg) +            &
[1819]1991                                  rota(3) * w_int(inot,ring,rseg)
1992!
[1864]1993!--                Determination of the angle phi_rel between the rotor plane
1994!--                and the direction of the flow relative to the rotor:
[1819]1995
[1864]1996                   phi_rel(rseg) = ATAN( u_rot /                               &
1997                                         ( omega_rot(inot) * cur_r -           &
[1819]1998                                           vtheta(rseg) ) )
1999
2000!
[1864]2001!--                Interpolation of the local pitch angle from tabulated values
2002!--                to the current radial position:
[1819]2003
2004                   lct=minloc(ABS(cur_r-lrd))
2005                   rad_d=cur_r-lrd(lct)
2006                   
2007                   IF (cur_r == 0.0_wp) THEN
2008                      alpha_attack(rseg) = 0.0_wp
2009                   ELSE IF (cur_r >= lrd(size(ard))) THEN
[1864]2010                      alpha_attack(rseg) = ( ard(size(ard)) +                  &
2011                                             ard(size(ard)-1) ) / 2.0_wp
[1819]2012                   ELSE
[1864]2013                      alpha_attack(rseg) = ( ard(lct(1)) *  &
2014                                             ( ( lrd(lct(1)+1) - cur_r ) /     &
2015                                               ( lrd(lct(1)+1) - lrd(lct(1)) ) &
2016                                             ) ) + ( ard(lct(1)+1) *           &
2017                                             ( ( cur_r - lrd(lct(1)) ) /       &
2018                                               ( lrd(lct(1)+1) - lrd(lct(1)) ) ) )
[1819]2019                   ENDIF
2020
2021!
[1864]2022!--                In Fortran radian instead of degree is used as unit for all
2023!--                angles. Therefore, a transformation from angles given in
2024!--                degree to angles given in radian is necessary here:
2025                   alpha_attack(rseg) = alpha_attack(rseg) *                   &
[1819]2026                                        ( (2.0_wp*pi) / 360.0_wp )
2027!
[1864]2028!--                Substraction of the local pitch angle to obtain the local
2029!--                angle of attack:
[1819]2030                   alpha_attack(rseg) = phi_rel(rseg) - alpha_attack(rseg)
2031!
[1864]2032!--                Preliminary transformation back from angles given in radian
2033!--                to angles given in degree:
2034                   alpha_attack(rseg) = alpha_attack(rseg) *                   &
[1819]2035                                        ( 360.0_wp / (2.0_wp*pi) )
2036!
[1864]2037!--                Correct with collective pitch angle:
[2015]2038                   alpha_attack = alpha_attack - pitch_add(inot)
[1819]2039
2040!
[1864]2041!--                Determination of the magnitude of the flow velocity relative
2042!--                to the rotor:
[1912]2043                   vrel(rseg) = SQRT( u_rot**2 +                               &
2044                                      ( omega_rot(inot) * cur_r -              &
[1819]2045                                        vtheta(rseg) )**2 )
2046
2047!
[1864]2048!--                !-----------------------------------------------------------!
2049!--                !-- Interpolation of chord as well as lift and drag       --!
2050!--                !-- coefficients from tabulated values                    --!
2051!--                !-----------------------------------------------------------!
[1819]2052
2053!
[1864]2054!--                Interpolation of the chord_length from tabulated values to
2055!--                the current radial position:
[1819]2056
2057                   IF (cur_r == 0.0_wp) THEN
2058                      chord(rseg) = 0.0_wp
2059                   ELSE IF (cur_r >= lrd(size(crd))) THEN
[1864]2060                      chord(rseg) = (crd(size(crd)) + ard(size(crd)-1)) / 2.0_wp
[1819]2061                   ELSE
[1864]2062                      chord(rseg) = ( crd(lct(1)) *                            &
2063                            ( ( lrd(lct(1)+1) - cur_r ) /                      &
2064                              ( lrd(lct(1)+1) - lrd(lct(1)) ) ) ) +            &
2065                            ( crd(lct(1)+1) *                                  &
2066                            ( ( cur_r-lrd(lct(1)) ) /                          &
2067                              ( lrd(lct(1)+1) - lrd(lct(1)) ) ) )
[1819]2068                   ENDIF
2069
2070!
2071!--                Determine index of current angle of attack, needed for
[1864]2072!--                finding the appropriate interpolated values of the lift and
[2836]2073!--                drag coefficients (-180.0 degrees = 1, +180.0 degrees = 3601,
2074!--                so one index every 0.1 degrees):
[1864]2075                   iialpha = CEILING( ( alpha_attack(rseg) + 180.0_wp )        &
[2836]2076                                      * ( 1.0_wp / accu_cl_cd_tab ) ) + 1.0_wp
[1819]2077!
2078!--                Determine index of current radial position, needed for
[1864]2079!--                finding the appropriate interpolated values of the lift and
2080!--                drag coefficients (one index every 0.1 m):
[1819]2081                   iir = CEILING( cur_r * 10.0_wp )
2082!
[1864]2083!--                Read in interpolated values of the lift and drag coefficients
2084!--                for the current radial position and angle of attack:
[1839]2085                   turb_cl(rseg) = turb_cl_tab(iialpha,iir)
2086                   turb_cd(rseg) = turb_cd_tab(iialpha,iir)
[1819]2087
2088!
[1864]2089!--                Final transformation back from angles given in degree to
2090!--                angles given in radian:
2091                   alpha_attack(rseg) = alpha_attack(rseg) *                   &
[1819]2092                                        ( (2.0_wp*pi) / 360.0_wp )
2093
[2152]2094                   IF ( tl_cor )  THEN
2095                   
2096!--                  Tip loss correction following Schito
2097!--                  Schito applies the tip loss correction only to the lift force
2098!--                  Therefore, the tip loss correction is only applied to the lift
2099!--                  coefficient and not to the drag coefficient in our case
2100!--                 
2101                     tl_factor = ( 2.0 / pi ) *                                &
2102                          ACOS( EXP( -1.0 * ( 3.0 * ( rr(inot) - cur_r ) /     &
2103                          ( 2.0 * cur_r * abs( sin( phi_rel(rseg) ) ) ) ) ) )
2104                         
2105                     turb_cl(rseg)  = tl_factor * turb_cl(rseg)                                 
2106                                 
[2894]2107                   ENDIF               
[1819]2108!
2109!--                !-----------------------------------------------------!
2110!--                !-- Calculation of the forces                       --!
2111!--                !-----------------------------------------------------!
2112
2113!
[1864]2114!--                Calculate the pre_factor for the thrust and torque forces:
[1819]2115
2116                   pre_factor = 0.5_wp * (vrel(rseg)**2) * 3.0_wp *  &
2117                                chord(rseg) * delta_r(inot) / nsegs(ring,inot)
2118
2119!
[1864]2120!--                Calculate the thrust force (x-component of the total force)
2121!--                for each ring segment:
2122                   thrust_seg(rseg) = pre_factor *                             &
2123                                      ( turb_cl(rseg) * COS(phi_rel(rseg)) +   &
2124                                        turb_cd(rseg) * SIN(phi_rel(rseg)) )
[1819]2125
2126!
[1864]2127!--                Determination of the second of the additional forces acting
2128!--                on the flow in the azimuthal direction: force vector as basis
2129!--                for torque (torque itself would be the vector product of the
2130!--                radius vector and the force vector):
2131                   torque_seg = pre_factor *                                   &
2132                                ( turb_cl(rseg) * SIN(phi_rel(rseg)) -         &
[1839]2133                                  turb_cd(rseg) * COS(phi_rel(rseg)) )
[1819]2134!
2135!--                Decomposition of the force vector into two parts:
[1864]2136!--                One acting along the y-direction and one acting along the
2137!--                z-direction of the rotor coordinate system:
[1819]2138
2139                   torque_seg_y(rseg) = -torque_seg * sin_rot
2140                   torque_seg_z(rseg) =  torque_seg * cos_rot
2141
[1912]2142!
2143!--                Add the segment thrust to the thrust of the whole rotor
2144                   thrust_rotor(inot) = thrust_rotor(inot) +                   &
2145                                        thrust_seg(rseg)                   
2146                   
2147
[1819]2148                   torque_total(inot) = torque_total(inot) + (torque_seg * cur_r)
2149
[1864]2150                ENDDO   !-- end of loop over ring segments
[1819]2151
2152!
[1864]2153!--             Restore the forces into arrays containing all the segments of
2154!--             each ring:
[1819]2155                thrust_ring(ring,:)   = thrust_seg(:)
2156                torque_ring_y(ring,:) = torque_seg_y(:)
2157                torque_ring_z(ring,:) = torque_seg_z(:)
2158
2159
[1864]2160             ENDDO   !-- end of loop over rings
[1819]2161
2162
[1864]2163             CALL cpu_log( log_point_s(62), 'wtm_controller', 'start' )
[1819]2164
[1912]2165             
2166             IF ( speed_control )  THEN
2167!
2168!--             Calculation of the current generator speed for rotor speed control
2169             
2170!                                     
2171!--             The acceleration of the rotor speed is calculated from
2172!--             the force balance of the accelerating torque
2173!--             and the torque of the rotating rotor and generator
2174                om_rate = ( torque_total(inot) * air_dens * gear_eff -         &
2175                            gear_ratio * torque_gen_old(inot) ) /              &
2176                          ( inertia_rot +                                      & 
2177                            gear_ratio * gear_ratio * inertia_gen ) * dt_3d
[1819]2178
[1912]2179!
2180!--             The generator speed is given by the product of gear gear_ratio
2181!--             and rotor speed
2182                omega_gen(inot) = gear_ratio * ( omega_rot(inot) + om_rate )     
2183             
2184             ENDIF
2185             
[1864]2186             IF ( pitch_control )  THEN
[1819]2187
[1912]2188!
2189!--             If the current generator speed is above rated, the pitch is not
2190!--             saturated and the change from the last time step is within the
2191!--             maximum pitch rate, then the pitch loop is repeated with a pitch
2192!--             gain
2193                IF ( (  omega_gen(inot)  > rated_genspeed   )  .AND.           &
2194                     ( pitch_add(inot) < 25.0_wp ) .AND.                       &
2195                     ( pitch_add(inot) < pitch_add_old(inot) +                 & 
2196                       pitch_rate * dt_3d  ) ) THEN
[1864]2197                   pitch_sw = .TRUE.
[1912]2198!
2199!--                Go back to beginning of pit_loop                   
2200                   CYCLE pit_loop
[1819]2201                ENDIF
[1912]2202               
2203!
2204!--             The current pitch is saved for the next time step
2205                pitch_add_old(inot) = pitch_add(inot)
[1864]2206                pitch_sw = .FALSE.
[1819]2207             ENDIF
[1912]2208             EXIT pit_loop             
2209          ENDDO pit_loop ! Recursive pitch control loop
[1819]2210
[1864]2211
[1819]2212!
[1864]2213!--          Call the rotor speed controller
2214             
[1819]2215             IF ( speed_control )  THEN
2216!
[1864]2217!--             Find processor at i_hub, j_hub             
[1912]2218                IF ( ( nxl <= i_hub(inot) )  .AND.  ( nxr >= i_hub(inot) ) )   &
2219                   THEN
2220                   IF ( ( nys <= j_hub(inot) )  .AND.  ( nyn >= j_hub(inot) ) )&
2221                      THEN
[1864]2222                      CALL wtm_speed_control( inot )
2223                   ENDIF
[1912]2224                ENDIF
[1864]2225                               
[1819]2226             ENDIF
2227
2228
[1864]2229             CALL cpu_log( log_point_s(62), 'wtm_controller', 'stop' )
[1819]2230
[1864]2231             CALL cpu_log( log_point_s(63), 'wtm_smearing', 'start' )
[1819]2232
2233
[1864]2234!--          !-----------------------------------------------------------------!
2235!--          !--                  Regularization kernel                      --!
2236!--          !-- Smearing of the forces and interpolation to cartesian grid  --!
2237!--          !-----------------------------------------------------------------!
[1819]2238!
[1864]2239!--          The aerodynamic blade forces need to be distributed smoothly on
2240!--          several mesh points in order to avoid singular behaviour
[1819]2241!
2242!--          Summation over sum of weighted forces. The weighting factor
[1864]2243!--          (calculated in user_init) includes information on the distance
2244!--          between the center of the grid cell and the rotor segment under
2245!--          consideration
[1819]2246!
[1864]2247!--          To save computing time, apply smearing only for the relevant part
2248!--          of the model domain:
[1819]2249!
2250!--
2251!--          Calculation of the boundaries:
[1864]2252             i_smear(inot) = CEILING( ( rr(inot) * ABS( roty(inot,1) ) +       &
2253                                        eps_min ) / dx )
2254             j_smear(inot) = CEILING( ( rr(inot) * ABS( roty(inot,2) ) +       &
2255                                        eps_min ) / dy )
[1819]2256
[1864]2257             DO i = MAX( nxl, i_hub(inot) - i_smear(inot) ),                   &
[1819]2258                    MIN( nxr, i_hub(inot) + i_smear(inot) )
[1864]2259                DO j = MAX( nys, j_hub(inot) - j_smear(inot) ),                &
[1819]2260                        MIN( nyn, j_hub(inot) + j_smear(inot) )
[2232]2261!                    DO k = MAX( nzb_u_inner(j,i)+1, k_hub(inot) - k_smear(inot) ), &
2262!                                 k_hub(inot) + k_smear(inot)
2263                   DO  k = nzb+1, k_hub(inot) + k_smear(inot)
[1819]2264                      DO ring = 1, nrings(inot)
2265                         DO rseg = 1, nsegs(ring,inot)
2266!
[2232]2267!--                         Predetermine flag to mask topography
2268                            flag = MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_0(k,j,i), 1 ) )
2269     
2270!
[1819]2271!--                         Determine the square of the distance between the
2272!--                         current grid point and each rotor area segment:
[1864]2273                            dist_u_3d = ( i * dx               - rbx(ring,rseg) )**2 + &
2274                                        ( j * dy + 0.5_wp * dy - rby(ring,rseg) )**2 + &
2275                                        ( k * dz - 0.5_wp * dz - rbz(ring,rseg) )**2
2276                            dist_v_3d = ( i * dx + 0.5_wp * dx - rbx(ring,rseg) )**2 + &
2277                                        ( j * dy               - rby(ring,rseg) )**2 + &
2278                                        ( k * dz - 0.5_wp * dz - rbz(ring,rseg) )**2
2279                            dist_w_3d = ( i * dx + 0.5_wp * dx - rbx(ring,rseg) )**2 + &
2280                                        ( j * dy + 0.5_wp * dy - rby(ring,rseg) )**2 + &
2281                                        ( k * dz               - rbz(ring,rseg) )**2
[1819]2282
2283!
2284!--                         3D-smearing of the forces with a polynomial function
2285!--                         (much faster than the old Gaussian function), using
2286!--                         some parameters that have been calculated in user_init.
2287!--                         The function is only similar to Gaussian function for
2288!--                         squared distances <= eps_min2:
2289                            IF ( dist_u_3d <= eps_min2 ) THEN
[2232]2290                               thrust(k,j,i) = thrust(k,j,i) +                     &
2291                                               thrust_ring(ring,rseg) *            &
2292                                               ( ( pol_a * dist_u_3d - pol_b ) *   & 
2293                                                dist_u_3d + 1.0_wp ) * eps_factor *&
2294                                                                       flag
[1819]2295                            ENDIF
2296                            IF ( dist_v_3d <= eps_min2 ) THEN
[2232]2297                               torque_y(k,j,i) = torque_y(k,j,i) +                    &
2298                                                 torque_ring_y(ring,rseg) *           &
2299                                                 ( ( pol_a * dist_v_3d - pol_b ) *    &
2300                                                  dist_v_3d + 1.0_wp ) * eps_factor * &
2301                                                                         flag
[1819]2302                            ENDIF
2303                            IF ( dist_w_3d <= eps_min2 ) THEN
[2232]2304                               torque_z(k,j,i) = torque_z(k,j,i) +                    &
2305                                                 torque_ring_z(ring,rseg) *           &
2306                                                 ( ( pol_a * dist_w_3d - pol_b ) *    &
2307                                                  dist_w_3d + 1.0_wp ) * eps_factor * &
2308                                                                         flag
[1819]2309                            ENDIF
2310
2311                         ENDDO  ! End of loop over rseg
2312                      ENDDO     ! End of loop over ring
2313             
2314!
2315!--                   Rotation of force components:
[2232]2316                      rot_tend_x(k,j,i) = rot_tend_x(k,j,i) + (                &
[1864]2317                                      thrust(k,j,i)*rotx(inot,1) +             &
2318                                      torque_y(k,j,i)*roty(inot,1) +           &
[2232]2319                                      torque_z(k,j,i)*rotz(inot,1)             &
2320                                                              ) * flag
[1819]2321                               
[2232]2322                      rot_tend_y(k,j,i) = rot_tend_y(k,j,i) + (                &
[1864]2323                                      thrust(k,j,i)*rotx(inot,2) +             &
2324                                      torque_y(k,j,i)*roty(inot,2) +           &
[2232]2325                                      torque_z(k,j,i)*rotz(inot,2)             &
2326                                                              ) * flag
[1819]2327                               
[2232]2328                      rot_tend_z(k,j,i) = rot_tend_z(k,j,i) + (                &
[1864]2329                                      thrust(k,j,i)*rotx(inot,3) +             &
2330                                      torque_y(k,j,i)*roty(inot,3) +           &
[2232]2331                                      torque_z(k,j,i)*rotz(inot,3)             &
2332                                                              ) * flag                   
[1819]2333
2334                   ENDDO        ! End of loop over k
2335                ENDDO           ! End of loop over j
2336             ENDDO              ! End of loop over i
2337
[1864]2338             CALL cpu_log( log_point_s(63), 'wtm_smearing', 'stop' )         
[1819]2339                   
[1912]2340          ENDDO                  !-- end of loop over turbines
[1819]2341
2342               
2343          IF ( yaw_control )  THEN
2344!
2345!--          Allocate arrays for yaw control at first call
2346!--          Can't be allocated before dt_3d is set
2347             IF ( start_up )  THEN
[1864]2348                WDLON = NINT( 30.0_wp / dt_3d )  ! 30s running mean array
[1819]2349                ALLOCATE( wd30(1:nturbines,1:WDLON) )
[1912]2350                wd30 = 999.0_wp                  ! Set to dummy value
[1819]2351                ALLOCATE( wd30_l(1:WDLON) )
2352               
[1864]2353                WDSHO = NINT( 2.0_wp / dt_3d )   ! 2s running mean array
[1819]2354                ALLOCATE( wd2(1:nturbines,1:WDSHO) )
[1912]2355                wd2 = 999.0_wp                   ! Set to dummy value
[1819]2356                ALLOCATE( wd2_l(1:WDSHO) )
2357                start_up = .FALSE.
2358             ENDIF         
2359
2360!
2361!--          Calculate the inflow wind speed
2362!--
2363!--          Loop over number of turbines:
2364             DO inot = 1, nturbines
2365!
2366!--             Find processor at i_hub, j_hub             
[1912]2367                IF ( ( nxl <= i_hub(inot) )  .AND.  ( nxr >= i_hub(inot) ) )   &
2368                   THEN
2369                   IF ( ( nys <= j_hub(inot) )  .AND.  ( nyn >= j_hub(inot) ) )&
2370                      THEN
[1864]2371
[1819]2372                      u_inflow_l(inot) = u(k_hub(inot),j_hub(inot),i_hub(inot))
[1864]2373
[1912]2374                      wdir_l(inot) = -1.0_wp * ATAN2(                          &
2375                         0.5_wp * ( v(k_hub(inot),j_hub(inot),i_hub(inot)+1) + &
2376                                    v(k_hub(inot),j_hub(inot),i_hub(inot)) ) , &
2377                         0.5_wp * ( u(k_hub(inot),j_hub(inot)+1,i_hub(inot)) + &
2378                                    u(k_hub(inot),j_hub(inot),i_hub(inot)) ) )
[1864]2379
2380                      CALL wtm_yawcontrol( inot )
2381
[1819]2382                      phi_yaw_l(inot) = phi_yaw(inot)
[2015]2383                     
[1819]2384                   ENDIF
2385                ENDIF
2386                   
[1864]2387             ENDDO                                 !-- end of loop over turbines
2388
2389!
[1929]2390!--          Transfer of information to the other cpus
2391#if defined( __parallel )         
[1864]2392             CALL MPI_ALLREDUCE( u_inflow_l, u_inflow, nturbines, MPI_REAL,    &
2393                                 MPI_SUM, comm2d, ierr )
2394             CALL MPI_ALLREDUCE( wdir_l, wdir, nturbines, MPI_REAL, MPI_SUM,   &
2395                                 comm2d, ierr )
2396             CALL MPI_ALLREDUCE( phi_yaw_l, phi_yaw, nturbines, MPI_REAL,      &
2397                                 MPI_SUM, comm2d, ierr )
[1929]2398#else
2399             u_inflow = u_inflow_l
2400             wdir     = wdir_l
2401             phi_yaw  = phi_yaw_l
[2015]2402             
2403             
[1929]2404#endif
[1819]2405             DO inot = 1, nturbines
[1864]2406!             
2407!--             Update rotor orientation               
2408                CALL wtm_rotate_rotor( inot )
[1819]2409
2410             ENDDO ! End of loop over turbines
2411                           
[2894]2412          ENDIF  ! end of yaw control
[1864]2413         
2414          IF ( speed_control )  THEN
2415!
2416!--          Transfer of information to the other cpus
[1912]2417!              CALL MPI_ALLREDUCE( omega_gen, omega_gen_old, nturbines,        &
2418!                                  MPI_REAL,MPI_SUM, comm2d, ierr )
[1929]2419#if defined( __parallel )   
[1864]2420             CALL MPI_ALLREDUCE( torque_gen, torque_gen_old, nturbines,        &
2421                                 MPI_REAL, MPI_SUM, comm2d, ierr )
2422             CALL MPI_ALLREDUCE( omega_rot_l, omega_rot, nturbines,            &
2423                                 MPI_REAL, MPI_SUM, comm2d, ierr )
[1912]2424             CALL MPI_ALLREDUCE( omega_gen_f, omega_gen_f_old, nturbines,      &
2425                                 MPI_REAL, MPI_SUM, comm2d, ierr )
[1929]2426#else
2427             torque_gen_old  = torque_gen
2428             omega_rot       = omega_rot_l
2429             omega_gen_f_old = omega_gen_f
2430#endif
[1864]2431           
2432          ENDIF
[1819]2433
2434          DO inot = 1, nturbines
2435
2436             IF ( myid == 0 ) THEN
2437                IF ( openfile_turb_mod(400+inot)%opened )  THEN
2438                   WRITE ( 400+inot, 106 ) simulated_time, omega_rot(inot),    &
[1912]2439                             omega_gen(inot), torque_gen_old(inot),            &
[1864]2440                             torque_total(inot), pitch_add(inot),              &
[1912]2441                             torque_gen_old(inot)*omega_gen(inot)*gen_eff,     &
[1864]2442                             torque_total(inot)*omega_rot(inot)*air_dens,      &
[1912]2443                             thrust_rotor(inot),                               & 
[1864]2444                             wdir(inot)*180.0_wp/pi,                           &
2445                             (phi_yaw(inot))*180.0_wp/pi                   
[1912]2446                             
[1819]2447                ELSE
2448
[2669]2449                   WRITE ( turbine_id,'(A2,I2.2)')  '_T', inot
2450                   OPEN ( 400+inot, FILE=( 'WTM_OUTPUT_DATA' //                &
2451                                           TRIM( coupling_char ) //            &
2452                                           turbine_id ), FORM='FORMATTED' )
[1819]2453                   WRITE ( 400+inot, 105 ) inot
2454                   WRITE ( 400+inot, 106 ) simulated_time, omega_rot(inot),    &
[1912]2455                             omega_gen(inot), torque_gen_old(inot),            &
[1864]2456                             torque_total(inot), pitch_add(inot),              &
[1912]2457                             torque_gen_old(inot)*omega_gen(inot)*gen_eff,     &
[1864]2458                             torque_total(inot)*omega_rot(inot)*air_dens,      &
[1912]2459                             thrust_rotor(inot),                               & 
[1864]2460                             wdir(inot)*180.0_wp/pi,                           &                   
2461                             (phi_yaw(inot))*180.0_wp/pi
[1819]2462                ENDIF
2463             ENDIF
2464
[1912]2465!--          Set open flag
[1819]2466             openfile_turb_mod(400+inot)%opened = .TRUE.
[1864]2467          ENDDO                                    !-- end of loop over turbines
[1819]2468
2469       ENDIF
2470
[1864]2471       CALL cpu_log( log_point_s(61), 'wtm_forces', 'stop' )
[1819]2472       
[1912]2473!
2474!--    Formats
[1819]2475       105 FORMAT ('Turbine control data for turbine ',I2,1X,':'/ &
2476              &'----------------------------------------'/ &
2477              &'   Time   RSpeed  GSpeed  ', &
[1912]2478               'GenTorque  AeroTorque  Pitch  Power(Gen)  Power(Rot)  ',       &
2479               'RotThrust  WDirection  YawOrient')
[1819]2480
[1864]2481       106 FORMAT (F9.3,2X,F7.3,2X,F7.2,2X,F9.1,3X,F9.1,1X,F6.2,2X,F10.1,2X,   &
2482                   F10.1,1X,F9.1,2X,F7.2,1X,F7.2)
[1819]2483
2484
2485    END SUBROUTINE wtm_forces
2486
2487   
[1839]2488!------------------------------------------------------------------------------!
2489! Description:
2490! ------------
2491!> Yaw controller for the wind turbine model
2492!------------------------------------------------------------------------------!
2493    SUBROUTINE wtm_yawcontrol( inot )
2494   
[1819]2495       USE kinds
[1839]2496               
2497       IMPLICIT NONE
[1819]2498     
2499       INTEGER(iwp)             :: inot
2500       INTEGER(iwp)             :: i_wd_30
2501       REAL(wp)                 :: missal
2502
2503       i_wd_30 = 0_iwp
2504
2505
[1864]2506!--    The yaw controller computes a 30s running mean of the wind direction.
2507!--    If the difference between turbine alignment and wind direction exceeds
2508!--    5°, the turbine is yawed. The mechanism stops as soon as the 2s-running
2509!--    mean of the missalignment is smaller than 0.5°.
2510!--    Attention: If the timestep during the simulation changes significantly
2511!--    the lengths of the running means change and it does not correspond to
2512!--    30s/2s anymore.
2513!--    ! Needs to be modified for these situations !
2514!--    For wind from the east, the averaging of the wind direction could cause
2515!--    problems and the yaw controller is probably flawed. -> Routine for
2516!--    averaging needs to be improved!
2517!
2518!--    Check if turbine is not yawing
[1819]2519       IF ( .NOT. doyaw(inot) )  THEN
[1843]2520!
[1864]2521!--       Write current wind direction into array
[1843]2522          wd30_l    = wd30(inot,:)
2523          wd30_l    = CSHIFT( wd30_l, SHIFT=-1 )
[1819]2524          wd30_l(1) = wdir(inot)
[1843]2525!
[1864]2526!--       Check if array is full ( no more dummies )
[1819]2527          IF ( .NOT. ANY( wd30_l == 999.) ) THEN
2528
2529             missal = SUM( wd30_l ) / SIZE( wd30_l ) - phi_yaw(inot)
2530!
[1864]2531!--          Check if turbine is missaligned by more than max_miss
[1843]2532             IF ( ABS( missal ) > max_miss )  THEN
2533!
[1864]2534!--             Check in which direction to yaw         
[1843]2535                yawdir(inot) = SIGN( 1.0_wp, missal )
[1819]2536!
[1864]2537!--             Start yawing of turbine
[1843]2538                phi_yaw(inot) = phi_yaw(inot) + yawdir(inot) * yaw_speed * dt_3d
[1819]2539                doyaw(inot) = .TRUE.
[1864]2540                wd30_l = 999.  ! fill with dummies again
[1819]2541             ENDIF
2542          ENDIF
2543         
2544          wd30(inot,:) = wd30_l
2545
2546!     
[1864]2547!--    If turbine is already yawing:
2548!--    Initialize 2 s running mean and yaw until the missalignment is smaller
2549!--    than min_miss
[1819]2550
2551       ELSE
2552!
2553!--       Initialize 2 s running mean
2554          wd2_l = wd2(inot,:)
[1864]2555          wd2_l = CSHIFT( wd2_l, SHIFT = -1 )
[1819]2556          wd2_l(1) = wdir(inot)
[1843]2557!     
[1864]2558!--       Check if array is full ( no more dummies )
2559          IF ( .NOT. ANY( wd2_l == 999.0_wp ) ) THEN
2560!
2561!--          Calculate missalignment of turbine       
[1819]2562             missal = SUM( wd2_l - phi_yaw(inot) ) / SIZE( wd2_l )
[1864]2563!
2564!--          Check if missalignment is still larger than 0.5 degree and if the
2565!--          yaw direction is still right
2566             IF ( ( ABS( missal ) > min_miss )  .AND.                          &
2567                  ( yawdir(inot) == SIGN( 1.0_wp, missal ) ) )  THEN
2568!
2569!--             Continue yawing       
2570                phi_yaw(inot) = phi_yaw(inot) + yawdir(inot) * yaw_speed * dt_3d
[1819]2571             ELSE
[1864]2572!
2573!--             Stop yawing       
[1819]2574                doyaw(inot) = .FALSE.
[1864]2575                wd2_l = 999.0_wp ! fill with dummies again
[1819]2576             ENDIF
2577          ELSE
[1864]2578!
2579!--          Continue yawing
[1843]2580             phi_yaw(inot) = phi_yaw(inot) + yawdir(inot) * yaw_speed * dt_3d
[1819]2581          ENDIF
2582     
2583          wd2(inot,:) = wd2_l
2584           
2585       ENDIF
2586     
[1839]2587    END SUBROUTINE wtm_yawcontrol 
[1819]2588
[1864]2589
[1819]2590!------------------------------------------------------------------------------!
2591! Description:
2592! ------------
[1864]2593!> Initialization of the speed control
2594!------------------------------------------------------------------------------!
2595    SUBROUTINE wtm_init_speed_control
2596
2597
2598       IMPLICIT NONE
2599
2600!
2601!--    If speed control is set, remaining variables and control_parameters for
2602!--    the control algorithm are calculated
2603!
2604!--    Calculate slope constant for region 15
2605       slope15   = ( slope2 * min_reg2 * min_reg2 ) / ( min_reg2 - min_reg15 )
2606!
2607!--    Calculate upper limit of slipage region
2608       vs_sysp   = rated_genspeed / 1.1_wp
2609!
2610!--    Calculate slope of slipage region
2611       slope25   = ( rated_power / rated_genspeed ) /                          &
2612                   ( rated_genspeed - vs_sysp )
2613!
2614!--    Calculate lower limit of slipage region
2615       min_reg25 = ( slope25 - SQRT( slope25 * ( slope25 - 4.0_wp *            &
2616                                                 slope2 * vs_sysp ) ) ) /      &
[2410]2617                   ( 2.0_wp * slope2 ) 
[1864]2618!
2619!--    Frequency for the simple low pass filter
2620       Fcorner   = 0.25_wp
2621!
2622!--    At the first timestep the torque is set to its maximum to prevent
2623!--    an overspeeding of the rotor
[2563]2624       IF ( TRIM( initializing_actions ) /= 'read_restart_data' ) THEN
2625          torque_gen_old(:) = max_torque_gen
2626       ENDIF 
[1864]2627     
2628    END SUBROUTINE wtm_init_speed_control
2629
2630
2631!------------------------------------------------------------------------------!
2632! Description:
2633! ------------
2634!> Simple controller for the regulation of the rotor speed
2635!------------------------------------------------------------------------------!
2636    SUBROUTINE wtm_speed_control( inot )
2637
2638
2639       IMPLICIT NONE
2640
[1912]2641       INTEGER(iwp)             :: inot
2642       
2643         
[1864]2644
2645!
2646!--    The controller is based on the fortran script from Jonkman
2647!--    et al. 2009 "Definition of a 5 MW Reference Wind Turbine for
2648!--    offshore system developement"
2649
2650!
2651!--    The generator speed is filtered by a low pass filter
2652!--    for the control of the generator torque       
2653       lp_coeff = EXP( -2.0_wp * 3.14_wp * dt_3d * Fcorner )
[1912]2654       omega_gen_f(inot) = ( 1.0_wp - lp_coeff ) * omega_gen(inot) + lp_coeff *&
[1864]2655                           omega_gen_f_old(inot)
2656
2657       IF ( omega_gen_f(inot) <= min_reg15 )  THEN
2658!                       
2659!--       Region 1: Generator torque is set to zero to accelerate the rotor:
2660          torque_gen(inot) = 0
2661       
2662       ELSEIF ( omega_gen_f(inot) <= min_reg2 )  THEN
2663!                       
2664!--       Region 1.5: Generator torque is increasing linearly with rotor speed:
2665          torque_gen(inot) = slope15 * ( omega_gen_f(inot) - min_reg15 )
2666                         
2667       ELSEIF ( omega_gen_f(inot) <= min_reg25 )  THEN
2668!
2669!--       Region 2: Generator torque is increased by the square of the generator
2670!--                 speed to keep the TSR optimal:
2671          torque_gen(inot) = slope2 * omega_gen_f(inot) * omega_gen_f(inot)
2672       
2673       ELSEIF ( omega_gen_f(inot) < rated_genspeed )  THEN
2674!                       
2675!--       Region 2.5: Slipage region between 2 and 3:
2676          torque_gen(inot) = slope25 * ( omega_gen_f(inot) - vs_sysp )
2677       
2678       ELSE
2679!                       
2680!--       Region 3: Generator torque is antiproportional to the rotor speed to
2681!--                 keep the power constant:
2682          torque_gen(inot) = rated_power / omega_gen_f(inot)
2683       
2684       ENDIF
2685!                       
2686!--    Calculate torque rate and confine with a max
2687       trq_rate = ( torque_gen(inot) - torque_gen_old(inot) ) / dt_3d
2688       trq_rate = MIN( MAX( trq_rate, -1.0_wp * max_trq_rate ), max_trq_rate )
2689!                       
2690!--    Calculate new gen torque and confine with max torque                         
2691       torque_gen(inot) = torque_gen_old(inot) + trq_rate * dt_3d
2692       torque_gen(inot) = MIN( torque_gen(inot), max_torque_gen )                                             
2693!
2694!--    Overwrite values for next timestep                       
[1912]2695       omega_rot_l(inot) = omega_gen(inot) / gear_ratio
[1864]2696
2697   
2698    END SUBROUTINE wtm_speed_control   
2699
2700
2701!------------------------------------------------------------------------------!
2702! Description:
2703! ------------
[1839]2704!> Application of the additional forces generated by the wind turbine on the
2705!> flow components (tendency terms)
2706!> Call for all grid points
[1819]2707!------------------------------------------------------------------------------!
2708    SUBROUTINE wtm_tendencies( component )
2709
[1839]2710   
[1819]2711       IMPLICIT NONE
2712
[1839]2713       INTEGER(iwp) ::  component   !< prognostic variable (u,v,w)
2714       INTEGER(iwp) ::  i           !< running index
2715       INTEGER(iwp) ::  j           !< running index
2716       INTEGER(iwp) ::  k           !< running index
[1819]2717
2718
2719       SELECT CASE ( component )
2720
2721       CASE ( 1 )
2722!
2723!--       Apply the x-component of the force to the u-component of the flow:
[1864]2724          IF ( simulated_time >= time_turbine_on )  THEN
[1819]2725             DO  i = nxlg, nxrg
2726                DO  j = nysg, nyng
[2553]2727                   DO  k = nzb+1, MAXVAL(k_hub) + MAXVAL(k_smear)
[1819]2728!
[1864]2729!--                   Calculate the thrust generated by the nacelle and the tower
[1912]2730                      tend_nac_x = 0.5_wp * nac_cd_surf(k,j,i) *               &
[2553]2731                                      SIGN( u(k,j,i)**2 , u(k,j,i) )     
[1912]2732                      tend_tow_x   = 0.5_wp * tow_cd_surf(k,j,i) *             &
[1819]2733                                         SIGN( u(k,j,i)**2 , u(k,j,i) ) 
[2553]2734                                               
[2232]2735                      tend(k,j,i) = tend(k,j,i) + ( - rot_tend_x(k,j,i)        &
2736                                  - tend_nac_x - tend_tow_x )                  &
2737                                      * MERGE( 1.0_wp, 0.0_wp,                 &
2738                                               BTEST( wall_flags_0(k,j,i), 1 ) )
[1819]2739                   ENDDO
2740                ENDDO
2741             ENDDO
2742          ENDIF
2743
2744       CASE ( 2 )
2745!
2746!--       Apply the y-component of the force to the v-component of the flow:
[1864]2747          IF ( simulated_time >= time_turbine_on )  THEN
[1819]2748             DO  i = nxlg, nxrg
2749                DO  j = nysg, nyng
[2553]2750                   DO  k = nzb+1, MAXVAL(k_hub) + MAXVAL(k_smear)
[1912]2751                      tend_nac_y = 0.5_wp * nac_cd_surf(k,j,i) *               &
[1819]2752                                         SIGN( v(k,j,i)**2 , v(k,j,i) )     
[1912]2753                      tend_tow_y   = 0.5_wp * tow_cd_surf(k,j,i) *             &
[1819]2754                                         SIGN( v(k,j,i)**2 , v(k,j,i) )                     
[2232]2755                      tend(k,j,i) = tend(k,j,i) + ( - rot_tend_y(k,j,i)        &
2756                                  - tend_nac_y - tend_tow_y )                  &
2757                                      * MERGE( 1.0_wp, 0.0_wp,                 &
2758                                               BTEST( wall_flags_0(k,j,i), 2 ) )
[1819]2759                   ENDDO
2760                ENDDO
2761             ENDDO
2762          ENDIF
2763
2764       CASE ( 3 )
2765!
2766!--       Apply the z-component of the force to the w-component of the flow:
[1864]2767          IF ( simulated_time >= time_turbine_on )  THEN
[1819]2768             DO  i = nxlg, nxrg
2769                DO  j = nysg, nyng
[2553]2770                   DO  k = nzb+1,  MAXVAL(k_hub) + MAXVAL(k_smear)
[2232]2771                      tend(k,j,i) = tend(k,j,i) - rot_tend_z(k,j,i)            &
2772                                      * MERGE( 1.0_wp, 0.0_wp,                 &
2773                                               BTEST( wall_flags_0(k,j,i), 3 ) )
[1819]2774                   ENDDO
2775                ENDDO
2776             ENDDO
2777          ENDIF
2778
2779
2780       CASE DEFAULT
2781
2782          WRITE( message_string, * ) 'unknown prognostic variable: ', component
2783          CALL message( 'wtm_tendencies', 'PA04??', 1, 2, 0, 6, 0 ) 
2784
2785       END SELECT
2786
2787
2788    END SUBROUTINE wtm_tendencies
2789
2790
2791!------------------------------------------------------------------------------!
2792! Description:
2793! ------------
[1839]2794!> Application of the additional forces generated by the wind turbine on the
2795!> flow components (tendency terms)
2796!> Call for grid point i,j
[1819]2797!------------------------------------------------------------------------------!
2798    SUBROUTINE wtm_tendencies_ij( i, j, component )
2799
2800
2801       IMPLICIT NONE
2802
[1839]2803       INTEGER(iwp) ::  component   !< prognostic variable (u,v,w)
2804       INTEGER(iwp) ::  i           !< running index
2805       INTEGER(iwp) ::  j           !< running index
2806       INTEGER(iwp) ::  k           !< running index
[1819]2807
2808       SELECT CASE ( component )
2809
2810       CASE ( 1 )
2811!
2812!--       Apply the x-component of the force to the u-component of the flow:
[1839]2813          IF ( simulated_time >= time_turbine_on )  THEN
[2553]2814             DO  k = nzb+1,  MAXVAL(k_hub) + MAXVAL(k_smear)
[1819]2815!
[1839]2816!--             Calculate the thrust generated by the nacelle and the tower
[1912]2817                tend_nac_x = 0.5_wp * nac_cd_surf(k,j,i) *                     &
[1819]2818                                   SIGN( u(k,j,i)**2 , u(k,j,i) )     
[1912]2819                tend_tow_x   = 0.5_wp * tow_cd_surf(k,j,i) *                   &
[1819]2820                                   SIGN( u(k,j,i)**2 , u(k,j,i) ) 
[2232]2821                tend(k,j,i) = tend(k,j,i) + ( - rot_tend_x(k,j,i)              &
2822                            - tend_nac_x - tend_tow_x )                        &
2823                                      * MERGE( 1.0_wp, 0.0_wp,                 &
[2553]2824                                            BTEST( wall_flags_0(k,j,i), 1 ) )
[1819]2825             ENDDO
2826          ENDIF
2827
2828       CASE ( 2 )
2829!
2830!--       Apply the y-component of the force to the v-component of the flow:
[1839]2831          IF ( simulated_time >= time_turbine_on )  THEN
[2553]2832             DO  k = nzb+1,  MAXVAL(k_hub) + MAXVAL(k_smear)
[1912]2833                tend_nac_y = 0.5_wp * nac_cd_surf(k,j,i) *                     &
[1819]2834                                   SIGN( v(k,j,i)**2 , v(k,j,i) )     
[1912]2835                tend_tow_y   = 0.5_wp * tow_cd_surf(k,j,i) *                   &
[1819]2836                                   SIGN( v(k,j,i)**2 , v(k,j,i) )                     
[2232]2837                tend(k,j,i) = tend(k,j,i) + ( - rot_tend_y(k,j,i)              &
2838                            - tend_nac_y - tend_tow_y )                        &
2839                                      * MERGE( 1.0_wp, 0.0_wp,                 &
2840                                               BTEST( wall_flags_0(k,j,i), 2 ) )
[2553]2841                ENDDO
[1819]2842          ENDIF
2843
2844       CASE ( 3 )
2845!
2846!--       Apply the z-component of the force to the w-component of the flow:
[1839]2847          IF ( simulated_time >= time_turbine_on )  THEN
[2553]2848             DO  k = nzb+1,  MAXVAL(k_hub) + MAXVAL(k_smear)
[2232]2849                tend(k,j,i) = tend(k,j,i) - rot_tend_z(k,j,i)                  &
2850                                      * MERGE( 1.0_wp, 0.0_wp,                 &
2851                                               BTEST( wall_flags_0(k,j,i), 3 ) )
[1819]2852             ENDDO
2853          ENDIF
2854
2855
2856       CASE DEFAULT
2857
2858          WRITE( message_string, * ) 'unknown prognostic variable: ', component
2859          CALL message( 'wtm_tendencies', 'PA04??', 1, 2, 0, 6, 0 ) 
2860
2861       END SELECT
2862
2863
2864    END SUBROUTINE wtm_tendencies_ij
2865
2866 END MODULE wind_turbine_model_mod
Note: See TracBrowser for help on using the repository browser.