Line data Source code
1 : !=======================================================================
2 : !
3 : ! snow redistribution and metamorphism
4 : !
5 : ! authors Elizabeth Hunke, LANL
6 : ! Nicole Jeffery, LANL
7 : !
8 : module icepack_snow
9 :
10 : use icepack_kinds
11 : use icepack_parameters, only: puny, p1, p5, c0, c1, c4, c10, c100, pi
12 : use icepack_parameters, only: rhos, rhow, rhoi, rhofresh, snwgrain
13 : use icepack_parameters, only: snwlvlfac, Tffresh, cp_ice, Lfresh
14 : use icepack_parameters, only: snwredist, rsnw_fall, rsnw_tmax, rhosnew
15 : use icepack_parameters, only: rhosmin, rhosmax, windmin, drhosdwind
16 : use icepack_parameters, only: isnw_T, isnw_Tgrd, isnw_rhos
17 : use icepack_parameters, only: snowage_rhos, snowage_Tgrd, snowage_T
18 : use icepack_parameters, only: snowage_tau, snowage_kappa, snowage_drdt0
19 : use icepack_parameters, only: snw_aging_table, use_smliq_pnd
20 : use icepack_tracers, only: ncat, nilyr, nslyr
21 :
22 : use icepack_therm_shared, only: icepack_ice_temperature
23 : use icepack_therm_shared, only: adjust_enthalpy
24 :
25 : use icepack_warnings, only: icepack_warnings_add, icepack_warnings_setabort
26 : use icepack_warnings, only: icepack_warnings_aborted
27 :
28 : implicit none
29 : private
30 :
31 : public :: icepack_step_snow, drain_snow, icepack_init_snow
32 :
33 : real (kind=dbl_kind), parameter, public :: &
34 : S_r = 0.033_dbl_kind, & ! irreducible saturation (Anderson 1976)
35 : S_wet= 4.22e5_dbl_kind ! wet metamorphism parameter (um^3/s)
36 : ! = 1.e18 * 4.22e-13 (Oleson 2010)
37 :
38 : real (kind=dbl_kind) :: &
39 : min_rhos, & ! snowtable axis data, assumes linear data
40 : del_rhos, &
41 : min_Tgrd, &
42 : del_Tgrd, &
43 : min_T , &
44 : del_T
45 :
46 : logical (kind=log_kind) :: &
47 : lin_rhos = .false., & ! flag to specify whether the snowtable dimensions are linear
48 : lin_Tgrd = .false., & ! this will allow quick lookup
49 : lin_T = .false.
50 :
51 : !=======================================================================
52 :
53 : contains
54 :
55 : !=======================================================================
56 : !autodocument_start icepack_init_snow
57 : ! Updates snow tracers
58 : !
59 : ! authors: Elizabeth C. Hunke, LANL
60 : ! Nicole Jeffery, LANL
61 :
62 12 : subroutine icepack_init_snow
63 :
64 : !autodocument_end
65 :
66 : ! local variables
67 :
68 : integer (kind=int_kind) :: n
69 :
70 : character (len=*),parameter :: subname='(icepack_init_snow)'
71 :
72 : !-----------------------------------------------------------------
73 : ! Snow metamorphism lookup table
74 : !-----------------------------------------------------------------
75 :
76 : ! if snw_aging_table = 'snicar'
77 : ! best-fit parameters are read from a table (netcdf)
78 : ! snowage_tau, snowage_kappa, snowage_drdt0
79 : ! 11 temperatures from 223.15 to 273.15 K by 5.0
80 : ! 31 temperature gradients from 0 to 300 K/m by 10
81 : ! 8 snow densities from 50 to 400 kg/m3 by 50
82 :
83 : ! if snw_aging_table = 'test'
84 : ! for testing Icepack without netcdf,
85 : ! use a subsampled, hard-coded table
86 : ! 5 temperatures from 243.15 by 5.0 K
87 : ! 5 temperature gradients from 0 to 40 K/m by 10
88 : ! 1 snow density at 300 kg/m3
89 :
90 : ! if snw_aging_table = 'file'
91 : ! all data has to be passed into icepack_parameters
92 :
93 12 : if (snwgrain) then
94 11 : if (trim(snw_aging_table) == 'snicar') then ! read netcdf file
95 0 : isnw_rhos = 8 ! maxiumum snow density index
96 0 : isnw_Tgrd = 31 ! maxiumum temperature gradient index
97 0 : isnw_T = 11 ! maxiumum temperature index
98 0 : min_rhos = 50.0_dbl_kind ! snowtable dimension data
99 0 : del_rhos = 50.0_dbl_kind
100 0 : lin_rhos = .true.
101 0 : min_Tgrd = 0.0_dbl_kind
102 0 : del_Tgrd = 10.0_dbl_kind
103 0 : lin_Tgrd = .true.
104 0 : min_T = 223.15_dbl_kind
105 0 : del_T = 5.0_dbl_kind
106 0 : lin_T = .true.
107 : ! check if these are already allocated/set, if so, make sure size is OK
108 0 : if (allocated(snowage_tau)) then
109 : if (size(snowage_tau,dim=1) /= isnw_rhos .or. &
110 0 : size(snowage_tau,dim=2) /= isnw_Tgrd .or. &
111 : size(snowage_tau,dim=3) /= isnw_T ) then
112 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
113 0 : call icepack_warnings_add(subname//'ERROR: snowage_tau size snw_aging_table=snicar')
114 0 : return
115 : endif
116 : else
117 0 : allocate (snowage_tau (isnw_rhos,isnw_Tgrd,isnw_T))
118 : endif
119 :
120 0 : if (allocated(snowage_kappa)) then
121 : if (size(snowage_kappa,dim=1) /= isnw_rhos .or. &
122 0 : size(snowage_kappa,dim=2) /= isnw_Tgrd .or. &
123 : size(snowage_kappa,dim=3) /= isnw_T ) then
124 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
125 0 : call icepack_warnings_add(subname//'ERROR: snowage_kappa size snw_aging_table=snicar')
126 0 : return
127 : endif
128 : else
129 0 : allocate (snowage_kappa(isnw_rhos,isnw_Tgrd,isnw_T))
130 : endif
131 :
132 0 : if (allocated(snowage_drdt0)) then
133 : if (size(snowage_drdt0,dim=1) /= isnw_rhos .or. &
134 0 : size(snowage_drdt0,dim=2) /= isnw_Tgrd .or. &
135 : size(snowage_drdt0,dim=3) /= isnw_T ) then
136 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
137 0 : call icepack_warnings_add(subname//'ERROR: snowage_drdt0 size snw_aging_table=snicar')
138 0 : return
139 : endif
140 : else
141 0 : allocate (snowage_drdt0(isnw_rhos,isnw_Tgrd,isnw_T))
142 : endif
143 :
144 0 : if (allocated(snowage_rhos)) deallocate(snowage_rhos)
145 0 : if (allocated(snowage_Tgrd)) deallocate(snowage_Tgrd)
146 0 : if (allocated(snowage_T)) deallocate(snowage_T)
147 0 : allocate (snowage_rhos (isnw_rhos))
148 0 : allocate (snowage_Tgrd (isnw_Tgrd))
149 0 : allocate (snowage_T (isnw_T))
150 0 : do n = 1, isnw_rhos
151 0 : snowage_rhos(n) = min_rhos + real((n-1),dbl_kind)*del_rhos
152 : enddo
153 0 : do n = 1, isnw_Tgrd
154 0 : snowage_Tgrd(n) = min_Tgrd + real((n-1),dbl_kind)*del_Tgrd
155 : enddo
156 0 : do n = 1, isnw_T
157 0 : snowage_T(n) = min_T + real((n-1),dbl_kind)*del_T
158 : enddo
159 :
160 11 : elseif (trim(snw_aging_table) == 'file') then
161 0 : isnw_rhos = -1 ! maxiumum snow density index
162 0 : isnw_Tgrd = -1 ! maxiumum temperature gradient index
163 0 : isnw_T = -1 ! maxiumum temperature index
164 :
165 11 : elseif (trim(snw_aging_table) == 'test') then
166 11 : isnw_rhos = 1 ! maxiumum snow density index
167 11 : isnw_Tgrd = 5 ! maxiumum temperature gradient index
168 11 : isnw_T = 5 ! maxiumum temperature index
169 11 : min_rhos = 300.0_dbl_kind ! snowtable dimension data
170 11 : del_rhos = 50.0_dbl_kind
171 11 : lin_rhos = .true.
172 11 : min_Tgrd = 0.0_dbl_kind
173 11 : del_Tgrd = 10.0_dbl_kind
174 11 : lin_Tgrd = .true.
175 11 : min_T = 243.15_dbl_kind
176 11 : del_T = 5.0_dbl_kind
177 11 : lin_T = .true.
178 11 : if (allocated(snowage_tau)) deallocate(snowage_tau)
179 11 : if (allocated(snowage_kappa)) deallocate(snowage_kappa)
180 11 : if (allocated(snowage_drdt0)) deallocate(snowage_drdt0)
181 11 : if (allocated(snowage_rhos)) deallocate(snowage_rhos)
182 11 : if (allocated(snowage_Tgrd)) deallocate(snowage_Tgrd)
183 11 : if (allocated(snowage_T)) deallocate(snowage_T)
184 11 : allocate (snowage_tau (isnw_rhos,isnw_Tgrd,isnw_T))
185 11 : allocate (snowage_kappa(isnw_rhos,isnw_Tgrd,isnw_T))
186 11 : allocate (snowage_drdt0(isnw_rhos,isnw_Tgrd,isnw_T))
187 11 : allocate (snowage_rhos (isnw_rhos))
188 11 : allocate (snowage_Tgrd (isnw_Tgrd))
189 11 : allocate (snowage_T (isnw_T))
190 22 : do n = 1, isnw_rhos
191 22 : snowage_rhos(n) = min_rhos + real((n-1),dbl_kind)*del_rhos
192 : enddo
193 66 : do n = 1, isnw_Tgrd
194 66 : snowage_Tgrd(n) = min_Tgrd + real((n-1),dbl_kind)*del_Tgrd
195 : enddo
196 66 : do n = 1, isnw_T
197 66 : snowage_T(n) = min_T + real((n-1),dbl_kind)*del_T
198 : enddo
199 :
200 : ! Subset of dry snow aging parameters
201 : snowage_tau = reshape((/ &
202 : 3.34947394_dbl_kind, 4.02124159_dbl_kind, 4.03328223_dbl_kind, &
203 : 3.02686921_dbl_kind, 2.14125851_dbl_kind, 3.97008737_dbl_kind, &
204 : 4.72725821_dbl_kind, 3.65313459_dbl_kind, 2.41198936_dbl_kind, &
205 : 2.53065623e-1_dbl_kind, 4.60286630_dbl_kind, 4.99721440_dbl_kind, &
206 : 3.29168191_dbl_kind, 2.66426779e-1_dbl_kind, 9.15830596e-5_dbl_kind, &
207 : 5.33186128_dbl_kind, 4.90833452_dbl_kind, 1.55269141_dbl_kind, &
208 : 1.31225526e-3_dbl_kind, 9.36078196e-4_dbl_kind, 6.25428631_dbl_kind, &
209 : 5.04394794_dbl_kind, 2.92857366e-3_dbl_kind, 9.01488751e-3_dbl_kind, &
210 : 1.19037046e-2_dbl_kind/), &
211 44 : (/isnw_rhos,isnw_Tgrd,isnw_T/))
212 :
213 : snowage_kappa = reshape((/ &
214 : 0.60824438, 0.56442972, 0.5527807, 0.64299537, 0.77672359, &
215 : 0.57105932, 0.52791041, 0.59868076, 0.7487191, 1.57946877, &
216 : 0.54236508, 0.52458285, 0.65520877, 1.52356017, 4.37789838, &
217 : 0.51449138, 0.54494334, 0.91628508, 3.28847035, 3.64418487, &
218 : 0.48538708, 0.55386601, 2.81247103, 2.72445522, 2.8230216/), &
219 660 : (/isnw_rhos,isnw_Tgrd,isnw_T/))
220 :
221 : snowage_drdt0 = reshape((/ &
222 : 1.26597871, 1.26602416, 1.26613263, 1.26620414, 1.26629424, &
223 : 1.92418877, 1.92430063, 1.92445964, 1.92451557, 1.92469806, &
224 : 2.79086547, 2.79147315, 2.79137562, 2.79150846, 2.79216439, &
225 : 3.85605846, 3.85668001, 3.85844559, 3.86073682, 3.863199, &
226 : 5.0861907, 5.08765668, 5.09200195, 5.09665276, 5.10079895/), &
227 660 : (/isnw_rhos,isnw_Tgrd,isnw_T/))
228 : else
229 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
230 0 : call icepack_warnings_add(subname//'ERROR: snw_aging_table value')
231 0 : return
232 : endif
233 : endif
234 :
235 : end subroutine icepack_init_snow
236 :
237 : !=======================================================================
238 : !autodocument_start icepack_step_snow
239 : ! Updates snow tracers
240 : !
241 : ! authors: Elizabeth C. Hunke, LANL
242 : ! Nicole Jeffery, LANL
243 :
244 339264 : subroutine icepack_step_snow(dt, &
245 : wind, aice, &
246 339264 : aicen, vicen, &
247 678528 : vsnon, Tsfc, &
248 339264 : zqin1, zSin1, &
249 339264 : zqsn, &
250 339264 : alvl, vlvl, &
251 339264 : smice, smliq, &
252 678528 : rsnw, rhos_cmpn, &
253 : fresh, fhocn, &
254 : fsloss, fsnow)
255 :
256 : real (kind=dbl_kind), intent(in) :: &
257 : dt , & ! time step
258 : wind , & ! wind speed (m/s)
259 : fsnow , & ! snowfall rate (kg m-2 s-1)
260 : aice ! ice area fraction
261 :
262 : real (kind=dbl_kind), dimension(:), intent(in) :: &
263 : aicen, & ! ice area fraction
264 : vicen, & ! ice volume (m)
265 : Tsfc , & ! surface temperature (C)
266 : zqin1, & ! ice upper layer enthalpy
267 : zSin1, & ! ice upper layer salinity
268 : alvl, & ! level ice area tracer
269 : vlvl ! level ice volume tracer
270 :
271 : real (kind=dbl_kind), intent(inout) :: &
272 : fresh , & ! fresh water flux to ocean (kg/m^2/s)
273 : fhocn , & ! net heat flux to ocean (W/m^2)
274 : fsloss ! rate of snow loss to leads (kg/m^2/s)
275 :
276 : real (kind=dbl_kind), dimension(:), intent(inout) :: &
277 : vsnon ! snow volume (m)
278 :
279 : real (kind=dbl_kind), dimension(:,:), intent(inout) :: &
280 : zqsn , & ! snow enthalpy (J/m^3)
281 : smice , & ! tracer for mass of ice in snow (kg/m^3)
282 : smliq , & ! tracer for mass of liquid in snow (kg/m^3)
283 : rsnw , & ! snow grain radius (10^-6 m)
284 : rhos_cmpn ! effective snow density: compaction (kg/m^3)
285 :
286 : !autodocument_end
287 :
288 : ! local variables
289 :
290 : integer (kind=int_kind) :: k, n
291 :
292 : real (kind=dbl_kind), dimension(ncat) :: &
293 678528 : zTin1, & ! ice upper layer temperature (C)
294 678528 : hsn , & ! snow thickness (m)
295 339264 : hin ! ice thickness
296 :
297 : real (kind=dbl_kind) :: &
298 : vsno, & ! snow volume (m)
299 : tmp1, tmp2
300 :
301 : character (len=*),parameter :: subname='(icepack_step_snow)'
302 :
303 : !-----------------------------------------------------------------
304 : ! Initialize effective snow density (compaction) for new snow
305 : !-----------------------------------------------------------------
306 :
307 339264 : if (snwredist(1:3) == 'ITD') then
308 1825344 : do n = 1, ncat
309 9430944 : do k = 1, nslyr
310 9126720 : if (rhos_cmpn(k,n) < rhosmin) rhos_cmpn(k,n) = rhosnew
311 : enddo
312 : enddo
313 : endif
314 :
315 : !-----------------------------------------------------------------
316 : ! Redistribute snow based on wind
317 : !-----------------------------------------------------------------
318 :
319 339264 : vsno = c0
320 2035584 : do n = 1, ncat
321 2035584 : vsno = vsno + vsnon(n)
322 : enddo
323 339264 : tmp1 = rhos*vsno + fresh*dt
324 :
325 339264 : if (snwredist(1:3) == 'ITD' .and. aice > puny) then
326 : call snow_redist(dt, &
327 : wind, aicen(:), &
328 : vicen(:), vsnon(:), &
329 : zqsn(:,:), &
330 : alvl(:), vlvl(:), &
331 : fresh, fhocn, &
332 : fsloss, rhos_cmpn, &
333 217083 : fsnow)
334 217083 : if (icepack_warnings_aborted(subname)) return
335 : endif
336 :
337 339264 : vsno = c0
338 2035584 : do n = 1, ncat
339 2035584 : vsno = vsno + vsnon(n)
340 : enddo
341 339264 : tmp2 = rhos*vsno + fresh*dt
342 :
343 : ! check conservation
344 339264 : if (abs(tmp1-tmp2)>puny) then
345 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
346 0 : call icepack_warnings_add(subname//'ERROR: snow redistribution')
347 : endif
348 :
349 : !-----------------------------------------------------------------
350 : ! Adjust snow grain radius
351 : !-----------------------------------------------------------------
352 :
353 339264 : if (snwgrain) then
354 1825344 : do n = 1, ncat
355 1521120 : zTin1(n) = c0
356 1521120 : hsn (n) = c0
357 1521120 : hin (n) = c0
358 1825344 : if (aicen(n) > puny) then
359 885331 : zTin1(n) = icepack_ice_temperature(zqin1(n), zSin1(n))
360 885331 : hsn(n) = vsnon(n)/aicen(n)
361 885331 : hin(n) = vicen(n)/aicen(n)
362 : endif
363 : enddo
364 :
365 : call update_snow_radius (dt, &
366 : rsnw, hin, &
367 : Tsfc, zTin1, &
368 : hsn, zqsn, &
369 304224 : smice, smliq)
370 304224 : if (icepack_warnings_aborted(subname)) return
371 : endif
372 :
373 : end subroutine icepack_step_snow
374 :
375 : !=======================================================================
376 :
377 : ! Snow redistribution by wind, based on O. Lecomte Ph.D. (2014).
378 : ! The original formulation:
379 : ! Snow in suspension depends on wind speed, density and the standard
380 : ! deviation of the ice thickness distribution. Snow is redistributed
381 : ! among ice categories proportionally to the category areas.
382 : !
383 : ! Namelist option snwredist = 'ITDrdg' modifies the approach to use
384 : ! the level and ridged ice tracers:
385 : ! As above, but use the standard deviation of the level and ridged
386 : ! ice thickness distribution for snow in suspension, and redistribute
387 : ! based on ridged ice area.
388 : !
389 : ! convention:
390 : ! volume, mass and energy include factor of ain
391 : ! thickness does not
392 :
393 217083 : subroutine snow_redist(dt, wind, ain, vin, vsn, zqsn, &
394 217083 : alvl, vlvl, fresh, fhocn, fsloss, rhos_cmpn, fsnow)
395 :
396 : real (kind=dbl_kind), intent(in) :: &
397 : dt , & ! time step (s)
398 : wind , & ! wind speed (m/s)
399 : fsnow ! snowfall rate (kg m-2 s-1)
400 :
401 : real (kind=dbl_kind), dimension(:), intent(in) :: &
402 : ain , & ! ice area fraction
403 : vin , & ! ice volume (m)
404 : alvl , & ! level ice area tracer
405 : vlvl ! level ice volume tracer
406 :
407 : real (kind=dbl_kind), intent(inout) :: &
408 : fresh , & ! fresh water flux to ocean (kg/m^2/s)
409 : fhocn , & ! net heat flux to ocean (W/m^2)
410 : fsloss ! rate of snow loss to leads (kg/m^2/s)
411 :
412 : real (kind=dbl_kind), dimension(:), intent(inout) :: &
413 : vsn ! snow volume (m)
414 :
415 : real (kind=dbl_kind), dimension(:,:), intent(inout) :: &
416 : zqsn , & ! snow enthalpy (J/m^3)
417 : rhos_cmpn ! effective snow density: compaction (kg/m^3)
418 :
419 : ! local variables
420 :
421 : integer (kind=int_kind) :: &
422 : n , & ! category index
423 : k ! layer index
424 :
425 : integer (kind=int_kind), dimension(ncat) :: &
426 434166 : klyr ! layer index
427 :
428 : real (kind=dbl_kind), parameter :: &
429 : refsd = c1 , & ! standard deviation reference
430 : gamma = 1.e-5_dbl_kind ! tuning coefficient
431 :
432 : real (kind=dbl_kind) :: &
433 : Vseas , & ! critical seasonal wind speed (m/s)
434 : ITDsd , & ! standard deviation of ITD
435 : flost , & ! fraction of snow lost in leads
436 : alost , & ! effective lead area for snow lost in leads
437 : suma , & ! sum of ice area over categories
438 : sumv , & ! sum of ice volume over categories (m)
439 : summ , & ! sum of snow mass over categories (kg/m^2)
440 : sumq , & ! sum of snow enthalpy over categories (kg/m^2)
441 : msusp , & ! potential mass of snow in suspension (kg/m^2)
442 : msnw_susp , & ! mass of snow in suspension (kg/m^2)
443 : esnw_susp , & ! energy of snow in suspension (J/m^2)
444 : asnw_lvl , & ! mass of snow redeposited on level ice (kg/m^2)
445 : e_redeptmp, & ! redeposited energy (J/m^2)
446 : dhsn , & ! change in snow depth (m)
447 : dmp , & ! mass difference in previous layer (kg/m^2)
448 : hslyr , & ! snow layer thickness (m)
449 : hslab , & ! new snow thickness (m)
450 : drhos , & ! change in snow density due to compaction (kg/m^3)
451 : mlost , & ! mass of suspended snow lost in leads (kg/m^2)
452 : elost , & ! energy of suspended snow lost in leads (J/m^2)
453 : de , & ! change in energy (J/m^2)
454 : al, ar , & ! areas of level and ridged ice
455 : hlvl, hrdg, & ! thicknesses of level and ridged ice
456 : tmp1, tmp2, & ! temporary values
457 : tmp3, tmp4, & ! temporary values
458 : tmp5 , & ! temporary values
459 : work ! temporary value
460 :
461 : real (kind=dbl_kind), dimension(ncat) :: &
462 434166 : sfac , & ! temporary for snwlvlfac
463 217083 : ardg , & ! ridged ice area tracer
464 434166 : m_erosion , & ! eroded mass (kg/m^2)
465 434166 : e_erosion , & ! eroded energy (J/m^2)
466 434166 : m_redep , & ! redeposited mass (kg/m^2)
467 434166 : e_redep , & ! redeposited energy (J/m^2)
468 434166 : vsn_init , & ! initial volume (m)
469 434166 : esn_init , & ! initial energy (J/m^2)
470 434166 : esn_final , & ! final energy (J/m^2)
471 434166 : atmp , & ! temporary variable for ain, for debugging convenience
472 434166 : hin , & ! ice thickness (m)
473 434166 : hsn , & ! snow depth (m)
474 434166 : hsn_new ! new snow depth (m)
475 :
476 : real (kind=dbl_kind), dimension (nslyr) :: &
477 434166 : dzs ! snow layer thickness after redistribution (m)
478 :
479 : real (kind=dbl_kind), dimension (nslyr+1) :: &
480 434166 : zs1 , & ! depth of snow layer boundaries (m)
481 217083 : zs2 ! adjusted depths, with equal hslyr (m)
482 :
483 : character (len=*),parameter :: subname='(snow_redist)'
484 :
485 : !-----------------------------------------------------------------
486 : ! Conservation checks
487 : !-----------------------------------------------------------------
488 :
489 217083 : tmp1 = c0
490 217083 : tmp3 = c0
491 1302498 : do n = 1, ncat
492 : ! mass conservation check
493 1085415 : tmp1 = tmp1 + vsn(n)
494 1085415 : vsn_init(n) = vsn(n)
495 1085415 : esn_init(n) = c0
496 : ! energy conservation check
497 6729573 : do k = 1, nslyr
498 5427075 : tmp3 = tmp3 + vsn(n)*zqsn(k,n)/nslyr
499 6512490 : esn_init(n) = esn_init(n) + vsn(n)*zqsn(k,n)/nslyr
500 : enddo
501 : enddo
502 :
503 : !-----------------------------------------------------------------
504 : ! category thickness and sums
505 : !-----------------------------------------------------------------
506 :
507 1302498 : hin(:) = c0
508 1302498 : hsn(:) = c0
509 217083 : suma = c0
510 217083 : sumv = c0
511 1302498 : do n = 1, ncat
512 1085415 : atmp(n) = ain(n)
513 1085415 : if (atmp(n) > puny) then
514 887689 : hin(n) = vin(n)/atmp(n)
515 887689 : hsn(n) = vsn(n)/atmp(n)
516 : endif
517 1085415 : hsn_new(n) = hsn(n)
518 1085415 : suma = suma + atmp(n)
519 1085415 : sumv = sumv + vin(n)
520 : ! maintain positive definite enthalpy
521 6729573 : do k = 1, nslyr
522 6512490 : zqsn(k,n) = min(zqsn(k,n) + Lfresh*rhos, c0)
523 : enddo
524 : enddo ! ncat
525 :
526 : !-----------------------------------------------------------------
527 : ! standard deviation of ice thickness distribution
528 : !-----------------------------------------------------------------
529 :
530 217083 : work = c0
531 217083 : asnw_lvl = c0
532 217083 : if (trim(snwredist) == 'ITDrdg') then ! use level and ridged ice
533 1302498 : do n = 1, ncat
534 1085415 : ardg(n) = c1 - alvl(n) ! ridged ice tracer
535 1085415 : al = alvl(n) * atmp(n) ! level
536 1085415 : ar = ardg(n) * atmp(n) ! ridged
537 1085415 : hlvl = c0
538 1085415 : hrdg = c0
539 1085415 : if (al > puny) hlvl = vin(n)*vlvl(n)/al
540 1085415 : if (ar > puny) hrdg = vin(n)*(c1-vlvl(n))/ar
541 1085415 : work = work + al*(hlvl - sumv)**2 + ar*(hrdg - sumv)**2
542 :
543 : ! for redeposition of snow on level ice
544 1085415 : sfac(n) = snwlvlfac
545 1085415 : if (ardg(n) > c0) sfac(n) = min(snwlvlfac, alvl(n)/ardg(n))
546 1302498 : asnw_lvl = asnw_lvl + al - sfac(n)*ar
547 : enddo
548 217083 : asnw_lvl = asnw_lvl/suma
549 : ! else ! snwredist = 'ITDsd' ! use standard ITD
550 : ! do n = 1, ncat
551 : ! work = work + atmp(n)*(hin(n) - sumv)**2
552 : ! enddo
553 : endif
554 217083 : ITDsd = sqrt(work)
555 :
556 : !-----------------------------------------------------------------
557 : ! fraction of suspended snow lost in leads
558 : !-----------------------------------------------------------------
559 :
560 217083 : flost = (c1 - suma) * exp(-ITDsd/refsd)
561 : ! flost = c0 ! echmod for testing
562 217083 : alost = c1 - suma * (c1-flost)
563 :
564 : !-----------------------------------------------------------------
565 : ! suspended snow
566 : !-----------------------------------------------------------------
567 :
568 217083 : msusp = c0
569 1302498 : do n = 1, ncat
570 : ! critical seasonal wind speed needed to compact snow to density rhos
571 1085415 : Vseas = (rhos_cmpn(1,n) - 44.6_dbl_kind)/174.0_dbl_kind ! use top layer
572 1085415 : Vseas = max(Vseas, c0)
573 : ! maximum mass per unit area of snow in suspension (kg/m^2)
574 1085415 : if (ITDsd > puny) &
575 : msusp = msusp + atmp(n)*gamma*dt*max(wind-Vseas,c0) &
576 1302378 : * (rhosmax-rhos_cmpn(1,n))/(rhosmax*ITDsd)
577 : enddo
578 :
579 : !-----------------------------------------------------------------
580 : ! erosion
581 : !-----------------------------------------------------------------
582 :
583 217083 : msnw_susp = c0
584 217083 : esnw_susp = c0
585 1302498 : klyr(:) = 1
586 1302498 : do n = 1, ncat
587 1085415 : m_erosion(n) = c0 ! mass
588 1085415 : e_erosion(n) = c0 ! energy
589 1302498 : if (atmp(n) > puny) then
590 887689 : m_erosion(n) = min(msusp, rhos*vsn(n))
591 887689 : if (m_erosion(n) > puny) then
592 828533 : summ = c0
593 828533 : dmp = m_erosion(n)
594 4971198 : do k = 1, nslyr
595 4971198 : if (dmp > c0) then
596 3059450 : dhsn = min(hsn(n)/nslyr, dmp/(rhos*atmp(n)))
597 3059450 : msnw_susp = msnw_susp + dhsn*rhos*atmp(n) ! total mass in suspension
598 3059450 : hsn_new(n) = hsn_new(n) - dhsn
599 3059450 : e_erosion(n) = e_erosion(n) + dhsn*zqsn(k,n)*atmp(n)
600 3059450 : klyr(n) = k ! number of affected layers
601 3059450 : summ = summ + rhos*vsn(n)/nslyr ! mass, partial sum
602 3059450 : dmp = max(m_erosion(n) - summ, c0)
603 : endif ! dmp
604 : enddo
605 828533 : esnw_susp = esnw_susp + e_erosion(n) ! total energy in suspension
606 : endif
607 : endif
608 : enddo
609 :
610 : !-----------------------------------------------------------------
611 : ! redeposition
612 : !-----------------------------------------------------------------
613 :
614 1302498 : do n = 1, ncat
615 1085415 : if (trim(snwredist) == 'ITDrdg') then ! use level and ridged ice
616 1085415 : work = atmp(n)*(c1-flost)*(ardg(n)*(c1+sfac(n)) + asnw_lvl)
617 : else ! use standard ITD
618 0 : work = atmp(n)*(c1-flost)
619 : endif
620 1085415 : m_redep(n) = msnw_susp*work ! mass
621 1085415 : e_redep(n) = c0
622 1085415 : e_redeptmp = esnw_susp*work ! energy
623 :
624 : ! change in snow depth
625 1085415 : dhsn = c0
626 1085415 : if (atmp(n) > puny) then
627 887689 : dhsn = m_redep(n) / (rhos*atmp(n))
628 :
629 887689 : if (abs(dhsn) > c0) then
630 :
631 832612 : e_redep(n) = e_redeptmp
632 832612 : vsn(n) = (hsn_new(n)+dhsn)*atmp(n)
633 :
634 : ! change in snow energy
635 832612 : de = e_redeptmp / klyr(n)
636 : ! spread among affected layers
637 832612 : sumq = c0
638 3896141 : do k = 1, klyr(n)
639 : zqsn(k,n) = (atmp(n)*hsn_new(n)*zqsn(k,n) + de) &
640 3063529 : / (vsn(n)) ! factor of nslyr cancels out
641 :
642 3896141 : if (zqsn(k,n) > c0) then
643 7 : sumq = sumq + zqsn(k,n)
644 7 : zqsn(k,n) = c0
645 : endif
646 :
647 : enddo ! klyr
648 832612 : zqsn(klyr(n),n) = min(zqsn(klyr(n),n) + sumq, c0) ! may lose energy here
649 :
650 : !-----------------------------------------------------------------
651 : ! Conserving energy, compute the enthalpy of the new equal layers
652 : !-----------------------------------------------------------------
653 :
654 832612 : if (nslyr > 1) then
655 :
656 4995672 : dzs(:) = hsn(n) / real(nslyr,kind=dbl_kind) ! old layer thickness
657 3896141 : do k = 1, klyr(n)
658 3896141 : dzs(k) = dzs(k) + dhsn / klyr(n) ! old layer thickness (updated)
659 : enddo
660 832612 : hsn_new(n) = hsn_new(n) + dhsn
661 832612 : hslyr = hsn_new(n) / real(nslyr,kind=dbl_kind) ! new layer thickness
662 :
663 832612 : zs1(1) = c0
664 832612 : zs1(1+nslyr) = hsn_new(n)
665 :
666 832612 : zs2(1) = c0
667 832612 : zs2(1+nslyr) = hsn_new(n)
668 :
669 4163060 : do k = 1, nslyr-1
670 3330448 : zs1(k+1) = zs1(k) + dzs(k) ! old layer depths (unequal thickness)
671 4163060 : zs2(k+1) = zs2(k) + hslyr ! new layer depths (equal thickness)
672 : enddo
673 :
674 : call adjust_enthalpy (nslyr, &
675 : zs1(:), zs2(:), &
676 : hslyr , hsn_new(n), &
677 832612 : zqsn(:,n))
678 832612 : if (icepack_warnings_aborted(subname)) return
679 : else
680 0 : hsn_new(n) = hsn_new(n) + dhsn
681 : endif ! nslyr > 1
682 : endif ! |dhsn| > puny
683 : endif ! ain > puny
684 :
685 : ! maintain positive definite enthalpy
686 6729573 : do k = 1, nslyr
687 6512490 : zqsn(k,n) = zqsn(k,n) - Lfresh*rhos
688 : enddo
689 : enddo ! ncat
690 :
691 : !-----------------------------------------------------------------
692 : ! mass of suspended snow lost in leads
693 : !-----------------------------------------------------------------
694 217083 : mlost = msnw_susp*alost
695 217083 : fsloss = fsloss + mlost / dt
696 :
697 : !-----------------------------------------------------------------
698 : ! mass conservation check
699 : !-----------------------------------------------------------------
700 :
701 217083 : tmp2 = c0
702 1302498 : do n = 1, ncat
703 1302498 : tmp2 = tmp2 + vsn(n)
704 : enddo
705 :
706 217083 : if (tmp2 > tmp1) then ! correct roundoff error
707 24 : vsn(:) = vsn(:) * tmp1/tmp2
708 4 : tmp2 = c0
709 24 : do n = 1, ncat
710 24 : tmp2 = tmp2 + vsn(n)
711 : enddo
712 : endif
713 :
714 217083 : if (tmp2 < tmp1) fresh = fresh + rhos*(tmp1-tmp2)/dt
715 :
716 217083 : tmp2 = tmp2 + (mlost/rhos)
717 :
718 217083 : if (abs(tmp1-tmp2) > puny) then
719 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
720 0 : call icepack_warnings_add(subname//'ERROR: snow redistribution mass conservation error')
721 : ! write(warning,*)'mass conservation error in snow_redist', tmp1, tmp2
722 : ! write(warning,*)'klyr',klyr
723 : ! write(warning,*)'ain',atmp(:)
724 : ! write(warning,*)'vsn final',vsn(:)
725 : ! write(warning,*)'vsn init',vsn_init(:)
726 : ! write(warning,*)'rhos*vsn init',rhos*vsn_init(:)
727 : ! write(warning,*)'m_erosion',m_erosion(:)
728 : ! write(warning,*)'m_redep',m_redep(:)
729 : ! write(warning,*)'mlost',mlost
730 : ! write(warning,*)'v_erosion',m_erosion(:)/rhos
731 : ! write(warning,*)'v_redep',m_redep(:)/rhos
732 : ! write(warning,*)'v lost',mlost/rhos
733 : ! write(warning,*)'hsn',hsn(:)
734 : ! write(warning,*)'hsn_new',hsn_new(:)
735 : ! write(warning,*)'vsn_new',hsn_new(:)*atmp(:)
736 : ! write(warning,*)'lost',suma,flost,alost,msnw_susp
737 : endif
738 :
739 : !-----------------------------------------------------------------
740 : ! energy conservation check
741 : !-----------------------------------------------------------------
742 :
743 217083 : tmp4 = c0
744 217083 : tmp5 = c0
745 1302498 : esn_final(:) = c0
746 1302498 : do n = 1, ncat
747 6512490 : do k = 1, nslyr
748 5427075 : tmp4 = tmp4 + vsn(n)*zqsn(k,n)/nslyr
749 6512490 : esn_final(n) = esn_final(n) + vsn(n)*zqsn(k,n)/nslyr
750 : enddo
751 1302498 : tmp5 = tmp5 - e_erosion(n) + e_redep(n)
752 : enddo
753 217083 : tmp5 = tmp5 + esnw_susp*alost
754 :
755 : !-----------------------------------------------------------------
756 : ! energy of suspended snow lost in leads
757 : !-----------------------------------------------------------------
758 217083 : elost = tmp3 - tmp4
759 217083 : fhocn = fhocn + elost / dt
760 :
761 217083 : if (abs(tmp5) > nslyr*Lfresh*puny) then
762 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
763 0 : call icepack_warnings_add(subname//'ERROR: snow redistribution energy conservation error')
764 : ! write(warning,*)'energy conservation error in snow_redist', tmp3, tmp4, tmp5
765 : ! write(warning,*)'klyr',klyr
766 : ! write(warning,*)'ain',atmp(:)
767 : ! write(warning,*)'vsn final',vsn(:)
768 : ! write(warning,*)'vsn init',vsn_init(:)
769 : ! write(warning,*)'rhos*vsn init',rhos*vsn_init(:)
770 : ! write(warning,*)'m_erosion',m_erosion(:)
771 : ! write(warning,*)'m_redep',m_redep(:)
772 : ! write(warning,*)'mlost',mlost
773 : ! write(warning,*)'v_erosion',m_erosion(:)/rhos
774 : ! write(warning,*)'v_redep',m_redep(:)/rhos
775 : ! write(warning,*)'v lost',mlost/rhos
776 : ! write(warning,*)'hsn',hsn(:)
777 : ! write(warning,*)'hsn_new',hsn_new(:)
778 : ! write(warning,*)'vsn_new',hsn_new(:)*atmp(:)
779 : ! write(warning,*)'lost',suma,flost,alost,msnw_susp
780 : ! write(warning,*)'tmp3(1)', (vsn(1)*zqsn(k,1)/nslyr,k=1,nslyr)
781 : ! write(warning,*)'esn init',esn_init(:)
782 : ! write(warning,*)'esn final',esn_final(:)
783 : ! write(warning,*)'e_erosion',e_erosion(:)
784 : ! write(warning,*)'e_redep',e_redep(:)
785 : ! write(warning,*)'elost',elost,esnw_susp*alost,Lfresh*mlost
786 : ! write(warning,*)'esnw_susp',esnw_susp
787 : endif
788 :
789 : !-----------------------------------------------------------------
790 : ! wind compaction
791 : !-----------------------------------------------------------------
792 :
793 1302498 : do n = 1, ncat
794 1302498 : if (vsn(n) > puny) then
795 : ! compact freshly fallen or redistributed snow
796 863880 : drhos = drhosdwind * max(wind - windmin, c0)
797 863880 : hslab = c0
798 863880 : if (fsnow > c0) &
799 833455 : hslab = max(min(fsnow*dt/(rhos+drhos), hsn_new(n)-hsn(n)), c0)
800 863880 : hslyr = hsn_new(n) / real(nslyr,kind=dbl_kind)
801 5183280 : do k = 1, nslyr
802 4319400 : work = hslab - hslyr * real(k-1,kind=dbl_kind)
803 4319400 : work = max(c0, min(hslyr, work))
804 4319400 : rhos_cmpn(k,n) = rhos_cmpn(k,n) + drhos*work/hslyr
805 5183280 : rhos_cmpn(k,n) = min(rhos_cmpn(k,n), rhosmax)
806 : enddo
807 : endif
808 : enddo
809 :
810 : end subroutine snow_redist
811 :
812 : !=======================================================================
813 :
814 : ! Snow grain metamorphism
815 :
816 304224 : subroutine update_snow_radius (dt, rsnw, hin, &
817 304224 : Tsfc, zTin, hsn, zqsn, smice, smliq)
818 :
819 : real (kind=dbl_kind), intent(in) :: &
820 : dt ! time step
821 :
822 : real (kind=dbl_kind), dimension(ncat), intent(in) :: &
823 : zTin , & ! surface ice temperature (oC)
824 : Tsfc , & ! surface temperature (oC)
825 : hin , & ! ice thickness (m)
826 : hsn ! snow thickness (m)
827 :
828 : real (kind=dbl_kind), dimension(nslyr,ncat), intent(in) :: &
829 : zqsn ! enthalpy of snow (J m-3)
830 :
831 : real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: &
832 : rsnw ! snow grain radius
833 :
834 : real (kind=dbl_kind), dimension(nslyr,ncat), intent(inout) :: &
835 : smice , & ! tracer for mass of ice in snow (kg/m^3)
836 : smliq ! tracer for mass of liquid in snow (kg/m^3)
837 :
838 : ! local temporary variables
839 :
840 : integer (kind=int_kind) :: k, n
841 :
842 : real (kind=dbl_kind), dimension(nslyr) :: &
843 608448 : drsnw_wet, & ! wet metamorphism (10^-6 m)
844 304224 : drsnw_dry ! dry (temperature gradient) metamorphism (10^-6 m)
845 :
846 : character (len=*),parameter :: subname='(update_snow_radius)'
847 :
848 1825344 : do n = 1, ncat
849 :
850 1825344 : if (hsn(n) > puny .and. hin(n) > puny) then
851 :
852 5183388 : drsnw_dry(:) = c0
853 5183388 : drsnw_wet(:) = c0
854 :
855 : !-----------------------------------------------------------------
856 : ! dry metamorphism
857 : !-----------------------------------------------------------------
858 : call snow_dry_metamorph (dt, rsnw(:,n), &
859 : drsnw_dry, zqsn(:,n), Tsfc(n), &
860 863898 : zTin(n), hsn(n), hin(n))
861 863898 : if (icepack_warnings_aborted(subname)) return
862 :
863 : !-----------------------------------------------------------------
864 : ! wet metamorphism
865 : !-----------------------------------------------------------------
866 5183388 : do k = 1,nslyr
867 : call snow_wet_metamorph (dt, drsnw_wet(k), rsnw(k,n), &
868 4319490 : smice(k,n), smliq(k,n))
869 4319490 : if (icepack_warnings_aborted(subname)) return
870 5183388 : rsnw(k,n) = min(rsnw_tmax, rsnw(k,n) + drsnw_dry(k) + drsnw_wet(k))
871 : enddo
872 :
873 : else ! hsn or hin < puny
874 3943332 : do k = 1,nslyr
875 : ! rsnw_fall < rsnw < rsnw_tmax
876 3286110 : rsnw (k,n) = max(rsnw_fall, min(rsnw_tmax, rsnw(k,n)))
877 3286110 : smice(k,n) = rhos
878 3943332 : smliq(k,n) = c0
879 : enddo
880 : endif ! hsn, hin
881 : enddo
882 :
883 : end subroutine update_snow_radius
884 :
885 : !=======================================================================
886 :
887 : ! Snow grain metamorphism
888 :
889 863898 : subroutine snow_dry_metamorph (dt, rsnw, drsnw_dry, zqsn, &
890 : Tsfc, zTin1, hsn, hin)
891 :
892 : ! Vapor redistribution: Method is to retrieve 3 best-fit parameters that
893 : ! depend on snow temperature, temperature gradient, and density,
894 : ! that are derived from the microphysical model described in:
895 : ! Flanner and Zender (2006), Linking snowpack microphysics and albedo
896 : ! evolution, J. Geophys. Res., 111, D12208, doi:10.1029/2005JD006834.
897 : ! The parametric equation has the form:
898 : ! dr/dt = drdt_0*(tau/(dr_fresh+tau))^(1/kappa), where:
899 : ! r is the effective radius,
900 : ! tau and kappa are best-fit parameters,
901 : ! drdt_0 is the initial rate of change of effective radius, and
902 : ! dr_fresh is the difference between the current and fresh snow states
903 : ! (r_current - r_fresh).
904 :
905 : real (kind=dbl_kind), intent(in) :: &
906 : dt ! time step (s)
907 :
908 : real (kind=dbl_kind), dimension(nslyr), intent(in) :: &
909 : rsnw, & ! snow grain radius (10^-6 m)
910 : zqsn ! snow enthalpy (J m-3)
911 :
912 : real (kind=dbl_kind), dimension(nslyr), intent(inout) :: &
913 : drsnw_dry ! change due to snow aging (10^-6 m)
914 :
915 : real (kind=dbl_kind), intent(in) :: &
916 : Tsfc, & ! surface temperature (C)
917 : zTin1, & ! top ice layer temperature (C)
918 : hsn, & ! snow thickness (m)
919 : hin ! ice thickness (m)
920 :
921 : ! local temporary variables
922 :
923 : integer (kind=int_kind) :: k
924 :
925 : integer (kind=int_kind) :: &
926 : T_idx, & ! temperature index
927 : Tgrd_idx, & ! temperature gradient index
928 : rhos_idx ! density index
929 :
930 : real (kind=dbl_kind), dimension(nslyr):: &
931 2591694 : zdTdz, & ! temperature gradient (K/s)
932 863898 : zTsn ! snow temperature (C)
933 :
934 : real (kind=dbl_kind) :: &
935 : bst_tau, & ! snow aging parameter retrieved from lookup table [hour]
936 : bst_kappa, & ! snow aging parameter retrieved from lookup table [unitless]
937 : bst_drdt0, & ! snow aging parameter retrieved from lookup table [um hr-1]
938 : dr_fresh, & ! change in snow radius from fresh (10^-6 m)
939 : dzs, & ! snow layer thickness (m)
940 : dzi, & ! ice layer thickness (m)
941 : dz ! dzs + dzi (m)
942 :
943 : logical (kind=log_kind), save :: &
944 : first_call = .true. ! first call flag
945 :
946 : character (char_len) :: &
947 : string ! generic string for writing messages
948 :
949 : character (len=*),parameter :: subname='(snow_dry_metamorph)'
950 :
951 : !-----------------------------------------------------------------
952 : ! On the first call, check that the table is setup properly
953 : ! Check sizes of 1D and 3D data
954 : ! Check that the 1D data is regularly spaced and set min, del, and lin values
955 : ! for each 1D variable. This info will be used later for the table lookup.
956 : !-----------------------------------------------------------------
957 :
958 863898 : if (first_call) then
959 : if (isnw_rhos < 1 .or. isnw_Tgrd < 1 .or. isnw_T < 1 .or. &
960 : size(snowage_rhos) /= isnw_rhos .or. &
961 : size(snowage_Tgrd) /= isnw_Tgrd .or. &
962 : size(snowage_T) /= isnw_T .or. &
963 : size(snowage_tau) /= isnw_rhos*isnw_Tgrd*isnw_T .or. &
964 110 : size(snowage_kappa) /= isnw_rhos*isnw_Tgrd*isnw_T .or. &
965 : size(snowage_drdt0) /= isnw_rhos*isnw_Tgrd*isnw_T) then
966 0 : write(string,'(a,3i4)') subname//' snowtable size1 = ',isnw_rhos, isnw_Tgrd, isnw_T
967 0 : call icepack_warnings_add(string)
968 0 : write(string,'(a,3i4)') subname//' snowtable size2 = ',size(snowage_rhos),size(snowage_Tgrd),size(snowage_T)
969 0 : call icepack_warnings_add(string)
970 0 : write(string,'(a,3i9)') subname//' snowtable size3 = ',size(snowage_tau),size(snowage_kappa),size(snowage_drdt0)
971 0 : call icepack_warnings_add(string)
972 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
973 0 : call icepack_warnings_add(subname//'ERROR: arrays sizes error')
974 0 : return
975 : endif
976 11 : call snowtable_check_dimension(snowage_rhos, min_rhos, del_rhos, lin_rhos)
977 11 : if (icepack_warnings_aborted(subname)) return
978 11 : call snowtable_check_dimension(snowage_Tgrd, min_Tgrd, del_Tgrd, lin_Tgrd)
979 11 : if (icepack_warnings_aborted(subname)) return
980 11 : call snowtable_check_dimension(snowage_T , min_T , del_T , lin_T )
981 11 : if (icepack_warnings_aborted(subname)) return
982 : endif
983 :
984 : !-----------------------------------------------------------------
985 : ! Needed for variable snow density not currently modeled
986 : ! calculate density based on liquid and ice content of snow
987 : !-----------------------------------------------------------------
988 :
989 5183388 : drsnw_dry(:) = c0
990 5183388 : zTsn(:) = c0
991 5183388 : zdTdz(:) = c0
992 :
993 863898 : dzs = hsn/real(nslyr,kind=dbl_kind)
994 863898 : dzi = hin/real(nilyr,kind=dbl_kind)
995 863898 : dz = dzs + dzi
996 :
997 863898 : zTsn(1) = (Lfresh + zqsn(1)/rhos)/cp_ice
998 863898 : if (nslyr == 1) then
999 : zdTdz(1) = min(c10*isnw_Tgrd, &
1000 : !ech refactored abs((zTsn(1)*dzi+zTin1*dzs)/(dzs+dzi+puny) - Tsfc)/(hsn+puny))
1001 0 : abs(zTsn(1)*dzi + zTin1*dzs - Tsfc*dz)/(dz*hsn+puny))
1002 : else
1003 4319490 : do k = 2, nslyr
1004 3455592 : zTsn(k) = (Lfresh + zqsn(k)/rhos)/cp_ice
1005 3455592 : if (k == 2) then
1006 863898 : zdTdz(k-1) = abs((zTsn(k-1)+zTsn(k))*p5 - Tsfc)/(dzs+puny)
1007 : else
1008 2591694 : zdTdz(k-1) = abs (zTsn(k-2)-zTsn(k))*p5 /(dzs+puny)
1009 : endif
1010 4319490 : zdTdz(k-1) = min(c10*isnw_Tgrd,zdTdz(k-1))
1011 : enddo
1012 : !ech refactored zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs)/(dzs + dzi+puny) &
1013 : !ech refactored - (zTsn(nslyr) + zTsn(nslyr-1))*p5) / (dzs+puny)
1014 : zdTdz(nslyr) = abs((zTsn(nslyr)*dzi + zTin1*dzs) &
1015 863898 : - (zTsn(nslyr) + zTsn(nslyr-1))*p5*dz) / (dz*dzs+puny)
1016 863898 : zdTdz(nslyr) = min(c10*isnw_Tgrd, zdTdz(nslyr))
1017 : endif
1018 :
1019 5183388 : do k = 1, nslyr
1020 :
1021 : !-----------------------------------------------------------------
1022 : ! best-fit table indices:
1023 : ! Will abort if 1D data is not regularly spaced (lin_* flag must be true)
1024 : ! Leave option for doing a search into non regularly spaced 1D data in the future
1025 : ! via a binary search or similar.
1026 : !-----------------------------------------------------------------
1027 :
1028 4319490 : if (lin_rhos) then
1029 4319490 : rhos_idx = nint( (rhos - min_rhos) / del_rhos, kind=int_kind) + 1
1030 : else
1031 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
1032 0 : call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for rhos not supported yet')
1033 0 : return
1034 : endif
1035 :
1036 4319490 : if (lin_Tgrd) then
1037 4319490 : Tgrd_idx = nint( (zdTdz(k) - min_Tgrd) / del_Tgrd, kind=int_kind) + 1
1038 : else
1039 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
1040 0 : call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for Tgrd not supported yet')
1041 0 : return
1042 : endif
1043 :
1044 4319490 : if (lin_T) then
1045 4319490 : T_idx = nint(abs(zTsn(k)+ Tffresh - min_T ) / del_T , kind=int_kind) + 1
1046 : else
1047 0 : call icepack_warnings_setabort(.true.,__FILE__,__LINE__)
1048 0 : call icepack_warnings_add(subname//'ERROR: nonlinear lookup table for T not supported yet')
1049 0 : return
1050 : endif
1051 :
1052 : ! boundary check:
1053 4319490 : rhos_idx = min(isnw_rhos, max(1,rhos_idx))
1054 4319490 : Tgrd_idx = min(isnw_Tgrd, max(1,Tgrd_idx))
1055 4319490 : T_idx = min(isnw_T , max(1,T_idx ))
1056 :
1057 4319490 : bst_tau = snowage_tau (rhos_idx,Tgrd_idx,T_idx)
1058 4319490 : bst_kappa = snowage_kappa(rhos_idx,Tgrd_idx,T_idx)
1059 4319490 : bst_drdt0 = snowage_drdt0(rhos_idx,Tgrd_idx,T_idx)
1060 :
1061 : ! change in snow effective radius, using best-fit parameters
1062 4319490 : dr_fresh = max(c0,rsnw(k)-rsnw_fall)
1063 : drsnw_dry(k) = (bst_drdt0*(bst_tau/(dr_fresh+bst_tau))**(1/bst_kappa))&
1064 5183388 : * (dt/3600.0_dbl_kind)
1065 : enddo
1066 :
1067 863898 : first_call = .false.
1068 :
1069 : end subroutine snow_dry_metamorph
1070 :
1071 : !=======================================================================
1072 :
1073 : ! Snow grain metamorphism
1074 :
1075 4319490 : subroutine snow_wet_metamorph (dt, dr_wet, rsnw, smice, smliq)
1076 : !
1077 : ! Liquid water redistribution: Apply the grain growth function from:
1078 : ! Brun, E. (1989), Investigation of wet-snow metamorphism in respect of
1079 : ! liquid-water content, Annals of Glaciology, 13, 22-26.
1080 : ! There are two parameters that describe the grain growth rate as
1081 : ! a function of snow liquid water content (LWC). The "LWC=0" parameter
1082 : ! is zeroed here because we are accounting for dry snowing with a
1083 : ! different representation
1084 : !
1085 : real (kind=dbl_kind), intent(in) :: &
1086 : dt ! time step
1087 :
1088 : real (kind=dbl_kind), intent(in) :: &
1089 : rsnw , & ! snow grain radius (10^-6 m)
1090 : smice, & ! snow ice density (kg/m^3)
1091 : smliq ! snow liquid density (kg/m^3)
1092 :
1093 : real (kind=dbl_kind), intent(inout) :: &
1094 : dr_wet
1095 :
1096 : real (kind=dbl_kind) :: &
1097 : fliq ! liquid mass fraction
1098 :
1099 : character (len=*),parameter :: subname='(snow_wet_metamorph)'
1100 :
1101 4319490 : dr_wet = c0
1102 4319490 : fliq = c1
1103 4319490 : if (smice + smliq > c0 .and. rsnw > c0) then
1104 4319490 : fliq = min(smliq/(smice + smliq),p1)
1105 4319490 : dr_wet = S_wet * fliq**3*dt/(c4*pi*rsnw**2)
1106 : endif
1107 :
1108 4319490 : end subroutine snow_wet_metamorph
1109 :
1110 : !=======================================================================
1111 :
1112 : ! Analyze 1D array for regular spacing for snow table lookup
1113 : ! and set the min, del, and lin values.
1114 : ! Tolerance for regular spacing set at 1.0e-8 * typical array value
1115 :
1116 33 : subroutine snowtable_check_dimension(array, min_fld, del_fld, lin_fld)
1117 :
1118 : real (kind=dbl_kind), intent(in), dimension(:) :: &
1119 : array ! array to check
1120 :
1121 : real (kind=dbl_kind), intent(inout) :: &
1122 : min_fld, & ! min value if linear
1123 : del_fld ! delta value if linear
1124 :
1125 : logical (kind=log_kind), intent(inout) :: &
1126 : lin_fld ! linear flag
1127 :
1128 : ! local temporary variables
1129 :
1130 : integer (kind=int_kind) :: n, asize
1131 :
1132 : real (kind=dbl_kind) :: tolerance ! tolerance for linear checking
1133 :
1134 : character (len=*),parameter :: subname='(snowtable_check_dimension)'
1135 :
1136 33 : asize = size(array)
1137 :
1138 33 : if (asize == 1) then
1139 11 : min_fld = array(1)
1140 11 : del_fld = array(1) ! arbitrary
1141 11 : lin_fld = .true.
1142 : else
1143 22 : lin_fld = .true.
1144 22 : min_fld = array(1)
1145 22 : del_fld = array(2) - array(1)
1146 22 : tolerance = 1.0e-08_dbl_kind * max(abs(array(1)),abs(array(2))) ! relative to typical value
1147 88 : do n = 3,asize
1148 88 : if (abs(array(n) - array(n-1) - del_fld) > tolerance) lin_fld = .false.
1149 : enddo
1150 : endif
1151 :
1152 33 : end subroutine snowtable_check_dimension
1153 :
1154 : !=======================================================================
1155 :
1156 : ! Conversions between ice mass, liquid water mass in snow
1157 :
1158 1521120 : subroutine drain_snow (vsnon, aicen, &
1159 1521120 : massice, massliq, meltsliq)
1160 :
1161 : real (kind=dbl_kind), intent(in) :: &
1162 : vsnon, & ! snow volume (m)
1163 : aicen ! aice area fraction
1164 :
1165 : real (kind=dbl_kind), intent(inout) :: &
1166 : meltsliq ! total liquid content (kg/m^2)
1167 :
1168 : real (kind=dbl_kind), dimension(nslyr), intent(in) :: &
1169 : massice ! mass of ice in snow (kg/m^2)
1170 :
1171 : real (kind=dbl_kind), dimension(nslyr), intent(inout) :: &
1172 : massliq ! mass of liquid in snow (kg/m^2)
1173 :
1174 : ! local temporary variables
1175 :
1176 : integer (kind=int_kind) :: k
1177 :
1178 : real (kind=dbl_kind) :: &
1179 : hslyr, & ! snow layer thickness (m)
1180 : hsn, & ! snow thickness (m)
1181 : sliq ! snow liquid content (kg/m^2)
1182 :
1183 : real (kind=dbl_kind), dimension(nslyr) :: &
1184 3042240 : dlin , & ! liquid mass into the layer from above (kg/m^2)
1185 3042240 : dlout , & ! liquid mass out of the layer (kg/m^2)
1186 3042240 : phi_liq , & ! volumetric liquid fraction
1187 3042240 : phi_ice ! volumetric ice fraction
1188 :
1189 : character (len=*), parameter :: subname='(drain_snow)'
1190 :
1191 1521120 : hsn = c0
1192 1521120 : sliq = c0
1193 1521120 : if (aicen > c0) hsn = vsnon/aicen
1194 1521120 : if (hsn > puny) then
1195 5153766 : dlin (:) = c0
1196 5153766 : dlout(:) = c0
1197 858961 : hslyr = hsn / real(nslyr,kind=dbl_kind)
1198 5153766 : do k = 1, nslyr
1199 4294805 : massliq(k) = massliq(k) + dlin(k) ! add liquid in from layer above
1200 4294805 : phi_ice(k) = min(c1, massice(k) / (rhoi *hslyr))
1201 4294805 : phi_liq(k) = massliq(k) / (rhofresh*hslyr)
1202 4294805 : dlout(k) = max(c0, (phi_liq(k) - S_r*(c1-phi_ice(k))) * rhofresh * hslyr)
1203 4294805 : massliq(k) = massliq(k) - dlout(k)
1204 5153766 : if (k < nslyr) then
1205 3435844 : dlin(k+1) = dlout(k)
1206 : else
1207 858961 : sliq = dlout(nslyr) ! this (re)initializes meltsliq
1208 : endif
1209 : enddo
1210 : else
1211 662159 : sliq = meltsliq ! computed in thickness_changes
1212 : endif
1213 1521120 : if (use_smliq_pnd) meltsliq = sliq
1214 :
1215 1521120 : end subroutine drain_snow
1216 :
1217 : !=======================================================================
1218 :
1219 : end module icepack_snow
1220 :
1221 : !=======================================================================
|