/*!\file SurfaceMassBalancex * \brief: calculates SMB */ #include #include "./SurfaceMassBalancex.h" #include "../../shared/shared.h" #include "../../toolkits/toolkits.h" #include "../modules.h" #include "../../classes/Inputs/TransientInput.h" #include "../../shared/Random/random.h" void SmbForcingx(FemModel* femmodel){/*{{{*/ // void SmbForcingx(smb,ni){ // INPUT parameters: ni: working size of arrays // OUTPUT: mass-balance (m/yr ice): agd(NA) }/*}}}*/ void SmbGradientsx(FemModel* femmodel){/*{{{*/ // void SurfaceMassBalancex(hd,agd,ni){ // INPUT parameters: ni: working size of arrays // INPUT: surface elevation (m): hd(NA) // OUTPUT: mass-balance (m/yr ice): agd(NA) int v; IssmDouble rho_water; // density of fresh water IssmDouble rho_ice; // density of ice IssmDouble yts; // conversion factor year to second /*Loop over all the elements of this partition*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); /*Allocate all arrays*/ int numvertices = element->GetNumberOfVertices(); IssmDouble* Href = xNew(numvertices); // reference elevation from which deviations are used to calculate the SMB adjustment IssmDouble* Smbref = xNew(numvertices); // reference SMB to which deviations are added IssmDouble* b_pos = xNew(numvertices); // Hs-SMB relation parameter IssmDouble* b_neg = xNew(numvertices); // Hs-SMB relation paremeter IssmDouble* s = xNew(numvertices); // surface elevation (m) IssmDouble* smb = xNew(numvertices); /*Recover SmbGradients*/ element->GetInputListOnVertices(Href,SmbHrefEnum); element->GetInputListOnVertices(Smbref,SmbSmbrefEnum); element->GetInputListOnVertices(b_pos,SmbBPosEnum); element->GetInputListOnVertices(b_neg,SmbBNegEnum); /*Recover surface elevation at vertices: */ element->GetInputListOnVertices(s,SurfaceEnum); /*Get material parameters :*/ rho_ice=element->FindParam(MaterialsRhoIceEnum); rho_water=element->FindParam(MaterialsRhoFreshwaterEnum); /* Get constants */ femmodel->parameters->FindParam(&yts,ConstantsYtsEnum); // loop over all vertices for(v=0;v0){ smb[v]=Smbref[v]+b_pos[v]*(s[v]-Href[v]); } else{ smb[v]=Smbref[v]+b_neg[v]*(s[v]-Href[v]); } smb[v]=smb[v]/1000*rho_water/rho_ice; // SMB in m/y ice } //end of the loop over the vertices /*Add input to element and Free memory*/ element->AddInput(SmbMassBalanceEnum,smb,P1Enum); xDelete(Href); xDelete(Smbref); xDelete(b_pos); xDelete(b_neg); xDelete(s); xDelete(smb); } }/*}}}*/ void SmbGradientsElax(FemModel* femmodel){/*{{{*/ // void SurfaceMassBalancex(hd,agd,ni){ // INPUT parameters: ni: working size of arrays // INPUT: surface elevation (m): hd(NA) // OUTPUT: surface mass-balance (m/yr ice): agd(NA) int v; /*Loop over all the elements of this partition*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); /*Allocate all arrays*/ int numvertices = element->GetNumberOfVertices(); IssmDouble* ela = xNew(numvertices); // Equilibrium Line Altitude (m a.s.l) to which deviations are used to calculate the SMB IssmDouble* b_pos = xNew(numvertices); // SMB gradient above ELA (m ice eq. per m elevation change) IssmDouble* b_neg = xNew(numvertices); // SMB gradient below ELA (m ice eq. per m elevation change) IssmDouble* b_max = xNew(numvertices); // Upper cap on SMB rate (m/y ice eq.) IssmDouble* b_min = xNew(numvertices); // Lower cap on SMB rate (m/y ice eq.) IssmDouble* s = xNew(numvertices); // Surface elevation (m a.s.l.) IssmDouble* smb = xNew(numvertices); // SMB (m/y ice eq.) /*Recover ELA, SMB gradients, and caps*/ element->GetInputListOnVertices(ela,SmbElaEnum); element->GetInputListOnVertices(b_pos,SmbBPosEnum); element->GetInputListOnVertices(b_neg,SmbBNegEnum); element->GetInputListOnVertices(b_max,SmbBMaxEnum); element->GetInputListOnVertices(b_min,SmbBMinEnum); /*Recover surface elevation at vertices: */ element->GetInputListOnVertices(s,SurfaceEnum); /*Loop over all vertices, calculate SMB*/ for(v=0;vela[v]){ smb[v]=b_pos[v]*(s[v]-ela[v]); } // if surface is below or equal to the ELA else{ smb[v]=b_neg[v]*(s[v]-ela[v]); } // if SMB is larger than upper cap, set SMB to upper cap if(smb[v]>b_max[v]){ smb[v]=b_max[v]; } // if SMB is smaller than lower cap, set SMB to lower cap if(smb[v]AddInput(SmbMassBalanceEnum,smb,P1Enum); xDelete(ela); xDelete(b_pos); xDelete(b_neg); xDelete(b_max); xDelete(b_min); xDelete(s); xDelete(smb); } }/*}}}*/ void SmbautoregressionInitx(FemModel* femmodel){/*{{{*/ /*Initialization step of Smbautoregressionx*/ int M,N,Nphi,arorder,numbasins,my_rank; IssmDouble starttime,tstep_ar,tinit_ar; femmodel->parameters->FindParam(&numbasins,SmbNumBasinsEnum); femmodel->parameters->FindParam(&arorder,SmbAutoregressiveOrderEnum); IssmDouble* beta0 = NULL; IssmDouble* beta1 = NULL; IssmDouble* phi = NULL; femmodel->parameters->FindParam(&starttime,TimesteppingStartTimeEnum); femmodel->parameters->FindParam(&tstep_ar,SmbAutoregressionTimestepEnum); femmodel->parameters->FindParam(&tinit_ar,SmbAutoregressionInitialTimeEnum); femmodel->parameters->FindParam(&beta0,&M,SmbBeta0Enum); _assert_(M==numbasins); femmodel->parameters->FindParam(&beta1,&M,SmbBeta1Enum); _assert_(M==numbasins); femmodel->parameters->FindParam(&phi,&M,&Nphi,SmbPhiEnum); _assert_(M==numbasins); _assert_(Nphi==arorder); /*AR model spin-up with 0 noise to initialize SmbValuesAutoregressionEnum (688 = log(0.001)/log(0.99): decaying time of inluence of phi[0]=0.99 to 0.001 of beta_0*/ int nspin = 688; for(Object* &object:femmodel->elements->objects){ Element* element = xDynamicCast(object); //generate element object element->AutoregressionInit(numbasins,arorder,nspin,starttime,tstep_ar,tinit_ar,beta0,beta1,phi,SMBautoregressionEnum); } /*Cleanup*/ xDelete(beta0); xDelete(beta1); xDelete(phi); }/*}}}*/ void Smbautoregressionx(FemModel* femmodel){/*{{{*/ /*Get time parameters*/ IssmDouble time,dt,starttime,tstep_ar; femmodel->parameters->FindParam(&time,TimeEnum); femmodel->parameters->FindParam(&dt,TimesteppingTimeStepEnum); femmodel->parameters->FindParam(&starttime,TimesteppingStartTimeEnum); femmodel->parameters->FindParam(&tstep_ar,SmbAutoregressionTimestepEnum); /*Initialize module at first time step*/ if(time<=starttime+dt){SmbautoregressionInitx(femmodel);} /*Determine if this is a time step for the AR model*/ bool isstepforar = false; #ifndef _HAVE_AD_ if((fmod(time,tstep_ar)parameters->FindParam(&numbasins,SmbNumBasinsEnum); femmodel->parameters->FindParam(&arorder,SmbAutoregressiveOrderEnum); femmodel->parameters->FindParam(&numelevbins,SmbNumElevationBinsEnum); IssmDouble tinit_ar; IssmDouble* beta0 = NULL; IssmDouble* beta1 = NULL; IssmDouble* phi = NULL; IssmDouble* lapserates = NULL; IssmDouble* elevbins = NULL; IssmDouble* refelevation = NULL; femmodel->parameters->FindParam(&tinit_ar,SmbAutoregressionInitialTimeEnum); femmodel->parameters->FindParam(&beta0,&M,SmbBeta0Enum); _assert_(M==numbasins); femmodel->parameters->FindParam(&beta1,&M,SmbBeta1Enum); _assert_(M==numbasins); femmodel->parameters->FindParam(&phi,&M,&Nphi,SmbPhiEnum); _assert_(M==numbasins); _assert_(Nphi==arorder); femmodel->parameters->FindParam(&lapserates,&M,&N,SmbLapseRatesEnum); _assert_(M==numbasins); _assert_(N==numelevbins); femmodel->parameters->FindParam(&elevbins,&M,&N,SmbElevationBinsEnum); _assert_(M==numbasins); _assert_(N==numelevbins-1); femmodel->parameters->FindParam(&refelevation,&M,SmbRefElevationEnum); _assert_(M==numbasins); femmodel->parameters->FindParam(&isstochastic,StochasticForcingIsStochasticForcingEnum); if(isstochastic){ int numstochasticfields; int* stochasticfields; femmodel->parameters->FindParam(&numstochasticfields,StochasticForcingNumFieldsEnum); femmodel->parameters->FindParam(&stochasticfields,&N,StochasticForcingFieldsEnum); _assert_(N==numstochasticfields); for(int i=0;i(stochasticfields); } /*Time elapsed with respect to AR model initial time*/ IssmDouble telapsed_ar = time-tinit_ar; /*Loop over each element to compute SMB at vertices*/ for(Object* &object:femmodel->elements->objects){ Element* element = xDynamicCast(object); /*Compute autoregression*/ element->Autoregression(isstepforar,arorder,telapsed_ar,beta0,beta1,phi,issmbstochastic,SMBautoregressionEnum); /*Compute lapse rate adjustment*/ element->LapseRateBasinSMB(numelevbins,lapserates,elevbins,refelevation); } /*Cleanup*/ xDelete(beta0); xDelete(beta1); xDelete(phi); xDelete(lapserates); xDelete(elevbins); xDelete(refelevation); }/*}}}*/ void Delta18oParameterizationx(FemModel* femmodel){/*{{{*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); element->Delta18oParameterization(); } }/*}}}*/ void MungsmtpParameterizationx(FemModel* femmodel){/*{{{*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); element->MungsmtpParameterization(); } }/*}}}*/ void Delta18opdParameterizationx(FemModel* femmodel){/*{{{*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); element->Delta18opdParameterization(); } }/*}}}*/ void PositiveDegreeDayx(FemModel* femmodel){/*{{{*/ // void PositiveDegreeDayx(hd,vTempsea,vPrec,agd,Tsurf,ni){ // note "v" prefix means 12 monthly means, ie time dimension // INPUT parameters: ni: working size of arrays // INPUT: surface elevation (m): hd(NA) // monthly mean surface sealevel temperature (degrees C): vTempsea(NA // ,NTIME) // monthly mean precip rate (m/yr water equivalent): vPrec(NA,NTIME) // OUTPUT: mass-balance (m/yr ice): agd(NA) // mean annual surface temperature (degrees C): Tsurf(NA) int it, jj, itm; IssmDouble DT = 0.02, sigfac, snormfac; IssmDouble signorm = 5.5; // signorm : sigma of the temperature distribution for a normal day IssmDouble siglim; // sigma limit for the integration which is equal to 2.5 sigmanorm IssmDouble signormc = signorm - 0.5; // sigma of the temperature distribution for cloudy day IssmDouble siglimc, siglim0, siglim0c; IssmDouble tstep, tsint, tint, tstepc; int NPDMAX = 1504, NPDCMAX = 1454; //IssmDouble pdds[NPDMAX]={0}; //IssmDouble pds[NPDCMAX]={0}; IssmDouble pddt, pd ; // pd : snow/precip fraction, precipitation falling as snow IssmDouble PDup, PDCUT = 2.0; // PDcut: rain/snow cutoff temperature (C) IssmDouble tstar; // monthly mean surface temp bool ismungsm; bool issetpddfac; IssmDouble *pdds = NULL; IssmDouble *pds = NULL; Element *element = NULL; pdds=xNew(NPDMAX+1); pds=xNew(NPDCMAX+1); // Get ismungsm parameter femmodel->parameters->FindParam(&ismungsm,SmbIsmungsmEnum); // Get issetpddfac parameter femmodel->parameters->FindParam(&issetpddfac,SmbIssetpddfacEnum); /* initialize PDD (creation of a lookup table)*/ tstep = 0.1; tsint = tstep*0.5; sigfac = -1.0/(2.0*pow(signorm,2)); snormfac = 1.0/(signorm*sqrt(2.0*acos(-1.0))); siglim = 2.5*signorm; siglimc = 2.5*signormc; siglim0 = siglim/DT + 0.5; siglim0c = siglimc/DT + 0.5; PDup = siglimc+PDCUT; itm = reCast((2*siglim/DT + 1.5)); if(itm >= NPDMAX) _error_("increase NPDMAX in massBalance.cpp"); for(it = 0; it < itm; it++){ // tstar = REAL(it)*DT-siglim; tstar = it*DT-siglim; tint = tsint; pddt = 0.; for ( jj = 0; jj < 600; jj++){ if (tint > (tstar+siglim)){break;} pddt = pddt + tint*exp(sigfac*(pow((tint-tstar),2)))*tstep; tint = tint+tstep; } pdds[it] = pddt*snormfac; } pdds[itm+1] = siglim + DT; //*********compute PD(T) : snow/precip fraction. precipitation falling as snow tstepc = 0.1; tsint = PDCUT-tstepc*0.5; signormc = signorm - 0.5; sigfac = -1.0/(2.0*pow(signormc,2)); snormfac = 1.0/(signormc*sqrt(2.0*acos(-1.0))); siglimc = 2.5*signormc ; itm = reCast((PDCUT+2.*siglimc)/DT + 1.5); if(itm >= NPDCMAX) _error_("increase NPDCMAX in p35com"); for(it = 0; it < itm; it++ ){ tstar = it*DT-siglimc; // tstar = REAL(it)*DT-siglimc; tint = tsint; // start against upper bound pd = 0.; for (jj = 0; jj < 600; jj++){ if (tint<(tstar-siglimc)) {break;} pd = pd + exp(sigfac*(pow((tint-tstar),2)))*tstepc; tint = tint-tstepc; } pds[it] = pd*snormfac; // gaussian integral lookup table for snow fraction } pds[itm+1] = 0.; // *******END initialize PDD for(Object* & object : femmodel->elements->objects){ element=xDynamicCast(object); element->PositiveDegreeDay(pdds,pds,signorm,ismungsm,issetpddfac); } /*free ressouces: */ xDelete(pdds); xDelete(pds); }/*}}}*/ void PositiveDegreeDaySicopolisx(FemModel* femmodel){/*{{{*/ bool isfirnwarming; femmodel->parameters->FindParam(&isfirnwarming,SmbIsfirnwarmingEnum); for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); element->PositiveDegreeDaySicopolis(isfirnwarming); } }/*}}}*/ void SmbHenningx(FemModel* femmodel){/*{{{*/ /*Intermediaries*/ IssmDouble z_critical = 1675.; IssmDouble dz = 0; IssmDouble a = -15.86; IssmDouble b = 0.00969; IssmDouble c = -0.235; IssmDouble f = 1.; IssmDouble g = -0.0011; IssmDouble h = -1.54e-5; IssmDouble smb,smbref,anomaly,yts,z; /* Get constants */ femmodel->parameters->FindParam(&yts,ConstantsYtsEnum); /*iomodel->FindConstant(&yts,"md.constants.yts");*/ /*this->parameters->FindParam(&yts,ConstantsYtsEnum);*/ /*Mathieu original*/ /*IssmDouble smb,smbref,z;*/ /*Loop over all the elements of this partition*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); /*Get reference SMB (uncorrected) and allocate all arrays*/ int numvertices = element->GetNumberOfVertices(); IssmDouble* surfacelist = xNew(numvertices); IssmDouble* smblistref = xNew(numvertices); IssmDouble* smblist = xNew(numvertices); element->GetInputListOnVertices(surfacelist,SurfaceEnum); element->GetInputListOnVertices(smblistref,SmbSmbrefEnum); /*Loop over all vertices of element and correct SMB as a function of altitude z*/ for(int v=0;v z_critical = 1675 */ z_critical = z_critical + dz; /* Calculate smb acc. to the surface elevation z */ if(zAddInput(SmbMassBalanceEnum,smblist,P1Enum); xDelete(surfacelist); xDelete(smblistref); xDelete(smblist); } }/*}}}*/ void SmbComponentsx(FemModel* femmodel){/*{{{*/ // void SmbComponentsx(acc,evap,runoff,ni){ // INPUT parameters: ni: working size of arrays // INPUT: surface accumulation (m/yr water equivalent): acc // surface evaporation (m/yr water equivalent): evap // surface runoff (m/yr water equivalent): runoff // OUTPUT: mass-balance (m/yr ice): agd(NA) /*Loop over all the elements of this partition*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); /*Allocate all arrays*/ int numvertices = element->GetNumberOfVertices(); IssmDouble* acc = xNew(numvertices); IssmDouble* evap = xNew(numvertices); IssmDouble* runoff = xNew(numvertices); IssmDouble* smb = xNew(numvertices); /*Recover Smb Components*/ element->GetInputListOnVertices(acc,SmbAccumulationEnum); element->GetInputListOnVertices(evap,SmbEvaporationEnum); element->GetInputListOnVertices(runoff,SmbRunoffEnum); // loop over all vertices for(int v=0;vAddInput(SmbMassBalanceEnum,smb,P1Enum); xDelete(acc); xDelete(evap); xDelete(runoff); xDelete(smb); } }/*}}}*/ void SmbMeltComponentsx(FemModel* femmodel){/*{{{*/ // void SmbMeltComponentsx(acc,evap,melt,refreeze,ni){ // INPUT parameters: ni: working size of arrays // INPUT: surface accumulation (m/yr water equivalent): acc // surface evaporation (m/yr water equivalent): evap // surface melt (m/yr water equivalent): melt // refreeze of surface melt (m/yr water equivalent): refreeze // OUTPUT: mass-balance (m/yr ice): agd(NA) /*Loop over all the elements of this partition*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); /*Allocate all arrays*/ int numvertices = element->GetNumberOfVertices(); IssmDouble* acc = xNew(numvertices); IssmDouble* evap = xNew(numvertices); IssmDouble* melt = xNew(numvertices); IssmDouble* refreeze = xNew(numvertices); IssmDouble* smb = xNew(numvertices); /*Recover Smb Components*/ element->GetInputListOnVertices(acc,SmbAccumulationEnum); element->GetInputListOnVertices(evap,SmbEvaporationEnum); element->GetInputListOnVertices(melt,SmbMeltEnum); element->GetInputListOnVertices(refreeze,SmbRefreezeEnum); // loop over all vertices for(int v=0;vAddInput(SmbMassBalanceEnum,smb,P1Enum); xDelete(acc); xDelete(evap); xDelete(melt); xDelete(refreeze); xDelete(smb); } }/*}}}*/ void SmbGradientsComponentsx(FemModel* femmodel){/*{{{*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); element->SmbGradCompParameterization(); } }/*}}}*/ #ifdef _HAVE_SEMIC_ void SmbSemicx(FemModel* femmodel){/*{{{*/ for(Object* & object : femmodel->elements->objects){ Element* element=xDynamicCast(object); element->SmbSemic(); } }/*}}}*/ #else void SmbSemicx(FemModel* femmodel){_error_("SEMIC not installed");} #endif //_HAVE_SEMIC_