[19554] | 1 | /*!\file GEMB module from Alex Gardner.
|
---|
| 2 | * \brief: calculates SMB
|
---|
| 3 | */
|
---|
| 4 |
|
---|
| 5 | #include "./SurfaceMassBalancex.h"
|
---|
| 6 | #include "../../shared/shared.h"
|
---|
| 7 | #include "../../toolkits/toolkits.h"
|
---|
[24686] | 8 | #include "../modules.h"
|
---|
[25836] | 9 | #include "../../classes/Inputs/TransientInput.h"
|
---|
[19554] | 10 |
|
---|
[19582] | 11 | const double Pi = 3.141592653589793;
|
---|
[22758] | 12 | const double CtoK = 273.15; // Kelvin to Celcius conversion/ice melt. point T in K
|
---|
| 13 | const double dts = 86400.0; // Number of seconds in a day
|
---|
[19554] | 14 |
|
---|
[22758] | 15 | /* Tolerances have to be defined for if loops involving some specific values
|
---|
| 16 | like densitiy of ice or melting point temp because values are "rounded"
|
---|
| 17 | (e.g rho ice = 909.99... instead of 910.0) and we don't always go into the right loop */
|
---|
| 18 | const double Ttol = 1e-10;
|
---|
| 19 | const double Dtol = 1e-11;
|
---|
| 20 | const double Gdntol = 1e-10;
|
---|
| 21 | const double Wtol = 1e-13;
|
---|
[24313] | 22 | const double Ptol = 1e-6;
|
---|
[22758] | 23 |
|
---|
| 24 | const double CI = 2102.0; // heat capacity of snow/ice (J kg-1 k-1)
|
---|
[27232] | 25 | const double LF = 0.3345e6; // latent heat of fusion (J kg-1)
|
---|
| 26 | const double LV = 2.495e6; // latent heat of vaporization (J kg-1)
|
---|
| 27 | const double LS = 2.8295e6; // latent heat of sublimation (J kg-1)
|
---|
| 28 | const double SB = 5.67e-8; // Stefan-Boltzmann constant (W m-2 K-4)
|
---|
[23189] | 29 | const double CA = 1005.0; // heat capacity of air (J kg-1 K-1)
|
---|
| 30 | const double R = 8.314; // gas constant (J mol-1 K-1)
|
---|
[22758] | 31 |
|
---|
[24313] | 32 | const double Delflag=-99999;
|
---|
| 33 |
|
---|
[19554] | 34 | void Gembx(FemModel* femmodel){ /*{{{*/
|
---|
| 35 |
|
---|
[24686] | 36 | int count=0;
|
---|
[25836] | 37 | IssmDouble time,dt,finaltime;
|
---|
[24686] | 38 | IssmDouble timeclim=0.0;
|
---|
| 39 | IssmDouble t,smb_dt;
|
---|
| 40 | IssmDouble delta;
|
---|
[25836] | 41 | bool linear_interp=true;
|
---|
[24686] | 42 |
|
---|
[26744] | 43 | femmodel->parameters->FindParam(&linear_interp,TimesteppingInterpForcingEnum); /*is interpolation requested*/
|
---|
[24686] | 44 | femmodel->parameters->FindParam(&time,TimeEnum); /*transient core time at which we run the smb core*/
|
---|
| 45 | femmodel->parameters->FindParam(&dt,TimesteppingTimeStepEnum); /*transient core time step*/
|
---|
| 46 | femmodel->parameters->FindParam(&finaltime,TimesteppingFinalTimeEnum);
|
---|
| 47 | femmodel->parameters->FindParam(&smb_dt,SmbDtEnum); /*time period for the smb solution, usually smaller than the glaciological dt*/
|
---|
| 48 |
|
---|
| 49 | //before starting loop, realize that the transient core runs this smb_core at time = time +deltaT.
|
---|
| 50 | //go back to time - deltaT:
|
---|
| 51 | time-=dt;
|
---|
| 52 |
|
---|
| 53 | IssmDouble timeinputs = time;
|
---|
| 54 |
|
---|
| 55 | /*Start loop: */
|
---|
| 56 | count=1;
|
---|
[25836] | 57 | for (t=time;t<=time+dt-smb_dt;t=t+smb_dt){
|
---|
[24686] | 58 |
|
---|
[25836] | 59 | for(Object* & object : femmodel->elements->objects){
|
---|
| 60 | Element* element=xDynamicCast<Element*>(object);
|
---|
[24686] | 61 |
|
---|
| 62 | timeclim=time;
|
---|
[25836] | 63 | if (linear_interp) timeinputs = t-time+timeclim;
|
---|
| 64 | else timeinputs = t-time+timeclim+smb_dt/2;
|
---|
[24686] | 65 | element->SmbGemb(timeinputs,count);
|
---|
| 66 | }
|
---|
| 67 | count=count+1;
|
---|
[19554] | 68 | }
|
---|
| 69 |
|
---|
| 70 | } /*}}}*/
|
---|
| 71 | void GembgridInitialize(IssmDouble** pdz, int* psize, IssmDouble zTop, IssmDouble dzTop, IssmDouble zMax, IssmDouble zY){ /*{{{*/
|
---|
| 72 |
|
---|
| 73 | /* This file sets up the initial grid spacing and total grid depth. The
|
---|
| 74 | grid structure is set as constant grid length 'dzTop' for the top
|
---|
| 75 | 'zTop' meters of the model grid. Bellow 'zTop' the gid length increases
|
---|
| 76 | linearly with depth */
|
---|
| 77 |
|
---|
| 78 | /*intermediary:*/
|
---|
[22758] | 79 | IssmDouble dgpTop=0.0;
|
---|
| 80 | int gpTop=0;
|
---|
| 81 | int gpBottom=0;
|
---|
| 82 | int i=0;
|
---|
| 83 | IssmDouble gp0=0.0;
|
---|
| 84 | IssmDouble z0=0.0;
|
---|
[19554] | 85 | IssmDouble* dzT=NULL;
|
---|
| 86 | IssmDouble* dzB=NULL;
|
---|
| 87 |
|
---|
| 88 | /*output: */
|
---|
| 89 | IssmDouble* dz=NULL;
|
---|
| 90 |
|
---|
| 91 | //----------------------Calculate Grid Lengths------------------------------
|
---|
| 92 | //calculate number of top grid points
|
---|
| 93 | dgpTop = zTop/dzTop;
|
---|
| 94 |
|
---|
| 95 | //check to see if the top grid cell structure length (dzTop) goes evenly
|
---|
| 96 | //into specified top structure depth (zTop). Also make sure top grid cell
|
---|
| 97 | //structure length (dzTop) is greater than 5 cm
|
---|
[23394] | 98 | #ifndef _HAVE_AD_ //avoid the round operation check!
|
---|
[19613] | 99 | if (dgpTop != round(dgpTop)){
|
---|
[25836] | 100 | _error_("top grid cell structure length does not go evenly into specified top structure depth, adjust dzTop or zTop\n");
|
---|
[19554] | 101 | }
|
---|
[19613] | 102 | #endif
|
---|
| 103 | if(dzTop < 0.05){
|
---|
[25836] | 104 | _printf_("initial top grid cell length (dzTop) is < 0.05 m\n");
|
---|
[19554] | 105 | }
|
---|
[19613] | 106 | gpTop=reCast<int,IssmDouble>(dgpTop);
|
---|
[19554] | 107 |
|
---|
| 108 | //initialize top grid depth vector
|
---|
| 109 | dzT = xNew<IssmDouble>(gpTop);
|
---|
| 110 | for (i=0;i<gpTop;i++)dzT[i]=dzTop;
|
---|
| 111 |
|
---|
| 112 | //bottom grid cell depth = x*zY^(cells from to structure)
|
---|
| 113 | //figure out the number of grid points in the bottom vector (not known a priori)
|
---|
| 114 | gp0 = dzTop;
|
---|
| 115 | z0 = zTop;
|
---|
| 116 | gpBottom = 0;
|
---|
| 117 | while (zMax > z0){
|
---|
| 118 | gp0= gp0 * zY;
|
---|
| 119 | z0 = z0 + gp0;
|
---|
| 120 | gpBottom++;
|
---|
| 121 | }
|
---|
[21341] | 122 | //initialize bottom vectors
|
---|
[19554] | 123 | dzB = xNewZeroInit<IssmDouble>(gpBottom);
|
---|
| 124 | gp0 = dzTop;
|
---|
| 125 | z0 = zTop;
|
---|
| 126 | for(i=0;i<gpBottom;i++){
|
---|
| 127 | gp0=gp0*zY;
|
---|
| 128 | dzB[i]=gp0;
|
---|
| 129 | }
|
---|
| 130 |
|
---|
| 131 | //combine top and bottom dz vectors
|
---|
| 132 | dz = xNew<IssmDouble>(gpTop+gpBottom);
|
---|
| 133 | for(i=0;i<gpTop;i++){
|
---|
| 134 | dz[i]=dzT[i];
|
---|
| 135 | }
|
---|
| 136 | for(i=0;i<gpBottom;i++){
|
---|
| 137 | dz[gpTop+i]=dzB[i];
|
---|
| 138 | }
|
---|
| 139 |
|
---|
[24686] | 140 | /*Free resouces:*/
|
---|
[19554] | 141 | xDelete(dzT);
|
---|
| 142 | xDelete(dzB);
|
---|
[23189] | 143 |
|
---|
[19554] | 144 | //---------NEED TO IMPLEMENT A PROPER GRID STRECHING ALGORITHM------------
|
---|
| 145 |
|
---|
| 146 | /*assign ouput pointers: */
|
---|
| 147 | *pdz=dz;
|
---|
| 148 | *psize=gpTop+gpBottom;
|
---|
| 149 | } /*}}}*/
|
---|
| 150 | IssmDouble Marbouty(IssmDouble T, IssmDouble d, IssmDouble dT){ /*{{{*/
|
---|
| 151 |
|
---|
| 152 | // calculates grain growth according to Fig. 9 of Marbouty, 1980
|
---|
[21341] | 153 | // ------NO GRAIN GROWTH FOR d > 400 kg m-3 because H is set to zero------
|
---|
[19554] | 154 | // ---------------this is a major limitation of the model-------------------
|
---|
| 155 |
|
---|
| 156 | // initialize
|
---|
[22758] | 157 | IssmDouble F = 0.0, H=0.0, G=0.0;
|
---|
[19582] | 158 | const IssmDouble E = 0.09; //[mm d-1] model time growth constant E
|
---|
[24313] | 159 | // convert T from K to degC
|
---|
[22758] | 160 | T = T - CtoK;
|
---|
[27232] | 161 | // convert dT from degC/m to degC/cm
|
---|
| 162 | dT = dT/100;
|
---|
[19554] | 163 |
|
---|
| 164 | // temperature coefficient F
|
---|
[24313] | 165 | if(T> -6.0+Ttol) F = 0.7 + ((T/-6.0) * 0.3);
|
---|
| 166 | if(T<= -6.0+Ttol && T> -22.0+Ttol) F = 1.0 - ((T+6.0)/-16.0 * 0.8);
|
---|
| 167 | if(T<= -22.0+Ttol && T> -40.0+Ttol) F = 0.2 - ((T+22.0)/-18.0 * 0.2);
|
---|
[19554] | 168 |
|
---|
| 169 | // density coefficient F
|
---|
[24313] | 170 | if(d< 150.0-Dtol) H=1.0;
|
---|
[19554] | 171 |
|
---|
[24313] | 172 | if(d>= 150.0-Dtol && d <400.0-Dtol) H = 1.0 - ((d-150.0)/250.0);
|
---|
[19554] | 173 |
|
---|
| 174 | // temperature gradient coefficient G
|
---|
[24313] | 175 | if(dT >= 0.16-Ttol && dT < 0.25-Ttol) G = ((dT - 0.16)/0.09) * 0.1;
|
---|
| 176 | if(dT >= 0.25-Ttol && dT < 0.4-Ttol) G = 0.1 + (((dT - 0.25)/0.15) * 0.57);
|
---|
| 177 | if(dT >= 0.4-Ttol && dT < 0.5-Ttol) G = 0.67 + (((dT - 0.4)/0.1) * 0.23);
|
---|
| 178 | if(dT >= 0.5-Ttol && dT < 0.7-Ttol) G = 0.9 + (((dT - 0.5)/0.2) * 0.1);
|
---|
| 179 | if(dT >= 0.7-Ttol) G = 1.0;
|
---|
[19554] | 180 |
|
---|
| 181 | // grouped coefficient Q
|
---|
| 182 | return F*H*G*E;
|
---|
| 183 |
|
---|
| 184 | } /*}}}*/
|
---|
[26744] | 185 | IssmDouble gardnerAlb(IssmDouble* re, IssmDouble* dz, IssmDouble* d, IssmDouble clabSnow, IssmDouble clabIce, IssmDouble SZA, IssmDouble COT, IssmDouble dPHC, int m){ /*{{{*/
|
---|
| 186 | //gardnerAlb(S1, c1, SZA, t, z1, S2, c2)
|
---|
| 187 | //This is an implementation of the snow and ice broadband albedo
|
---|
| 188 | // parameterization developed by Alex Gardner.
|
---|
| 189 | //Created By: Alex S. Gardner, Jet Propulsion Laboratory [alex.s.gardner@jpl.nasa.gov]
|
---|
| 190 | // Last Modified: June, 2014
|
---|
| 191 | //Full Reference: Gardner, A. S., and Sharp, M. J.: A review of snow and
|
---|
| 192 | // ice albedo and the development of a new physically based broadband albedo
|
---|
| 193 | // parameterization, J. Geophys. Res., 115, F01009, 10.1029/2009jf001444,
|
---|
| 194 | // 2010.
|
---|
| 195 |
|
---|
| 196 | //INPUTS
|
---|
| 197 | // ONE LAYER
|
---|
| 198 | // - S1 : specific surface area of the snow or ice [cm^2 g-1]
|
---|
| 199 | // - c1 : concentration of light absorbing carbon [ppm1]
|
---|
| 200 | // - SZA : solar zenith angle of the incident radiation [deg]
|
---|
| 201 | // - t : cloud optical thickness
|
---|
| 202 | // TWO LAYER
|
---|
| 203 | // - z1 : depth of snow suface layer [mm w.e.]
|
---|
| 204 | // - S2 : specific surface area of bottom ice layer [cm^2 g-1]
|
---|
| 205 | // - c2 : concentration of light absorbing carbon of bottom ice
|
---|
| 206 | // layer [ppm1]
|
---|
| 207 | IssmDouble c1=clabSnow;
|
---|
| 208 | IssmDouble c2=clabIce;
|
---|
| 209 | IssmDouble t=COT;
|
---|
| 210 | IssmDouble a=0.0;
|
---|
| 211 |
|
---|
| 212 | //Single layer albedo parameterization
|
---|
| 213 | //convert effective radius to specific surface area [cm2 g-1]
|
---|
| 214 | IssmDouble S1 = 3.0 / (0.091 * re[0]);
|
---|
| 215 |
|
---|
| 216 | //effective solar zenith angle
|
---|
| 217 | IssmDouble x = min(pow(t/(3*cos(Pi*SZA/180.0)),0.5), 1.0);
|
---|
| 218 | IssmDouble u = 0.64*x + (1-x)*cos(Pi*SZA/180.0);
|
---|
| 219 |
|
---|
| 220 | // pure snow albedo
|
---|
| 221 | IssmDouble as = 1.48 - pow(S1,-0.07);
|
---|
| 222 |
|
---|
| 223 | //change in pure snow albedo due to soot loading
|
---|
| 224 | IssmDouble dac = max(0.04 - as, pow(-c1,0.55)/(0.16 + 0.6*pow(S1,0.5) + (1.8*pow(c1,0.6))*pow(S1,-0.25)));
|
---|
| 225 |
|
---|
| 226 | //Two layer albedo parameterization
|
---|
| 227 | // do two layer calculation if there is more than 1 layer
|
---|
| 228 | IssmDouble z1=0.0;
|
---|
| 229 | int lice=0;
|
---|
| 230 | for(int l=0;(l<m & d[l]<dPHC-Dtol);l++){
|
---|
| 231 | z1=z1+dz[l]*d[l]; //mm
|
---|
| 232 | lice=l+1;
|
---|
| 233 | }
|
---|
| 234 | if (m>0 & lice<m & z1 > Dtol){
|
---|
| 235 | // determine albedo values for bottom layer
|
---|
| 236 | IssmDouble S2 = 3.0 / (0.091 * re[lice]);
|
---|
| 237 |
|
---|
| 238 | // pure snow albedo
|
---|
| 239 | IssmDouble as2 = 1.48 - pow(S2,-0.07);
|
---|
| 240 |
|
---|
| 241 | // change in pure snow albedo due to soot loading
|
---|
| 242 | IssmDouble dac2 = max(0.04 - as2, pow(-c2,0.55)/(0.16 + 0.6*pow(S1,0.5) + (1.8*pow(c2,0.6))*pow(S2,-0.25)));
|
---|
| 243 |
|
---|
| 244 | // determine the effective change due to finite depth and soot loading
|
---|
| 245 | IssmDouble A = min(1.0, (2.1 * pow(z1,1.35*(1-as) - 0.1*c1 - 0.13)));
|
---|
| 246 |
|
---|
| 247 | dac = (as2 + dac2 - as) + A*((as + dac) - (as2 + dac2));
|
---|
| 248 | }
|
---|
| 249 |
|
---|
| 250 | // change in albedo due to solar zenith angle
|
---|
| 251 | IssmDouble dasz = 0.53*as*(1 - (as + dac))*pow(1 - u,1.2);
|
---|
| 252 |
|
---|
| 253 | // change in albedo due to cloud (apart from change in diffuse fraction)
|
---|
| 254 | IssmDouble dat = (0.1*t*pow(as + dac,1.3)) / (pow(1 + 1.5*t,as));
|
---|
| 255 |
|
---|
| 256 | // Broadband albedo
|
---|
| 257 | a = as + dac + dasz + dat;
|
---|
| 258 |
|
---|
| 259 | return a;
|
---|
| 260 | } /*}}}*/
|
---|
[22758] | 261 | void grainGrowth(IssmDouble** pre, IssmDouble** pgdn, IssmDouble** pgsp, IssmDouble* T,IssmDouble* dz,IssmDouble* d, IssmDouble* W,IssmDouble smb_dt,int m,int aIdx,int sid){ /*{{{*/
|
---|
[19554] | 262 |
|
---|
| 263 | /*Created by: Alex S. Gardner, University of Alberta
|
---|
| 264 |
|
---|
| 265 | *Description*: models the effective snow grain size
|
---|
| 266 |
|
---|
| 267 | *Reference:*
|
---|
| 268 | DENDRITIC SNOW METAMORPHISM:
|
---|
| 269 | Brun, E., P. David, M. Sudul, and G. Brunot, 1992: A numerical model to
|
---|
| 270 | simulate snow-cover stratigraphy for operational avalanche forecasting.
|
---|
| 271 | Journal of Glaciology, 38, 13-22.
|
---|
| 272 |
|
---|
| 273 | NONDENDRITIC SNOW METAMORPHISM:
|
---|
| 274 | Dry snow metamorphism:
|
---|
| 275 | Marbouty, D., 1980: An experimental study of temperature-gradient
|
---|
| 276 | metamorphism. Journal of Glaciology, 26, 303-312.
|
---|
| 277 |
|
---|
| 278 | WET SNOW METAMORPHISM:
|
---|
| 279 | Brun, E., 1989: Investigation on wet-snow metamorphism in respect of
|
---|
| 280 | liquid-water content. Annals of Glaciology, 13, 22-26.
|
---|
| 281 |
|
---|
| 282 | INPUTS
|
---|
[27232] | 283 | * T: grid cell temperature [K]
|
---|
[19554] | 284 | * dz: grid cell depth [m]
|
---|
| 285 | * d: grid cell density [kg m-3]
|
---|
| 286 | * W: water content [kg/m^2]
|
---|
| 287 | * re: effective grain size [mm]
|
---|
| 288 | * gdn: grain dentricity
|
---|
| 289 | * gsp: grain sphericity
|
---|
| 290 | * dt: time step of input data [s]
|
---|
| 291 |
|
---|
| 292 | OUTPUTS
|
---|
| 293 | * re: effective grain size [mm]
|
---|
| 294 | * gdn: grain dentricity
|
---|
| 295 | * gsp: grain sphericity*/
|
---|
| 296 |
|
---|
| 297 | /*intermediary: */
|
---|
[22758] | 298 | IssmDouble dt=0.0;
|
---|
[27232] | 299 | IssmDouble Ti=0.0;
|
---|
[19554] | 300 | IssmDouble* gsz=NULL;
|
---|
| 301 | IssmDouble* dT=NULL;
|
---|
| 302 | IssmDouble* zGPC=NULL;
|
---|
| 303 | IssmDouble* lwc=NULL;
|
---|
[22758] | 304 | IssmDouble Q=0.0;
|
---|
[19554] | 305 |
|
---|
[22758] | 306 | /*output: */
|
---|
| 307 | IssmDouble* re=NULL;
|
---|
| 308 | IssmDouble* gdn=NULL;
|
---|
| 309 | IssmDouble* gsp=NULL;
|
---|
| 310 |
|
---|
[19566] | 311 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0)_printf0_(" grain growth module\n");
|
---|
[22758] | 312 |
|
---|
| 313 | /*Recover pointers: */
|
---|
| 314 | re=*pre;
|
---|
| 315 | gdn=*pgdn;
|
---|
| 316 | gsp=*pgsp;
|
---|
[23189] | 317 |
|
---|
[19554] | 318 | /*only when aIdx = 1 or 2 do we run grainGrowth: */
|
---|
[24313] | 319 | if(aIdx!=1 && aIdx!=2){
|
---|
[19554] | 320 | /*come out as we came in: */
|
---|
| 321 | return;
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 | /*Figure out grain size from effective grain radius: */
|
---|
[19582] | 325 | gsz=xNew<IssmDouble>(m); for(int i=0;i<m;i++)gsz[i]=re[i]*2.0;
|
---|
[19554] | 326 |
|
---|
| 327 | /*Convert dt from seconds to day: */
|
---|
[22758] | 328 | dt=smb_dt/dts;
|
---|
[19554] | 329 |
|
---|
| 330 | /*Determine liquid-water content in percentage: */
|
---|
| 331 | lwc=xNew<IssmDouble>(m); for(int i=0;i<m;i++)lwc[i]= W[i] / (d[i]*dz[i])*100.0;
|
---|
| 332 |
|
---|
| 333 | //set maximum water content by mass to 9 percent (Brun, 1980)
|
---|
[24313] | 334 | for(int i=0;i<m;i++)if(lwc[i]>9.0+Wtol) lwc[i]=9.0;
|
---|
[19554] | 335 |
|
---|
| 336 | /* Calculate temperature gradiant across grid cells
|
---|
[27232] | 337 | * Returns the average gradient across the upper and lower grid cell */
|
---|
[19554] | 338 |
|
---|
| 339 | //initialize
|
---|
| 340 | dT=xNewZeroInit<IssmDouble>(m);
|
---|
| 341 |
|
---|
| 342 | //depth of grid point center from surface
|
---|
| 343 | zGPC=xNewZeroInit<IssmDouble>(m);
|
---|
| 344 | for(int i=0;i<m;i++){
|
---|
| 345 | for (int j=0;j<=i;j++) zGPC[i]+=dz[j];
|
---|
[22758] | 346 | zGPC[i]-=(dz[i]/2.0);
|
---|
[19554] | 347 | }
|
---|
| 348 |
|
---|
| 349 | // Take forward differences on left and right edges
|
---|
[27232] | 350 | if(m>2){
|
---|
| 351 | dT[0] = (T[2] - T[0])/(zGPC[2]-zGPC[0]);
|
---|
| 352 | dT[m-1] = (T[m-1] - T[m-3])/(zGPC[m-1]-zGPC[m-3]);
|
---|
| 353 | }
|
---|
| 354 | else if(m>1){
|
---|
[25836] | 355 | dT[0] = (T[1] - T[0])/(zGPC[1]-zGPC[0]);
|
---|
| 356 | dT[m-1] = (T[m-1] - T[m-2])/(zGPC[m-1]-zGPC[m-2]);
|
---|
| 357 | }
|
---|
[19554] | 358 |
|
---|
| 359 | //Take centered differences on interior points
|
---|
| 360 | for(int i=1;i<m-1;i++) dT[i] = (T[i+1]-T[i-1])/(zGPC[i+1]-zGPC[i-1]);
|
---|
| 361 |
|
---|
| 362 | // take absolute value of temperature gradient
|
---|
[19613] | 363 | for(int i=0;i<m;i++)dT[i]=fabs(dT[i]);
|
---|
[23189] | 364 |
|
---|
[19554] | 365 | /*Snow metamorphism. Depends on value of snow dendricity and wetness of the snowpack: */
|
---|
| 366 | for(int i=0;i<m;i++){
|
---|
[27232] | 367 |
|
---|
| 368 | // T for this layer
|
---|
| 369 | Ti = T[i];
|
---|
| 370 |
|
---|
[22758] | 371 | if (gdn[i]>0.0+Gdntol){
|
---|
[19554] | 372 |
|
---|
[24313] | 373 | if(W[i]<=0.0+Wtol){
|
---|
| 374 | //_printf_("Dendritic dry snow metamorphism\n");
|
---|
| 375 | //index for dentricity > 0 and T gradients < 5 degC m-1 and >= 5 degC m-1
|
---|
[27232] | 376 | if(fabs(dT[i])<=5.0+Ttol){
|
---|
[24313] | 377 | //determine coefficients
|
---|
[27232] | 378 | IssmDouble A = - 2e8 * exp(-6e3 / Ti) * dt;
|
---|
| 379 | IssmDouble B = 1e9 * exp(-6e3 / Ti) * dt;
|
---|
[24313] | 380 | //new dentricity and sphericity for dT < 5 degC m-1
|
---|
| 381 | gdn[i] += A;
|
---|
| 382 | gsp[i] += B;
|
---|
| 383 | }
|
---|
| 384 | else{
|
---|
| 385 | // new dendricity and sphericity for dT >= 5 degC m-1
|
---|
[19554] | 386 |
|
---|
[27232] | 387 | //determine coefficients
|
---|
| 388 | IssmDouble C = (-2e8 * exp(-6e3 / Ti) * dt) * pow(fabs(dT[i]),.4);
|
---|
[24313] | 389 | gdn[i] +=C;
|
---|
| 390 | gsp[i] +=C;
|
---|
| 391 | }
|
---|
[19554] | 392 | }
|
---|
| 393 | else{
|
---|
[24313] | 394 | // wet snow metamorphism
|
---|
| 395 | //_printf_("Dendritic wet snow metamorphism\n");
|
---|
[19554] | 396 |
|
---|
| 397 | //determine coefficient
|
---|
[19582] | 398 | IssmDouble D = (1.0/16.0) * pow(lwc[i],3.0) * dt;
|
---|
[19554] | 399 |
|
---|
[24313] | 400 | // new dendricity for wet snow
|
---|
[19554] | 401 | gdn[i] -= D;
|
---|
[24313] | 402 | // new sphericity for wet snow
|
---|
[19554] | 403 | gsp[i] += D;
|
---|
| 404 | }
|
---|
| 405 | // dendricity and sphericity can not be > 1 or < 0
|
---|
[26744] | 406 | if (gdn[i]<=0.0+Gdntol)gdn[i]=0.0;
|
---|
| 407 | if (gsp[i]<=0.0+Gdntol)gsp[i]=0.0;
|
---|
| 408 | if (gdn[i]>=1.0-Gdntol)gdn[i]=1.0;
|
---|
| 409 | if (gsp[i]>=1.0-Gdntol)gsp[i]=1.0;
|
---|
[19554] | 410 |
|
---|
[24313] | 411 | // determine new grain size (mm)
|
---|
[27232] | 412 | gsz[i] = 1e-1*(gdn[i]/.99+(1-1*gdn[i]/.99)*(gsp[i]/.99*3+(1-gsp[i]/.99)*4));
|
---|
[19554] | 413 |
|
---|
| 414 | }
|
---|
| 415 | else{
|
---|
| 416 |
|
---|
[24313] | 417 | //When wet-snow grains (class 6) are submitted to a
|
---|
[25836] | 418 | // temperature gradient higher than 5 degC m-1, their sphericity
|
---|
[24313] | 419 | // decreases according to Equations (4). When sphericity
|
---|
| 420 | // reaches 0, their size increases according to the functions
|
---|
| 421 | // determined by Marbouty. (Brun et al., 1992)
|
---|
[26744] | 422 | if(gsp[i]>0.0+Gdntol && gsp[i]<1.0-Gdntol){
|
---|
| 423 |
|
---|
| 424 | IssmDouble F = 0.0;
|
---|
| 425 |
|
---|
[27232] | 426 | if (fabs(dT[i])>5.0+Ttol){
|
---|
| 427 | F = (-2e8 * exp(-6e3 / Ti) * dt) * pow(fabs(dT[i]),.4);
|
---|
[26744] | 428 | }
|
---|
| 429 | else if (W[i]>0.0+Wtol){
|
---|
| 430 | F = (1.0/16.0) * pow(lwc[i],3.0) * dt;
|
---|
| 431 | }
|
---|
| 432 | else{
|
---|
[27232] | 433 | F = 1e9 * exp(-6e3 / Ti) * dt;
|
---|
[26744] | 434 | }
|
---|
| 435 | gsp[i] +=F;
|
---|
| 436 |
|
---|
[24313] | 437 | }
|
---|
[26744] | 438 | if (gsp[i]<=0.0+Gdntol)gsp[i]=0.0;
|
---|
| 439 | if (gsp[i]>=1.0-Gdntol)gsp[i]=1.0;
|
---|
| 440 |
|
---|
[24313] | 441 | /*Dry snow metamorphism (Marbouty, 1980) grouped model coefficents
|
---|
[19554] | 442 | *from Marbouty, 1980: Figure 9*/
|
---|
[27232] | 443 | if(W[i]<=0.0+Wtol || (gsp[i]<=0.0+Gdntol && fabs(dT[i])>5.0+Ttol)){
|
---|
[24313] | 444 | //_printf_("Nondendritic snow metamorphism\n");
|
---|
[27232] | 445 | Q = Marbouty(Ti,d[i],dT[i]);
|
---|
[19554] | 446 |
|
---|
[24313] | 447 | // calculate grain growth
|
---|
| 448 | gsz[i] += (Q*dt);
|
---|
| 449 | }
|
---|
[19554] | 450 | //Wet snow metamorphism (Brun, 1989)
|
---|
[24313] | 451 | else{
|
---|
| 452 | //_printf_("Nondendritic wet snow metamorphism\n");
|
---|
[19554] | 453 | //wet rate of change coefficient
|
---|
[25836] | 454 | IssmDouble E = (1.28e-8 + 4.22e-10 * pow(lwc[i],3.0))* (dt *dts); // [mm^3 s^-1]
|
---|
[19554] | 455 |
|
---|
| 456 | // calculate change in grain volume and convert to grain size
|
---|
[19582] | 457 | gsz[i] = 2.0 * pow(3.0/(Pi * 4.0)*((4.0/ 3.0)*Pi*pow(gsz[i]/2.0,3.0) + E),1.0/3.0);
|
---|
[19554] | 458 | }
|
---|
| 459 |
|
---|
| 460 | // grains with sphericity == 1 can not have grain sizes > 2 mm (Brun, 1992)
|
---|
[22758] | 461 | if (fabs(gsp[i]-1.0)<Wtol && gsz[i]>2.0-Wtol) gsz[i]=2.0;
|
---|
[19554] | 462 |
|
---|
| 463 | // grains with sphericity == 0 can not have grain sizes > 5 mm (Brun, 1992)
|
---|
[24313] | 464 | if (fabs(gsp[i]-1.0)>=Wtol && gsz[i]>5.0-Wtol) gsz[i]=5.0;
|
---|
[19554] | 465 | }
|
---|
| 466 |
|
---|
[24313] | 467 | //convert grain size back to effective grain radius:
|
---|
[19582] | 468 | re[i]=gsz[i]/2.0;
|
---|
[19554] | 469 | }
|
---|
[23189] | 470 |
|
---|
[24686] | 471 | /*Free resources:*/
|
---|
[19554] | 472 | xDelete<IssmDouble>(gsz);
|
---|
| 473 | xDelete<IssmDouble>(dT);
|
---|
| 474 | xDelete<IssmDouble>(zGPC);
|
---|
| 475 | xDelete<IssmDouble>(lwc);
|
---|
| 476 |
|
---|
[22758] | 477 | /*Assign output pointers:*/
|
---|
| 478 | *pre=re;
|
---|
| 479 | *pgdn=gdn;
|
---|
| 480 | *pgsp=gsp;
|
---|
| 481 |
|
---|
[19554] | 482 | } /*}}}*/
|
---|
[26744] | 483 | void albedo(IssmDouble** pa, IssmDouble** padiff, int aIdx, IssmDouble* re, IssmDouble* dz, IssmDouble* d, IssmDouble cldFrac, IssmDouble aIce, IssmDouble aSnow, IssmDouble aValue, IssmDouble adThresh, IssmDouble* TK, IssmDouble* W, IssmDouble P, IssmDouble EC, IssmDouble Msurf, IssmDouble clabSnow, IssmDouble clabIce, IssmDouble SZA, IssmDouble COT, IssmDouble t0wet, IssmDouble t0dry, IssmDouble K, IssmDouble dt, IssmDouble dIce, int m,int sid) { /*{{{*/
|
---|
[19554] | 484 |
|
---|
| 485 | //// Calculates Snow, firn and ice albedo as a function of:
|
---|
[22758] | 486 | // 0 : direct input from aValue parameter
|
---|
[19554] | 487 | // 1 : effective grain radius (Gardner & Sharp, 2009)
|
---|
[25836] | 488 | // 2 : effective grain radius (Brun et al., 1992, Lefebre et al., 2003)
|
---|
[19554] | 489 | // 3 : density and cloud amount (Greuell & Konzelmann, 1994)
|
---|
| 490 | // 4 : exponential time decay & wetness (Bougamont & Bamber, 2005)
|
---|
| 491 |
|
---|
| 492 | //// Inputs
|
---|
| 493 | // aIdx = albedo method to use
|
---|
[23189] | 494 |
|
---|
[22758] | 495 | // Method 0
|
---|
| 496 | // aValue = direct input value for albedo, override all changes to albedo
|
---|
[19554] | 497 |
|
---|
[22758] | 498 | // adThresh
|
---|
| 499 | // Apply below method to all areas with densities below this value,
|
---|
| 500 | // or else apply direct input value, allowing albedo to be altered.
|
---|
| 501 | // Default value is rho water (1023 kg m-3).
|
---|
| 502 |
|
---|
[19554] | 503 | // Methods 1 & 2
|
---|
| 504 | // re = surface effective grain radius [mm]
|
---|
[26744] | 505 | // Method 1, optional
|
---|
| 506 | // clabSnow = concentration of light absorbing carbon [ppm1], default 0
|
---|
| 507 | // SZA = solar zenith angle of the incident radiation [deg], default 0
|
---|
| 508 | // COT = cloud optical thickness, default 0
|
---|
| 509 | // For TWO LAYER
|
---|
| 510 | // clabIce = concentration of light absorbing carbon of first ice layer [ppm1], default 0
|
---|
[19554] | 511 |
|
---|
[26744] | 512 | // Method 3
|
---|
[19554] | 513 | // d = snow surface density [kg m-3]
|
---|
| 514 | // n = cloud amount
|
---|
| 515 | // aIce = albedo of ice
|
---|
| 516 | // aSnow = albedo of fresh snow
|
---|
| 517 |
|
---|
[26744] | 518 | // Method 4
|
---|
[19554] | 519 | // aIce = albedo of ice
|
---|
| 520 | // aSnow = albedo of fresh snow
|
---|
| 521 | // a = grid cell albedo from prevous time step;
|
---|
| 522 | // T = grid cell temperature [k]
|
---|
| 523 | // W = pore water [kg]
|
---|
| 524 | // P = precipitation [mm w.e.] or [kg m-3]
|
---|
| 525 | // EC = surface evaporation (-) condensation (+) [kg m-2]
|
---|
| 526 | // t0wet = time scale for wet snow (15-21.9) [d]
|
---|
| 527 | // t0dry = warm snow timescale [15] [d]
|
---|
| 528 | // K = time scale temperature coef. (7) [d]
|
---|
| 529 | // dt = time step of input data [s]
|
---|
| 530 |
|
---|
| 531 | //// Output
|
---|
| 532 | // a = grid cell albedo
|
---|
| 533 |
|
---|
| 534 | //// Usage
|
---|
| 535 | // Method 1
|
---|
| 536 | // a = albedo(1, 0.1);
|
---|
| 537 |
|
---|
| 538 | // Method 4
|
---|
| 539 | // a = albedo(4, [], [], [], 0.48, 0.85, [0.8 0.5 ... 0.48], ...
|
---|
| 540 | // [273 272.5 ... 265], [0 0.001 ... 0], 0, 0.01, 15, 15, 7, 3600)
|
---|
[19566] | 541 |
|
---|
[22758] | 542 | /*output: */
|
---|
| 543 | IssmDouble* a=NULL;
|
---|
[26744] | 544 | IssmDouble* adiff=NULL;
|
---|
[22758] | 545 |
|
---|
[19566] | 546 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0)_printf0_(" albedo module\n");
|
---|
[22758] | 547 |
|
---|
| 548 | /*Recover pointers: */
|
---|
| 549 | a=*pa;
|
---|
[26744] | 550 | adiff=*padiff;
|
---|
[23189] | 551 |
|
---|
[19554] | 552 | //some constants:
|
---|
| 553 | const IssmDouble dSnow = 300; // density of fresh snow [kg m-3]
|
---|
[25836] | 554 | const IssmDouble dPHC = 830; //Pore closeoff density
|
---|
| 555 | const IssmDouble ai_max = 0.58; //maximum ice albedo, from Lefebre,2003
|
---|
| 556 | const IssmDouble ai_min = aIce; //minimum ice albedo
|
---|
| 557 | const IssmDouble as_min = 0.65; //minimum snow albedo, from Alexander 2014
|
---|
[19554] | 558 |
|
---|
[24313] | 559 | if(aIdx==0 || (adThresh - d[0])<Dtol){
|
---|
[22758] | 560 | a[0] = aValue;
|
---|
[19554] | 561 | }
|
---|
[22758] | 562 | else{
|
---|
| 563 | if(aIdx==1){
|
---|
| 564 | //function of effective grain radius
|
---|
[26744] | 565 | // clabSnow, IssmDouble clabIce, IssmDouble SZA, IssmDouble COT, int m
|
---|
| 566 | a[0]=gardnerAlb(re, dz, d, clabSnow, clabIce, SZA, COT, dPHC, m);
|
---|
| 567 | adiff[0]=gardnerAlb(re, dz, d, clabSnow, clabIce, 50, COT, dPHC, m);
|
---|
[22758] | 568 | }
|
---|
| 569 | else if(aIdx==2){
|
---|
[19554] | 570 |
|
---|
[22758] | 571 | // Spectral fractions (Lefebre et al., 2003)
|
---|
| 572 | // [0.3-0.8um 0.8-1.5um 1.5-2.8um]
|
---|
| 573 |
|
---|
| 574 | IssmDouble sF[3] = {0.606, 0.301, 0.093};
|
---|
| 575 |
|
---|
| 576 | // convert effective radius to grain size in meters
|
---|
| 577 | IssmDouble gsz = (re[0] * 2.0) / 1000.0;
|
---|
| 578 |
|
---|
| 579 | // spectral range:
|
---|
| 580 | // 0.3 - 0.8um
|
---|
[27232] | 581 | IssmDouble a0 = min(0.98, 0.95 - 1.58 *pow(gsz,0.5));
|
---|
[22758] | 582 | // 0.8 - 1.5um
|
---|
[23394] | 583 | IssmDouble a1 = max(0., 0.95 - 15.4 *pow(gsz,0.5));
|
---|
[22758] | 584 | // 1.5 - 2.8um
|
---|
[23394] | 585 | IssmDouble a2 = max(0.127, 0.88 + 346.3*gsz - 32.31*pow(gsz,0.5));
|
---|
[22758] | 586 |
|
---|
| 587 | // broadband surface albedo
|
---|
| 588 | a[0] = sF[0]*a0 + sF[1]*a1 + sF[2]*a2;
|
---|
[25836] | 589 |
|
---|
[22758] | 590 | }
|
---|
| 591 | else if(aIdx==3){
|
---|
| 592 |
|
---|
| 593 | // a as a function of density
|
---|
| 594 |
|
---|
| 595 | // calculate albedo
|
---|
| 596 | a[0] = aIce + (d[0] - dIce)*(aSnow - aIce) / (dSnow - dIce) + (0.05 * (cldFrac - 0.5));
|
---|
| 597 | }
|
---|
| 598 | else if(aIdx==4){
|
---|
| 599 |
|
---|
| 600 | // exponential time decay & wetness
|
---|
| 601 |
|
---|
| 602 | // change in albedo with time:
|
---|
| 603 | // (d_a) = (a - a_old)/(t0)
|
---|
| 604 | // where: t0 = timescale for albedo decay
|
---|
| 605 |
|
---|
| 606 | dt = dt / dts; // convert from [s] to [d]
|
---|
| 607 |
|
---|
| 608 | // initialize variables
|
---|
| 609 | IssmDouble* t0=xNew<IssmDouble>(m);
|
---|
| 610 | IssmDouble* T=xNew<IssmDouble>(m);
|
---|
| 611 | IssmDouble* t0warm=xNew<IssmDouble>(m);
|
---|
| 612 | IssmDouble* d_a=xNew<IssmDouble>(m);
|
---|
| 613 |
|
---|
| 614 | // specify constants
|
---|
| 615 | // a_wet = 0.15; // water albedo (0.15)
|
---|
| 616 | // a_new = aSnow // new snow albedo (0.64 - 0.89)
|
---|
| 617 | // a_old = aIce; // old snow/ice albedo (0.27-0.53)
|
---|
| 618 | // t0_wet = t0wet; // time scale for wet snow (15-21.9) [d]
|
---|
| 619 | // t0_dry = t0dry; // warm snow timescale [15] [d]
|
---|
| 620 | // K = 7 // time scale temperature coef. (7) [d]
|
---|
| 621 | // W0 = 300; // 200 - 600 [mm]
|
---|
| 622 | const IssmDouble z_snow = 15.0; // 16 - 32 [mm]
|
---|
| 623 |
|
---|
| 624 | // determine timescale for albedo decay
|
---|
| 625 | for(int i=0;i<m;i++)if(W[i]>0.0+Wtol)t0[i]=t0wet; // wet snow timescale
|
---|
| 626 | for(int i=0;i<m;i++)T[i]=TK[i] - CtoK; // change T from K to degC
|
---|
| 627 | for(int i=0;i<m;i++) t0warm[i]= fabs(T[i]) * K + t0dry; //// 'warm' snow timescale
|
---|
| 628 | for(int i=0;i<m;i++)if(fabs(W[i])<Wtol && T[i]>=-10.0-Ttol)t0[i]= t0warm[i];
|
---|
| 629 | for(int i=0;i<m;i++)if(T[i]<-10.0-Ttol) t0[i] = 10.0 * K + t0dry; // 'cold' snow timescale
|
---|
| 630 |
|
---|
| 631 | // calculate new albedo
|
---|
| 632 | for(int i=0;i<m;i++)d_a[i] = (a[i] - aIce) / t0[i] * dt; // change in albedo
|
---|
| 633 | for(int i=0;i<m;i++)a[i] -= d_a[i]; // new albedo
|
---|
| 634 |
|
---|
| 635 | // modification of albedo due to thin layer of snow or solid
|
---|
[24686] | 636 | // condensation (deposition) at the surface
|
---|
[22758] | 637 |
|
---|
| 638 | // check if condensation occurs & if it is deposited in solid phase
|
---|
| 639 | if ( EC > 0.0 + Dtol && T[0] < 0.0-Ttol) P = P + (EC/dSnow) * 1000.0; // add cond to precip [mm]
|
---|
| 640 |
|
---|
| 641 | a[0] = aSnow - (aSnow - a[0]) * exp(-P/z_snow);
|
---|
| 642 |
|
---|
| 643 | //----------THIS NEEDS TO BE IMPLEMENTED AT A LATER DATE------------
|
---|
| 644 | // modification of albedo due to thin layer of water on the surface
|
---|
| 645 | // a_surf = a_wet - (a_wet - a_surf) * exp(-W_surf/W0);
|
---|
| 646 |
|
---|
[24686] | 647 | /*Free resources:*/
|
---|
[22758] | 648 | xDelete<IssmDouble>(t0);
|
---|
| 649 | xDelete<IssmDouble>(T);
|
---|
| 650 | xDelete<IssmDouble>(t0warm);
|
---|
| 651 | xDelete<IssmDouble>(d_a);
|
---|
| 652 |
|
---|
| 653 | }
|
---|
| 654 | else _error_("albedo method switch should range from 0 to 4!");
|
---|
[25836] | 655 |
|
---|
| 656 | //If we do not have fresh snow
|
---|
| 657 | if (aIdx<3 && aIdx>0 && (adThresh - d[0])>=Dtol){
|
---|
[26744] | 658 | // In a snow layer < 10cm, account for mix of ice and snow,
|
---|
[25836] | 659 | // after P. Alexander et al., 2014
|
---|
| 660 | IssmDouble depthsnow=0.0;
|
---|
| 661 | IssmDouble aice=0.0;
|
---|
| 662 | int lice=0;
|
---|
| 663 | for(int l=0;(l<m & d[l]<dPHC-Dtol);l++){
|
---|
| 664 | depthsnow=depthsnow+dz[l];
|
---|
| 665 | lice=l+1;
|
---|
| 666 | }
|
---|
| 667 | if (depthsnow<=0.1+Dtol & lice<m & d[lice]>=dPHC-Dtol){
|
---|
| 668 | aice = ai_max + (as_min - ai_max)*(d[lice]-dIce)/(dPHC-dIce);
|
---|
| 669 | a[0]= aice + max(a[0]-aice,0.0)*(depthsnow/0.1);
|
---|
| 670 | }
|
---|
| 671 |
|
---|
| 672 | if (d[0]>=dPHC-Dtol){
|
---|
| 673 | if (d[0]<dIce-Dtol){ //For continuity of albedo in firn i.e. P. Alexander et al., 2014
|
---|
| 674 |
|
---|
| 675 | //ai=ai_max + (as_min - ai_max)*(dI-dIce)/(dPHC-dIce);
|
---|
| 676 | //dPHC is pore close off (830 kg m^-3)
|
---|
| 677 | //dI is density of the upper firn layer
|
---|
| 678 |
|
---|
| 679 | a[0] = ai_max + (as_min - ai_max)*(d[0]-dIce)/(dPHC-dIce);
|
---|
| 680 |
|
---|
| 681 | }
|
---|
| 682 | else{ //surface layer is density of ice
|
---|
| 683 |
|
---|
| 684 | //When density is > dIce (typically 910 kg m^-3, 920 is used by Alexander in MAR),
|
---|
| 685 | //ai=ai_min + (ai_max - ai_min)*e^(-1*(Msw(t)/K))
|
---|
| 686 | //K is a scale factor (set to 200 kg m^-2)
|
---|
| 687 | //Msw(t) is the time-dependent accumulated amount of excessive surface meltwater
|
---|
| 688 | // before run-off in kg m^-2 (melt per GEMB timestep, i.e. 3 hourly)
|
---|
| 689 | IssmDouble M = Msurf+W[0];
|
---|
| 690 | a[0]=max(ai_min + (ai_max - ai_min)*exp(-1*(M/200)), ai_min);
|
---|
| 691 |
|
---|
| 692 | }
|
---|
| 693 | }
|
---|
| 694 | }
|
---|
[19554] | 695 | }
|
---|
[22758] | 696 |
|
---|
[19554] | 697 | // Check for erroneous values
|
---|
| 698 | if (a[0] > 1) _printf_("albedo > 1.0\n");
|
---|
| 699 | else if (a[0] < 0) _printf_("albedo is negative\n");
|
---|
[19613] | 700 | else if (xIsNan(a[0])) _error_("albedo == NAN\n");
|
---|
[22758] | 701 |
|
---|
| 702 | /*Assign output pointers:*/
|
---|
| 703 | *pa=a;
|
---|
[26744] | 704 | *padiff=adiff;
|
---|
[22758] | 705 |
|
---|
[19554] | 706 | } /*}}}*/
|
---|
[27232] | 707 | void thermo(IssmDouble* pshf, IssmDouble* plhf, IssmDouble* pEC, IssmDouble** pT, IssmDouble* pulwrf, IssmDouble* re, IssmDouble* dz, IssmDouble* d, IssmDouble* swf, IssmDouble dlwrf, IssmDouble Ta, IssmDouble V, IssmDouble eAir, IssmDouble pAir, IssmDouble tcIdx, IssmDouble eIdx, IssmDouble teValue, IssmDouble dulwrfValue, IssmDouble teThresh, IssmDouble Ws, IssmDouble dt0, IssmDouble dzMin, int m, IssmDouble Vz, IssmDouble Tz, IssmDouble thermo_scaling, IssmDouble dIce, int sid, bool isconstrainsurfaceT, bool isdeltaLWup) { /*{{{*/
|
---|
[19554] | 708 |
|
---|
| 709 | /* ENGLACIAL THERMODYNAMICS*/
|
---|
[23189] | 710 |
|
---|
[19554] | 711 | /* Description:
|
---|
| 712 | computes new temperature profile accounting for energy absorption and
|
---|
| 713 | thermal diffusion.*/
|
---|
| 714 |
|
---|
| 715 | // INPUTS
|
---|
| 716 | // T: grid cell temperature [k]
|
---|
| 717 | // dz: grid cell depth [m]
|
---|
| 718 | // d: grid cell density [kg m-3]
|
---|
| 719 | // swf: shortwave radiation fluxes [W m-2]
|
---|
| 720 | // dlwrf: downward longwave radiation fluxes [W m-2]
|
---|
| 721 | // Ta: 2 m air temperature
|
---|
| 722 | // V: wind velocity [m s-1]
|
---|
| 723 | // eAir: screen level vapor pressure [Pa]
|
---|
| 724 | // Ws: surface water content [kg]
|
---|
| 725 | // dt0: time step of input data [s]
|
---|
| 726 | // elev: surface elevation [m a.s.l.]
|
---|
| 727 | // Vz: air temperature height above surface [m]
|
---|
| 728 | // Tz: wind height above surface [m]
|
---|
[22758] | 729 | // thermo_scaling: scaling factor to multiply the thermal diffusion timestep (delta t)
|
---|
[19554] | 730 |
|
---|
| 731 | // OUTPUTS
|
---|
| 732 | // T: grid cell temperature [k]
|
---|
| 733 | // EC: evaporation/condensation [kg]
|
---|
[24313] | 734 | // ulwrf: upward longwave radiation flux [W m-2]
|
---|
[23189] | 735 |
|
---|
[19554] | 736 | /*intermediary: */
|
---|
| 737 | IssmDouble* K = NULL;
|
---|
| 738 | IssmDouble* KU = NULL;
|
---|
| 739 | IssmDouble* KD = NULL;
|
---|
| 740 | IssmDouble* KP = NULL;
|
---|
| 741 | IssmDouble* Au = NULL;
|
---|
| 742 | IssmDouble* Ad = NULL;
|
---|
| 743 | IssmDouble* Ap = NULL;
|
---|
| 744 | IssmDouble* Nu = NULL;
|
---|
| 745 | IssmDouble* Nd = NULL;
|
---|
| 746 | IssmDouble* Np = NULL;
|
---|
| 747 | IssmDouble* dzU = NULL;
|
---|
| 748 | IssmDouble* dzD = NULL;
|
---|
| 749 | IssmDouble* sw = NULL;
|
---|
| 750 | IssmDouble* dT_sw = NULL;
|
---|
| 751 | IssmDouble* T0 = NULL;
|
---|
| 752 | IssmDouble* Tu = NULL;
|
---|
| 753 | IssmDouble* Td = NULL;
|
---|
| 754 |
|
---|
[27232] | 755 | IssmDouble z0=0.0;
|
---|
| 756 | IssmDouble zT=0.0;
|
---|
| 757 | IssmDouble zQ=0.0;
|
---|
| 758 | IssmDouble zratio=1;
|
---|
| 759 | IssmDouble dt=0.0;
|
---|
[22758] | 760 | IssmDouble max_fdt=0.0;
|
---|
[27232] | 761 | IssmDouble Ts=0.0;
|
---|
| 762 | IssmDouble L=0.0;
|
---|
| 763 | IssmDouble eS=0.0;
|
---|
| 764 | IssmDouble Ri=0.0;
|
---|
| 765 | IssmDouble coefM=0.0;
|
---|
| 766 | IssmDouble coefH=0.0;
|
---|
| 767 | IssmDouble coefHT=0.0;
|
---|
| 768 | IssmDouble coefHQ=0.0;
|
---|
| 769 | IssmDouble An_num=0.0;
|
---|
| 770 | IssmDouble An_den_T=0.0;
|
---|
| 771 | IssmDouble An_den_Q=0.0;
|
---|
[22758] | 772 | IssmDouble An=0.0;
|
---|
| 773 | IssmDouble C=0.0;
|
---|
| 774 | IssmDouble shf=0.0;
|
---|
| 775 | IssmDouble ds=0.0;
|
---|
| 776 | IssmDouble dAir=0.0;
|
---|
| 777 | IssmDouble TCs=0.0;
|
---|
| 778 | IssmDouble lhf=0.0;
|
---|
| 779 | IssmDouble EC_day=0.0;
|
---|
[27232] | 780 | IssmDouble lhf_cum=0.0;
|
---|
| 781 | IssmDouble shf_cum=0.0;
|
---|
[22758] | 782 | IssmDouble dT_turb=0.0;
|
---|
| 783 | IssmDouble turb=0.0;
|
---|
| 784 | IssmDouble ulw=0.0;
|
---|
| 785 | IssmDouble dT_ulw=0.0;
|
---|
| 786 | IssmDouble dlw=0.0;
|
---|
| 787 | IssmDouble dT_dlw=0.0;
|
---|
[23189] | 788 |
|
---|
[19554] | 789 | /*outputs:*/
|
---|
[22758] | 790 | IssmDouble EC=0.0;
|
---|
| 791 | IssmDouble* T=*pT;
|
---|
[24313] | 792 | IssmDouble ulwrf=0.0;
|
---|
[19554] | 793 |
|
---|
[19566] | 794 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0)_printf0_(" thermal module\n");
|
---|
| 795 |
|
---|
[19554] | 796 | ds = d[0]; // density of top grid cell
|
---|
| 797 |
|
---|
| 798 | // calculated air density [kg/m3]
|
---|
[22758] | 799 | dAir = 0.029 * pAir /(R * Ta);
|
---|
[19554] | 800 |
|
---|
| 801 | // thermal capacity of top grid cell [J/k]
|
---|
| 802 | TCs = d[0]*dz[0]*CI;
|
---|
| 803 |
|
---|
| 804 | //initialize Evaporation - Condenstation
|
---|
[22758] | 805 | EC = 0.0;
|
---|
[23189] | 806 |
|
---|
[19554] | 807 | // check if all SW applied to surface or distributed throught subsurface
|
---|
| 808 | // swIdx = length(swf) > 1
|
---|
| 809 |
|
---|
| 810 | // SURFACE ROUGHNESS (Bougamont, 2006)
|
---|
| 811 | // wind/temperature surface roughness height [m]
|
---|
[27232] | 812 | if (ds < dIce-Dtol && Ws < Wtol) z0 = 0.00012; // 0.12 mm for dry snow
|
---|
[22758] | 813 | else if (ds >= dIce-Dtol) z0 = 0.0032; // 3.2 mm for ice
|
---|
[19554] | 814 | else z0 = 0.0013; // 1.3 mm for wet snow
|
---|
| 815 |
|
---|
[27232] | 816 | //zT and zQ are percentage of z0 (Foken 2008)
|
---|
| 817 | zratio=10;
|
---|
| 818 | zT=z0/zratio;
|
---|
| 819 | zQ=z0/zratio;
|
---|
| 820 |
|
---|
[19554] | 821 | // if V = 0 goes to infinity therfore if V = 0 change
|
---|
[22758] | 822 | if(V<0.01-Dtol)V=0.01;
|
---|
[23189] | 823 |
|
---|
[19554] | 824 | // Bulk-transfer coefficient for turbulent fluxes
|
---|
[27232] | 825 | An = pow(0.4,2); // Bulk-transfer coefficient
|
---|
| 826 | C = An*V; // shf & lhf common coefficient
|
---|
| 827 | An_den_T = (log(Tz/zT)*log(Vz/z0));
|
---|
| 828 | An_den_Q = (log(Tz/zQ)*log(Vz/z0));
|
---|
[19554] | 829 |
|
---|
| 830 | // THERMAL CONDUCTIVITY (Sturm, 1997: J. Glaciology)
|
---|
| 831 | // calculate new K profile [W m-1 K-1]
|
---|
| 832 |
|
---|
| 833 | // initialize conductivity
|
---|
| 834 | K= xNewZeroInit<IssmDouble>(m);
|
---|
| 835 |
|
---|
[27232] | 836 | // for snow and firn (density < 910 kg m-3) (Sturm et al, 1997) or (Calonne et al., 2011)
|
---|
| 837 | if (tcIdx == 2){
|
---|
| 838 | for(int i=0;i<m;i++) if(d[i]<dIce-Dtol) K[i] = 0.024 - 1.23e-4 * d[i] + 2.5e-6 * (pow(d[i],2));
|
---|
| 839 | }
|
---|
| 840 | else{ //default (Sturm et al, 1997)
|
---|
| 841 | for(int i=0;i<m;i++) if(d[i]<dIce-Dtol) K[i] = 0.138 - 1.01e-3 * d[i] + 3.233e-6 * (pow(d[i],2));
|
---|
| 842 | }
|
---|
[19554] | 843 |
|
---|
| 844 | // for ice (density >= 910 kg m-3)
|
---|
[27232] | 845 | for(int i=0;i<m;i++) if(d[i]>=dIce-Dtol) K[i] = 9.828 * exp(-5.7e-3*T[i]);
|
---|
[19554] | 846 |
|
---|
| 847 | // THERMAL DIFFUSION COEFFICIENTS
|
---|
[23189] | 848 |
|
---|
[19554] | 849 | // A discretization scheme which truncates the Taylor-Series expansion
|
---|
| 850 | // after the 3rd term is used. See Patankar 1980, Ch. 3&4
|
---|
[23189] | 851 |
|
---|
[19554] | 852 | // discretized heat equation:
|
---|
[23189] | 853 |
|
---|
[24686] | 854 | // Tp = (Au*Tuo+ Ad*Tdo+ (Ap-Au-Ad)Tpo+ S) / Ap
|
---|
[23189] | 855 |
|
---|
[19554] | 856 | // where neighbor coefficients Au, Ap, & Ad are
|
---|
[23189] | 857 |
|
---|
[27232] | 858 | // Au = [dz_u/2KU + dz/2KP]^-1
|
---|
| 859 | // Ad = [dz_d/2KD + dz/2KP]^-1
|
---|
[19554] | 860 | // Ap = d*CI*dz/Dt
|
---|
| 861 |
|
---|
| 862 | // and u & d represent grid points up and down from the center grid point
|
---|
[24686] | 863 | // point p and o identifies previous time step values. S is a source term.
|
---|
[19554] | 864 |
|
---|
| 865 | // u, d, and p conductivities
|
---|
| 866 | KU = xNew<IssmDouble>(m);
|
---|
| 867 | KD = xNew<IssmDouble>(m);
|
---|
| 868 | KP = xNew<IssmDouble>(m);
|
---|
[23189] | 869 |
|
---|
[27232] | 870 | KU[0] = Delflag; //Thermal conductivity of air = 0.025 W/m/K
|
---|
[24313] | 871 | KD[m-1] = Delflag;
|
---|
[19554] | 872 | for(int i=1;i<m;i++) KU[i]= K[i-1];
|
---|
| 873 | for(int i=0;i<m-1;i++) KD[i] = K[i+1];
|
---|
| 874 | for(int i=0;i<m;i++) KP[i] = K[i];
|
---|
| 875 |
|
---|
| 876 | // determine u, d & p cell widths
|
---|
| 877 | dzU = xNew<IssmDouble>(m);
|
---|
| 878 | dzD = xNew<IssmDouble>(m);
|
---|
[24313] | 879 | dzU[0]=Delflag;
|
---|
| 880 | dzD[m-1]=Delflag;
|
---|
[23189] | 881 |
|
---|
[19554] | 882 | for(int i=1;i<m;i++) dzU[i]= dz[i-1];
|
---|
| 883 | for(int i=0;i<m-1;i++) dzD[i] = dz[i+1];
|
---|
| 884 |
|
---|
| 885 | // determine minimum acceptable delta t (diffusion number > 1/2) [s]
|
---|
[22758] | 886 | // NS: 2.16.18 divided dt by scaling factor, default set to 1/11 for stability
|
---|
[19554] | 887 | dt=1e12;
|
---|
[27232] | 888 | for(int i=0;i<m;i++) dt = min(dt,CI * pow(dz[i],2) * d[i] / (3 * K[i]) * thermo_scaling);
|
---|
[19554] | 889 |
|
---|
| 890 | // smallest possible even integer of 60 min where diffusion number > 1/2
|
---|
| 891 | // must go evenly into one hour or the data frequency if it is smaller
|
---|
| 892 |
|
---|
[19566] | 893 | // all integer factors of the number of second in a day (86400 [s])
|
---|
[19554] | 894 | int f[45] = {1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 30, 36, 40, 45, 48, 50, 60,
|
---|
| 895 | 72, 75, 80, 90, 100, 120, 144, 150, 180, 200, 225, 240, 300, 360, 400, 450, 600, 720, 900, 1200, 1800, 3600};
|
---|
| 896 |
|
---|
| 897 | // return the min integer factor that is < dt
|
---|
[19566] | 898 | max_fdt=f[0];
|
---|
[19554] | 899 | for(int i=0;i<45;i++){
|
---|
[22758] | 900 | if (f[i]<dt-Dtol)if(f[i]>=max_fdt-Dtol)max_fdt=f[i];
|
---|
[19554] | 901 | }
|
---|
| 902 | dt=max_fdt;
|
---|
[22758] | 903 |
|
---|
[19554] | 904 | // determine mean (harmonic mean) of K/dz for u, d, & p
|
---|
| 905 | Au = xNew<IssmDouble>(m);
|
---|
| 906 | Ad = xNew<IssmDouble>(m);
|
---|
| 907 | Ap = xNew<IssmDouble>(m);
|
---|
| 908 | for(int i=0;i<m;i++){
|
---|
[27232] | 909 | Au[i] = pow((dzU[i]/2.0/KU[i] + dz[i]/2.0/KP[i]),-1.0);
|
---|
| 910 | Ad[i] = pow((dzD[i]/2.0/KD[i] + dz[i]/2.0/KP[i]),-1.0);
|
---|
[19554] | 911 | Ap[i] = (d[i]*dz[i]*CI)/dt;
|
---|
| 912 | }
|
---|
[23189] | 913 |
|
---|
[19554] | 914 | // create "neighbor" coefficient matrix
|
---|
[27232] | 915 | Nu = xNewZeroInit<IssmDouble>(m);
|
---|
| 916 | Nd = xNewZeroInit<IssmDouble>(m);
|
---|
| 917 | Np = xNewZeroInit<IssmDouble>(m);
|
---|
[19554] | 918 | for(int i=0;i<m;i++){
|
---|
| 919 | Nu[i] = Au[i] / Ap[i];
|
---|
| 920 | Nd[i] = Ad[i] / Ap[i];
|
---|
[22758] | 921 | Np[i]= 1.0 - Nu[i] - Nd[i];
|
---|
[19554] | 922 | }
|
---|
[23189] | 923 |
|
---|
[19554] | 924 | // specify boundary conditions: constant flux at bottom
|
---|
[22758] | 925 | Nu[m-1] = 0.0;
|
---|
| 926 | Np[m-1] = 1.0;
|
---|
[23189] | 927 |
|
---|
[19554] | 928 | // zero flux at surface
|
---|
[22758] | 929 | Np[0] = 1.0 - Nd[0];
|
---|
[23189] | 930 |
|
---|
[19554] | 931 | // Create neighbor arrays for diffusion calculations instead of a tridiagonal matrix
|
---|
[22758] | 932 | Nu[0] = 0.0;
|
---|
| 933 | Nd[m-1] = 0.0;
|
---|
[23189] | 934 |
|
---|
[19554] | 935 | /* RADIATIVE FLUXES*/
|
---|
| 936 |
|
---|
| 937 | // energy supplied by shortwave radiation [J]
|
---|
| 938 | sw = xNew<IssmDouble>(m);
|
---|
| 939 | for(int i=0;i<m;i++) sw[i]= swf[i] * dt;
|
---|
[23189] | 940 |
|
---|
[19554] | 941 | // temperature change due to SW
|
---|
| 942 | dT_sw = xNew<IssmDouble>(m);
|
---|
| 943 | for(int i=0;i<m;i++) dT_sw[i]= sw[i] / (CI * d[i] * dz[i]);
|
---|
| 944 |
|
---|
| 945 | // Upward longwave radiation flux is calculated from the snow surface
|
---|
| 946 | // temperature which is set equal to the average temperature of the
|
---|
| 947 | // top grid cells.
|
---|
| 948 |
|
---|
| 949 | // energy supplied by downward longwave radiation to the top grid cell [J]
|
---|
| 950 | dlw = dlwrf * dt;
|
---|
| 951 |
|
---|
| 952 | // temperature change due to dlw_surf
|
---|
| 953 | dT_dlw = dlw / TCs;
|
---|
| 954 |
|
---|
| 955 | // PREALLOCATE ARRAYS BEFORE LOOP FOR IMPROVED PERFORMANCE
|
---|
[19582] | 956 | T0 = xNewZeroInit<IssmDouble>(m+2);
|
---|
[19554] | 957 | Tu=xNew<IssmDouble>(m);
|
---|
| 958 | Td=xNew<IssmDouble>(m);
|
---|
| 959 |
|
---|
| 960 | /* CALCULATE ENERGY SOURCES AND DIFFUSION FOR EVERY TIME STEP [dt]*/
|
---|
[19613] | 961 | for (IssmDouble i=1;i<=dt0;i+=dt){
|
---|
[19554] | 962 |
|
---|
| 963 | // PART OF ENERGY CONSERVATION CHECK
|
---|
| 964 | // store initial temperature
|
---|
| 965 | //T_init = T;
|
---|
[23189] | 966 |
|
---|
[19554] | 967 | // calculate temperature of snow surface (Ts)
|
---|
[27232] | 968 | Ts = T[0];
|
---|
[23394] | 969 | Ts = min(CtoK,Ts); // don't allow Ts to exceed 273.15 K (0 degC)
|
---|
[23189] | 970 |
|
---|
[19554] | 971 | //TURBULENT HEAT FLUX
|
---|
[23189] | 972 |
|
---|
[22758] | 973 | // Monin-Obukhov Stability Correction
|
---|
[19554] | 974 | // Reference:
|
---|
| 975 | // Ohmura, A., 1982: Climate and Energy-Balance on the Arctic Tundra.
|
---|
| 976 | // Journal of Climatology, 2, 65-84.
|
---|
| 977 |
|
---|
| 978 | // calculate the Bulk Richardson Number (Ri)
|
---|
[27232] | 979 | Ri = pow(100000/pAir,0.286)*(2.0*9.81*(Ta - Ts)) / (Tz*(Ta + Ts)* pow(V/(Vz),2.0));
|
---|
[23189] | 980 |
|
---|
[27232] | 981 | IssmDouble PhiM;
|
---|
| 982 | IssmDouble PhiH;
|
---|
| 983 |
|
---|
[22758] | 984 | // calculate Monin-Obukhov stability factors 'coefM' and 'coefH'
|
---|
[27232] | 985 | if (false){
|
---|
| 986 | // do not allow Ri to exceed 0.16
|
---|
| 987 | Ri = min(Ri, 0.16); //Ohmura, 1982
|
---|
[23189] | 988 |
|
---|
[27232] | 989 | // calculate momentum 'coefM' stability factor
|
---|
| 990 | if (Ri > 0.0+Ttol){
|
---|
| 991 | // if stable
|
---|
| 992 | coefM = 1.0/(1.0-5.2*Ri);
|
---|
| 993 | }
|
---|
| 994 | else {
|
---|
| 995 | coefM =pow (1.0-18*Ri,-0.25);
|
---|
| 996 | }
|
---|
[19554] | 997 |
|
---|
[27232] | 998 | // calculate heat/wind 'coef_H' stability factor
|
---|
| 999 | if (Ri <= -0.03+Ttol) coefH = coefM/1.3;
|
---|
| 1000 | else coefH = coefM;
|
---|
| 1001 |
|
---|
| 1002 | coefHT = coefH*An_den_T;
|
---|
| 1003 | coefHQ = coefH*An_den_Q;
|
---|
| 1004 |
|
---|
[19554] | 1005 | }
|
---|
[27232] | 1006 | else if(false){
|
---|
| 1007 |
|
---|
| 1008 | // do not allow Ri to exceed 0.19
|
---|
| 1009 | Ri = min(Ri, 0.19); //Ohmura, 1982
|
---|
| 1010 |
|
---|
| 1011 | // calculate momentum 'coefM' stability factor
|
---|
| 1012 | if (Ri > 0.0+Ttol){
|
---|
| 1013 | // if stable
|
---|
| 1014 | //coefM = pow(1.0-5.0*Ri,2.0); //Fitzpatrick et al., 2017, from Brock et al., 2010
|
---|
| 1015 | coefM=1+5.3*min((Ri/(1-5*Ri)),0.5);
|
---|
| 1016 | coefH=1+8*min((Ri/(1-5*Ri)),0.5);
|
---|
| 1017 | }
|
---|
| 1018 | else {
|
---|
| 1019 | //coefM =pow(1.0-16.0*max(Ri,-1.0),0.75); //Fitzpatrick et al., 2017, from Brock et al., 2010
|
---|
| 1020 | coefM=pow(1-19*max(Ri/1.5,-2.0),-0.25);
|
---|
| 1021 | coefH=0.95*pow(1-11.6*max(Ri/1.5,-2.0),-0.5);
|
---|
| 1022 | }
|
---|
| 1023 |
|
---|
| 1024 | coefHT = coefH*An_den_T;
|
---|
| 1025 | coefHQ = coefH*An_den_Q;
|
---|
| 1026 |
|
---|
[19554] | 1027 | }
|
---|
[27232] | 1028 | else if (false){
|
---|
| 1029 | // Greuell and Konzelman, 1994
|
---|
| 1030 | // calculate momentum 'coefM' stability factor
|
---|
[23189] | 1031 |
|
---|
[27232] | 1032 | if (Ri > 0.0+Ttol){
|
---|
| 1033 | // if stable
|
---|
| 1034 | coefM=1+15*Ri*pow(1+Ri,1/2);
|
---|
| 1035 | coefH=1;
|
---|
| 1036 | }
|
---|
| 1037 | else {
|
---|
| 1038 | coefM=pow(1-15*Ri/(1+75*pow(0.4/log(Tz/zT),2)*pow(Tz/zT*fabs(Ri),1/2)),-1);
|
---|
| 1039 | coefH=1;
|
---|
| 1040 | }
|
---|
[23189] | 1041 |
|
---|
[27232] | 1042 | coefHT = coefH*An_den_T;
|
---|
| 1043 | coefHQ = coefH*An_den_Q;
|
---|
[19554] | 1044 |
|
---|
[27232] | 1045 | }
|
---|
| 1046 | else {
|
---|
| 1047 | IssmDouble a1=1.0;
|
---|
| 1048 | IssmDouble b1=2/3;
|
---|
| 1049 | IssmDouble c1=5.0;
|
---|
| 1050 | IssmDouble d1=0.35;
|
---|
| 1051 | IssmDouble PhiMz;
|
---|
| 1052 | IssmDouble PhiHz;
|
---|
| 1053 | IssmDouble PhiMz0=0.0;
|
---|
| 1054 | IssmDouble PhiHzT=0.0;
|
---|
| 1055 | IssmDouble PhiHzQ=0.0;
|
---|
| 1056 | IssmDouble zL;
|
---|
| 1057 | IssmDouble zLT;
|
---|
| 1058 | IssmDouble zLM;
|
---|
[19554] | 1059 |
|
---|
[27232] | 1060 | if (Ri > 0.0+Ttol){
|
---|
| 1061 | // if stable
|
---|
[19554] | 1062 |
|
---|
[27232] | 1063 | if(Ri < 0.2-Ttol){
|
---|
| 1064 | zL = Ri/(1-5*Ri);
|
---|
| 1065 | }
|
---|
| 1066 | else{
|
---|
| 1067 | zL=Ri;
|
---|
| 1068 | }
|
---|
| 1069 | //zL = min(zL, 0.5); //Sjoblom, 2014
|
---|
| 1070 | zLM=max(zL/Vz*z0,1e-3);
|
---|
| 1071 | zLT=max(zL/Tz*zT,1e-3);
|
---|
[23189] | 1072 |
|
---|
[27232] | 1073 | //Ding et al. 2020, from Beljaars and Holtslag (1991)
|
---|
| 1074 | PhiMz=-1*(a1*zL + b1*(zL-c1/d1)*exp(-1*d1*zL) + b1*c1/d1);
|
---|
| 1075 | PhiHz=-1*(pow(1+2*a1*zL/3,1.5) + b1*(zL-c1/d1)*exp(-1*d1*zL) + b1*c1/d1 - 1);
|
---|
| 1076 | PhiMz0=-1*(a1*zLM + b1*(zLM-c1/d1)*exp(-1*d1*zLM) + b1*c1/d1);
|
---|
| 1077 | PhiHzT=-1*(pow(1+2*a1*zLT/3,1.5) + b1*(zLT-c1/d1)*exp(-1*d1*zLT) + b1*c1/d1 - 1);
|
---|
[22758] | 1078 |
|
---|
[27232] | 1079 | PhiHzQ=PhiHzT;
|
---|
| 1080 | }
|
---|
| 1081 | else {
|
---|
| 1082 | IssmDouble xm;
|
---|
| 1083 | IssmDouble xh;
|
---|
| 1084 | IssmDouble xmT;
|
---|
| 1085 | IssmDouble xmM;
|
---|
[22758] | 1086 |
|
---|
[27232] | 1087 | zL = Ri/1.5; //max(Ri, -0.5+Ttol)/1.5; //Hogstrom (1996)
|
---|
| 1088 | //zL = max(zL, -2.0); //Sjoblom, 2014
|
---|
| 1089 | zLM=min(zL/Vz*z0,-1e-3);
|
---|
| 1090 | zLT=min(zL/Tz*zT,-1e-3);
|
---|
[19554] | 1091 |
|
---|
[27232] | 1092 | if (true){ //Sjoblom, 2014
|
---|
| 1093 | xm=pow(1.0-19*zL,-0.25);
|
---|
| 1094 | PhiMz=2*log((1+xm)/2.0) + log((1+pow(xm,2))/2.0) - 2*atan(xm) + Pi/2;
|
---|
| 1095 |
|
---|
| 1096 | xh=0.95*pow(1.0-11.6*zL,-0.5);
|
---|
| 1097 | PhiHz=2*log((1+pow(xh,2))/2.0);
|
---|
| 1098 | }
|
---|
| 1099 | else{ //Ding et al., 2020
|
---|
| 1100 | xm=pow(1.0-16*zL,0.25);
|
---|
| 1101 | xmM=pow(1.0-16*zLM,0.25);
|
---|
| 1102 | xmT=pow(1.0-16*zLT,0.25);
|
---|
| 1103 | PhiMz=2*log((1+xm)/2.0) + log((1+pow(xm,2))/2.0) - 2*atan(xm) + Pi/2;
|
---|
| 1104 | PhiMz0=2*log((1+xmM)/2.0) + log((1+pow(xmM,2))/2.0) - 2*atan(xmM) + Pi/2;
|
---|
| 1105 |
|
---|
| 1106 | PhiHz=2*log((1+pow(xm,2))/2.0);
|
---|
| 1107 | PhiHzT=2*log((1+pow(xmT,2))/2.0);
|
---|
| 1108 |
|
---|
| 1109 | PhiHzQ=PhiHzT;
|
---|
| 1110 | }
|
---|
| 1111 | }
|
---|
| 1112 |
|
---|
| 1113 | PhiM=PhiMz;
|
---|
| 1114 | PhiH=PhiHz;
|
---|
| 1115 | coefM = log(Vz/z0) - PhiMz + PhiMz0; //Ding et al., 2019
|
---|
| 1116 | coefHT = log(Tz/zT) - PhiHz + PhiHzT; //Sjoblom, 2014, after Foken 2008
|
---|
| 1117 | coefHQ = log(Tz/zQ) - PhiHz + PhiHzQ; //Sjoblom, 2014, after Foken 2008
|
---|
| 1118 |
|
---|
| 1119 | }
|
---|
| 1120 |
|
---|
| 1121 | //// Sensible Heat
|
---|
| 1122 | // calculate the sensible heat flux [W m-2](Patterson, 1998)
|
---|
| 1123 | shf = dAir * C * CA * (Ta - Ts) * pow(100000/pAir,0.286);
|
---|
| 1124 |
|
---|
| 1125 | // adjust using Monin-Obukhov stability theory
|
---|
| 1126 | shf = shf/(coefM*coefHT);
|
---|
| 1127 |
|
---|
| 1128 | //// Latent Heat
|
---|
| 1129 | // determine if snow pack is melting & calcualte surface vapour pressure over ice or liquid water
|
---|
| 1130 | if (Ts >= CtoK-Ttol){
|
---|
| 1131 | L = LV; //for liquid water at 273.15 k to vapor
|
---|
| 1132 |
|
---|
| 1133 | //for liquid surface (assume liquid on surface when Ts == 0 deg C)
|
---|
| 1134 | // Wright (1997), US Meteorological Handbook from Murphy and Koop, 2005 Appendix A
|
---|
| 1135 | //eS = 611.21 * exp(17.502 * (Ts - CtoK) / (240.97 + Ts - CtoK));
|
---|
| 1136 | // Murray 1967, https://cran.r-project.org/web/packages/humidity/vignettes/humidity-measures.html
|
---|
| 1137 | eS = 610.78 * exp(17.2693882 * (Ts - CtoK - 0.01) / (Ts - 35.86));
|
---|
| 1138 | }
|
---|
| 1139 | else{
|
---|
| 1140 | L = LS; // latent heat of sublimation
|
---|
| 1141 |
|
---|
| 1142 | // for an ice surface Murphy and Koop, 2005 [Equation 7]
|
---|
| 1143 | //eS = exp(9.550426 - 5723.265/Ts + 3.53068 * log(Ts) - 0.00728332 * Ts);
|
---|
| 1144 | // for an ice surface Ding et al., 2019 after Bolton, 1980
|
---|
| 1145 | eS = 610.78 * exp(21.8745584 * (Ts - CtoK - 0.01) / (Ts - 7.66));
|
---|
| 1146 | }
|
---|
| 1147 |
|
---|
| 1148 | // Latent heat flux [W m-2]
|
---|
| 1149 | lhf = C * L * (eAir - eS) / (461.9*(Ta+Ts)/2);
|
---|
| 1150 |
|
---|
| 1151 | // adjust using Monin-Obukhov stability theory (if lhf '+' then there is energy and mass gained at the surface,
|
---|
| 1152 | // if '-' then there is mass and energy loss at the surface.
|
---|
| 1153 | lhf = lhf/(coefM*coefHQ);
|
---|
| 1154 |
|
---|
[19554] | 1155 | //mass loss (-)/acreation(+) due to evaporation/condensation [kg]
|
---|
[22758] | 1156 | EC_day = lhf * dts / L;
|
---|
[19554] | 1157 |
|
---|
| 1158 | // temperature change due turbulent fluxes
|
---|
| 1159 | turb = (shf + lhf)* dt;
|
---|
| 1160 | dT_turb = turb / TCs;
|
---|
| 1161 |
|
---|
| 1162 | // upward longwave contribution
|
---|
[26744] | 1163 | IssmDouble deltaULW=0.0;
|
---|
| 1164 | IssmDouble emissivity=1.0;
|
---|
| 1165 | //If user wants to set a upward long wave bias
|
---|
| 1166 | if(isdeltaLWup) deltaULW = dulwrfValue;
|
---|
| 1167 | //If user wants to directly set emissivity, or grain radius is larger than the
|
---|
| 1168 | // threshold, or eIdx is 2 and we have wet snow or ice, use prescribed emissivity
|
---|
| 1169 | if(eIdx==0 || (teThresh - re[0])<Gdntol || (eIdx==2 && z0>0.001)) emissivity = teValue;
|
---|
| 1170 | ulw = - (SB * pow(Ts,4.0)* emissivity + deltaULW) * dt;
|
---|
[24313] | 1171 | ulwrf = ulwrf - ulw/dt0;
|
---|
| 1172 |
|
---|
[19554] | 1173 | dT_ulw = ulw / TCs;
|
---|
[23189] | 1174 |
|
---|
[19554] | 1175 | // new grid point temperature
|
---|
[23189] | 1176 |
|
---|
[19554] | 1177 | //SW penetrates surface
|
---|
[27232] | 1178 | if(!isconstrainsurfaceT){
|
---|
| 1179 | for(int j=0;j<m;j++) T[j] = T[j] + dT_sw[j];
|
---|
| 1180 | T[0] = T[0] + dT_dlw + dT_ulw + dT_turb;
|
---|
| 1181 | }
|
---|
[23189] | 1182 |
|
---|
[19554] | 1183 | // temperature diffusion
|
---|
[22758] | 1184 | for(int j=0;j<m;j++) T0[1+j]=T[j];
|
---|
[27232] | 1185 | T0[0]=Ta;
|
---|
| 1186 | T0[m+1]=T[m-1];
|
---|
[19566] | 1187 | for(int j=0;j<m;j++) Tu[j] = T0[j];
|
---|
| 1188 | for(int j=0;j<m;j++) Td[j] = T0[2+j];
|
---|
| 1189 | for(int j=0;j<m;j++) T[j] = (Np[j] * T[j]) + (Nu[j] * Tu[j]) + (Nd[j] * Td[j]);
|
---|
[23189] | 1190 |
|
---|
[19554] | 1191 | // calculate cumulative evaporation (+)/condensation(-)
|
---|
[25836] | 1192 | if(!isconstrainsurfaceT) EC = EC + (EC_day/dts)*dt;
|
---|
[27232] | 1193 | lhf_cum=lhf_cum+lhf*dt/dt0;
|
---|
| 1194 | shf_cum=shf_cum+shf*dt/dt0;
|
---|
[22758] | 1195 |
|
---|
[19554] | 1196 | /* CHECK FOR ENERGY (E) CONSERVATION [UNITS: J]
|
---|
| 1197 | //energy flux across lower boundary (energy supplied by underling ice)
|
---|
| 1198 | base_flux = Ad(-1)*(T_init()-T_init(-1)) * dt;
|
---|
| 1199 |
|
---|
| 1200 | E_used = sum((T - T_init) * (d*dz*CI));
|
---|
| 1201 | E_sup = ((sum(swf) * dt) + dlw + ulw + turb + base_flux);
|
---|
| 1202 |
|
---|
| 1203 | E_diff = E_used - E_sup;
|
---|
| 1204 |
|
---|
[25836] | 1205 | if fabs(E_diff) > 1E-6 || isnan(E_diff)
|
---|
[19554] | 1206 | disp(T(1))
|
---|
| 1207 | _error_("energy not conserved in thermodynamics equations");
|
---|
| 1208 | */
|
---|
| 1209 | }
|
---|
[22758] | 1210 |
|
---|
[24686] | 1211 | /*Free resources:*/
|
---|
[19554] | 1212 | xDelete<IssmDouble>(K);
|
---|
| 1213 | xDelete<IssmDouble>(KU);
|
---|
| 1214 | xDelete<IssmDouble>(KD);
|
---|
| 1215 | xDelete<IssmDouble>(KP);
|
---|
| 1216 | xDelete<IssmDouble>(Au);
|
---|
| 1217 | xDelete<IssmDouble>(Ad);
|
---|
| 1218 | xDelete<IssmDouble>(Ap);
|
---|
| 1219 | xDelete<IssmDouble>(Nu);
|
---|
| 1220 | xDelete<IssmDouble>(Nd);
|
---|
| 1221 | xDelete<IssmDouble>(Np);
|
---|
| 1222 | xDelete<IssmDouble>(dzU);
|
---|
| 1223 | xDelete<IssmDouble>(dzD);
|
---|
| 1224 | xDelete<IssmDouble>(sw);
|
---|
| 1225 | xDelete<IssmDouble>(dT_sw);
|
---|
| 1226 | xDelete<IssmDouble>(T0);
|
---|
| 1227 | xDelete<IssmDouble>(Tu);
|
---|
| 1228 | xDelete<IssmDouble>(Td);
|
---|
| 1229 |
|
---|
| 1230 | /*Assign output pointers:*/
|
---|
| 1231 | *pEC=EC;
|
---|
[27232] | 1232 | *plhf=lhf_cum;
|
---|
| 1233 | *pshf=shf_cum;
|
---|
[22758] | 1234 | *pT=T;
|
---|
[24313] | 1235 | *pulwrf=ulwrf;
|
---|
[19554] | 1236 |
|
---|
| 1237 | } /*}}}*/
|
---|
[26744] | 1238 | void shortwave(IssmDouble** pswf, int swIdx, int aIdx, IssmDouble dsw, IssmDouble dswdiff, IssmDouble as, IssmDouble asdiff, IssmDouble* d, IssmDouble* dz, IssmDouble* re, IssmDouble dIce, int m, int sid){ /*{{{*/
|
---|
[19554] | 1239 |
|
---|
| 1240 | // DISTRIBUTES ABSORBED SHORTWAVE RADIATION WITHIN SNOW/ICE
|
---|
| 1241 |
|
---|
| 1242 | // swIdx = 0 : all absorbed SW energy is assigned to the top grid cell
|
---|
| 1243 |
|
---|
| 1244 | // swIdx = 1 : absorbed SW is distributed with depth as a function of:
|
---|
[26744] | 1245 | // default : snow density (taken from Bassford, 2002)
|
---|
[25836] | 1246 | // if aIdx=2 : grain size in 3 spectral bands (Brun et al., 1992)
|
---|
[19554] | 1247 |
|
---|
| 1248 | // Inputs
|
---|
| 1249 | // swIdx = shortwave allowed to penetrate surface (0 = No, 1 = Yes)
|
---|
| 1250 | // aIdx = method for calculating albedo (1-4)
|
---|
| 1251 | // dsw = downward shortwave radiative flux [w m-2]
|
---|
[26744] | 1252 | // dswdiff = downward shortwave diffuse radiative flux [w m-2]
|
---|
[19554] | 1253 | // as = surface albedo
|
---|
[26744] | 1254 | // asdiff = surface albedo for diffuse radiation
|
---|
[19554] | 1255 | // d = grid cell density [kg m-3]
|
---|
| 1256 | // dz = grid cell depth [m]
|
---|
| 1257 | // re = grid cell effective grain radius [mm]
|
---|
| 1258 |
|
---|
| 1259 | // Outputs
|
---|
| 1260 | // swf = absorbed shortwave radiation [W m-2]
|
---|
[19582] | 1261 | //
|
---|
[23189] | 1262 |
|
---|
[19582] | 1263 | /*outputs: */
|
---|
| 1264 | IssmDouble* swf=NULL;
|
---|
[19554] | 1265 |
|
---|
[19566] | 1266 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0)_printf0_(" shortwave module\n");
|
---|
[19554] | 1267 |
|
---|
[19582] | 1268 | /*Initialize and allocate: */
|
---|
| 1269 | swf=xNewZeroInit<IssmDouble>(m);
|
---|
| 1270 |
|
---|
[19554] | 1271 | // SHORTWAVE FUNCTION
|
---|
[27232] | 1272 | if (swIdx == 0 | (dIce - d[0])<Dtol) {// all sw radation is absorbed in by the top grid cell
|
---|
[23189] | 1273 |
|
---|
[19554] | 1274 | // calculate surface shortwave radiation fluxes [W m-2]
|
---|
[26744] | 1275 | if (aIdx == 1){
|
---|
| 1276 | swf[0] = (1.0 - as) * max(0.0,(dsw - dswdiff)) + (1.0 - asdiff) * dswdiff;
|
---|
| 1277 | }
|
---|
| 1278 | else{
|
---|
| 1279 | swf[0] = (1.0 - as) * dsw;
|
---|
| 1280 | }
|
---|
[19554] | 1281 | }
|
---|
| 1282 | else{ // sw radation is absorbed at depth within the glacier
|
---|
| 1283 |
|
---|
| 1284 | if (aIdx == 2){ // function of effective radius (3 spectral bands)
|
---|
| 1285 |
|
---|
| 1286 | IssmDouble * gsz=NULL;
|
---|
| 1287 | IssmDouble * B1_cum=NULL;
|
---|
| 1288 | IssmDouble * B2_cum=NULL;
|
---|
| 1289 | IssmDouble* h =NULL;
|
---|
| 1290 | IssmDouble* B1 =NULL;
|
---|
| 1291 | IssmDouble* B2 =NULL;
|
---|
| 1292 | IssmDouble* exp1 = NULL;
|
---|
| 1293 | IssmDouble* exp2 = NULL;
|
---|
| 1294 | IssmDouble* Qs1 = NULL;
|
---|
| 1295 | IssmDouble* Qs2 = NULL;
|
---|
| 1296 |
|
---|
| 1297 | // convert effective radius [mm] to grain size [m]
|
---|
| 1298 | gsz=xNew<IssmDouble>(m);
|
---|
[22758] | 1299 | for(int i=0;i<m;i++) gsz[i]= (re[i] * 2.0) / 1000.0;
|
---|
[19554] | 1300 |
|
---|
| 1301 | // Spectral fractions [0.3-0.8um 0.8-1.5um 1.5-2.8um]
|
---|
| 1302 | // (Lefebre et al., 2003)
|
---|
| 1303 | IssmDouble sF[3] = {0.606, 0.301, 0.093};
|
---|
| 1304 |
|
---|
| 1305 | // initialize variables
|
---|
| 1306 | B1_cum=xNew<IssmDouble>(m+1);
|
---|
| 1307 | B2_cum=xNew<IssmDouble>(m+1);
|
---|
| 1308 | for(int i=0;i<m+1;i++){
|
---|
[22758] | 1309 | B1_cum[i]=1.0;
|
---|
| 1310 | B2_cum[i]=1.0;
|
---|
[19554] | 1311 | }
|
---|
| 1312 |
|
---|
| 1313 | // spectral albedos:
|
---|
| 1314 | // 0.3 - 0.8um
|
---|
[27232] | 1315 | IssmDouble a0 = min(0.98, 0.95 - 1.58 *pow(gsz[0],0.5));
|
---|
[19554] | 1316 | // 0.8 - 1.5um
|
---|
[23394] | 1317 | IssmDouble a1 = max(0.0, 0.95 - 15.4 *pow(gsz[0],0.5));
|
---|
[19554] | 1318 | // 1.5 - 2.8um
|
---|
[23394] | 1319 | IssmDouble a2 = max(0.127, 0.88 + 346.3*gsz[0] - 32.31*pow(gsz[0],0.5));
|
---|
[19554] | 1320 |
|
---|
| 1321 | // separate net shortwave radiative flux into spectral ranges
|
---|
| 1322 | IssmDouble swfS[3];
|
---|
[22758] | 1323 | swfS[0] = (sF[0] * dsw) * (1.0 - a0);
|
---|
| 1324 | swfS[1] = (sF[1] * dsw) * (1.0 - a1);
|
---|
| 1325 | swfS[2] = (sF[2] * dsw) * (1.0 - a2);
|
---|
[19554] | 1326 |
|
---|
[26744] | 1327 | // absorption coefficient for spectral range:
|
---|
[19554] | 1328 | h =xNew<IssmDouble>(m);
|
---|
| 1329 | B1 =xNew<IssmDouble>(m);
|
---|
| 1330 | B2 =xNew<IssmDouble>(m);
|
---|
| 1331 | for(int i=0;i<m;i++) h[i]= d[i] /(pow(gsz[i],0.5));
|
---|
[22758] | 1332 | for(int i=0;i<m;i++) B1[i] = 0.0192 * h[i]; // 0.3 - 0.8um
|
---|
| 1333 | for(int i=0;i<m;i++) B2[i]= 0.1098 * h[i]; // 0.8 - 1.5um
|
---|
[19554] | 1334 | // B3 = +inf // 1.5 - 2.8um
|
---|
| 1335 |
|
---|
| 1336 | // cumulative extinction factors
|
---|
| 1337 | exp1 = xNew<IssmDouble>(m);
|
---|
| 1338 | exp2 = xNew<IssmDouble>(m);
|
---|
| 1339 | for(int i=0;i<m;i++) exp1[i]=exp(-B1[i]*dz[i]);
|
---|
| 1340 | for(int i=0;i<m;i++) exp2[i]=exp(-B2[i]*dz[i]);
|
---|
| 1341 |
|
---|
| 1342 | for(int i=0;i<m;i++){
|
---|
| 1343 | IssmDouble cum1=exp1[0];
|
---|
| 1344 | IssmDouble cum2=exp2[0];
|
---|
| 1345 | for(int j=1;j<=i;j++){
|
---|
| 1346 | cum1 = cum1*exp1[j];
|
---|
| 1347 | cum2 = cum2*exp2[j];
|
---|
| 1348 | }
|
---|
| 1349 | B1_cum[i+1]=cum1;
|
---|
| 1350 | B2_cum[i+1]=cum2;
|
---|
| 1351 | }
|
---|
| 1352 |
|
---|
| 1353 | // flux across grid cell boundaries
|
---|
| 1354 | Qs1 = xNew<IssmDouble>(m+1);
|
---|
| 1355 | Qs2 = xNew<IssmDouble>(m+1);
|
---|
| 1356 | for(int i=0;i<m+1;i++){
|
---|
| 1357 | Qs1[i] = swfS[0] * B1_cum[i];
|
---|
| 1358 | Qs2[i] = swfS[1] * B2_cum[i];
|
---|
| 1359 | }
|
---|
| 1360 |
|
---|
| 1361 | // net energy flux to each grid cell
|
---|
| 1362 | for(int i=0;i<m;i++) swf[i]= (Qs1[i]-Qs1[i+1]) + (Qs2[i]-Qs2[i+1]);
|
---|
| 1363 |
|
---|
| 1364 | // add flux absorbed at surface
|
---|
| 1365 | swf[0] = swf[0]+ swfS[2];
|
---|
| 1366 |
|
---|
[24686] | 1367 | /*Free resources: */
|
---|
[19554] | 1368 | xDelete<IssmDouble>(gsz);
|
---|
| 1369 | xDelete<IssmDouble>(B1_cum);
|
---|
| 1370 | xDelete<IssmDouble>(B2_cum);
|
---|
| 1371 | xDelete<IssmDouble>(h);
|
---|
| 1372 | xDelete<IssmDouble>(B1);
|
---|
| 1373 | xDelete<IssmDouble>(B2);
|
---|
| 1374 | xDelete<IssmDouble>(exp1);
|
---|
| 1375 | xDelete<IssmDouble>(exp2);
|
---|
| 1376 | xDelete<IssmDouble>(Qs1);
|
---|
| 1377 | xDelete<IssmDouble>(Qs2);
|
---|
[23189] | 1378 |
|
---|
[19554] | 1379 | }
|
---|
| 1380 | else{ //function of grid cell density
|
---|
| 1381 |
|
---|
| 1382 | /*intermediary: */
|
---|
| 1383 | IssmDouble* B_cum = NULL;
|
---|
| 1384 | IssmDouble* exp_B = NULL;
|
---|
| 1385 | IssmDouble* Qs = NULL;
|
---|
| 1386 | IssmDouble* B = NULL;
|
---|
| 1387 |
|
---|
| 1388 | // fraction of sw radiation absorbed in top grid cell (wavelength > 0.8um)
|
---|
| 1389 | IssmDouble SWs = 0.36;
|
---|
| 1390 |
|
---|
| 1391 | // SWs and SWss coefficients need to be better constranted. Greuell
|
---|
| 1392 | // and Konzelmann 1994 used SWs = 0.36 and SWss = 0.64 as this the
|
---|
[24686] | 1393 | // the % of SW radiation with wavelengths > and < 800 nm
|
---|
[19554] | 1394 | // respectively. This, however, may not account for the fact that
|
---|
| 1395 | // the albedo of wavelengths > 800 nm has a much lower albedo.
|
---|
| 1396 |
|
---|
| 1397 | // calculate surface shortwave radiation fluxes [W m-2]
|
---|
[22758] | 1398 | IssmDouble swf_s = SWs * (1.0 - as) * dsw;
|
---|
[19554] | 1399 |
|
---|
| 1400 | // calculate surface shortwave radiation fluxes [W m-2]
|
---|
[22758] | 1401 | IssmDouble swf_ss = (1.0-SWs) * (1.0 - as) * dsw;
|
---|
[19554] | 1402 |
|
---|
| 1403 | // SW allowed to penetrate into snowpack
|
---|
[22758] | 1404 | IssmDouble Bs = 10.0; // snow SW extinction coefficient [m-1] (Bassford,2006)
|
---|
[19554] | 1405 | IssmDouble Bi = 1.3; // ice SW extinction coefficient [m-1] (Bassford,2006)
|
---|
| 1406 |
|
---|
| 1407 | // calculate extinction coefficient B [m-1] vector
|
---|
| 1408 | B=xNew<IssmDouble>(m);
|
---|
[22758] | 1409 | for(int i=0;i<m;i++) B[i] = Bs + (300.0 - d[i]) * ((Bs - Bi)/(dIce - 300.0));
|
---|
[19554] | 1410 |
|
---|
| 1411 | // cumulative extinction factor
|
---|
| 1412 | B_cum = xNew<IssmDouble>(m+1);
|
---|
| 1413 | exp_B = xNew<IssmDouble>(m);
|
---|
| 1414 | for(int i=0;i<m;i++)exp_B[i]=exp(-B[i]*dz[i]);
|
---|
| 1415 |
|
---|
[22758] | 1416 | B_cum[0]=1.0;
|
---|
[19554] | 1417 | for(int i=0;i<m;i++){
|
---|
| 1418 | IssmDouble cum_B=exp_B[0];
|
---|
| 1419 | for(int j=1;j<=i;j++) cum_B=cum_B*exp_B[j];
|
---|
| 1420 | B_cum[i+1]= cum_B;
|
---|
| 1421 | }
|
---|
| 1422 |
|
---|
| 1423 | // flux across grid cell boundaries
|
---|
| 1424 | Qs=xNew<IssmDouble>(m+1);
|
---|
| 1425 | for(int i=0;i<m+1;i++) Qs[i] = swf_ss * B_cum[i];
|
---|
| 1426 |
|
---|
| 1427 | // net energy flux to each grid cell
|
---|
| 1428 | for(int i=0;i<m;i++) swf[i] = (Qs[i]-Qs[i+1]);
|
---|
| 1429 |
|
---|
| 1430 | // add flux absorbed at surface
|
---|
[19566] | 1431 | swf[0] += swf_s;
|
---|
[19554] | 1432 |
|
---|
[24686] | 1433 | /*Free resources:*/
|
---|
[19554] | 1434 | xDelete<IssmDouble>(B_cum);
|
---|
| 1435 | xDelete<IssmDouble>(exp_B);
|
---|
| 1436 | xDelete<IssmDouble>(Qs);
|
---|
| 1437 | xDelete<IssmDouble>(B);
|
---|
| 1438 | }
|
---|
| 1439 | }
|
---|
[19582] | 1440 | /*Assign output pointers: */
|
---|
| 1441 | *pswf=swf;
|
---|
| 1442 |
|
---|
[19554] | 1443 | } /*}}}*/
|
---|
[26744] | 1444 | void accumulation(IssmDouble** pT, IssmDouble** pdz, IssmDouble** pd, IssmDouble** pW, IssmDouble** pa, IssmDouble** padiff, IssmDouble** pre, IssmDouble** pgdn, IssmDouble** pgsp, IssmDouble* pRa, int* pm, int aIdx, int dsnowIdx, IssmDouble Tmean, IssmDouble T_air, IssmDouble P, IssmDouble dzMin, IssmDouble aSnow, IssmDouble C, IssmDouble V, IssmDouble Vmean, IssmDouble dIce, int sid){ /*{{{*/
|
---|
[19554] | 1445 |
|
---|
| 1446 | // Adds precipitation and deposition to the model grid
|
---|
| 1447 |
|
---|
| 1448 | // Author: Alex Gardner, University of Alberta
|
---|
| 1449 | // Date last modified: JAN, 2008
|
---|
| 1450 |
|
---|
| 1451 | /* Description:
|
---|
| 1452 | adjusts the properties of the top grid cell to account for accumulation
|
---|
| 1453 | T_air & T = Air and top grid cell temperatures [K]
|
---|
[24313] | 1454 | Tmean = average surface temperature [K]
|
---|
| 1455 | Vmean = average wind velocity [m s-1]
|
---|
| 1456 | V = wind velocity [m s-1]
|
---|
| 1457 | C = average accumulation rate [kg m-2 yr-1]
|
---|
[19554] | 1458 | dz = topgrid cell length [m]
|
---|
| 1459 | d = density of top grid gell [kg m-3]
|
---|
[26744] | 1460 | P = precipitation [mm w.e.] or [kg m-3]
|
---|
| 1461 | Ra = rainfall [mm w.e.] or [kg m-3]
|
---|
| 1462 | re = effective grain radius [mm]
|
---|
| 1463 | gdn = grain dentricity
|
---|
| 1464 | gsp = grain sphericity*/
|
---|
[19554] | 1465 |
|
---|
| 1466 | // MAIN FUNCTION
|
---|
| 1467 | // specify constants
|
---|
[24313] | 1468 | IssmDouble dSnow = 150; // density of snow [kg m-3]
|
---|
[27232] | 1469 | IssmDouble reNew = 0.05; // new snow grain size [mm]
|
---|
| 1470 | IssmDouble gdnNew = 1.0; // new snow dendricity
|
---|
| 1471 | IssmDouble gspNew = 0.5; // new snow sphericity
|
---|
[19554] | 1472 |
|
---|
| 1473 | /*intermediary: */
|
---|
| 1474 | IssmDouble* mInit=NULL;
|
---|
| 1475 | bool top=true;
|
---|
[22758] | 1476 | IssmDouble mass=0;
|
---|
| 1477 | IssmDouble massinit=0;
|
---|
| 1478 | IssmDouble mass_diff=0;
|
---|
[19554] | 1479 |
|
---|
| 1480 | /*output: */
|
---|
| 1481 | IssmDouble* T=NULL;
|
---|
| 1482 | IssmDouble* dz=NULL;
|
---|
| 1483 | IssmDouble* d=NULL;
|
---|
| 1484 | IssmDouble* W=NULL;
|
---|
| 1485 | IssmDouble* a=NULL;
|
---|
[26744] | 1486 | IssmDouble* adiff=NULL;
|
---|
[19554] | 1487 | IssmDouble* re=NULL;
|
---|
| 1488 | IssmDouble* gdn=NULL;
|
---|
| 1489 | IssmDouble* gsp=NULL;
|
---|
[26744] | 1490 | IssmDouble ra=0.0;
|
---|
[22758] | 1491 | int m=0;
|
---|
[19554] | 1492 |
|
---|
[19566] | 1493 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0)_printf0_(" accumulation module\n");
|
---|
| 1494 |
|
---|
[19554] | 1495 | /*Recover pointers: */
|
---|
| 1496 | T=*pT;
|
---|
| 1497 | dz=*pdz;
|
---|
| 1498 | d=*pd;
|
---|
| 1499 | W=*pW;
|
---|
| 1500 | a=*pa;
|
---|
[26744] | 1501 | adiff=*padiff;
|
---|
[19554] | 1502 | re=*pre;
|
---|
| 1503 | gdn=*pgdn;
|
---|
| 1504 | gsp=*pgsp;
|
---|
| 1505 | m=*pm;
|
---|
[26744] | 1506 | ra=*pRa;
|
---|
[19554] | 1507 |
|
---|
[24313] | 1508 | //Density of fresh snow [kg m-3]
|
---|
| 1509 | switch (dsnowIdx){
|
---|
| 1510 | case 0: // Default value defined above
|
---|
| 1511 | break;
|
---|
| 1512 |
|
---|
| 1513 | case 1: // Density of Antarctica snow
|
---|
| 1514 | dSnow = 350;
|
---|
[25836] | 1515 | //dSnow = 360; //FirnMICE Lundin et al., 2017
|
---|
[24313] | 1516 | break;
|
---|
| 1517 |
|
---|
[26744] | 1518 | case 2: // Density of Greenland snow, Fausto et al., 2018
|
---|
[24313] | 1519 | dSnow = 315;
|
---|
[27232] | 1520 | //From Vionnet et al., 2012 (Crocus)
|
---|
| 1521 | gdnNew = min(max(1.29 - 0.17*V,0.20),1.0);
|
---|
| 1522 | gspNew = min(max(0.08*V + 0.38,0.5),0.9);
|
---|
| 1523 | reNew=max(1e-1*(gdnNew/.99+(1-1*gdnNew/.99)*(gspNew/.99*3+(1-gspNew/.99)*4))/2,Gdntol);
|
---|
[24313] | 1524 | break;
|
---|
| 1525 |
|
---|
| 1526 | case 3: //Surface snow accumulation density from Kaspers et al., 2004, Antarctica
|
---|
| 1527 | //dSnow = alpha1 + beta1*T + delta1*C + epsilon1*W
|
---|
| 1528 | // 7.36x10-2 1.06x10-3 6.69x10-2 4.77x10-3
|
---|
| 1529 | dSnow=(7.36e-2 + 1.06e-3*min(Tmean,CtoK-Ttol) + 6.69e-2*C/1000 + 4.77e-3*Vmean)*1000;
|
---|
| 1530 | break;
|
---|
| 1531 |
|
---|
| 1532 | case 4: // Kuipers Munneke and others (2015), Greenland
|
---|
| 1533 | dSnow = 481.0 + 4.834*(Tmean-CtoK);
|
---|
| 1534 | break;
|
---|
| 1535 | }
|
---|
| 1536 |
|
---|
[19582] | 1537 | // determine initial mass
|
---|
[19554] | 1538 | mInit=xNew<IssmDouble>(m);
|
---|
[19582] | 1539 | for(int i=0;i<m;i++) mInit[i]= d[i] * dz[i];
|
---|
[22758] | 1540 | massinit=0.0;
|
---|
| 1541 | for(int i=0;i<m;i++)massinit+=mInit[i];
|
---|
[19554] | 1542 |
|
---|
[24313] | 1543 | if (P > 0.0+Ptol){
|
---|
[19554] | 1544 |
|
---|
[22758] | 1545 | if (T_air <= CtoK+Ttol){ // if snow
|
---|
[19554] | 1546 |
|
---|
| 1547 | IssmDouble z_snow = P/dSnow; // depth of snow
|
---|
[24313] | 1548 | IssmDouble dfall = gdnNew;
|
---|
| 1549 | IssmDouble sfall = gspNew;
|
---|
| 1550 | IssmDouble refall = reNew;
|
---|
[19554] | 1551 |
|
---|
| 1552 | // if snow depth is greater than specified min dz, new cell created
|
---|
[22758] | 1553 | if (z_snow > dzMin+Dtol){
|
---|
[19554] | 1554 |
|
---|
| 1555 | newcell(&T,T_air,top,m); //new cell T
|
---|
| 1556 | newcell(&dz,z_snow,top,m); //new cell dz
|
---|
| 1557 | newcell(&d,dSnow,top,m); //new cell d
|
---|
[22758] | 1558 | newcell(&W,0.0,top,m); //new cell W
|
---|
[19554] | 1559 | newcell(&a,aSnow,top,m); //new cell a
|
---|
[26744] | 1560 | newcell(&adiff,aSnow,top,m); //new cell a
|
---|
[24313] | 1561 | newcell(&re,refall,top,m); //new cell grain size
|
---|
| 1562 | newcell(&gdn,dfall,top,m); //new cell grain dendricity
|
---|
| 1563 | newcell(&gsp,sfall,top,m); //new cell grain sphericity
|
---|
[19554] | 1564 | m=m+1;
|
---|
| 1565 | }
|
---|
| 1566 | else { // if snow depth is less than specified minimum dz snow
|
---|
| 1567 |
|
---|
[24313] | 1568 | mass = mInit[0] + P; // grid cell adjust mass
|
---|
[19554] | 1569 |
|
---|
| 1570 | dz[0] = dz[0] + P/dSnow; // adjust grid cell depth
|
---|
| 1571 | d[0] = mass / dz[0]; // adjust grid cell density
|
---|
| 1572 |
|
---|
| 1573 | // adjust variables as a linearly weighted function of mass
|
---|
| 1574 | // adjust temperature (assume P is same temp as air)
|
---|
| 1575 | T[0] = (T_air * P + T[0] * mInit[0])/mass;
|
---|
| 1576 |
|
---|
| 1577 | // adjust a, re, gdn & gsp
|
---|
[22758] | 1578 | if(aIdx>0)a[0] = (aSnow * P + a[0] * mInit[0])/mass;
|
---|
[27232] | 1579 | gdn[0] = dfall;
|
---|
| 1580 | gsp[0] = sfall;
|
---|
| 1581 | re[0] = max(1e-1*(gdn[0]/.99+(1-1*gdn[0]/.99)*(gsp[0]/.99*3+(1-gsp[0]/.99)*4))/2,Gdntol);
|
---|
[19554] | 1582 | }
|
---|
| 1583 | }
|
---|
| 1584 | else{ // if rain
|
---|
| 1585 |
|
---|
| 1586 | /*rain is added by increasing the mass and temperature of the ice
|
---|
| 1587 | of the top grid cell. Temperatures are set artifically high to
|
---|
| 1588 | account for the latent heat of fusion. This is the same as
|
---|
| 1589 | directly adding liquid water to the the snow pack surface but
|
---|
| 1590 | makes the numerics easier.*/
|
---|
| 1591 |
|
---|
| 1592 | // grid cell adjust mass
|
---|
| 1593 | mass = mInit[0] + P;
|
---|
| 1594 |
|
---|
| 1595 | // adjust temperature
|
---|
| 1596 | // liquid: must account for latent heat of fusion
|
---|
| 1597 | T[0] = (P *(T_air + LF/CI) + T[0] * mInit[0]) / mass;
|
---|
| 1598 |
|
---|
| 1599 | // adjust grid cell density
|
---|
| 1600 | d[0] = mass / dz[0];
|
---|
| 1601 |
|
---|
| 1602 | // if d > the density of ice, d = dIce
|
---|
[24313] | 1603 | if (d[0] > dIce-Dtol){
|
---|
[19554] | 1604 | d[0] = dIce; // adjust d
|
---|
| 1605 | dz[0] = mass / d[0]; // dz is adjusted to conserve mass
|
---|
| 1606 | }
|
---|
[26744] | 1607 |
|
---|
| 1608 | ra=P;
|
---|
[19554] | 1609 | }
|
---|
| 1610 |
|
---|
| 1611 | // check for conservation of mass
|
---|
| 1612 | mass=0; for(int i=0;i<m;i++)mass+=d[i]*dz[i];
|
---|
| 1613 |
|
---|
| 1614 | mass_diff = mass - massinit - P;
|
---|
[23189] | 1615 |
|
---|
[23394] | 1616 | #ifndef _HAVE_AD_ //avoid round operation. only check in forward mode.
|
---|
[22758] | 1617 | mass_diff = round(mass_diff * 100.0)/100.0;
|
---|
[19554] | 1618 | if (mass_diff > 0) _error_("mass not conserved in accumulation function");
|
---|
[19613] | 1619 | #endif
|
---|
[19554] | 1620 |
|
---|
| 1621 | }
|
---|
[24686] | 1622 | /*Free resources:*/
|
---|
[19554] | 1623 | if(mInit)xDelete<IssmDouble>(mInit);
|
---|
| 1624 |
|
---|
| 1625 | /*Assign output pointers:*/
|
---|
| 1626 | *pT=T;
|
---|
| 1627 | *pdz=dz;
|
---|
| 1628 | *pd=d;
|
---|
| 1629 | *pW=W;
|
---|
| 1630 | *pa=a;
|
---|
[26744] | 1631 | *padiff=adiff;
|
---|
[19554] | 1632 | *pre=re;
|
---|
| 1633 | *pgdn=gdn;
|
---|
| 1634 | *pgsp=gsp;
|
---|
| 1635 | *pm=m;
|
---|
[26744] | 1636 | *pRa=ra;
|
---|
[19554] | 1637 | } /*}}}*/
|
---|
[26744] | 1638 | void melt(IssmDouble* pM, IssmDouble* pMs, IssmDouble* pR, IssmDouble* pF, IssmDouble* pmAdd, IssmDouble* pdz_add, IssmDouble** pT, IssmDouble** pd, IssmDouble** pdz, IssmDouble** pW, IssmDouble** pa, IssmDouble** padiff, IssmDouble** pre, IssmDouble** pgdn, IssmDouble** pgsp, int* pn, IssmDouble Ra, IssmDouble dzMin, IssmDouble zMax, IssmDouble zMin, IssmDouble zTop, IssmDouble zY, IssmDouble dIce, int sid){ /*{{{*/
|
---|
[19554] | 1639 |
|
---|
| 1640 | //// MELT ROUTINE
|
---|
| 1641 |
|
---|
| 1642 | // Description:
|
---|
| 1643 | // computes the quantity of meltwater due to snow temperature in excess of
|
---|
| 1644 | // 0 deg C, determines pore water content and adjusts grid spacing
|
---|
| 1645 |
|
---|
| 1646 | /*intermediary:*/
|
---|
| 1647 | IssmDouble* m=NULL;
|
---|
| 1648 | IssmDouble* maxF=NULL;
|
---|
| 1649 | IssmDouble* dW=NULL;
|
---|
| 1650 | IssmDouble* exsW=NULL;
|
---|
| 1651 | IssmDouble* exsT=NULL;
|
---|
| 1652 | IssmDouble* surpT=NULL;
|
---|
| 1653 | IssmDouble* surpE=NULL;
|
---|
| 1654 | IssmDouble* flxDn=NULL;
|
---|
[22758] | 1655 | IssmDouble ER=0.0;
|
---|
[19554] | 1656 | IssmDouble* EI=NULL;
|
---|
| 1657 | IssmDouble* EW=NULL;
|
---|
| 1658 | IssmDouble* M=NULL;
|
---|
[26744] | 1659 | int* D=NULL;
|
---|
[23189] | 1660 |
|
---|
[22758] | 1661 | IssmDouble sumM=0.0;
|
---|
| 1662 | IssmDouble sumER=0.0;
|
---|
| 1663 | IssmDouble addE=0.0;
|
---|
| 1664 | IssmDouble mSum0=0.0;
|
---|
| 1665 | IssmDouble sumE0=0.0;
|
---|
| 1666 | IssmDouble mSum1=0.0;
|
---|
| 1667 | IssmDouble sumE1=0.0;
|
---|
| 1668 | IssmDouble dE=0.0;
|
---|
| 1669 | IssmDouble dm=0.0;
|
---|
| 1670 | IssmDouble X=0.0;
|
---|
| 1671 | IssmDouble Wi=0.0;
|
---|
[23189] | 1672 |
|
---|
[22758] | 1673 | int D_size = 0;
|
---|
[19554] | 1674 |
|
---|
| 1675 | /*outputs:*/
|
---|
[25836] | 1676 | IssmDouble Msurf = 0.0;
|
---|
[22758] | 1677 | IssmDouble mAdd = 0.0;
|
---|
[24686] | 1678 | IssmDouble surplusE = 0.0;
|
---|
| 1679 | IssmDouble surplusT = 0.0;
|
---|
[26744] | 1680 | IssmDouble dz_add = 0.0;
|
---|
[22758] | 1681 | IssmDouble Rsum = 0.0;
|
---|
[26744] | 1682 | IssmDouble Fsum = 0.0;
|
---|
[19554] | 1683 | IssmDouble* T=*pT;
|
---|
| 1684 | IssmDouble* d=*pd;
|
---|
| 1685 | IssmDouble* dz=*pdz;
|
---|
| 1686 | IssmDouble* W=*pW;
|
---|
| 1687 | IssmDouble* a=*pa;
|
---|
[26744] | 1688 | IssmDouble* adiff=*padiff;
|
---|
[19554] | 1689 | IssmDouble* re=*pre;
|
---|
| 1690 | IssmDouble* gdn=*pgdn;
|
---|
| 1691 | IssmDouble* gsp=*pgsp;
|
---|
| 1692 | int n=*pn;
|
---|
[22758] | 1693 | IssmDouble* R=NULL;
|
---|
[23189] | 1694 |
|
---|
[19566] | 1695 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0)_printf0_(" melt module\n");
|
---|
| 1696 |
|
---|
[19554] | 1697 | //// INITIALIZATION
|
---|
| 1698 |
|
---|
| 1699 | /*Allocations: */
|
---|
| 1700 | M=xNewZeroInit<IssmDouble>(n);
|
---|
[22758] | 1701 | maxF=xNewZeroInit<IssmDouble>(n);
|
---|
| 1702 | dW=xNewZeroInit<IssmDouble>(n);
|
---|
[19554] | 1703 |
|
---|
| 1704 | // store initial mass [kg] and energy [J]
|
---|
| 1705 | m=xNew<IssmDouble>(n); for(int i=0;i<n;i++) m[i] = dz[i]* d[i]; // grid cell mass [kg]
|
---|
| 1706 | EI=xNew<IssmDouble>(n); for(int i=0;i<n;i++)EI[i] = m[i] * T[i] * CI; // initial enegy of snow/ice
|
---|
| 1707 | EW=xNew<IssmDouble>(n); for(int i=0;i<n;i++)EW[i]= W[i] * (LF + CtoK * CI); // initial enegy of water
|
---|
| 1708 |
|
---|
| 1709 | mSum0 = cellsum(W,n) + cellsum(m,n); // total mass [kg]
|
---|
| 1710 | sumE0 = cellsum(EI,n) + cellsum(EW,n); // total energy [J]
|
---|
| 1711 |
|
---|
| 1712 | // initialize melt and runoff scalars
|
---|
[22758] | 1713 | Rsum = 0.0; // runoff [kg]
|
---|
[26744] | 1714 | Fsum = 0.0; // refreeze [kg]
|
---|
[22758] | 1715 | sumM = 0.0; // total melt [kg]
|
---|
| 1716 | mAdd = 0.0; // mass added/removed to/from base of model [kg]
|
---|
| 1717 | addE = 0.0; // energy added/removed to/from base of model [J]
|
---|
| 1718 | dz_add=0.0; // thickness of the layer added/removed to/from base of model [m]
|
---|
[19554] | 1719 |
|
---|
[19582] | 1720 | // calculate temperature excess above 0 deg C
|
---|
[19554] | 1721 | exsT=xNewZeroInit<IssmDouble>(n);
|
---|
[23394] | 1722 | for(int i=0;i<n;i++) exsT[i]= max(0.0, T[i] - CtoK); // [K] to [degC]
|
---|
[19554] | 1723 |
|
---|
| 1724 | // new grid point center temperature, T [K]
|
---|
[22758] | 1725 | // for(int i=0;i<n;i++) T[i]-=exsT[i];
|
---|
[23394] | 1726 | for(int i=0;i<n;i++) T[i]=min(T[i],CtoK);
|
---|
[23189] | 1727 |
|
---|
[19554] | 1728 | // specify irreducible water content saturation [fraction]
|
---|
| 1729 | const IssmDouble Swi = 0.07; // assumed constant after Colbeck, 1974
|
---|
[25836] | 1730 | const IssmDouble dPHC = 830; //Pore closeoff density
|
---|
[19554] | 1731 |
|
---|
| 1732 | //// REFREEZE PORE WATER
|
---|
| 1733 | // check if any pore water
|
---|
[22758] | 1734 | if (cellsum(W,n) >0.0+Wtol){
|
---|
[19582] | 1735 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0)_printf0_(" pore water refreeze\n");
|
---|
[19554] | 1736 | // calculate maximum freeze amount, maxF [kg]
|
---|
[23394] | 1737 | for(int i=0;i<n;i++) maxF[i] = max(0.0, -((T[i] - CtoK) * m[i] * CI) / LF);
|
---|
[19554] | 1738 |
|
---|
| 1739 | // freeze pore water and change snow/ice properties
|
---|
[23394] | 1740 | for(int i=0;i<n;i++) dW[i] = min(maxF[i], W[i]); // freeze mass [kg]
|
---|
[19554] | 1741 | for(int i=0;i<n;i++) W[i] -= dW[i]; // pore water mass [kg]
|
---|
| 1742 | for(int i=0;i<n;i++) m[i] += dW[i]; // new mass [kg]
|
---|
| 1743 | for(int i=0;i<n;i++) d[i] = m[i] / dz[i]; // density [kg m-3]
|
---|
[24313] | 1744 | for(int i=0;i<n;i++) if(m[i]>Wtol) T[i] = T[i] + (dW[i]*(LF+(CtoK - T[i])*CI)/(m[i]*CI)); // temperature [K]
|
---|
[19554] | 1745 |
|
---|
| 1746 | // if pore water froze in ice then adjust d and dz thickness
|
---|
[24313] | 1747 | for(int i=0;i<n;i++)if(d[i]> dIce-Dtol)d[i]=dIce;
|
---|
[19582] | 1748 | for(int i=0;i<n;i++) dz[i]= m[i]/d[i];
|
---|
[22758] | 1749 |
|
---|
[19554] | 1750 | }
|
---|
| 1751 |
|
---|
| 1752 | // squeeze water from snow pack
|
---|
[19582] | 1753 | exsW=xNew<IssmDouble>(n);
|
---|
| 1754 | for(int i=0;i<n;i++){
|
---|
[22758] | 1755 | Wi= (dIce - d[i]) * Swi * (m[i] / d[i]); // irreducible water content [kg]
|
---|
[23394] | 1756 | exsW[i] = max(0.0, W[i] - Wi); // water "squeezed" from snow [kg]
|
---|
[19554] | 1757 | }
|
---|
| 1758 |
|
---|
| 1759 | //// MELT, PERCOLATION AND REFREEZE
|
---|
| 1760 |
|
---|
[26744] | 1761 | // initialize refreeze, runoff, flxDn and dW vectors [kg]
|
---|
| 1762 | IssmDouble* F = xNewZeroInit<IssmDouble>(n);
|
---|
| 1763 |
|
---|
| 1764 | // Add previous refreeze to F and reset dW
|
---|
| 1765 | for(int i=0;i<n;i++){
|
---|
| 1766 | F[i]=F[i]+dW[i];
|
---|
| 1767 | dW[i] = 0.0;
|
---|
| 1768 | }
|
---|
| 1769 |
|
---|
[19554] | 1770 | // run melt algorithm if there is melt water or excess pore water
|
---|
[24313] | 1771 | if ((cellsum(exsT,n) > 0.0+Ttol) || (cellsum(exsW,n) > 0.0+Wtol)){
|
---|
[19554] | 1772 | // _printf_(""MELT OCCURS");
|
---|
| 1773 | // check to see if thermal energy exceeds energy to melt entire cell
|
---|
| 1774 | // if so redistribute temperature to lower cells (temperature surplus)
|
---|
| 1775 | // (maximum T of snow before entire grid cell melts is a constant
|
---|
| 1776 | // LF/CI = 159.1342)
|
---|
[23394] | 1777 | surpT=xNew<IssmDouble>(n); for(int i=0;i<n;i++)surpT[i] = max(0.0, exsT[i]- LF/CI);
|
---|
[22758] | 1778 |
|
---|
[24313] | 1779 | if (cellsum(surpT,n) > 0.0+Ttol ){
|
---|
[19554] | 1780 | // _printf_("T Surplus");
|
---|
| 1781 | // calculate surplus energy
|
---|
[21341] | 1782 | surpE=xNew<IssmDouble>(n); for(int i=0;i<n;i++)surpE[i] = surpT[i] * CI * m[i];
|
---|
[22758] | 1783 |
|
---|
[19554] | 1784 | int i = 0;
|
---|
[24313] | 1785 | while (cellsum(surpE,n) > 0.0+Ttol && i<n){
|
---|
[22758] | 1786 |
|
---|
[24686] | 1787 | if (i<n-1){
|
---|
| 1788 | // use surplus energy to increase the temperature of lower cell
|
---|
| 1789 | T[i+1] = surpE[i]/m[i+1]/CI + T[i+1];
|
---|
[22758] | 1790 |
|
---|
[24686] | 1791 | exsT[i+1] = max(0.0, T[i+1] - CtoK) + exsT[i+1];
|
---|
| 1792 | T[i+1] = min(CtoK, T[i+1]);
|
---|
[22758] | 1793 |
|
---|
[24686] | 1794 | surpT[i+1] = max(0.0, exsT[i+1] - LF/CI);
|
---|
| 1795 | surpE[i+1] = surpT[i+1] * CI * m[i+1];
|
---|
| 1796 | }
|
---|
| 1797 | else{
|
---|
| 1798 | surplusT=max(0.0, exsT[i] - LF/CI);
|
---|
| 1799 | surplusE=surpE[i];
|
---|
| 1800 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0){
|
---|
| 1801 | _printf0_(" WARNING: surplus energy at the base of GEMB column\n");
|
---|
| 1802 | }
|
---|
| 1803 | }
|
---|
| 1804 |
|
---|
[19554] | 1805 | // adjust current cell properties (again 159.1342 is the max T)
|
---|
[22758] | 1806 | exsT[i] = LF/CI;
|
---|
| 1807 | surpE[i] = 0.0;
|
---|
[19554] | 1808 | i = i + 1;
|
---|
| 1809 | }
|
---|
| 1810 | }
|
---|
| 1811 |
|
---|
| 1812 | // convert temperature excess to melt [kg]
|
---|
[24313] | 1813 | IssmDouble Mmax=0.0;
|
---|
| 1814 | for(int i=0;i<n;i++){
|
---|
| 1815 | Mmax=exsT[i] * d[i] * dz[i] * CI / LF;
|
---|
| 1816 | M[i] = min(Mmax, m[i]); // melt
|
---|
| 1817 | }
|
---|
[25836] | 1818 | Msurf = M[0];
|
---|
[26744] | 1819 | sumM = max(0.0,cellsum(M,n)-Ra); // total melt [kg] minus the liquid rain that had been added
|
---|
[19554] | 1820 |
|
---|
| 1821 | // calculate maximum refreeze amount, maxF [kg]
|
---|
[23394] | 1822 | for(int i=0;i<n;i++)maxF[i] = max(0.0, -((T[i] - CtoK) * d[i] * dz[i] * CI)/ LF);
|
---|
[19554] | 1823 |
|
---|
| 1824 | // initialize refreeze, runoff, flxDn and dW vectors [kg]
|
---|
[22758] | 1825 | IssmDouble* R = xNewZeroInit<IssmDouble>(n);
|
---|
[19582] | 1826 |
|
---|
[22758] | 1827 | flxDn=xNewZeroInit<IssmDouble>(n+1);
|
---|
[19554] | 1828 |
|
---|
| 1829 | // determine the deepest grid cell where melt/pore water is generated
|
---|
| 1830 | X = 0;
|
---|
| 1831 | for(int i=n-1;i>=0;i--){
|
---|
[24313] | 1832 | if(M[i]> 0.0+Wtol || exsW[i]> 0.0+Wtol){
|
---|
[19554] | 1833 | X=i;
|
---|
| 1834 | break;
|
---|
| 1835 | }
|
---|
| 1836 | }
|
---|
| 1837 |
|
---|
[25836] | 1838 | IssmDouble depthice=0.0;
|
---|
[26744] | 1839 | int Xi=0;
|
---|
[19554] | 1840 | //// meltwater percolation
|
---|
| 1841 | for(int i=0;i<n;i++){
|
---|
| 1842 | // calculate total melt water entering cell
|
---|
| 1843 | IssmDouble inM = M[i]+ flxDn[i];
|
---|
| 1844 |
|
---|
[25836] | 1845 | depthice=0.0;
|
---|
| 1846 | if (d[i] >= dPHC-Dtol){
|
---|
| 1847 | for(int l=i;(l<n && d[l]>=dPHC-Dtol);l++) depthice=depthice+dz[l];
|
---|
| 1848 | }
|
---|
| 1849 |
|
---|
[19554] | 1850 | // break loop if there is no meltwater and if depth is > mw_depth
|
---|
[24313] | 1851 | if (fabs(inM) < Wtol && i > X){
|
---|
[19554] | 1852 | break;
|
---|
| 1853 | }
|
---|
| 1854 | // if reaches impermeable ice layer all liquid water runs off (R)
|
---|
[25836] | 1855 | else if (d[i] >= dIce-Dtol || (d[i] >= dPHC-Dtol && depthice>0.1)){ // dPHC = pore hole close off [kg m-3]
|
---|
[19554] | 1856 | // _printf_("ICE LAYER");
|
---|
| 1857 | // no water freezes in this cell
|
---|
| 1858 | // no water percolates to lower cell
|
---|
| 1859 | // cell ice temperature & density do not change
|
---|
| 1860 |
|
---|
| 1861 | m[i] = m[i] - M[i]; // mass after melt
|
---|
[22758] | 1862 | Wi = (dIce-d[i]) * Swi * (m[i]/d[i]); // irreducible water
|
---|
[23394] | 1863 | dW[i] = max(min(inM, Wi - W[i]),-1*W[i]); // change in pore water
|
---|
| 1864 | R[i] = max(0.0, inM - dW[i]); // runoff
|
---|
[19554] | 1865 | }
|
---|
[21341] | 1866 | // check if no energy to refreeze meltwater
|
---|
[22758] | 1867 | else if (fabs(maxF[i]) < Dtol){
|
---|
[19554] | 1868 | // _printf_("REFREEZE == 0");
|
---|
| 1869 | // no water freezes in this cell
|
---|
| 1870 | // cell ice temperature & density do not change
|
---|
| 1871 |
|
---|
| 1872 | m[i] = m[i] - M[i]; // mass after melt
|
---|
[22758] | 1873 | Wi = (dIce-d[i]) * Swi * (m[i]/d[i]); // irreducible water
|
---|
[23394] | 1874 | dW[i] = max(min(inM, Wi - W[i]),-1*W[i]); // change in pore water
|
---|
| 1875 | flxDn[i+1] = max(0.0, inM - dW[i]); // meltwater out
|
---|
[22758] | 1876 | R[i] = 0.0;
|
---|
[19554] | 1877 | }
|
---|
| 1878 | // some or all meltwater refreezes
|
---|
| 1879 | else{
|
---|
[24313] | 1880 | // change in density and temperature
|
---|
[19554] | 1881 | // _printf_("MELT REFREEZE");
|
---|
| 1882 | //-----------------------melt water-----------------------------
|
---|
[22758] | 1883 | m[i] = m[i] - M[i];
|
---|
[19554] | 1884 | IssmDouble dz_0 = m[i]/d[i];
|
---|
| 1885 | IssmDouble dMax = (dIce - d[i])*dz_0; // d max = dIce
|
---|
[23394] | 1886 | IssmDouble F1 = min(min(inM,dMax),maxF[i]); // maximum refreeze
|
---|
[19554] | 1887 | m[i] = m[i] + F1; // mass after refreeze
|
---|
| 1888 | d[i] = m[i]/dz_0;
|
---|
| 1889 |
|
---|
| 1890 | //-----------------------pore water-----------------------------
|
---|
[22758] | 1891 | Wi = (dIce-d[i])* Swi * dz_0; // irreducible water
|
---|
[26744] | 1892 | dW[i] = max(min(inM - F1, Wi-W[i]),-1*W[i]); // change in pore water
|
---|
[22758] | 1893 | IssmDouble F2 = 0.0;
|
---|
[19554] | 1894 |
|
---|
[22758] | 1895 | if (dW[i] < 0.0-Wtol){ // excess pore water
|
---|
[19554] | 1896 | dMax = (dIce - d[i])*dz_0; // maximum refreeze
|
---|
[23394] | 1897 | IssmDouble maxF2 = min(dMax, maxF[i]-F1); // maximum refreeze
|
---|
| 1898 | F2 = min(-1*dW[i], maxF2); // pore water refreeze
|
---|
[19554] | 1899 | m[i] = m[i] + F2; // mass after refreeze
|
---|
| 1900 | d[i] = m[i]/dz_0;
|
---|
| 1901 | }
|
---|
| 1902 |
|
---|
[26744] | 1903 | F[i] = F[i] + F1 + F2;
|
---|
[22758] | 1904 |
|
---|
[26744] | 1905 | flxDn[i+1] = max(0.0,inM - F1 - dW[i]); // meltwater out
|
---|
[24313] | 1906 | if (m[i]>Wtol){
|
---|
| 1907 | T[i] = T[i] + ((F1+F2)*(LF+(CtoK - T[i])*CI)/(m[i]*CI));// change in temperature
|
---|
| 1908 | }
|
---|
[19554] | 1909 |
|
---|
| 1910 | // check if an ice layer forms
|
---|
[22758] | 1911 | if (fabs(d[i] - dIce) < Dtol){
|
---|
[19554] | 1912 | // _printf_("ICE LAYER FORMS");
|
---|
| 1913 | // excess water runs off
|
---|
| 1914 | R[i] = flxDn[i+1];
|
---|
| 1915 | // no water percolates to lower cell
|
---|
[22758] | 1916 | flxDn[i+1] = 0.0;
|
---|
[19554] | 1917 | }
|
---|
| 1918 | }
|
---|
[26744] | 1919 | Xi=Xi+1;
|
---|
[19554] | 1920 | }
|
---|
| 1921 |
|
---|
| 1922 | //// GRID CELL SPACING AND MODEL DEPTH
|
---|
[24313] | 1923 | for(int i=0;i<n;i++)if (W[i] < 0.0-Wtol) _error_("negative pore water generated in melt equations");
|
---|
[23189] | 1924 |
|
---|
[19554] | 1925 | // delete all cells with zero mass
|
---|
| 1926 | // adjust pore water
|
---|
| 1927 | for(int i=0;i<n;i++)W[i] += dW[i];
|
---|
| 1928 |
|
---|
[22758] | 1929 | //calculate Rsum:
|
---|
[26744] | 1930 | Rsum=cellsum(R,n) + flxDn[Xi];
|
---|
[22758] | 1931 |
|
---|
[19554] | 1932 | // delete all cells with zero mass
|
---|
[24313] | 1933 | D_size=0; for(int i=0;i<n;i++)if(m[i]> (0.0+Wtol))D_size++;
|
---|
[22758] | 1934 | D=xNew<int>(D_size);
|
---|
[24313] | 1935 | D_size=0; for(int i=0;i<n;i++)if(m[i]> (0.0+Wtol)){ D[D_size] = i; D_size++;}
|
---|
[22758] | 1936 |
|
---|
[19554] | 1937 | celldelete(&m,n,D,D_size);
|
---|
| 1938 | celldelete(&W,n,D,D_size);
|
---|
| 1939 | celldelete(&d,n,D,D_size);
|
---|
[25836] | 1940 | celldelete(&dz,n,D,D_size);
|
---|
[19554] | 1941 | celldelete(&T,n,D,D_size);
|
---|
| 1942 | celldelete(&a,n,D,D_size);
|
---|
[26744] | 1943 | celldelete(&adiff,n,D,D_size);
|
---|
[19554] | 1944 | celldelete(&re,n,D,D_size);
|
---|
| 1945 | celldelete(&gdn,n,D,D_size);
|
---|
| 1946 | celldelete(&gsp,n,D,D_size);
|
---|
[19582] | 1947 | celldelete(&EI,n,D,D_size);
|
---|
| 1948 | celldelete(&EW,n,D,D_size);
|
---|
[19554] | 1949 | n=D_size;
|
---|
[19613] | 1950 | xDelete<int>(D);
|
---|
[23189] | 1951 |
|
---|
[19554] | 1952 | // calculate new grid lengths
|
---|
| 1953 | for(int i=0;i<n;i++)dz[i] = m[i] / d[i];
|
---|
[19582] | 1954 |
|
---|
[24686] | 1955 | /*Free resources:*/
|
---|
[19613] | 1956 | xDelete<IssmDouble>(R);
|
---|
[19554] | 1957 | }
|
---|
[22758] | 1958 |
|
---|
[26744] | 1959 | //calculate Fsum:
|
---|
| 1960 | Fsum=cellsum(F,n);
|
---|
| 1961 |
|
---|
| 1962 | /*Free resources:*/
|
---|
| 1963 | xDelete<IssmDouble>(F);
|
---|
| 1964 |
|
---|
[27232] | 1965 | //Manage the layering to match the user defined requirements
|
---|
| 1966 | managelayers(&mAdd, &dz_add, &addE, &m, &EI, &EW, &T, &d, &dz, &W, &a, &adiff, &re, &gdn, &gsp, &n, dzMin, zMax, zMin, zTop, zY);
|
---|
| 1967 |
|
---|
| 1968 | //// CHECK FOR MASS AND ENERGY CONSERVATION
|
---|
| 1969 |
|
---|
| 1970 | // calculate final mass [kg] and energy [J]
|
---|
| 1971 | sumER = Rsum * (LF + CtoK * CI);
|
---|
| 1972 | for(int i=0;i<n;i++)EI[i] = m[i] * T[i] * CI;
|
---|
| 1973 | for(int i=0;i<n;i++)EW[i] = W[i] * (LF + CtoK * CI);
|
---|
| 1974 |
|
---|
| 1975 | mSum1 = cellsum(W,n) + cellsum(m,n) + Rsum;
|
---|
| 1976 | sumE1 = cellsum(EI,n) + cellsum(EW,n);
|
---|
| 1977 |
|
---|
| 1978 | /*checks: */
|
---|
| 1979 | for(int i=0;i<n;i++) if (W[i]<0.0-Wtol) _error_("negative pore water generated in melt equations\n");
|
---|
| 1980 |
|
---|
| 1981 | /*only in forward mode! avoid round in AD mode as it is not differentiable: */
|
---|
| 1982 | #ifndef _HAVE_AD_
|
---|
| 1983 | dm = round((mSum0 - mSum1 + mAdd)*100.0)/100.0;
|
---|
| 1984 | dE = round(sumE0 - sumE1 - sumER + addE - surplusE);
|
---|
| 1985 | if (dm !=0 || dE !=0) _error_("mass or energy are not conserved in melt equations\n"
|
---|
| 1986 | << "dm: " << dm << " dE: " << dE << "\n");
|
---|
| 1987 | #endif
|
---|
| 1988 |
|
---|
| 1989 | /*Free resources:*/
|
---|
| 1990 | if(m)xDelete<IssmDouble>(m);
|
---|
| 1991 | if(EI)xDelete<IssmDouble>(EI);
|
---|
| 1992 | if(EW)xDelete<IssmDouble>(EW);
|
---|
| 1993 | if(maxF)xDelete<IssmDouble>(maxF);
|
---|
| 1994 | if(dW)xDelete<IssmDouble>(dW);
|
---|
| 1995 | if(exsW)xDelete<IssmDouble>(exsW);
|
---|
| 1996 | if(exsT)xDelete<IssmDouble>(exsT);
|
---|
| 1997 | if(surpT)xDelete<IssmDouble>(surpT);
|
---|
| 1998 | if(surpE)xDelete<IssmDouble>(surpE);
|
---|
| 1999 | if(flxDn)xDelete<IssmDouble>(flxDn);
|
---|
| 2000 | if(D)xDelete<int>(D);
|
---|
| 2001 | if(M)xDelete<IssmDouble>(M);
|
---|
| 2002 |
|
---|
| 2003 | /*Assign output pointers:*/
|
---|
| 2004 | *pMs=Msurf;
|
---|
| 2005 | *pM=sumM;
|
---|
| 2006 | *pR=Rsum;
|
---|
| 2007 | *pF=Fsum;
|
---|
| 2008 | *pmAdd=mAdd;
|
---|
| 2009 | *pdz_add=dz_add;
|
---|
| 2010 |
|
---|
| 2011 | *pT=T;
|
---|
| 2012 | *pd=d;
|
---|
| 2013 | *pdz=dz;
|
---|
| 2014 | *pW=W;
|
---|
| 2015 | *pa=a;
|
---|
| 2016 | *padiff=adiff;
|
---|
| 2017 | *pre=re;
|
---|
| 2018 | *pgdn=gdn;
|
---|
| 2019 | *pgsp=gsp;
|
---|
| 2020 | *pn=n;
|
---|
| 2021 |
|
---|
| 2022 | } /*}}}*/
|
---|
| 2023 | void managelayers(IssmDouble* pmAdd, IssmDouble* pdz_add, IssmDouble* paddE, IssmDouble** pm, IssmDouble** pEI, IssmDouble** pEW, IssmDouble** pT, IssmDouble** pd, IssmDouble** pdz, IssmDouble** pW, IssmDouble** pa, IssmDouble** padiff, IssmDouble** pre, IssmDouble** pgdn, IssmDouble** pgsp, int* pn, IssmDouble dzMin, IssmDouble zMax, IssmDouble zMin, IssmDouble zTop, IssmDouble zY){ /*{{{*/
|
---|
| 2024 |
|
---|
| 2025 | /*intermediary:*/
|
---|
| 2026 | IssmDouble* Zcum=NULL;
|
---|
| 2027 | IssmDouble* dzMin2=NULL;
|
---|
| 2028 | IssmDouble* dzMax2=NULL;
|
---|
| 2029 | int* D=NULL;
|
---|
| 2030 |
|
---|
| 2031 | IssmDouble zY2=zY;
|
---|
| 2032 | IssmDouble X=0.0;
|
---|
| 2033 | int X1=0;
|
---|
| 2034 | int X2=0;
|
---|
| 2035 | int D_size = 0;
|
---|
| 2036 |
|
---|
| 2037 | IssmDouble Ztot=0.0;
|
---|
| 2038 | IssmDouble T_bot=0.0;
|
---|
| 2039 | IssmDouble m_bot=0.0;
|
---|
| 2040 | IssmDouble dz_bot=0.0;
|
---|
| 2041 | IssmDouble d_bot=0.0;
|
---|
| 2042 | IssmDouble W_bot=0.0;
|
---|
| 2043 | IssmDouble a_bot=0.0;
|
---|
| 2044 | IssmDouble adiff_bot=0.0;
|
---|
| 2045 | IssmDouble re_bot=0.0;
|
---|
| 2046 | IssmDouble gdn_bot=0.0;
|
---|
| 2047 | IssmDouble gsp_bot=0.0;
|
---|
| 2048 | IssmDouble EI_bot=0.0;
|
---|
| 2049 | IssmDouble EW_bot=0.0;
|
---|
| 2050 | bool top=false;
|
---|
| 2051 |
|
---|
| 2052 | /*outputs:*/
|
---|
| 2053 | IssmDouble mAdd = 0.0;
|
---|
| 2054 | IssmDouble addE = 0.0;
|
---|
| 2055 | IssmDouble dz_add = 0.0;
|
---|
| 2056 | IssmDouble* T=*pT;
|
---|
| 2057 | IssmDouble* d=*pd;
|
---|
| 2058 | IssmDouble* dz=*pdz;
|
---|
| 2059 | IssmDouble* W=*pW;
|
---|
| 2060 | IssmDouble* a=*pa;
|
---|
| 2061 | IssmDouble* adiff=*padiff;
|
---|
| 2062 | IssmDouble* re=*pre;
|
---|
| 2063 | IssmDouble* gdn=*pgdn;
|
---|
| 2064 | IssmDouble* gsp=*pgsp;
|
---|
| 2065 | IssmDouble* m=*pm;
|
---|
| 2066 | IssmDouble* EI=*pEI;
|
---|
| 2067 | IssmDouble* EW=*pEW;
|
---|
| 2068 | int n=*pn;
|
---|
| 2069 |
|
---|
[21341] | 2070 | //Merging of cells as they are burried under snow.
|
---|
| 2071 | Zcum=xNew<IssmDouble>(n);
|
---|
| 2072 | dzMin2=xNew<IssmDouble>(n);
|
---|
[25836] | 2073 | dzMax2=xNew<IssmDouble>(n);
|
---|
[23189] | 2074 |
|
---|
[25836] | 2075 | X=0;
|
---|
[21341] | 2076 | Zcum[0]=dz[0]; // Compute a cumulative depth vector
|
---|
| 2077 | for (int i=0;i<n;i++){
|
---|
[25836] | 2078 | if (i==0){
|
---|
[21341] | 2079 | dzMin2[i]=dzMin;
|
---|
| 2080 | }
|
---|
| 2081 | else{
|
---|
[25836] | 2082 | Zcum[i]=Zcum[i-1]+dz[i];
|
---|
| 2083 | if (Zcum[i]<=zTop+Dtol){
|
---|
| 2084 | dzMin2[i]=dzMin;
|
---|
| 2085 | X=i;
|
---|
| 2086 | }
|
---|
| 2087 | else{
|
---|
| 2088 | dzMin2[i]=zY2*dzMin2[i-1];
|
---|
| 2089 | }
|
---|
[21341] | 2090 | }
|
---|
| 2091 | }
|
---|
[19554] | 2092 |
|
---|
[25836] | 2093 | // Check to see if any cells are too small and need to be merged
|
---|
| 2094 | for (int i=0; i<n; i++){
|
---|
| 2095 | if ( (i<=X && dz[i]<dzMin-Dtol) || (i>X && dz[i]<dzMin2[i]-Dtol) ) {
|
---|
[23189] | 2096 |
|
---|
[25836] | 2097 | if (i==n-1){
|
---|
| 2098 | X2=i;
|
---|
| 2099 | //find closest cell to merge with
|
---|
| 2100 | for(int j=n-2;j>=0;j--){
|
---|
| 2101 | if(m[j]!=Delflag){
|
---|
| 2102 | X1=j;
|
---|
| 2103 | break;
|
---|
| 2104 | }
|
---|
| 2105 | }
|
---|
| 2106 | }
|
---|
| 2107 | else{
|
---|
| 2108 | X1=i+1;
|
---|
| 2109 | X2=i;
|
---|
| 2110 | }
|
---|
[19554] | 2111 |
|
---|
| 2112 | // adjust variables as a linearly weighted function of mass
|
---|
[25836] | 2113 | IssmDouble m_new = m[X2] + m[X1];
|
---|
| 2114 | T[X1] = (T[X2]*m[X2] + T[X1]*m[X1]) / m_new;
|
---|
| 2115 | a[X1] = (a[X2]*m[X2] + a[X1]*m[X1]) / m_new;
|
---|
[26744] | 2116 | adiff[X1] = (adiff[X2]*m[X2] + adiff[X1]*m[X1]) / m_new;
|
---|
[27232] | 2117 | //use grain properties from lower cell
|
---|
| 2118 | re[X1] = re[X2];
|
---|
| 2119 | gdn[X1] = gdn[X2];
|
---|
| 2120 | gsp[X1] = gsp[X2];
|
---|
[23189] | 2121 |
|
---|
[19554] | 2122 | // merge with underlying grid cell and delete old cell
|
---|
[25836] | 2123 | dz[X1] = dz[X2] + dz[X1]; // combine cell depths
|
---|
| 2124 | d[X1] = m_new / dz[X1]; // combine top densities
|
---|
| 2125 | W[X1] = W[X1] + W[X2]; // combine liquid water
|
---|
| 2126 | m[X1] = m_new; // combine top masses
|
---|
[23189] | 2127 |
|
---|
[24686] | 2128 | // set cell to -99999 for deletion
|
---|
[25836] | 2129 | m[X2] = Delflag;
|
---|
[19554] | 2130 | }
|
---|
| 2131 | }
|
---|
| 2132 |
|
---|
| 2133 | // delete combined cells
|
---|
[24313] | 2134 | D_size=0; for(int i=0;i<n;i++)if(m[i]> Delflag+Wtol)D_size++;
|
---|
[22758] | 2135 | D=xNew<int>(D_size);
|
---|
[24313] | 2136 | D_size=0; for(int i=0;i<n;i++)if(m[i]> Delflag+Wtol){ D[D_size] = i; D_size++;}
|
---|
[19554] | 2137 |
|
---|
[19582] | 2138 | celldelete(&m,n,D,D_size);
|
---|
| 2139 | celldelete(&W,n,D,D_size);
|
---|
| 2140 | celldelete(&dz,n,D,D_size);
|
---|
| 2141 | celldelete(&d,n,D,D_size);
|
---|
| 2142 | celldelete(&T,n,D,D_size);
|
---|
| 2143 | celldelete(&a,n,D,D_size);
|
---|
[26744] | 2144 | celldelete(&adiff,n,D,D_size);
|
---|
[19582] | 2145 | celldelete(&re,n,D,D_size);
|
---|
| 2146 | celldelete(&gdn,n,D,D_size);
|
---|
| 2147 | celldelete(&gsp,n,D,D_size);
|
---|
| 2148 | celldelete(&EI,n,D,D_size);
|
---|
| 2149 | celldelete(&EW,n,D,D_size);
|
---|
| 2150 | n=D_size;
|
---|
[19613] | 2151 | xDelete<int>(D);
|
---|
[23189] | 2152 |
|
---|
[25836] | 2153 | // check if any of the cell depths are too large
|
---|
[19582] | 2154 | X=0;
|
---|
[25836] | 2155 | Zcum[0]=dz[0]; // Compute a cumulative depth vector
|
---|
| 2156 | for (int i=0;i<n;i++){
|
---|
| 2157 | if (i==0){
|
---|
| 2158 | dzMax2[i]=dzMin*2;
|
---|
[19582] | 2159 | }
|
---|
[25836] | 2160 | else{
|
---|
| 2161 | Zcum[i]=Zcum[i-1]+dz[i];
|
---|
| 2162 | if (Zcum[i]<=zTop+Dtol){
|
---|
| 2163 | dzMax2[i]=dzMin*2;
|
---|
| 2164 | X=i;
|
---|
| 2165 | }
|
---|
| 2166 | else{
|
---|
| 2167 | dzMax2[i]=max(zY2*dzMin2[i-1],dzMin*2);
|
---|
| 2168 | }
|
---|
| 2169 | }
|
---|
[19582] | 2170 | }
|
---|
[23189] | 2171 |
|
---|
[25836] | 2172 | for (int j=n-1;j>=0;j--){
|
---|
| 2173 | if ((j<X && dz[j] > dzMax2[j]+Dtol) || (dz[j] > dzMax2[j]*zY2+Dtol)){
|
---|
[24686] | 2174 | // _printf_("dz > dzMin * 2");
|
---|
| 2175 | // split in two
|
---|
| 2176 | cellsplit(&dz, n, j,.5);
|
---|
| 2177 | cellsplit(&W, n, j,.5);
|
---|
| 2178 | cellsplit(&m, n, j,.5);
|
---|
| 2179 | cellsplit(&T, n, j,1.0);
|
---|
| 2180 | cellsplit(&d, n, j,1.0);
|
---|
| 2181 | cellsplit(&a, n, j,1.0);
|
---|
[26744] | 2182 | cellsplit(&adiff, n, j,1.0);
|
---|
[24686] | 2183 | cellsplit(&EI, n, j,.5);
|
---|
| 2184 | cellsplit(&EW, n, j,.5);
|
---|
| 2185 | cellsplit(&re, n, j,1.0);
|
---|
| 2186 | cellsplit(&gdn, n, j,1.0);
|
---|
| 2187 | cellsplit(&gsp, n, j,1.0);
|
---|
| 2188 | n++;
|
---|
[19582] | 2189 | }
|
---|
| 2190 | }
|
---|
| 2191 |
|
---|
[19554] | 2192 | //// CORRECT FOR TOTAL MODEL DEPTH
|
---|
| 2193 | // WORKS FINE BUT HAS BEEN DISABLED FOR CONVIENCE OF MODEL OUTPUT
|
---|
| 2194 | // INTERPRETATION
|
---|
[22758] | 2195 | // calculate total model depth
|
---|
[21341] | 2196 | Ztot = cellsum(dz,n);
|
---|
[23189] | 2197 |
|
---|
[22758] | 2198 | if (Ztot < zMin-Dtol){
|
---|
[21341] | 2199 | // printf("Total depth < zMin %f \n", Ztot);
|
---|
| 2200 | // mass and energy to be added
|
---|
| 2201 | mAdd = m[n-1]+W[n-1];
|
---|
[22758] | 2202 | addE = T[n-1]*m[n-1]*CI + W[n-1]*(LF+CtoK*CI);
|
---|
[23189] | 2203 |
|
---|
[21341] | 2204 | // add a grid cell of the same size and temperature to the bottom
|
---|
| 2205 | dz_bot=dz[n-1];
|
---|
| 2206 | T_bot=T[n-1];
|
---|
| 2207 | W_bot=W[n-1];
|
---|
| 2208 | m_bot=m[n-1];
|
---|
| 2209 | d_bot=d[n-1];
|
---|
| 2210 | a_bot=a[n-1];
|
---|
[26744] | 2211 | adiff_bot=adiff[n-1];
|
---|
[21341] | 2212 | re_bot=re[n-1];
|
---|
| 2213 | gdn_bot=gdn[n-1];
|
---|
| 2214 | gsp_bot=gsp[n-1];
|
---|
[22758] | 2215 | EI_bot=EI[n-1];
|
---|
| 2216 | EW_bot=EW[n-1];
|
---|
[23189] | 2217 |
|
---|
[21341] | 2218 | dz_add=dz_bot;
|
---|
[23189] | 2219 |
|
---|
[21341] | 2220 | newcell(&dz,dz_bot,top,n);
|
---|
| 2221 | newcell(&T,T_bot,top,n);
|
---|
| 2222 | newcell(&W,W_bot,top,n);
|
---|
| 2223 | newcell(&m,m_bot,top,n);
|
---|
| 2224 | newcell(&d,d_bot,top,n);
|
---|
| 2225 | newcell(&a,a_bot,top,n);
|
---|
[26744] | 2226 | newcell(&adiff,adiff_bot,top,n);
|
---|
[21341] | 2227 | newcell(&re,re_bot,top,n);
|
---|
| 2228 | newcell(&gdn,gdn_bot,top,n);
|
---|
| 2229 | newcell(&gsp,gsp_bot,top,n);
|
---|
[22758] | 2230 | newcell(&EI,EI_bot,top,n);
|
---|
| 2231 | newcell(&EW,EW_bot,top,n);
|
---|
[21341] | 2232 | n=n+1;
|
---|
| 2233 | }
|
---|
[22758] | 2234 | else if (Ztot > zMax+Dtol){
|
---|
[21341] | 2235 | // printf("Total depth > zMax %f \n", Ztot);
|
---|
| 2236 | // mass and energy loss
|
---|
| 2237 | mAdd = -(m[n-1]+W[n-1]);
|
---|
[22758] | 2238 | addE = -(T[n-1]*m[n-1]*CI) - (W[n-1]*(LF+CtoK*CI));
|
---|
[21341] | 2239 | dz_add=-(dz[n-1]);
|
---|
[23189] | 2240 |
|
---|
[22758] | 2241 | // remove a grid cell from the bottom
|
---|
[21341] | 2242 | D_size=n-1;
|
---|
| 2243 | D=xNew<int>(D_size);
|
---|
[23189] | 2244 |
|
---|
[21341] | 2245 | for(int i=0;i<n-1;i++) D[i]=i;
|
---|
| 2246 | celldelete(&dz,n,D,D_size);
|
---|
| 2247 | celldelete(&T,n,D,D_size);
|
---|
| 2248 | celldelete(&W,n,D,D_size);
|
---|
| 2249 | celldelete(&m,n,D,D_size);
|
---|
| 2250 | celldelete(&d,n,D,D_size);
|
---|
| 2251 | celldelete(&a,n,D,D_size);
|
---|
[26744] | 2252 | celldelete(&adiff,n,D,D_size);
|
---|
[21341] | 2253 | celldelete(&re,n,D,D_size);
|
---|
| 2254 | celldelete(&gdn,n,D,D_size);
|
---|
| 2255 | celldelete(&gsp,n,D,D_size);
|
---|
[22758] | 2256 | celldelete(&EI,n,D,D_size);
|
---|
| 2257 | celldelete(&EW,n,D,D_size);
|
---|
[21341] | 2258 | n=D_size;
|
---|
| 2259 | xDelete<int>(D);
|
---|
| 2260 | }
|
---|
[19554] | 2261 |
|
---|
[24686] | 2262 | /*Free resources:*/
|
---|
[21341] | 2263 | xDelete<IssmDouble>(Zcum);
|
---|
| 2264 | xDelete<IssmDouble>(dzMin2);
|
---|
[25836] | 2265 | xDelete<IssmDouble>(dzMax2);
|
---|
[27232] | 2266 | if(D)xDelete<int>(D);
|
---|
[23189] | 2267 |
|
---|
[19554] | 2268 | /*Assign output pointers:*/
|
---|
| 2269 | *pT=T;
|
---|
| 2270 | *pd=d;
|
---|
| 2271 | *pdz=dz;
|
---|
| 2272 | *pW=W;
|
---|
| 2273 | *pa=a;
|
---|
[26744] | 2274 | *padiff=adiff;
|
---|
[19554] | 2275 | *pre=re;
|
---|
| 2276 | *pgdn=gdn;
|
---|
| 2277 | *pgsp=gsp;
|
---|
| 2278 | *pn=n;
|
---|
[27232] | 2279 | *pm=m;
|
---|
| 2280 | *pEI=EI;
|
---|
| 2281 | *pEW=EW;
|
---|
[19554] | 2282 |
|
---|
[27232] | 2283 | *pmAdd=mAdd;
|
---|
| 2284 | *paddE=addE;
|
---|
| 2285 | *pdz_add=dz_add;
|
---|
| 2286 |
|
---|
[19554] | 2287 | } /*}}}*/
|
---|
[25836] | 2288 | void densification(IssmDouble** pd,IssmDouble** pdz, IssmDouble* T, IssmDouble* re, int denIdx, int aIdx, int swIdx, IssmDouble adThresh, IssmDouble C, IssmDouble dt, IssmDouble Tmean, IssmDouble dIce, int m, int sid){ /*{{{*/
|
---|
[19554] | 2289 |
|
---|
[22758] | 2290 | //// THIS NEEDS TO BE DOUBLE CHECKED AS THERE SEAMS TO BE LITTLE DENSIFICATION IN THE MODEL OUTOUT [MAYBE COMPACTION IS COMPENSATED FOR BY TRACES OF SNOW???]
|
---|
[19554] | 2291 |
|
---|
| 2292 | //// FUNCTION INFO
|
---|
| 2293 |
|
---|
| 2294 | // Author: Alex Gardner, University of Alberta
|
---|
| 2295 | // Date last modified: FEB, 2008
|
---|
| 2296 |
|
---|
| 2297 | // Description:
|
---|
| 2298 | // computes the densification of snow/firn using the emperical model of
|
---|
| 2299 | // Herron and Langway (1980) or the semi-emperical model of Anthern et al.
|
---|
| 2300 | // (2010)
|
---|
| 2301 |
|
---|
| 2302 | // Inputs:
|
---|
| 2303 | // denIdx = densification model to use:
|
---|
| 2304 | // 1 = emperical model of Herron and Langway (1980)
|
---|
| 2305 | // 2 = semi-imerical model of Anthern et al. (2010)
|
---|
| 2306 | // 3 = physical model from Appendix B of Anthern et al. (2010)
|
---|
| 2307 | // d = initial snow/firn density [kg m-3]
|
---|
| 2308 | // T = temperature [K]
|
---|
| 2309 | // dz = grid cell size [m]
|
---|
| 2310 | // C = average accumulation rate [kg m-2 yr-1]
|
---|
| 2311 | // dt = time lapsed [s]
|
---|
| 2312 | // re = effective grain radius [mm];
|
---|
| 2313 | // Ta = mean annual temperature
|
---|
| 2314 |
|
---|
| 2315 | // Reference:
|
---|
| 2316 | // Herron and Langway (1980), Anthern et al. (2010)
|
---|
| 2317 |
|
---|
| 2318 | //// FOR TESTING
|
---|
| 2319 | // denIdx = 2;
|
---|
| 2320 | // d = 800;
|
---|
| 2321 | // T = 270;
|
---|
| 2322 | // dz = 0.005;
|
---|
| 2323 | // C = 200;
|
---|
| 2324 | // dt = 60*60;
|
---|
| 2325 | // re = 0.7;
|
---|
| 2326 | // Tmean = 273.15-18;
|
---|
| 2327 |
|
---|
| 2328 | //// MAIN FUNCTION
|
---|
| 2329 | // specify constants
|
---|
[22758] | 2330 | dt = dt / dts; // convert from [s] to [d]
|
---|
[19554] | 2331 | // R = 8.314 // gas constant [mol-1 K-1]
|
---|
| 2332 | // Ec = 60 // activation energy for self-diffusion of water
|
---|
| 2333 | // // molecules through the ice tattice [kJ mol-1]
|
---|
| 2334 | // Eg = 42.4 // activation energy for grain growth [kJ mol-1]
|
---|
| 2335 |
|
---|
| 2336 | /*intermediary: */
|
---|
[22758] | 2337 | IssmDouble c0=0.0;
|
---|
| 2338 | IssmDouble c1=0.0;
|
---|
[27232] | 2339 | IssmDouble c2=0.0;
|
---|
[22758] | 2340 | IssmDouble H=0.0;
|
---|
[23189] | 2341 | IssmDouble M0=0.0;
|
---|
| 2342 | IssmDouble M1=0.0;
|
---|
[27232] | 2343 | IssmDouble M2=0.0;
|
---|
[23189] | 2344 | IssmDouble c0arth=0.0;
|
---|
| 2345 | IssmDouble c1arth=0.0;
|
---|
[22758] | 2346 |
|
---|
| 2347 | /*output: */
|
---|
| 2348 | IssmDouble* dz=NULL;
|
---|
| 2349 | IssmDouble* d=NULL;
|
---|
[23189] | 2350 |
|
---|
[19566] | 2351 | if(VerboseSmb() && sid==0 && IssmComm::GetRank()==0)_printf0_(" densification module\n");
|
---|
[19554] | 2352 |
|
---|
[22758] | 2353 | /*Recover pointers: */
|
---|
| 2354 | dz=*pdz;
|
---|
| 2355 | d=*pd;
|
---|
| 2356 |
|
---|
[19554] | 2357 | // initial mass
|
---|
| 2358 | IssmDouble* mass_init = xNew<IssmDouble>(m);for(int i=0;i<m;i++) mass_init[i]=d[i] * dz[i];
|
---|
[23189] | 2359 |
|
---|
[19554] | 2360 | /*allocations and initialization of overburden pressure and factor H: */
|
---|
| 2361 | IssmDouble* cumdz = xNew<IssmDouble>(m-1);
|
---|
| 2362 | cumdz[0]=dz[0];
|
---|
| 2363 | for(int i=1;i<m-1;i++)cumdz[i]=cumdz[i-1]+dz[i];
|
---|
| 2364 |
|
---|
| 2365 | IssmDouble* obp = xNew<IssmDouble>(m);
|
---|
[22758] | 2366 | obp[0]=0.0;
|
---|
[19582] | 2367 | for(int i=1;i<m;i++)obp[i]=cumdz[i-1]*d[i-1];
|
---|
[23189] | 2368 |
|
---|
[19554] | 2369 | // calculate new snow/firn density for:
|
---|
| 2370 | // snow with densities <= 550 [kg m-3]
|
---|
| 2371 | // snow with densities > 550 [kg m-3]
|
---|
[23189] | 2372 |
|
---|
[19554] | 2373 | for(int i=0;i<m;i++){
|
---|
| 2374 | switch (denIdx){
|
---|
| 2375 | case 1: // Herron and Langway (1980)
|
---|
[23189] | 2376 | c0 = (11.0 * exp(-10160.0 / (T[i] * R))) * C/1000.0;
|
---|
| 2377 | c1 = (575.0 * exp(-21400.0 / (T[i]* R))) * pow(C/1000.0,.5);
|
---|
[19554] | 2378 | break;
|
---|
[23189] | 2379 |
|
---|
[19554] | 2380 | case 2: // Arthern et al. (2010) [semi-emperical]
|
---|
| 2381 | // common variable
|
---|
| 2382 | // NOTE: Ec=60000, Eg=42400 (i.e. should be in J not kJ)
|
---|
[23189] | 2383 | H = exp((-60000.0/(T[i] * R)) + (42400.0/(Tmean * R))) * (C * 9.81);
|
---|
[19554] | 2384 | c0 = 0.07 * H;
|
---|
| 2385 | c1 = 0.03 * H;
|
---|
| 2386 | break;
|
---|
| 2387 |
|
---|
| 2388 | case 3: // Arthern et al. (2010) [physical model eqn. B1]
|
---|
| 2389 |
|
---|
| 2390 | // common variable
|
---|
[23189] | 2391 | H = exp((-60000.0/(T[i] * R))) * obp[i] / pow(re[i]/1000.0,2.0);
|
---|
[19582] | 2392 | c0 = 9.2e-9 * H;
|
---|
| 2393 | c1 = 3.7e-9 * H;
|
---|
[19554] | 2394 | break;
|
---|
| 2395 |
|
---|
| 2396 | case 4: // Li and Zwally (2004)
|
---|
[22758] | 2397 | c0 = (C/dIce) * (139.21 - 0.542*Tmean)*8.36*pow(CtoK - T[i],-2.061);
|
---|
[19554] | 2398 | c1 = c0;
|
---|
| 2399 | break;
|
---|
| 2400 |
|
---|
| 2401 | case 5: // Helsen et al. (2008)
|
---|
| 2402 | // common variable
|
---|
[22758] | 2403 | c0 = (C/dIce) * (76.138 - 0.28965*Tmean)*8.36*pow(CtoK - T[i],-2.061);
|
---|
[19554] | 2404 | c1 = c0;
|
---|
| 2405 | break;
|
---|
[23189] | 2406 |
|
---|
| 2407 | case 6: // Ligtenberg and others (2011) [semi-emperical], Antarctica
|
---|
| 2408 | // common variable
|
---|
[24313] | 2409 | // From literature: H = exp((-60000.0/(Tmean * R)) + (42400.0/(Tmean * R))) * (C * 9.81);
|
---|
| 2410 | H = exp((-60000.0/(T[i] * R)) + (42400.0/(Tmean * R))) * (C * 9.81);
|
---|
[23189] | 2411 | c0arth = 0.07 * H;
|
---|
| 2412 | c1arth = 0.03 * H;
|
---|
[25836] | 2413 | //ERA-5 old
|
---|
| 2414 | //M0 = max(2.3128 - (0.2480 * log(C)),0.25);
|
---|
| 2415 | //M1 = max(2.7950 - (0.3318 * log(C)),0.25);
|
---|
| 2416 | // ERA5 new aIdx=1, swIdx=0
|
---|
| 2417 | if (aIdx==1 && swIdx==0){
|
---|
| 2418 | if (fabs(adThresh - 820) < Dtol){
|
---|
[27232] | 2419 | // ERA5 v4
|
---|
| 2420 | M0 = max(1.5131 - (0.1317 * log(C)),0.25);
|
---|
| 2421 | M1 = max(1.8819 - (0.2158 * log(C)),0.25);
|
---|
[25836] | 2422 | }
|
---|
| 2423 | else{
|
---|
| 2424 | // ERA5 new aIdx=1, swIdx=0
|
---|
| 2425 | //M0 = max(1.8785 - (0.1811 * log(C)),0.25);
|
---|
| 2426 | //M1 = max(2.0005 - (0.2346 * log(C)),0.25);
|
---|
| 2427 | // ERA5 new aIdx=1, swIdx=0, bare ice
|
---|
| 2428 | M0 = max(1.8422 - (0.1688 * log(C)),0.25);
|
---|
| 2429 | M1 = max(2.4979 - (0.3225 * log(C)),0.25);
|
---|
| 2430 | }
|
---|
| 2431 | }
|
---|
| 2432 | // ERA5 new aIdx=2, swIdx=1
|
---|
| 2433 | else if (aIdx<3 && swIdx>0){
|
---|
| 2434 | M0 = max(2.2191 - (0.2301 * log(C)),0.25);
|
---|
| 2435 | M1 = max(2.2917 - (0.2710 * log(C)),0.25);
|
---|
| 2436 | }
|
---|
| 2437 | // ERA5 new aIdx=2, swIdx=0
|
---|
| 2438 | //else if (aIdx==2){
|
---|
| 2439 | //}
|
---|
[24686] | 2440 | //From Ligtenberg
|
---|
| 2441 | //H = exp((-60000.0/(Tmean * R)) + (42400.0/(Tmean * R))) * (C * 9.81);
|
---|
[24313] | 2442 | //M0 = max(1.435 - (0.151 * log(C)),0.25);
|
---|
| 2443 | //M1 = max(2.366 - (0.293 * log(C)),0.25);
|
---|
[27232] | 2444 | //RACMO
|
---|
| 2445 | M0 = max(1.6383 - (0.1691 * log(C)),0.25);
|
---|
| 2446 | M1 = max(1.9991 - (0.2414 * log(C)),0.25);
|
---|
[23189] | 2447 | c0 = M0*c0arth;
|
---|
| 2448 | c1 = M1*c1arth;
|
---|
[27232] | 2449 | c2 = M2*c1arth;
|
---|
[23189] | 2450 | break;
|
---|
| 2451 |
|
---|
| 2452 | case 7: // Kuipers Munneke and others (2015) [semi-emperical], Greenland
|
---|
| 2453 | // common variable
|
---|
[24313] | 2454 | // From literature: H = exp((-60000.0/(T[i] * R)) + (42400.0/(T[i] * R))) * (C * 9.81);
|
---|
| 2455 | H = exp((-60000.0/(T[i] * R)) + (42400.0/(Tmean * R))) * (C * 9.81);
|
---|
[23189] | 2456 | c0arth = 0.07 * H;
|
---|
| 2457 | c1arth = 0.03 * H;
|
---|
[25836] | 2458 | // ERA5 old
|
---|
| 2459 | //M0 = max(1.8554 - (0.1316 * log(C)),0.25);
|
---|
| 2460 | //M1 = max(2.8901 - (0.3014 * log(C)),0.25);
|
---|
| 2461 | // ERA5 new aIdx=1, swIdx=0
|
---|
| 2462 | if (aIdx==1 && swIdx==0){
|
---|
| 2463 | if (fabs(adThresh - 820) < Dtol){
|
---|
[27232] | 2464 | // ERA5 v4
|
---|
| 2465 | M0 = max(1.3566 - (0.1350 * log(C)),0.25);
|
---|
| 2466 | M1 = max(1.8705 - (0.2290 * log(C)),0.25);
|
---|
[25836] | 2467 | }
|
---|
| 2468 | else{
|
---|
| 2469 | // ERA5 new aIdx=1, swIdx=0
|
---|
| 2470 | //M0 = max(1.4574 - (0.1123 * log(C)),0.25);
|
---|
| 2471 | //M1 = max(2.0238 - (0.2070 * log(C)),0.25);
|
---|
| 2472 | // ERA5 new aIdx=1, swIdx=0, bare ice
|
---|
| 2473 | M0 = max(1.4318 - (0.1055 * log(C)),0.25);
|
---|
| 2474 | M1 = max(2.0453 - (0.2137 * log(C)),0.25);
|
---|
| 2475 | }
|
---|
| 2476 | }
|
---|
| 2477 | // ERA5 new aIdx=2, swIdx=1
|
---|
| 2478 | else if (aIdx<3 && swIdx>0){
|
---|
| 2479 | M0 = max(1.7834 - (0.1409 * log(C)),0.25);
|
---|
| 2480 | M1 = max(1.9260 - (0.1527 * log(C)),0.25);
|
---|
| 2481 | }
|
---|
| 2482 | // ERA5 new aIdx=2, swIdx=0
|
---|
| 2483 | //else if (aIdx==2){
|
---|
| 2484 | //}
|
---|
| 2485 | // From Kuipers Munneke
|
---|
| 2486 | //M0 = max(1.042 - (0.0916 * log(C)),0.25);
|
---|
| 2487 | //M1 = max(1.734 - (0.2039 * log(C)),0.25);
|
---|
[24686] | 2488 | // RACMO
|
---|
[27232] | 2489 | M0 = max(1.2691 - (0.1184 * log(C)),0.25);
|
---|
| 2490 | M1 = max(1.9983 - (0.2511 * log(C)),0.25);
|
---|
| 2491 | c0 = M0*c0arth;
|
---|
| 2492 | c1 = M1*c1arth;
|
---|
| 2493 | c2 = M2*c1arth;
|
---|
[23189] | 2494 | break;
|
---|
[19554] | 2495 | }
|
---|
| 2496 |
|
---|
[27232] | 2497 | // new snow density
|
---|
| 2498 | if(d[i] <= 550.0+Dtol) d[i] = d[i] + (c0 * (dIce - d[i]) / 365.0 * dt);
|
---|
| 2499 | else if(d[i] <= 830.0+Dtol | fabs(c2)<Dtol) d[i] = d[i] + (c1 * (dIce - d[i]) / 365.0 * dt);
|
---|
| 2500 | else d[i] = d[i] + (c2 * (dIce - d[i]) / 365.0 * dt);
|
---|
[19554] | 2501 |
|
---|
| 2502 | // do not allow densities to exceed the density of ice
|
---|
[24313] | 2503 | if(d[i] > dIce-Ptol) d[i]=dIce;
|
---|
[19554] | 2504 |
|
---|
| 2505 | // calculate new grid cell length
|
---|
| 2506 | dz[i] = mass_init[i] / d[i];
|
---|
| 2507 | }
|
---|
[19566] | 2508 |
|
---|
[24686] | 2509 | /*Free resources:*/
|
---|
[19554] | 2510 | xDelete<IssmDouble>(mass_init);
|
---|
| 2511 | xDelete<IssmDouble>(cumdz);
|
---|
| 2512 | xDelete<IssmDouble>(obp);
|
---|
| 2513 |
|
---|
[22758] | 2514 | /*Assign output pointers:*/
|
---|
| 2515 | *pdz=dz;
|
---|
| 2516 | *pd=d;
|
---|
| 2517 |
|
---|
[19554] | 2518 | } /*}}}*/
|
---|