FE-Project
Loading...
Searching...
No Matches
scale_atm_phy_rd_solarins_simple.F90
Go to the documentation of this file.
1!> module FElib / Atmosphere / Physics radiation / Solar insolation / Simple gray-radiation scheme
2!!
3!! @par Description
4!! A module for idealized solar insolation scheme
5!!
6!! @author Yuta Kawai, Team SCALE
7!!
8!! @par Reference
9!! - Frierson, D.M.W., Held, I.M., and Zurita-Gotor, P. 2006:
10!! A gray-radiation aquaplanet moist GCM. Part I: Static stability and eddy scale.
11!! J. Atmos. Sci., 63, 2548–2566.
12!<
13!-------------------------------------------------------------------------------
14#include "scaleFElib.h"
16 !-----------------------------------------------------------------------------
17 !
18 !++ Used modules
19 !
20 use scale_precision
21 use scale_io
22 use scale_prc
23 use scale_prof
24
25 use scale_const, only: &
26 undef => const_undef, &
27 pi => const_pi
28
29 !-----------------------------------------------------------------------------
30 implicit none
31 private
32 !-----------------------------------------------------------------------------
33 !
34 !++ Public type & procedure
35 !
39
40 !-----------------------------------------------------------------------------
41 !++ Public parameters & variables
42 !
43
44 !-----------------------------------------------------------------------------
45 !++ Private procedure
46 !
47 private :: annual_mean_insol
48 private :: daily_mean_insol
49 private :: days_in_month
50 private :: is_leap_year
51 private :: seconds_to_hms
52
53 !-----------------------------------------------------------------------------
54 !
55 !++ Private parameters & variables
56 !
57 integer :: SOLARINS_TYPE_ID !< Solar insolation type ID
58
59 integer, parameter :: SOLARINS_SIMPLE_TYPE_ID_CONST = 1 !< Type ID for constant solar insolation
60 integer, parameter :: SOLARINS_SIMPLE_TYPE_ID_ANNUAL_MEAN = 2 !< Type ID for annual mean solar insolation
61 integer, parameter :: SOLARINS_SIMPLE_TYPE_ID_FRIERSON2006 = 3 !< Type ID for an idealized solar insolation based on Frierson et al. (2006)
62
63
64 real(RP) :: CONST_FLUX = 340.0_rp !< Constant solar flux value [W/m2]
65
66 integer :: ORBIT_REFERENCE_YEAR = 2000 !< Reference year for orbital calculations
67 integer :: ANNUAL_MEAN_YEAR = 2000 !< Year for computing annual mean insolation
68 integer :: ANNUAL_SAMPLES_PER_DAY = 1 !< Number of samples per day for annual mean calculation
69 logical :: CACHE_ANNUAL_MEAN = .true. !< Flag to cache annual mean insolation
70
71 integer, parameter :: DATE_YEAR = 1
72 integer, parameter :: DATE_MONTH = 2
73 integer, parameter :: DATE_DAY = 3
74 integer, parameter :: DATE_HOUR = 4
75 integer, parameter :: DATE_MINUTE = 5
76 integer, parameter :: DATE_SECOND = 6
77 integer, parameter :: DATE_SIZE = 6
78
79 !-
80 real(RP) :: FRIERSON2006_DELTA_s = 1.4e0_rp !< Parameter for latitudinal variation (Delta_s) in Frierson et al. (2006) insolation scheme
81
82contains
83 !> Setup the simplified solar insolation module.
85 use scale_atmos_solarins, only: &
86 atmos_solarins_setup
87 implicit none
88 character(len=H_SHORT) :: solarins_type = 'ANNUAL_MEAN'
89 namelist / param_atmos_solarins_simple / &
90 solarins_type, &
91 const_flux, &
92 orbit_reference_year, &
93 annual_mean_year, &
94 annual_samples_per_day, &
95 cache_annual_mean, &
96 frierson2006_delta_s
97
98 integer :: ierr
99 !------------------------------------------------------------------------------
100
101 log_newline
102 log_info("ATMOS_PHY_RD_SOLARINS_SIMPLE_setup",*) 'Setup'
103
104 !--- read namelist
105 rewind(io_fid_conf)
106 read(io_fid_conf,nml=param_atmos_solarins_simple,iostat=ierr)
107 if( ierr < 0 ) then !--- missing
108 log_info("ATMOS_PHY_RD_SOLARINS_SIMPLE_setup",*) 'Not found namelist. Default used.'
109 elseif( ierr > 0 ) then !--- fatal error
110 log_error("ATMOS_PHY_RD_SOLARINS_SIMPLE_setup",*) 'Not appropriate names in namelist PARAM_ATMOS_SOLARINS_SIMPLE. Check!'
111 call prc_abort
112 endif
113 log_nml(param_atmos_solarins_simple)
114
115 select case (solarins_type)
116 case ('CONST')
117 solarins_type_id = solarins_simple_type_id_const
118 case ('ANNUAL_MEAN')
119 solarins_type_id = solarins_simple_type_id_annual_mean
120 case ('FRIERSON2006')
121 solarins_type_id = solarins_simple_type_id_frierson2006
122 case default
123 log_error("ATMOS_PHY_RD_SOLARINS_SIMPLE_setup",*) 'Not appropriate SOLARINS_TYPE. Check!'
124 call prc_abort
125 end select
126
127 !- Initializes orbital parameters, the vernal-equinox reference date, and related internal state.
128 ! Here, longitude and latitude are irrelevant because this module uses only the orbital state returned by ecliptic_longitude.
129 call atmos_solarins_setup( 0.0_rp, 0.0_rp, orbit_reference_year )
130
131 return
133
134!OCL SERIAL
137
138 !> Get solar insolation and cosine of the solar zenith angle for the given latitude array.
139!OCL SERIAL
140 subroutine atm_phy_rd_solarins_simple_get( solins, cosSZA, &
141 lat, Np )
142 use scale_atmos_solarins, only: &
143 atmos_solarins_constant
144 implicit none
145 integer, intent(in) :: np !< Number of points
146 real(rp), intent(out) :: solins(np) !< Solar insolation [W/m2] for each latitude point
147 real(rp), intent(out) :: cossza(np) !< Cosine of the solar zenith angle for each latitude point
148 real(rp), intent(in) :: lat(np) !< Array storing latitude values [radians] for each point
149 !------------------------------------------------------------------------------
150
151 select case (solarins_type_id)
152 case (solarins_simple_type_id_const)
153 solins(:) = const_flux
154 cossza(:) = undef
155 case (solarins_simple_type_id_annual_mean)
156 call annual_mean_insol( solins, & ! (out)
157 lat, np ) ! (in)
158 cossza(:) = undef
159 case (solarins_simple_type_id_frierson2006)
160 solins(:) = 0.25_rp * atmos_solarins_constant &
161 * ( 1.0_rp + 0.25_rp * frierson2006_delta_s * ( 1.0_rp - 3.0_rp * sin(lat(:))**2 ) )
162 cossza(:) = undef
163 end select
164 return
165 end subroutine atm_phy_rd_solarins_simple_get
166
167!- Private subroutines ------------------------------------
168 subroutine annual_mean_insol( solins, &
169 lat, Np )
170 use scale_atmos_solarins, only: &
171 atmos_solarins_ecliptic_longitude
172 implicit none
173 integer, intent(in) :: np
174 real(rp), intent(out) :: solins(np)
175 real(rp), intent(in) :: lat(np)
176
177 integer :: date(date_size)
178 integer :: month, day
179 integer :: ndays_month
180 integer :: nsample
181
182 real(rp) :: re_factor
183 real(rp) :: sin_decl
184 real(rp) :: cos_decl
185 real(rp) :: hour_angle
186 integer, parameter :: offset_year = 0
187
188 integer :: i
189
190 real(rp) :: sample_second
191
192 real(rp) :: daily_solins(np)
193 real(rp) :: sum_flux(np)
194 !------------------------------------------------------------------------------
195
196 date(date_year) = annual_mean_year
197 nsample = 1
198 sum_flux(:) = 0.0_rp
199
200 do month=1, 12
201 ndays_month = days_in_month( annual_mean_year, month )
202 date(date_month) = month
203 do day=1, ndays_month
204 date(date_day) = day
205 do i=1, annual_samples_per_day
206 ! Midpoint sampling within each day.
207 sample_second = 86400.0_rp &
208 * ( real(i,rp) - 0.5_rp ) / real(annual_samples_per_day,rp)
209
210 call seconds_to_hms( sample_second, & ! (in)
211 date(date_hour), date(date_minute), date(date_second) ) ! (out)
212
213 call atmos_solarins_ecliptic_longitude( &
214 re_factor, sin_decl, cos_decl, hour_angle, & ! (out)
215 date, offset_year ) ! (in)
216
217 call daily_mean_insol( daily_solins, & ! (out)
218 lat, re_factor, sin_decl, cos_decl, np ) ! (in)
219
220 sum_flux(:) = sum_flux(:) + daily_solins(:)
221 nsample = nsample + 1
222 end do
223 end do
224 end do
225
226 solins(:) = sum_flux(:) / real(nsample, rp)
227 return
228 end subroutine annual_mean_insol
229
230!OCL SERIAL
231 subroutine daily_mean_insol( solins, &
232 lat, re_factor, sin_decl, cos_decl, Np )
233 use scale_atmos_solarins, only: &
234 atmos_solarins_constant
235 implicit none
236 integer, intent(in) :: np
237 real(rp), intent(out) :: solins(np)
238 real(rp), intent(in) :: lat(np)
239 real(rp), intent(in) :: re_factor
240 real(rp), intent(in) :: sin_decl
241 real(rp), intent(in) :: cos_decl
242
243 real(rp) :: sin_lat
244 real(rp) :: cos_lat
245 real(rp) :: cos_h0
246 real(rp) :: h0
247
248 real(rp), parameter :: pole_eps = 100.0_rp * epsilon(1.0_rp)
249
250 integer :: i
251 !------------------------------------------------------------------------------
252
253 !$omp parallel do private(sin_lat, cos_lat, cos_h0, h0)
254 do i=1, np
255 sin_lat = sin(lat(i))
256 cos_lat = cos(lat(i))
257 if ( abs(cos_lat) <= pole_eps ) then
258 if ( sin_lat * sin_decl > 0.0_rp ) then
259 h0 = pi
260 else
261 h0 = 0.0_rp
262 end if
263 else if ( abs(cos_decl) <= pole_eps ) then
264 if ( sin_lat * sin_decl > 0.0_rp ) then
265 h0 = pi
266 else
267 h0 = 0.0_rp
268 end if
269 else
270 cos_h0 = - ( sin_lat * sin_decl ) / ( cos_lat * cos_decl )
271 if ( cos_h0 >= 1.0_rp ) then ! Polar night
272 h0 = 0.0_rp
273 else if ( cos_h0 <= -1.0_rp ) then ! Polar day
274 h0 = pi
275 else
276 h0 = acos(cos_h0)
277 end if
278 end if
279
280 solins(i) = atmos_solarins_constant * re_factor / pi &
281 * ( h0 * sin_lat * sin_decl + sin(h0) * cos_lat * cos_decl )
282
283 solins(i) = max( solins(i), 0.0_rp )
284 end do
285 return
286 end subroutine daily_mean_insol
287
288 !> Number of days in a month
289 pure function days_in_month( YEAR, MONTH ) result(NDAYS)
290 implicit none
291 integer, intent(in) :: year
292 integer, intent(in) :: month
293
294 integer :: ndays
295 integer, parameter :: ndays_normal(12) = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
296 !---------------------------------------------------------------------------
297
298 ndays = ndays_normal(month)
299 if ( month == 2 .and. is_leap_year(year) ) ndays = 29
300 return
301 end function days_in_month
302
303 !> Gregorian leap-year test
304!OCL SERIAL
305 pure function is_leap_year( YEAR ) result(IS_LEAP)
306 implicit none
307 integer, intent(in) :: year
308 logical :: is_leap
309 !---------------------------------------------------------------------------
310
311 is_leap = mod(year,4) == 0
312
313 if ( mod(year,100) == 0 ) is_leap = .false.
314 if ( mod(year,400) == 0 ) is_leap = .true.
315 return
316 end function is_leap_year
317
318 !> Convert seconds from start of day to hour/minute/second
319!OCL SERIAL
320 pure subroutine seconds_to_hms( DAY_SECOND, &
321 HOUR, MINUTE, SECOND )
322 implicit none
323 real(rp), intent(in) :: day_second
324 integer, intent(out) :: hour
325 integer, intent(out) :: minute
326 integer, intent(out) :: second
327
328 integer :: total_second
329 !---------------------------------------------------------------------------
330
331 total_second = int(day_second)
332 total_second = max(0, min(total_second, 86399))
333
334 hour = total_second / 3600
335 total_second = total_second - hour * 3600
336
337 minute = total_second / 60
338 second = total_second - minute * 60
339 return
340 end subroutine seconds_to_hms
341
module FElib / Atmosphere / Physics radiation / Solar insolation / Simple gray-radiation scheme
subroutine, public atm_phy_rd_solarins_simple_get(solins, cossza, lat, np)
Get solar insolation and cosine of the solar zenith angle for the given latitude array.
subroutine, public atm_phy_rd_solarins_simple_setup()
Setup the simplified solar insolation module.