|
| 1 | +/* |
| 2 | + * SUMMARY: CalcAerodynamic.c - Calculate the aerodynamic resistances |
| 3 | + * USAGE: Part of DHSVM |
| 4 | + * |
| 5 | + * AUTHOR: Bart Nijssen and Pascal Storck |
| 6 | + * ORG: University of Washington, Department of Civil Engineering |
| 7 | + * E-MAIL: nijssen@u.washington.edu, pstorck@u.washington.edu |
| 8 | + * ORIG-DATE: Thu Mar 27 18:00:10 1997 |
| 9 | + * LAST-MOD: Thu Mar 8 13:24:10 2001 by Keith Cherkauer <cherkaue@u.washington.edu> |
| 10 | + * DESCRIPTION: Calculate the aerodynamic resistances |
| 11 | + * DESCRIP-END. |
| 12 | + * FUNCTIONS: CalcAerodynamic() |
| 13 | + * COMMENTS: Modified for use with the vicNl model 3-12-98 |
| 14 | + * by Keith Cherkauer |
| 15 | + */ |
| 16 | + |
| 17 | +#include <stdio.h> |
| 18 | +#include <stdlib.h> |
| 19 | +#include <vicNl.h> |
| 20 | +#include <math.h> |
| 21 | + |
| 22 | +static char vcid[] = "$Id$"; |
| 23 | + |
| 24 | + |
| 25 | +/***************************************************************************** |
| 26 | + Function name: CalcAerodynamic() |
| 27 | +
|
| 28 | + Purpose : Calculate the aerodynamic resistance for each vegetation |
| 29 | + layer, and the wind 2m above the layer boundary. In case of |
| 30 | + an overstory, also calculate the wind in the overstory. |
| 31 | + The values are normalized based on a reference height wind |
| 32 | + speed, Uref, of 1 m/s. To get wind speeds and aerodynamic |
| 33 | + resistances for other values of Uref, you need to multiply |
| 34 | + the here calculated wind speeds by Uref and divide the |
| 35 | + here calculated aerodynamic resistances by Uref |
| 36 | + |
| 37 | + Required : |
| 38 | + int NVegLayers - Number of vegetation layers |
| 39 | + char OverStory - flag for presence of overstory. Only used if NVegLayers |
| 40 | + is equal to 1 |
| 41 | + double Zref[0] - Reference height for windspeed |
| 42 | + double n - Attenuation coefficient for wind in the overstory |
| 43 | + double Height - Height of the vegetation layers (top layer first) |
| 44 | + double Trunk - Multiplier for Height[0] that indictaes the top of the |
| 45 | + trunk space |
| 46 | + double *U - Vector of length 3, contains wind for vegetation |
| 47 | + conditions listed below: |
| 48 | + [0] is always wind speed for the snow-free case, |
| 49 | + [2] is always wind speed for the snow covered case, |
| 50 | + [1] will contain the wind speed in the canopy if |
| 51 | + OverStory is TRUE, otherwise it is unused. |
| 52 | + double *Ra - Vector of length 3, contains aerodynamic resistance |
| 53 | + values for the conditions outlined for *U. |
| 54 | + double *Zref - Vector of length 3, contains reference height |
| 55 | + values for the conditions outlined for *U. |
| 56 | + double *Z0 - Vector of length 3, contains roughness length |
| 57 | + values for the conditions outlined for *U. |
| 58 | + double *d - Vector of length 3, contains displacement height |
| 59 | + values for the conditions outlined for *U. |
| 60 | +
|
| 61 | + Returns : int |
| 62 | +
|
| 63 | + Modifies : |
| 64 | + double *U |
| 65 | + double *Ra |
| 66 | + double *Zref |
| 67 | + double *Z0 |
| 68 | + double *d |
| 69 | + |
| 70 | + Comments : |
| 71 | +*****************************************************************************/ |
| 72 | +int CalcAerodynamic(char OverStory, /* overstory flag */ |
| 73 | + double Height, /* vegetation height */ |
| 74 | + double Trunk, /* trunk ratio parameter */ |
| 75 | + double Z0_SNOW, /* snow roughness */ |
| 76 | + double Z0_SOIL, /* soil roughness */ |
| 77 | + double n, /* wind attenuation parameter */ |
| 78 | + double *Ra, /* aerodynamic resistances */ |
| 79 | + double *U, /* adjusted wind speed */ |
| 80 | + double *displacement, /* vegetation displacement */ |
| 81 | + double *ref_height, /* vegetation reference height */ |
| 82 | + double *roughness) /* vegetation roughness */ |
| 83 | +{ |
| 84 | + /****************************************************************** |
| 85 | + Modifications: |
| 86 | + 2007-Apr-04 Modified to catch and return error flags from surface_fluxes |
| 87 | + subroutine. GCT/KAC |
| 88 | + 2009-Jun-09 Modified to use extension of veg_lib structure to contain |
| 89 | + bare soil information. TJB |
| 90 | + *******************************************************************/ |
| 91 | + |
| 92 | + |
| 93 | + double d_Lower; |
| 94 | + double d_Upper; |
| 95 | + double K2; |
| 96 | + double Uh; |
| 97 | + double Ut; |
| 98 | + double Uw; |
| 99 | + double Z0_Lower; |
| 100 | + double Z0_Upper; |
| 101 | + double Zt; |
| 102 | + double Zw; |
| 103 | + double tmp_wind; |
| 104 | + |
| 105 | + tmp_wind = U[0]; |
| 106 | + |
| 107 | + K2 = von_K * von_K; |
| 108 | + |
| 109 | + /* No OverStory, thus maximum one soil layer */ |
| 110 | + |
| 111 | + if ( OverStory == FALSE ) { |
| 112 | + |
| 113 | + /* vegetation cover */ |
| 114 | + Z0_Lower = roughness[0]; |
| 115 | + d_Lower = displacement[0]; |
| 116 | + |
| 117 | + /* No snow */ |
| 118 | + U[0] = log((2. + Z0_Lower)/Z0_Lower)/log((ref_height[0] - d_Lower)/Z0_Lower); |
| 119 | + /****** DHSVM ****** |
| 120 | + Ra[0] = log((2. + Z0_Lower)/Z0_Lower) * log((ref_height[0] - d_Lower)/Z0_Lower) |
| 121 | + /K2; |
| 122 | + ***** Old VIC *****/ |
| 123 | + Ra[0] = log((2. + (1.0/0.63 - 1.0) * d_Lower) / Z0_Lower) |
| 124 | + * log((2. + (1.0/0.63 - 1.0) * d_Lower) / (0.1*Z0_Lower)) / K2; |
| 125 | + /******************/ |
| 126 | + |
| 127 | + /* Copy bare parameters into canopy top parameters */ |
| 128 | + U[1] = U[0]; |
| 129 | + Ra[1] = Ra[0]; |
| 130 | + |
| 131 | + /** Set aerodynamic resistance terms for canopy */ |
| 132 | + /* not currently used */ |
| 133 | + ref_height[1] = ref_height[0]; |
| 134 | + roughness[1] = roughness[0]; |
| 135 | + displacement[1] = displacement[0]; |
| 136 | + |
| 137 | + /* Snow */ |
| 138 | + U[2] = log((2. + Z0_SNOW)/Z0_SNOW)/log(ref_height[0]/Z0_SNOW); |
| 139 | + Ra[2] = log((2. + Z0_SNOW)/Z0_SNOW) * log(ref_height[0]/Z0_SNOW)/K2; |
| 140 | + /** Set aerodynamic resistance terms for snow */ |
| 141 | + ref_height[2] = 2. + Z0_SNOW; |
| 142 | + roughness[2] = Z0_SNOW; |
| 143 | + displacement[2] = 0.; |
| 144 | + |
| 145 | + } |
| 146 | + |
| 147 | + /* Overstory present, one or two vegetation layers possible */ |
| 148 | + else { |
| 149 | + Z0_Upper = roughness[0]; |
| 150 | + d_Upper = displacement[0]; |
| 151 | + |
| 152 | + Z0_Lower = Z0_SOIL; |
| 153 | + d_Lower = 0; |
| 154 | + |
| 155 | + Zw = 1.5 * Height - 0.5 * d_Upper; |
| 156 | + Zt = Trunk * Height; |
| 157 | + |
| 158 | + if (Zt < (Z0_Lower+d_Lower)) { |
| 159 | + fprintf(stderr,"ERROR: CalcAerodynamic - Trunk space height below \"center\" of lower boundary"); |
| 160 | + return( ERROR ); |
| 161 | + } |
| 162 | + |
| 163 | + /* Resistance for overstory */ |
| 164 | + Ra[1] = log((ref_height[0]-d_Upper)/Z0_Upper)/K2 |
| 165 | + * (Height/(n*(Zw-d_Upper)) |
| 166 | + * (exp(n*(1-(d_Upper+Z0_Upper)/Height))-1) |
| 167 | + + (Zw-Height)/(Zw-d_Upper) |
| 168 | + + log((ref_height[0]-d_Upper)/(Zw-d_Upper))); |
| 169 | + |
| 170 | + /* Wind at different levels in the profile */ |
| 171 | + Uw = log((Zw-d_Upper)/Z0_Upper) / log((ref_height[0]-d_Upper)/Z0_Upper); |
| 172 | + Uh = Uw - (1-(Height-d_Upper)/(Zw-d_Upper)) |
| 173 | + / log((ref_height[0]-d_Upper)/Z0_Upper); |
| 174 | + U[1] = Uh * exp(n * ((Z0_Upper+d_Upper)/Height - 1.)); |
| 175 | + Ut = Uh * exp(n * (Zt/Height - 1.)); |
| 176 | + |
| 177 | + /* resistance at the lower boundary */ |
| 178 | + |
| 179 | + |
| 180 | + /***** Old VIC *****/ |
| 181 | + U[0] = log((2. + Z0_Upper)/Z0_Upper)/log((ref_height[0] - d_Upper)/Z0_Upper); |
| 182 | + Ra[0] = log((2. + (1.0/0.63 - 1.0) * d_Upper) / Z0_Upper) |
| 183 | + * log((2. + (1.0/0.63 - 1.0) * d_Upper) / (0.1*Z0_Upper)) / K2; |
| 184 | + /******************/ |
| 185 | + |
| 186 | + |
| 187 | + |
| 188 | + /* Snow */ |
| 189 | + /* case 1: the wind profile to a height of 2m above the lower boundary is |
| 190 | + entirely logarithmic */ |
| 191 | + if (Zt > (2. + Z0_SNOW)) { |
| 192 | + U[2] = Ut*log((2.+Z0_SNOW)/Z0_SNOW)/log(Zt/Z0_SNOW); |
| 193 | + Ra[2] = log((2.+Z0_SNOW)/Z0_SNOW) * log(Zt/Z0_SNOW)/(K2*Ut); |
| 194 | + } |
| 195 | + |
| 196 | + /* case 2: the wind profile to a height of 2m above the lower boundary |
| 197 | + is part logarithmic and part exponential, but the top of the overstory |
| 198 | + is more than 2 m above the lower boundary */ |
| 199 | + else if (Height > (2. + Z0_SNOW)) { |
| 200 | + U[2] = Uh * exp(n * ((2. + Z0_SNOW)/Height - 1.)); |
| 201 | + Ra[2] = log(Zt/Z0_SNOW) * log(Zt/Z0_SNOW)/ |
| 202 | + (K2*Ut) + |
| 203 | + Height * log((ref_height[0]-d_Upper)/Z0_Upper) / (n*K2*(Zw-d_Upper)) * |
| 204 | + (exp(n*(1-Zt/Height)) - exp(n*(1-(Z0_SNOW+2.)/Height))); |
| 205 | + } |
| 206 | + |
| 207 | + /* case 3: the top of the overstory is less than 2 m above the lower |
| 208 | + boundary. The wind profile above the lower boundary is part |
| 209 | + logarithmic and part exponential, but only extends to the top of the |
| 210 | + overstory */ |
| 211 | + else { |
| 212 | + U[2] = Uh; |
| 213 | + Ra[2] = log(Zt/Z0_SNOW) * log(Zt/Z0_SNOW)/ |
| 214 | + (K2*Ut) + |
| 215 | + Height * log((ref_height[0]-d_Upper)/Z0_Upper) / (n*K2*(Zw-d_Upper)) * |
| 216 | + (exp(n*(1-Zt/Height)) - 1); |
| 217 | + /* fprintf(stderr, "WARNING: Top of overstory is less than 2 meters above the lower boundary\n"); */ |
| 218 | + } |
| 219 | + |
| 220 | + /** Set aerodynamic resistance terms for canopy */ |
| 221 | + /* not currently used */ |
| 222 | + ref_height[1] = ref_height[0]; |
| 223 | + roughness[1] = roughness[0]; |
| 224 | + displacement[1] = displacement[0]; |
| 225 | + ref_height[0] = 2.; |
| 226 | + roughness[0] = Z0_Lower; |
| 227 | + displacement[0] = d_Lower; |
| 228 | + |
| 229 | + /** Set aerodynamic resistance terms for snow */ |
| 230 | + ref_height[2] = 2. + Z0_SNOW; |
| 231 | + roughness[2] = Z0_SNOW; |
| 232 | + displacement[2] = 0.; |
| 233 | + |
| 234 | + } |
| 235 | + |
| 236 | + if ( tmp_wind > 0. ) { |
| 237 | + U[0] *= tmp_wind; |
| 238 | + Ra[0] /= tmp_wind; |
| 239 | + if(U[1]!=-999) { |
| 240 | + U[1] *= tmp_wind; |
| 241 | + Ra[1] /= tmp_wind; |
| 242 | + } |
| 243 | + if(U[2]!=-999) { |
| 244 | + U[2] *= tmp_wind; |
| 245 | + Ra[2] /= tmp_wind; |
| 246 | + } |
| 247 | + } |
| 248 | + else { |
| 249 | + U[0] *= tmp_wind; |
| 250 | + Ra[0] = HUGE_RESIST; |
| 251 | + if(U[1]!=-999) |
| 252 | + U[1] *= tmp_wind; |
| 253 | + Ra[1] = HUGE_RESIST; |
| 254 | + if(U[2]!=-999) |
| 255 | + U[2] *= tmp_wind; |
| 256 | + Ra[2] = HUGE_RESIST; |
| 257 | + } |
| 258 | + return (0); |
| 259 | + |
| 260 | +} |
0 commit comments