! source file: /Users/csomes/Research/Models/UVic_ESCM/2.9/updates/02/source/ice/therm.F subroutine therm (is, ie, js, je) !======================================================================= ! thermodynamic ice model ! Note: if run with embm this routine must be called after "fluxes" ! and before "solve" ! calculates ice and open water growth rates based on the surface ! energy budget. see Parkinson and Washington, JGR, Vol.84, C1, ! 311-337, 1979 and Hibler, JPO, Vol.9, 815-846, 1979 ! heat and fresh water fluxes between the ocean and atmosphere ! are adjusted depending on ice growth or melt. ice thickness is ! changed by the amount of growth or melt and sublimation !======================================================================= implicit none integer i, ie, iem1, imax, index, iter, is, isp1, j, je, jem1 integer jmax, js, jsp1, maxit real ai, aice3, al, amin, ao, as, as_agric, ca, delta, df, dh real dha, dhflxi, dhflxs, dhi, hice3, dho, dhs, hsno3, dhss real dhstot, dhtot, dswr, dt, dultnt, dulwr, dusens, emax, f, fa real fas, fb, fbot, fcond, fd, fds, fe, ff, ffs, fh, fl, fls, fm real fn, fptf, fpts, ftopi, ftopo, ho, hsextra, qair,qice, sla real sub, tair, tcdh, ti, tiold, tol, tol2, ultnt, ulwr, usens real wspd, zintfc, C2K include "size.h" include "param.h" include "pconst.h" include "stdunits.h" include "csbc.h" include "cembm.h" include "atm.h" include "ice.h" include "coord.h" include "grdvar.h" include "veg.h" include "mtlm.h" isp1 = is + 1 iem1 = ie - 1 jsp1 = js + 1 jem1 = je - 1 fa = dts/(rhoice*flice) fb = 0.94*rhoatm*cpatm fd = rhoatm/rhoice fe = rhoatm*slice ff = rhoice*flice fh = 21.8746*265.5 fas = dts/(rhosno*flice) fds = rhoatm/rhosno ffs = rhosno*flice ho = 1.0 amin = 0.15 maxit = 10 tol = 0.01 emax = 0.0 imax = 0 jmax = 0 fptf = 0.0 index = 1 sla = zw(1)*secday/dampice/2.389e-8 tol2 = tol*2.0 C2K = 273.15 do j=jsp1,jem1 do i=isp1,iem1 hsno3 = hsno(i,j,index) hice3 = hice(i,j,index) aice3 = 0 !----------------------------------------------------------------------- ! set the incoming shortwave over snow and ice !----------------------------------------------------------------------- ! if snow is less than 25 cm linearly reduce to ice albedo as = min(hsno(i,j,2)*0.04/(aice(i,j,2) + epsln), c1) ca = ice_calb*(c1 - as) + sno_calb*as dswr = solins(i,j)*sbc(i,j,iaca)*pass*ca wspd = sbc(i,j,iws) aice(i,j,index) = min(c1, aice(i,j,index)) ai = aice(i,j,2) if (tmsk(i,j) .lt. 0.5 .and. land_map(i,j) .eq. 0) then !----------------------------------------------------------------------- ! land points !----------------------------------------------------------------------- tair = at(i,j,2,isat) - elev(i,j)*rlapse & - hicel(i,j,2)*rlapse aice3 = 0.0 ! snow masking distance for different vegetation types as = hsno(i,j,2)/(100.0*veg_smd(iveg(i,j))) as_agric = hsno(i,j,2)/(100.0*veg_smd(iagric)) as_agric = min(c1, max(c0, as_agric)) as = (1.-agric(i,j,2))*as + agric(i,j,2)*as_agric ! limit snow coverage between 0 and 1 aice3 = min(c1, max(c0, as)) aice3 = max(aice3, aicel(i,j,2)) !----------------------------------------------------------------------- ! start loop for grid points with snow or ice !----------------------------------------------------------------------- if (ai .gt. c0) then !----------------------------------------------------------------------- ! find snow temperature by balancing the surface heat budget ! dwsr = ultnt + usens + ulwr ! using Newton's method: ! t(i+1) = t(i) - f(t(i))/df(t(i)) ! where: ! f(t(i)) = dwsr - ultnt - usens - ulwr ! -df(t(i)) = dultnt - dusens - dulwr !----------------------------------------------------------------------- al = 1.0 - ai ti = tice(i,j) tiold = tice(i,j) fm = esatm*(tair + C2K)**4 fls = fe*dalt_i*wspd dusens = fb*dalt_i*wspd qair = rh(i,j)*cssh*exp(17.67*tair/(tair + 243.5)) iter = 0 delta = tol2 do while (abs(delta) .gt. tol .and. iter .le. maxit) iter = iter + 1 dt = ti - tair qice = cssh*exp(21.8746*ti/(ti + 265.5)) if (qice .gt. qair) then ultnt = fls*(qice - qair) dultnt = fls*qice*21.8746*265.5/(ti + 265.5)**2 else ultnt = 0.0 dultnt = 0.0 endif usens = dusens*dt ulwr = esice*(ti + C2K)**4 - fm dulwr = 4.0*esice*(ti + C2K)**3 f = dswr - ultnt - usens - ulwr df = dultnt + dusens + dulwr delta = f/df ti = ti + delta enddo if (iter .gt. maxit) then ! if not converged, set to last converged temperature if (abs(delta) .gt. emax .and. ti .lt. fptf) then emax = abs(delta) imax = i jmax = j ti = tiold endif endif !----------------------------------------------------------------------- ! set maximum tice to freezing and calculate fluxes !----------------------------------------------------------------------- ti = min(ti, fptf) dt = ti - tair qice = cssh*exp(21.8746*ti/(ti + 265.5)) sub = max(c0, fds*dalt_i*wspd*(qice - qair)) usens = dusens*dt ulwr = esice*(ti + C2K)**4 - fm ! ensure that snow sublimated does not exceed hsno dha = -dts*sub*ai if (-dha .gt. hsno3) then dha = -hsno3 sub = -dha/(ai*dts) endif ultnt = rhosno*slice*sub sub = sub*rhosno ftopi = dswr - ulwr - usens - ultnt !----------------------------------------------------------------------- ! add ice/snow covered area fluxes to land fluxes !----------------------------------------------------------------------- tice(i,j) = ti evap(i,j) = evap(i,j)*al + sub*ai dnswr(i,j) = dnswr(i,j)*al + dswr*ai upltnt(i,j) = upltnt(i,j)*al + ultnt*ai upsens(i,j) = upsens(i,j)*al + usens*ai uplwr(i,j) = uplwr(i,j)*al + ulwr*ai !----------------------------------------------------------------------- ! calculate total change in snow volume on land ! allocate snowmelt to flux for input to bucket !----------------------------------------------------------------------- dhs = 0.0 dhtot = 0.0 if (tice(i,j) .ge. fptf .and. ftopi .gt. 0.0) & dhs = -ai*fas*ftopi dhs = min(0.0, max(-(hsno3 + dha), dhs)) dhtot = dhs + dha hsno3 = hsno3 + dhtot flux(i,j,ishum) = flux(i,j,ishum) + dhs*rhosno/dts ! ensure fluxes are balanced since land can't absorb error upsens(i,j) = dnswr(i,j) - upltnt(i,j) - uplwr(i,j) & + dhs*ffs/dts !----------------------------------------------------------------------- ! if no snow on land !----------------------------------------------------------------------- else tice(i,j) = 0.0 endif elseif (tmsk(i,j) .ge. 0.5) then !----------------------------------------------------------------------- ! ocean points !----------------------------------------------------------------------- ao = 1.0 - ai tair = at(i,j,2,isat) !----------------------------------------------------------------------- ! calculate fluxes to and from the ocean (without ice) !----------------------------------------------------------------------- ftopo = dnswr(i,j) - uplwr(i,j) - upsens(i,j) - upltnt(i,j) fbot = sla*(frzpt(i,j) - sbc(i,j,isst)) ! calculate growth of ice in open water areas dho = fa*(fbot - ftopo) if (ai .ne. 0.0) then !----------------------------------------------------------------------- ! find ice temperature by balancing the surface heat budget: ! tcdh*(ti - fpts) = dswr - ultnt - usens - ulwr ! using Newton's method: ! t(i+1) = t(i) - f(t(i))/df(t(i)) ! where: ! f(t(i)) = dswr - ultnt - usens - ulwr - tcdh*(ti - fpts) ! -df(t(i)) = dultnt + dusens + dulwr + tcdh !----------------------------------------------------------------------- tcdh = condice/(hice(i,j,2) + 6.5*hsno(i,j,2)) ti = tice(i,j) tiold = tice(i,j) fpts = frzpt(i,j) fm = esatm*(tair + C2K)**4 fn = 4.0*esice fl = fe*dalt_i*wspd dusens = fb*dalt_i*wspd qair = at(i,j,2,ishum) iter = 0 delta = tol2 do while (abs(delta) .gt. tol .and. iter .le. maxit) iter = iter + 1 dt = ti - tair qice = cssh*exp(21.8746*ti/(ti + 265.5)) if (qice .gt. qair) then ultnt = fl*(qice - qair) dultnt = fl*qice*fh/(ti + 265.5)**2 else ultnt = 0.0 dultnt = 0.0 endif usens = dusens*dt ulwr = esice*(ti + C2K)**4 - fm dulwr = fn*(ti + C2K)**3 f = dswr - ultnt - usens - ulwr - tcdh*(ti - fpts) df = dultnt + dusens + dulwr + tcdh delta = f/df ti = ti + delta enddo if (iter .gt. maxit) then ! if not converged, set to last converged temperature if (abs(delta) .gt. emax .and. ti .lt. fptf) then emax = abs(delta) imax = i jmax = j ti = tiold endif endif !----------------------------------------------------------------------- ! set maximum tice to freezing and calculate fluxes !----------------------------------------------------------------------- ti = min(ti, fptf) dt = ti - tair qice = cssh*exp(21.8746*ti/(ti + 265.5)) sub = max(c0, dalt_i*wspd*(qice - qair)) ultnt = fe*sub fcond = tcdh*(ti - fpts) if (hsno(i,j,index) .gt. 0.0) then sub = fds*sub dha = -dts*sub sub = sub*ai*rhosno else sub = fd*sub dha = -dts*sub sub = sub*ai*rhoice endif usens = dusens*dt ulwr = esice*(ti + C2K)**4 - fm !----------------------------------------------------------------------- ! add ice covered area fluxes to ocean area fluxes !----------------------------------------------------------------------- tice(i,j) = ti dnswr(i,j) = dnswr(i,j)*ao + dswr*ai upltnt(i,j) = upltnt(i,j)*ao + ultnt*ai upsens(i,j) = upsens(i,j)*ao + usens*ai uplwr(i,j) = uplwr(i,j)*ao + ulwr*ai ftopi = dswr - ulwr - usens - ultnt !----------------------------------------------------------------------- ! calculate change in ice volume due to sublimation of ! ice (dha). adjust evaporation to the atmosphere to ! account for sublimation from ice. subtract this ! adjustment from the ocean freshwater flux !----------------------------------------------------------------------- if (addflxa) flux(i,j,ishum) = flux(i,j,ishum) + dts*sub evap(i,j) = evap(i,j)*ao + sub else tice(i,j) = sbc(i,j,isst) ftopi = 0.0 fcond = 0.0 dha = 0.0 endif !----------------------------------------------------------------------- ! calculate total change in ice volume (dh) !----------------------------------------------------------------------- dha = dha*ai dhflxs = 0.0 dhs = 0.0 if (hsno(i,j,index) .le. 0.0) then ! total growth of ice from the ocean dhi = ai*fa*(fbot - ftopi) + ao*dho ! total growth (loss + sublimation limited to total amount) dh = max(-hice(i,j,index), dhi + dha) ! adjust ocean fluxes for ice growth or melt + sublimation dhflxi = dh - dha else ! total growth of ice from the ocean dhi = ai*fa*(fbot - fcond) + ao*dho ! loss of snow due to melt if (tice(i,j) .ge. fptf) dhs = ai*fas*(fcond - ftopi) ! total loss of snow including sublimation dhs = dhs + dha ! check if snow loss greater than total if (-dhs .gt. hsno(i,j,index)) then ! take extra melt from ice dhi = dhi + rhosno/rhoice*(dhs + hsno(i,j,index)) ! remove all snow dhs = -hsno(i,j,index) endif ! adjust ocean fluxes for snow melt and sublimation dhflxs = dhs - dha ! ice loss limited to total dh = max(-hice(i,j,index), dhi) ! adjust ocean fluxes for ice growth or melt dhflxi = dh endif !----------------------------------------------------------------------- ! calculate new area and thickness from thermodynamics !----------------------------------------------------------------------- ! use minimum area (amin) of open water ai = max(amin, aice(i,j,index)) aice3 = aice(i,j,index) + ((1.0 - ai)*max(c0, dho)/ho & + 0.5*min(c0, dhi)*ai/(hice(i,j,index) + epsln)) ! update ice and snow thickness hice3 = hice(i,j,index) + dh hsno3 = hsno(i,j,index) + dhs ! lower ice area where thickness is < 1 cm aice3 = min(aice3, hice3) ! max ice area where thickness is > 10 m aice3 = max(aice3, hice3*0.001) aice3 = max(c0, min(c1, aice3)) if (aice3 .eq. 0.0) then dhflxs = dhflxs - hsno3 hsno3 = 0.0 endif ! check if the weight of the snow pushes the ice/snow ! interface below the waterline (if so, change snow to ice) zintfc = hice3 - (rhosno*hsno3 + rhoice*hice3)/rhoocn if (zintfc .lt. 0.0) then dhss = rhoice/rhosno*zintfc if (-dhss .gt. hsno3) then write(*,*) '==> Warning: dhss is too large: ',dhss dhss = -hsno3 endif hice3 = hice3 - rhosno/rhoice*dhss hsno3 = hsno3 + dhss endif hsno3 = max(hsno3, c0) !----------------------------------------------------------------------- ! adjust fluxes to the ocean due to ice melt or growth !----------------------------------------------------------------------- if (addflxa) then flux(i,j,isat) = flux(i,j,isat) + ff*dhflxi + ffs*dhflxs flux(i,j,ishum) = flux(i,j,ishum) - rhoice*dhflxi & - rhosno*dhflxs endif endif !----------------------------------------------------------------------- ! shuffle time levels !----------------------------------------------------------------------- hice(i,j,1) = hice(i,j,2) hice(i,j,2) = hice3 aice(i,j,1) = aice(i,j,2) aice(i,j,2) = aice3 hsno(i,j,1) = hsno(i,j,2) hsno(i,j,2) = hsno3 enddo enddo if (emax .gt. 0.0) write (stdout,*) & '==> Warning: ice temperature not converging: emax, i, j:' &, emax, imax, jmax !----------------------------------------------------------------------- ! set boundary conditions !----------------------------------------------------------------------- call embmbc (hice(1,1,2)) call embmbc (aice(1,1,2)) call embmbc (hsno(1,1,2)) return end