28 use mom_time_manager,
only : time_type,
operator(+),
operator(/), time_type_to_real
33 implicit none ;
private
35 #include <MOM_memory.h>
37 public idealized_hurricane_wind_init
39 public idealized_hurricane_wind_forcing
41 public scm_idealized_hurricane_wind_forcing
49 real :: pressure_ambient
50 real :: pressure_central
53 real :: hurr_translation_spd
54 real :: hurr_translation_dir
65 real :: holland_axbxdp
67 logical :: relative_tau
69 logical :: answers_2018
79 real :: dy_from_center
88 #include "version_variable.h"
90 character(len=40) :: mdl =
"idealized_hurricane"
95 subroutine idealized_hurricane_wind_init(Time, G, US, param_file, CS)
96 type(time_type),
intent(in) :: time
105 logical :: default_2018_answers
108 # include "version_variable.h"
110 if (
associated(cs))
then
111 call mom_error(fatal,
"idealized_hurricane_wind_init called "// &
112 "with an associated control structure.")
118 cs%pi = 4.0*atan(1.0)
119 cs%Deg2Rad = cs%pi/180.
125 call get_param(param_file, mdl,
"IDL_HURR_RHO_AIR", cs%rho_a, &
126 "Air density used to compute the idealized hurricane wind profile.", &
127 units=
'kg/m3', default=1.2, scale=us%kg_m3_to_R)
128 call get_param(param_file, mdl,
"IDL_HURR_AMBIENT_PRESSURE", cs%pressure_ambient, &
129 "Ambient pressure used in the idealized hurricane wind profile.", &
130 units=
'Pa', default=101200., scale=us%m_s_to_L_T**2*us%kg_m3_to_R)
131 call get_param(param_file, mdl,
"IDL_HURR_CENTRAL_PRESSURE", cs%pressure_central, &
132 "Central pressure used in the idealized hurricane wind profile.", &
133 units=
'Pa', default=96800., scale=us%m_s_to_L_T**2*us%kg_m3_to_R)
134 call get_param(param_file, mdl,
"IDL_HURR_RAD_MAX_WIND", &
135 cs%rad_max_wind,
"Radius of maximum winds used in the "//&
136 "idealized hurricane wind profile.", units=
'm', &
137 default=50.e3, scale=us%m_to_L)
138 call get_param(param_file, mdl,
"IDL_HURR_MAX_WIND", cs%max_windspeed, &
139 "Maximum wind speed used in the idealized hurricane"// &
140 "wind profile.", units=
'm/s', default=65., scale=us%m_s_to_L_T)
141 call get_param(param_file, mdl,
"IDL_HURR_TRAN_SPEED", cs%hurr_translation_spd, &
142 "Translation speed of hurricane used in the idealized "//&
143 "hurricane wind profile.", units=
'm/s', default=5.0, scale=us%m_s_to_L_T)
144 call get_param(param_file, mdl,
"IDL_HURR_TRAN_DIR", cs%hurr_translation_dir, &
145 "Translation direction (towards) of hurricane used in the "//&
146 "idealized hurricane wind profile.", units=
'degrees', &
147 default=180.0, scale=cs%Deg2Rad)
148 call get_param(param_file, mdl,
"IDL_HURR_X0", cs%Hurr_cen_X0, &
149 "Idealized Hurricane initial X position", &
150 units=
'm', default=0., scale=us%m_to_L)
151 call get_param(param_file, mdl,
"IDL_HURR_Y0", cs%Hurr_cen_Y0, &
152 "Idealized Hurricane initial Y position", &
153 units=
'm', default=0., scale=us%m_to_L)
154 call get_param(param_file, mdl,
"IDL_HURR_TAU_CURR_REL", cs%relative_tau, &
155 "Current relative stress switch "//&
156 "used in the idealized hurricane wind profile.", &
157 units=
'', default=.false.)
160 call get_param(param_file, mdl,
"IDL_HURR_SCM_BR_BENCH", cs%BR_BENCH, &
161 "Single column mode benchmark case switch, which is "// &
162 "invoking a modification (bug) in the wind profile meant to "//&
163 "reproduce a previous implementation.", units=
'', default=.false.)
164 call get_param(param_file, mdl,
"IDL_HURR_SCM", cs%SCM_MODE, &
165 "Single Column mode switch "//&
166 "used in the SCM idealized hurricane wind profile.", &
167 units=
'', default=.false.)
168 call get_param(param_file, mdl,
"IDL_HURR_SCM_LOCY", cs%dy_from_center, &
169 "Y distance of station used in the SCM idealized hurricane "//&
170 "wind profile.", units=
'm', default=50.e3, scale=us%m_to_L)
171 call get_param(param_file, mdl,
"DEFAULT_2018_ANSWERS", default_2018_answers, &
172 "This sets the default value for the various _2018_ANSWERS parameters.", &
174 call get_param(param_file, mdl,
"IDL_HURR_2018_ANSWERS", cs%answers_2018, &
175 "If true, use expressions driving the idealized hurricane test case that recover "//&
176 "the answers from the end of 2018. Otherwise use expressions that are rescalable "//&
177 "and respect rotational symmetry.", default=default_2018_answers)
182 call get_param(param_file, mdl,
"RHO_0", cs%Rho0, &
183 "The mean ocean density used with BOUSSINESQ true to "//&
184 "calculate accelerations and the mass for conservation "//&
185 "properties, or with BOUSSINSEQ false to convert some "//&
186 "parameters from vertical units of m to kg m-2.", &
187 units=
"kg m-3", default=1035.0, scale=us%kg_m3_to_R, do_not_log=.true.)
188 call get_param(param_file, mdl,
"GUST_CONST", cs%gustiness, &
189 "The background gustiness in the winds.", units=
"Pa", &
190 default=0.0, scale=us%kg_m3_to_R*us%m_s_to_L_T**2*us%L_to_Z, do_not_log=.true.)
192 if (cs%BR_BENCH)
then
193 cs%rho_a = 1.2*us%kg_m3_to_R
195 dp = cs%pressure_ambient - cs%pressure_central
196 if (cs%answers_2018)
then
197 c = cs%max_windspeed / sqrt( us%R_to_kg_m3 * dp )
198 cs%Holland_B = c**2 * us%R_to_kg_m3*cs%rho_a * exp(1.0)
200 cs%Holland_B = cs%max_windspeed**2 * cs%rho_a * exp(1.0) / dp
202 cs%Holland_A = (us%L_to_m*cs%rad_max_wind)**cs%Holland_B
203 cs%Holland_AxBxDP = cs%Holland_A*cs%Holland_B*dp
205 end subroutine idealized_hurricane_wind_init
208 subroutine idealized_hurricane_wind_forcing(sfc_state, forces, day, G, US, CS)
211 type(time_type),
intent(in) :: day
217 integer :: i, j, is, ie, js, je, isq, ieq, jsq, jeq
218 integer :: isd, ied, jsd, jed, isdb, iedb, jsdb, jedb
232 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
233 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
234 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
235 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
240 if (cs%relative_tau)
then
247 xc = cs%Hurr_cen_X0 + (time_type_to_real(day)*us%s_to_T * cs%hurr_translation_spd * &
248 cos(cs%hurr_translation_dir))
249 yc = cs%Hurr_cen_Y0 + (time_type_to_real(day)*us%s_to_T * cs%hurr_translation_spd * &
250 sin(cs%hurr_translation_dir))
253 if (cs%BR_Bench)
then
255 fbench = 5.5659e-05 * us%T_to_s
265 uocn = sfc_state%u(i,j) * rel_tau_fac
266 if (cs%answers_2018)
then
267 vocn = 0.25*(sfc_state%v(i,j)+sfc_state%v(i+1,j-1)&
268 +sfc_state%v(i+1,j)+sfc_state%v(i,j-1))*rel_tau_fac
270 vocn =0.25*((sfc_state%v(i,j)+sfc_state%v(i+1,j-1)) +&
271 (sfc_state%v(i+1,j)+sfc_state%v(i,j-1))) * rel_tau_fac
273 f_local = abs(0.5*(g%CoriolisBu(i,j)+g%CoriolisBu(i,j-1)))*fbench_fac + fbench
275 if (cs%SCM_mode)
then
276 yy = yc + cs%dy_from_center
279 yy = g%geoLatCu(i,j)*1000.*us%m_to_L - yc
280 xx = g%geoLonCu(i,j)*1000.*us%m_to_L - xc
282 call idealized_hurricane_wind_profile(cs, us, f_local, yy, xx, uocn, vocn, tx, ty)
283 forces%taux(i,j) = g%mask2dCu(i,j) * tx
289 if (cs%answers_2018)
then
290 uocn = 0.25*(sfc_state%u(i,j)+sfc_state%u(i-1,j+1) + &
291 sfc_state%u(i-1,j)+sfc_state%u(i,j+1))*rel_tau_fac
293 uocn = 0.25*((sfc_state%u(i,j)+sfc_state%u(i-1,j+1)) + &
294 (sfc_state%u(i-1,j)+sfc_state%u(i,j+1))) * rel_tau_fac
296 vocn = sfc_state%v(i,j) * rel_tau_fac
297 f_local = abs(0.5*(g%CoriolisBu(i-1,j)+g%CoriolisBu(i,j)))*fbench_fac + fbench
299 if (cs%SCM_mode)
then
300 yy = yc + cs%dy_from_center
303 yy = g%geoLatCv(i,j)*1000.*us%m_to_L - yc
304 xx = g%geoLonCv(i,j)*1000.*us%m_to_L - xc
306 call idealized_hurricane_wind_profile(cs, us, f_local, yy, xx, uocn, vocn, tx, ty)
307 forces%tauy(i,j) = g%mask2dCv(i,j) * ty
315 forces%ustar(i,j) = g%mask2dT(i,j) * sqrt(us%L_to_Z * (cs%gustiness/cs%Rho0 + &
316 sqrt(0.5*(forces%taux(i-1,j)**2 + forces%taux(i,j)**2) + &
317 0.5*(forces%tauy(i,j-1)**2 + forces%tauy(i,j)**2))/cs%Rho0))
322 end subroutine idealized_hurricane_wind_forcing
325 subroutine idealized_hurricane_wind_profile(CS, US, absf, YY, XX, UOCN, VOCN, Tx, Ty)
333 real,
intent(in) :: absf
334 real,
intent(in) :: YY
335 real,
intent(in) :: XX
336 real,
intent(in) :: UOCN
337 real,
intent(in) :: VOCN
338 real,
intent(out) :: Tx
339 real,
intent(out) :: Ty
367 radius = sqrt(xx**2 + yy**2)
375 if (cs%BR_Bench)
then
376 radius_km = radius/1000.
381 radiusb = (us%L_to_m*radius)**cs%Holland_B
386 if (cs%answers_2018)
then
387 if ( (radius > 0.001*cs%rad_max_wind) .and. (radius < 10.*cs%rad_max_wind) )
then
388 u10 = sqrt(cs%Holland_AxBxDP*exp(-cs%Holland_A/radiusb) / (cs%rho_a*radiusb) + &
389 0.25*(radius_km*absf)**2) - 0.5*radius_km*absf
390 elseif ( (radius > 10.*cs%rad_max_wind) .and. (radius < 15.*cs%rad_max_wind) )
then
391 radius10 = cs%rad_max_wind*10.
392 if (cs%BR_Bench)
then
393 radius_km = radius10/1000.
397 radiusb = (us%L_to_m*radius10)**cs%Holland_B
399 u10 = (sqrt(cs%Holland_AxBxDp*exp(-cs%Holland_A/radiusb) / (cs%rho_a*radiusb) + &
400 0.25*(radius_km*absf)**2) - 0.5*radius_km*absf) &
401 * (15. - radius/cs%rad_max_wind)/5.
406 if ( (radius > 0.001*cs%rad_max_wind) .and. (radius < 10.*cs%rad_max_wind) )
then
407 tmp = ( 0.5*radius_km*absf) * (cs%rho_a*radiusb)
408 u10 = (cs%Holland_AxBxDP * exp(-cs%Holland_A/radiusb)) / &
409 ( tmp + sqrt(cs%Holland_AxBxDP*exp(-cs%Holland_A/radiusb) * (cs%rho_a*radiusb) + tmp**2) )
410 elseif ( (radius > 10.*cs%rad_max_wind) .and. (radius < 15.*cs%rad_max_wind) )
then
411 radius_km = 10.0 * cs%rad_max_wind
412 if (cs%BR_Bench) radius_km = radius_km/1000.
413 radiusb = (10.0*us%L_to_m*cs%rad_max_wind)**cs%Holland_B
414 tmp = ( 0.5*radius_km*absf) * (cs%rho_a*radiusb)
415 u10 = (3.0 - radius/(5.0*cs%rad_max_wind)) * (cs%Holland_AxBxDp*exp(-cs%Holland_A/radiusb) ) / &
416 ( tmp + sqrt(cs%Holland_AxBxDp*exp(-cs%Holland_A/radiusb) * (cs%rho_a*radiusb) + tmp**2) )
428 rstr = min(10., radius / cs%rad_max_wind)
429 a0 = -0.9*rstr - 0.09*us%L_T_to_m_s*cs%max_windspeed - 14.33
430 a1 = -a0*(0.04*rstr + 0.05*us%L_T_to_m_s*cs%hurr_translation_spd + 0.14)
431 p1 = (6.88*rstr - 9.60*us%L_T_to_m_s*cs%hurr_translation_spd + 85.31) * cs%Deg2Rad
432 alph = a0 - a1*cos(cs%hurr_translation_dir-adir-p1)
433 if ( (radius > 10.*cs%rad_max_wind) .and.&
434 (radius < 15.*cs%rad_max_wind) )
then
435 alph = alph*(15.0 - radius/cs%rad_max_wind)/5.
436 elseif (radius > 15.*cs%rad_max_wind)
then
439 alph = alph * cs%Deg2Rad
442 u_ts = cs%hurr_translation_spd * 0.5*cos(cs%hurr_translation_dir)
443 v_ts = cs%hurr_translation_spd * 0.5*sin(cs%hurr_translation_dir)
446 du = u10*sin(adir-cs%Pi-alph) - uocn + u_ts
447 dv = u10*cos(adir-alph) - vocn + v_ts
450 du10 = sqrt(du**2+dv**2)
451 if (du10 < 11.0*us%m_s_to_L_T)
then
453 elseif (du10 < 20.0*us%m_s_to_L_T)
then
454 if (cs%answers_2018)
then
455 cd = (0.49 + 0.065*us%L_T_to_m_s*u10)*1.e-3
457 cd = (0.49 + 0.065*us%L_T_to_m_s*du10)*1.e-3
464 tx = us%L_to_Z * cs%rho_a * cd * sqrt(du**2 + dv**2) * du
465 ty = us%L_to_Z * cs%rho_a * cd * sqrt(du**2 + dv**2) * dv
467 end subroutine idealized_hurricane_wind_profile
473 subroutine scm_idealized_hurricane_wind_forcing(sfc_state, forces, day, G, US, CS)
476 type(time_type),
intent(in) :: day
481 integer :: i, j, is, ie, js, je, isq, ieq, jsq, jeq
482 integer :: isd, ied, jsd, jed, isdb, iedb, jsdb, jedb
498 real :: alph,rstr, a0, a1, p1, adir, transdir
502 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
503 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
504 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
505 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
510 pie = 4.0*atan(1.0) ; deg2rad = pie/180.
518 dp = cs%pressure_ambient - cs%pressure_central
519 if (cs%answers_2018)
then
520 c = cs%max_windspeed / sqrt( us%R_to_kg_m3*dp )
521 b = c**2 * us%R_to_kg_m3*cs%rho_a * exp(1.0)
523 b = c**2 * 1.2 * exp(1.0)
525 elseif (br_bench)
then
526 b = (cs%max_windspeed**2 / dp ) * 1.2*us%kg_m3_to_R * exp(1.0)
528 b = (cs%max_windspeed**2 /dp ) * cs%rho_a * exp(1.0)
531 a = (us%L_to_m*cs%rad_max_wind / 1000.)**b
532 f_local = g%CoriolisBu(is,js)
535 f_local = 5.5659e-05*us%T_to_s
539 xx = us%s_to_T*( t0 - time_type_to_real(day)) * cs%hurr_translation_spd * cos(transdir)
540 rad = sqrt(xx**2 + cs%dy_from_center**2)
549 rb = (us%L_to_m*rkm)**b
553 rb = (us%L_to_m*rad)**b
559 if (rad > 0.001*cs%rad_max_wind .AND. rad < 10.*cs%rad_max_wind)
then
560 u10 = sqrt( a*b*dp*exp(-a/rb)/(1.2*us%kg_m3_to_R*rb) + 0.25*(rkm*f_local)**2 ) - 0.5*rkm*f_local
561 elseif (rad > 10.*cs%rad_max_wind .AND. rad < 12.*cs%rad_max_wind)
then
562 rad=(cs%rad_max_wind)*10.
565 rb = (us%L_to_m*rkm)**b
568 rb = (us%L_to_m*rad)**b
570 u10 = ( sqrt( a*b*dp*exp(-a/rb)/(1.2*us%kg_m3_to_R*rb) + 0.25*(rkm*f_local)**2 ) - 0.5*rkm*f_local) &
571 * (12. - rad/cs%rad_max_wind)/2.
575 adir = atan2(cs%dy_from_center,xx)
580 rstr = min(10., rad / cs%rad_max_wind)
581 a0 = -0.9*rstr - 0.09*us%L_T_to_m_s*cs%max_windspeed - 14.33
582 a1 = -a0 *(0.04*rstr + 0.05*us%L_T_to_m_s*cs%hurr_translation_spd + 0.14)
583 p1 = (6.88*rstr - 9.60*us%L_T_to_m_s*cs%hurr_translation_spd + 85.31)*pie/180.
584 alph = a0 - a1*cos( (transdir - adir ) - p1)
585 if (rad > 10.*cs%rad_max_wind .AND. rad < 12.*cs%rad_max_wind)
then
586 alph = alph* (12. - rad/cs%rad_max_wind)/2.
587 elseif (rad > 12.*cs%rad_max_wind)
then
590 alph = alph * deg2rad
595 u_ts = cs%hurr_translation_spd*0.5*cos(transdir)
596 v_ts = cs%hurr_translation_spd*0.5*sin(transdir)
602 do j=js,je ;
do i=is-1,ieq
612 du = u10*sin(adir-pie-alph) - uocn + u_ts
613 dv = u10*cos(adir-alph) - vocn + v_ts
618 du10 = sqrt(du**2+dv**2)
619 if (du10 < 11.0*us%m_s_to_L_T)
then
621 elseif (du10 < 20.0*us%m_s_to_L_T)
then
622 if (cs%answers_2018)
then
623 cd = (0.49 + 0.065 * us%L_T_to_m_s*u10 )*0.001
625 cd = (0.49 + 0.065 * us%L_T_to_m_s*du10 )*0.001
630 forces%taux(i,j) = cs%rho_a * us%L_to_Z * g%mask2dCu(i,j) * cd*du10*du
634 do j=js-1,jeq ;
do i=is,ie
638 du = u10*sin(adir-pie-alph) - uocn + u_ts
639 dv = u10*cos(adir-alph) - vocn + v_ts
640 du10=sqrt(du**2+dv**2)
641 if (du10 < 11.0*us%m_s_to_L_T)
then
643 elseif (du10 < 20.0*us%m_s_to_L_T)
then
644 if (cs%answers_2018)
then
645 cd = (0.49 + 0.065 * us%L_T_to_m_s*u10 )*0.001
647 cd = (0.49 + 0.065 * us%L_T_to_m_s*du10 )*0.001
652 forces%tauy(i,j) = cs%rho_a * us%L_to_Z * g%mask2dCv(i,j) * cd*du10*dv
655 do j=js,je ;
do i=is,ie
657 forces%ustar(i,j) = g%mask2dT(i,j) * sqrt(us%L_to_Z * (cs%gustiness/cs%Rho0 + &
658 sqrt(0.5*(forces%taux(i-1,j)**2 + forces%taux(i,j)**2) + &
659 0.5*(forces%tauy(i,j-1)**2 + forces%tauy(i,j)**2))/cs%Rho0))
662 end subroutine scm_idealized_hurricane_wind_forcing