-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathStieglitzSnow.F90
More file actions
2283 lines (1697 loc) · 84.3 KB
/
StieglitzSnow.F90
File metadata and controls
2283 lines (1697 loc) · 84.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
module StieglitzSnow
! This is a merge of Teppei's snow tracer code with the Heracles (H52) version
! reichle, 12 Aug 2014 - moved "*_calc_asnow()" to here from catchment.F90
! - renamed "get_tf_nd()" to "StieglitzSnow_calc_tpsnow()"
! - removed "relayer()" (obsolete)
! - renamed "N_sm" ("soil moisture") to "N_zones" (could be LandIce...)
! - cleaned up MAPL constants
! - additional minor clean-up
! reichle, 19 Nov 2015 - changed WEMIN back to 13 kg/m2
! (snow cover fraction better agrees w/ MODIS over land)
! Sarith, 4/21/2016 - WEMIN made public, sibalb uses it
! Justin, 4/16/2018 - moved WEMIN, AICEV, AICEN to SurfParams,
! removed LAND_UPD ifdef's
USE MAPL_ConstantsMod, ONLY: &
PIE => MAPL_PI, & ! -
ALHE => MAPL_ALHL, & ! J/kg @15C
ALHM => MAPL_ALHF, & ! J/kg
TF => MAPL_TICE, & ! K
RHOW => MAPL_RHOWTR ! kg/m^3
USE MAPL_BaseMod, ONLY: MAPL_LANDICE
USE SurfParams, ONLY: WEMIN, AICEV, AICEN
implicit none
public :: StieglitzSnow_snowrt ! used by LandIce, Catchment[CN]
public :: StieglitzSnow_trid ! used by LandIce
public :: StieglitzSnow_snow_albedo ! used by LandIce, Catchment[CN], LDAS
public :: StieglitzSnow_calc_asnow ! used by Catchment[CN], LDAS
public :: StieglitzSnow_calc_tpsnow ! used by Catchment[CN], LDAS
public :: StieglitzSnow_echo_constants ! used by LDAS
public :: StieglitzSnow_relayer ! used by LDAS, land-atm DAS
public :: StieglitzSnow_RHOMA ! used by LDAS, land-atm DAS
public :: StieglitzSnow_MINSWE ! used by LandIce
public :: StieglitzSnow_CPW ! used by LandIce
interface StieglitzSnow_calc_asnow
module procedure StieglitzSnow_calc_asnow_1
module procedure StieglitzSnow_calc_asnow_2
module procedure StieglitzSnow_calc_asnow_3
end interface StieglitzSnow_calc_asnow
interface StieglitzSnow_calc_tpsnow
module procedure StieglitzSnow_calc_tpsnow_scalar ! replicates original get_tf0d()
module procedure StieglitzSnow_calc_tpsnow_vector ! replicates original get_tf_nd()
end interface StieglitzSnow_calc_tpsnow
! constants specific to StieglitzSnow
real, parameter :: StieglitzSnow_RHOMA = 500. ! kg/m^3 maximum snow density
real, parameter :: StieglitzSnow_MINSWE = 0.013 ! kg/m^2 min SWE to avoid immediate melt
real, parameter :: StieglitzSnow_CPW = 2065.22 ! J/kg/K spec heat of ice near 0 deg C [cf. MAPL_CAPICE=2000. near -10 deg C]
real, private, parameter :: SNWALB_VISMIN = 0.5
real, private, parameter :: SNWALB_NIRMIN = 0.3
!================================ Added by Teppei Yasunari ==================================
!--------------------------------------------------------------------------------------------
! Teppei J. Yasunari produced this file, 23 May 2014
! Teppei, 23 May 2014 - Moved the constants from StieglitzSnow.F90 to here and revised comments.
! Teppei, 19 August 2014 - no longer considered goswim_constants.F90
! and put all the GOSWIM-related constants here
! Teppei, 27 August 2014 - if condition was revised for ALB_WITH_IMPURITY
! - ABVIS and ABNIR are not needed in the subroutine because spcified below
!
!--------------------------------------------------------------------------------------------
! snow albedo related constants
!--------------------------------------------------------------------------------------------
! See details in:
! Yasunari, T. J., K.-M. Lau, S. P. P. Mahanama, P. R. Colarco, A. M. da Silva,
! T. Aoki, K. Aoki, N. Murao, S. Yamagata, and Y. Kodama, 2014:
! GOddard SnoW Impurity Module (GOSWIM) for the NASA GEOS-5 Earth System Model:
! Preliminary comparisons with observations in Sapporo, Japan. SOLA, 10, 50-56,
! doi:10.2151/sola.2014-011.
! The URL of the paper: https://www.jstage.jst.go.jp/article/sola/10/0/10_2014-011/_article
!--------------------------------------------------------------------------------------------
! **************** IMPORTANT IMPORTANT IMPORTANT IMPORTANT ***********************
! Below number of constituents in each group must be consistent with the AERO_DP (expChem) bundle
! in GEOSchem_GridComp/GOCART_GridComp/GOCART_GridCompMod.F90
integer, parameter, public :: NUM_DUDP = 5, NUM_DUSV = 5, NUM_DUWT = 5, NUM_DUSD = 5
integer, parameter, public :: NUM_BCDP = 2, NUM_BCSV = 2, NUM_BCWT = 2, NUM_BCSD = 2
integer, parameter, public :: NUM_OCDP = 2, NUM_OCSV = 2, NUM_OCWT = 2, NUM_OCSD = 2
integer, parameter, public :: NUM_SUDP = 1, NUM_SUSV = 1, NUM_SUWT = 1, NUM_SUSD = 1
integer, parameter, public :: NUM_SSDP = 5, NUM_SSSV = 5, NUM_SSWT = 5, NUM_SSSD = 5
! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!
! Turn off GOSWIM by setting N_constit=0
!
integer, parameter, public :: N_constit = 0 ! number of constituents *used* below
integer, parameter, private :: N_constit_GOSWIM = 9 ! number of constituents in GOSWIM
!
! Previously, N_constit=9 was hardwired even though GOSWIM was never used.
! The GCM's rc parameter AEROSOL_DEPOSITION was set to 0, which forced
! the constituent mass and the deposition rates to remain zero, but the many
! do loops through the 9 constituents were still executed, thus multiplying and adding lots
! zeros many times.
!
! If needed, recover original behavior by setting N_constit=N_constit_GOSWIM=9
!
! - reichle, 31 Jan 2025
!
! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! (for riv, rin,aicev, aicen, and denice, instead use Teppei-defined
! values below)
!--------------------------------------------------------------------------------------------
! Spectrally integrated values for VIS and NIR using
! the updated ice refractive indices by Warren and Brandt, (JGR, 2008).
! were used.
! VIS: 300-690 nm; NIR: 690-3847 nm
real, private, parameter :: RIV=0.018, RIN=0.017
!--------------------------------------------------------------------------------------------
! So as to explain Abs. Co. for ice of 10 [m-1] by Kondo et al. (1988)
! the spectrally integrated Abs. Co. in VIS was used to get the one in NIR
! as a tuning parameter (see Yasunari et al., JGR, 2011).
real, private, parameter :: DENICE=917.
!--------------------------------------------------------------------------------------------
! Mass Absorption Coefficient or Mass Absorption Cross-section (MAC) [m2 g-1]
! Then the representative MACs for VIS & NIR was estimated from
! the GOCART/GEOS-5 optical properties.
! VIS: 300-690 nm; NIR: 690-3850 nm
! (Spectrally integrated with the standard surface radiation:
! ASTM G173-03 Tables; http://rredc.nrel.gov/solar/spectra/am1.5/)
! Updated on May 10, 2012
! ---------------------------------------------------------------------------
!
! constants for snow constituents (dust, carbon, etc.)
! MAC, visible (VIS)
real, private, parameter, dimension(N_constit_GOSWIM) :: ABVIS = (/ &
0.148, & ! Dust1
0.106, & ! Dust2
0.076, & ! Dust3
0.051, & ! Dust4
0.032, & ! Dust5
7.747, & ! Black carbon hydrophobic
11.227, & ! Black carbon hydrophilic
0.103, & ! Organic carbon hydrophobic
0.114 /) ! Organic carbon hydrophic
! MAC, near-infrared (NIR)
real, private, parameter, dimension(N_constit_GOSWIM) :: ABNIR = (/ &
0.095, & ! Dust1
0.080, & ! Dust2
0.062, & ! Dust3
0.043, & ! Dust4
0.029, & ! Dust5
4.621, & ! Black carbon hydrophobic
6.528, & ! Black carbon hydrophilic
0.092, & ! Organic carbon hydrophobic
0.127 /) ! Organic carbon hydrophic
!--------------------------------------------------------------------------------------------
! Scavenging coefficients for flushing effect in snow for constituents:
! Based on GOCART/GEOS-5 particle size;
! Tuning parameters so as to satisfy NCAR/CLM based scavenging efficiencies;
! See more in Yasunari et al. (SOLA, 2014)
real, private, parameter, dimension(N_constit_GOSWIM) :: SCAV = (/ &
0.065442, & ! Dust 1
0.077829, & ! Dust 2
0.306841, & ! Dust 3
0. , & ! Dust 4
0. , & ! Dust 5
0.074361, & ! Black carbon hydrophobic
0.502814, & ! Black carbon hydrophilic
0.075855, & ! Organic carbon hydrophobic
0.535225 /) ! Organic carbon hydrophic
! Representative particle size in diameter
! based on effective radius GOCART/GEOS-5 (dust 1-5 bins, BC, and OC) [um]
real, private, parameter, dimension(N_constit_GOSWIM) :: PSIZE = (/ &
1.272, & ! Dust 1
2.649, & ! Dust 2
4.602, & ! Dust 3
8.334, & ! Dust 4
15.341, & ! Dust 5
0.078, & ! Black carbon hydrophobic
0.148, & ! Black carbon hydrophilic
0.175, & ! Organic carbon hydrophobic
0.441 /) ! Organic carbon hydrophic
!============================================================================================
contains
subroutine StieglitzSnow_snowrt(tile_lon, tile_lat, & ! in [radians]
N_zones, N_snow, tileType, & ! in
maxsndepth, rhofs, targetthick, & ! in
t1, area, tkgnd, precip, snowf, ts, dts, eturb, dedtc, hsturb, dhsdtc, & ! in
hlwtc, dhlwtc, raddn, zc1, totdepos, & ! in
wesn, htsnn, sndz, rconstit, & ! inout
hlwout, fices, tpsn, rmelt, & ! out
areasc, areasc0, pre, fhgnd, evap, shflux, lhflux, hcorr, ghfluxsno, & ! out
sndzsc, wesnprec, sndzprec, sndz1perc, & ! out
wesnperc, wesndens, wesnrepar, mltwtr, & ! out
excs, drho0, wesnbot, tksno, dtss ) ! out
!*********************************************************************
! AUTHORS: M. Stieglitz, M. Suarez, R. Koster & S. Dery.
! VERSION: 2003b - This version last updated: 05/30/03.
!*********
! INPUTS:
!*********
! tile_lon : longitude of tile in [radians]
! tile_lat : latitude of tile in [radians]
! N_zones : number of zones in the horizontal dimension (eg, 3 for Catchment, 1 for LandIce)
! N_snow : number of snow layers
! N_constit : Number of constituent tracers in snow
! tileType : surface type of the tile
! t1 : Temperature of catchment zones [C]
! ts : Air temperature [K]
! area : Fraction of snow-free area in each catchment zone [0-1]
! precip : Precipitation (Rain+snowfall) [kg/m^2/s == mm/s]
! snowf : Snowfall per unit area of catchment [kg/m^2/s == mm/s]
! dts : Time step [s]
! eturb : Evaporation per unit area of snow [kg/m^2/s == mm/s]
! dedtc : d(eturb)/d(ts) [kg/m^2/s/K]
! hsturb : Sensible heat flux per unit area of snow [W/m^2]
! dhsdtc : d(hsturb)/d(ts) [W/m^2/K]
! hlwtc : Emitted IR per unit area of snow [W/m^2]
! dhlwtc : d(hlwtc)/d(ts) [W/m^2/K]
! raddn : Net solar + incident terrestrial per unit area of snow [W/m^2]
! tkgnd : Thermal diffusivity of soil in catchment zones [W/m/K]
! zc1 : Half-thickness (mid-point) of top soil layer [m]
!*** Bin Zhao added *************************************************
! maxsndepth : Maximum snow depth beyond which snow gets thrown away
! rhofs : fresh snow density
! targetthick : the target thickness distribution relayer redistribute mass
! and energy to; currently its value is surface type dependent
! for catchment, the 1st array element the target thickness
! the rest define a sigma distribution;
! for landice, it is an array with specified thicknesses
!*********
! UPDATES:
!*********
! wesn : Layer water contents per unit area of catchment [kg/m^2]
! htsnn : Layer heat contents relative to liquid water at 0 C [J/m^2]
! sndz : Layer depths [m]
! rconstit : Mass of constituents in snow layer [kg] (i.e., [kg m-2])
! rmelt : Flushed mass amount of constituents from the bottom snow layer [kg m-2 s-1 (kg/m^2/s)]
!*********
! OUTPUTS:
!*********
! tpsn : Layer temperatures [C]
! fices : Layer frozen fraction [0-1]
! areasc : Areal snow coverage at beginning of step [0-1]
! areasc0 : Areal snow coverage at end of step [0-1]
! pre : Liquid water outflow from snow base [kg/m^2/s]
! fhgnd : Heat flux at snow base at catchment zones [W/m^2]
! hlwout : Final emitted IR flux per unit area of snow [W/m^2]
! lhflux : Final latent heat flux per unit area of snow [W/m^2]
! shflux : Final sensible heat flux per unit area of snow [W/m^2]
! evap : Final evaporation per unit area of snow [kg/m^2/s]
!*** Bin Zhao added *************************************************
! sndzsc : top layer thickness change due to sublimation/condensation
! wesnprec : top layer water content change due to precip (different from precip itself)
! sndzprec : top layer thickness change due to precip
! sndz1perc : top layer thickness change due to percolation
! wesnperc : layer water content change due to percolation
! wesndens : layer water content change due to densification
! wesnrepar : layer water content change due to relayer
! mltwtr : total melt water production rate
! excs : frozen part of water content from densification excess
! drho0 : layer density change due to densification
! wesnbot : excessive water content due to thickness exceeding maximum depth
! tksno : layer conductivity
! dtss : top layer temperature change
!
!******************************************************************************
! NOTA: By convention, wesn is representative for a catchment area
! equal to 1 whereas sndz is relative to the area covered by snow only.
!******************************************************************************
implicit none
! real, parameter :: lhv = 2.4548E6 ! 2.5008e6 ! @ 0 C [J/kg]
! real, parameter :: lhs = 2.8368E6 ! 2.8434e6 ! @ 0 C [J/kg]
! real, parameter :: lhf = (lhs-lhv) ! @ 0 C [J/kg]
!rr real, parameter :: cpw_liquid = 4185. ! [J/kg/K]
! real, parameter :: tfrz = 273.16 ! @ 0 C [K]
! real, parameter :: rhofs = 150. ! [kg/m^3]
! real, parameter :: rhoma = 500. ! [kg/m^3]
! real, parameter :: rhow = 1000. ! [kg/m^3]
! real, parameter :: wemin = 13. ! [kg/m^2]
real, parameter :: snfr = 0.01 ! holding capacity
real, parameter :: small = 1.e-6 ! small number
real, intent(in) :: tile_lon, tile_lat
integer, intent(in) :: N_zones, N_snow, tileType
real, dimension(N_zones), intent(in) :: t1, area, tkgnd
real, dimension(N_constit), intent(in) :: totdepos
real, intent(in) :: ts, precip, snowf, dts, dedtc, raddn, hlwtc
real, intent(in ) :: dhsdtc, dhlwtc, eturb, hsturb, zc1
real, dimension(N_snow), intent(inout) :: wesn, htsnn, sndz
real, dimension(N_snow, N_constit), intent(inout) :: rconstit
real, dimension(N_snow), intent(out) :: tpsn, fices
real, dimension(N_zones), intent(out) :: fhgnd
real, intent(out) :: hlwout, lhflux, shflux, areasc0, evap, areasc, pre
real, intent(out) :: hcorr
real, dimension(N_constit), intent(out) :: rmelt
real, intent(out) :: ghfluxsno
real, intent(out) :: wesnprec
real, intent(out) :: sndzsc, sndzprec
real, intent(out) :: sndz1perc
real, dimension(N_snow), intent(out) :: wesnperc
real, dimension(N_snow), intent(out) :: wesndens
real, dimension(N_snow), intent(out) :: wesnrepar
real, intent(out) :: mltwtr
real, dimension(N_snow), intent(out) :: excs
real, dimension(N_snow), intent(out) :: drho0
real, intent(out) :: wesnbot
real, dimension(N_snow), intent(out) :: tksno
real, intent(out) :: dtss
real, intent(in) :: maxsndepth
real, intent(in) :: rhofs
real, dimension(N_snow), intent(in) :: targetthick
! ----------------------------------------
!
! Locals
real :: tsx, mass,snowd,rainf,denom,alhv,lhturb,dlhdtc, &
enew,eold,tdum,fnew,tnew,icedens,densfac,hnew,scale,t1ave, &
flxnet,fdum,dw,waterin,waterout,snowin,snowout, mtwt, &
waterbal,precision,flow,term,dz,w(0:N_snow),HTSPRIME, &
wlossfrac
real :: excsdz, excswe, sndzsum, mtwt0
real, dimension(size(wesn) ) :: cmpc,dens
real, dimension(size(wesn) ) :: tksn
real, dimension(size(wesn) ) :: dtc,q,cl,cd,cr
real, dimension(size(wesn)+1) :: fhsn,df
real, dimension(size(wesn) ) :: htest,ttest,ftest
! by Teppei --- GOSWIM related variables
!============================================================================================
real, dimension(size(wesn) ) :: denblk ! bulk snow density
real, dimension(size(wesn) ) :: po ! snow porosity
!============================================================================================
logical, dimension(size(wesn) ) :: ice1, tzero
real, dimension(size(wesn) ) :: dens0
real, dimension(N_constit) :: flow_r,rconc
integer :: i,izone,k
logical :: logdum
integer :: rc_tmp
! --------------------------------------------------------------
snowd = sum(wesn)
snowin = snowd
ghfluxsno = 0.
!rr correction for "cold" snow
tsx = min(ts-tf,0.)*StieglitzSnow_CPW
!rr correction for heat content of rain
!rr tsx_rain = max(ts-tf,0.)*cpw_liquid
df = 0.
dtc = 0.
tpsn = 0.
fices = 0.
areasc = 0.
areasc0= 0.
pre = 0.
fhgnd = 0.
hlwout = 0.
shflux = 0.
lhflux = 0.
evap = 0.
excs = 0.
hcorr = 0.
dens = rhofs
rainf = precip - snowf ! [kg/m^2/s]
sndzsc = 0.
wesnprec = 0.
sndzprec = 0.
sndz1perc = 0.
wesnperc = 0.
wesndens = 0.
wesnrepar = 0.
wesnbot = 0.
dtss = 0.
excswe = 0.
if (N_constit>0) rmelt = 0.0
mltwtr = 0.0
drho0 = 0.0
tksno = 0.0
if(snowd <= StieglitzSnow_MINSWE) then ! initial snow mass is negligible
! Melt off initial (very small) snowpack; new snow pack is based
! on new snowfall only (if any)
call StieglitzSnow_calc_asnow( snowd, areasc )
areasc0 = 0.
pre = snowd/dts + areasc*rainf ! pre = melted snowpack plus rainfall
wesn = 0.
hcorr = hcorr + raddn*areasc + sum(htsnn)/dts
htsnn = 0.
sndz = 0.
mltwtr = snowd/dts ! mltwtr = melted snowpack
do k=1,N_constit
rmelt(k)=sum(rconstit(:,k))/dts
enddo
if (N_constit>0) rconstit(:,:) = 0.
if(snowf > 0.) then ! only initialize with non-liquid part of precip
! liquid precip (rainf) is part of outflow from snow base (see "pre" above)
wesn = snowf*dts/float(N_snow)
htsnn = (tsx-alhm)*wesn
call StieglitzSnow_calc_asnow( snowf*dts, areasc0 )
!*** should have fractional snow cover taken into account
sndz = wesn/(max(areasc0,small)*rhofs)
hcorr = hcorr - tsx*snowf ! randy
! Add constituent to top snow layer, in area covered by snow.
do k=1,N_constit
rconstit(1,k)=rconstit(1,k)+areasc0*totdepos(k)*dts
enddo
! call relayer *without* heat content adjustment [incl. call to StieglitzSnow_calc_tpsnow()]
call StieglitzSnow_relayer( N_snow, N_constit, tileType, targetthick, &
htsnn, wesn, sndz, rconstit, tpsn, fices, &
conserve_ice10_tzero=.false., rc_calc_tpsn=rc_tmp ) ! optional args
if (rc_tmp/=0) write (*,*) 'PosSnowHeat: values printed above detected at lon, lat = ', tile_lon*180./PIE, tile_lat*180./PIE
endif ! (snowf > 0.)
return ! if there was no snow at start of time step
endif ! (snowd <= StieglitzSnow_MINSWE)
! ---------------------------------------------------------------
!
! derive new snow pack from existing snow pack and new snowfall:
!**** Determine the fractional snow coverage
call StieglitzSnow_calc_asnow( snowd, areasc )
!**** Set the mean density & diffusivity of the layers
do i=1,N_snow
if(sndz(i) > 0) dens(i) = max(wesn(i)/(areasc*sndz(i)),rhofs)
enddo
tksn = 3.2217e-06*dens**2
tksno = tksn
dens0 = dens
!**** Determine temperature & frozen fraction of snow layers
call StieglitzSnow_calc_tpsnow(N_snow, htsnn, wesn, tpsn, fices, ignore_pos_tpsnow=.true.)
mtwt = sum(wesn*(1.-fices))
!**** Calculate the ground-snow energy flux at 3 zones
denom = 1./(sndz(N_snow)*0.5-zc1)
fhgnd = -sqrt(tkgnd*tksn(N_snow))*area*denom*(tpsn(N_snow)-t1)
fhsn(N_snow+1) = sum(fhgnd)
do i=1,N_zones
df(N_snow+1)=df(N_snow+1)-sqrt(tkgnd(i)*tksn(N_snow))*area(i)*denom
enddo
!**** Ensure against excessive heat flux between ground and snow:
!**** if heat flux found to cause the lowest snow layer temperature
!**** to "overshoot" (e.g. to become higher than the ground temperature
!**** when it had been lower), reduce the heat flux. If the lowest
!**** snow layer starts off at zero and the new temperature is greater
!**** than zero, reduce the heat flux to melt only half of the lowest
!**** layer snow.
t1ave=sum(t1*area)/sum(area)
htest=htsnn
htest(N_snow)=htest(N_snow)+fhsn(N_snow+1)*dts*areasc
! tpsnow may be positive in the following call; set optional flag accordingly
call StieglitzSnow_calc_tpsnow(N_snow, htest, wesn, ttest, ftest, ignore_pos_tpsnow=.true.)
scale=1.
if((t1ave-tpsn(N_snow))*(t1ave-ttest(N_snow)) .lt. 0.) then
scale=0.5*(tpsn(N_snow)-t1ave)/(tpsn(N_snow)-ttest(N_snow))
endif
if(tpsn(N_snow) .eq. 0. .and. ttest(N_snow) .gt. 0. .and. &
abs(fhsn(N_snow+1)) .gt. 1.e-10) then
scale=(-0.5*htsnn(N_snow)/(dts*areasc))/fhsn(N_snow+1)
endif
fhsn(N_snow+1)=fhsn(N_snow+1)*scale
df(N_snow+1)=df(N_snow+1)*scale
fhgnd=fhgnd*scale
!**** Calculate heat fluxes between snow layers.
do i=2,N_snow
df(i) = -sqrt(tksn(i-1)*tksn(i))/((sndz(i-1)+sndz(i))*0.5)
fhsn(i)= df(i)*(tpsn(i-1)-tpsn(i))
enddo
ghfluxsno = fhsn(2)
!**** Effective heat of vaporization includes bringing snow to 0 C
alhv = alhe + alhm ! randy
!**** Initial estimate of latent heat flux change with Tc
lhturb = alhv*eturb
dlhdtc = alhv*dedtc
!**** Initial estimate of net surface flux & its change with Tc
fhsn(1) = lhturb + hsturb + hlwtc - raddn
df(1) = -(dlhdtc + dhsdtc + dhlwtc)
!**** Prepare array elements for solution & coefficient matrices.
!**** Terms are as follows: left (cl), central (cd) & right (cr)
!**** diagonal terms in coefficient matrix & solution (q) terms.
do i=1,N_snow
call StieglitzSnow_calc_tpsnow(htsnn(i),wesn(i),tdum,fdum, ice1(i),tzero(i), .true., ignore_pos_tpsnow=.true.)
if(ice1(i)) then
cl(i) = df(i)
cd(i) = StieglitzSnow_CPW*wesn(i)/dts - df(i) - df(i+1)
cr(i) = df(i+1)
q(i) = fhsn(i+1)-fhsn(i)
else
cl(i) = 0.
cd(i) = 1.
cr(i) = 0.
q(i) = 0.
endif
enddo
cl(1) = 0.
cr(N_snow) = 0.
do i=1,N_snow-1
if(.not.ice1(i)) cl(i+1) = 0.
enddo
do i=2,N_snow
if(.not.ice1(i)) cr(i-1) = 0.
enddo
!**** Solve the tri-diagonal matrix for implicit change in Tc.
call STIEGLITZSNOW_TRID(dtc,cl,cd,cr,q,N_snow)
!**** Check temperature changes for passages across critical points,i.e.
!**** If implicit change has taken layer past melting/freezing, correct.
do i=1,N_snow
if(tpsn(i)+dtc(i) > 0. .or. htsnn(i)+wesn(i)*StieglitzSnow_CPW*dtc(i) > 0.) then
dtc(i)=-tpsn(i)
endif
if(.not.ice1(i)) dtc(i)=0.
enddo
!**** Further adjustments; compute new values of h associated with
!**** all adjustments.
eold=sum(htsnn)
do i=1,N_snow
if (.not.tzero(i) .and. .not.ice1(i)) then
!**** "Impossible" condition:
write(*,*) 'bad snow condition: fice,tpsn =',fices(i),tpsn(i)
stop
else if (.not.tzero(i)) then
!**** Condition 1: layer starts fully frozen (temp < 0.)
tnew=tpsn(i)+dtc(i)
fnew=1.
else if (.not.ice1(i)) then
!**** Condition 2: layer starts with temp = 0, fices < 1.
! Corrections for flxnet calculation: Koster, March 18, 2003.
tnew=0.
if(i==1) flxnet= fhsn(i+1)+df(i+1)*(dtc(i)-dtc(i+1)) &
-fhsn(i)-df(i)*dtc(i)
if(i > 1 .and. i < N_snow) flxnet= &
fhsn(i+1)+df(i+1)*(dtc(i)-dtc(i+1)) &
-fhsn(i)-df(i)*(dtc(i-1)-dtc(i))
if(i==N_snow) flxnet=fhsn(i+1)+df(i+1)*dtc(i) &
-fhsn(i)-df(i)*(dtc(i-1)-dtc(i))
HTSPRIME=HTSNN(I)+AREASC*FLXNET*DTS
call StieglitzSnow_calc_tpsnow( HTSPRIME, wesn(i), tdum, fnew, logdum, logdum, .true., ignore_pos_tpsnow=.true.)
fnew=amax1(0., amin1(1., fnew))
else ! (ice1(i) .and. tzero(i))
!**** Condition 3: layer starts with temp = 0, fices = 1.
! Corrections for flxnet calculation: Koster, March 18, 2003.
if(dtc(i) < 0.) then
tnew=tpsn(i)+dtc(i)
fnew=1.
endif
if(dtc(i) >= 0.) then
tnew=0.
if(i==1) flxnet=fhsn(i+1)+df(i+1)*(dtc(i)-dtc(i+1)) &
-fhsn(i)-df(i)*dtc(i)
if(i > 1 .and. i < N_snow) flxnet= &
fhsn(i+1)+df(i+1)*(dtc(i)-dtc(i+1)) &
-fhsn(i)-df(i)*(dtc(i-1)-dtc(i))
if(i==N_snow) flxnet=fhsn(i+1)+df(i+1)*dtc(i) &
-fhsn(i)-df(i)*(dtc(i-1)-dtc(i))
HTSPRIME=HTSNN(I)+AREASC*FLXNET*DTS
call StieglitzSnow_calc_tpsnow( HTSPRIME, wesn(i), tdum, fnew, logdum, logdum, .true., ignore_pos_tpsnow=.true.)
fnew=amax1(0., amin1(1., fnew))
endif
endif
!**** Now update heat fluxes & compute sublimation or deposition.
!**** Note: constituents (dust, etc.) do not evaporate.
if(i == 1) then
dtss = dtc(1)
lhflux = lhturb + dlhdtc*dtc(1)
shflux = hsturb + dhsdtc*dtc(1)
hlwout = hlwtc + dhlwtc*dtc(1)
evap = lhflux/alhv
dw = -evap*dts*areasc
if(-dw > wesn(1) ) then
dw = -wesn(1)
evap = -dw/(dts*areasc)
!hcorr=hcorr+(lhflux-evap*alhv)*areasc ! removed, was double-counting corr, see "Store excess heat in hcorr" below; koster+reichle, 31 May 2024
lhflux=evap*alhv
endif
wesn(1) = wesn(1) + dw
denom = 1./dens(1)
if(dw > 0.) denom = 1./StieglitzSnow_RHOMA
sndz(1) = sndz(1) + dw*denom
sndzsc = dw*denom
endif
if(i == N_snow) then
do izone=1,N_zones
fhgnd(izone)=fhgnd(izone)+area(izone)*df(N_snow+1)*dtc(N_snow)
enddo
endif
!**** Now update thermodynamic quantities.
htsnn(i)=(StieglitzSnow_CPW*tnew-fnew*alhm)*wesn(i)
tpsn(i) = tnew
fices(i)= fnew
enddo ! (i=1,N_snow)
! -----------------------------------------------------------------------------
!
!**** Store excess heat in hcorr.
enew=sum(htsnn)
hcorr=hcorr-((enew-eold)/dts+areasc*(lhflux+shflux+hlwout-raddn) &
-areasc*(fhsn(N_snow+1)+df(N_snow+1)*dtc(N_snow)) &
)
call StieglitzSnow_calc_tpsnow(N_snow, htsnn, wesn, tpsn, fices, ignore_pos_tpsnow=.true.)
mltwtr = max(0., sum(wesn*(1.-fices)) - mtwt)
mltwtr = mltwtr / dts
mtwt0 = sum(wesn*fices)
!rr!**** Add rainwater and snow at ts., bal. budget with shflux.
!rr (tried and failed 19 Jun 2003, reichle)
!rr
!rr wesn (1) = wesn (1) + (rainf*areasc+snowf)*dts
!rr htsnn(1) = htsnn(1) + (tsx -alhm)*(snowf*dts) + tsx_rain*rainf*dts
!rr sndz (1) = sndz (1) + (snowf/rhofs)*dts
!rr ! shflux = shflux + tsx*snowf ! randy
!rr hcorr = hcorr - (tsx-alhm)*snowf - tsx_rain*rainf ! randy
!**** Add rainwater at 0 C, snow at ts., bal. budget with shflux.
wesn (1) = wesn (1) + (rainf*areasc+snowf)*dts
htsnn(1) = htsnn(1) + (tsx -alhm)*(snowf*dts)
sndz (1) = sndz (1) + (snowf/rhofs)*dts
wesnprec = (rainf*areasc+snowf)*dts
sndzprec = (snowf/rhofs)*dts
hcorr = hcorr - tsx*snowf ! randy
snowd=sum(wesn)
call StieglitzSnow_calc_tpsnow(N_snow, htsnn, wesn, tpsn, fices, ignore_pos_tpsnow=.true.)
!**** Constituent deposition: Add to top snow layer, in area covered by snow.
do k=1,N_constit
rconstit(1,k)=rconstit(1,k)+areasc*totdepos(k)*dts
enddo
!**** Move meltwater through the pack.
!**** Updated by Koster, August 27, 2002.
pre = 0.
if (N_constit>0) rmelt(:) = 0.
flow = 0.
if (N_constit>0) flow_r(:) = 0.
wesnperc = wesn
do i=1,N_snow
if(flow > 0.) then
wesn (i) = wesn(i) + flow ! add "flow" [kg/m2] from layer i-1 to wesn(i)
do k=1,N_constit
rconstit(i,k)=rconstit(i,k)+flow_r(k)
enddo
call StieglitzSnow_calc_tpsnow(N_snow, htsnn, wesn, tpsn, fices, ignore_pos_tpsnow=.true.)
endif
pre = max((1.-fices(i))*wesn(i), 0.)
flow = 0.
if (N_constit>0) then
flow_r(:) = 0.
rconc(:) = 0.
end if
if(snowd > wemin) then
icedens = wesn(i)*fices(i)/(sndz(i)+1.e-20)
densfac = amax1(0., amin1(1., icedens/rhofs))
term = densfac*snfr*(sndz(i)*rhow-wesn(i)*fices(i))
if(pre > term) then
pre = min(pre - term, wesn(i)) ! when asnow=1, retain some liquid water in snow pack
do k=1,N_constit
rconc(k)=rconstit(i,k)/wesn(i)
enddo
wesn(i) = wesn(i) - pre
flow = pre
endif
else
do k=1,N_constit
rconc(k)=rconstit(i,k)/wesn(i)
enddo
wesn(i) = wesn(i) - pre ! when asnow<1, remove all liquid water from snow pack
flow = pre
endif
!------------------------------- by Teppei ---------------------------------------
if(areasc.ge.0.999) then
do k=1,N_constit
! mass loss by excess water
! To calculate bulk snow density in snow layers
denblk(i)=( wesn(i)/(areasc+1.e-20) )/(sndz(i)+1.e-20)
! porosity of snow layers
po(i)=-7.2E-07*(denblk(i)**2.0)-(0.00063*denblk(i))+0.967073
if(denblk(i) > 800.) po(i)=0.
! constituents flushing
flow_r(k)=(po(i)*(1.0-(min(PSIZE(k),5.0)/5.0))*SCAV(k)) &
*(rconc(k)+1.0e-20)*flow
if ( (flow < 1.0e-20).or.(denblk(i) > 800.) ) flow_r(k)=0.
rconstit(i,k)=rconstit(i,k)-flow_r(k)
rconstit(i,k)=amax1(0.,rconstit(i,k)) ! guard against truncation error
enddo
endif
if(areasc.lt.0.999) then
do k=1,N_constit
flow_r(k)=rconc(k)*flow
rconstit(i,k)=rconstit(i,k)-flow_r(k)
rconstit(i,k)=amax1(0.,rconstit(i,k)) ! guard against truncation error
enddo
endif
!---------------------------------------------------------------------------------
!**** Adjust top layer snow depth to get proper density values
!**** But limit this change for large throughflow (STEPH 06/19/03)
if (i==1) then
dz=min(flow/dens(i),0.5*sndz(i))
sndz(i)=sndz(i)-dz
sndz1perc = -dz
endif
enddo ! (i=1,N_snow)
! ----------------------------------------------------------------------------------------
wesnperc = wesn - wesnperc
pre = flow/dts ! convert outflow to flux units [kg/m2/s]
do k=1,N_constit
rmelt(k)=rmelt(k)+flow_r(k)/dts
enddo
snowd=sum(wesn)
!**** Update snow density by compaction (Pitman et al. 1991)
mass = 0.
w = 0.
wesndens = wesn
if(snowd > wemin) then ! Compaction only after full coverage.
do i=1,N_snow
dens(i) = rhofs
if(sndz(i)>0.) dens(i) = max(wesn(i)/(sndz(i)),rhofs)
enddo
drho0 = dens
cmpc = exp(14.643 - (4000./min(tpsn+tf,tf))-.02*dens)
do i=1,N_snow
w(i) = wesn(i)
mass = mass + 0.5*(w(i)+w(i-1))
dens(i) = dens(i)*(1. + (dts*0.5e-7*9.81)*mass*cmpc(i))
!**** Clip densities below maximum value, adjust quantities accordingly
!**** while conserving heat & mass (STEPH 06/21/03).
if(dens(i) > StieglitzSnow_RHOMA) then
!! if (tileType==MAPL_LANDICE) then ! restrict SWE adjustment to LANDICE tiles
! excs = SWE in excess of max density given fixed snow depth
excs(i) = (dens(i)-StieglitzSnow_RHOMA)*sndz(i) ! solid + liquid
wlossfrac=excs(i)/wesn(i)
wesn(i) = wesn(i) - excs(i) ! remove EXCS from SWE
do k=1,N_constit
rmelt(k)=rmelt(k)+rconstit(i,k)*wlossfrac/dts
rconstit(i,k)=rconstit(i,k)*(1.-wlossfrac)
rconstit(i,k)=amax1(0.,rconstit(i,k)) ! guard against truncation error
enddo
hnew = (StieglitzSnow_CPW*tpsn(i)-fices(i)*alhm)*wesn(i) ! adjust heat content accordingly
hcorr= hcorr+(htsnn(i)-hnew)/dts ! add excess heat content into residual accounting term
htsnn(i)= hnew
!! end if
dens(i) = StieglitzSnow_RHOMA
endif
enddo
drho0 = dens - drho0
endif
wesndens = wesn - wesndens
!! if (tileType==MAPL_LANDICE) then ! finish SWE adjustment for LANDICE tiles
pre = pre + sum(excs*max(1.-fices,0.0))/dts
excs = excs * fices / dts
!! end if
snowd=sum(wesn)
call StieglitzSnow_calc_asnow( snowd, areasc0 )
areasc0 = max(small, areasc0 )
sndz = (wesn/areasc0)/dens
sndzsum = sum(sndz)
if(sndzsum > maxsndepth) then
excsdz = sndzsum - maxsndepth
excswe = dens(N_snow) * excsdz
wlossfrac=excswe/wesn(N_snow)
wesn(N_snow) = wesn(N_snow) - excswe
do k=1,N_constit
rmelt(k)=rmelt(k)+rconstit(N_snow,k)*wlossfrac/dts
rconstit(N_snow,k)=rconstit(N_snow,k)*(1.-wlossfrac)
rconstit(N_snow,k)=amax1(0.,rconstit(N_snow,k)) ! guard against truncation error
enddo
hnew = (StieglitzSnow_CPW*tpsn(N_snow)-fices(N_snow)*alhm)*wesn(N_snow)
htsnn(N_snow)= hnew
sndz(N_snow) = sndz(N_snow) - excsdz
wesnbot = excswe
endif
!**** Restore layers to sigma values.
wesnrepar = wesn
! call relayer *with* adjustment of heat content and hcorr accounting [incl. call to StieglitzSnow_calc_tpsnow()]
call StieglitzSnow_relayer( N_snow, N_constit, tileType, targetthick, &
htsnn, wesn, sndz, rconstit, tpsn, fices, &
conserve_ice10_tzero=.true., dts=dts, hcorr=hcorr, rc_calc_tpsn=rc_tmp ) ! optional arguments
if (rc_tmp/=0) write (*,*) 'PosSnowHeat: values printed above detected at lon, lat = ', tile_lon*180./PIE, tile_lat*180./PIE
wesnrepar = wesn - wesnrepar
!**** Reset fractional area coverage.
call StieglitzSnow_calc_asnow( sum(wesn), areasc0 )
!**** Final check for water balance.
waterin = (rainf*areasc+snowf)*dts + max(dw,0.)
waterout = pre*dts - min(dw,0.)
snowout = sum(wesn) + sum(excs) + excswe
waterbal = snowin + waterin - waterout - snowout
precision = snowout*small
#if 0
if((waterbal > precision).and.(waterbal > small) .or. pre < -1.e-13 ) then
write(*,*) 'Warning: Imbalance in snow water budget!', waterbal
write(*,*) 'waterin = ', waterin
write(*,*) 'snowin = ', snowin
write(*,*) 'waterout = ', waterout
write(*,*) 'snowout = ', snowout
write(*,*) 'dw = ', dw
write(*,*) 'excswe = ', excswe
write(*,*) 'sum(excs) = ', sum(excs)
write(*,*) 'snowf*dts = ', snowf*dts
write(*,*) 'sum(wesn) = ', sum(wesn)
write(*,*) (wesn(i), i=1,N_snow)
write(*,*) 'sum(sndz) = ', sum(sndz)
write(*,*) (sndz(i), i=1,N_snow)
write(*,*) 'dens0 = '
write(*,*) (dens0(i), i=1,N_snow)
!write(*,*) 'sum(wesn0) = ', sum(wesn0)
!write(*,*) (wesn0(i), i=1,N_snow)
write(*,*) 'sum(wesn1) = ', sum(wesn1)
write(*,*) (wesn1(i), i=1,N_snow)