From 7f09a0739a94cac8ae82bb2ec440ec44e4631dc8 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Tue, 16 Jan 2018 09:37:36 +0100 Subject: [PATCH 01/45] Added the single-column xice modifications to the github version on branch -xice- --- CryoGrid3.m | 140 +++++--- add_modules.m | 5 +- .../CryoGridInfiltration.m | 2 +- .../cryoGridExcessIce/conductivityFreeWater.m | 9 + modules/cryoGridExcessIce/excessGroundIce.m | 8 + .../cryoGridExcessIce/excessGroundIceThaw4.m | 140 ++++++++ .../cryoGridExcessIce/initializeExcessIce.m | 19 ++ .../cryoGridExcessIce/initializeExcessIce2.m | 23 ++ modules/cryoGridExcessIce/mixingWaterBody.m | 14 + modules/cryoGridExcessIce/moveWater2Top.m | 44 +++ modules/cryoGridExcessIce/removeWater.m | 36 ++ .../cryoGridExcessIce/updateGRID_excessice.m | 78 +++++ .../excessGroundIceInfiltration.m | 18 + .../excessGroundIceThaw4Infiltration.m | 211 ++++++++++++ .../updateGRID_excessiceInfiltration.m | 88 +++++ .../updateGRID_excessiceInfiltration2.m | 43 +++ modules/cryoGridFlake/cryoGridFLAKE.m | 144 ++++++++ modules/cryoGridFlake/updateGRID_flake.m | 16 + .../cryoGridInitialize/generateTemporary.m | 20 ++ .../cryoGridInitialize/initializeBALANCE.m | 7 +- modules/cryoGridInitialize/initializeHYDRO.m | 34 ++ modules/cryoGridInitialize/initializeLAKE.m | 31 ++ modules/cryoGridSnow/CryoGridSnow.m | 16 +- modules/cryoGridSnow/maxLiqWater.m | 15 +- modules/cryoGridSnow/melt.m | 49 ++- modules/cryoGridSnow/refreeze.m | 2 +- modules/cryoGridSnow/snowMelt.m | 52 ++- modules/cryoGridSnow/updateGRID_snow.m | 319 +++++++++--------- modules/cryoGridSoil/conductionDevries.m | 215 ++++++++++++ modules/cryoGridSoil/getSoilThermalNew.m | 70 ++++ modules/cryoGridTechnical/add_modules.m | 15 + modules/cryoGridTechnical/generateLOOPVAR.m | 45 +++ modules/cryoGridTechnical/generateOUT.m | 13 +- .../initializeWaterEnergyBalance.m | 14 + modules/cryoGridTechnical/loadConstants.m | 14 +- .../cryoGridTechnical/sum_up_output_store.m | 46 ++- .../updateWaterEnergyBalance.m | 63 ++-- 37 files changed, 1776 insertions(+), 302 deletions(-) create mode 100644 modules/cryoGridExcessIce/conductivityFreeWater.m create mode 100644 modules/cryoGridExcessIce/excessGroundIce.m create mode 100644 modules/cryoGridExcessIce/excessGroundIceThaw4.m create mode 100644 modules/cryoGridExcessIce/initializeExcessIce.m create mode 100644 modules/cryoGridExcessIce/initializeExcessIce2.m create mode 100644 modules/cryoGridExcessIce/mixingWaterBody.m create mode 100644 modules/cryoGridExcessIce/moveWater2Top.m create mode 100644 modules/cryoGridExcessIce/removeWater.m create mode 100644 modules/cryoGridExcessIce/updateGRID_excessice.m create mode 100644 modules/cryoGridExcessIceInfiltration/excessGroundIceInfiltration.m create mode 100644 modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m create mode 100644 modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration.m create mode 100644 modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m create mode 100644 modules/cryoGridFlake/cryoGridFLAKE.m create mode 100644 modules/cryoGridFlake/updateGRID_flake.m create mode 100644 modules/cryoGridInitialize/initializeHYDRO.m create mode 100644 modules/cryoGridInitialize/initializeLAKE.m create mode 100644 modules/cryoGridSoil/conductionDevries.m create mode 100644 modules/cryoGridSoil/getSoilThermalNew.m create mode 100644 modules/cryoGridTechnical/add_modules.m create mode 100644 modules/cryoGridTechnical/generateLOOPVAR.m create mode 100644 modules/cryoGridTechnical/initializeWaterEnergyBalance.m diff --git a/CryoGrid3.m b/CryoGrid3.m index 47231d8..2e98a26 100755 --- a/CryoGrid3.m +++ b/CryoGrid3.m @@ -7,16 +7,29 @@ % ------------------------------------------------------------------------- paraFromFile = exist('configFile'); % check if config file passed -add_modules; % adds required modules -createLogFile=1; % set to true/1 if the command window output shall be saved + +add_modules; %adds required modules + +createLogFile=1; %---------------define input parameters------------------------------------ % here you provide the ground stratigraphy % z w/i m o type porosity + +%default used in publication: PARA.soil.layer_properties=[ 0.0 0.40 0.10 0.15 1 0.75;... 0.15 0.65 0.30 0.05 2 0.65;... 0.9 0.40 0.55 0.05 1 0.40;... 9.0 0.30 0.70 0.00 1 0.30 ]; +%simple stratigraphy with excess ice used to test water balance: +% PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... +% 0.4 0.8 0.2 0.00 1 0.40;... +% 10.0 0.25 0.75 0.00 1 0.25 ]; +%very simply stratigraphy without excess ice used to test energy balance +% soilType = 1; +% PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... +% 1.0 0.5 0.5 0.00 1 0.5 ;... +% 10.0 0.25 0.75 0.00 1 0.25 ]; % soil stratigraphy % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer % extends until the end of the model domain @@ -27,7 +40,6 @@ % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs %------ model parameters -------------------------------------------------- -% parameters related to surface energy balance and boundary conditions PARA.soil.albedo=0.2; % albedo snow-free surface PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development PARA.soil.epsilon=0.97; % emissvity snow-free surface @@ -46,7 +58,7 @@ PARA.soil.externalWaterFlux=0;%-2e-3; %external water flux / drainage in [m/day] PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile -PARA.soil.waterTable=0.0; % depth at which a water table will form [m] - above excess water is removed, below it pools up +PARA.soil.waterTable=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up % parameters related to snow PARA.snow.max_albedo=0.85; % albedo of fresh snow @@ -58,19 +70,29 @@ PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] PARA.snow.tau_a=0.008; % [per day] PARA.snow.tau_f=0.24; % [per day] -PARA.snow.maxSnow= [] ; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold +PARA.snow.maxSnow= [0.2] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold PARA.snow.extinction=25.0; % light extinction coefficient of snow -% parameters related to the site location +% parameters related to water body on top of soil domain +PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) +PARA.water.epsilon=0.99; % surface emissivity water +PARA.water.rs=0.0; % surface resistance -> should be 0 for water +PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation + +PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 +PARA.ice.epsilon=0.98; % surface emissivity snow +PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice +PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow +PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given -% technical parameters PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity PARA.technical.starttime=datenum('2000.06.01 00:00:00','yyyy.mm.dd HH:MM:SS'); % starttime of the simulation - if empty start from first value of time series -PARA.technical.endtime=datenum('2000.06.15 00:00:00','yyyy.mm.dd HH:MM:SS'); % endtime of the simulation - if empty end at last value of time series +PARA.technical.endtime=datenum('2000.07.01 00:00:00','yyyy.mm.dd HH:MM:SS'); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -78,42 +100,51 @@ PARA.technical.saveDate='01.08.'; % date of year when output file is written - no effect if "saveInterval" is empty PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + +%default grid used for publications and testing of water balance: PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] +%very simple grid used for testing of energy balance: +%PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; %initial temperature profile -> first column depth [m] -> second column temperature [degree C] %default: -PARA.Tinitial = [-5 10;... - 0 0;... - 5 -5;... - 20 -10;... - 100 -10;... - 2000 10]; - -% load natural constants (given in SI units) to PARA.constants -PARA = loadConstants(PARA); +PARA.Tinitial = [ -5 5 ;... + 0 -5 ;... + 1 -5 ;... + 10 -8 ;... + 20 -10 ;... + 100 -10 ;... + 2000 10 ]; + +PARA = loadConstants( PARA ); + %FORCING data mat-file PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files -PARA.forcing.rain_fraction=0; -PARA.forcing.snow_fraction=0; +PARA.forcing.rain_fraction=1; +PARA.forcing.snow_fraction=1; % switches for modules -PARA.modules.infiltration = 0; % true if infiltration into unfrozen ground occurs +PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs +PARA.modules.xice=1; % true if thaw subsicdence is enabled % ------update parameter values if config file provided ------------------- -% ------changes output directory to name specified in configfile which is the config filename by default +% ------changes output directory to name specified in configfile which is +% the config filename by default if paraFromFile run(configFile); end -run_number = sprintf('testrun'); +run_number = sprintf('testrun_infiltration%d_xice%d_rf%d_sf%d_wt%0.2f_exampleFlorentina', ... + [PARA.modules.infiltration, PARA.modules.xice, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.soil.waterTable]); + % ------make output directory (name depends on parameters) ---------------- mkdir(run_number) % ------redirect command line output to logfile --------------------------- if createLogFile - diary(['./' run_number '/' run_number '_log.mat']); + diary(['./' run_number '/' run_number '_diary.log']); end @@ -123,15 +154,18 @@ [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file if ~success - return + warning('A problem with the Forcing occured.'); end clear success PARA = initializeParameters(PARA, FORCING); %set start time, etc. %----------------create and initialize the grids -------------------------- -GRID=makeGrids(PARA); %create all grids -GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid +GRID=makeGrids(PARA); %create all grids +GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + +%----- initializie excess ground ice -------------------------------------- +[GRID,PARA] = initializeExcessIce2(GRID,PARA); %----- initializie soil thermal properties -------------------------------- GRID = initializeSoilThermalProperties(GRID, PARA); @@ -142,6 +176,9 @@ %---- initialize the surface energy balance struct ------------------------ SEB = initializeSEB(); +%---- initialize the water body module ------------------------------------ +GRID = initializeLAKE(GRID); + %---- initialize temperature profile -------------------------------------- T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); @@ -151,7 +188,7 @@ GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; %---- preallocate temporary arrays for capacity and conductivity----------- -[c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); +[c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid %---- energy and water balance initialization ----------------------------- BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); @@ -176,7 +213,6 @@ %------determine the thermal properties of the model domains ---------- [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = getThermalPropertiesInfiltration(T, wc, c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid, GRID, PARA); - lwc = lwc_cTgrid(GRID.soil.cT_domain); %------- water and energy balance calculations ------------------------ BALANCE = updateBALANCE(T, wc, c_cTgrid, lwc_cTgrid, BALANCE, GRID, PARA); @@ -194,13 +230,16 @@ %------ sum up heat fluxes -------------------------------------------- SEB.dE_dt = SEB.dE_dt_cond + SEB.dE_dt_SEB; - %------ determine optimal timestep [days] ----------------------------- - % accounting for min and max timesteps specified, maximum energy change per grid cell and the CFT stability criterion - timestep = min( [ max( [ min( [ 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600), ... - PARA.technical.targetDeltaE .* min( abs(GRID.general.K_delta ./ SEB.dE_dt) ) ./ (24.*3600), ... + %------ determine optimal timestep ------------------------------------ + % account for min and max timesteps specified, max. energy change per grid cell and the CFT stability criterion. + % energy change due to advection of heat through water fluxes is still excluded. + % timestep in [days] + timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600), ... + PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... PARA.technical.maxTimestep ] ), ... PARA.technical.minTimestep ] ), ... TEMPORARY.outputTime-t ] ); + % give a warning when timestep required by CFT criterion is below the minimum timestep specified if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) @@ -209,7 +248,10 @@ %------ update T array ------------------------------------------------ T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; - T(GRID.air.cT_domain)=FORCING.i.Tair; + T(GRID.air.cT_domain)=FORCING.i.Tair; %set grid cells in air to air temperature + + %------- water body module -------------------------------------------- + T = mixingWaterBody(T, GRID); %------- snow cover module -------------------------------------------- [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); @@ -219,7 +261,18 @@ if PARA.modules.infiltration [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); end - + + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.modules.infiltration + warning( 'energy and water balances are not correct for this combination of modules'); + [GRID, PARA] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); + elseif PARA.modules.xice && PARA.modules.infiltration + [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); + GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + end + %------- update Lstar for next time step ------------------------------ SEB = L_star(FORCING, PARA, SEB); @@ -227,25 +280,14 @@ % rainfall BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval % snowfall - BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm SWE] per output interval + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval - %---------- sum up + OUTPUT ------------------------------------------- - sum_up_output_store; - %------- next time step ----------------------------------------------- t=t+timestep; - - %final energy state - if t>=PARA.technical.endtime - % get lwc for current (after timestep) thermal state - [c_cTgrid, ~, ~, lwc_cTgrid] = getThermalPropertiesInfiltration(T, wc, c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid, GRID, PARA); - BALANCE = updateBALANCE(T, wc, c_cTgrid, lwc_cTgrid, BALANCE, GRID, PARA); - % final output at t=endtime - sum_up_output_store; - end - + %---------- sum up + OUTPUT ------------------------------------------- + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT); end %profile off save([run_number '/' run_number '_output.mat'], 'OUT') -disp('Done.'); \ No newline at end of file +disp('Done.'); diff --git a/add_modules.m b/add_modules.m index 09a0800..ffce5fe 100644 --- a/add_modules.m +++ b/add_modules.m @@ -5,7 +5,7 @@ close all profile off dbclear if error - +%dbstop if error %import CryoGrid modules (matlab functions) addpath('modules/cryoGridTechnical/') @@ -14,3 +14,6 @@ addpath('modules/cryoGridSoil/') addpath('modules/cryoGridSnow/') addpath('modules/CryoGridInfiltrationUnfrozenSoil') +addpath('modules/cryoGridExcessIce/') +addpath('modules/cryoGridExcessIceInfiltration') +%addpath('modules/cryoGridRockFields/') diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m index 459d8fe..cd092a8 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m @@ -10,7 +10,7 @@ % external flux external_flux_rate = PARA.soil.externalWaterFlux; % in m/day - BALANCE.water.dr_subsurface = BALANCE.water.dr_subsurface + external_flux_rate.*timestep.*1000; %in mm + BALANCE.water.dr_external = BALANCE.water.dr_external + external_flux_rate.*timestep.*1000; %in mm if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 %no snow cover and uppermost grid cell unfrozen diff --git a/modules/cryoGridExcessIce/conductivityFreeWater.m b/modules/cryoGridExcessIce/conductivityFreeWater.m new file mode 100644 index 0000000..31ff8b8 --- /dev/null +++ b/modules/cryoGridExcessIce/conductivityFreeWater.m @@ -0,0 +1,9 @@ +function k_old=conductivityFreeWater(k_old, T, soilWater) + +k_freeWater=5; %set conductivity for mobile water to 5 +i=1; + +while T(i)>0 && soilWater(i)>=1 + k_old(i)=k_freeWater; + i=i+1; +end \ No newline at end of file diff --git a/modules/cryoGridExcessIce/excessGroundIce.m b/modules/cryoGridExcessIce/excessGroundIce.m new file mode 100644 index 0000000..32e6732 --- /dev/null +++ b/modules/cryoGridExcessIce/excessGroundIce.m @@ -0,0 +1,8 @@ +function [GRID, PARA] = excessGroundIce(T, GRID, PARA) + +if ~isempty(PARA.soil.mobileWaterDomain) && (sum(double(T(GRID.soil.cT_domain)>0 & GRID.soil.excessGroundIce==1))~=0) && isempty(GRID.snow.cT_domain_ub) + disp('excess ice thawing'); + GRID.soil.excessGroundIce = GRID.soil.excessGroundIce==1 & T(GRID.soil.cT_domain)<=0; %remove the thawed cell from the list + [GRID meltwaterGroundIce PARA] = excessGroundIceThaw4(T, GRID, PARA); %meltwaterGroundIce could be read out, but is not yet implemented + GRID = updateGRID_excessice(GRID); +end \ No newline at end of file diff --git a/modules/cryoGridExcessIce/excessGroundIceThaw4.m b/modules/cryoGridExcessIce/excessGroundIceThaw4.m new file mode 100644 index 0000000..6d98e90 --- /dev/null +++ b/modules/cryoGridExcessIce/excessGroundIceThaw4.m @@ -0,0 +1,140 @@ +function [GRID, meltwaterGroundIce, PARA]=excessGroundIceThaw4(T, GRID, PARA) + +%disp('rearranging grid cells due to ground ice thaw') + +waterLevel=PARA.soil.waterTable; %remove supersaturation only when there is no snow on top of soil!!!!!!! + + +mineral=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_mineral; %calculates amounts in [m] +organic=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_organic; +water=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_water; +natPor=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_natPor; + +cT_grid=GRID.general.cT_grid(GRID.soil.cT_domain); +K_delta=GRID.general.K_delta(GRID.soil.cT_domain); + + +mobileWater = double(T(GRID.soil.cT_domain)>0) .* (water-natPor) .* double(water>natPor); +[startCell ~]= LayerIndex(mobileWater~=0); %this is faster + +%move solids down +for i=startCell:-1:1 + F_solid_down=K_delta(i)-mineral(i)-organic(i)-natPor(i); + j=i-1; + while j>0 && F_solid_down>0 + mineralDown = min(mineral(j), mineral(j)./(mineral(j)+organic(j)).*F_solid_down); + organicDown = min(organic(j), organic(j)./(mineral(j)+organic(j)).*F_solid_down); + mineral(i)=mineral(i)+mineralDown; + organic(i)=organic(i)+organicDown; + mineral(j)=mineral(j)-mineralDown; + organic(j)=organic(j)-organicDown; + F_solid_down=F_solid_down-mineralDown-organicDown; + j=j-1; + end +end + +%adjust the natural porosity +natPor(1:startCell)=K_delta(1:startCell)-mineral(1:startCell)-organic(1:startCell); + +%move water up +mobileWater=0; +for i=startCell:-1:1 + totalWater=water(i)+mobileWater; + mobileWater=totalWater-natPor(i); + mobileWater=max(0,mobileWater); + water(i)=totalWater-mobileWater; +end + +%clean up grid cells with non-zero+non-unity water content in domains without soil matrix +mobileWater=0; +for i=1:startCell + if mineral(i)+organic(i)==0 + mobileWater=mobileWater+water(i); + water(i)=0; + end +end +for i=startCell:-1:1 + if mineral(i)+organic(i)==0 + water(i)=min(K_delta(i), mobileWater); + mobileWater=mobileWater-water(i); + water(i)=round(water(i)./K_delta(i)).*K_delta(i); %this violates the water balance, but ensures that no grid cells with partly water and partly air can exist; + end +end + + +GRID.soil.cT_mineral=mineral./K_delta; +GRID.soil.cT_organic=organic./K_delta; +GRID.soil.cT_water=water./K_delta; +GRID.soil.cT_natPor=natPor./K_delta; +test=mineral+water+organic; +GRID.soil.cT_soilType(water(:,1)==1,1)=1; %sets sand freeze curve for all water grid cells (comment: find was replaced!!!) + +GRID.soil.K_mineral(1)=GRID.soil.cT_mineral(1); +GRID.soil.K_mineral(2:startCell+1)=(GRID.soil.cT_mineral(2:startCell+1)+GRID.soil.cT_mineral(1:startCell))/2 ; +GRID.soil.K_organic(1)=GRID.soil.cT_organic(1); +GRID.soil.K_organic(2:startCell+1)=(GRID.soil.cT_organic(2:startCell+1)+GRID.soil.cT_organic(1:startCell))/2 ; +GRID.soil.K_water(1)=GRID.soil.cT_water(1); +GRID.soil.K_water(2:startCell+1)=(GRID.soil.cT_water(2:startCell+1)+GRID.soil.cT_water(1:startCell))/2 ; +% GRID.soil.K_natPor(1)=GRID.soil.cT_natPor(1); +% GRID.soil.K_natPor(2:startCell+1)=(GRID.soil.cT_natPor(2:startCell+1)+GRID.soil.cT_natPor(1:startCell))/2 ; +GRID.soil.K_soilType(1)=GRID.soil.cT_soilType(1); +GRID.soil.K_soilType(2:startCell+1)=round((GRID.soil.cT_soilType(2:startCell+1)+GRID.soil.cT_soilType(1:startCell))/2) ; + +meltwaterGroundIce=0; + +while (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+GRID.soil.cT_water(1)==0) || (GRID.soil.cT_water(1)==1 && GRID.general.K_grid(GRID.soil.K_domain_ub)=PARA.soil.mobileWaterDomain(1) & GRID.general.cT_grid(GRID.soil.cT_domain)<=PARA.soil.mobileWaterDomain(2); + GRID.soil.cT_natPor(~mobileWaterDomain)=GRID.soil.cT_water(~mobileWaterDomain); % why??? +end + +% lower the water table if air is present above the excess ground ice +GRID.soil.excessGroundIce = GRID.soil.cT_water>GRID.soil.cT_natPor; +firstCellExcessIce=find(GRID.soil.excessGroundIce(:,1)==1, 1, 'first'); + +if ~isempty(firstCellExcessIce) && firstCellExcessIce>1 + PARA.soil.waterTable=max(PARA.soil.waterTable,... + sum((1 - GRID.soil.cT_water(1:firstCellExcessIce-1) - GRID.soil.cT_mineral(1:firstCellExcessIce-1) - GRID.soil.cT_organic(1:firstCellExcessIce-1))... + .*GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+firstCellExcessIce-2))); +end \ No newline at end of file diff --git a/modules/cryoGridExcessIce/initializeExcessIce2.m b/modules/cryoGridExcessIce/initializeExcessIce2.m new file mode 100644 index 0000000..cf3aea8 --- /dev/null +++ b/modules/cryoGridExcessIce/initializeExcessIce2.m @@ -0,0 +1,23 @@ +function [GRID,PARA] = initializeExcessIce2(GRID,PARA) + +GRID.soil.excessGroundIce = GRID.soil.cT_water>GRID.soil.cT_natPor; + + +%JAN: I think modifying cT_natPor is not necessary as long as it is initalized correctly in the PARA.soilLayerProperties struct +% set the natural porosity that only water in "mobilewaterDomain" is mobile +%if isempty(PARA.soil.mobileWaterDomain) +% GRID.soil.cT_natPor=GRID.soil.cT_water; % why??? +%else +% mobileWaterDomain = GRID.general.cT_grid(GRID.soil.cT_domain)>=PARA.soil.mobileWaterDomain(1) & GRID.general.cT_grid(GRID.soil.cT_domain)<=PARA.soil.mobileWaterDomain(2); +% GRID.soil.cT_natPor(~mobileWaterDomain)=GRID.soil.cT_water(~mobileWaterDomain); % why??? +%end + +%JAN: I commented this out, as I am not sure why this modification of +%waterTable is necessary +% lower the water table if air is present above the excess ground ice +%firstCellExcessIce=find(GRID.soil.excessGroundIce(:,1)==1, 1, 'first'); +%if ~isempty(firstCellExcessIce) && firstCellExcessIce>1 +% PARA.soil.waterTable=max(PARA.soil.waterTable,... +% sum((1 - GRID.soil.cT_water(1:firstCellExcessIce-1) - GRID.soil.cT_mineral(1:firstCellExcessIce-1) - GRID.soil.cT_organic(1:firstCellExcessIce-1))... +% .*GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+firstCellExcessIce-2))); +%end \ No newline at end of file diff --git a/modules/cryoGridExcessIce/mixingWaterBody.m b/modules/cryoGridExcessIce/mixingWaterBody.m new file mode 100644 index 0000000..2790ebb --- /dev/null +++ b/modules/cryoGridExcessIce/mixingWaterBody.m @@ -0,0 +1,14 @@ +function [T] = mixingWaterBody(T, GRID) + + % mixing of temperatures in unfrozen water domain + if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 && T(GRID.soil.cT_domain_ub)>0 + unfrozenWaterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6 & T(GRID.soil.cT_domain)>0; + waterCells = sum( unfrozenWaterBody ); + if waterCells > 1 + Tav = sum( T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+waterCells-1) .* GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+waterCells-1) ) ... + ./ sum( GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+waterCells-1) ) ; + T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+waterCells-1) = Tav; + end + end + +end \ No newline at end of file diff --git a/modules/cryoGridExcessIce/moveWater2Top.m b/modules/cryoGridExcessIce/moveWater2Top.m new file mode 100644 index 0000000..64c860a --- /dev/null +++ b/modules/cryoGridExcessIce/moveWater2Top.m @@ -0,0 +1,44 @@ +function [cT_water, cT_mineral, cT_organic, K_water, K_mineral, K_organic]=moveWater2Top(T, cT_water, cT_mineral, cT_organic, cT_natPor, K_water, K_mineral, K_organic, K_delta, cT_firstGroundCell) + superSaturatedCells=find(cT_water(:,1)>cT_natPor(:,1) & T(:,1)>0); + cellsChanged=superSaturatedCells; + for i=1:size(superSaturatedCells,1) + mobileWater=(cT_water(superSaturatedCells(i),1)-cT_natPor(superSaturatedCells(i),1)).*K_delta(superSaturatedCells(i),1); %in [m] + j=cT_firstGroundCell; + while mobileWater>0 && j<=size(cT_water,1) + waterAdded=min(mobileWater, K_delta(j,1).*(1-cT_water(j,1))); + cT_water(j,1)=cT_water(j,1)+waterAdded./K_delta(j,1); + cT_water(superSaturatedCells(i),1)= cT_water(superSaturatedCells(i),1)-waterAdded./K_delta(superSaturatedCells(i),1); + if cT_organic(j,1)+cT_mineral(j,1)>0 + organicSubtracted=waterAdded.*cT_organic(j,1)./(cT_organic(j,1)+cT_mineral(j,1)); + mineralSubtracted=waterAdded.*cT_mineral(j,1)./(cT_organic(j,1)+cT_mineral(j,1)); + else + organicSubtracted=0; + mineralSubtracted=0; + end + cT_organic(j,1)=cT_organic(j,1)-organicSubtracted./K_delta(j,1); + cT_organic(superSaturatedCells(i),1)= cT_organic(superSaturatedCells(i),1)+organicSubtracted./K_delta(superSaturatedCells(i),1); + + cT_mineral(j,1)=cT_mineral(j,1)-mineralSubtracted./K_delta(j,1); + cT_mineral(superSaturatedCells(i),1)= cT_mineral(superSaturatedCells(i),1)+mineralSubtracted./K_delta(superSaturatedCells(i),1); + + mobileWater=mobileWater-waterAdded; + cellsChanged=[cellsChanged; j]; + j=j+1; + end + end + + for i=cellsChanged' + if i==cT_firstGroundCell + K_water(i,1)=cT_water(i,1); + K_mineral(i,1)=cT_mineral(i,1); + K_organic(i,1)=cT_organic(i,1); + else + K_water(i,1)=(cT_water(i-1,1)+cT_water(i,1))/2; + K_mineral(i,1)=(cT_mineral(i-1,1)+cT_mineral(i,1))/2; + K_organic(i,1)=(cT_organic(i-1,1)+cT_organic(i,1))/2; + + K_water(i+1,1)=(cT_water(i+1,1)+cT_water(i,1))/2; + K_mineral(i+1,1)=(cT_mineral(i+1,1)+cT_mineral(i,1))/2; + K_organic(i+1,1)=(cT_organic(i+1,1)+cT_organic(i,1))/2; + end + end \ No newline at end of file diff --git a/modules/cryoGridExcessIce/removeWater.m b/modules/cryoGridExcessIce/removeWater.m new file mode 100644 index 0000000..e2e6a78 --- /dev/null +++ b/modules/cryoGridExcessIce/removeWater.m @@ -0,0 +1,36 @@ +function [cT_water, cT_mineral, cT_organic, K_water, K_mineral, K_organic, K_grid]=... + removeWater(T, cT_water, cT_mineral, cT_organic, cT_natPor, K_water, K_mineral, K_organic, K_delta, K_grid, targetSaturation) + + +%function[cT_water, cT_mineral, cT_organic, K_grid]=... + % removeWater(T, cT_water, cT_mineral, cT_organic, cT_natPor, K_delta, K_grid, targetSaturation) + + superSaturatedCells=find(cT_water(:,1)>cT_natPor(:,1) & T(:,1)>0); + for i=superSaturatedCells + + newGridCellSize=(cT_mineral(i,1)+cT_organic(i,1)).*K_delta(i,1)./(1-cT_natPor(i,1)); %in [m] + K_grid(i+1:end)=K_grid(i+1:end)-(K_delta(i,1)-newGridCellSize); + cT_water(i,1)=cT_natPor(i,1).*targetSaturation; + cT_mineral(i,1)=cT_mineral(i,1).*K_delta(i,1)./newGridCellSize; + cT_organic(i,1)=cT_organic(i,1).*K_delta(i,1)./newGridCellSize; + % mobileWater=(cT_water(i,1)-cT_natPor(i,1)).*K_delta(i,1); %in [m] + + % K_grid(i+1:end)=K_grid(i+1:end)-mobileWater; + + + + K_water(i,1)=(cT_water(i-1,1)+cT_water(i,1))/2; + K_mineral(i,1)=(cT_mineral(i-1,1)+cT_mineral(i,1))/2; + K_organic(i,1)=(cT_organic(i-1,1)+cT_organic(i,1))/2; + + K_water(i+1,1)=(cT_water(i+1,1)+cT_water(i,1))/2; + K_mineral(i+1,1)=(cT_mineral(i+1,1)+cT_mineral(i,1))/2; + K_organic(i+1,1)=(cT_organic(i+1,1)+cT_organic(i,1))/2; + + + end + + + %mineral+org content (cT_mineral(i,1)+cT_organic(i,1)).*K_delta(i,1) + + %soll (1-cT_natPor).*newK_delta ergeben \ No newline at end of file diff --git a/modules/cryoGridExcessIce/updateGRID_excessice.m b/modules/cryoGridExcessIce/updateGRID_excessice.m new file mode 100644 index 0000000..64053c7 --- /dev/null +++ b/modules/cryoGridExcessIce/updateGRID_excessice.m @@ -0,0 +1,78 @@ +function GRID = updateGRID_excessice(GRID) +%--- update soil and water grid after subsidence ---------------------- + +% change soil with 100% water to water cell +soilGRIDsize = sum(GRID.soil.cT_domain); + + +% JAN: set all cells above without soil to air (water runs off and no snow cover +% present) +% this needs to be improved!!! +GRID.air.cT_domain(GRID.soil.cT_domain) = (GRID.soil.cT_organic==0 & GRID.soil.cT_mineral==0); +GRID.air.K_domain(GRID.soil.K_domain) = (GRID.soil.K_organic==0 & GRID.soil.K_mineral==0); + +GRID.soil.cT_domain(GRID.soil.cT_domain) = (GRID.soil.cT_organic>0 | GRID.soil.cT_mineral>0); +GRID.soil.K_domain(GRID.soil.K_domain) = (GRID.soil.K_organic>0 | GRID.soil.K_mineral>0); + + + +if soilGRIDsize ~= sum(GRID.soil.cT_domain) + + disp('subsidence - updating grid information'); + + %water_bucket = GRID.soil.cT_water(1); + cT_no_water = (GRID.soil.cT_organic>0 | GRID.soil.cT_mineral>0); + K_no_water = (GRID.soil.K_organic>0 | GRID.soil.K_mineral>0); + + [GRID.soil.cT_domain_lb GRID.soil.cT_domain_ub] = LayerIndex(GRID.soil.cT_domain); + [GRID.soil.K_domain_lb GRID.soil.K_domain_ub] = LayerIndex(GRID.soil.K_domain); + + [GRID.air.cT_domain_lb GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + +% GRID.water.cT_domain(max([GRID.air.cT_domain_lb+1 GRID.ice.cT_domain_lb+1]) : GRID.soil.cT_domain_ub-1) = 1; +% GRID.water.K_domain(max([GRID.air.K_domain_lb+1 GRID.ice.K_domain_lb+1]) : GRID.soil.K_domain_ub-1) = 1; +% +% [GRID.water.cT_domain_lb GRID.water.cT_domain_ub] = LayerIndex(GRID.water.cT_domain); +% [GRID.water.K_domain_lb GRID.water.K_domain_ub] = LayerIndex(GRID.water.K_domain); + + %-- update all other soil grid infos if size has changed + + + + % adjust cT grid fields + GRID.soil.cT_water = GRID.soil.cT_water(cT_no_water); + GRID.soil.cT_mineral = GRID.soil.cT_mineral(cT_no_water); + GRID.soil.cT_organic = GRID.soil.cT_organic(cT_no_water); + GRID.soil.cT_soilType = GRID.soil.cT_soilType(cT_no_water); + GRID.soil.cT_natPor = GRID.soil.cT_natPor(cT_no_water); + GRID.soil.excessGroundIce = GRID.soil.excessGroundIce(cT_no_water); + GRID.soil.conductivity = GRID.soil.conductivity(cT_no_water, :); + GRID.soil.capacity = GRID.soil.capacity(cT_no_water, :); + GRID.soil.liquidWaterContent = GRID.soil.liquidWaterContent(cT_no_water, :); + GRID.soil.cT_frozen = GRID.soil.cT_frozen(cT_no_water); + GRID.soil.cT_thawed = GRID.soil.cT_thawed(cT_no_water); + GRID.soil.K_frozen = GRID.soil.cT_frozen; % this is ok since K_frozen and cT_frozen + GRID.soil.K_thawed = GRID.soil.cT_thawed; % are the same from the start (see initialize.m) + + % adjust K grid fields + GRID.soil.soilGrid = GRID.soil.soilGrid(K_no_water); + GRID.soil.K_water = GRID.soil.K_water(K_no_water); + GRID.soil.K_mineral = GRID.soil.K_mineral(K_no_water); + GRID.soil.K_organic = GRID.soil.K_organic(K_no_water); + GRID.soil.K_soilType = GRID.soil.K_soilType(K_no_water); + + % s = fieldnames(GRID.soil); +% for i=1:length(s) +% if isempty(strfind(char(s(i)),'domain')) && isempty(strfind(char(s(i)),'K_frozen')) && isempty(strfind(char(s(i)),'K_thawed'))% exclude all with name 'domain' +% if isempty(strfind(char(s(i)),'K_')) && isempty(strfind(char(s(i)),'soilGrid')) +% %evaluate on cT grid +% eval(['GRID.soil.' char(s(i)) '=' 'GRID.soil.' char(s(i)) '(cT_no_water,:);']); +% else +% %evaluate on K grid +% eval(['GRID.soil.' char(s(i)) '=' 'GRID.soil.' char(s(i)) '(K_no_water,:);']); +% end +% end +% end +end \ No newline at end of file diff --git a/modules/cryoGridExcessIceInfiltration/excessGroundIceInfiltration.m b/modules/cryoGridExcessIceInfiltration/excessGroundIceInfiltration.m new file mode 100644 index 0000000..431bb34 --- /dev/null +++ b/modules/cryoGridExcessIceInfiltration/excessGroundIceInfiltration.m @@ -0,0 +1,18 @@ +function [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA) +meltwaterGroundIce=0; +if ~isempty(PARA.soil.mobileWaterDomain) && (sum(double(T(GRID.soil.cT_domain)>0 & GRID.soil.excessGroundIce==1))~=0) && isempty(GRID.snow.cT_domain_ub) + disp('excess ice thawing'); + GRID.soil.excessGroundIce = GRID.soil.excessGroundIce==1 & T(GRID.soil.cT_domain)<=0; %remove the thawed cell from the list + [GRID, meltwaterGroundIce, wc] = excessGroundIceThaw4Infiltration(T, wc, GRID, PARA); %meltwaterGroundIce could be read out, but is not yet implemented + + %[GRID, wc] = updateGRID_excessiceInfiltration(wc, GRID); + %JAN: updateGRID not necessary as long as no distinct water domain, the + %regridding of soil/air domain happens already in the Thaw4 function + + % modification due to infiltration --> finally change cT_water to wc + %GRID.soil.cT_water = wc; + % JAN: do NOT update cT_water as this stores the latest frozen water + % content and is used to check whether the LUT needs to be updated in + % the infiltration module + +end \ No newline at end of file diff --git a/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m b/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m new file mode 100644 index 0000000..3ff1409 --- /dev/null +++ b/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m @@ -0,0 +1,211 @@ +function [GRID, meltwaterGroundIce, wc]=excessGroundIceThaw4Infiltration(T, wc, GRID, PARA) + +%disp('rearranging grid cells due to ground ice thaw') +meltwaterGroundIce=0; % in [m] + + +waterLevel=PARA.soil.waterTable; %remove supersaturation only when there is no snow on top of soil!!!!!!! + +%calculates amounts of soil constituents in [m] +mineral=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_mineral; +organic=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_organic; +natPor=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_natPor; + +% modification for infiltration +%water=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_water; +water=GRID.general.K_delta(GRID.soil.cT_domain).*wc; + +cT_grid=GRID.general.cT_grid(GRID.soil.cT_domain); +K_delta=GRID.general.K_delta(GRID.soil.cT_domain); + +mobileWater = double(T(GRID.soil.cT_domain)>0) .* (water-natPor) .* double(water>natPor); +[startCell ~]= LayerIndex(mobileWater~=0); %this is faster + +%move solids down +for i=startCell:-1:1 + F_solid_down=K_delta(i)-mineral(i)-organic(i)-natPor(i); + j=i-1; + while j>0 && F_solid_down>0 + mineralDown = min(mineral(j), mineral(j)./(mineral(j)+organic(j)).*F_solid_down); + organicDown = min(organic(j), organic(j)./(mineral(j)+organic(j)).*F_solid_down); + mineral(i)=mineral(i)+mineralDown; + organic(i)=organic(i)+organicDown; + mineral(j)=mineral(j)-mineralDown; + organic(j)=organic(j)-organicDown; + F_solid_down=F_solid_down-mineralDown-organicDown; + j=j-1; + end +end + +%adjust the natural porosity +natPor(1:startCell)=K_delta(1:startCell)-mineral(1:startCell)-organic(1:startCell); + +%move water up +mobileWater=0; +for i=startCell:-1:1 + totalWater=water(i)+mobileWater; + mobileWater=totalWater-natPor(i); + mobileWater=max(0,mobileWater); + water(i)=totalWater-mobileWater; +end + +%clean up grid cells with non-zero+non-unity water content in domains without soil matrix +% JAN: these loops thould be removed to increase performance, possible? +mobileWater=0; +for i=1:startCell + if mineral(i)+organic(i)==0 + mobileWater=mobileWater+water(i); + water(i)=0; + end +end +for i=startCell:-1:1 + if mineral(i)+organic(i)==0 + water_temp=min( [ K_delta(i), mobileWater ] ); + mobileWater=mobileWater-water_temp; + %water(i)=round(water_temp./K_delta(i)).*K_delta(i); %this violates the water balance, but ensures that no grid cells with partly water and partly air can exist; + water(i)=water_temp; + %water_mismatch = water_temp-water(i); + %GRID.lake.residualWater = GRID.lake.residualWater + water_mismatch; + %meltwaterGroundIce=meltwaterGroundIce+water_mismatch; % this corrects the violated water balance: if round=floor then water_mismatch>=0 and this is added to runoff + end +end + +%%% modifications due to infiltration module +%GRID.soil.cT_water=water./K_delta; +%GRID.soil.K_water(1)=GRID.soil.cT_water(1); +%GRID.soil.K_water(2:startCell+1)=(GRID.soil.cT_water(2:startCell+1)+GRID.soil.cT_water(1:startCell))/2 ; +wc=water./K_delta; +% GRID.soil.K_water(1)=wc(1); +% GRID.soil.K_water(2:startCell+1)=(wc(2:startCell+1)+wc(1:startCell))/2 ; +%%% + +GRID.soil.cT_mineral=mineral./K_delta; +GRID.soil.cT_organic=organic./K_delta; +GRID.soil.cT_natPor=natPor./K_delta; +GRID.soil.cT_soilType( (GRID.soil.cT_mineral+GRID.soil.cT_organic)<=1e-6 )=1; %sets sand freeze curve for all water grid cells %wc(:,1)==1,1 + + +% K fields not used currently +% GRID.soil.K_mineral(1)=GRID.soil.cT_mineral(1); +% GRID.soil.K_mineral(2:startCell+1)=(GRID.soil.cT_mineral(2:startCell+1)+GRID.soil.cT_mineral(1:startCell))/2 ; +% GRID.soil.K_organic(1)=GRID.soil.cT_organic(1); +% GRID.soil.K_organic(2:startCell+1)=(GRID.soil.cT_organic(2:startCell+1)+GRID.soil.cT_organic(1:startCell))/2 ; + +% GRID.soil.K_natPor(1)=GRID.soil.cT_natPor(1); +% GRID.soil.K_natPor(2:startCell+1)=(GRID.soil.cT_natPor(2:startCell+1)+GRID.soil.cT_natPor(1:startCell))/2 ; +% GRID.soil.K_soilType(1)=GRID.soil.cT_soilType(1); +% GRID.soil.K_soilType(2:startCell+1)=round((GRID.soil.cT_soilType(2:startCell+1)+GRID.soil.cT_soilType(1:startCell))/2) ; + + +%remove grid cells until the water level is reached +soilGRIDsizeOld = sum( GRID.soil.cT_domain ); +%%% modified due to infiltration module +%while (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+GRID.soil.cT_water(1)==0) || (GRID.soil.cT_water(1)==1 && GRID.general.K_grid(GRID.soil.K_domain_ub)h + wc(1)=h./K_delta(1); + meltwaterGroundIce = meltwaterGroundIce + actualWater-h; + end + + +end + + +soilGRIDsizeNew = sum (GRID.soil.cT_domain ); + +% update look up tables since soil water contents changed +% --> only if grid cells freeze, otherwise not necessary ????? +%if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 +if soilGRIDsizeOld~=soilGRIDsizeNew + disp('xice - reinitializing LUT - soil/air domains changed'); + GRID.soil.cT_water=wc; + GRID = initializeSoilThermalProperties(GRID, PARA); +end +%end +%reduce water content above the perched water table +%it might be also good to use an external function for this since this is +%only an option in the model +%i=0; +% while i./startCell < 1-PARA.soil.perchedWaterTable +% GRID.soil.cT_water(i+1,1) = PARA.soil.saturationAbovePerchedWaterTable.*(1-GRID.soil.cT_mineral(i+1,1)-GRID.soil.cT_organic(i+1,1)); +% +% GRID.soil.K_water(i+1,1) = PARA.soil.saturationAbovePerchedWaterTable.*(1-GRID.soil.K_mineral(i+1,1)-GRID.soil.K_organic(i+1,1)); +% i=i+1; +% end + + +% [GRID.soil.cT_frozen,... +% GRID.soil.cT_thawed,... +% GRID.soil.K_frozen,... +% GRID.soil.K_thawed,... +% GRID.soil.conductivity,... +% GRID.soil.capacity] = initialize(GRID.soil.cT_water,... +% GRID.soil.cT_mineral,... +% GRID.soil.cT_organic,... +% GRID.soil.cT_soilType,... +% GRID.soil.K_water,... +% GRID.soil.K_mineral,... +% GRID.soil.K_organic,... +% GRID.soil.K_soilType,... +% PARA.technical.arraySizeT,... +% GRID.general.cT_grid(GRID.soil.cT_domain),... +% PARA.soil.kh_bedrock); diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration.m new file mode 100644 index 0000000..2ac9b63 --- /dev/null +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration.m @@ -0,0 +1,88 @@ +function [GRID, wc] = updateGRID_excessiceInfiltration(wc, GRID) +%--- update soil and water grid after subsidence ---------------------- + +% JAN: I think this whole function is not necessary as long as water cells +% below water table are treated as "soil" + + +% change soil with 100% water to water cell +soilGRIDsize = sum(GRID.soil.cT_domain); + + +% JAN: set all cells without mineral or organic to air (water runs off and no snow cover +% present) +% this needs to be improved!!! +%GRID.air.cT_domain(GRID.soil.cT_domain) = (GRID.soil.cT_organic==0 && GRID.soil.cT_mineral==0); +%GRID.air.K_domain(GRID.soil.K_domain) = (GRID.soil.K_organic==0 && GRID.soil.K_mineral==0); + +%GRID.soil.cT_domain(GRID.soil.cT_domain) = (GRID.soil.cT_organic>0 || GRID.soil.cT_mineral>0); +%GRID.soil.K_domain(GRID.soil.K_domain) = (GRID.soil.K_organic>0 || GRID.soil.K_mineral>0); + + + +if soilGRIDsize ~= sum(GRID.soil.cT_domain) + + disp('subsidence - updating grid information'); + + %water_bucket = GRID.soil.cT_water(1); + %water_bucket = wc(1); + + cT_no_water = (GRID.soil.cT_organic>0 || GRID.soil.cT_mineral>0); + K_no_water = (GRID.soil.K_organic>0 || GRID.soil.K_mineral>0); + + [GRID.soil.cT_domain_lb, GRID.soil.cT_domain_ub] = LayerIndex(GRID.soil.cT_domain); + [GRID.soil.K_domain_lb, GRID.soil.K_domain_ub] = LayerIndex(GRID.soil.K_domain); + + [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + %JAN : add here new domain specifications. what about soil domain? + +% GRID.water.cT_domain(max([GRID.air.cT_domain_lb+1 GRID.ice.cT_domain_lb+1]) : GRID.soil.cT_domain_ub-1) = 1; +% GRID.water.K_domain(max([GRID.air.K_domain_lb+1 GRID.ice.K_domain_lb+1]) : GRID.soil.K_domain_ub-1) = 1; +% +% [GRID.water.cT_domain_lb GRID.water.cT_domain_ub] = LayerIndex(GRID.water.cT_domain); +% [GRID.water.K_domain_lb GRID.water.K_domain_ub] = LayerIndex(GRID.water.K_domain); + + %-- update all other soil grid infos if size has changed + + + + % adjust cT grid fields + % modification due to infiltration + wc = wc(cT_no_water); + %GRID.soil.cT_water = GRID.soil.cT_water(cT_no_water); + + GRID.soil.cT_mineral = GRID.soil.cT_mineral(cT_no_water); + GRID.soil.cT_organic = GRID.soil.cT_organic(cT_no_water); + GRID.soil.cT_soilType = GRID.soil.cT_soilType(cT_no_water); + GRID.soil.cT_natPor = GRID.soil.cT_natPor(cT_no_water); + GRID.soil.excessGroundIce = GRID.soil.excessGroundIce(cT_no_water); + GRID.soil.conductivity = GRID.soil.conductivity(cT_no_water, :); + GRID.soil.capacity = GRID.soil.capacity(cT_no_water, :); + GRID.soil.liquidWaterContent = GRID.soil.liquidWaterContent(cT_no_water, :); + GRID.soil.cT_frozen = GRID.soil.cT_frozen(cT_no_water); + GRID.soil.cT_thawed = GRID.soil.cT_thawed(cT_no_water); + GRID.soil.K_frozen = GRID.soil.cT_frozen; % this is ok since K_frozen and cT_frozen + GRID.soil.K_thawed = GRID.soil.cT_thawed; % are the same from the start (see initialize.m) + + % adjust K grid fields + GRID.soil.soilGrid = GRID.soil.soilGrid(K_no_water); + GRID.soil.K_water = GRID.soil.K_water(K_no_water); + GRID.soil.K_mineral = GRID.soil.K_mineral(K_no_water); + GRID.soil.K_organic = GRID.soil.K_organic(K_no_water); + GRID.soil.K_soilType = GRID.soil.K_soilType(K_no_water); + + % s = fieldnames(GRID.soil); +% for i=1:length(s) +% if isempty(strfind(char(s(i)),'domain')) && isempty(strfind(char(s(i)),'K_frozen')) && isempty(strfind(char(s(i)),'K_thawed'))% exclude all with name 'domain' +% if isempty(strfind(char(s(i)),'K_')) && isempty(strfind(char(s(i)),'soilGrid')) +% %evaluate on cT grid +% eval(['GRID.soil.' char(s(i)) '=' 'GRID.soil.' char(s(i)) '(cT_no_water,:);']); +% else +% %evaluate on K grid +% eval(['GRID.soil.' char(s(i)) '=' 'GRID.soil.' char(s(i)) '(K_no_water,:);']); +% end +% end +% end +end \ No newline at end of file diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m new file mode 100644 index 0000000..effa7b7 --- /dev/null +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m @@ -0,0 +1,43 @@ +function [GRID] = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID) + + % pass excess meltwater to storage variable + GRID.lake.residualWater = meltwaterGroundIce; + + % update GRID domains of water body + if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 % upper soil cell pure air/water + % general water body extent + cT_waterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6; + GRID.lake.cT_domain(logical(GRID.air.cT_domain+GRID.snow.cT_domain)) = 0; + GRID.lake.cT_domain(GRID.soil.cT_domain) = cT_waterBody; + [GRID.lake.cT_domain_lb, GRID.lake.cT_domain_ub] = LayerIndex(GRID.lake.cT_domain); + GRID.lake.K_domain(logical(GRID.air.K_domain+GRID.snow.K_domain)) = 0; + GRID.lake.K_domain(GRID.lake.cT_domain_ub:GRID.lake.cT_domain_lb+1) = 1; + GRID.lake.K_domain(GRID.lake.cT_domain_lb+2:end) = 0; + [GRID.lake.K_domain_lb, GRID.lake.K_domain_ub] = LayerIndex(GRID.lake.K_domain); + +% % distinction frozen and unfrozen parts +% unfrozenWaterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6 & T(GRID.soil.cT_domain)>0; +% frozenWaterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6 & T(GRID.soil.cT_domain)<=0; +% GRID.lake.water.cT_domain = GRID.lake.cT_domain & T>0; +% [GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); +% GRID.lake.ice.cT_domain = GRID.lake.cT_domain & T<=0; +% [GRID.lake.ice.cT_domain_lb, GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); %these might be two domains + % K domains not implemented so far + else + GRID.lake.cT_domain = false(size(GRID.general.cT_grid)); + GRID.lake.K_domain = false(size(GRID.general.K_grid)); + [GRID.lake.cT_domain_lb, GRID.lake.cT_domain_ub] = LayerIndex(GRID.lake.cT_domain); + [GRID.lake.K_domain_lb, GRID.lake.K_domain_ub] = LayerIndex(GRID.lake.K_domain); + end + + + + + + + + + + + +end \ No newline at end of file diff --git a/modules/cryoGridFlake/cryoGridFLAKE.m b/modules/cryoGridFlake/cryoGridFLAKE.m new file mode 100644 index 0000000..fa7b5a1 --- /dev/null +++ b/modules/cryoGridFlake/cryoGridFLAKE.m @@ -0,0 +1,144 @@ +function [T, GRID, FLAKE]=cryoGridFLAKE(FLAKE,GRID,SEB,PARA,T,T_old,timestep,k_eff,dE_dt,dE_dt_SEB) + +%update average temperature of the water domain +FLAKE.t_mnw_n_flk = sum(T_old(GRID.lake.water.cT_domain).*GRID.general.K_delta(GRID.lake.water.cT_domain)) ... + ./ sum(GRID.general.K_delta(GRID.lake.water.cT_domain)) + 273.15; + +%update water depth +FLAKE.depth_w = GRID.general.K_grid(GRID.lake.water.cT_domain_lb + 1) - GRID.general.K_grid(GRID.lake.water.cT_domain_ub); + +%update mean temperature according to changes in average temperature with +%water depth. This prevents changes in the bottom temperature due to sudden +%changes in water depth +if GRID.lake.ice.z_ice>0 + FLAKE.t_mnw_p_flk = FLAKE.t_mnw_n_flk; + FLAKE.t_mnw_n_flk = FLAKE.t_wml_n_flk - FLAKE.c_t_n_flk.*(FLAKE.t_wml_n_flk-FLAKE.t_bot_n_flk).*(1.-FLAKE.h_ml_n_flk./FLAKE.depth_w); + GRID.lake.ice.z_ice = GRID.lake.ice.z_ice - (FLAKE.t_mnw_p_flk-FLAKE.t_mnw_n_flk).*4.2e6.*FLAKE.depth_w./(334e3 * 910); +end + +%update ice cover status and thickness +if FLAKE.h_ice_n_flk<1e-3 && GRID.lake.ice.z_ice>=1e-3 + FLAKE.l_ice_create = true; +else + FLAKE.l_ice_create = false; +end +FLAKE.h_ice_n_flk = GRID.lake.ice.z_ice; + +%set boundary conditions +FLAKE.q_snow_flk= 0.; +FLAKE.q_ice_flk = 0.; +FLAKE.q_bot_flk = -(T_old(GRID.lake.water.cT_domain_lb+1)-T_old(GRID.lake.water.cT_domain_lb))... + ./ GRID.general.cT_delta(GRID.lake.water.cT_domain_lb) .* k_eff(GRID.lake.water.cT_domain_lb+1); + +FLAKE.q_w_flk = sum(dE_dt_SEB(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb+1)) ... + - SEB.Sin_water ... + + sum(dE_dt(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb)) ... + - sum(dE_dt_SEB(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb)) ... + + FLAKE.q_bot_flk ... + + GRID.lake.ice.dz_dt_freeze*334e3*910 ... + + GRID.lake.ice.dE_dt_melt_residual; + +if FLAKE.q_w_flk>0 && GRID.lake.ice.z_ice>0 + %correct for positive water heat fluxes under ice cover. This is + %necessary due to the very simple ice cover scheme which needs to + %be improved in fututre model versions. + GRID.lake.ice.z_ice = GRID.lake.ice.z_ice - FLAKE.q_w_flk.*(timestep *24*3600)/(334e3 * 910); + FLAKE.q_w_flk = 0; + FLAKE.h_ice_n_flk = GRID.lake.ice.z_ice; +end + +%transform u_star in atmosphere to u_star in water assuming constant +%desities for air and water. +FLAKE.u_star_w_flk=(SEB.u_star.^2.*(1.293./1e3)).^0.5; + +%calculate FLAKE radiative heat transfer +[FLAKE.i_atm_flk,... + FLAKE.i_w_flk,... + FLAKE.i_ice_flk,... + FLAKE.i_snow_flk,... + FLAKE.i_h_flk,... + FLAKE.i_bot_flk,... + FLAKE.i_intm_0_h_flk,... + FLAKE.i_intm_h_d_flk] = flake_radflux(SEB.Sin_water,FLAKE,PARA); + +% %call FLAKE main function +% if PARA.technical.MEX +% FLAKE = flake_driver_mex(FLAKE, timestep.*24.*3600); +% else + FLAKE = flake_driver(FLAKE, timestep.*24.*3600); +% end + +%map water temperature from shape function on the regular grid +%calculate dimensionless water depth of thermocline +% zeta_cT = (GRID.lake.water.cT_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) - FLAKE.h_ml_n_flk) ... +% ./ ((FLAKE.depth_w - FLAKE.h_ml_n_flk)); + +zeta_K = (GRID.lake.water.K_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) - FLAKE.h_ml_n_flk) ... + ./ ((FLAKE.depth_w - FLAKE.h_ml_n_flk)); +zeta_K = [zeta_K; 1]; +zeta_delta = diff(zeta_K); + +if ~isempty(zeta_delta) + %The original FLAKE shape function not used due to interpolation + %errors on discrete grid + %phi_theta = (40/3*FLAKE.c_t_n_flk-20/3)*zeta_cT ... + % + (18-30*FLAKE.c_t_n_flk)*zeta_cT.^2 ... + % + (20*FLAKE.c_t_n_flk-12)*zeta_cT.^3 ... + % + (5/3 - 10/3*FLAKE.c_t_n_flk)*zeta_cT.^4; + + %Integrated shape function to calculate averages on discrete grid + int_phi_theta = (40/3*FLAKE.c_t_n_flk-20/3)*1/2*zeta_K.^2 ... + + (18-30*FLAKE.c_t_n_flk)*1/3*zeta_K.^3 ... + + (20*FLAKE.c_t_n_flk-12)*1/4*zeta_K.^4 ... + + (5/3 - 10/3*FLAKE.c_t_n_flk)*1/5*zeta_K.^5; + + %calculate partial intergral for grid cells + int_phi_theta = int_phi_theta(2:end) - int_phi_theta(1:end-1); + phi_theta = int_phi_theta./zeta_delta; + + %change from dimensionless temperature to absolute temperature + Tw_z = -(phi_theta*(FLAKE.t_wml_n_flk-FLAKE.t_bot_n_flk) - FLAKE.t_wml_n_flk)-273.15; +else + Tw_z = []; +end +%map temperature on water grid +Tw = T(GRID.lake.water.cT_domain); + +%note that a step is introduced which introduces small discretization +%errors which need to be corrected later +Tw(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) = Tw_z; +Tw(GRID.lake.water.K_grid0 + GRID.lake.ice.z_ice = GRID.lake.ice.z_ice + dE./(334e3 * 910); + %set T water surf to zero + %dE=(0-T(GRID.lake.water.cT_domain_ub))*GRID.general.K_delta(GRID.lake.water.cT_domain_ub)*4.2e6; + %GRID.lake.ice.z_ice = GRID.lake.ice.z_ice + dE./(334e3 * 910); + %T(GRID.lake.water.cT_domain_ub) = 0; +else + ub_h_ml=min([GRID.lake.water.K_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk); FLAKE.depth_w]); + lb_h_ml=FLAKE.depth_w; + if (lb_h_ml-ub_h_ml)>0 + Tw(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) = Tw_z - dE/(4.2e6* (lb_h_ml-ub_h_ml)); + else + Tw = Tw - dE/(4.2e6 * FLAKE.depth_w); + end + T(GRID.lake.water.cT_domain) = Tw; +end + +%update FLAKE average temperature of the water domain +FLAKE.t_mnw_n_flk = sum(T(GRID.lake.water.cT_domain).*GRID.general.K_delta(GRID.lake.water.cT_domain)) ... + ./ sum(GRID.general.K_delta(GRID.lake.water.cT_domain)) + 273.15; + + + diff --git a/modules/cryoGridFlake/updateGRID_flake.m b/modules/cryoGridFlake/updateGRID_flake.m new file mode 100644 index 0000000..0a7df70 --- /dev/null +++ b/modules/cryoGridFlake/updateGRID_flake.m @@ -0,0 +1,16 @@ +function GRID = updateGRID_flake(GRID) + + +%update ice cover and water grid +GRID.lake.ice.cT_domain = (GRID.general.K_grid(2:end) - GRID.general.K_grid(min([GRID.lake.water.cT_domain_ub GRID.lake.ice.cT_domain_ub GRID.lake.ice.cT_domain_ub])))<=GRID.lake.ice.z_ice & ... + (GRID.general.K_grid(2:end) - GRID.general.K_grid(min([GRID.lake.water.cT_domain_ub GRID.lake.ice.cT_domain_ub])))> 0; + +GRID.lake.ice.K_domain = GRID.lake.ice.cT_domain; +[GRID.lake.ice.cT_domain_lb GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); +[GRID.lake.ice.K_domain_lb GRID.lake.ice.K_domain_ub] = LayerIndex(GRID.lake.ice.K_domain); + +%update water body grid +GRID.lake.water.cT_domain = (~GRID.air.cT_domain & ~GRID.snow.cT_domain & ~GRID.lake.ice.cT_domain & ~GRID.soil.cT_domain); +GRID.lake.water.K_domain = GRID.lake.water.cT_domain; +[GRID.lake.water.cT_domain_lb GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); +[GRID.lake.water.K_domain_lb GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); diff --git a/modules/cryoGridInitialize/generateTemporary.m b/modules/cryoGridInitialize/generateTemporary.m index 68db4dd..c28eb9b 100644 --- a/modules/cryoGridInitialize/generateTemporary.m +++ b/modules/cryoGridInitialize/generateTemporary.m @@ -14,6 +14,26 @@ TEMPORARY.Qnet_sum=0; TEMPORARY.Qg_sum=0; +%for EB checks +TEMPORARY.Qsurf_sum = 0; +TEMPORARY.dE_dt_SEB_sum = 0.*T; +TEMPORARY.dE_dt_cond_sum = 0.*T; + + +%TEMPORARY.dEeffSoil = 0; + +TEMPORARY.dE_soil_sens = 0; +TEMPORARY.dE_soil_lat = 0; +TEMPORARY.dE_soil = 0; +TEMPORARY.dE_snow_sens = 0; +TEMPORARY.dE_snow_lat = 0; +TEMPORARY.dE_snow = 0; + +% TEMPORARY.dEsensSoil = 0; +% TEMPORARY.dEsensSnow = 0; +% TEMPORARY.dElatentSoil = 0; +% TEMPORARY.dElatentSnow = 0; + TEMPORARY.timestep_sum=0; TEMPORARY.T_sum=0.*T; diff --git a/modules/cryoGridInitialize/initializeBALANCE.m b/modules/cryoGridInitialize/initializeBALANCE.m index af8b6ec..79d23c2 100644 --- a/modules/cryoGridInitialize/initializeBALANCE.m +++ b/modules/cryoGridInitialize/initializeBALANCE.m @@ -18,6 +18,9 @@ BALANCE.energy.dE_snow_lat = 0; BALANCE.energy.dE_snow = 0; + BALANCE.energy.Q_lateral = zeros( length(GRID.general.cT_grid) , 1 ); + + % WATER balance % water content soil domain in [m] BALANCE.water.W_soil = nansum( wc .* GRID.general.K_delta(GRID.soil.cT_domain) ); @@ -35,8 +38,10 @@ BALANCE.water.ds=0; % runoff BALANCE.water.dr_surface=0; - BALANCE.water.dr_subsurface=0; + BALANCE.water.dr_external=0; BALANCE.water.dr_snowmelt=0; BALANCE.water.dr_excessSnow=0; + BALANCE.water.dr_lateralSnow=0; BALANCE.water.dr_rain=0; % this is only rain on frozen ground + BALANCE.water.dr_lateral=0; end \ No newline at end of file diff --git a/modules/cryoGridInitialize/initializeHYDRO.m b/modules/cryoGridInitialize/initializeHYDRO.m new file mode 100644 index 0000000..1a1457c --- /dev/null +++ b/modules/cryoGridInitialize/initializeHYDRO.m @@ -0,0 +1,34 @@ +function HYDRO = initializeHYDRO() + +% NEW variable names +% storage +HYDRO.dW_soil = 0; +HYDRO.dW_snow = 0; +% precipitation +HYDRO.dp_rain=0; +HYDRO.dp_snow=0; % SWE +% evapotranspiration and sublimation +HYDRO.de=0; +HYDRO.ds=0; +% runoff +HYDRO.dr_surface=0; +HYDRO.dr_subsurface=0; +HYDRO.dr_snowmelt=0; +HYDRO.dr_excessSnow=0; +HYDRO.dr_rain=0; % this is only rain on frozen ground + +end +% OLD variable names: +% HYDRO.rain = 0; +% HYDRO.snow = 0; +% HYDRO.sublimation = 0; +% HYDRO.condensation = 0; +% HYDRO.evapotranspiration = 0; +% HYDRO.surfaceRunoffBucket = 0; +% HYDRO.surfaceRunoffRain = 0; +% HYDRO.surfaceRunoffSnow = 0; +% HYDRO.surfaceRunoffLastCell = 0; +% HYDRO.surfaceRunoffGroundIce = 0; +% HYDRO.lateralFluxBucket = 0; +% HYDRO.excessSnow = 0; +% HYDRO.initialSnow = 0; diff --git a/modules/cryoGridInitialize/initializeLAKE.m b/modules/cryoGridInitialize/initializeLAKE.m new file mode 100644 index 0000000..00d40c9 --- /dev/null +++ b/modules/cryoGridInitialize/initializeLAKE.m @@ -0,0 +1,31 @@ +function [GRID] = initializeLAKE(GRID); + +GRID.lake.unfrozenWaterSurface = false; +GRID.lake.residualWater = 0; % the water content stored "mixed" cells of air and water if a water body is present + +% %---- flake initialization ------------------------------------------------ +% FLAKE.t_snow_n_flk=0+273.15; +% FLAKE.t_ice_n_flk=0+273.15; +% FLAKE.t_wml_n_flk=6+273.15; +% FLAKE.t_mnw_n_flk=5+273.15; +% FLAKE.t_bot_n_flk=4+273.15; +% FLAKE.t_b1_n_flk=7+273.15; +% FLAKE.h_snow_n_flk=0; +% FLAKE.h_ice_n_flk=0; +% FLAKE.h_ml_n_flk=3; +% FLAKE.h_b1_n_flk=10; +% FLAKE.c_t_n_flk=0; +% FLAKE.h_ice_n_flk=0; +% +% FLAKE.i_w_flk=0; +% FLAKE.i_bot_flk=0; +% FLAKE.q_w_flk=0; +% FLAKE.q_bot_flk=0; +% +% FLAKE.fetch=100; +% FLAKE.depth_w=PARA.water.depth; +% +% FLAKE.d_h_ice_dt = 0; +% FLAKE.q_ice_water = 0; +% FLAKE.extincoef_water_typ=PARA.water.extinction; +% FLAKE.latitude=PARA.location.latitude; \ No newline at end of file diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index 1a4aca0..85d1a8a 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -1,4 +1,6 @@ function [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_temp, timestep, BALANCE) + %L=3.34e5; + %L_lv=2.8e6; %also worng here. JAN: yes, should be smaller if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis @@ -23,7 +25,7 @@ - ( SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i./nonAirFractionUppermostGridCell ...% - ( SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000./nonAirFractionUppermostGridCell ... - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i); %- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000); - + %SEB.sublim=SEB.sublim+SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000; BALANCE.water.ds = BALANCE.water.ds - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i*1000; % sublimation in [mm] %---------- melt and infiltration ------------------------------------- @@ -42,7 +44,7 @@ c_temp(GRID.snow.cT_domain),... PARA); - %account for meltwater in water balance + %SEB.meltwater=SEB.meltwater+newMelt; BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt + (-newMelt.*1000); % in [mm] end @@ -51,30 +53,24 @@ deltaSnow_i = max(0, FORCING.i.snowfall.*timestep./1000); else snowHeight = abs( GRID.general.K_grid(GRID.snow.cT_domain_ub) - GRID.general.K_grid(GRID.snow.cT_domain_lb+1) ); - if snowHeight>PARA.snow.maxSnow - warning(' excess snow occurs '); - end deltaSnow_i = max( [ 0, ... min( [ FORCING.i.snowfall.*timestep./1000, ... (PARA.snow.maxSnow - snowHeight ) .* PARA.snow.rho_snow ./ PARA.constants.rho_w ] ) ] ); %ensures that no more than maxSnow can accumulate %account for excess snow in water balance - BALANCE.water.dr_excessSnow = BALANCE.water.dr_excessSnow -( FORCING.i.snowfall.*timestep - deltaSnow_i*1000 ); %defined as negative when snow is removed; in [mm] + BALANCE.water.dr_excessSnow = BALANCE.water.dr_excessSnow -( FORCING.i.snowfall.*timestep - deltaSnow_i*1000 ); %defined as negative when snow is removed end GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... + deltaSnow_i; GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... - + (deltaSnow_i./(PARA.snow.rho_snow./1000) ... - - deltaSnow_i); - + + ( deltaSnow_i./(PARA.snow.rho_snow./ PARA.constants.rho_w) - deltaSnow_i); else %no snow cover %---------- add the new snow into initial SWE variable in case of no snow cover------------------ GRID.snow.SWEinitial = GRID.snow.SWEinitial + FORCING.i.snowfall.*timestep./1000 - GRID.snow.SWEinitial.*0.1.*timestep; - % account for decrease in SWEinitial in water balance BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - GRID.snow.SWEinitial.*0.1.*timestep*1000; %SWEinitial decreasing counted as surface runoff %----- add the rainfall as runoff in case of no infiltration into frozen ground diff --git a/modules/cryoGridSnow/maxLiqWater.m b/modules/cryoGridSnow/maxLiqWater.m index 639c04c..3a9f31b 100644 --- a/modules/cryoGridSnow/maxLiqWater.m +++ b/modules/cryoGridSnow/maxLiqWater.m @@ -1,11 +1,10 @@ -function maxLiqWater=maxLiqWater(T, snow_i, snow_w, snow_a, poreSpace, c_temp, PARA) +function maxLiqWater=maxLiqWater(T, snow_i, snow_w, snow_a, poreSpace, c_temp) - L=PARA.constants.L_sl.*PARA.constants.rho_w; %3.34e8; +L=3.34e8; - waterHoldingPot=0.05.* (poreSpace.*snow_i)./(1-poreSpace); %in m; 5% of the pore space can be filled by water +waterHoldingPot=0.05.* (poreSpace.*snow_i)./(1-poreSpace); %in m; 5% of the pore space can be filled by water + +maxLiqWater = (waterHoldingPot - snow_w - T.*c_temp.*(snow_i+snow_w+snow_a)./L); %in m +maxLiqWater = min([snow_a maxLiqWater]'); +maxLiqWater = maxLiqWater'; % negative if snow_w>waterHoldingPot - maxLiqWater = (waterHoldingPot - snow_w - T.*c_temp.*(snow_i+snow_w+snow_a)./L); %in m - maxLiqWater = min([snow_a maxLiqWater]'); - maxLiqWater = maxLiqWater'; % negative if snow_w>waterHoldingPot - -end \ No newline at end of file diff --git a/modules/cryoGridSnow/melt.m b/modules/cryoGridSnow/melt.m index 7b893ba..563d797 100644 --- a/modules/cryoGridSnow/melt.m +++ b/modules/cryoGridSnow/melt.m @@ -1,37 +1,36 @@ -function [T, snow_i, snow_w, snow_a]=melt(T, snow_i, snow_w, snow_a, poreSpace, c_temp, PARA) +function [T, snow_i, snow_w, snow_a]=melt(T, snow_i, snow_w, snow_a, poreSpace, c_temp) - L=PARA.constants.L_sl.*PARA.constants.rho_w; %3.34e8; +L=3.34e8; - pot_SWE=double(T>0).*T.*c_temp.*(snow_i+snow_w+snow_a)./L; +pot_SWE=double(T>0).*T.*c_temp.*(snow_i+snow_w+snow_a)./L; - T=double(T<=0).*T; - delta_SWE=pot_SWE; +T=double(T<=0).*T; +delta_SWE=pot_SWE; - if sum(pot_SWE>snow_i)~=0% in one cell more energy than needed to melt entire cell - for i=1:size(T,1)-1 - delta_SWE(i)=min([snow_i(i) pot_SWE(i)]); - SWEres=pot_SWE(i) - delta_SWE(i); - if (snow_i(i+1)+snow_w(i+1)+snow_a(i+1))~=0 - T(i+1)=T(i+1) + SWEres.*L./(c_temp(i+1).*(snow_i(i+1)+snow_w(i+1)+snow_a(i+1))); - end - pot_SWE(i+1)=pot_SWE(i+1) + double(T(i+1)>0).*T(i+1).*c_temp(i+1).*(snow_i(i+1)+snow_w(i+1)+snow_a(i+1))./L; - T(i+1)=double(T(i+1)<=0).*T(i+1); - end - i=size(T,1); +if sum(pot_SWE>snow_i)~=0% in one cell more energy than needed to melt entire cell + for i=1:size(T,1)-1 delta_SWE(i)=min([snow_i(i) pot_SWE(i)]); + SWEres=pot_SWE(i) - delta_SWE(i); + if (snow_i(i+1)+snow_w(i+1)+snow_a(i+1))~=0 + T(i+1)=T(i+1) + SWEres.*L./(c_temp(i+1).*(snow_i(i+1)+snow_w(i+1)+snow_a(i+1))); + end + pot_SWE(i+1)=pot_SWE(i+1) + double(T(i+1)>0).*T(i+1).*c_temp(i+1).*(snow_i(i+1)+snow_w(i+1)+snow_a(i+1))./L; + T(i+1)=double(T(i+1)<=0).*T(i+1); end - %T(find(isnan(T(:,1))==1),1)=0; - + i=size(T,1); + delta_SWE(i)=min([snow_i(i) pot_SWE(i)]); +end +%T(find(isnan(T(:,1))==1),1)=0; - %delta_SWE - % delta_SWE = min([snow_i double(T>0).*T.*c_temp.*(snow_i+snow_w+snow_a)./L]'); %Energy conserving since sensible heat term is only excess energy from SEB+conduction - % delta_SWE=delta_SWE'; + +%delta_SWE +% delta_SWE = min([snow_i double(T>0).*T.*c_temp.*(snow_i+snow_w+snow_a)./L]'); %Energy conserving since sensible heat term is only excess energy from SEB+conduction +% delta_SWE=delta_SWE'; - snow_i=snow_i - delta_SWE; %melting only changes SWE, not density theta_s +snow_i=snow_i - delta_SWE; %melting only changes SWE, not density theta_s - snow_w=snow_w + delta_SWE; - %snow_a=(poreSpace.*snow_i + poreSpace.*snow_w - snow_w)./(1-poreSpace); %pore space stays stays constant +snow_w=snow_w + delta_SWE; +%snow_a=(poreSpace.*snow_i + poreSpace.*snow_w - snow_w)./(1-poreSpace); %pore space stays stays constant -end \ No newline at end of file diff --git a/modules/cryoGridSnow/refreeze.m b/modules/cryoGridSnow/refreeze.m index 279c8ce..566bb58 100644 --- a/modules/cryoGridSnow/refreeze.m +++ b/modules/cryoGridSnow/refreeze.m @@ -1,6 +1,6 @@ function [T, snow_i, snow_w]=refreeze(T, snow_i, snow_w, snow_a, c_temp, PARA) - L=PARA.constants.L_sl.*PARA.constants.rho_w;%3.34e8; + L=PARA.constants.L_sl.*PARA.constants.rho_w; %3.34e8; delta_SWE = min([snow_w, -1.*double(T<=0).*T.*c_temp.*(snow_i+snow_w+snow_a)./L]'); delta_SWE=delta_SWE'; diff --git a/modules/cryoGridSnow/snowMelt.m b/modules/cryoGridSnow/snowMelt.m index 6b4c4f4..d319297 100644 --- a/modules/cryoGridSnow/snowMelt.m +++ b/modules/cryoGridSnow/snowMelt.m @@ -1,31 +1,65 @@ function [T, snow_i, snow_w, snow_a, runoff] = snowMelt(T, snow_i, snow_w, snow_a, water_flux, c_temp, PARA) +%------------melt the snow for cells with T>0------------ runoff=0; - - %------------melt the snow for cells with T>0------------ + +%energyC=sum(T.*c_temp.*(snow_i+snow_w+snow_a))+(sum(snow_w)+water_flux).*3.34e8; + poreSpace=(snow_w+snow_a)./(snow_i+snow_w+snow_a); - poreSpace(isnan(poreSpace(:,1)),1)=300/1000; + poreSpace(isnan(poreSpace(:,1)),1)=300/1000; %JAN: what does this number mean?? - [T, snow_i, snow_w, snow_a]=melt(T, snow_i, snow_w, snow_a, poreSpace, c_temp, PARA); + [T, snow_i, snow_w, snow_a]=melt(T, snow_i, snow_w, snow_a, poreSpace, c_temp); + % energyC2=sum(T.*c_temp.*(snow_i+snow_w+snow_a))+(sum(snow_w)+water_flux).*3.34e8; pS=(snow_w+snow_a)./(snow_i+snow_w+snow_a); pS(isnan(pS(:,1)),1)=300/1000; - %-----------calculate how much water (in m) a snow cell can hold----- - maxWater=maxLiqWater(T(pS>0), snow_i(pS>0), snow_w(pS>0), snow_a(pS>0), poreSpace(pS>0), c_temp(pS>0), PARA); + + + + + +%-----------calculate how much water (in m) a snow cell can hold----- + + maxWater=maxLiqWater(T(pS>0), snow_i(pS>0), snow_w(pS>0), snow_a(pS>0), poreSpace(pS>0), c_temp(pS>0)); + + if water_flux>0 || (~isempty(maxWater) && min(maxWater)<0) %infiltration occurs - %------------infiltrate from top to bottom-------------------- +%------------infiltrate from top to bottom-------------------- + + [snow_w(pS>0), snow_a(pS>0), water_flux] = infiltrateTop2Bottom(snow_i(pS>0), snow_w(pS>0), snow_a(pS>0), poreSpace(pS>0), maxWater, water_flux); + + + +%------------infiltrate bottom to top---------------------- + + % energyC3=sum(T.*c_temp.*(snow_i+snow_w+snow_a))+(sum(snow_w)+water_flux).*3.34e8; + + + - %------------infiltrate bottom to top---------------------- if water_flux>0 [snow_w(pS>0), snow_a(pS>0), runoff] = infiltrateBottom2Top(snow_i(pS>0), snow_w(pS>0), snow_a(pS>0), water_flux); end + + % energyC4=sum(T.*c_temp.*(snow_i+snow_w+snow_a))+(sum(snow_w)+runoff).*3.34e8; + + +%----------shift energy from water to T due to refreezing--------- end - %----------shift energy from water to T due to refreezing--------- + [T, snow_i, snow_w] = refreeze(T, snow_i, snow_w, snow_a, c_temp, PARA); + + % energyC5=sum(T.*c_temp.*(snow_i+snow_w+snow_a))+(sum(snow_w)+runoff).*3.34e8; + + % if abs((energyC5-energyC)./energyC)>0.01 + % energyC + % energyC2 + + % energyC5 end diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index 3467dc3..d2b53e4 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -1,157 +1,174 @@ function [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE) -snowCellSize=GRID.snow.snowCellSize; - -if isempty(GRID.snow.cT_domain_lb)==1 %no snow exists - - if GRID.snow.SWEinitial>=PARA.technical.SWEperCell/2 %create and initialize first cell of snow - - %------ modify snow and air grid ----------------------------- - GRID.snow.cT_domain(GRID.air.cT_domain_lb)=1; - GRID.snow.K_domain(GRID.air.K_domain_lb)=1; - [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); - [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); - - GRID.air.cT_domain(GRID.air.cT_domain_lb)=0; - GRID.air.K_domain(GRID.air.K_domain_lb)=0; - [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); - [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); - - % ------- update SWE grid ------------------------------------- - GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.SWEinitial; - GRID.snow.Snow_w(GRID.snow.cT_domain_ub) = 0; - GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = (GRID.snow.SWEinitial./(PARA.snow.rho_snow./1000) - GRID.snow.SWEinitial); - GRID.snow.SWEinitial=0; - - % -------- update K grid ------------------------------------- - GRID.general.K_grid(GRID.snow.K_domain_ub)=-1.*( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ); - T(GRID.snow.cT_domain_ub)=T(GRID.air.cT_domain_lb); - - end - -else %snow exists - - check_change=false; - GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) -... - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); %updates the position of the uppermost snow grid cell - - if GRID.snow.Snow_i(GRID.snow.cT_domain_ub)>=1.5.*PARA.technical.SWEperCell %create new grid cell % JAN: why 1.5 ??? - - %------ modify snow and air grid ----------------------------- - GRID.snow.cT_domain(GRID.air.cT_domain_lb)=1; - GRID.snow.K_domain(GRID.air.K_domain_lb)=1; - [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); - [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); - - GRID.air.cT_domain(GRID.air.cT_domain_lb)=0; - GRID.air.K_domain(GRID.air.K_domain_lb)=0; - [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); - [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); - - % ------- update SWE grid - GRID.snow.Snow_i(GRID.snow.cT_domain_ub)=1./3.*GRID.snow.Snow_i(GRID.snow.cT_domain_ub+1); - GRID.snow.Snow_w(GRID.snow.cT_domain_ub)=1./3.*GRID.snow.Snow_w(GRID.snow.cT_domain_ub+1); - GRID.snow.Snow_a(GRID.snow.cT_domain_ub)=1./3.*GRID.snow.Snow_a(GRID.snow.cT_domain_ub+1); - GRID.snow.Snow_i(GRID.snow.cT_domain_ub+1)=GRID.snow.Snow_i(GRID.snow.cT_domain_ub+1) - GRID.snow.Snow_i(GRID.snow.cT_domain_ub); - GRID.snow.Snow_w(GRID.snow.cT_domain_ub+1)=GRID.snow.Snow_w(GRID.snow.cT_domain_ub+1) - GRID.snow.Snow_w(GRID.snow.cT_domain_ub); - GRID.snow.Snow_a(GRID.snow.cT_domain_ub+1)=GRID.snow.Snow_a(GRID.snow.cT_domain_ub+1) - GRID.snow.Snow_a(GRID.snow.cT_domain_ub); - T(GRID.snow.cT_domain_ub)=T(GRID.snow.cT_domain_ub+1); - check_change=true; - end - - if min(GRID.snow.Snow_i(GRID.snow.cT_domain))<=0.5.*PARA.technical.SWEperCell %avoid looping when unnecessary - for i=GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb-1 %check all snow cells except for the lowermost one for too small ice and water contents - merge with lower cell - - if GRID.snow.Snow_i(i)<=0.5.*PARA.technical.SWEperCell - - %------ modify snow and air grid ----------------------------- - GRID.snow.cT_domain(GRID.snow.cT_domain_ub)=0; - GRID.snow.K_domain(GRID.snow.K_domain_ub)=0; - [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); - [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); - - GRID.air.cT_domain(GRID.air.cT_domain_lb+1)=1; - GRID.air.K_domain(GRID.air.K_domain_lb+1)=1; - [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); - [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); - - %-------- rearrange SWE and T grids -------------------------- - GRID.snow.Snow_i(i+1)=GRID.snow.Snow_i(i+1)+GRID.snow.Snow_i(i); - GRID.snow.Snow_w(i+1)=GRID.snow.Snow_w(i+1)+GRID.snow.Snow_w(i); - GRID.snow.Snow_a(i+1)=GRID.snow.Snow_a(i+1)+GRID.snow.Snow_a(i); - GRID.snow.Snow_i(2:i)=GRID.snow.Snow_i(1:i-1); - GRID.snow.Snow_w(2:i)=GRID.snow.Snow_w(1:i-1); - GRID.snow.Snow_a(2:i)=GRID.snow.Snow_a(1:i-1); - T(i+1)=(T(i+1)+T(i))/2; - T(2:i)=T(1:i-1); - end + snowCellSize=GRID.snow.snowCellSize; + + if isempty(GRID.snow.cT_domain_lb)==1 %no snow exists + + if GRID.snow.SWEinitial>=PARA.technical.SWEperCell/2 %create and initialize first cell of snow + + %------ modify snow and air grid ----------------------------- + GRID.snow.cT_domain(GRID.air.cT_domain_lb)=1; + GRID.snow.K_domain(GRID.air.K_domain_lb)=1; + [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); + [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); + + GRID.air.cT_domain(GRID.air.cT_domain_lb)=0; + GRID.air.K_domain(GRID.air.K_domain_lb)=0; + [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + % ------- update SWE grid ------------------------------------- + GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.SWEinitial; + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) = 0; + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = (GRID.snow.SWEinitial./(PARA.snow.rho_snow./1000) - GRID.snow.SWEinitial); + GRID.snow.SWEinitial=0; + + % -------- update K grid ------------------------------------- + GRID.general.K_grid(GRID.snow.K_domain_ub)= GRID.general.K_grid(GRID.air.cT_domain_lb+1) - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ); + T(GRID.snow.cT_domain_ub)=T(GRID.air.cT_domain_lb); + + end + + else %snow exists + + check_change=false; + + GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) -... + ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); %updates the position of the uppermost snow grid cell + + if GRID.snow.Snow_i(GRID.snow.cT_domain_ub)>=1.5.*PARA.technical.SWEperCell %create new grid cell % JAN: why 1.5 ??? + + %------ modify snow and air grid ----------------------------- + GRID.snow.cT_domain(GRID.air.cT_domain_lb)=1; + GRID.snow.K_domain(GRID.air.K_domain_lb)=1; + [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); + [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); + + GRID.air.cT_domain(GRID.air.cT_domain_lb)=0; + GRID.air.K_domain(GRID.air.K_domain_lb)=0; + [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + % ------- update SWE grid + GRID.snow.Snow_i(GRID.snow.cT_domain_ub)=1./3.*GRID.snow.Snow_i(GRID.snow.cT_domain_ub+1); + GRID.snow.Snow_w(GRID.snow.cT_domain_ub)=1./3.*GRID.snow.Snow_w(GRID.snow.cT_domain_ub+1); + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)=1./3.*GRID.snow.Snow_a(GRID.snow.cT_domain_ub+1); + GRID.snow.Snow_i(GRID.snow.cT_domain_ub+1)=GRID.snow.Snow_i(GRID.snow.cT_domain_ub+1) - GRID.snow.Snow_i(GRID.snow.cT_domain_ub); + GRID.snow.Snow_w(GRID.snow.cT_domain_ub+1)=GRID.snow.Snow_w(GRID.snow.cT_domain_ub+1) - GRID.snow.Snow_w(GRID.snow.cT_domain_ub); + GRID.snow.Snow_a(GRID.snow.cT_domain_ub+1)=GRID.snow.Snow_a(GRID.snow.cT_domain_ub+1) - GRID.snow.Snow_a(GRID.snow.cT_domain_ub); + T(GRID.snow.cT_domain_ub)=T(GRID.snow.cT_domain_ub+1); + check_change=true; + end + + if min(GRID.snow.Snow_i(GRID.snow.cT_domain))<=0.5.*PARA.technical.SWEperCell %avoid looping when unnecessary + for i=GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb-1 %check all snow cells except for the lowermost one for too small ice and water contents - merge with lower cell %JAN: replace with while-loop instead? + + if GRID.snow.Snow_i(i)<=0.5.*PARA.technical.SWEperCell + + %------ modify snow and air grid ----------------------------- + GRID.snow.cT_domain(GRID.snow.cT_domain_ub)=0; + GRID.snow.K_domain(GRID.snow.K_domain_ub)=0; + [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); + [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); + + GRID.air.cT_domain(GRID.air.cT_domain_lb+1)=1; + GRID.air.K_domain(GRID.air.K_domain_lb+1)=1; + [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + %-------- rearrange SWE and T grids -------------------------- + GRID.snow.Snow_i(i+1)=GRID.snow.Snow_i(i+1)+GRID.snow.Snow_i(i); + GRID.snow.Snow_w(i+1)=GRID.snow.Snow_w(i+1)+GRID.snow.Snow_w(i); + GRID.snow.Snow_a(i+1)=GRID.snow.Snow_a(i+1)+GRID.snow.Snow_a(i); + GRID.snow.Snow_i(2:i)=GRID.snow.Snow_i(1:i-1); + GRID.snow.Snow_w(2:i)=GRID.snow.Snow_w(1:i-1); + GRID.snow.Snow_a(2:i)=GRID.snow.Snow_a(1:i-1); + T(i+1)=(T(i+1)+T(i))/2; + T(2:i)=T(1:i-1); + end + end + check_change=true; + end + + if GRID.snow.Snow_i(GRID.snow.cT_domain_lb)<=0.5.*PARA.technical.SWEperCell && sum(GRID.snow.cT_domain)>=2 %lowermost grid cell has too little snow, but there still is 2 or more snow cells - merge with upper cell + + %------ modify snow and air grid ---------------------------------- + GRID.snow.cT_domain(GRID.snow.cT_domain_ub)=0; + GRID.snow.K_domain(GRID.snow.cT_domain_ub)=0; + [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); + [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); + + GRID.air.cT_domain(GRID.air.cT_domain_lb+1)=1; + GRID.air.K_domain(GRID.air.K_domain_lb+1)=1; + [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + %-------- rearrange SWE and T grids -------------------------- + GRID.snow.Snow_i(GRID.snow.cT_domain_lb)=GRID.snow.Snow_i(GRID.snow.cT_domain_lb)+GRID.snow.Snow_i(GRID.snow.cT_domain_lb-1); + GRID.snow.Snow_w(GRID.snow.cT_domain_lb)=GRID.snow.Snow_w(GRID.snow.cT_domain_lb)+GRID.snow.Snow_w(GRID.snow.cT_domain_lb-1); + GRID.snow.Snow_a(GRID.snow.cT_domain_lb)=GRID.snow.Snow_a(GRID.snow.cT_domain_lb)+GRID.snow.Snow_a(GRID.snow.cT_domain_lb-1); + GRID.snow.Snow_i(2:GRID.snow.cT_domain_lb-1)=GRID.snow.Snow_i(1:GRID.snow.cT_domain_lb-2); + GRID.snow.Snow_w(2:GRID.snow.cT_domain_lb-1)=GRID.snow.Snow_w(1:GRID.snow.cT_domain_lb-2); + GRID.snow.Snow_a(2:GRID.snow.cT_domain_lb-1)=GRID.snow.Snow_a(1:GRID.snow.cT_domain_lb-2); + + T(GRID.snow.cT_domain_lb)=(T(GRID.snow.cT_domain_lb)+T(GRID.snow.cT_domain_lb-1))/2; + T(2:GRID.snow.cT_domain_lb-1)=T(1:GRID.snow.cT_domain_lb-2); + + check_change=true; end - check_change=true; + + + if check_change==true %update grid spacings + GRID.general.K_grid(GRID.snow.cT_domain)=GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); + GRID.general.K_grid(GRID.air.cT_domain)=[GRID.general.K_grid(GRID.air.cT_domain_lb)+(-snowCellSize)*(GRID.air.cT_domain_lb-1):snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; + end + + if (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)<=0.5.*PARA.technical.SWEperCell && sum(GRID.snow.cT_domain)<2) %remove last grid cell if snow threshold is reached + + % for water balance: add snow of last grid cell to runoff + BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ).*1000; + + %------ modify snow and air grid ---------------------------------- + GRID.snow.cT_domain(GRID.snow.cT_domain_ub)=0; + GRID.snow.K_domain(GRID.snow.cT_domain_ub)=0; + [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); + [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); + + GRID.air.cT_domain(GRID.air.cT_domain_lb+1)=1; + GRID.air.K_domain(GRID.air.K_domain_lb+1)=1; + [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + + GRID.snow.Snow_i(GRID.air.cT_domain_lb)=0; + GRID.snow.Snow_w(GRID.air.cT_domain_lb)=0; + GRID.snow.Snow_a(GRID.air.cT_domain_lb)=0; + T(GRID.air.cT_domain_lb)=0; + + end + + end - - if GRID.snow.Snow_i(GRID.snow.cT_domain_lb)<=0.5.*PARA.technical.SWEperCell && sum(GRID.snow.cT_domain)>=2 %lowermost grid cell has too little snow, but there still is 2 or more snow cells - merge with upper cell - - %------ modify snow and air grid ---------------------------------- - GRID.snow.cT_domain(GRID.snow.cT_domain_ub)=0; - GRID.snow.K_domain(GRID.snow.cT_domain_ub)=0; - [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); - [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); - - GRID.air.cT_domain(GRID.air.cT_domain_lb+1)=1; - GRID.air.K_domain(GRID.air.K_domain_lb+1)=1; - [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); - [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); - - %-------- rearrange SWE and T grids -------------------------- - GRID.snow.Snow_i(GRID.snow.cT_domain_lb)=GRID.snow.Snow_i(GRID.snow.cT_domain_lb)+GRID.snow.Snow_i(GRID.snow.cT_domain_lb-1); - GRID.snow.Snow_w(GRID.snow.cT_domain_lb)=GRID.snow.Snow_w(GRID.snow.cT_domain_lb)+GRID.snow.Snow_w(GRID.snow.cT_domain_lb-1); - GRID.snow.Snow_a(GRID.snow.cT_domain_lb)=GRID.snow.Snow_a(GRID.snow.cT_domain_lb)+GRID.snow.Snow_a(GRID.snow.cT_domain_lb-1); - GRID.snow.Snow_i(2:GRID.snow.cT_domain_lb-1)=GRID.snow.Snow_i(1:GRID.snow.cT_domain_lb-2); - GRID.snow.Snow_w(2:GRID.snow.cT_domain_lb-1)=GRID.snow.Snow_w(1:GRID.snow.cT_domain_lb-2); - GRID.snow.Snow_a(2:GRID.snow.cT_domain_lb-1)=GRID.snow.Snow_a(1:GRID.snow.cT_domain_lb-2); - - T(GRID.snow.cT_domain_lb)=(T(GRID.snow.cT_domain_lb)+T(GRID.snow.cT_domain_lb-1))/2; - T(2:GRID.snow.cT_domain_lb-1)=T(1:GRID.snow.cT_domain_lb-2); - - check_change=true; + + % JAN: why does this need to be done in each timestep? + + GRID.general.K_grid(GRID.air.cT_domain_lb)= GRID.general.K_grid(GRID.air.cT_domain_lb+1)-snowCellSize; + GRID.general.K_grid(GRID.air.cT_domain_lb-1)= GRID.general.K_grid(GRID.air.cT_domain_lb+1)-2.*snowCellSize; + + GRID.general.cT_grid=( GRID.general.K_grid(1:end-1)+ GRID.general.K_grid(2:end))./2; %grid on which capacity and temperature information lives (midpoints of grid cells) + GRID.general.cT_delta=(- GRID.general.cT_grid(1:end-1,1)+ GRID.general.cT_grid(2:end,1)); + GRID.general.K_delta=(- GRID.general.K_grid(1:end-1,1)+ GRID.general.K_grid(2:end,1)); + + + % bugfix as still situations can occur where K_delta<0 + if sum( GRID.general.K_delta < 0 ) > 0 + disp('updateGRID_snow - bugfix K grid'); + %update grid spacings + GRID.general.K_grid(GRID.snow.cT_domain) = GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); + GRID.general.K_grid(GRID.air.cT_domain) = [GRID.general.K_grid(GRID.air.cT_domain_lb)+(-2*snowCellSize)*(GRID.air.cT_domain_lb-1):2*snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; + GRID.general.cT_grid = ( GRID.general.K_grid(1:end-1) + GRID.general.K_grid(2:end) ) ./ 2; %grid on which capacity and temperature information lives (midpoints of grid cells) + GRID.general.cT_delta = ( -GRID.general.cT_grid(1:end-1,1) + GRID.general.cT_grid(2:end,1) ); + GRID.general.K_delta = ( -GRID.general.K_grid(1:end-1,1) + GRID.general.K_grid(2:end,1) ); end - - - if check_change==true %update grid spacings - GRID.general.K_grid(GRID.snow.cT_domain)=GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); - GRID.general.K_grid(GRID.air.cT_domain)=[GRID.general.K_grid(GRID.air.cT_domain_lb)+(-snowCellSize)*(GRID.air.cT_domain_lb-1):snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; - end - - if (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)<=0.5.*PARA.technical.SWEperCell && sum(GRID.snow.cT_domain)<2) %remove last grid cell if snow threshold is reached - - % for water balance: add snow of last grid cell to runoff - BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ).*1000; - - %------ modify snow and air grid ---------------------------------- - GRID.snow.cT_domain(GRID.snow.cT_domain_ub)=0; - GRID.snow.K_domain(GRID.snow.cT_domain_ub)=0; - [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); - [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); - - GRID.air.cT_domain(GRID.air.cT_domain_lb+1)=1; - GRID.air.K_domain(GRID.air.K_domain_lb+1)=1; - [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); - [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); - - - GRID.snow.Snow_i(GRID.air.cT_domain_lb)=0; - GRID.snow.Snow_w(GRID.air.cT_domain_lb)=0; - GRID.snow.Snow_a(GRID.air.cT_domain_lb)=0; - T(GRID.air.cT_domain_lb)=0; - - end - - -end -% update grid spacings -GRID.general.K_grid(GRID.air.cT_domain_lb)= GRID.general.K_grid(GRID.air.cT_domain_lb+1)-snowCellSize; -GRID.general.K_grid(GRID.air.cT_domain_lb-1)= GRID.general.K_grid(GRID.air.cT_domain_lb+1)-2.*snowCellSize; -GRID.general.cT_grid=( GRID.general.K_grid(1:end-1)+ GRID.general.K_grid(2:end))./2; %grid on which capacity and temperature information lives (midpoints of grid cells) -GRID.general.cT_delta=(- GRID.general.cT_grid(1:end-1,1)+ GRID.general.cT_grid(2:end,1)); -GRID.general.K_delta=(- GRID.general.K_grid(1:end-1,1)+ GRID.general.K_grid(2:end,1)); \ No newline at end of file +end diff --git a/modules/cryoGridSoil/conductionDevries.m b/modules/cryoGridSoil/conductionDevries.m new file mode 100644 index 0000000..86d44e4 --- /dev/null +++ b/modules/cryoGridSoil/conductionDevries.m @@ -0,0 +1,215 @@ +function [Lambda]=conductionDevries(w_c,i_c,min_c,org_c,T,Xo,qo) +% function calculates soil heat conductivity using volumetric contents of water, ice, +% organic and minerals. +% Based on de Vries (1963) / Campbell et al. (1994) +% Input parameters: w_c:=water content +% i_c:=ice content +% min_c:=mineral content +% org_c:=organic content +% T:=soil temperature [°C] +% Xo:=cutoff water content for liquid recirculation [m³/m³] +% qo:=power for liquid recirculation function +%-------------------------------------------------------------------------- + + +warning off all +P=1-min_c-org_c; + +L(1,:)=0.025; %air [Hillel(1982)] +L(2,:)=0.57; %water [Hillel(1982)] +L(3,:)=2.2; %ice [Hillel(1982)] +L(4,:)=0.25; %organic [Hillel(1982)] +L(5,:)=3.8;%7.7;%y2.9; %mineral [Hillel(1982)] + +%calaculated conductivties [Campbell et al. (1994)] +%L(1,:)=0.024+7.73*10^-5*T-2.6*10^-8*T^2; %air +%L(2,:)=0.554+2.24*10^-3*T-9.87*10^-6*T^2;%water + +%-------------------------------------------------------------------------- +%conductivity function due to variation in water-air content (no ice) +wc=[0:0.01:P]; +ac=P-wc; +m=size(wc,2); +space=zeros(m*3, 3); + +for i=1:size(wc,2) + X(1,:)=ac(i); %air + X(2,:)=wc(i); %water + X(3,:)=0.0; %ice + X(4,:)=org_c; %organic + X(5,:)=min_c; %mineral + %---------------------------------------------------------------------- + [kwa(i)]=conductDV63_aw(X,L,T,Xo,qo,[]); + KK(i,1)=wc(i); + KK(i,2)=0; + KK(i,3)=kwa(i); + space(i,1)=wc(i); + space(i,3)=kwa(i); +end +%plot(space(1:m,1), space(1:m,3)) +KK(end,:)=[]; +l=size(KK,1); +%-------------------------------------------------------------------------- +%conductivity function due to variation in ice-air content (no watr) +ic=[0:0.01:P]; +ac=P-ic; + +for i=1:size(ic,2) + X(1,:)=ac(i); %air + X(2,:)=0.0; %water + X(3,:)=ic(i); %ice + X(4,:)=org_c; %organic + X(5,:)=min_c; %mineral + %---------------------------------------------------------------------- + [kia(i)]=conductDV63_ia(X,L,T,Xo,qo,[]); + KK(l+i,1)=0; + KK(l+i,2)=ic(i); + KK(l+i,3)=kia(i); + space(m+i,2)=ic(i); + space(m+i,3)=kia(i); +end + +KK(end,:)=[]; +l=size(KK,1); +%------------------------------------------------------------------------- +%conductivity function due to variation in ice-water content (no air) +ic=[0:0.01:P]; +wc=P-ic; + +for i=1:size(wc,2) + X(1,:)=0.0; %air + X(2,:)=wc(i); %water + X(3,:)=ic(i); %ice + X(4,:)=org_c; %organic + X(5,:)=min_c; %mineral + %---------------------------------------------------------------------- + [kiw(i)]=conductDV63_iw(X,L,T,Xo,qo,[]); + KK(l+i,1)=wc(i); + KK(l+i,2)=ic(i); + KK(l+i,3)=kiw(i); + space(2*m+i,1)=wc(i); + space(2*m+i,2)=ic(i); + space(2*m+i,3)=kiw(i); + +end + +KK(end,:)=[0 P kiw(end)]; +KK(1,:)=[]; +%-------------------------------------------------------------------------- +%interpolate boundary functions and calculate searched conductivity + +%Lamda = griddata(KK(:,1),KK(:,2),KK(:,3),XI,YI,'v4'); + +max_size1=max([size(1-min_c-org_c,1) size(w_c,1) size(i_c,1)]); +max_size2=max([size(1-min_c-org_c,2) size(w_c,2) size(i_c,2)]); +if max_size1>max_size2 %column vector + a_c=zeros(max_size1,1)+1-min_c-org_c-w_c-i_c; + w_c=zeros(max_size1,1)+w_c; + i_c=zeros(max_size1,1)+i_c; +else %row vector + a_c=zeros(1,max_size2)+1-min_c-org_c-w_c-i_c; + w_c=zeros(1, max_size2)+w_c; + i_c=zeros(1, max_size2)+i_c; +end +Lambda=griddata(space(:,1), space(:,2), space(:,3),w_c, i_c, 'v4'); +%F=TriScatteredInterp(space(:,1), space(:,2), space(:,3), space(:,4)); +%Lambda=F(a_c, w_c, i_c) +%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +function [k]=conductDV63_aw(X,L,T,Xo,qo,fw) +%function calculates heat conductivity based on de Vries (1963) +%Input parameter: X:=fraction of soil material +% L:=individual conductivities of soil components +% Xo:=cutoff water content for liquid recirculation [m³/m³] +% qo:=power for liquid recirculation function +% fw:=weighting function (if empty else fw=1 for saturated +% soil or fw=0 for dry soils +%-------------------------------------------------------------------------- +%g:=shape factores of soil components (set to spherical gx=gy=gz) +g(1,:)=1/3; +g(2,:)=1/3; +g(3,:)=1/3; +%power for liquid recirculation function +qo=qo; +%cutoff water content for liquid recirculation [m³/m³] +Xo=Xo; +%calculate Ly:=conductivity of matrix material +q=qo*((T+273.15)/303)^2; +if isempty(fw)==1 + fw=1/(1+(X(2,:)/Xo)^-q); +end +Ly=L(1,:)+fw*(L(2,:)-L(1,:)); +%calculate k:=effectiv conductivity +for i=1:5 + for j=1:3 + K1(i,j)=1/(1+(L(i,1)/Ly-1)*g(j,1)); + end +end +K=1/3*sum(K1')'; +k=sum(K.*L.*X)/sum(K.*X); + + +function [k]=conductDV63_ia(X,L,T,Xo,qo,fw) +%function calculates heat conductivity based on de Vries (1963) +%Input parameter: X:=fraction of soil material +% L:=individual conductivities of soil components +% Xo:=cutoff water content for liquid recirculation [m³/m³] +% qo:=power for liquid recirculation function +% fw:=weighting function (if empty else fw=1 for saturated +% soil or fw=0 for dry soils +%-------------------------------------------------------------------------- +%g:=shape factores of soil components (set to spherical gx=gy=gz) +g(1,:)=1/3; +g(2,:)=1/3; +g(3,:)=1/3; +%power for liquid recirculation function +qo=qo; +%cutoff water content for liquid recirculation [m³/m³] +Xo=Xo; +%calculate Ly:=conductivity of matrix material +q=qo*((T+273.15)/303)^2; +if isempty(fw)==1 + fw=1/(1+(X(3,:)/Xo)^-q); +end +Ly=L(1,:)+fw*(L(3,:)-L(1,:)); +%calculate k:=effectiv conductivity +for i=1:5 + for j=1:3 + K1(i,j)=1/(1+(L(i,1)/Ly-1)*g(j,1)); + end +end +K=1/3*sum(K1')'; +k=sum(K.*L.*X)/sum(K.*X); + + +function [k]=conductDV63_iw(X,L,T,Xo,qo,fw) +%function calculates heat conductivity based on de Vries (1963) +%Input parameter: X:=fraction of soil material +% L:=individual conductivities of soil components +% Xo:=cutoff water content for liquid recirculation [m³/m³] +% qo:=power for liquid recirculation function +% fw:=weighting function (if empty else fw=1 for saturated +% soil or fw=0 for dry soils +%-------------------------------------------------------------------------- +%g:=shape factores of soil components (set to spherical gx=gy=gz) +g(1,:)=1/3; +g(2,:)=1/3; +g(3,:)=1/3; +%power for liquid recirculation function +qo=qo; +%cutoff water content for liquid recirculation [m³/m³] +Xo=Xo; +%calculate Ly:=conductivity of matrix material +q=qo*((T+273.15)/303)^2; +if isempty(fw)==1 + fw=1/(1+(X(2,:)/Xo)^-q); +end +Ly=L(3,:)+fw*(L(2,:)-L(3,:)); +%calculate k:=effectiv conductivity +for i=1:5 + for j=1:3 + K1(i,j)=1/(1+(L(i,1)/Ly-1)*g(j,1)); + end +end +K=1/3*sum(K1')'; +k=sum(K.*L.*X)/sum(K.*X); diff --git a/modules/cryoGridSoil/getSoilThermalNew.m b/modules/cryoGridSoil/getSoilThermalNew.m new file mode 100644 index 0000000..cb44c18 --- /dev/null +++ b/modules/cryoGridSoil/getSoilThermalNew.m @@ -0,0 +1,70 @@ +function soilParam=getSoilThermalNew(soilcode) + +code(1)=11; +par(1).numbers=[0 0.3 0.6 0 0 1 0; 1.9 0.3 0.6 0 0 1 0; 2.1 0.4 0.6 0 0 1 0; 9.9 0.4 0.6 0 0 1 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(2)=15; +par(2).numbers=[0 0.3 0.6 0 0 1 0; 1.9 0.3 0.6 0 0 1 0; 2.1 0.4 0.6 0 0 1 0; 9.9 0.4 0.6 0 0 1 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(3)=81; +par(3).numbers=[0 0.3 0.6 0 0 1 0; 1.9 0.3 0.6 0 0 1 0; 2.1 0.4 0.6 0 0 1 0; 9.9 0.4 0.6 0 0 1 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(4)=12; +par(4).numbers=[0 0.3 0.6 0 0 1 0; 0.99 0.3 0.6 0 0 1 0; 1.01 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(5)=140; +par(5).numbers=[0 0.3 0.6 0 0 1 0; 0.99 0.3 0.6 0 0 1 0; 1.01 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(6)=130; +par(6).numbers=[0 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + + + + +code(7)=20; +par(7).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 19.9 0.4 0.6 0 0 1 0; 20.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(8)=21; +par(8).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 19.9 0.4 0.6 0 0 1 0; 20.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + + +code(9)=50; +par(9).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 9.9 0.4 0.6 0 0 1 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + + + + +code(10)=70; +par(10).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 1.9 0.4 0.6 0 0 1 0; 2.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(11)=71; +par(11).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 4.9 0.4 0.6 0 0 1 0; 5.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(12)=73; +par(12).numbers=[0 0.1 0.6 0 0 1 0; 1.9 0.1 0.6 0 0 1 0; 2.1 0.4 0.6 0 0 1 0; 4.9 0.4 0.6 0 0 1 0; 5.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(13)=22; +par(13).numbers=[0 0.1 0.6 0 0 1 0; 4.9 0.1 0.6 0 0 1 0; 5.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + + + + +code(14)=90; +%par(14).numbers=[0 0.3 0.1 0.3 0 1 0; 0.99 0.3 0.1 0.3 0 1 0; 1.01 0.6 0.1 0.3 0 1 0; 1.9 0.6 0.1 0.3 0 1 0; 2.1 0.5 0.4 0.1 0 2 0; 9.9 0.5 0.4 0.1 0 2 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; +par(14).numbers=[0 0.3 0.2 0.3 0 1 0; 0.5 0.3 0.2 0.3 0 1 0; 0.51 0.5 0.2 0.3 0 1 0; 1.9 0.5 0.2 0.3 0 1 0; 2.1 0.5 0.4 0.1 0 2 0; 9.9 0.5 0.4 0.1 0 2 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(15)=100; +par(15).numbers=[0 0.5 0.4 0.1 0 1 0; 0.49 0.5 0.4 0.1 0 1 0; 0.51 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; + +code(16)=1000; % soil stratigraphy assumed for Samoilov run +par(16).numbers=[0 0.7 0.25 0.05 0 2 0; 10 0.3 0.7 0 0 1 0; 101 0.3 0.7 0 0 1 0]; + + +if ~isempty(find(code==soilcode)) + soilParam=par(find(code==soilcode)).numbers; + soilParam=[-100 0.0 0.5 0 0 1 0; soilParam]; +else + soilParam=[NaN NaN NaN NaN NaN NaN NaN]; +end + + diff --git a/modules/cryoGridTechnical/add_modules.m b/modules/cryoGridTechnical/add_modules.m new file mode 100644 index 0000000..d93d711 --- /dev/null +++ b/modules/cryoGridTechnical/add_modules.m @@ -0,0 +1,15 @@ +clear all +close all +profile off +dbclear if error +%dbstop if error + +%import CryoGrid modules (matlab functions) +addpath('modules/cryoGridTechnical/') +addpath('modules/cryoGridInitialize/') +addpath('modules/cryoGridSEB/') +addpath('modules/cryoGridSoil/') +addpath('modules/cryoGridSnow/') + +addpath('modules/cryoGridExcessIce/') +addpath('modules/cryoGridRockFields/') diff --git a/modules/cryoGridTechnical/generateLOOPVAR.m b/modules/cryoGridTechnical/generateLOOPVAR.m new file mode 100644 index 0000000..a61ad13 --- /dev/null +++ b/modules/cryoGridTechnical/generateLOOPVAR.m @@ -0,0 +1,45 @@ +function [loop_PARA loopI_PERMUT] = generateLOOPVAR(LOOPVAR, LI) + + +%example +% LI=5; +% LOOPVAR.ice_albedo = [0.1 0.2 0.3]; +% LOOPVAR.ice_extinction = [7.0 8.4 9.0]; +% LOOPVAR.water_extinction = [0.2 0.5 0.8]; +% LOOPVAR.FLAKE_fetch = [50 150 250]; + +var_names = fieldnames(LOOPVAR); + +for i=1:length(var_names) + var_names{i,2}=['i_' num2str(i)]; + var_names{i,3}=num2str(length(eval(['LOOPVAR.' var_names{1}]))); +end + +start_str=[]; +mind_str=[]; +end_str=[]; +for i=1:length(var_names) + start_str=[start_str 'for ' var_names{i,2} '=1:' var_names{i,3} '; ']; + mind_str=[mind_str var_names{i,2} ' ']; + end_str=[end_str 'end; ']; +end +loop_index=[]; +eval([start_str 'loop_index=[loop_index; ' mind_str ']; ' end_str]) + +for i=1:length(var_names) + eval(['loopI_PERMUT.' var_names{i,1} '=' 'loop_index(:,' num2str(i) ');']) + eval(['loop_PARA.' var_names{i,1} '=' 'LOOPVAR.' var_names{i,1} '(loop_index(' num2str(LI) ',' num2str(i) '));' ]) + + +end + + + + + + + + + + + diff --git a/modules/cryoGridTechnical/generateOUT.m b/modules/cryoGridTechnical/generateOUT.m index 169e37a..9b0bc3e 100644 --- a/modules/cryoGridTechnical/generateOUT.m +++ b/modules/cryoGridTechnical/generateOUT.m @@ -10,6 +10,10 @@ OUT.timestamp=[]; OUT.TIMESTEP=[]; + %auxiliary for tracking heat fluxes + OUT.SEB.dE_dt_SEB = []; + OUT.SEB.dE_dt_cond = []; + OUT.SEB.Lsta=[]; OUT.SEB.QE=[]; OUT.SEB.QH=[]; @@ -26,6 +30,9 @@ OUT.snow.topPosition=[]; OUT.snow.botPosition=[]; + % for DEBUGGING + OUT.K_grid = []; + % water balance (WB) % all flows are defined as positive when they go into the soil/snow column % cumulative values per output interval in [mm] @@ -40,11 +47,12 @@ OUT.WB.ds=[]; % runoff OUT.WB.dr_surface=[]; - OUT.WB.dr_subsurface=[]; + OUT.WB.dr_external=[]; OUT.WB.dr_snowmelt=[]; OUT.WB.dr_excessSnow=[]; OUT.WB.dr_rain=[]; % this is only rain on frozen ground - + + % energy balance (EB) % accumulated energy fluxes per output time in [ J / m^2 ] OUT.EB.Qg = []; % ground heat flux (positive into ground) @@ -52,6 +60,7 @@ OUT.EB.Qh = []; % sensible heat flux (positive into ground) OUT.EB.Qnet = []; OUT.EB.Qgeo = []; % geothermal heat flux + OUT.EB.Qsurf = []; % heat flux into uppermost grid cell OUT.EB.dE_soil_sens = []; OUT.EB.dE_soil_lat = []; diff --git a/modules/cryoGridTechnical/initializeWaterEnergyBalance.m b/modules/cryoGridTechnical/initializeWaterEnergyBalance.m new file mode 100644 index 0000000..c3c73bf --- /dev/null +++ b/modules/cryoGridTechnical/initializeWaterEnergyBalance.m @@ -0,0 +1,14 @@ +% energy content soil domain in [J/m^2] +% distinguished by sensible and latent part +E_soil_sens = nansum( ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral + PARA.constants.c_o .* GRID.soil.cT_organic ) .* T(GRID.soil.cT_domain) ... + .* GRID.general.K_delta(GRID.soil.cT_domain) ); +E_soil_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc .* GRID.general.K_delta(GRID.soil.cT_domain) ); +E_soil = E_soil_sens + E_soil_lat; +% energy content snow domain in [J/m^2] +E_snow_sens = nansum( c_cTgrid(GRID.snow.cT_domain) .* T(GRID.snow.cT_domain) .* GRID.general.K_delta(GRID.snow.cT_domain) ); +E_snow_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc_cTgrid(GRID.snow.cT_domain).* GRID.general.K_delta(GRID.snow.cT_domain) ); +E_snow = E_snow_sens + E_snow_lat; +% water content soil domain in [m] +W_soil = nansum( wc .* GRID.general.K_delta(GRID.soil.cT_domain) ); +% water content snow domain in [m] +W_snow = nansum( GRID.snow.Snow_i + GRID.snow.Snow_w ) + GRID.snow.SWEinitial; \ No newline at end of file diff --git a/modules/cryoGridTechnical/loadConstants.m b/modules/cryoGridTechnical/loadConstants.m index 276fc90..2af6fae 100644 --- a/modules/cryoGridTechnical/loadConstants.m +++ b/modules/cryoGridTechnical/loadConstants.m @@ -1,5 +1,5 @@ function PARA = loadConstants( PARA ) - % important natural constants, given in SI units [m, kg, s, J, K] + % important natural constants, given in SI units PARA.constants.kappa = 0.4; % von Kármán constant [-] PARA.constants.sigma = 5.6704e-8; % Stefan-Boltzmann constant [ W / (m^2 K^4) ] PARA.constants.g = 9.81; % gravitational acceleration [m/s^2] @@ -12,7 +12,7 @@ PARA.constants.rho_i = 1000; % density of ice, assumed to be equal to that of water [kg/m^3] PARA.constants.c_i = 1900 * PARA.constants.rho_i; % volumetric heat capacity of ice [ J / (m^3 K) ] PARA.constants.k_i = 2.2; % heat conductivity of ice [ W/(mK) ] [Hillel(1982)] - %latent heat of water phase changes + %latent heat of water PARA.constants.T_f = 273.15; % freezing point of water / zero degree Celsius [K] PARA.constants.L_sl = 334e3; % specific latent heat of fusion of water [J/kg] [AMS] PARA.constants.L_lg = 2501e3; % specific latent heat of vaporization of water [J/kg] [AMS] @@ -22,10 +22,12 @@ PARA.constants.c_a = 1005.7 * PARA.constants.rho_a; %c_a= 0.00125*10^6;%[J/m^3 K] % volumetric heat capacity of dry air [J/(m^3 K)] @ 0°C, sea level, isobar PARA.constants.k_a = 0.0243; %ka=0.025; [Hillel(1982)] % heat conductivity of air [ W/(mK)] @ 0 °C, sea level pressure PARA.constants.R_a = 287.058; % specific gas constant of air [ J/(kg K) ] - %organic + % organic + %PARA.constants.rho_o = 1; % n.a. PARA.constants.c_o = 2.5e6; %[J/(K m^3)] % volumetric heat capacity of organic material [J/(K m^3)] PARA.constants.k_o = 0.25; % heat conductivity of organic material [ W/(mK) ] [Hillel(1982)] - %mineral - PARA.constants.c_m = 2.0e6; %[J/(K m^3)] % volumetric heat capacity of minearal material [J/(K m^3)] - PARA.constants.k_m = PARA.soil.kh_bedrock; % heat conductivity of mineral material / bedrock [ W/(mK)] (specified above) %km=3.8 %mineral [Hillel(1982)] + % mineral + %PARA.constants.rho_m = 1; % n.a. + PARA.constants.c_m = 2.0e6; %[J/(K m^3)] % volumetric heat capacity of minearal material [J/(K m^3)] + PARA.constants.k_m = PARA.soil.kh_bedrock; % heat conductivity of mineral material / bedrock [ W/(mK)] (specified above) %km=3.8 %mineral [Hillel(1982)] end \ No newline at end of file diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 26a3b2a..6a07520 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -1,3 +1,6 @@ +function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT) + + TEMPORARY.timestep_sum=TEMPORARY.timestep_sum+(timestep*24*3600)*timestep; TEMPORARY.T_sum=TEMPORARY.T_sum+T.*timestep; TEMPORARY.Qe_sum=TEMPORARY.Qe_sum+SEB.Qe.*timestep; @@ -5,6 +8,13 @@ TEMPORARY.Qnet_sum=TEMPORARY.Qnet_sum+SEB.Qnet.*timestep; TEMPORARY.Qg_sum=TEMPORARY.Qg_sum+SEB.Qg.*timestep; + TEMPORARY.Qsurf_sum = TEMPORARY.Qsurf_sum + SEB.Qsurf * timestep; + TEMPORARY.dE_dt_SEB_sum = TEMPORARY.dE_dt_SEB_sum + SEB.dE_dt_SEB * timestep; + TEMPORARY.dE_dt_cond_sum = TEMPORARY.dE_dt_cond_sum + SEB.dE_dt_cond * timestep; + + + + %----store in output table -------------------------------------------- if t==TEMPORARY.outputTime @@ -22,6 +32,11 @@ TEMPORARY.Qnet=TEMPORARY.Qnet_sum./TEMPORARY.dt_out; TEMPORARY.Qg=TEMPORARY.Qg_sum./TEMPORARY.dt_out; + TEMPORARY.Qsurf = TEMPORARY.Qsurf_sum ./ TEMPORARY.dt_out; + TEMPORARY.dE_dt_SEB=TEMPORARY.dE_dt_SEB_sum./TEMPORARY.dt_out; + TEMPORARY.dE_dt_cond=TEMPORARY.dE_dt_cond_sum./TEMPORARY.dt_out; + + TEMPORARY.timestep_out=TEMPORARY.timestep_sum./TEMPORARY.dt_out; %reset sum variables @@ -30,7 +45,11 @@ TEMPORARY.Qh_sum=0; TEMPORARY.Qe_sum=0; TEMPORARY.Qnet_sum=0; - TEMPORARY.Qg_sum=0; + TEMPORARY.Qg_sum=0; + TEMPORARY.Qsurf_sum = 0; + TEMPORARY.dE_dt_SEB_sum=0; + TEMPORARY.dE_dt_cond_sum=0; + TEMPORARY.timestep_sum=0; @@ -45,7 +64,10 @@ OUT.snow.outSnow_a=[OUT.snow.outSnow_a GRID.snow.Snow_a]; OUT.snow.outSnow_w=[OUT.snow.outSnow_w GRID.snow.Snow_w]; - % surface energy balance + % surface energy balance + OUT.SEB.dE_dt_SEB = [OUT.SEB.dE_dt_SEB [ TEMPORARY.dE_dt_SEB ] ]; + OUT.SEB.dE_dt_cond = [OUT.SEB.dE_dt_cond [ TEMPORARY.dE_dt_cond ]]; + OUT.SEB.Lsta=[OUT.SEB.Lsta; mean(SEB.L_star)]; OUT.SEB.QE=[OUT.SEB.QE; TEMPORARY.Qe]; OUT.SEB.QH=[OUT.SEB.QH; TEMPORARY.Qh]; @@ -60,6 +82,7 @@ OUT.EB.Qh = [OUT.EB.Qh; TEMPORARY.Qh]; % sensible heat flux (positive into ground) OUT.EB.Qnet = [OUT.EB.Qnet; TEMPORARY.Qnet]; OUT.EB.Qgeo = [OUT.EB.Qgeo; PARA.soil.Qgeo]; % geothermal heat flux + OUT.EB.Qsurf = [OUT.EB.Qsurf; TEMPORARY.Qsurf]; OUT.EB.dE_soil_sens = [OUT.EB.dE_soil_sens; BALANCE.energy.dE_soil_sens ]; BALANCE.energy.dE_soil_sens = 0; OUT.EB.dE_soil_lat = [OUT.EB.dE_soil_lat; BALANCE.energy.dE_soil_lat ]; @@ -86,12 +109,13 @@ OUT.WB.de = [ OUT.WB.de; BALANCE.water.de ]; OUT.WB.ds = [ OUT.WB.ds; BALANCE.water.ds ]; % runoff - OUT.WB.dr_surface=[ OUT.WB.dr_surface; BALANCE.water.dr_surface ]; - OUT.WB.dr_subsurface = [ OUT.WB.dr_subsurface; BALANCE.water.dr_subsurface ]; + OUT.WB.dr_surface= [ OUT.WB.dr_surface; BALANCE.water.dr_surface ]; + OUT.WB.dr_external = [ OUT.WB.dr_external; BALANCE.water.dr_external ]; OUT.WB.dr_snowmelt = [ OUT.WB.dr_snowmelt; BALANCE.water.dr_snowmelt ]; OUT.WB.dr_excessSnow=[ OUT.WB.dr_excessSnow; BALANCE.water.dr_excessSnow ]; OUT.WB.dr_rain = [ OUT.WB.dr_rain; BALANCE.water.dr_rain ]; % this is only rain on frozen ground % set accumulated fluxes in BALANCE.water struct to zero + % storage BALANCE.water.dW_soil = 0; BALANCE.water.dW_snow = 0; % precipitation @@ -102,16 +126,22 @@ BALANCE.water.ds=0; % runoff BALANCE.water.dr_surface=0; - BALANCE.water.dr_subsurface=0; + BALANCE.water.dr_external=0; BALANCE.water.dr_snowmelt=0; BALANCE.water.dr_excessSnow=0; - BALANCE.water.dr_rain=0; % this is only rain on frozen ground + BALANCE.water.dr_rain=0; % soil OUT.soil.soil{1, size(OUT.soil.soil,2)+1}=[GRID.soil.cT_water GRID.soil.cT_mineral GRID.soil.cT_organic]; OUT.soil.topPosition=[OUT.soil.topPosition; -GRID.general.K_grid(GRID.soil.cT_domain_ub)]; % water body +% waterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6; +% if sum(waterBody)>0 +% OUT.soil.lakeFloor = [OUT.soil.lakeFloor; - GRID.general.K_grid( GRID.soil.cT_domain_ub + find(waterBody,1,'last') ) ] ; +% else +% OUT.soil.lakeFloor = [OUT.soil.lakeFloor; NaN]; +% end if ~isempty( GRID.lake.cT_domain_ub ) OUT.soil.lakeFloor = [OUT.soil.lakeFloor; - GRID.general.K_grid(GRID.lake.cT_domain_lb+1) ]; else @@ -129,6 +159,10 @@ OUT.snow.topPosition=[OUT.snow.topPosition; TEMPORARY.topPosition]; OUT.snow.botPosition=[OUT.snow.botPosition; TEMPORARY.botPosition]; + % for DEBUGGING + OUT.K_grid = [OUT.K_grid, GRID.general.K_grid ]; + + %------------------------------------------------------------------ disp([datestr(now,'yyyy-mm-dd HH:MM:SS'),': at ',datestr(t), ', Average timestep: ', num2str(TEMPORARY.timestep_out), ' seconds']) diff --git a/modules/cryoGridTechnical/updateWaterEnergyBalance.m b/modules/cryoGridTechnical/updateWaterEnergyBalance.m index 9d4e980..6bcf599 100644 --- a/modules/cryoGridTechnical/updateWaterEnergyBalance.m +++ b/modules/cryoGridTechnical/updateWaterEnergyBalance.m @@ -1,32 +1,31 @@ - % at this point the thermal and hydrological state of the soil and snow is calculated - % energy content soil domain in [J/m^2] - % distinguished by sensible and latent part - E_soil_sens_old = E_soil_sens; - E_soil_lat_old = E_soil_lat; - E_soil_old = E_soil; - E_soil_sens = nansum( ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral + PARA.constants.c_o .* GRID.soil.cT_organic ) .* T(GRID.soil.cT_domain) ... - .* GRID.general.K_delta(GRID.soil.cT_domain) ); - E_soil_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc .* GRID.general.K_delta(GRID.soil.cT_domain) ); - E_soil = E_soil_sens + E_soil_lat; - TEMPORARY.dE_soil_sens = TEMPORARY.dE_soil_sens + E_soil_sens - E_soil_sens_old; - TEMPORARY.dE_soil_lat = TEMPORARY.dE_soil_lat + E_soil_lat - E_soil_lat_old; - TEMPORARY.dE_soil = TEMPORARY.dE_soil + E_soil - E_soil_old; - % energy content snow domain in [J/m^2] - E_snow_sens_old = E_snow_sens; - E_snow_lat_old = E_snow_lat; - E_snow_old = E_snow; - E_snow_sens = nansum( c_cTgrid(GRID.snow.cT_domain) .* T(GRID.snow.cT_domain) .* GRID.general.K_delta(GRID.snow.cT_domain) ); - E_snow_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc_cTgrid(GRID.snow.cT_domain).* GRID.general.K_delta(GRID.snow.cT_domain) ); - E_snow = E_snow_sens + E_snow_lat; - TEMPORARY.dE_snow_sens = TEMPORARY.dE_snow_sens + E_snow_sens - E_snow_sens_old; - TEMPORARY.dE_snow_lat = TEMPORARY.dE_snow_lat + E_snow_lat - E_snow_lat_old; - TEMPORARY.dE_snow = TEMPORARY.dE_snow + E_snow - E_snow_old; - % water content soil domain in [m] - W_soil_old = W_soil; - W_soil = nansum( wc .* GRID.general.K_delta(GRID.soil.cT_domain) ); - HYDRO.dW_soil = HYDRO.dW_soil + (W_soil - W_soil_old)*1000; % in [mm] - % water content snow domain in [m] - W_snow_old = W_snow; - W_snow = nansum( GRID.snow.Snow_i + GRID.snow.Snow_w ) + GRID.snow.SWEinitial; - HYDRO.dW_snow = HYDRO.dW_snow + (W_snow - W_snow_old)*1000; % in [mm] - \ No newline at end of file +% at this point the thermal and hydrological state of the soil and snow is calculated +% energy content soil domain in [J/m^2] +% distinguished by sensible and latent part +E_soil_sens_old = E_soil_sens; +E_soil_lat_old = E_soil_lat; +E_soil_old = E_soil; +E_soil_sens = nansum( ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral + PARA.constants.c_o .* GRID.soil.cT_organic ) .* T(GRID.soil.cT_domain) ... + .* GRID.general.K_delta(GRID.soil.cT_domain) ); +E_soil_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc .* GRID.general.K_delta(GRID.soil.cT_domain) ); +E_soil = E_soil_sens + E_soil_lat; +TEMPORARY.dE_soil_sens = TEMPORARY.dE_soil_sens + E_soil_sens - E_soil_sens_old; +TEMPORARY.dE_soil_lat = TEMPORARY.dE_soil_lat + E_soil_lat - E_soil_lat_old; +TEMPORARY.dE_soil = TEMPORARY.dE_soil + E_soil - E_soil_old; +% energy content snow domain in [J/m^2] +E_snow_sens_old = E_snow_sens; +E_snow_lat_old = E_snow_lat; +E_snow_old = E_snow; +E_snow_sens = nansum( c_cTgrid(GRID.snow.cT_domain) .* T(GRID.snow.cT_domain) .* GRID.general.K_delta(GRID.snow.cT_domain) ); +E_snow_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc_cTgrid(GRID.snow.cT_domain).* GRID.general.K_delta(GRID.snow.cT_domain) ); +E_snow = E_snow_sens + E_snow_lat; +TEMPORARY.dE_snow_sens = TEMPORARY.dE_snow_sens + E_snow_sens - E_snow_sens_old; +TEMPORARY.dE_snow_lat = TEMPORARY.dE_snow_lat + E_snow_lat - E_snow_lat_old; +TEMPORARY.dE_snow = TEMPORARY.dE_snow + E_snow - E_snow_old; +% water content soil domain in [m] +W_soil_old = W_soil; +W_soil = nansum( wc .* GRID.general.K_delta(GRID.soil.cT_domain) ); +HYDRO.dW_soil = HYDRO.dW_soil + (W_soil - W_soil_old)*1000; % in [mm] +% water content snow domain in [m] +W_snow_old = W_snow; +W_snow = nansum( GRID.snow.Snow_i + GRID.snow.Snow_w ) + GRID.snow.SWEinitial; +HYDRO.dW_snow = HYDRO.dW_snow + (W_snow - W_snow_old)*1000; % in [mm] \ No newline at end of file From e32e99040ec13524e811baf412f010416288bbce Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Tue, 16 Jan 2018 09:42:33 +0100 Subject: [PATCH 02/45] removed unnecessary functions from git repo --- modules/cryoGridFlake/cryoGridFLAKE.m | 144 ------------ modules/cryoGridFlake/updateGRID_flake.m | 16 -- modules/cryoGridInitialize/initializeHYDRO.m | 34 --- modules/cryoGridSoil/conductionDevries.m | 215 ------------------ modules/cryoGridSoil/getSoilThermalNew.m | 70 ------ modules/cryoGridTechnical/generateLOOPVAR.m | 45 ---- .../initializeWaterEnergyBalance.m | 14 -- .../updateWaterEnergyBalance.m | 31 --- 8 files changed, 569 deletions(-) delete mode 100644 modules/cryoGridFlake/cryoGridFLAKE.m delete mode 100644 modules/cryoGridFlake/updateGRID_flake.m delete mode 100644 modules/cryoGridInitialize/initializeHYDRO.m delete mode 100644 modules/cryoGridSoil/conductionDevries.m delete mode 100644 modules/cryoGridSoil/getSoilThermalNew.m delete mode 100644 modules/cryoGridTechnical/generateLOOPVAR.m delete mode 100644 modules/cryoGridTechnical/initializeWaterEnergyBalance.m delete mode 100644 modules/cryoGridTechnical/updateWaterEnergyBalance.m diff --git a/modules/cryoGridFlake/cryoGridFLAKE.m b/modules/cryoGridFlake/cryoGridFLAKE.m deleted file mode 100644 index fa7b5a1..0000000 --- a/modules/cryoGridFlake/cryoGridFLAKE.m +++ /dev/null @@ -1,144 +0,0 @@ -function [T, GRID, FLAKE]=cryoGridFLAKE(FLAKE,GRID,SEB,PARA,T,T_old,timestep,k_eff,dE_dt,dE_dt_SEB) - -%update average temperature of the water domain -FLAKE.t_mnw_n_flk = sum(T_old(GRID.lake.water.cT_domain).*GRID.general.K_delta(GRID.lake.water.cT_domain)) ... - ./ sum(GRID.general.K_delta(GRID.lake.water.cT_domain)) + 273.15; - -%update water depth -FLAKE.depth_w = GRID.general.K_grid(GRID.lake.water.cT_domain_lb + 1) - GRID.general.K_grid(GRID.lake.water.cT_domain_ub); - -%update mean temperature according to changes in average temperature with -%water depth. This prevents changes in the bottom temperature due to sudden -%changes in water depth -if GRID.lake.ice.z_ice>0 - FLAKE.t_mnw_p_flk = FLAKE.t_mnw_n_flk; - FLAKE.t_mnw_n_flk = FLAKE.t_wml_n_flk - FLAKE.c_t_n_flk.*(FLAKE.t_wml_n_flk-FLAKE.t_bot_n_flk).*(1.-FLAKE.h_ml_n_flk./FLAKE.depth_w); - GRID.lake.ice.z_ice = GRID.lake.ice.z_ice - (FLAKE.t_mnw_p_flk-FLAKE.t_mnw_n_flk).*4.2e6.*FLAKE.depth_w./(334e3 * 910); -end - -%update ice cover status and thickness -if FLAKE.h_ice_n_flk<1e-3 && GRID.lake.ice.z_ice>=1e-3 - FLAKE.l_ice_create = true; -else - FLAKE.l_ice_create = false; -end -FLAKE.h_ice_n_flk = GRID.lake.ice.z_ice; - -%set boundary conditions -FLAKE.q_snow_flk= 0.; -FLAKE.q_ice_flk = 0.; -FLAKE.q_bot_flk = -(T_old(GRID.lake.water.cT_domain_lb+1)-T_old(GRID.lake.water.cT_domain_lb))... - ./ GRID.general.cT_delta(GRID.lake.water.cT_domain_lb) .* k_eff(GRID.lake.water.cT_domain_lb+1); - -FLAKE.q_w_flk = sum(dE_dt_SEB(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb+1)) ... - - SEB.Sin_water ... - + sum(dE_dt(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb)) ... - - sum(dE_dt_SEB(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb)) ... - + FLAKE.q_bot_flk ... - + GRID.lake.ice.dz_dt_freeze*334e3*910 ... - + GRID.lake.ice.dE_dt_melt_residual; - -if FLAKE.q_w_flk>0 && GRID.lake.ice.z_ice>0 - %correct for positive water heat fluxes under ice cover. This is - %necessary due to the very simple ice cover scheme which needs to - %be improved in fututre model versions. - GRID.lake.ice.z_ice = GRID.lake.ice.z_ice - FLAKE.q_w_flk.*(timestep *24*3600)/(334e3 * 910); - FLAKE.q_w_flk = 0; - FLAKE.h_ice_n_flk = GRID.lake.ice.z_ice; -end - -%transform u_star in atmosphere to u_star in water assuming constant -%desities for air and water. -FLAKE.u_star_w_flk=(SEB.u_star.^2.*(1.293./1e3)).^0.5; - -%calculate FLAKE radiative heat transfer -[FLAKE.i_atm_flk,... - FLAKE.i_w_flk,... - FLAKE.i_ice_flk,... - FLAKE.i_snow_flk,... - FLAKE.i_h_flk,... - FLAKE.i_bot_flk,... - FLAKE.i_intm_0_h_flk,... - FLAKE.i_intm_h_d_flk] = flake_radflux(SEB.Sin_water,FLAKE,PARA); - -% %call FLAKE main function -% if PARA.technical.MEX -% FLAKE = flake_driver_mex(FLAKE, timestep.*24.*3600); -% else - FLAKE = flake_driver(FLAKE, timestep.*24.*3600); -% end - -%map water temperature from shape function on the regular grid -%calculate dimensionless water depth of thermocline -% zeta_cT = (GRID.lake.water.cT_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) - FLAKE.h_ml_n_flk) ... -% ./ ((FLAKE.depth_w - FLAKE.h_ml_n_flk)); - -zeta_K = (GRID.lake.water.K_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) - FLAKE.h_ml_n_flk) ... - ./ ((FLAKE.depth_w - FLAKE.h_ml_n_flk)); -zeta_K = [zeta_K; 1]; -zeta_delta = diff(zeta_K); - -if ~isempty(zeta_delta) - %The original FLAKE shape function not used due to interpolation - %errors on discrete grid - %phi_theta = (40/3*FLAKE.c_t_n_flk-20/3)*zeta_cT ... - % + (18-30*FLAKE.c_t_n_flk)*zeta_cT.^2 ... - % + (20*FLAKE.c_t_n_flk-12)*zeta_cT.^3 ... - % + (5/3 - 10/3*FLAKE.c_t_n_flk)*zeta_cT.^4; - - %Integrated shape function to calculate averages on discrete grid - int_phi_theta = (40/3*FLAKE.c_t_n_flk-20/3)*1/2*zeta_K.^2 ... - + (18-30*FLAKE.c_t_n_flk)*1/3*zeta_K.^3 ... - + (20*FLAKE.c_t_n_flk-12)*1/4*zeta_K.^4 ... - + (5/3 - 10/3*FLAKE.c_t_n_flk)*1/5*zeta_K.^5; - - %calculate partial intergral for grid cells - int_phi_theta = int_phi_theta(2:end) - int_phi_theta(1:end-1); - phi_theta = int_phi_theta./zeta_delta; - - %change from dimensionless temperature to absolute temperature - Tw_z = -(phi_theta*(FLAKE.t_wml_n_flk-FLAKE.t_bot_n_flk) - FLAKE.t_wml_n_flk)-273.15; -else - Tw_z = []; -end -%map temperature on water grid -Tw = T(GRID.lake.water.cT_domain); - -%note that a step is introduced which introduces small discretization -%errors which need to be corrected later -Tw(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) = Tw_z; -Tw(GRID.lake.water.K_grid0 - GRID.lake.ice.z_ice = GRID.lake.ice.z_ice + dE./(334e3 * 910); - %set T water surf to zero - %dE=(0-T(GRID.lake.water.cT_domain_ub))*GRID.general.K_delta(GRID.lake.water.cT_domain_ub)*4.2e6; - %GRID.lake.ice.z_ice = GRID.lake.ice.z_ice + dE./(334e3 * 910); - %T(GRID.lake.water.cT_domain_ub) = 0; -else - ub_h_ml=min([GRID.lake.water.K_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk); FLAKE.depth_w]); - lb_h_ml=FLAKE.depth_w; - if (lb_h_ml-ub_h_ml)>0 - Tw(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) = Tw_z - dE/(4.2e6* (lb_h_ml-ub_h_ml)); - else - Tw = Tw - dE/(4.2e6 * FLAKE.depth_w); - end - T(GRID.lake.water.cT_domain) = Tw; -end - -%update FLAKE average temperature of the water domain -FLAKE.t_mnw_n_flk = sum(T(GRID.lake.water.cT_domain).*GRID.general.K_delta(GRID.lake.water.cT_domain)) ... - ./ sum(GRID.general.K_delta(GRID.lake.water.cT_domain)) + 273.15; - - - diff --git a/modules/cryoGridFlake/updateGRID_flake.m b/modules/cryoGridFlake/updateGRID_flake.m deleted file mode 100644 index 0a7df70..0000000 --- a/modules/cryoGridFlake/updateGRID_flake.m +++ /dev/null @@ -1,16 +0,0 @@ -function GRID = updateGRID_flake(GRID) - - -%update ice cover and water grid -GRID.lake.ice.cT_domain = (GRID.general.K_grid(2:end) - GRID.general.K_grid(min([GRID.lake.water.cT_domain_ub GRID.lake.ice.cT_domain_ub GRID.lake.ice.cT_domain_ub])))<=GRID.lake.ice.z_ice & ... - (GRID.general.K_grid(2:end) - GRID.general.K_grid(min([GRID.lake.water.cT_domain_ub GRID.lake.ice.cT_domain_ub])))> 0; - -GRID.lake.ice.K_domain = GRID.lake.ice.cT_domain; -[GRID.lake.ice.cT_domain_lb GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); -[GRID.lake.ice.K_domain_lb GRID.lake.ice.K_domain_ub] = LayerIndex(GRID.lake.ice.K_domain); - -%update water body grid -GRID.lake.water.cT_domain = (~GRID.air.cT_domain & ~GRID.snow.cT_domain & ~GRID.lake.ice.cT_domain & ~GRID.soil.cT_domain); -GRID.lake.water.K_domain = GRID.lake.water.cT_domain; -[GRID.lake.water.cT_domain_lb GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); -[GRID.lake.water.K_domain_lb GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); diff --git a/modules/cryoGridInitialize/initializeHYDRO.m b/modules/cryoGridInitialize/initializeHYDRO.m deleted file mode 100644 index 1a1457c..0000000 --- a/modules/cryoGridInitialize/initializeHYDRO.m +++ /dev/null @@ -1,34 +0,0 @@ -function HYDRO = initializeHYDRO() - -% NEW variable names -% storage -HYDRO.dW_soil = 0; -HYDRO.dW_snow = 0; -% precipitation -HYDRO.dp_rain=0; -HYDRO.dp_snow=0; % SWE -% evapotranspiration and sublimation -HYDRO.de=0; -HYDRO.ds=0; -% runoff -HYDRO.dr_surface=0; -HYDRO.dr_subsurface=0; -HYDRO.dr_snowmelt=0; -HYDRO.dr_excessSnow=0; -HYDRO.dr_rain=0; % this is only rain on frozen ground - -end -% OLD variable names: -% HYDRO.rain = 0; -% HYDRO.snow = 0; -% HYDRO.sublimation = 0; -% HYDRO.condensation = 0; -% HYDRO.evapotranspiration = 0; -% HYDRO.surfaceRunoffBucket = 0; -% HYDRO.surfaceRunoffRain = 0; -% HYDRO.surfaceRunoffSnow = 0; -% HYDRO.surfaceRunoffLastCell = 0; -% HYDRO.surfaceRunoffGroundIce = 0; -% HYDRO.lateralFluxBucket = 0; -% HYDRO.excessSnow = 0; -% HYDRO.initialSnow = 0; diff --git a/modules/cryoGridSoil/conductionDevries.m b/modules/cryoGridSoil/conductionDevries.m deleted file mode 100644 index 86d44e4..0000000 --- a/modules/cryoGridSoil/conductionDevries.m +++ /dev/null @@ -1,215 +0,0 @@ -function [Lambda]=conductionDevries(w_c,i_c,min_c,org_c,T,Xo,qo) -% function calculates soil heat conductivity using volumetric contents of water, ice, -% organic and minerals. -% Based on de Vries (1963) / Campbell et al. (1994) -% Input parameters: w_c:=water content -% i_c:=ice content -% min_c:=mineral content -% org_c:=organic content -% T:=soil temperature [°C] -% Xo:=cutoff water content for liquid recirculation [m³/m³] -% qo:=power for liquid recirculation function -%-------------------------------------------------------------------------- - - -warning off all -P=1-min_c-org_c; - -L(1,:)=0.025; %air [Hillel(1982)] -L(2,:)=0.57; %water [Hillel(1982)] -L(3,:)=2.2; %ice [Hillel(1982)] -L(4,:)=0.25; %organic [Hillel(1982)] -L(5,:)=3.8;%7.7;%y2.9; %mineral [Hillel(1982)] - -%calaculated conductivties [Campbell et al. (1994)] -%L(1,:)=0.024+7.73*10^-5*T-2.6*10^-8*T^2; %air -%L(2,:)=0.554+2.24*10^-3*T-9.87*10^-6*T^2;%water - -%-------------------------------------------------------------------------- -%conductivity function due to variation in water-air content (no ice) -wc=[0:0.01:P]; -ac=P-wc; -m=size(wc,2); -space=zeros(m*3, 3); - -for i=1:size(wc,2) - X(1,:)=ac(i); %air - X(2,:)=wc(i); %water - X(3,:)=0.0; %ice - X(4,:)=org_c; %organic - X(5,:)=min_c; %mineral - %---------------------------------------------------------------------- - [kwa(i)]=conductDV63_aw(X,L,T,Xo,qo,[]); - KK(i,1)=wc(i); - KK(i,2)=0; - KK(i,3)=kwa(i); - space(i,1)=wc(i); - space(i,3)=kwa(i); -end -%plot(space(1:m,1), space(1:m,3)) -KK(end,:)=[]; -l=size(KK,1); -%-------------------------------------------------------------------------- -%conductivity function due to variation in ice-air content (no watr) -ic=[0:0.01:P]; -ac=P-ic; - -for i=1:size(ic,2) - X(1,:)=ac(i); %air - X(2,:)=0.0; %water - X(3,:)=ic(i); %ice - X(4,:)=org_c; %organic - X(5,:)=min_c; %mineral - %---------------------------------------------------------------------- - [kia(i)]=conductDV63_ia(X,L,T,Xo,qo,[]); - KK(l+i,1)=0; - KK(l+i,2)=ic(i); - KK(l+i,3)=kia(i); - space(m+i,2)=ic(i); - space(m+i,3)=kia(i); -end - -KK(end,:)=[]; -l=size(KK,1); -%------------------------------------------------------------------------- -%conductivity function due to variation in ice-water content (no air) -ic=[0:0.01:P]; -wc=P-ic; - -for i=1:size(wc,2) - X(1,:)=0.0; %air - X(2,:)=wc(i); %water - X(3,:)=ic(i); %ice - X(4,:)=org_c; %organic - X(5,:)=min_c; %mineral - %---------------------------------------------------------------------- - [kiw(i)]=conductDV63_iw(X,L,T,Xo,qo,[]); - KK(l+i,1)=wc(i); - KK(l+i,2)=ic(i); - KK(l+i,3)=kiw(i); - space(2*m+i,1)=wc(i); - space(2*m+i,2)=ic(i); - space(2*m+i,3)=kiw(i); - -end - -KK(end,:)=[0 P kiw(end)]; -KK(1,:)=[]; -%-------------------------------------------------------------------------- -%interpolate boundary functions and calculate searched conductivity - -%Lamda = griddata(KK(:,1),KK(:,2),KK(:,3),XI,YI,'v4'); - -max_size1=max([size(1-min_c-org_c,1) size(w_c,1) size(i_c,1)]); -max_size2=max([size(1-min_c-org_c,2) size(w_c,2) size(i_c,2)]); -if max_size1>max_size2 %column vector - a_c=zeros(max_size1,1)+1-min_c-org_c-w_c-i_c; - w_c=zeros(max_size1,1)+w_c; - i_c=zeros(max_size1,1)+i_c; -else %row vector - a_c=zeros(1,max_size2)+1-min_c-org_c-w_c-i_c; - w_c=zeros(1, max_size2)+w_c; - i_c=zeros(1, max_size2)+i_c; -end -Lambda=griddata(space(:,1), space(:,2), space(:,3),w_c, i_c, 'v4'); -%F=TriScatteredInterp(space(:,1), space(:,2), space(:,3), space(:,4)); -%Lambda=F(a_c, w_c, i_c) -%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -function [k]=conductDV63_aw(X,L,T,Xo,qo,fw) -%function calculates heat conductivity based on de Vries (1963) -%Input parameter: X:=fraction of soil material -% L:=individual conductivities of soil components -% Xo:=cutoff water content for liquid recirculation [m³/m³] -% qo:=power for liquid recirculation function -% fw:=weighting function (if empty else fw=1 for saturated -% soil or fw=0 for dry soils -%-------------------------------------------------------------------------- -%g:=shape factores of soil components (set to spherical gx=gy=gz) -g(1,:)=1/3; -g(2,:)=1/3; -g(3,:)=1/3; -%power for liquid recirculation function -qo=qo; -%cutoff water content for liquid recirculation [m³/m³] -Xo=Xo; -%calculate Ly:=conductivity of matrix material -q=qo*((T+273.15)/303)^2; -if isempty(fw)==1 - fw=1/(1+(X(2,:)/Xo)^-q); -end -Ly=L(1,:)+fw*(L(2,:)-L(1,:)); -%calculate k:=effectiv conductivity -for i=1:5 - for j=1:3 - K1(i,j)=1/(1+(L(i,1)/Ly-1)*g(j,1)); - end -end -K=1/3*sum(K1')'; -k=sum(K.*L.*X)/sum(K.*X); - - -function [k]=conductDV63_ia(X,L,T,Xo,qo,fw) -%function calculates heat conductivity based on de Vries (1963) -%Input parameter: X:=fraction of soil material -% L:=individual conductivities of soil components -% Xo:=cutoff water content for liquid recirculation [m³/m³] -% qo:=power for liquid recirculation function -% fw:=weighting function (if empty else fw=1 for saturated -% soil or fw=0 for dry soils -%-------------------------------------------------------------------------- -%g:=shape factores of soil components (set to spherical gx=gy=gz) -g(1,:)=1/3; -g(2,:)=1/3; -g(3,:)=1/3; -%power for liquid recirculation function -qo=qo; -%cutoff water content for liquid recirculation [m³/m³] -Xo=Xo; -%calculate Ly:=conductivity of matrix material -q=qo*((T+273.15)/303)^2; -if isempty(fw)==1 - fw=1/(1+(X(3,:)/Xo)^-q); -end -Ly=L(1,:)+fw*(L(3,:)-L(1,:)); -%calculate k:=effectiv conductivity -for i=1:5 - for j=1:3 - K1(i,j)=1/(1+(L(i,1)/Ly-1)*g(j,1)); - end -end -K=1/3*sum(K1')'; -k=sum(K.*L.*X)/sum(K.*X); - - -function [k]=conductDV63_iw(X,L,T,Xo,qo,fw) -%function calculates heat conductivity based on de Vries (1963) -%Input parameter: X:=fraction of soil material -% L:=individual conductivities of soil components -% Xo:=cutoff water content for liquid recirculation [m³/m³] -% qo:=power for liquid recirculation function -% fw:=weighting function (if empty else fw=1 for saturated -% soil or fw=0 for dry soils -%-------------------------------------------------------------------------- -%g:=shape factores of soil components (set to spherical gx=gy=gz) -g(1,:)=1/3; -g(2,:)=1/3; -g(3,:)=1/3; -%power for liquid recirculation function -qo=qo; -%cutoff water content for liquid recirculation [m³/m³] -Xo=Xo; -%calculate Ly:=conductivity of matrix material -q=qo*((T+273.15)/303)^2; -if isempty(fw)==1 - fw=1/(1+(X(2,:)/Xo)^-q); -end -Ly=L(3,:)+fw*(L(2,:)-L(3,:)); -%calculate k:=effectiv conductivity -for i=1:5 - for j=1:3 - K1(i,j)=1/(1+(L(i,1)/Ly-1)*g(j,1)); - end -end -K=1/3*sum(K1')'; -k=sum(K.*L.*X)/sum(K.*X); diff --git a/modules/cryoGridSoil/getSoilThermalNew.m b/modules/cryoGridSoil/getSoilThermalNew.m deleted file mode 100644 index cb44c18..0000000 --- a/modules/cryoGridSoil/getSoilThermalNew.m +++ /dev/null @@ -1,70 +0,0 @@ -function soilParam=getSoilThermalNew(soilcode) - -code(1)=11; -par(1).numbers=[0 0.3 0.6 0 0 1 0; 1.9 0.3 0.6 0 0 1 0; 2.1 0.4 0.6 0 0 1 0; 9.9 0.4 0.6 0 0 1 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(2)=15; -par(2).numbers=[0 0.3 0.6 0 0 1 0; 1.9 0.3 0.6 0 0 1 0; 2.1 0.4 0.6 0 0 1 0; 9.9 0.4 0.6 0 0 1 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(3)=81; -par(3).numbers=[0 0.3 0.6 0 0 1 0; 1.9 0.3 0.6 0 0 1 0; 2.1 0.4 0.6 0 0 1 0; 9.9 0.4 0.6 0 0 1 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(4)=12; -par(4).numbers=[0 0.3 0.6 0 0 1 0; 0.99 0.3 0.6 0 0 1 0; 1.01 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(5)=140; -par(5).numbers=[0 0.3 0.6 0 0 1 0; 0.99 0.3 0.6 0 0 1 0; 1.01 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(6)=130; -par(6).numbers=[0 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - - - - -code(7)=20; -par(7).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 19.9 0.4 0.6 0 0 1 0; 20.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(8)=21; -par(8).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 19.9 0.4 0.6 0 0 1 0; 20.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - - -code(9)=50; -par(9).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 9.9 0.4 0.6 0 0 1 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - - - - -code(10)=70; -par(10).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 1.9 0.4 0.6 0 0 1 0; 2.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(11)=71; -par(11).numbers=[0 0.1 0.6 0 0 1 0; 0.99 0.1 0.6 0 0 1 0; 1.01 0.4 0.6 0 0 1 0; 4.9 0.4 0.6 0 0 1 0; 5.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(12)=73; -par(12).numbers=[0 0.1 0.6 0 0 1 0; 1.9 0.1 0.6 0 0 1 0; 2.1 0.4 0.6 0 0 1 0; 4.9 0.4 0.6 0 0 1 0; 5.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(13)=22; -par(13).numbers=[0 0.1 0.6 0 0 1 0; 4.9 0.1 0.6 0 0 1 0; 5.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - - - - -code(14)=90; -%par(14).numbers=[0 0.3 0.1 0.3 0 1 0; 0.99 0.3 0.1 0.3 0 1 0; 1.01 0.6 0.1 0.3 0 1 0; 1.9 0.6 0.1 0.3 0 1 0; 2.1 0.5 0.4 0.1 0 2 0; 9.9 0.5 0.4 0.1 0 2 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; -par(14).numbers=[0 0.3 0.2 0.3 0 1 0; 0.5 0.3 0.2 0.3 0 1 0; 0.51 0.5 0.2 0.3 0 1 0; 1.9 0.5 0.2 0.3 0 1 0; 2.1 0.5 0.4 0.1 0 2 0; 9.9 0.5 0.4 0.1 0 2 0; 10.1 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(15)=100; -par(15).numbers=[0 0.5 0.4 0.1 0 1 0; 0.49 0.5 0.4 0.1 0 1 0; 0.51 0.03 0.97 0 0 1 0; 500 0.03 0.97 0 0 1 0]; - -code(16)=1000; % soil stratigraphy assumed for Samoilov run -par(16).numbers=[0 0.7 0.25 0.05 0 2 0; 10 0.3 0.7 0 0 1 0; 101 0.3 0.7 0 0 1 0]; - - -if ~isempty(find(code==soilcode)) - soilParam=par(find(code==soilcode)).numbers; - soilParam=[-100 0.0 0.5 0 0 1 0; soilParam]; -else - soilParam=[NaN NaN NaN NaN NaN NaN NaN]; -end - - diff --git a/modules/cryoGridTechnical/generateLOOPVAR.m b/modules/cryoGridTechnical/generateLOOPVAR.m deleted file mode 100644 index a61ad13..0000000 --- a/modules/cryoGridTechnical/generateLOOPVAR.m +++ /dev/null @@ -1,45 +0,0 @@ -function [loop_PARA loopI_PERMUT] = generateLOOPVAR(LOOPVAR, LI) - - -%example -% LI=5; -% LOOPVAR.ice_albedo = [0.1 0.2 0.3]; -% LOOPVAR.ice_extinction = [7.0 8.4 9.0]; -% LOOPVAR.water_extinction = [0.2 0.5 0.8]; -% LOOPVAR.FLAKE_fetch = [50 150 250]; - -var_names = fieldnames(LOOPVAR); - -for i=1:length(var_names) - var_names{i,2}=['i_' num2str(i)]; - var_names{i,3}=num2str(length(eval(['LOOPVAR.' var_names{1}]))); -end - -start_str=[]; -mind_str=[]; -end_str=[]; -for i=1:length(var_names) - start_str=[start_str 'for ' var_names{i,2} '=1:' var_names{i,3} '; ']; - mind_str=[mind_str var_names{i,2} ' ']; - end_str=[end_str 'end; ']; -end -loop_index=[]; -eval([start_str 'loop_index=[loop_index; ' mind_str ']; ' end_str]) - -for i=1:length(var_names) - eval(['loopI_PERMUT.' var_names{i,1} '=' 'loop_index(:,' num2str(i) ');']) - eval(['loop_PARA.' var_names{i,1} '=' 'LOOPVAR.' var_names{i,1} '(loop_index(' num2str(LI) ',' num2str(i) '));' ]) - - -end - - - - - - - - - - - diff --git a/modules/cryoGridTechnical/initializeWaterEnergyBalance.m b/modules/cryoGridTechnical/initializeWaterEnergyBalance.m deleted file mode 100644 index c3c73bf..0000000 --- a/modules/cryoGridTechnical/initializeWaterEnergyBalance.m +++ /dev/null @@ -1,14 +0,0 @@ -% energy content soil domain in [J/m^2] -% distinguished by sensible and latent part -E_soil_sens = nansum( ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral + PARA.constants.c_o .* GRID.soil.cT_organic ) .* T(GRID.soil.cT_domain) ... - .* GRID.general.K_delta(GRID.soil.cT_domain) ); -E_soil_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc .* GRID.general.K_delta(GRID.soil.cT_domain) ); -E_soil = E_soil_sens + E_soil_lat; -% energy content snow domain in [J/m^2] -E_snow_sens = nansum( c_cTgrid(GRID.snow.cT_domain) .* T(GRID.snow.cT_domain) .* GRID.general.K_delta(GRID.snow.cT_domain) ); -E_snow_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc_cTgrid(GRID.snow.cT_domain).* GRID.general.K_delta(GRID.snow.cT_domain) ); -E_snow = E_snow_sens + E_snow_lat; -% water content soil domain in [m] -W_soil = nansum( wc .* GRID.general.K_delta(GRID.soil.cT_domain) ); -% water content snow domain in [m] -W_snow = nansum( GRID.snow.Snow_i + GRID.snow.Snow_w ) + GRID.snow.SWEinitial; \ No newline at end of file diff --git a/modules/cryoGridTechnical/updateWaterEnergyBalance.m b/modules/cryoGridTechnical/updateWaterEnergyBalance.m deleted file mode 100644 index 6bcf599..0000000 --- a/modules/cryoGridTechnical/updateWaterEnergyBalance.m +++ /dev/null @@ -1,31 +0,0 @@ -% at this point the thermal and hydrological state of the soil and snow is calculated -% energy content soil domain in [J/m^2] -% distinguished by sensible and latent part -E_soil_sens_old = E_soil_sens; -E_soil_lat_old = E_soil_lat; -E_soil_old = E_soil; -E_soil_sens = nansum( ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral + PARA.constants.c_o .* GRID.soil.cT_organic ) .* T(GRID.soil.cT_domain) ... - .* GRID.general.K_delta(GRID.soil.cT_domain) ); -E_soil_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc .* GRID.general.K_delta(GRID.soil.cT_domain) ); -E_soil = E_soil_sens + E_soil_lat; -TEMPORARY.dE_soil_sens = TEMPORARY.dE_soil_sens + E_soil_sens - E_soil_sens_old; -TEMPORARY.dE_soil_lat = TEMPORARY.dE_soil_lat + E_soil_lat - E_soil_lat_old; -TEMPORARY.dE_soil = TEMPORARY.dE_soil + E_soil - E_soil_old; -% energy content snow domain in [J/m^2] -E_snow_sens_old = E_snow_sens; -E_snow_lat_old = E_snow_lat; -E_snow_old = E_snow; -E_snow_sens = nansum( c_cTgrid(GRID.snow.cT_domain) .* T(GRID.snow.cT_domain) .* GRID.general.K_delta(GRID.snow.cT_domain) ); -E_snow_lat = nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* lwc_cTgrid(GRID.snow.cT_domain).* GRID.general.K_delta(GRID.snow.cT_domain) ); -E_snow = E_snow_sens + E_snow_lat; -TEMPORARY.dE_snow_sens = TEMPORARY.dE_snow_sens + E_snow_sens - E_snow_sens_old; -TEMPORARY.dE_snow_lat = TEMPORARY.dE_snow_lat + E_snow_lat - E_snow_lat_old; -TEMPORARY.dE_snow = TEMPORARY.dE_snow + E_snow - E_snow_old; -% water content soil domain in [m] -W_soil_old = W_soil; -W_soil = nansum( wc .* GRID.general.K_delta(GRID.soil.cT_domain) ); -HYDRO.dW_soil = HYDRO.dW_soil + (W_soil - W_soil_old)*1000; % in [mm] -% water content snow domain in [m] -W_snow_old = W_snow; -W_snow = nansum( GRID.snow.Snow_i + GRID.snow.Snow_w ) + GRID.snow.SWEinitial; -HYDRO.dW_snow = HYDRO.dW_snow + (W_snow - W_snow_old)*1000; % in [mm] \ No newline at end of file From 45546fb8042ce9c312770befd22411d85087868f Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Wed, 17 Jan 2018 17:33:23 +0100 Subject: [PATCH 03/45] bugfix in update_SNOW: only air domain adjusted when K-grid has error. created functions to be run in parallel mode and wrapper script run_parallel. still not clear about best and most stable way to run parameter variations in parallel. --- CryoGrid3.m | 60 +++-- CryoGrid3_function_spinup.m | 298 ++++++++++++++++++++++++ CryoGrid3_function_variableExice.m | 305 +++++++++++++++++++++++++ README.md | 2 - add_modules_function.m | 17 ++ modules/cryoGridSnow/updateGRID_snow.m | 2 +- run_parallel.m | 83 +++++++ 7 files changed, 739 insertions(+), 28 deletions(-) create mode 100755 CryoGrid3_function_spinup.m create mode 100755 CryoGrid3_function_variableExice.m create mode 100644 add_modules_function.m create mode 100644 run_parallel.m diff --git a/CryoGrid3.m b/CryoGrid3.m index 2e98a26..de8306c 100755 --- a/CryoGrid3.m +++ b/CryoGrid3.m @@ -10,6 +10,9 @@ add_modules; %adds required modules +addpath('./nansuite/') + + createLogFile=1; %---------------define input parameters------------------------------------ @@ -17,10 +20,11 @@ % z w/i m o type porosity %default used in publication: -PARA.soil.layer_properties=[ 0.0 0.40 0.10 0.15 1 0.75;... - 0.15 0.65 0.30 0.05 2 0.65;... - 0.9 0.40 0.55 0.05 1 0.40;... - 9.0 0.30 0.70 0.00 1 0.30 ]; +PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + %simple stratigraphy with excess ice used to test water balance: % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... % 0.4 0.8 0.2 0.00 1 0.40;... @@ -58,7 +62,7 @@ PARA.soil.externalWaterFlux=0;%-2e-3; %external water flux / drainage in [m/day] PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile -PARA.soil.waterTable=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up +PARA.soil.waterTable=10.; % depth at which a water table will form [m] - above excess water is removed, below it pools up % parameters related to snow PARA.snow.max_albedo=0.85; % albedo of fresh snow @@ -70,7 +74,7 @@ PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] PARA.snow.tau_a=0.008; % [per day] PARA.snow.tau_f=0.24; % [per day] -PARA.snow.maxSnow= [0.2] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold +PARA.snow.maxSnow= [0.4] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold PARA.snow.extinction=25.0; % light extinction coefficient of snow % parameters related to water body on top of soil domain @@ -91,8 +95,8 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity -PARA.technical.starttime=datenum('2000.06.01 00:00:00','yyyy.mm.dd HH:MM:SS'); % starttime of the simulation - if empty start from first value of time series -PARA.technical.endtime=datenum('2000.07.01 00:00:00','yyyy.mm.dd HH:MM:SS'); % endtime of the simulation - if empty end at last value of time series +PARA.technical.starttime=datenum(2000, 6, 1); % starttime of the simulation - if empty start from first value of time series +PARA.technical.endtime=datenum(2001, 6, 1); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -103,17 +107,19 @@ %default grid used for publications and testing of water balance: PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] +%PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + %very simple grid used for testing of energy balance: %PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; %initial temperature profile -> first column depth [m] -> second column temperature [degree C] %default: -PARA.Tinitial = [ -5 5 ;... - 0 -5 ;... - 1 -5 ;... - 10 -8 ;... - 20 -10 ;... - 100 -10 ;... +PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... 2000 10 ]; PARA = loadConstants( PARA ); @@ -135,16 +141,17 @@ run(configFile); end -run_number = sprintf('testrun_infiltration%d_xice%d_rf%d_sf%d_wt%0.2f_exampleFlorentina', ... - [PARA.modules.infiltration, PARA.modules.xice, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.soil.waterTable]); +run_number = sprintf('testrun_%d-%d_stratSamExice_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f_exice%0.2f_natPor%0.2f_subsurfaceGridDefault_timestepSoil', ... + [ 2000, 2001, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity, theta_w, natPor ]); % ------make output directory (name depends on parameters) ---------------- -mkdir(run_number) +mkdir(['./runs/' run_number]) + % ------redirect command line output to logfile --------------------------- if createLogFile - diary(['./' run_number '/' run_number '_diary.log']); + diary(['./runs/' run_number '/' run_number '_diary.log']); end @@ -199,7 +206,7 @@ OUT = generateOUT(); disp('initialization successful'); -save([run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') +save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') %% ________________________________________________________________________ % Time Integration Routine I @@ -234,17 +241,17 @@ % account for min and max timesteps specified, max. energy change per grid cell and the CFT stability criterion. % energy change due to advection of heat through water fluxes is still excluded. % timestep in [days] - timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600), ... - PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... + timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain ) ) ./ (24.*3600), ... %+ GRID.snow.cT_domain + PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta(GRID.soil.cT_domain ) ./ SEB.dE_dt(GRID.soil.cT_domain ) ) ) ./ (24.*3600), ... PARA.technical.maxTimestep ] ), ... PARA.technical.minTimestep ] ), ... TEMPORARY.outputTime-t ] ); % give a warning when timestep required by CFT criterion is below the minimum timestep specified - if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) - warning( 'numerical stability not guaranteed' ); - end +% if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) +% warning( 'numerical stability not guaranteed' ); +% end %------ update T array ------------------------------------------------ T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; @@ -289,5 +296,8 @@ end %profile off -save([run_number '/' run_number '_output.mat'], 'OUT') +save(['./runs/' run_number '/' run_number '_output.mat'], 'OUT') disp('Done.'); +if createLogFile + diary off; +end diff --git a/CryoGrid3_function_spinup.m b/CryoGrid3_function_spinup.m new file mode 100755 index 0000000..7e30d51 --- /dev/null +++ b/CryoGrid3_function_spinup.m @@ -0,0 +1,298 @@ +function CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity ) + +% ------------------------------------------------------------------------- + % CryoGRID3 + % main script for running the model + % + % Developed by: S. Westermann and M. Langer 2015 + % + % ------------------------------------------------------------------------- + + paraFromFile = exist('configFile'); % check if config file passed + + %add_modules_function; %adds required modules + %add_modules; + + createLogFile=1; + + %---------------define input parameters------------------------------------ + % here you provide the ground stratigraphy + % z w/i m o type porosity + + %default used in publication: + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.30 0.05 2 0.65;... + 0.9 0.65 0.30 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + %simple stratigraphy with excess ice used to test water balance: + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... + % 0.4 0.8 0.2 0.00 1 0.40;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + %very simply stratigraphy without excess ice used to test energy balance + % soilType = 1; + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... + % 1.0 0.5 0.5 0.00 1 0.5 ;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer + % extends until the end of the model domain + % column 2: volumetric water+ice content + % column 3: volumetric mineral content + % column 4: volumetric organic content + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + %------ model parameters -------------------------------------------------- + PARA.soil.albedo=0.2; % albedo snow-free surface + PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development + PARA.soil.epsilon=0.97; % emissvity snow-free surface + PARA.soil.z0=1e-3; % roughness length [m] snow-free surface + PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface + PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] + PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + + % parameters related to hydrology scheme + PARA.soil.fieldCapacity=fieldCapacity; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries + PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation + PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. + PARA.soil.externalWaterFlux=extFlux;%-2e-3; %external water flux / drainage in [m/day] + PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible + PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile + PARA.soil.waterTable=waterTable; % depth at which a water table will form [m] - above excess water is removed, below it pools up + + % parameters related to snow + PARA.snow.max_albedo=0.85; % albedo of fresh snow + PARA.snow.min_albedo=0.5; % albedo of old snow + PARA.snow.epsilon=0.99; % surface emissivity snow + PARA.snow.z0=5e-4; % roughness length surface [m] + PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow + PARA.snow.rho_snow=snowDens; % density in [kg/m3] + PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] + PARA.snow.tau_a=0.008; % [per day] + PARA.snow.tau_f=0.24; % [per day] + PARA.snow.maxSnow= [maxSnow] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.extinction=25.0; % light extinction coefficient of snow + + % parameters related to water body on top of soil domain + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.epsilon=0.99; % surface emissivity water + PARA.water.rs=0.0; % surface resistance -> should be 0 for water + PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation + + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + PARA.ice.epsilon=0.98; % surface emissivity snow + PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice + PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow + PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + + PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given + + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases + PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells + PARA.technical.maxSWE=0.4; % in [m] SWE + PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity + PARA.technical.starttime=startDate; % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=endDate; % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds + PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds + PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.saveDate='01.09.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + + %default grid used for publications and testing of water balance: + PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + %very simple grid used for testing of energy balance: + %PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; + + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] + %default: + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... + 2000 10 ]; + + + PARA = loadConstants( PARA ); + + + %FORCING data mat-file + PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.rain_fraction=rainFrac; + PARA.forcing.snow_fraction=snowFrac; + + % switches for modules + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=1; % true if thaw subsicdence is enabled + + % ------update parameter values if config file provided ------------------- + % ------changes output directory to name specified in configfile which is + % the config filename by default + if paraFromFile + run(configFile); + end + + run_number = sprintf( [ 'spinup_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... + [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... + PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); + + + % ------make output directory (name depends on parameters) ---------------- + mkdir(['./runs/' run_number]) + + % ------redirect command line output to logfile --------------------------- + if createLogFile + diary(['./runs/' run_number '/' run_number '_diary.log']); + end + + + %-------------------------------------------------------------------------- + %-----------do not modify from here onwards-------------------------------- + %-------------------------------------------------------------------------- + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + + if ~success + warning('A problem with the Forcing occured.'); + end + clear success + + PARA = initializeParameters(PARA, FORCING); %set start time, etc. + + %----------------create and initialize the grids -------------------------- + GRID=makeGrids(PARA); %create all grids + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + + %----- initializie excess ground ice -------------------------------------- + [GRID,PARA] = initializeExcessIce2(GRID,PARA); + + %----- initializie soil thermal properties -------------------------------- + GRID = initializeSoilThermalProperties(GRID, PARA); + + %------ initializie snow properties---------------------------------------- + GRID = initializeSnow(GRID); + + %---- initialize the surface energy balance struct ------------------------ + SEB = initializeSEB(); + + %---- initialize the water body module ------------------------------------ + GRID = initializeLAKE(GRID); + + %---- initialize temperature profile -------------------------------------- + T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); + + %---- modification for infiltration + wc=GRID.soil.cT_water; + GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; + GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; + + %---- preallocate temporary arrays for capacity and conductivity----------- + [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid + + %---- energy and water balance initialization ----------------------------- + BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); + + %__________________________________________________________________________ + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); + + disp('initialization successful'); + save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') + + %% ________________________________________________________________________ + % Time Integration Routine I + % I + %_________________________________________________________________________I + + while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) +% warning( 'numerical stability not guaranteed' ); +% end + + %------ update T array ------------------------------------------------ + T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; + T(GRID.air.cT_domain)=FORCING.i.Tair; %set grid cells in air to air temperature + + %------- water body module -------------------------------------------- + T = mixingWaterBody(T, GRID); + + %------- snow cover module -------------------------------------------- + [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + + %------- infiltration module------------------------------------------- + if PARA.modules.infiltration + [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); + end + + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.modules.infiltration + warning( 'energy and water balances are not correct for this combination of modules'); + [GRID, PARA] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); + elseif PARA.modules.xice && PARA.modules.infiltration + [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); + GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + end + + %------- update Lstar for next time step ------------------------------ + SEB = L_star(FORCING, PARA, SEB); + + %------- water balance calculations ----------------------------------- + % rainfall + BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval + % snowfall + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval + + %------- next time step ----------------------------------------------- + t=t+timestep; + %---------- sum up + OUTPUT ------------------------------------------- + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT); + + end + %profile off + save(['./runs/' run_number '/' run_number '_output.mat'], 'OUT') + disp('Done.'); diff --git a/CryoGrid3_function_variableExice.m b/CryoGrid3_function_variableExice.m new file mode 100755 index 0000000..88c9a17 --- /dev/null +++ b/CryoGrid3_function_variableExice.m @@ -0,0 +1,305 @@ +function [] = CryoGrid3_function_variableExice( startYear, endYear, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity, exice, natPor ) + + % ------------------------------------------------------------------------- + % CryoGRID3 + % main script for running the model + % + % Developed by: S. Westermann and M. Langer 2015 + % + % ------------------------------------------------------------------------- + + paraFromFile = exist('configFile'); % check if config file passed + + %add_modules_function; %adds required modules + %add_modules; + + createLogFile=1; + + %---------------define input parameters------------------------------------ + % here you provide the ground stratigraphy + % z w/i m o type porosity + + theta_o=0.05; + theta_w=exice; + theta_m=1-theta_w-theta_o; + + %default used in publication: + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 theta_w theta_m theta_o 2 natPor;... + 0.9 theta_w theta_m theta_o 1 natPor;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + %simple stratigraphy with excess ice used to test water balance: + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... + % 0.4 0.8 0.2 0.00 1 0.40;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + %very simply stratigraphy without excess ice used to test energy balance + % soilType = 1; + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... + % 1.0 0.5 0.5 0.00 1 0.5 ;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer + % extends until the end of the model domain + % column 2: volumetric water+ice content + % column 3: volumetric mineral content + % column 4: volumetric organic content + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + %------ model parameters -------------------------------------------------- + PARA.soil.albedo=0.2; % albedo snow-free surface + PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development + PARA.soil.epsilon=0.97; % emissvity snow-free surface + PARA.soil.z0=1e-3; % roughness length [m] snow-free surface + PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface + PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] + PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + + % parameters related to hydrology scheme + PARA.soil.fieldCapacity=fieldCapacity; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries + PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation + PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. + PARA.soil.externalWaterFlux=extFlux;%-2e-3; %external water flux / drainage in [m/day] + PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible + PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile + PARA.soil.waterTable=waterTable; % depth at which a water table will form [m] - above excess water is removed, below it pools up + + % parameters related to snow + PARA.snow.max_albedo=0.85; % albedo of fresh snow + PARA.snow.min_albedo=0.5; % albedo of old snow + PARA.snow.epsilon=0.99; % surface emissivity snow + PARA.snow.z0=5e-4; % roughness length surface [m] + PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow + PARA.snow.rho_snow=snowDens; % density in [kg/m3] + PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] + PARA.snow.tau_a=0.008; % [per day] + PARA.snow.tau_f=0.24; % [per day] + PARA.snow.maxSnow= [maxSnow] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.extinction=25.0; % light extinction coefficient of snow + + % parameters related to water body on top of soil domain + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.epsilon=0.99; % surface emissivity water + PARA.water.rs=0.0; % surface resistance -> should be 0 for water + PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation + + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + PARA.ice.epsilon=0.98; % surface emissivity snow + PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice + PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow + PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + + PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given + + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases + PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells + PARA.technical.maxSWE=0.4; % in [m] SWE + PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity + PARA.technical.starttime=datenum(startYear, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(endYear, 6, 1); % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds + PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds + PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.saveDate='01.08.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + + %default grid used for publications and testing of water balance: + %PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + % use finer grid in upper 10 m to ensure correct evapotranspiration in case of subsidence + PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + + %very simple grid used for testing of energy balance: + %PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; + + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] + %default: + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... + 2000 10 ]; + + + PARA = loadConstants( PARA ); + + + %FORCING data mat-file + PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.rain_fraction=rainFrac; + PARA.forcing.snow_fraction=snowFrac; + + % switches for modules + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=1; % true if thaw subsicdence is enabled + + % ------update parameter values if config file provided ------------------- + % ------changes output directory to name specified in configfile which is + % the config filename by default + if paraFromFile + run(configFile); + end + + run_number = sprintf('spinup_%d-%d_stratSamExice_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f_exice%0.2f_natPor%0.2f', ... + [ startYear, endYear, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, ... + PARA.snow.maxSnow, PARA.snow.rho_snow, PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity, exice, natPor ]); + + + % ------make output directory (name depends on parameters) ---------------- + mkdir(['./runs/' run_number]) + + % ------redirect command line output to logfile --------------------------- + if createLogFile + diary(['./runs/' run_number '/' run_number '_diary.log']); + end + + + %-------------------------------------------------------------------------- + %-----------do not modify from here onwards-------------------------------- + %-------------------------------------------------------------------------- + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + + if ~success + warning('A problem with the Forcing occured.'); + end + clear success + + PARA = initializeParameters(PARA, FORCING); %set start time, etc. + + %----------------create and initialize the grids -------------------------- + GRID=makeGrids(PARA); %create all grids + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + + %----- initializie excess ground ice -------------------------------------- + [GRID,PARA] = initializeExcessIce2(GRID,PARA); + + %----- initializie soil thermal properties -------------------------------- + GRID = initializeSoilThermalProperties(GRID, PARA); + + %------ initializie snow properties---------------------------------------- + GRID = initializeSnow(GRID); + + %---- initialize the surface energy balance struct ------------------------ + SEB = initializeSEB(); + + %---- initialize the water body module ------------------------------------ + GRID = initializeLAKE(GRID); + + %---- initialize temperature profile -------------------------------------- + T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); + + %---- modification for infiltration + wc=GRID.soil.cT_water; + GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; + GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; + + %---- preallocate temporary arrays for capacity and conductivity----------- + [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid + + %---- energy and water balance initialization ----------------------------- + BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); + + %__________________________________________________________________________ + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); + + disp('initialization successful'); + save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') + + %% ________________________________________________________________________ + % Time Integration Routine I + % I + %_________________________________________________________________________I + + while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) +% warning( 'numerical stability not guaranteed' ); +% end + + %------ update T array ------------------------------------------------ + T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; + T(GRID.air.cT_domain)=FORCING.i.Tair; %set grid cells in air to air temperature + + %------- water body module -------------------------------------------- + T = mixingWaterBody(T, GRID); + + %------- snow cover module -------------------------------------------- + [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + + %------- infiltration module------------------------------------------- + if PARA.modules.infiltration + [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); + end + + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.modules.infiltration + warning( 'energy and water balances are not correct for this combination of modules'); + [GRID, PARA] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); + elseif PARA.modules.xice && PARA.modules.infiltration + [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); + GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + end + + %------- update Lstar for next time step ------------------------------ + SEB = L_star(FORCING, PARA, SEB); + + %------- water balance calculations ----------------------------------- + % rainfall + BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval + % snowfall + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval + + %------- next time step ----------------------------------------------- + t=t+timestep; + %---------- sum up + OUTPUT ------------------------------------------- + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT); + + end + %profile off + save(['./runs/' run_number '/' run_number '_output.mat'], 'OUT') + disp('Done.'); diff --git a/README.md b/README.md index bdb6e63..ce6f878 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,2 @@ # CryoGrid3 CryoGrid 3 is a simple land-surface scheme dedicated to modeling of ground temperatures in permafrost environments. -Test -test jan diff --git a/add_modules_function.m b/add_modules_function.m new file mode 100644 index 0000000..bd62ab3 --- /dev/null +++ b/add_modules_function.m @@ -0,0 +1,17 @@ +% %clear all +clearvars -except startYear endYear rainFrac snowFrac waterTable maxSnow extFlux fieldCapacity snowDens + +close all +profile off +dbclear if error +%dbstop if error + +%import CryoGrid modules (matlab functions) +addpath('modules/cryoGridTechnical/') +addpath('modules/cryoGridInitialize/') +addpath('modules/cryoGridSEB/') +addpath('modules/cryoGridSoil/') +addpath('modules/cryoGridSnow/') +addpath('modules/CryoGridInfiltrationUnfrozenSoil') +addpath('modules/cryoGridExcessIce/') +addpath('modules/cryoGridExcessIceInfiltration') diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index d2b53e4..4abe8c0 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -164,7 +164,7 @@ if sum( GRID.general.K_delta < 0 ) > 0 disp('updateGRID_snow - bugfix K grid'); %update grid spacings - GRID.general.K_grid(GRID.snow.cT_domain) = GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); + %GRID.general.K_grid(GRID.snow.cT_domain) = GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); GRID.general.K_grid(GRID.air.cT_domain) = [GRID.general.K_grid(GRID.air.cT_domain_lb)+(-2*snowCellSize)*(GRID.air.cT_domain_lb-1):2*snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; GRID.general.cT_grid = ( GRID.general.K_grid(1:end-1) + GRID.general.K_grid(2:end) ) ./ 2; %grid on which capacity and temperature information lives (midpoints of grid cells) GRID.general.cT_delta = ( -GRID.general.cT_grid(1:end-1,1) + GRID.general.cT_grid(2:end,1) ); diff --git a/run_parallel.m b/run_parallel.m new file mode 100644 index 0000000..90ce386 --- /dev/null +++ b/run_parallel.m @@ -0,0 +1,83 @@ +% script to excecute multiple indipendent runs of CryoGrid3 in parallel + +delete( gcp('nocreate') ); + +add_modules_function; + +number_of_combinations = 12; + + +startDate=datenum( 1979, 6, 1); +endDate=datenum( 1999, 6, 1); + +rainFrac=1; +snowFrac=1; +waterTable = 0; +waterTables = [ 0.0, 10.0 ]; +maxSnow = 0.4; +maxSnows = [ 0.2, 0.4 ]; +snowDens = 200; +snowDensities = [ 200, 250 ]; +extFlux = 0; +externalFluxes = [ -2e-3, 0, 2e-3 ]; +fieldCapacity = 0.3; +exices = [ 0.9, 0.8, 0.7, 0.6, 0.5, 0.4]; +natPor = 0.4; + + +combinations = {}; + +i=1; +for ms=maxSnows + for sd=snowDensities + for ef=externalFluxes + combinations{i} = [ms, sd, ef]; + i=i+1; + end + end +end + +% +% i=1; +% for wt=waterTables +% for ex=exices +% combinations{i} = [wt, ex]; +% i=i+1; +% end +% end + +%start parallel pool +parpool(number_of_combinations, 'SpmdEnabled', false ); + +parfor i=1:number_of_combinations + fprintf ( 'Started execution of combination %d ...', i ); + %CryoGrid3_function_variableExice( startYear, endYear, rainFrac, snowFrac, combinations{i}(1), maxSnow, snowDens, extFlux, fieldCapacity, combinations{i}(2), natPor); + CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, waterTable, combinations{i}(1), combinations{i}(2), combinations{i}(3), fieldCapacity ) + fprintf ( '... finished execution of combination %d.', i ); +end + +delete( gcp('nocreate') ); + +%parpool(number_of_combinations ); +% alternative implementation using spmd +%spmd + %i=labindex() + %CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, waterTable, combinations{i}(1), combinations{i}(2), combinations{i}(3), fieldCapacity ) +%end + +% alternative implementation using parfeval + +% parpool( number_of_combinations ); +% % To request multiple evaluations, use a loop. +% for idx = 1:number_of_combinations +% parfeval(CryoGrid3_function_spinup, 0, startDate, endDate, rainFrac, snowFrac, waterTable, combinations{i}(1), combinations{i}(2), combinations{i}(3), fieldCapacity); % Square size determined by idx +% end +% % Collect the results as they become available. +% % magicResults = cell(1,10); +% % for idx = 1:10 +% % % fetchNext blocks until next results are available. +% % [completedIdx,value] = fetchNext(f); +% % magicResults{completedIdx} = value; +% % fprintf('Got result with index: %d.\n', completedIdx); +% % end + From 1bb3b0d4ba4263924e9b85441a2cd70fda16e9fb Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Tue, 23 Jan 2018 18:51:55 +0100 Subject: [PATCH 04/45] further modifications in updateGRID_snow, now the K grid of snow and air domain is attached. No more errors in K-grid occur (until now). Still problems as SEB crahses during melting periods. created batch scripts. --- CryoGrid3.m | 65 ++++++++-- CryoGrid3_function_spinup.m | 22 ++-- modules/cryoGridSnow/CryoGridSnow.m | 172 ++++++++++++------------- modules/cryoGridSnow/updateGRID_snow.m | 53 ++++++-- run_batch.m | 77 +++++++++++ run_parallel.m | 34 ++--- run_single.m | 21 +++ 7 files changed, 307 insertions(+), 137 deletions(-) create mode 100644 run_batch.m create mode 100644 run_single.m diff --git a/CryoGrid3.m b/CryoGrid3.m index de8306c..f747914 100755 --- a/CryoGrid3.m +++ b/CryoGrid3.m @@ -10,7 +10,7 @@ add_modules; %adds required modules -addpath('./nansuite/') +%addpath('./nansuite/') createLogFile=1; @@ -59,10 +59,10 @@ PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. -PARA.soil.externalWaterFlux=0;%-2e-3; %external water flux / drainage in [m/day] +PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile -PARA.soil.waterTable=10.; % depth at which a water table will form [m] - above excess water is removed, below it pools up +PARA.soil.waterTable=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up % parameters related to snow PARA.snow.max_albedo=0.85; % albedo of fresh snow @@ -95,8 +95,8 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity -PARA.technical.starttime=datenum(2000, 6, 1); % starttime of the simulation - if empty start from first value of time series -PARA.technical.endtime=datenum(2001, 6, 1); % endtime of the simulation - if empty end at last value of time series +PARA.technical.starttime=datenum(1980, 6, 1); % starttime of the simulation - if empty start from first value of time series +PARA.technical.endtime=datenum(1983, 6, 1); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -141,9 +141,10 @@ run(configFile); end -run_number = sprintf('testrun_%d-%d_stratSamExice_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f_exice%0.2f_natPor%0.2f_subsurfaceGridDefault_timestepSoil', ... - [ 2000, 2001, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity, theta_w, natPor ]); - + +run_number = sprintf( [ 'TESTRUN_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... + [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... + PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); % ------make output directory (name depends on parameters) ---------------- mkdir(['./runs/' run_number]) @@ -151,7 +152,7 @@ % ------redirect command line output to logfile --------------------------- if createLogFile - diary(['./runs/' run_number '/' run_number '_diary.log']); + diary(['./runs/' run_number '/' run_number '_diary.txt']); end @@ -220,6 +221,12 @@ %------determine the thermal properties of the model domains ---------- [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = getThermalPropertiesInfiltration(T, wc, c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid, GRID, PARA); + + try + assert( sum( isnan(k_cTgrid)) + sum( isnan(k_Kgrid)) + sum( isnan( c_cTgrid)) ==0, 'Cryogrid3 - nan in c or k grids'); + catch + save( [ './runs/' run_number '/' run_number '_workspaceAtckgridCrash.mat'] ); + end %------- water and energy balance calculations ------------------------ BALANCE = updateBALANCE(T, wc, c_cTgrid, lwc_cTgrid, BALANCE, GRID, PARA); @@ -229,6 +236,12 @@ [PARA, GRID] = surfaceCondition(GRID, PARA, T); %calculate the surface energy balance [SEB, dwc_dt] = surfaceEnergyBalanceInfiltration(T, wc, FORCING, GRID, PARA, SEB); + try + assert( abs(SEB.Qe)<1e5 && abs(SEB.Qh)<1e5 , 'CryoGrid3 - Qe or Qh too large' ); + catch + save( [ './runs/' run_number '/' run_number '_workspaceAtQeQhCrash.mat'] ); + end + %------ soil module -------------------------------------------------- %calculate heat conduction @@ -259,11 +272,34 @@ %------- water body module -------------------------------------------- T = mixingWaterBody(T, GRID); - + + try + assert( sum( T<-60 )+sum(T>50)==0, 'CryoGrid3 - T exceeds physical limits' ); + catch + save( [ './runs/' run_number '/' run_number '_workspaceAtTlimitsCrash.mat'] ); + end + + %------- snow cover module -------------------------------------------- - [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + %[T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + [T, GRID, PARA, SEB] = CryoGridSnow_old(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + try + assert( ~isnan(T(GRID.air.cT_domain_lb+1)) , 'CryoGrid3 - T surf is nan after snow module'); + catch + save( [ './runs/' run_number '/' run_number '_workspaceAtTsurfCrash.mat'] ); + end + + + + try + assert( sum(GRID.general.K_delta<0)==0 , 'updateGRIDsnow - error in K grid'); + catch + save( [ './runs/' run_number '/' run_number '_workspaceAtKgridCrash.mat'] ); + end + %------- infiltration module------------------------------------------- if PARA.modules.infiltration [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); @@ -281,7 +317,12 @@ end %------- update Lstar for next time step ------------------------------ - SEB = L_star(FORCING, PARA, SEB); + SEB = L_star(FORCING, PARA, SEB); + try + assert( ~isnan(SEB.L_star(end)), 'L_star - Lstar is nan' ); + catch + save( [ './runs/' run_number '/' run_number '_workspaceAtLstarCrash.mat'] ); + end %------- water balance calculations ----------------------------------- % rainfall diff --git a/CryoGrid3_function_spinup.m b/CryoGrid3_function_spinup.m index 7e30d51..ce77f3b 100755 --- a/CryoGrid3_function_spinup.m +++ b/CryoGrid3_function_spinup.m @@ -1,4 +1,4 @@ -function CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity ) +function CryoGrid3_function_spinup( taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity ) % ------------------------------------------------------------------------- % CryoGRID3 @@ -13,7 +13,7 @@ function CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, wate %add_modules_function; %adds required modules %add_modules; - createLogFile=1; + createLogFile=0; %---------------define input parameters------------------------------------ % here you provide the ground stratigraphy @@ -138,18 +138,19 @@ function CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, wate if paraFromFile run(configFile); end + +% run_number = sprintf( [ 'spinup_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... +% [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... +% PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); - run_number = sprintf( [ 'spinup_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... - [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... - PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); - + run_number = taskName; % ------make output directory (name depends on parameters) ---------------- - mkdir(['./runs/' run_number]) + mkdir(['./runs/' run_number]); % ------redirect command line output to logfile --------------------------- if createLogFile - diary(['./runs/' run_number '/' run_number '_diary.log']); + diary(['./runs/' run_number '/' run_number '_diary.txt']); end @@ -262,6 +263,7 @@ function CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, wate [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + %------- infiltration module------------------------------------------- if PARA.modules.infiltration [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); @@ -279,7 +281,9 @@ function CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, wate end %------- update Lstar for next time step ------------------------------ - SEB = L_star(FORCING, PARA, SEB); + SEB = L_star(FORCING, PARA, SEB); + + %------- water balance calculations ----------------------------------- % rainfall diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index 85d1a8a..71aca34 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -1,90 +1,90 @@ function [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_temp, timestep, BALANCE) - %L=3.34e5; - %L_lv=2.8e6; %also worng here. JAN: yes, should be smaller - - if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis - - %----------calculate snow surface albedo ------------------------------ - - if max(T(GRID.snow.cT_domain))>=0 % melting conditions - PARA.snow.albedo = PARA.snow.min_albedo + (PARA.snow.albedo - PARA.snow.min_albedo) ... - .* exp(-PARA.snow.tau_f .* timestep.*24.*3600 ./ PARA.snow.tau_1); - else - PARA.snow.albedo=max(PARA.snow.albedo-PARA.snow.tau_a.*timestep.*24.*3600./PARA.snow.tau_1, PARA.snow.min_albedo); - end - - %--------SEB.sublimation----------------------------------------------- - - GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... - - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i;%- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000; - - nonAirFractionUppermostGridCell = (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)+GRID.snow.Snow_w(GRID.snow.cT_domain_ub))./... - (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)+GRID.snow.Snow_w(GRID.snow.cT_domain_ub)+GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); - - GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... - - ( SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i./nonAirFractionUppermostGridCell ...% - ( SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000./nonAirFractionUppermostGridCell ... - - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i); %- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000); - - %SEB.sublim=SEB.sublim+SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000; - BALANCE.water.ds = BALANCE.water.ds - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i*1000; % sublimation in [mm] - - %---------- melt and infiltration ------------------------------------- - if max(T(GRID.snow.cT_domain))>0 || FORCING.i.rainfall>0 || sum(GRID.snow.Snow_w)>0 %cases when melt or infiltration occur - - [T(GRID.snow.cT_domain),... - GRID.snow.Snow_i(GRID.snow.cT_domain),... - GRID.snow.Snow_w(GRID.snow.cT_domain),... - GRID.snow.Snow_a(GRID.snow.cT_domain),... - newMelt] = ... - snowMelt(T(GRID.snow.cT_domain),... - GRID.snow.Snow_i(GRID.snow.cT_domain),... - GRID.snow.Snow_w(GRID.snow.cT_domain),... - GRID.snow.Snow_a(GRID.snow.cT_domain),... - FORCING.i.rainfall.*timestep./1000,... - c_temp(GRID.snow.cT_domain),... - PARA); - - %SEB.meltwater=SEB.meltwater+newMelt; - BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt + (-newMelt.*1000); % in [mm] - end - - %-------- add the new snow to the upper most snow cell in the case of a exisiting snow cover ------------------- - if isempty(PARA.snow.maxSnow) - deltaSnow_i = max(0, FORCING.i.snowfall.*timestep./1000); - else - snowHeight = abs( GRID.general.K_grid(GRID.snow.cT_domain_ub) - GRID.general.K_grid(GRID.snow.cT_domain_lb+1) ); - deltaSnow_i = max( [ 0, ... - min( [ FORCING.i.snowfall.*timestep./1000, ... - (PARA.snow.maxSnow - snowHeight ) .* PARA.snow.rho_snow ./ PARA.constants.rho_w ] ) ] ); %ensures that no more than maxSnow can accumulate - %account for excess snow in water balance - BALANCE.water.dr_excessSnow = BALANCE.water.dr_excessSnow -( FORCING.i.snowfall.*timestep - deltaSnow_i*1000 ); %defined as negative when snow is removed - end - - GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... - + deltaSnow_i; - - GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... - + ( deltaSnow_i./(PARA.snow.rho_snow./ PARA.constants.rho_w) - deltaSnow_i); - - else %no snow cover - - %---------- add the new snow into initial SWE variable in case of no snow cover------------------ - - GRID.snow.SWEinitial = GRID.snow.SWEinitial + FORCING.i.snowfall.*timestep./1000 - GRID.snow.SWEinitial.*0.1.*timestep; - BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - GRID.snow.SWEinitial.*0.1.*timestep*1000; %SWEinitial decreasing counted as surface runoff - - %----- add the rainfall as runoff in case of no infiltration into frozen ground - if ~PARA.modules.infiltration || (PARA.modules.infiltration && T(GRID.soil.cT_domain_ub)<=0 )%no infiltration scheme or uppermost soil cell frozen - BALANCE.water.dr_rain = BALANCE.water.dr_rain - FORCING.i.rainfall.*timestep; - end - +%L=3.34e5; +%L_lv=2.8e6; %also worng here. JAN: yes, should be smaller + +if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis + + %----------calculate snow surface albedo ------------------------------ + + if max(T(GRID.snow.cT_domain))>=0 % melting conditions + PARA.snow.albedo = PARA.snow.min_albedo + (PARA.snow.albedo - PARA.snow.min_albedo) ... + .* exp(-PARA.snow.tau_f .* timestep.*24.*3600 ./ PARA.snow.tau_1); + else + PARA.snow.albedo=max(PARA.snow.albedo-PARA.snow.tau_a.*timestep.*24.*3600./PARA.snow.tau_1, PARA.snow.min_albedo); end - - %--------- update albedo after fresh fallen snow -------------------------- - % determine time of last snowfall for albedo calculation - SEB.newSnow = SEB.newSnow-SEB.newSnow.*0.1.*timestep + FORCING.i.snowfall.*timestep./1000; - if SEB.newSnow>= PARA.technical.SWEperCell/2 - PARA.snow.albedo=PARA.snow.max_albedo; - SEB.newSnow=0; + + %--------SEB.sublimation----------------------------------------------- + + GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... + - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i;%- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000; + + nonAirFractionUppermostGridCell = (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)+GRID.snow.Snow_w(GRID.snow.cT_domain_ub))./... + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)+GRID.snow.Snow_w(GRID.snow.cT_domain_ub)+GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); + + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... + - ( SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i./nonAirFractionUppermostGridCell ...% - ( SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000./nonAirFractionUppermostGridCell ... + - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i); %- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000); + + %SEB.sublim=SEB.sublim+SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000; + BALANCE.water.ds = BALANCE.water.ds - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i*1000; % sublimation in [mm] + + %---------- melt and infiltration ------------------------------------- + if max(T(GRID.snow.cT_domain))>0 || FORCING.i.rainfall>0 || sum(GRID.snow.Snow_w)>0 %cases when melt or infiltration occur + + [T(GRID.snow.cT_domain),... + GRID.snow.Snow_i(GRID.snow.cT_domain),... + GRID.snow.Snow_w(GRID.snow.cT_domain),... + GRID.snow.Snow_a(GRID.snow.cT_domain),... + newMelt] = ... + snowMelt(T(GRID.snow.cT_domain),... + GRID.snow.Snow_i(GRID.snow.cT_domain),... + GRID.snow.Snow_w(GRID.snow.cT_domain),... + GRID.snow.Snow_a(GRID.snow.cT_domain),... + FORCING.i.rainfall.*timestep./1000,... + c_temp(GRID.snow.cT_domain),... + PARA); + + %SEB.meltwater=SEB.meltwater+newMelt; + BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt + (-newMelt.*1000); % in [mm] + end + + %-------- add the new snow to the upper most snow cell in the case of a exisiting snow cover ------------------- + if isempty(PARA.snow.maxSnow) + deltaSnow_i = max(0, FORCING.i.snowfall.*timestep./1000); + else + snowHeight = abs( GRID.general.K_grid(GRID.snow.cT_domain_ub) - GRID.general.K_grid(GRID.snow.cT_domain_lb+1) ); + deltaSnow_i = max( [ 0, ... + min( [ FORCING.i.snowfall.*timestep./1000, ... + (PARA.snow.maxSnow - snowHeight ) .* PARA.snow.rho_snow ./ PARA.constants.rho_w ] ) ] ); %ensures that no more than maxSnow can accumulate + %account for excess snow in water balance + BALANCE.water.dr_excessSnow = BALANCE.water.dr_excessSnow -( FORCING.i.snowfall.*timestep - deltaSnow_i*1000 ); %defined as negative when snow is removed + end + + GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... + + deltaSnow_i; + + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... + + ( deltaSnow_i./(PARA.snow.rho_snow./ PARA.constants.rho_w) - deltaSnow_i); + +else %no snow cover + + %---------- add the new snow into initial SWE variable in case of no snow cover------------------ + + GRID.snow.SWEinitial = GRID.snow.SWEinitial + FORCING.i.snowfall.*timestep./1000 - GRID.snow.SWEinitial.*0.1.*timestep; + BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - GRID.snow.SWEinitial.*0.1.*timestep*1000; %SWEinitial decreasing counted as surface runoff + + %----- add the rainfall as runoff in case of no infiltration into frozen ground + if ~PARA.modules.infiltration || (PARA.modules.infiltration && T(GRID.soil.cT_domain_ub)<=0 )%no infiltration scheme or uppermost soil cell frozen + BALANCE.water.dr_rain = BALANCE.water.dr_rain - FORCING.i.rainfall.*timestep; end + +end + +%--------- update albedo after fresh fallen snow -------------------------- +% determine time of last snowfall for albedo calculation +SEB.newSnow = SEB.newSnow-SEB.newSnow.*0.1.*timestep + FORCING.i.snowfall.*timestep./1000; +if SEB.newSnow>= PARA.technical.SWEperCell/2 + PARA.snow.albedo=PARA.snow.max_albedo; + SEB.newSnow=0; +end end \ No newline at end of file diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index 4abe8c0..580833d 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -24,7 +24,7 @@ GRID.snow.SWEinitial=0; % -------- update K grid ------------------------------------- - GRID.general.K_grid(GRID.snow.K_domain_ub)= GRID.general.K_grid(GRID.air.cT_domain_lb+1) - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ); + GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ); T(GRID.snow.cT_domain_ub)=T(GRID.air.cT_domain_lb); end @@ -36,7 +36,9 @@ GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) -... ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); %updates the position of the uppermost snow grid cell - if GRID.snow.Snow_i(GRID.snow.cT_domain_ub)>=1.5.*PARA.technical.SWEperCell %create new grid cell % JAN: why 1.5 ??? + assert( ~isnan( GRID.general.K_grid(GRID.snow.cT_domain_ub) ), 'updateGRID_snow - error in uppermost snow cell position' ); + + if GRID.snow.Snow_i(GRID.snow.cT_domain_ub)>=1.5.*PARA.technical.SWEperCell %create new grid cell %------ modify snow and air grid ----------------------------- GRID.snow.cT_domain(GRID.air.cT_domain_lb)=1; @@ -61,7 +63,7 @@ end if min(GRID.snow.Snow_i(GRID.snow.cT_domain))<=0.5.*PARA.technical.SWEperCell %avoid looping when unnecessary - for i=GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb-1 %check all snow cells except for the lowermost one for too small ice and water contents - merge with lower cell %JAN: replace with while-loop instead? + for i=GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb-1 %check all snow cells except for the lowermost one for too small ice and water contents - merge with lower cell if GRID.snow.Snow_i(i)<=0.5.*PARA.technical.SWEperCell @@ -118,9 +120,25 @@ end - if check_change==true %update grid spacings - GRID.general.K_grid(GRID.snow.cT_domain)=GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); - GRID.general.K_grid(GRID.air.cT_domain)=[GRID.general.K_grid(GRID.air.cT_domain_lb)+(-snowCellSize)*(GRID.air.cT_domain_lb-1):snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; + if check_change==true %update grid spacings + + assert( sum( sum( isnan(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)) ) ) == 0 , 'updateGRID_snow - error in Snow_i/a/w grid' ); + + % snow grid + soilTop = GRID.general.K_grid(GRID.snow.cT_domain_lb+1); + GRID.general.K_grid(GRID.snow.cT_domain)= soilTop - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); + + assert( sum( isnan( GRID.general.K_grid ) )==0, 'updateGRID_snow - error in K grid after snow grid update') + + % air grid + snowTop = GRID.general.K_grid(GRID.snow.cT_domain_ub); + numAirCells = sum( GRID.air.cT_domain ); + GRID.general.K_grid(GRID.air.cT_domain) = flip( snowTop-snowCellSize:-snowCellSize:snowTop-snowCellSize*numAirCells ); + + assert( sum( isnan( GRID.general.K_grid ) )==0, 'updateGRID_snow - error in K grid after air grid update') + + + %GRID.general.K_grid(GRID.air.cT_domain) = [GRID.general.K_grid(GRID.air.cT_domain_lb)+(-2*snowCellSize)*(GRID.air.cT_domain_lb-1):2*snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; end if (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)<=0.5.*PARA.technical.SWEperCell && sum(GRID.snow.cT_domain)<2) %remove last grid cell if snow threshold is reached @@ -150,8 +168,6 @@ end - % JAN: why does this need to be done in each timestep? - GRID.general.K_grid(GRID.air.cT_domain_lb)= GRID.general.K_grid(GRID.air.cT_domain_lb+1)-snowCellSize; GRID.general.K_grid(GRID.air.cT_domain_lb-1)= GRID.general.K_grid(GRID.air.cT_domain_lb+1)-2.*snowCellSize; @@ -160,15 +176,26 @@ GRID.general.K_delta=(- GRID.general.K_grid(1:end-1,1)+ GRID.general.K_grid(2:end,1)); - % bugfix as still situations can occur where K_delta<0 - if sum( GRID.general.K_delta < 0 ) > 0 + %bugfix as still situations may occur where K_delta<0 + if ( sum( GRID.general.K_delta < 0 ) > 0 ) disp('updateGRID_snow - bugfix K grid'); %update grid spacings - %GRID.general.K_grid(GRID.snow.cT_domain) = GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); - GRID.general.K_grid(GRID.air.cT_domain) = [GRID.general.K_grid(GRID.air.cT_domain_lb)+(-2*snowCellSize)*(GRID.air.cT_domain_lb-1):2*snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; - GRID.general.cT_grid = ( GRID.general.K_grid(1:end-1) + GRID.general.K_grid(2:end) ) ./ 2; %grid on which capacity and temperature information lives (midpoints of grid cells) + % snow grid + if ~isempty(GRID.snow.cT_domain_ub) % snow cover + GRID.general.K_grid(GRID.snow.cT_domain) = GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); + surfaceTop = GRID.general.K_grid(GRID.snow.cT_domain_ub); + else % no snow cover + surfaceTop = GRID.general.K_grid(GRID.soil.cT_domain_ub); + end + % air grid + numAirCells = sum( GRID.air.cT_domain ); + GRID.general.K_grid(GRID.air.cT_domain) = flip( surfaceTop-snowCellSize:-snowCellSize:surfaceTop-snowCellSize*numAirCells ); + GRID.general.cT_grid = ( GRID.general.K_grid(1:end-1) + GRID.general.K_grid(2:end) ) ./ 2; GRID.general.cT_delta = ( -GRID.general.cT_grid(1:end-1,1) + GRID.general.cT_grid(2:end,1) ); GRID.general.K_delta = ( -GRID.general.K_grid(1:end-1,1) + GRID.general.K_grid(2:end,1) ); end + + assert( sum( isnan(T(GRID.snow.cT_domain)))==0, 'updateGRID_snow - error in T after grid update' ); + assert( sum( isnan(GRID.general.K_grid))==0, 'update_GRID_snow - error in Kgrid after grid update'); end diff --git a/run_batch.m b/run_batch.m new file mode 100644 index 0000000..a90d033 --- /dev/null +++ b/run_batch.m @@ -0,0 +1,77 @@ +% script to excecute multiple independent runs of CryoGrid3 in parallel +% using the job/task batch framwork + +add_modules_function; + +startDate=datenum( 1979, 6, 1); +endDate=datenum( 1989, 6, 1); + +rainFrac=1; +snowFrac=1; +waterTable = 0; +waterTables = [ 0.0, 10.0 ]; +maxSnow = 0.4; +maxSnows = [ 0.2, 0.4 ]; +snowDens = 200; +snowDensities = [ 200, 250 ]; +extFlux = 0; +externalFluxes = [ -2e-3, 0, 2e-3 ]; +fieldCapacity = 0.3; +exices = [ 0.9, 0.8, 0.7, 0.6, 0.5, 0.4]; +natPor = 0.4; + + +combinations = {}; + +i=1; +for ms=maxSnows + for sd=snowDensities + for ef=externalFluxes + combinations{i} = [ms, sd, ef]; + i=i+1; + end + end +end + +%% + +numTasks = length( combinations ); + +jobName = 'SPINUP'; + +parallel.defaultClusterProfile('local'); +c = parcluster(); + +job = createJob( c, 'Name', jobName ); +disp( [datestr(now) ': created job ' jobName ] ); + +tasks = {}; +for i=1:numTasks + maxSnow=combinations{i}(1); + snowDens=combinations{i}(2); + extFlux = combinations{i}(3); + + taskName = sprintf( [ jobName '_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... + [ rainFrac, snowFrac, maxSnow, snowDens, ... + waterTable, extFlux, fieldCapacity ] ); + tasks{i} = createTask( job , @CryoGrid3_function_spinup, 0 , { taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity }, 'CaptureDiary', true, 'Name', taskName ); + disp( [ datestr(now) ': created task ' taskName ] ); +end + +submit(job); +disp( [ datestr(now) ': submitted job ' jobName ] ); + +whos + +% wait(job); +% disp( [ datestr(now) ': finished job ' jobName ] ); +% +% for i=1:numTasks +% diary( [ './runs/' tasks{i}.Name '/' tasks{i}.Name '_diary.txt' ] ); +% tasks{i}.Diary +% diary off +% disp( [datestr(now) ': saved diary of task ' tasks{i}.Name ] ); +% end + +%delete(job); +%disp( [datestr(now) ': deleted job ' jobName ' - Done.'] ); \ No newline at end of file diff --git a/run_parallel.m b/run_parallel.m index 90ce386..2d9e494 100644 --- a/run_parallel.m +++ b/run_parallel.m @@ -1,4 +1,4 @@ -% script to excecute multiple indipendent runs of CryoGrid3 in parallel +% script to excecute multiple independent runs of CryoGrid3 in parallel delete( gcp('nocreate') ); @@ -8,7 +8,7 @@ startDate=datenum( 1979, 6, 1); -endDate=datenum( 1999, 6, 1); +endDate=datenum( 1989, 6, 1); rainFrac=1; snowFrac=1; @@ -47,23 +47,23 @@ % end %start parallel pool -parpool(number_of_combinations, 'SpmdEnabled', false ); - -parfor i=1:number_of_combinations - fprintf ( 'Started execution of combination %d ...', i ); - %CryoGrid3_function_variableExice( startYear, endYear, rainFrac, snowFrac, combinations{i}(1), maxSnow, snowDens, extFlux, fieldCapacity, combinations{i}(2), natPor); - CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, waterTable, combinations{i}(1), combinations{i}(2), combinations{i}(3), fieldCapacity ) - fprintf ( '... finished execution of combination %d.', i ); -end +% parpool(number_of_combinations, 'SpmdEnabled', false ); +% +% parfor i=1:number_of_combinations +% fprintf ( 'Started execution of combination %d ...', i ); +% %CryoGrid3_function_variableExice( startYear, endYear, rainFrac, snowFrac, combinations{i}(1), maxSnow, snowDens, extFlux, fieldCapacity, combinations{i}(2), natPor); +% CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, waterTable, combinations{i}(1), combinations{i}(2), combinations{i}(3), fieldCapacity ) +% fprintf ( '... finished execution of combination %d.', i ); +% end -delete( gcp('nocreate') ); +%delete( gcp('nocreate') ); -%parpool(number_of_combinations ); -% alternative implementation using spmd -%spmd - %i=labindex() - %CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, waterTable, combinations{i}(1), combinations{i}(2), combinations{i}(3), fieldCapacity ) -%end +parpool(number_of_combinations ); +%alternative implementation using spmd +spmd + i=labindex(); + CryoGrid3_function_spinup( startDate, endDate, rainFrac, snowFrac, waterTable, combinations{i}(1), combinations{i}(2), combinations{i}(3), fieldCapacity ); +end % alternative implementation using parfeval diff --git a/run_single.m b/run_single.m new file mode 100644 index 0000000..b46df52 --- /dev/null +++ b/run_single.m @@ -0,0 +1,21 @@ +add_modules_function; + +startDate=datenum( 1979, 6, 1); +endDate=datenum( 1982, 7, 1); + +rainFrac=1; +snowFrac=1; +waterTable = 0; +waterTables = [ 0.0, 10.0 ]; +maxSnow = 0.4; +snowDens = 200; +extFlux = 2e-3; +fieldCapacity = 0.3; +exices = [ 0.9, 0.8, 0.7, 0.6, 0.5, 0.4]; +natPor = 0.4; + +jobName = 'TESTRUN'; +taskName = sprintf( [ jobName '_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... + [ rainFrac, snowFrac, maxSnow, snowDens, ... + waterTable, extFlux, fieldCapacity ] ); +CryoGrid3_function_spinup(taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity ); \ No newline at end of file From da7c8c47c878d7898029b6f2cae2439e2dcc2591 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Thu, 25 Jan 2018 11:33:05 +0100 Subject: [PATCH 05/45] bugfix in all main scripts: snow domain is again considered when determining the optimal timestep, otherwise unstabilities in the SEB during snowmelt occured. --- CryoGrid3.m | 75 ++++++++++--------- CryoGrid3_function_spinup.m | 16 ++-- CryoGrid3_function_variableExice.m | 10 +-- .../surfaceEnergyBalanceInfiltration.m | 9 +-- modules/cryoGridSEB/L_star.m | 9 +-- modules/cryoGridSoil/heatConduction.m | 1 - run_batch.m | 3 +- 7 files changed, 55 insertions(+), 68 deletions(-) diff --git a/CryoGrid3.m b/CryoGrid3.m index f747914..eb10e8f 100755 --- a/CryoGrid3.m +++ b/CryoGrid3.m @@ -95,8 +95,8 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity -PARA.technical.starttime=datenum(1980, 6, 1); % starttime of the simulation - if empty start from first value of time series -PARA.technical.endtime=datenum(1983, 6, 1); % endtime of the simulation - if empty end at last value of time series +PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series +PARA.technical.endtime=datenum(1989, 6, 1); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -142,7 +142,7 @@ end -run_number = sprintf( [ 'TESTRUN_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... +run_number = sprintf( [ 'TESTRUN_oldSnowScheme_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); @@ -222,11 +222,11 @@ %------determine the thermal properties of the model domains ---------- [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = getThermalPropertiesInfiltration(T, wc, c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid, GRID, PARA); - try - assert( sum( isnan(k_cTgrid)) + sum( isnan(k_Kgrid)) + sum( isnan( c_cTgrid)) ==0, 'Cryogrid3 - nan in c or k grids'); - catch - save( [ './runs/' run_number '/' run_number '_workspaceAtckgridCrash.mat'] ); - end +% try +% assert( sum( isnan(k_cTgrid)) + sum( isnan(k_Kgrid)) + sum( isnan( c_cTgrid)) ==0, 'Cryogrid3 - nan in c or k grids'); +% catch +% save( [ './runs/' run_number '/' run_number '_workspaceAtckgridCrash.mat'] ); +% end %------- water and energy balance calculations ------------------------ BALANCE = updateBALANCE(T, wc, c_cTgrid, lwc_cTgrid, BALANCE, GRID, PARA); @@ -236,11 +236,11 @@ [PARA, GRID] = surfaceCondition(GRID, PARA, T); %calculate the surface energy balance [SEB, dwc_dt] = surfaceEnergyBalanceInfiltration(T, wc, FORCING, GRID, PARA, SEB); - try - assert( abs(SEB.Qe)<1e5 && abs(SEB.Qh)<1e5 , 'CryoGrid3 - Qe or Qh too large' ); - catch - save( [ './runs/' run_number '/' run_number '_workspaceAtQeQhCrash.mat'] ); - end +% try +% assert( abs(SEB.Qe)<1e5 && abs(SEB.Qh)<1e5 , 'CryoGrid3 - Qe or Qh too large' ); +% catch +% save( [ './runs/' run_number '/' run_number '_workspaceAtQeQhCrash.mat'] ); +% end %------ soil module -------------------------------------------------- @@ -254,8 +254,8 @@ % account for min and max timesteps specified, max. energy change per grid cell and the CFT stability criterion. % energy change due to advection of heat through water fluxes is still excluded. % timestep in [days] - timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain ) ) ./ (24.*3600), ... %+ GRID.snow.cT_domain - PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta(GRID.soil.cT_domain ) ./ SEB.dE_dt(GRID.soil.cT_domain ) ) ) ./ (24.*3600), ... + timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... + PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... PARA.technical.maxTimestep ] ), ... PARA.technical.minTimestep ] ), ... TEMPORARY.outputTime-t ] ); @@ -272,33 +272,34 @@ %------- water body module -------------------------------------------- T = mixingWaterBody(T, GRID); - - try - assert( sum( T<-60 )+sum(T>50)==0, 'CryoGrid3 - T exceeds physical limits' ); - catch - save( [ './runs/' run_number '/' run_number '_workspaceAtTlimitsCrash.mat'] ); - end +% +% try +% assert( sum( T<-60 )+sum(T>50)==0, 'CryoGrid3 - T exceeds physical limits' ); +% catch +% save( [ './runs/' run_number '/' run_number '_workspaceAtTlimitsCrash.mat'] ); +% end %------- snow cover module -------------------------------------------- %[T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); [T, GRID, PARA, SEB] = CryoGridSnow_old(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep); - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + %[GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + [GRID, T] = updateGRID_snow_old(T, GRID, PARA); - try - assert( ~isnan(T(GRID.air.cT_domain_lb+1)) , 'CryoGrid3 - T surf is nan after snow module'); - catch - save( [ './runs/' run_number '/' run_number '_workspaceAtTsurfCrash.mat'] ); - end +% try +% assert( ~isnan(T(GRID.air.cT_domain_lb+1)) , 'CryoGrid3 - T surf is nan after snow module'); +% catch +% save( [ './runs/' run_number '/' run_number '_workspaceAtTsurfCrash.mat'] ); +% end - try - assert( sum(GRID.general.K_delta<0)==0 , 'updateGRIDsnow - error in K grid'); - catch - save( [ './runs/' run_number '/' run_number '_workspaceAtKgridCrash.mat'] ); - end +% try +% assert( sum(GRID.general.K_delta<0)==0 , 'updateGRIDsnow - error in K grid'); +% catch +% save( [ './runs/' run_number '/' run_number '_workspaceAtKgridCrash.mat'] ); +% end %------- infiltration module------------------------------------------- if PARA.modules.infiltration @@ -318,11 +319,11 @@ %------- update Lstar for next time step ------------------------------ SEB = L_star(FORCING, PARA, SEB); - try - assert( ~isnan(SEB.L_star(end)), 'L_star - Lstar is nan' ); - catch - save( [ './runs/' run_number '/' run_number '_workspaceAtLstarCrash.mat'] ); - end +% try +% assert( ~isnan(SEB.L_star(end)), 'L_star - Lstar is nan' ); +% catch +% save( [ './runs/' run_number '/' run_number '_workspaceAtLstarCrash.mat'] ); +% end %------- water balance calculations ----------------------------------- % rainfall diff --git a/CryoGrid3_function_spinup.m b/CryoGrid3_function_spinup.m index ce77f3b..3a1f50d 100755 --- a/CryoGrid3_function_spinup.m +++ b/CryoGrid3_function_spinup.m @@ -240,17 +240,17 @@ function CryoGrid3_function_spinup( taskName, startDate, endDate, rainFrac, snow % account for min and max timesteps specified, max. energy change per grid cell and the CFT stability criterion. % energy change due to advection of heat through water fluxes is still excluded. % timestep in [days] - timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain) ) ./ (24.*3600), ... % + GRID.snow.cT_domain - PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta(GRID.soil.cT_domain) ./ SEB.dE_dt(GRID.soil.cT_domain) ) ) ./ (24.*3600), ... - PARA.technical.maxTimestep ] ), ... - PARA.technical.minTimestep ] ), ... - TEMPORARY.outputTime-t ] ); + timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... + PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... + PARA.technical.maxTimestep ] ), ... + PARA.technical.minTimestep ] ), ... + TEMPORARY.outputTime-t ] ); % give a warning when timestep required by CFT criterion is below the minimum timestep specified -% if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) -% warning( 'numerical stability not guaranteed' ); -% end + if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) + warning( 'numerical stability not guaranteed' ); + end %------ update T array ------------------------------------------------ T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; diff --git a/CryoGrid3_function_variableExice.m b/CryoGrid3_function_variableExice.m index 88c9a17..fdc3159 100755 --- a/CryoGrid3_function_variableExice.m +++ b/CryoGrid3_function_variableExice.m @@ -246,11 +246,11 @@ % account for min and max timesteps specified, max. energy change per grid cell and the CFT stability criterion. % energy change due to advection of heat through water fluxes is still excluded. % timestep in [days] - timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain) ) ./ (24.*3600), ... % + GRID.snow.cT_domain - PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta(GRID.soil.cT_domain) ./ SEB.dE_dt(GRID.soil.cT_domain) ) ) ./ (24.*3600), ... - PARA.technical.maxTimestep ] ), ... - PARA.technical.minTimestep ] ), ... - TEMPORARY.outputTime-t ] ); + timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... + PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... + PARA.technical.maxTimestep ] ), ... + PARA.technical.minTimestep ] ), ... + TEMPORARY.outputTime-t ] ); % give a warning when timestep required by CFT criterion is below the minimum timestep specified diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m index 5515e2b..b78b38d 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m @@ -26,11 +26,6 @@ dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); end -% JAN : here a modification for water bodies would be needed (extinction), -% but this would probably make no difference for summer due to mixing, -% maybe different in winter/spring - - %__________________________________________________________________________ Sout = PARA.surf.albedo*FORCING.i.Sin; Lout = PARA.surf.epsilon.*sigma.*(T(GRID.air.cT_domain_lb+1)+273.15).^4 + (1-PARA.surf.epsilon).*FORCING.i.Lin; @@ -41,7 +36,7 @@ %calculate ET if PARA.modules.infiltration - %snow cover or uppermost grid cell frozen --> no ET ; JAN: this includes the case of a frozen water body + % snow cover or uppermost grid cell frozen --> no ET ; this includes the case of a frozen water body if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); % unfrozen water body at surface @@ -49,7 +44,7 @@ Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); dwc_dt(1)=-Qe./L; %in m water per sec, this can be evaporation or condensation - % JAN: this is the "default" case of an unfrozen soil surface + % unfrozen soil surface else Qe_pot=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, 0, FORCING.i.p, PARA)); %potential ET if Qe_pot>0 diff --git a/modules/cryoGridSEB/L_star.m b/modules/cryoGridSEB/L_star.m index 029ef93..ac3eed9 100644 --- a/modules/cryoGridSEB/L_star.m +++ b/modules/cryoGridSEB/L_star.m @@ -28,11 +28,4 @@ SEB.ustar = u_star; -SEB.L_star=[SEB.L_star(2:end) L_star]; - - -assert(~isnan(L_star), 'Lstar is nan'); - - - - +SEB.L_star=[SEB.L_star(2:end) L_star]; \ No newline at end of file diff --git a/modules/cryoGridSoil/heatConduction.m b/modules/cryoGridSoil/heatConduction.m index b7546a6..1bb7c07 100644 --- a/modules/cryoGridSoil/heatConduction.m +++ b/modules/cryoGridSoil/heatConduction.m @@ -4,7 +4,6 @@ cT_delta = GRID.general.cT_delta; cT_cellAboveSurface = GRID.air.cT_domain_lb; - dE_dt=T.*0; dE_dt(cT_cellAboveSurface+1)= k_eff(cT_cellAboveSurface+2).*(T(cT_cellAboveSurface+2)-T(cT_cellAboveSurface+1))./cT_delta(cT_cellAboveSurface+1) ; diff --git a/run_batch.m b/run_batch.m index a90d033..eb5f766 100644 --- a/run_batch.m +++ b/run_batch.m @@ -61,7 +61,6 @@ submit(job); disp( [ datestr(now) ': submitted job ' jobName ] ); -whos % wait(job); % disp( [ datestr(now) ': finished job ' jobName ] ); @@ -74,4 +73,4 @@ % end %delete(job); -%disp( [datestr(now) ': deleted job ' jobName ' - Done.'] ); \ No newline at end of file +%disp( [datestr(now) ': deleted job ' jobName ' - Done.'] ); From 3ef227cdbe48ed259975d3693cd39d6f5da587ab Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Thu, 25 Jan 2018 17:51:49 +0100 Subject: [PATCH 06/45] added analysis script. setup new spinup runs wiht excess ice --- CryoGrid3_function_variableExice.m | 15 ++- analysis/cm_blueautumn.mat | Bin 0 -> 2757 bytes analysis/plot_output.m | 206 +++++++++++++++++++++++++++++ run_batch.m | 55 +++++--- 4 files changed, 253 insertions(+), 23 deletions(-) create mode 100644 analysis/cm_blueautumn.mat create mode 100644 analysis/plot_output.m diff --git a/CryoGrid3_function_variableExice.m b/CryoGrid3_function_variableExice.m index fdc3159..c490cd3 100755 --- a/CryoGrid3_function_variableExice.m +++ b/CryoGrid3_function_variableExice.m @@ -1,4 +1,4 @@ -function [] = CryoGrid3_function_variableExice( startYear, endYear, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity, exice, natPor ) +function [] = CryoGrid3_function_variableExice( taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity, exice, natPor ) % ------------------------------------------------------------------------- % CryoGRID3 @@ -25,7 +25,7 @@ %default used in publication: PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 theta_w theta_m theta_o 2 natPor;... + 0.15 theta_w theta_m theta_o 2 natPor;... 0.9 theta_w theta_m theta_o 1 natPor;... 9.0 0.30 0.70 0.00 1 0.30 ]; %simple stratigraphy with excess ice used to test water balance: @@ -98,8 +98,8 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(startYear, 6, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(endYear, 6, 1); % endtime of the simulation - if empty end at last value of time series + PARA.technical.starttime=startDate; % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=endDate; % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -146,10 +146,11 @@ run(configFile); end - run_number = sprintf('spinup_%d-%d_stratSamExice_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f_exice%0.2f_natPor%0.2f', ... - [ startYear, endYear, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, ... - PARA.snow.maxSnow, PARA.snow.rho_snow, PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity, exice, natPor ]); +% run_number = sprintf('spinup_%d-%d_stratSamExice_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f_exice%0.2f_natPor%0.2f', ... +% [ startYear, endYear, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, ... +% PARA.snow.maxSnow, PARA.snow.rho_snow, PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity, exice, natPor ]); + run_number = taskName; % ------make output directory (name depends on parameters) ---------------- mkdir(['./runs/' run_number]) diff --git a/analysis/cm_blueautumn.mat b/analysis/cm_blueautumn.mat new file mode 100644 index 0000000000000000000000000000000000000000..523e3466e1b7cb30ebcfd5d557882e24c206c58b GIT binary patch literal 2757 zcmV;$3Oe;oK~zjZLLfCRFd$7qR4ry{Y-KDUP;6mzW^ZzBIv__(PFO)UG%O%Pa%Ew3 zWn>_4ZaN@MZ*Cw#aB?6ZF(5K9Iy5pmGC3eJFflVAARr(hARr(hARr(hARr(hARr(h zARr(hARr(hARr(hARr(hARr(B00000000000ZB~{0000z3IG6joa~r+R8&V6hZ_(< z0udL88dQQ16%`Rh#fTRNj7u~sLBt(U76~Y#NF**`a6v^DMbsE^K_?oU3DckInf_Gw#s;fF*o&SJk_em0B!k26}b*mv)l^^EmKQX&zLx}km;Un0cvh{1@8|D0qyR` z7joQtTS+0uU4K2Wi2aurjEdOz%(Lz1pPjH)$L3qECTWH&4l%s#*6QvUN?`|2DurIu{2JNU*0VUk;efSRi=X=EPBixls z*|%;qE@l6C<+@V#C#(*`ZD+4e zb0)Y{V|*Wn!B=Y}z~2_N!25L%tzo}XYF@)$ufnwk<9l`rJ~c5BG_VSi@Hmqjr_`dZ zjSmO)+}?tPF`Mg{2jy9yiHS))vwqjPdcNP8cu@o2XK}Af1N*mg^BOR|12Y?$_Q^kh zn##&e%%p|xpy#n7P&a3el$k&H3g~A&sF`UT?g`eGm4P9nsD){<;X3#{QlpjnP7lxf z+0TCd4f+2+zxK2L{NI26@8_SB{pbJw^Z(!B{NH``?F7n_Q`5rNEBBw4Q+a!jZ^A}7 zJq!L#=#f*xbb0n?-JKL$#vPq>_1l&)kB@Xx_*jnUq@%yqdCu19q;Fkn&iP0?$m4^` z&E2~UubPD9#H)3(Xz!y|kn z87WLkQj1lT(Tm)lg(tU@)a%iDqlk8@(0+Kx!=atBAK$$lGpU^t@qjjpQ;ZQ!N@}C1 z>pxC(JJv>LmRz&GVbexOIxh=v+D5)%7o*0vwvq=P+)A6o5ihUpYbERbr-c!;(gMBE zMfyWqX;xa$j?GmqWaxJ6{1qWjqwzv5H2Cg!GTqNwNYU0$%U-#KdS36H7n#>g%|GlB zM%+x|`MX0#Z)v8SCVtUodK$RB{`=ph6g$OT$b^)x7P!tB6(prI-cB3Vtd`Qzk&cJY zej=rB6L{vc1D3jWj8o2i8bq z%ogT`?rbE@YD*!bjilsnp{uFdNH6ux7cVbtpq30Xuag%VsKT8G+(6ly(^J%^HPF-h zQ#-zRQ%`YrleLeh)>9NudvHBPTrzMSw6>lCtvC_&v=`G`N83+)EX+(DIT(*nANXAz z+3++jtD}YA4A~g)Q5~7-aDr-SGEY}bEsfctQZavbEorI_Q1rK`B_*B~wOVSA?EUAv z8xqQE?iMm9A-qOm4W0Lqat7(ZQ;Gc5n`%OMNHr~4UU=$-el<;vcqU}DiiS&4W_2yA zqTWvvh0IoxWLtb?$L>l>d58?tjdwQ=v_*<3=yT4rn0B7LFs?bHg6vAeg^X8_`IzAJ zhOTnbbLPyKlge%XuWLt@lZ==7oiZvAR%Nwi8S&~`S6)gNczL>)lD`(uNGUlBvsM~j zLQ8pB8J3VSzkXsdX$jd7W{7&R9Eu39xwnW?)u&lzYZg&7Pvf;h3g*`_D|v4H0BV_)UdxSv(0CLhlyq)j)UDtUQs&7d zzSFzWp>LnDZ@_+H>ga_1B71W)_76v=t=I=%JGWzB2yykOrrTrP4GuuZc9i;`%$7& z9rqu7YK8i2n{=oSb^Vt#_!qyZpk5~@FREuB`fDKSwtY$#yiw{0sNa92E=AqWP76XE zKcAipI%W)R#CbAv1^8QLDEK(5u#w{epAADDx68I^V*hDQcoX)ooKpCd+>fN}!}9E; z>>cvYq0So@h{2>98Ms3B4y=8xiF)s;GOii<9B$f-{YP&hyt?rk_;B;DL4z;$fe-A0 z!3EBj!IGW#KqvoHu;*kMc<4eas1^MNycVy~!Zb}C3#JxM16S2rw(xUnI#yx7aed~8Nn{|=NfXV{JcM@XlDZ@uS(waTkx9G4L8D#Q23U@!bP4}#%WEw~Drl{^GTJ7s|i zJ=I`SKo{bYhbwnry+@7cV83t1}oLyTE>UhfJ|MUOD{kQxV00030|6^bPfe-c!RHDN|LEz{pJxY(# LBaj9Fbxd?xjOAVJ literal 0 HcmV?d00001 diff --git a/analysis/plot_output.m b/analysis/plot_output.m new file mode 100644 index 0000000..0068abc --- /dev/null +++ b/analysis/plot_output.m @@ -0,0 +1,206 @@ +% Plotting script for temperature and water content fields +% Author: Jan Nitzbon +% +function plot_output(dirname, runname, number_of_realizations) + +% dirname = './'; +% runname = 'testrunMPI_PAIRWISE_xH1_xW1_xS1_infil1_xice1_rF1.0_sF1.0_Dsnow1e-6_realization'; +% number_of_realizations = 2; +% + + %% load output data and settings from files of all workers + + + dir = dirname;%'/home/jnitzbon/gls1/CryoGrid/CryoGrid3_infiltration_xice_mpi_DEV/'; + cm=load( [ dir 'cm_blueautumn.mat' ] ); + + infil=0; + xice=0; + rainFrac=0; + snowFrac=0; + wt = 0.0; + + OUTS = {}; + + for i=1:number_of_realizations + run = runname; %sprintf('testrun_mpi_waterExchange_noGroundHeatFlux_realization' ); + run = [ run num2str(i) ]; + outputfile = [dir run '/' run '_output.mat']; + configfile = [dir run '/' run '_settings.mat']; + + load(outputfile); + load(configfile); + + OUTS{i}.OUT=OUT; + OUTS{i}.PARA = PARA; + OUTS{i}.GRID = GRID; + OUTS{i}.FORCING = FORCING; + + clear OUT PARA GRID FORCING + end + + %% extract relevant vectors + + ts = OUTS{1}.OUT.timestamp(); + zs = {}; + Ts = {}; + LWCs = {}; + WCs = {}; + snowTop = {}; + soilTop = {}; + + for i=1:number_of_realizations + zs{i} = OUTS{i}.PARA.ensemble.initial_altitude(i)-OUTS{i}.GRID.general.cT_grid; + Ts{i} = OUTS{i}.OUT.cryoGrid3; + LWCs{i} = OUTS{i}.OUT.liquidWater; + WCs{i} = OUTS{i}.OUT.water; + snowTop{i} = OUTS{i}.OUT.soil.topPosition; + end + %lakeFloor = OUT.soil.lakeFloor(); + %lakeFloor = [ NaN(length(soilTop)-length(lakeFloor),1); lakeFloor ]; + + % limits + minz = min(OUTS{1}.PARA.ensemble.initial_altitude - 4); + maxz = max(OUTS{1}.PARA.ensemble.initial_altitude + 0.5); + + mint = min(ts); + maxt = max(ts); + + + %% plot evolution of simple ensemlbe variables + + figure; + + subplot(2,3,1) + hold on + for i=1:number_of_realizations + plot(ts, OUTS{1}.OUT.ensemble.active_layer_depth_altitude(:,i)) ; %abs(OUTS{1}.OUT.ensemble.altitude(:,i)- + end + datetick; + title('Frost table [m asl]') + hold off + + subplot(2,3,2) + hold on + for i=1:number_of_realizations + plot(ts, OUTS{1}.OUT.ensemble.water_table(:,i)); + end + datetick; + title('Water table [m asl]') + hold off + + subplot(2,3,3) + hold on + for i=1:number_of_realizations + plot(ts, OUTS{1}.OUT.ensemble.surface_altitude(:,i)); + end + datetick; + title('Surface altitude [m asl]') + hold off + + subplot(2,3,4) + hold on + for i=1:number_of_realizations + plot(ts, nansum(OUTS{i}.OUT.ensemble.heat_fluxes , 2)); + end + datetick; + title('Heat fluxes [ W / m^2 ]') + hold off + + subplot(2,3,5) + hold on + for i=1:number_of_realizations + plot(ts, nansum(OUTS{i}.OUT.ensemble.water_fluxes .*1000 .* 3600 , 2)); + end + datetick; + title('Water fluxes [mm/h]') + hold off + + subplot(2,3,6) + hold on + for i=1:number_of_realizations + plot(ts, nansum(OUTS{i}.OUT.ensemble.snow_fluxes .*1000 .* 3600 , 2) ); + end + datetick; + title('Snow fluxes [mm/h]') + hold off + + currentFigure = gcf; + title(currentFigure.Children(end), runname); + + + %% plot temperature and water content fields + + figure; + + title(runname); + + %temperature fields + for i=1:number_of_realizations + subplot(2, number_of_realizations, i); + pcolor( ts', zs{i}', Ts{i}); + hold on; + shading flat; % do not show grid + %shading interp; + % colormap and colorbar + caxis( [ -40, 20] ); + colormap(gca, cm.Colormap_blueautumn); + if i==1 + cbar=colorbar('location','westoutside'); + end + % layout + axis( [ mint maxt minz maxz ] ); + datetick; + xlabel('time') + ylabel('$z$ [m]', 'Interpreter', 'latex'); + xlabel(cbar, '$T$ [$^\circ$C]', 'Interpreter', 'latex'); + title(sprintf('Temperature - realization %d', i)); + hold off; + end + + % (liquid) water content fields + for i=1:number_of_realizations + subplot(2, number_of_realizations, number_of_realizations+i); + pcolor( ts', zs{i}', LWCs{i}); %ax, + hold on; + caxis( [ 0. , 1. ] ); + colormap(gca, 'parula'); + colormap(gca, flipud(colormap)); + if i==1 + cbar=colorbar('location','westoutside'); + end + shading flat; + % layout + axis( [ mint maxt minz maxz ] ); + datetick; + xlabel('time'); + ylabel('$z$ [m]', 'Interpreter', 'latex'); + xlabel(cbar, '$\theta_w$ [-]', 'Interpreter', 'latex'); + title(sprintf('Water content - realization %d', i)); + hold off; + end + + currentFigure = gcf; + title(currentFigure.Children(end), runname); + + %% plot temperature in 2m depth + + figure; + hold on; + + title(runname); + + depth = 2.0; + [val, idx] = min( abs(depth-OUTS{1}.GRID.general.cT_grid) ); + + plot( ts', Ts{1}( idx , :) ); + plot( ts', Ts{2}( idx , :) ); + + axis( [mint maxt -20 0 ] ); + + title(sprintf('Temperature in [°C] at z=%f', OUTS{1}.GRID.general.cT_grid(idx) )); + + hold off; + + + \ No newline at end of file diff --git a/run_batch.m b/run_batch.m index eb5f766..9f2c286 100644 --- a/run_batch.m +++ b/run_batch.m @@ -1,5 +1,5 @@ % script to excecute multiple independent runs of CryoGrid3 in parallel -% using the job/task batch framwork +% using the job/task batch framework add_modules_function; @@ -21,15 +21,25 @@ natPor = 0.4; +% combinations = {}; +% +% i=1; +% for ms=maxSnows +% for sd=snowDensities +% for ef=externalFluxes +% combinations{i} = [ms, sd, ef]; +% i=i+1; +% end +% end +% end + combinations = {}; i=1; -for ms=maxSnows - for sd=snowDensities - for ef=externalFluxes - combinations{i} = [ms, sd, ef]; - i=i+1; - end +for ex=exices + for wt=waterTables + combinations{i}= [ex,wt]; + i=i+1; end end @@ -37,7 +47,7 @@ numTasks = length( combinations ); -jobName = 'SPINUP'; +jobName = 'SPINUP-EXICE'; parallel.defaultClusterProfile('local'); c = parcluster(); @@ -46,16 +56,29 @@ disp( [datestr(now) ': created job ' jobName ] ); tasks = {}; +% for i=1:numTasks +% maxSnow=combinations{i}(1); +% snowDens=combinations{i}(2); +% extFlux = combinations{i}(3); +% +% taskName = sprintf( [ jobName '_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... +% [ rainFrac, snowFrac, maxSnow, snowDens, ... +% waterTable, extFlux, fieldCapacity ] ); +% tasks{i} = createTask( job , @CryoGrid3_function_spinup, 0 , { taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity }, 'CaptureDiary', true, 'Name', taskName ); +% disp( [ datestr(now) ': created task ' taskName ] ); +% end + for i=1:numTasks - maxSnow=combinations{i}(1); - snowDens=combinations{i}(2); - extFlux = combinations{i}(3); + exice=combinations{i}(1); + waterTable=combinations{i}(2); - taskName = sprintf( [ jobName '_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... - [ rainFrac, snowFrac, maxSnow, snowDens, ... - waterTable, extFlux, fieldCapacity ] ); - tasks{i} = createTask( job , @CryoGrid3_function_spinup, 0 , { taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity }, 'CaptureDiary', true, 'Name', taskName ); - disp( [ datestr(now) ': created task ' taskName ] ); + taskName = sprintf( [ jobName '_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSamExice_rf%d_sf%d_maxSnow%0.2f_snowDens=%d_wt%0.1f_extFlux%0.4f_fc%0.2f_exice%0.2f_natPor%0.2f' ], ... + [ rainFrac, snowFrac, maxSnow, snowDens, waterTable, extFlux, fieldCapacity, exice, natPor ] ); + + tasks{i} = createTask( job, @CryoGrid3_function_variableExice, 0, ... + { taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity, exice, natPor }, ... + 'CaptureDiary', true, 'Name', taskName); + disp( [ datestr(now) ': created task ' taskName ] ); end submit(job); From 8e91d484b865296724f9f6df9a21558772b558dd Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Fri, 26 Jan 2018 12:27:32 +0100 Subject: [PATCH 07/45] bugfix, such that yearly output is possible. --- CryoGrid3_function_spinup.m | 2 +- CryoGrid3_function_variableExice.m | 2 +- modules/cryoGridTechnical/sum_up_output_store.m | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CryoGrid3_function_spinup.m b/CryoGrid3_function_spinup.m index 3a1f50d..6e8e689 100755 --- a/CryoGrid3_function_spinup.m +++ b/CryoGrid3_function_spinup.m @@ -294,7 +294,7 @@ function CryoGrid3_function_spinup( taskName, startDate, endDate, rainFrac, snow %------- next time step ----------------------------------------------- t=t+timestep; %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT); + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number); end %profile off diff --git a/CryoGrid3_function_variableExice.m b/CryoGrid3_function_variableExice.m index c490cd3..aa28b60 100755 --- a/CryoGrid3_function_variableExice.m +++ b/CryoGrid3_function_variableExice.m @@ -298,7 +298,7 @@ %------- next time step ----------------------------------------------- t=t+timestep; %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT); + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number); end %profile off diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 6a07520..5563681 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -1,4 +1,4 @@ -function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT) +function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number) TEMPORARY.timestep_sum=TEMPORARY.timestep_sum+(timestep*24*3600)*timestep; From ae7f71415c3a3c10bda9ee952f96e74d51894c4c Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Fri, 26 Jan 2018 12:34:05 +0100 Subject: [PATCH 08/45] modified run_batch for testing --- run_batch.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run_batch.m b/run_batch.m index eb5f766..d3d2b05 100644 --- a/run_batch.m +++ b/run_batch.m @@ -4,7 +4,7 @@ add_modules_function; startDate=datenum( 1979, 6, 1); -endDate=datenum( 1989, 6, 1); +endDate=datenum( 1980, 6, 1); rainFrac=1; snowFrac=1; From 72ecf1ecdf49556ea435dcbe437bfb3df220c24f Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Fri, 26 Jan 2018 19:27:38 +0100 Subject: [PATCH 09/45] added functionality that the model state is saved together with the output. this allows crashed runs to continue from a previous state. added a basic spinupFile function to CryoGrid3.m. --- CryoGrid3.m | 449 +++++++++--------- CryoGrid3_function_spinup.m | 9 +- CryoGrid3_function_variableExice.m | 12 +- analysis/plot_output.m | 176 ++++--- .../cryoGridTechnical/sum_up_output_store.m | 3 +- run_batch.m | 6 +- 6 files changed, 341 insertions(+), 314 deletions(-) diff --git a/CryoGrid3.m b/CryoGrid3.m index eb10e8f..480d042 100755 --- a/CryoGrid3.m +++ b/CryoGrid3.m @@ -13,202 +13,242 @@ %addpath('./nansuite/') -createLogFile=1; - -%---------------define input parameters------------------------------------ -% here you provide the ground stratigraphy -% z w/i m o type porosity - -%default used in publication: -PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 0.65 0.3 0.05 2 0.65;... - 0.9 0.65 0.3 0.05 1 0.65;... - 9.0 0.30 0.70 0.00 1 0.30 ]; - -%simple stratigraphy with excess ice used to test water balance: -% PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... -% 0.4 0.8 0.2 0.00 1 0.40;... -% 10.0 0.25 0.75 0.00 1 0.25 ]; -%very simply stratigraphy without excess ice used to test energy balance -% soilType = 1; -% PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... -% 1.0 0.5 0.5 0.00 1 0.5 ;... -% 10.0 0.25 0.75 0.00 1 0.25 ]; -% soil stratigraphy -% column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer -% extends until the end of the model domain -% column 2: volumetric water+ice content -% column 3: volumetric mineral content -% column 4: volumetric organic content -% column 5: code for soil type: 1: sand, 2: silt -% column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs - -%------ model parameters -------------------------------------------------- -PARA.soil.albedo=0.2; % albedo snow-free surface -PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development -PARA.soil.epsilon=0.97; % emissvity snow-free surface -PARA.soil.z0=1e-3; % roughness length [m] snow-free surface -PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface -PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] -PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] - -% parameters related to hydrology scheme -PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! -PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries -PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries -PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off -PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation -PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. -PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] -PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible -PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile -PARA.soil.waterTable=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up - -% parameters related to snow -PARA.snow.max_albedo=0.85; % albedo of fresh snow -PARA.snow.min_albedo=0.5; % albedo of old snow -PARA.snow.epsilon=0.99; % surface emissivity snow -PARA.snow.z0=5e-4; % roughness length surface [m] -PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow -PARA.snow.rho_snow=200.0; % density in [kg/m3] -PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] -PARA.snow.tau_a=0.008; % [per day] -PARA.snow.tau_f=0.24; % [per day] -PARA.snow.maxSnow= [0.4] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold -PARA.snow.extinction=25.0; % light extinction coefficient of snow - -% parameters related to water body on top of soil domain -PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) -PARA.water.epsilon=0.99; % surface emissivity water -PARA.water.rs=0.0; % surface resistance -> should be 0 for water -PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation - -PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 -PARA.ice.epsilon=0.98; % surface emissivity snow -PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice -PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow -PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 - -PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given - -PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases -PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells -PARA.technical.maxSWE=0.4; % in [m] SWE -PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity -PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series -PARA.technical.endtime=datenum(1989, 6, 1); % endtime of the simulation - if empty end at last value of time series -PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds -PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds -PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K -PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours -PARA.technical.saveDate='01.08.'; % date of year when output file is written - no effect if "saveInterval" is empty -PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year -PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] - -%default grid used for publications and testing of water balance: -PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] -%PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - -%very simple grid used for testing of energy balance: -%PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; - -%initial temperature profile -> first column depth [m] -> second column temperature [degree C] -%default: -PARA.Tinitial = [ -2 5 ;... - 0 0 ;... - 2 -5 ;... - 10 -10 ;... - 25 -9 ;... - 100 -9 ;... - 2000 10 ]; - -PARA = loadConstants( PARA ); - - -%FORCING data mat-file -PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files -PARA.forcing.rain_fraction=1; -PARA.forcing.snow_fraction=1; - -% switches for modules -PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs -PARA.modules.xice=1; % true if thaw subsicdence is enabled - -% ------update parameter values if config file provided ------------------- -% ------changes output directory to name specified in configfile which is -% the config filename by default -if paraFromFile - run(configFile); -end +createLogFile=0; + +spinupFile = [ './runs/TESTRUN_197906-197906_stratSam_rf1_sf1_maxSnow0.4_snowDens=200.0_wt0.0_extFlux0.0020_fc0.30/TESTRUN_197906-197906_stratSam_rf1_sf1_maxSnow0.4_snowDens=200.0_wt0.0_extFlux0.0020_fc0.30_finalState.mat' ]; + +if isempty(spinupFile) + + + %---------------define input parameters------------------------------------ + % here you provide the ground stratigraphy + % z w/i m o type porosity + + %default used in publication: + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + + %simple stratigraphy with excess ice used to test water balance: + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... + % 0.4 0.8 0.2 0.00 1 0.40;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + %very simply stratigraphy without excess ice used to test energy balance + % soilType = 1; + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... + % 1.0 0.5 0.5 0.00 1 0.5 ;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer + % extends until the end of the model domain + % column 2: volumetric water+ice content + % column 3: volumetric mineral content + % column 4: volumetric organic content + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + %------ model parameters -------------------------------------------------- + PARA.soil.albedo=0.2; % albedo snow-free surface + PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development + PARA.soil.epsilon=0.97; % emissvity snow-free surface + PARA.soil.z0=1e-3; % roughness length [m] snow-free surface + PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface + PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] + PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + + % parameters related to hydrology scheme + PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries + PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation + PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. + PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] + PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible + PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile + PARA.soil.waterTable=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up + + % parameters related to snow + PARA.snow.max_albedo=0.85; % albedo of fresh snow + PARA.snow.min_albedo=0.5; % albedo of old snow + PARA.snow.epsilon=0.99; % surface emissivity snow + PARA.snow.z0=5e-4; % roughness length surface [m] + PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow + PARA.snow.rho_snow=200.0; % density in [kg/m3] + PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] + PARA.snow.tau_a=0.008; % [per day] + PARA.snow.tau_f=0.24; % [per day] + PARA.snow.maxSnow= [0.4] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.extinction=25.0; % light extinction coefficient of snow + + % parameters related to water body on top of soil domain + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.epsilon=0.99; % surface emissivity water + PARA.water.rs=0.0; % surface resistance -> should be 0 for water + PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation + + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + PARA.ice.epsilon=0.98; % surface emissivity snow + PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice + PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow + PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + + PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given + + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases + PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells + PARA.technical.maxSWE=0.4; % in [m] SWE + PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity + PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(1979, 6, 15); % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds + PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds + PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.saveDate='01.08.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + + %default grid used for publications and testing of water balance: + PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + + %very simple grid used for testing of energy balance: + %PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; + + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] + %default: + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... + 2000 10 ]; + + PARA = loadConstants( PARA ); + + + %FORCING data mat-file + PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.rain_fraction=1; + PARA.forcing.snow_fraction=1; + + % switches for modules + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=1; % true if thaw subsicdence is enabled + + % ------update parameter values if config file provided ------------------- + % ------changes output directory to name specified in configfile which is + % the config filename by default + if paraFromFile + run(configFile); + end - -run_number = sprintf( [ 'TESTRUN_oldSnowScheme_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... - [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... - PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); -% ------make output directory (name depends on parameters) ---------------- -mkdir(['./runs/' run_number]) + run_number = sprintf( [ 'TESTRUN_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... + [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... + PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); + % ------make output directory (name depends on parameters) ---------------- + mkdir(['./runs/' run_number]) -% ------redirect command line output to logfile --------------------------- -if createLogFile - diary(['./runs/' run_number '/' run_number '_diary.txt']); -end + % ------redirect command line output to logfile --------------------------- + if createLogFile + diary(['./runs/' run_number '/' run_number '_diary.txt']); + end -%-------------------------------------------------------------------------- -%-----------do not modify from here onwards-------------------------------- -%-------------------------------------------------------------------------- -[FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file -if ~success - warning('A problem with the Forcing occured.'); -end -clear success + %-------------------------------------------------------------------------- + %-----------do not modify from here onwards-------------------------------- + %-------------------------------------------------------------------------- + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + + if ~success + warning('A problem with the Forcing occured.'); + end + clear success -PARA = initializeParameters(PARA, FORCING); %set start time, etc. + PARA = initializeParameters(PARA, FORCING); %set start time, etc. -%----------------create and initialize the grids -------------------------- -GRID=makeGrids(PARA); %create all grids -GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + %----------------create and initialize the grids -------------------------- + GRID=makeGrids(PARA); %create all grids + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid -%----- initializie excess ground ice -------------------------------------- -[GRID,PARA] = initializeExcessIce2(GRID,PARA); + %----- initializie excess ground ice -------------------------------------- + [GRID,PARA] = initializeExcessIce2(GRID,PARA); -%----- initializie soil thermal properties -------------------------------- -GRID = initializeSoilThermalProperties(GRID, PARA); + %----- initializie soil thermal properties -------------------------------- + GRID = initializeSoilThermalProperties(GRID, PARA); -%------ initializie snow properties---------------------------------------- -GRID = initializeSnow(GRID); + %------ initializie snow properties---------------------------------------- + GRID = initializeSnow(GRID); -%---- initialize the surface energy balance struct ------------------------ -SEB = initializeSEB(); + %---- initialize the surface energy balance struct ------------------------ + SEB = initializeSEB(); -%---- initialize the water body module ------------------------------------ -GRID = initializeLAKE(GRID); + %---- initialize the water body module ------------------------------------ + GRID = initializeLAKE(GRID); -%---- initialize temperature profile -------------------------------------- -T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); + %---- initialize temperature profile -------------------------------------- + T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); -%---- modification for infiltration -wc=GRID.soil.cT_water; -GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; -GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; + %---- modification for infiltration + wc=GRID.soil.cT_water; + GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; + GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; -%---- preallocate temporary arrays for capacity and conductivity----------- -[c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid + %---- preallocate temporary arrays for capacity and conductivity----------- + [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid -%---- energy and water balance initialization ----------------------------- -BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); + %---- energy and water balance initialization ----------------------------- + BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); -%__________________________________________________________________________ -%-------- provide arrays for data storage --------------------------------- -[t, TEMPORARY] = generateTemporary(T, PARA); -OUT = generateOUT(); + %__________________________________________________________________________ + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); -disp('initialization successful'); -save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') + disp('initialization successful'); + save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') + +else %take setting from spinup file + load(spinupFile); % this loads T, wc, PARA, GRID, SEB from final state of spinup run + + % here one could optionally change the forcing settings + + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + if ~success + warning('A problem with the Forcing occured.'); + end + clear success + + PARA.technical.starttime = PARA.technical.endtime; %take the end time from the spinup run as start time + PARA.technical.endtime = datenum(1979, 7, 1); + + run_number = sprintf( [ 'TESTRUN_SPUNUP_' datestr( PARA.technical.starttime, 'yyyymmdd' ) '-' datestr(PARA.technical.endtime, 'yyyymmdd' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... + [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... + PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); + % ------make output directory (name depends on parameters) ---------------- + mkdir(['./runs/' run_number]) + % necessary initializations + %---- preallocate temporary arrays for capacity and conductivity----------- + [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid + %---- energy and water balance initialization ----------------------------- + BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); + disp('initialization from spinup successful'); + save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') + + + + +end %% ________________________________________________________________________ % Time Integration Routine I % I @@ -221,12 +261,6 @@ %------determine the thermal properties of the model domains ---------- [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = getThermalPropertiesInfiltration(T, wc, c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid, GRID, PARA); - -% try -% assert( sum( isnan(k_cTgrid)) + sum( isnan(k_Kgrid)) + sum( isnan( c_cTgrid)) ==0, 'Cryogrid3 - nan in c or k grids'); -% catch -% save( [ './runs/' run_number '/' run_number '_workspaceAtckgridCrash.mat'] ); -% end %------- water and energy balance calculations ------------------------ BALANCE = updateBALANCE(T, wc, c_cTgrid, lwc_cTgrid, BALANCE, GRID, PARA); @@ -236,13 +270,7 @@ [PARA, GRID] = surfaceCondition(GRID, PARA, T); %calculate the surface energy balance [SEB, dwc_dt] = surfaceEnergyBalanceInfiltration(T, wc, FORCING, GRID, PARA, SEB); -% try -% assert( abs(SEB.Qe)<1e5 && abs(SEB.Qh)<1e5 , 'CryoGrid3 - Qe or Qh too large' ); -% catch -% save( [ './runs/' run_number '/' run_number '_workspaceAtQeQhCrash.mat'] ); -% end - - + %------ soil module -------------------------------------------------- %calculate heat conduction SEB = heatConduction(T, k_Kgrid, GRID, PARA, SEB); @@ -262,9 +290,9 @@ % give a warning when timestep required by CFT criterion is below the minimum timestep specified -% if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) -% warning( 'numerical stability not guaranteed' ); -% end + if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) + warning( 'numerical stability not guaranteed' ); + end %------ update T array ------------------------------------------------ T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; @@ -272,35 +300,12 @@ %------- water body module -------------------------------------------- T = mixingWaterBody(T, GRID); -% -% try -% assert( sum( T<-60 )+sum(T>50)==0, 'CryoGrid3 - T exceeds physical limits' ); -% catch -% save( [ './runs/' run_number '/' run_number '_workspaceAtTlimitsCrash.mat'] ); -% end - %------- snow cover module -------------------------------------------- - %[T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); - [T, GRID, PARA, SEB] = CryoGridSnow_old(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep); + [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); - %[GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - [GRID, T] = updateGRID_snow_old(T, GRID, PARA); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); -% try -% assert( ~isnan(T(GRID.air.cT_domain_lb+1)) , 'CryoGrid3 - T surf is nan after snow module'); -% catch -% save( [ './runs/' run_number '/' run_number '_workspaceAtTsurfCrash.mat'] ); -% end - - - -% try -% assert( sum(GRID.general.K_delta<0)==0 , 'updateGRIDsnow - error in K grid'); -% catch -% save( [ './runs/' run_number '/' run_number '_workspaceAtKgridCrash.mat'] ); -% end - %------- infiltration module------------------------------------------- if PARA.modules.infiltration [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); @@ -319,11 +324,6 @@ %------- update Lstar for next time step ------------------------------ SEB = L_star(FORCING, PARA, SEB); -% try -% assert( ~isnan(SEB.L_star(end)), 'L_star - Lstar is nan' ); -% catch -% save( [ './runs/' run_number '/' run_number '_workspaceAtLstarCrash.mat'] ); -% end %------- water balance calculations ----------------------------------- % rainfall @@ -334,11 +334,14 @@ %------- next time step ----------------------------------------------- t=t+timestep; %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT); + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number); end %profile off -save(['./runs/' run_number '/' run_number '_output.mat'], 'OUT') +save(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') +save(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], 'T', 'wc', 'SEB', 'PARA', 'GRID') + + disp('Done.'); if createLogFile diary off; diff --git a/CryoGrid3_function_spinup.m b/CryoGrid3_function_spinup.m index 6e8e689..cd07268 100755 --- a/CryoGrid3_function_spinup.m +++ b/CryoGrid3_function_spinup.m @@ -100,8 +100,8 @@ function CryoGrid3_function_spinup( taskName, startDate, endDate, rainFrac, snow PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.saveDate='01.09.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] %default grid used for publications and testing of water balance: @@ -298,5 +298,8 @@ function CryoGrid3_function_spinup( taskName, startDate, endDate, rainFrac, snow end %profile off - save(['./runs/' run_number '/' run_number '_output.mat'], 'OUT') + save(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') + save(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], 'T', 'wc', 'SEB', 'PARA', 'GRID') + + disp('Done.'); diff --git a/CryoGrid3_function_variableExice.m b/CryoGrid3_function_variableExice.m index aa28b60..be21506 100755 --- a/CryoGrid3_function_variableExice.m +++ b/CryoGrid3_function_variableExice.m @@ -13,7 +13,7 @@ %add_modules_function; %adds required modules %add_modules; - createLogFile=1; + createLogFile=0; %---------------define input parameters------------------------------------ % here you provide the ground stratigraphy @@ -104,14 +104,14 @@ PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.saveDate='01.08.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] %default grid used for publications and testing of water balance: %PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] % use finer grid in upper 10 m to ensure correct evapotranspiration in case of subsidence - PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + PARA.technical.subsurfaceGrid = [[0:0.02:5], [5.1:0.1:15], [15.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] %very simple grid used for testing of energy balance: %PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; @@ -302,5 +302,7 @@ end %profile off - save(['./runs/' run_number '/' run_number '_output.mat'], 'OUT') + save(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') + save(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], 'T', 'wc', 'SEB', 'PARA', 'GRID') + disp('Done.'); diff --git a/analysis/plot_output.m b/analysis/plot_output.m index 0068abc..6e60668 100644 --- a/analysis/plot_output.m +++ b/analysis/plot_output.m @@ -1,18 +1,21 @@ % Plotting script for temperature and water content fields % Author: Jan Nitzbon % -function plot_output(dirname, runname, number_of_realizations) +%function plot_output(dirname, runname, number_of_realizations) -% dirname = './'; -% runname = 'testrunMPI_PAIRWISE_xH1_xW1_xS1_infil1_xice1_rF1.0_sF1.0_Dsnow1e-6_realization'; -% number_of_realizations = 2; +clear all +close all + + dirname = '../runs/'; + runname = 'SPINUP-EXICE_197906-198906_stratSamExice_rf1_sf1_maxSnow0.40_snowDens=200_wt10.0_extFlux0.0000_fc0.30_exice0.60_natPor0.40'; + number_of_realizations = 1; % %% load output data and settings from files of all workers dir = dirname;%'/home/jnitzbon/gls1/CryoGrid/CryoGrid3_infiltration_xice_mpi_DEV/'; - cm=load( [ dir 'cm_blueautumn.mat' ] ); + cm=load( [ 'cm_blueautumn.mat' ] ); infil=0; xice=0; @@ -24,7 +27,9 @@ function plot_output(dirname, runname, number_of_realizations) for i=1:number_of_realizations run = runname; %sprintf('testrun_mpi_waterExchange_noGroundHeatFlux_realization' ); - run = [ run num2str(i) ]; + if number_of_realizations>1 + run = [ run num2str(i) ]; + end outputfile = [dir run '/' run '_output.mat']; configfile = [dir run '/' run '_settings.mat']; @@ -50,7 +55,8 @@ function plot_output(dirname, runname, number_of_realizations) soilTop = {}; for i=1:number_of_realizations - zs{i} = OUTS{i}.PARA.ensemble.initial_altitude(i)-OUTS{i}.GRID.general.cT_grid; + %zs{i} = OUTS{i}.PARA.ensemble.initial_altitude(i)-OUTS{i}.GRID.general.cT_grid; + zs{i} = OUTS{i}.PARA.location.altitude-OUTS{i}.GRID.general.cT_grid; Ts{i} = OUTS{i}.OUT.cryoGrid3; LWCs{i} = OUTS{i}.OUT.liquidWater; WCs{i} = OUTS{i}.OUT.water; @@ -60,8 +66,8 @@ function plot_output(dirname, runname, number_of_realizations) %lakeFloor = [ NaN(length(soilTop)-length(lakeFloor),1); lakeFloor ]; % limits - minz = min(OUTS{1}.PARA.ensemble.initial_altitude - 4); - maxz = max(OUTS{1}.PARA.ensemble.initial_altitude + 0.5); + minz = min(OUTS{1}.PARA.location.altitude - 10); + maxz = max(OUTS{1}.PARA.location.altitude + 1); mint = min(ts); maxt = max(ts); @@ -69,65 +75,70 @@ function plot_output(dirname, runname, number_of_realizations) %% plot evolution of simple ensemlbe variables - figure; - - subplot(2,3,1) - hold on - for i=1:number_of_realizations - plot(ts, OUTS{1}.OUT.ensemble.active_layer_depth_altitude(:,i)) ; %abs(OUTS{1}.OUT.ensemble.altitude(:,i)- - end - datetick; - title('Frost table [m asl]') - hold off + if number_of_realizations>1 + + figure; - subplot(2,3,2) - hold on - for i=1:number_of_realizations - plot(ts, OUTS{1}.OUT.ensemble.water_table(:,i)); - end - datetick; - title('Water table [m asl]') - hold off + subplot(2,3,1) + hold on + for i=1:number_of_realizations + plot(ts, OUTS{1}.OUT.ensemble.active_layer_depth_altitude(:,i)) ; %abs(OUTS{1}.OUT.ensemble.altitude(:,i)- + end + datetick; + title('Frost table [m asl]') + hold off - subplot(2,3,3) - hold on - for i=1:number_of_realizations - plot(ts, OUTS{1}.OUT.ensemble.surface_altitude(:,i)); - end - datetick; - title('Surface altitude [m asl]') - hold off - - subplot(2,3,4) - hold on - for i=1:number_of_realizations - plot(ts, nansum(OUTS{i}.OUT.ensemble.heat_fluxes , 2)); - end - datetick; - title('Heat fluxes [ W / m^2 ]') - hold off + subplot(2,3,2) + hold on + for i=1:number_of_realizations + plot(ts, OUTS{1}.OUT.ensemble.water_table(:,i)); + end + datetick; + title('Water table [m asl]') + hold off - subplot(2,3,5) - hold on - for i=1:number_of_realizations - plot(ts, nansum(OUTS{i}.OUT.ensemble.water_fluxes .*1000 .* 3600 , 2)); - end - datetick; - title('Water fluxes [mm/h]') - hold off - - subplot(2,3,6) - hold on - for i=1:number_of_realizations - plot(ts, nansum(OUTS{i}.OUT.ensemble.snow_fluxes .*1000 .* 3600 , 2) ); + subplot(2,3,3) + hold on + for i=1:number_of_realizations + plot(ts, OUTS{1}.OUT.ensemble.surface_altitude(:,i)); + end + datetick; + title('Surface altitude [m asl]') + hold off + + subplot(2,3,4) + hold on + for i=1:number_of_realizations + plot(ts, nansum(OUTS{i}.OUT.ensemble.heat_fluxes , 2)); + end + datetick; + title('Heat fluxes [ W / m^2 ]') + hold off + + subplot(2,3,5) + hold on + for i=1:number_of_realizations + plot(ts, nansum(OUTS{i}.OUT.ensemble.water_fluxes .*1000 .* 3600 , 2)); + end + datetick; + title('Water fluxes [mm/h]') + hold off + + subplot(2,3,6) + hold on + for i=1:number_of_realizations + plot(ts, nansum(OUTS{i}.OUT.ensemble.snow_fluxes .*1000 .* 3600 , 2) ); + end + datetick; + title('Snow fluxes [mm/h]') + hold off + + currentFigure = gcf; + title(currentFigure.Children(end), runname); + end - datetick; - title('Snow fluxes [mm/h]') - hold off - - currentFigure = gcf; - title(currentFigure.Children(end), runname); + %% plot temperature and water content fields @@ -181,26 +192,33 @@ function plot_output(dirname, runname, number_of_realizations) end currentFigure = gcf; - title(currentFigure.Children(end), runname); - - %% plot temperature in 2m depth - - figure; - hold on; - - title(runname); + title(currentFigure.Children(end), runname); - depth = 2.0; - [val, idx] = min( abs(depth-OUTS{1}.GRID.general.cT_grid) ); - plot( ts', Ts{1}( idx , :) ); - plot( ts', Ts{2}( idx , :) ); + %% plot soil moisture and temperature of requested depth - axis( [mint maxt -20 0 ] ); + % request time series for a certain depths + requestedDepth = 0.3 ; - title(sprintf('Temperature in [°C] at z=%f', OUTS{1}.GRID.general.cT_grid(idx) )); + % get the altitude of the uppermost soil cell (which indeed contains + % mineral or organic material, i.e. excluding a potential waterbody) + soil_surface_altitude = OUTS{1}.PARA.location.altitude + min( OUTS{1}.OUT.soil.topPosition, OUTS{1}.OUT.soil.lakeFloor ); - hold off; + % the static altitude grid + altitude_grid = zs{1}; + % compute the index of the requested cell for each timestep + A = zeros( length(altitude_grid), length(soil_surface_altitude) ); % matrix to serach in + for j=1:size(A,2) %loop over all timesteps + A(:,j) = soil_surface_altitude(j)- altitude_grid; % distance of each grid cell (first dim) to the surface for each timestep (second dim) + end + [~, indexes] = min( abs( A - requestedDepth ) ); % determine index of closest cell to the requested depth - \ No newline at end of file + % transform column-wise index to linear index of whole matrix + linindexes = sub2ind( [length(altitude_grid),length(ts)], indexes, [1:1:length(ts)] ); + + figure; + plot( ts, LWCs{i}(linindexes) ); + + figure; + plot( ts, Ts{i}(linindexes) ); \ No newline at end of file diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 5563681..29c6432 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -170,7 +170,8 @@ %write output files if round((t-TEMPORARY.saveTime).*48)==0 - save([run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') + save(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') + save(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], 'T', 'wc', 'SEB', 'PARA', 'GRID') OUT = generateOUT(); TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(datestr(t,'mm')), str2num(datestr(t,'dd')), str2num(datestr(t,'HH')), str2num(datestr(t,'MM')), 0); end diff --git a/run_batch.m b/run_batch.m index 9550376..590f2ba 100644 --- a/run_batch.m +++ b/run_batch.m @@ -4,7 +4,7 @@ add_modules_function; startDate=datenum( 1979, 6, 1); -endDate=datenum( 1980, 6, 1); +endDate=datenum( 2014, 6, 1); rainFrac=1; snowFrac=1; @@ -85,8 +85,8 @@ disp( [ datestr(now) ': submitted job ' jobName ] ); -% wait(job); -% disp( [ datestr(now) ': finished job ' jobName ] ); +wait(job); +disp( [ datestr(now) ': finished job ' jobName ] ); % % for i=1:numTasks % diary( [ './runs/' tasks{i}.Name '/' tasks{i}.Name '_diary.txt' ] ); From 2e48b997c80ed7e5182ec897439aa35c38b43791 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Mon, 29 Jan 2018 15:51:00 +0100 Subject: [PATCH 10/45] major bugfix. now water contents below residualWC are prohibited. however, this may slighly violate the water balance. mismatches are tracked in BALANCE.water --- CryoGrid3.m | 32 +++++-- analysis/plot_output.m | 14 +-- .../CryoGridInfiltration.m | 4 +- .../bucketScheme.m | 13 ++- .../getET_fraction.m | 2 +- .../cryoGridInitialize/initializeBALANCE.m | 2 + .../initializeSoilThermalProperties.m | 94 +++++++++---------- modules/cryoGridTechnical/generateOUT.m | 1 + .../cryoGridTechnical/sum_up_output_store.m | 4 + 9 files changed, 95 insertions(+), 71 deletions(-) diff --git a/CryoGrid3.m b/CryoGrid3.m index 480d042..ed353d4 100755 --- a/CryoGrid3.m +++ b/CryoGrid3.m @@ -12,10 +12,11 @@ %addpath('./nansuite/') +dbstop if error; createLogFile=0; -spinupFile = [ './runs/TESTRUN_197906-197906_stratSam_rf1_sf1_maxSnow0.4_snowDens=200.0_wt0.0_extFlux0.0020_fc0.30/TESTRUN_197906-197906_stratSam_rf1_sf1_maxSnow0.4_snowDens=200.0_wt0.0_extFlux0.0020_fc0.30_finalState.mat' ]; +spinupFile = [ './runs/SPINUP-EXICE_197906-201406_stratSamExice_rf1_sf1_maxSnow0.40_snowDens=200_wt0.0_extFlux0.0000_fc0.30_exice0.60_natPor0.40/SPINUP-EXICE_197906-201406_stratSamExice_rf1_sf1_maxSnow0.40_snowDens=200_wt0.0_extFlux0.0000_fc0.30_exice0.60_natPor0.40_finalState2012.mat' ]; if isempty(spinupFile) @@ -106,8 +107,8 @@ PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.saveDate='01.08.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] %default grid used for publications and testing of water balance: @@ -216,7 +217,11 @@ else %take setting from spinup file load(spinupFile); % this loads T, wc, PARA, GRID, SEB from final state of spinup run + wc(wc 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) - warning( 'numerical stability not guaranteed' ); - end +% if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) +% warning( 'numerical stability not guaranteed' ); +% end %------ update T array ------------------------------------------------ T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; @@ -322,6 +329,11 @@ GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); end + assert( sum( sum( GRID.soil.capacity < 0 ) ) == 0, 'CryoGrid3 - negative entry in capacity LUT'); + + assert( sum( sum( GRID.soil.conductivity < 0 ) ) == 0, 'CryoGrid3 - negative entry in conductivity LUT'); + + %------- update Lstar for next time step ------------------------------ SEB = L_star(FORCING, PARA, SEB); diff --git a/analysis/plot_output.m b/analysis/plot_output.m index 6e60668..87cd51b 100644 --- a/analysis/plot_output.m +++ b/analysis/plot_output.m @@ -3,11 +3,11 @@ % %function plot_output(dirname, runname, number_of_realizations) -clear all +%clear all close all dirname = '../runs/'; - runname = 'SPINUP-EXICE_197906-198906_stratSamExice_rf1_sf1_maxSnow0.40_snowDens=200_wt10.0_extFlux0.0000_fc0.30_exice0.60_natPor0.40'; + runname = 'SPINUP-EXICE_197906-201406_stratSamExice_rf1_sf1_maxSnow0.40_snowDens=200_wt0.0_extFlux0.0000_fc0.30_exice0.60_natPor0.40'; number_of_realizations = 1; % @@ -15,7 +15,7 @@ dir = dirname;%'/home/jnitzbon/gls1/CryoGrid/CryoGrid3_infiltration_xice_mpi_DEV/'; - cm=load( [ 'cm_blueautumn.mat' ] ); + %cm=load( [ './analysis/cm_blueautumn.mat' ] ); infil=0; xice=0; @@ -30,7 +30,7 @@ if number_of_realizations>1 run = [ run num2str(i) ]; end - outputfile = [dir run '/' run '_output.mat']; + outputfile = [dir run '/' run '_output2012.mat']; configfile = [dir run '/' run '_settings.mat']; load(outputfile); @@ -66,8 +66,8 @@ %lakeFloor = [ NaN(length(soilTop)-length(lakeFloor),1); lakeFloor ]; % limits - minz = min(OUTS{1}.PARA.location.altitude - 10); - maxz = max(OUTS{1}.PARA.location.altitude + 1); + minz = min(OUTS{1}.PARA.location.altitude - 1); + maxz = max(OUTS{1}.PARA.location.altitude + 0.5); mint = min(ts); maxt = max(ts); @@ -172,7 +172,7 @@ % (liquid) water content fields for i=1:number_of_realizations subplot(2, number_of_realizations, number_of_realizations+i); - pcolor( ts', zs{i}', LWCs{i}); %ax, + pcolor( ts', zs{i}', WCs{i}); %ax, hold on; caxis( [ 0. , 1. ] ); colormap(gca, 'parula'); diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m index cd092a8..5f13b93 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m @@ -26,7 +26,7 @@ dwc_dt(1)=dwc_dt(1)+meltwaterGroundIce; % routing of water - [wc, surface_runoff] = bucketScheme(T, wc, dwc_dt, GRID, PARA, external_flux_rate.*timestep); + [wc, surface_runoff, lacking_water] = bucketScheme(T, wc, dwc_dt, GRID, PARA, external_flux_rate.*timestep); % consistency check if sum( wc<0 )~=0 @@ -61,7 +61,7 @@ % store remaining surface runoff BALANCE.water.dr_surface = BALANCE.water.dr_surface - surface_runoff*1000; % in [mm] - + BALANCE.water.d_lacking = BALANCE.water.d_lacking + lacking_water*1000; end diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m index 0706de8..8d28b11 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m @@ -1,16 +1,21 @@ -function [wc, surface_runoff]=bucketScheme(T, wc, dwc_dt, GRID, PARA, external_flux) +function [wc, surface_runoff, lacking_water]=bucketScheme(T, wc, dwc_dt, GRID, PARA, external_flux) T=T(GRID.soil.cT_domain); K_delta=GRID.general.K_delta(GRID.soil.cT_domain); %in m -porosity=1-GRID.soil.cT_mineral-GRID.soil.cT_organic; %in percent JAN: why not use GRID.soil.cT_natPor here? +porosity=1-GRID.soil.cT_mineral-GRID.soil.cT_organic; % A=sum(K_delta(1:30).*wc(1:30)+dwc_dt(1:30)) - +lacking_water=0; i=1; i_max=70; % maximum infiltration depth, must be defined somehow before while T(i)>0 && i<=i_max max_water=K_delta(i).*PARA.soil.fieldCapacity; %maximum amount of water (in m) that a grid cell can hold - actual_water=wc(i).*K_delta(i)+dwc_dt(i); % should be dwc (already multiplied with timestep) + min_water=K_delta(i).*PARA.soil.residualWC; %minimum amount of water which stays in a cell + + actual_water= max( min_water, wc(i).*K_delta(i)+dwc_dt(i) ); % should be dwc (already multiplied with timestep) %JAN: this violates the WB + + lacking_water = lacking_water + (wc(i).*K_delta(i)+dwc_dt(i)0).*min(1, max(0, (wc-zero_reached)./(start_reduction-zero_reached))); -fraction=double(T>0).*(double(wc>=start_reduction) + double(wc0).*(double(wc>=start_reduction) + double(wc wiltingPoint and residualWC have no effect currently \ No newline at end of file diff --git a/modules/cryoGridInitialize/initializeBALANCE.m b/modules/cryoGridInitialize/initializeBALANCE.m index 79d23c2..263c039 100644 --- a/modules/cryoGridInitialize/initializeBALANCE.m +++ b/modules/cryoGridInitialize/initializeBALANCE.m @@ -44,4 +44,6 @@ BALANCE.water.dr_lateralSnow=0; BALANCE.water.dr_rain=0; % this is only rain on frozen ground BALANCE.water.dr_lateral=0; + BALANCE.water.d_lacking=0; + end \ No newline at end of file diff --git a/modules/cryoGridSoil/initializeSoilThermalProperties.m b/modules/cryoGridSoil/initializeSoilThermalProperties.m index 19d7f50..b02bf4d 100644 --- a/modules/cryoGridSoil/initializeSoilThermalProperties.m +++ b/modules/cryoGridSoil/initializeSoilThermalProperties.m @@ -48,7 +48,6 @@ ch=mineral*c_m+organic*c_o+waterMin.*c_w+(water-waterMin)*c_i; -% JAN: Why the additional loop from -30 to -1??? --> determine cT_frozen %preallocate variable c_h2o=ones(length(a),length(-30:0.01:-1)); @@ -71,7 +70,8 @@ c_h2o(:,1) = L_si*rho_w* (freezeC(water, 1-mineral-organic, a, cT_frozen+deltaT/2, PARA)-freezeC(water, 1-mineral-organic, a, cT_frozen-deltaT/2, PARA))/deltaT(1,1); for i=1:arraySize-2 water_c(:,i+1) = freezeC(water, 1-mineral-organic, a, cT_thawed+(cT_frozen-cT_thawed)*(arraySize-2-i)/(arraySize-2), PARA); - ch(:,i+1) = mineral*c_m+organic*c_o+freezeC(water, 1-mineral-organic, a, cT_thawed+(cT_frozen-cT_thawed)*(arraySize-2-i)/(arraySize-2), PARA)*(c_w-c_i)+water*c_i; + ch(:,i+1) = mineral*c_m+organic*c_o+water_c(:,i+1)*(c_w-c_i)+water*c_i; + %ch(:,i+1) = mineral*c_m+organic*c_o+freezeC(water, 1-mineral-organic, a, cT_thawed+(cT_frozen-cT_thawed)*(arraySize-2-i)/(arraySize-2), PARA)*(c_w-c_i)+water*c_i; c_h2o(:,i+1) = L_si*rho_w*(freezeC(water, 1-mineral-organic, a, cT_thawed+(cT_frozen-cT_thawed)*(arraySize-2-i)/(arraySize-2)+deltaT/2, PARA)-freezeC(water, 1-mineral-organic, a, cT_thawed+(cT_frozen-cT_thawed)*(arraySize-2-i)/(arraySize-2)-deltaT/2, PARA))/deltaT(1,1); end @@ -97,28 +97,31 @@ %K_frozen=[cT_frozen(1,1); 0.5.*(cT_frozen(1:end-1,1)+cT_frozen(2:end,1)) ; cT_frozen(end,1)]; %K_thawed=zeros(size(a,1),1); -% changed to cT-grid since K- interpolation is done external now -water=cT_water; -mineral=cT_mineral; -organic=cT_organic; -a=cT_soilType; -K_frozen=cT_frozen; -K_thawed=cT_thawed; +% changed to cT-grid since K- interpolation is done external now +% water=cT_water; +% mineral=cT_mineral; +% organic=cT_organic; +% a=cT_soilType; +% +% K_frozen=cT_frozen; +% K_thawed=cT_thawed; +% +% %preallocate variables +% water_c2=ones(length(a),length(1:arraySize-2)+1); +% water_c2(:,1)=freezeC(water, 1-mineral-organic, a, K_frozen, PARA); % JAN: this is identical to water_c for -%preallocate variables -water_c=ones(length(a),length(1:arraySize-2)+1); -water_c(:,1)=freezeC(water, 1-mineral-organic, a, K_frozen, PARA); conductivity=water_c; -for i=1:arraySize-2 - water_c(:,i+1)=freezeC(water, 1-mineral-organic, a, K_thawed+(K_frozen-K_thawed)*(arraySize-2-i)/(arraySize-2), PARA); -end +% for i=1:arraySize-2 +% water_c2(:,i+1)=freezeC(water, 1-mineral-organic, a, K_thawed+(K_frozen-K_thawed)*(arraySize-2-i)/(arraySize-2), PARA); +% end +% +% assert( isequal(water_c, water_c2), 'initializeSoilThermalProperties - water_c not equal for cap and cond calculations'); + for i=1:size(a,1) ice_c=water(i,1)*ones(1,arraySize-1)-water_c(i,:); - %plot(water_c(i,:)') conductivity(i,:)=conductivity2(water_c(i,:), ice_c, mineral(i,1), organic(i,1), PARA); - %plot(heatcond(water_c(i,:)', ice_c, mineral(i,1), organic(i,1), 0, 0.15, 2)) end @@ -160,7 +163,7 @@ n=zeros(size(soilType)); - %set conditions for soil rypes + %set conditions for soil types thetaRes(soilType==1) = 0; alpha(soilType==1) = 4; n(soilType==1) = 2; @@ -168,40 +171,13 @@ thetaRes(soilType==2) = 0.05; alpha(soilType==2) = 0.65; n(soilType==2) = 1.7; - - - % thetaTot=0.2; - % thetaSat=0.5; - % thetaRes=0.05; - % alpha=0.15; %units meter - % n=1.25; + m=1-1./n; waterPotZero=-1./alpha .*( ((thetaTot-thetaRes)./(thetaSat-thetaRes) ).^(-1./m) -1 ).^(1./n); %Tstar=273.15+9.81.*273.15./3.34e5.*waterPotZero; Tstar = 273.15 + PARA.constants.g .* 273.15 ./ PARA.constants.L_sl .* waterPotZero; waterC=zeros(size(T)); - % for i=1:size(soilType,1) - % if T(i)>=273.15 - % waterC(i,1)=thetaTot(i,1); - % else - % - % if T(i,1)>273.1 - % - % - % waterPot=waterPotZero(i,1)+(3.34e5./9.81./Tstar(i,1).*(273.1-Tstar(i,1))).*(273.1=273.15) = thetaTot(T>=273.15); @@ -220,10 +196,34 @@ waterPot(T<=273.1)= waterPotZero(T<=273.1)+(3.34e5./9.81./Tstar(T<=273.1).*(T(T<=273.1)-Tstar(T<=273.1))).*(T(T<=273.1)=273.15 + % waterC(i,1)=thetaTot(i,1); + % else + % + % if T(i,1)>273.1 + % + % + % waterPot=waterPotZero(i,1)+(3.34e5./9.81./Tstar(i,1).*(273.1-Tstar(i,1))).*(273.1 Date: Tue, 30 Jan 2018 23:27:29 +0100 Subject: [PATCH 11/45] NOT TESTED! included lateral exchange module to xice branch version. restructuring of lateral exchange part with wrapper functions. all functions which are not in modules/cryoGridLateral should also work for single-column version. introduced PARA.soil.soilTypes to handle soil properties including freezeCurve and fieldCapacity. all changes outside lateral module should be integrable into single-column-versions. --- CryoGrid3.m | 360 ------------- CryoGrid3_function_spinup.m | 305 ----------- CryoGrid3_function_variableExice.m | 308 ----------- CryoGrid3_xice_mpi.m | 489 ++++++++++++++++++ add_modules.m | 14 +- add_modules_function.m | 17 - .../CryoGridInfiltration.m | 23 +- .../bucketScheme.m | 29 +- .../updateGRID_infiltration.m | 18 +- .../excessGroundIceInfiltration.m | 2 +- .../excessGroundIceThaw4Infiltration.m | 88 +--- .../updateGRID_excessiceInfiltration2.m | 13 +- .../cryoGridInitialize/generateTemporary.m | 11 +- .../cryoGridInitialize/initializeBALANCE.m | 4 +- .../cryoGridLateral/applyLateralSnowFluxes.m | 78 +++ .../calculateLateralHeatFluxes.m | 52 ++ .../calculateLateralSnowFluxes.m | 49 ++ .../calculateLateralSnowFluxes2.m | 15 + .../calculateLateralWaterFluxes.m | 145 ++++++ .../calculateTerrainIndexSnow.m | 22 + .../checkPreconditionSnowExchange.m | 16 + .../checkPreconditionWaterExchange.m | 17 + modules/cryoGridLateral/getMaxSnowAltitude.m | 3 + modules/cryoGridLateral/getMaxWaterAltitude.m | 3 + .../cryoGridLateral/get_parallel_variables.m | 78 +++ ...ateAuxiliaryVariablesAndCommonThresholds.m | 35 ++ modules/cryoGridSEB/L_star.m | 6 +- modules/cryoGridSnow/CryoGridSnow.m | 17 +- modules/cryoGridSnow/updateGRID_snow.m | 2 +- modules/cryoGridSoil/createStratigraphy.m | 8 +- .../initializeSoilThermalProperties.m | 74 +-- modules/cryoGridTechnical/generateOUT.m | 53 +- .../getActiveLayerDepthAltitude.m | 17 + modules/cryoGridTechnical/getAltitude.m | 5 + .../cryoGridTechnical/getSurfaceAltitude.m | 10 + .../cryoGridTechnical/getWaterTableAltitude.m | 24 + modules/cryoGridTechnical/iSaveOUT.m | 3 + modules/cryoGridTechnical/iSaveSettings.m | 3 + modules/cryoGridTechnical/iSaveState.m | 3 + modules/cryoGridTechnical/loadSoilTypes.m | 7 + .../cryoGridTechnical/sum_up_output_store.m | 156 +++--- 41 files changed, 1284 insertions(+), 1298 deletions(-) delete mode 100755 CryoGrid3.m delete mode 100755 CryoGrid3_function_spinup.m delete mode 100755 CryoGrid3_function_variableExice.m create mode 100755 CryoGrid3_xice_mpi.m delete mode 100644 add_modules_function.m create mode 100644 modules/cryoGridLateral/applyLateralSnowFluxes.m create mode 100644 modules/cryoGridLateral/calculateLateralHeatFluxes.m create mode 100644 modules/cryoGridLateral/calculateLateralSnowFluxes.m create mode 100644 modules/cryoGridLateral/calculateLateralSnowFluxes2.m create mode 100644 modules/cryoGridLateral/calculateLateralWaterFluxes.m create mode 100644 modules/cryoGridLateral/calculateTerrainIndexSnow.m create mode 100644 modules/cryoGridLateral/checkPreconditionSnowExchange.m create mode 100644 modules/cryoGridLateral/checkPreconditionWaterExchange.m create mode 100644 modules/cryoGridLateral/getMaxSnowAltitude.m create mode 100644 modules/cryoGridLateral/getMaxWaterAltitude.m create mode 100644 modules/cryoGridLateral/get_parallel_variables.m create mode 100644 modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m create mode 100644 modules/cryoGridTechnical/getActiveLayerDepthAltitude.m create mode 100644 modules/cryoGridTechnical/getAltitude.m create mode 100644 modules/cryoGridTechnical/getSurfaceAltitude.m create mode 100644 modules/cryoGridTechnical/getWaterTableAltitude.m create mode 100644 modules/cryoGridTechnical/iSaveOUT.m create mode 100644 modules/cryoGridTechnical/iSaveSettings.m create mode 100644 modules/cryoGridTechnical/iSaveState.m create mode 100644 modules/cryoGridTechnical/loadSoilTypes.m diff --git a/CryoGrid3.m b/CryoGrid3.m deleted file mode 100755 index ed353d4..0000000 --- a/CryoGrid3.m +++ /dev/null @@ -1,360 +0,0 @@ -% ------------------------------------------------------------------------- -% CryoGRID3 -% main script for running the model -% -% Developed by: S. Westermann and M. Langer 2015 -% -% ------------------------------------------------------------------------- - -paraFromFile = exist('configFile'); % check if config file passed - -add_modules; %adds required modules - -%addpath('./nansuite/') - -dbstop if error; - -createLogFile=0; - -spinupFile = [ './runs/SPINUP-EXICE_197906-201406_stratSamExice_rf1_sf1_maxSnow0.40_snowDens=200_wt0.0_extFlux0.0000_fc0.30_exice0.60_natPor0.40/SPINUP-EXICE_197906-201406_stratSamExice_rf1_sf1_maxSnow0.40_snowDens=200_wt0.0_extFlux0.0000_fc0.30_exice0.60_natPor0.40_finalState2012.mat' ]; - -if isempty(spinupFile) - - - %---------------define input parameters------------------------------------ - % here you provide the ground stratigraphy - % z w/i m o type porosity - - %default used in publication: - PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 0.65 0.3 0.05 2 0.65;... - 0.9 0.65 0.3 0.05 1 0.65;... - 9.0 0.30 0.70 0.00 1 0.30 ]; - - %simple stratigraphy with excess ice used to test water balance: - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... - % 0.4 0.8 0.2 0.00 1 0.40;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - %very simply stratigraphy without excess ice used to test energy balance - % soilType = 1; - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... - % 1.0 0.5 0.5 0.00 1 0.5 ;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - % soil stratigraphy - % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer - % extends until the end of the model domain - % column 2: volumetric water+ice content - % column 3: volumetric mineral content - % column 4: volumetric organic content - % column 5: code for soil type: 1: sand, 2: silt - % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs - - %------ model parameters -------------------------------------------------- - PARA.soil.albedo=0.2; % albedo snow-free surface - PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development - PARA.soil.epsilon=0.97; % emissvity snow-free surface - PARA.soil.z0=1e-3; % roughness length [m] snow-free surface - PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface - PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] - PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] - - % parameters related to hydrology scheme - PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! - PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries - PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries - PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off - PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation - PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. - PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] - PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible - PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile - PARA.soil.waterTable=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up - - % parameters related to snow - PARA.snow.max_albedo=0.85; % albedo of fresh snow - PARA.snow.min_albedo=0.5; % albedo of old snow - PARA.snow.epsilon=0.99; % surface emissivity snow - PARA.snow.z0=5e-4; % roughness length surface [m] - PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow - PARA.snow.rho_snow=200.0; % density in [kg/m3] - PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] - PARA.snow.tau_a=0.008; % [per day] - PARA.snow.tau_f=0.24; % [per day] - PARA.snow.maxSnow= [0.4] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold - PARA.snow.extinction=25.0; % light extinction coefficient of snow - - % parameters related to water body on top of soil domain - PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) - PARA.water.epsilon=0.99; % surface emissivity water - PARA.water.rs=0.0; % surface resistance -> should be 0 for water - PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation - - PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 - PARA.ice.epsilon=0.98; % surface emissivity snow - PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice - PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow - PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 - - PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given - - PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases - PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells - PARA.technical.maxSWE=0.4; % in [m] SWE - PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1979, 6, 15); % endtime of the simulation - if empty end at last value of time series - PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds - PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds - PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K - PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year - PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] - - %default grid used for publications and testing of water balance: - PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - - %very simple grid used for testing of energy balance: - %PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; - - %initial temperature profile -> first column depth [m] -> second column temperature [degree C] - %default: - PARA.Tinitial = [ -2 5 ;... - 0 0 ;... - 2 -5 ;... - 10 -10 ;... - 25 -9 ;... - 100 -9 ;... - 2000 10 ]; - - PARA = loadConstants( PARA ); - - - %FORCING data mat-file - PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files - PARA.forcing.rain_fraction=1; - PARA.forcing.snow_fraction=1; - - % switches for modules - PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs - PARA.modules.xice=1; % true if thaw subsicdence is enabled - - % ------update parameter values if config file provided ------------------- - % ------changes output directory to name specified in configfile which is - % the config filename by default - if paraFromFile - run(configFile); - end - - - run_number = sprintf( [ 'TESTRUN_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... - [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... - PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); - - % ------make output directory (name depends on parameters) ---------------- - mkdir(['./runs/' run_number]) - - - % ------redirect command line output to logfile --------------------------- - if createLogFile - diary(['./runs/' run_number '/' run_number '_diary.txt']); - end - - - %-------------------------------------------------------------------------- - %-----------do not modify from here onwards-------------------------------- - %-------------------------------------------------------------------------- - [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file - - if ~success - warning('A problem with the Forcing occured.'); - end - clear success - - PARA = initializeParameters(PARA, FORCING); %set start time, etc. - - %----------------create and initialize the grids -------------------------- - GRID=makeGrids(PARA); %create all grids - GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid - - %----- initializie excess ground ice -------------------------------------- - [GRID,PARA] = initializeExcessIce2(GRID,PARA); - - %----- initializie soil thermal properties -------------------------------- - GRID = initializeSoilThermalProperties(GRID, PARA); - - %------ initializie snow properties---------------------------------------- - GRID = initializeSnow(GRID); - - %---- initialize the surface energy balance struct ------------------------ - SEB = initializeSEB(); - - %---- initialize the water body module ------------------------------------ - GRID = initializeLAKE(GRID); - - %---- initialize temperature profile -------------------------------------- - T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); - - %---- modification for infiltration - wc=GRID.soil.cT_water; - GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; - GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; - - %---- preallocate temporary arrays for capacity and conductivity----------- - [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid - - %---- energy and water balance initialization ----------------------------- - BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); - - %__________________________________________________________________________ - %-------- provide arrays for data storage --------------------------------- - [t, TEMPORARY] = generateTemporary(T, PARA); - OUT = generateOUT(); - - disp('initialization successful'); - save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') - -else %take setting from spinup file - load(spinupFile); % this loads T, wc, PARA, GRID, SEB from final state of spinup run - wc(wc 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) -% warning( 'numerical stability not guaranteed' ); -% end - - %------ update T array ------------------------------------------------ - T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; - T(GRID.air.cT_domain)=FORCING.i.Tair; %set grid cells in air to air temperature - - %------- water body module -------------------------------------------- - T = mixingWaterBody(T, GRID); - - %------- snow cover module -------------------------------------------- - [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); - - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - - %------- infiltration module------------------------------------------- - if PARA.modules.infiltration - [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); - end - - %------- excess ice module -------------------------------------------- - if PARA.modules.xice && ~PARA.modules.infiltration - warning( 'energy and water balances are not correct for this combination of modules'); - [GRID, PARA] = excessGroundIce(T, GRID, PARA); - % assure wc has correct length - wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); - elseif PARA.modules.xice && PARA.modules.infiltration - [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); - GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); - end - - assert( sum( sum( GRID.soil.capacity < 0 ) ) == 0, 'CryoGrid3 - negative entry in capacity LUT'); - - assert( sum( sum( GRID.soil.conductivity < 0 ) ) == 0, 'CryoGrid3 - negative entry in conductivity LUT'); - - - %------- update Lstar for next time step ------------------------------ - SEB = L_star(FORCING, PARA, SEB); - - %------- water balance calculations ----------------------------------- - % rainfall - BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval - % snowfall - BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval - - %------- next time step ----------------------------------------------- - t=t+timestep; - %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number); - -end -%profile off -save(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') -save(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], 'T', 'wc', 'SEB', 'PARA', 'GRID') - - -disp('Done.'); -if createLogFile - diary off; -end diff --git a/CryoGrid3_function_spinup.m b/CryoGrid3_function_spinup.m deleted file mode 100755 index cd07268..0000000 --- a/CryoGrid3_function_spinup.m +++ /dev/null @@ -1,305 +0,0 @@ -function CryoGrid3_function_spinup( taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity ) - -% ------------------------------------------------------------------------- - % CryoGRID3 - % main script for running the model - % - % Developed by: S. Westermann and M. Langer 2015 - % - % ------------------------------------------------------------------------- - - paraFromFile = exist('configFile'); % check if config file passed - - %add_modules_function; %adds required modules - %add_modules; - - createLogFile=0; - - %---------------define input parameters------------------------------------ - % here you provide the ground stratigraphy - % z w/i m o type porosity - - %default used in publication: - PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 0.65 0.30 0.05 2 0.65;... - 0.9 0.65 0.30 0.05 1 0.65;... - 9.0 0.30 0.70 0.00 1 0.30 ]; - %simple stratigraphy with excess ice used to test water balance: - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... - % 0.4 0.8 0.2 0.00 1 0.40;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - %very simply stratigraphy without excess ice used to test energy balance - % soilType = 1; - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... - % 1.0 0.5 0.5 0.00 1 0.5 ;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - % soil stratigraphy - % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer - % extends until the end of the model domain - % column 2: volumetric water+ice content - % column 3: volumetric mineral content - % column 4: volumetric organic content - % column 5: code for soil type: 1: sand, 2: silt - % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs - - %------ model parameters -------------------------------------------------- - PARA.soil.albedo=0.2; % albedo snow-free surface - PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development - PARA.soil.epsilon=0.97; % emissvity snow-free surface - PARA.soil.z0=1e-3; % roughness length [m] snow-free surface - PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface - PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] - PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] - - % parameters related to hydrology scheme - PARA.soil.fieldCapacity=fieldCapacity; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! - PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries - PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries - PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off - PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation - PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. - PARA.soil.externalWaterFlux=extFlux;%-2e-3; %external water flux / drainage in [m/day] - PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible - PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile - PARA.soil.waterTable=waterTable; % depth at which a water table will form [m] - above excess water is removed, below it pools up - - % parameters related to snow - PARA.snow.max_albedo=0.85; % albedo of fresh snow - PARA.snow.min_albedo=0.5; % albedo of old snow - PARA.snow.epsilon=0.99; % surface emissivity snow - PARA.snow.z0=5e-4; % roughness length surface [m] - PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow - PARA.snow.rho_snow=snowDens; % density in [kg/m3] - PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] - PARA.snow.tau_a=0.008; % [per day] - PARA.snow.tau_f=0.24; % [per day] - PARA.snow.maxSnow= [maxSnow] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold - PARA.snow.extinction=25.0; % light extinction coefficient of snow - - % parameters related to water body on top of soil domain - PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) - PARA.water.epsilon=0.99; % surface emissivity water - PARA.water.rs=0.0; % surface resistance -> should be 0 for water - PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation - - PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 - PARA.ice.epsilon=0.98; % surface emissivity snow - PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice - PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow - PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 - - PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given - - PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases - PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells - PARA.technical.maxSWE=0.4; % in [m] SWE - PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=startDate; % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=endDate; % endtime of the simulation - if empty end at last value of time series - PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds - PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds - PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K - PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year - PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] - - %default grid used for publications and testing of water balance: - PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - %very simple grid used for testing of energy balance: - %PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; - - %initial temperature profile -> first column depth [m] -> second column temperature [degree C] - %default: - PARA.Tinitial = [ -2 5 ;... - 0 0 ;... - 2 -5 ;... - 10 -10 ;... - 25 -9 ;... - 100 -9 ;... - 2000 10 ]; - - - PARA = loadConstants( PARA ); - - - %FORCING data mat-file - PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files - PARA.forcing.rain_fraction=rainFrac; - PARA.forcing.snow_fraction=snowFrac; - - % switches for modules - PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs - PARA.modules.xice=1; % true if thaw subsicdence is enabled - - % ------update parameter values if config file provided ------------------- - % ------changes output directory to name specified in configfile which is - % the config filename by default - if paraFromFile - run(configFile); - end - -% run_number = sprintf( [ 'spinup_' datestr( startDate, 'yyyymm' ) '-' datestr( endDate, 'yyyymm' ) '_stratSam_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f' ], ... -% [ PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, PARA.snow.maxSnow, PARA.snow.rho_snow, ... -% PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity ] ); - - run_number = taskName; - - % ------make output directory (name depends on parameters) ---------------- - mkdir(['./runs/' run_number]); - - % ------redirect command line output to logfile --------------------------- - if createLogFile - diary(['./runs/' run_number '/' run_number '_diary.txt']); - end - - - %-------------------------------------------------------------------------- - %-----------do not modify from here onwards-------------------------------- - %-------------------------------------------------------------------------- - [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file - - if ~success - warning('A problem with the Forcing occured.'); - end - clear success - - PARA = initializeParameters(PARA, FORCING); %set start time, etc. - - %----------------create and initialize the grids -------------------------- - GRID=makeGrids(PARA); %create all grids - GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid - - %----- initializie excess ground ice -------------------------------------- - [GRID,PARA] = initializeExcessIce2(GRID,PARA); - - %----- initializie soil thermal properties -------------------------------- - GRID = initializeSoilThermalProperties(GRID, PARA); - - %------ initializie snow properties---------------------------------------- - GRID = initializeSnow(GRID); - - %---- initialize the surface energy balance struct ------------------------ - SEB = initializeSEB(); - - %---- initialize the water body module ------------------------------------ - GRID = initializeLAKE(GRID); - - %---- initialize temperature profile -------------------------------------- - T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); - - %---- modification for infiltration - wc=GRID.soil.cT_water; - GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; - GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; - - %---- preallocate temporary arrays for capacity and conductivity----------- - [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid - - %---- energy and water balance initialization ----------------------------- - BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); - - %__________________________________________________________________________ - %-------- provide arrays for data storage --------------------------------- - [t, TEMPORARY] = generateTemporary(T, PARA); - OUT = generateOUT(); - - disp('initialization successful'); - save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') - - %% ________________________________________________________________________ - % Time Integration Routine I - % I - %_________________________________________________________________________I - - while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) - warning( 'numerical stability not guaranteed' ); - end - - %------ update T array ------------------------------------------------ - T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; - T(GRID.air.cT_domain)=FORCING.i.Tair; %set grid cells in air to air temperature - - %------- water body module -------------------------------------------- - T = mixingWaterBody(T, GRID); - - %------- snow cover module -------------------------------------------- - [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - - - %------- infiltration module------------------------------------------- - if PARA.modules.infiltration - [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); - end - - %------- excess ice module -------------------------------------------- - if PARA.modules.xice && ~PARA.modules.infiltration - warning( 'energy and water balances are not correct for this combination of modules'); - [GRID, PARA] = excessGroundIce(T, GRID, PARA); - % assure wc has correct length - wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); - elseif PARA.modules.xice && PARA.modules.infiltration - [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); - GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); - end - - %------- update Lstar for next time step ------------------------------ - SEB = L_star(FORCING, PARA, SEB); - - - - %------- water balance calculations ----------------------------------- - % rainfall - BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval - % snowfall - BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval - - %------- next time step ----------------------------------------------- - t=t+timestep; - %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number); - - end - %profile off - save(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') - save(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], 'T', 'wc', 'SEB', 'PARA', 'GRID') - - - disp('Done.'); diff --git a/CryoGrid3_function_variableExice.m b/CryoGrid3_function_variableExice.m deleted file mode 100755 index be21506..0000000 --- a/CryoGrid3_function_variableExice.m +++ /dev/null @@ -1,308 +0,0 @@ -function [] = CryoGrid3_function_variableExice( taskName, startDate, endDate, rainFrac, snowFrac, waterTable, maxSnow, snowDens, extFlux, fieldCapacity, exice, natPor ) - - % ------------------------------------------------------------------------- - % CryoGRID3 - % main script for running the model - % - % Developed by: S. Westermann and M. Langer 2015 - % - % ------------------------------------------------------------------------- - - paraFromFile = exist('configFile'); % check if config file passed - - %add_modules_function; %adds required modules - %add_modules; - - createLogFile=0; - - %---------------define input parameters------------------------------------ - % here you provide the ground stratigraphy - % z w/i m o type porosity - - theta_o=0.05; - theta_w=exice; - theta_m=1-theta_w-theta_o; - - %default used in publication: - PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 theta_w theta_m theta_o 2 natPor;... - 0.9 theta_w theta_m theta_o 1 natPor;... - 9.0 0.30 0.70 0.00 1 0.30 ]; - %simple stratigraphy with excess ice used to test water balance: - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... - % 0.4 0.8 0.2 0.00 1 0.40;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - %very simply stratigraphy without excess ice used to test energy balance - % soilType = 1; - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... - % 1.0 0.5 0.5 0.00 1 0.5 ;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - % soil stratigraphy - % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer - % extends until the end of the model domain - % column 2: volumetric water+ice content - % column 3: volumetric mineral content - % column 4: volumetric organic content - % column 5: code for soil type: 1: sand, 2: silt - % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs - - %------ model parameters -------------------------------------------------- - PARA.soil.albedo=0.2; % albedo snow-free surface - PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development - PARA.soil.epsilon=0.97; % emissvity snow-free surface - PARA.soil.z0=1e-3; % roughness length [m] snow-free surface - PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface - PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] - PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] - - % parameters related to hydrology scheme - PARA.soil.fieldCapacity=fieldCapacity; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! - PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries - PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries - PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off - PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation - PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. - PARA.soil.externalWaterFlux=extFlux;%-2e-3; %external water flux / drainage in [m/day] - PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible - PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile - PARA.soil.waterTable=waterTable; % depth at which a water table will form [m] - above excess water is removed, below it pools up - - % parameters related to snow - PARA.snow.max_albedo=0.85; % albedo of fresh snow - PARA.snow.min_albedo=0.5; % albedo of old snow - PARA.snow.epsilon=0.99; % surface emissivity snow - PARA.snow.z0=5e-4; % roughness length surface [m] - PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow - PARA.snow.rho_snow=snowDens; % density in [kg/m3] - PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] - PARA.snow.tau_a=0.008; % [per day] - PARA.snow.tau_f=0.24; % [per day] - PARA.snow.maxSnow= [maxSnow] ;%0.2 % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold - PARA.snow.extinction=25.0; % light extinction coefficient of snow - - % parameters related to water body on top of soil domain - PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) - PARA.water.epsilon=0.99; % surface emissivity water - PARA.water.rs=0.0; % surface resistance -> should be 0 for water - PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation - - PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 - PARA.ice.epsilon=0.98; % surface emissivity snow - PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice - PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow - PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 - - PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given - - PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases - PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells - PARA.technical.maxSWE=0.4; % in [m] SWE - PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=startDate; % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=endDate; % endtime of the simulation - if empty end at last value of time series - PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds - PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds - PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K - PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year - PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] - - %default grid used for publications and testing of water balance: - %PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - % use finer grid in upper 10 m to ensure correct evapotranspiration in case of subsidence - PARA.technical.subsurfaceGrid = [[0:0.02:5], [5.1:0.1:15], [15.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - - %very simple grid used for testing of energy balance: - %PARA.technical.subsurfaceGrid = [ [0:0.02:2] ]'; - - %initial temperature profile -> first column depth [m] -> second column temperature [degree C] - %default: - PARA.Tinitial = [ -2 5 ;... - 0 0 ;... - 2 -5 ;... - 10 -10 ;... - 25 -9 ;... - 100 -9 ;... - 2000 10 ]; - - - PARA = loadConstants( PARA ); - - - %FORCING data mat-file - PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files - PARA.forcing.rain_fraction=rainFrac; - PARA.forcing.snow_fraction=snowFrac; - - % switches for modules - PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs - PARA.modules.xice=1; % true if thaw subsicdence is enabled - - % ------update parameter values if config file provided ------------------- - % ------changes output directory to name specified in configfile which is - % the config filename by default - if paraFromFile - run(configFile); - end - -% run_number = sprintf('spinup_%d-%d_stratSamExice_rf%d_sf%d_maxSnow%0.1f_snowDens=%0.1f_wt%0.1f_extFlux%0.4f_fc%0.2f_exice%0.2f_natPor%0.2f', ... -% [ startYear, endYear, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, ... -% PARA.snow.maxSnow, PARA.snow.rho_snow, PARA.soil.waterTable, PARA.soil.externalWaterFlux, PARA.soil.fieldCapacity, exice, natPor ]); - - run_number = taskName; - - % ------make output directory (name depends on parameters) ---------------- - mkdir(['./runs/' run_number]) - - % ------redirect command line output to logfile --------------------------- - if createLogFile - diary(['./runs/' run_number '/' run_number '_diary.log']); - end - - - %-------------------------------------------------------------------------- - %-----------do not modify from here onwards-------------------------------- - %-------------------------------------------------------------------------- - [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file - - if ~success - warning('A problem with the Forcing occured.'); - end - clear success - - PARA = initializeParameters(PARA, FORCING); %set start time, etc. - - %----------------create and initialize the grids -------------------------- - GRID=makeGrids(PARA); %create all grids - GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid - - %----- initializie excess ground ice -------------------------------------- - [GRID,PARA] = initializeExcessIce2(GRID,PARA); - - %----- initializie soil thermal properties -------------------------------- - GRID = initializeSoilThermalProperties(GRID, PARA); - - %------ initializie snow properties---------------------------------------- - GRID = initializeSnow(GRID); - - %---- initialize the surface energy balance struct ------------------------ - SEB = initializeSEB(); - - %---- initialize the water body module ------------------------------------ - GRID = initializeLAKE(GRID); - - %---- initialize temperature profile -------------------------------------- - T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); - - %---- modification for infiltration - wc=GRID.soil.cT_water; - GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; - GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; - - %---- preallocate temporary arrays for capacity and conductivity----------- - [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid - - %---- energy and water balance initialization ----------------------------- - BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); - - %__________________________________________________________________________ - %-------- provide arrays for data storage --------------------------------- - [t, TEMPORARY] = generateTemporary(T, PARA); - OUT = generateOUT(); - - disp('initialization successful'); - save([ './runs/' run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') - - %% ________________________________________________________________________ - % Time Integration Routine I - % I - %_________________________________________________________________________I - - while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) -% warning( 'numerical stability not guaranteed' ); -% end - - %------ update T array ------------------------------------------------ - T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; - T(GRID.air.cT_domain)=FORCING.i.Tair; %set grid cells in air to air temperature - - %------- water body module -------------------------------------------- - T = mixingWaterBody(T, GRID); - - %------- snow cover module -------------------------------------------- - [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - - %------- infiltration module------------------------------------------- - if PARA.modules.infiltration - [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE); - end - - %------- excess ice module -------------------------------------------- - if PARA.modules.xice && ~PARA.modules.infiltration - warning( 'energy and water balances are not correct for this combination of modules'); - [GRID, PARA] = excessGroundIce(T, GRID, PARA); - % assure wc has correct length - wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); - elseif PARA.modules.xice && PARA.modules.infiltration - [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); - GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); - end - - %------- update Lstar for next time step ------------------------------ - SEB = L_star(FORCING, PARA, SEB); - - %------- water balance calculations ----------------------------------- - % rainfall - BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval - % snowfall - BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval - - %------- next time step ----------------------------------------------- - t=t+timestep; - %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number); - - end - %profile off - save(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') - save(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], 'T', 'wc', 'SEB', 'PARA', 'GRID') - - disp('Done.'); diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m new file mode 100755 index 0000000..444ac90 --- /dev/null +++ b/CryoGrid3_xice_mpi.m @@ -0,0 +1,489 @@ +% ------------------------------------------------------------------------- +% CryoGRID3 +% main script for running the model +% +% Developed by: S. Westermann and M. Langer 2015 +% +% ------------------------------------------------------------------------- + +delete(gcp('nocreate')) % useful to restart from a crash + +add_modules; %adds required modules + +dbstop if error; + +number_of_realizations=2; + +if number_of_realizations>1 + parpool(number_of_realizations); +end + +spmd + index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run + + %---------------define input parameters------------------------------------ + % here you provide the ground stratigraphy + % z w/i m o type porosity + + % default stratigraphy used in publication: + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + % simple stratigraphy with excess ice used to test water balance: + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... + % 0.4 0.8 0.2 0.00 1 0.40;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % very simply stratigraphy without excess ice used to test energy balance + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... + % 1.0 0.5 0.5 0.00 1 0.5 ;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer + % extends until the end of the model domain + % column 2: volumetric water+ice content + % column 3: volumetric mineral content + % column 4: volumetric organic content + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + %------ model parameters -------------------------------------------------- + % parameters related to soil + PARA.soil.albedo=0.2; % albedo snow-free surface + PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development + PARA.soil.epsilon=0.97; % emissvity snow-free surface + PARA.soil.z0=1e-3; % roughness length [m] snow-free surface + PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface + PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] + PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + + % parameters related to hydrology scheme + PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries + PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation + PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. + PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] + PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible + PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile + PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up + PARA = loadSoilTypes(); + + % parameters related to snow + PARA.snow.max_albedo=0.85; % albedo of fresh snow + PARA.snow.min_albedo=0.5; % albedo of old snow + PARA.snow.epsilon=0.99; % surface emissivity snow + PARA.snow.z0=5e-4; % roughness length surface [m] + PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow + PARA.snow.rho_snow=200.0; % density in [kg/m3] + PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] + PARA.snow.tau_a=0.008; % [per day] + PARA.snow.tau_f=0.24; % [per day] + PARA.snow.relative_maxSnow= [0.1]; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.extinction=25.0; % light extinction coefficient of snow + + % parameters related to water body on top of soil domain + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.epsilon=0.99; % surface emissivity water + PARA.water.rs=0.0; % surface resistance -> should be 0 for water + PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation + + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + PARA.ice.epsilon=0.98; % surface emissivity snow + PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice + PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow + PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases + PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells + PARA.technical.maxSWE=0.4; % in [m] SWE + PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity + PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(1979, 6, 15); % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds + PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds + PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.syncTimestep = 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + + %default grid used for publications and testing of water balance: + PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + + PARA.location.initial_altitude=20.0; + % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" + PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain + PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow + PARA.location.active_layer_depth_altitude = nan; % defined at runtime + PARA.location.water_table_altitude = nan; % defined at runtime + % thresholds + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.waterTable; + if isempty( PARA.snow.relative_maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.maxSnow ]; + end + + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... + 2000 10 ]; + + PARA = loadConstants( PARA ); + + %FORCING data mat-file + PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.rain_fraction=1; + PARA.forcing.snow_fraction=1; + + % switches for modules + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=1; % true if thaw subsicdence is enabled + PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) + + if PARA.modules.lateral + % switches for lateral processes + PARA.modules.exchange_heat = 1; + PARA.modules.exchange_water = 1; + PARA.modules.exchange_snow = 1; + + %---------overwrites variables for each realization-------------------- + % this function must define everything that is realization-specific or dependent of all realizations + PARA = get_parallel_variables( PARA ); + end + + % ------make output directory (name depends on parameters) ---------------- + run_number= sprintf( 'testrunMPI_POOL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%f_sF%f_realization%d' , ... + [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... + PARA.modules.infiltration, PARA.modules.xice, ... + PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , ... + index ] ); + + mkdir(['./runs/' run_number]) + + %-------------------------------------------------------------------------- + %-----------do not modify from here onwards-------------------------------- + %-------------------------------------------------------------------------- + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + + if ~success + warning('A problem with the Forcing occured.'); + end + + PARA = initializeParameters(PARA, FORCING); %set start time, etc. + + %----------------create and initialize the grids -------------------------- + GRID=makeGrids(PARA); %create all grids + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + + %----- initializie excess ground ice -------------------------------------- + [GRID,PARA] = initializeExcessIce2(GRID,PARA); + + %----- initializie soil thermal properties -------------------------------- + GRID = initializeSoilThermalProperties(GRID, PARA); + + %------ initializie snow properties---------------------------------------- + GRID = initializeSnow(GRID); + + %---- initialize the surface energy balance struct ------------------------ + SEB = initializeSEB(); + + %---- initialize the water body module ------------------------------------ + GRID = initializeLAKE(GRID); + + %---- initialize temperature profile -------------------------------------- + T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); + + %---- modification for infiltration + wc=GRID.soil.cT_water; + GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; + GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; + + %---- preallocate temporary arrays for capacity and conductivity----------- + [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid + + %---- energy and water balance initialization ----------------------------- + BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); + + %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? + water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index + snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index + heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index + + %__________________________________________________________________________ + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); + + disp('initialization successful'); + iSaveSettings( [ './runs/' run_number '/' run_number '_settings.mat'] , FORCING, PARA, GRID) + + + %% ________________________________________________________________________ + % Time Integration Routine I + % I + %_________________________________________________________________________I + + while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) + warning( 'numerical stability not guaranteed' ); + end + + %------ update T array ------------------------------------------------ + % account for vertical heat fluxes from ground heat flux and heat conduction + T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; + % account for lateral heat fluxes + T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] + % set grid cells in air to air temperature + T(GRID.air.cT_domain)=FORCING.i.Tair; + + %------- water body module -------------------------------------------- + T = mixingWaterBody(T, GRID); + + %------- snow cover module -------------------------------------------- + [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + + %------- infiltration module------------------------------------------- + if PARA.modules.infiltration + lateral_water_flux = nansum( water_fluxes ); % lateral fluxes to/from other workers in [m/s] + [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_water_flux); + end + + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.modules.infiltration + warning( 'energy and water balances are not correct for this combination of modules'); + [GRID, PARA] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); + elseif PARA.modules.xice && PARA.modules.infiltration + [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); + GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + end + + %------- update Lstar for next time step ------------------------------ + SEB = L_star(FORCING, PARA, SEB); + + %------- update auxiliary state variables + PARA.location.altitude = getAltitude( PARA, GRID ); + PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); + PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); + PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); + + %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time + if ~PARA.modules.lateral + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; + end + end + + %------- water balance calculations ----------------------------------- + % rainfall + BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval + % snowfall + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval + + + %------- lateral exchange module -------------------------------------- + % all functions called in this block should go into + % /modules/cryoGridLateral + % calling PARA.ensemble is only allowed here + if PARA.modules.lateral + if t==TEMPORARY.syncTime %communication between workers + disp('CryoGridLateral: sync - start'); + labBarrier(); %common start + updateAuxiliaryVariablesAndCommonThresholds() ; + + % heat exchange module + if PARA.modules.exchange_heat + labBarrier(); + % check preconditions + precondition_heatExchange = true; %no specific conditions so far + if precondition_heatExchange + %WRAPPER + disp('sync - exchanging heat'); + % calculate lateral heat fluxes + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + heat_fluxes = zeros( numlabs, 1); + PACKAGE_heatExchange.T = T; + PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; + PACKAGE_heatExchange.k_cTgrid = k_cTgrid; + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_heatExchange, j, 1); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_heatExchange_j = labReceive(j, 1); + [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index + heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes + dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations + end + end + end + end + + % water exchange module + if PARA.modules.exchange_water + labBarrier(); + % check preconditions + precondition_waterExchage = checkPreconditionsWaterExchange( T, GRID ) + if precondition_waterExchange + % WRAPPER + disp('sync - exchanging water'); + % calculate lateral water fluxes + water_fluxes = nan( number_of_realizations, 1 ); % in [m/s] + PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table(index); + PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_waterExchange, j, 2); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_waterExchange_j = labReceive(j, 2); + % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) + water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); % matrix containing all fluxes in [m/s] scaled to row index + end + end + % for debugging: print water flux per column + waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m + fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); + end + + end + + % snow exchange module + if PARA.modules.exchange_snow + labBarrier(); + % check preconditions + precondition_snowExchange = checkPreconditionsSnowExchnge( GRID, PARA ) + if precondition_snowExchange + disp('sync - exchanging snow'); + % calculate terrain index with updated surface_altitudes + PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); + + % calculate mobile snow + % WRAPPER + mobile_snow = zeros( 1, number_of_realizations ); + my_mobile_snow = 0; + meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE + if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions + i=0; + while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold + > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains + && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) + - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) + my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile + i=i+1; + end + end + mobile_snow(index) = my_mobile_snow; + % exchange mobile snow amounts + for j=1:number_of_realizations + if j~=index + % send mobile snow amount in [m SWE] + labSend( mobile_snow(index), j, 4 ); + end + end + for j=1:number_of_realizations + if j~=index + % receive mobile snow amount [m SWE] + mobile_snow(j) = labReceive(j, 4); + end + end + % calculate lateral snow fluxes + my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); + % apply lateral snow fluxes directly + if my_snow_change ~= 0 + [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; + end + + snow_fluxes = zeros( numlabs , 1 ); + snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes + fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); + + end + end + + labBarrier(); + updateAuxiliaryVariablesAndCommonThresholds() ; + + TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; + disp('sync - done'); + end + end + + + %------- next time step ----------------------------------------------- + t=t+timestep; + %---------- sum up + OUTPUT ------------------------------------------- + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes); + + + end + + % save final state and output at t=endtime + iSaveOUT(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) + iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + +end + +if number_of_realizations>1 + delete(gcp('nocreate')) +end + +disp('Done.'); diff --git a/add_modules.m b/add_modules.m index ffce5fe..12489eb 100644 --- a/add_modules.m +++ b/add_modules.m @@ -1,11 +1,13 @@ % %clear all -if ~paraFromFile - clearvars -except paraFromFile %added by JAN to enable running with or without config file from same script -end +% if ~paraFromFile +% clearvars -except paraFromFile %added by JAN to enable running with or without config file from same script +% end + +clear all close all profile off -dbclear if error -%dbstop if error +%dbclear if error +dbstop if error %import CryoGrid modules (matlab functions) addpath('modules/cryoGridTechnical/') @@ -16,4 +18,4 @@ addpath('modules/CryoGridInfiltrationUnfrozenSoil') addpath('modules/cryoGridExcessIce/') addpath('modules/cryoGridExcessIceInfiltration') -%addpath('modules/cryoGridRockFields/') +addpath('modules/cryoGridLateral') diff --git a/add_modules_function.m b/add_modules_function.m deleted file mode 100644 index bd62ab3..0000000 --- a/add_modules_function.m +++ /dev/null @@ -1,17 +0,0 @@ -% %clear all -clearvars -except startYear endYear rainFrac snowFrac waterTable maxSnow extFlux fieldCapacity snowDens - -close all -profile off -dbclear if error -%dbstop if error - -%import CryoGrid modules (matlab functions) -addpath('modules/cryoGridTechnical/') -addpath('modules/cryoGridInitialize/') -addpath('modules/cryoGridSEB/') -addpath('modules/cryoGridSoil/') -addpath('modules/cryoGridSnow/') -addpath('modules/CryoGridInfiltrationUnfrozenSoil') -addpath('modules/cryoGridExcessIce/') -addpath('modules/cryoGridExcessIceInfiltration') diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m index 5f13b93..f909052 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m @@ -1,16 +1,20 @@ -function [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE) +function [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_flux_rate) % possible meltwater contribution from xice if ~PARA.modules.xice - meltwaterGroundIce = 0; + meltwaterGroundIceAboveWaterTableThreshold = 0; else - meltwaterGroundIce = GRID.lake.residualWater; + meltwaterGroundIceAboveWaterTableThreshold = GRID.lake.residualWater; GRID.lake.residualWater=0; end % external flux external_flux_rate = PARA.soil.externalWaterFlux; % in m/day BALANCE.water.dr_external = BALANCE.water.dr_external + external_flux_rate.*timestep.*1000; %in mm + + % lateral flux to/from other workers + lateral_flux_rate = lateral_flux_rate.*3600.*24; % now in m/day + BALANCE.water.dr_lateral = BALANCE.water.dr_lateral + lateral_flux_rate.*timestep.*1000; if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 %no snow cover and uppermost grid cell unfrozen @@ -23,25 +27,26 @@ dwc_dt(1)=dwc_dt(1)+FORCING.i.rainfall./1000.*timestep; % changes due to meltwater from excess ice - dwc_dt(1)=dwc_dt(1)+meltwaterGroundIce; + dwc_dt(1)=dwc_dt(1)+meltwaterGroundIceAboveWaterTableThreshold; % routing of water - [wc, surface_runoff, lacking_water] = bucketScheme(T, wc, dwc_dt, GRID, PARA, external_flux_rate.*timestep); + [wc, surface_runoff, lacking_water] = bucketScheme(T, wc, dwc_dt, GRID, PARA, (external_flux_rate+lateral_flux_rate).*timestep); % consistency check if sum( wc<0 )~=0 - warning('negative water content occured'); + warning( 'CryoGridInfiltration - negative water content occured after bucket scheme' ); %here one could correct the water balance + end % remove water above water table in case of ponding, e.g. through rain (independent of xice module) if GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)<1e-6 && ... - GRID.general.K_grid(GRID.soil.cT_domain_ub)PARA.location.absolute_maxWater_altitude cellSize = GRID.general.K_delta(GRID.soil.cT_domain_ub); actualWater = wc(1)*cellSize; - h = GRID.general.K_grid(GRID.soil.K_domain_ub+1)-PARA.soil.waterTable; + h = PARA.location.absolute_maxWater_altitude - (PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub+1)); if h<0 warning('h<0. too much water above water table!') end @@ -61,7 +66,7 @@ % store remaining surface runoff BALANCE.water.dr_surface = BALANCE.water.dr_surface - surface_runoff*1000; % in [mm] - BALANCE.water.d_lacking = BALANCE.water.d_lacking + lacking_water*1000; + BALANCE.water.dm_lacking = BALANCE.water.dm_lacking + lacking_water*1000; end diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m index 8d28b11..258a3af 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m @@ -2,29 +2,36 @@ T=T(GRID.soil.cT_domain); K_delta=GRID.general.K_delta(GRID.soil.cT_domain); %in m -porosity=1-GRID.soil.cT_mineral-GRID.soil.cT_organic; +porosity=1-GRID.soil.cT_mineral-GRID.soil.cT_organic; +soilType = GRID.soil.cT_soilType; + +% to be changed! +fieldCapacity = zeros(size(soilType)); +residualWaterContent = zeros(size(soilType)); +for i=1:size(PARA.soil.soilTypes,1) + fieldCapacity(soilType==i) = PARA.soil.soilTypes( i, 2 ); + residualWaterContent(soilType==1) = PARA.soil.soilType( i, 1 ); +end -% A=sum(K_delta(1:30).*wc(1:30)+dwc_dt(1:30)) lacking_water=0; i=1; -i_max=70; % maximum infiltration depth, must be defined somehow before +i_max=200; % maximum infiltration depth, must be defined somehow before, includes also water body on to of soil while T(i)>0 && i<=i_max - max_water=K_delta(i).*PARA.soil.fieldCapacity; %maximum amount of water (in m) that a grid cell can hold - min_water=K_delta(i).*PARA.soil.residualWC; %minimum amount of water which stays in a cell + max_water=K_delta(i).*fieldCapacity(i); %maximum amount of water (in m) that a grid cell can hold + min_water=K_delta(i).*residualWaterContent(i); %minimum amount of water which stays in a cell (independent of soil type, but should be if "freezing = drying") actual_water= max( min_water, wc(i).*K_delta(i)+dwc_dt(i) ); % should be dwc (already multiplied with timestep) %JAN: this violates the WB - lacking_water = lacking_water + (wc(i).*K_delta(i)+dwc_dt(i)=1 && excess_water>0 @@ -36,8 +43,6 @@ i=i-1; end +lacking_water = lacking_water + (excess_water<0)*excess_water; % this accounts for violations of the water balance -surface_runoff=excess_water; - -% C=sum(K_delta(1:30).*wc(1:30))+surface_runoff - +surface_runoff=(excess_water>0)*excess_water; % surface runoff only if excess_water>0 diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m index 1bc8a06..87fbcf1 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m @@ -27,25 +27,20 @@ GRID.soil.cT_natPor(1)=[]; GRID.soil.cT_mineral(1)=[]; GRID.soil.cT_soilType(1)=[]; - % K fields are not used currently -% GRID.soil.K_water(1)=[]; -% GRID.soil.K_organic(1)=[]; -% GRID.soil.K_mineral(1)=[]; -% GRID.soil.K_soilType(1)=[]; + GRID.soil.excessGroundIce(1)=[]; end %%% step 2b) ponding of surface runoff below water table while surface_runoff>1e-6 && ... % not >0 as sometimes numerical errors occur during calculation of surface_runoff - GRID.general.K_grid(GRID.soil.K_domain_ub)>PARA.soil.waterTable %&& ... + PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub)=1 % this prevents a bug for very small %surface_runoff when upper cell not filled // but this %does not allow ponding on top of actual soil disp('infiltration - update GRID - ponding of water below water table') - h = GRID.general.K_grid(GRID.soil.K_domain_ub)-PARA.soil.waterTable; % this is guruanteed to be >0 - + h = PARA.location.absolute_maxWater_altitude - ( PARA.location.initial_altitude - GRID.general.K_grid(GRID.soil.cT_domain_ub) ) ; % this is guruanteed to be >0 % create new water cell / change GRID domains GRID.soil.cT_domain(GRID.air.cT_domain_lb)=1; @@ -58,7 +53,6 @@ GRID.air.K_domain_lb=GRID.air.K_domain_lb-1; % fill new water cell - %cellSize = GRID.general.K_delta(GRID.soil.cT_domain_ub); cellSize = PARA.technical.waterCellSize; waterAdded = min( [surface_runoff, cellSize, h] ); % add water until water table is reached or surface_runoff "empty" wc = [ waterAdded./cellSize ; wc ]; @@ -69,11 +63,7 @@ GRID.soil.cT_natPor = [ GRID.soil.cT_natPor(1); GRID.soil.cT_natPor ]; % take natPor of cell below GRID.soil.cT_mineral = [ 0 ; GRID.soil.cT_mineral ]; GRID.soil.cT_soilType = [ 1; GRID.soil.cT_soilType]; % assume sand as soil type for water cell - % K fields are not used currently - %GRID.soil.K_water = [ wc(1); GRID.soil.K_water ]; - %GRID.soil.K_organic = [ 0 ; GRID.soil.K_organic ]; - %GRID.soil.K_mineral = [ 0 ; GRID.soil.K_mineral ]; - %GRID.soil.K_soilType = [ GRID.soil.K_soilType(1); GRID.soil.K_soilType]; + GRID.soil.excessGroundIce = [ 0 ; GRID.soil.excessGroundIce ]; % update GRID spacings diff --git a/modules/cryoGridExcessIceInfiltration/excessGroundIceInfiltration.m b/modules/cryoGridExcessIceInfiltration/excessGroundIceInfiltration.m index 431bb34..c580be3 100644 --- a/modules/cryoGridExcessIceInfiltration/excessGroundIceInfiltration.m +++ b/modules/cryoGridExcessIceInfiltration/excessGroundIceInfiltration.m @@ -1,7 +1,7 @@ function [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA) meltwaterGroundIce=0; if ~isempty(PARA.soil.mobileWaterDomain) && (sum(double(T(GRID.soil.cT_domain)>0 & GRID.soil.excessGroundIce==1))~=0) && isempty(GRID.snow.cT_domain_ub) - disp('excess ice thawing'); + disp('excessGroundIceInfiltration - excess ice thawing'); GRID.soil.excessGroundIce = GRID.soil.excessGroundIce==1 & T(GRID.soil.cT_domain)<=0; %remove the thawed cell from the list [GRID, meltwaterGroundIce, wc] = excessGroundIceThaw4Infiltration(T, wc, GRID, PARA); %meltwaterGroundIce could be read out, but is not yet implemented diff --git a/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m b/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m index 3ff1409..7674fd4 100644 --- a/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m +++ b/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m @@ -1,25 +1,19 @@ function [GRID, meltwaterGroundIce, wc]=excessGroundIceThaw4Infiltration(T, wc, GRID, PARA) -%disp('rearranging grid cells due to ground ice thaw') meltwaterGroundIce=0; % in [m] - -waterLevel=PARA.soil.waterTable; %remove supersaturation only when there is no snow on top of soil!!!!!!! - %calculates amounts of soil constituents in [m] mineral=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_mineral; organic=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_organic; natPor=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_natPor; % modification for infiltration -%water=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_water; water=GRID.general.K_delta(GRID.soil.cT_domain).*wc; -cT_grid=GRID.general.cT_grid(GRID.soil.cT_domain); K_delta=GRID.general.K_delta(GRID.soil.cT_domain); mobileWater = double(T(GRID.soil.cT_domain)>0) .* (water-natPor) .* double(water>natPor); -[startCell ~]= LayerIndex(mobileWater~=0); %this is faster +[startCell ~]= LayerIndex(mobileWater~=0); %move solids down for i=startCell:-1:1 @@ -50,7 +44,6 @@ end %clean up grid cells with non-zero+non-unity water content in domains without soil matrix -% JAN: these loops thould be removed to increase performance, possible? mobileWater=0; for i=1:startCell if mineral(i)+organic(i)==0 @@ -70,42 +63,18 @@ end end -%%% modifications due to infiltration module -%GRID.soil.cT_water=water./K_delta; -%GRID.soil.K_water(1)=GRID.soil.cT_water(1); -%GRID.soil.K_water(2:startCell+1)=(GRID.soil.cT_water(2:startCell+1)+GRID.soil.cT_water(1:startCell))/2 ; wc=water./K_delta; -% GRID.soil.K_water(1)=wc(1); -% GRID.soil.K_water(2:startCell+1)=(wc(2:startCell+1)+wc(1:startCell))/2 ; -%%% GRID.soil.cT_mineral=mineral./K_delta; GRID.soil.cT_organic=organic./K_delta; GRID.soil.cT_natPor=natPor./K_delta; -GRID.soil.cT_soilType( (GRID.soil.cT_mineral+GRID.soil.cT_organic)<=1e-6 )=1; %sets sand freeze curve for all water grid cells %wc(:,1)==1,1 - - -% K fields not used currently -% GRID.soil.K_mineral(1)=GRID.soil.cT_mineral(1); -% GRID.soil.K_mineral(2:startCell+1)=(GRID.soil.cT_mineral(2:startCell+1)+GRID.soil.cT_mineral(1:startCell))/2 ; -% GRID.soil.K_organic(1)=GRID.soil.cT_organic(1); -% GRID.soil.K_organic(2:startCell+1)=(GRID.soil.cT_organic(2:startCell+1)+GRID.soil.cT_organic(1:startCell))/2 ; - -% GRID.soil.K_natPor(1)=GRID.soil.cT_natPor(1); -% GRID.soil.K_natPor(2:startCell+1)=(GRID.soil.cT_natPor(2:startCell+1)+GRID.soil.cT_natPor(1:startCell))/2 ; -% GRID.soil.K_soilType(1)=GRID.soil.cT_soilType(1); -% GRID.soil.K_soilType(2:startCell+1)=round((GRID.soil.cT_soilType(2:startCell+1)+GRID.soil.cT_soilType(1:startCell))/2) ; +GRID.soil.cT_soilType( (GRID.soil.cT_mineral+GRID.soil.cT_organic)<=1e-6 )=1; %sets sand freeze curve for all water grid cells - -%remove grid cells until the water level is reached -soilGRIDsizeOld = sum( GRID.soil.cT_domain ); -%%% modified due to infiltration module -%while (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+GRID.soil.cT_water(1)==0) || (GRID.soil.cT_water(1)==1 && GRID.general.K_grid(GRID.soil.K_domain_ub) PARA.location.absolute_maxWater_altitude) ) disp('xice - update GRID - removing grid cell ...') if wc(1)==0 @@ -128,7 +97,6 @@ GRID.soil.cT_domain_ub=GRID.soil.cT_domain_ub+1; GRID.soil.K_domain_ub=GRID.soil.K_domain_ub+1; GRID.soil.soilGrid(1)=[]; - %GRID.soil.convectiveDomain(1)=[]; %%% modification due to infiltration module GRID.soil.cT_water(1)=[]; @@ -139,23 +107,19 @@ GRID.soil.cT_natPor(1)=[]; GRID.soil.cT_mineral(1)=[]; GRID.soil.cT_soilType(1)=[]; - % K fields are not used currently -% GRID.soil.K_water(1)=[]; -% GRID.soil.K_organic(1)=[]; -% GRID.soil.K_mineral(1)=[]; -% GRID.soil.K_soilType(1)=[]; + GRID.soil.excessGroundIce(1)=[]; end -% check if the uppermost +% check if the uppermost soil cell contains water above water table if GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)<=1e-6 && ... - GRID.general.K_grid(GRID.soil.cT_domain_ub) PARA.location.absolute_maxWater_altitude disp('xice - checking upper cell for excess water'); actualWater = wc(1)*K_delta(1); - h = GRID.general.K_grid(GRID.soil.cT_domain_ub+1)-waterLevel; + h = PARA.location.absolute_maxWater_altitude - (PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub+1)); if h<0 warning('xice - h<0. too much water above water table!') @@ -166,46 +130,14 @@ meltwaterGroundIce = meltwaterGroundIce + actualWater-h; end - end - soilGRIDsizeNew = sum (GRID.soil.cT_domain ); - % update look up tables since soil water contents changed % --> only if grid cells freeze, otherwise not necessary ????? -%if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 +% if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 if soilGRIDsizeOld~=soilGRIDsizeNew disp('xice - reinitializing LUT - soil/air domains changed'); GRID.soil.cT_water=wc; GRID = initializeSoilThermalProperties(GRID, PARA); end -%end -%reduce water content above the perched water table -%it might be also good to use an external function for this since this is -%only an option in the model -%i=0; -% while i./startCell < 1-PARA.soil.perchedWaterTable -% GRID.soil.cT_water(i+1,1) = PARA.soil.saturationAbovePerchedWaterTable.*(1-GRID.soil.cT_mineral(i+1,1)-GRID.soil.cT_organic(i+1,1)); -% -% GRID.soil.K_water(i+1,1) = PARA.soil.saturationAbovePerchedWaterTable.*(1-GRID.soil.K_mineral(i+1,1)-GRID.soil.K_organic(i+1,1)); -% i=i+1; -% end - - -% [GRID.soil.cT_frozen,... -% GRID.soil.cT_thawed,... -% GRID.soil.K_frozen,... -% GRID.soil.K_thawed,... -% GRID.soil.conductivity,... -% GRID.soil.capacity] = initialize(GRID.soil.cT_water,... -% GRID.soil.cT_mineral,... -% GRID.soil.cT_organic,... -% GRID.soil.cT_soilType,... -% GRID.soil.K_water,... -% GRID.soil.K_mineral,... -% GRID.soil.K_organic,... -% GRID.soil.K_soilType,... -% PARA.technical.arraySizeT,... -% GRID.general.cT_grid(GRID.soil.cT_domain),... -% PARA.soil.kh_bedrock); diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m index effa7b7..4875e20 100644 --- a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m @@ -22,7 +22,8 @@ % [GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); % GRID.lake.ice.cT_domain = GRID.lake.cT_domain & T<=0; % [GRID.lake.ice.cT_domain_lb, GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); %these might be two domains - % K domains not implemented so far +% % K domains not implemented so far + else GRID.lake.cT_domain = false(size(GRID.general.cT_grid)); GRID.lake.K_domain = false(size(GRID.general.K_grid)); @@ -30,14 +31,4 @@ [GRID.lake.K_domain_lb, GRID.lake.K_domain_ub] = LayerIndex(GRID.lake.K_domain); end - - - - - - - - - - end \ No newline at end of file diff --git a/modules/cryoGridInitialize/generateTemporary.m b/modules/cryoGridInitialize/generateTemporary.m index c28eb9b..dda3304 100644 --- a/modules/cryoGridInitialize/generateTemporary.m +++ b/modules/cryoGridInitialize/generateTemporary.m @@ -1,8 +1,10 @@ function [t, TEMPORARY] = generateTemporary(T, PARA) - t=PARA.technical.starttime; + TEMPORARY.outputTime=t+PARA.technical.outputTimestep; +TEMPORARY.syncTime=t+PARA.technical.syncTimeStep; + if ~isempty(PARA.technical.saveInterval) TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(PARA.technical.saveDate(4:5)), str2num(PARA.technical.saveDate(1:2)))-PARA.technical.outputTimestep; else @@ -19,9 +21,6 @@ TEMPORARY.dE_dt_SEB_sum = 0.*T; TEMPORARY.dE_dt_cond_sum = 0.*T; - -%TEMPORARY.dEeffSoil = 0; - TEMPORARY.dE_soil_sens = 0; TEMPORARY.dE_soil_lat = 0; TEMPORARY.dE_soil = 0; @@ -29,10 +28,6 @@ TEMPORARY.dE_snow_lat = 0; TEMPORARY.dE_snow = 0; -% TEMPORARY.dEsensSoil = 0; -% TEMPORARY.dEsensSnow = 0; -% TEMPORARY.dElatentSoil = 0; -% TEMPORARY.dElatentSnow = 0; TEMPORARY.timestep_sum=0; diff --git a/modules/cryoGridInitialize/initializeBALANCE.m b/modules/cryoGridInitialize/initializeBALANCE.m index 263c039..c4e6d79 100644 --- a/modules/cryoGridInitialize/initializeBALANCE.m +++ b/modules/cryoGridInitialize/initializeBALANCE.m @@ -44,6 +44,6 @@ BALANCE.water.dr_lateralSnow=0; BALANCE.water.dr_rain=0; % this is only rain on frozen ground BALANCE.water.dr_lateral=0; - BALANCE.water.d_lacking=0; - + % mismatch + BALANCE.water.dm_lacking=0; end \ No newline at end of file diff --git a/modules/cryoGridLateral/applyLateralSnowFluxes.m b/modules/cryoGridLateral/applyLateralSnowFluxes.m new file mode 100644 index 0000000..f9e7957 --- /dev/null +++ b/modules/cryoGridLateral/applyLateralSnowFluxes.m @@ -0,0 +1,78 @@ +function [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ) + + if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis + if my_snow_change>0 + disp( 'depositing lateral snow' ); + while my_snow_change > 0 + temp_snow_flux = min( [ my_snow_change, PARA.technical.SWEperCell-GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ]); + + GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... + + temp_snow_flux; + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... + + (temp_snow_flux./(PARA.snow.rho_snow./PARA.constants.rho_w) - temp_snow_flux); % could replace this to assure correct fresh snow density + + + % add an empty snow cell + GRID.snow.cT_domain(GRID.air.cT_domain_lb)=1; + GRID.snow.K_domain(GRID.air.K_domain_lb)=1; + [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); + [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); + + GRID.air.cT_domain(GRID.air.cT_domain_lb)=0; + GRID.air.K_domain(GRID.air.K_domain_lb)=0; + [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + GRID.snow.Snow_i(GRID.snow.cT_domain_ub)=0; + GRID.snow.Snow_w(GRID.snow.cT_domain_ub)=0; + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)=0; + T(GRID.snow.cT_domain_ub)=T(GRID.snow.cT_domain_ub+1); + + my_snow_change = my_snow_change - temp_snow_flux; + + end + elseif my_snow_change<0 + disp( 'removing lateral snow' ); + while -my_snow_change >= GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + + my_snow_change = my_snow_change + GRID.snow.Snow_i(GRID.snow.cT_domain_ub); + % route down water + GRID.snow.Snow_w(GRID.snow.cT_domain_ub+1) = GRID.snow.Snow_w(GRID.snow.cT_domain_ub+1) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub); % this will not work if only one snow cell left + % clean upper cell + GRID.snow.Snow_i(GRID.snow.cT_domain_ub)=0; + GRID.snow.Snow_w(GRID.snow.cT_domain_ub)=0; + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)=0; + T(GRID.snow.cT_domain_ub)=FORCING.i.Tair; + + % remove upper cell + GRID.snow.cT_domain(GRID.snow.cT_domain_ub)=0; + GRID.snow.K_domain(GRID.snow.cT_domain_ub)=0; + [GRID.snow.cT_domain_lb, GRID.snow.cT_domain_ub] = LayerIndex(GRID.snow.cT_domain); + [GRID.snow.K_domain_lb, GRID.snow.K_domain_ub] = LayerIndex(GRID.snow.K_domain); + + GRID.air.cT_domain(GRID.air.cT_domain_lb+1)=1; + GRID.air.K_domain(GRID.air.K_domain_lb+1)=1; + [GRID.air.cT_domain_lb, GRID.air.cT_domain_ub] = LayerIndex(GRID.air.cT_domain); + [GRID.air.K_domain_lb, GRID.air.K_domain_ub] = LayerIndex(GRID.air.K_domain); + + end + + % remove remaining snow_flux from upper cell + GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + my_snow_change; + %GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + (my_snow_change./(PARA.snow.rho_snow./PARA.constants.rho_w) - my_snow_change); + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) .* ( (PARA.constants.rho_w ./ PARA.snow.rho_snow ) - 1 ); % this assures fresh snow density for upper cell + else % lateral_snow_flux==0 + %do nothing + end + + elseif my_snow_change>0 %no snow cover and positive lateral input + %---------- add the new snow into initial SWE variable in case of no snow cover------------------ + GRID.snow.SWEinitial = GRID.snow.SWEinitial + my_snow_change; + elseif my_snow_change<0 % no snow cover, but negative lateral flow calculated + warning('snow exchange - negative lateral snow flux without existing snow cover'); + end + + + + +end \ No newline at end of file diff --git a/modules/cryoGridLateral/calculateLateralHeatFluxes.m b/modules/cryoGridLateral/calculateLateralHeatFluxes.m new file mode 100644 index 0000000..7fbaf34 --- /dev/null +++ b/modules/cryoGridLateral/calculateLateralHeatFluxes.m @@ -0,0 +1,52 @@ +function [dE_dt, BALANCE] = calculateLateralHeatFluxes(T_index, k_index, PACKAGE_heatExchange_j, GRID, PARA, BALANCE, j) + + index = labindex; + dE_dt = zeros( length(GRID.general.cT_grid), 1); + if PARA.ensemble.thermal_contact_length(index,j)>0 % calculate lateral heat flux only for laterally connected workers + + % change to absolute altitude grid + altitude_cTgrid_index = -GRID.general.cT_grid + PARA.ensemble.initial_altitude(index); + + % determine the contact domain + distance_index_j = PARA.ensemble.distanceBetweenPoints(j, index); + weight_index = PARA.ensemble.weight(index); + weight_j = PARA.ensemble.weight(j); + contact_length_index_j = PARA.ensemble.thermal_contact_length(j, index); + contact_altitude = min( [ PARA.ensemble.altitude(j), PARA.ensemble.altitude(index) ] ) - distance_index_j; %below this depth, grid cells will exchange heat + contact_domain = altitude_cTgrid_index <= contact_altitude; %all cells in the current ensemble member + + % interpolate j-values to index-grid + altitude_cTgrid_j = -PACKAGE_heatExchange_j.cT_grid + PARA.ensemble.initial_altitude(j); + min_contact_altitude = min( [altitude_cTgrid_index(end), altitude_cTgrid_j(end)] ); + altitude_cTgrid_index(end) = min_contact_altitude; + altitude_cTgrid_j(end) = min_contact_altitude; + T_j = PACKAGE_heatExchange_j.T; + k_j = PACKAGE_heatExchange_j.k_cTgrid; + if ~isreal(altitude_cTgrid_index) + disp('altitude_cTgrid_index contains complex values'); + end + if ~isreal(altitude_cTgrid_j) + disp('altitude_cTgrid_j contains complex values'); + end + if ~isreal(T_j) + disp('T_j contains complex values'); + end + if ~isreal(k_j) + disp('k_j contains complex values'); + end + T_interp_j = interp1( altitude_cTgrid_j, T_j, altitude_cTgrid_index, 'linear'); + k_interp_j = interp1( altitude_cTgrid_j, k_j, altitude_cTgrid_index, 'linear'); + + % determine effectice thermal conductivities + k_eff = (weight_index+weight_j) ./ ( weight_index./k_index + weight_j./k_interp_j ); + + % energy flux from worker j to index in [J / m^3 / s] + dE_dt(contact_domain) = k_eff(contact_domain) .* (T_interp_j(contact_domain)-T_index(contact_domain)) ./ distance_index_j .* contact_length_index_j ./ PARA.ensemble.area(index) ; % in [ J / m^3 / s ] + +% T_index(contact_domain) = T_index(contact_domain) + dE_dt_j ./ c_index(contact_domain) .* PARA.technical.syncTimeStep .* 24 .* 3600; + + % balance is not correct + BALANCE.energy.Q_lateral(contact_domain) = BALANCE.energy.Q_lateral(contact_domain) + dE_dt(contact_domain) .* PARA.technical.syncTimeStep .* 24 .* 3600 .* GRID.general.K_delta(contact_domain); % in [ J / m^2 ] + + end +end diff --git a/modules/cryoGridLateral/calculateLateralSnowFluxes.m b/modules/cryoGridLateral/calculateLateralSnowFluxes.m new file mode 100644 index 0000000..a67aaaa --- /dev/null +++ b/modules/cryoGridLateral/calculateLateralSnowFluxes.m @@ -0,0 +1,49 @@ +function snow_flux_j = calculateLateralSnowFluxes( mobile_snow_index, PACKAGE_snowExchange_j, GRID, PARA, index, j) + + snow_flux_j = 0; + snow_diffusivity = PARA.ensemble.snow_diffusivity; % in [m^2/s] constant of proportionality + + + distance_index_j = PARA.ensemble.distanceBetweenPoints(index,j); + surface_altitude_index = PARA.ensemble.surface_altitude(index); + surface_altitude_j = PARA.ensemble.surface_altitude(j); + snow_w_j = PACKAGE_snowExchange_j.snow.Snow_w; + mobile_snow_j = PACKAGE_snowExchange_j.mobile_snow; + + % preconditions: points connected and minimum surface elevation difference in order to prevent oscillations between two workers + if distance_index_j~=0 && abs(surface_altitude_index-surface_altitude_j) > GRID.snow.snowCellSize + + + hasMobileSnow_index = surface_altitude_index > PARA.ensemble.altitude(index)+PARA.ensemble.immobile_snow_height(index); + hasMobileSnow_j = surface_altitude_j > PARA.ensemble.altitude(j)+PARA.ensemble.immobile_snow_height(j); + + isMelting_index = sum(GRID.snow.Snow_w)>0; + isMelting_j = sum(snow_w_j) > 0; + + if isMelting_index || isMelting_j + disp('melting conditions'); + end + + % this does not account for wind speed so far + maxSnowFlux = snow_diffusivity .* abs(surface_altitude_j - surface_altitude_index) ./ distance_index_j .* PARA.ensemble.snow_contact_length(index,j) ./ PARA.ensemble.area(index); % in [m SWE / s] + + + + + if surface_altitude_j > surface_altitude_index && hasMobileSnow_j && ~isMelting_j % worker index receiving drift snow from j + + snow_flux_j = min( [maxSnowFlux, mobile_snow_j * PARA.ensemble.weight(j) / PARA.ensemble.weight(index) ]); + + elseif surface_altitude_index > surface_altitude_j && hasMobileSnow_index && ~isMelting_index % worker index is depositing drift snow to j + + snow_flux_j = -min( [ maxSnowFlux, mobile_snow_index ] ) ; + + else % no drift snow exchange + + snow_flux_j = 0; + + end + + end + +end \ No newline at end of file diff --git a/modules/cryoGridLateral/calculateLateralSnowFluxes2.m b/modules/cryoGridLateral/calculateLateralSnowFluxes2.m new file mode 100644 index 0000000..dc75c35 --- /dev/null +++ b/modules/cryoGridLateral/calculateLateralSnowFluxes2.m @@ -0,0 +1,15 @@ +function snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ) + + index = labindex; + % calculate mobile snow volume + mobile_snow_volume = sum ( mobile_snow .* PARA.ensemble.weight .* (PARA.ensemble.terrain_index_snow>0) ); + % calculate individual change (deposit or removal) dependent on terrain index + if PARA.ensemble.terrain_index_snow(index)>0 %removal + snow_change = -mobile_snow(index); + elseif PARA.ensemble.terrain_index_snow(index)<0 % deposit + snow_change = -mobile_snow_volume .* PARA.ensemble.terrain_index_snow(index); + else % terrain index = 0 or NaN + snow_change = 0; + end + +end diff --git a/modules/cryoGridLateral/calculateLateralWaterFluxes.m b/modules/cryoGridLateral/calculateLateralWaterFluxes.m new file mode 100644 index 0000000..7b5745b --- /dev/null +++ b/modules/cryoGridLateral/calculateLateralWaterFluxes.m @@ -0,0 +1,145 @@ +function water_flux_j = calculateLateralWaterFluxes(T, PACKAGE_waterExchange_j, GRID, PARA, j) +% Function that calculate the water fluxes between the 2 workers. +% PARA.ensemble should contain the elevations, the water table values, the +% bucketbottom the weight and conductivities of each worcker. +% GRID will contain the soil water content. +% T is the temperature vector of the current worker. +% packageWorkerj has to be a bundle as defined considering necessary inputs + +index = labindex; + +water_flux_j = NaN; + + +% Check whether the considered workers (index, j) are +% hydrologically connceted + +if PARA.ensemble.hydraulic_contact_length(index,j)>0 + % conditions for water infiltration / exchanges + infiltration_condition_index = isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0; + infiltration_condition_j = PACKAGE_waterExchange_j.infiltration_condition; + + + if infiltration_condition_index && infiltration_condition_j + + wt_index = PARA.ensemble.water_table(index); + wt_j = PACKAGE_waterExchange_j.water_table_altitude; + ald_index = PARA.ensemble.active_layer_depth_altitude(index); + ald_j = PACKAGE_waterExchange_j.active_layer_depth_altitude; + + + % Decipher between cases + [waterpotWindex, hasWater_index] = nanmax([wt_index, ald_index ] ); + [waterpotWj, hasWater_j] = nanmax([wt_j, ald_j ] ); + + + if (waterpotWj > waterpotWindex && hasWater_j==1);% Current worker is gaining water + + % Calculate the maximum exchanged water volume + DeltaH = waterpotWj - waterpotWindex; + contact_height = waterpotWj - nanmax( [ waterpotWindex, ald_j ]); + Distance=sqrt(DeltaH^2 + PARA.ensemble.hydraulicDistance(j,index)^2); + %section=(PARA.ensemble.waterTable(j)-soilGrid_workerj(PARA.ensemble.bottomBucketSoilcTIndex(j)+1)) * PARA.ensemble.contactLength(j,index); + section=contact_height .* PARA.ensemble.hydraulic_contact_length(j,index); + DarcyFlux=PARA.ensemble.hydraulic_conductivity(j,index) * (DeltaH/Distance) * section / PARA.ensemble.area(index); + %MaxWaterHeight=DarcyFlux * PARA.technical.syncTimeStep ; % Jan : weight here corresponds to an actual area in m^2 + +% % Calculate available water volume that can be lost +% availableWater_li=Wc_workerj > PARA.soil.fieldCapacity; % Find where there is water above field capacity +% cellresidual_water=0; +% +% if (altitude_j-soilGrid_workerj(PARA.ensemble.bottomBucketSoilcTIndex(j)+1))> waterpotWindex; % Bucket bottom of the worker loosing water is higher than water table of the worker gaining water +% +% availableWater_li(PARA.ensemble.bottomBucketSoilcTIndex(j)+1:end)=0; % Stop accounting for water after the bottom of the bucket +% +% else % Bucket bottom of the worker loosing water is below the water table of the worker gaining water +% +% [ ind_cT, missingHeightInCell ] = getWTsoilcTindex(soilGrid_workerj,altitude_j,waterpotWindex );% find the index of the cell of worker loosing water matching with the waterTable elevation of worker gaining water +% [ ind_wT, ~ ] = getWTsoilcTindex(soilGrid_workerj,altitude_j,PARA.ensemble.waterTable(j) ); +% if ind_cT==ind_wT; +% fprintf('WARNING from getWaterFluxes2Workers : waterTable of workers 1 and 2 in the same gridcell\n') +% PARA.ensemble.lateralFlux_inWaterHeight(j,index)=0; +% PARA.ensemble.lateralFlux_inWaterHeight(index,j)=0; +% return +% end +% cellresidual_water=Wc_workerj(ind_cT)*missingHeightInCell; %err here +% availableWater_li(ind_cT:end)=0; % Stop accounting for water after the watertable of the worker gaining water +% +% end +% +% availableWater=sum((Wc_workerj(availableWater_li)-PARA.soil.fieldCapacity).*K_deltaSoil_workerj(availableWater_li))+cellresidual_water; +% +% lateralFlux_inWaterHeight=DarcyFlux;% min(MaxWaterHeight,availableWater); +% PARA.ensemble.lateralFlux_inWaterHeight(j,index)=-lateralFlux_inWaterHeight; % lateralFlux_inWaterHeight is a non symetric matrix where mat(worker1,worker2) givesthe water height between both but scale to worker 1 +% PARA.ensemble.lateralFlux_inWaterHeight(index,j)=(PARA.ensemble.weight(j)/PARA.ensemble.weight(index)).*lateralFlux_inWaterHeight; +% + water_flux_j=DarcyFlux; + elseif (waterpotWindex > waterpotWj && hasWater_index==1); % Current worker is loosing water + + % Calculate maximum of the exchange water volume + DeltaH= waterpotWindex - waterpotWj; + contact_height =waterpotWindex - nanmax( [ waterpotWj, ald_index ] ); + Distance=sqrt(DeltaH^2 + PARA.ensemble.hydraulicDistance(j,index)^2); + %section=(PARA.ensemble.waterTable(index)-GRID.soil.soilGrid(PARA.ensemble.bottomBucketSoilcTIndex(index)+1)) * PARA.ensemble.contactLength(j,index); + %Jan: see question above + section=contact_height .* PARA.ensemble.hydraulic_contact_length(j,index); + DarcyFlux=PARA.ensemble.hydraulic_conductivity(j,index) * (DeltaH/Distance) * section / PARA.ensemble.area(index); + %MaxWaterHeight=DarcyFlux * PARA.technical.syncTimeStep; + + + +% % Calculate available water volume that can be lost +% availableWater_li=wc > PARA.soil.fieldCapacity; % Find where there is water above field capacity +% cellresidual_water=0; +% +% if (altitude_index-GRID.soil.soilGrid(PARA.ensemble.bottomBucketSoilcTIndex(index)+1))> waterpotWj; % Bucket bottom of the worker loosing water is higher than water table of the worker gaining water +% +% availableWater_li(PARA.ensemble.bottomBucketSoilcTIndex(index)+1:end)=0; % Stop accounting for water after the bottom of the bucket +% +% else % Bucket bottom of the worker loosing water is below the water table of the worker gaining water +% +% [ ind_cT, missingHeightInCell ] = getWTsoilcTindex(GRID.soil.soilGrid,altitude_index,waterpotWj ); % find the index of the cell of worker loosing water matching with the waterTable elevation of worker gaining water +% [ ind_wT, ~ ] = getWTsoilcTindex(GRID.soil.soilGrid,altitude_index,PARA.ensemble.waterTable(index) ); +% if ind_cT==ind_wT; +% fprintf('WARNING from getWaterFluxes2Workers : waterTable of workers 1 and 2 in the same gridcell\n') +% PARA.ensemble.lateralFlux_inWaterHeight(j,index)=0; +% PARA.ensemble.lateralFlux_inWaterHeight(index,j)=0; +% return +% end +% cellresidual_water=missingHeightInCell*wc(ind_cT); % err here +% availableWater_li(ind_cT:end)=0; % Stop accounting for water after the watertable of the worker gaining water +% +% end +% +% K_deltaSoil=GRID.general.K_delta(GRID.soil.cT_domain); +% availableWater=sum((wc(availableWater_li)-PARA.soil.fieldCapacity).*K_deltaSoil(availableWater_li))+cellresidual_water; +% lateralFlux_inWaterHeight=min(MaxWaterHeight,availableWater); + % Jan: for now: take maximum flux + + water_flux_j=-DarcyFlux; + +% lateralFlux_inWaterHeight=DarcyFlux; +% PARA.ensemble.lateralFlux_inWaterHeight(j,index)=(PARA.ensemble.weight(index)/PARA.ensemble.weight(j)).*lateralFlux_inWaterHeight; +% PARA.ensemble.lateralFlux_inWaterHeight(index,j)=-lateralFlux_inWaterHeight; + else % same water table, no lateralFlux + water_flux_j=0; +% PARA.ensemble.lateralFlux_inWaterHeight(j,index)=0; +% PARA.ensemble.lateralFlux_inWaterHeight(index,j)=0; + end + + else % No possible movement of water, because of snow or suficial freezing +% PARA.ensemble.lateralFlux_inWaterHeight(j,index)=0; +% PARA.ensemble.lateralFlux_inWaterHeight(index,j)=0; + water_flux_j=0; + end +else +% % No connection between workers +% PARA.ensemble.lateralFlux_inWaterHeight(j,index)=NaN; +% PARA.ensemble.lateralFlux_inWaterHeight(index,j)=NaN; + water_flux_j = NaN; +end + +%water_fluxes = PARA.ensemble.lateralFlux_inWaterHeight(index); + + +end diff --git a/modules/cryoGridLateral/calculateTerrainIndexSnow.m b/modules/cryoGridLateral/calculateTerrainIndexSnow.m new file mode 100644 index 0000000..6d8abfb --- /dev/null +++ b/modules/cryoGridLateral/calculateTerrainIndexSnow.m @@ -0,0 +1,22 @@ +function terrain_index_snow_final = calculateTerrainIndexSnow(altitudes, weight) +% +snowCellSize = 0.025; +allAltitudes=[]; +for i=1:size(weight,2) + %allAltitudes=[allAltitudes repmat( altitudes(1,i) ,1, weight(1,i))]; + allAltitudes=[allAltitudes repmat( round(altitudes(1,i)./snowCellSize).*snowCellSize ,1, weight(1,i))]; + +end + +terrain_index_snow=(allAltitudes-mean(allAltitudes))./std(allAltitudes); +terrain_index_snow=terrain_index_snow./sum(terrain_index_snow(terrain_index_snow>0)); %this must be normalized to conserve energy, check later with PARA.location.aerial_fraction +terrain_index_snow(isnan(terrain_index_snow))=0; + +terrain_index_snow_final=[]; +j=1; +for i=1:size(weight,2) + terrain_index_snow_final=[terrain_index_snow_final terrain_index_snow(1,j)]; + j=j+weight(1,i); +end + +%terrain_index_snow_final = terrain_index_snow_final./sum(terrain_index_snow_final(terrain_index_snow_final>0)); \ No newline at end of file diff --git a/modules/cryoGridLateral/checkPreconditionSnowExchange.m b/modules/cryoGridLateral/checkPreconditionSnowExchange.m new file mode 100644 index 0000000..fd0322f --- /dev/null +++ b/modules/cryoGridLateral/checkPreconditionSnowExchange.m @@ -0,0 +1,16 @@ +function [precond_snow] = checkPreconditionsSnowExchnge( GRID, PARA ) + + precondition_snowExchange = double( ~isempty(GRID.snow.cT_domain_ub) && ( PARA.ensemble.surface_altitude(labindex) > PARA.ensemble.altitude(labindex)+PARA.ensemble.immobile_snow_height(labindex) ) ); + + for j=1:numlabs + if j~=labindex + labSend( precondition_snowExchange, j, 3); + end + end + for j=1:numlabs + if j~=labindex + precondition_snowExchange = precondition_snowExchange + labReceive( j, 3); + end + end + + precond_snow = precondition_snowExchange > 0; % sufficient if one realization has mobile snow diff --git a/modules/cryoGridLateral/checkPreconditionWaterExchange.m b/modules/cryoGridLateral/checkPreconditionWaterExchange.m new file mode 100644 index 0000000..ba08da0 --- /dev/null +++ b/modules/cryoGridLateral/checkPreconditionWaterExchange.m @@ -0,0 +1,17 @@ +function [precond_water] = checkPreconditionsWaterExchange( T, GRID ) + + precondition_waterExchange = double( T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub) ); % matches with conditions of infiltration + + for j=1:numlabs + if j~=labindex + labSend( precondition_waterExchange_index, j, 2); + end + end + + for j=1:numlabs + if j~=labindex + precondition_waterExchange = precondition_waterExchange + labReceive( j, 2); + end + end + + precond_water = precondition_waterExchange > 1; % at least two workers need matching conditions diff --git a/modules/cryoGridLateral/getMaxSnowAltitude.m b/modules/cryoGridLateral/getMaxSnowAltitude.m new file mode 100644 index 0000000..2638f98 --- /dev/null +++ b/modules/cryoGridLateral/getMaxSnowAltitude.m @@ -0,0 +1,3 @@ +function max_snow = getMaxSnowAltitude(PARA) + max_snow = max( PARA.ensemble.altitude ) + PARA.snow.relative_maxSnow; +end diff --git a/modules/cryoGridLateral/getMaxWaterAltitude.m b/modules/cryoGridLateral/getMaxWaterAltitude.m new file mode 100644 index 0000000..dfa07e7 --- /dev/null +++ b/modules/cryoGridLateral/getMaxWaterAltitude.m @@ -0,0 +1,3 @@ +function max_water = getMaxWaterAltitude(PARA) + max_water = max( PARA.ensemble.altitude ) + PARA.soil.relative_maxWater; +end diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m new file mode 100644 index 0000000..a2a2c5a --- /dev/null +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -0,0 +1,78 @@ +function PARA = get_parallel_variables(PARA) + + index = labindex; + + % auxiliary calculations for circular geometry + diameter=10; % in [m] + area = pi.*(diameter./2)^2; % in [m^2] + perimeter = 2*pi.*(diameter./2); % in [m] + + % geometric relations + PARA.ensemble.distanceBetweenPoints= diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members + PARA.ensemble.weight = [1, 1];%[2, 1, 1]; + PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 + + % topographical relations + PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + PARA.ensemble.altitude = PARA.ensemble.initial_altitude; + PARA.ensemble.surface_altitude = PARA.ensemble.initial_altitude; + + % parameters related to heat exchange + PARA.ensemble.thermal_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); % [ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; % + + % parameters related to water exchange + PARA.ensemble.external_water_flux=[0, 0 ] ; % 0]; %in m/day + PARA.ensemble.hydraulic_conductivity= PARA.soil.hydraulic_conductivity * ( ones(numlabs) - eye(numlabs ) );%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; %in m/sec % [Roth: 1e-5 for saturated silt, 2.2e-5 for saturated sand] + PARA.ensemble.water_table_altitude = PARA.ensemble.altitude; %initialize somehow; + + %PARA.ensemble.max_water_flux= [0 0]; %in m water equivalent + PARA.ensemble.hydraulic_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) );%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; + PARA.ensemble.active_layer_depth_altitude = [NaN NaN NaN]; + PARA.ensemble.hydraulicDistance = PARA.ensemble.distanceBetweenPoints; + + % parameters related to snow exchange + %PARA.ensemble.snow_diffusivity = PARA.snow.diffusivity; + %PARA.ensemble.relative_max_snow_height = 0.2; + PARA.ensemble.immobile_snow_height = [0.1, 0.1 ]; %, 0.2 ]; %in m %this replaces PARA.snow.maxSnow ? + PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.altitude, PARA.ensemble.weight); + PARA.ensemble.snow_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); + + % location-specific static + PARA.location.initial_altitude = PARA.ensemble.initial_altitude(index); + PARA.soil.externalWaterFlux = PARA.ensemble.external_water_flux(index); + % location-specific dynamic auxiliary variables + PARA.location.altitude = PARA.ensemble.altitude(index); + PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index); + PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(index); + PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + % location-specific dynamic common thresholds + PARA.location.absolute_maxWater_altitude = [max( PARA.ensemble.altitude ) + PARA.soil.realtive_maxWater]; + PARA.location.absolute_maxSnow_altitude = [max( PARA.ensemble.altitude ) + PARA.snow.relative_maxSnow]; + + % different stratigraphies + PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % center stratigraphy without excess ice + 1.0 0.5 0.5 0.00 1 0.50 ;... + 10.0 0.25 0.75 0.00 1 0.25 ] , ... + [0.0 0.5 0.5 0.00 1 0.50;... % rim stratigraphy with excess ice + 0.7 0.8 0.2 0.00 1 0.50;... + 10.0 0.25 0.75 0.00 1 0.25 ], ... + [0.0 0.5 0.5 0.00 1 0.50;... % trough stratigraphy with excess ice + 0.1 0.8 0.2 0.00 1 0.50;... + 10.0 0.25 0.75 0.00 1 0.25 ]}; + + PARA.soil.layer_properties = PARA.soil.layer_properties{index}; + + + + % different initial conditions + PARA.Tinitial = [-5 5 5 5;... + 0 -5 -5 -5;... + 1 -5 -5 -5;... + 10 -8 -8 -8;... + 20 -10 -10 -10;... + 100 -10 -10 -10;... + 2000 10 10 10]; + + PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; + +end diff --git a/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m b/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m new file mode 100644 index 0000000..6a622fc --- /dev/null +++ b/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m @@ -0,0 +1,35 @@ +function [PARA] = updateAuxiliaryVariablesAndCommonThresholds( T, wc, GRID, PARA) + + PARA.ensemble.surface_altitude(labindex) = getSurfaceAltitude( PARA, GRID ); + PARA.ensemble.altitude(labindex) = getAltitude( PARA, GRID ); + PARA.ensemble.water_table_altitude(labindex) = getWaterTableAltitude(T, wc, GRID, PARA ); %JAN: Leo uses getWaterTabelFC to account for non-saturated cells above fieldCapacity + PARA.ensemble.active_layer_depth_altitude(labindex) = getActiveLayerDepthAltitude(PARA, GRID, T, labindex); + % sending information from "labindex" to all "j" + for j=1:numlabs + if j~=labindex + labSend(PARA.ensemble.surface_altitude(labindex), j, 1); + labSend(PARA.ensemble.altitude(labindex), j, 2); + labSend(PARA.ensemble.water_table(labindex), j, 3); + labSend(PARA.ensemble.active_layer_depth_altitude(labindex), j, 4); + end + end + % receiving --------------------------------------------------- + % receive information from all other realizations + for j=1:numlabs %update surface altitudes to recalculate terrain index + if j~=labindex + PARA.ensemble.surface_altitude(j)=labReceive(j, 1); + PARA.ensemble.altitude(j)=labReceive(j, 2); + PARA.ensemble.water_table(j)=labReceive(j, 3); + PARA.ensemble.active_layer_depth_altitude(j)=labReceive(j, 4); + end + end + + % update common thresholds for water and snow exchagne + PARA.location.absolute_maxSnow_altitude = getMaxSnowAltitude(PARA); + PARA.location.absolute_maxWater_altitude = getMaxWaterAltitude(PARA); + + % update auxiliary variables in location struct // MORE? + PARA.location.altitude = PARA.ensemble.altitude(index); + PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index); + PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(index); + PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); diff --git a/modules/cryoGridSEB/L_star.m b/modules/cryoGridSEB/L_star.m index ac3eed9..c27c3d9 100644 --- a/modules/cryoGridSEB/L_star.m +++ b/modules/cryoGridSEB/L_star.m @@ -19,12 +19,10 @@ % potential error here, pressure set to 1005 hPa, must be changed? -%Tz=Tz+273.15; - - u_star = real(uz.*kappa./(log(z./z0)- psi_M(z./Lstar, z0./Lstar))); L_star = real(-rho.*cp.*Tz./kappa./g.*u_star.^3./(Qh + 0.61.*cp./L.*Tz.*Qe)); -L_star=(abs(L_star)<1e-7).*L_star./abs(L_star).*1e-7 + (abs(L_star)>=1e-7).*L_star; %changed to 1e-5, as 1e-7 before +L_star=(abs(L_star)<1e-6).*L_star./abs(L_star).*1e-6 + (abs(L_star)>=1e-6).*L_star; % lower limit for Lstar (before 1e-7 and 1e-5) +L_star=(abs(L_star)>1e6).*L_star./abs(L_star).*1e6 + (abs(L_star)<=1e6).*L_star; % introduced upper limit for Lstar SEB.ustar = u_star; diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index 71aca34..510c98d 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -1,6 +1,5 @@ function [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_temp, timestep, BALANCE) -%L=3.34e5; -%L_lv=2.8e6; %also worng here. JAN: yes, should be smaller + if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis @@ -25,7 +24,6 @@ - ( SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i./nonAirFractionUppermostGridCell ...% - ( SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000./nonAirFractionUppermostGridCell ... - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i); %- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000); - %SEB.sublim=SEB.sublim+SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000; BALANCE.water.ds = BALANCE.water.ds - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i*1000; % sublimation in [mm] %---------- melt and infiltration ------------------------------------- @@ -44,27 +42,27 @@ c_temp(GRID.snow.cT_domain),... PARA); - %SEB.meltwater=SEB.meltwater+newMelt; BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt + (-newMelt.*1000); % in [mm] end %-------- add the new snow to the upper most snow cell in the case of a exisiting snow cover ------------------- - if isempty(PARA.snow.maxSnow) + if isempty( PARA.location.absolute_maxSnow_altitude ) deltaSnow_i = max(0, FORCING.i.snowfall.*timestep./1000); else snowHeight = abs( GRID.general.K_grid(GRID.snow.cT_domain_ub) - GRID.general.K_grid(GRID.snow.cT_domain_lb+1) ); + maxSnowHeight = PARA.location.absolute_maxSnow_altitude - getAltitude( PARA, GRID ); deltaSnow_i = max( [ 0, ... - min( [ FORCING.i.snowfall.*timestep./1000, ... - (PARA.snow.maxSnow - snowHeight ) .* PARA.snow.rho_snow ./ PARA.constants.rho_w ] ) ] ); %ensures that no more than maxSnow can accumulate + min( [ FORCING.i.snowfall.*timestep./1000, ... + (maxSnowHeight - snowHeight ) .* PARA.snow.rho_snow ./ PARA.constants.rho_w ] ) ] ); %ensures that no more than maxSnow can accumulate %account for excess snow in water balance BALANCE.water.dr_excessSnow = BALANCE.water.dr_excessSnow -( FORCING.i.snowfall.*timestep - deltaSnow_i*1000 ); %defined as negative when snow is removed end GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... - + deltaSnow_i; + + deltaSnow_i; GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... - + ( deltaSnow_i./(PARA.snow.rho_snow./ PARA.constants.rho_w) - deltaSnow_i); + + ( deltaSnow_i./(PARA.snow.rho_snow./ PARA.constants.rho_w) - deltaSnow_i); else %no snow cover @@ -87,4 +85,5 @@ PARA.snow.albedo=PARA.snow.max_albedo; SEB.newSnow=0; end + end \ No newline at end of file diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index 580833d..aac34c3 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -20,7 +20,7 @@ % ------- update SWE grid ------------------------------------- GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.SWEinitial; GRID.snow.Snow_w(GRID.snow.cT_domain_ub) = 0; - GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = (GRID.snow.SWEinitial./(PARA.snow.rho_snow./1000) - GRID.snow.SWEinitial); + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = (GRID.snow.SWEinitial./(PARA.snow.rho_snow./PARA.constants.rho_w) - GRID.snow.SWEinitial); GRID.snow.SWEinitial=0; % -------- update K grid ------------------------------------- diff --git a/modules/cryoGridSoil/createStratigraphy.m b/modules/cryoGridSoil/createStratigraphy.m index 185f2ce..7b8475b 100644 --- a/modules/cryoGridSoil/createStratigraphy.m +++ b/modules/cryoGridSoil/createStratigraphy.m @@ -19,8 +19,8 @@ GRID.soil.cT_soilType = interp1(soilParam(:,1),soilParam(:,5),GRID.general.cT_grid(GRID.soil.cT_domain),'nearest'); GRID.soil.cT_natPor = interp1(soilParam(:,1),soilParam(:,6),GRID.general.cT_grid(GRID.soil.cT_domain),'linear'); -GRID.soil.K_water = interp1(soilParam(:,1),soilParam(:,2),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -GRID.soil.K_mineral = interp1(soilParam(:,1),soilParam(:,3),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -GRID.soil.K_organic = interp1(soilParam(:,1),soilParam(:,4),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -GRID.soil.K_soilType = interp1(soilParam(:,1),soilParam(:,5),GRID.general.K_grid(GRID.soil.K_domain),'nearest'); +%GRID.soil.K_water = interp1(soilParam(:,1),soilParam(:,2),GRID.general.K_grid(GRID.soil.K_domain),'linear'); +%GRID.soil.K_mineral = interp1(soilParam(:,1),soilParam(:,3),GRID.general.K_grid(GRID.soil.K_domain),'linear'); +%GRID.soil.K_organic = interp1(soilParam(:,1),soilParam(:,4),GRID.general.K_grid(GRID.soil.K_domain),'linear'); +%GRID.soil.K_soilType = interp1(soilParam(:,1),soilParam(:,5),GRID.general.K_grid(GRID.soil.K_domain),'nearest'); diff --git a/modules/cryoGridSoil/initializeSoilThermalProperties.m b/modules/cryoGridSoil/initializeSoilThermalProperties.m index b02bf4d..6092e06 100644 --- a/modules/cryoGridSoil/initializeSoilThermalProperties.m +++ b/modules/cryoGridSoil/initializeSoilThermalProperties.m @@ -8,10 +8,7 @@ cT_mineral = GRID.soil.cT_mineral; cT_organic = GRID.soil.cT_organic; cT_soilType = GRID.soil.cT_soilType; -K_water = GRID.soil.K_water; -K_mineral = GRID.soil.K_mineral; -K_organic = GRID.soil.K_organic; -K_soilType = GRID.soil.K_soilType; + arraySize = PARA.technical.arraySizeT; cT_grid = GRID.general.cT_grid(GRID.soil.cT_domain); kh_bedrock = PARA.soil.kh_bedrock; @@ -42,24 +39,19 @@ organic=cT_organic; a=cT_soilType; - +% set cT_thawed cT_thawed=zeros(size(a,1),1); -%cT_frozen=-15*ones(size(a,1),1); - +% determine cT_frozen ch=mineral*c_m+organic*c_o+waterMin.*c_w+(water-waterMin)*c_i; - %preallocate variable c_h2o=ones(length(a),length(-30:0.01:-1)); - j=1; for i= -30:0.01:-1 c_h2o(:,j)=L_si*rho_w*(freezeC(water, 1-mineral-organic, a, i+deltaT/2, PARA)-freezeC(water, 1-mineral-organic, a, i-deltaT/2, PARA))/deltaT(1,1) < 0.05.*ch; j=j+1; end - %preallocate variables cT_frozen=-30+((sum(c_h2o')')-1).*0.01; - c_h2o=ones(length(a),length(1:arraySize-2)+1); water_c=c_h2o; ch=c_h2o; @@ -89,15 +81,6 @@ %---------- conductivity part --------------------------------------------- -% water=K_water; -% mineral=K_mineral; -% organic=K_organic; -% a=K_soilType; -%%K_frozen=-15*ones(size(a,1),1); -%K_frozen=[cT_frozen(1,1); 0.5.*(cT_frozen(1:end-1,1)+cT_frozen(2:end,1)) ; cT_frozen(end,1)]; -%K_thawed=zeros(size(a,1),1); - - % changed to cT-grid since K- interpolation is done external now % water=cT_water; % mineral=cT_mineral; @@ -111,7 +94,7 @@ % water_c2=ones(length(a),length(1:arraySize-2)+1); % water_c2(:,1)=freezeC(water, 1-mineral-organic, a, K_frozen, PARA); % JAN: this is identical to water_c for -conductivity=water_c; +conductivity=water_c; % initialize to same size as water_c % for i=1:arraySize-2 % water_c2(:,i+1)=freezeC(water, 1-mineral-organic, a, K_thawed+(K_frozen-K_thawed)*(arraySize-2-i)/(arraySize-2), PARA); @@ -128,11 +111,6 @@ conductivity=[conductivity conductivity(:,size(conductivity,2))]; %conductivity matrix for soil filled -% lastSnowCell=find((:,1)<0); -% lastSnowCell=lastSnowCell(end); -% conductivity(1:lastSnowCell,:) = repmat(kh_snow, lastSnowCell, size(conductivity,2)); - - %----------- write lookup tables to GRID struct liquidWaterContent = real(liquidWaterContent); @@ -142,8 +120,6 @@ GRID.soil.cT_frozen = cT_frozen; GRID.soil.cT_thawed = cT_thawed; -GRID.soil.K_frozen = K_frozen; -GRID.soil.K_thawed = K_thawed; GRID.soil.conductivity = conductivity; GRID.soil.capacity = capacity; GRID.soil.liquidWaterContent = liquidWaterContent; @@ -155,26 +131,23 @@ %content is 'water' by default function waterC = freezeC(thetaTot, thetaSat, soilType, T, PARA) T=T+273.15; - % thetaTot=0.3; - % thetaSat=0.4; + thetaTot=min(thetaSat, thetaTot); thetaRes=zeros(size(soilType)); alpha=zeros(size(soilType)); n=zeros(size(soilType)); - %set conditions for soil types - thetaRes(soilType==1) = 0; - alpha(soilType==1) = 4; - n(soilType==1) = 2; + thetaRes(soilType==1) = PARA.soil.soilType(1,1); + alpha(soilType==1) = PARA.soil.soilType(1,3); + n(soilType==1) = PARA.soil.soilType(1,4); - thetaRes(soilType==2) = 0.05; - alpha(soilType==2) = 0.65; - n(soilType==2) = 1.7; + thetaRes(soilType==2) = PARA.soil.soilType(2,1); + alpha(soilType==2) = PARA.soil.soilType(2,3); + n(soilType==2) = PARA.soil.soilType(2,4); m=1-1./n; waterPotZero=-1./alpha .*( ((thetaTot-thetaRes)./(thetaSat-thetaRes) ).^(-1./m) -1 ).^(1./n); - %Tstar=273.15+9.81.*273.15./3.34e5.*waterPotZero; Tstar = 273.15 + PARA.constants.g .* 273.15 ./ PARA.constants.L_sl .* waterPotZero; waterC=zeros(size(T)); @@ -182,7 +155,7 @@ waterC(T>=273.15) = thetaTot(T>=273.15); - % OLD implementation ( plateau from 0 to -0.05 ) + % implementation ( linear from 0 to -0.05 ) waterPot(T<273.15 & T>273.1) = waterPotZero(T<273.15 & T>273.1)... + (3.34e5./9.81./Tstar(T<273.15 & T>273.1).*(273.1-Tstar(T<273.15 & T>273.1)))... .* (273.1273.1)); @@ -201,29 +174,10 @@ waterC( isnan(waterC) ) = thetaRes( isnan(waterC) ); -%JAN: new implementation ( smooth functions ) +%JAN: alternative implementation ( smooth functions ) % waterPot(T<=273.15)= waterPotZero(T<=273.15)+(PARA.constants.L_sl./PARA.constants.g./Tstar(T<=273.15).*(T(T<=273.15)-Tstar(T<=273.15))).*(T(T<=273.15)=273.15 - % waterC(i,1)=thetaTot(i,1); - % else - % - % if T(i,1)>273.1 - % - % - % waterPot=waterPotZero(i,1)+(3.34e5./9.81./Tstar(i,1).*(273.1-Tstar(i,1))).*(273.10; % Condition to work on infiltration + T=T(GRID.soil.cT_domain); + i=1; + i_max=200; + while T(i)>0 && i<=i_max + i=i+1; + end + ald_cT_index=i-1; + ald_altitude = PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub+ald_cT_index); + end + + +end diff --git a/modules/cryoGridTechnical/getAltitude.m b/modules/cryoGridTechnical/getAltitude.m new file mode 100644 index 0000000..4acd540 --- /dev/null +++ b/modules/cryoGridTechnical/getAltitude.m @@ -0,0 +1,5 @@ +function altitude = getAltitude( PARA, GRID ) + + altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.soil.cT_domain_ub); + +end \ No newline at end of file diff --git a/modules/cryoGridTechnical/getSurfaceAltitude.m b/modules/cryoGridTechnical/getSurfaceAltitude.m new file mode 100644 index 0000000..802f7c6 --- /dev/null +++ b/modules/cryoGridTechnical/getSurfaceAltitude.m @@ -0,0 +1,10 @@ +function surface_altitude = getSurfaceAltitude(PARA, GRID) + +surface_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.air.cT_domain_lb+1) + +%if ~isempty(GRID.snow.cT_domain_ub) +% surface_altitude = PARA.location.altitude + sum( GRID.general.K_delta(GRID.snow.cT_domain) ); +%else +% surface_altitude = PARA.location.altitude; +%end + diff --git a/modules/cryoGridTechnical/getWaterTableAltitude.m b/modules/cryoGridTechnical/getWaterTableAltitude.m new file mode 100644 index 0000000..9ee41b9 --- /dev/null +++ b/modules/cryoGridTechnical/getWaterTableAltitude.m @@ -0,0 +1,24 @@ +function waterTable = getWaterTableAltitude(T, wc, GRID, PARA) + + T=T(GRID.soil.cT_domain); + K_delta=GRID.general.K_delta(GRID.soil.cT_domain); %in m + + if ~isempty(GRID.snow.cT_domain_ub) || T(1)<=0 + waterTable=NaN; + else + waterTable = PARA.location.altitude; + water = wc; + porosity=(1. - GRID.soil.cT_mineral - GRID.soil.cT_organic); + i=1; + while water(i)0 + waterTable = waterTable - K_delta(i); + i=i+1; + end + + if T(i)<=0; + waterTable=NaN; + disp('Dry to permafrost - waterTable=NaN \n')% Loop was stopped by the temperature condition so no water table + end + end + +end diff --git a/modules/cryoGridTechnical/iSaveOUT.m b/modules/cryoGridTechnical/iSaveOUT.m new file mode 100644 index 0000000..85603c8 --- /dev/null +++ b/modules/cryoGridTechnical/iSaveOUT.m @@ -0,0 +1,3 @@ +function iSaveOUT( fname, OUT ) + save( fname, 'OUT' ); +end \ No newline at end of file diff --git a/modules/cryoGridTechnical/iSaveSettings.m b/modules/cryoGridTechnical/iSaveSettings.m new file mode 100644 index 0000000..8a3bcdd --- /dev/null +++ b/modules/cryoGridTechnical/iSaveSettings.m @@ -0,0 +1,3 @@ +function iSaveSettings( fname, FORCING, PARA, GRID) + save( fname, 'FORCING', 'PARA', 'GRID' ); +end \ No newline at end of file diff --git a/modules/cryoGridTechnical/iSaveState.m b/modules/cryoGridTechnical/iSaveState.m new file mode 100644 index 0000000..7554638 --- /dev/null +++ b/modules/cryoGridTechnical/iSaveState.m @@ -0,0 +1,3 @@ +function iSaveState( fname, T, wc, t, SEB, PARA, GRID) + save( fname, 'T', 'wc', 't', 'SEB', 'PARA', 'GRID' ); +end \ No newline at end of file diff --git a/modules/cryoGridTechnical/loadSoilTypes.m b/modules/cryoGridTechnical/loadSoilTypes.m new file mode 100644 index 0000000..c6a2572 --- /dev/null +++ b/modules/cryoGridTechnical/loadSoilTypes.m @@ -0,0 +1,7 @@ +function [PARA] = loadSoilTypes(PARA) + + % specify one soil type per row: residualWC [%], fieldCapacity [%], alpha [1/m], n + PARA.soil.soilTypes = [ [ 0.00, PARA.soil.fieldCapacity, 4.00, 2.0 ]; ... % sand + [ 0.05, PARA.soil.fieldCapacity, 0.65, 1.7 ] ]; % silt + +% JAN: additional type for water? [ 0.00, 1.0, 4.00, 2.0 ] diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index ebc2600..71c95c6 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -1,4 +1,4 @@ -function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number) +function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes); TEMPORARY.timestep_sum=TEMPORARY.timestep_sum+(timestep*24*3600)*timestep; @@ -12,9 +12,6 @@ TEMPORARY.dE_dt_SEB_sum = TEMPORARY.dE_dt_SEB_sum + SEB.dE_dt_SEB * timestep; TEMPORARY.dE_dt_cond_sum = TEMPORARY.dE_dt_cond_sum + SEB.dE_dt_cond * timestep; - - - %----store in output table -------------------------------------------- if t==TEMPORARY.outputTime @@ -50,24 +47,18 @@ TEMPORARY.dE_dt_SEB_sum=0; TEMPORARY.dE_dt_cond_sum=0; - TEMPORARY.timestep_sum=0; - %store new values in OUT struct ----------------------------------- + %------ store new values in OUT struct ----------------------------------- + + % key state variables OUT.cryoGrid3=[OUT.cryoGrid3 [NaN(GRID.air.cT_domain_lb,1); TEMPORARY.T_out(GRID.air.cT_domain_lb+1:end,1)]]; OUT.water=[OUT.water [ NaN( GRID.soil.cT_domain_ub-1,1) ; wc ] ]; OUT.liquidWater=[OUT.liquidWater [ NaN( GRID.soil.cT_domain_ub-1,1) ; lwc ] ]; OUT.TIMESTEP=[OUT.TIMESTEP; TEMPORARY.timestep_out]; OUT.timestamp=[OUT.timestamp; t]; - OUT.snow.outSnow_i=[OUT.snow.outSnow_i GRID.snow.Snow_i]; - OUT.snow.outSnow_a=[OUT.snow.outSnow_a GRID.snow.Snow_a]; - OUT.snow.outSnow_w=[OUT.snow.outSnow_w GRID.snow.Snow_w]; - - % surface energy balance - OUT.SEB.dE_dt_SEB = [OUT.SEB.dE_dt_SEB [ TEMPORARY.dE_dt_SEB ] ]; - OUT.SEB.dE_dt_cond = [OUT.SEB.dE_dt_cond [ TEMPORARY.dE_dt_cond ]]; - + % realated to surface energy balance OUT.SEB.Lsta=[OUT.SEB.Lsta; mean(SEB.L_star)]; OUT.SEB.QE=[OUT.SEB.QE; TEMPORARY.Qe]; OUT.SEB.QH=[OUT.SEB.QH; TEMPORARY.Qh]; @@ -75,28 +66,48 @@ OUT.SEB.QNET=[OUT.SEB.QNET; TEMPORARY.Qnet]; OUT.SEB.Tsurf=[OUT.SEB.Tsurf; TEMPORARY.T_out(GRID.air.cT_domain_lb+1)]; OUT.SEB.albedo_stored=[OUT.SEB.albedo_stored; PARA.surf.albedo]; - - % complete energy balance (EB) - OUT.EB.Qg = [OUT.EB.Qg; TEMPORARY.Qg]; % ground heat flux (positive into ground) - OUT.EB.Qe = [OUT.EB.Qe; TEMPORARY.Qe]; % latent heat flux (positive into ground) - OUT.EB.Qh = [OUT.EB.Qh; TEMPORARY.Qh]; % sensible heat flux (positive into ground) - OUT.EB.Qnet = [OUT.EB.Qnet; TEMPORARY.Qnet]; - OUT.EB.Qgeo = [OUT.EB.Qgeo; PARA.soil.Qgeo]; % geothermal heat flux - OUT.EB.Qsurf = [OUT.EB.Qsurf; TEMPORARY.Qsurf]; - OUT.EB.dE_soil_sens = [OUT.EB.dE_soil_sens; BALANCE.energy.dE_soil_sens ]; - BALANCE.energy.dE_soil_sens = 0; - OUT.EB.dE_soil_lat = [OUT.EB.dE_soil_lat; BALANCE.energy.dE_soil_lat ]; - BALANCE.energy.dE_soil_lat = 0; - OUT.EB.dE_soil = [OUT.EB.dE_soil; BALANCE.energy.dE_soil ]; - BALANCE.energy.dE_soil = 0; - OUT.EB.dE_snow_sens = [ OUT.EB.dE_snow_sens; BALANCE.energy.dE_snow_sens ]; - BALANCE.energy.dE_snow_sens = 0; - OUT.EB.dE_snow_lat = [ OUT.EB.dE_snow_lat; BALANCE.energy.dE_snow_lat ]; - BALANCE.energy.dE_snow_lat = 0; - OUT.EB.dE_snow = [ OUT.EB.dE_snow; BALANCE.energy.dE_snow ]; - BALANCE.energy.dE_snow = 0; - - % water balance (WB) + + + % related to soil + OUT.soil.topPosition=[OUT.soil.topPosition; -GRID.general.K_grid(GRID.soil.cT_domain_ub)]; + if ~isempty( GRID.lake.cT_domain_ub ) + OUT.soil.lakeFloor = [OUT.soil.lakeFloor; - GRID.general.K_grid(GRID.lake.cT_domain_lb+1) ]; + else + OUT.soil.lakeFloor = [OUT.soil.lakeFloor; NaN]; + end + OUT.soil.soil{1, size(OUT.soil.soil,2)+1}=[GRID.soil.cT_water GRID.soil.cT_mineral GRID.soil.cT_organic]; + + + % related to snow + OUT.snow.outSnow_i=[OUT.snow.outSnow_i GRID.snow.Snow_i]; + OUT.snow.outSnow_a=[OUT.snow.outSnow_a GRID.snow.Snow_a]; + OUT.snow.outSnow_w=[OUT.snow.outSnow_w GRID.snow.Snow_w]; + if ~isempty(GRID.snow.cT_domain_ub) + TEMPORARY.topPosition=-GRID.general.K_grid(GRID.snow.cT_domain_ub); + TEMPORARY.botPosition=-GRID.general.K_grid(GRID.snow.cT_domain_lb+1); + else + TEMPORARY.topPosition=NaN; + TEMPORARY.botPosition=NaN; + end + OUT.snow.topPosition=[OUT.snow.topPosition; TEMPORARY.topPosition]; + OUT.snow.botPosition=[OUT.snow.botPosition; TEMPORARY.botPosition]; + + + + % derived characteristics and related to geometry + OUT.loaction.area = [OUT.location.area; PARA.location.area]; + OUT.location.altitude=[OUT.loacation.altitude; PARA.location.altitude]; + OUT.location.surface_altitude=[OUT.location.surface_altitude; PARA.location.surface_altitude]; + OUT.location.active_layer_depth_altitude = [OUT.location.active_layer_depth_altitude; PARA.location.active_layer_depth_altitude]; + OUT.location.water_table=[OUT.location.water_table; PARA.location.water_table]; + + % lateral fluxes + OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow; PARA.ensemble.terrain_index_snow ]; + OUT.lateral.water_fluxes = [ OUT.lateral.water_fluxes; water_fluxes ]; % vector containing water fluxes in [m/s] to the current worker + OUT.lateral.snow_fluxes = [ OUT.lateral.snow_fluxes; snow_fluxes ]; % vector containing snow fluxes in [m SWE / s] to the current worker + OUT.lateral.heat_fluxes = [ OUT.lateral.heat_fluxes; heat_fluxes ]; % vector containing depth-integrated heat fluxes in [J/m^2 s ] to the current worker + + % water balance (WB) % all flows are defined as positive when they go into the soil/snow column % cumulative values per output interval in [mm] % storage @@ -113,9 +124,11 @@ OUT.WB.dr_external = [ OUT.WB.dr_external; BALANCE.water.dr_external ]; OUT.WB.dr_snowmelt = [ OUT.WB.dr_snowmelt; BALANCE.water.dr_snowmelt ]; OUT.WB.dr_excessSnow=[ OUT.WB.dr_excessSnow; BALANCE.water.dr_excessSnow ]; - OUT.WB.dr_rain = [ OUT.WB.dr_rain; BALANCE.water.dr_rain ]; % this is only rain on frozen ground + OUT.WB.dr_lateralSnow=[ OUT.WB.dr_lateralSnow; BALANCE.water.dr_lateralSnow ]; % lateral snow flux to other realizations + OUT.WB.dr_rain = [ OUT.WB.dr_rain; BALANCE.water.dr_rain ]; % this is only rain on frozen ground + OUT.WB.dr_lateral = [OUT.WB.dr_lateral; BALANCE.water.dr_lateral ]; % lateral water flux to other realizations % mismatch - OUT.WB.d_lackgin = [OUT.WB.d_lacking; BALANCE.water.d_lacking ]; + OUT.WB.dm_lacking = [OUT.WB.dm_lacking; BALANCE.water.dm_lacking ]; % set accumulated fluxes in BALANCE.water struct to zero % storage BALANCE.water.dW_soil = 0; @@ -131,41 +144,38 @@ BALANCE.water.dr_external=0; BALANCE.water.dr_snowmelt=0; BALANCE.water.dr_excessSnow=0; + BALANCE.water.dr_lateralSnow=0; BALANCE.water.dr_rain=0; + BALANCE.water.dr_lateral=0; %mismatch - BALANCe.water.d_lacking=0; + BALANCE.water.dm_lacking=0; + + % complete energy balance (EB) + OUT.EB.Qg = [OUT.EB.Qg; TEMPORARY.Qg]; % ground heat flux (positive into ground) + OUT.EB.Qe = [OUT.EB.Qe; TEMPORARY.Qe]; % latent heat flux (positive into ground) + OUT.EB.Qh = [OUT.EB.Qh; TEMPORARY.Qh]; % sensible heat flux (positive into ground) + OUT.EB.Qnet = [OUT.EB.Qnet; TEMPORARY.Qnet]; + OUT.EB.Qgeo = [OUT.EB.Qgeo; PARA.soil.Qgeo]; % geothermal heat flux + OUT.EB.dE_soil_sens = [OUT.EB.dE_soil_sens; BALANCE.energy.dE_soil_sens ]; + BALANCE.energy.dE_soil_sens = 0; + OUT.EB.dE_soil_lat = [OUT.EB.dE_soil_lat; BALANCE.energy.dE_soil_lat ]; + BALANCE.energy.dE_soil_lat = 0; + OUT.EB.dE_soil = [OUT.EB.dE_soil; BALANCE.energy.dE_soil ]; + BALANCE.energy.dE_soil = 0; + OUT.EB.dE_snow_sens = [ OUT.EB.dE_snow_sens; BALANCE.energy.dE_snow_sens ]; + BALANCE.energy.dE_snow_sens = 0; + OUT.EB.dE_snow_lat = [ OUT.EB.dE_snow_lat; BALANCE.energy.dE_snow_lat ]; + BALANCE.energy.dE_snow_lat = 0; + OUT.EB.dE_snow = [ OUT.EB.dE_snow; BALANCE.energy.dE_snow ]; + BALANCE.energy.dE_snow = 0; + OUT.EB.Q_lateral = [OUT.EB.Q_lateral, [ BALANCE.energy.Q_lateral ] ]; + BALANCE.energy.Q_lateral = zeros( length(GRID.general.cT_grid) , 1 ); + + % for DEBUGGING + OUT.debugging.dE_dt_SEB = [OUT.debugging.dE_dt_SEB [ TEMPORARY.dE_dt_SEB ] ]; + OUT.debugging.dE_dt_cond = [OUT.debugging.dE_dt_cond [ TEMPORARY.dE_dt_cond ] ]; + OUT.debugging.K_grid = [OUT.debugging.K_grid, GRID.general.K_grid ]; - % soil - OUT.soil.soil{1, size(OUT.soil.soil,2)+1}=[GRID.soil.cT_water GRID.soil.cT_mineral GRID.soil.cT_organic]; - OUT.soil.topPosition=[OUT.soil.topPosition; -GRID.general.K_grid(GRID.soil.cT_domain_ub)]; - - % water body -% waterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6; -% if sum(waterBody)>0 -% OUT.soil.lakeFloor = [OUT.soil.lakeFloor; - GRID.general.K_grid( GRID.soil.cT_domain_ub + find(waterBody,1,'last') ) ] ; -% else -% OUT.soil.lakeFloor = [OUT.soil.lakeFloor; NaN]; -% end - if ~isempty( GRID.lake.cT_domain_ub ) - OUT.soil.lakeFloor = [OUT.soil.lakeFloor; - GRID.general.K_grid(GRID.lake.cT_domain_lb+1) ]; - else - OUT.soil.lakeFloor = [OUT.soil.lakeFloor; NaN]; - end - - % snow - if ~isempty(GRID.snow.cT_domain_ub) - TEMPORARY.topPosition=-GRID.general.K_grid(GRID.snow.cT_domain_ub); - TEMPORARY.botPosition=-GRID.general.K_grid(GRID.snow.cT_domain_lb+1); - else - TEMPORARY.topPosition=NaN; - TEMPORARY.botPosition=NaN; - end - OUT.snow.topPosition=[OUT.snow.topPosition; TEMPORARY.topPosition]; - OUT.snow.botPosition=[OUT.snow.botPosition; TEMPORARY.botPosition]; - - % for DEBUGGING - OUT.K_grid = [OUT.K_grid, GRID.general.K_grid ]; - %------------------------------------------------------------------ disp([datestr(now,'yyyy-mm-dd HH:MM:SS'),': at ',datestr(t), ', Average timestep: ', num2str(TEMPORARY.timestep_out), ' seconds']) @@ -174,9 +184,9 @@ %write output files if round((t-TEMPORARY.saveTime).*48)==0 - save(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], 'OUT') - save(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], 'T', 'wc', 'SEB', 'PARA', 'GRID') + iSaveOUT(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) + iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, SEB, PARA, GRID) OUT = generateOUT(); TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(datestr(t,'mm')), str2num(datestr(t,'dd')), str2num(datestr(t,'HH')), str2num(datestr(t,'MM')), 0); end - end \ No newline at end of file + end From c0a9be5c00fd57428d3bfb8f9c706b7400968353 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Mon, 5 Feb 2018 17:59:57 +0100 Subject: [PATCH 12/45] bugfixing last commit such that model is running stable. --- CryoGrid3_xice_mpi.m | 31 +++++++++--------- add_modules.m | 4 +-- analysis/plot_output.m | 22 ++++++------- .../bucketScheme.m | 6 ++-- .../calculateLateralWaterFluxes.m | 6 ++-- .../checkPreconditionSnowExchange.m | 2 +- .../checkPreconditionWaterExchange.m | 4 +-- .../cryoGridLateral/get_parallel_variables.m | 3 +- ...ateAuxiliaryVariablesAndCommonThresholds.m | 14 ++++---- .../initializeSoilThermalProperties.m | 32 ++++++++++--------- modules/cryoGridTechnical/generateOUT.m | 4 +-- .../cryoGridTechnical/getSurfaceAltitude.m | 2 +- .../cryoGridTechnical/getWaterTableAltitude.m | 4 +-- modules/cryoGridTechnical/loadConstants.m | 2 +- modules/cryoGridTechnical/loadSoilTypes.m | 2 +- .../cryoGridTechnical/sum_up_output_store.m | 17 +++++----- 16 files changed, 81 insertions(+), 74 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 444ac90..33fb036 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -10,7 +10,7 @@ add_modules; %adds required modules -dbstop if error; +%dbstop if error; number_of_realizations=2; @@ -68,7 +68,8 @@ PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up - PARA = loadSoilTypes(); + PARA.soil.hydraulic_conductivity = 1e-5; + PARA = loadSoilTypes( PARA ); % parameters related to snow PARA.snow.max_albedo=0.85; % albedo of fresh snow @@ -100,12 +101,12 @@ PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1979, 6, 15); % endtime of the simulation - if empty end at last value of time series + PARA.technical.endtime=datenum(1980, 6, 1); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.syncTimestep = 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] @@ -114,6 +115,7 @@ PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + PARA.location.area=1.0; PARA.location.initial_altitude=20.0; % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain @@ -121,11 +123,11 @@ PARA.location.active_layer_depth_altitude = nan; % defined at runtime PARA.location.water_table_altitude = nan; % defined at runtime % thresholds - PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.waterTable; + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; if isempty( PARA.snow.relative_maxSnow ) PARA.location.absolute_maxSnow_altitude = []; else - PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.maxSnow ]; + PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; end %initial temperature profile -> first column depth [m] -> second column temperature [degree C] @@ -280,7 +282,7 @@ % account for lateral heat fluxes T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] % set grid cells in air to air temperature - T(GRID.air.cT_domain)=FORCING.i.Tair; + T(GRID.air.cT_domain)=FORCING.i.Tair; %------- water body module -------------------------------------------- T = mixingWaterBody(T, GRID); @@ -313,7 +315,7 @@ PARA.location.altitude = getAltitude( PARA, GRID ); PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); - PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); + PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time if ~PARA.modules.lateral @@ -331,7 +333,6 @@ % snowfall BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval - %------- lateral exchange module -------------------------------------- % all functions called in this block should go into % /modules/cryoGridLateral @@ -340,7 +341,7 @@ if t==TEMPORARY.syncTime %communication between workers disp('CryoGridLateral: sync - start'); labBarrier(); %common start - updateAuxiliaryVariablesAndCommonThresholds() ; + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; % heat exchange module if PARA.modules.exchange_heat @@ -376,13 +377,13 @@ if PARA.modules.exchange_water labBarrier(); % check preconditions - precondition_waterExchage = checkPreconditionsWaterExchange( T, GRID ) + precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); if precondition_waterExchange % WRAPPER disp('sync - exchanging water'); % calculate lateral water fluxes water_fluxes = nan( number_of_realizations, 1 ); % in [m/s] - PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table(index); + PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); for j=1:number_of_realizations @@ -408,7 +409,7 @@ if PARA.modules.exchange_snow labBarrier(); % check preconditions - precondition_snowExchange = checkPreconditionsSnowExchnge( GRID, PARA ) + precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); if precondition_snowExchange disp('sync - exchanging snow'); % calculate terrain index with updated surface_altitudes @@ -460,7 +461,7 @@ end labBarrier(); - updateAuxiliaryVariablesAndCommonThresholds() ; + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; disp('sync - done'); @@ -486,4 +487,4 @@ delete(gcp('nocreate')) end -disp('Done.'); +disp('Done.'); \ No newline at end of file diff --git a/add_modules.m b/add_modules.m index 12489eb..daa7705 100644 --- a/add_modules.m +++ b/add_modules.m @@ -5,9 +5,9 @@ clear all close all + profile off -%dbclear if error -dbstop if error + %import CryoGrid modules (matlab functions) addpath('modules/cryoGridTechnical/') diff --git a/analysis/plot_output.m b/analysis/plot_output.m index 87cd51b..023d78b 100644 --- a/analysis/plot_output.m +++ b/analysis/plot_output.m @@ -3,12 +3,12 @@ % %function plot_output(dirname, runname, number_of_realizations) -%clear all +clear all close all - dirname = '../runs/'; - runname = 'SPINUP-EXICE_197906-201406_stratSamExice_rf1_sf1_maxSnow0.40_snowDens=200_wt0.0_extFlux0.0000_fc0.30_exice0.60_natPor0.40'; - number_of_realizations = 1; + dirname = '/home/jnitzbon/CryoGrid/github/GITHUB_CryoGrid3_infiltration_xice_mpi/runs/'; + runname = 'testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1.000000_sF1.000000_realization'; + number_of_realizations = 2; % %% load output data and settings from files of all workers @@ -30,7 +30,7 @@ if number_of_realizations>1 run = [ run num2str(i) ]; end - outputfile = [dir run '/' run '_output2012.mat']; + outputfile = [dir run '/' run '_output1979.mat']; configfile = [dir run '/' run '_settings.mat']; load(outputfile); @@ -82,7 +82,7 @@ subplot(2,3,1) hold on for i=1:number_of_realizations - plot(ts, OUTS{1}.OUT.ensemble.active_layer_depth_altitude(:,i)) ; %abs(OUTS{1}.OUT.ensemble.altitude(:,i)- + plot(ts, OUTS{i}.OUT.location.active_layer_depth_altitude(:)) ; %abs(OUTS{1}.OUT.ensemble.altitude(:,i)- end datetick; title('Frost table [m asl]') @@ -91,7 +91,7 @@ subplot(2,3,2) hold on for i=1:number_of_realizations - plot(ts, OUTS{1}.OUT.ensemble.water_table(:,i)); + plot(ts, OUTS{i}.OUT.location.water_table_altitude(:)); end datetick; title('Water table [m asl]') @@ -100,7 +100,7 @@ subplot(2,3,3) hold on for i=1:number_of_realizations - plot(ts, OUTS{1}.OUT.ensemble.surface_altitude(:,i)); + plot(ts, OUTS{i}.OUT.location.surface_altitude(:)); end datetick; title('Surface altitude [m asl]') @@ -109,7 +109,7 @@ subplot(2,3,4) hold on for i=1:number_of_realizations - plot(ts, nansum(OUTS{i}.OUT.ensemble.heat_fluxes , 2)); + plot(ts, nansum(OUTS{i}.OUT.lateral.heat_fluxes , 2)); end datetick; title('Heat fluxes [ W / m^2 ]') @@ -118,7 +118,7 @@ subplot(2,3,5) hold on for i=1:number_of_realizations - plot(ts, nansum(OUTS{i}.OUT.ensemble.water_fluxes .*1000 .* 3600 , 2)); + plot(ts, nansum(OUTS{i}.OUT.lateral.water_fluxes .*1000 .* 3600 , 2)); end datetick; title('Water fluxes [mm/h]') @@ -127,7 +127,7 @@ subplot(2,3,6) hold on for i=1:number_of_realizations - plot(ts, nansum(OUTS{i}.OUT.ensemble.snow_fluxes .*1000 .* 3600 , 2) ); + plot(ts, nansum(OUTS{i}.OUT.lateral.snow_fluxes .*1000 .* 3600 , 2) ); end datetick; title('Snow fluxes [mm/h]') diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m index 258a3af..ef1858e 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m @@ -10,7 +10,7 @@ residualWaterContent = zeros(size(soilType)); for i=1:size(PARA.soil.soilTypes,1) fieldCapacity(soilType==i) = PARA.soil.soilTypes( i, 2 ); - residualWaterContent(soilType==1) = PARA.soil.soilType( i, 1 ); + residualWaterContent(soilType==1) = PARA.soil.soilTypes( i, 1 ); end lacking_water=0; @@ -32,6 +32,9 @@ excess_water=dwc_dt(i)+external_flux; %add external flux +lacking_water = lacking_water + (excess_water<0)*excess_water; % this accounts for violations of the water balance + + i=i-1; while i>=1 && excess_water>0 @@ -43,6 +46,5 @@ i=i-1; end -lacking_water = lacking_water + (excess_water<0)*excess_water; % this accounts for violations of the water balance surface_runoff=(excess_water>0)*excess_water; % surface runoff only if excess_water>0 diff --git a/modules/cryoGridLateral/calculateLateralWaterFluxes.m b/modules/cryoGridLateral/calculateLateralWaterFluxes.m index 7b5745b..945ff2d 100644 --- a/modules/cryoGridLateral/calculateLateralWaterFluxes.m +++ b/modules/cryoGridLateral/calculateLateralWaterFluxes.m @@ -22,7 +22,7 @@ if infiltration_condition_index && infiltration_condition_j - wt_index = PARA.ensemble.water_table(index); + wt_index = PARA.ensemble.water_table_altitude(index); wt_j = PACKAGE_waterExchange_j.water_table_altitude; ald_index = PARA.ensemble.active_layer_depth_altitude(index); ald_j = PACKAGE_waterExchange_j.active_layer_depth_altitude; @@ -33,7 +33,7 @@ [waterpotWj, hasWater_j] = nanmax([wt_j, ald_j ] ); - if (waterpotWj > waterpotWindex && hasWater_j==1);% Current worker is gaining water + if (waterpotWj > waterpotWindex && hasWater_j==1)% Current worker is gaining water % Calculate the maximum exchanged water volume DeltaH = waterpotWj - waterpotWindex; @@ -74,7 +74,7 @@ % PARA.ensemble.lateralFlux_inWaterHeight(index,j)=(PARA.ensemble.weight(j)/PARA.ensemble.weight(index)).*lateralFlux_inWaterHeight; % water_flux_j=DarcyFlux; - elseif (waterpotWindex > waterpotWj && hasWater_index==1); % Current worker is loosing water + elseif (waterpotWindex > waterpotWj && hasWater_index==1) % Current worker is loosing water % Calculate maximum of the exchange water volume DeltaH= waterpotWindex - waterpotWj; diff --git a/modules/cryoGridLateral/checkPreconditionSnowExchange.m b/modules/cryoGridLateral/checkPreconditionSnowExchange.m index fd0322f..2daa206 100644 --- a/modules/cryoGridLateral/checkPreconditionSnowExchange.m +++ b/modules/cryoGridLateral/checkPreconditionSnowExchange.m @@ -1,4 +1,4 @@ -function [precond_snow] = checkPreconditionsSnowExchnge( GRID, PARA ) +function [precond_snow] = checkPreconditionSnowExchange( GRID, PARA ) precondition_snowExchange = double( ~isempty(GRID.snow.cT_domain_ub) && ( PARA.ensemble.surface_altitude(labindex) > PARA.ensemble.altitude(labindex)+PARA.ensemble.immobile_snow_height(labindex) ) ); diff --git a/modules/cryoGridLateral/checkPreconditionWaterExchange.m b/modules/cryoGridLateral/checkPreconditionWaterExchange.m index ba08da0..aef070c 100644 --- a/modules/cryoGridLateral/checkPreconditionWaterExchange.m +++ b/modules/cryoGridLateral/checkPreconditionWaterExchange.m @@ -1,10 +1,10 @@ -function [precond_water] = checkPreconditionsWaterExchange( T, GRID ) +function [precond_water] = checkPreconditionWaterExchange( T, GRID ) precondition_waterExchange = double( T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub) ); % matches with conditions of infiltration for j=1:numlabs if j~=labindex - labSend( precondition_waterExchange_index, j, 2); + labSend( precondition_waterExchange, j, 2); end end diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index a2a2c5a..391bfc5 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -41,12 +41,13 @@ PARA.location.initial_altitude = PARA.ensemble.initial_altitude(index); PARA.soil.externalWaterFlux = PARA.ensemble.external_water_flux(index); % location-specific dynamic auxiliary variables + PARA.location.area = PARA.ensemble.area(index); PARA.location.altitude = PARA.ensemble.altitude(index); PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index); PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(index); PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); % location-specific dynamic common thresholds - PARA.location.absolute_maxWater_altitude = [max( PARA.ensemble.altitude ) + PARA.soil.realtive_maxWater]; + PARA.location.absolute_maxWater_altitude = [max( PARA.ensemble.altitude ) + PARA.soil.relative_maxWater]; PARA.location.absolute_maxSnow_altitude = [max( PARA.ensemble.altitude ) + PARA.snow.relative_maxSnow]; % different stratigraphies diff --git a/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m b/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m index 6a622fc..c6cbc6b 100644 --- a/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m +++ b/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m @@ -3,13 +3,13 @@ PARA.ensemble.surface_altitude(labindex) = getSurfaceAltitude( PARA, GRID ); PARA.ensemble.altitude(labindex) = getAltitude( PARA, GRID ); PARA.ensemble.water_table_altitude(labindex) = getWaterTableAltitude(T, wc, GRID, PARA ); %JAN: Leo uses getWaterTabelFC to account for non-saturated cells above fieldCapacity - PARA.ensemble.active_layer_depth_altitude(labindex) = getActiveLayerDepthAltitude(PARA, GRID, T, labindex); + PARA.ensemble.active_layer_depth_altitude(labindex) = getActiveLayerDepthAltitude(PARA, GRID, T); % sending information from "labindex" to all "j" for j=1:numlabs if j~=labindex labSend(PARA.ensemble.surface_altitude(labindex), j, 1); labSend(PARA.ensemble.altitude(labindex), j, 2); - labSend(PARA.ensemble.water_table(labindex), j, 3); + labSend(PARA.ensemble.water_table_altitude(labindex), j, 3); labSend(PARA.ensemble.active_layer_depth_altitude(labindex), j, 4); end end @@ -19,7 +19,7 @@ if j~=labindex PARA.ensemble.surface_altitude(j)=labReceive(j, 1); PARA.ensemble.altitude(j)=labReceive(j, 2); - PARA.ensemble.water_table(j)=labReceive(j, 3); + PARA.ensemble.water_table_altitude(j)=labReceive(j, 3); PARA.ensemble.active_layer_depth_altitude(j)=labReceive(j, 4); end end @@ -29,7 +29,7 @@ PARA.location.absolute_maxWater_altitude = getMaxWaterAltitude(PARA); % update auxiliary variables in location struct // MORE? - PARA.location.altitude = PARA.ensemble.altitude(index); - PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index); - PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(index); - PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + PARA.location.altitude = PARA.ensemble.altitude(labindex); + PARA.location.surface_altitude = PARA.ensemble.surface_altitude(labindex); + PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(labindex); + PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(labindex); diff --git a/modules/cryoGridSoil/initializeSoilThermalProperties.m b/modules/cryoGridSoil/initializeSoilThermalProperties.m index 6092e06..464d1c3 100644 --- a/modules/cryoGridSoil/initializeSoilThermalProperties.m +++ b/modules/cryoGridSoil/initializeSoilThermalProperties.m @@ -14,14 +14,14 @@ kh_bedrock = PARA.soil.kh_bedrock; -c_w = PARA.constants.c_w; %4.2*10^6; %[J/m�K] -c_o = PARA.constants.c_o; %2.5*10^6; %[J/m�K] -c_m = PARA.constants.c_m; %2*10^6; %[J/m�K] -c_a = PARA.constants.c_a; %0.00125*10^6;%[J/m�K] -c_i = PARA.constants.c_i; %1.9*10^6;%[J/m�K] +c_w = PARA.constants.c_w; %4.2*10^6; %[J/m???K] +c_o = PARA.constants.c_o; %2.5*10^6; %[J/m???K] +c_m = PARA.constants.c_m; %2*10^6; %[J/m???K] +c_a = PARA.constants.c_a; %0.00125*10^6;%[J/m???K] +c_i = PARA.constants.c_i; %1.9*10^6;%[J/m???K] %density of water -rho_w = PARA.constants.rho_w; %1000; %[kg/m�] +rho_w = PARA.constants.rho_w; %1000; %[kg/m???] %rho_i=900; %latent heat of freezing L_si = PARA.constants.L_sl; %334000; % [J/kg] @@ -31,7 +31,6 @@ cT_water(cT_mineral+cT_organic<=1e-6)=1.; - %------- capacity part ---------------------------------------------------- waterMin=0; water=cT_water; @@ -87,8 +86,7 @@ % organic=cT_organic; % a=cT_soilType; % -% K_frozen=cT_frozen; -% K_thawed=cT_thawed; + % % %preallocate variables % water_c2=ones(length(a),length(1:arraySize-2)+1); @@ -120,6 +118,10 @@ GRID.soil.cT_frozen = cT_frozen; GRID.soil.cT_thawed = cT_thawed; +K_frozen=cT_frozen; +K_thawed=cT_thawed; +GRID.soil.K_frozen = K_frozen; +GRID.soil.K_thawed = K_thawed; GRID.soil.conductivity = conductivity; GRID.soil.capacity = capacity; GRID.soil.liquidWaterContent = liquidWaterContent; @@ -138,13 +140,13 @@ n=zeros(size(soilType)); %set conditions for soil types - thetaRes(soilType==1) = PARA.soil.soilType(1,1); - alpha(soilType==1) = PARA.soil.soilType(1,3); - n(soilType==1) = PARA.soil.soilType(1,4); + thetaRes(soilType==1) = PARA.soil.soilTypes(1,1); + alpha(soilType==1) = PARA.soil.soilTypes(1,3); + n(soilType==1) = PARA.soil.soilTypes(1,4); - thetaRes(soilType==2) = PARA.soil.soilType(2,1); - alpha(soilType==2) = PARA.soil.soilType(2,3); - n(soilType==2) = PARA.soil.soilType(2,4); + thetaRes(soilType==2) = PARA.soil.soilTypes(2,1); + alpha(soilType==2) = PARA.soil.soilTypes(2,3); + n(soilType==2) = PARA.soil.soilTypes(2,4); m=1-1./n; waterPotZero=-1./alpha .*( ((thetaTot-thetaRes)./(thetaSat-thetaRes) ).^(-1./m) -1 ).^(1./n); diff --git a/modules/cryoGridTechnical/generateOUT.m b/modules/cryoGridTechnical/generateOUT.m index 096e3bb..7e35a9b 100644 --- a/modules/cryoGridTechnical/generateOUT.m +++ b/modules/cryoGridTechnical/generateOUT.m @@ -30,11 +30,11 @@ OUT.snow.botPosition=[]; % relative to initial altitude % derived characteristics and related to geometry - OUT.loaction.area = []; + OUT.location.area = []; OUT.location.altitude=[]; OUT.location.surface_altitude=[]; OUT.location.active_layer_depth_altitude = []; - OUT.location.water_table=[]; + OUT.location.water_table_altitude=[]; % lateral fluxes OUT.lateral.terrain_index_snow=[]; diff --git a/modules/cryoGridTechnical/getSurfaceAltitude.m b/modules/cryoGridTechnical/getSurfaceAltitude.m index 802f7c6..4f5956b 100644 --- a/modules/cryoGridTechnical/getSurfaceAltitude.m +++ b/modules/cryoGridTechnical/getSurfaceAltitude.m @@ -1,6 +1,6 @@ function surface_altitude = getSurfaceAltitude(PARA, GRID) -surface_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.air.cT_domain_lb+1) +surface_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.air.cT_domain_lb+1); %if ~isempty(GRID.snow.cT_domain_ub) % surface_altitude = PARA.location.altitude + sum( GRID.general.K_delta(GRID.snow.cT_domain) ); diff --git a/modules/cryoGridTechnical/getWaterTableAltitude.m b/modules/cryoGridTechnical/getWaterTableAltitude.m index 9ee41b9..c19049a 100644 --- a/modules/cryoGridTechnical/getWaterTableAltitude.m +++ b/modules/cryoGridTechnical/getWaterTableAltitude.m @@ -15,9 +15,9 @@ i=i+1; end - if T(i)<=0; + if T(i)<=0 waterTable=NaN; - disp('Dry to permafrost - waterTable=NaN \n')% Loop was stopped by the temperature condition so no water table + %disp('Dry to permafrost - waterTable=NaN \n')% Loop was stopped by the temperature condition so no water table end end diff --git a/modules/cryoGridTechnical/loadConstants.m b/modules/cryoGridTechnical/loadConstants.m index 2af6fae..645e986 100644 --- a/modules/cryoGridTechnical/loadConstants.m +++ b/modules/cryoGridTechnical/loadConstants.m @@ -30,4 +30,4 @@ %PARA.constants.rho_m = 1; % n.a. PARA.constants.c_m = 2.0e6; %[J/(K m^3)] % volumetric heat capacity of minearal material [J/(K m^3)] PARA.constants.k_m = PARA.soil.kh_bedrock; % heat conductivity of mineral material / bedrock [ W/(mK)] (specified above) %km=3.8 %mineral [Hillel(1982)] -end \ No newline at end of file +end diff --git a/modules/cryoGridTechnical/loadSoilTypes.m b/modules/cryoGridTechnical/loadSoilTypes.m index c6a2572..c074b1f 100644 --- a/modules/cryoGridTechnical/loadSoilTypes.m +++ b/modules/cryoGridTechnical/loadSoilTypes.m @@ -1,4 +1,4 @@ -function [PARA] = loadSoilTypes(PARA) +function [PARA] = loadSoilTypes( PARA ) % specify one soil type per row: residualWC [%], fieldCapacity [%], alpha [1/m], n PARA.soil.soilTypes = [ [ 0.00, PARA.soil.fieldCapacity, 4.00, 2.0 ]; ... % sand diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 71c95c6..96214ea 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -1,4 +1,4 @@ -function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes); +function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes) TEMPORARY.timestep_sum=TEMPORARY.timestep_sum+(timestep*24*3600)*timestep; @@ -95,17 +95,17 @@ % derived characteristics and related to geometry - OUT.loaction.area = [OUT.location.area; PARA.location.area]; - OUT.location.altitude=[OUT.loacation.altitude; PARA.location.altitude]; + OUT.location.area = [OUT.location.area; PARA.location.area]; + OUT.location.altitude=[OUT.location.altitude; PARA.location.altitude]; OUT.location.surface_altitude=[OUT.location.surface_altitude; PARA.location.surface_altitude]; OUT.location.active_layer_depth_altitude = [OUT.location.active_layer_depth_altitude; PARA.location.active_layer_depth_altitude]; - OUT.location.water_table=[OUT.location.water_table; PARA.location.water_table]; + OUT.location.water_table_altitude=[OUT.location.water_table_altitude; PARA.location.water_table_altitude]; % lateral fluxes OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow; PARA.ensemble.terrain_index_snow ]; - OUT.lateral.water_fluxes = [ OUT.lateral.water_fluxes; water_fluxes ]; % vector containing water fluxes in [m/s] to the current worker - OUT.lateral.snow_fluxes = [ OUT.lateral.snow_fluxes; snow_fluxes ]; % vector containing snow fluxes in [m SWE / s] to the current worker - OUT.lateral.heat_fluxes = [ OUT.lateral.heat_fluxes; heat_fluxes ]; % vector containing depth-integrated heat fluxes in [J/m^2 s ] to the current worker + OUT.lateral.water_fluxes = [ OUT.lateral.water_fluxes; water_fluxes' ]; % vector containing water fluxes in [m/s] to the current worker + OUT.lateral.snow_fluxes = [ OUT.lateral.snow_fluxes; snow_fluxes' ]; % vector containing snow fluxes in [m SWE / s] to the current worker + OUT.lateral.heat_fluxes = [ OUT.lateral.heat_fluxes; heat_fluxes' ]; % vector containing depth-integrated heat fluxes in [J/m^2 s ] to the current worker % water balance (WB) % all flows are defined as positive when they go into the soil/snow column @@ -185,8 +185,9 @@ %write output files if round((t-TEMPORARY.saveTime).*48)==0 iSaveOUT(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) - iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, SEB, PARA, GRID) + iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) OUT = generateOUT(); TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(datestr(t,'mm')), str2num(datestr(t,'dd')), str2num(datestr(t,'HH')), str2num(datestr(t,'MM')), 0); end end +end From 3746bdb72a27c7b1c1ace885dddce2f900102411 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Tue, 6 Feb 2018 17:23:37 +0100 Subject: [PATCH 13/45] preparing integration of features from branch xice --- CryoGrid3_xice_mpi.m | 6 +++--- modules/cryoGridSoil/initializeSoilThermalProperties.m | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 33fb036..891f7e5 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -27,7 +27,7 @@ % default stratigraphy used in publication: PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 0.65 0.3 0.05 2 0.65;... + 0.15 0.65 0.3 0.05 2 0.4;... 0.9 0.65 0.3 0.05 1 0.65;... 9.0 0.30 0.70 0.00 1 0.30 ]; % simple stratigraphy with excess ice used to test water balance: @@ -101,7 +101,7 @@ PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1980, 6, 1); % endtime of the simulation - if empty end at last value of time series + PARA.technical.endtime=datenum(1980, 7, 1); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -163,7 +163,7 @@ end % ------make output directory (name depends on parameters) ---------------- - run_number= sprintf( 'testrunMPI_POOL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%f_sF%f_realization%d' , ... + run_number= sprintf( 'testrunMPI_POOL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... PARA.modules.infiltration, PARA.modules.xice, ... PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , ... diff --git a/modules/cryoGridSoil/initializeSoilThermalProperties.m b/modules/cryoGridSoil/initializeSoilThermalProperties.m index 464d1c3..57adf5f 100644 --- a/modules/cryoGridSoil/initializeSoilThermalProperties.m +++ b/modules/cryoGridSoil/initializeSoilThermalProperties.m @@ -27,9 +27,14 @@ L_si = PARA.constants.L_sl; %334000; % [J/kg] deltaT=0.001*ones(size(cT_grid,1),1); -% JAN: modification to assume pure water for mixed air/water cells +% modification to assume pure water for mixed air/water cells cT_water(cT_mineral+cT_organic<=1e-6)=1.; +% % upscale min+org fractions in cells with too low min+org fraction in order to have realistic thermal properties +% cT_natPor = GRID.soil.cT_natPor; +% lowMinOrg = cT_mineral+cT_organic < 1-natPor; +% cT_mineral(lowMinOrg) = cT_mineral(lowMinOrg) .* (1 - natPor(lowMinOrg)) ./ (cT_mineral(lowMinOrg) + cT_organic(lowMinOrg) ); +% cT_organic(lowMinOrg) = cT_organic(lowMinOrg) .* (1 - natPor(lowMinOrg)) ./ (cT_mineral(lowMinOrg) + cT_organic(lowMinOrg) ); %------- capacity part ---------------------------------------------------- waterMin=0; From 1deae9e0595e98b22100cb1a0d506e2c6eeaa828 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Tue, 6 Feb 2018 17:31:23 +0100 Subject: [PATCH 14/45] integrated bugfixes from branch xice such that the thermal properties of cells with low min+org fractions and the conductivities of free water are now adjusted. --- .../bucketScheme.m | 31 +++--- .../capacityUnfrozen.m | 23 +++- .../conductivityUnfrozen.m | 25 ++++- .../getThermalPropertiesInfiltration.m | 4 + .../excessGroundIceThaw4Infiltration.m | 94 +++++++++++++--- .../updateGRID_excessiceInfiltration.m | 1 + modules/cryoGridSoil/createStratigraphy.m | 9 +- .../initializeSoilThermalProperties.m | 102 +++++++++++++----- 8 files changed, 225 insertions(+), 64 deletions(-) diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m index ef1858e..742e7ec 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m @@ -2,39 +2,29 @@ T=T(GRID.soil.cT_domain); K_delta=GRID.general.K_delta(GRID.soil.cT_domain); %in m -porosity=1-GRID.soil.cT_mineral-GRID.soil.cT_organic; -soilType = GRID.soil.cT_soilType; - -% to be changed! -fieldCapacity = zeros(size(soilType)); -residualWaterContent = zeros(size(soilType)); -for i=1:size(PARA.soil.soilTypes,1) - fieldCapacity(soilType==i) = PARA.soil.soilTypes( i, 2 ); - residualWaterContent(soilType==1) = PARA.soil.soilTypes( i, 1 ); -end +porosity=1-GRID.soil.cT_mineral-GRID.soil.cT_organic; +% A=sum(K_delta(1:30).*wc(1:30)+dwc_dt(1:30)) lacking_water=0; i=1; -i_max=200; % maximum infiltration depth, must be defined somehow before, includes also water body on to of soil +i_max=70; % maximum infiltration depth, must be defined somehow before while T(i)>0 && i<=i_max - max_water=K_delta(i).*fieldCapacity(i); %maximum amount of water (in m) that a grid cell can hold - min_water=K_delta(i).*residualWaterContent(i); %minimum amount of water which stays in a cell (independent of soil type, but should be if "freezing = drying") + max_water=K_delta(i).*PARA.soil.fieldCapacity; %maximum amount of water (in m) that a grid cell can hold + min_water=K_delta(i).*PARA.soil.residualWC; %minimum amount of water which stays in a cell actual_water= max( min_water, wc(i).*K_delta(i)+dwc_dt(i) ); % should be dwc (already multiplied with timestep) %JAN: this violates the WB - lacking_water = lacking_water + (wc(i).*K_delta(i)+dwc_dt(i)-actual_water); + lacking_water = lacking_water + (wc(i).*K_delta(i)+dwc_dt(i)=1 && excess_water>0 @@ -47,4 +37,7 @@ end -surface_runoff=(excess_water>0)*excess_water; % surface runoff only if excess_water>0 +surface_runoff=excess_water; + +% C=sum(K_delta(1:30).*wc(1:30))+surface_runoff + diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/capacityUnfrozen.m b/modules/CryoGridInfiltrationUnfrozenSoil/capacityUnfrozen.m index de13d05..689789b 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/capacityUnfrozen.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/capacityUnfrozen.m @@ -4,5 +4,24 @@ c_o = PARA.constants.c_o; % 2.5*10^6; %[J/m�K] c_m = PARA.constants.c_m; % 2*10^6; %[J/m�K] -c_temp = (GRID.soil.cT_mineral+GRID.soil.cT_organic>1e-6) .* (GRID.soil.cT_mineral.*c_m + GRID.soil.cT_organic.*c_o + wc.*c_w) + ... - (GRID.soil.cT_mineral+GRID.soil.cT_organic<=1e-6) .* c_w ; % assume pure water for cells which consist partly of air and water +c_temp = (GRID.soil.cT_mineral.*c_m + GRID.soil.cT_organic.*c_o + wc.*c_w); + + +% adjust for free water +freeWater_domain = GRID.soil.cT_mineral+GRID.soil.cT_organic<1e-6; % cells without soil matrix material +c_temp(freeWater_domain) = c_w; % assume pure water for cells which consist partly of air and water + +% adjust for low soil matrix +lowMinOrg_domain = GRID.soil.cT_mineral+GRID.soil.cT_organic>=1e-6 & ~GRID.soil.excessGroundIce & ( GRID.soil.cT_actPor > GRID.soil.cT_natPor ); % cells with lower soil matrix material than 1-natPor + +if sum(lowMinOrg_domain)>0 + + water = wc; + mineral = GRID.soil.cT_mineral; + organic = GRID.soil.cT_organic; + matrix = mineral + organic; + mineral(lowMinOrg_domain) = mineral(lowMinOrg_domain) ./ matrix(lowMinOrg_domain) .* (1 - GRID.soil.cT_natPor(lowMinOrg_domain)) ; + organic(lowMinOrg_domain) = organic(lowMinOrg_domain) ./ matrix(lowMinOrg_domain) .* (1 - GRID.soil.cT_natPor(lowMinOrg_domain)) ; + water(lowMinOrg_domain) = min( water(lowMinOrg_domain), GRID.soil.cT_natPor(lowMinOrg_domain) ) ; + c_temp(lowMinOrg_domain) = water(lowMinOrg_domain) .* c_w + mineral(lowMinOrg_domain) .* c_m + organic(lowMinOrg_domain).* c_o; +end diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/conductivityUnfrozen.m b/modules/CryoGridInfiltrationUnfrozenSoil/conductivityUnfrozen.m index 4ae6465..e48dd24 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/conductivityUnfrozen.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/conductivityUnfrozen.m @@ -1,13 +1,32 @@ -function k_temp = capacityUnfrozen(wc,GRID, PARA) +function k_temp = conductivityUnfrozen(wc,GRID, PARA) ka = PARA.constants.k_a; %0.025; %air [Hillel(1982)] kw = PARA.constants.k_w; %0.57; %water [Hillel(1982)] ko = PARA.constants.k_o; %0.25; %organic [Hillel(1982)] km = PARA.constants.k_m; %soil.kh_bedrock; %mineral +k_freeWater = 5.0; % to ensure fast heat transfer + air=1-wc-GRID.soil.cT_mineral-GRID.soil.cT_organic; -k_temp = (GRID.soil.cT_mineral+GRID.soil.cT_organic>1e-6) .* (wc.* kw.^0.5 + GRID.soil.cT_mineral.* km.^0.5 + GRID.soil.cT_organic.* ko.^0.5 + air.* ka.^0.5).^2 + ... - (GRID.soil.cT_mineral+GRID.soil.cT_organic<=1e-6) .* kw; % assume pure water for cells which consist partly of air and water +k_temp = (wc.* kw.^0.5 + GRID.soil.cT_mineral.* km.^0.5 + GRID.soil.cT_organic.* ko.^0.5 + air.* ka.^0.5).^2 ; + +% adjust for free water +freeWater_domain = GRID.soil.cT_mineral+GRID.soil.cT_organic<1e-6; % cells without soil matrix material +k_temp(freeWater_domain) = k_freeWater; % assume pure water for cells which consist partly of air and water + +% adjust for low soil matrix +lowMinOrg_domain = GRID.soil.cT_mineral+GRID.soil.cT_organic>=1e-6 & ~GRID.soil.excessGroundIce & ( GRID.soil.cT_actPor > GRID.soil.cT_natPor ); % cells with lower soil matrix material than 1-natPor +if sum(lowMinOrg_domain)>0 + water = wc; + mineral = GRID.soil.cT_mineral; + organic = GRID.soil.cT_organic; + matrix = mineral + organic; + mineral(lowMinOrg_domain) = mineral(lowMinOrg_domain) ./ matrix(lowMinOrg_domain) .* (1 - GRID.soil.cT_natPor(lowMinOrg_domain)) ; + organic(lowMinOrg_domain) = organic(lowMinOrg_domain) ./ matrix(lowMinOrg_domain) .* (1 - GRID.soil.cT_natPor(lowMinOrg_domain)) ; + water(lowMinOrg_domain) = min( water(lowMinOrg_domain), GRID.soil.cT_natPor(lowMinOrg_domain) ) ; + air(lowMinOrg_domain) = 1-mineral(lowMinOrg_domain)-organic(lowMinOrg_domain)-water(lowMinOrg_domain); + k_temp(lowMinOrg_domain) = (water(lowMinOrg_domain) .* kw.^0.5 + mineral(lowMinOrg_domain) .* km.^0.5 + organic(lowMinOrg_domain).* ko.^0.5 + air(lowMinOrg_domain) .* ka.^0.5).^2 ; +end \ No newline at end of file diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m index 86fc6ad..e78f7ba 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m @@ -18,6 +18,10 @@ k_temp(GRID.soil.cT_domain) = double(T(GRID.soil.cT_domain)<=0).*k_temp(GRID.soil.cT_domain) + double(T(GRID.soil.cT_domain)>0).* conductivityUnfrozen(wc,GRID,PARA); lwc_temp(GRID.soil.cT_domain) = double(T(GRID.soil.cT_domain)<=0).*lwc_temp(GRID.soil.cT_domain) + double(T(GRID.soil.cT_domain)>0).* wc; + %-------- set higher conductivity for free water ---------------------- + % now done in conductivityUnfrozen + + %------- snow domain -------------------------------------------------- c_temp(GRID.snow.cT_domain) = cap_snow(GRID.snow.Snow_i(GRID.snow.cT_domain),... GRID.snow.Snow_w(GRID.snow.cT_domain),... diff --git a/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m b/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m index 7674fd4..d832489 100644 --- a/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m +++ b/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m @@ -1,19 +1,26 @@ function [GRID, meltwaterGroundIce, wc]=excessGroundIceThaw4Infiltration(T, wc, GRID, PARA) +%disp('rearranging grid cells due to ground ice thaw') meltwaterGroundIce=0; % in [m] + +waterLevel=PARA.soil.waterTable; %remove supersaturation only when there is no snow on top of soil!!!!!!! + %calculates amounts of soil constituents in [m] mineral=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_mineral; organic=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_organic; natPor=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_natPor; +actPor=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_actPor; % modification for infiltration +%water=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_water; water=GRID.general.K_delta(GRID.soil.cT_domain).*wc; +cT_grid=GRID.general.cT_grid(GRID.soil.cT_domain); K_delta=GRID.general.K_delta(GRID.soil.cT_domain); mobileWater = double(T(GRID.soil.cT_domain)>0) .* (water-natPor) .* double(water>natPor); -[startCell ~]= LayerIndex(mobileWater~=0); +[startCell ~]= LayerIndex(mobileWater~=0); %this is faster %move solids down for i=startCell:-1:1 @@ -32,13 +39,13 @@ end %adjust the natural porosity -natPor(1:startCell)=K_delta(1:startCell)-mineral(1:startCell)-organic(1:startCell); +actPor(1:startCell)=K_delta(1:startCell)-mineral(1:startCell)-organic(1:startCell); %move water up mobileWater=0; for i=startCell:-1:1 totalWater=water(i)+mobileWater; - mobileWater=totalWater-natPor(i); + mobileWater=totalWater-actPor(i); mobileWater=max(0,mobileWater); water(i)=totalWater-mobileWater; end @@ -63,18 +70,43 @@ end end +%%% modifications due to infiltration module +%GRID.soil.cT_water=water./K_delta; +%GRID.soil.K_water(1)=GRID.soil.cT_water(1); +%GRID.soil.K_water(2:startCell+1)=(GRID.soil.cT_water(2:startCell+1)+GRID.soil.cT_water(1:startCell))/2 ; wc=water./K_delta; +% GRID.soil.K_water(1)=wc(1); +% GRID.soil.K_water(2:startCell+1)=(wc(2:startCell+1)+wc(1:startCell))/2 ; +%%% GRID.soil.cT_mineral=mineral./K_delta; GRID.soil.cT_organic=organic./K_delta; GRID.soil.cT_natPor=natPor./K_delta; -GRID.soil.cT_soilType( (GRID.soil.cT_mineral+GRID.soil.cT_organic)<=1e-6 )=1; %sets sand freeze curve for all water grid cells +GRID.soil.cT_actPor=actPor./K_delta; +GRID.soil.cT_soilType( (GRID.soil.cT_mineral+GRID.soil.cT_organic)<=1e-6 )=1; %sets sand freeze curve for all water grid cells %wc(:,1)==1,1 + + +% K fields not used currently +% GRID.soil.K_mineral(1)=GRID.soil.cT_mineral(1); +% GRID.soil.K_mineral(2:startCell+1)=(GRID.soil.cT_mineral(2:startCell+1)+GRID.soil.cT_mineral(1:startCell))/2 ; +% GRID.soil.K_organic(1)=GRID.soil.cT_organic(1); +% GRID.soil.K_organic(2:startCell+1)=(GRID.soil.cT_organic(2:startCell+1)+GRID.soil.cT_organic(1:startCell))/2 ; + +% GRID.soil.K_natPor(1)=GRID.soil.cT_natPor(1); +% GRID.soil.K_natPor(2:startCell+1)=(GRID.soil.cT_natPor(2:startCell+1)+GRID.soil.cT_natPor(1:startCell))/2 ; +% GRID.soil.K_soilType(1)=GRID.soil.cT_soilType(1); +% GRID.soil.K_soilType(2:startCell+1)=round((GRID.soil.cT_soilType(2:startCell+1)+GRID.soil.cT_soilType(1:startCell))/2) ; -soilGRIDsizeOld = sum( GRID.soil.cT_domain ); % to check if LUT update necessary + +%remove grid cells until the water level is reached +soilGRIDsizeOld = sum( GRID.soil.cT_domain ); +%%% modified due to infiltration module +%while (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+GRID.soil.cT_water(1)==0) || (GRID.soil.cT_water(1)==1 && GRID.general.K_grid(GRID.soil.K_domain_ub) PARA.location.absolute_maxWater_altitude) ) +while GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+wc(1)<=0 || ... % upper cell filled with pure air + (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)<=1e-6 && GRID.general.K_grid(GRID.soil.cT_domain_ub+1) PARA.location.absolute_maxWater_altitude + GRID.general.K_grid(GRID.soil.cT_domain_ub) only if grid cells freeze, otherwise not necessary ????? -% if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 +%if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 if soilGRIDsizeOld~=soilGRIDsizeNew disp('xice - reinitializing LUT - soil/air domains changed'); GRID.soil.cT_water=wc; GRID = initializeSoilThermalProperties(GRID, PARA); end +%end +%reduce water content above the perched water table +%it might be also good to use an external function for this since this is +%only an option in the model +%i=0; +% while i./startCell < 1-PARA.soil.perchedWaterTable +% GRID.soil.cT_water(i+1,1) = PARA.soil.saturationAbovePerchedWaterTable.*(1-GRID.soil.cT_mineral(i+1,1)-GRID.soil.cT_organic(i+1,1)); +% +% GRID.soil.K_water(i+1,1) = PARA.soil.saturationAbovePerchedWaterTable.*(1-GRID.soil.K_mineral(i+1,1)-GRID.soil.K_organic(i+1,1)); +% i=i+1; +% end + + +% [GRID.soil.cT_frozen,... +% GRID.soil.cT_thawed,... +% GRID.soil.K_frozen,... +% GRID.soil.K_thawed,... +% GRID.soil.conductivity,... +% GRID.soil.capacity] = initialize(GRID.soil.cT_water,... +% GRID.soil.cT_mineral,... +% GRID.soil.cT_organic,... +% GRID.soil.cT_soilType,... +% GRID.soil.K_water,... +% GRID.soil.K_mineral,... +% GRID.soil.K_organic,... +% GRID.soil.K_soilType,... +% PARA.technical.arraySizeT,... +% GRID.general.cT_grid(GRID.soil.cT_domain),... +% PARA.soil.kh_bedrock); diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration.m index 2ac9b63..e2dc7a5 100644 --- a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration.m +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration.m @@ -57,6 +57,7 @@ GRID.soil.cT_organic = GRID.soil.cT_organic(cT_no_water); GRID.soil.cT_soilType = GRID.soil.cT_soilType(cT_no_water); GRID.soil.cT_natPor = GRID.soil.cT_natPor(cT_no_water); + GRID.soil.cT_actPor = GRID.soil.cT_actPor(cT_no_water); GRID.soil.excessGroundIce = GRID.soil.excessGroundIce(cT_no_water); GRID.soil.conductivity = GRID.soil.conductivity(cT_no_water, :); GRID.soil.capacity = GRID.soil.capacity(cT_no_water, :); diff --git a/modules/cryoGridSoil/createStratigraphy.m b/modules/cryoGridSoil/createStratigraphy.m index 7b8475b..e99f418 100644 --- a/modules/cryoGridSoil/createStratigraphy.m +++ b/modules/cryoGridSoil/createStratigraphy.m @@ -18,9 +18,10 @@ GRID.soil.cT_organic = interp1(soilParam(:,1),soilParam(:,4),GRID.general.cT_grid(GRID.soil.cT_domain),'linear'); GRID.soil.cT_soilType = interp1(soilParam(:,1),soilParam(:,5),GRID.general.cT_grid(GRID.soil.cT_domain),'nearest'); GRID.soil.cT_natPor = interp1(soilParam(:,1),soilParam(:,6),GRID.general.cT_grid(GRID.soil.cT_domain),'linear'); +GRID.soil.cT_actPor = 1. - GRID.soil.cT_mineral - GRID.soil.cT_organic; -%GRID.soil.K_water = interp1(soilParam(:,1),soilParam(:,2),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -%GRID.soil.K_mineral = interp1(soilParam(:,1),soilParam(:,3),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -%GRID.soil.K_organic = interp1(soilParam(:,1),soilParam(:,4),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -%GRID.soil.K_soilType = interp1(soilParam(:,1),soilParam(:,5),GRID.general.K_grid(GRID.soil.K_domain),'nearest'); +% GRID.soil.K_water = interp1(soilParam(:,1),soilParam(:,2),GRID.general.K_grid(GRID.soil.K_domain),'linear'); +% GRID.soil.K_mineral = interp1(soilParam(:,1),soilParam(:,3),GRID.general.K_grid(GRID.soil.K_domain),'linear'); +% GRID.soil.K_organic = interp1(soilParam(:,1),soilParam(:,4),GRID.general.K_grid(GRID.soil.K_domain),'linear'); +% GRID.soil.K_soilType = interp1(soilParam(:,1),soilParam(:,5),GRID.general.K_grid(GRID.soil.K_domain),'nearest'); \ No newline at end of file diff --git a/modules/cryoGridSoil/initializeSoilThermalProperties.m b/modules/cryoGridSoil/initializeSoilThermalProperties.m index 57adf5f..f5888a9 100644 --- a/modules/cryoGridSoil/initializeSoilThermalProperties.m +++ b/modules/cryoGridSoil/initializeSoilThermalProperties.m @@ -8,7 +8,10 @@ cT_mineral = GRID.soil.cT_mineral; cT_organic = GRID.soil.cT_organic; cT_soilType = GRID.soil.cT_soilType; - +% K_water = GRID.soil.K_water; +% K_mineral = GRID.soil.K_mineral; +% K_organic = GRID.soil.K_organic; +% K_soilType = GRID.soil.K_soilType; arraySize = PARA.technical.arraySizeT; cT_grid = GRID.general.cT_grid(GRID.soil.cT_domain); kh_bedrock = PARA.soil.kh_bedrock; @@ -27,14 +30,25 @@ L_si = PARA.constants.L_sl; %334000; % [J/kg] deltaT=0.001*ones(size(cT_grid,1),1); -% modification to assume pure water for mixed air/water cells -cT_water(cT_mineral+cT_organic<=1e-6)=1.; -% % upscale min+org fractions in cells with too low min+org fraction in order to have realistic thermal properties -% cT_natPor = GRID.soil.cT_natPor; -% lowMinOrg = cT_mineral+cT_organic < 1-natPor; -% cT_mineral(lowMinOrg) = cT_mineral(lowMinOrg) .* (1 - natPor(lowMinOrg)) ./ (cT_mineral(lowMinOrg) + cT_organic(lowMinOrg) ); -% cT_organic(lowMinOrg) = cT_organic(lowMinOrg) .* (1 - natPor(lowMinOrg)) ./ (cT_mineral(lowMinOrg) + cT_organic(lowMinOrg) ); + +% temporary upscaling of min+org fractions in cells with too low min+org fraction in order to have realistic thermal properties +cT_natPor = GRID.soil.cT_natPor; +cT_actPor = GRID.soil.cT_actPor; + +lowMinOrg_domain = cT_mineral+cT_organic>=1e-6 & ~GRID.soil.excessGroundIce & (cT_actPor > cT_natPor ); % cells with lower soil matrix material than 1-natPor + +if sum(lowMinOrg_domain)>0 + warning('cells with low matrix material exist - upscaling of matrix fraction to ensure correct thermal properties'); + cT_matrix = cT_mineral + cT_organic; + cT_mineral(lowMinOrg_domain) = cT_mineral(lowMinOrg_domain) ./ cT_matrix(lowMinOrg_domain) .* (1 - cT_natPor(lowMinOrg_domain)) ; + cT_organic(lowMinOrg_domain) = cT_organic(lowMinOrg_domain) ./ cT_matrix(lowMinOrg_domain) .* (1 - cT_natPor(lowMinOrg_domain)) ; + cT_water(lowMinOrg_domain) = min( cT_water(lowMinOrg_domain), cT_natPor(lowMinOrg_domain) ) ; +end + +% temporary upscaling of pure water for mixed air/water cells +freeWater_domain = cT_mineral+cT_organic<1e-6; % cells without soil matrix material +cT_water(freeWater_domain)=1.; %------- capacity part ---------------------------------------------------- waterMin=0; @@ -43,19 +57,24 @@ organic=cT_organic; a=cT_soilType; -% set cT_thawed + cT_thawed=zeros(size(a,1),1); -% determine cT_frozen +%cT_frozen=-15*ones(size(a,1),1); + ch=mineral*c_m+organic*c_o+waterMin.*c_w+(water-waterMin)*c_i; + %preallocate variable c_h2o=ones(length(a),length(-30:0.01:-1)); + j=1; for i= -30:0.01:-1 c_h2o(:,j)=L_si*rho_w*(freezeC(water, 1-mineral-organic, a, i+deltaT/2, PARA)-freezeC(water, 1-mineral-organic, a, i-deltaT/2, PARA))/deltaT(1,1) < 0.05.*ch; j=j+1; end + %preallocate variables cT_frozen=-30+((sum(c_h2o')')-1).*0.01; + c_h2o=ones(length(a),length(1:arraySize-2)+1); water_c=c_h2o; ch=c_h2o; @@ -85,19 +104,29 @@ %---------- conductivity part --------------------------------------------- +% water=K_water; +% mineral=K_mineral; +% organic=K_organic; +% a=K_soilType; +%%K_frozen=-15*ones(size(a,1),1); +%K_frozen=[cT_frozen(1,1); 0.5.*(cT_frozen(1:end-1,1)+cT_frozen(2:end,1)) ; cT_frozen(end,1)]; +%K_thawed=zeros(size(a,1),1); + + % changed to cT-grid since K- interpolation is done external now % water=cT_water; % mineral=cT_mineral; % organic=cT_organic; % a=cT_soilType; % - +K_frozen=cT_frozen; +K_thawed=cT_thawed; % % %preallocate variables % water_c2=ones(length(a),length(1:arraySize-2)+1); % water_c2(:,1)=freezeC(water, 1-mineral-organic, a, K_frozen, PARA); % JAN: this is identical to water_c for -conductivity=water_c; % initialize to same size as water_c +conductivity=water_c; % for i=1:arraySize-2 % water_c2(:,i+1)=freezeC(water, 1-mineral-organic, a, K_thawed+(K_frozen-K_thawed)*(arraySize-2-i)/(arraySize-2), PARA); @@ -114,6 +143,11 @@ conductivity=[conductivity conductivity(:,size(conductivity,2))]; %conductivity matrix for soil filled +% lastSnowCell=find((:,1)<0); +% lastSnowCell=lastSnowCell(end); +% conductivity(1:lastSnowCell,:) = repmat(kh_snow, lastSnowCell, size(conductivity,2)); + + %----------- write lookup tables to GRID struct liquidWaterContent = real(liquidWaterContent); @@ -123,8 +157,6 @@ GRID.soil.cT_frozen = cT_frozen; GRID.soil.cT_thawed = cT_thawed; -K_frozen=cT_frozen; -K_thawed=cT_thawed; GRID.soil.K_frozen = K_frozen; GRID.soil.K_thawed = K_thawed; GRID.soil.conductivity = conductivity; @@ -138,23 +170,26 @@ %content is 'water' by default function waterC = freezeC(thetaTot, thetaSat, soilType, T, PARA) T=T+273.15; - + % thetaTot=0.3; + % thetaSat=0.4; thetaTot=min(thetaSat, thetaTot); thetaRes=zeros(size(soilType)); alpha=zeros(size(soilType)); n=zeros(size(soilType)); + %set conditions for soil types - thetaRes(soilType==1) = PARA.soil.soilTypes(1,1); - alpha(soilType==1) = PARA.soil.soilTypes(1,3); - n(soilType==1) = PARA.soil.soilTypes(1,4); + thetaRes(soilType==1) = 0; + alpha(soilType==1) = 4; + n(soilType==1) = 2; - thetaRes(soilType==2) = PARA.soil.soilTypes(2,1); - alpha(soilType==2) = PARA.soil.soilTypes(2,3); - n(soilType==2) = PARA.soil.soilTypes(2,4); + thetaRes(soilType==2) = 0.05; + alpha(soilType==2) = 0.65; + n(soilType==2) = 1.7; m=1-1./n; waterPotZero=-1./alpha .*( ((thetaTot-thetaRes)./(thetaSat-thetaRes) ).^(-1./m) -1 ).^(1./n); + %Tstar=273.15+9.81.*273.15./3.34e5.*waterPotZero; Tstar = 273.15 + PARA.constants.g .* 273.15 ./ PARA.constants.L_sl .* waterPotZero; waterC=zeros(size(T)); @@ -162,7 +197,7 @@ waterC(T>=273.15) = thetaTot(T>=273.15); - % implementation ( linear from 0 to -0.05 ) + % OLD implementation ( plateau from 0 to -0.05 ) waterPot(T<273.15 & T>273.1) = waterPotZero(T<273.15 & T>273.1)... + (3.34e5./9.81./Tstar(T<273.15 & T>273.1).*(273.1-Tstar(T<273.15 & T>273.1)))... .* (273.1273.1)); @@ -181,10 +216,29 @@ waterC( isnan(waterC) ) = thetaRes( isnan(waterC) ); -%JAN: alternative implementation ( smooth functions ) +%JAN: new implementation ( smooth functions ) % waterPot(T<=273.15)= waterPotZero(T<=273.15)+(PARA.constants.L_sl./PARA.constants.g./Tstar(T<=273.15).*(T(T<=273.15)-Tstar(T<=273.15))).*(T(T<=273.15)=273.15 + % waterC(i,1)=thetaTot(i,1); + % else + % + % if T(i,1)>273.1 + % + % + % waterPot=waterPotZero(i,1)+(3.34e5./9.81./Tstar(i,1).*(273.1-Tstar(i,1))).*(273.1 Date: Tue, 6 Feb 2018 17:36:42 +0100 Subject: [PATCH 15/45] restored previous modifications to initializeSoilThermalProperties.m --- .../initializeSoilThermalProperties.m | 87 ++++--------------- 1 file changed, 17 insertions(+), 70 deletions(-) diff --git a/modules/cryoGridSoil/initializeSoilThermalProperties.m b/modules/cryoGridSoil/initializeSoilThermalProperties.m index f5888a9..d12b789 100644 --- a/modules/cryoGridSoil/initializeSoilThermalProperties.m +++ b/modules/cryoGridSoil/initializeSoilThermalProperties.m @@ -8,10 +8,7 @@ cT_mineral = GRID.soil.cT_mineral; cT_organic = GRID.soil.cT_organic; cT_soilType = GRID.soil.cT_soilType; -% K_water = GRID.soil.K_water; -% K_mineral = GRID.soil.K_mineral; -% K_organic = GRID.soil.K_organic; -% K_soilType = GRID.soil.K_soilType; + arraySize = PARA.technical.arraySizeT; cT_grid = GRID.general.cT_grid(GRID.soil.cT_domain); kh_bedrock = PARA.soil.kh_bedrock; @@ -30,8 +27,6 @@ L_si = PARA.constants.L_sl; %334000; % [J/kg] deltaT=0.001*ones(size(cT_grid,1),1); - - % temporary upscaling of min+org fractions in cells with too low min+org fraction in order to have realistic thermal properties cT_natPor = GRID.soil.cT_natPor; cT_actPor = GRID.soil.cT_actPor; @@ -57,24 +52,19 @@ organic=cT_organic; a=cT_soilType; - +% set cT_thawed cT_thawed=zeros(size(a,1),1); -%cT_frozen=-15*ones(size(a,1),1); - +% determine cT_frozen ch=mineral*c_m+organic*c_o+waterMin.*c_w+(water-waterMin)*c_i; - %preallocate variable c_h2o=ones(length(a),length(-30:0.01:-1)); - j=1; for i= -30:0.01:-1 c_h2o(:,j)=L_si*rho_w*(freezeC(water, 1-mineral-organic, a, i+deltaT/2, PARA)-freezeC(water, 1-mineral-organic, a, i-deltaT/2, PARA))/deltaT(1,1) < 0.05.*ch; j=j+1; end - %preallocate variables cT_frozen=-30+((sum(c_h2o')')-1).*0.01; - c_h2o=ones(length(a),length(1:arraySize-2)+1); water_c=c_h2o; ch=c_h2o; @@ -96,37 +86,20 @@ liquidWaterContent = [water_c water]; % water content - -% lastSnowCell=find(cT_grid(:,1)<0); -% lastSnowCell=lastSnowCell(end); -% -% capacity(1:lastSnowCell,:) = repmat(rho_snow/rho_i*c_i, lastSnowCell, size(capacity,2)); - - %---------- conductivity part --------------------------------------------- -% water=K_water; -% mineral=K_mineral; -% organic=K_organic; -% a=K_soilType; -%%K_frozen=-15*ones(size(a,1),1); -%K_frozen=[cT_frozen(1,1); 0.5.*(cT_frozen(1:end-1,1)+cT_frozen(2:end,1)) ; cT_frozen(end,1)]; -%K_thawed=zeros(size(a,1),1); - - % changed to cT-grid since K- interpolation is done external now % water=cT_water; % mineral=cT_mineral; % organic=cT_organic; % a=cT_soilType; % -K_frozen=cT_frozen; -K_thawed=cT_thawed; + % % %preallocate variables % water_c2=ones(length(a),length(1:arraySize-2)+1); % water_c2(:,1)=freezeC(water, 1-mineral-organic, a, K_frozen, PARA); % JAN: this is identical to water_c for -conductivity=water_c; +conductivity=water_c; % initialize to same size as water_c % for i=1:arraySize-2 % water_c2(:,i+1)=freezeC(water, 1-mineral-organic, a, K_thawed+(K_frozen-K_thawed)*(arraySize-2-i)/(arraySize-2), PARA); @@ -143,11 +116,6 @@ conductivity=[conductivity conductivity(:,size(conductivity,2))]; %conductivity matrix for soil filled -% lastSnowCell=find((:,1)<0); -% lastSnowCell=lastSnowCell(end); -% conductivity(1:lastSnowCell,:) = repmat(kh_snow, lastSnowCell, size(conductivity,2)); - - %----------- write lookup tables to GRID struct liquidWaterContent = real(liquidWaterContent); @@ -157,6 +125,8 @@ GRID.soil.cT_frozen = cT_frozen; GRID.soil.cT_thawed = cT_thawed; +K_frozen=cT_frozen; +K_thawed=cT_thawed; GRID.soil.K_frozen = K_frozen; GRID.soil.K_thawed = K_thawed; GRID.soil.conductivity = conductivity; @@ -170,26 +140,23 @@ %content is 'water' by default function waterC = freezeC(thetaTot, thetaSat, soilType, T, PARA) T=T+273.15; - % thetaTot=0.3; - % thetaSat=0.4; + thetaTot=min(thetaSat, thetaTot); thetaRes=zeros(size(soilType)); alpha=zeros(size(soilType)); n=zeros(size(soilType)); - %set conditions for soil types - thetaRes(soilType==1) = 0; - alpha(soilType==1) = 4; - n(soilType==1) = 2; + thetaRes(soilType==1) = PARA.soil.soilTypes(1,1); + alpha(soilType==1) = PARA.soil.soilTypes(1,3); + n(soilType==1) = PARA.soil.soilTypes(1,4); - thetaRes(soilType==2) = 0.05; - alpha(soilType==2) = 0.65; - n(soilType==2) = 1.7; + thetaRes(soilType==2) = PARA.soil.soilTypes(2,1); + alpha(soilType==2) = PARA.soil.soilTypes(2,3); + n(soilType==2) = PARA.soil.soilTypes(2,4); m=1-1./n; waterPotZero=-1./alpha .*( ((thetaTot-thetaRes)./(thetaSat-thetaRes) ).^(-1./m) -1 ).^(1./n); - %Tstar=273.15+9.81.*273.15./3.34e5.*waterPotZero; Tstar = 273.15 + PARA.constants.g .* 273.15 ./ PARA.constants.L_sl .* waterPotZero; waterC=zeros(size(T)); @@ -197,7 +164,7 @@ waterC(T>=273.15) = thetaTot(T>=273.15); - % OLD implementation ( plateau from 0 to -0.05 ) + % implementation ( linear from 0 to -0.05 ) waterPot(T<273.15 & T>273.1) = waterPotZero(T<273.15 & T>273.1)... + (3.34e5./9.81./Tstar(T<273.15 & T>273.1).*(273.1-Tstar(T<273.15 & T>273.1)))... .* (273.1273.1)); @@ -216,29 +183,9 @@ waterC( isnan(waterC) ) = thetaRes( isnan(waterC) ); -%JAN: new implementation ( smooth functions ) +%JAN: alternative implementation ( smooth functions ) % waterPot(T<=273.15)= waterPotZero(T<=273.15)+(PARA.constants.L_sl./PARA.constants.g./Tstar(T<=273.15).*(T(T<=273.15)-Tstar(T<=273.15))).*(T(T<=273.15)=273.15 - % waterC(i,1)=thetaTot(i,1); - % else - % - % if T(i,1)>273.1 - % - % - % waterPot=waterPotZero(i,1)+(3.34e5./9.81./Tstar(i,1).*(273.1-Tstar(i,1))).*(273.1 Date: Wed, 7 Feb 2018 13:55:34 +0100 Subject: [PATCH 16/45] fixed problem with previous merge. --- .../bucketScheme.m | 28 +++--- .../updateGRID_infiltration.m | 5 +- .../excessGroundIceThaw4Infiltration.m | 92 +++---------------- 3 files changed, 34 insertions(+), 91 deletions(-) diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m index 742e7ec..4940ba3 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m @@ -2,29 +2,37 @@ T=T(GRID.soil.cT_domain); K_delta=GRID.general.K_delta(GRID.soil.cT_domain); %in m -porosity=1-GRID.soil.cT_mineral-GRID.soil.cT_organic; +porosity=1-GRID.soil.cT_mineral-GRID.soil.cT_organic; +soilType = GRID.soil.cT_soilType; + +% to be changed! +fieldCapacity = zeros(size(soilType)); +residualWaterContent = zeros(size(soilType)); +for i=1:size(PARA.soil.soilTypes,1) + fieldCapacity(soilType==i) = PARA.soil.soilTypes( i, 2 ); + residualWaterContent(soilType==1) = PARA.soil.soilTypes( i, 1 ); +end -% A=sum(K_delta(1:30).*wc(1:30)+dwc_dt(1:30)) lacking_water=0; i=1; -i_max=70; % maximum infiltration depth, must be defined somehow before +i_max=200; % maximum infiltration depth, must be defined somehow before, includes also water body on to of soil while T(i)>0 && i<=i_max - max_water=K_delta(i).*PARA.soil.fieldCapacity; %maximum amount of water (in m) that a grid cell can hold - min_water=K_delta(i).*PARA.soil.residualWC; %minimum amount of water which stays in a cell + max_water=K_delta(i).*fieldCapacity(i); %maximum amount of water (in m) that a grid cell can hold + min_water=K_delta(i).*residualWaterContent(i); %minimum amount of water which stays in a cell (independent of soil type, but should be if "freezing = drying") actual_water= max( min_water, wc(i).*K_delta(i)+dwc_dt(i) ); % should be dwc (already multiplied with timestep) %JAN: this violates the WB - lacking_water = lacking_water + (wc(i).*K_delta(i)+dwc_dt(i)=1 && excess_water>0 @@ -37,7 +45,5 @@ end -surface_runoff=excess_water; - -% C=sum(K_delta(1:30).*wc(1:30))+surface_runoff +surface_runoff=(excess_water>0)*excess_water; % surface runoff only if excess_water>0 diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m index 87fbcf1..ba3b8c3 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m @@ -25,9 +25,11 @@ GRID.soil.cT_organic(1)=[]; GRID.soil.cT_natPor(1)=[]; + GRID.soil.cT_actPor(1)=[]; GRID.soil.cT_mineral(1)=[]; GRID.soil.cT_soilType(1)=[]; + GRID.soil.excessGroundIce(1)=[]; end @@ -61,6 +63,7 @@ % update remaining soil fields with exception of cT_water GRID.soil.cT_organic = [ 0 ; GRID.soil.cT_organic ]; GRID.soil.cT_natPor = [ GRID.soil.cT_natPor(1); GRID.soil.cT_natPor ]; % take natPor of cell below + GRID.soil.cT_actPor = [ 1; GRID.soil.cT_actPor ]; % set to 1 GRID.soil.cT_mineral = [ 0 ; GRID.soil.cT_mineral ]; GRID.soil.cT_soilType = [ 1; GRID.soil.cT_soilType]; % assume sand as soil type for water cell @@ -88,4 +91,4 @@ -end \ No newline at end of file +end diff --git a/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m b/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m index d832489..b7269cd 100644 --- a/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m +++ b/modules/cryoGridExcessIceInfiltration/excessGroundIceThaw4Infiltration.m @@ -1,11 +1,7 @@ function [GRID, meltwaterGroundIce, wc]=excessGroundIceThaw4Infiltration(T, wc, GRID, PARA) -%disp('rearranging grid cells due to ground ice thaw') meltwaterGroundIce=0; % in [m] - -waterLevel=PARA.soil.waterTable; %remove supersaturation only when there is no snow on top of soil!!!!!!! - %calculates amounts of soil constituents in [m] mineral=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_mineral; organic=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_organic; @@ -13,14 +9,12 @@ actPor=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_actPor; % modification for infiltration -%water=GRID.general.K_delta(GRID.soil.cT_domain).*GRID.soil.cT_water; water=GRID.general.K_delta(GRID.soil.cT_domain).*wc; -cT_grid=GRID.general.cT_grid(GRID.soil.cT_domain); K_delta=GRID.general.K_delta(GRID.soil.cT_domain); mobileWater = double(T(GRID.soil.cT_domain)>0) .* (water-natPor) .* double(water>natPor); -[startCell ~]= LayerIndex(mobileWater~=0); %this is faster +[startCell ~]= LayerIndex(mobileWater~=0); %move solids down for i=startCell:-1:1 @@ -38,7 +32,8 @@ end end -%adjust the natural porosity +%adjust the actual porosity +%natPor(1:startCell)=K_delta(1:startCell)-mineral(1:startCell)-organic(1:startCell); actPor(1:startCell)=K_delta(1:startCell)-mineral(1:startCell)-organic(1:startCell); %move water up @@ -70,43 +65,19 @@ end end -%%% modifications due to infiltration module -%GRID.soil.cT_water=water./K_delta; -%GRID.soil.K_water(1)=GRID.soil.cT_water(1); -%GRID.soil.K_water(2:startCell+1)=(GRID.soil.cT_water(2:startCell+1)+GRID.soil.cT_water(1:startCell))/2 ; wc=water./K_delta; -% GRID.soil.K_water(1)=wc(1); -% GRID.soil.K_water(2:startCell+1)=(wc(2:startCell+1)+wc(1:startCell))/2 ; -%%% GRID.soil.cT_mineral=mineral./K_delta; GRID.soil.cT_organic=organic./K_delta; GRID.soil.cT_natPor=natPor./K_delta; GRID.soil.cT_actPor=actPor./K_delta; -GRID.soil.cT_soilType( (GRID.soil.cT_mineral+GRID.soil.cT_organic)<=1e-6 )=1; %sets sand freeze curve for all water grid cells %wc(:,1)==1,1 - - -% K fields not used currently -% GRID.soil.K_mineral(1)=GRID.soil.cT_mineral(1); -% GRID.soil.K_mineral(2:startCell+1)=(GRID.soil.cT_mineral(2:startCell+1)+GRID.soil.cT_mineral(1:startCell))/2 ; -% GRID.soil.K_organic(1)=GRID.soil.cT_organic(1); -% GRID.soil.K_organic(2:startCell+1)=(GRID.soil.cT_organic(2:startCell+1)+GRID.soil.cT_organic(1:startCell))/2 ; - -% GRID.soil.K_natPor(1)=GRID.soil.cT_natPor(1); -% GRID.soil.K_natPor(2:startCell+1)=(GRID.soil.cT_natPor(2:startCell+1)+GRID.soil.cT_natPor(1:startCell))/2 ; -% GRID.soil.K_soilType(1)=GRID.soil.cT_soilType(1); -% GRID.soil.K_soilType(2:startCell+1)=round((GRID.soil.cT_soilType(2:startCell+1)+GRID.soil.cT_soilType(1:startCell))/2) ; - +GRID.soil.cT_soilType( (GRID.soil.cT_mineral+GRID.soil.cT_organic)<=1e-6 )=1; %sets sand freeze curve for all water grid cells -%remove grid cells until the water level is reached -soilGRIDsizeOld = sum( GRID.soil.cT_domain ); -%%% modified due to infiltration module -%while (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+GRID.soil.cT_water(1)==0) || (GRID.soil.cT_water(1)==1 && GRID.general.K_grid(GRID.soil.K_domain_ub) PARA.location.absolute_maxWater_altitude) ) disp('xice - update GRID - removing grid cell ...') if wc(1)==0 @@ -129,7 +100,6 @@ GRID.soil.cT_domain_ub=GRID.soil.cT_domain_ub+1; GRID.soil.K_domain_ub=GRID.soil.K_domain_ub+1; GRID.soil.soilGrid(1)=[]; - %GRID.soil.convectiveDomain(1)=[]; %%% modification due to infiltration module GRID.soil.cT_water(1)=[]; @@ -141,23 +111,19 @@ GRID.soil.cT_actPor(1)=[]; GRID.soil.cT_mineral(1)=[]; GRID.soil.cT_soilType(1)=[]; - % K fields are not used currently -% GRID.soil.K_water(1)=[]; -% GRID.soil.K_organic(1)=[]; -% GRID.soil.K_mineral(1)=[]; -% GRID.soil.K_soilType(1)=[]; + GRID.soil.excessGroundIce(1)=[]; end -% check if the uppermost +% check if the uppermost soil cell contains water above water table if GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)<=1e-6 && ... - GRID.general.K_grid(GRID.soil.cT_domain_ub) PARA.location.absolute_maxWater_altitude disp('xice - checking upper cell for excess water'); actualWater = wc(1)*K_delta(1); - h = GRID.general.K_grid(GRID.soil.cT_domain_ub+1)-waterLevel; + h = PARA.location.absolute_maxWater_altitude - (PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub+1)); if h<0 warning('xice - h<0. too much water above water table!') @@ -168,46 +134,14 @@ meltwaterGroundIce = meltwaterGroundIce + actualWater-h; end - end - soilGRIDsizeNew = sum (GRID.soil.cT_domain ); - % update look up tables since soil water contents changed % --> only if grid cells freeze, otherwise not necessary ????? -%if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 +% if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 if soilGRIDsizeOld~=soilGRIDsizeNew disp('xice - reinitializing LUT - soil/air domains changed'); GRID.soil.cT_water=wc; GRID = initializeSoilThermalProperties(GRID, PARA); -end -%end -%reduce water content above the perched water table -%it might be also good to use an external function for this since this is -%only an option in the model -%i=0; -% while i./startCell < 1-PARA.soil.perchedWaterTable -% GRID.soil.cT_water(i+1,1) = PARA.soil.saturationAbovePerchedWaterTable.*(1-GRID.soil.cT_mineral(i+1,1)-GRID.soil.cT_organic(i+1,1)); -% -% GRID.soil.K_water(i+1,1) = PARA.soil.saturationAbovePerchedWaterTable.*(1-GRID.soil.K_mineral(i+1,1)-GRID.soil.K_organic(i+1,1)); -% i=i+1; -% end - - -% [GRID.soil.cT_frozen,... -% GRID.soil.cT_thawed,... -% GRID.soil.K_frozen,... -% GRID.soil.K_thawed,... -% GRID.soil.conductivity,... -% GRID.soil.capacity] = initialize(GRID.soil.cT_water,... -% GRID.soil.cT_mineral,... -% GRID.soil.cT_organic,... -% GRID.soil.cT_soilType,... -% GRID.soil.K_water,... -% GRID.soil.K_mineral,... -% GRID.soil.K_organic,... -% GRID.soil.K_soilType,... -% PARA.technical.arraySizeT,... -% GRID.general.cT_grid(GRID.soil.cT_domain),... -% PARA.soil.kh_bedrock); +end \ No newline at end of file From 80c5a2ab1046a4f1f2db26e538f5e94ff276d866 Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Mon, 12 Feb 2018 10:59:04 +0100 Subject: [PATCH 17/45] main.m replaced by my version (including lake) --- .gitignore | 3 + CryoGrid3_xice_mpi.m | 809 ++++++++++++++++++------------------------- 2 files changed, 345 insertions(+), 467 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1cd9242 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +analysis +forcing + diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 891f7e5..5f2f11a 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -6,485 +6,360 @@ % % ------------------------------------------------------------------------- -delete(gcp('nocreate')) % useful to restart from a crash - -add_modules; %adds required modules - -%dbstop if error; - -number_of_realizations=2; - -if number_of_realizations>1 - parpool(number_of_realizations); +paraFromFile = exist('configFile'); % check if config file passed +add_modules; % adds required modules +createLogFile=1; % set to true if the command window output shall be saved +%tsvd +debug_mode=0; % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) + +%---------------define input parameters------------------------------------ +% here you provide the ground stratigraphy +% z w/i m o type porosity +PARA.soil.layer_properties=[ 0.0 0.40 0.10 0.15 1 0.75;... + 0.15 0.65 0.30 0.05 2 0.65;... + 0.9 0.40 0.55 0.05 1 0.40;... + 9.0 0.30 0.70 0.00 1 0.30 ]; +% PARA.soil.layer_properties=[ 0.0 0.4 0.3 0.00 1 0.70;... +% 0.2 0.7 0.3 0.00 1 0.30;... +% 2.0 0.25 0.75 0.00 1 0.25 ]; +%tsvd +% calculation of soil content +Test=PARA.soil.layer_properties( : , [2 3 4]); +Bodeninhalt=sum(Test,2); +%very simply stratigraphy used to test energy balance +%PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.5 ]; +% soil stratigraphy +% column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer +% extends until the end of the model domain +% column 2: volumetric water+ice content +% column 3: volumetric mineral content +% column 4: volumetric organic content +% column 5: code for soil type: 1: sand, 2: silt +% column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + +%------ model parameters -------------------------------------------------- +% parameters related to surface energy balance and boundary conditions +PARA.soil.albedo=0.2; % albedo snow-free surface +PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development +PARA.soil.epsilon=0.97; % emissvity snow-free surface +PARA.soil.z0=1e-3; % roughness length [m] snow-free surface +PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface +PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] +PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + +% parameters related to hydrology scheme +PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! +PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries +PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries +PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off +PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation +PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. +PARA.soil.externalWaterFlux=0;%-2e-3; %external water flux / drainage in [m/day] +PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible +PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile +PARA.soil.waterTable=0.0; % depth at which a water table will form [m] - above excess water is removed, below it pools up + +% parameters related to snow +PARA.snow.max_albedo=0.85; % albedo of fresh snow +PARA.snow.min_albedo=0.5; % albedo of old snow +PARA.snow.epsilon=0.99; % surface emissivity snow +PARA.snow.z0=5e-4; % roughness length surface [m] +PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow +PARA.snow.rho_snow=200.0; % density in [kg/m3] +PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] +PARA.snow.tau_a=0.008; % [per day] +PARA.snow.tau_f=0.24; % [per day] +PARA.snow.maxSnow= [] ; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold +PARA.snow.extinction=25.0; % light extinction coefficient of snow +%tsvd add lake parameters +% parameters related to lake +PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) +PARA.water.epsilon=0.99; % surface emissivity water +PARA.water.rs=0.; % surface resistance -> should be 0 for water +%tsvd +PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m +PARA.water.extinction=1.2; % light extinction coefficient of water +PARA.water.depth=1.; +PARA.water.fetch=20; + +%tsvd added +PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 < - +PARA.ice.epsilon=0.98; % surface emissivity snow < - +PARA.ice.rs=0; % surface resistance -> should be 0 for ice < - +PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a < - + +PARA.location.latitude = 72.376; % [deg] < - +PARA.location.longitude = 126.491; % [deg] < - +PARA.location.altitude = 20; % [m] used to generate pressure forcing based on baromet < - +PARA.location.GridCellSize = 1e6; % [m^2] < - +PARA.location.TileFraction = 1e-2; + +% parameters related to the site location +PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given + +% technical parameters +PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases +PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells +PARA.technical.maxSWE=0.4; % in [m] SWE +PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity +PARA.technical.starttime=datenum('2000.06.01 00:00:00','yyyy.mm.dd HH:MM:SS'); % starttime of the simulation - if empty start from first value of time series +PARA.technical.endtime=datenum('2002.06.01 00:00:00','yyyy.mm.dd HH:MM:SS'); % endtime of the simulation - if empty end at last value of time series +%PARA.technical.starttime=[]; +%PARA.technical.endtime=[]; +PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds +PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds +PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K +PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours +%tsvd +%PARA.technical.outputTimestep= 1 ./ 24.0 ; % output time step in [days] - here one hour +PARA.technical.saveDate='01.08.'; % date of year when output file is written - no effect if "saveInterval" is empty +PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year +PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] +PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + +%default grid used for publications and testing of water balance: +%PARA.technical.subsurfaceGrid = [[0:0.02:2] [2.1:0.1:8] [8.2:0.2:20] [21:1:30] [35:5:50] [60:10:100] [200:100:1000]]'; % the subsurface K-grid in [m] +%PARA.technical.subsurfaceGrid = [[0:0.02:13] [13.05:0.05:18] [18.2:0.2:20] [21:1:30] [35:5:50] [60:10:100] [200:100:1000]]'; % the subsurface K-grid in [m] +%very simple grid used for testing of energy balance: +PARA.technical.subsurfaceGrid = [ [0:0.02:3] ]'; +%initial temperature profile -> first column depth [m] -> second column temperature [degree C] +PARA.Tinitial = [-5 10;... + 0 0;... + 5 -5;... + 20 -10;... + 100 -10;... + 2000 10]; + +% load natural constants (given in SI units) to PARA.constants +PARA = loadConstants(PARA); + +%FORCING data mat-file +PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files +%PARA.forcing.filename='CG3_CCLM_forcing_90_101.mat'; +PARA.forcing.rain_fraction=1; +PARA.forcing.snow_fraction=1; +%tsvd new switched introduced +PARA.soil.infiltration= 1; % true if infiltration into unfrozen ground occurs +PARA.modules.xice = 1; % true if thaw subsicdence is enabled +% change this to meaningful output +run_number = sprintf('WBcheck_Xice%d_xice%d_rf%d_sf%d', [PARA.soil.infiltration,PARA.modules.xice, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction]); +% ------update parameter values if config file provided ------------------- +% ------changes output directory to name specified in configfile which is the config filename by default +if paraFromFile + run(configFile); end -spmd - index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run - - %---------------define input parameters------------------------------------ - % here you provide the ground stratigraphy - % z w/i m o type porosity - - % default stratigraphy used in publication: - PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 0.65 0.3 0.05 2 0.4;... - 0.9 0.65 0.3 0.05 1 0.65;... - 9.0 0.30 0.70 0.00 1 0.30 ]; - % simple stratigraphy with excess ice used to test water balance: - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... - % 0.4 0.8 0.2 0.00 1 0.40;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - % very simply stratigraphy without excess ice used to test energy balance - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... - % 1.0 0.5 0.5 0.00 1 0.5 ;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - % soil stratigraphy - % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer - % extends until the end of the model domain - % column 2: volumetric water+ice content - % column 3: volumetric mineral content - % column 4: volumetric organic content - % column 5: code for soil type: 1: sand, 2: silt - % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs - - %------ model parameters -------------------------------------------------- - % parameters related to soil - PARA.soil.albedo=0.2; % albedo snow-free surface - PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development - PARA.soil.epsilon=0.97; % emissvity snow-free surface - PARA.soil.z0=1e-3; % roughness length [m] snow-free surface - PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface - PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] - PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] - - % parameters related to hydrology scheme - PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! - PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries - PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries - PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off - PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation - PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. - PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] - PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible - PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile - PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up - PARA.soil.hydraulic_conductivity = 1e-5; - PARA = loadSoilTypes( PARA ); - - % parameters related to snow - PARA.snow.max_albedo=0.85; % albedo of fresh snow - PARA.snow.min_albedo=0.5; % albedo of old snow - PARA.snow.epsilon=0.99; % surface emissivity snow - PARA.snow.z0=5e-4; % roughness length surface [m] - PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow - PARA.snow.rho_snow=200.0; % density in [kg/m3] - PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] - PARA.snow.tau_a=0.008; % [per day] - PARA.snow.tau_f=0.24; % [per day] - PARA.snow.relative_maxSnow= [0.1]; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold - PARA.snow.extinction=25.0; % light extinction coefficient of snow - - % parameters related to water body on top of soil domain - PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) - PARA.water.epsilon=0.99; % surface emissivity water - PARA.water.rs=0.0; % surface resistance -> should be 0 for water - PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation - - PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 - PARA.ice.epsilon=0.98; % surface emissivity snow - PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice - PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow - PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 - - PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases - PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells - PARA.technical.maxSWE=0.4; % in [m] SWE - PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1980, 7, 1); % endtime of the simulation - if empty end at last value of time series - PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds - PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds - PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K - PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year - PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] - - %default grid used for publications and testing of water balance: - PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - - PARA.location.area=1.0; - PARA.location.initial_altitude=20.0; - % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" - PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain - PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow - PARA.location.active_layer_depth_altitude = nan; % defined at runtime - PARA.location.water_table_altitude = nan; % defined at runtime - % thresholds - PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; - if isempty( PARA.snow.relative_maxSnow ) - PARA.location.absolute_maxSnow_altitude = []; - else - PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; - end - - %initial temperature profile -> first column depth [m] -> second column temperature [degree C] - PARA.Tinitial = [ -2 5 ;... - 0 0 ;... - 2 -5 ;... - 10 -10 ;... - 25 -9 ;... - 100 -9 ;... - 2000 10 ]; - - PARA = loadConstants( PARA ); - - %FORCING data mat-file - PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files - PARA.forcing.rain_fraction=1; - PARA.forcing.snow_fraction=1; - - % switches for modules - PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs - PARA.modules.xice=1; % true if thaw subsicdence is enabled - PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) - - if PARA.modules.lateral - % switches for lateral processes - PARA.modules.exchange_heat = 1; - PARA.modules.exchange_water = 1; - PARA.modules.exchange_snow = 1; - - %---------overwrites variables for each realization-------------------- - % this function must define everything that is realization-specific or dependent of all realizations - PARA = get_parallel_variables( PARA ); - end - - % ------make output directory (name depends on parameters) ---------------- - run_number= sprintf( 'testrunMPI_POOL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... - [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... - PARA.modules.infiltration, PARA.modules.xice, ... - PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , ... - index ] ); - - mkdir(['./runs/' run_number]) - - %-------------------------------------------------------------------------- - %-----------do not modify from here onwards-------------------------------- - %-------------------------------------------------------------------------- - [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file - - if ~success - warning('A problem with the Forcing occured.'); - end - - PARA = initializeParameters(PARA, FORCING); %set start time, etc. - - %----------------create and initialize the grids -------------------------- - GRID=makeGrids(PARA); %create all grids - GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid - - %----- initializie excess ground ice -------------------------------------- - [GRID,PARA] = initializeExcessIce2(GRID,PARA); +% ------make output directory (name depends on parameters) ---------------- - %----- initializie soil thermal properties -------------------------------- - GRID = initializeSoilThermalProperties(GRID, PARA); +% ------make output directory (name depends on parameters) ---------------- +mkdir(run_number) - %------ initializie snow properties---------------------------------------- - GRID = initializeSnow(GRID); - - %---- initialize the surface energy balance struct ------------------------ - SEB = initializeSEB(); - - %---- initialize the water body module ------------------------------------ - GRID = initializeLAKE(GRID); - - %---- initialize temperature profile -------------------------------------- - T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); - - %---- modification for infiltration - wc=GRID.soil.cT_water; - GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; - GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; +% ------redirect command line output to logfile --------------------------- +if createLogFile + diary(['./' run_number '/' run_number '_log.mat']); +end - %---- preallocate temporary arrays for capacity and conductivity----------- - [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid - %---- energy and water balance initialization ----------------------------- - BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); +%-------------------------------------------------------------------------- +%-----------do not modify from here onwards-------------------------------- +%-------------------------------------------------------------------------- +[FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file - %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? - water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index - snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index - heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index - dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index +if ~success + return +end +clear success + +PARA = initializeParameters(PARA, FORCING); %set start time, etc. + +%----------------create and initialize the grids -------------------------- +GRID = makeGrids(PARA); %create all grids +GRID = createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + +%tsvd +% @ ALEX: this is the excess ice module to be tested in combination with +% the "hydrology" module. here it is initialized. +%----- initializie excess ground ice -------------------------------------- +[GRID,PARA] = initializeExcessIce(GRID,PARA); +%----- initializie soil thermal properties -------------------------------- +% JAN: here the LOOKUP tables GRID.soil.capacity and GRID.soil.conductivity +% are generated, later thermal properties are extracted from these tables +GRID = initializeSoilThermalProperties(GRID, PARA); + +%------ initializie snow properties---------------------------------------- +GRID = initializeSnow(GRID); + +%---- initialize the surface energy balance struct ------------------------ +SEB = initializeSEB(); +%tsvd +%---- initialize the lake scheme structs ---------------------------------- +[FLAKE GRID] = initializeLAKE(GRID, PARA); +%---- initialize temperature profile -------------------------------------- +T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); +% JAN: sets Tair from forcing, Tsnow to -4°C and interpolats Tsoil from PARA.Tinitial + +%---- modification for infiltration --------------------------------------- +wc=GRID.soil.cT_water; % zzz needs to be updated first? L289 [wc, GRID] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING); +GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; +GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; + +%---- preallocate temporary arrays for capacity and conductivity----------- +% this is basically the same as "getThermalProperties" during integration, but without interpolation +[c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); + +% JAN: added for energy balance checks: absolute "energetic state" of the soil domain [in J/m^2]----------------------------------------- + +%tsvd zzz +%EtotSoil = nansum( ( ( PARA.constants.c_w .* lwc_cTgrid(GRID.soil.cT_domain) + PARA.constants.c_i .* (wc-lwc_cTgrid(GRID.soil.cT_domain)) + PARA.constants.c_m .* GRID.soil.cT_mineral ) .* T(GRID.soil.cT_domain) + ... +% + PARA.constants.rho_w .* PARA.constants.L_sl .* lwc_cTgrid(GRID.soil.cT_domain) ) ... +% .* GRID.general.K_delta(GRID.soil.cT_domain) ); + + +%__________________________________________________________________________ +%-------- provide arrays for data storage --------------------------------- +[t, TEMPORARY] = generateTemporary(T, PARA); +OUT = generateOUT(); + +disp('initialization successful'); +save([run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') + +%% ________________________________________________________________________ +% Time Integration Routine I +% I +%tsvd _________________________________________________________________________I +%check if stratigraphy is ok +if sum(Bodeninhalt)>size(Bodeninhalt,1); warning( 'soil content must not exceed 100% - check stratigraphy' ); end +i=1; +whileloop_counter=0; +while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) - warning( 'numerical stability not guaranteed' ); - end - - %------ update T array ------------------------------------------------ - % account for vertical heat fluxes from ground heat flux and heat conduction - T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; - % account for lateral heat fluxes - T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] - % set grid cells in air to air temperature - T(GRID.air.cT_domain)=FORCING.i.Tair; - - %------- water body module -------------------------------------------- - T = mixingWaterBody(T, GRID); - - %------- snow cover module -------------------------------------------- - [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - - %------- infiltration module------------------------------------------- - if PARA.modules.infiltration - lateral_water_flux = nansum( water_fluxes ); % lateral fluxes to/from other workers in [m/s] - [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_water_flux); - end + %------ surface energy balance module --------------------------------- + %set surface conditions (albedo, roughness length, etc.) + +%tsvd [PARA, GRID] = surfaceCondition(GRID, PARA, T); % old implementation + [PARA, GRID] = surfaceCondition(GRID, PARA, T, t, FORCING, SEB); - %------- excess ice module -------------------------------------------- - if PARA.modules.xice && ~PARA.modules.infiltration - warning( 'energy and water balances are not correct for this combination of modules'); - [GRID, PARA] = excessGroundIce(T, GRID, PARA); - % assure wc has correct length - wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); - elseif PARA.modules.xice && PARA.modules.infiltration - [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); - GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + %calculate the surface energy balance + [SEB, dwc_dt] = surfaceEnergyBalanceInfiltration(T, wc, FORCING, GRID, PARA, SEB); + + %------ soil module -------------------------------------------------- + %calculate heat conduction + SEB = heatConduction(T, k_Kgrid, GRID, PARA, SEB); + + %------ sum up heat fluxes -------------------------------------------- + SEB.dE_dt = SEB.dE_dt_cond + SEB.dE_dt_SEB; + + %------ determine optimal timestep [days] ----------------------------- + % accounting for min and max timesteps specified, maximum energy change per grid cell and the CFT stability criterion +% use new timestep definition as below +% timestep = min( [ max( [ min( [ 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600), ... +% PARA.technical.targetDeltaE .* min( abs(GRID.general.K_delta ./ SEB.dE_dt) ) ./ (24.*3600), ... +% PARA.technical.maxTimestep ] ), ... +% PARA.technical.minTimestep ] ), ... +% TEMPORARY.outputTime-t ] ); +%tsvd +%% NEW implementation: + if(~debug_mode) + timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain + GRID.lake.ice.cT_domain)) ./ (24.*3600), ... + PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt) ./ (GRID.soil.cT_domain + GRID.snow.cT_domain + GRID.lake.ice.cT_domain)) ./ (24.*3600), ... + PARA.technical.maxTimestep ] ), ... + PARA.technical.minTimestep ] ), ... + TEMPORARY.outputTime-t ] ); + else % debug mode + timestep = PARA.technical.minTimestep; % use for debugging to avoid NaN... zzz + disp('WARNING: timestep set to minTimestep for debugging') + end + % give a warning when timestep required by CFT criterion is below the + % minimum timestep specified +% if timestep > 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) +% warning( 'numerical stability not guaranteed' ); +% end + %------ update T array ------------------------------------------------ + T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; + T(GRID.air.cT_domain)=FORCING.i.Tair; + if max((T<-100))==1; disp('dwd'); end + + %------- snow cover module -------------------------------------------- + [T, GRID, PARA, SEB] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep); + [GRID, T] = updateGRID_snow(T, GRID, PARA); + + %------- infiltration module------------------------------------------- + if PARA.soil.infiltration %tsvd + [wc, GRID] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING); + end +%tsvd + %------- water body module -------------------------------------------- + if timestep>0 && ( ~isempty(GRID.lake.water.cT_domain_ub) || ~isempty(GRID.lake.ice.cT_domain_ub) ) + %ice cover + [T GRID FLAKE] = cryoGridIceCover(GRID, SEB, FLAKE, T, c_cTgrid, timestep); + %FLAKE + if isempty(GRID.lake.ice.cT_domain_ub) && sum(GRID.lake.water.cT_domain)>=3 + %FLAKE is used if no ice cells exist + [T GRID FLAKE] = cryoGridFLAKE(FLAKE, GRID, SEB, PARA, T, T_old, timestep, k_Kgrid, SEB.dE_dt, SEB.dE_dt_SEB); + else + %updated FLAKE variables also when FLAKE is not used + FLAKE.t_bot_n_flk = T(GRID.lake.water.cT_domain_lb) + 273.15; + %set mixed layerdepth to zero + FLAKE.h_ml_n_flk = 0; end - - %------- update Lstar for next time step ------------------------------ - SEB = L_star(FORCING, PARA, SEB); - - %------- update auxiliary state variables - PARA.location.altitude = getAltitude( PARA, GRID ); - PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); - PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); - PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); - - %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time - if ~PARA.modules.lateral - PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; - if isempty( PARA.snow.maxSnow ) - PARA.location.absolute_maxSnow_altitude = []; - else - PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; - end - end - - %------- water balance calculations ----------------------------------- - % rainfall - BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval - % snowfall - BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval - - %------- lateral exchange module -------------------------------------- - % all functions called in this block should go into - % /modules/cryoGridLateral - % calling PARA.ensemble is only allowed here - if PARA.modules.lateral - if t==TEMPORARY.syncTime %communication between workers - disp('CryoGridLateral: sync - start'); - labBarrier(); %common start - PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; - - % heat exchange module - if PARA.modules.exchange_heat - labBarrier(); - % check preconditions - precondition_heatExchange = true; %no specific conditions so far - if precondition_heatExchange - %WRAPPER - disp('sync - exchanging heat'); - % calculate lateral heat fluxes - dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] - heat_fluxes = zeros( numlabs, 1); - PACKAGE_heatExchange.T = T; - PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; - PACKAGE_heatExchange.k_cTgrid = k_cTgrid; - for j=1:number_of_realizations - if j~=index - labSend( PACKAGE_heatExchange, j, 1); - end - end - for j=1:number_of_realizations - if j~=index - PACKAGE_heatExchange_j = labReceive(j, 1); - [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index - heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes - dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations - end - end - end - end - - % water exchange module - if PARA.modules.exchange_water - labBarrier(); - % check preconditions - precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); - if precondition_waterExchange - % WRAPPER - disp('sync - exchanging water'); - % calculate lateral water fluxes - water_fluxes = nan( number_of_realizations, 1 ); % in [m/s] - PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); - PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); - PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); - for j=1:number_of_realizations - if j~=index - labSend( PACKAGE_waterExchange, j, 2); - end - end - for j=1:number_of_realizations - if j~=index - PACKAGE_waterExchange_j = labReceive(j, 2); - % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) - water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); % matrix containing all fluxes in [m/s] scaled to row index - end - end - % for debugging: print water flux per column - waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m - fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); - end - - end - - % snow exchange module - if PARA.modules.exchange_snow - labBarrier(); - % check preconditions - precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); - if precondition_snowExchange - disp('sync - exchanging snow'); - % calculate terrain index with updated surface_altitudes - PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); - - % calculate mobile snow - % WRAPPER - mobile_snow = zeros( 1, number_of_realizations ); - my_mobile_snow = 0; - meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE - if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions - i=0; - while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold - > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains - && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) - - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) - my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile - i=i+1; - end - end - mobile_snow(index) = my_mobile_snow; - % exchange mobile snow amounts - for j=1:number_of_realizations - if j~=index - % send mobile snow amount in [m SWE] - labSend( mobile_snow(index), j, 4 ); - end - end - for j=1:number_of_realizations - if j~=index - % receive mobile snow amount [m SWE] - mobile_snow(j) = labReceive(j, 4); - end - end - % calculate lateral snow fluxes - my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); - % apply lateral snow fluxes directly - if my_snow_change ~= 0 - [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; - end - - snow_fluxes = zeros( numlabs , 1 ); - snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes - fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); - - end - end - - labBarrier(); - PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; - - TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; - disp('sync - done'); - end - end - - - %------- next time step ----------------------------------------------- - t=t+timestep; - %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes); - - + GRID = updateGRID_flake(GRID); + end + %--------- buoyancy calculation in block fields------------------------ + %T = convectionInBlocks(T, c_cTgrid, GRID) %not available + % @ ALEX: here the calculations of the excess ice module take place + % (uncomment this line to "activate" the module). Note that the + % stratigraphy must be modified such that excess ground ice is present + % in order to make the module "work" + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.soil.infiltration + [GRID, PARA, wc] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc( end-sum(GRID.soil.cT_domain)+1 : end ); %tsvd make vector dims consistent + elseif PARA.modules.xice && PARA.soil.infiltration + [GRID, PARA, wc] = excessGroundIceInfiltration(T, wc, GRID, PARA); end + %------- update Lstar for next time step ------------------------------ + SEB = L_star(FORCING, PARA, SEB); +%tsvd + % caluclations for energy balance (can be ignored if not testing) + %------- energy balance calculations --> could go into sum_up_output_store() +% TEMPORARY.dEsensSoil = TEMPORARY.dEsensSoil + ... +% nansum( (T(GRID.soil.cT_domain)-T_old(GRID.soil.cT_domain)) .* ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral ) .* GRID.general.K_delta(GRID.soil.cT_domain) ); +% TEMPORARY.dEsensSnow = TEMPORARY.dEsensSnow + ... +% nansum( (T(GRID.snow.cT_domain)-T_old(GRID.snow.cT_domain)) .* ( PARA.constants.c_w .* GRID.snow.Snow_w(GRID.snow.cT_domain) + PARA.constants.c_i .* GRID.snow.Snow_i(GRID.snow.cT_domain) ) ); +% TEMPORARY.dElatentSoil = TEMPORARY.dElatentSoil + ... +% nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* ( lwc - lwc_old ) .* GRID.general.K_delta(GRID.soil.cT_domain) ); +% TEMPORARY.dElatentSnow = TEMPORARY.dElatentSnow + ... +% nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* ( GRID.snow.Snow_w - Snow_w_old ) ); +% +% EtotSoil = nansum( ( ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral ) .* T(GRID.soil.cT_domain) + ... +% + PARA.constants.rho_w .* PARA.constants.L_sl .* lwc ) ... +% .* GRID.general.K_delta(GRID.soil.cT_domain) ); +% TEMPORARY.dEtotSoil = TEMPORARY.dEtotSoil + EtotSoil - EtotSoil_old; +% + %---------- sum up + OUTPUT ------------------------------------------- + sum_up_output_store; + %------- next time step ----------------------------------------------- + t=t+timestep; - % save final state and output at t=endtime - iSaveOUT(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) - iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) - + %---------- sum up + OUTPUT ------------------------------------------- + sum_up_output_store; end - -if number_of_realizations>1 - delete(gcp('nocreate')) -end - +%profile off +save([run_number '/' run_number '_output.mat'], 'OUT') disp('Done.'); \ No newline at end of file From e101cff1f517390986b71c62985cc3fe9daf9601 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Mon, 12 Feb 2018 14:38:42 +0100 Subject: [PATCH 18/45] changes to treating lacking water in bucket scheme. --- modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m index 4940ba3..d5de0c5 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m @@ -31,8 +31,9 @@ end excess_water=dwc_dt(i)+external_flux; %add external flux -lacking_water = lacking_water + (excess_water<0)*excess_water; % this accounts for violations of the water balance +excess_water=excess_water - lacking_water; % remove potential mismatches (e.g. when evaporation in cell with low water content) +lacking_water = -(excess_water<0)*excess_water; % this accounts for violations of the water balance i=i-1; while i>=1 && excess_water>0 From fa0170240f34c702749659d5a840863d0dfd8487 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Mon, 12 Feb 2018 14:42:21 +0100 Subject: [PATCH 19/45] minor bugfix in bucketScheme.m --- modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m index d5de0c5..3c447ba 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m @@ -10,7 +10,7 @@ residualWaterContent = zeros(size(soilType)); for i=1:size(PARA.soil.soilTypes,1) fieldCapacity(soilType==i) = PARA.soil.soilTypes( i, 2 ); - residualWaterContent(soilType==1) = PARA.soil.soilTypes( i, 1 ); + residualWaterContent(soilType==i) = PARA.soil.soilTypes( i, 1 ); end lacking_water=0; From 1402107177ab019cada00e568d452910144ea6ce Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Mon, 12 Feb 2018 15:26:40 +0100 Subject: [PATCH 20/45] merge of Flake version with Jan's version for main.m and add_modules.m --- .gitignore | 2 + CryoGrid3_xice_mpi.m | 766 ++++++++++++++++++++++++++----------------- add_modules.m | 5 +- 3 files changed, 468 insertions(+), 305 deletions(-) diff --git a/.gitignore b/.gitignore index 1cd9242..3c80e8c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ analysis forcing +runs +*.asv diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 5f2f11a..8e8de95 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -6,75 +6,87 @@ % % ------------------------------------------------------------------------- -paraFromFile = exist('configFile'); % check if config file passed -add_modules; % adds required modules -createLogFile=1; % set to true if the command window output shall be saved -%tsvd -debug_mode=0; % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) - -%---------------define input parameters------------------------------------ -% here you provide the ground stratigraphy -% z w/i m o type porosity -PARA.soil.layer_properties=[ 0.0 0.40 0.10 0.15 1 0.75;... - 0.15 0.65 0.30 0.05 2 0.65;... - 0.9 0.40 0.55 0.05 1 0.40;... - 9.0 0.30 0.70 0.00 1 0.30 ]; -% PARA.soil.layer_properties=[ 0.0 0.4 0.3 0.00 1 0.70;... -% 0.2 0.7 0.3 0.00 1 0.30;... -% 2.0 0.25 0.75 0.00 1 0.25 ]; -%tsvd -% calculation of soil content -Test=PARA.soil.layer_properties( : , [2 3 4]); -Bodeninhalt=sum(Test,2); -%very simply stratigraphy used to test energy balance -%PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.5 ]; -% soil stratigraphy -% column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer -% extends until the end of the model domain -% column 2: volumetric water+ice content -% column 3: volumetric mineral content -% column 4: volumetric organic content -% column 5: code for soil type: 1: sand, 2: silt -% column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs - -%------ model parameters -------------------------------------------------- -% parameters related to surface energy balance and boundary conditions -PARA.soil.albedo=0.2; % albedo snow-free surface -PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development -PARA.soil.epsilon=0.97; % emissvity snow-free surface -PARA.soil.z0=1e-3; % roughness length [m] snow-free surface -PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface -PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] -PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] - -% parameters related to hydrology scheme -PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! -PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries -PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries -PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off -PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation -PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. -PARA.soil.externalWaterFlux=0;%-2e-3; %external water flux / drainage in [m/day] -PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible -PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile -PARA.soil.waterTable=0.0; % depth at which a water table will form [m] - above excess water is removed, below it pools up - -% parameters related to snow -PARA.snow.max_albedo=0.85; % albedo of fresh snow -PARA.snow.min_albedo=0.5; % albedo of old snow -PARA.snow.epsilon=0.99; % surface emissivity snow -PARA.snow.z0=5e-4; % roughness length surface [m] -PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow -PARA.snow.rho_snow=200.0; % density in [kg/m3] -PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] -PARA.snow.tau_a=0.008; % [per day] -PARA.snow.tau_f=0.24; % [per day] -PARA.snow.maxSnow= [] ; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold -PARA.snow.extinction=25.0; % light extinction coefficient of snow +delete(gcp('nocreate')) % useful to restart from a crash + +add_modules; %adds required modules + +%dbstop if error; + +number_of_realizations=2; + +if number_of_realizations>1 + parpool(number_of_realizations); +end + +spmd + index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run + + %---------------define input parameters------------------------------------ + % here you provide the ground stratigraphy + % z w/i m o type porosity + + % default stratigraphy used in publication: + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.3 0.05 2 0.4;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + % simple stratigraphy with excess ice used to test water balance: + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... + % 0.4 0.8 0.2 0.00 1 0.40;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % very simply stratigraphy without excess ice used to test energy balance + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... + % 1.0 0.5 0.5 0.00 1 0.5 ;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer + % extends until the end of the model domain + % column 2: volumetric water+ice content + % column 3: volumetric mineral content + % column 4: volumetric organic content + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + %------ model parameters -------------------------------------------------- + % parameters related to soil + PARA.soil.albedo=0.2; % albedo snow-free surface + PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development + PARA.soil.epsilon=0.97; % emissvity snow-free surface + PARA.soil.z0=1e-3; % roughness length [m] snow-free surface + PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface + PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] + PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + + % parameters related to hydrology scheme + PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries + PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation + PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. + PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] + PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible + PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile + PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up + PARA.soil.hydraulic_conductivity = 1e-5; + PARA = loadSoilTypes( PARA ); + + % parameters related to snow + PARA.snow.max_albedo=0.85; % albedo of fresh snow + PARA.snow.min_albedo=0.5; % albedo of old snow + PARA.snow.epsilon=0.99; % surface emissivity snow + PARA.snow.z0=5e-4; % roughness length surface [m] + PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow + PARA.snow.rho_snow=200.0; % density in [kg/m3] + PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] + PARA.snow.tau_a=0.008; % [per day] + PARA.snow.tau_f=0.24; % [per day] + PARA.snow.relative_maxSnow= [0.1]; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.extinction=25.0; % light extinction coefficient of snow %tsvd add lake parameters % parameters related to lake -PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) -PARA.water.epsilon=0.99; % surface emissivity water + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.epsilon=0.99; % surface emissivity water PARA.water.rs=0.; % surface resistance -> should be 0 for water %tsvd PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m @@ -82,226 +94,219 @@ PARA.water.depth=1.; PARA.water.fetch=20; -%tsvd added -PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 < - -PARA.ice.epsilon=0.98; % surface emissivity snow < - -PARA.ice.rs=0; % surface resistance -> should be 0 for ice < - -PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a < - - -PARA.location.latitude = 72.376; % [deg] < - -PARA.location.longitude = 126.491; % [deg] < - -PARA.location.altitude = 20; % [m] used to generate pressure forcing based on baromet < - -PARA.location.GridCellSize = 1e6; % [m^2] < - -PARA.location.TileFraction = 1e-2; - -% parameters related to the site location -PARA.location.altitude=20.0; %used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given - -% technical parameters -PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases -PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells -PARA.technical.maxSWE=0.4; % in [m] SWE -PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity -PARA.technical.starttime=datenum('2000.06.01 00:00:00','yyyy.mm.dd HH:MM:SS'); % starttime of the simulation - if empty start from first value of time series -PARA.technical.endtime=datenum('2002.06.01 00:00:00','yyyy.mm.dd HH:MM:SS'); % endtime of the simulation - if empty end at last value of time series -%PARA.technical.starttime=[]; -%PARA.technical.endtime=[]; -PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds -PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds -PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K -PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours -%tsvd -%PARA.technical.outputTimestep= 1 ./ 24.0 ; % output time step in [days] - here one hour -PARA.technical.saveDate='01.08.'; % date of year when output file is written - no effect if "saveInterval" is empty -PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year -PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] -PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - -%default grid used for publications and testing of water balance: -%PARA.technical.subsurfaceGrid = [[0:0.02:2] [2.1:0.1:8] [8.2:0.2:20] [21:1:30] [35:5:50] [60:10:100] [200:100:1000]]'; % the subsurface K-grid in [m] -%PARA.technical.subsurfaceGrid = [[0:0.02:13] [13.05:0.05:18] [18.2:0.2:20] [21:1:30] [35:5:50] [60:10:100] [200:100:1000]]'; % the subsurface K-grid in [m] -%very simple grid used for testing of energy balance: -PARA.technical.subsurfaceGrid = [ [0:0.02:3] ]'; -%initial temperature profile -> first column depth [m] -> second column temperature [degree C] -PARA.Tinitial = [-5 10;... - 0 0;... - 5 -5;... - 20 -10;... - 100 -10;... - 2000 10]; - + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + PARA.ice.epsilon=0.98; % surface emissivity snow + PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice + PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow + PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases + PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells + PARA.technical.maxSWE=0.4; % in [m] SWE + PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity + PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(1980, 7, 1); % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds + PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds + PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + + %default grid used for publications and testing of water balance: + PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + + PARA.location.area=1.0; + PARA.location.initial_altitude=20.0; + % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" + PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain + PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow + PARA.location.active_layer_depth_altitude = nan; % defined at runtime + PARA.location.water_table_altitude = nan; % defined at runtime + % thresholds + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.relative_maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; + end + + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... + 2000 10 ]; + % load natural constants (given in SI units) to PARA.constants -PARA = loadConstants(PARA); - -%FORCING data mat-file -PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files -%PARA.forcing.filename='CG3_CCLM_forcing_90_101.mat'; -PARA.forcing.rain_fraction=1; -PARA.forcing.snow_fraction=1; -%tsvd new switched introduced -PARA.soil.infiltration= 1; % true if infiltration into unfrozen ground occurs -PARA.modules.xice = 1; % true if thaw subsicdence is enabled -% change this to meaningful output -run_number = sprintf('WBcheck_Xice%d_xice%d_rf%d_sf%d', [PARA.soil.infiltration,PARA.modules.xice, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction]); -% ------update parameter values if config file provided ------------------- -% ------changes output directory to name specified in configfile which is the config filename by default -if paraFromFile - run(configFile); -end + PARA = loadConstants( PARA ); -% ------make output directory (name depends on parameters) ---------------- + %FORCING data mat-file + PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.rain_fraction=1; + PARA.forcing.snow_fraction=1; -% ------make output directory (name depends on parameters) ---------------- -mkdir(run_number) + % switches for modules + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=1; % true if thaw subsicdence is enabled + PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) + + if PARA.modules.lateral + % switches for lateral processes + PARA.modules.exchange_heat = 1; + PARA.modules.exchange_water = 1; + PARA.modules.exchange_snow = 1; + + %---------overwrites variables for each realization-------------------- + % this function must define everything that is realization-specific or dependent of all realizations + PARA = get_parallel_variables( PARA ); + end + + % ------make output directory (name depends on parameters) ---------------- + run_number= sprintf( 'testrunMPI_POOL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... + [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... + PARA.modules.infiltration, PARA.modules.xice, ... + PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , ... + index ] ); + + mkdir(['./runs/' run_number]) -% ------redirect command line output to logfile --------------------------- -if createLogFile - diary(['./' run_number '/' run_number '_log.mat']); -end + %-------------------------------------------------------------------------- + %-----------do not modify from here onwards-------------------------------- + %-------------------------------------------------------------------------- + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + if ~success + warning('A problem with the Forcing occured.'); + end -%-------------------------------------------------------------------------- -%-----------do not modify from here onwards-------------------------------- -%-------------------------------------------------------------------------- -[FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + PARA = initializeParameters(PARA, FORCING); %set start time, etc. -if ~success - return -end -clear success + %----------------create and initialize the grids -------------------------- + GRID=makeGrids(PARA); %create all grids + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid -PARA = initializeParameters(PARA, FORCING); %set start time, etc. + %----- initializie excess ground ice -------------------------------------- + [GRID,PARA] = initializeExcessIce2(GRID,PARA); -%----------------create and initialize the grids -------------------------- -GRID = makeGrids(PARA); %create all grids -GRID = createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + %----- initializie soil thermal properties -------------------------------- + GRID = initializeSoilThermalProperties(GRID, PARA); -%tsvd -% @ ALEX: this is the excess ice module to be tested in combination with -% the "hydrology" module. here it is initialized. -%----- initializie excess ground ice -------------------------------------- -[GRID,PARA] = initializeExcessIce(GRID,PARA); -%----- initializie soil thermal properties -------------------------------- -% JAN: here the LOOKUP tables GRID.soil.capacity and GRID.soil.conductivity -% are generated, later thermal properties are extracted from these tables -GRID = initializeSoilThermalProperties(GRID, PARA); - -%------ initializie snow properties---------------------------------------- -GRID = initializeSnow(GRID); - -%---- initialize the surface energy balance struct ------------------------ -SEB = initializeSEB(); -%tsvd -%---- initialize the lake scheme structs ---------------------------------- -[FLAKE GRID] = initializeLAKE(GRID, PARA); -%---- initialize temperature profile -------------------------------------- -T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); -% JAN: sets Tair from forcing, Tsnow to -4°C and interpolats Tsoil from PARA.Tinitial - -%---- modification for infiltration --------------------------------------- -wc=GRID.soil.cT_water; % zzz needs to be updated first? L289 [wc, GRID] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING); -GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; -GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; - -%---- preallocate temporary arrays for capacity and conductivity----------- -% this is basically the same as "getThermalProperties" during integration, but without interpolation -[c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); - -% JAN: added for energy balance checks: absolute "energetic state" of the soil domain [in J/m^2]----------------------------------------- - -%tsvd zzz -%EtotSoil = nansum( ( ( PARA.constants.c_w .* lwc_cTgrid(GRID.soil.cT_domain) + PARA.constants.c_i .* (wc-lwc_cTgrid(GRID.soil.cT_domain)) + PARA.constants.c_m .* GRID.soil.cT_mineral ) .* T(GRID.soil.cT_domain) + ... -% + PARA.constants.rho_w .* PARA.constants.L_sl .* lwc_cTgrid(GRID.soil.cT_domain) ) ... -% .* GRID.general.K_delta(GRID.soil.cT_domain) ); - - -%__________________________________________________________________________ -%-------- provide arrays for data storage --------------------------------- -[t, TEMPORARY] = generateTemporary(T, PARA); -OUT = generateOUT(); - -disp('initialization successful'); -save([run_number '/' run_number '_settings.mat'], 'FORCING', 'PARA', 'GRID') - -%% ________________________________________________________________________ -% Time Integration Routine I -% I -%tsvd _________________________________________________________________________I -%check if stratigraphy is ok -if sum(Bodeninhalt)>size(Bodeninhalt,1); warning( 'soil content must not exceed 100% - check stratigraphy' ); end -i=1; -whileloop_counter=0; -while t these could go into a LATERAL struct or TEMPORARY? + water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index + snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index + heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index - %------determine the thermal properties of the model domains ---------- - [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = getThermalPropertiesInfiltration(T, wc, c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid, GRID, PARA); + %__________________________________________________________________________ + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); - %------ surface energy balance module --------------------------------- - %set surface conditions (albedo, roughness length, etc.) + disp('initialization successful'); + iSaveSettings( [ './runs/' run_number '/' run_number '_settings.mat'] , FORCING, PARA, GRID) + + + %% ________________________________________________________________________ + % Time Integration Routine I + % I + %_________________________________________________________________________I + + while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) + warning( 'numerical stability not guaranteed' ); + end - %calculate the surface energy balance - [SEB, dwc_dt] = surfaceEnergyBalanceInfiltration(T, wc, FORCING, GRID, PARA, SEB); - - %------ soil module -------------------------------------------------- - %calculate heat conduction - SEB = heatConduction(T, k_Kgrid, GRID, PARA, SEB); - - %------ sum up heat fluxes -------------------------------------------- - SEB.dE_dt = SEB.dE_dt_cond + SEB.dE_dt_SEB; - - %------ determine optimal timestep [days] ----------------------------- - % accounting for min and max timesteps specified, maximum energy change per grid cell and the CFT stability criterion -% use new timestep definition as below -% timestep = min( [ max( [ min( [ 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600), ... -% PARA.technical.targetDeltaE .* min( abs(GRID.general.K_delta ./ SEB.dE_dt) ) ./ (24.*3600), ... -% PARA.technical.maxTimestep ] ), ... -% PARA.technical.minTimestep ] ), ... -% TEMPORARY.outputTime-t ] ); -%tsvd -%% NEW implementation: - if(~debug_mode) - timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain + GRID.lake.ice.cT_domain)) ./ (24.*3600), ... - PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt) ./ (GRID.soil.cT_domain + GRID.snow.cT_domain + GRID.lake.ice.cT_domain)) ./ (24.*3600), ... - PARA.technical.maxTimestep ] ), ... - PARA.technical.minTimestep ] ), ... - TEMPORARY.outputTime-t ] ); - else % debug mode - timestep = PARA.technical.minTimestep; % use for debugging to avoid NaN... zzz - disp('WARNING: timestep set to minTimestep for debugging') - end - % give a warning when timestep required by CFT criterion is below the - % minimum timestep specified -% if timestep > 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) -% warning( 'numerical stability not guaranteed' ); -% end - %------ update T array ------------------------------------------------ - T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; - T(GRID.air.cT_domain)=FORCING.i.Tair; + %------ update T array ------------------------------------------------ + % account for vertical heat fluxes from ground heat flux and heat conduction + T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; + % account for lateral heat fluxes + T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] + % set grid cells in air to air temperature + T(GRID.air.cT_domain)=FORCING.i.Tair; if max((T<-100))==1; disp('dwd'); end - - %------- snow cover module -------------------------------------------- - [T, GRID, PARA, SEB] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep); - [GRID, T] = updateGRID_snow(T, GRID, PARA); - - %------- infiltration module------------------------------------------- - if PARA.soil.infiltration %tsvd - [wc, GRID] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING); - end + + %------- water body module -------------------------------------------- + T = mixingWaterBody(T, GRID); + + %------- snow cover module -------------------------------------------- + [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + + %------- infiltration module------------------------------------------- + if PARA.modules.infiltration + lateral_water_flux = nansum( water_fluxes ); % lateral fluxes to/from other workers in [m/s] + [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_water_flux); + end %tsvd %------- water body module -------------------------------------------- if timestep>0 && ( ~isempty(GRID.lake.water.cT_domain_ub) || ~isempty(GRID.lake.ice.cT_domain_ub) ) @@ -325,41 +330,194 @@ % (uncomment this line to "activate" the module). Note that the % stratigraphy must be modified such that excess ground ice is present % in order to make the module "work" - %------- excess ice module -------------------------------------------- - if PARA.modules.xice && ~PARA.soil.infiltration - [GRID, PARA, wc] = excessGroundIce(T, GRID, PARA); - % assure wc has correct length - wc( end-sum(GRID.soil.cT_domain)+1 : end ); %tsvd make vector dims consistent - elseif PARA.modules.xice && PARA.soil.infiltration - [GRID, PARA, wc] = excessGroundIceInfiltration(T, wc, GRID, PARA); + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.modules.infiltration + warning( 'energy and water balances are not correct for this combination of modules'); + [GRID, PARA] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); + elseif PARA.modules.xice && PARA.modules.infiltration + [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); + GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + end + + %------- update Lstar for next time step ------------------------------ + SEB = L_star(FORCING, PARA, SEB); + + %------- update auxiliary state variables + PARA.location.altitude = getAltitude( PARA, GRID ); + PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); + PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); + PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); + + %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time + if ~PARA.modules.lateral + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; + end + end + + %------- water balance calculations ----------------------------------- + % rainfall + BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval + % snowfall + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval + + %------- lateral exchange module -------------------------------------- + % all functions called in this block should go into + % /modules/cryoGridLateral + % calling PARA.ensemble is only allowed here + if PARA.modules.lateral + if t==TEMPORARY.syncTime %communication between workers + disp('CryoGridLateral: sync - start'); + labBarrier(); %common start + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + % heat exchange module + if PARA.modules.exchange_heat + labBarrier(); + % check preconditions + precondition_heatExchange = true; %no specific conditions so far + if precondition_heatExchange + %WRAPPER + disp('sync - exchanging heat'); + % calculate lateral heat fluxes + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + heat_fluxes = zeros( numlabs, 1); + PACKAGE_heatExchange.T = T; + PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; + PACKAGE_heatExchange.k_cTgrid = k_cTgrid; + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_heatExchange, j, 1); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_heatExchange_j = labReceive(j, 1); + [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index + heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes + dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations + end + end + end + end + + % water exchange module + if PARA.modules.exchange_water + labBarrier(); + % check preconditions + precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); + if precondition_waterExchange + % WRAPPER + disp('sync - exchanging water'); + % calculate lateral water fluxes + water_fluxes = nan( number_of_realizations, 1 ); % in [m/s] + PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); + PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_waterExchange, j, 2); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_waterExchange_j = labReceive(j, 2); + % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) + water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); % matrix containing all fluxes in [m/s] scaled to row index + end + end + % for debugging: print water flux per column + waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m + fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); + end + + end + + % snow exchange module + if PARA.modules.exchange_snow + labBarrier(); + % check preconditions + precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); + if precondition_snowExchange + disp('sync - exchanging snow'); + % calculate terrain index with updated surface_altitudes + PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); + + % calculate mobile snow + % WRAPPER + mobile_snow = zeros( 1, number_of_realizations ); + my_mobile_snow = 0; + meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE + if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions + i=0; + while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold + > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains + && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) + - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) + my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile + i=i+1; + end + end + mobile_snow(index) = my_mobile_snow; + % exchange mobile snow amounts + for j=1:number_of_realizations + if j~=index + % send mobile snow amount in [m SWE] + labSend( mobile_snow(index), j, 4 ); + end + end + for j=1:number_of_realizations + if j~=index + % receive mobile snow amount [m SWE] + mobile_snow(j) = labReceive(j, 4); + end + end + % calculate lateral snow fluxes + my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); + % apply lateral snow fluxes directly + if my_snow_change ~= 0 + [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; + end + + snow_fluxes = zeros( numlabs , 1 ); + snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes + fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); + + end + end + + labBarrier(); + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; + disp('sync - done'); + end + end + + + %------- next time step ----------------------------------------------- + t=t+timestep; + %---------- sum up + OUTPUT ------------------------------------------- + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes); + + end - %------- update Lstar for next time step ------------------------------ - SEB = L_star(FORCING, PARA, SEB); -%tsvd - % caluclations for energy balance (can be ignored if not testing) - %------- energy balance calculations --> could go into sum_up_output_store() -% TEMPORARY.dEsensSoil = TEMPORARY.dEsensSoil + ... -% nansum( (T(GRID.soil.cT_domain)-T_old(GRID.soil.cT_domain)) .* ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral ) .* GRID.general.K_delta(GRID.soil.cT_domain) ); -% TEMPORARY.dEsensSnow = TEMPORARY.dEsensSnow + ... -% nansum( (T(GRID.snow.cT_domain)-T_old(GRID.snow.cT_domain)) .* ( PARA.constants.c_w .* GRID.snow.Snow_w(GRID.snow.cT_domain) + PARA.constants.c_i .* GRID.snow.Snow_i(GRID.snow.cT_domain) ) ); -% TEMPORARY.dElatentSoil = TEMPORARY.dElatentSoil + ... -% nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* ( lwc - lwc_old ) .* GRID.general.K_delta(GRID.soil.cT_domain) ); -% TEMPORARY.dElatentSnow = TEMPORARY.dElatentSnow + ... -% nansum( PARA.constants.rho_w .* PARA.constants.L_sl .* ( GRID.snow.Snow_w - Snow_w_old ) ); -% -% EtotSoil = nansum( ( ( PARA.constants.c_w .* lwc + PARA.constants.c_i .* (wc-lwc) + PARA.constants.c_m .* GRID.soil.cT_mineral ) .* T(GRID.soil.cT_domain) + ... -% + PARA.constants.rho_w .* PARA.constants.L_sl .* lwc ) ... -% .* GRID.general.K_delta(GRID.soil.cT_domain) ); -% TEMPORARY.dEtotSoil = TEMPORARY.dEtotSoil + EtotSoil - EtotSoil_old; -% - %---------- sum up + OUTPUT ------------------------------------------- - sum_up_output_store; - %------- next time step ----------------------------------------------- - t=t+timestep; - %---------- sum up + OUTPUT ------------------------------------------- - sum_up_output_store; + % save final state and output at t=endtime + iSaveOUT(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) + iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + end -%profile off -save([run_number '/' run_number '_output.mat'], 'OUT') + +if number_of_realizations>1 + delete(gcp('nocreate')) +end + disp('Done.'); \ No newline at end of file diff --git a/add_modules.m b/add_modules.m index daa7705..8e6b4cf 100644 --- a/add_modules.m +++ b/add_modules.m @@ -15,7 +15,10 @@ addpath('modules/cryoGridSEB/') addpath('modules/cryoGridSoil/') addpath('modules/cryoGridSnow/') -addpath('modules/CryoGridInfiltrationUnfrozenSoil') +addpath('modules/CryoGridInfiltrationUnfrozenSoil/') +%tsvd new modules added addpath('modules/cryoGridExcessIce/') addpath('modules/cryoGridExcessIceInfiltration') addpath('modules/cryoGridLateral') +%tsvd +addpath('modules/cryoGridLake/') \ No newline at end of file From fe3a56297c90fe4c6aa49550be56430a5c8b1cf6 Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Mon, 12 Feb 2018 15:34:44 +0100 Subject: [PATCH 21/45] cryoGridLake folder added --- modules/cryoGridLake/FlakeConstants.m | 89 ++ modules/cryoGridLake/FlakeParameters.m | 82 ++ modules/cryoGridLake/SolarAzEl.m | 137 ++ modules/cryoGridLake/cryoGridFLAKE.m | 144 +++ modules/cryoGridLake/cryoGridIceCover.m | 95 ++ modules/cryoGridLake/flake_driver.m | 1104 +++++++++++++++++ modules/cryoGridLake/flake_radflux.m | 65 + modules/cryoGridLake/flake_roughnessLength.m | 174 +++ modules/cryoGridLake/heatConductionIceCover.m | 28 + .../cryoGridLake/heatConductionIceCover.m~ | 28 + modules/cryoGridLake/heatConductionLateral.m | 16 + modules/cryoGridLake/heatConductionLateral.m~ | 16 + modules/cryoGridLake/initializeLAKE.m | 29 + modules/cryoGridLake/updateGRID_flake.m | 16 + modules/cryoGridLake/waterAlbedo.m | 33 + modules/cryoGridLake/waterDensity.m | 10 + 16 files changed, 2066 insertions(+) create mode 100644 modules/cryoGridLake/FlakeConstants.m create mode 100644 modules/cryoGridLake/FlakeParameters.m create mode 100644 modules/cryoGridLake/SolarAzEl.m create mode 100644 modules/cryoGridLake/cryoGridFLAKE.m create mode 100644 modules/cryoGridLake/cryoGridIceCover.m create mode 100644 modules/cryoGridLake/flake_driver.m create mode 100644 modules/cryoGridLake/flake_radflux.m create mode 100644 modules/cryoGridLake/flake_roughnessLength.m create mode 100644 modules/cryoGridLake/heatConductionIceCover.m create mode 100644 modules/cryoGridLake/heatConductionIceCover.m~ create mode 100644 modules/cryoGridLake/heatConductionLateral.m create mode 100644 modules/cryoGridLake/heatConductionLateral.m~ create mode 100644 modules/cryoGridLake/initializeLAKE.m create mode 100644 modules/cryoGridLake/updateGRID_flake.m create mode 100644 modules/cryoGridLake/waterAlbedo.m create mode 100644 modules/cryoGridLake/waterDensity.m diff --git a/modules/cryoGridLake/FlakeConstants.m b/modules/cryoGridLake/FlakeConstants.m new file mode 100644 index 0000000..3222cdd --- /dev/null +++ b/modules/cryoGridLake/FlakeConstants.m @@ -0,0 +1,89 @@ +function varargout = FlakeConstants + + c_Karman = 0.40 ; % The von Karman constant + Pr_neutral = 1.0 ; % Turbulent Prandtl number at neutral static stability + Sc_neutral = 1.0 ; % Turbulent Schmidt number at neutral static stability + c_MO_u_stab = 5.0 ; % Constant of the MO theory (wind, stable stratification) + c_MO_t_stab = 5.0 ; % Constant of the MO theory (temperature, stable stratification) + c_MO_q_stab = 5.0 ; % Constant of the MO theory (humidity, stable stratification) + c_MO_u_conv = 15.0 ; % Constant of the MO theory (wind, convection) + c_MO_t_conv = 15.0 ; % Constant of the MO theory (temperature, convection) + c_MO_q_conv = 15.0 ; % Constant of the MO theory (humidity, convection) + c_MO_u_exp = 0.25 ; % Constant of the MO theory (wind, exponent) + c_MO_t_exp = 0.5 ; % Constant of the MO theory (temperature, exponent) + c_MO_q_exp = 0.5 ; % Constant of the MO theory (humidity, exponent) + z0u_ice_rough = 1.0E-03 ; % Aerodynamic roughness of the ice surface [m] (rough flow) + c_z0u_smooth = 0.1 ; % Constant in the expression for z0u (smooth flow) + c_z0u_rough = 1.23E-02 ; % The Charnock constant in the expression for z0u (rough flow) + c_z0u_rough_l = 1.00E-01 ; % An increased Charnock constant (used as the upper limit) + c_z0u_ftch_f = 0.70 ; % Factor in the expression for fetch-dependent Charnock parameter + c_z0u_ftch_ex = 0.3333333 ; % Exponent in the expression for fetch-dependent Charnock parameter + c_z0t_rough_1 = 4.0 ; % Constant in the expression for z0t (factor) + c_z0t_rough_2 = 3.2 ; % Constant in the expression for z0t (factor) + c_z0t_rough_3 = 0.5 ; % Constant in the expression for z0t (exponent) + c_z0q_rough_1 = 4.0 ; % Constant in the expression for z0q (factor) + c_z0q_rough_2 = 4.2 ; % Constant in the expression for z0q (factor) + c_z0q_rough_3 = 0.5 ; % Constant in the expression for z0q (exponent) + c_z0t_ice_b0s = 1.250 ; % Constant in the expression for z0t over ice + c_z0t_ice_b0t = 0.149 ; % Constant in the expression for z0t over ice + c_z0t_ice_b1t = -0.550 ; % Constant in the expression for z0t over ice + c_z0t_ice_b0r = 0.317 ; % Constant in the expression for z0t over ice + c_z0t_ice_b1r = -0.565 ; % Constant in the expression for z0t over ice + c_z0t_ice_b2r = -0.183 ; % Constant in the expression for z0t over ice + c_z0q_ice_b0s = 1.610 ; % Constant in the expression for z0q over ice + c_z0q_ice_b0t = 0.351 ; % Constant in the expression for z0q over ice + c_z0q_ice_b1t = -0.628 ; % Constant in the expression for z0q over ice + c_z0q_ice_b0r = 0.396 ; % Constant in the expression for z0q over ice + c_z0q_ice_b1r = -0.512 ; % Constant in the expression for z0q over ice + c_z0q_ice_b2r = -0.180 ; % Constant in the expression for z0q over ice + re_z0s_ice_t = 2.5 ; % Threshold value of the surface Reynolds number + % used to compute z0t and z0q over ice (Andreas 2002) + re_z0u_thresh = 0.1; % Threshold value of the roughness Reynolds number + % [value from Zilitinkevich, Grachev, and Fairall (200), + % currently not used] + +% Dimensionless constants + c_free_conv = 0.14; % Constant in the expressions for fluxes in free convection + +% Dimensionless constants + c_lwrad_emis = 0.99; % Surface emissivity with respect to the long-wave radiation + +% Thermodynamic parameters + tpsf_C_stefboltz = 5.67E-08 ; % The Stefan-Boltzmann constant [W m^{-2} K^{-4}] + tpsf_R_dryair = 2.8705E+02 ; % Gas constant for dry air [J kg^{-1} K^{-1}] + tpsf_R_watvap = 4.6151E+02 ; % Gas constant for water vapour [J kg^{-1} K^{-1}] + tpsf_c_a_p = 1.005E+03 ; % Specific heat of air at constant pressure [J kg^{-1} K^{-1}] + tpsf_L_evap = 2.501E+06 ; % Specific heat of evaporation [J kg^{-1}] + tpsf_nu_u_a = 1.50E-05 ; % Kinematic molecular viscosity of air [m^{2} s^{-1}] + tpsf_kappa_t_a = 2.20E-05 ; % Molecular temperature conductivity of air [m^{2} s^{-1}] + tpsf_kappa_q_a = 2.40E-05 ; % Molecular diffusivity of air for water vapour [m^{2} s^{-1}] + +% Derived thermodynamic parameters + tpsf_Rd_o_Rv = tpsf_R_dryair/tpsf_R_watvap ; % Ratio of gas constants (Rd/Rv) + tpsf_alpha_q = (1.-tpsf_Rd_o_Rv)/tpsf_Rd_o_Rv ; % Diemsnionless ratio + +% Thermodynamic parameters + P_a_ref = 1.0E+05 ; % Reference pressure [N m^{-2} = kg m^{-1} s^{-2}] + + +% Security constants + u_wind_min_sf = 1.0E-02 ; % Minimum wind speed [m s^{-1}] + u_star_min_sf = 1.0E-04 ; % Minimum value of friction velocity [m s^{-1}] + c_accur_sf = 1.0E-07 ; % A small number (accuracy) + c_small_sf = 1.0E-04 ; % A small number (used to compute fluxes) + +% Useful constants + num_1o3_sf = 1./3.; % 1/3 + + + % OUTPUT of all variables + fieldNames=who; + nFields = length(fieldNames); + + for iField = 1:nFields + assignin('caller',fieldNames{iField},eval([fieldNames{iField}])); + end + + + + diff --git a/modules/cryoGridLake/FlakeParameters.m b/modules/cryoGridLake/FlakeParameters.m new file mode 100644 index 0000000..d1caa81 --- /dev/null +++ b/modules/cryoGridLake/FlakeParameters.m @@ -0,0 +1,82 @@ +function varargout = FlakeParameters + +% Dimensionless constants +% in the equations for the mixed-layer depth +% and for the shape factor with respect to the temperature profile in the thermocline + c_cbl_1 = 0.17 ; % Constant in the CBL entrainment equation + c_cbl_2 = 1. ; % Constant in the CBL entrainment equation + c_sbl_zm_n = 0.5 ; % Constant in the ZM1996 equation for the equilibrium SBL depth + c_sbl_zm_s = 10. ; % Constant in the ZM1996 equation for the equilibrium SBL depth + c_sbl_zm_i = 20. ; % Constant in the ZM1996 equation for the equilibrium SBL depth + c_relax_h = 0.030 ; % Constant in the relaxation equation for the SBL depth + c_relax_c = 0.0030 ; % Constant in the relaxation equation for the shape factor + % with respect to the temperature profile in the thermocline + +% Parameters of the shape functions +% Indices refer to T - thermocline, S - snow, I - ice, +% B1 - upper layer of the bottom sediments, B2 - lower layer of the bottom sediments. +% "pr0" and "pr1" denote zeta derivatives of the corresponding shape function +% at "zeta=0" ad "zeta=1", respectively. + c_t_min = 0.5 ; % Minimum value of the shape factor C_T (thermocline) + c_t_max = 0.8 ; % Maximum value of the shape factor C_T (thermocline) + phi_t_pr0_1 = 40./3. ; % Constant in the expression for the T shape-function derivative + phi_t_pr0_2 = 20./3. ; % Constant in the expression for the T shape-function derivative + c_tt_1 = 11./18. ; % Constant in the expression for C_TT (thermocline) + c_tt_2 = 7./45. ; % Constant in the expression for C_TT (thermocline) + c_b1 = 2./3. ; % Shape factor (upper layer of bottom sediments) + c_b2 = 3./5. ; % Shape factor (lower layer of bottom sediments) + phi_b1_pr0 = 2. ; % B1 shape-function derivative + c_s_lin = 0.5 ; % Shape factor (linear temperature profile in the snow layer) + phi_s_pr0_lin = 1. ; % S shape-function derivative (linear profile) + c_i_lin = 0.5 ; % Shape factor (linear temperature profile in the ice layer) + phi_i_pr0_lin = 1. ; % I shape-function derivative (linear profile) + phi_i_pr1_lin = 1. ; % I shape-function derivative (linear profile) + phi_i_ast_mr = 2. ; % Constant in the MR2004 expression for I shape factor + c_i_mr = 1./12. ; % Constant in the MR2004 expression for I shape factor + h_ice_max = 3. ; % Maximum ice tickness in + % the Mironov and Ritter (2004, MR2004) ice model [m] + +% Security constants + h_snow_min_flk = 1.0E-5 ; % Minimum snow thickness [m] + h_ice_min_flk = 1.0E-3 ; % Minimum ice thickness [m] + h_ml_min_flk = 1.0E-2 ; % Minimum mixed-layer depth [m] + h_ml_max_flk = 1.0E+3 ; % Maximum mixed-layer depth [m] + h_b1_min_flk = 1.0E-3 ; % Minimum thickness of the upper layer of bottom sediments [m] + u_star_min_flk = 1.0E-6 ; % Minimum value of the surface friction velocity [m s^{-1}] + +% Security constant(s) + c_small_flk = 1.0E-10; % A small number + +% Thermodynamic parameters + tpl_grav = 9.81 ; % Acceleration due to gravity [m s^{-2}] + tpl_t_r = 277.13 ; % Temperature of maximum density of fresh water [K] + tpl_t_f = 273.15 ; % Fresh water freezing point [K] + tpl_a_T = 1.6509E-05 ; % Constant in the fresh-water equation of state [K^{-2}] + tpl_rho_w_r = 1.0E+03 ; % Maximum density of fresh water [kg m^{-3}] + tpl_rho_i = 9.1E+02 ; % Density of ice [kg m^{-3}] + tpl_rho_s_min = 1.0E+02 ; % Minimum snow density [kg m^{-3}] + tpl_rho_s_max = 4.0E+02 ; % Maximum snow density [kg m^{-3}] + tpl_gamma_rho_s = 2.0E+02 ; % Empirical parameter [kg m^{-4}] + % in the expression for the snow density + tpl_l_f = 3.3E+05 ; % Latent heat of fusion [J kg^{-1}] + tpl_c_w = 4.2E+03 ; % Specific heat of water [J kg^{-1} K^{-1}] + tpl_c_i = 2.1E+03 ; % Specific heat of ice [J kg^{-1} K^{-1}] + tpl_c_s = 2.1E+03 ; % Specific heat of snow [J kg^{-1} K^{-1}] + tpl_kappa_w = 5.46E-01 ; % Molecular heat conductivity of water [J m^{-1} s^{-1} K^{-1}] + tpl_kappa_i = 2.29 ; % Molecular heat conductivity of ice [J m^{-1} s^{-1} K^{-1}] + tpl_kappa_s_min = 0.2 ; % Minimum molecular heat conductivity of snow [J m^{-1} s^{-1} K^{-1}] + tpl_kappa_s_max = 1.5 ; % Maximum molecular heat conductivity of snow [J m^{-1} s^{-1} K^{-1}] + tpl_gamma_kappa_s = 1.3; % Empirical parameter [J m^{-2} s^{-1} K^{-1}] + % in the expression for the snow heat conductivity + +%============================================================================== + + % OUTPUT of all variables + fieldNames=who; + nFields = length(fieldNames); + + for iField = 1:nFields + assignin('caller',fieldNames{iField},eval([fieldNames{iField}])); + end + + diff --git a/modules/cryoGridLake/SolarAzEl.m b/modules/cryoGridLake/SolarAzEl.m new file mode 100644 index 0000000..7917f41 --- /dev/null +++ b/modules/cryoGridLake/SolarAzEl.m @@ -0,0 +1,137 @@ +function [Az El] = SolarAzEl(UTC,Lat,Lon,Alt) %#codegen +%% Revision History: +% Programed by Darin C. Koblick 2/17/2009 +% +% Darin C. Koblick 4/16/2013 Vectorized for Speed +% Allow for MATLAB Datevec input in +% addition to a UTC string. +% Cleaned up comments and code to +% avoid warnings in MATLAB editor. +% +%-------------------------------------------------------------------------- +% External Function Call Sequence: +%[Az El] = SolarAzEl('1991/05/19 13:00:00',50,10,0) +%% Function Description: +% SolarAzEl will ingest a Universal Time, and specific site location on earth +% it will then output the solar Azimuth and Elevation angles relative to that +% site. +% +%% Input Description: +% UTC/DateVec: [N x 1] (Coordinated Universal Time +% yyyy/mm/dd HH:MM:SS) or MATLAB +% Date vector if input is a double +% instead of a cell +% +% Lat: [N x 1] (Site Latitude in degrees +% -90:90 -> S(-) N(+)) +% +% Lon: [N x 1] (Site Longitude in degrees +% -180:180 W(-) E(+)) +% +% Alt: [N x 1] Altitude of the site above sea +% level (km) +% +%% Output Description: +%Az [N x 1] Azimuth location of the sun (deg) +%El [N x 1] Elevation location of the sun (deg) +% +% +%% Source References: +%Solar Position obtained from: +%http://stjarnhimlen.se/comp/tutorial.html#5 +%% Begin Code Sequence + +%compute JD from UTC or datevec + +jd = juliandate(UTC); + +d = jd-2451543.5; + +% Keplerian Elements for the Sun (geocentric) +w = 282.9404+4.70935e-5*d; % (longitude of perihelion degrees) +%a = 1.000000;% (mean distance, a.u.) +e = 0.016709-1.151e-9.*d;% (eccentricity) +M = mod(356.0470+0.9856002585.*d,360);% (mean anomaly degrees) +L = w + M; %(Sun's mean longitude degrees) +oblecl = 23.4393-3.563e-7.*d; %(Sun's obliquity of the ecliptic) + +%auxiliary angle +E = M+(180/pi).*e.*sin(M.*(pi/180)).*(1+e.*cos(M.*(pi/180))); + +%rectangular coordinates in the plane of the ecliptic (x axis toward +%perhilion) +x = cos(E.*(pi/180))-e; +y = sin(E.*(pi/180)).*sqrt(1-e.^2); + +%find the distance and true anomaly +r = sqrt(x.^2 + y.^2); +v = atan2(y,x).*(180/pi); + +%find the longitude of the sun +lon = v + w; + +%compute the ecliptic rectangular coordinates +xeclip = r.*cos(lon.*(pi/180)); +yeclip = r.*sin(lon.*(pi/180)); +zeclip = 0.0; + +%rotate these coordinates to equitorial rectangular coordinates +xequat = xeclip; +yequat = yeclip.*cos(oblecl.*(pi/180))+zeclip*sin(oblecl.*(pi/180)); +zequat = yeclip.*sin(23.4406.*(pi/180))+zeclip*cos(oblecl.*(pi/180)); + +%convert equatorial rectangular coordinates to RA and Decl: +r = sqrt(xequat.^2 + yequat.^2 + zequat.^2)-(Alt./149598000); %roll up the altitude correction +RA = atan2(yequat,xequat).*(180/pi); +delta = asin(zequat./r).*(180/pi); + +%Following the RA DEC to Az Alt conversion sequence explained here: +%http://www.stargazing.net/kepler/altaz.html + +%Find the J2000 value +%J2000 = jd - 2451545.0; +% hourvec = datevec(UTC); +% UTH = hourvec(:,4) + hourvec(:,5)/60 + hourvec(:,6)/3600; +%also works +UTH = (UTC-floor(UTC))*24; + + +%Calculate local siderial time +GMST0=mod(L+180,360)./15; +SIDTIME = GMST0 + UTH + Lon./15; + +%Replace RA with hour angle HA +HA = (SIDTIME.*15 - RA); + +%convert to rectangular coordinate system +x = cos(HA.*(pi/180)).*cos(delta.*(pi/180)); +y = sin(HA.*(pi/180)).*cos(delta.*(pi/180)); +z = sin(delta.*(pi/180)); + +%rotate this along an axis going east-west. +xhor = x.*cos((90-Lat).*(pi/180))-z.*sin((90-Lat).*(pi/180)); +yhor = y; +zhor = x.*sin((90-Lat).*(pi/180))+z.*cos((90-Lat).*(pi/180)); + +%Find the h and AZ +Az = atan2(yhor,xhor).*(180/pi) + 180; +El = asin(zhor).*(180/pi); +end + +function jd = juliandate(UTC) %#codegen +%should work as well +jd = 1.7210275e+06+31 + UTC ; + +% % This sub function is provided in case juliandate does not come with your +% % distribution of Matlab +% [year month day hour min sec] = datevec(UTC); +% +% idx = (month <= 2); +% year(idx) = year(idx)-1; +% month(idx) = month(idx)+12; +% jd = floor( 365.25*(year + 4716.0)) + floor( 30.6001*( month + 1.0)) + 2.0 - ... +% floor( year/100.0 ) + floor( floor( year/100.0 )/4.0 ) + day - 1524.5 + ... +% (hour + min/60 + sec/3600)/24; +end + + diff --git a/modules/cryoGridLake/cryoGridFLAKE.m b/modules/cryoGridLake/cryoGridFLAKE.m new file mode 100644 index 0000000..fa7b5a1 --- /dev/null +++ b/modules/cryoGridLake/cryoGridFLAKE.m @@ -0,0 +1,144 @@ +function [T, GRID, FLAKE]=cryoGridFLAKE(FLAKE,GRID,SEB,PARA,T,T_old,timestep,k_eff,dE_dt,dE_dt_SEB) + +%update average temperature of the water domain +FLAKE.t_mnw_n_flk = sum(T_old(GRID.lake.water.cT_domain).*GRID.general.K_delta(GRID.lake.water.cT_domain)) ... + ./ sum(GRID.general.K_delta(GRID.lake.water.cT_domain)) + 273.15; + +%update water depth +FLAKE.depth_w = GRID.general.K_grid(GRID.lake.water.cT_domain_lb + 1) - GRID.general.K_grid(GRID.lake.water.cT_domain_ub); + +%update mean temperature according to changes in average temperature with +%water depth. This prevents changes in the bottom temperature due to sudden +%changes in water depth +if GRID.lake.ice.z_ice>0 + FLAKE.t_mnw_p_flk = FLAKE.t_mnw_n_flk; + FLAKE.t_mnw_n_flk = FLAKE.t_wml_n_flk - FLAKE.c_t_n_flk.*(FLAKE.t_wml_n_flk-FLAKE.t_bot_n_flk).*(1.-FLAKE.h_ml_n_flk./FLAKE.depth_w); + GRID.lake.ice.z_ice = GRID.lake.ice.z_ice - (FLAKE.t_mnw_p_flk-FLAKE.t_mnw_n_flk).*4.2e6.*FLAKE.depth_w./(334e3 * 910); +end + +%update ice cover status and thickness +if FLAKE.h_ice_n_flk<1e-3 && GRID.lake.ice.z_ice>=1e-3 + FLAKE.l_ice_create = true; +else + FLAKE.l_ice_create = false; +end +FLAKE.h_ice_n_flk = GRID.lake.ice.z_ice; + +%set boundary conditions +FLAKE.q_snow_flk= 0.; +FLAKE.q_ice_flk = 0.; +FLAKE.q_bot_flk = -(T_old(GRID.lake.water.cT_domain_lb+1)-T_old(GRID.lake.water.cT_domain_lb))... + ./ GRID.general.cT_delta(GRID.lake.water.cT_domain_lb) .* k_eff(GRID.lake.water.cT_domain_lb+1); + +FLAKE.q_w_flk = sum(dE_dt_SEB(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb+1)) ... + - SEB.Sin_water ... + + sum(dE_dt(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb)) ... + - sum(dE_dt_SEB(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb)) ... + + FLAKE.q_bot_flk ... + + GRID.lake.ice.dz_dt_freeze*334e3*910 ... + + GRID.lake.ice.dE_dt_melt_residual; + +if FLAKE.q_w_flk>0 && GRID.lake.ice.z_ice>0 + %correct for positive water heat fluxes under ice cover. This is + %necessary due to the very simple ice cover scheme which needs to + %be improved in fututre model versions. + GRID.lake.ice.z_ice = GRID.lake.ice.z_ice - FLAKE.q_w_flk.*(timestep *24*3600)/(334e3 * 910); + FLAKE.q_w_flk = 0; + FLAKE.h_ice_n_flk = GRID.lake.ice.z_ice; +end + +%transform u_star in atmosphere to u_star in water assuming constant +%desities for air and water. +FLAKE.u_star_w_flk=(SEB.u_star.^2.*(1.293./1e3)).^0.5; + +%calculate FLAKE radiative heat transfer +[FLAKE.i_atm_flk,... + FLAKE.i_w_flk,... + FLAKE.i_ice_flk,... + FLAKE.i_snow_flk,... + FLAKE.i_h_flk,... + FLAKE.i_bot_flk,... + FLAKE.i_intm_0_h_flk,... + FLAKE.i_intm_h_d_flk] = flake_radflux(SEB.Sin_water,FLAKE,PARA); + +% %call FLAKE main function +% if PARA.technical.MEX +% FLAKE = flake_driver_mex(FLAKE, timestep.*24.*3600); +% else + FLAKE = flake_driver(FLAKE, timestep.*24.*3600); +% end + +%map water temperature from shape function on the regular grid +%calculate dimensionless water depth of thermocline +% zeta_cT = (GRID.lake.water.cT_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) - FLAKE.h_ml_n_flk) ... +% ./ ((FLAKE.depth_w - FLAKE.h_ml_n_flk)); + +zeta_K = (GRID.lake.water.K_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) - FLAKE.h_ml_n_flk) ... + ./ ((FLAKE.depth_w - FLAKE.h_ml_n_flk)); +zeta_K = [zeta_K; 1]; +zeta_delta = diff(zeta_K); + +if ~isempty(zeta_delta) + %The original FLAKE shape function not used due to interpolation + %errors on discrete grid + %phi_theta = (40/3*FLAKE.c_t_n_flk-20/3)*zeta_cT ... + % + (18-30*FLAKE.c_t_n_flk)*zeta_cT.^2 ... + % + (20*FLAKE.c_t_n_flk-12)*zeta_cT.^3 ... + % + (5/3 - 10/3*FLAKE.c_t_n_flk)*zeta_cT.^4; + + %Integrated shape function to calculate averages on discrete grid + int_phi_theta = (40/3*FLAKE.c_t_n_flk-20/3)*1/2*zeta_K.^2 ... + + (18-30*FLAKE.c_t_n_flk)*1/3*zeta_K.^3 ... + + (20*FLAKE.c_t_n_flk-12)*1/4*zeta_K.^4 ... + + (5/3 - 10/3*FLAKE.c_t_n_flk)*1/5*zeta_K.^5; + + %calculate partial intergral for grid cells + int_phi_theta = int_phi_theta(2:end) - int_phi_theta(1:end-1); + phi_theta = int_phi_theta./zeta_delta; + + %change from dimensionless temperature to absolute temperature + Tw_z = -(phi_theta*(FLAKE.t_wml_n_flk-FLAKE.t_bot_n_flk) - FLAKE.t_wml_n_flk)-273.15; +else + Tw_z = []; +end +%map temperature on water grid +Tw = T(GRID.lake.water.cT_domain); + +%note that a step is introduced which introduces small discretization +%errors which need to be corrected later +Tw(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) = Tw_z; +Tw(GRID.lake.water.K_grid0 + GRID.lake.ice.z_ice = GRID.lake.ice.z_ice + dE./(334e3 * 910); + %set T water surf to zero + %dE=(0-T(GRID.lake.water.cT_domain_ub))*GRID.general.K_delta(GRID.lake.water.cT_domain_ub)*4.2e6; + %GRID.lake.ice.z_ice = GRID.lake.ice.z_ice + dE./(334e3 * 910); + %T(GRID.lake.water.cT_domain_ub) = 0; +else + ub_h_ml=min([GRID.lake.water.K_grid(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk); FLAKE.depth_w]); + lb_h_ml=FLAKE.depth_w; + if (lb_h_ml-ub_h_ml)>0 + Tw(GRID.lake.water.K_grid>=FLAKE.h_ml_n_flk) = Tw_z - dE/(4.2e6* (lb_h_ml-ub_h_ml)); + else + Tw = Tw - dE/(4.2e6 * FLAKE.depth_w); + end + T(GRID.lake.water.cT_domain) = Tw; +end + +%update FLAKE average temperature of the water domain +FLAKE.t_mnw_n_flk = sum(T(GRID.lake.water.cT_domain).*GRID.general.K_delta(GRID.lake.water.cT_domain)) ... + ./ sum(GRID.general.K_delta(GRID.lake.water.cT_domain)) + 273.15; + + + diff --git a/modules/cryoGridLake/cryoGridIceCover.m b/modules/cryoGridLake/cryoGridIceCover.m new file mode 100644 index 0000000..3b9a575 --- /dev/null +++ b/modules/cryoGridLake/cryoGridIceCover.m @@ -0,0 +1,95 @@ +function [T,GRID,FLAKE]=cryoGridIceCover(GRID,SEB,FLAKE,T,c_temp,timestep) + +%construct water grids relative to the water surface +if ~isempty(GRID.lake.water.cT_domain_ub) + GRID.lake.water.cT_grid = GRID.general.cT_grid(GRID.lake.water.cT_domain) - GRID.general.K_grid(GRID.lake.water.cT_domain_ub); + GRID.lake.water.K_grid = GRID.general.K_grid(GRID.lake.water.K_domain) - GRID.general.K_grid(GRID.lake.water.cT_domain_ub); +else + GRID.lake.water.cT_grid = []; + GRID.lake.water.K_grid = []; +end + +%initialisize +GRID.lake.ice.dz_dt_freeze=0; +GRID.lake.ice.dz_dt_melt=0; +GRID.lake.ice.dE_dt_melt_residual=0; + +%ice cover build up before +if min(T(GRID.lake.water.cT_domain))<0 + + %distribute heat into the mixed water layer in order to avoid unrealistic freezing of the first water cell + if FLAKE.h_ml_n_flk>0 + Tw=T(GRID.lake.water.cT_domain); + K_delta=GRID.general.K_delta(GRID.lake.water.cT_domain); + + Tw(GRID.lake.water.K_grid0 + dE_dt_ice = (0-T(GRID.lake.ice.cT_domain)) ... + .* c_temp(GRID.lake.ice.cT_domain) ... + .* GRID.general.K_delta(GRID.lake.ice.cT_domain) ... + ./ (timestep.*24.*3600); + + dE_dt_ice = dE_dt_ice .* (T(GRID.lake.ice.cT_domain)>0); + dE_dt_ice = sum(dE_dt_ice); + + %set temperature T to 0°C for cells with melting ice + T((GRID.lake.ice.cT_domain) & T>0) = 0; + GRID.lake.ice.dz_dt_melt = dE_dt_ice./ (334e3 * 910); + GRID.lake.ice.dz_dt_melt(isinf(GRID.lake.ice.dz_dt_melt) | isnan(GRID.lake.ice.dz_dt_melt)) = 0; + + %set melt flag true if the entire ice cover is affected by melting + if sum(T(GRID.lake.ice.cT_domain))==0; + GRID.lake.ice.melt_flag=true; + end +end + +%melt remaining ice cover +GRID.lake.ice.dE_dt_melt_residual = 0; +if isempty(GRID.lake.ice.cT_domain_ub) && GRID.lake.ice.z_ice>0 && T(GRID.lake.water.cT_domain_ub)>0 + GRID.lake.ice.dz_dt_melt = max(-GRID.lake.ice.z_ice/(timestep*24*3600), -SEB.Qg/(334e3 * 910)); + GRID.lake.ice.dE_dt_melt_residual = GRID.lake.ice.dz_dt_melt*(334e3 * 910); +end + +%calculate change of ice cover depth +GRID.lake.ice.dz_dt_ice = GRID.lake.ice.dz_dt_freeze + GRID.lake.ice.dz_dt_melt - GRID.lake.ice.dE_dt_cond_residual./(334e3 * 910); + +%change ice cover thickness +GRID.lake.ice.z_ice = GRID.lake.ice.z_ice + GRID.lake.ice.dz_dt_ice.*(timestep.*24.*3600); +GRID.lake.ice.z_ice = GRID.lake.ice.z_ice*(GRID.lake.ice.z_ice>0); + +%sort water cells under ice cover according to density +if ~isempty(GRID.lake.ice.cT_domain_ub) && ~isempty(GRID.lake.water.cT_domain_ub) + DW = waterDensity(T(GRID.lake.water.cT_domain)); + [~, XI]=sort(DW); + DW=T(GRID.lake.water.cT_domain); + T(GRID.lake.water.cT_domain)=DW(XI); +end + + + + + + diff --git a/modules/cryoGridLake/flake_driver.m b/modules/cryoGridLake/flake_driver.m new file mode 100644 index 0000000..fc027a8 --- /dev/null +++ b/modules/cryoGridLake/flake_driver.m @@ -0,0 +1,1104 @@ +%------------------------------------------------------------------------------ + +function [FLAKE]=flake_driver(FLAKE, del_time) %#codegen + +%------------------------------------------------------------------------------ +% +% Description: +% +% The main driving routine of the lake model FLake +% where computations are performed. +% Advances the surface temperature +% and other FLake variables one time step. +% At the moment, the Euler explicit scheme is used. +% +% Lines embraced with '!_tmp' contain temporary parts of the code. +% Lines embraced/marked with '!_dev' may be replaced +% as improved parameterizations are developed and tested. +% Lines embraced/marked with '!_dm' are DM's comments +% that may be helpful to a user. +% Lines embraced/marked with '!_dbg' are used +% for debugging purposes only. +% +% +% Current Code Owner: DWD, Dmitrii Mironov +% Phone: +49-69-8062 2705 +% Fax: +49-69-8062 3721 +% E-mail: dmitrii.mironov@dwd.de +%------------------------------------------------------------------------------ +% +% Dimensionless constants +% in the equations for the mixed-layer depth +% and for the shape factor with respect to the temperature profile in the thermocline + c_cbl_1 = 0.17 ; % Constant in the CBL entrainment equation + c_cbl_2 = 1. ; % Constant in the CBL entrainment equation + c_sbl_zm_n = 0.5 ; % Constant in the ZM1996 equation for the equilibrium SBL depth + c_sbl_zm_s = 10. ; % Constant in the ZM1996 equation for the equilibrium SBL depth + c_sbl_zm_i = 20. ; % Constant in the ZM1996 equation for the equilibrium SBL depth + c_relax_h = 0.030 ; % Constant in the relaxation equation for the SBL depth + c_relax_c = 0.0030 ; % Constant in the relaxation equation for the shape factor + % with respect to the temperature profile in the thermocline + +% Parameters of the shape functions +% Indices refer to T - thermocline, S - snow, I - ice, +% B1 - upper layer of the bottom sediments, B2 - lower layer of the bottom sediments. +% "pr0" and "pr1" denote zeta derivatives of the corresponding shape function +% at "zeta=0" ad "zeta=1", respectively. + c_t_min = 0.5 ; % Minimum value of the shape factor C_T (thermocline) + c_t_max = 0.8 ; % Maximum value of the shape factor C_T (thermocline) +% phi_t_pr0_1 = 40./3. ; % Constant in the expression for the T shape-function derivative +% phi_t_pr0_2 = 20./3. ; % Constant in the expression for the T shape-function derivative + c_tt_1 = 11./18. ; % Constant in the expression for C_TT (thermocline) + c_tt_2 = 7./45. ; % Constant in the expression for C_TT (thermocline) +% c_b1 = 2./3. ; % Shape factor (upper layer of bottom sediments) +% c_b2 = 3./5. ; % Shape factor (lower layer of bottom sediments) +% phi_b1_pr0 = 2. ; % B1 shape-function derivative +% c_s_lin = 0.5 ; % Shape factor (linear temperature profile in the snow layer) +% phi_s_pr0_lin = 1. ; % S shape-function derivative (linear profile) +% c_i_lin = 0.5 ; % Shape factor (linear temperature profile in the ice layer) +% phi_i_pr0_lin = 1. ; % I shape-function derivative (linear profile) +% phi_i_pr1_lin = 1. ; % I shape-function derivative (linear profile) +% phi_i_ast_mr = 2. ; % Constant in the MR2004 expression for I shape factor +% c_i_mr = 1./12. ; % Constant in the MR2004 expression for I shape factor +% h_ice_max = 3. ; % Maximum ice tickness in + % the Mironov and Ritter (2004, MR2004) ice model [m] + +% Security constants + h_snow_min_flk = 1.0E-5 ; % Minimum snow thickness [m] + h_ice_min_flk = 1.0E-3 ; % Minimum ice thickness [m] + h_ml_min_flk = 1.0E-2 ; % Minimum mixed-layer depth [m] + h_ml_max_flk = 1.0E+3 ; % Maximum mixed-layer depth [m] +% h_b1_min_flk = 1.0E-3 ; % Minimum thickness of the upper layer of bottom sediments [m] + u_star_min_flk = 1.0E-6 ; % Minimum value of the surface friction velocity [m s^{-1}] + +% Security constant(s) + c_small_flk = 1.0E-10 ; % A small number + +% Thermodynamic parameters + tpl_grav = 9.81 ; % Acceleration due to gravity [m s^{-2}] + tpl_t_r = 277.13 ; % Temperature of maximum density of fresh water [K] + tpl_t_f = 273.15 ; % Fresh water freezing point [K] + tpl_a_T = 1.6509E-05 ; % Constant in the fresh-water equation of state [K^{-2}] + tpl_rho_w_r = 1.0E+03 ; % Maximum density of fresh water [kg m^{-3}] +% tpl_rho_i = 9.1E+02 ; % Density of ice [kg m^{-3}] +% tpl_rho_s_min = 1.0E+02 ; % Minimum snow density [kg m^{-3}] +% tpl_rho_s_max = 4.0E+02 ; % Maximum snow density [kg m^{-3}] +% tpl_gamma_rho_s = 2.0E+02 ; % Empirical parameter [kg m^{-4}] + % in the expression for the snow density +% tpl_l_f = 3.34E+05 ; % Latent heat of fusion [J kg^{-1}] + tpl_c_w = 4.2E+03 ; % Specific heat of water [J kg^{-1} K^{-1}] +% tpl_c_i = 1.9E+03 ; % Specific heat of ice [J kg^{-1} K^{-1}] +% tpl_c_s = 2.1E+03 ; % Specific heat of snow [J kg^{-1} K^{-1}] +% tpl_kappa_w = 0.546 ; % Molecular heat conductivity of water [J m^{-1} s^{-1} K^{-1}] +% tpl_kappa_i = 2.29 ; % Molecular heat conductivity of ice [J m^{-1} s^{-1} K^{-1}] + + +%============================================================================== + +%============================================================================== +% +% Declarations + +% Input (procedure arguments) + +% The lake depth [m] +% real( ireals), intent(in) :: ; +% Depth of the thermally active layer of bottom sediments [m] +%depth_bs ,; +% Temperature at the outer edge of +%t_bs ,; +% the thermally active layer of bottom sediments [K] +% The Coriolis parameter [s^{-1}] +%par_coriolis; +% 'Typical' extinction coefficient of the lake water [m^{-1}], +%extincoef_water_typ ,; +% used to compute the equilibrium CBL depth +% The model time step [s] +%del_time ,; +% Surface temperature at the previous time step [K] +%t_sfc_p; +% (equal to either T_ice, T_snow or to T_wML) + +% Output (procedure arguments) + +% Updated surface temperature [K] +% (equal to the updated value of either T_ice, T_snow or T_wML) + +% Local variables of type LOGICAL +% Switch, true = ice does not exist but should be created +l_ice_create=false; +% Switch, true = there is snow above the ice +l_snow_exists=false; +% Switch, true = snow/ice melting from above takes place +l_ice_meltabove=[]; + +% Local variables of type INTEGER +% Loop index +i=0; +% Local variables of type REAL +% Time derivative of T_mnw [K s^{-1}] +d_t_mnw_dt=0; +% Time derivative of T_ice [K s^{-1}] +d_t_ice_dt=0; +% Time derivative of T_bot [K s^{-1}] +d_t_bot_d=0; +% Time derivative of T_B1 [K s^{-1}] +d_t_b1_dt=0; +% Time derivative of h_snow [m s^{-1}] +d_h_snow_dt=0; +% Time derivative of h_ice [m s^{-1}] +d_h_ice_dt=0; +% Time derivative of h_ML [m s^{-1}] +d_h_ml_dt=0; +% Time derivative of H_B1 [m s^{-1}] +d_h_b1_dt=0; +% Time derivative of C_T [s^{-1}] +d_c_t_dt=0; + +% Local variables of type REAL +% The mean buoyancy frequency in the thermocline [s^{-1}] +n_t_mean=0; + +% The ZM96 equilibrium SBL depth scale [m] +zm_h_scale=0; +% The equilibrium CBL depth scale [m] +conv_equil_h_scale=0; + +% Local variables of type REAL +% If h_ice=h_ice_min_flk) +% % Mixed-layer depth is zero, compute flux +% if(h_ml_p_flk<=h_ml_min_flk) +% % Flux with linear T(z) +% q_w_flk = -tpl_kappa_w.*(t_bot_p_flk-t_wml_p_flk)./depth_w; +% % d\Phi(0)/d\zeta (thermocline) +% phi_t_pr0_flk = phi_t_pr0_1.*c_t_p_flk-phi_t_pr0_2; +% % Account for an increased d\Phi(0)/d\zeta +% q_w_flk = q_w_flk.*max(phi_t_pr0_flk, 1.); +% %q_w_flk = FLAKE.q_w_flk;%!!! use external q_w_flk +% else +% % Mixed-layer depth is greater than zero, set flux to zero +% q_w_flk = 0.; +% end +% end; +% % disp([q_w_flk FLAKE.q_ice_flk]) + +% A generalized heat flux scale + q_star_flk = q_w_flk + i_w_flk + i_h_flk - 2..*i_intm_0_h_flk; + +% %Heat flux through the water-bottom sediment interface +% if(lflk_botsed_use) +% q_bot_flk = -tpl_kappa_w.*(t_b1_p_flk-t_bot_p_flk)./max(h_b1_p_flk, h_b1_min_flk).*phi_b1_pr0; +% else +% % The bottom-sediment scheme is not used +% q_bot_flk = 0.; +% end; +% +% couple to CryoGrid soil scheme +% set external t_b1_p_flk = temperature of first soil cell +% set external h_b1_p_flk = delta K grid of first soil cell +% tpl_kappa_w = heat conductivity is assumed to be water +% +%q_bot_flk = - k_b1_p_flk .* (t_b1_p_flk - t_bot_p_flk) ./ h_b1_p_flk; + +%q_bot_flk = 0; +q_bot_flk = FLAKE.q_bot_flk; + + +% %------------------------------------------------------------------------------ +% % Check if ice exists or should be created. +% % If so, compute the thickness and the temperature of ice and snow. +% %------------------------------------------------------------------------------ +% % +% %_dm +% % Notice that a quasi-equilibrium ice-snow model is used +% % to avoid numerical instability when the ice is thin. +% % This is always the case when new ice is created. +% %_dm +% +% %_dev +% % The dependence of snow density and of snow heat conductivity +% % on the snow thickness is accounted for parametrically. +% % That is, the time derivatives of \rho_S and \kappa_S are neglected. +% % The exception is the equation for the snow thickness +% % in case of snow accumulation and no melting, +% % where d\rho_S/dt is incorporated. +% % Furthermore, some (presumably small) correction terms incorporating +% % the snow density and the snow heat conductivity are dropped out. +% % Those terms may be included as better formulations +% % for \rho_S and \kappa_S are available. +% %_dev +% +% % Default values +% l_ice_create = false; +% l_ice_meltabove = false; +% +% +% % Ice does not exist +% if(h_ice_p_flk0) +% h_snow_n_flk = h_snow_p_flk + d_h_snow_dt.*del_time; +% % d\Phi_I(1)/d\zeta_I (ice) +% phi_i_pr1_flk = phi_i_pr1_lin+ phi_i_ast_mr.*min(1., h_ice_n_flk./h_ice_max); +% r_h_icesnow = phi_i_pr1_flk./phi_s_pr0_lin.*tpl_kappa_i./flake_snowheatconduct(h_snow_n_flk).* h_snow_n_flk./max(h_ice_n_flk, h_ice_min_flk); +% % Snow temperature +% t_snow_n_flk = t_ice_n_flk + r_h_icesnow.*(t_ice_n_flk-tpl_t_f); +% else +% h_snow_n_flk=0; +% r_h_icesnow=0; +% t_snow_n_flk=t_ice_n_flk; +% end +% +% end +% +% % Ice exists +% else +% +% % Check if there is snow above the ice +% l_snow_exists = h_snow_p_flk>=h_snow_min_flk; +% +% % T_sfc = T_f, check for melting from above +% if(t_snow_p_flk>=(tpl_t_f-c_small_flk)) +% % T_snow = T_ice if snow is absent +% % There is snow above the ice +% if(l_snow_exists) +% % Atmospheric forcing +% flk_str_1 = q_snow_flk + i_snow_flk - i_ice_flk; +% % Melting of snow and ice from above +% if(flk_str_1>=0.) +% l_ice_meltabove = true; +% d_h_snow_dt =(-flk_str_1./tpl_l_f+dmsnowdt_flk)./flake_snowdensity(h_snow_p_flk); +% d_h_ice_dt = -(i_ice_flk - i_w_flk - q_w_flk)./tpl_l_f./tpl_rho_i; +% end +% % No snow above the ice +% else +% % Atmospheric forcing + heating from the water +% flk_str_1 = q_ice_flk + i_ice_flk - i_w_flk - q_w_flk; +% % Melting of ice from above, snow accumulation may occur +% if(flk_str_1>=0.) +% l_ice_meltabove = true; +% d_h_ice_dt = -flk_str_1./tpl_l_f./tpl_rho_i; +% d_h_snow_dt = dmsnowdt_flk./tpl_rho_s_min; +% end +% end +% % Melting from above takes place +% if(l_ice_meltabove) +% % Advance h_ice +% h_ice_n_flk = h_ice_p_flk + d_h_ice_dt .*del_time; +% % Advance h_snow +% h_snow_n_flk = h_snow_p_flk + d_h_snow_dt.*del_time; +% % Set T_ice to the freezing point +% t_ice_n_flk = tpl_t_f; +% % Set T_snow to the freezing point +% t_snow_n_flk = tpl_t_f; +% end +% +% end +% +% % No melting from above +% if(~l_ice_meltabove) +% +% %d_h_snow_dt = flake_snowdensity(h_snow_p_flk); +% d_h_snow_dt = 0; %!!! avoid snow cover +% % Account for d\rho_S/dt +% if(d_h_snow_dt=h_ice_min_flk) + % Limit the mean temperature under the ice by T_r + t_mnw_n_flk = min(t_mnw_n_flk, tpl_t_r); + % The mixed-layer temperature is equal to the freezing point + t_wml_n_flk = tpl_t_f; + + % Ice has just been created + if(l_ice_create) + % h_ML=D when ice is created +% if (h_ml_p_flk>=depth_w-h_ml_min_flk) %!!! changed since a persistent isothermal layer is not observed + % Set h_ML to zero + h_ml_n_flk = 0.; + % Set C_T to its minimum value + c_t_n_flk = c_t_min; + % h_ML=0) %!!! i_w_flk-q_bot_flk>=0 (warming under ice) + % h_ML > 0 + if(h_ml_p_flk>=c_small_flk) + % C_T (thermocline) remains unchanged + c_t_n_flk = c_t_p_flk; + h_ml_n_flk = depth_w.*(1.-(t_wml_n_flk-t_mnw_n_flk)./(t_wml_n_flk-t_bot_n_flk)./c_t_n_flk); + % Update the mixed-layer depth + h_ml_n_flk = max(h_ml_n_flk, 0.); + % h_ML = 0 + else + % h_ML remains unchanged + h_ml_n_flk = h_ml_p_flk; + c_t_n_flk =(t_wml_n_flk-t_mnw_n_flk)./(t_wml_n_flk-t_bot_n_flk); + % Update the shape factor (thermocline) + c_t_n_flk = min(c_t_max, max(c_t_n_flk, c_t_min)); + end + + else %!!! i_w_flk-q_bot_flk<0 (cooling from the bottom) + + %h_ML remains unchanged + h_ml_n_flk = h_ml_p_flk; + % C_T (thermocline) remains unchanged + c_t_n_flk = c_t_p_flk; + t_bot_n_flk = t_wml_n_flk -(t_wml_n_flk-t_mnw_n_flk)./c_t_n_flk./(1.-h_ml_n_flk./depth_w); + % Update the bottom temperature + + end + + end + + % Security, limit the bottom temperature by T_r + t_bot_n_flk = min(t_bot_n_flk, tpl_t_r); + +% Open water +else + + % Generalised buoyancy flux scale and convective velocity scale + T_water=t_wml_p_flk; + flake_buoypar = tpl_grav*tpl_a_T*(T_water-tpl_t_r); + flk_str_1 = flake_buoypar*q_star_flk/tpl_rho_w_r/tpl_c_w; + if (flk_str_1<0.) + % Convection + w_star_sfc_flk =(-flk_str_1.*h_ml_p_flk).^(1../3.); + else + % Neutral or stable stratification + w_star_sfc_flk = 0.; + end + + %_dm + % The equilibrium depth of the CBL due to surface cooling with the volumetric heating + % is not computed as a solution to the transcendental equation. + % Instead, an algebraic formula is used + % that interpolates between the two asymptotic limits. + %_dm + conv_equil_h_scale = -q_w_flk/max(i_w_flk, c_small_flk); + % The equilibrium CBL depth scale is only used above T_r + if(conv_equil_h_scale>0. && conv_equil_h_scale<1.&& t_wml_p_flk>tpl_t_r) + conv_equil_h_scale = sqrt(6..*conv_equil_h_scale)+ 2..*conv_equil_h_scale./(1.-conv_equil_h_scale); + conv_equil_h_scale = min(depth_w, conv_equil_h_scale./extincoef_water_typ); + else + % Set the equilibrium CBL depth to zero + conv_equil_h_scale = 0.; + end; + + % Mean buoyancy frequency in the thermocline + T_water=0.5.*(t_wml_p_flk+t_bot_p_flk); + flake_buoypar = tpl_grav*tpl_a_T*(T_water-tpl_t_r); + n_t_mean = flake_buoypar.*(t_wml_p_flk-t_bot_p_flk); + if(h_ml_p_flk<=depth_w-h_ml_min_flk) && (n_t_mean>=0) %!!! && (n_t_mean>=0) added to avoid complex numbers + % Compute N + n_t_mean = sqrt(n_t_mean./(depth_w-h_ml_p_flk)); + else + % h_ML=D, set N to zero + n_t_mean = 0.; + end + + % The rate of change of C_T + d_c_t_dt = max([w_star_sfc_flk, u_star_min_flk]).^2; + % Relaxation time scale for C_T + d_c_t_dt = n_t_mean.*(depth_w-h_ml_p_flk).^2./ c_relax_c./d_c_t_dt; + % Rate-of-change of C_T + d_c_t_dt =(c_t_max-c_t_min)./max(d_c_t_dt, c_small_flk); + + % Compute the shape factor and the mixed-layer depth, + % using different formulations for convection and wind mixing + + % C_TT, using C_T at the previous time step + c_tt_flk = c_tt_1.*c_t_p_flk-c_tt_2; + % C_Q using C_T at the previous time step + c_q_flk = 2..*c_tt_flk./c_t_p_flk; + + + % Convective mixing + if(flk_str_1<0.) + + % Update C_T, assuming dh_ML/dt>0 + c_t_n_flk = c_t_p_flk + d_c_t_dt.*del_time; + % Limit C_T + c_t_n_flk = min(c_t_max, max(c_t_n_flk, c_t_min)); + % Re-compute dC_T/dt + d_c_t_dt =(c_t_n_flk-c_t_p_flk)./del_time; + + % Compute dh_ML/dt + if(h_ml_p_flk<=depth_w-h_ml_min_flk) + % Use a reduced entrainment equation (spin-up) + if(h_ml_p_flk<=h_ml_min_flk) + d_h_ml_dt = c_cbl_1./c_cbl_2.*max(w_star_sfc_flk, c_small_flk); + + %_dbg + % WRITE*, ' FLake: reduced entrainment eq. D_time*d_h_ML_dt = ', d_h_ML_dt*del_time + % WRITE*, ' w_* = ', w_star_sfc_flk + % WRITE*, ' \beta*Q_* = ', flk_str_1 + %_dbg + + % Use a complete entrainment equation + else + r_h_icesnow = depth_w./h_ml_p_flk; + r_rho_c_icesnow = r_h_icesnow-1.; + r_ti_icesnow = c_t_p_flk./c_tt_flk; + r_tstar_icesnow =(r_ti_icesnow./2.-1.).*r_rho_c_icesnow + 1.; + d_h_ml_dt = -q_star_flk.*(r_tstar_icesnow.*(1.+c_cbl_1)-1.) - q_bot_flk; + % Q_* and Q_b flux terms + d_h_ml_dt = d_h_ml_dt./tpl_rho_w_r./tpl_c_w; + flk_str_2 =(depth_w-h_ml_p_flk).*(t_wml_p_flk-t_bot_p_flk).*c_tt_2./c_tt_flk.*d_c_t_dt; + % Add dC_T/dt term + d_h_ml_dt = d_h_ml_dt + flk_str_2; + flk_str_2 = i_bot_flk +(r_ti_icesnow-1.).*i_h_flk - r_ti_icesnow.*i_intm_h_d_flk; + flk_str_2 = flk_str_2 +(r_ti_icesnow-2.).*r_rho_c_icesnow.*(i_h_flk-i_intm_0_h_flk); + flk_str_2 = flk_str_2./tpl_rho_w_r./tpl_c_w; + % Add radiation terms + d_h_ml_dt = d_h_ml_dt + flk_str_2; + flk_str_2 = -c_cbl_2.*r_tstar_icesnow.*q_star_flk./tpl_rho_w_r./tpl_c_w./max(w_star_sfc_flk, c_small_flk); + flk_str_2 = flk_str_2 + c_t_p_flk.*(t_wml_p_flk-t_bot_p_flk); + % dh_ML/dt = r.h.s. + d_h_ml_dt = d_h_ml_dt./flk_str_2; + end + %_dm + % Notice that dh_ML/dt may appear to be negative + % (e.g. due to buoyancy loss to bottom sediments and/or + % the effect of volumetric radiation heating), + % although a negative generalized buoyancy flux scale indicates + % that the equilibrium CBL depth has not yet been reached + % and convective deepening of the mixed layer should take place. + % Physically, this situation reflects an approximate character of the lake model. + % Using the self-similar temperature profile in the thermocline, + % there is always communication between the mixed layer, the thermocline + % and the lake bottom. As a result, the rate of change of the CBL depth + % is always dependent on the bottom heat flux and the radiation heating of the thermocline. + % In reality, convective mixed-layer deepening may be completely decoupled + % from the processes underneath. In order to account for this fact, + % the rate of CBL deepening is set to a small value + % if dh_ML/dt proves to be negative. + % This is 'double insurance' however, + % as a negative dh_ML/dt is encountered very rarely. + %_dm + + %_dbg + % IF(d_h_ML_dt.LT.0.) THEN + % WRITE*, 'FLake: negative d_h_ML_dt during convection, = ', d_h_ML_dt + % WRITE*, ' d_h_ML_dt*del_time = ', MAX(d_h_ML_dt, c_small_flk)*del_time + % WRITE*, ' u_* = ', u_star_w_flk + % WRITE*, ' w_* = ', w_star_sfc_flk + % WRITE*, ' h_CBL_eqi = ', conv_equil_h_scale + % WRITE*, ' ZM scale = ', ZM_h_scale + % WRITE*, ' h_ML_p_flk = ', h_ML_p_flk + % endif + % WRITE*, 'FLake: Convection, = ', d_h_ML_dt + % WRITE*, ' Q_* = ', Q_star_flk + % WRITE*, ' \beta*Q_* = ', flk_str_1 + %_dbg + + d_h_ml_dt = max(d_h_ml_dt, c_small_flk); + % Update h_ML + h_ml_n_flk = h_ml_p_flk + d_h_ml_dt.*del_time; + % Security, limit h_ML + h_ml_n_flk = max(h_ml_min_flk, min(h_ml_n_flk, depth_w)); + % Mixing down to the lake bottom + else + h_ml_n_flk = depth_w; + %disp('convec 2 bottom') + end + + % Wind mixing + else + %disp(' wind mixing') + % The surface friction velocity + d_h_ml_dt = max(u_star_w_flk, u_star_min_flk); + zm_h_scale =(abs(par_coriolis)./c_sbl_zm_n + n_t_mean./c_sbl_zm_i).*d_h_ml_dt.^2; + zm_h_scale = zm_h_scale + flk_str_1./c_sbl_zm_s; + zm_h_scale = max(zm_h_scale, c_small_flk); + zm_h_scale = d_h_ml_dt.^3./zm_h_scale; + % The ZM96 SBL depth scale + zm_h_scale = max(h_ml_min_flk, min(zm_h_scale, h_ml_max_flk)); + % Equilibrium mixed-layer depth + zm_h_scale = max(zm_h_scale, conv_equil_h_scale); + + %_dm + % In order to avoid numerical discretization problems, + % an analytical solution to the evolution equation + % for the wind-mixed layer depth is used. + % That is, an exponential relaxation formula is applied + % over the time interval equal to the model time step. + %_dm + + d_h_ml_dt = c_relax_h.*d_h_ml_dt./zm_h_scale.*del_time; + % Update h_ML + h_ml_n_flk = zm_h_scale -(zm_h_scale-h_ml_p_flk).*exp(-d_h_ml_dt); + % Limit h_ML + h_ml_n_flk = max(h_ml_min_flk, min(h_ml_n_flk, depth_w)); + % Re-compute dh_ML/dt + d_h_ml_dt =(h_ml_n_flk-h_ml_p_flk)./del_time; + % Mixed-layer retreat or stationary state, dC_T/dt<0 + if(h_ml_n_flk<=h_ml_p_flk) + d_c_t_dt = -d_c_t_dt; + end + % Update C_T + c_t_n_flk = c_t_p_flk + d_c_t_dt.*del_time; + % Limit C_T + c_t_n_flk = min(c_t_max, max(c_t_n_flk, c_t_min)); + % Re-compute dC_T/dt + d_c_t_dt =(c_t_n_flk-c_t_p_flk)./del_time; + + %_dbg + % WRITE*, 'FLake: wind mixing: d_h_ML_dt*del_time = ', d_h_ML_dt*del_time + % WRITE*, ' h_CBL_eqi = ', conv_equil_h_scale + % WRITE*, ' ZM scale = ', ZM_h_scale + % WRITE*, ' w_* = ', w_star_sfc_flk + % WRITE*, ' u_* = ', u_star_w_flk + % WRITE*, ' h_ML_p_flk = ', h_ML_p_flk + %_dbg + + end + + % Compute the time-rate-of-change of the the bottom temperature, + % depending on the sign of dh_ML/dt + % Update the bottom temperature and the mixed-layer temperature + + % Mixing did not reach the bottom + if(h_ml_n_flk<=depth_w-h_ml_min_flk) + + % Mixed-layer deepening + if(h_ml_n_flk>h_ml_p_flk) + r_h_icesnow = h_ml_p_flk./depth_w; + r_rho_c_icesnow = 1.-r_h_icesnow; + r_ti_icesnow = 0.5.*c_t_p_flk.*r_rho_c_icesnow+c_tt_flk.*(2..*r_h_icesnow-1.); + r_tstar_icesnow =(0.5+c_tt_flk-c_q_flk)./r_ti_icesnow; + r_ti_icesnow =(1.-c_t_p_flk.*r_rho_c_icesnow)./r_ti_icesnow; + + d_t_bot_dt =(q_w_flk-q_bot_flk+i_w_flk-i_bot_flk)./tpl_rho_w_r./tpl_c_w; + d_t_bot_dt = d_t_bot_dt - c_t_p_flk.*(t_wml_p_flk-t_bot_p_flk).*d_h_ml_dt; + % Q+I fluxes and dh_ML/dt term + d_t_bot_dt = d_t_bot_dt.*r_tstar_icesnow./depth_w; + + flk_str_2 = i_intm_h_d_flk -(1.-c_q_flk).*i_h_flk - c_q_flk.*i_bot_flk; + flk_str_2 = flk_str_2.*r_ti_icesnow./(depth_w-h_ml_p_flk)./tpl_rho_w_r./tpl_c_w; + % Add radiation-flux term + d_t_bot_dt = d_t_bot_dt + flk_str_2; + + flk_str_2 =(1.-c_tt_2.*r_ti_icesnow)./c_t_p_flk; + flk_str_2 = flk_str_2.*(t_wml_p_flk-t_bot_p_flk).*d_c_t_dt; + % Add dC_T/dt term + d_t_bot_dt = d_t_bot_dt + flk_str_2; + + % Mixed-layer retreat or stationary state + else + % dT_bot/dt=0 + d_t_bot_dt = 0.; + end + + % Update T_bot + t_bot_n_flk = t_bot_p_flk + d_t_bot_dt.*del_time; + % Security, limit T_bot by the freezing point + t_bot_n_flk = max(t_bot_n_flk, tpl_t_f); + T_water=t_mnw_n_flk; + tpl = tpl_grav*tpl_a_T*(T_water-tpl_t_r); + flk_str_2 =(t_bot_n_flk-tpl_t_r)*flake_buoypar; + % Security, avoid T_r crossover + if(flk_str_2<0.) + t_bot_n_flk = tpl_t_r; + end + t_wml_n_flk = c_t_n_flk.*(1.-h_ml_n_flk./depth_w); + t_wml_n_flk =(t_mnw_n_flk-t_bot_n_flk.*t_wml_n_flk)./(1.-t_wml_n_flk); + % Security, limit T_wML by the freezing point + t_wml_n_flk = max(t_wml_n_flk, tpl_t_f); + + % Mixing down to the lake bottom + else + + h_ml_n_flk = depth_w; + t_wml_n_flk = t_mnw_n_flk; + t_bot_n_flk = t_mnw_n_flk; + c_t_n_flk = c_t_min; + + end + +end + + +%------------------------------------------------------------------------------ +% Compute the depth of the upper layer of bottom sediments +% and the temperature at that depth. +%------------------------------------------------------------------------------ + +% % The bottom-sediment scheme is used +% if(lflk_botsed_use) +% +% % No T(z) maximum (no thermal wave) +% if(h_b1_p_flk>=depth_bs-h_b1_min_flk) +% % Set H_B1_p to zero +% h_b1_p_flk = 0.; +% % Set T_B1_p to the bottom temperature +% t_b1_p_flk = t_bot_p_flk; +% end +% +% flk_str_1 = 2..*phi_b1_pr0./(1.-c_b1).*tpl_kappa_w./tpl_rho_w_r./tpl_c_w.*del_time; +% % Threshold value of H_B1 +% h_ice_threshold = sqrt(flk_str_1); +% % Limit H_B1 +% h_ice_threshold = min(0.9.*depth_bs, h_ice_threshold); +% flk_str_2 = c_b2./(1.-c_b2).*(t_bs-t_b1_p_flk)./(depth_bs-h_b1_p_flk); +% +% % Use a truncated equation for H_B1(t) +% if(h_b1_p_flk=h_snow_min_flk) + % Snow exists, use the snow temperature + t_sfc_n = t_snow_n_flk; +elseif(h_ice_n_flk>=h_ice_min_flk) + % Ice exists but there is no snow, use the ice temperature + t_sfc_n = t_ice_n_flk; +else + % No ice-snow cover, use the mixed-layer temperature + t_sfc_n = t_wml_n_flk; +end + +%------------------------------------------------------------------------------ +% End calculations +%============================================================================== + +FLAKE.t_snow_n_flk = t_snow_n_flk; +FLAKE.t_ice_n_flk = t_ice_n_flk; +FLAKE.t_ice_p_flk = t_ice_p_flk; +FLAKE.t_wml_n_flk = t_wml_n_flk; +FLAKE.t_wml_p_flk = t_wml_p_flk; +FLAKE.t_mnw_n_flk = t_mnw_n_flk; +FLAKE.t_mnw_p_flk = t_mnw_p_flk; +FLAKE.d_t_mnw_dt = d_t_mnw_dt; +FLAKE.t_bot_n_flk = t_bot_n_flk; +FLAKE.t_bot_p_flk = t_bot_p_flk; +FLAKE.h_snow_n_flk = h_snow_n_flk; +FLAKE.h_ice_n_flk = h_ice_n_flk; +FLAKE.h_ml_n_flk = h_ml_n_flk; +FLAKE.c_t_n_flk = c_t_n_flk; +FLAKE.c_i_flk = c_i_flk; +FLAKE.q_bot_flk = q_bot_flk; +FLAKE.d_h_ice_dt = d_h_ice_dt; +FLAKE.q_w_flk = q_w_flk; + + diff --git a/modules/cryoGridLake/flake_radflux.m b/modules/cryoGridLake/flake_radflux.m new file mode 100644 index 0000000..2b3d414 --- /dev/null +++ b/modules/cryoGridLake/flake_radflux.m @@ -0,0 +1,65 @@ + +function [i_atm_flk, i_w_flk, i_ice_flk, i_snow_flk, i_h_flk, i_bot_flk, i_intm_0_h_flk, i_intm_h_d_flk]=flake_radflux(flake_SWnet,FLAKE,PARA) %#codegen + +%FlakeParameters +% Security constants + h_ice_min_flk = 1.0E-3 ; % Minimum ice thickness [m] + h_ml_min_flk = 1.0E-2 ; % Minimum mixed-layer depth [m] + +%-------------------------------------------------------------------------- +blueice_extincoef_optic=PARA.ice.extinction; +blueice_frac_optic=1; + +water_extincoef_optic=PARA.water.extinction; +water_frac_optic=1; + +% transwater_extincoef_optic=0.3; +% transwater_frac_optic=1; +% +% drysnow.extincoef_optic=25; +% drysnow.frac_optic=1; +% +% meltingsnow.extincoef_optic=15; +% meltingsnow.frac_optic=1; +%-------------------------------------------------------------------------- + +i_atm_flk=flake_SWnet; %net sw radiation at the top of the ice cover +h_ice_p_flk=0; %set to zero due to external ice cover scheme +h_ml_p_flk=FLAKE.h_ml_n_flk; + + + +if (h_ice_p_flk >= h_ice_min_flk) % ice exists (snow is excluded) + i_snow_flk = i_atm_flk; + i_ice_flk = i_atm_flk; + i_bot_flk = blueice_frac_optic .* exp(-blueice_extincoef_optic .* h_ice_p_flk); + i_w_flk = i_ice_flk .* i_bot_flk; +else % no ice cover + i_snow_flk = i_atm_flk; + i_ice_flk = i_atm_flk; + i_w_flk = i_atm_flk; +end + + if(h_ml_p_flk >= h_ml_min_flk) %there is a mixed layer + i_bot_flk = water_frac_optic.*exp(-water_extincoef_optic .* h_ml_p_flk); + i_h_flk = i_w_flk*i_bot_flk; + else % mixed layer depth is less then a minimum value + i_h_flk = i_w_flk; + end + + i_bot_flk = water_frac_optic .* exp(-water_extincoef_optic * (FLAKE.depth_w)); + i_bot_flk = i_w_flk.*i_bot_flk; + +if(h_ml_p_flk >= h_ml_min_flk) %integral-mean radiation flux over the mixed layer + i_intm_0_h_flk = water_frac_optic ./ water_extincoef_optic.* (1 - exp(-water_extincoef_optic .* h_ml_p_flk)); + i_intm_0_h_flk = i_w_flk .* i_intm_0_h_flk ./ h_ml_p_flk; +else + i_intm_0_h_flk = i_h_flk; +end + +if(h_ml_p_flk <= FLAKE.depth_w - h_ml_min_flk) % integral-mean radiation flux over the thermocline + i_intm_h_d_flk = water_frac_optic ./ water_extincoef_optic .* ( exp(-water_extincoef_optic .* h_ml_p_flk) - exp(-water_extincoef_optic .* FLAKE.depth_w) ); + i_intm_h_d_flk = i_w_flk .* i_intm_h_d_flk ./ (FLAKE.depth_w-h_ml_p_flk); +else + i_intm_h_d_flk = i_h_flk; +end \ No newline at end of file diff --git a/modules/cryoGridLake/flake_roughnessLength.m b/modules/cryoGridLake/flake_roughnessLength.m new file mode 100644 index 0000000..fdaf4c0 --- /dev/null +++ b/modules/cryoGridLake/flake_roughnessLength.m @@ -0,0 +1,174 @@ +function [z0u, z0t, z0q]=flake_roughnessLength(fetch, u_a, u_star, h_ice_p_flk) + +%------------------------------------------------------------------------------ +% +% Description: +% +% Computes the water-surface or the ice-surface roughness lengths +% with respect to wind velocity, potential temperature and specific humidity. +% +% The water-surface roughness lengths with respect to wind velocity is computed +% from the Charnock formula when the surface is aerodynamically rough. +% A simple empirical formulation is used to account for the dependence +% of the Charnock parameter on the wind fetch. +% When the flow is aerodynamically smooth, the roughness length with respect to +% wind velocity is proportional to the depth of the viscous sub-layer. +% The water-surface roughness lengths for scalars are computed using the power-law +% formulations in terms of the roughness Reynolds number (Zilitinkevich et al. 2001). +% The ice-surface aerodynamic roughness is taken to be constant. +% The ice-surface roughness lengths for scalars +% are computed through the power-law formulations +% in terms of the roughness Reynolds number (Andreas 2002). +% +% +% Current Code Owner: DWD, Dmitrii Mironov +% Phone: +49-69-8062 2705 +% Fax: +49-69-8062 3721 +% E-mail: dmitrii.mironov@dwd.de +% +% History: +% Version Date Name +% ---------- ---------- ---- +% 1.00 2005/11/17 Dmitrii Mironov +% Initial release +% 1.01 2014/08/09 Moritz Langer +% - modifited to work with CryoGrid3 +% +% Code Description: +% Language: Fortran 90. +% Software Standards: 'European Standards for Writing and +% Documenting Exchangeable Fortran 90 Code'. +%============================================================================== + +% fetch: Typical wind fetch [m] +% u_a: Wind speed [m s^{-1}] +% u_star: Friction velocity in the surface air layer [m s^{-1}] +% h_ice: Ice thickness [m] + +%Flake constants +%============================================================================== + + c_Karman = 0.40 ; % The von Karman constant + Pr_neutral = 1.0 ; % Turbulent Prandtl number at neutral static stability + Sc_neutral = 1.0 ; % Turbulent Schmidt number at neutral static stability + + + z0u_ice_rough = 1.0E-03 ; % Aerodynamic roughness of the ice surface [m] (rough flow) + c_z0u_smooth = 0.1 ; % Constant in the expression for z0u (smooth flow) + c_z0u_rough = 1.23E-02 ; % The Charnock constant in the expression for z0u (rough flow) + c_z0u_rough_L = 1.00E-01 ; % An increased Charnock constant (used as the upper limit) + c_z0u_ftch_f = 0.70 ; % Factor in the expression for fetch-dependent Charnock parameter + c_z0u_ftch_ex = 0.3333333 ; % Exponent in the expression for fetch-dependent Charnock parameter + c_z0t_rough_1 = 4.0 ; % Constant in the expression for z0t (factor) + c_z0t_rough_2 = 3.2 ; % Constant in the expression for z0t (factor) + c_z0t_rough_3 = 0.5 ; % Constant in the expression for z0t (exponent) + c_z0q_rough_1 = 4.0 ; % Constant in the expression for z0q (factor) + c_z0q_rough_2 = 4.2 ; % Constant in the expression for z0q (factor) + c_z0q_rough_3 = 0.5 ; % Constant in the expression for z0q (exponent) + c_z0t_ice_b0s = 1.250 ; % Constant in the expression for z0t over ice + c_z0t_ice_b0t = 0.149 ; % Constant in the expression for z0t over ice + c_z0t_ice_b1t = -0.550 ; % Constant in the expression for z0t over ice + c_z0t_ice_b0r = 0.317 ; % Constant in the expression for z0t over ice + c_z0t_ice_b1r = -0.565 ; % Constant in the expression for z0t over ice + c_z0t_ice_b2r = -0.183 ; % Constant in the expression for z0t over ice + c_z0q_ice_b0s = 1.610 ; % Constant in the expression for z0q over ice + c_z0q_ice_b0t = 0.351 ; % Constant in the expression for z0q over ice + c_z0q_ice_b1t = -0.628 ; % Constant in the expression for z0q over ice + c_z0q_ice_b0r = 0.396 ; % Constant in the expression for z0q over ice + c_z0q_ice_b1r = -0.512 ; % Constant in the expression for z0q over ice + c_z0q_ice_b2r = -0.180 ; % Constant in the expression for z0q over ice + + re_z0s_ice_t = 2.5 ; % Threshold value of the surface Reynolds number + % used to compute z0t and z0q over ice (Andreas 2002) + re_z0u_thresh = 0.1; % Threshold value of the roughness Reynolds number + % [value from Zilitinkevich, Grachev, and Fairall (200), + % currently not used] + + +% Thermodynamic parameters + tpl_grav = 9.81 ; % Acceleration due to gravity [m s^{-2}] + tpsf_R_dryair = 2.8705E+02 ; % Gas constant for dry air [J kg^{-1} K^{-1}] + tpsf_R_watvap = 4.6151E+02 ; % Gas constant for water vapour [J kg^{-1} K^{-1}] + + + tpsf_nu_u_a = 1.50E-05 ; % Kinematic molecular viscosity of air [m^{2} s^{-1}] + + +% Security constants + u_wind_min_sf = 1.0E-02 ; % Minimum wind speed [m s^{-1}] + h_Ice_min_flk = 1.0E-3 ; % Minimum ice thickness [m] + +% Useful constants +% num_1o3_sf = 1./3.; % 1/3 + +%Flake parameters +%============================================================================== + + +%============================================================================== +% Start calculations +%------------------------------------------------------------------------------ + +% Water surface +if(h_ice_p_flk < h_Ice_min_flk) + + % The Charnock parameter as dependent on dimensionless fetch + % Inverse dimensionless fetch + c_z0u_fetch = max(u_a, u_wind_min_sf).^2./tpl_grav./fetch; + c_z0u_fetch = c_z0u_rough + c_z0u_ftch_f.*c_z0u_fetch.^c_z0u_ftch_ex; + % Limit Charnock parameter + c_z0u_fetch = min(c_z0u_fetch, c_z0u_rough_L); + + % Threshold value of friction velocity + %u_star_thresh =(c_z0u_smooth./c_z0u_fetch.*tpl_grav.*tpsf_nu_u_a).^num_1o3_sf; + + % Surface Reynolds number and its threshold value + re_s = u_star.^3./tpsf_nu_u_a./tpl_grav; + re_s_thresh = c_z0u_smooth./c_z0u_fetch; + + % Aerodynamic roughness + if(re_s <= re_s_thresh) + % Smooth flow + z0u = c_z0u_smooth.*tpsf_nu_u_a./u_star; + else + % Rough flow + z0u = c_z0u_fetch.*u_star.*u_star./tpl_grav; + end + % Roughness for scalars + z0q = c_z0u_fetch.*max(re_s, re_s_thresh); + z0t = c_z0t_rough_1.*z0q.^c_z0t_rough_3 - c_z0t_rough_2; + z0q = c_z0q_rough_1.*z0q.^c_z0q_rough_3 - c_z0q_rough_2; + z0t = z0u.*exp(-c_Karman./Pr_neutral.*z0t); + z0q = z0u.*exp(-c_Karman./Sc_neutral.*z0q); + +% Ice surface +else + + % Threshold value of friction velocity + %u_star_thresh = c_z0u_smooth.*tpsf_nu_u_a./z0u_ice_rough; + + % Aerodynamic roughness + z0u = max(z0u_ice_rough, c_z0u_smooth.*tpsf_nu_u_a./u_star); + + % Roughness Reynolds number + re_s = max(u_star.*z0u./tpsf_nu_u_a, 1.0E-07 ); + + % Roughness for scalars + if(re_s<=re_z0s_ice_t) + z0t = c_z0t_ice_b0t + c_z0t_ice_b1t.*log(re_s); + z0t = min(z0t, c_z0t_ice_b0s); + z0q = c_z0q_ice_b0t + c_z0q_ice_b1t.*log(re_s); + z0q = min(z0q, c_z0q_ice_b0s); + else + z0t = c_z0t_ice_b0r + c_z0t_ice_b1r.*log(re_s) + c_z0t_ice_b2r.*log(re_s).^2; + z0q = c_z0q_ice_b0r + c_z0q_ice_b1r.*log(re_s) + c_z0q_ice_b2r.*log(re_s).^2; + end + z0t = z0u.*exp(z0t); + z0q = z0u.*exp(z0q); + +end + + +%------------------------------------------------------------------------------ +% End calculations +%============================================================================== diff --git a/modules/cryoGridLake/heatConductionIceCover.m b/modules/cryoGridLake/heatConductionIceCover.m new file mode 100644 index 0000000..68d216c --- /dev/null +++ b/modules/cryoGridLake/heatConductionIceCover.m @@ -0,0 +1,28 @@ +function [dE_dt_cond GRID]= heatConductionIceCover(dE_dt_cond, T, k_eff, k_temp, GRID) + +GRID.lake.ice.dE_dt_cond_residual=0; +if ~isempty(GRID.lake.ice.cT_domain_ub) && ~isempty(GRID.lake.water.cT_domain_ub) + dE_dt_cond_save = dE_dt_cond(GRID.lake.ice.cT_domain_lb) + dE_dt_cond(GRID.lake.ice.cT_domain_lb+1); + + if sum(GRID.lake.ice.cT_domain)<2 + + dE_dt_cond(GRID.lake.ice.cT_domain_lb) = k_temp(GRID.lake.ice.K_domain_lb) .* (0-T(GRID.lake.ice.cT_domain_lb)) ... + ./ GRID.general.K_delta(GRID.lake.ice.K_domain_lb)./2; + else + + dE_dt_cond(GRID.lake.ice.cT_domain_lb) = k_temp(GRID.lake.ice.K_domain_lb) .* (0-T(GRID.lake.ice.cT_domain_lb)) ... + ./ GRID.general.K_delta(GRID.lake.ice.K_domain_lb)./2 ... + - ... + k_eff(GRID.lake.ice.cT_domain_ub-1) .* (T(GRID.lake.ice.cT_domain_lb)-T(GRID.lake.ice.cT_domain_ub-1)) ... + ./ GRID.general.cT_delta(GRID.lake.ice.cT_domain_ub-1); + end + + dE_dt_cond(GRID.lake.ice.cT_domain_lb+1) = k_eff(GRID.lake.ice.cT_domain_lb+2).*(T(GRID.lake.ice.cT_domain_lb+2)-T(GRID.lake.ice.cT_domain_lb+1)) ... + ./ GRID.general.cT_delta(GRID.lake.ice.cT_domain_lb+2) ... + - ... + k_temp(GRID.lake.ice.K_domain_lb+1) .* (T(GRID.lake.ice.cT_domain_lb+1)-0) ... + ./ GRID.general.K_delta(GRID.lake.ice.K_domain_lb+1)./2; + + %residual heat flux used for ice cover + GRID.lake.ice.dE_dt_cond_residual = dE_dt_cond_save - (dE_dt_cond(GRID.lake.ice.cT_domain_lb) + dE_dt_cond(GRID.lake.ice.cT_domain_lb+1)); +end diff --git a/modules/cryoGridLake/heatConductionIceCover.m~ b/modules/cryoGridLake/heatConductionIceCover.m~ new file mode 100644 index 0000000..2b91c6a --- /dev/null +++ b/modules/cryoGridLake/heatConductionIceCover.m~ @@ -0,0 +1,28 @@ +function [dE_dt_cond GRID]= heatConductionIceCover(dE_dt_cond, T, k_eff, k_temp, GRID) + +GRID.ice.dE_dt_cond_residual=0; +if ~isempty(GRID.ice.cT_domain_ub) && ~isempty(GRID.water.cT_domain_ub) + dE_dt_cond_save = dE_dt_cond(GRID.ice.cT_domain_lb) + dE_dt_cond(GRID.ice.cT_domain_lb+1); + + if sum(GRID.ice.cT_domain)<2 + + dE_dt_cond(GRID.ice.cT_domain_lb) = k_temp(GRID.ice.K_domain_lb) .* (0-T(GRID.ice.cT_domain_lb)) ... + ./ GRID.general.K_delta(GRID.ice.K_domain_lb)./2; + else + + dE_dt_cond(GRID.ice.cT_domain_lb) = k_temp(GRID.ice.K_domain_lb) .* (0-T(GRID.ice.cT_domain_lb)) ... + ./ GRID.general.K_delta(GRID.ice.K_domain_lb)./2 ... + - ... + k_eff(GRID.ice.cT_domain_ub-1) .* (T(GRID.ice.cT_domain_lb)-T(GRID.ice.cT_domain_ub-1)) ... + ./ GRID.general.cT_delta(GRID.ice.cT_domain_ub-1); + end + + dE_dt_cond(GRID.ice.cT_domain_lb+1) = k_eff(GRID.ice.cT_domain_lb+2).*(T(GRID.ice.cT_domain_lb+2)-T(GRID.ice.cT_domain_lb+1)) ... + ./ GRID.general.cT_delta(GRID.ice.cT_domain_lb+2) ... + - ... + k_temp(GRID.ice.K_domain_lb+1) .* (T(GRID.ice.cT_domain_lb+1)-0) ... + ./ GRID.general.K_delta(GRID.ice.K_domain_lb+1)./2; + + %residual heat flux used for ice cover + GRID.ice.dE_dt_cond_residual = dE_dt_cond_save - (dE_dt_cond(GRID.ice.cT_domain_lb) + dE_dt_cond(GRID.ice.cT_domain_lb+1)); +end \ No newline at end of file diff --git a/modules/cryoGridLake/heatConductionLateral.m b/modules/cryoGridLake/heatConductionLateral.m new file mode 100644 index 0000000..c905833 --- /dev/null +++ b/modules/cryoGridLake/heatConductionLateral.m @@ -0,0 +1,16 @@ +function [dE_dt_cond dE_dt_lateral T_lateral]=heatConductionLateral(dE_dt_cond,T,k_temp,GRID,REF,FLAKE,t) + +[~, idx]=min(abs(REF.load.OUT.timestamp-t)); +T_lateral=REF.load.OUT.cryoGrid3(:,idx); + +%Estimated lateral heat flux. This procedure assumes that the thermal regime +%of the ground is not affected by the lake in a distance of about 2 twice +%the diameter of the lake. Assuming a circular lake shape, the lake has +%an effetive cross section with the soil domain of pi. Thus, the lateral +%heat flux per m^2 scales with (3.14.*FLAKE.fetch.*GRID.general.K_delta)./(3.14./4.*FLAKE.fetch.^2) + +dE_dt_lateral = k_temp.*(T_lateral-T)./(2.*FLAKE.fetch) .* 4.*GRID.general.K_delta./FLAKE.fetch; +dE_dt_lateral(~GRID.soil.cT_domain | T>0)=0; %exclude talik from lateral heat flux + +dE_dt_cond=dE_dt_cond+dE_dt_lateral; + diff --git a/modules/cryoGridLake/heatConductionLateral.m~ b/modules/cryoGridLake/heatConductionLateral.m~ new file mode 100644 index 0000000..c905833 --- /dev/null +++ b/modules/cryoGridLake/heatConductionLateral.m~ @@ -0,0 +1,16 @@ +function [dE_dt_cond dE_dt_lateral T_lateral]=heatConductionLateral(dE_dt_cond,T,k_temp,GRID,REF,FLAKE,t) + +[~, idx]=min(abs(REF.load.OUT.timestamp-t)); +T_lateral=REF.load.OUT.cryoGrid3(:,idx); + +%Estimated lateral heat flux. This procedure assumes that the thermal regime +%of the ground is not affected by the lake in a distance of about 2 twice +%the diameter of the lake. Assuming a circular lake shape, the lake has +%an effetive cross section with the soil domain of pi. Thus, the lateral +%heat flux per m^2 scales with (3.14.*FLAKE.fetch.*GRID.general.K_delta)./(3.14./4.*FLAKE.fetch.^2) + +dE_dt_lateral = k_temp.*(T_lateral-T)./(2.*FLAKE.fetch) .* 4.*GRID.general.K_delta./FLAKE.fetch; +dE_dt_lateral(~GRID.soil.cT_domain | T>0)=0; %exclude talik from lateral heat flux + +dE_dt_cond=dE_dt_cond+dE_dt_lateral; + diff --git a/modules/cryoGridLake/initializeLAKE.m b/modules/cryoGridLake/initializeLAKE.m new file mode 100644 index 0000000..b76c5c4 --- /dev/null +++ b/modules/cryoGridLake/initializeLAKE.m @@ -0,0 +1,29 @@ +function [FLAKE GRID] = initializeLAKE(GRID, PARA); + + +%---- flake initialization ------------------------------------------------ +FLAKE.t_snow_n_flk=0+273.15; +FLAKE.t_ice_n_flk=0+273.15; +FLAKE.t_wml_n_flk=6+273.15; +FLAKE.t_mnw_n_flk=5+273.15; +FLAKE.t_bot_n_flk=4+273.15; +FLAKE.t_b1_n_flk=7+273.15; +FLAKE.h_snow_n_flk=0; +FLAKE.h_ice_n_flk=0; +FLAKE.h_ml_n_flk=3; +FLAKE.h_b1_n_flk=10; +FLAKE.c_t_n_flk=0; +FLAKE.h_ice_n_flk=0; + +FLAKE.i_w_flk=0; +FLAKE.i_bot_flk=0; +FLAKE.q_w_flk=0; +FLAKE.q_bot_flk=0; + +FLAKE.fetch=100; +FLAKE.depth_w=PARA.water.depth; + +FLAKE.d_h_ice_dt = 0; +FLAKE.q_ice_water = 0; +FLAKE.extincoef_water_typ=PARA.water.extinction; +FLAKE.latitude=PARA.location.latitude; \ No newline at end of file diff --git a/modules/cryoGridLake/updateGRID_flake.m b/modules/cryoGridLake/updateGRID_flake.m new file mode 100644 index 0000000..0a7df70 --- /dev/null +++ b/modules/cryoGridLake/updateGRID_flake.m @@ -0,0 +1,16 @@ +function GRID = updateGRID_flake(GRID) + + +%update ice cover and water grid +GRID.lake.ice.cT_domain = (GRID.general.K_grid(2:end) - GRID.general.K_grid(min([GRID.lake.water.cT_domain_ub GRID.lake.ice.cT_domain_ub GRID.lake.ice.cT_domain_ub])))<=GRID.lake.ice.z_ice & ... + (GRID.general.K_grid(2:end) - GRID.general.K_grid(min([GRID.lake.water.cT_domain_ub GRID.lake.ice.cT_domain_ub])))> 0; + +GRID.lake.ice.K_domain = GRID.lake.ice.cT_domain; +[GRID.lake.ice.cT_domain_lb GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); +[GRID.lake.ice.K_domain_lb GRID.lake.ice.K_domain_ub] = LayerIndex(GRID.lake.ice.K_domain); + +%update water body grid +GRID.lake.water.cT_domain = (~GRID.air.cT_domain & ~GRID.snow.cT_domain & ~GRID.lake.ice.cT_domain & ~GRID.soil.cT_domain); +GRID.lake.water.K_domain = GRID.lake.water.cT_domain; +[GRID.lake.water.cT_domain_lb GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); +[GRID.lake.water.K_domain_lb GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); diff --git a/modules/cryoGridLake/waterAlbedo.m b/modules/cryoGridLake/waterAlbedo.m new file mode 100644 index 0000000..090b0b4 --- /dev/null +++ b/modules/cryoGridLake/waterAlbedo.m @@ -0,0 +1,33 @@ +function water_albedo = waterAlbedo(sun_elevation,windspeed) +%water albedo parameterization after Wayne and Burt (1954) +%assuming a fixed atmospheric turbitiy T'=3. +%This is a very simple parameterization and might be replaced by a more +%sophisticated model in the future. + +u_a=windspeed; + +%translate wind speeds [m/s] into wave slopes following suggestions of +%Wayne and Burt (1954) +h2 = (0.0<=u_a & u_a<0.2) .* 100; +h2 = h2 + (0.2<=u_a & u_a<5.5) .* 30; +h2 = h2 + (5.5<=u_a & u_a<13.9).* 20; +h2 = h2 + (13.9<=u_a).*10; + +%tabulation of wave slopes after Wayne and Burt (1954) +H2 = [100; 30; 20; 10]; +[~, i_h]=min(abs(H2-h2)); + +p=sun_elevation; +%tabulation of sun elevation angles after Wayne and Burt (1954) +P=[90 50 30 10]; +[~, i_p]=min(abs(P-p)); + +water_albedo_tab = [0.044 0.053 0.089 0.168; + 0.045 0.050 0.086 0.202; + 0.045 0.050 0.084 0.219; + 0.046 0.050 0.080 0.281]; + +water_albedo = water_albedo_tab(i_h,i_p); + + + diff --git a/modules/cryoGridLake/waterDensity.m b/modules/cryoGridLake/waterDensity.m new file mode 100644 index 0000000..9d7fd34 --- /dev/null +++ b/modules/cryoGridLake/waterDensity.m @@ -0,0 +1,10 @@ +function DW = waterDensity(T) + +%calulated following the CIPM formula +a1=-3.983035; +a2=301.797; +a3=522528.9; +a4=69.34881; +a5=999.974950; + +DW=a5*(1- ((T+a1).^2.*(T+a2))./(a3.*(T+a4))); %[kg/m³] \ No newline at end of file From 127f19288f9827d2af1269170e76ca638a05b141 Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Mon, 12 Feb 2018 16:58:24 +0100 Subject: [PATCH 22/45] main updated, makeGrids modified to include Flake --- CryoGrid3_xice_mpi.m | 19 ++++++--- modules/cryoGridTechnical/makeGrids.m | 61 +++++++++++++++++++-------- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 8e8de95..cba143a 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -64,7 +64,8 @@ PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. - PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] + %tsvd PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] + PARA.soil.externalWaterFlux=0.; %external water flux / drainage in [m/day] PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up @@ -87,10 +88,11 @@ % parameters related to lake PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) PARA.water.epsilon=0.99; % surface emissivity water -PARA.water.rs=0.; % surface resistance -> should be 0 for water +PARA.water.rs=0.; % surface resistance -> should be 0 for water %tsvd -PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m -PARA.water.extinction=1.2; % light extinction coefficient of water +PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation +%PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m version Flake +PARA.water.extinction=1.2; % light extinction coefficient of water PARA.water.depth=1.; PARA.water.fetch=20; @@ -296,7 +298,7 @@ if max((T<-100))==1; disp('dwd'); end %------- water body module -------------------------------------------- - T = mixingWaterBody(T, GRID); + T = mixingWaterBody(T, GRID); % zzz ok to keep? %------- snow cover module -------------------------------------------- [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); @@ -332,15 +334,18 @@ % in order to make the module "work" %------- excess ice module -------------------------------------------- if PARA.modules.xice && ~PARA.modules.infiltration - warning( 'energy and water balances are not correct for this combination of modules'); + warning( 'energy and water balances are not correct for this combination of modules'); % zzz ... [GRID, PARA] = excessGroundIce(T, GRID, PARA); +%tsvd version Flake [GRID, PARA, wc] = excessGroundIce(T, GRID, PARA); % assure wc has correct length wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); +%tsvd wc( end-sum(GRID.soil.cT_domain)+1 : end ); %tsvd make vector dims consistent elseif PARA.modules.xice && PARA.modules.infiltration [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); +%tsvd [GRID, PARA, wc] = excessGroundIceInfiltration(T, wc, GRID, PARA); GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); end - + %------- update Lstar for next time step ------------------------------ SEB = L_star(FORCING, PARA, SEB); diff --git a/modules/cryoGridTechnical/makeGrids.m b/modules/cryoGridTechnical/makeGrids.m index 2ee1150..67a627b 100644 --- a/modules/cryoGridTechnical/makeGrids.m +++ b/modules/cryoGridTechnical/makeGrids.m @@ -3,9 +3,17 @@ GRID.snow.snowCellSize=PARA.technical.SWEperCell/(PARA.snow.rho_snow/PARA.constants.rho_w); GRID.snow.snowGrid=[-1.*(PARA.technical.maxSWE./(PARA.technical.SWEperCell)+2).*GRID.snow.snowCellSize:GRID.snow.snowCellSize:-GRID.snow.snowCellSize]'; +%tsvd added + GRID.lake.water.waterGrid=[0:0.02:PARA.water.depth-0.02]'; %with water (it is recommended to use a grid resolution of about 2cm) +%GRID.lake.water.waterGrid=[]'; %no water +if ~isempty(GRID.lake.water.waterGrid) + GRID.soil.soilGrid=PARA.technical.subsurfaceGrid + (2*GRID.lake.water.waterGrid(end)-GRID.lake.water.waterGrid(end-1)); +else GRID.soil.soilGrid=PARA.technical.subsurfaceGrid; +end -K_grid =[GRID.snow.snowGrid; GRID.soil.soilGrid]; %grid on which the conductivty information lives (edges of grid cells) +%tsvd K_grid =[GRID.snow.snowGrid; GRID.soil.soilGrid]; %grid on which the conductivty information lives (edges of grid cells) + K_grid =[GRID.snow.snowGrid; GRID.lake.water.waterGrid; GRID.soil.soilGrid]; %grid on which the conductivty information lives (edges of grid cells) cT_grid=(K_grid(1:end-1)+K_grid(2:end))/2; %grid on which heat capacity and temperature information lives (midpoints of grid cells) cT_delta=(-cT_grid(1:end-1,1)+cT_grid(2:end,1)); K_delta=(-K_grid(1:end-1,1)+K_grid(2:end,1)); @@ -25,7 +33,8 @@ %set soil grid GRID.soil.cT_domain= false(size(GRID.general.cT_grid)); -GRID.soil.cT_domain(GRID.general.cT_grid>0)=1; +%tsvd GRID.soil.cT_domain(GRID.general.cT_grid>0)=1; + GRID.soil.cT_domain(end-length(GRID.soil.soilGrid)+2:end)=1; %required if there is a lake on top [GRID.soil.cT_domain_lb, GRID.soil.cT_domain_ub] = LayerIndex(GRID.soil.cT_domain); GRID.soil.K_domain= false(size(GRID.general.K_grid)); GRID.soil.K_domain(GRID.soil.cT_domain_ub:end)=1; @@ -43,20 +52,38 @@ % different and mixing occurs in summer. Initially, the lake domain is % empty, but it is updated in the first time step. -%set water and ice cover grid -GRID.lake.cT_domain = false(size(GRID.general.cT_grid)); -%GRID.lake.cT_domain(GRID.air.cT_domain_lb+1:GRID.soil.cT_domain_ub-1)=1; -GRID.lake.K_domain= false(size(GRID.general.K_grid)); -%GRID.lake.K_domain(GRID.air.K_domain_lb+1:GRID.soil.K_domain_ub-1)=1; -[GRID.lake.cT_domain_lb, GRID.lake.cT_domain_ub] = LayerIndex(GRID.lake.cT_domain); -[GRID.lake.K_domain_lb, GRID.lake.K_domain_ub] = LayerIndex(GRID.lake.K_domain); +%tsvd replaced by Flake conditions below - zzz Jan, if you update your model version with using GRID.lake.water.* instead of GRID.lake.*, our handling of GRID.lake is consistent +% %set water and ice cover grid +% GRID.lake.cT_domain = false(size(GRID.general.cT_grid)); +% %GRID.lake.cT_domain(GRID.air.cT_domain_lb+1:GRID.soil.cT_domain_ub-1)=1; +% GRID.lake.K_domain= false(size(GRID.general.K_grid)); +% %GRID.lake.K_domain(GRID.air.K_domain_lb+1:GRID.soil.K_domain_ub-1)=1; +% [GRID.lake.cT_domain_lb, GRID.lake.cT_domain_ub] = LayerIndex(GRID.lake.cT_domain); +% [GRID.lake.K_domain_lb, GRID.lake.K_domain_ub] = LayerIndex(GRID.lake.K_domain); +% +% GRID.lake.water.cT_domain= false(size(GRID.general.cT_grid)); +% GRID.lake.water.K_domain= false(size(GRID.general.K_grid)); +% [GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); +% [GRID.lake.water.K_domain_lb, GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); +% +% GRID.lake.ice.cT_domain=false(size(GRID.general.cT_grid)); +% GRID.lake.ice.K_domain=false(size(GRID.general.K_grid)); +% [GRID.lake.ice.cT_domain_lb, GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); +% [GRID.lake.ice.K_domain_lb, GRID.lake.ice.K_domain_ub] = LayerIndex(GRID.lake.ice.K_domain); +%tsvd +%set water and ice cover grid GRID.lake.water.cT_domain= false(size(GRID.general.cT_grid)); -GRID.lake.water.K_domain= false(size(GRID.general.K_grid)); -[GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); -[GRID.lake.water.K_domain_lb, GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); - -GRID.lake.ice.cT_domain=false(size(GRID.general.cT_grid)); -GRID.lake.ice.K_domain=false(size(GRID.general.K_grid)); -[GRID.lake.ice.cT_domain_lb, GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); -[GRID.lake.ice.K_domain_lb, GRID.lake.ice.K_domain_ub] = LayerIndex(GRID.lake.ice.K_domain); \ No newline at end of file +GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1:GRID.soil.cT_domain_ub-1)=1; +GRID.lake.water.K_domain= false(size(GRID.general.cT_grid)); +GRID.lake.water.K_domain(GRID.air.K_domain_lb+1:GRID.soil.K_domain_ub-1)=1; +[GRID.lake.water.cT_domain_lb GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); +[GRID.lake.water.K_domain_lb GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); +GRID.lake.ice.cT_domain=logical(GRID.air.cT_domain.*0); +GRID.lake.ice.K_domain=logical(GRID.air.K_domain.*0); +[GRID.lake.ice.cT_domain_lb GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); +[GRID.lake.ice.K_domain_lb GRID.lake.ice.K_domain_ub] = LayerIndex(GRID.lake.ice.K_domain); +GRID.lake.ice.z_ice = 0; +GRID.lake.ice.dz_dt_ice = 0; +GRID.lake.ice.dE_dt_cond_residual=0; +GRID.lake.ice.melt_flag=false; \ No newline at end of file From c5d854ca2d13c458ea7dedad082e341b165c24f1 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Mon, 12 Feb 2018 16:58:24 +0100 Subject: [PATCH 23/45] included updates from single-column version. soil altitude as reference for max Water threshold. exess water from snowmelt and rain on frozen ground ponded below threshold. --- CryoGrid3_xice_mpi.m | 524 +++++++++--------- .../CryoGridInfiltration.m | 128 +++-- .../bucketScheme.m | 11 +- .../surfaceEnergyBalanceInfiltration.m | 38 +- .../updateGRID_excessiceInfiltration2.m | 15 +- modules/cryoGridLateral/getMaxWaterAltitude.m | 2 +- .../cryoGridLateral/get_parallel_variables.m | 2 +- ...ateAuxiliaryVariablesAndCommonThresholds.m | 4 + modules/cryoGridSnow/CryoGridSnow.m | 3 + modules/cryoGridSoil/createStratigraphy.m | 8 +- .../initializeSoilThermalProperties.m | 4 +- modules/cryoGridTechnical/generateOUT.m | 1 + modules/cryoGridTechnical/getSoilAltitude.m | 7 + .../cryoGridTechnical/sum_up_output_store.m | 1 + 14 files changed, 379 insertions(+), 369 deletions(-) create mode 100644 modules/cryoGridTechnical/getSoilAltitude.m diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 891f7e5..ce550e6 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -20,24 +20,24 @@ spmd index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run - + %---------------define input parameters------------------------------------ % here you provide the ground stratigraphy % z w/i m o type porosity - + % default stratigraphy used in publication: - PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 0.65 0.3 0.05 2 0.4;... - 0.9 0.65 0.3 0.05 1 0.65;... - 9.0 0.30 0.70 0.00 1 0.30 ]; + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; % simple stratigraphy with excess ice used to test water balance: - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... % 0.4 0.8 0.2 0.00 1 0.40;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; + % 10.0 0.25 0.75 0.00 1 0.25 ]; % very simply stratigraphy without excess ice used to test energy balance % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... % 1.0 0.5 0.5 0.00 1 0.5 ;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; + % 10.0 0.25 0.75 0.00 1 0.25 ]; % soil stratigraphy % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer % extends until the end of the model domain @@ -46,31 +46,31 @@ % column 4: volumetric organic content % column 5: code for soil type: 1: sand, 2: silt % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs - + %------ model parameters -------------------------------------------------- - % parameters related to soil - PARA.soil.albedo=0.2; % albedo snow-free surface + % parameters related to soil + PARA.soil.albedo=0.2; % albedo snow-free surface PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development PARA.soil.epsilon=0.97; % emissvity snow-free surface PARA.soil.z0=1e-3; % roughness length [m] snow-free surface PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] - + % parameters related to hydrology scheme PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries - PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile - PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up - PARA.soil.hydraulic_conductivity = 1e-5; + PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up + PARA.soil.hydraulic_conductivity = 1e-5; PARA = loadSoilTypes( PARA ); - + % parameters related to snow PARA.snow.max_albedo=0.85; % albedo of fresh snow PARA.snow.min_albedo=0.5; % albedo of old snow @@ -83,25 +83,25 @@ PARA.snow.tau_f=0.24; % [per day] PARA.snow.relative_maxSnow= [0.1]; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold PARA.snow.extinction=25.0; % light extinction coefficient of snow - + % parameters related to water body on top of soil domain - PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) PARA.water.epsilon=0.99; % surface emissivity water PARA.water.rs=0.0; % surface resistance -> should be 0 for water PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation - - PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 PARA.ice.epsilon=0.98; % surface emissivity snow PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 - + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1980, 7, 1); % endtime of the simulation - if empty end at last value of time series + PARA.technical.starttime=datenum(1979, 7, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(1979, 7, 5); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -110,172 +110,173 @@ PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] - + %default grid used for publications and testing of water balance: PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - + PARA.location.area=1.0; - PARA.location.initial_altitude=20.0; - % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" - PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain - PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow + PARA.location.initial_altitude=20.0; + % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" + PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain + PARA.location.soil_altitude=PARA.location.initial_altitude; + PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow PARA.location.active_layer_depth_altitude = nan; % defined at runtime - PARA.location.water_table_altitude = nan; % defined at runtime - % thresholds - PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; - if isempty( PARA.snow.relative_maxSnow ) - PARA.location.absolute_maxSnow_altitude = []; - else - PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; - end - + PARA.location.water_table_altitude = nan; % defined at runtime + % thresholds + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.relative_maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; + end + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] PARA.Tinitial = [ -2 5 ;... - 0 0 ;... - 2 -5 ;... - 10 -10 ;... - 25 -9 ;... - 100 -9 ;... - 2000 10 ]; - + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... + 2000 10 ]; + PARA = loadConstants( PARA ); - + %FORCING data mat-file PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files PARA.forcing.rain_fraction=1; PARA.forcing.snow_fraction=1; - + % switches for modules PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs PARA.modules.xice=1; % true if thaw subsicdence is enabled - PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) + PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) + + if PARA.modules.lateral + % switches for lateral processes + PARA.modules.exchange_heat = 1; + PARA.modules.exchange_water = 1; + PARA.modules.exchange_snow = 1; + + %---------overwrites variables for each realization-------------------- + % this function must define everything that is realization-specific or dependent of all realizations + PARA = get_parallel_variables( PARA ); + end - if PARA.modules.lateral - % switches for lateral processes - PARA.modules.exchange_heat = 1; - PARA.modules.exchange_water = 1; - PARA.modules.exchange_snow = 1; - - %---------overwrites variables for each realization-------------------- - % this function must define everything that is realization-specific or dependent of all realizations - PARA = get_parallel_variables( PARA ); - end - % ------make output directory (name depends on parameters) ---------------- - run_number= sprintf( 'testrunMPI_POOL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... + run_number= sprintf( 'testrunMPI_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... - PARA.modules.infiltration, PARA.modules.xice, ... - PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , ... - index ] ); + PARA.modules.infiltration, PARA.modules.xice, ... + PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , ... + index ] ); mkdir(['./runs/' run_number]) - + %-------------------------------------------------------------------------- %-----------do not modify from here onwards-------------------------------- %-------------------------------------------------------------------------- [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file - + if ~success warning('A problem with the Forcing occured.'); end - + PARA = initializeParameters(PARA, FORCING); %set start time, etc. - + %----------------create and initialize the grids -------------------------- GRID=makeGrids(PARA); %create all grids GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid - + %----- initializie excess ground ice -------------------------------------- [GRID,PARA] = initializeExcessIce2(GRID,PARA); - + %----- initializie soil thermal properties -------------------------------- GRID = initializeSoilThermalProperties(GRID, PARA); - + %------ initializie snow properties---------------------------------------- GRID = initializeSnow(GRID); - + %---- initialize the surface energy balance struct ------------------------ SEB = initializeSEB(); - + %---- initialize the water body module ------------------------------------ GRID = initializeLAKE(GRID); - + %---- initialize temperature profile -------------------------------------- - T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); - + T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); + %---- modification for infiltration wc=GRID.soil.cT_water; GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; - + %---- preallocate temporary arrays for capacity and conductivity----------- [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid - + %---- energy and water balance initialization ----------------------------- BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); - - %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? + + %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index - dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index %__________________________________________________________________________ %-------- provide arrays for data storage --------------------------------- [t, TEMPORARY] = generateTemporary(T, PARA); OUT = generateOUT(); - + disp('initialization successful'); iSaveSettings( [ './runs/' run_number '/' run_number '_settings.mat'] , FORCING, PARA, GRID) - - + + %% ________________________________________________________________________ % Time Integration Routine I % I %_________________________________________________________________________I - + while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) warning( 'numerical stability not guaranteed' ); end - + %------ update T array ------------------------------------------------ % account for vertical heat fluxes from ground heat flux and heat conduction T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; @@ -283,20 +284,20 @@ T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] % set grid cells in air to air temperature T(GRID.air.cT_domain)=FORCING.i.Tair; - + %------- water body module -------------------------------------------- T = mixingWaterBody(T, GRID); - + %------- snow cover module -------------------------------------------- [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - + %------- infiltration module------------------------------------------- if PARA.modules.infiltration lateral_water_flux = nansum( water_fluxes ); % lateral fluxes to/from other workers in [m/s] [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_water_flux); end - + %------- excess ice module -------------------------------------------- if PARA.modules.xice && ~PARA.modules.infiltration warning( 'energy and water balances are not correct for this combination of modules'); @@ -307,174 +308,175 @@ [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); end - + %------- update Lstar for next time step ------------------------------ SEB = L_star(FORCING, PARA, SEB); - - %------- update auxiliary state variables - PARA.location.altitude = getAltitude( PARA, GRID ); - PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); - PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); - PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); - - %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time - if ~PARA.modules.lateral - PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; - if isempty( PARA.snow.maxSnow ) - PARA.location.absolute_maxSnow_altitude = []; - else - PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; - end - end - + + %------- update auxiliary state variables + PARA.location.altitude = getAltitude( PARA, GRID ); + PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); + PARA.location.soil_altitude = getSoilAltitude( PARA, GRID ); + PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); + PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); + + %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time + if ~PARA.modules.lateral + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; + end + end + %------- water balance calculations ----------------------------------- % rainfall - BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval + BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval % snowfall - BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval - + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval + %------- lateral exchange module -------------------------------------- - % all functions called in this block should go into + % all functions called in this block should go into % /modules/cryoGridLateral - % calling PARA.ensemble is only allowed here - if PARA.modules.lateral - if t==TEMPORARY.syncTime %communication between workers - disp('CryoGridLateral: sync - start'); - labBarrier(); %common start - PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; - - % heat exchange module - if PARA.modules.exchange_heat - labBarrier(); - % check preconditions - precondition_heatExchange = true; %no specific conditions so far - if precondition_heatExchange - %WRAPPER - disp('sync - exchanging heat'); - % calculate lateral heat fluxes - dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] - heat_fluxes = zeros( numlabs, 1); - PACKAGE_heatExchange.T = T; - PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; - PACKAGE_heatExchange.k_cTgrid = k_cTgrid; - for j=1:number_of_realizations - if j~=index - labSend( PACKAGE_heatExchange, j, 1); - end - end - for j=1:number_of_realizations - if j~=index - PACKAGE_heatExchange_j = labReceive(j, 1); - [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index - heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes - dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations - end - end - end - end - - % water exchange module - if PARA.modules.exchange_water - labBarrier(); - % check preconditions - precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); - if precondition_waterExchange - % WRAPPER - disp('sync - exchanging water'); - % calculate lateral water fluxes - water_fluxes = nan( number_of_realizations, 1 ); % in [m/s] - PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); - PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); - PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); - for j=1:number_of_realizations - if j~=index - labSend( PACKAGE_waterExchange, j, 2); - end - end - for j=1:number_of_realizations - if j~=index - PACKAGE_waterExchange_j = labReceive(j, 2); - % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) - water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); % matrix containing all fluxes in [m/s] scaled to row index - end - end - % for debugging: print water flux per column - waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m - fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); - end - - end - - % snow exchange module - if PARA.modules.exchange_snow - labBarrier(); - % check preconditions - precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); - if precondition_snowExchange - disp('sync - exchanging snow'); - % calculate terrain index with updated surface_altitudes - PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); - - % calculate mobile snow - % WRAPPER - mobile_snow = zeros( 1, number_of_realizations ); - my_mobile_snow = 0; - meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE - if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions - i=0; - while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold - > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains - && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) - - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) - my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile - i=i+1; - end - end - mobile_snow(index) = my_mobile_snow; - % exchange mobile snow amounts - for j=1:number_of_realizations - if j~=index - % send mobile snow amount in [m SWE] - labSend( mobile_snow(index), j, 4 ); - end - end - for j=1:number_of_realizations - if j~=index - % receive mobile snow amount [m SWE] - mobile_snow(j) = labReceive(j, 4); - end - end - % calculate lateral snow fluxes - my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); - % apply lateral snow fluxes directly - if my_snow_change ~= 0 - [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; - end - - snow_fluxes = zeros( numlabs , 1 ); - snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes - fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); - - end - end - - labBarrier(); - PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; - - TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; - disp('sync - done'); - end - end + % calling PARA.ensemble is only allowed here + if PARA.modules.lateral + if t==TEMPORARY.syncTime %communication between workers + disp('CryoGridLateral: sync - start'); + labBarrier(); %common start + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + % heat exchange module + if PARA.modules.exchange_heat + labBarrier(); + % check preconditions + precondition_heatExchange = true; %no specific conditions so far + if precondition_heatExchange + %WRAPPER + disp('sync - exchanging heat'); + % calculate lateral heat fluxes + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + heat_fluxes = zeros( numlabs, 1); + PACKAGE_heatExchange.T = T; + PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; + PACKAGE_heatExchange.k_cTgrid = k_cTgrid; + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_heatExchange, j, 1); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_heatExchange_j = labReceive(j, 1); + [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index + heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes + dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations + end + end + end + end + + % water exchange module + if PARA.modules.exchange_water + labBarrier(); + % check preconditions + precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); + if precondition_waterExchange + % WRAPPER + disp('sync - exchanging water'); + % calculate lateral water fluxes + water_fluxes = nan( number_of_realizations, 1 ); % in [m/s] + PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); + PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_waterExchange, j, 2); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_waterExchange_j = labReceive(j, 2); + % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) + water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); % matrix containing all fluxes in [m/s] scaled to row index + end + end + % for debugging: print water flux per column + waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m + fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); + end + + end + + % snow exchange module + if PARA.modules.exchange_snow + labBarrier(); + % check preconditions + precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); + if precondition_snowExchange + disp('sync - exchanging snow'); + % calculate terrain index with updated surface_altitudes + PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); + + % calculate mobile snow + % WRAPPER + mobile_snow = zeros( 1, number_of_realizations ); + my_mobile_snow = 0; + meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE + if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions + i=0; + while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold + > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains + && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) + - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) + my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile + i=i+1; + end + end + mobile_snow(index) = my_mobile_snow; + % exchange mobile snow amounts + for j=1:number_of_realizations + if j~=index + % send mobile snow amount in [m SWE] + labSend( mobile_snow(index), j, 4 ); + end + end + for j=1:number_of_realizations + if j~=index + % receive mobile snow amount [m SWE] + mobile_snow(j) = labReceive(j, 4); + end + end + % calculate lateral snow fluxes + my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); + % apply lateral snow fluxes directly + if my_snow_change ~= 0 + [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; + end + + snow_fluxes = zeros( numlabs , 1 ); + snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes + fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); + + end + end + + labBarrier(); + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; + disp('sync - done'); + end + end %------- next time step ----------------------------------------------- t=t+timestep; %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes); - - + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes); + + end % save final state and output at t=endtime diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m index f909052..f1ce3bd 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m @@ -1,12 +1,10 @@ function [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_flux_rate) + +if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 %no snow cover and uppermost grid cell unfrozen - % possible meltwater contribution from xice - if ~PARA.modules.xice - meltwaterGroundIceAboveWaterTableThreshold = 0; - else - meltwaterGroundIceAboveWaterTableThreshold = GRID.lake.residualWater; - GRID.lake.residualWater=0; - end + % possible contribution from xice meltwater, snowmelt, rain on frozen ground + residualWater = GRID.lake.residualWater; + GRID.lake.residualWater=0; % external flux external_flux_rate = PARA.soil.externalWaterFlux; % in m/day @@ -15,68 +13,66 @@ % lateral flux to/from other workers lateral_flux_rate = lateral_flux_rate.*3600.*24; % now in m/day BALANCE.water.dr_lateral = BALANCE.water.dr_lateral + lateral_flux_rate.*timestep.*1000; - - if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 %no snow cover and uppermost grid cell unfrozen - - %%% step 1: infiltrate rain and meltwater and external flux through bucket scheme - % changes due to evapotranspiration and condensation - dwc_dt=dwc_dt.*timestep.*24.*3600; %now in m water per grid cell - BALANCE.water.de = BALANCE.water.de + sum(dwc_dt)*1000; % in mm accumulated over soil column - - % changes due to rainfall - dwc_dt(1)=dwc_dt(1)+FORCING.i.rainfall./1000.*timestep; - - % changes due to meltwater from excess ice - dwc_dt(1)=dwc_dt(1)+meltwaterGroundIceAboveWaterTableThreshold; - - % routing of water - [wc, surface_runoff, lacking_water] = bucketScheme(T, wc, dwc_dt, GRID, PARA, (external_flux_rate+lateral_flux_rate).*timestep); - - % consistency check - if sum( wc<0 )~=0 - warning( 'CryoGridInfiltration - negative water content occured after bucket scheme' ); - %here one could correct the water balance - + + %%% step 1: infiltrate rain and meltwater and external flux through bucket scheme + % changes due to evapotranspiration and condensation + dwc_dt=dwc_dt.*timestep.*24.*3600; %now in m water per grid cell + BALANCE.water.de = BALANCE.water.de + sum(dwc_dt)*1000; % in mm accumulated over soil column + + % changes due to rainfall + dwc_dt(1)=dwc_dt(1)+FORCING.i.rainfall./1000.*timestep; + + % changes due to residual water + dwc_dt(1)=dwc_dt(1)+residualWater; + + % routing of water + [wc, surface_runoff, lacking_water] = bucketScheme(T, wc, dwc_dt, GRID, PARA, (external_flux_rate+lateral_flux_rate).*timestep); + + % consistency check + if sum( wc<0 )~=0 + warning( 'CryoGridInfiltration - negative water content occured after bucket scheme' ); + %here one could correct the water balance + + end + + % remove water above water table in case of ponding, e.g. through rain (independent of xice module) + if GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)<1e-6 && ... + PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub)>PARA.location.absolute_maxWater_altitude + + + cellSize = GRID.general.K_delta(GRID.soil.cT_domain_ub); + actualWater = wc(1)*cellSize; + h = PARA.location.absolute_maxWater_altitude - (PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub+1)); + if h<0 + warning('h<0. too much water above water table!') end - - % remove water above water table in case of ponding, e.g. through rain (independent of xice module) - if GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)<1e-6 && ... - PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub)>PARA.location.absolute_maxWater_altitude - - - cellSize = GRID.general.K_delta(GRID.soil.cT_domain_ub); - actualWater = wc(1)*cellSize; - h = PARA.location.absolute_maxWater_altitude - (PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub+1)); - if h<0 - warning('h<0. too much water above water table!') - end - - if actualWater>h - disp('infiltration - removing excess water from upper cell'); - wc(1)=h./cellSize; - surface_runoff = surface_runoff + actualWater-h; - end - - + + if actualWater>h + disp('infiltration - removing excess water from upper cell'); + wc(1)=h./cellSize; + surface_runoff = surface_runoff + actualWater-h; end - - %%% step 2: update GRID including reomval of excess water above water table and ponding below water table - [ wc, GRID, surface_runoff ] = updateGRID_infiltration(wc, GRID, PARA, surface_runoff); - - - % store remaining surface runoff - BALANCE.water.dr_surface = BALANCE.water.dr_surface - surface_runoff*1000; % in [mm] - BALANCE.water.dm_lacking = BALANCE.water.dm_lacking + lacking_water*1000; - + + end + + %%% step 2: update GRID including reomval of excess water above water table and ponding below water table + [ wc, GRID, surface_runoff ] = updateGRID_infiltration(wc, GRID, PARA, surface_runoff); + + + % store remaining surface runoff + BALANCE.water.dr_surface = BALANCE.water.dr_surface - surface_runoff*1000; % in [mm] + BALANCE.water.dm_lacking = BALANCE.water.dm_lacking + lacking_water*1000; + +end - % step 3: LUT update - % JAN:recalculate lookup tables when water content of freezing grid cells - % has changed (infiltrated cells can freeze --> LUT is updated) - if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 - disp('infiltration - reinitializing LUT - freezing of infiltrated cell(s)'); - GRID.soil.cT_water = wc; - GRID = initializeSoilThermalProperties(GRID, PARA); - end +% step 3: LUT update +% JAN:recalculate lookup tables when water content of freezing grid cells +% has changed (infiltrated cells can freeze --> LUT is updated) +if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 + disp('infiltration - reinitializing LUT - freezing of infiltrated cell(s)'); + GRID.soil.cT_water = wc; + GRID = initializeSoilThermalProperties(GRID, PARA); +end end \ No newline at end of file diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m index 3c447ba..36680ef 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/bucketScheme.m @@ -22,8 +22,11 @@ actual_water= max( min_water, wc(i).*K_delta(i)+dwc_dt(i) ); % should be dwc (already multiplied with timestep) %JAN: this violates the WB - lacking_water = lacking_water + (wc(i).*K_delta(i)+dwc_dt(i)-actual_water); - + lacking_water = lacking_water + (actual_water - (wc(i).*K_delta(i)+dwc_dt(i) ) ); +% if abs(lacking_water)>1e-8 +% warning('bucketScheme - lacking water'); +% end + dwc_dt(i+1)=dwc_dt(i+1) + max(0, actual_water-max_water); %when excess water, move it to next grid cell wc(i)=min(max_water, actual_water)./K_delta(i); @@ -45,6 +48,4 @@ i=i-1; end - -surface_runoff=(excess_water>0)*excess_water; % surface runoff only if excess_water>0 - +surface_runoff=(excess_water>0)*excess_water; % surface runoff only if excess_water>0 \ No newline at end of file diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m index b78b38d..a9de979 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m @@ -18,12 +18,12 @@ dE_dt(GRID.air.cT_domain_lb+1)=(1-PARA.surf.albedo).*FORCING.i.Sin; %------ snow surface (solid state green house effect) --------------------- -if ~isempty(GRID.snow.cT_domain_ub) - beta=PARA.snow.extinction; +if ~isempty(GRID.snow.cT_domain_ub) + beta=PARA.snow.extinction; Qsolar(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb+1) = dE_dt(GRID.snow.cT_domain_ub) .* exp(-beta.*(GRID.general.K_grid(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb+1)-GRID.general.K_grid(GRID.snow.cT_domain_ub))); dE_dt(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb) = -Qsolar(GRID.snow.cT_domain_ub+1:GRID.snow.cT_domain_lb+1) + Qsolar(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb); %put the rest to cell below snow - dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); + dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); end %__________________________________________________________________________ @@ -37,25 +37,25 @@ if PARA.modules.infiltration % snow cover or uppermost grid cell frozen --> no ET ; this includes the case of a frozen water body - if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 + if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); % unfrozen water body at surface - elseif GRID.lake.unfrozenWaterSurface + elseif GRID.lake.unfrozenWaterSurface Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); dwc_dt(1)=-Qe./L; %in m water per sec, this can be evaporation or condensation - % unfrozen soil surface - else - Qe_pot=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, 0, FORCING.i.p, PARA)); %potential ET + % unfrozen soil surface + else + Qe_pot=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, 0, FORCING.i.p, PARA)); %potential ET if Qe_pot>0 fraction_T=getET_fraction(T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1), wc(1:GRID.soil.T_lb), PARA.soil.fieldCapacity, PARA.soil.wiltingPoint); fraction_E=getET_fraction(T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.E_lb-1), wc(1:GRID.soil.E_lb), PARA.soil.fieldCapacity, PARA.soil.residualWC); fraction_ET = fraction_T.*PARA.soil.ratioET; fraction_ET(1:GRID.soil.E_lb) = fraction_ET(1:GRID.soil.E_lb) + fraction_E.*(1-PARA.soil.ratioET); - + Qe=sum(fraction_ET.*GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1))./sum(GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1)).*Qe_pot; fraction_ET=fraction_ET.*GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1)./sum(fraction_ET.*GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1)); - % sum(fraction_ET) is always 1 + % sum(fraction_ET) is always 1 dwc_dt(1:GRID.soil.T_lb)=-Qe./L.*fraction_ET; %in m water per sec else %condensation Qe=Qe_pot; @@ -72,19 +72,12 @@ %grid cells, should be identical if no snow cover and no evapotranspiration %occur dE_dt(GRID.air.cT_domain_lb+1) = dE_dt(GRID.air.cT_domain_lb+1) ... - + PARA.surf.epsilon.*FORCING.i.Lin ... - - PARA.surf.epsilon.*sigma.*(T(GRID.air.cT_domain_lb+1)+273.15).^4 ... - - Qh - Qe; % Qe positive: cooling of soil => evaporation/subl. => loss of SWE - - - -% fluxes are in [ W / m^2 ] -SEB.Qsurf = dE_dt(GRID.air.cT_domain_lb+1); + + PARA.surf.epsilon.*FORCING.i.Lin ... + - PARA.surf.epsilon.*sigma.*(T(GRID.air.cT_domain_lb+1)+273.15).^4 ... + - Qh - Qe; % Qe positive: cooling of soil => evaporation/subl. => loss of SWE -% if abs( SEB.Qsurf-Qg ) > 1e-6 -% warning ( ' Qsurf != Qg ' ); -% end - +% fluxes are in [ W / m^2 ] +SEB.Qsurf = dE_dt(GRID.air.cT_domain_lb+1); SEB.dE_dt_SEB = dE_dt; SEB.Qnet = Qnet; SEB.Qh = Qh; @@ -93,4 +86,3 @@ SEB.Sout = Sout; SEB.Lout = Lout; - \ No newline at end of file diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m index 4875e20..5fbbe95 100644 --- a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m @@ -1,7 +1,7 @@ function [GRID] = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID) % pass excess meltwater to storage variable - GRID.lake.residualWater = meltwaterGroundIce; + GRID.lake.residualWater = GRID.lake.residualWater + meltwaterGroundIce; % update GRID domains of water body if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 % upper soil cell pure air/water @@ -22,8 +22,7 @@ % [GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); % GRID.lake.ice.cT_domain = GRID.lake.cT_domain & T<=0; % [GRID.lake.ice.cT_domain_lb, GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); %these might be two domains -% % K domains not implemented so far - + % K domains not implemented so far else GRID.lake.cT_domain = false(size(GRID.general.cT_grid)); GRID.lake.K_domain = false(size(GRID.general.K_grid)); @@ -31,4 +30,14 @@ [GRID.lake.K_domain_lb, GRID.lake.K_domain_ub] = LayerIndex(GRID.lake.K_domain); end + + + + + + + + + + end \ No newline at end of file diff --git a/modules/cryoGridLateral/getMaxWaterAltitude.m b/modules/cryoGridLateral/getMaxWaterAltitude.m index dfa07e7..e774051 100644 --- a/modules/cryoGridLateral/getMaxWaterAltitude.m +++ b/modules/cryoGridLateral/getMaxWaterAltitude.m @@ -1,3 +1,3 @@ function max_water = getMaxWaterAltitude(PARA) - max_water = max( PARA.ensemble.altitude ) + PARA.soil.relative_maxWater; + max_water = max( PARA.ensemble.soil_altitude ) + PARA.soil.relative_maxWater; end diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index 391bfc5..bb5e990 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -16,7 +16,7 @@ PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids PARA.ensemble.altitude = PARA.ensemble.initial_altitude; PARA.ensemble.surface_altitude = PARA.ensemble.initial_altitude; - + PARA.ensemble.soil_altitude = PARA.ensemble.initial_altitude; % parameters related to heat exchange PARA.ensemble.thermal_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); % [ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; % diff --git a/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m b/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m index c6cbc6b..f2a2175 100644 --- a/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m +++ b/modules/cryoGridLateral/updateAuxiliaryVariablesAndCommonThresholds.m @@ -2,6 +2,7 @@ PARA.ensemble.surface_altitude(labindex) = getSurfaceAltitude( PARA, GRID ); PARA.ensemble.altitude(labindex) = getAltitude( PARA, GRID ); + PARA.ensemble.soil_altitude(labindex) = getSoilAltitude( PARA, GRID ); PARA.ensemble.water_table_altitude(labindex) = getWaterTableAltitude(T, wc, GRID, PARA ); %JAN: Leo uses getWaterTabelFC to account for non-saturated cells above fieldCapacity PARA.ensemble.active_layer_depth_altitude(labindex) = getActiveLayerDepthAltitude(PARA, GRID, T); % sending information from "labindex" to all "j" @@ -11,6 +12,7 @@ labSend(PARA.ensemble.altitude(labindex), j, 2); labSend(PARA.ensemble.water_table_altitude(labindex), j, 3); labSend(PARA.ensemble.active_layer_depth_altitude(labindex), j, 4); + labSend(PARA.ensemble.soil_altitude(labindex), j, 5); end end % receiving --------------------------------------------------- @@ -21,6 +23,7 @@ PARA.ensemble.altitude(j)=labReceive(j, 2); PARA.ensemble.water_table_altitude(j)=labReceive(j, 3); PARA.ensemble.active_layer_depth_altitude(j)=labReceive(j, 4); + PARA.ensemble.soil_altitude(j)=labReceive(j, 5); end end @@ -31,5 +34,6 @@ % update auxiliary variables in location struct // MORE? PARA.location.altitude = PARA.ensemble.altitude(labindex); PARA.location.surface_altitude = PARA.ensemble.surface_altitude(labindex); + PARA.location.soil_altitude = PARA.ensemble.soil_altitude(labindex); PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(labindex); PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(labindex); diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index 510c98d..1081fb6 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -42,6 +42,7 @@ c_temp(GRID.snow.cT_domain),... PARA); + GRID.lake.residualWater = GRID.lake.residualWater + newMelt; BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt + (-newMelt.*1000); % in [mm] end @@ -69,10 +70,12 @@ %---------- add the new snow into initial SWE variable in case of no snow cover------------------ GRID.snow.SWEinitial = GRID.snow.SWEinitial + FORCING.i.snowfall.*timestep./1000 - GRID.snow.SWEinitial.*0.1.*timestep; + GRID.lake.residualWater = GRID.lake.residualWater + GRID.snow.SWEinitial.*0.1.*timestep; BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - GRID.snow.SWEinitial.*0.1.*timestep*1000; %SWEinitial decreasing counted as surface runoff %----- add the rainfall as runoff in case of no infiltration into frozen ground if ~PARA.modules.infiltration || (PARA.modules.infiltration && T(GRID.soil.cT_domain_ub)<=0 )%no infiltration scheme or uppermost soil cell frozen + GRID.lake.residualWater = GRID.lake.residualWater + FORCING.i.rainfall.*timestep./1000; BALANCE.water.dr_rain = BALANCE.water.dr_rain - FORCING.i.rainfall.*timestep; end diff --git a/modules/cryoGridSoil/createStratigraphy.m b/modules/cryoGridSoil/createStratigraphy.m index e99f418..4ffede1 100644 --- a/modules/cryoGridSoil/createStratigraphy.m +++ b/modules/cryoGridSoil/createStratigraphy.m @@ -18,10 +18,4 @@ GRID.soil.cT_organic = interp1(soilParam(:,1),soilParam(:,4),GRID.general.cT_grid(GRID.soil.cT_domain),'linear'); GRID.soil.cT_soilType = interp1(soilParam(:,1),soilParam(:,5),GRID.general.cT_grid(GRID.soil.cT_domain),'nearest'); GRID.soil.cT_natPor = interp1(soilParam(:,1),soilParam(:,6),GRID.general.cT_grid(GRID.soil.cT_domain),'linear'); -GRID.soil.cT_actPor = 1. - GRID.soil.cT_mineral - GRID.soil.cT_organic; - - -% GRID.soil.K_water = interp1(soilParam(:,1),soilParam(:,2),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -% GRID.soil.K_mineral = interp1(soilParam(:,1),soilParam(:,3),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -% GRID.soil.K_organic = interp1(soilParam(:,1),soilParam(:,4),GRID.general.K_grid(GRID.soil.K_domain),'linear'); -% GRID.soil.K_soilType = interp1(soilParam(:,1),soilParam(:,5),GRID.general.K_grid(GRID.soil.K_domain),'nearest'); \ No newline at end of file +GRID.soil.cT_actPor = 1. - GRID.soil.cT_mineral - GRID.soil.cT_organic; \ No newline at end of file diff --git a/modules/cryoGridSoil/initializeSoilThermalProperties.m b/modules/cryoGridSoil/initializeSoilThermalProperties.m index d12b789..fd85e98 100644 --- a/modules/cryoGridSoil/initializeSoilThermalProperties.m +++ b/modules/cryoGridSoil/initializeSoilThermalProperties.m @@ -31,10 +31,10 @@ cT_natPor = GRID.soil.cT_natPor; cT_actPor = GRID.soil.cT_actPor; -lowMinOrg_domain = cT_mineral+cT_organic>=1e-6 & ~GRID.soil.excessGroundIce & (cT_actPor > cT_natPor ); % cells with lower soil matrix material than 1-natPor +lowMinOrg_domain = cT_mineral+cT_organic>=1e-6 & ~GRID.soil.excessGroundIce & (cT_actPor > cT_natPor+1e-6 ); % cells with lower soil matrix material than 1-natPor if sum(lowMinOrg_domain)>0 - warning('cells with low matrix material exist - upscaling of matrix fraction to ensure correct thermal properties'); + disp('initializeSoilThermalProperties - cells with low matrix material exist --> upscaling of matrix fraction to ensure realistic thermal properties'); cT_matrix = cT_mineral + cT_organic; cT_mineral(lowMinOrg_domain) = cT_mineral(lowMinOrg_domain) ./ cT_matrix(lowMinOrg_domain) .* (1 - cT_natPor(lowMinOrg_domain)) ; cT_organic(lowMinOrg_domain) = cT_organic(lowMinOrg_domain) ./ cT_matrix(lowMinOrg_domain) .* (1 - cT_natPor(lowMinOrg_domain)) ; diff --git a/modules/cryoGridTechnical/generateOUT.m b/modules/cryoGridTechnical/generateOUT.m index 7e35a9b..4f4c073 100644 --- a/modules/cryoGridTechnical/generateOUT.m +++ b/modules/cryoGridTechnical/generateOUT.m @@ -32,6 +32,7 @@ % derived characteristics and related to geometry OUT.location.area = []; OUT.location.altitude=[]; + OUT.location.soil_altitude = []; OUT.location.surface_altitude=[]; OUT.location.active_layer_depth_altitude = []; OUT.location.water_table_altitude=[]; diff --git a/modules/cryoGridTechnical/getSoilAltitude.m b/modules/cryoGridTechnical/getSoilAltitude.m new file mode 100644 index 0000000..83c4db1 --- /dev/null +++ b/modules/cryoGridTechnical/getSoilAltitude.m @@ -0,0 +1,7 @@ +function soil_altitude = getSoilAltitude(PARA, GRID) + +if ~isempty( GRID.lake.cT_domain_ub ) + soil_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.lake.cT_domain_lb+1); +else + soil_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.soil.cT_domain_ub); +end \ No newline at end of file diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 96214ea..61223cf 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -97,6 +97,7 @@ % derived characteristics and related to geometry OUT.location.area = [OUT.location.area; PARA.location.area]; OUT.location.altitude=[OUT.location.altitude; PARA.location.altitude]; + OUT.location.soil_altitude= [OUT.location.soil_altitude; PARA.location.soil_altitude]; OUT.location.surface_altitude=[OUT.location.surface_altitude; PARA.location.surface_altitude]; OUT.location.active_layer_depth_altitude = [OUT.location.active_layer_depth_altitude; PARA.location.active_layer_depth_altitude]; OUT.location.water_table_altitude=[OUT.location.water_table_altitude; PARA.location.water_table_altitude]; From 7a9a00cfab0c049ad189993f8478878a74cc3fc2 Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Wed, 14 Feb 2018 16:33:36 +0100 Subject: [PATCH 24/45] source Jan combined with FLAKE settings --- .../surfaceEnergyBalanceInfiltration.m | 43 ++++++++++++++++--- .../updateGRID_excessiceInfiltration2.m | 7 +++ modules/cryoGridSEB/surfaceCondition.m | 29 ++++++++++--- 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m index b78b38d..4b03429 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m @@ -15,8 +15,10 @@ %______here SW radiation is calculated_____________________________________ dE_dt=GRID.general.cT_grid.*0; Qsolar=GRID.general.cT_grid.*0; - -dE_dt(GRID.air.cT_domain_lb+1)=(1-PARA.surf.albedo).*FORCING.i.Sin; +%tsvd + Sin_water=0; +%tsvd dE_dt(GRID.air.cT_domain_lb+1)=(1-PARA.surf.albedo).*FORCING.i.Sin; + dE_dt(GRID.air.cT_domain_lb+1,1)=(1-PARA.surf.albedo).*FORCING.i.Sin; %------ snow surface (solid state green house effect) --------------------- if ~isempty(GRID.snow.cT_domain_ub) beta=PARA.snow.extinction; @@ -26,6 +28,29 @@ dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); end +%tsvd +%------- ice surface (solid state green house effect) --------------------- +if ~isempty(GRID.lake.ice.cT_domain_ub) + beta=PARA.ice.extinction; +% if GRID.lake.ice.melt_flag +% %increse light extinction coeff under melt conditions +% beta=PARA.ice.extinction.*2; +% end + Qsolar(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb+1) = dE_dt(GRID.lake.ice.cT_domain_ub) .* exp(-beta.*(GRID.general.K_grid(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb+1)-GRID.general.K_grid(GRID.lake.ice.cT_domain_ub))); + dE_dt(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb) = -Qsolar(GRID.lake.ice.cT_domain_ub+1:GRID.lake.ice.cT_domain_lb+1) + Qsolar(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb); + %put the rest to cell below ice cover + dE_dt(GRID.lake.ice.cT_domain_lb+1) = Qsolar(GRID.lake.ice.cT_domain_lb+1); +end +%------- water domain ----------------------------------------------------- +if ~isempty(GRID.lake.water.cT_domain_ub) + beta=PARA.water.extinction; + Qsolar(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb+1) = dE_dt(GRID.lake.water.cT_domain_ub) .* exp(-beta.*(GRID.general.K_grid(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb+1)-GRID.general.K_grid(GRID.lake.water.cT_domain_ub))); + dE_dt(GRID.lake.water.cT_domain_ub :GRID.lake.water.cT_domain_lb) = -Qsolar(GRID.lake.water.cT_domain_ub+1:GRID.lake.water.cT_domain_lb+1) + Qsolar(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb); + %put the rest to cell below water body + dE_dt(GRID.lake.water.cT_domain_lb+1) = Qsolar(GRID.lake.water.cT_domain_lb+1); + %SW output for FLAKE radiation scheme + Sin_water = Qsolar(GRID.lake.water.cT_domain_ub); +end %__________________________________________________________________________ Sout = PARA.surf.albedo*FORCING.i.Sin; Lout = PARA.surf.epsilon.*sigma.*(T(GRID.air.cT_domain_lb+1)+273.15).^4 + (1-PARA.surf.epsilon).*FORCING.i.Lin; @@ -36,8 +61,10 @@ %calculate ET if PARA.modules.infiltration - % snow cover or uppermost grid cell frozen --> no ET ; this includes the case of a frozen water body - if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 + %snow cover or uppermost grid cell frozen --> no ET +%tsvd added from version FLAKE +if PARA.soil.infiltration + if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || ~isempty(GRID.lake.water.cT_domain_ub) % islake ... %snow cover or uppermost grid cell frozen --> no ET tsvd: addition case LAKE added Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); % unfrozen water body at surface elseif GRID.lake.unfrozenWaterSurface @@ -47,7 +74,8 @@ % unfrozen soil surface else Qe_pot=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, 0, FORCING.i.p, PARA)); %potential ET - if Qe_pot>0 +%tsvd if Qe_pot>0 + if Qe_pot>0 && GRID.soil.cT_domain(GRID.air.cT_domain_lb+1)==1 fraction_T=getET_fraction(T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1), wc(1:GRID.soil.T_lb), PARA.soil.fieldCapacity, PARA.soil.wiltingPoint); fraction_E=getET_fraction(T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.E_lb-1), wc(1:GRID.soil.E_lb), PARA.soil.fieldCapacity, PARA.soil.residualWC); fraction_ET = fraction_T.*PARA.soil.ratioET; @@ -92,5 +120,6 @@ SEB.Qg = Qg; SEB.Sout = Sout; SEB.Lout = Lout; - - \ No newline at end of file + %tsvd + SEB.Sin_water=Sin_water; +end \ No newline at end of file diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m index 4875e20..e3ee2fe 100644 --- a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m @@ -23,6 +23,13 @@ % GRID.lake.ice.cT_domain = GRID.lake.cT_domain & T<=0; % [GRID.lake.ice.cT_domain_lb, GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); %these might be two domains % % K domains not implemented so far + +%tsvd + GRID.lake.water.cT_domain(max([GRID.air.cT_domain_lb+1 GRID.ice.cT_domain_lb+1]) : GRID.soil.cT_domain_ub-1) = 1; + GRID.lake.water.K_domain(max([GRID.air.K_domain_lb+1 GRID.ice.K_domain_lb+1]) : GRID.soil.K_domain_ub-1) = 1; + + [GRID.lake.water.cT_domain_lb GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); + [GRID.lake.water.K_domain_lb GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); else GRID.lake.cT_domain = false(size(GRID.general.cT_grid)); diff --git a/modules/cryoGridSEB/surfaceCondition.m b/modules/cryoGridSEB/surfaceCondition.m index 8569c2e..69a27a4 100644 --- a/modules/cryoGridSEB/surfaceCondition.m +++ b/modules/cryoGridSEB/surfaceCondition.m @@ -1,9 +1,9 @@ -function [PARA, GRID] = surfaceCondition(GRID, PARA, T) +%tsvd function [PARA, GRID] = surfaceCondition(GRID, PARA, T) % old implementation +function [PARA, GRID] = surfaceCondition(GRID, PARA, T, t, FORCING, SEB) -% set surface parameters (albedo, emissivity, roughnesslength, resistance -% to evaporation) according to the actual surface conditions +% set surface parameters (albedo, emissivity, roughnesslength, resistance to evaporation) according to the actual surface conditions -GRID.lake.unfrozenWaterSurface=false; +GRID.lake.unfrozenWaterSurface=false; % zzz %default soil surface PARA.surf.albedo = PARA.soil.albedo; @@ -37,4 +37,23 @@ PARA.surf.rs = PARA.ice.rs; end end - \ No newline at end of file +%tsvd check if lake exists + if GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface + %note SolarAzEl.m delivers only an approximation of sun position / t must be in UTC + + [~, sun_elevation] = SolarAzEl(t,PARA.location.latitude,PARA.location.longitude,PARA.location.altitude); + PARA.water.albedo = waterAlbedo(sun_elevation, FORCING.i.wind); + PARA.surf.albedo = PARA.water.albedo; + PARA.surf.epsilon = PARA.water.epsilon; + [PARA.surf.z0, z0t, z0q] = flake_roughnessLength(PARA.water.fetch, FORCING.i.wind, SEB.u_star, 0); + PARA.surf.z0=real(PARA.surf.z0); + PARA.surf.rs = PARA.water.rs; + end + if GRID.lake.ice.z_ice>0 %GRID.lake.ice.cT_domain(GRID.air.cT_domain_lb+1)==1 % ice surface + PARA.surf.albedo = PARA.ice.albedo; + PARA.surf.epsilon = PARA.ice.epsilon; + [PARA.surf.z0, z0t, z0q] = flake_roughnessLength(PARA.water.fetch, FORCING.i.wind, SEB.u_star, 1); + PARA.surf.z0=real(PARA.surf.z0); + PARA.surf.rs = PARA.ice.rs; + end +end \ No newline at end of file From 97e6bbe55cba19856fd60dae224f83e7a8a334c2 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Mon, 5 Mar 2018 13:28:10 +0100 Subject: [PATCH 25/45] adjusted get_parallel_variables for hexagonal geometry. --- CryoGrid3_xice_mpi.m | 42 +++--- .../cryoGridLateral/get_parallel_variables.m | 140 +++++++++++++----- .../cryoGridTechnical/sum_up_output_store.m | 1 + 3 files changed, 129 insertions(+), 54 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index ce550e6..a01a27d 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -12,7 +12,7 @@ %dbstop if error; -number_of_realizations=2; +number_of_realizations=3; if number_of_realizations>1 parpool(number_of_realizations); @@ -50,7 +50,7 @@ %------ model parameters -------------------------------------------------- % parameters related to soil PARA.soil.albedo=0.2; % albedo snow-free surface - PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development + %PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development PARA.soil.epsilon=0.97; % emissvity snow-free surface PARA.soil.z0=1e-3; % roughness length [m] snow-free surface PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface @@ -58,7 +58,7 @@ PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] % parameters related to hydrology scheme - PARA.soil.fieldCapacity=0.3; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.fieldCapacity=0.5; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off @@ -81,14 +81,14 @@ PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] PARA.snow.tau_a=0.008; % [per day] PARA.snow.tau_f=0.24; % [per day] - PARA.snow.relative_maxSnow= [0.1]; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.relative_maxSnow= [1.0]; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold PARA.snow.extinction=25.0; % light extinction coefficient of snow % parameters related to water body on top of soil domain PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) PARA.water.epsilon=0.99; % surface emissivity water PARA.water.rs=0.0; % surface resistance -> should be 0 for water - PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation + PARA.water.z0=5e-4; % roughness length surface [m] % JAN: value for summer / vegetation PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 PARA.ice.epsilon=0.98; % surface emissivity snow @@ -100,8 +100,8 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1979, 7, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1979, 7, 5); % endtime of the simulation - if empty end at last value of time series + PARA.technical.starttime=datenum(2006, 10, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(2007, 10, 1); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -112,7 +112,7 @@ PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] %default grid used for publications and testing of water balance: - PARA.technical.subsurfaceGrid = [[0:0.02:2], [2.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + PARA.technical.subsurfaceGrid = [[0:0.02:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] PARA.location.area=1.0; @@ -132,14 +132,22 @@ end %initial temperature profile -> first column depth [m] -> second column temperature [degree C] - PARA.Tinitial = [ -2 5 ;... - 0 0 ;... - 2 -5 ;... - 10 -10 ;... - 25 -9 ;... - 100 -9 ;... - 2000 10 ]; - +% PARA.Tinitial = [ -2 5 ;... +% 0 0 ;... +% 2 -5 ;... +% 10 -10 ;... +% 25 -9 ;... +% 100 -9 ;... +% 2000 10 ]; + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -2 ;... + 5 -7 ;... + 10 -9 ;... + 25 -9 ;... + 100 -8 ;... + 1100 10.2 ]; % the geothermal gradient for Qgeo=0.05W/m² and K=2.746W/Km is about 18.2 K/km + PARA = loadConstants( PARA ); %FORCING data mat-file @@ -164,7 +172,7 @@ end % ------make output directory (name depends on parameters) ---------------- - run_number= sprintf( 'testrunMPI_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... + run_number= sprintf( 'testrunMPI_geometryHEX_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... PARA.modules.infiltration, PARA.modules.xice, ... PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , ... diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index bb5e990..0d0e2c9 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -2,44 +2,72 @@ index = labindex; - % auxiliary calculations for circular geometry - diameter=10; % in [m] - area = pi.*(diameter./2)^2; % in [m^2] - perimeter = 2*pi.*(diameter./2); % in [m] + % auxiliary calculations for geometry + % input: typical total polygon area + areal weights (as integers) of center/rim/troughs + area_tot = 100.0; % typical area of polygon center [Cresto Aleina / Muster ] + PARA.ensemble.weight = [3, 6, 1];%[2, 1, 1]; + + % areas + PARA.ensemble.area = PARA.ensemble.weight ./ sum(PARA.ensemble.weight) .* area_tot ; % in m^2 + area_C = PARA.ensemble.area(1); + area_R = PARA.ensemble.area(2); + area_T = PARA.ensemble.area(3); + % distances + distance_CR = (0.5.*area_C + 0.25.*area_R) ./ sqrt( area_tot ); % in m + distance_RT = (0.5.*area_T + 0.25.*area_R) ./ sqrt( area_tot ); + + % perimeters % assuming hexagonal shapes of centers and polygons + perimeter_CR = 6 .* sqrt( 2 .* area_C ./ (3 .* sqrt(3) ) ); % assuming hexagonal shape of center + %2 .* pi .* ( diameter_C ./2); % assuming circular shape of polygons + perimeter_RT = 6. * sqrt( 2 .* (area_C+area_R) ./ (3 .* sqrt(3) ) ); + + % geometric relations - PARA.ensemble.distanceBetweenPoints= diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members - PARA.ensemble.weight = [1, 1];%[2, 1, 1]; - PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 - + PARA.ensemble.distanceBetweenPoints= [ 0, distance_CR, 0; distance_CR, 0, distance_RT; 0, distance_RT, 0 ]; %diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members + A = double( PARA.ensemble.distanceBetweenPoints > 0 ); % connectivity of the networ (auxiliary) + % topographical relations - PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + altitude_C = 20.0; + elevation_R = 0.4; + elevation_T = 0.1; + altitude_R = altitude_C + elevation_R; + altitude_T = altitude_C + elevation_T; + + PARA.ensemble.initial_altitude = [ altitude_C, altitude_R, altitude_T ]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids PARA.ensemble.altitude = PARA.ensemble.initial_altitude; PARA.ensemble.surface_altitude = PARA.ensemble.initial_altitude; PARA.ensemble.soil_altitude = PARA.ensemble.initial_altitude; + % parameters related to heat exchange - PARA.ensemble.thermal_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); % [ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; % + PARA.ensemble.thermal_contact_length = [0, perimeter_CR, 0; perimeter_CR, 0, perimeter_RT; 0, perimeter_RT, 0 ]; % [ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; % % parameters related to water exchange - PARA.ensemble.external_water_flux=[0, 0 ] ; % 0]; %in m/day - PARA.ensemble.hydraulic_conductivity= PARA.soil.hydraulic_conductivity * ( ones(numlabs) - eye(numlabs ) );%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; %in m/sec % [Roth: 1e-5 for saturated silt, 2.2e-5 for saturated sand] - PARA.ensemble.water_table_altitude = PARA.ensemble.altitude; %initialize somehow; + PARA.ensemble.hydraulic_conductivity= PARA.soil.hydraulic_conductivity .* A;%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; %in m/sec % [Roth: 1e-5 for saturated silt, 2.2e-5 for saturated sand] + PARA.ensemble.water_table_altitude = [NaN NaN NaN]; %initialize somehow; %PARA.ensemble.max_water_flux= [0 0]; %in m water equivalent - PARA.ensemble.hydraulic_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) );%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; + PARA.ensemble.hydraulic_contact_length = PARA.ensemble.thermal_contact_length;%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; PARA.ensemble.active_layer_depth_altitude = [NaN NaN NaN]; PARA.ensemble.hydraulicDistance = PARA.ensemble.distanceBetweenPoints; % parameters related to snow exchange %PARA.ensemble.snow_diffusivity = PARA.snow.diffusivity; %PARA.ensemble.relative_max_snow_height = 0.2; - PARA.ensemble.immobile_snow_height = [0.1, 0.1 ]; %, 0.2 ]; %in m %this replaces PARA.snow.maxSnow ? + PARA.ensemble.immobile_snow_height = [0.1, 0.1, 0.1 ]; %, 0.2 ]; %in m %this replaces PARA.snow.maxSnow ? PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.altitude, PARA.ensemble.weight); - PARA.ensemble.snow_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); + PARA.ensemble.snow_contact_length = PARA.ensemble.thermal_contact_length; - % location-specific static + % parameters related to infiltration scheme + PARA.ensemble.external_water_flux=[0, 0, 0 ] ; % 0]; %in m/day + PARA.ensemble.rootDepth = [ 0.2, 0.1, 0.2 ]; + PARA.ensemble.fieldCapacity = [ 0.5, 0.5, 0.5 ]; + + % location-specific fix parameter values PARA.location.initial_altitude = PARA.ensemble.initial_altitude(index); PARA.soil.externalWaterFlux = PARA.ensemble.external_water_flux(index); + PARA.soil.rootDepth = PARA.ensemble.rootDetph(index); + PARA.soil.fieldCapacity= PARA.ensemble.fieldCapacity(index); % location-specific dynamic auxiliary variables PARA.location.area = PARA.ensemble.area(index); PARA.location.altitude = PARA.ensemble.altitude(index); @@ -50,30 +78,68 @@ PARA.location.absolute_maxWater_altitude = [max( PARA.ensemble.altitude ) + PARA.soil.relative_maxWater]; PARA.location.absolute_maxSnow_altitude = [max( PARA.ensemble.altitude ) + PARA.snow.relative_maxSnow]; + % different stratigraphies - PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % center stratigraphy without excess ice - 1.0 0.5 0.5 0.00 1 0.50 ;... - 10.0 0.25 0.75 0.00 1 0.25 ] , ... - [0.0 0.5 0.5 0.00 1 0.50;... % rim stratigraphy with excess ice - 0.7 0.8 0.2 0.00 1 0.50;... - 10.0 0.25 0.75 0.00 1 0.25 ], ... - [0.0 0.5 0.5 0.00 1 0.50;... % trough stratigraphy with excess ice - 0.1 0.8 0.2 0.00 1 0.50;... - 10.0 0.25 0.75 0.00 1 0.25 ]}; + depth_xice_C = 0.9; + vwc_xice_C = 0.65; + depth_xice_R = 0.6; + vwc_xice_R = 0.75; + depth_xice_T = 0.3; + vwc_xice_T = 0.90; + natPor = 0.5; + stratigraphyMap= containers.Map( { 'DEFAULT', 'WET', 'DRY', 'CENTER', 'RIM', 'TROUGH' }, ... + { [ 0.0 0.40 0.10 0.15 1 0.75;... + 0.15 0.65 0.30 0.05 1 0.65;... + 0.9 0.65 0.30 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ], ... + [ 0.0 0.85 0.00 0.15 1 0.85;... + 0.15 0.75 0.2 0.05 1 0.75;... + 0.30 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ], ... + [ 0.0 0.50 0.10 0.15 1 0.75;... + 0.1 0.65 0.30 0.05 2 0.65;... + 0.9 0.65 0.30 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ],... + [ 0.0 0.85 0.00 0.15 1 0.85;... + 0.15 0.75 0.20 0.05 1 0.75;... + 0.30 0.65 0.30 0.05 2 0.65;... + depth_xice_C vwc_xice_C 0.30 0.05 1 natPor;... + 9.0 0.30 0.70 0.00 1 0.30 ], ... + [ 0.0 0.50 0.10 0.15 1 0.75;... + 0.1 0.65 0.30 0.05 2 0.65;... + depth_xice_R vwc_xice_R 0.20 0.05 1 natPor;... + 9.0+elevation_R 0.30 0.70 0.00 1 0.30 ], ... + [ 0.0 0.40 0.00 0.15 1 0.85;... + depth_xice_T vwc_xice_T 0.20 0.05 1 natPor;... + 9.0+elevation_T 0.30 0.70 0.00 1 0.30 ] } ); + + PARA.soil.layer_properties = { stratigraphyMap{'CENTER'}, ... + stratigraphyMap{'RIM'}, ... + stratigraphyMap{'TROUGH'} }; PARA.soil.layer_properties = PARA.soil.layer_properties{index}; - - - % different initial conditions - PARA.Tinitial = [-5 5 5 5;... - 0 -5 -5 -5;... - 1 -5 -5 -5;... - 10 -8 -8 -8;... - 20 -10 -10 -10;... - 100 -10 -10 -10;... - 2000 10 10 10]; + % typical profile for beginning of October + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -2 ;... + 5 -7 ;... + 10 -9 ;... + 25 -9 ;... + 100 -8 ;... + 1100 10.2 ]; % the geothermal gradient for Qgeo=0.05W/m² and K=2.746W/Km is about 18.2 K/km - PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; + +% % different initial conditions +% PARA.Tinitial = [-5 5 5 5;... +% 0 -5 -5 -5;... +% 1 -5 -5 -5;... +% 10 -8 -8 -8;... +% 20 -10 -10 -10;... +% 100 -10 -10 -10;... +% 2000 10 10 10]; +% +% PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; end diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 61223cf..a03e816 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -187,6 +187,7 @@ if round((t-TEMPORARY.saveTime).*48)==0 iSaveOUT(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + %iPlotAltitudes( ['./runs/' run_number '/' run_number '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); OUT = generateOUT(); TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(datestr(t,'mm')), str2num(datestr(t,'dd')), str2num(datestr(t,'HH')), str2num(datestr(t,'MM')), 0); end From e2984b9e5a9b1cd25fd017337f8bfcf9a1dd95b3 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Mon, 5 Mar 2018 13:46:43 +0100 Subject: [PATCH 26/45] added plotting during simulation --- CryoGrid3_xice_mpi.m | 2 +- modules/cryoGridTechnical/sum_up_output_store.m | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index a01a27d..4e7c439 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -482,7 +482,7 @@ %------- next time step ----------------------------------------------- t=t+timestep; %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes); + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes); end diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index a03e816..3d38af2 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -1,4 +1,4 @@ -function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes) +function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes) TEMPORARY.timestep_sum=TEMPORARY.timestep_sum+(timestep*24*3600)*timestep; @@ -185,9 +185,9 @@ %write output files if round((t-TEMPORARY.saveTime).*48)==0 - iSaveOUT(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) - iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) - %iPlotAltitudes( ['./runs/' run_number '/' run_number '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); + iSaveOUT([ saveDir '/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) + iSaveState([ saveDir '/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); OUT = generateOUT(); TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(datestr(t,'mm')), str2num(datestr(t,'dd')), str2num(datestr(t,'HH')), str2num(datestr(t,'MM')), 0); end From eb923d7c49fa0251af4e5738e241706808c9159e Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Tue, 6 Mar 2018 17:09:24 +0100 Subject: [PATCH 27/45] bugfix for upper water cells also included on branch xice_mpi. --- CryoGrid3_xice_mpi.m | 26 +++++++++---------- .../updateGRID_infiltration.m | 5 ++-- .../cryoGridLateral/get_parallel_variables.m | 10 +++---- .../cryoGridTechnical/sum_up_output_store.m | 8 +++--- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 4e7c439..2a7e900 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -14,6 +14,8 @@ number_of_realizations=3; +saveDir = '/data/scratch/nitzbon/CryoGrid/CryoGrid3_infiltration_xice_mpi/runs'; + if number_of_realizations>1 parpool(number_of_realizations); end @@ -50,7 +52,6 @@ %------ model parameters -------------------------------------------------- % parameters related to soil PARA.soil.albedo=0.2; % albedo snow-free surface - %PARA.soil.albedoPond=0.07; % albedo of water, used when the uppermost grod cell is 100% water due to modeled thermokarst development PARA.soil.epsilon=0.97; % emissvity snow-free surface PARA.soil.z0=1e-3; % roughness length [m] snow-free surface PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface @@ -100,8 +101,8 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(2006, 10, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(2007, 10, 1); % endtime of the simulation - if empty end at last value of time series + PARA.technical.starttime=datenum(2000, 10, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(2014, 10, 1); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -172,13 +173,10 @@ end % ------make output directory (name depends on parameters) ---------------- - run_number= sprintf( 'testrunMPI_geometryHEX_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... - [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... - PARA.modules.infiltration, PARA.modules.xice, ... - PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , ... - index ] ); + run_number = sprintf( [ 'TESTRUN-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) '_stratSAM_geomHEX_extFluxT-0.005_xH%d_xW%d_xS%d_rf%d_sf%d' ], ... + [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction] ) ; - mkdir(['./runs/' run_number]) + mkdir([ saveDir '/' run_number]); %-------------------------------------------------------------------------- %-----------do not modify from here onwards-------------------------------- @@ -236,7 +234,7 @@ OUT = generateOUT(); disp('initialization successful'); - iSaveSettings( [ './runs/' run_number '/' run_number '_settings.mat'] , FORCING, PARA, GRID) + iSaveSettings( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_settings.mat'] , FORCING, PARA, GRID) %% ________________________________________________________________________ @@ -488,13 +486,13 @@ end % save final state and output at t=endtime - iSaveOUT(['./runs/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) - iSaveState(['./runs/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) - + iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) + iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); end if number_of_realizations>1 delete(gcp('nocreate')) end -disp('Done.'); \ No newline at end of file +disp('Done.'); diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m index ba3b8c3..81afc06 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m @@ -29,7 +29,6 @@ GRID.soil.cT_mineral(1)=[]; GRID.soil.cT_soilType(1)=[]; - GRID.soil.excessGroundIce(1)=[]; end @@ -63,7 +62,7 @@ % update remaining soil fields with exception of cT_water GRID.soil.cT_organic = [ 0 ; GRID.soil.cT_organic ]; GRID.soil.cT_natPor = [ GRID.soil.cT_natPor(1); GRID.soil.cT_natPor ]; % take natPor of cell below - GRID.soil.cT_actPor = [ 1; GRID.soil.cT_actPor ]; % set to 1 + GRID.soil.cT_actPor = [ 1; GRID.soil.cT_actPor ]; % set actual porosity to 1 GRID.soil.cT_mineral = [ 0 ; GRID.soil.cT_mineral ]; GRID.soil.cT_soilType = [ 1; GRID.soil.cT_soilType]; % assume sand as soil type for water cell @@ -91,4 +90,4 @@ -end +end \ No newline at end of file diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index 0d0e2c9..cb4f82c 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -59,14 +59,14 @@ PARA.ensemble.snow_contact_length = PARA.ensemble.thermal_contact_length; % parameters related to infiltration scheme - PARA.ensemble.external_water_flux=[0, 0, 0 ] ; % 0]; %in m/day + PARA.ensemble.external_water_flux=[0, 0, -5e-3 ] ; % 0]; %in m/day PARA.ensemble.rootDepth = [ 0.2, 0.1, 0.2 ]; PARA.ensemble.fieldCapacity = [ 0.5, 0.5, 0.5 ]; % location-specific fix parameter values PARA.location.initial_altitude = PARA.ensemble.initial_altitude(index); PARA.soil.externalWaterFlux = PARA.ensemble.external_water_flux(index); - PARA.soil.rootDepth = PARA.ensemble.rootDetph(index); + PARA.soil.rootDepth = PARA.ensemble.rootDepth(index); PARA.soil.fieldCapacity= PARA.ensemble.fieldCapacity(index); % location-specific dynamic auxiliary variables PARA.location.area = PARA.ensemble.area(index); @@ -114,9 +114,9 @@ depth_xice_T vwc_xice_T 0.20 0.05 1 natPor;... 9.0+elevation_T 0.30 0.70 0.00 1 0.30 ] } ); - PARA.soil.layer_properties = { stratigraphyMap{'CENTER'}, ... - stratigraphyMap{'RIM'}, ... - stratigraphyMap{'TROUGH'} }; + PARA.soil.layer_properties = { stratigraphyMap('CENTER'), ... + stratigraphyMap('RIM'), ... + stratigraphyMap('TROUGH') }; PARA.soil.layer_properties = PARA.soil.layer_properties{index}; diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 3d38af2..601d2cf 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -179,15 +179,15 @@ %------------------------------------------------------------------ - disp([datestr(now,'yyyy-mm-dd HH:MM:SS'),': at ',datestr(t), ', Average timestep: ', num2str(TEMPORARY.timestep_out), ' seconds']) + disp([datestr(now,'yyyy-mm-dd HH:MM:SS'),': at ', datestr(t), ', Average timestep: ', num2str(TEMPORARY.timestep_out), ' seconds']) TEMPORARY.outputTime=round((TEMPORARY.outputTime+PARA.technical.outputTimestep)./PARA.technical.outputTimestep).*PARA.technical.outputTimestep; %write output files if round((t-TEMPORARY.saveTime).*48)==0 - iSaveOUT([ saveDir '/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) - iSaveState([ saveDir '/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) - iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); + iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_output' datestr(t,'yyyy') '.mat' ], OUT); + iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_finalState' datestr(t,'yyyy') '.mat' ], T, wc, t, SEB, PARA, GRID); + iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_altitudes_vs_time_' datestr(t,'yyyy') '.png' ], OUT, PARA ); OUT = generateOUT(); TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(datestr(t,'mm')), str2num(datestr(t,'dd')), str2num(datestr(t,'HH')), str2num(datestr(t,'MM')), 0); end From 0fbfbca145490b11edff0264a53d8d24e7c1f9ea Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Tue, 6 Mar 2018 17:16:17 +0100 Subject: [PATCH 28/45] bugfix continued. --- .../updateGRID_infiltration.m | 2 +- modules/cryoGridTechnical/loadSoilTypes.m | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m index 81afc06..ae7c110 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m @@ -64,7 +64,7 @@ GRID.soil.cT_natPor = [ GRID.soil.cT_natPor(1); GRID.soil.cT_natPor ]; % take natPor of cell below GRID.soil.cT_actPor = [ 1; GRID.soil.cT_actPor ]; % set actual porosity to 1 GRID.soil.cT_mineral = [ 0 ; GRID.soil.cT_mineral ]; - GRID.soil.cT_soilType = [ 1; GRID.soil.cT_soilType]; % assume sand as soil type for water cell + GRID.soil.cT_soilType = [ 3; GRID.soil.cT_soilType]; % soilType 3 = pond (sand freeze curve, field cap =0 ) GRID.soil.excessGroundIce = [ 0 ; GRID.soil.excessGroundIce ]; diff --git a/modules/cryoGridTechnical/loadSoilTypes.m b/modules/cryoGridTechnical/loadSoilTypes.m index c074b1f..6a5e4f6 100644 --- a/modules/cryoGridTechnical/loadSoilTypes.m +++ b/modules/cryoGridTechnical/loadSoilTypes.m @@ -2,6 +2,5 @@ % specify one soil type per row: residualWC [%], fieldCapacity [%], alpha [1/m], n PARA.soil.soilTypes = [ [ 0.00, PARA.soil.fieldCapacity, 4.00, 2.0 ]; ... % sand - [ 0.05, PARA.soil.fieldCapacity, 0.65, 1.7 ] ]; % silt - -% JAN: additional type for water? [ 0.00, 1.0, 4.00, 2.0 ] + [ 0.05, PARA.soil.fieldCapacity, 0.65, 1.7 ]; ... % silt + [ 0.00, 0.00 , 4.00, 2.0 ] ]; % pond (freeze curve of sand but fieldCapacity = 0) \ No newline at end of file From f96b87b65878c417d2c6a7712646679b4a896f67 Mon Sep 17 00:00:00 2001 From: Jan Nitzbon Date: Thu, 8 Mar 2018 17:06:03 +0100 Subject: [PATCH 29/45] bugfix: vectors with lateral water fluxes are always reinitialized to zero --- CryoGrid3_xice_mpi.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 4e7c439..b2451c9 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -356,6 +356,7 @@ % heat exchange module if PARA.modules.exchange_heat labBarrier(); + heat_fluxes = zeros( number_of_realizations, 1); % check preconditions precondition_heatExchange = true; %no specific conditions so far if precondition_heatExchange @@ -363,7 +364,6 @@ disp('sync - exchanging heat'); % calculate lateral heat fluxes dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] - heat_fluxes = zeros( numlabs, 1); PACKAGE_heatExchange.T = T; PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; PACKAGE_heatExchange.k_cTgrid = k_cTgrid; @@ -386,13 +386,13 @@ % water exchange module if PARA.modules.exchange_water labBarrier(); + water_fluxes = zeros( number_of_realizations, 1 ); % in [m/s] % check preconditions precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); if precondition_waterExchange % WRAPPER disp('sync - exchanging water'); % calculate lateral water fluxes - water_fluxes = nan( number_of_realizations, 1 ); % in [m/s] PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); @@ -405,7 +405,7 @@ if j~=index PACKAGE_waterExchange_j = labReceive(j, 2); % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) - water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); % matrix containing all fluxes in [m/s] scaled to row index + water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); end end % for debugging: print water flux per column From 04be7d6c2e898c0f000b2f2295edc3c293b0559f Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Tue, 20 Mar 2018 12:45:19 +0100 Subject: [PATCH 30/45] extended for setting lake - nonlake, and several further fixes to get model runing with FLAKE coupled (so far only ok for lake depth 0m) --- CryoGrid3_xice_mpi.m | 62 +++++++++++++----- add_modules.m | 4 +- .../surfaceEnergyBalanceInfiltration.m | 9 ++- .../updateGRID_excessiceInfiltration2.m | 4 +- ...izeLAKE.m => initializeLAKE_version_Jan.m} | 0 modules/cryoGridLake/initializeLAKE.m | 3 +- .../cryoGridLateral/get_parallel_variables.m | 64 ++++++++++++------- modules/cryoGridSnow/updateGRID_snow.m | 2 +- 8 files changed, 97 insertions(+), 51 deletions(-) rename modules/cryoGridInitialize/{initializeLAKE.m => initializeLAKE_version_Jan.m} (100%) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index cba143a..ee40142 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -5,6 +5,8 @@ % Developed by: S. Westermann and M. Langer 2015 % % ------------------------------------------------------------------------- + clear all + close all delete(gcp('nocreate')) % useful to restart from a crash @@ -13,6 +15,7 @@ %dbstop if error; number_of_realizations=2; +debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) if number_of_realizations>1 parpool(number_of_realizations); @@ -91,7 +94,7 @@ PARA.water.rs=0.; % surface resistance -> should be 0 for water %tsvd PARA.water.z0=1e-3; % roughness length surface [m] % JAN: value for summer / vegetation -%PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m version Flake +%tsvd PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m version Flake PARA.water.extinction=1.2; % light extinction coefficient of water PARA.water.depth=1.; PARA.water.fetch=20; @@ -106,7 +109,7 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.starttime=datenum(1979, 6, 10); % starttime of the simulation - if empty start from first value of time series PARA.technical.endtime=datenum(1980, 7, 1); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds @@ -135,7 +138,13 @@ else PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; end - +%tsvd + PARA.location.latitude = 72.376; % [deg] < - + PARA.location.longitude = 126.491; % [deg] < - + %PARA.location.GridCellSize = 1e6; % [m^2] < - + %PARA.location.TileFraction = 1e-2; + % parameters related to the site location + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] PARA.Tinitial = [ -2 5 ;... 0 0 ;... @@ -157,17 +166,23 @@ PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs PARA.modules.xice=1; % true if thaw subsicdence is enabled PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) - - if PARA.modules.lateral - % switches for lateral processes - PARA.modules.exchange_heat = 1; - PARA.modules.exchange_water = 1; - PARA.modules.exchange_snow = 1; - - %---------overwrites variables for each realization-------------------- +%tsvd extended for lateral switched off + if ~PARA.modules.lateral + PARA.modules.exchange_heat = 0; + PARA.modules.exchange_water = 0; + PARA.modules.exchange_snow = 0; + PARA.snow.maxSnow= [] ; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + % in par mode this is replaced by PARA.ensemble.immobile_snow_height + elseif PARA.modules.lateral + % switches for lateral processes + PARA.modules.exchange_heat = 1; %zzz for testing switching off of lateral exchange, set to 1 afterwards! + PARA.modules.exchange_water = 1; + PARA.modules.exchange_snow = 1; + + %---------overwrites variables for each realization-------------------- % this function must define everything that is realization-specific or dependent of all realizations - PARA = get_parallel_variables( PARA ); - end + PARA = get_parallel_variables( PARA ); + end % ------make output directory (name depends on parameters) ---------------- run_number= sprintf( 'testrunMPI_POOL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_realization%d' , ... @@ -246,6 +261,13 @@ %_________________________________________________________________________I while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) @@ -339,7 +366,7 @@ %tsvd version Flake [GRID, PARA, wc] = excessGroundIce(T, GRID, PARA); % assure wc has correct length wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); -%tsvd wc( end-sum(GRID.soil.cT_domain)+1 : end ); %tsvd make vector dims consistent +%tsvd wc( end-sum(GRID.soil.cT_domain)+1 : end ); % make vector dims consistent elseif PARA.modules.xice && PARA.modules.infiltration [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); %tsvd [GRID, PARA, wc] = excessGroundIceInfiltration(T, wc, GRID, PARA); @@ -358,11 +385,12 @@ %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time if ~PARA.modules.lateral PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; - if isempty( PARA.snow.maxSnow ) + if isempty( PARA.snow.maxSnow ) + %tsvd if isempty( PARA.ensemble.immobile_snow_height ) PARA.location.absolute_maxSnow_altitude = []; else PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; - end + end end %------- water balance calculations ----------------------------------- diff --git a/add_modules.m b/add_modules.m index 8e6b4cf..1c8647d 100644 --- a/add_modules.m +++ b/add_modules.m @@ -3,8 +3,8 @@ % clearvars -except paraFromFile %added by JAN to enable running with or without config file from same script % end -clear all -close all +%clear all +%close all profile off diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m index 4b03429..f5cebfd 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m @@ -58,16 +58,15 @@ -%calculate ET -if PARA.modules.infiltration - +%calculate ET + %snow cover or uppermost grid cell frozen --> no ET %tsvd added from version FLAKE -if PARA.soil.infiltration +if PARA.modules.infiltration if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || ~isempty(GRID.lake.water.cT_domain_ub) % islake ... %snow cover or uppermost grid cell frozen --> no ET tsvd: addition case LAKE added Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); % unfrozen water body at surface - elseif GRID.lake.unfrozenWaterSurface + elseif GRID.lake.unfrozenWaterSurface % zzz check Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); dwc_dt(1)=-Qe./L; %in m water per sec, this can be evaporation or condensation diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m index e3ee2fe..a32d15d 100644 --- a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m @@ -25,8 +25,8 @@ % % K domains not implemented so far %tsvd - GRID.lake.water.cT_domain(max([GRID.air.cT_domain_lb+1 GRID.ice.cT_domain_lb+1]) : GRID.soil.cT_domain_ub-1) = 1; - GRID.lake.water.K_domain(max([GRID.air.K_domain_lb+1 GRID.ice.K_domain_lb+1]) : GRID.soil.K_domain_ub-1) = 1; + GRID.lake.water.cT_domain(max([GRID.air.cT_domain_lb+1 GRID.lake.ice.cT_domain_lb+1]) : GRID.soil.cT_domain_ub-1) = 1; + GRID.lake.water.K_domain(max([GRID.air.K_domain_lb+1 GRID.lake.ice.K_domain_lb+1]) : GRID.soil.K_domain_ub-1) = 1; [GRID.lake.water.cT_domain_lb GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); [GRID.lake.water.K_domain_lb GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); diff --git a/modules/cryoGridInitialize/initializeLAKE.m b/modules/cryoGridInitialize/initializeLAKE_version_Jan.m similarity index 100% rename from modules/cryoGridInitialize/initializeLAKE.m rename to modules/cryoGridInitialize/initializeLAKE_version_Jan.m diff --git a/modules/cryoGridLake/initializeLAKE.m b/modules/cryoGridLake/initializeLAKE.m index b76c5c4..60a6738 100644 --- a/modules/cryoGridLake/initializeLAKE.m +++ b/modules/cryoGridLake/initializeLAKE.m @@ -1,5 +1,7 @@ function [FLAKE GRID] = initializeLAKE(GRID, PARA); +GRID.lake.unfrozenWaterSurface = false; % zzz needed? +GRID.lake.residualWater = 0; % the water content stored "mixed" cells of air and water if a water body is present %---- flake initialization ------------------------------------------------ FLAKE.t_snow_n_flk=0+273.15; @@ -22,7 +24,6 @@ FLAKE.fetch=100; FLAKE.depth_w=PARA.water.depth; - FLAKE.d_h_ice_dt = 0; FLAKE.q_ice_water = 0; FLAKE.extincoef_water_typ=PARA.water.extinction; diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index 391bfc5..86f463a 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -13,7 +13,8 @@ PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 % topographical relations - PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + %tsvd PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + PARA.ensemble.initial_altitude = [20.0, 20.0]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids PARA.ensemble.altitude = PARA.ensemble.initial_altitude; PARA.ensemble.surface_altitude = PARA.ensemble.initial_altitude; @@ -51,29 +52,46 @@ PARA.location.absolute_maxSnow_altitude = [max( PARA.ensemble.altitude ) + PARA.snow.relative_maxSnow]; % different stratigraphies - PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % center stratigraphy without excess ice - 1.0 0.5 0.5 0.00 1 0.50 ;... - 10.0 0.25 0.75 0.00 1 0.25 ] , ... - [0.0 0.5 0.5 0.00 1 0.50;... % rim stratigraphy with excess ice - 0.7 0.8 0.2 0.00 1 0.50;... - 10.0 0.25 0.75 0.00 1 0.25 ], ... - [0.0 0.5 0.5 0.00 1 0.50;... % trough stratigraphy with excess ice - 0.1 0.8 0.2 0.00 1 0.50;... - 10.0 0.25 0.75 0.00 1 0.25 ]}; - - PARA.soil.layer_properties = PARA.soil.layer_properties{index}; - - - +% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % center stratigraphy without excess ice +% 1.0 0.5 0.5 0.00 1 0.50 ;... +% 10.0 0.25 0.75 0.00 1 0.25 ] , ... +% [0.0 0.5 0.5 0.00 1 0.50;... % rim stratigraphy with excess ice +% 0.7 0.8 0.2 0.00 1 0.50;... +% 10.0 0.25 0.75 0.00 1 0.25 ], ... +% [0.0 0.5 0.5 0.00 1 0.50;... % trough stratigraphy with excess ice +% 0.1 0.8 0.2 0.00 1 0.50;... +% 10.0 0.25 0.75 0.00 1 0.25 ]}; + +% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) +% 1.0 0.5 0.5 0.00 1 0.50 ;... +% 10.0 0.25 0.75 0.00 1 0.25 ] , ... +% [0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (identical to lake stratigraphy) +% 1.0 0.5 0.5 0.00 1 0.50 ;... +% 10.0 0.25 0.75 0.00 1 0.25 ]}; + PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) + 0.02 0.5 0.5 0.00 1 0.50 ;... + 0.04 0.5 0.5 0.00 1 0.50 ;... + 0.06 0.5 0.5 0.00 1 0.50 ;... + 0.08 0.5 0.5 0.00 1 0.50 ;... + 0.10 0.5 0.5 0.00 1 0.50 ;... + 0.12 0.5 0.5 0.00 1 0.50 ;... + 0.14 0.5 0.5 0.00 1 0.50 ;... + 0.16 0.5 0.5 0.00 1 0.50 ;... + 0.18 0.5 0.5 0.00 1 0.50 ;... + 0.20 0.5 0.5 0.00 1 0.50 ]}; + PARA.soil.layer_properties = PARA.soil.layer_properties{index}; + % different initial conditions - PARA.Tinitial = [-5 5 5 5;... - 0 -5 -5 -5;... - 1 -5 -5 -5;... - 10 -8 -8 -8;... - 20 -10 -10 -10;... - 100 -10 -10 -10;... - 2000 10 10 10]; +% PARA.Tinitial = [-5 5 5;... +% 0 -5 -5;... +% 1 -5 -5;... +% 10 -8 -8;... +% 20 -10 -10;... +% 100 -10 -10;... +% 2000 10 10]; PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; - + + PARA.water.depth = [0.1,0.1]; + PARA.water.depth = PARA.water.depth(index); end diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index aac34c3..d938a73 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -25,6 +25,7 @@ % -------- update K grid ------------------------------------- GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ); + %tsvd GRID.general.K_grid(GRID.snow.K_domain_ub)=-1.*( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ); T(GRID.snow.cT_domain_ub)=T(GRID.air.cT_domain_lb); end @@ -32,7 +33,6 @@ else %snow exists check_change=false; - GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) -... ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); %updates the position of the uppermost snow grid cell From 48153834eb9ed6193127dc63fa3758e09e3e7e7e Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Tue, 20 Mar 2018 15:03:14 +0100 Subject: [PATCH 31/45] occurences of GRID.water. replaced by GRID.water.lake. --- .../updateGRID_excessiceInfiltration2.m | 28 ++++---- .../cryoGridLateral/get_parallel_variables.m | 70 ++++++++++++------- modules/cryoGridTechnical/makeGrids.m | 4 +- .../cryoGridTechnical/sum_up_output_store.m | 5 +- 4 files changed, 64 insertions(+), 43 deletions(-) diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m index a32d15d..517159f 100644 --- a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m @@ -1,5 +1,7 @@ function [GRID] = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID) +%tsvd GRID.lake.water.cT/Kdomain replaced by GRID.lake.water.* + % pass excess meltwater to storage variable GRID.lake.residualWater = meltwaterGroundIce; @@ -7,20 +9,20 @@ if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 % upper soil cell pure air/water % general water body extent cT_waterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6; - GRID.lake.cT_domain(logical(GRID.air.cT_domain+GRID.snow.cT_domain)) = 0; - GRID.lake.cT_domain(GRID.soil.cT_domain) = cT_waterBody; - [GRID.lake.cT_domain_lb, GRID.lake.cT_domain_ub] = LayerIndex(GRID.lake.cT_domain); - GRID.lake.K_domain(logical(GRID.air.K_domain+GRID.snow.K_domain)) = 0; - GRID.lake.K_domain(GRID.lake.cT_domain_ub:GRID.lake.cT_domain_lb+1) = 1; - GRID.lake.K_domain(GRID.lake.cT_domain_lb+2:end) = 0; - [GRID.lake.K_domain_lb, GRID.lake.K_domain_ub] = LayerIndex(GRID.lake.K_domain); + GRID.lake.water.cT_domain(logical(GRID.air.cT_domain+GRID.snow.cT_domain)) = 0; + GRID.lake.water.cT_domain(GRID.soil.cT_domain) = cT_waterBody; + [GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); + GRID.lake.water.K_domain(logical(GRID.air.K_domain+GRID.snow.K_domain)) = 0; + GRID.lake.water.K_domain(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb+1) = 1; + GRID.lake.water.K_domain(GRID.lake.water.cT_domain_lb+2:end) = 0; + [GRID.lake.water.K_domain_lb, GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); % % distinction frozen and unfrozen parts % unfrozenWaterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6 & T(GRID.soil.cT_domain)>0; % frozenWaterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6 & T(GRID.soil.cT_domain)<=0; -% GRID.lake.water.cT_domain = GRID.lake.cT_domain & T>0; +% GRID.lake.water.cT_domain = GRID.lake.water.cT_domain & T>0; % [GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); -% GRID.lake.ice.cT_domain = GRID.lake.cT_domain & T<=0; +% GRID.lake.ice.cT_domain = GRID.lake.water.cT_domain & T<=0; % [GRID.lake.ice.cT_domain_lb, GRID.lake.ice.cT_domain_ub] = LayerIndex(GRID.lake.ice.cT_domain); %these might be two domains % % K domains not implemented so far @@ -32,10 +34,10 @@ [GRID.lake.water.K_domain_lb GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); else - GRID.lake.cT_domain = false(size(GRID.general.cT_grid)); - GRID.lake.K_domain = false(size(GRID.general.K_grid)); - [GRID.lake.cT_domain_lb, GRID.lake.cT_domain_ub] = LayerIndex(GRID.lake.cT_domain); - [GRID.lake.K_domain_lb, GRID.lake.K_domain_ub] = LayerIndex(GRID.lake.K_domain); + GRID.lake.water.cT_domain = false(size(GRID.general.cT_grid)); + GRID.lake.water.K_domain = false(size(GRID.general.K_grid)); + [GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); + [GRID.lake.water.K_domain_lb, GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); end end \ No newline at end of file diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index 86f463a..4798020 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -34,7 +34,7 @@ % parameters related to snow exchange %PARA.ensemble.snow_diffusivity = PARA.snow.diffusivity; %PARA.ensemble.relative_max_snow_height = 0.2; - PARA.ensemble.immobile_snow_height = [0.1, 0.1 ]; %, 0.2 ]; %in m %this replaces PARA.snow.maxSnow ? + PARA.ensemble.immobile_snow_height = [0.1, 0.1 ]; %, 0.2 ]; %in m %this replaces PARA.snow.maxSnow ? zzz PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.altitude, PARA.ensemble.weight); PARA.ensemble.snow_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); @@ -62,36 +62,54 @@ % 0.1 0.8 0.2 0.00 1 0.50;... % 10.0 0.25 0.75 0.00 1 0.25 ]}; -% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) -% 1.0 0.5 0.5 0.00 1 0.50 ;... -% 10.0 0.25 0.75 0.00 1 0.25 ] , ... -% [0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (identical to lake stratigraphy) -% 1.0 0.5 0.5 0.00 1 0.50 ;... -% 10.0 0.25 0.75 0.00 1 0.25 ]}; - PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) - 0.02 0.5 0.5 0.00 1 0.50 ;... - 0.04 0.5 0.5 0.00 1 0.50 ;... - 0.06 0.5 0.5 0.00 1 0.50 ;... - 0.08 0.5 0.5 0.00 1 0.50 ;... - 0.10 0.5 0.5 0.00 1 0.50 ;... - 0.12 0.5 0.5 0.00 1 0.50 ;... - 0.14 0.5 0.5 0.00 1 0.50 ;... - 0.16 0.5 0.5 0.00 1 0.50 ;... - 0.18 0.5 0.5 0.00 1 0.50 ;... - 0.20 0.5 0.5 0.00 1 0.50 ]}; + PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) + 1.0 0.5 0.5 0.00 1 0.50 ;... + 10.0 0.25 0.75 0.00 1 0.25 ] , ... + [0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (identical to lake stratigraphy) + 1.0 0.5 0.5 0.00 1 0.50 ;... + 10.0 0.25 0.75 0.00 1 0.25 ]}; +% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) +% 0.02 0.5 0.5 0.00 1 0.50 ;... +% 0.04 0.5 0.5 0.00 1 0.50 ;... +% 0.06 0.5 0.5 0.00 1 0.50 ;... +% 0.08 0.5 0.5 0.00 1 0.50 ;... +% 0.10 0.5 0.5 0.00 1 0.50 ;... +% 0.12 0.5 0.5 0.00 1 0.50 ;... +% 0.14 0.5 0.5 0.00 1 0.50 ;... +% 0.16 0.5 0.5 0.00 1 0.50 ;... +% 0.18 0.5 0.5 0.00 1 0.50 ;... +% 0.20 0.5 0.5 0.00 1 0.50 ] , ... +% +% [0.0 0.5 0.5 0.00 1 0.50 ;... % lab 2 +% 0.02 0.5 0.5 0.00 1 0.50 ;... +% 0.04 0.5 0.5 0.00 1 0.50 ;... +% 0.06 0.5 0.5 0.00 1 0.50 ;... +% 0.08 0.5 0.5 0.00 1 0.50 ;... +% 0.10 0.5 0.5 0.00 1 0.50 ;... +% 0.12 0.5 0.5 0.00 1 0.50 ;... +% 0.14 0.5 0.5 0.00 1 0.50 ;... +% 0.16 0.5 0.5 0.00 1 0.50 ;... +% 0.18 0.5 0.5 0.00 1 0.50 ;... +% 0.20 0.5 0.5 0.00 1 0.50 ] }; PARA.soil.layer_properties = PARA.soil.layer_properties{index}; % different initial conditions -% PARA.Tinitial = [-5 5 5;... -% 0 -5 -5;... -% 1 -5 -5;... -% 10 -8 -8;... -% 20 -10 -10;... -% 100 -10 -10;... -% 2000 10 10]; + PARA.Tinitial = [-5 5 5;... + 0 -5 -5;... + 1 -5 -5;... + 10 -8 -8;... + 20 -10 -10;... + 100 -10 -10;... + 2000 10 10]; +% PARA.Tinitial = [-5 10 10;... this profile causes problems! +% 0 0 0;... +% 5 -5 -5;... +% 20 -10 -10;... +% 100 -10 -10;... +% 2000 10 10]; PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; - PARA.water.depth = [0.1,0.1]; + PARA.water.depth = [0.,1.]; PARA.water.depth = PARA.water.depth(index); end diff --git a/modules/cryoGridTechnical/makeGrids.m b/modules/cryoGridTechnical/makeGrids.m index 67a627b..0c338d7 100644 --- a/modules/cryoGridTechnical/makeGrids.m +++ b/modules/cryoGridTechnical/makeGrids.m @@ -4,7 +4,7 @@ GRID.snow.snowCellSize=PARA.technical.SWEperCell/(PARA.snow.rho_snow/PARA.constants.rho_w); GRID.snow.snowGrid=[-1.*(PARA.technical.maxSWE./(PARA.technical.SWEperCell)+2).*GRID.snow.snowCellSize:GRID.snow.snowCellSize:-GRID.snow.snowCellSize]'; %tsvd added - GRID.lake.water.waterGrid=[0:0.02:PARA.water.depth-0.02]'; %with water (it is recommended to use a grid resolution of about 2cm) +GRID.lake.water.waterGrid=[0:0.02:PARA.water.depth-0.02]'; %with water (it is recommended to use a grid resolution of about 2cm) %GRID.lake.water.waterGrid=[]'; %no water if ~isempty(GRID.lake.water.waterGrid) GRID.soil.soilGrid=PARA.technical.subsurfaceGrid + (2*GRID.lake.water.waterGrid(end)-GRID.lake.water.waterGrid(end-1)); @@ -13,7 +13,7 @@ end %tsvd K_grid =[GRID.snow.snowGrid; GRID.soil.soilGrid]; %grid on which the conductivty information lives (edges of grid cells) - K_grid =[GRID.snow.snowGrid; GRID.lake.water.waterGrid; GRID.soil.soilGrid]; %grid on which the conductivty information lives (edges of grid cells) +K_grid =[GRID.snow.snowGrid; GRID.lake.water.waterGrid; GRID.soil.soilGrid]; %grid on which the conductivty information lives (edges of grid cells) cT_grid=(K_grid(1:end-1)+K_grid(2:end))/2; %grid on which heat capacity and temperature information lives (midpoints of grid cells) cT_delta=(-cT_grid(1:end-1,1)+cT_grid(2:end,1)); K_delta=(-K_grid(1:end-1,1)+K_grid(2:end,1)); diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 96214ea..2adcf1b 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -1,5 +1,6 @@ function [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc, timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, run_number, water_fluxes, snow_fluxes, heat_fluxes) +%tsvd GRID.lake.cT_domain replaced by GRID.lake.water.cT_domain TEMPORARY.timestep_sum=TEMPORARY.timestep_sum+(timestep*24*3600)*timestep; TEMPORARY.T_sum=TEMPORARY.T_sum+T.*timestep; @@ -70,8 +71,8 @@ % related to soil OUT.soil.topPosition=[OUT.soil.topPosition; -GRID.general.K_grid(GRID.soil.cT_domain_ub)]; - if ~isempty( GRID.lake.cT_domain_ub ) - OUT.soil.lakeFloor = [OUT.soil.lakeFloor; - GRID.general.K_grid(GRID.lake.cT_domain_lb+1) ]; + if ~isempty( GRID.lake.water.cT_domain_ub ) + OUT.soil.lakeFloor = [OUT.soil.lakeFloor; - GRID.general.K_grid(GRID.lake.water.cT_domain_lb+1) ]; else OUT.soil.lakeFloor = [OUT.soil.lakeFloor; NaN]; end From 32f10295c54cb7fc44c2f16f50f7c919418ecfbb Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Tue, 20 Mar 2018 15:37:04 +0100 Subject: [PATCH 32/45] makeGrids modfied --- modules/cryoGridTechnical/makeGrids.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cryoGridTechnical/makeGrids.m b/modules/cryoGridTechnical/makeGrids.m index 0c338d7..e22e1e5 100644 --- a/modules/cryoGridTechnical/makeGrids.m +++ b/modules/cryoGridTechnical/makeGrids.m @@ -34,7 +34,7 @@ %set soil grid GRID.soil.cT_domain= false(size(GRID.general.cT_grid)); %tsvd GRID.soil.cT_domain(GRID.general.cT_grid>0)=1; - GRID.soil.cT_domain(end-length(GRID.soil.soilGrid)+2:end)=1; %required if there is a lake on top +GRID.soil.cT_domain(end-length(GRID.soil.soilGrid)+2:end)=1; %required if there is a lake on top [GRID.soil.cT_domain_lb, GRID.soil.cT_domain_ub] = LayerIndex(GRID.soil.cT_domain); GRID.soil.K_domain= false(size(GRID.general.K_grid)); GRID.soil.K_domain(GRID.soil.cT_domain_ub:end)=1; From 3f61bcd7ef5f23f54d3a4c1f9c096e31cd3e720a Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Thu, 22 Mar 2018 17:11:19 +0100 Subject: [PATCH 33/45] checkout of pervious version of get_parallel_variables --- .../cryoGridLateral/get_parallel_variables.m | 107 +++--------------- 1 file changed, 16 insertions(+), 91 deletions(-) diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index bcbf653..4798020 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -2,47 +2,32 @@ index = labindex; - % auxiliary calculations for geometry - % input: typical total polygon area + areal weights (as integers) of center/rim/troughs - area_tot = 100.0; % typical area of polygon center [Cresto Aleina / Muster ] - PARA.ensemble.weight = [3, 6, 1];%[2, 1, 1]; - - % areas - PARA.ensemble.area = PARA.ensemble.weight ./ sum(PARA.ensemble.weight) .* area_tot ; % in m^2 - area_C = PARA.ensemble.area(1); - area_R = PARA.ensemble.area(2); - area_T = PARA.ensemble.area(3); + % auxiliary calculations for circular geometry + diameter=10; % in [m] + area = pi.*(diameter./2)^2; % in [m^2] + perimeter = 2*pi.*(diameter./2); % in [m] - % distances - distance_CR = (0.5.*area_C + 0.25.*area_R) ./ sqrt( area_tot ); % in m - distance_RT = (0.5.*area_T + 0.25.*area_R) ./ sqrt( area_tot ); - - % perimeters % assuming hexagonal shapes of centers and polygons - perimeter_CR = 6 .* sqrt( 2 .* area_C ./ (3 .* sqrt(3) ) ); % assuming hexagonal shape of center - %2 .* pi .* ( diameter_C ./2); % assuming circular shape of polygons - perimeter_RT = 6. * sqrt( 2 .* (area_C+area_R) ./ (3 .* sqrt(3) ) ); - - % geometric relations - PARA.ensemble.distanceBetweenPoints= [ 0, distance_CR, 0; distance_CR, 0, distance_RT; 0, distance_RT, 0 ]; %diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members - A = double( PARA.ensemble.distanceBetweenPoints > 0 ); % connectivity of the networ (auxiliary) - + PARA.ensemble.distanceBetweenPoints= diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members + PARA.ensemble.weight = [1, 1];%[2, 1, 1]; + PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 + % topographical relations %tsvd PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids PARA.ensemble.initial_altitude = [20.0, 20.0]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids PARA.ensemble.altitude = PARA.ensemble.initial_altitude; PARA.ensemble.surface_altitude = PARA.ensemble.initial_altitude; - PARA.ensemble.soil_altitude = PARA.ensemble.initial_altitude; - + % parameters related to heat exchange - PARA.ensemble.thermal_contact_length = [0, perimeter_CR, 0; perimeter_CR, 0, perimeter_RT; 0, perimeter_RT, 0 ]; % [ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; % + PARA.ensemble.thermal_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); % [ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; % % parameters related to water exchange - PARA.ensemble.hydraulic_conductivity= PARA.soil.hydraulic_conductivity .* A;%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; %in m/sec % [Roth: 1e-5 for saturated silt, 2.2e-5 for saturated sand] - PARA.ensemble.water_table_altitude = [NaN NaN NaN]; %initialize somehow; + PARA.ensemble.external_water_flux=[0, 0 ] ; % 0]; %in m/day + PARA.ensemble.hydraulic_conductivity= PARA.soil.hydraulic_conductivity * ( ones(numlabs) - eye(numlabs ) );%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; %in m/sec % [Roth: 1e-5 for saturated silt, 2.2e-5 for saturated sand] + PARA.ensemble.water_table_altitude = PARA.ensemble.altitude; %initialize somehow; %PARA.ensemble.max_water_flux= [0 0]; %in m water equivalent - PARA.ensemble.hydraulic_contact_length = PARA.ensemble.thermal_contact_length;%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; + PARA.ensemble.hydraulic_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) );%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; PARA.ensemble.active_layer_depth_altitude = [NaN NaN NaN]; PARA.ensemble.hydraulicDistance = PARA.ensemble.distanceBetweenPoints; @@ -51,18 +36,11 @@ %PARA.ensemble.relative_max_snow_height = 0.2; PARA.ensemble.immobile_snow_height = [0.1, 0.1 ]; %, 0.2 ]; %in m %this replaces PARA.snow.maxSnow ? zzz PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.altitude, PARA.ensemble.weight); - PARA.ensemble.snow_contact_length = PARA.ensemble.thermal_contact_length; + PARA.ensemble.snow_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); - % parameters related to infiltration scheme - PARA.ensemble.external_water_flux=[0, 0, -5e-3 ] ; % 0]; %in m/day - PARA.ensemble.rootDepth = [ 0.2, 0.1, 0.2 ]; - PARA.ensemble.fieldCapacity = [ 0.5, 0.5, 0.5 ]; - - % location-specific fix parameter values + % location-specific static PARA.location.initial_altitude = PARA.ensemble.initial_altitude(index); PARA.soil.externalWaterFlux = PARA.ensemble.external_water_flux(index); - PARA.soil.rootDepth = PARA.ensemble.rootDepth(index); - PARA.soil.fieldCapacity= PARA.ensemble.fieldCapacity(index); % location-specific dynamic auxiliary variables PARA.location.area = PARA.ensemble.area(index); PARA.location.altitude = PARA.ensemble.altitude(index); @@ -73,7 +51,6 @@ PARA.location.absolute_maxWater_altitude = [max( PARA.ensemble.altitude ) + PARA.soil.relative_maxWater]; PARA.location.absolute_maxSnow_altitude = [max( PARA.ensemble.altitude ) + PARA.snow.relative_maxSnow]; - % different stratigraphies % PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % center stratigraphy without excess ice % 1.0 0.5 0.5 0.00 1 0.50 ;... @@ -135,56 +112,4 @@ PARA.water.depth = [0.,1.]; PARA.water.depth = PARA.water.depth(index); -% ======= -% %tsvd Jan's latest implementations: -% depth_xice_C = 0.9; -% vwc_xice_C = 0.65; -% depth_xice_R = 0.6; -% vwc_xice_R = 0.75; -% depth_xice_T = 0.3; -% vwc_xice_T = 0.90; -% natPor = 0.5; -% stratigraphyMap= containers.Map( { 'DEFAULT', 'WET', 'DRY', 'CENTER', 'RIM', 'TROUGH' }, ... -% { [ 0.0 0.40 0.10 0.15 1 0.75;... -% 0.15 0.65 0.30 0.05 1 0.65;... -% 0.9 0.65 0.30 0.05 1 0.65;... -% 9.0 0.30 0.70 0.00 1 0.30 ], ... -% [ 0.0 0.85 0.00 0.15 1 0.85;... -% 0.15 0.75 0.2 0.05 1 0.75;... -% 0.30 0.65 0.3 0.05 2 0.65;... -% 0.9 0.65 0.3 0.05 1 0.65;... -% 9.0 0.30 0.70 0.00 1 0.30 ], ... -% [ 0.0 0.50 0.10 0.15 1 0.75;... -% 0.1 0.65 0.30 0.05 2 0.65;... -% 0.9 0.65 0.30 0.05 1 0.65;... -% 9.0 0.30 0.70 0.00 1 0.30 ],... -% [ 0.0 0.85 0.00 0.15 1 0.85;... -% 0.15 0.75 0.20 0.05 1 0.75;... -% 0.30 0.65 0.30 0.05 2 0.65;... -% depth_xice_C vwc_xice_C 0.30 0.05 1 natPor;... -% 9.0 0.30 0.70 0.00 1 0.30 ], ... -% [ 0.0 0.50 0.10 0.15 1 0.75;... -% 0.1 0.65 0.30 0.05 2 0.65;... -% depth_xice_R vwc_xice_R 0.20 0.05 1 natPor;... -% 9.0+elevation_R 0.30 0.70 0.00 1 0.30 ], ... -% [ 0.0 0.40 0.00 0.15 1 0.85;... -% depth_xice_T vwc_xice_T 0.20 0.05 1 natPor;... -% 9.0+elevation_T 0.30 0.70 0.00 1 0.30 ] } ); -% -% PARA.soil.layer_properties = { stratigraphyMap('CENTER'), ... -% stratigraphyMap('RIM'), ... -% stratigraphyMap('TROUGH') }; -% -% PARA.soil.layer_properties = PARA.soil.layer_properties{index}; -% -% % typical profile for beginning of October -% PARA.Tinitial = [ -2 5 ;... -% 0 0 ;... -% 2 -2 ;... -% 5 -7 ;... -% 10 -9 ;... -% 25 -9 ;... -% 100 -8 ;... -% 1100 10.2 ]; % the geothermal gradient for Qgeo=0.05W/m² and K=2.746W/Km is about 18.2 K/km -% end From 075354ee34e95c6d3e803e4ac12e6acfb9f728ad Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Wed, 4 Apr 2018 15:15:59 +0200 Subject: [PATCH 34/45] various fixes applied to prevent problems with updateGRID_snow.m if lateral exchange is switched on (e.g. prevent of snow buildup on lake water), adapting of altitude calculation, and more --- .gitignore | 2 + CryoGrid3_xice_mpi.m | 82 ++++++--- analysis/plot_output.m | 4 +- .../cryoGridLateral/get_parallel_variables.m | 31 ++-- modules/cryoGridSEB/surfaceCondition.m | 78 ++++---- modules/cryoGridSnow/CryoGridSnow.m | 172 +++++++++--------- modules/cryoGridSnow/updateGRID_snow.m | 31 +++- modules/cryoGridTechnical/getAltitude.m | 10 +- modules/cryoGridTechnical/getSoilAltitude.m | 5 +- modules/cryoGridTechnical/makeGrids.m | 1 - .../cryoGridTechnical/sum_up_output_store.m | 6 +- 11 files changed, 248 insertions(+), 174 deletions(-) diff --git a/.gitignore b/.gitignore index 3c80e8c..c1e7d69 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ analysis forcing runs *.asv +*.docx +*.mat diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index b767312..e8a2465 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -8,8 +8,11 @@ clear all close all -delete(gcp('nocreate')) % useful to restart from a crash - + par_mode = 1; % parallel mode off/on + +if(par_mode==1) + delete(gcp('nocreate')) % useful to restart from a crash +end add_modules; %adds required modules %dbstop if error; @@ -17,16 +20,18 @@ number_of_realizations=2; debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) -%tsvd saveDir = '/data/scratch/nitzbon/CryoGrid/CryoGrid3_infiltration_xice_mpi/runs'; +saveDir = './runs'; if number_of_realizations>1 parpool(number_of_realizations); end +%nnn spmd index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run +%nnn index=1 - %---------------define input parameters------------------------------------ +%---------------define input parameters------------------------------------ % here you provide the ground stratigraphy % z w/i m o type porosity @@ -86,7 +91,7 @@ PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] PARA.snow.tau_a=0.008; % [per day] PARA.snow.tau_f=0.24; % [per day] - PARA.snow.relative_maxSnow= [1.0]; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.relative_maxSnow= [0.1]; %ttt maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold PARA.snow.extinction=25.0; % light extinction coefficient of snow %tsvd add lake parameters % parameters related to lake @@ -97,7 +102,7 @@ PARA.water.z0=5e-4; % roughness length surface [m] % JAN: value for summer / vegetation %tsvd PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m version Flake PARA.water.extinction=1.2; % light extinction coefficient of water - PARA.water.depth=1.; + PARA.water.depth=0.; PARA.water.fetch=20; PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 @@ -174,8 +179,8 @@ PARA.forcing.snow_fraction=1; % switches for modules - PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs - PARA.modules.xice=1; % true if thaw subsicdence is enabled + PARA.modules.infiltration=0; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=0; % true if thaw subsicdence is enabled PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) %tsvd extended for lateral switched off if ~PARA.modules.lateral @@ -186,9 +191,9 @@ % in par mode this is replaced by PARA.ensemble.immobile_snow_height elseif PARA.modules.lateral % switches for lateral processes - PARA.modules.exchange_heat = 1; %zzz for testing switching off of lateral exchange, set to 1 afterwards! - PARA.modules.exchange_water = 1; - PARA.modules.exchange_snow = 1; + PARA.modules.exchange_heat = 0; %ttt + PARA.modules.exchange_water = 0; %ttt + PARA.modules.exchange_snow = 0; %ttt %---------overwrites variables for each realization-------------------- % this function must define everything that is realization-specific or dependent of all realizations @@ -248,6 +253,7 @@ BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? +%nnn comment out for single mode... water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index @@ -259,6 +265,7 @@ OUT = generateOUT(); disp('initialization successful'); + %%% nnn iSaveSettings( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_settings.mat'] , FORCING, PARA, GRID) @@ -306,12 +313,33 @@ % timestep in [days] %tsvd if(~debug_mode) - timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... - PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... - PARA.technical.maxTimestep ] ), ... - PARA.technical.minTimestep ] ), ... - TEMPORARY.syncTime-t,... - TEMPORARY.outputTime-t ] ); + + %tsvd new timestep calculation to avoid problems with lateral mode switched off + +% old +% timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... +% PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... +% PARA.technical.maxTimestep ] ), ... +% PARA.technical.minTimestep ] ), ... +% TEMPORARY.syncTime-t,... +% TEMPORARY.outputTime-t ] ); + +% new + if PARA.modules.lateral + timestep = min( [ max( [ min( [ 0.5 * nanmin(GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... + PARA.technical.targetDeltaE .* nanmin(abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... + PARA.technical.maxTimestep ] ), ... + PARA.technical.minTimestep ] ), ... + TEMPORARY.syncTime-t,... + TEMPORARY.outputTime-t ] ); + else + timestep = min( [ max( [ min( [ 0.5 * nanmin(GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... + PARA.technical.targetDeltaE .* nanmin(abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... + PARA.technical.maxTimestep ] ), ... + PARA.technical.minTimestep ] ), ... + TEMPORARY.outputTime-t ] ); + end + else % debug mode timestep = PARA.technical.minTimestep; % use for debugging to avoid NaN... zzz %disp('WARNING: timestep set to minTimestep for debugging') @@ -333,7 +361,7 @@ if max((T<-100))==1; disp('dwd'); end %------- water body module -------------------------------------------- - T = mixingWaterBody(T, GRID); % zzz ok to keep? +%tsvd T = mixingWaterBody(T, GRID); % zzz check whether this is ok to switch off %------- snow cover module -------------------------------------------- [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); @@ -414,7 +442,7 @@ if t==TEMPORARY.syncTime %communication between workers disp('CryoGridLateral: sync - start'); labBarrier(); %common start - PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; %ddd commenting out (here and below) does not help prevent snow grid crash % heat exchange module if PARA.modules.exchange_heat @@ -545,15 +573,19 @@ %------- next time step ----------------------------------------------- t=t+timestep; %---------- sum up + OUTPUT ------------------------------------------- - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes); - - + %nnn + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes); end % save final state and output at t=endtime - iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) - iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) - iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); +%nnn +iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) +%nnn +iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) +%nnn +%iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); + +%nnn end if number_of_realizations>1 diff --git a/analysis/plot_output.m b/analysis/plot_output.m index b04b6b0..54e1c73 100644 --- a/analysis/plot_output.m +++ b/analysis/plot_output.m @@ -9,7 +9,9 @@ %tsvd dirname = '/home/jnitzbon/CryoGrid/github/GITHUB_CryoGrid3_infiltration_xice_mpi/runs/'; %runname = 'testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1.000000_sF1.000000_realization'; dirname = 'E:\CryoGrid3\runs'; - runname = 'testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2'; +% runname = 'testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2'; +%runname = ' TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH1_xW1_xS0_rf1_sf1'; +runname ='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; number_of_realizations = 2; % diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index 4798020..cd5a14c 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -14,7 +14,9 @@ % topographical relations %tsvd PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids - PARA.ensemble.initial_altitude = [20.0, 20.0]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids +% PARA.ensemble.initial_altitude = [20.0, 20.0]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + PARA.ensemble.initial_altitude = [0.0, 0.0]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + PARA.ensemble.altitude = PARA.ensemble.initial_altitude; PARA.ensemble.surface_altitude = PARA.ensemble.initial_altitude; @@ -94,22 +96,23 @@ PARA.soil.layer_properties = PARA.soil.layer_properties{index}; % different initial conditions - PARA.Tinitial = [-5 5 5;... - 0 -5 -5;... - 1 -5 -5;... - 10 -8 -8;... - 20 -10 -10;... - 100 -10 -10;... - 2000 10 10]; -% PARA.Tinitial = [-5 10 10;... this profile causes problems! -% 0 0 0;... -% 5 -5 -5;... -% 20 -10 -10;... -% 100 -10 -10;... -% 2000 10 10]; +% PARA.Tinitial = [-5 5 5;... +% 0 -5 -5;... +% 1 -5 -5;... +% 10 -8 -8;... +% 20 -10 -10;... +% 100 -10 -10;... +% 2000 10 10]; + PARA.Tinitial = [-5 10 10;... this profile can cause model crashes in mpi... + 0 0 0;... + 5 -5 -5;... + 20 -10 -10;... + 100 -10 -10;... + 2000 10 10]; PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; +% PARA.water.depth = [1.,0.]; PARA.water.depth = [0.,1.]; PARA.water.depth = PARA.water.depth(index); end diff --git a/modules/cryoGridSEB/surfaceCondition.m b/modules/cryoGridSEB/surfaceCondition.m index 69a27a4..fd84d3e 100644 --- a/modules/cryoGridSEB/surfaceCondition.m +++ b/modules/cryoGridSEB/surfaceCondition.m @@ -18,42 +18,46 @@ PARA.surf.z0 = PARA.snow.z0; PARA.surf.rs = PARA.snow.rs; -% check if water surface exists and whether it is frozen +% lll comment out this block +% % check if water surface exists and whether it is frozen +% +% elseif GRID.soil.cT_domain(GRID.air.cT_domain_lb+1)==1 ... +% && GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 +% +% % upper soil cell is pure water +% if T(GRID.soil.cT_domain_ub)>0 % unfrozen +% GRID.lake.unfrozenWaterSurface = true; +% PARA.surf.albedo = PARA.water.albedo; +% PARA.surf.epsilon = PARA.water.epsilon; +% PARA.surf.z0 = PARA.water.z0; +% PARA.surf.rs = PARA.water.rs; +% else %frozen +% PARA.surf.albedo = PARA.ice.albedo; +% PARA.surf.epsilon = PARA.ice.epsilon; +% PARA.surf.z0 = PARA.ice.z0; +% PARA.surf.rs = PARA.ice.rs; +% end +% end -elseif GRID.soil.cT_domain(GRID.air.cT_domain_lb+1)==1 ... - && GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 - - % upper soil cell is pure water - if T(GRID.soil.cT_domain_ub)>0 % unfrozen - GRID.lake.unfrozenWaterSurface = true; - PARA.surf.albedo = PARA.water.albedo; - PARA.surf.epsilon = PARA.water.epsilon; - PARA.surf.z0 = PARA.water.z0; - PARA.surf.rs = PARA.water.rs; - else %frozen - PARA.surf.albedo = PARA.ice.albedo; - PARA.surf.epsilon = PARA.ice.epsilon; - PARA.surf.z0 = PARA.ice.z0; - PARA.surf.rs = PARA.ice.rs; - end -end %tsvd check if lake exists - if GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface - %note SolarAzEl.m delivers only an approximation of sun position / t must be in UTC - - [~, sun_elevation] = SolarAzEl(t,PARA.location.latitude,PARA.location.longitude,PARA.location.altitude); - PARA.water.albedo = waterAlbedo(sun_elevation, FORCING.i.wind); - PARA.surf.albedo = PARA.water.albedo; - PARA.surf.epsilon = PARA.water.epsilon; - [PARA.surf.z0, z0t, z0q] = flake_roughnessLength(PARA.water.fetch, FORCING.i.wind, SEB.u_star, 0); - PARA.surf.z0=real(PARA.surf.z0); - PARA.surf.rs = PARA.water.rs; - end - if GRID.lake.ice.z_ice>0 %GRID.lake.ice.cT_domain(GRID.air.cT_domain_lb+1)==1 % ice surface - PARA.surf.albedo = PARA.ice.albedo; - PARA.surf.epsilon = PARA.ice.epsilon; - [PARA.surf.z0, z0t, z0q] = flake_roughnessLength(PARA.water.fetch, FORCING.i.wind, SEB.u_star, 1); - PARA.surf.z0=real(PARA.surf.z0); - PARA.surf.rs = PARA.ice.rs; - end -end \ No newline at end of file +%lll if GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface +elseif GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface + GRID.lake.unfrozenWaterSurface = true; %tsvd lll + %note SolarAzEl.m delivers only an approximation of sun position / t must be in UTC + [~, sun_elevation] = SolarAzEl(t,PARA.location.latitude,PARA.location.longitude,PARA.location.altitude); + PARA.water.albedo = waterAlbedo(sun_elevation, FORCING.i.wind); + PARA.surf.albedo = PARA.water.albedo; + PARA.surf.epsilon = PARA.water.epsilon; + [PARA.surf.z0, z0t, z0q] = flake_roughnessLength(PARA.water.fetch, FORCING.i.wind, SEB.u_star, 0); + PARA.surf.z0=real(PARA.surf.z0); + PARA.surf.rs = PARA.water.rs; + +elseif GRID.lake.ice.z_ice>0 %GRID.lake.ice.cT_domain(GRID.air.cT_domain_lb+1)==1 % ice surface + PARA.surf.albedo = PARA.ice.albedo; + PARA.surf.epsilon = PARA.ice.epsilon; + [PARA.surf.z0, z0t, z0q] = flake_roughnessLength(PARA.water.fetch, FORCING.i.wind, SEB.u_star, 1); + PARA.surf.z0=real(PARA.surf.z0); + PARA.surf.rs = PARA.ice.rs; +end + +end diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index 1081fb6..9aed047 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -1,92 +1,92 @@ function [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_temp, timestep, BALANCE) + if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis -if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis - - %----------calculate snow surface albedo ------------------------------ - - if max(T(GRID.snow.cT_domain))>=0 % melting conditions - PARA.snow.albedo = PARA.snow.min_albedo + (PARA.snow.albedo - PARA.snow.min_albedo) ... - .* exp(-PARA.snow.tau_f .* timestep.*24.*3600 ./ PARA.snow.tau_1); - else - PARA.snow.albedo=max(PARA.snow.albedo-PARA.snow.tau_a.*timestep.*24.*3600./PARA.snow.tau_1, PARA.snow.min_albedo); - end - - %--------SEB.sublimation----------------------------------------------- - - GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... - - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i;%- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000; - - nonAirFractionUppermostGridCell = (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)+GRID.snow.Snow_w(GRID.snow.cT_domain_ub))./... - (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)+GRID.snow.Snow_w(GRID.snow.cT_domain_ub)+GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); - - GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... - - ( SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i./nonAirFractionUppermostGridCell ...% - ( SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000./nonAirFractionUppermostGridCell ... - - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i); %- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000); - - BALANCE.water.ds = BALANCE.water.ds - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i*1000; % sublimation in [mm] - - %---------- melt and infiltration ------------------------------------- - if max(T(GRID.snow.cT_domain))>0 || FORCING.i.rainfall>0 || sum(GRID.snow.Snow_w)>0 %cases when melt or infiltration occur - - [T(GRID.snow.cT_domain),... - GRID.snow.Snow_i(GRID.snow.cT_domain),... - GRID.snow.Snow_w(GRID.snow.cT_domain),... - GRID.snow.Snow_a(GRID.snow.cT_domain),... - newMelt] = ... - snowMelt(T(GRID.snow.cT_domain),... - GRID.snow.Snow_i(GRID.snow.cT_domain),... - GRID.snow.Snow_w(GRID.snow.cT_domain),... - GRID.snow.Snow_a(GRID.snow.cT_domain),... - FORCING.i.rainfall.*timestep./1000,... - c_temp(GRID.snow.cT_domain),... - PARA); - - GRID.lake.residualWater = GRID.lake.residualWater + newMelt; - BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt + (-newMelt.*1000); % in [mm] - end - - %-------- add the new snow to the upper most snow cell in the case of a exisiting snow cover ------------------- - if isempty( PARA.location.absolute_maxSnow_altitude ) - deltaSnow_i = max(0, FORCING.i.snowfall.*timestep./1000); - else - snowHeight = abs( GRID.general.K_grid(GRID.snow.cT_domain_ub) - GRID.general.K_grid(GRID.snow.cT_domain_lb+1) ); - maxSnowHeight = PARA.location.absolute_maxSnow_altitude - getAltitude( PARA, GRID ); - deltaSnow_i = max( [ 0, ... - min( [ FORCING.i.snowfall.*timestep./1000, ... - (maxSnowHeight - snowHeight ) .* PARA.snow.rho_snow ./ PARA.constants.rho_w ] ) ] ); %ensures that no more than maxSnow can accumulate - %account for excess snow in water balance - BALANCE.water.dr_excessSnow = BALANCE.water.dr_excessSnow -( FORCING.i.snowfall.*timestep - deltaSnow_i*1000 ); %defined as negative when snow is removed - end - - GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... - + deltaSnow_i; - - GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... - + ( deltaSnow_i./(PARA.snow.rho_snow./ PARA.constants.rho_w) - deltaSnow_i); - -else %no snow cover - - %---------- add the new snow into initial SWE variable in case of no snow cover------------------ - - GRID.snow.SWEinitial = GRID.snow.SWEinitial + FORCING.i.snowfall.*timestep./1000 - GRID.snow.SWEinitial.*0.1.*timestep; - GRID.lake.residualWater = GRID.lake.residualWater + GRID.snow.SWEinitial.*0.1.*timestep; - BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - GRID.snow.SWEinitial.*0.1.*timestep*1000; %SWEinitial decreasing counted as surface runoff - - %----- add the rainfall as runoff in case of no infiltration into frozen ground - if ~PARA.modules.infiltration || (PARA.modules.infiltration && T(GRID.soil.cT_domain_ub)<=0 )%no infiltration scheme or uppermost soil cell frozen - GRID.lake.residualWater = GRID.lake.residualWater + FORCING.i.rainfall.*timestep./1000; - BALANCE.water.dr_rain = BALANCE.water.dr_rain - FORCING.i.rainfall.*timestep; - end - -end + %----------calculate snow surface albedo ------------------------------ + + if max(T(GRID.snow.cT_domain))>=0 % melting conditions + PARA.snow.albedo = PARA.snow.min_albedo + (PARA.snow.albedo - PARA.snow.min_albedo) ... + .* exp(-PARA.snow.tau_f .* timestep.*24.*3600 ./ PARA.snow.tau_1); + else + PARA.snow.albedo=max(PARA.snow.albedo-PARA.snow.tau_a.*timestep.*24.*3600./PARA.snow.tau_1, PARA.snow.min_albedo); + end + + %--------SEB.sublimation----------------------------------------------- + + GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... + - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i;%- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000; + + nonAirFractionUppermostGridCell = (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)+GRID.snow.Snow_w(GRID.snow.cT_domain_ub))./... + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub)+GRID.snow.Snow_w(GRID.snow.cT_domain_ub)+GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); + + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... + - ( SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i./nonAirFractionUppermostGridCell ...% - ( SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000./nonAirFractionUppermostGridCell ... + - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i); %- SEB.Qe.*timestep.*24.*3600./(L+L_lv)./1000); + + BALANCE.water.ds = BALANCE.water.ds - SEB.Qe.*timestep.*24.*3600./PARA.constants.L_sg./PARA.constants.rho_i*1000; % sublimation in [mm] + + %---------- melt and infiltration ------------------------------------- + if max(T(GRID.snow.cT_domain))>0 || FORCING.i.rainfall>0 || sum(GRID.snow.Snow_w)>0 %cases when melt or infiltration occur -%--------- update albedo after fresh fallen snow -------------------------- -% determine time of last snowfall for albedo calculation -SEB.newSnow = SEB.newSnow-SEB.newSnow.*0.1.*timestep + FORCING.i.snowfall.*timestep./1000; -if SEB.newSnow>= PARA.technical.SWEperCell/2 - PARA.snow.albedo=PARA.snow.max_albedo; - SEB.newSnow=0; -end + [T(GRID.snow.cT_domain),... + GRID.snow.Snow_i(GRID.snow.cT_domain),... + GRID.snow.Snow_w(GRID.snow.cT_domain),... + GRID.snow.Snow_a(GRID.snow.cT_domain),... + newMelt] = ... + snowMelt(T(GRID.snow.cT_domain),... + GRID.snow.Snow_i(GRID.snow.cT_domain),... + GRID.snow.Snow_w(GRID.snow.cT_domain),... + GRID.snow.Snow_a(GRID.snow.cT_domain),... + FORCING.i.rainfall.*timestep./1000,... + c_temp(GRID.snow.cT_domain),... + PARA); + GRID.lake.residualWater = GRID.lake.residualWater + newMelt; % zzz + BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt + (-newMelt.*1000); % in [mm] + end + + %-------- add the new snow to the upper most snow cell in the case of a exisiting snow cover ------------------- + if isempty( PARA.location.absolute_maxSnow_altitude ) + deltaSnow_i = max(0, FORCING.i.snowfall.*timestep./1000); + else + snowHeight = abs( GRID.general.K_grid(GRID.snow.cT_domain_ub) - GRID.general.K_grid(GRID.snow.cT_domain_lb+1) ); + maxSnowHeight = PARA.location.absolute_maxSnow_altitude - getAltitude( PARA, GRID ); + + assert(maxSnowHeight - snowHeight >=0,'neg snow height!') %ttt + + deltaSnow_i = max( [ 0, ... + min( [ FORCING.i.snowfall.*timestep./1000, ... + (maxSnowHeight - snowHeight ) .* PARA.snow.rho_snow ./ PARA.constants.rho_w ] ) ] ); %ensures that no more than maxSnow can accumulate + %account for excess snow in water balance + BALANCE.water.dr_excessSnow = BALANCE.water.dr_excessSnow -( FORCING.i.snowfall.*timestep - deltaSnow_i*1000 ); %defined as negative when snow is removed + end + + GRID.snow.Snow_i(GRID.snow.cT_domain_ub) = GRID.snow.Snow_i(GRID.snow.cT_domain_ub) ... + + deltaSnow_i; + + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) = GRID.snow.Snow_a(GRID.snow.cT_domain_ub) ... + + ( deltaSnow_i./(PARA.snow.rho_snow./ PARA.constants.rho_w) - deltaSnow_i); + + else %no snow cover + %---------- add the new snow into initial SWE variable in case of no snow cover------------------ + if(isempty(GRID.lake.water.cT_domain_ub) || ~isempty(GRID.lake.ice.cT_domain_ub) ) %tsvd only allow for snow buildup if no lake, or if lake ice exists + GRID.snow.SWEinitial = GRID.snow.SWEinitial + FORCING.i.snowfall.*timestep./1000 - GRID.snow.SWEinitial.*0.1.*timestep; + end + GRID.lake.residualWater = GRID.lake.residualWater + GRID.snow.SWEinitial.*0.1.*timestep; + BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - GRID.snow.SWEinitial.*0.1.*timestep*1000; %SWEinitial decreasing counted as surface runoff + + %----- add the rainfall as runoff in case of no infiltration into frozen ground + if ~PARA.modules.infiltration || (PARA.modules.infiltration && T(GRID.soil.cT_domain_ub)<=0 )%no infiltration scheme or uppermost soil cell frozen + GRID.lake.residualWater = GRID.lake.residualWater + FORCING.i.rainfall.*timestep./1000; + BALANCE.water.dr_rain = BALANCE.water.dr_rain - FORCING.i.rainfall.*timestep; + end + end + + %--------- update albedo after fresh fallen snow -------------------------- + % determine time of last snowfall for albedo calculation + SEB.newSnow = SEB.newSnow-SEB.newSnow.*0.1.*timestep + FORCING.i.snowfall.*timestep./1000; + if SEB.newSnow>= PARA.technical.SWEperCell/2 + PARA.snow.albedo=PARA.snow.max_albedo; + SEB.newSnow=0; + end end \ No newline at end of file diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index 24baaa8..aff9af1 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -24,23 +24,37 @@ GRID.snow.SWEinitial=0; % -------- update K grid ------------------------------------- + assert(~isnan(GRID.general.K_grid(GRID.snow.cT_domain_ub+1)),' error in uppermost lake cell K_grid'); %tsvd + GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ); %tsvd GRID.general.K_grid(GRID.snow.K_domain_ub)=-1.*( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) ); T(GRID.snow.cT_domain_ub)=T(GRID.air.cT_domain_lb); - + assert( sum(isnan( GRID.general.K_grid ) )==0, 'updateGRID_snow - error xxx') + assert( sum(isnan(GRID.snow.Snow_i) )==0,' GRID.snow.snow_i NAN 1') end else %snow exists check_change=false; + try + assert( sum(isnan(GRID.snow.Snow_i) )==0,' GRID.snow.snow_i NAN 1') + catch + %GRID.general.K_grid + G2=GRID; + G2ind = labindex; + save Data2_check G2 G2ind + end GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) -... ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); %updates the position of the uppermost snow grid cell - - try + %try assert( ~isnan( GRID.general.K_grid(GRID.snow.cT_domain_ub) ), 'updateGRID_snow - error in uppermost snow cell position' ); - catch - xxx=GRID.general.K_grid; ...save + % assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.snow.cT_domain_lb)<2,'snow on lake!'); + if(~isempty(GRID.lake.water.cT_domain_ub)) + assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); end + %catch + % save Data_check PARA GRID %labindex + %end if GRID.snow.Snow_i(GRID.snow.cT_domain_ub)>=1.5.*PARA.technical.SWEperCell %create new grid cell @@ -200,6 +214,13 @@ end assert( sum( isnan(T(GRID.snow.cT_domain)))==0, 'updateGRID_snow - error in T after grid update' ); +%try assert( sum( isnan(GRID.general.K_grid))==0, 'update_GRID_snow - error in Kgrid after grid update'); +%catch +% %GRID.general.K_grid +% x2=GRID; +% x2ind = labindex; +% save Data2_check x2 x2ind +% end end diff --git a/modules/cryoGridTechnical/getAltitude.m b/modules/cryoGridTechnical/getAltitude.m index 4acd540..dc09ebf 100644 --- a/modules/cryoGridTechnical/getAltitude.m +++ b/modules/cryoGridTechnical/getAltitude.m @@ -1,5 +1,13 @@ function altitude = getAltitude( PARA, GRID ) + +%tsvd account for lake surface (snow can accumulate on lake ice) +if ~isempty( GRID.lake.water.cT_domain_ub )% lake water is present + altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.lake.water.cT_domain_ub); +elseif ~isempty( GRID.lake.ice.cT_domain_ub ) % lake ice is present + altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.lake.ice.cT_domain_ub); - altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.soil.cT_domain_ub); +else + altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.soil.cT_domain_ub); % no lake +end end \ No newline at end of file diff --git a/modules/cryoGridTechnical/getSoilAltitude.m b/modules/cryoGridTechnical/getSoilAltitude.m index 83c4db1..8995992 100644 --- a/modules/cryoGridTechnical/getSoilAltitude.m +++ b/modules/cryoGridTechnical/getSoilAltitude.m @@ -1,7 +1,8 @@ function soil_altitude = getSoilAltitude(PARA, GRID) -if ~isempty( GRID.lake.cT_domain_ub ) - soil_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.lake.cT_domain_lb+1); +%tsvd GRID.lake.cT_domain replaced by GRID.lake.water.cT_domain +if ~isempty( GRID.lake.water.cT_domain_ub ) + soil_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.lake.water.cT_domain_lb+1); else soil_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.soil.cT_domain_ub); end \ No newline at end of file diff --git a/modules/cryoGridTechnical/makeGrids.m b/modules/cryoGridTechnical/makeGrids.m index e22e1e5..d83f1b7 100644 --- a/modules/cryoGridTechnical/makeGrids.m +++ b/modules/cryoGridTechnical/makeGrids.m @@ -1,6 +1,5 @@ function GRID=makeGrids(PARA) - GRID.snow.snowCellSize=PARA.technical.SWEperCell/(PARA.snow.rho_snow/PARA.constants.rho_w); GRID.snow.snowGrid=[-1.*(PARA.technical.maxSWE./(PARA.technical.SWEperCell)+2).*GRID.snow.snowCellSize:GRID.snow.snowCellSize:-GRID.snow.snowCellSize]'; %tsvd added diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index c9258d8..a37d4a7 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -104,7 +104,9 @@ OUT.location.water_table_altitude=[OUT.location.water_table_altitude; PARA.location.water_table_altitude]; % lateral fluxes - OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow; PARA.ensemble.terrain_index_snow ]; +%tsvd OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow; PARA.ensemble.terrain_index_snow ]; + OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow ]; % exclude ensemble struct for lateral=0 zzz define switch Abfrage... lateral 0/1? + OUT.lateral.water_fluxes = [ OUT.lateral.water_fluxes; water_fluxes' ]; % vector containing water fluxes in [m/s] to the current worker OUT.lateral.snow_fluxes = [ OUT.lateral.snow_fluxes; snow_fluxes' ]; % vector containing snow fluxes in [m SWE / s] to the current worker OUT.lateral.heat_fluxes = [ OUT.lateral.heat_fluxes; heat_fluxes' ]; % vector containing depth-integrated heat fluxes in [J/m^2 s ] to the current worker @@ -188,7 +190,7 @@ if round((t-TEMPORARY.saveTime).*48)==0 iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_output' datestr(t,'yyyy') '.mat' ], OUT); iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_finalState' datestr(t,'yyyy') '.mat' ], T, wc, t, SEB, PARA, GRID); - iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_altitudes_vs_time_' datestr(t,'yyyy') '.png' ], OUT, PARA ); + %ttt iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_altitudes_vs_time_' datestr(t,'yyyy') '.png' ], OUT, PARA ); OUT = generateOUT(); TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(datestr(t,'mm')), str2num(datestr(t,'dd')), str2num(datestr(t,'HH')), str2num(datestr(t,'MM')), 0); end From 795b44dc62fcc5dfe12dbc435a41020cef9bb234 Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Wed, 4 Apr 2018 16:26:15 +0200 Subject: [PATCH 35/45] new branch xice_mpi with FLAKE included (not fully operational so far) --- CryoGrid3_xice_mpi.m | 4 ++-- analysis/plot_output.m | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index e8a2465..0820fae 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -179,7 +179,7 @@ PARA.forcing.snow_fraction=1; % switches for modules - PARA.modules.infiltration=0; % true if infiltration into unfrozen ground occurs + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs PARA.modules.xice=0; % true if thaw subsicdence is enabled PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) %tsvd extended for lateral switched off @@ -201,7 +201,7 @@ end % ------make output directory (name depends on parameters) ---------------- - run_number = sprintf( [ 'TESTRUN-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) '_stratSAM_geomHEX_extFluxT-0.005_xH%d_xW%d_xS%d_rf%d_sf%d' ], ... + run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) ], ... [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction] ) ; mkdir([ saveDir '/' run_number]); diff --git a/analysis/plot_output.m b/analysis/plot_output.m index 54e1c73..49aff0d 100644 --- a/analysis/plot_output.m +++ b/analysis/plot_output.m @@ -11,8 +11,10 @@ dirname = 'E:\CryoGrid3\runs'; % runname = 'testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2'; %runname = ' TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH1_xW1_xS0_rf1_sf1'; -runname ='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; - number_of_realizations = 2; +%runname ='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; +runname='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; + +number_of_realizations = 2; % %% load output data and settings from files of all workers @@ -39,8 +41,8 @@ outputfile = [dir run '\' run '_output1979.mat']; configfile = [dir run '\' run '_settings.mat']; - outputfile = 'E:\CryoGrid3\runs\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2_output1979.mat' - configfile = 'E:\CryoGrid3\runs\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2_settings.mat' + %outputfile = 'E:\CryoGrid3\runs\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2_output1979.mat' + %configfile = 'E:\CryoGrid3\runs\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2_settings.mat' load(outputfile); load(configfile); From b69ce210fced5c9f8a28c9d41325bf0ac2c0653d Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Mon, 9 Apr 2018 16:41:26 +0200 Subject: [PATCH 36/45] bug fix u_star, and implementation of c_temp k_temp lwc_temp in initializeConductivityCapacity.m and getThermalPropertiesInfiltration.m --- CryoGrid3_xice_flake.m | 579 ++++++++++++++++++ CryoGrid3_xice_mpi.m | 39 +- analysis/plot_output.m | 10 +- .../getThermalPropertiesInfiltration.m | 11 + .../initializeConductivityCapacity.m | 10 +- .../calculateLateralHeatFluxes.m | 11 +- .../checkPreconditionWaterExchange.m | 2 +- .../cryoGridLateral/get_parallel_variables.m | 30 +- modules/cryoGridSEB/L_star.m | 2 +- modules/cryoGridSnow/CryoGridSnow.m | 9 +- modules/cryoGridTechnical/makeGrids.m | 2 +- .../cryoGridTechnical/sum_up_output_store.m | 3 + 12 files changed, 653 insertions(+), 55 deletions(-) create mode 100644 CryoGrid3_xice_flake.m diff --git a/CryoGrid3_xice_flake.m b/CryoGrid3_xice_flake.m new file mode 100644 index 0000000..8af17e6 --- /dev/null +++ b/CryoGrid3_xice_flake.m @@ -0,0 +1,579 @@ +% ------------------------------------------------------------------------- +% CryoGRID3 +% main script for running the model +% +% Developed by: S. Westermann and M. Langer 2015 +% +% ------------------------------------------------------------------------- +clear all +close all +%tsvd define simulation setting +debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) +run_mode = 1; % 1: single mode 1 column & lateral exchange setting 2: offline 3: online +number_of_realizations=1; + +if(run_mode==1) % single run + index=1 +elseif(run_mode==2) % multiple runs - offline + disp('not implemented so far') +elseif(run_mode==3) % multiple runs - online + delete(gcp('nocreate')) % useful to restart from a crash + parpool(number_of_realizations) + disp('need to complement run mode...') +end + +add_modules; %adds required modules + +saveDir = './runs'; + +%ooo spmd +% index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run + +%---------------define input parameters------------------------------------ + % here you provide the ground stratigraphy + % z w/i m o type porosity + + % default stratigraphy used in publication: + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + % simple stratigraphy with excess ice used to test water balance: + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... + % 0.4 0.8 0.2 0.00 1 0.40;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % very simply stratigraphy without excess ice used to test energy balance + % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... + % 1.0 0.5 0.5 0.00 1 0.5 ;... + % 10.0 0.25 0.75 0.00 1 0.25 ]; + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer + % extends until the end of the model domain + % column 2: volumetric water+ice content + % column 3: volumetric mineral content + % column 4: volumetric organic content + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + %------ model parameters -------------------------------------------------- + % parameters related to soil + PARA.soil.albedo=0.2; % albedo snow-free surface + PARA.soil.epsilon=0.97; % emissvity snow-free surface + PARA.soil.z0=1e-3; % roughness length [m] snow-free surface + PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface + PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] + PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + + % parameters related to hydrology scheme + PARA.soil.fieldCapacity=0.5; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries + PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation + PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. + %tsvd PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] + PARA.soil.externalWaterFlux=0.; %external water flux / drainage in [m/day] + PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible + PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile + PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up + PARA.soil.hydraulic_conductivity = 1e-5; + PARA = loadSoilTypes( PARA ); + + % parameters related to snow + PARA.snow.max_albedo=0.85; % albedo of fresh snow + PARA.snow.min_albedo=0.5; % albedo of old snow + PARA.snow.epsilon=0.99; % surface emissivity snow + PARA.snow.z0=5e-4; % roughness length surface [m] + PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow + PARA.snow.rho_snow=200.0; % density in [kg/m3] + PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] + PARA.snow.tau_a=0.008; % [per day] + PARA.snow.tau_f=0.24; % [per day] + PARA.snow.relative_maxSnow= [0.1]; %ttt maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.extinction=25.0; % light extinction coefficient of snow + %tsvd add lake parameters + % parameters related to lake + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.epsilon=0.99; % surface emissivity water + PARA.water.rs=0.; % surface resistance -> should be 0 for water + %tsvd + PARA.water.z0=5e-4; % roughness length surface [m] % JAN: value for summer / vegetation + %tsvd PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m version Flake + PARA.water.extinction=1.2; % light extinction coefficient of water + PARA.water.depth=1.; + PARA.water.fetch=20; + + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + PARA.ice.epsilon=0.98; % surface emissivity snow + PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice + PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow + PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases + PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells + PARA.technical.maxSWE=0.4; % in [m] SWE + PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity + PARA.technical.starttime=datenum(1979, 6, 10); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(1980, 7, 1); % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds + PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds + PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + + %default grid used for publications and testing of water balance: + PARA.technical.subsurfaceGrid = [[0:0.02:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + + PARA.location.area=1.0; + PARA.location.initial_altitude=20.0; + % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" + PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain + PARA.location.soil_altitude=PARA.location.initial_altitude; + PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow + PARA.location.active_layer_depth_altitude = nan; % defined at runtime + PARA.location.water_table_altitude = nan; % defined at runtime + % thresholds + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.relative_maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; + end +%tsvd + PARA.location.latitude = 72.376; % [deg] < - + PARA.location.longitude = 126.491; % [deg] < - + %PARA.location.GridCellSize = 1e6; % [m^2] < - + %PARA.location.TileFraction = 1e-2; + % parameters related to the site location + PARA.location.water_table_altitude = nan; % defined at runtime + + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] +% PARA.Tinitial = [ -2 5 ;... +% 0 0 ;... +% 2 -5 ;... +% 10 -10 ;... +% 25 -9 ;... +% 100 -9 ;... +% 2000 10 ]; + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -2 ;... + 5 -7 ;... + 10 -9 ;... + 25 -9 ;... + 100 -8 ;... + 1100 10.2 ]; % the geothermal gradient for Qgeo=0.05W/m² and K=2.746W/Km is about 18.2 K/km + +% load natural constants (given in SI units) to PARA.constants + PARA = loadConstants( PARA ); + + %FORCING data mat-file + PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.rain_fraction=1; + PARA.forcing.snow_fraction=1; + + % switches for modules + PARA.modules.infiltration=0; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=0; % true if thaw subsicdence is enabled + PARA.modules.lateral=0; % true if adjacent realizations are run (this does not require actual lateral fluxes) +%tsvd extended for lateral switched off + if ~PARA.modules.lateral + PARA.modules.exchange_heat = 0; + PARA.modules.exchange_water = 0; + PARA.modules.exchange_snow = 0; + PARA.snow.maxSnow= [] ; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + % in par mode this is replaced by PARA.ensemble.immobile_snow_height + elseif PARA.modules.lateral + % switches for lateral processes + PARA.modules.exchange_heat = 1; %ttt + PARA.modules.exchange_water = 1; %ttt + PARA.modules.exchange_snow = 1; %ttt + + %---------overwrites variables for each realization-------------------- + % this function must define everything that is realization-specific or dependent of all realizations + PARA = get_parallel_variables( PARA ); + end + + % ------make output directory (name depends on parameters) ---------------- + run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) ], ... + ['_', PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow] ) ; + mkdir([ saveDir '/' run_number]); + + %-------------------------------------------------------------------------- + %-----------do not modify from here onwards-------------------------------- + %-------------------------------------------------------------------------- + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + + if ~success + warning('A problem with the Forcing occured.'); + end + + PARA = initializeParameters(PARA, FORCING); %set start time, etc. + + %----------------create and initialize the grids -------------------------- + GRID=makeGrids(PARA); %create all grids + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + + %----- initializie excess ground ice -------------------------------------- + [GRID,PARA] = initializeExcessIce2(GRID,PARA); + + %----- initializie soil thermal properties -------------------------------- + GRID = initializeSoilThermalProperties(GRID, PARA); + + %------ initializie snow properties---------------------------------------- + GRID = initializeSnow(GRID); + + %---- initialize the surface energy balance struct ------------------------ + SEB = initializeSEB(); +%tsvd replace by new call lake scheme +% %---- initialize the water body module ------------------------------------ +% GRID = initializeLAKE(GRID); + +%---- initialize the lake scheme structs ---------------------------------- + [FLAKE GRID] = initializeLAKE(GRID, PARA); + %---- initialize temperature profile -------------------------------------- + T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); + + %---- modification for infiltration + wc=GRID.soil.cT_water; + GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; + GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; + + %---- preallocate temporary arrays for capacity and conductivity----------- + [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid + + %---- energy and water balance initialization ----------------------------- + BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); + + %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? +%ooo + if(run_mode==1) + water_fluxes = 0.; + snow_fluxes = 0.; + heat_fluxes = 0.; + dE_dt_lateral = zeros(length(GRID.general.cT_grid), 1); + elseif(run_mode==2) + disp('need to implement...') + elseif(run_mode==3) + water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index + snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index + heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index + end + %__________________________________________________________________________ + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); + + disp('initialization successful'); + %%% nnn + iSaveSettings( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_settings.mat'] , FORCING, PARA, GRID) + + + %% ________________________________________________________________________ + % Time Integration Routine I + % I + %_________________________________________________________________________I + + while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) + warning( 'numerical stability not guaranteed' ); + end + + %------ update T array ------------------------------------------------ + % account for vertical heat fluxes from ground heat flux and heat conduction + T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; + % account for lateral heat fluxes + T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] + % set grid cells in air to air temperature + T(GRID.air.cT_domain)=FORCING.i.Tair; + + if max((T<-100))==1; disp('dwd'); end + + %------- water body module -------------------------------------------- +%tsvd T = mixingWaterBody(T, GRID); % zzz check whether this is ok to switch off + %------- snow cover module -------------------------------------------- + [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + + %------- infiltration module------------------------------------------- + if PARA.modules.infiltration + lateral_water_flux = nansum( water_fluxes ); % lateral fluxes to/from other workers in [m/s] + [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_water_flux); + end +%tsvd + %------- water body module -------------------------------------------- + if timestep>0 && ( ~isempty(GRID.lake.water.cT_domain_ub) || ~isempty(GRID.lake.ice.cT_domain_ub) ) + %ice cover + [T GRID FLAKE] = cryoGridIceCover(GRID, SEB, FLAKE, T, c_cTgrid, timestep); + %FLAKE + if isempty(GRID.lake.ice.cT_domain_ub) && sum(GRID.lake.water.cT_domain)>=3 + %FLAKE is used if no ice cells exist + [T GRID FLAKE] = cryoGridFLAKE(FLAKE, GRID, SEB, PARA, T, T_old, timestep, k_Kgrid, SEB.dE_dt, SEB.dE_dt_SEB); + else + %updated FLAKE variables also when FLAKE is not used + FLAKE.t_bot_n_flk = T(GRID.lake.water.cT_domain_lb) + 273.15; + %set mixed layerdepth to zero + FLAKE.h_ml_n_flk = 0; + end + GRID = updateGRID_flake(GRID); + end + %--------- buoyancy calculation in block fields------------------------ + %T = convectionInBlocks(T, c_cTgrid, GRID) %not available + % @ ALEX: here the calculations of the excess ice module take place + % (uncomment this line to "activate" the module). Note that the + % stratigraphy must be modified such that excess ground ice is present + % in order to make the module "work" + + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.modules.infiltration + warning( 'energy and water balances are not correct for this combination of modules'); % zzz ... + [GRID, PARA] = excessGroundIce(T, GRID, PARA); +%tsvd version Flake [GRID, PARA, wc] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); +%tsvd wc( end-sum(GRID.soil.cT_domain)+1 : end ); % make vector dims consistent + elseif PARA.modules.xice && PARA.modules.infiltration + [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); +%tsvd [GRID, PARA, wc] = excessGroundIceInfiltration(T, wc, GRID, PARA); + GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + end + + %------- update Lstar for next time step ------------------------------ + SEB = L_star(FORCING, PARA, SEB); + + %------- update auxiliary state variables + PARA.location.altitude = getAltitude( PARA, GRID ); + PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); + PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); + PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); + + %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time + if ~PARA.modules.lateral + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.maxSnow ) + %tsvd if isempty( PARA.ensemble.immobile_snow_height ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; + end + end + %------- water balance calculations ----------------------------------- + % rainfall + BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval + % snowfall + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval + + %------- lateral exchange module -------------------------------------- + % all functions called in this block should go into + % /modules/cryoGridLateral + % calling PARA.ensemble is only allowed here + if PARA.modules.lateral + if t==TEMPORARY.syncTime %communication between workers + disp('CryoGridLateral: sync - start'); + labBarrier(); %common start + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; %ddd commenting out (here and below) does not help prevent snow grid crash + + % heat exchange module + if PARA.modules.exchange_heat + labBarrier(); + heat_fluxes = zeros( number_of_realizations, 1); + % check preconditions + precondition_heatExchange = true; %no specific conditions so far + if precondition_heatExchange + %WRAPPER + disp('sync - exchanging heat'); + % calculate lateral heat fluxes + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + PACKAGE_heatExchange.T = T; + PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; + PACKAGE_heatExchange.k_cTgrid = k_cTgrid; + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_heatExchange, j, 1); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_heatExchange_j = labReceive(j, 1); + [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index + heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes + dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations + end + end + end + end + + % water exchange module + if PARA.modules.exchange_water + labBarrier(); + water_fluxes = zeros( number_of_realizations, 1 ); % in [m/s] + % check preconditions + precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); + if precondition_waterExchange + % WRAPPER + disp('sync - exchanging water'); + % calculate lateral water fluxes + PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); + PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_waterExchange, j, 2); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_waterExchange_j = labReceive(j, 2); + % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) + water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); + end + end + % for debugging: print water flux per column + waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m + fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); + end + + end + + % snow exchange module + if PARA.modules.exchange_snow + labBarrier(); + % check preconditions + precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); + if precondition_snowExchange + disp('sync - exchanging snow'); + % calculate terrain index with updated surface_altitudes + PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); + + % calculate mobile snow + % WRAPPER + mobile_snow = zeros( 1, number_of_realizations ); + my_mobile_snow = 0; + meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE + if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions + i=0; + while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold + > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains + && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) + - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) + my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile + i=i+1; + end + end + mobile_snow(index) = my_mobile_snow; + % exchange mobile snow amounts + for j=1:number_of_realizations + if j~=index + % send mobile snow amount in [m SWE] + labSend( mobile_snow(index), j, 4 ); + end + end + for j=1:number_of_realizations + if j~=index + % receive mobile snow amount [m SWE] + mobile_snow(j) = labReceive(j, 4); + end + end + % calculate lateral snow fluxes + my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); + % apply lateral snow fluxes directly + if my_snow_change ~= 0 + [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; + end + + snow_fluxes = zeros( numlabs , 1 ); + snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes + fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); + + end + end + + labBarrier(); + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; + disp('sync - done'); + end + end + + + %------- next time step ----------------------------------------------- + t=t+timestep; + %---------- sum up + OUTPUT ------------------------------------------- + %nnn + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes); + end + + % save final state and output at t=endtime +%nnn +iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) +%nnn +iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) +%nnn +%iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); + +%ooo end %end spmd + +%ooo adapt... +if number_of_realizations>1 + delete(gcp('nocreate')) +end + +disp('Done.'); diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 0820fae..65183b6 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -123,7 +123,7 @@ PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] %default grid used for publications and testing of water balance: @@ -191,7 +191,7 @@ % in par mode this is replaced by PARA.ensemble.immobile_snow_height elseif PARA.modules.lateral % switches for lateral processes - PARA.modules.exchange_heat = 0; %ttt + PARA.modules.exchange_heat = 1; %ttt PARA.modules.exchange_water = 0; %ttt PARA.modules.exchange_snow = 0; %ttt @@ -311,40 +311,19 @@ % account for min and max timesteps specified, max. energy change per grid cell and the CFT stability criterion. % energy change due to advection of heat through water fluxes is still excluded. % timestep in [days] -%tsvd - if(~debug_mode) %tsvd new timestep calculation to avoid problems with lateral mode switched off - -% old -% timestep = min( [ max( [ min( [ 0.5 * nanmin( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... -% PARA.technical.targetDeltaE .* nanmin( abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... -% PARA.technical.maxTimestep ] ), ... -% PARA.technical.minTimestep ] ), ... -% TEMPORARY.syncTime-t,... -% TEMPORARY.outputTime-t ] ); - -% new - if PARA.modules.lateral - timestep = min( [ max( [ min( [ 0.5 * nanmin(GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... + timestep = min( [ max( [ min( [ 0.5 * nanmin(GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... PARA.technical.targetDeltaE .* nanmin(abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... PARA.technical.maxTimestep ] ), ... PARA.technical.minTimestep ] ), ... - TEMPORARY.syncTime-t,... - TEMPORARY.outputTime-t ] ); - else - timestep = min( [ max( [ min( [ 0.5 * nanmin(GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain ) ) ./ (24.*3600), ... - PARA.technical.targetDeltaE .* nanmin(abs(GRID.general.K_delta ./ SEB.dE_dt ) ) ./ (24.*3600), ... - PARA.technical.maxTimestep ] ), ... - PARA.technical.minTimestep ] ), ... - TEMPORARY.outputTime-t ] ); + TEMPORARY.outputTime-t ] ); + if PARA.modules.lateral + timestep = min(timestep,TEMPORARY.syncTime-t); + end + if(debug_mode) + timestep = PARA.technical.minTimestep; % use for debugging to avoid NaN... zzz end - - else % debug mode - timestep = PARA.technical.minTimestep; % use for debugging to avoid NaN... zzz - %disp('WARNING: timestep set to minTimestep for debugging') - end - % give a warning when timestep required by CFT criterion is below the minimum timestep specified if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) warning( 'numerical stability not guaranteed' ); diff --git a/analysis/plot_output.m b/analysis/plot_output.m index 49aff0d..74bf212 100644 --- a/analysis/plot_output.m +++ b/analysis/plot_output.m @@ -14,7 +14,7 @@ %runname ='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; runname='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; -number_of_realizations = 2; +number_of_realizations = 1 % %% load output data and settings from files of all workers @@ -38,8 +38,12 @@ end %tsvd outputfile = [dir run '/' run '_output1979.mat']; % configfile = [dir run '/' run '_settings.mat']; - outputfile = [dir run '\' run '_output1979.mat']; - configfile = [dir run '\' run '_settings.mat']; + + %outputfile = [dir run '\' run '_output1979.mat']; + %configfile = [dir run '\' run '_settings.mat']; + + outputfile = ['..\runs\' run '_output1979.mat']; + configfile = ['..\runs\' run '_settings.mat']; %outputfile = 'E:\CryoGrid3\runs\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2_output1979.mat' %configfile = 'E:\CryoGrid3\runs\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2_settings.mat' diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m index e78f7ba..3a13351 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m @@ -34,6 +34,17 @@ lwc_temp(GRID.snow.cT_domain) = GRID.snow.Snow_w(GRID.snow.cT_domain)./GRID.general.K_delta(GRID.snow.cT_domain); + %tsvd------ lake domain -------------------------------------------------- + %zzz check if ok!? + c_temp(GRID.lake.water.cT_domain) = PARA.constants.c_w; + k_temp(GRID.lake.water.cT_domain) = 5.46E-01 ; % in loadConstants.m 0.57 is used! FLAKE: Molecular heat conductivity of water [J m^{-1} s^{-1} K^{-1}] zzz + lwc_temp(GRID.lake.water.cT_domain) = 1.; + + c_temp(GRID.lake.ice.cT_domain) = PARA.constants.c_i; + k_temp(GRID.lake.ice.cT_domain) = 2.29; ; % in loadConstants.m 2.2 is used! FLAKE: Molecular heat conductivity of ice [J m^{-1} s^{-1} K^{-1}] + lwc_temp(GRID.lake.ice.cT_domain) = 0.; + + %------- interpolate conductivity to K-grid --------------------------- k_eff(2:end-1) = GRID.general.K_delta(1:end-1)./(2.*GRID.general.cT_delta) .* (1./k_temp(1:end-1)).^2 ... + GRID.general.K_delta(2:end) ./(2.*GRID.general.cT_delta) .* (1./k_temp(2:end)).^2; diff --git a/modules/cryoGridInitialize/initializeConductivityCapacity.m b/modules/cryoGridInitialize/initializeConductivityCapacity.m index 95ff467..f8a0943 100644 --- a/modules/cryoGridInitialize/initializeConductivityCapacity.m +++ b/modules/cryoGridInitialize/initializeConductivityCapacity.m @@ -24,7 +24,6 @@ k_temp(GRID.soil.cT_domain) = double(T(GRID.soil.cT_domain)<=0).*k_temp(GRID.soil.cT_domain) + double(T(GRID.soil.cT_domain)>0).* conductivityUnfrozen(wc,GRID,PARA); lwc_temp(GRID.soil.cT_domain) = double(T(GRID.soil.cT_domain)<=0).*lwc_temp(GRID.soil.cT_domain) + double(T(GRID.soil.cT_domain)>0).* wc; - %------- snow domain -------------------------------------- c_temp(GRID.snow.cT_domain) = cap_snow(GRID.snow.Snow_i(GRID.snow.cT_domain),... GRID.snow.Snow_w(GRID.snow.cT_domain),... @@ -36,3 +35,12 @@ GRID.snow.Snow_a(GRID.snow.cT_domain)); lwc_temp(GRID.snow.cT_domain) = GRID.snow.Snow_w(GRID.snow.cT_domain)./GRID.general.K_delta(GRID.snow.cT_domain); + +%tsvd------ lake domain -------- +c_temp(GRID.lake.water.cT_domain) = PARA.constants.c_w; +k_temp(GRID.lake.water.cT_domain) = 5.46E-01 ; % in loadConstants.m 0.57 is used! FLAKE: Molecular heat conductivity of water [J m^{-1} s^{-1} K^{-1}] zzz +lwc_temp(GRID.lake.water.cT_domain) = 1.; + +c_temp(GRID.lake.ice.cT_domain) = PARA.constants.c_i; +k_temp(GRID.lake.ice.cT_domain) = 2.29; ; % in loadConstants.m 2.2 is used! FLAKE: Molecular heat conductivity of ice [J m^{-1} s^{-1} K^{-1}] +lwc_temp(GRID.lake.ice.cT_domain) = 0.; diff --git a/modules/cryoGridLateral/calculateLateralHeatFluxes.m b/modules/cryoGridLateral/calculateLateralHeatFluxes.m index 32b4b0f..bee9522 100644 --- a/modules/cryoGridLateral/calculateLateralHeatFluxes.m +++ b/modules/cryoGridLateral/calculateLateralHeatFluxes.m @@ -1,6 +1,7 @@ function [dE_dt, BALANCE] = calculateLateralHeatFluxes(T_index, k_index, PACKAGE_heatExchange_j, GRID, PARA, BALANCE, j) - index = labindex; +%ooo index = labindex; + index=1 dE_dt = zeros( length(GRID.general.cT_grid), 1); if PARA.ensemble.thermal_contact_length(index,j)>0 % calculate lateral heat flux only for laterally connected workers @@ -35,7 +36,13 @@ disp('k_j contains complex values'); end T_interp_j = interp1( altitude_cTgrid_j, T_j, altitude_cTgrid_index, 'linear'); - k_interp_j = interp1( altitude_cTgrid_j, k_j, altitude_cTgrid_index, 'linear'); + try + assert( sum( isnan( T_interp_j ) )==0, 'calc lat heat fluxes - error in T interpolation') %ttt + catch + save Data_Tinterp T_interp_j altitude_cTgrid_j T_j altitude_cTgrid_index + end + k_interp_j = interp1( altitude_cTgrid_j, k_j, altitude_cTgrid_index, 'linear'); + assert( sum( isnan( k_interp_j ) )==0, 'calc lat heat fluxes - error in k interpolation') %ttt % determine effectice thermal conductivities k_eff = (weight_index+weight_j) ./ ( weight_index./k_index + weight_j./k_interp_j ); diff --git a/modules/cryoGridLateral/checkPreconditionWaterExchange.m b/modules/cryoGridLateral/checkPreconditionWaterExchange.m index aef070c..5186ddb 100644 --- a/modules/cryoGridLateral/checkPreconditionWaterExchange.m +++ b/modules/cryoGridLateral/checkPreconditionWaterExchange.m @@ -14,4 +14,4 @@ end end - precond_water = precondition_waterExchange > 1; % at least two workers need matching conditions + precond_water = precondition_waterExchange > 1 % at least two workers need matching conditions diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index cd5a14c..d5ea01b 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -1,7 +1,7 @@ function PARA = get_parallel_variables(PARA) - index = labindex; - +%ooo index = labindex; + % auxiliary calculations for circular geometry diameter=10; % in [m] area = pi.*(diameter./2)^2; % in [m^2] @@ -96,19 +96,19 @@ PARA.soil.layer_properties = PARA.soil.layer_properties{index}; % different initial conditions -% PARA.Tinitial = [-5 5 5;... -% 0 -5 -5;... -% 1 -5 -5;... -% 10 -8 -8;... -% 20 -10 -10;... -% 100 -10 -10;... -% 2000 10 10]; - PARA.Tinitial = [-5 10 10;... this profile can cause model crashes in mpi... - 0 0 0;... - 5 -5 -5;... - 20 -10 -10;... - 100 -10 -10;... - 2000 10 10]; + PARA.Tinitial = [-5 5 5;... + 0 -5 -5;... + 1 -5 -5;... + 10 -8 -8;... + 20 -10 -10;... + 100 -10 -10;... + 2000 10 10]; +% PARA.Tinitial = [-5 10 10;... this profile can cause model crashes in mpi... +% 0 0 0;... +% 5 -5 -5;... +% 20 -10 -10;... +% 100 -10 -10;... +% 2000 10 10]; PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; diff --git a/modules/cryoGridSEB/L_star.m b/modules/cryoGridSEB/L_star.m index c27c3d9..c0ee3a3 100644 --- a/modules/cryoGridSEB/L_star.m +++ b/modules/cryoGridSEB/L_star.m @@ -25,5 +25,5 @@ L_star=(abs(L_star)>1e6).*L_star./abs(L_star).*1e6 + (abs(L_star)<=1e6).*L_star; % introduced upper limit for Lstar -SEB.ustar = u_star; +SEB.u_star = u_star; %ttt check whether u_star or ustar!? SEB.L_star=[SEB.L_star(2:end) L_star]; \ No newline at end of file diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index 9aed047..bf9e4d6 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -1,5 +1,8 @@ function [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_temp, timestep, BALANCE) + if(~isempty(GRID.lake.water.cT_domain_ub)) %ttt + assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); + end if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis %----------calculate snow surface albedo ------------------------------ @@ -72,7 +75,7 @@ if(isempty(GRID.lake.water.cT_domain_ub) || ~isempty(GRID.lake.ice.cT_domain_ub) ) %tsvd only allow for snow buildup if no lake, or if lake ice exists GRID.snow.SWEinitial = GRID.snow.SWEinitial + FORCING.i.snowfall.*timestep./1000 - GRID.snow.SWEinitial.*0.1.*timestep; end - GRID.lake.residualWater = GRID.lake.residualWater + GRID.snow.SWEinitial.*0.1.*timestep; + GRID.lake.residualWater = GRID.lake.residualWater + GRID.snow.SWEinitial.*0.1.*timestep; % zzz check with Jan: what if rain on lake ice...(collect in residualWater?), where collect rain on lake water? what if SWEinitial exists, then lake ice melts away...? BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - GRID.snow.SWEinitial.*0.1.*timestep*1000; %SWEinitial decreasing counted as surface runoff %----- add the rainfall as runoff in case of no infiltration into frozen ground @@ -89,4 +92,8 @@ PARA.snow.albedo=PARA.snow.max_albedo; SEB.newSnow=0; end + + if(~isempty(GRID.lake.water.cT_domain_ub)) %ttt + assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake (2)!'); + end end \ No newline at end of file diff --git a/modules/cryoGridTechnical/makeGrids.m b/modules/cryoGridTechnical/makeGrids.m index d83f1b7..941e3fd 100644 --- a/modules/cryoGridTechnical/makeGrids.m +++ b/modules/cryoGridTechnical/makeGrids.m @@ -1,6 +1,6 @@ function GRID=makeGrids(PARA) -GRID.snow.snowCellSize=PARA.technical.SWEperCell/(PARA.snow.rho_snow/PARA.constants.rho_w); +GRID.snow.snowCellSize=PARA.technical.SWEperCell/(PARA.snow.rho_snow/PARA.constants.rho_w); % only used to calculate length initial air grid... GRID.snow.snowGrid=[-1.*(PARA.technical.maxSWE./(PARA.technical.SWEperCell)+2).*GRID.snow.snowCellSize:GRID.snow.snowCellSize:-GRID.snow.snowCellSize]'; %tsvd added GRID.lake.water.waterGrid=[0:0.02:PARA.water.depth-0.02]'; %with water (it is recommended to use a grid resolution of about 2cm) diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index a37d4a7..a419cb0 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -186,6 +186,9 @@ TEMPORARY.outputTime=round((TEMPORARY.outputTime+PARA.technical.outputTimestep)./PARA.technical.outputTimestep).*PARA.technical.outputTimestep; + %ooo + index=1 + %write output files if round((t-TEMPORARY.saveTime).*48)==0 iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_output' datestr(t,'yyyy') '.mat' ], OUT); From 8b41d512ba9d9211efe9e85072e188a6c470c4cc Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Sat, 14 Apr 2018 00:14:52 +0200 Subject: [PATCH 37/45] fixes for lateral heat exchange and some more issues solved --- .gitignore | 1 - CryoGrid3_xice_mpi.m | 20 ++++-- analysis/plot_T_02.m | 63 +++++++++++++++++ analysis/plot_output.m | 8 +-- .../CryoGridInfiltration.m | 8 ++- .../surfaceEnergyBalanceInfiltration.m | 12 ++-- .../updateGRID_infiltration.m | 68 +++++++++---------- .../cryoGridExcessIce/excessGroundIceThaw4.m | 4 +- .../updateGRID_excessiceInfiltration2.m | 20 ++---- .../initializeConductivityCapacity.m | 2 +- modules/cryoGridLake/initializeLAKE.m | 2 +- .../calculateLateralHeatFluxes.m | 45 ++++++------ modules/cryoGridLateral/getMaxWaterAltitude.m | 2 +- .../cryoGridLateral/get_parallel_variables.m | 8 +-- modules/cryoGridSEB/L_star.m | 2 +- modules/cryoGridSEB/surfaceCondition.m | 4 +- modules/cryoGridSnow/CryoGridSnow.m | 5 +- modules/cryoGridSnow/updateGRID_snow.m | 8 +-- modules/cryoGridTechnical/getAltitude.m | 2 +- modules/cryoGridTechnical/getSoilAltitude.m | 2 +- .../cryoGridTechnical/getWaterTableAltitude.m | 2 +- modules/cryoGridTechnical/makeGrids.m | 2 +- .../cryoGridTechnical/sum_up_output_store.m | 3 +- 23 files changed, 177 insertions(+), 116 deletions(-) create mode 100644 analysis/plot_T_02.m diff --git a/.gitignore b/.gitignore index c1e7d69..4996338 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -analysis forcing runs *.asv diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 65183b6..f5944b7 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -200,12 +200,21 @@ PARA = get_parallel_variables( PARA ); end + disp('Running experiment with xxxx -> give switches here') % ------make output directory (name depends on parameters) ---------------- - run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) ], ... - [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction] ) ; - +% run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) , ... +% PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, index ] ) + run_number= sprintf( 'LAKE-MPI_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_i%d' , ... + [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... + PARA.modules.infiltration, PARA.modules.xice, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , index ] ) mkdir([ saveDir '/' run_number]); + %tsvd ------redirect command line output to logfile --------------------------- + % if createLogFile +% diary(['./' run_number '/' run_number '_log.mat']); + diary([ saveDir '/' run_number '/' run_number '_log.mat']); + % end + %-------------------------------------------------------------------------- %-----------do not modify from here onwards-------------------------------- %-------------------------------------------------------------------------- @@ -242,7 +251,8 @@ T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); %---- modification for infiltration - wc=GRID.soil.cT_water; + wc=GRID.soil.cT_water; + %tsvd wc=GRID.general.cT_water; GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; @@ -465,7 +475,7 @@ % calculate lateral water fluxes PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); - PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); + PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); %jjj for j=1:number_of_realizations if j~=index labSend( PACKAGE_waterExchange, j, 2); diff --git a/analysis/plot_T_02.m b/analysis/plot_T_02.m new file mode 100644 index 0000000..e437c53 --- /dev/null +++ b/analysis/plot_T_02.m @@ -0,0 +1,63 @@ +% plot T timeseries for various depth + +% OUT=OUTS{2}.OUT; GRID=OUTS{2}.GRID; PARA=OUTS{2}.PARA + +% GRID=g1; PARA=p1; OUT=o1; +%% +figure(1) + +outputfile = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_output1980.mat' +configfile = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_settings.mat' + +load(outputfile); load(configfile); + +%z_soil=GRID.soil.soilGrid; ub_soil=GRID.soil.cT_domain_ub; +zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); + +tstamp=OUT.timestamp; +T=OUT.cryoGrid3; +Tsoil=T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb,:); + +txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; +txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; +%plot(tstamp,T(ub_soil:end,:)) +plot(tstamp,T(ub_soil:10:end,:)) +grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; + +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +%text(xxx(1),0.8*yyy(2),txt_forcing, 'Interpreter', 'none') +title(txt_forcing, 'Interpreter', 'none') + +%% +figure(2) + +outputfile = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_output1980.mat' +configfile = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_settings.mat' + +load(outputfile); load(configfile); + +%z_soil=GRID.soil.soilGrid; ub_soil=GRID.soil.cT_domain_ub; + +tstamp=OUT.timestamp; +T=OUT.cryoGrid3; + +txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; +txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; +%plot(tstamp,T(ub_soil:end,:)) +plot(tstamp,T(ub_soil:10:end,:)) +grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; + +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +%text(xxx(1),0.8*yyy(2),txt_forcing, 'Interpreter', 'none') +title(txt_forcing, 'Interpreter', 'none') + +%% +%[ ~ ,idx ] = min( abs( datenum(1979, 7, 1 ) - OUT.timestamp() )) % find index of date +figure(3) +year=1979; +[~,tJan]=min(abs(datenum(year,1,1)-OUT.timestamp())); [~,tApr]=min(abs(datenum(year,4,1)-OUT.timestamp())); [~,tJul]=min(abs(datenum(year,7,1)-OUT.timestamp())); [~,tOct]=min(abs(datenum(year,10,1)-OUT.timestamp())); %1. Jan 1. Apr 1.Jul 1.Oct + +z2=101; z10=261; % corresponds to 2m, 10m +plot(Tsoil(1:z1,ti),zsoil(1:z1)) +set(gca,'Ydir','reverse'); xlabel('T'); ylabel('z'); grid on +title(datestr(tstamp(ti))) diff --git a/analysis/plot_output.m b/analysis/plot_output.m index 74bf212..2833134 100644 --- a/analysis/plot_output.m +++ b/analysis/plot_output.m @@ -12,9 +12,9 @@ % runname = 'testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2'; %runname = ' TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH1_xW1_xS0_rf1_sf1'; %runname ='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; -runname='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; - -number_of_realizations = 1 +%runname='TESTRUN-MPI_197906-198007_stratSAM_geomHEX_extFluxT-0.005_xH0_xW0_xS0_rf1_sf1'; +runname='LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization' +number_of_realizations = 2 % %% load output data and settings from files of all workers @@ -42,7 +42,7 @@ %outputfile = [dir run '\' run '_output1979.mat']; %configfile = [dir run '\' run '_settings.mat']; - outputfile = ['..\runs\' run '_output1979.mat']; + outputfile = ['..\runs\' run '_output1980.mat']; configfile = ['..\runs\' run '_settings.mat']; %outputfile = 'E:\CryoGrid3\runs\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2\testrunMPI_POOL_xH1_xW1_xS1_infil1_xice1_rF1_sF1_realization2_output1979.mat' diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m index f1ce3bd..0b85377 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m @@ -1,7 +1,9 @@ function [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_flux_rate) -if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 %no snow cover and uppermost grid cell unfrozen - +% if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 %no snow cover and uppermost grid cell unfrozen +% zzz check whether it helps to exclude lake case + if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 || ~isempty (GRID.lake.water.cT_domain_ub) || ~isempty (GRID.lake.ice.cT_domain_ub) %no snow cover and uppermost grid cell unfrozen + % possible contribution from xice meltwater, snowmelt, rain on frozen ground residualWater = GRID.lake.residualWater; GRID.lake.residualWater=0; @@ -70,7 +72,7 @@ % step 3: LUT update % JAN:recalculate lookup tables when water content of freezing grid cells % has changed (infiltrated cells can freeze --> LUT is updated) -if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 +if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 %zzz jjj disp('infiltration - reinitializing LUT - freezing of infiltrated cell(s)'); GRID.soil.cT_water = wc; GRID = initializeSoilThermalProperties(GRID, PARA); diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m index 2487303..8ba7ee2 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m @@ -58,13 +58,14 @@ %calculate ET - %snow cover or uppermost grid cell frozen --> no ET + %snow cover or uppermost grid cell frozen, or lake ice --> no ET %tsvd added from version FLAKE if PARA.modules.infiltration - if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || ~isempty(GRID.lake.water.cT_domain_ub) %zzz islake ... %snow cover or uppermost grid cell frozen --> no ET tsvd: addition case LAKE added + if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || ~isempty(GRID.lake.ice.cT_domain_ub) %lll water replaced by ice %snow cover or uppermost grid cell frozen --> no ET tsvd: addition case LAKE added Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); % unfrozen water body at surface - elseif GRID.lake.unfrozenWaterSurface % zzz check + %tsvd elseif GRID.lake.unfrozenWaterSurface % zzz + elseif ~isempty(GRID.lake.water.cT_domain_ub) Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); dwc_dt(1)=-Qe./L; %in m water per sec, this can be evaporation or condensation @@ -110,7 +111,8 @@ SEB.Qg = Qg; SEB.Sout = Sout; SEB.Lout = Lout; - %tsvd - SEB.Sin_water=Sin_water; +%tsvd +SEB.Sin_water=Sin_water; + end diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m index ae7c110..8ac4d63 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m @@ -3,36 +3,37 @@ %%% step 2: GRID update %%% TODO: add a function updateGRID_infiltration - soilGRIDsizeOld = sum(GRID.soil.cT_domain); - - %%% step 2a) remove cells filled with air (e.g. due to evaporation - %%% of uppermost grid cell ) - while (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+wc(1)<=0) - disp('infiltration - update GRID - removing air cell') - - % adjust air and soil domains and boundaries - GRID.air.cT_domain(GRID.soil.cT_domain_ub)=1; - GRID.air.K_domain(GRID.soil.K_domain_ub)=1; - GRID.air.cT_domain_lb=GRID.air.cT_domain_lb+1; - GRID.air.K_domain_lb=GRID.air.K_domain_lb+1; - GRID.soil.cT_domain(GRID.soil.cT_domain_ub)=0; - GRID.soil.K_domain(GRID.soil.K_domain_ub)=0; - GRID.soil.cT_domain_ub=GRID.soil.cT_domain_ub+1; - GRID.soil.K_domain_ub=GRID.soil.K_domain_ub+1; - GRID.soil.soilGrid(1)=[]; - - wc(1)=[]; - - GRID.soil.cT_organic(1)=[]; - GRID.soil.cT_natPor(1)=[]; - GRID.soil.cT_actPor(1)=[]; - GRID.soil.cT_mineral(1)=[]; - GRID.soil.cT_soilType(1)=[]; - - GRID.soil.excessGroundIce(1)=[]; - + soilGRIDsizeOld = sum(GRID.soil.cT_domain); %zzz use grid + lake? + + %%% step 2a) remove cells filled with air (e.g. due to evaporation of uppermost grid cell ) + + if(isempty(GRID.lake.water.cT_domain_ub)) %tsvd only update grid when no lake exists zzz include case when lake level is dynamic! + while (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+wc(1)<=0) + disp('infiltration - update GRID - updating air cell') + + % adjust air and soil domains and boundaries zzz check how to adapt for lake... + GRID.air.cT_domain(GRID.soil.cT_domain_ub)=1; + GRID.air.K_domain(GRID.soil.K_domain_ub)=1; + GRID.air.cT_domain_lb=GRID.air.cT_domain_lb+1; + GRID.air.K_domain_lb=GRID.air.K_domain_lb+1; + GRID.soil.cT_domain(GRID.soil.cT_domain_ub)=0; + GRID.soil.K_domain(GRID.soil.K_domain_ub)=0; + GRID.soil.cT_domain_ub=GRID.soil.cT_domain_ub+1; + GRID.soil.K_domain_ub=GRID.soil.K_domain_ub+1; + GRID.soil.soilGrid(1)=[]; + + wc(1)=[]; + + GRID.soil.cT_organic(1)=[]; + GRID.soil.cT_natPor(1)=[]; + GRID.soil.cT_actPor(1)=[]; + GRID.soil.cT_mineral(1)=[]; + GRID.soil.cT_soilType(1)=[]; + + GRID.soil.excessGroundIce(1)=[]; + end end - + %%% step 2b) ponding of surface runoff below water table while surface_runoff>1e-6 && ... % not >0 as sometimes numerical errors occur during calculation of surface_runoff PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub) LUT update soilGRIDsizeNew = sum(GRID.soil.cT_domain); if soilGRIDsizeOld~=soilGRIDsizeNew - disp('infiltration - reinitializing LUT - soil/air domains changed'); + disp(['infiltration - reinitializing LUT - soil/air domains changed on worker ',num2str(labindex)]); GRID.soil.cT_water = wc; GRID = initializeSoilThermalProperties(GRID, PARA); end - - end \ No newline at end of file diff --git a/modules/cryoGridExcessIce/excessGroundIceThaw4.m b/modules/cryoGridExcessIce/excessGroundIceThaw4.m index 6d98e90..8ac0650 100644 --- a/modules/cryoGridExcessIce/excessGroundIceThaw4.m +++ b/modules/cryoGridExcessIce/excessGroundIceThaw4.m @@ -14,7 +14,7 @@ K_delta=GRID.general.K_delta(GRID.soil.cT_domain); -mobileWater = double(T(GRID.soil.cT_domain)>0) .* (water-natPor) .* double(water>natPor); +mobileWater = double(T(GRID.soil.cT_domain)>0) .* (water-natPor) .* double(water>natPor); %zzz [startCell ~]= LayerIndex(mobileWater~=0); %this is faster %move solids down @@ -57,7 +57,7 @@ if mineral(i)+organic(i)==0 water(i)=min(K_delta(i), mobileWater); mobileWater=mobileWater-water(i); - water(i)=round(water(i)./K_delta(i)).*K_delta(i); %this violates the water balance, but ensures that no grid cells with partly water and partly air can exist; + water(i)=round(water(i)./K_delta(i)).*K_delta(i); %this violates the water balance, but ensures that no grid cells with partly water and partly air can exist; zzz end end diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m index 13339a7..6895cbe 100644 --- a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m @@ -1,12 +1,14 @@ function [GRID] = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID) -%tsvd GRID.lake.water.cT/Kdomain replaced by GRID.lake.water.* +%tsvd GRID.lake.cT_domain and GRID.lake.K_domain replaced by GRID.lake.water.* % pass excess meltwater to storage variable GRID.lake.residualWater = GRID.lake.residualWater + meltwaterGroundIce; - % update GRID domains of water body - if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 % upper soil cell pure air/water + % update GRID domains of water body zzz +%tsvd if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 % upper soil cell pure air/water (and no lake exists) + if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 && isempty(GRID.lake.water.cT_domain_ub) && isempty(GRID.lake.ice.cT_domain_ub) % upper soil cell pure air/water or no lake + % general water body extent cT_waterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6; GRID.lake.water.cT_domain(logical(GRID.air.cT_domain+GRID.snow.cT_domain)) = 0; @@ -39,15 +41,5 @@ [GRID.lake.water.cT_domain_lb, GRID.lake.water.cT_domain_ub] = LayerIndex(GRID.lake.water.cT_domain); [GRID.lake.water.K_domain_lb, GRID.lake.water.K_domain_ub] = LayerIndex(GRID.lake.water.K_domain); end - - - - - - - - - - - + end \ No newline at end of file diff --git a/modules/cryoGridInitialize/initializeConductivityCapacity.m b/modules/cryoGridInitialize/initializeConductivityCapacity.m index f8a0943..50d9fea 100644 --- a/modules/cryoGridInitialize/initializeConductivityCapacity.m +++ b/modules/cryoGridInitialize/initializeConductivityCapacity.m @@ -42,5 +42,5 @@ lwc_temp(GRID.lake.water.cT_domain) = 1.; c_temp(GRID.lake.ice.cT_domain) = PARA.constants.c_i; -k_temp(GRID.lake.ice.cT_domain) = 2.29; ; % in loadConstants.m 2.2 is used! FLAKE: Molecular heat conductivity of ice [J m^{-1} s^{-1} K^{-1}] +k_temp(GRID.lake.ice.cT_domain) = 2.29; ; % in loadConstants.m 2.2 is used! FLAKE: Molecular heat conductivity of ice [J m^{-1} s^{-1} K^{-1}] zzz lwc_temp(GRID.lake.ice.cT_domain) = 0.; diff --git a/modules/cryoGridLake/initializeLAKE.m b/modules/cryoGridLake/initializeLAKE.m index 60a6738..de8cbb3 100644 --- a/modules/cryoGridLake/initializeLAKE.m +++ b/modules/cryoGridLake/initializeLAKE.m @@ -1,6 +1,6 @@ function [FLAKE GRID] = initializeLAKE(GRID, PARA); -GRID.lake.unfrozenWaterSurface = false; % zzz needed? +% GRID.lake.unfrozenWaterSurface = false; %tsvd not needed anymore GRID.lake.residualWater = 0; % the water content stored "mixed" cells of air and water if a water body is present %---- flake initialization ------------------------------------------------ diff --git a/modules/cryoGridLateral/calculateLateralHeatFluxes.m b/modules/cryoGridLateral/calculateLateralHeatFluxes.m index bee9522..866ea05 100644 --- a/modules/cryoGridLateral/calculateLateralHeatFluxes.m +++ b/modules/cryoGridLateral/calculateLateralHeatFluxes.m @@ -1,7 +1,6 @@ function [dE_dt, BALANCE] = calculateLateralHeatFluxes(T_index, k_index, PACKAGE_heatExchange_j, GRID, PARA, BALANCE, j) -%ooo index = labindex; - index=1 + index = labindex; dE_dt = zeros( length(GRID.general.cT_grid), 1); if PARA.ensemble.thermal_contact_length(index,j)>0 % calculate lateral heat flux only for laterally connected workers @@ -18,32 +17,30 @@ % interpolate j-values to index-grid altitude_cTgrid_j = -PACKAGE_heatExchange_j.cT_grid + PARA.ensemble.initial_altitude(j); - min_contact_altitude = min( [altitude_cTgrid_index(end), altitude_cTgrid_j(end)] ); + min_contact_altitude = min( [altitude_cTgrid_index(end), altitude_cTgrid_j(end)] ); %zzz max instead of min def. also max_contact_alt ? altitude_cTgrid_index(end) = min_contact_altitude; altitude_cTgrid_j(end) = min_contact_altitude; T_j = PACKAGE_heatExchange_j.T; k_j = PACKAGE_heatExchange_j.k_cTgrid; - if ~isreal(altitude_cTgrid_index) %likley not relevant anymore - disp('altitude_cTgrid_index contains complex values'); - end - if ~isreal(altitude_cTgrid_j) - disp('altitude_cTgrid_j contains complex values'); - end - if ~isreal(T_j) - disp('T_j contains complex values'); - end - if ~isreal(k_j) - disp('k_j contains complex values'); - end - T_interp_j = interp1( altitude_cTgrid_j, T_j, altitude_cTgrid_index, 'linear'); - try - assert( sum( isnan( T_interp_j ) )==0, 'calc lat heat fluxes - error in T interpolation') %ttt - catch - save Data_Tinterp T_interp_j altitude_cTgrid_j T_j altitude_cTgrid_index - end - k_interp_j = interp1( altitude_cTgrid_j, k_j, altitude_cTgrid_index, 'linear'); - assert( sum( isnan( k_interp_j ) )==0, 'calc lat heat fluxes - error in k interpolation') %ttt - + if ~isreal(altitude_cTgrid_index); disp('altitude_cTgrid_index contains complex values'); end %likley not relevant anymore + if ~isreal(altitude_cTgrid_j); disp('altitude_cTgrid_j contains complex values'); end + if ~isreal(T_j); disp('T_j contains complex values'); end + if ~isreal(k_j); disp('k_j contains complex values'); end + + T_interp_j = interp1( altitude_cTgrid_j, T_j, altitude_cTgrid_index, 'linear'); +% try +% assert( sum( isnan( T_interp_j ) )==0, 'calc lat heat fluxes - error in T interpolation') %ttt +% catch +% save Data_Tinterp T_interp_j altitude_cTgrid_j T_j altitude_cTgrid_index index +% % error('interpolation NAN T error') +% end + k_interp_j = interp1( altitude_cTgrid_j, k_j, altitude_cTgrid_index, 'linear'); +% try +% assert( sum( isnan( k_interp_j ) )==0, 'calc lat heat fluxes - error in k interpolation') %ttt +% catch +% save Data_kinterp k_interp_j altitude_cTgrid_j k_j altitude_cTgrid_index index +% error('interpolation NAN K error') +% end % determine effectice thermal conductivities k_eff = (weight_index+weight_j) ./ ( weight_index./k_index + weight_j./k_interp_j ); diff --git a/modules/cryoGridLateral/getMaxWaterAltitude.m b/modules/cryoGridLateral/getMaxWaterAltitude.m index e774051..abb2682 100644 --- a/modules/cryoGridLateral/getMaxWaterAltitude.m +++ b/modules/cryoGridLateral/getMaxWaterAltitude.m @@ -1,3 +1,3 @@ function max_water = getMaxWaterAltitude(PARA) - max_water = max( PARA.ensemble.soil_altitude ) + PARA.soil.relative_maxWater; + max_water = max( PARA.ensemble.soil_altitude ) + PARA.soil.relative_maxWater; %zzz end diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index d5ea01b..349ba1d 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -1,6 +1,6 @@ function PARA = get_parallel_variables(PARA) -%ooo index = labindex; + index = labindex; % auxiliary calculations for circular geometry diameter=10; % in [m] @@ -15,7 +15,7 @@ % topographical relations %tsvd PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids % PARA.ensemble.initial_altitude = [20.0, 20.0]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids - PARA.ensemble.initial_altitude = [0.0, 0.0]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + PARA.ensemble.initial_altitude = [0., 0.]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids PARA.ensemble.altitude = PARA.ensemble.initial_altitude; PARA.ensemble.surface_altitude = PARA.ensemble.initial_altitude; @@ -46,7 +46,7 @@ % location-specific dynamic auxiliary variables PARA.location.area = PARA.ensemble.area(index); PARA.location.altitude = PARA.ensemble.altitude(index); - PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index); + PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index) PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(index); PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); % location-specific dynamic common thresholds @@ -113,6 +113,6 @@ PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; % PARA.water.depth = [1.,0.]; - PARA.water.depth = [0.,1.]; + PARA.water.depth = [0.,1.] %ttt PARA.water.depth = PARA.water.depth(index); end diff --git a/modules/cryoGridSEB/L_star.m b/modules/cryoGridSEB/L_star.m index c0ee3a3..dcf4a82 100644 --- a/modules/cryoGridSEB/L_star.m +++ b/modules/cryoGridSEB/L_star.m @@ -25,5 +25,5 @@ L_star=(abs(L_star)>1e6).*L_star./abs(L_star).*1e6 + (abs(L_star)<=1e6).*L_star; % introduced upper limit for Lstar -SEB.u_star = u_star; %ttt check whether u_star or ustar!? +SEB.u_star = u_star; SEB.L_star=[SEB.L_star(2:end) L_star]; \ No newline at end of file diff --git a/modules/cryoGridSEB/surfaceCondition.m b/modules/cryoGridSEB/surfaceCondition.m index fd84d3e..5ce89ea 100644 --- a/modules/cryoGridSEB/surfaceCondition.m +++ b/modules/cryoGridSEB/surfaceCondition.m @@ -3,7 +3,7 @@ % set surface parameters (albedo, emissivity, roughnesslength, resistance to evaporation) according to the actual surface conditions -GRID.lake.unfrozenWaterSurface=false; % zzz +% GRID.lake.unfrozenWaterSurface=false; %tsvd not needed anymore %default soil surface PARA.surf.albedo = PARA.soil.albedo; @@ -42,7 +42,7 @@ %tsvd check if lake exists %lll if GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface elseif GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface - GRID.lake.unfrozenWaterSurface = true; %tsvd lll + % GRID.lake.unfrozenWaterSurface = true; %tsvd not needed any more %note SolarAzEl.m delivers only an approximation of sun position / t must be in UTC [~, sun_elevation] = SolarAzEl(t,PARA.location.latitude,PARA.location.longitude,PARA.location.altitude); PARA.water.albedo = waterAlbedo(sun_elevation, FORCING.i.wind); diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index bf9e4d6..2133345 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -55,7 +55,7 @@ snowHeight = abs( GRID.general.K_grid(GRID.snow.cT_domain_ub) - GRID.general.K_grid(GRID.snow.cT_domain_lb+1) ); maxSnowHeight = PARA.location.absolute_maxSnow_altitude - getAltitude( PARA, GRID ); - assert(maxSnowHeight - snowHeight >=0,'neg snow height!') %ttt + % assert(maxSnowHeight - snowHeight >=0,'neg snow height!') %ttt deltaSnow_i = max( [ 0, ... min( [ FORCING.i.snowfall.*timestep./1000, ... @@ -79,7 +79,8 @@ BALANCE.water.dr_snowmelt = BALANCE.water.dr_snowmelt - GRID.snow.SWEinitial.*0.1.*timestep*1000; %SWEinitial decreasing counted as surface runoff %----- add the rainfall as runoff in case of no infiltration into frozen ground - if ~PARA.modules.infiltration || (PARA.modules.infiltration && T(GRID.soil.cT_domain_ub)<=0 )%no infiltration scheme or uppermost soil cell frozen + %ppp + if ~PARA.modules.infiltration || (PARA.modules.infiltration && T(GRID.soil.cT_domain_ub)<=0 )%no infiltration scheme or uppermost soil cell frozen zzz GRID.lake.residualWater = GRID.lake.residualWater + FORCING.i.rainfall.*timestep./1000; BALANCE.water.dr_rain = BALANCE.water.dr_rain - FORCING.i.rainfall.*timestep; end diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index aff9af1..6ce079c 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -143,18 +143,18 @@ assert( sum( sum( isnan(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)) ) ) == 0 , 'updateGRID_snow - error in Snow_i/a/w grid' ); % snow grid - soilTop = GRID.general.K_grid(GRID.snow.cT_domain_lb+1); + soilTop = GRID.general.K_grid(GRID.snow.cT_domain_lb+1); %tsvd in case of an lake, soilTop corresponds to lakeTop GRID.general.K_grid(GRID.snow.cT_domain)= soilTop - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); - + GRID.general.K_grid(GRID.air.cT_domain)=[GRID.general.K_grid(GRID.air.cT_domain_lb)+(-snowCellSize)*(GRID.air.cT_domain_lb-1):snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; + assert( sum( isnan( GRID.general.K_grid ) )==0, 'updateGRID_snow - error in K grid after snow grid update') - % air grid + % air grid zzz this is not in FLAKE version... jjj snowTop = GRID.general.K_grid(GRID.snow.cT_domain_ub); numAirCells = sum( GRID.air.cT_domain ); GRID.general.K_grid(GRID.air.cT_domain) = flip( snowTop-snowCellSize:-snowCellSize:snowTop-snowCellSize*numAirCells ); assert( sum( isnan( GRID.general.K_grid ) )==0, 'updateGRID_snow - error in K grid after air grid update') - %GRID.general.K_grid(GRID.air.cT_domain) = [GRID.general.K_grid(GRID.air.cT_domain_lb)+(-2*snowCellSize)*(GRID.air.cT_domain_lb-1):2*snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; end diff --git a/modules/cryoGridTechnical/getAltitude.m b/modules/cryoGridTechnical/getAltitude.m index dc09ebf..376cf53 100644 --- a/modules/cryoGridTechnical/getAltitude.m +++ b/modules/cryoGridTechnical/getAltitude.m @@ -1,5 +1,5 @@ function altitude = getAltitude( PARA, GRID ) - + %zzz same as get soil altitude! used? %tsvd account for lake surface (snow can accumulate on lake ice) if ~isempty( GRID.lake.water.cT_domain_ub )% lake water is present altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.lake.water.cT_domain_ub); diff --git a/modules/cryoGridTechnical/getSoilAltitude.m b/modules/cryoGridTechnical/getSoilAltitude.m index 8995992..93e6f9b 100644 --- a/modules/cryoGridTechnical/getSoilAltitude.m +++ b/modules/cryoGridTechnical/getSoilAltitude.m @@ -1,7 +1,7 @@ function soil_altitude = getSoilAltitude(PARA, GRID) %tsvd GRID.lake.cT_domain replaced by GRID.lake.water.cT_domain -if ~isempty( GRID.lake.water.cT_domain_ub ) +if ~isempty( GRID.lake.water.cT_domain_ub ) %zzz rm what is soil_altitude needed for...? check.... soil_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.lake.water.cT_domain_lb+1); else soil_altitude = PARA.location.initial_altitude - GRID.general.K_grid(GRID.soil.cT_domain_ub); diff --git a/modules/cryoGridTechnical/getWaterTableAltitude.m b/modules/cryoGridTechnical/getWaterTableAltitude.m index c19049a..e5e0400 100644 --- a/modules/cryoGridTechnical/getWaterTableAltitude.m +++ b/modules/cryoGridTechnical/getWaterTableAltitude.m @@ -6,7 +6,7 @@ if ~isempty(GRID.snow.cT_domain_ub) || T(1)<=0 waterTable=NaN; else - waterTable = PARA.location.altitude; + waterTable = PARA.location.altitude; % zzz ???! water = wc; porosity=(1. - GRID.soil.cT_mineral - GRID.soil.cT_organic); i=1; diff --git a/modules/cryoGridTechnical/makeGrids.m b/modules/cryoGridTechnical/makeGrids.m index 941e3fd..59952cd 100644 --- a/modules/cryoGridTechnical/makeGrids.m +++ b/modules/cryoGridTechnical/makeGrids.m @@ -6,7 +6,7 @@ GRID.lake.water.waterGrid=[0:0.02:PARA.water.depth-0.02]'; %with water (it is recommended to use a grid resolution of about 2cm) %GRID.lake.water.waterGrid=[]'; %no water if ~isempty(GRID.lake.water.waterGrid) - GRID.soil.soilGrid=PARA.technical.subsurfaceGrid + (2*GRID.lake.water.waterGrid(end)-GRID.lake.water.waterGrid(end-1)); + GRID.soil.soilGrid=PARA.technical.subsurfaceGrid + (2*GRID.lake.water.waterGrid(end)-GRID.lake.water.waterGrid(end-1)); %zzz ok? else GRID.soil.soilGrid=PARA.technical.subsurfaceGrid; end diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index a419cb0..c368990 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -186,8 +186,7 @@ TEMPORARY.outputTime=round((TEMPORARY.outputTime+PARA.technical.outputTimestep)./PARA.technical.outputTimestep).*PARA.technical.outputTimestep; - %ooo - index=1 + %ooo index=1 %write output files if round((t-TEMPORARY.saveTime).*48)==0 From e91820bbea9811bd69c249053b379cba07f80fd7 Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Mon, 23 Apr 2018 14:18:56 +0200 Subject: [PATCH 38/45] Lstar limited to [-1e-4 1e4], further NAN checks included and some lake/soil specific conditions modified --- CryoGrid3_xice_mpi.m | 29 +++-- analysis/plot_T_02.m | 63 ---------- analysis/plot_T_04.m | 112 ++++++++++++++++++ .../CryoGridInfiltration.m | 6 +- .../surfaceEnergyBalanceInfiltration.m | 13 +- .../updateGRID_infiltration.m | 44 +++++-- .../cryoGridLateral/get_parallel_variables.m | 29 +++-- modules/cryoGridSEB/L_star.m | 9 +- modules/cryoGridSEB/Q_eq.m | 3 + modules/cryoGridSEB/surfaceEnergyBalance.m | 63 ---------- modules/cryoGridSnow/updateGRID_snow.m | 35 ++---- 11 files changed, 221 insertions(+), 185 deletions(-) delete mode 100644 analysis/plot_T_02.m create mode 100644 analysis/plot_T_04.m delete mode 100644 modules/cryoGridSEB/surfaceEnergyBalance.m diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index f5944b7..1563633 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -6,8 +6,11 @@ % % ------------------------------------------------------------------------- clear all - close all - + close all + +%ttt fileID1 = fopen('log_updateGridInfil_1.txt','w') +% fileID2 = fopen('log_updateGridInfil_2.txt','w') + par_mode = 1; % parallel mode off/on if(par_mode==1) @@ -27,7 +30,7 @@ end %nnn -spmd +spmd %zzz use function calls to calls below to enable debugging in par mode! index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run %nnn index=1 @@ -40,6 +43,11 @@ 0.15 0.65 0.3 0.05 2 0.65;... 0.9 0.65 0.3 0.05 1 0.65;... 9.0 0.30 0.70 0.00 1 0.30 ]; + +% disp('new stratigraphy........') +% PARA.soil.layer_properties = [0.0 0.2 0.7 0.00 1 0.30 ;... +% 1.0 0.2 0.7 0.00 1 0.30 ;... +% 10.0 0.1 0.8 0.00 1 0.2 ]; % simple stratigraphy with excess ice used to test water balance: % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... % 0.4 0.8 0.2 0.00 1 0.40;... @@ -115,8 +123,8 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1979, 6, 10); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1980, 7, 1); % endtime of the simulation - if empty end at last value of time series + PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(1980, 12, 31); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -175,11 +183,12 @@ %FORCING data mat-file PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + %PARA.forcing.filename='CG3_CCLM_forcing_90_101'; PARA.forcing.rain_fraction=1; PARA.forcing.snow_fraction=1; % switches for modules - PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs + PARA.modules.infiltration=0; % true if infiltration into unfrozen ground occurs PARA.modules.xice=0; % true if thaw subsicdence is enabled PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) %tsvd extended for lateral switched off @@ -200,7 +209,7 @@ PARA = get_parallel_variables( PARA ); end - disp('Running experiment with xxxx -> give switches here') + disp('Running experiment with xxxx -> indicate switches here') % ------make output directory (name depends on parameters) ---------------- % run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) , ... % PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, index ] ) @@ -276,8 +285,7 @@ disp('initialization successful'); %%% nnn - iSaveSettings( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_settings.mat'] , FORCING, PARA, GRID) - + iSaveSettings( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_settings.mat'] , FORCING, PARA, GRID) %tsvd non-interpolated forcing data saved! %% ________________________________________________________________________ % Time Integration Routine I @@ -295,7 +303,7 @@ %------ interpolate forcing data to time t ---------------------------- FORCING = interpolateForcingData(t, FORCING); - + %------determine the thermal properties of the model domains ---------- [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = getThermalPropertiesInfiltration(T, wc, c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid, GRID, PARA); @@ -582,3 +590,4 @@ end disp('Done.'); + diff --git a/analysis/plot_T_02.m b/analysis/plot_T_02.m deleted file mode 100644 index e437c53..0000000 --- a/analysis/plot_T_02.m +++ /dev/null @@ -1,63 +0,0 @@ -% plot T timeseries for various depth - -% OUT=OUTS{2}.OUT; GRID=OUTS{2}.GRID; PARA=OUTS{2}.PARA - -% GRID=g1; PARA=p1; OUT=o1; -%% -figure(1) - -outputfile = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_output1980.mat' -configfile = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_settings.mat' - -load(outputfile); load(configfile); - -%z_soil=GRID.soil.soilGrid; ub_soil=GRID.soil.cT_domain_ub; -zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); - -tstamp=OUT.timestamp; -T=OUT.cryoGrid3; -Tsoil=T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb,:); - -txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; -txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; -%plot(tstamp,T(ub_soil:end,:)) -plot(tstamp,T(ub_soil:10:end,:)) -grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; - -xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) -%text(xxx(1),0.8*yyy(2),txt_forcing, 'Interpreter', 'none') -title(txt_forcing, 'Interpreter', 'none') - -%% -figure(2) - -outputfile = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_output1980.mat' -configfile = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_settings.mat' - -load(outputfile); load(configfile); - -%z_soil=GRID.soil.soilGrid; ub_soil=GRID.soil.cT_domain_ub; - -tstamp=OUT.timestamp; -T=OUT.cryoGrid3; - -txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; -txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; -%plot(tstamp,T(ub_soil:end,:)) -plot(tstamp,T(ub_soil:10:end,:)) -grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; - -xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) -%text(xxx(1),0.8*yyy(2),txt_forcing, 'Interpreter', 'none') -title(txt_forcing, 'Interpreter', 'none') - -%% -%[ ~ ,idx ] = min( abs( datenum(1979, 7, 1 ) - OUT.timestamp() )) % find index of date -figure(3) -year=1979; -[~,tJan]=min(abs(datenum(year,1,1)-OUT.timestamp())); [~,tApr]=min(abs(datenum(year,4,1)-OUT.timestamp())); [~,tJul]=min(abs(datenum(year,7,1)-OUT.timestamp())); [~,tOct]=min(abs(datenum(year,10,1)-OUT.timestamp())); %1. Jan 1. Apr 1.Jul 1.Oct - -z2=101; z10=261; % corresponds to 2m, 10m -plot(Tsoil(1:z1,ti),zsoil(1:z1)) -set(gca,'Ydir','reverse'); xlabel('T'); ylabel('z'); grid on -title(datestr(tstamp(ti))) diff --git a/analysis/plot_T_04.m b/analysis/plot_T_04.m new file mode 100644 index 0000000..af78829 --- /dev/null +++ b/analysis/plot_T_04.m @@ -0,0 +1,112 @@ +% plot T timeseries for various depth + +% OUT=OUTS{2}.OUT; GRID=OUTS{2}.GRID; PARA=OUTS{2}.PARA + +%p1=PARA{1}; p2=PARA{2}; g1=GRID{1}; g2=GRID{2}; o1=OUT{1}; o2=OUT{2}; + +dz=10; % increment used to plot vertical levels +%% Non_Lake + +% no infil no ex no lake +% outputfile1 = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_output1980.mat' +% configfile1 = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_settings.mat' +% outputfile2 = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_output1980.mat' +% configfile2 = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_settings.mat' +% +outputfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_output1980.mat' +configfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_settings.mat' +outputfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2_realization2_output1980.mat' +configfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2_realization2_settings.mat' + +load(outputfile1); load(configfile1); + +%PARA=p1; GRID=g1; OUT=o1; +%z_soil=GRID.soil.soilGrid; ub_soil=GRID.soil.cT_domain_ub; +zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); +tstamp=OUT.timestamp; +T=OUT.cryoGrid3; TSoil=T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb,:); %TLakeWater=T(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb,:); TLakeIce=T(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb,:); +%TAir=T(GRID.air.cT_domain_ub:GRID.air.cT_domain_lb,:); + +TSnow=T(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb,:); +TSnow_lb=T(GRID.lake.water.cT_domain_ub-1,:); + +% Forcing + tspan=FORCING.data.t_span; +[ ~ ,idx1 ] = min( abs( tstamp(1) - tspan )); [ ~ ,idx2 ] = min( abs( tstamp(end) - tspan )); +tstamp_forcing=FORCING.data.t_span(idx1:idx2); +Tair=FORCING.data.Tair(idx1:idx2); + + figure(1) +txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; +txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; +%plot(tstamp,T(ub_soil:end,:)) +plot(tstamp,T) +%hold on; plot(tstamp,Tair,'LineWidth',2); hold off +grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +title(txt_forcing, 'Interpreter', 'none') + + figure(2) +%plot(tstamp,TAir,'b', tstamp,TSnow,'y',tstamp,TLakeWater,'b',tstamp,TLakeIce,'c',tstamp,TSoil,'g') +%plot(tstamp,TSnow,'k--',tstamp,TSoil(1:dz:end,:),'g') +plot(tstamp,TSoil(1:dz:end,:),'g') +%hold on +% if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLakeWater(1:dz:end,:),'b'); end +% if(~isempty(GRID.lake.ice.cT_domain_ub)); plot(tstamp,TLakeIce(1:dz:end,:),'c'); end +% hold off +grid on; datetick; xlabel('timestamp'); ylabel('T Soil (°C)'); grid on; + +%% LAKE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%PARA=p2; GRID=g2; OUT=o2; +load(outputfile2); load(configfile2); +zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); +tstamp=OUT.timestamp; +T=OUT.cryoGrid3; TSoil=T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb,:); %TLakeWater=T(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb,:); TLakeIce=T(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb,:); +%TAir=T(GRID.air.cT_domain_ub:GRID.air.cT_domain_lb,:); +TSnow=T(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb,:); +TSnow_lb=T(GRID.lake.water.cT_domain_ub-1,:); +TLake = T(GRID.soil.cT_domain_ub-50:GRID.soil.cT_domain_ub-1,:); % lake 50 layers +Tx1 = T(GRID.soil.cT_domain_ub-51,:); +Tx2 = T(GRID.soil.cT_domain_ub+1,:); + + figure(11) +txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; +txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; +plot(tstamp,T) +grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +title(txt_forcing, 'Interpreter', 'none') + + figure(12) +%plot(tstamp,TAir,'b', tstamp,TSnow,'y',tstamp,TLakeWater,'b',tstamp,TLakeIce,'c',tstamp,TSoil,'g') +%plot(tstamp,TSnow,'k--',tstamp,TSoil(1:dz:end,:),'g') +plot(tstamp,TSoil(1:dz:end,:),'g') +hold on +if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLake(1:dz:end,:),'b'); end +%if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLakeWater(1:dz:end,:),'b'); end +%if(~isempty(GRID.lake.ice.cT_domain_ub)); plot(tstamp,TLakeIce(1:dz:end,:),'c'); end +hold off +grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; + + +%% +%[ ~ ,idx ] = min( abs( datenum(1979, 7, 1 ) - OUT.timestamp() )) % find index of date + figure(30) +year=1980; +[~,tJan]=min(abs(datenum(year,1,1)-tstamp())); [~,tFeb]=min(abs(datenum(year,2,1)-tstamp())); [~,tMar]=min(abs(datenum(year,3,1)-tstamp())); [~,tApr]=min(abs(datenum(year,4,1)-tstamp())); [~,tMay]=min(abs(datenum(year,5,1)-tstamp())); [~,tJun]=min(abs(datenum(year,6,1)-tstamp())); +[~,tJul]=min(abs(datenum(year,7,1)-tstamp())); [~,tAug]=min(abs(datenum(year,8,1)-tstamp())); [~,tSep]=min(abs(datenum(year,9,1)-tstamp())); [~,tOct]=min(abs(datenum(year,4,10)-tstamp())); [~,tNov]=min(abs(datenum(year,5,11)-tstamp())); [~,tDec]=min(abs(datenum(year,12,1)-tstamp())); + +z2m=101; z10m=261; % corresponds to 2m, 10m +zend=z2m; +plot(TSoil(1:zend,tJan),zsoil(1:zend),TSoil(1:zend,tFeb),zsoil(1:zend),TSoil(1:zend,tMar),zsoil(1:zend),TSoil(1:zend,tApr),zsoil(1:zend),TSoil(1:zend,tMay),zsoil(1:zend),TSoil(1:zend,tJun),zsoil(1:zend),... + TSoil(1:zend,tJul),zsoil(1:zend),TSoil(1:zend,tAug),zsoil(1:zend),TSoil(1:zend,tSep),zsoil(1:zend),TSoil(1:zend,tOct),zsoil(1:zend),TSoil(1:zend,tNov),zsoil(1:zend),TSoil(1:zend,tDec),zsoil(1:zend)) +hold on; +set(gca,'Ydir','reverse'); xlabel('T'); ylabel('z'); grid on +legend(datestr(tstamp(tJan)),datestr(tstamp(tFeb)),datestr(tstamp(tMar)),datestr(tstamp(tApr)),datestr(tstamp(tMay)),datestr(tstamp(tJun)),datestr(tstamp(tJul)),datestr(tstamp(tAug)),datestr(tstamp(tSep)),datestr(tstamp(tOct)),datestr(tstamp(tNov)),datestr(tstamp(tDec))) + + +figure(99) +hold on +plot(tstamp,TLake,'b',tstamp,Tx1,'g',tstamp,Tx2,'r') +grid on; datetick +hold off \ No newline at end of file diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m index 0b85377..9889dc7 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m @@ -2,7 +2,8 @@ % if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 %no snow cover and uppermost grid cell unfrozen % zzz check whether it helps to exclude lake case - if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 || ~isempty (GRID.lake.water.cT_domain_ub) || ~isempty (GRID.lake.ice.cT_domain_ub) %no snow cover and uppermost grid cell unfrozen +%lll if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 || ~isempty (GRID.lake.water.cT_domain_ub) || ~isempty (GRID.lake.ice.cT_domain_ub) %no snow cover and uppermost grid cell unfrozen + if (isempty (GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 ) || (~isempty (GRID.lake.water.cT_domain_ub) && isempty (GRID.lake.ice.cT_domain_ub) ) %no snow cover and uppermost grid cell unfrozen % possible contribution from xice meltwater, snowmelt, rain on frozen ground residualWater = GRID.lake.residualWater; @@ -39,8 +40,7 @@ % remove water above water table in case of ponding, e.g. through rain (independent of xice module) if GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)<1e-6 && ... - PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub)>PARA.location.absolute_maxWater_altitude - + PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub)>PARA.location.absolute_maxWater_altitude %zzz check for lake... cellSize = GRID.general.K_delta(GRID.soil.cT_domain_ub); actualWater = wc(1)*cellSize; diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m index 8ba7ee2..43bc6a1 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m @@ -21,11 +21,11 @@ dE_dt(GRID.air.cT_domain_lb+1,1)=(1-PARA.surf.albedo).*FORCING.i.Sin; %------ snow surface (solid state green house effect) --------------------- if ~isempty(GRID.snow.cT_domain_ub) - beta=PARA.snow.extinction; + beta=PARA.snow.extinction; % zzz also consider lake ice extinction... Qsolar(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb+1) = dE_dt(GRID.snow.cT_domain_ub) .* exp(-beta.*(GRID.general.K_grid(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb+1)-GRID.general.K_grid(GRID.snow.cT_domain_ub))); dE_dt(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb) = -Qsolar(GRID.snow.cT_domain_ub+1:GRID.snow.cT_domain_lb+1) + Qsolar(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb); %put the rest to cell below snow - dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); + dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); %mmm zzz can be too much dE if thin lake ice? end %tsvd @@ -49,7 +49,7 @@ %put the rest to cell below water body dE_dt(GRID.lake.water.cT_domain_lb+1) = Qsolar(GRID.lake.water.cT_domain_lb+1); %SW output for FLAKE radiation scheme - Sin_water = Qsolar(GRID.lake.water.cT_domain_ub); + Sin_water = Qsolar(GRID.lake.water.cT_domain_ub); %mmm Sin_ice missing above? end %__________________________________________________________________________ Sout = PARA.surf.albedo*FORCING.i.Sin; @@ -78,7 +78,7 @@ fraction_E=getET_fraction(T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.E_lb-1), wc(1:GRID.soil.E_lb), PARA.soil.fieldCapacity, PARA.soil.residualWC); fraction_ET = fraction_T.*PARA.soil.ratioET; fraction_ET(1:GRID.soil.E_lb) = fraction_ET(1:GRID.soil.E_lb) + fraction_E.*(1-PARA.soil.ratioET); - + Qe=sum(fraction_ET.*GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1))./sum(GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1)).*Qe_pot; fraction_ET=fraction_ET.*GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1)./sum(fraction_ET.*GRID.general.K_delta(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1)); % sum(fraction_ET) is always 1 @@ -88,6 +88,7 @@ dwc_dt(1)=-Qe./L; %in m water per sec, put everything in uppermost grid cell end end + else % this is identical to case with snow cover or frozen ground Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); end @@ -114,5 +115,9 @@ %tsvd SEB.Sin_water=Sin_water; +assert(~isnan(SEB.Qe),'Qe is NAN!') +assert(~isnan(SEB.Qh),'Qh is NAN!') +assert(~isnan(SEB.Qnet),'Qnet is NAN!') + end diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m index 8ac4d63..210cca7 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/updateGRID_infiltration.m @@ -1,6 +1,11 @@ function [ wc, GRID, surface_runoff ] = updateGRID_infiltration(wc, GRID, PARA, surface_runoff) - %%% step 2: GRID update +% create log files before run execution manually... + +% fileID = fopen('exp.txt','w'); +% logfile=['log_updateGridInfil_',num2str(labindex)]; + +%%% step 2: GRID update %%% TODO: add a function updateGRID_infiltration soilGRIDsizeOld = sum(GRID.soil.cT_domain); %zzz use grid + lake? @@ -9,8 +14,14 @@ if(isempty(GRID.lake.water.cT_domain_ub)) %tsvd only update grid when no lake exists zzz include case when lake level is dynamic! while (GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)+wc(1)<=0) - disp('infiltration - update GRID - updating air cell') - +%ttt disp('infiltration - update GRID - updating air cell') +% if labindex==1 +% disp('fileID1') +% fileID1 +% fprintf(fileID1,['infiltration - update GRID - updating air cell for worker ',num2str(labindex)]) +% elseif labindex==2 +% fprintf(fileID2,['infiltration - update GRID - updating air cell for worker ',num2str(labindex)]) +% end % adjust air and soil domains and boundaries zzz check how to adapt for lake... GRID.air.cT_domain(GRID.soil.cT_domain_ub)=1; GRID.air.K_domain(GRID.soil.K_domain_ub)=1; @@ -78,12 +89,31 @@ GRID.soil.soilGrid = [ GRID.general.K_grid(GRID.soil.cT_domain_ub) ; GRID.soil.soilGrid ]; end - %%% step 2c) check if soil/air domains changed --> LUT update +% %%% step 2c) check if soil/air domains changed --> LUT update +% soilGRIDsizeNew = sum(GRID.soil.cT_domain); +% if soilGRIDsizeOld~=soilGRIDsizeNew +% disp(['infiltration - reinitializing LUT - soil/air domains changed on worker ',num2str(labindex)]); +% GRID.soil.cT_water = wc; +% GRID = initializeSoilThermalProperties(GRID, PARA); +% end + +%tsvd %%% step 2c) check if soil/air domains changed --> LUT update soilGRIDsizeNew = sum(GRID.soil.cT_domain); - if soilGRIDsizeOld~=soilGRIDsizeNew - disp(['infiltration - reinitializing LUT - soil/air domains changed on worker ',num2str(labindex)]); + cellsChanged = soilGRIDsizeNew - soilGRIDsizeOld; + if cellsChanged > 0 + disp('infiltration - reinitializing LUT - new water cell(s)'); GRID.soil.cT_water = wc; GRID = initializeSoilThermalProperties(GRID, PARA); + elseif cellsChanged < 0 + disp('infiltration - shortening LUT - removed water cell(s)'); + GRID.soil.cT_water(1) = []; + GRID.soil.cT_frozen(1) = []; + GRID.soil.cT_thawed(1) = []; + GRID.soil.K_frozen(1) = []; + GRID.soil.K_thawed(1) = []; + GRID.soil.conductivity(1,:) = []; + GRID.soil.capacity(1,:) = []; + GRID.soil.liquidWaterContent(1,:) = []; end - + end \ No newline at end of file diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index 349ba1d..c198202 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -46,7 +46,7 @@ % location-specific dynamic auxiliary variables PARA.location.area = PARA.ensemble.area(index); PARA.location.altitude = PARA.ensemble.altitude(index); - PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index) + PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index); PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(index); PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); % location-specific dynamic common thresholds @@ -64,13 +64,24 @@ % 0.1 0.8 0.2 0.00 1 0.50;... % 10.0 0.25 0.75 0.00 1 0.25 ]}; - PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) - 1.0 0.5 0.5 0.00 1 0.50 ;... - 10.0 0.25 0.75 0.00 1 0.25 ] , ... - [0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (identical to lake stratigraphy) - 1.0 0.5 0.5 0.00 1 0.50 ;... - 10.0 0.25 0.75 0.00 1 0.25 ]}; -% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) + +% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) +% 1.0 0.5 0.5 0.00 1 0.50 ;... +% 10.0 0.25 0.75 0.00 1 0.25 ] , ... +% [0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (identical to lake stratigraphy) +% 1.0 0.5 0.5 0.00 1 0.50 ;... +% 10.0 0.25 0.75 0.00 1 0.25 ]}; + +disp(' new stratigraphy ...............................') + PARA.soil.layer_properties = {[0.0 0.2 0.7 0.00 1 0.30 ;... % lake stratigraphy (no excess ice) + 1.0 0.2 0.7 0.00 1 0.30 ;... + 10.0 0.1 0.8 0.00 1 0.2 ] , ... + [0.0 0.2 0.7 0.00 1 0.30 ;... % non-lake stratigraphy (identical to lake stratigraphy) + 1.0 0.2 0.7 0.00 1 0.30 ;... + 10.0 0.1 0.8 0.00 1 0.2 ]}; + + + % PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) % 0.02 0.5 0.5 0.00 1 0.50 ;... % 0.04 0.5 0.5 0.00 1 0.50 ;... % 0.06 0.5 0.5 0.00 1 0.50 ;... @@ -113,6 +124,6 @@ PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; % PARA.water.depth = [1.,0.]; - PARA.water.depth = [0.,1.] %ttt + PARA.water.depth = [0.,1.]; %ttt PARA.water.depth = PARA.water.depth(index); end diff --git a/modules/cryoGridSEB/L_star.m b/modules/cryoGridSEB/L_star.m index dcf4a82..ddd9725 100644 --- a/modules/cryoGridSEB/L_star.m +++ b/modules/cryoGridSEB/L_star.m @@ -21,9 +21,12 @@ u_star = real(uz.*kappa./(log(z./z0)- psi_M(z./Lstar, z0./Lstar))); L_star = real(-rho.*cp.*Tz./kappa./g.*u_star.^3./(Qh + 0.61.*cp./L.*Tz.*Qe)); -L_star=(abs(L_star)<1e-6).*L_star./abs(L_star).*1e-6 + (abs(L_star)>=1e-6).*L_star; % lower limit for Lstar (before 1e-7 and 1e-5) -L_star=(abs(L_star)>1e6).*L_star./abs(L_star).*1e6 + (abs(L_star)<=1e6).*L_star; % introduced upper limit for Lstar - +% L_star=(abs(L_star)<1e-6).*L_star./abs(L_star).*1e-6 + (abs(L_star)>=1e-6).*L_star; % lower limit for Lstar (before 1e-7 and 1e-5) +% L_star=(abs(L_star)>1e6).*L_star./abs(L_star).*1e6 + (abs(L_star)<=1e6).*L_star; % introduced upper limit for Lstar +%tsvd new limits for Lstar to prevent NAN in Lstar +L_star=(abs(L_star)<1e-4).*L_star./abs(L_star).*1e-4 + (abs(L_star)>=1e-4).*L_star; % lower limit for Lstar (before 1e-7 and 1e-4) +L_star=(abs(L_star)>1e4).*L_star./abs(L_star).*1e4 + (abs(L_star)<=1e4).*L_star; % introduced upper limit for Lstar +assert(~isnan(L_star),'L_star is NAN!') SEB.u_star = u_star; SEB.L_star=[SEB.L_star(2:end) L_star]; \ No newline at end of file diff --git a/modules/cryoGridSEB/Q_eq.m b/modules/cryoGridSEB/Q_eq.m index ba160a3..97a1181 100644 --- a/modules/cryoGridSEB/Q_eq.m +++ b/modules/cryoGridSEB/Q_eq.m @@ -15,6 +15,7 @@ +assert(~isnan(Lstar),'Lstar is NAN!') if T_surf<=273.15 Q_e = -rho.*L_i.*kappa.*uz.*kappa./(log(z./z0)- psi_M(z./Lstar, z0./Lstar)).*(q-satPresIce(T_surf)./p)./(log(z./z0)- psi_H(z./Lstar, z0./Lstar)); @@ -23,4 +24,6 @@ + rs.*uz.*kappa.^2./(log(z./z0)- psi_M(z./Lstar, z0./Lstar))); end +assert(~isnan(Q_e),'Q_e is NAN!') + %Q_e = -rho.*L.*kappa.*uz.*kappa./(log(z./z0)).*(RH.*satPresIce(Tz)-satPresIce(T_surf))./p./(log(z./z0)); \ No newline at end of file diff --git a/modules/cryoGridSEB/surfaceEnergyBalance.m b/modules/cryoGridSEB/surfaceEnergyBalance.m deleted file mode 100644 index d083466..0000000 --- a/modules/cryoGridSEB/surfaceEnergyBalance.m +++ /dev/null @@ -1,63 +0,0 @@ -function SEB=surfaceEnergyBalance(T, wc, FORCING, GRID, PARA, SEB); - - -Lstar=mean(SEB.L_star); - -sigma=5.67e-8; %Stefan-Boltzmann const. -z=PARA.technical.z; - -Qh=real(Q_h(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, FORCING.i.p, FORCING.i.q)); - - - -%______here SW radiation is calculated_____________________________________ -dE_dt=GRID.general.cT_grid.*0; -Qsolar=GRID.general.cT_grid.*0; - -dE_dt(GRID.air.cT_domain_lb+1,1)=(1-PARA.surf.albedo).*FORCING.i.Sin; -%------ snow surface (solid state green house effect) --------------------- -if ~isempty(GRID.snow.cT_domain_ub) - beta=PARA.snow.extinction; - Qsolar(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb+1) = dE_dt(GRID.snow.cT_domain_ub) .* exp(-beta.*(GRID.general.K_grid(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb+1)-GRID.general.K_grid(GRID.snow.cT_domain_ub))); - dE_dt(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb) = -Qsolar(GRID.snow.cT_domain_ub+1:GRID.snow.cT_domain_lb+1) + Qsolar(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb); - %put the rest to cell below snow - dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); -end - - -%__________________________________________________________________________ -Sout = PARA.surf.albedo*FORCING.i.Sin; -Lout = PARA.surf.epsilon.*sigma.*(T(GRID.air.cT_domain_lb+1)+273.15).^4+(1-PARA.surf.epsilon).*FORCING.i.Lin; -Qnet = FORCING.i.Sin-Sout + FORCING.i.Lin - Lout ; -Qg = Qnet-Qh-Qe; - - -%calculate ET - -if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 %snow cover or uppermost grid cell frozen - Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p)); -else - Qe_pot=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, 0, FORCING.i.p)); - fraction - -end - - -dE_dt(GRID.air.cT_domain_lb+1) = dE_dt(GRID.air.cT_domain_lb+1) ... - + PARA.surf.epsilon.*FORCING.i.Lin ... - - PARA.surf.epsilon.*sigma.*(T(GRID.air.cT_domain_lb+1)+273.15).^4 ... - - Qh - Qe; %Qe positive: cooling of soil =>epaporation/subl. => loss of SWE - - - - - -SEB.dE_dt_SEB = dE_dt; -SEB.Qnet = Qnet; -SEB.Qh = Qh; -SEB.Qe = Qe; -SEB.Qg = Qg; -SEB.Sout = Sout; -SEB.Lout = Lout; - - \ No newline at end of file diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index 6ce079c..90335e5 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -36,25 +36,15 @@ else %snow exists check_change=false; - try assert( sum(isnan(GRID.snow.Snow_i) )==0,' GRID.snow.snow_i NAN 1') - catch - %GRID.general.K_grid - G2=GRID; - G2ind = labindex; - save Data2_check G2 G2ind - end + GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) -... - ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); %updates the position of the uppermost snow grid cell - %try + ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); %updates the position of the uppermost snow grid cell assert( ~isnan( GRID.general.K_grid(GRID.snow.cT_domain_ub) ), 'updateGRID_snow - error in uppermost snow cell position' ); % assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.snow.cT_domain_lb)<2,'snow on lake!'); if(~isempty(GRID.lake.water.cT_domain_ub)) assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); end - %catch - % save Data_check PARA GRID %labindex - %end if GRID.snow.Snow_i(GRID.snow.cT_domain_ub)>=1.5.*PARA.technical.SWEperCell %create new grid cell @@ -194,7 +184,7 @@ GRID.general.K_delta=(- GRID.general.K_grid(1:end-1,1)+ GRID.general.K_grid(2:end,1)); - %bugfix as still situations may occur where K_delta<0 + %bugfix as still situations may occur where K_delta<0 mmm ... if ( sum( GRID.general.K_delta < 0 ) > 0 ) disp('updateGRID_snow - bugfix K grid'); %update grid spacings @@ -202,8 +192,15 @@ if ~isempty(GRID.snow.cT_domain_ub) % snow cover GRID.general.K_grid(GRID.snow.cT_domain) = GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); surfaceTop = GRID.general.K_grid(GRID.snow.cT_domain_ub); - else % no snow cover - surfaceTop = GRID.general.K_grid(GRID.soil.cT_domain_ub); + % now snow cover +%tsvd else +% surfaceTop = GRID.general.K_grid(GRID.soil.cT_domain_ub); + elseif(~isempty(GRID.lake.ice.cT_domain_ub) ) % lake ice + surfaceTop = GRID.general.K_grid(GRID.ice.water.cT_domain_ub); + elseif(~isempty(GRID.lake.water.cT_domain_ub) && isempty(GRID.lake.ice.cT_domain_ub) ) % open lake + surfaceTop = GRID.general.K_grid(GRID.lake.water.cT_domain_ub); + else + surfaceTop = GRID.general.K_grid(GRID.soil.cT_domain_ub); % soil end % air grid numAirCells = sum( GRID.air.cT_domain ); @@ -214,13 +211,5 @@ end assert( sum( isnan(T(GRID.snow.cT_domain)))==0, 'updateGRID_snow - error in T after grid update' ); -%try assert( sum( isnan(GRID.general.K_grid))==0, 'update_GRID_snow - error in Kgrid after grid update'); -%catch -% %GRID.general.K_grid -% x2=GRID; -% x2ind = labindex; -% save Data2_check x2 x2ind -% end - end From ecf7f879ba8efccac26d7099423a0fa57565b36c Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Wed, 9 May 2018 15:23:35 +0200 Subject: [PATCH 39/45] running version infiltration on, xice off, lateral heat exchange on (between lake and non-lake --- CryoGrid3_xice_mpi.m | 86 +++++++------------ analysis/plot_T_04.m | 27 +++--- .../CryoGridInfiltration.m | 43 ++++------ .../getThermalPropertiesInfiltration.m | 3 +- .../surfaceEnergyBalanceInfiltration.m | 33 +++---- .../updateGRID_excessiceInfiltration2.m | 2 +- .../calculateLateralWaterFluxes.m | 2 +- modules/cryoGridLateral/getMaxWaterAltitude.m | 2 +- .../cryoGridLateral/get_parallel_variables.m | 29 ++++--- modules/cryoGridSEB/surfaceCondition.m | 1 - modules/cryoGridSnow/CryoGridSnow.m | 8 +- modules/cryoGridSnow/updateGRID_snow.m | 30 +++---- .../getActiveLayerDepthAltitude.m | 2 +- .../cryoGridTechnical/getWaterTableAltitude.m | 1 + modules/cryoGridTechnical/makeGrids.m | 6 +- 15 files changed, 126 insertions(+), 149 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 1563633..93d18ca 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -3,36 +3,33 @@ % main script for running the model % % Developed by: S. Westermann and M. Langer 2015 + % -% ------------------------------------------------------------------------- - clear all - close all - -%ttt fileID1 = fopen('log_updateGridInfil_1.txt','w') -% fileID2 = fopen('log_updateGridInfil_2.txt','w') - - par_mode = 1; % parallel mode off/on - +% Extended by J. Nitzborn (infiltration of soils, lateral exchange of heat, water, snow) + +% Extended by T. Schneider von Deimling (coupling with FLAKE (based on version M. Langer) +% ---------------------------------------------------------------------------------------- +clear all +close all + +% runs modes +debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) +par_mode = 1; % parallel mode off/on + if(par_mode==1) delete(gcp('nocreate')) % useful to restart from a crash end -add_modules; %adds required modules - -%dbstop if error; - -number_of_realizations=2; -debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) -saveDir = './runs'; +add_modules; %adds required modules +number_of_realizations=2; % specify number of workers if number_of_realizations>1 parpool(number_of_realizations); end -%nnn spmd %zzz use function calls to calls below to enable debugging in par mode! index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run -%nnn index=1 +%nnn index=1 %---------------define input parameters------------------------------------ % here you provide the ground stratigraphy @@ -43,25 +40,9 @@ 0.15 0.65 0.3 0.05 2 0.65;... 0.9 0.65 0.3 0.05 1 0.65;... 9.0 0.30 0.70 0.00 1 0.30 ]; - -% disp('new stratigraphy........') -% PARA.soil.layer_properties = [0.0 0.2 0.7 0.00 1 0.30 ;... -% 1.0 0.2 0.7 0.00 1 0.30 ;... -% 10.0 0.1 0.8 0.00 1 0.2 ]; - % simple stratigraphy with excess ice used to test water balance: - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... - % 0.4 0.8 0.2 0.00 1 0.40;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - % very simply stratigraphy without excess ice used to test energy balance - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... - % 1.0 0.5 0.5 0.00 1 0.5 ;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; % soil stratigraphy - % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer - % extends until the end of the model domain - % column 2: volumetric water+ice content - % column 3: volumetric mineral content - % column 4: volumetric organic content + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer extends until the end of the model domain + % column 2: volumetric water+ice content; column 3: volumetric mineral content; column 4: volumetric organic content; % column 5: code for soil type: 1: sand, 2: silt % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs @@ -85,10 +66,10 @@ PARA.soil.externalWaterFlux=0.; %external water flux / drainage in [m/day] PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile - PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up + PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up jjj zzz PARA.soil.hydraulic_conductivity = 1e-5; PARA = loadSoilTypes( PARA ); - + % parameters related to snow PARA.snow.max_albedo=0.85; % albedo of fresh snow PARA.snow.min_albedo=0.5; % albedo of old snow @@ -123,7 +104,7 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1979, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.starttime=datenum(1979, 7, 1); % starttime of the simulation - if empty start from first value of time series PARA.technical.endtime=datenum(1980, 12, 31); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds @@ -188,7 +169,7 @@ PARA.forcing.snow_fraction=1; % switches for modules - PARA.modules.infiltration=0; % true if infiltration into unfrozen ground occurs + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs PARA.modules.xice=0; % true if thaw subsicdence is enabled PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) %tsvd extended for lateral switched off @@ -200,7 +181,7 @@ % in par mode this is replaced by PARA.ensemble.immobile_snow_height elseif PARA.modules.lateral % switches for lateral processes - PARA.modules.exchange_heat = 1; %ttt + PARA.modules.exchange_heat = 1; PARA.modules.exchange_water = 0; %ttt PARA.modules.exchange_snow = 0; %ttt @@ -211,9 +192,10 @@ disp('Running experiment with xxxx -> indicate switches here') % ------make output directory (name depends on parameters) ---------------- + saveDir = './runs'; % run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) , ... % PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, index ] ) - run_number= sprintf( 'LAKE-MPI_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_i%d' , ... + run_number= sprintf( 'LAKE-MPI-new _xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_i%d' , ... [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... PARA.modules.infiltration, PARA.modules.xice, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , index ] ) mkdir([ saveDir '/' run_number]); @@ -237,7 +219,7 @@ %----------------create and initialize the grids -------------------------- GRID=makeGrids(PARA); %create all grids - GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid (GRID.soil.*) %----- initializie excess ground ice -------------------------------------- [GRID,PARA] = initializeExcessIce2(GRID,PARA); @@ -261,7 +243,6 @@ %---- modification for infiltration wc=GRID.soil.cT_water; - %tsvd wc=GRID.general.cT_water; GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; @@ -293,7 +274,6 @@ %_________________________________________________________________________I while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) @@ -483,7 +464,7 @@ % calculate lateral water fluxes PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); - PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); %jjj + PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); %jjj zzz for j=1:number_of_realizations if j~=index labSend( PACKAGE_waterExchange, j, 2); @@ -574,15 +555,10 @@ [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes); end - % save final state and output at t=endtime -%nnn -iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) -%nnn + % save final state and output at t=endtime +iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) -%nnn %iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); - -%nnn end if number_of_realizations>1 diff --git a/analysis/plot_T_04.m b/analysis/plot_T_04.m index af78829..85df655 100644 --- a/analysis/plot_T_04.m +++ b/analysis/plot_T_04.m @@ -8,10 +8,10 @@ %% Non_Lake % no infil no ex no lake -% outputfile1 = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_output1980.mat' -% configfile1 = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_settings.mat' -% outputfile2 = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_output1980.mat' -% configfile2 = '../runs/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH0_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_settings.mat' +% outputfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_output1980.mat' +% configfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_settings.mat' +% outputfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_output1980.mat' +% configfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_settings.mat' % outputfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_output1980.mat' configfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_settings.mat' @@ -25,6 +25,8 @@ zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); tstamp=OUT.timestamp; T=OUT.cryoGrid3; TSoil=T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb,:); %TLakeWater=T(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb,:); TLakeIce=T(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb,:); +%OUT.soil.topPosition + %TAir=T(GRID.air.cT_domain_ub:GRID.air.cT_domain_lb,:); TSnow=T(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb,:); @@ -36,12 +38,11 @@ tstamp_forcing=FORCING.data.t_span(idx1:idx2); Tair=FORCING.data.Tair(idx1:idx2); - figure(1) txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; -%plot(tstamp,T(ub_soil:end,:)) + + figure(1) plot(tstamp,T) -%hold on; plot(tstamp,Tair,'LineWidth',2); hold off grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) title(txt_forcing, 'Interpreter', 'none') @@ -86,8 +87,9 @@ %if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLakeWater(1:dz:end,:),'b'); end %if(~isempty(GRID.lake.ice.cT_domain_ub)); plot(tstamp,TLakeIce(1:dz:end,:),'c'); end hold off -grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; - +grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +title(txt_forcing, 'Interpreter', 'none') %% %[ ~ ,idx ] = min( abs( datenum(1979, 7, 1 ) - OUT.timestamp() )) % find index of date @@ -107,6 +109,9 @@ figure(99) hold on -plot(tstamp,TLake,'b',tstamp,Tx1,'g',tstamp,Tx2,'r') +plot(tstamp,TLake(1:49:end,:),'b',tstamp,Tx1,'g',tstamp,Tx2,'r') grid on; datetick -hold off \ No newline at end of file +hold off +grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +title(txt_forcing, 'Interpreter', 'none') \ No newline at end of file diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m index 9889dc7..473caf6 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/CryoGridInfiltration.m @@ -1,80 +1,73 @@ function [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_flux_rate) % if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 %no snow cover and uppermost grid cell unfrozen -% zzz check whether it helps to exclude lake case %lll if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 || ~isempty (GRID.lake.water.cT_domain_ub) || ~isempty (GRID.lake.ice.cT_domain_ub) %no snow cover and uppermost grid cell unfrozen - if (isempty (GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 ) || (~isempty (GRID.lake.water.cT_domain_ub) && isempty (GRID.lake.ice.cT_domain_ub) ) %no snow cover and uppermost grid cell unfrozen - - % possible contribution from xice meltwater, snowmelt, rain on frozen ground +% only infiltrate if no snow, unfrozen soil exists, tsvd: no-LAKE case added +if (isempty (GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0 ) && isempty (GRID.lake.water.cT_domain_ub) && isempty (GRID.lake.ice.cT_domain_ub) % no snow cover and uppermost grid cell unfrozen, no lake +% possible contribution from xice meltwater, snowmelt, rain on frozen ground residualWater = GRID.lake.residualWater; GRID.lake.residualWater=0; - + % external flux external_flux_rate = PARA.soil.externalWaterFlux; % in m/day BALANCE.water.dr_external = BALANCE.water.dr_external + external_flux_rate.*timestep.*1000; %in mm - + % lateral flux to/from other workers lateral_flux_rate = lateral_flux_rate.*3600.*24; % now in m/day BALANCE.water.dr_lateral = BALANCE.water.dr_lateral + lateral_flux_rate.*timestep.*1000; - + %%% step 1: infiltrate rain and meltwater and external flux through bucket scheme % changes due to evapotranspiration and condensation dwc_dt=dwc_dt.*timestep.*24.*3600; %now in m water per grid cell BALANCE.water.de = BALANCE.water.de + sum(dwc_dt)*1000; % in mm accumulated over soil column - + % changes due to rainfall dwc_dt(1)=dwc_dt(1)+FORCING.i.rainfall./1000.*timestep; - + % changes due to residual water dwc_dt(1)=dwc_dt(1)+residualWater; - + % routing of water [wc, surface_runoff, lacking_water] = bucketScheme(T, wc, dwc_dt, GRID, PARA, (external_flux_rate+lateral_flux_rate).*timestep); - + % consistency check if sum( wc<0 )~=0 warning( 'CryoGridInfiltration - negative water content occured after bucket scheme' ); %here one could correct the water balance - end - % remove water above water table in case of ponding, e.g. through rain (independent of xice module) if GRID.soil.cT_mineral(1)+GRID.soil.cT_organic(1)<1e-6 && ... - PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub)>PARA.location.absolute_maxWater_altitude %zzz check for lake... - + PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub)>PARA.location.absolute_maxWater_altitude %zzz check for lake... cellSize = GRID.general.K_delta(GRID.soil.cT_domain_ub); actualWater = wc(1)*cellSize; h = PARA.location.absolute_maxWater_altitude - (PARA.location.initial_altitude-GRID.general.K_grid(GRID.soil.cT_domain_ub+1)); if h<0 warning('h<0. too much water above water table!') end - if actualWater>h disp('infiltration - removing excess water from upper cell'); wc(1)=h./cellSize; surface_runoff = surface_runoff + actualWater-h; end - - end - - %%% step 2: update GRID including reomval of excess water above water table and ponding below water table + +%%% step 2: update GRID including reomval of excess water above water table and ponding below water table [ wc, GRID, surface_runoff ] = updateGRID_infiltration(wc, GRID, PARA, surface_runoff); - - + + % store remaining surface runoff BALANCE.water.dr_surface = BALANCE.water.dr_surface - surface_runoff*1000; % in [mm] BALANCE.water.dm_lacking = BALANCE.water.dm_lacking + lacking_water*1000; - -end +end % step 3: LUT update % JAN:recalculate lookup tables when water content of freezing grid cells % has changed (infiltrated cells can freeze --> LUT is updated) -if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 %zzz jjj +if sum(double(wc~=GRID.soil.cT_water & T(GRID.soil.cT_domain)<=0))>0 %zzz jjj should be within if loop line 6...!? disp('infiltration - reinitializing LUT - freezing of infiltrated cell(s)'); GRID.soil.cT_water = wc; GRID = initializeSoilThermalProperties(GRID, PARA); end + end \ No newline at end of file diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m index 3a13351..c42acbf 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/getThermalPropertiesInfiltration.m @@ -35,13 +35,12 @@ lwc_temp(GRID.snow.cT_domain) = GRID.snow.Snow_w(GRID.snow.cT_domain)./GRID.general.K_delta(GRID.snow.cT_domain); %tsvd------ lake domain -------------------------------------------------- - %zzz check if ok!? c_temp(GRID.lake.water.cT_domain) = PARA.constants.c_w; k_temp(GRID.lake.water.cT_domain) = 5.46E-01 ; % in loadConstants.m 0.57 is used! FLAKE: Molecular heat conductivity of water [J m^{-1} s^{-1} K^{-1}] zzz lwc_temp(GRID.lake.water.cT_domain) = 1.; c_temp(GRID.lake.ice.cT_domain) = PARA.constants.c_i; - k_temp(GRID.lake.ice.cT_domain) = 2.29; ; % in loadConstants.m 2.2 is used! FLAKE: Molecular heat conductivity of ice [J m^{-1} s^{-1} K^{-1}] + k_temp(GRID.lake.ice.cT_domain) = 2.29; ; % in loadConstants.m 2.2 is used! FLAKE: Molecular heat conductivity of ice [J m^{-1} s^{-1} K^{-1}] zzz lwc_temp(GRID.lake.ice.cT_domain) = 0.; diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m index 43bc6a1..3d639d0 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m @@ -21,16 +21,17 @@ dE_dt(GRID.air.cT_domain_lb+1,1)=(1-PARA.surf.albedo).*FORCING.i.Sin; %------ snow surface (solid state green house effect) --------------------- if ~isempty(GRID.snow.cT_domain_ub) - beta=PARA.snow.extinction; % zzz also consider lake ice extinction... + beta=PARA.snow.extinction; Qsolar(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb+1) = dE_dt(GRID.snow.cT_domain_ub) .* exp(-beta.*(GRID.general.K_grid(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb+1)-GRID.general.K_grid(GRID.snow.cT_domain_ub))); dE_dt(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb) = -Qsolar(GRID.snow.cT_domain_ub+1:GRID.snow.cT_domain_lb+1) + Qsolar(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb); %put the rest to cell below snow - dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); %mmm zzz can be too much dE if thin lake ice? + dE_dt(GRID.snow.cT_domain_lb+1) = Qsolar(GRID.snow.cT_domain_lb+1); end -%tsvd +%tsvd also consider LAKE case %------- ice surface (solid state green house effect) --------------------- -if ~isempty(GRID.lake.ice.cT_domain_ub) +%if ~isempty(GRID.lake.ice.cT_domain_ub) lll +if GRID.lake.ice.z_ice>0 beta=PARA.ice.extinction; % if GRID.lake.ice.melt_flag % %increse light extinction coeff under melt conditions @@ -49,7 +50,7 @@ %put the rest to cell below water body dE_dt(GRID.lake.water.cT_domain_lb+1) = Qsolar(GRID.lake.water.cT_domain_lb+1); %SW output for FLAKE radiation scheme - Sin_water = Qsolar(GRID.lake.water.cT_domain_ub); %mmm Sin_ice missing above? + Sin_water = Qsolar(GRID.lake.water.cT_domain_ub); end %__________________________________________________________________________ Sout = PARA.surf.albedo*FORCING.i.Sin; @@ -59,22 +60,24 @@ %calculate ET %snow cover or uppermost grid cell frozen, or lake ice --> no ET -%tsvd added from version FLAKE +%tsvd LAKE case added if PARA.modules.infiltration - if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || ~isempty(GRID.lake.ice.cT_domain_ub) %lll water replaced by ice %snow cover or uppermost grid cell frozen --> no ET tsvd: addition case LAKE added + %lll if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || ~isempty(GRID.lake.ice.cT_domain_ub) % water replaced by ice %snow cover or uppermost grid cell frozen --> no ET tsvd: LAKE case added + if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || GRID.lake.ice.z_ice>0 % snow or lake ice cover, or uppermost grid cell frozen --> no ET zzz case of flooding of basin not captured correctly... Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); - % unfrozen water body at surface - %tsvd elseif GRID.lake.unfrozenWaterSurface % zzz - elseif ~isempty(GRID.lake.water.cT_domain_ub) + % unfrozen water body at surface + %tsvd elseif GRID.lake.unfrozenWaterSurface + %lll elseif ~isempty(GRID.lake.water.cT_domain_ub) + elseif GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); - dwc_dt(1)=-Qe./L; %in m water per sec, this can be evaporation or condensation - + %lll dwc_dt(1)=-Qe./L; %in m water per sec, this can be evaporation or condensation zzz dwc_dt is for soil domain!! need to adapt... + % put here lake bucket for calculating lake level change zzz % unfrozen soil surface else Qe_pot=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, 0, FORCING.i.p, PARA)); %potential ET %tsvd if Qe_pot>0 if Qe_pot>0 && GRID.soil.cT_domain(GRID.air.cT_domain_lb+1)==1 - fraction_T=getET_fraction(T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1), wc(1:GRID.soil.T_lb), PARA.soil.fieldCapacity, PARA.soil.wiltingPoint); + fraction_T=getET_fraction(T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.T_lb-1), wc(1:GRID.soil.T_lb), PARA.soil.fieldCapacity, PARA.soil.wiltingPoint); %zzz -1? fraction_E=getET_fraction(T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_ub+GRID.soil.E_lb-1), wc(1:GRID.soil.E_lb), PARA.soil.fieldCapacity, PARA.soil.residualWC); fraction_ET = fraction_T.*PARA.soil.ratioET; fraction_ET(1:GRID.soil.E_lb) = fraction_ET(1:GRID.soil.E_lb) + fraction_E.*(1-PARA.soil.ratioET); @@ -95,9 +98,7 @@ %ground heat flux Qg = Qnet-Qh-Qe; -%surface heat flux (into upper cell, ground heat flux regards also other -%grid cells, should be identical if no snow cover and no evapotranspiration -%occur +%surface heat flux (into upper cell, ground heat flux regards also other grid cells, should be identical if no snow cover and no evapotranspiration occur dE_dt(GRID.air.cT_domain_lb+1) = dE_dt(GRID.air.cT_domain_lb+1) ... + PARA.surf.epsilon.*FORCING.i.Lin ... - PARA.surf.epsilon.*sigma.*(T(GRID.air.cT_domain_lb+1)+273.15).^4 ... diff --git a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m index 6895cbe..b15f35e 100644 --- a/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m +++ b/modules/cryoGridExcessIceInfiltration/updateGRID_excessiceInfiltration2.m @@ -9,7 +9,7 @@ %tsvd if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 % upper soil cell pure air/water (and no lake exists) if GRID.soil.cT_organic(1)+GRID.soil.cT_mineral(1)<=1e-6 && isempty(GRID.lake.water.cT_domain_ub) && isempty(GRID.lake.ice.cT_domain_ub) % upper soil cell pure air/water or no lake - % general water body extent + % general water body extent zzz cT_waterBody = GRID.soil.cT_organic+GRID.soil.cT_mineral<=1e-6; GRID.lake.water.cT_domain(logical(GRID.air.cT_domain+GRID.snow.cT_domain)) = 0; GRID.lake.water.cT_domain(GRID.soil.cT_domain) = cT_waterBody; diff --git a/modules/cryoGridLateral/calculateLateralWaterFluxes.m b/modules/cryoGridLateral/calculateLateralWaterFluxes.m index 945ff2d..10516e5 100644 --- a/modules/cryoGridLateral/calculateLateralWaterFluxes.m +++ b/modules/cryoGridLateral/calculateLateralWaterFluxes.m @@ -29,7 +29,7 @@ % Decipher between cases - [waterpotWindex, hasWater_index] = nanmax([wt_index, ald_index ] ); + [waterpotWindex, hasWater_index] = nanmax([wt_index, ald_index ] ); %jjj [waterpotWj, hasWater_j] = nanmax([wt_j, ald_j ] ); diff --git a/modules/cryoGridLateral/getMaxWaterAltitude.m b/modules/cryoGridLateral/getMaxWaterAltitude.m index abb2682..69e129d 100644 --- a/modules/cryoGridLateral/getMaxWaterAltitude.m +++ b/modules/cryoGridLateral/getMaxWaterAltitude.m @@ -1,3 +1,3 @@ function max_water = getMaxWaterAltitude(PARA) - max_water = max( PARA.ensemble.soil_altitude ) + PARA.soil.relative_maxWater; %zzz + max_water = max( PARA.ensemble.soil_altitude ) + PARA.soil.relative_maxWater; %zzz jjj end diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index c198202..0ecf5b5 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -65,20 +65,20 @@ % 10.0 0.25 0.75 0.00 1 0.25 ]}; -% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) -% 1.0 0.5 0.5 0.00 1 0.50 ;... -% 10.0 0.25 0.75 0.00 1 0.25 ] , ... -% [0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (identical to lake stratigraphy) -% 1.0 0.5 0.5 0.00 1 0.50 ;... -% 10.0 0.25 0.75 0.00 1 0.25 ]}; + PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) + 1.0 0.5 0.5 0.00 1 0.50 ;... + 10.0 0.25 0.75 0.00 1 0.25 ] , ... + [0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (identical to lake stratigraphy) + 1.0 0.5 0.5 0.00 1 0.50 ;... + 10.0 0.25 0.75 0.00 1 0.25 ]}; -disp(' new stratigraphy ...............................') - PARA.soil.layer_properties = {[0.0 0.2 0.7 0.00 1 0.30 ;... % lake stratigraphy (no excess ice) - 1.0 0.2 0.7 0.00 1 0.30 ;... - 10.0 0.1 0.8 0.00 1 0.2 ] , ... - [0.0 0.2 0.7 0.00 1 0.30 ;... % non-lake stratigraphy (identical to lake stratigraphy) - 1.0 0.2 0.7 0.00 1 0.30 ;... - 10.0 0.1 0.8 0.00 1 0.2 ]}; +% disp(' new stratigraphy ...............................') +% PARA.soil.layer_properties = {[0.0 0.2 0.7 0.00 1 0.30 ;... % lake stratigraphy (no excess ice) +% 1.0 0.2 0.7 0.00 1 0.30 ;... +% 10.0 0.1 0.8 0.00 1 0.2 ] , ... +% [0.0 0.2 0.7 0.00 1 0.30 ;... % non-lake stratigraphy (identical to lake stratigraphy) +% 1.0 0.2 0.7 0.00 1 0.30 ;... +% 10.0 0.1 0.8 0.00 1 0.2 ]}; % PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) @@ -123,7 +123,8 @@ PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; +%tsvd set lake depths for workers % PARA.water.depth = [1.,0.]; - PARA.water.depth = [0.,1.]; %ttt + PARA.water.depth = [0.,1.]; PARA.water.depth = PARA.water.depth(index); end diff --git a/modules/cryoGridSEB/surfaceCondition.m b/modules/cryoGridSEB/surfaceCondition.m index 5ce89ea..07f8d7a 100644 --- a/modules/cryoGridSEB/surfaceCondition.m +++ b/modules/cryoGridSEB/surfaceCondition.m @@ -40,7 +40,6 @@ % end %tsvd check if lake exists -%lll if GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface elseif GRID.lake.water.cT_domain(GRID.air.cT_domain_lb+1)==1 % water surface % GRID.lake.unfrozenWaterSurface = true; %tsvd not needed any more %note SolarAzEl.m delivers only an approximation of sun position / t must be in UTC diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index 2133345..ade2ffe 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -1,7 +1,8 @@ function [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_temp, timestep, BALANCE) - if(~isempty(GRID.lake.water.cT_domain_ub)) %ttt - assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); + if(~isempty(GRID.lake.water.cT_domain_ub)) + assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); +% assert(GRID.lake.water.cT_domain_ub-GRID.snow.cT_domain_lb>1,'snow on lake!') end if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis @@ -94,7 +95,8 @@ SEB.newSnow=0; end - if(~isempty(GRID.lake.water.cT_domain_ub)) %ttt + if(~isempty(GRID.lake.water.cT_domain_ub)) assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake (2)!'); +% assert(GRID.lake.water.cT_domain_ub-GRID.snow.cT_domain_lb>1,'snow on lake (2)!') end end \ No newline at end of file diff --git a/modules/cryoGridSnow/updateGRID_snow.m b/modules/cryoGridSnow/updateGRID_snow.m index 90335e5..1c0a2c3 100644 --- a/modules/cryoGridSnow/updateGRID_snow.m +++ b/modules/cryoGridSnow/updateGRID_snow.m @@ -41,10 +41,10 @@ GRID.general.K_grid(GRID.snow.cT_domain_ub) = GRID.general.K_grid(GRID.snow.cT_domain_ub+1) -... ( GRID.snow.Snow_i(GRID.snow.cT_domain_ub) + GRID.snow.Snow_w(GRID.snow.cT_domain_ub) + GRID.snow.Snow_a(GRID.snow.cT_domain_ub)); %updates the position of the uppermost snow grid cell assert( ~isnan( GRID.general.K_grid(GRID.snow.cT_domain_ub) ), 'updateGRID_snow - error in uppermost snow cell position' ); - % assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.snow.cT_domain_lb)<2,'snow on lake!'); - if(~isempty(GRID.lake.water.cT_domain_ub)) - assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); - end + if(~isempty(GRID.lake.water.cT_domain_ub)) + assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); + % assert(GRID.lake.water.cT_domain_ub-GRID.snow.cT_domain_lb>1,'snow on lake in updateGRID_snow.m!') + end if GRID.snow.Snow_i(GRID.snow.cT_domain_ub)>=1.5.*PARA.technical.SWEperCell %create new grid cell @@ -133,7 +133,7 @@ assert( sum( sum( isnan(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)) ) ) == 0 , 'updateGRID_snow - error in Snow_i/a/w grid' ); % snow grid - soilTop = GRID.general.K_grid(GRID.snow.cT_domain_lb+1); %tsvd in case of an lake, soilTop corresponds to lakeTop + soilTop = GRID.general.K_grid(GRID.snow.cT_domain_lb+1); %tsvd in case of a lake, soilTop corresponds to lakeTop GRID.general.K_grid(GRID.snow.cT_domain)= soilTop - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); GRID.general.K_grid(GRID.air.cT_domain)=[GRID.general.K_grid(GRID.air.cT_domain_lb)+(-snowCellSize)*(GRID.air.cT_domain_lb-1):snowCellSize:GRID.general.K_grid(GRID.air.cT_domain_lb)]'; @@ -184,7 +184,7 @@ GRID.general.K_delta=(- GRID.general.K_grid(1:end-1,1)+ GRID.general.K_grid(2:end,1)); - %bugfix as still situations may occur where K_delta<0 mmm ... + %bugfix as still situations may occur where K_delta<0 ... zzz also if lake level changes !? if ( sum( GRID.general.K_delta < 0 ) > 0 ) disp('updateGRID_snow - bugfix K grid'); %update grid spacings @@ -192,15 +192,15 @@ if ~isempty(GRID.snow.cT_domain_ub) % snow cover GRID.general.K_grid(GRID.snow.cT_domain) = GRID.general.K_grid(GRID.snow.cT_domain_lb+1) - flipud(cumsum(flipud(GRID.snow.Snow_i(GRID.snow.cT_domain) + GRID.snow.Snow_w(GRID.snow.cT_domain) + GRID.snow.Snow_a(GRID.snow.cT_domain)))); surfaceTop = GRID.general.K_grid(GRID.snow.cT_domain_ub); - % now snow cover -%tsvd else -% surfaceTop = GRID.general.K_grid(GRID.soil.cT_domain_ub); - elseif(~isempty(GRID.lake.ice.cT_domain_ub) ) % lake ice - surfaceTop = GRID.general.K_grid(GRID.ice.water.cT_domain_ub); - elseif(~isempty(GRID.lake.water.cT_domain_ub) && isempty(GRID.lake.ice.cT_domain_ub) ) % open lake - surfaceTop = GRID.general.K_grid(GRID.lake.water.cT_domain_ub); - else - surfaceTop = GRID.general.K_grid(GRID.soil.cT_domain_ub); % soil + else %lll no snow cover +%tsvd LAKE cases added surfaceTop = GRID.general.K_grid(GRID.soil.cT_domain_ub); + if(~isempty(GRID.lake.ice.cT_domain_ub) ) % lake ice + surfaceTop = GRID.general.K_grid(GRID.ice.water.cT_domain_ub); + elseif(~isempty(GRID.lake.water.cT_domain_ub) ) % open lake + surfaceTop = GRID.general.K_grid(GRID.lake.water.cT_domain_ub); + else + surfaceTop = GRID.general.K_grid(GRID.soil.cT_domain_ub); % soil + end end % air grid numAirCells = sum( GRID.air.cT_domain ); diff --git a/modules/cryoGridTechnical/getActiveLayerDepthAltitude.m b/modules/cryoGridTechnical/getActiveLayerDepthAltitude.m index 4b73c0f..a1d399b 100644 --- a/modules/cryoGridTechnical/getActiveLayerDepthAltitude.m +++ b/modules/cryoGridTechnical/getActiveLayerDepthAltitude.m @@ -5,7 +5,7 @@ if isempty(GRID.snow.cT_domain_ub) && T(GRID.soil.cT_domain_ub)>0; % Condition to work on infiltration T=T(GRID.soil.cT_domain); i=1; - i_max=200; + i_max=200; %jjj while T(i)>0 && i<=i_max i=i+1; end diff --git a/modules/cryoGridTechnical/getWaterTableAltitude.m b/modules/cryoGridTechnical/getWaterTableAltitude.m index e5e0400..906223f 100644 --- a/modules/cryoGridTechnical/getWaterTableAltitude.m +++ b/modules/cryoGridTechnical/getWaterTableAltitude.m @@ -1,4 +1,5 @@ function waterTable = getWaterTableAltitude(T, wc, GRID, PARA) +%jjj zzz if lake -> watertable = lake surface T=T(GRID.soil.cT_domain); K_delta=GRID.general.K_delta(GRID.soil.cT_domain); %in m diff --git a/modules/cryoGridTechnical/makeGrids.m b/modules/cryoGridTechnical/makeGrids.m index 59952cd..6a5fc62 100644 --- a/modules/cryoGridTechnical/makeGrids.m +++ b/modules/cryoGridTechnical/makeGrids.m @@ -2,13 +2,13 @@ GRID.snow.snowCellSize=PARA.technical.SWEperCell/(PARA.snow.rho_snow/PARA.constants.rho_w); % only used to calculate length initial air grid... GRID.snow.snowGrid=[-1.*(PARA.technical.maxSWE./(PARA.technical.SWEperCell)+2).*GRID.snow.snowCellSize:GRID.snow.snowCellSize:-GRID.snow.snowCellSize]'; -%tsvd added +%tsvd LAKE grid GRID.lake.water.waterGrid=[0:0.02:PARA.water.depth-0.02]'; %with water (it is recommended to use a grid resolution of about 2cm) %GRID.lake.water.waterGrid=[]'; %no water if ~isempty(GRID.lake.water.waterGrid) - GRID.soil.soilGrid=PARA.technical.subsurfaceGrid + (2*GRID.lake.water.waterGrid(end)-GRID.lake.water.waterGrid(end-1)); %zzz ok? + GRID.soil.soilGrid=PARA.technical.subsurfaceGrid + (2*GRID.lake.water.waterGrid(end)-GRID.lake.water.waterGrid(end-1)); else -GRID.soil.soilGrid=PARA.technical.subsurfaceGrid; + GRID.soil.soilGrid=PARA.technical.subsurfaceGrid; end %tsvd K_grid =[GRID.snow.snowGrid; GRID.soil.soilGrid]; %grid on which the conductivty information lives (edges of grid cells) From c743bcf3543cb377c2cd791f7e0f66e4a14944cd Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Wed, 13 Jun 2018 17:36:49 +0200 Subject: [PATCH 40/45] fix for SEB to account for lateral heat exchange --- CryoGrid3_xice_mpi.m | 34 ++++++++---- analysis/plot_T_04.m | 10 ++-- .../surfaceEnergyBalanceInfiltration.m | 8 +-- .../calculateLateralHeatFluxes.m | 8 +-- .../cryoGridLateral/get_parallel_variables.m | 52 +++++++++++-------- modules/cryoGridSEB/surfaceCondition.m | 2 +- modules/cryoGridTechnical/loadConstants.m | 2 +- .../cryoGridTechnical/sum_up_output_store.m | 8 ++- 8 files changed, 73 insertions(+), 51 deletions(-) diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 93d18ca..3569732 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -1,3 +1,4 @@ + % ------------------------------------------------------------------------- % CryoGRID3 % main script for running the model @@ -9,8 +10,9 @@ % Extended by T. Schneider von Deimling (coupling with FLAKE (based on version M. Langer) % ---------------------------------------------------------------------------------------- -clear all -close all + +%clear all +%close all % runs modes debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) @@ -105,12 +107,14 @@ PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity PARA.technical.starttime=datenum(1979, 7, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1980, 12, 31); % endtime of the simulation - if empty end at last value of time series + PARA.technical.endtime=datenum(1980, 6, 30); % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds - PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + %tsvd PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.targetDeltaE=1e6; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K lll DeltaE increased by 1 order of M PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours +% PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.syncTimeStep = 3 ./ 24.0 ; % output time step in [days] - here three hours PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] @@ -163,7 +167,8 @@ PARA = loadConstants( PARA ); %FORCING data mat-file - PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + %PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.filename='Samoylov_rcp85_1901_2300_CryoGrid_windModified.mat'; %PARA.forcing.filename='CG3_CCLM_forcing_90_101'; PARA.forcing.rain_fraction=1; PARA.forcing.snow_fraction=1; @@ -195,9 +200,12 @@ saveDir = './runs'; % run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) , ... % PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, index ] ) - run_number= sprintf( 'LAKE-MPI-new _xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_i%d' , ... - [ PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... + %run_number= sprintf( 'SSW-NL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_i%d' , ... + + run_number= sprintf( 'TEST_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_i%d' , ... + [PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, ... PARA.modules.infiltration, PARA.modules.xice, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction , index ] ) + mkdir([ saveDir '/' run_number]); %tsvd ------redirect command line output to logfile --------------------------- @@ -303,8 +311,12 @@ SEB = heatConduction(T, k_Kgrid, GRID, PARA, SEB); %------ sum up heat fluxes -------------------------------------------- - SEB.dE_dt = SEB.dE_dt_cond + SEB.dE_dt_SEB; - +%tsvd account also for lateral heat exchange +% Julia Implementationfrom Moritz: SEB["dE_dt"] = SEB["dE_dt_cond"] + SEB["dE_dt_SEB"] + (dE_dt_lateral.*GRID["general"]["K_delta"]); +%original SEB.dE_dt = SEB.dE_dt_cond + SEB.dE_dt_SEB; + SEB.dE_dt = SEB.dE_dt_cond + SEB.dE_dt_SEB + dE_dt_lateral.*GRID.general.K_delta; + % dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; + %------ determine optimal timestep ------------------------------------ % account for min and max timesteps specified, max. energy change per grid cell and the CFT stability criterion. % energy change due to advection of heat through water fluxes is still excluded. @@ -327,7 +339,7 @@ if timestep > 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) warning( 'numerical stability not guaranteed' ); end - + %------ update T array ------------------------------------------------ % account for vertical heat fluxes from ground heat flux and heat conduction T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; diff --git a/analysis/plot_T_04.m b/analysis/plot_T_04.m index 85df655..fdbce10 100644 --- a/analysis/plot_T_04.m +++ b/analysis/plot_T_04.m @@ -12,11 +12,11 @@ % configfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_settings.mat' % outputfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_output1980.mat' % configfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_settings.mat' -% -outputfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_output1980.mat' -configfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_settings.mat' -outputfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2_realization2_output1980.mat' -configfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2_realization2_settings.mat' +% +outputfile1 = '../runs/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_output1980.mat' +configfile1 = '../runs/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_settings.mat' +outputfile2 = '../runs/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2_realization2_output1980.mat' +configfile2 = '../runs/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2_realization2_settings.mat' load(outputfile1); load(configfile1); diff --git a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m index 3d639d0..5b4f740 100644 --- a/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m +++ b/modules/CryoGridInfiltrationUnfrozenSoil/surfaceEnergyBalanceInfiltration.m @@ -30,8 +30,8 @@ %tsvd also consider LAKE case %------- ice surface (solid state green house effect) --------------------- -%if ~isempty(GRID.lake.ice.cT_domain_ub) lll -if GRID.lake.ice.z_ice>0 +if ~isempty(GRID.lake.ice.cT_domain_ub) +%%%if GRID.lake.ice.z_ice>0 beta=PARA.ice.extinction; % if GRID.lake.ice.melt_flag % %increse light extinction coeff under melt conditions @@ -62,8 +62,8 @@ %snow cover or uppermost grid cell frozen, or lake ice --> no ET %tsvd LAKE case added if PARA.modules.infiltration - %lll if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || ~isempty(GRID.lake.ice.cT_domain_ub) % water replaced by ice %snow cover or uppermost grid cell frozen --> no ET tsvd: LAKE case added - if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || GRID.lake.ice.z_ice>0 % snow or lake ice cover, or uppermost grid cell frozen --> no ET zzz case of flooding of basin not captured correctly... + if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || ~isempty(GRID.lake.ice.cT_domain_ub) % water replaced by ice %snow cover or uppermost grid cell frozen --> no ET tsvd: LAKE case added +%%% if ~isempty(GRID.snow.cT_domain_ub) || T(GRID.soil.cT_domain_ub)<=0 || GRID.lake.ice.z_ice>0 % snow or lake ice cover, or uppermost grid cell frozen --> no ET zzz case of flooding of basin not captured correctly... Qe=real(Q_eq(FORCING.i.wind, z, PARA.surf.z0, FORCING.i.q, FORCING.i.Tair, T(GRID.air.cT_domain_lb+1), Lstar, PARA.surf.rs, FORCING.i.p, PARA)); % unfrozen water body at surface %tsvd elseif GRID.lake.unfrozenWaterSurface diff --git a/modules/cryoGridLateral/calculateLateralHeatFluxes.m b/modules/cryoGridLateral/calculateLateralHeatFluxes.m index 866ea05..3cbcb0b 100644 --- a/modules/cryoGridLateral/calculateLateralHeatFluxes.m +++ b/modules/cryoGridLateral/calculateLateralHeatFluxes.m @@ -12,7 +12,8 @@ weight_index = PARA.ensemble.weight(index); weight_j = PARA.ensemble.weight(j); contact_length_index_j = PARA.ensemble.thermal_contact_length(j, index); - contact_altitude = min( [ PARA.ensemble.altitude(j), PARA.ensemble.altitude(index) ] ) - distance_index_j; %below this depth, grid cells will exchange heat +%tsvd allow for heat exchange over full vertical profile contact_altitude = min( [ PARA.ensemble.altitude(j), PARA.ensemble.altitude(index) ] ) - distance_index_j; %below this depth, grid cells will exchange heat + contact_altitude = min( [ PARA.ensemble.altitude(j), PARA.ensemble.altitude(index) ] ); %below this depth, grid cells will exchange heat contact_domain = altitude_cTgrid_index <= contact_altitude; %all cells in the current ensemble member % interpolate j-values to index-grid @@ -48,9 +49,10 @@ dE_dt(contact_domain) = k_eff(contact_domain) .* (T_interp_j(contact_domain)-T_index(contact_domain)) ./ distance_index_j .* contact_length_index_j ./ PARA.ensemble.area(index) ; % in [ J / m^3 / s ] % T_index(contact_domain) = T_index(contact_domain) + dE_dt_j ./ c_index(contact_domain) .* PARA.technical.syncTimeStep .* 24 .* 3600; - + % balance is not correct - BALANCE.energy.Q_lateral(contact_domain) = BALANCE.energy.Q_lateral(contact_domain) + dE_dt(contact_domain) .* PARA.technical.syncTimeStep .* 24 .* 3600 .* GRID.general.K_delta(contact_domain); % in [ J / m^2 ] + %tsvd BALANCE.energy.Q_lateral(contact_domain) = BALANCE.energy.Q_lateral(contact_domain) + dE_dt(contact_domain) .* PARA.technical.syncTimeStep .* 24 .* 3600 .* GRID.general.K_delta(contact_domain); % in [ J / m^2 ] + BALANCE.energy.Q_lateral(contact_domain) = k_eff(contact_domain) .* (T_interp_j(contact_domain)-T_index(contact_domain)) ./ distance_index_j; % in W/m2 end end diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index 0ecf5b5..757ed66 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -53,7 +53,11 @@ PARA.location.absolute_maxWater_altitude = [max( PARA.ensemble.altitude ) + PARA.soil.relative_maxWater]; PARA.location.absolute_maxSnow_altitude = [max( PARA.ensemble.altitude ) + PARA.snow.relative_maxSnow]; - % different stratigraphies + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer extends until the end of the model domain + % column 2: volumetric water+ice content; column 3: volumetric mineral content; column 4: volumetric organic content; + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs % PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % center stratigraphy without excess ice % 1.0 0.5 0.5 0.00 1 0.50 ;... % 10.0 0.25 0.75 0.00 1 0.25 ] , ... @@ -65,21 +69,23 @@ % 10.0 0.25 0.75 0.00 1 0.25 ]}; - PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) - 1.0 0.5 0.5 0.00 1 0.50 ;... - 10.0 0.25 0.75 0.00 1 0.25 ] , ... - [0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (identical to lake stratigraphy) - 1.0 0.5 0.5 0.00 1 0.50 ;... - 10.0 0.25 0.75 0.00 1 0.25 ]}; + PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (no excess ice) + 1.0 0.5 0.5 0.00 1 0.50 ;... + 10.0 0.25 0.75 0.00 1 0.25 ], ... + + [0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy + 1.0 0.5 0.5 0.00 1 0.50 ;... + 10.0 0.25 0.75 0.00 1 0.25 ]}; -% disp(' new stratigraphy ...............................') -% PARA.soil.layer_properties = {[0.0 0.2 0.7 0.00 1 0.30 ;... % lake stratigraphy (no excess ice) -% 1.0 0.2 0.7 0.00 1 0.30 ;... -% 10.0 0.1 0.8 0.00 1 0.2 ] , ... -% [0.0 0.2 0.7 0.00 1 0.30 ;... % non-lake stratigraphy (identical to lake stratigraphy) -% 1.0 0.2 0.7 0.00 1 0.30 ;... -% 10.0 0.1 0.8 0.00 1 0.2 ]}; - +%todotodo read parameters from file! +% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.25 1 0.50 ;... % reference case - Langer 2015 +% 0.2 0.5 0.5 0.00 1 0.50 ;... +% +% ... update +% 0.9 0.25 0.75 0.00 1 0.25 ] , ... +% 9.0 0.25 0.75 0.00 1 0.25 ] , ... +% 1000.0 0.25 0.75 0.00 1 0.25 ] , ... + % PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy (no excess ice) % 0.02 0.5 0.5 0.00 1 0.50 ;... @@ -108,11 +114,11 @@ % different initial conditions PARA.Tinitial = [-5 5 5;... - 0 -5 -5;... - 1 -5 -5;... - 10 -8 -8;... - 20 -10 -10;... - 100 -10 -10;... + 0 -5 -2;... + 1 -5 -1;... + 10 -8 0;... + 20 -10 0;... + 100 -10 1;... 2000 10 10]; % PARA.Tinitial = [-5 10 10;... this profile can cause model crashes in mpi... % 0 0 0;... @@ -125,6 +131,10 @@ %tsvd set lake depths for workers % PARA.water.depth = [1.,0.]; - PARA.water.depth = [0.,1.]; + +% PARA.water.depth = [0.,0.]; % non-lake setting + PARA.water.depth = [0.,0.9]; % non-lake and small-sized water body (SSW) + %PARA.water.depth = [0.,6.]; % non-lake and medium-sized water body (MSW) + PARA.water.depth = PARA.water.depth(index); end diff --git a/modules/cryoGridSEB/surfaceCondition.m b/modules/cryoGridSEB/surfaceCondition.m index 07f8d7a..3076519 100644 --- a/modules/cryoGridSEB/surfaceCondition.m +++ b/modules/cryoGridSEB/surfaceCondition.m @@ -51,7 +51,7 @@ PARA.surf.z0=real(PARA.surf.z0); PARA.surf.rs = PARA.water.rs; -elseif GRID.lake.ice.z_ice>0 %GRID.lake.ice.cT_domain(GRID.air.cT_domain_lb+1)==1 % ice surface +elseif GRID.lake.ice.cT_domain(GRID.air.cT_domain_lb+1)==1 % ice surface PARA.surf.albedo = PARA.ice.albedo; PARA.surf.epsilon = PARA.ice.epsilon; [PARA.surf.z0, z0t, z0q] = flake_roughnessLength(PARA.water.fetch, FORCING.i.wind, SEB.u_star, 1); diff --git a/modules/cryoGridTechnical/loadConstants.m b/modules/cryoGridTechnical/loadConstants.m index 645e986..98189ab 100644 --- a/modules/cryoGridTechnical/loadConstants.m +++ b/modules/cryoGridTechnical/loadConstants.m @@ -29,5 +29,5 @@ % mineral %PARA.constants.rho_m = 1; % n.a. PARA.constants.c_m = 2.0e6; %[J/(K m^3)] % volumetric heat capacity of minearal material [J/(K m^3)] - PARA.constants.k_m = PARA.soil.kh_bedrock; % heat conductivity of mineral material / bedrock [ W/(mK)] (specified above) %km=3.8 %mineral [Hillel(1982)] + PARA.constants.k_m = PARA.soil.kh_bedrock; % heat conductivity of mineral material / bedrock [ W/(mK)] (specified above) %km=3.8 %mineral [Hillel(1982)] tsvd: km=3.0! end diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index c368990..3a2236b 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -104,9 +104,8 @@ OUT.location.water_table_altitude=[OUT.location.water_table_altitude; PARA.location.water_table_altitude]; % lateral fluxes -%tsvd OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow; PARA.ensemble.terrain_index_snow ]; - OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow ]; % exclude ensemble struct for lateral=0 zzz define switch Abfrage... lateral 0/1? - + OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow; PARA.ensemble.terrain_index_snow ]; +%tsvd OUT.lateral.terrain_index_snow=[ OUT.lateral.terrain_index_snow ]; % exclude ensemble struct for lateral=0 zzz define switch Abfrage... lateral 0/1? OUT.lateral.water_fluxes = [ OUT.lateral.water_fluxes; water_fluxes' ]; % vector containing water fluxes in [m/s] to the current worker OUT.lateral.snow_fluxes = [ OUT.lateral.snow_fluxes; snow_fluxes' ]; % vector containing snow fluxes in [m SWE / s] to the current worker OUT.lateral.heat_fluxes = [ OUT.lateral.heat_fluxes; heat_fluxes' ]; % vector containing depth-integrated heat fluxes in [J/m^2 s ] to the current worker @@ -174,13 +173,12 @@ BALANCE.energy.dE_snow = 0; OUT.EB.Q_lateral = [OUT.EB.Q_lateral, [ BALANCE.energy.Q_lateral ] ]; BALANCE.energy.Q_lateral = zeros( length(GRID.general.cT_grid) , 1 ); - + % for DEBUGGING OUT.debugging.dE_dt_SEB = [OUT.debugging.dE_dt_SEB [ TEMPORARY.dE_dt_SEB ] ]; OUT.debugging.dE_dt_cond = [OUT.debugging.dE_dt_cond [ TEMPORARY.dE_dt_cond ] ]; OUT.debugging.K_grid = [OUT.debugging.K_grid, GRID.general.K_grid ]; - %------------------------------------------------------------------ disp([datestr(now,'yyyy-mm-dd HH:MM:SS'),': at ', datestr(t), ', Average timestep: ', num2str(TEMPORARY.timestep_out), ' seconds']) From dac5764657de6e62f4d81b22f19f44189fa106a4 Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Sun, 17 Jun 2018 20:31:39 +0200 Subject: [PATCH 41/45] update of area calculation, .... --- CryoGrid3_xice_flake.m | 579 ------------------ CryoGrid3_xice_mpi.m | 4 +- add_modules.m | 2 +- .../calculateLateralHeatFluxes.m | 3 +- .../cryoGridLateral/get_parallel_variables.m | 18 +- .../cryoGridTechnical/sum_up_output_store.m | 2 +- 6 files changed, 16 insertions(+), 592 deletions(-) delete mode 100644 CryoGrid3_xice_flake.m diff --git a/CryoGrid3_xice_flake.m b/CryoGrid3_xice_flake.m deleted file mode 100644 index 8af17e6..0000000 --- a/CryoGrid3_xice_flake.m +++ /dev/null @@ -1,579 +0,0 @@ -% ------------------------------------------------------------------------- -% CryoGRID3 -% main script for running the model -% -% Developed by: S. Westermann and M. Langer 2015 -% -% ------------------------------------------------------------------------- -clear all -close all -%tsvd define simulation setting -debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) -run_mode = 1; % 1: single mode 1 column & lateral exchange setting 2: offline 3: online -number_of_realizations=1; - -if(run_mode==1) % single run - index=1 -elseif(run_mode==2) % multiple runs - offline - disp('not implemented so far') -elseif(run_mode==3) % multiple runs - online - delete(gcp('nocreate')) % useful to restart from a crash - parpool(number_of_realizations) - disp('need to complement run mode...') -end - -add_modules; %adds required modules - -saveDir = './runs'; - -%ooo spmd -% index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run - -%---------------define input parameters------------------------------------ - % here you provide the ground stratigraphy - % z w/i m o type porosity - - % default stratigraphy used in publication: - PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... - 0.15 0.65 0.3 0.05 2 0.65;... - 0.9 0.65 0.3 0.05 1 0.65;... - 9.0 0.30 0.70 0.00 1 0.30 ]; - % simple stratigraphy with excess ice used to test water balance: - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 1 0.50;... - % 0.4 0.8 0.2 0.00 1 0.40;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - % very simply stratigraphy without excess ice used to test energy balance - % PARA.soil.layer_properties=[ 0.0 0.5 0.5 0.00 soilType 0.5 ;... - % 1.0 0.5 0.5 0.00 1 0.5 ;... - % 10.0 0.25 0.75 0.00 1 0.25 ]; - % soil stratigraphy - % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer - % extends until the end of the model domain - % column 2: volumetric water+ice content - % column 3: volumetric mineral content - % column 4: volumetric organic content - % column 5: code for soil type: 1: sand, 2: silt - % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs - - %------ model parameters -------------------------------------------------- - % parameters related to soil - PARA.soil.albedo=0.2; % albedo snow-free surface - PARA.soil.epsilon=0.97; % emissvity snow-free surface - PARA.soil.z0=1e-3; % roughness length [m] snow-free surface - PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface - PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] - PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] - - % parameters related to hydrology scheme - PARA.soil.fieldCapacity=0.5; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! - PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries - PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries - PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off - PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation - PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. - %tsvd PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] - PARA.soil.externalWaterFlux=0.; %external water flux / drainage in [m/day] - PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible - PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile - PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up - PARA.soil.hydraulic_conductivity = 1e-5; - PARA = loadSoilTypes( PARA ); - - % parameters related to snow - PARA.snow.max_albedo=0.85; % albedo of fresh snow - PARA.snow.min_albedo=0.5; % albedo of old snow - PARA.snow.epsilon=0.99; % surface emissivity snow - PARA.snow.z0=5e-4; % roughness length surface [m] - PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow - PARA.snow.rho_snow=200.0; % density in [kg/m3] - PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] - PARA.snow.tau_a=0.008; % [per day] - PARA.snow.tau_f=0.24; % [per day] - PARA.snow.relative_maxSnow= [0.1]; %ttt maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold - PARA.snow.extinction=25.0; % light extinction coefficient of snow - %tsvd add lake parameters - % parameters related to lake - PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) - PARA.water.epsilon=0.99; % surface emissivity water - PARA.water.rs=0.; % surface resistance -> should be 0 for water - %tsvd - PARA.water.z0=5e-4; % roughness length surface [m] % JAN: value for summer / vegetation - %tsvd PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m version Flake - PARA.water.extinction=1.2; % light extinction coefficient of water - PARA.water.depth=1.; - PARA.water.fetch=20; - - PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 - PARA.ice.epsilon=0.98; % surface emissivity snow - PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice - PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow - PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 - - PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases - PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells - PARA.technical.maxSWE=0.4; % in [m] SWE - PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1979, 6, 10); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1980, 7, 1); % endtime of the simulation - if empty end at last value of time series - PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds - PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds - PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K - PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours - PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty - PARA.technical.saveInterval=[]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year - PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] - - %default grid used for publications and testing of water balance: - PARA.technical.subsurfaceGrid = [[0:0.02:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - %PARA.technical.subsurfaceGrid = [[0:0.02:10], [10.1:0.1:20], [20.2:0.2:30], [31:1:40], [45:5:60], [70:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] - - PARA.location.area=1.0; - PARA.location.initial_altitude=20.0; - % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" - PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain - PARA.location.soil_altitude=PARA.location.initial_altitude; - PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow - PARA.location.active_layer_depth_altitude = nan; % defined at runtime - PARA.location.water_table_altitude = nan; % defined at runtime - % thresholds - PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; - if isempty( PARA.snow.relative_maxSnow ) - PARA.location.absolute_maxSnow_altitude = []; - else - PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; - end -%tsvd - PARA.location.latitude = 72.376; % [deg] < - - PARA.location.longitude = 126.491; % [deg] < - - %PARA.location.GridCellSize = 1e6; % [m^2] < - - %PARA.location.TileFraction = 1e-2; - % parameters related to the site location - PARA.location.water_table_altitude = nan; % defined at runtime - - %initial temperature profile -> first column depth [m] -> second column temperature [degree C] -% PARA.Tinitial = [ -2 5 ;... -% 0 0 ;... -% 2 -5 ;... -% 10 -10 ;... -% 25 -9 ;... -% 100 -9 ;... -% 2000 10 ]; - PARA.Tinitial = [ -2 5 ;... - 0 0 ;... - 2 -2 ;... - 5 -7 ;... - 10 -9 ;... - 25 -9 ;... - 100 -8 ;... - 1100 10.2 ]; % the geothermal gradient for Qgeo=0.05W/m² and K=2.746W/Km is about 18.2 K/km - -% load natural constants (given in SI units) to PARA.constants - PARA = loadConstants( PARA ); - - %FORCING data mat-file - PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files - PARA.forcing.rain_fraction=1; - PARA.forcing.snow_fraction=1; - - % switches for modules - PARA.modules.infiltration=0; % true if infiltration into unfrozen ground occurs - PARA.modules.xice=0; % true if thaw subsicdence is enabled - PARA.modules.lateral=0; % true if adjacent realizations are run (this does not require actual lateral fluxes) -%tsvd extended for lateral switched off - if ~PARA.modules.lateral - PARA.modules.exchange_heat = 0; - PARA.modules.exchange_water = 0; - PARA.modules.exchange_snow = 0; - PARA.snow.maxSnow= [] ; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold - % in par mode this is replaced by PARA.ensemble.immobile_snow_height - elseif PARA.modules.lateral - % switches for lateral processes - PARA.modules.exchange_heat = 1; %ttt - PARA.modules.exchange_water = 1; %ttt - PARA.modules.exchange_snow = 1; %ttt - - %---------overwrites variables for each realization-------------------- - % this function must define everything that is realization-specific or dependent of all realizations - PARA = get_parallel_variables( PARA ); - end - - % ------make output directory (name depends on parameters) ---------------- - run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) ], ... - ['_', PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow] ) ; - mkdir([ saveDir '/' run_number]); - - %-------------------------------------------------------------------------- - %-----------do not modify from here onwards-------------------------------- - %-------------------------------------------------------------------------- - [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file - - if ~success - warning('A problem with the Forcing occured.'); - end - - PARA = initializeParameters(PARA, FORCING); %set start time, etc. - - %----------------create and initialize the grids -------------------------- - GRID=makeGrids(PARA); %create all grids - GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid - - %----- initializie excess ground ice -------------------------------------- - [GRID,PARA] = initializeExcessIce2(GRID,PARA); - - %----- initializie soil thermal properties -------------------------------- - GRID = initializeSoilThermalProperties(GRID, PARA); - - %------ initializie snow properties---------------------------------------- - GRID = initializeSnow(GRID); - - %---- initialize the surface energy balance struct ------------------------ - SEB = initializeSEB(); -%tsvd replace by new call lake scheme -% %---- initialize the water body module ------------------------------------ -% GRID = initializeLAKE(GRID); - -%---- initialize the lake scheme structs ---------------------------------- - [FLAKE GRID] = initializeLAKE(GRID, PARA); - %---- initialize temperature profile -------------------------------------- - T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); - - %---- modification for infiltration - wc=GRID.soil.cT_water; - GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; - GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; - - %---- preallocate temporary arrays for capacity and conductivity----------- - [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid - - %---- energy and water balance initialization ----------------------------- - BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); - - %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? -%ooo - if(run_mode==1) - water_fluxes = 0.; - snow_fluxes = 0.; - heat_fluxes = 0.; - dE_dt_lateral = zeros(length(GRID.general.cT_grid), 1); - elseif(run_mode==2) - disp('need to implement...') - elseif(run_mode==3) - water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index - snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index - heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index - dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index - end - %__________________________________________________________________________ - %-------- provide arrays for data storage --------------------------------- - [t, TEMPORARY] = generateTemporary(T, PARA); - OUT = generateOUT(); - - disp('initialization successful'); - %%% nnn - iSaveSettings( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_settings.mat'] , FORCING, PARA, GRID) - - - %% ________________________________________________________________________ - % Time Integration Routine I - % I - %_________________________________________________________________________I - - while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) - warning( 'numerical stability not guaranteed' ); - end - - %------ update T array ------------------------------------------------ - % account for vertical heat fluxes from ground heat flux and heat conduction - T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; - % account for lateral heat fluxes - T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] - % set grid cells in air to air temperature - T(GRID.air.cT_domain)=FORCING.i.Tair; - - if max((T<-100))==1; disp('dwd'); end - - %------- water body module -------------------------------------------- -%tsvd T = mixingWaterBody(T, GRID); % zzz check whether this is ok to switch off - %------- snow cover module -------------------------------------------- - [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - - %------- infiltration module------------------------------------------- - if PARA.modules.infiltration - lateral_water_flux = nansum( water_fluxes ); % lateral fluxes to/from other workers in [m/s] - [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_water_flux); - end -%tsvd - %------- water body module -------------------------------------------- - if timestep>0 && ( ~isempty(GRID.lake.water.cT_domain_ub) || ~isempty(GRID.lake.ice.cT_domain_ub) ) - %ice cover - [T GRID FLAKE] = cryoGridIceCover(GRID, SEB, FLAKE, T, c_cTgrid, timestep); - %FLAKE - if isempty(GRID.lake.ice.cT_domain_ub) && sum(GRID.lake.water.cT_domain)>=3 - %FLAKE is used if no ice cells exist - [T GRID FLAKE] = cryoGridFLAKE(FLAKE, GRID, SEB, PARA, T, T_old, timestep, k_Kgrid, SEB.dE_dt, SEB.dE_dt_SEB); - else - %updated FLAKE variables also when FLAKE is not used - FLAKE.t_bot_n_flk = T(GRID.lake.water.cT_domain_lb) + 273.15; - %set mixed layerdepth to zero - FLAKE.h_ml_n_flk = 0; - end - GRID = updateGRID_flake(GRID); - end - %--------- buoyancy calculation in block fields------------------------ - %T = convectionInBlocks(T, c_cTgrid, GRID) %not available - % @ ALEX: here the calculations of the excess ice module take place - % (uncomment this line to "activate" the module). Note that the - % stratigraphy must be modified such that excess ground ice is present - % in order to make the module "work" - - %------- excess ice module -------------------------------------------- - if PARA.modules.xice && ~PARA.modules.infiltration - warning( 'energy and water balances are not correct for this combination of modules'); % zzz ... - [GRID, PARA] = excessGroundIce(T, GRID, PARA); -%tsvd version Flake [GRID, PARA, wc] = excessGroundIce(T, GRID, PARA); - % assure wc has correct length - wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); -%tsvd wc( end-sum(GRID.soil.cT_domain)+1 : end ); % make vector dims consistent - elseif PARA.modules.xice && PARA.modules.infiltration - [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); -%tsvd [GRID, PARA, wc] = excessGroundIceInfiltration(T, wc, GRID, PARA); - GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); - end - - %------- update Lstar for next time step ------------------------------ - SEB = L_star(FORCING, PARA, SEB); - - %------- update auxiliary state variables - PARA.location.altitude = getAltitude( PARA, GRID ); - PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); - PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); - PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); - - %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time - if ~PARA.modules.lateral - PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; - if isempty( PARA.snow.maxSnow ) - %tsvd if isempty( PARA.ensemble.immobile_snow_height ) - PARA.location.absolute_maxSnow_altitude = []; - else - PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; - end - end - %------- water balance calculations ----------------------------------- - % rainfall - BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval - % snowfall - BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval - - %------- lateral exchange module -------------------------------------- - % all functions called in this block should go into - % /modules/cryoGridLateral - % calling PARA.ensemble is only allowed here - if PARA.modules.lateral - if t==TEMPORARY.syncTime %communication between workers - disp('CryoGridLateral: sync - start'); - labBarrier(); %common start - PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; %ddd commenting out (here and below) does not help prevent snow grid crash - - % heat exchange module - if PARA.modules.exchange_heat - labBarrier(); - heat_fluxes = zeros( number_of_realizations, 1); - % check preconditions - precondition_heatExchange = true; %no specific conditions so far - if precondition_heatExchange - %WRAPPER - disp('sync - exchanging heat'); - % calculate lateral heat fluxes - dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] - PACKAGE_heatExchange.T = T; - PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; - PACKAGE_heatExchange.k_cTgrid = k_cTgrid; - for j=1:number_of_realizations - if j~=index - labSend( PACKAGE_heatExchange, j, 1); - end - end - for j=1:number_of_realizations - if j~=index - PACKAGE_heatExchange_j = labReceive(j, 1); - [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index - heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes - dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations - end - end - end - end - - % water exchange module - if PARA.modules.exchange_water - labBarrier(); - water_fluxes = zeros( number_of_realizations, 1 ); % in [m/s] - % check preconditions - precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); - if precondition_waterExchange - % WRAPPER - disp('sync - exchanging water'); - % calculate lateral water fluxes - PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); - PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); - PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); - for j=1:number_of_realizations - if j~=index - labSend( PACKAGE_waterExchange, j, 2); - end - end - for j=1:number_of_realizations - if j~=index - PACKAGE_waterExchange_j = labReceive(j, 2); - % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) - water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); - end - end - % for debugging: print water flux per column - waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m - fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); - end - - end - - % snow exchange module - if PARA.modules.exchange_snow - labBarrier(); - % check preconditions - precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); - if precondition_snowExchange - disp('sync - exchanging snow'); - % calculate terrain index with updated surface_altitudes - PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); - - % calculate mobile snow - % WRAPPER - mobile_snow = zeros( 1, number_of_realizations ); - my_mobile_snow = 0; - meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE - if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions - i=0; - while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold - > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains - && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) - - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) - my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile - i=i+1; - end - end - mobile_snow(index) = my_mobile_snow; - % exchange mobile snow amounts - for j=1:number_of_realizations - if j~=index - % send mobile snow amount in [m SWE] - labSend( mobile_snow(index), j, 4 ); - end - end - for j=1:number_of_realizations - if j~=index - % receive mobile snow amount [m SWE] - mobile_snow(j) = labReceive(j, 4); - end - end - % calculate lateral snow fluxes - my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); - % apply lateral snow fluxes directly - if my_snow_change ~= 0 - [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); - [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); - BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; - end - - snow_fluxes = zeros( numlabs , 1 ); - snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes - fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); - - end - end - - labBarrier(); - PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; - - TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; - disp('sync - done'); - end - end - - - %------- next time step ----------------------------------------------- - t=t+timestep; - %---------- sum up + OUTPUT ------------------------------------------- - %nnn - [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes); - end - - % save final state and output at t=endtime -%nnn -iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) -%nnn -iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) -%nnn -%iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); - -%ooo end %end spmd - -%ooo adapt... -if number_of_realizations>1 - delete(gcp('nocreate')) -end - -disp('Done.'); diff --git a/CryoGrid3_xice_mpi.m b/CryoGrid3_xice_mpi.m index 3569732..05ff2d4 100755 --- a/CryoGrid3_xice_mpi.m +++ b/CryoGrid3_xice_mpi.m @@ -1,4 +1,3 @@ - % ------------------------------------------------------------------------- % CryoGRID3 % main script for running the model @@ -11,8 +10,7 @@ % Extended by T. Schneider von Deimling (coupling with FLAKE (based on version M. Langer) % ---------------------------------------------------------------------------------------- -%clear all -%close all +%clear all; close all; profile off % runs modes debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) diff --git a/add_modules.m b/add_modules.m index 1c8647d..e1b45c5 100644 --- a/add_modules.m +++ b/add_modules.m @@ -6,7 +6,7 @@ %clear all %close all -profile off +%profile off %import CryoGrid modules (matlab functions) diff --git a/modules/cryoGridLateral/calculateLateralHeatFluxes.m b/modules/cryoGridLateral/calculateLateralHeatFluxes.m index 3cbcb0b..d788fdd 100644 --- a/modules/cryoGridLateral/calculateLateralHeatFluxes.m +++ b/modules/cryoGridLateral/calculateLateralHeatFluxes.m @@ -1,5 +1,4 @@ -function [dE_dt, BALANCE] = calculateLateralHeatFluxes(T_index, k_index, PACKAGE_heatExchange_j, GRID, PARA, BALANCE, j) - +function [dE_dt, BALANCE] = calculateLateralHeatFluxes(T_index, k_index, PACKAGE_heatExchange_j, GRID, PARA, BALANCE, j) index = labindex; dE_dt = zeros( length(GRID.general.cT_grid), 1); if PARA.ensemble.thermal_contact_length(index,j)>0 % calculate lateral heat flux only for laterally connected workers diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index 757ed66..c36187f 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -3,14 +3,20 @@ index = labindex; % auxiliary calculations for circular geometry - diameter=10; % in [m] - area = pi.*(diameter./2)^2; % in [m^2] - perimeter = 2*pi.*(diameter./2); % in [m] - + F_L = 0.5; % landscape Lake Fraction + radius = 10; % in [m] + perimeter = 2*pi.*radius; % in [m] + distance = sqrt(pi./(4*F_L)) * radius; % in [m] % geometric relations - PARA.ensemble.distanceBetweenPoints= diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members +% PARA.ensemble.distanceBetweenPoints = diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members + PARA.ensemble.distanceBetweenPoints = distance .* ( ones(numlabs) - eye(numlabs) ); %in m; put 0 for all non-connected ensemble members; %zzz needed? PARA.ensemble.weight = [1, 1];%[2, 1, 1]; - PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 +% PARA.ensemble.weight = [radius/(PARA.ensemble.distanceBetweenPoints+radius),PARA.ensemble.distanceBetweenPoints/(PARA.ensemble.distanceBetweenPoints+radius)]; % weight keff by length radius and distance + + % area = pi.*(diameter./2)^2; % in [m^2] + %area = [pi.*radius^2 , pi.*(PARA.ensemble.distanceBetweenPoints^2-radius^2); % in [m^2] +% PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 zzz jjj ??? + PARA.ensemble.area = [pi.*radius^2 , pi.*(distance^2-radius^2)]; % in [m^2] % topographical relations %tsvd PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 3a2236b..9d0ec44 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -8,7 +8,6 @@ TEMPORARY.Qh_sum=TEMPORARY.Qh_sum+SEB.Qh.*timestep; TEMPORARY.Qnet_sum=TEMPORARY.Qnet_sum+SEB.Qnet.*timestep; TEMPORARY.Qg_sum=TEMPORARY.Qg_sum+SEB.Qg.*timestep; - TEMPORARY.Qsurf_sum = TEMPORARY.Qsurf_sum + SEB.Qsurf * timestep; TEMPORARY.dE_dt_SEB_sum = TEMPORARY.dE_dt_SEB_sum + SEB.dE_dt_SEB * timestep; TEMPORARY.dE_dt_cond_sum = TEMPORARY.dE_dt_cond_sum + SEB.dE_dt_cond * timestep; @@ -159,6 +158,7 @@ OUT.EB.Qh = [OUT.EB.Qh; TEMPORARY.Qh]; % sensible heat flux (positive into ground) OUT.EB.Qnet = [OUT.EB.Qnet; TEMPORARY.Qnet]; OUT.EB.Qgeo = [OUT.EB.Qgeo; PARA.soil.Qgeo]; % geothermal heat flux + OUT.EB.dE_soil_sens = [OUT.EB.dE_soil_sens; BALANCE.energy.dE_soil_sens ]; BALANCE.energy.dE_soil_sens = 0; OUT.EB.dE_soil_lat = [OUT.EB.dE_soil_lat; BALANCE.energy.dE_soil_lat ]; From 77ed766ca554400156812d1a9b2362c79babc0de Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Mon, 25 Jun 2018 18:14:11 +0200 Subject: [PATCH 42/45] new files for batch handling --- CryoGrid3_lake.m | 608 +++++++++++++++++ CryoGrid3_lake_batch.m | 611 ++++++++++++++++++ .../get_parallel_variables_batch.m | 91 +++ run_batch_CryoGrid3_lake.m | 109 ++++ 4 files changed, 1419 insertions(+) create mode 100644 CryoGrid3_lake.m create mode 100644 CryoGrid3_lake_batch.m create mode 100644 modules/cryoGridLateral/get_parallel_variables_batch.m create mode 100644 run_batch_CryoGrid3_lake.m diff --git a/CryoGrid3_lake.m b/CryoGrid3_lake.m new file mode 100644 index 0000000..d283de1 --- /dev/null +++ b/CryoGrid3_lake.m @@ -0,0 +1,608 @@ +% ------------------------------------------------------------------------- +% CryoGRID3 +% main script for running the model +% +% Developed by: S. Westermann and M. Langer 2015 + +% +% Extended by J. Nitzborn (infiltration of soils, lateral exchange of heat, water, snow) + +% Extended by T. Schneider von Deimling (coupling with FLAKE (based on version M. Langer) +% ---------------------------------------------------------------------------------------- + +%clear all; close all; profile off + +% runs modes +debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) +par_mode = 1; % parallel mode off/on + +if(par_mode==1) + delete(gcp('nocreate')) % useful to restart from a crash +end + +add_modules; %adds required modules + +number_of_realizations=2; % specify number of workers +if number_of_realizations>1 + parpool(number_of_realizations); +end + +spmd %zzz use function calls to calls below to enable debugging in par mode! + index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run +%nnn index=1 + +%---------------define input parameters------------------------------------ + % here you provide the ground stratigraphy + % z w/i m o type porosity + + % default stratigraphy used in publication: + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer extends until the end of the model domain + % column 2: volumetric water+ice content; column 3: volumetric mineral content; column 4: volumetric organic content; + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + %------ model parameters -------------------------------------------------- + % parameters related to soil + PARA.soil.albedo=0.2; % albedo snow-free surface + PARA.soil.epsilon=0.97; % emissvity snow-free surface + PARA.soil.z0=1e-3; % roughness length [m] snow-free surface + PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface + PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] + PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + + % parameters related to hydrology scheme + PARA.soil.fieldCapacity=0.5; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries + PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation + PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. + %tsvd PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] + PARA.soil.externalWaterFlux=0.; %external water flux / drainage in [m/day] + PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible + PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile + PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up jjj zzz + PARA.soil.hydraulic_conductivity = 1e-5; + PARA = loadSoilTypes( PARA ); + + % parameters related to snow + PARA.snow.max_albedo=0.85; % albedo of fresh snow + PARA.snow.min_albedo=0.5; % albedo of old snow + PARA.snow.epsilon=0.99; % surface emissivity snow + PARA.snow.z0=5e-4; % roughness length surface [m] + PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow + PARA.snow.rho_snow=200.0; % density in [kg/m3] + PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] + PARA.snow.tau_a=0.008; % [per day] + PARA.snow.tau_f=0.24; % [per day] + PARA.snow.relative_maxSnow= [0.1]; %ttt maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.extinction=25.0; % light extinction coefficient of snow + %tsvd add lake parameters + % parameters related to lake + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.epsilon=0.99; % surface emissivity water + PARA.water.rs=0.; % surface resistance -> should be 0 for water + %tsvd + PARA.water.z0=5e-4; % roughness length surface [m] % JAN: value for summer / vegetation + %tsvd PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m version Flake + PARA.water.extinction=1.2; % light extinction coefficient of water + PARA.water.depth=0.; + PARA.water.fetch=20; + + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + PARA.ice.epsilon=0.98; % surface emissivity snow + PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice + PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow + PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases + PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells + PARA.technical.maxSWE=0.4; % in [m] SWE + PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity + PARA.technical.starttime=datenum(1970, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(1999, 12, 31); % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [day- here 0.1 seconds + PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds + %tsvd PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.targetDeltaE=1e6; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K lll DeltaE increased by 1 order of M + PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours +% PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.syncTimeStep = 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + + %default grid used for publications and testing of water balance: + %PARA.technical.subsurfaceGrid = [[0:0.02:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + PARA.technical.subsurfaceGrid = [[0:0.04:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + + PARA.location.area=1.0; + PARA.location.initial_altitude=0.0; + % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" + PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain + PARA.location.soil_altitude=PARA.location.initial_altitude; + PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow + PARA.location.active_layer_depth_altitude = nan; % defined at runtime + PARA.location.water_table_altitude = nan; % defined at runtime + % thresholds + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.relative_maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; + end +%tsvd + PARA.location.latitude = 72.376; % [deg] < - + PARA.location.longitude = 126.491; % [deg] < - + %PARA.location.GridCellSize = 1e6; % [m^2] < - + %PARA.location.TileFraction = 1e-2; + % parameters related to the site location + PARA.location.water_table_altitude = nan; % defined at runtime + + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... + 2000 10 ]; + +% PARA.Tinitial = [ -2 5 ;... +% 0 0 ;... +% 2 -2 ;... +% 5 -7 ;... +% 10 -9 ;... +% 25 -9 ;... +% 100 -8 ;... +% 1100 10.2 ]; % the geothermal gradient for Qgeo=0.05W/m² and K=2.746W/Km is about 18.2 K/km + +% load natural constants (given in SI units) to PARA.constants + PARA = loadConstants( PARA ); + + %FORCING data mat-file + %PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.filename='Samoylov_rcp85_1901_2300_CryoGrid_windModified.mat'; + %PARA.forcing.filename='CG3_CCLM_forcing_90_101'; + PARA.forcing.rain_fraction=1; + PARA.forcing.snow_fraction=1; + + % switches for modules + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=0; % true if thaw subsicdence is enabled + PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) +%tsvd extended for lateral switched off + if ~PARA.modules.lateral + PARA.modules.exchange_heat = 0; + PARA.modules.exchange_water = 0; + PARA.modules.exchange_snow = 0; + PARA.snow.maxSnow= [] ; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + % in par mode this is replaced by PARA.ensemble.immobile_snow_height + elseif PARA.modules.lateral + % switches for lateral processes + PARA.modules.exchange_heat = 1; + PARA.modules.exchange_water = 0; %ttt + PARA.modules.exchange_snow = 0; %ttt + + %---------overwrites variables for each realization-------------------- + % this function must define everything that is realization-specific or dependent of all realizations + PARA = get_parallel_variables( PARA ); + end + + disp('Running experiment with xxxx -> indicate switches here') + % ------make output directory (name depends on parameters) ---------------- + saveDir = './runs'; +% run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) , ... +% PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, index ] ) + %run_number= sprintf( 'SSW-NL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_i%d' , ... + + run_number= sprintf( 'WD%1.0f_xH%d',[PARA.water.depth,PARA.modules.exchange_heat] ) +% run_number= sprintf( 'SSW_xH%d_WD%3.1f_i%d',[PARA.modules.exchange_heat,PARA.water.depth,index ] ); + + mkdir([ saveDir '/' run_number]); + + %tsvd ------redirect command line output to logfile --------------------------- + % if createLogFile +% diary(['./' run_number '/' run_number '_log.mat']); + diary([ saveDir '/' run_number '/' run_number '_log.mat']); + % end + + %-------------------------------------------------------------------------- + %-----------do not modify from here onwards-------------------------------- + %-------------------------------------------------------------------------- + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + + if ~success + warning('A problem with the Forcing occured.'); + end + + PARA = initializeParameters(PARA, FORCING); %set start time, etc. + + %----------------create and initialize the grids -------------------------- + GRID=makeGrids(PARA); %create all grids + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid (GRID.soil.*) + + %----- initializie excess ground ice -------------------------------------- + [GRID,PARA] = initializeExcessIce2(GRID,PARA); + + %----- initializie soil thermal properties -------------------------------- + GRID = initializeSoilThermalProperties(GRID, PARA); + + %------ initializie snow properties---------------------------------------- + GRID = initializeSnow(GRID); + + %---- initialize the surface energy balance struct ------------------------ + SEB = initializeSEB(); +%tsvd replace by new call lake scheme +% %---- initialize the water body module ------------------------------------ +% GRID = initializeLAKE(GRID); + +%---- initialize the lake scheme structs ---------------------------------- + [FLAKE GRID] = initializeLAKE(GRID, PARA); + %---- initialize temperature profile -------------------------------------- + T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); + + %---- modification for infiltration + wc=GRID.soil.cT_water; + GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; + GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; + + %---- preallocate temporary arrays for capacity and conductivity----------- + [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid + + %---- energy and water balance initialization ----------------------------- + BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); + + %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? +%nnn comment out for single mode... + water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index + snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index + heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index + dE_dt_lateral_j_cor = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index, corrected for interp bias + xxx = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index, corrected for interp bias + + %__________________________________________________________________________ + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); + + disp('initialization successful'); + %iSaveSettings( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_settings.mat'] , FORCING, PARA, GRID) %tsvd non-interpolated forcing data saved! + iSaveSettings( [ saveDir '/' run_number '/' run_number '_settings.mat'] , FORCING, PARA, GRID) %tsvd non-interpolated forcing data saved! + + %% ________________________________________________________________________ + % Time Integration Routine I + % I + %_________________________________________________________________________I + + while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) + warning( 'numerical stability not guaranteed' ); + end + + %------ update T array ------------------------------------------------ + % account for vertical heat fluxes from ground heat flux and heat conduction + T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; + % account for lateral heat fluxes + T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] + % set grid cells in air to air temperature + T(GRID.air.cT_domain)=FORCING.i.Tair; + + if max((T<-100))==1; disp('dwd'); end + + %------- water body module -------------------------------------------- +%tsvd T = mixingWaterBody(T, GRID); % zzz check whether this is ok to switch off + %------- snow cover module -------------------------------------------- + [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + + %------- infiltration module------------------------------------------- + if PARA.modules.infiltration + lateral_water_flux = nansum( water_fluxes ); % lateral fluxes to/from other workers in [m/s] + [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_water_flux); + end +%tsvd + %------- water body module -------------------------------------------- + if timestep>0 && ( ~isempty(GRID.lake.water.cT_domain_ub) || ~isempty(GRID.lake.ice.cT_domain_ub) ) + %ice cover + [T GRID FLAKE] = cryoGridIceCover(GRID, SEB, FLAKE, T, c_cTgrid, timestep); + %FLAKE + if isempty(GRID.lake.ice.cT_domain_ub) && sum(GRID.lake.water.cT_domain)>=3 + %FLAKE is used if no ice cells exist + [T GRID FLAKE] = cryoGridFLAKE(FLAKE, GRID, SEB, PARA, T, T_old, timestep, k_Kgrid, SEB.dE_dt, SEB.dE_dt_SEB); + else + %updated FLAKE variables also when FLAKE is not used + FLAKE.t_bot_n_flk = T(GRID.lake.water.cT_domain_lb) + 273.15; + %set mixed layerdepth to zero + FLAKE.h_ml_n_flk = 0; + end + GRID = updateGRID_flake(GRID); + end + %--------- buoyancy calculation in block fields------------------------ + %T = convectionInBlocks(T, c_cTgrid, GRID) %not available + % @ ALEX: here the calculations of the excess ice module take place + % (uncomment this line to "activate" the module). Note that the + % stratigraphy must be modified such that excess ground ice is present + % in order to make the module "work" + + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.modules.infiltration + warning( 'energy and water balances are not correct for this combination of modules'); % zzz ... + [GRID, PARA] = excessGroundIce(T, GRID, PARA); +%tsvd version Flake [GRID, PARA, wc] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); +%tsvd wc( end-sum(GRID.soil.cT_domain)+1 : end ); % make vector dims consistent + elseif PARA.modules.xice && PARA.modules.infiltration + [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); +%tsvd [GRID, PARA, wc] = excessGroundIceInfiltration(T, wc, GRID, PARA); + GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + end + + %------- update Lstar for next time step ------------------------------ + SEB = L_star(FORCING, PARA, SEB); + + %------- update auxiliary state variables + PARA.location.altitude = getAltitude( PARA, GRID ); + PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); + PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); + PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); + + %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time + if ~PARA.modules.lateral + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.maxSnow ) + %tsvd if isempty( PARA.ensemble.immobile_snow_height ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; + end + end + %------- water balance calculations ----------------------------------- + % rainfall + BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval + % snowfall + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval + + %------- lateral exchange module -------------------------------------- + % all functions called in this block should go into /modules/cryoGridLateral + % calling PARA.ensemble is only allowed here + if PARA.modules.lateral + if t==TEMPORARY.syncTime %communication between workers + disp('CryoGridLateral: sync - start'); + labBarrier(); %common start + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + % heat exchange module + if PARA.modules.exchange_heat + labBarrier(); + heat_fluxes = zeros( number_of_realizations, 1); + % check preconditions + precondition_heatExchange = true; %no specific conditions so far + if precondition_heatExchange + %WRAPPER + disp('sync - exchanging heat'); + % calculate lateral heat fluxes + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + % zzz not needed!? dE_dt_lateral_j_cor = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + % xxx = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + PACKAGE_heatExchange.T = T; + PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; + PACKAGE_heatExchange.k_cTgrid = k_cTgrid; + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_heatExchange, j, 1); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_heatExchange_j = labReceive(j, 1); + [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index + % now down after correction heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes + % dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations + end + end +%tsvd correct for biases in dE_dt_lateral (due to interpolation?), by using mean value for pairwise heat exchange + labBarrier(); + for j=1:number_of_realizations + if j~=index + %yyy2=dE_dt_lateral_j + labSend( nansum(dE_dt_lateral_j), j, 2); + end + end + for j=1:number_of_realizations + if j~=index + xxx = labReceive(j, 2); %ttt rm xxx yyy .... if not needed... + %dE_dt_lateral_j_cor = -xxx/nansum(dE_dt_lateral_j) * dE_dt_lateral_j; % scale...xxx (fluxes have opposite sign) + dE_dt_lateral_j_cor = (-xxx+nansum(dE_dt_lateral_j))/(2*nansum(dE_dt_lateral_j)) * dE_dt_lateral_j; % scale dE_dt lateral to mean value between workers (fluxes have opposite sign) + heat_fluxes(j) = nansum( dE_dt_lateral_j_cor .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes +% % dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations + % dE_dt_lateral_cor = dE_dt_lateral_cor + dE_dt_lateral_j_cor; % sum up contributions from all realizations - here on two workers... + dE_dt_lateral = dE_dt_lateral_j_cor; % if more than two workers, need to sum up here.... xxx zzz + end + end + end + end + + % water exchange module + if PARA.modules.exchange_water + labBarrier(); + water_fluxes = zeros( number_of_realizations, 1 ); % in [m/s] + % check preconditions + precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); + if precondition_waterExchange + % WRAPPER + disp('sync - exchanging water'); + % calculate lateral water fluxes + PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); + PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); %jjj zzz + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_waterExchange, j, 3); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_waterExchange_j = labReceive(j, 3); + % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) + water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); + end + end + % for debugging: print water flux per column + waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m + fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); + end + + end + + % snow exchange module + if PARA.modules.exchange_snow + labBarrier(); + % check preconditions + precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); + if precondition_snowExchange + disp('sync - exchanging snow'); + % calculate terrain index with updated surface_altitudes + PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); + + % calculate mobile snow + % WRAPPER + mobile_snow = zeros( 1, number_of_realizations ); + my_mobile_snow = 0; + meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE + if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions + i=0; + while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold + > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains + && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) + - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) + my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile + i=i+1; + end + end + mobile_snow(index) = my_mobile_snow; + % exchange mobile snow amounts + for j=1:number_of_realizations + if j~=index + % send mobile snow amount in [m SWE] + labSend( mobile_snow(index), j, 4 ); + end + end + for j=1:number_of_realizations + if j~=index + % receive mobile snow amount [m SWE] + mobile_snow(j) = labReceive(j, 4); + end + end + % calculate lateral snow fluxes + my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); + % apply lateral snow fluxes directly + if my_snow_change ~= 0 + [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; + end + + snow_fluxes = zeros( numlabs , 1 ); + snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes + fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); + + end + end + + labBarrier(); + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; + disp('sync - done'); + end + end + + + %------- next time step ----------------------------------------------- + t=t+timestep; + %---------- sum up + OUTPUT ------------------------------------------- + %nnn + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes); + end + + % save final state and output at t=endtime +%iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) +%iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + +%iSaveOUT( [ saveDir '/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) +%iSaveState( [ saveDir '/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + +%iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); +end + +if number_of_realizations>1 + delete(gcp('nocreate')) +end +%tsvd +dsave('Workspace') % save all distributed variables + +disp('Done.'); + diff --git a/CryoGrid3_lake_batch.m b/CryoGrid3_lake_batch.m new file mode 100644 index 0000000..cb4d41c --- /dev/null +++ b/CryoGrid3_lake_batch.m @@ -0,0 +1,611 @@ +function CryoGrid3_lake_batch(SETUP) +% CryoGRID3 +% main script for running the model +% +% Developed by: S. Westermann and M. Langer 2015 + +% +% Extended by J. Nitzborn (infiltration of soils, lateral exchange of heat, water, snow) + +% Extended by T. Schneider von Deimling (coupling with FLAKE (based on version M. Langer) +% ---------------------------------------------------------------------------------------- + +%clear all; close all; profile off + +% runs modes +debug_mode=0 % if set to 1, timestep = timestepMin for debugging (avoid of NaN for timestep calculation) +par_mode = 1; % parallel mode off/on + +if(par_mode==1) +% delete(gcp('nocreate')) % must be off in batch mode +end + +% add_modules; %adds required modules + +number_of_realizations=2; % specify number of workers + +if number_of_realizations>1 && isempty( gcp('nocreate') ) + parpool(number_of_realizations); % must not be invoked here in batch mode +end + +% zzz addAttachedFiles(gcp,' + +spmd %zzz use function calls to calls below to enable debugging in par mode! + index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run +%nnn index=1 + +%---------------define input parameters------------------------------------ + % here you provide the ground stratigraphy + % z w/i m o type porosity + + % default stratigraphy used in publication: + PARA.soil.layer_properties=[ 0.0 0.60 0.10 0.15 1 0.75;... + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]; + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer extends until the end of the model domain + % column 2: volumetric water+ice content; column 3: volumetric mineral content; column 4: volumetric organic content; + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + %------ model parameters -------------------------------------------------- + % parameters related to soil + PARA.soil.albedo=0.2; % albedo snow-free surface + PARA.soil.epsilon=0.97; % emissvity snow-free surface + PARA.soil.z0=1e-3; % roughness length [m] snow-free surface + PARA.soil.rs=50; % surface resistance against evapotransiration [m^-1] snow-free surface + PARA.soil.Qgeo=0.05; % geothermal heat flux [W/m2] + PARA.soil.kh_bedrock=3.0; % thermal conductivity of the mineral soil fraction [W/mK] + + % parameters related to hydrology scheme + PARA.soil.fieldCapacity=0.5; %water holding capacity of the soil - this must be adapted to fit the upperlost layers!! + PARA.soil.evaporationDepth=0.1; %depth to which evaporation occurs - place on grid cell boundaries + PARA.soil.rootDepth=0.2; %depth affected by transpiration - place on grid cell boundaries + PARA.soil.wiltingPoint=0.2; %point at which transpiration shuts off + PARA.soil.residualWC=0.05; %water always remaining in the soil, not accessible to evaporation + PARA.soil.ratioET=0.5; % 1: only transpiration; 0: only evaporation, values in between must be made dependent on LAI, etc. + %tsvd PARA.soil.externalWaterFlux=2e-3; %external water flux / drainage in [m/day] + PARA.soil.externalWaterFlux=0.; %external water flux / drainage in [m/day] + PARA.soil.convectiveDomain=[]; % soil domain where air convection due to buoyancy is possible -> start and end [m] - if empty no convection is possible + PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile + PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up jjj zzz + PARA.soil.hydraulic_conductivity = 1e-5; + PARA = loadSoilTypes( PARA ); +%%%% tsvd now done here as otherwise problem in batch mode specify one soil type per row: residualWC [%], fieldCapacity [%], alpha [1/m], n +% PARA.soil.soilTypes = [ [ 0.00, PARA.soil.fieldCapacity, 4.00, 2.0 ]; ... % sand +% [ 0.05, PARA.soil.fieldCapacity, 0.65, 1.7 ]; ... % silt +% [ 0.00, 0.00 , 4.00, 2.0 ] ]; % pond (freeze curve of sand but fieldCapacity = 0) + + % parameters related to snow + PARA.snow.max_albedo=0.85; % albedo of fresh snow + PARA.snow.min_albedo=0.5; % albedo of old snow + PARA.snow.epsilon=0.99; % surface emissivity snow + PARA.snow.z0=5e-4; % roughness length surface [m] + PARA.snow.rs=0.0; % surface resistance -> should be 0 for snow + PARA.snow.rho_snow=200.0; % density in [kg/m3] + PARA.snow.tau_1=86400.0; % time constants of snow albedo change (according to ECMWF reanalysis) [sec] + PARA.snow.tau_a=0.008; % [per day] + PARA.snow.tau_f=0.24; % [per day] + PARA.snow.relative_maxSnow= [0.1]; %ttt maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + PARA.snow.extinction=25.0; % light extinction coefficient of snow + %tsvd add lake parameters + % parameters related to lake + PARA.water.albedo=0.05; % albedo water (parameterization after Wayne and Burt (1954) in surfaceCondition.m) + PARA.water.epsilon=0.99; % surface emissivity water + PARA.water.rs=0.; % surface resistance -> should be 0 for water + %tsvd + PARA.water.z0=5e-4; % roughness length surface [m] % JAN: value for summer / vegetation + %tsvd PARA.water.z0=1e-4; % roughness length surface [m] - gets overridden by value calculated by function flake_roughnessLength.m version Flake + PARA.water.extinction=1.2; % light extinction coefficient of water + PARA.water.depth=0.; + PARA.water.fetch=20; + + PARA.ice.albedo =0.20; % albedo ice / Lei et al. (2011) shows a range of 0.1 to 0.35 + PARA.ice.epsilon=0.98; % surface emissivity snow + PARA.ice.rs=0.0; % surface resistance -> should be 0 for ice + PARA.ice.z0=5e-4; % roughness length surface [m] % JAN: value for snow + PARA.ice.extinction=4.5; % [m^-1] light extinction coefficient of ice / Lei et al. (2011) shows a range of 1 to 5 m^-1 + + PARA.technical.z=2.0; % height of input air temperature above ground in [m] - assumed constant even when snow depth increases + PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells + PARA.technical.maxSWE=0.4; % in [m] SWE + PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity + PARA.technical.starttime=datenum(1970, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(1970, 6, 10); % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds + PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds + %tsvd PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K + PARA.technical.targetDeltaE=1e6; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K lll DeltaE increased by 1 order of M + PARA.technical.outputTimestep= 3 ./ 24.0 ; % output time step in [days] - here three hours +% PARA.technical.syncTimeStep = 12 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.syncTimeStep = 3 ./ 24.0 ; % output time step in [days] - here three hours + PARA.technical.saveDate='01.01.'; % date of year when output file is written - no effect if "saveInterval" is empty + PARA.technical.saveInterval=[1]; % interval [years] in which output files are written - if empty the entire time series is written - minimum is 1 year + PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] + + %default grid used for publications and testing of water balance: + %tsvd PARA.technical.subsurfaceGrid = [[0:0.02:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + PARA.technical.subsurfaceGrid = [[0:0.04:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + + PARA.location.area=1.0; + PARA.location.initial_altitude=0.0; + % JAN: the following quantities are dynamic and should hence be moved to another struct, e.g. "STATE" + PARA.location.altitude = PARA.location.initial_altitude; % used to generate pressure forcing based on barometric altitude formula, if pressure forcing is not given; excluding snow domain + PARA.location.soil_altitude=PARA.location.initial_altitude; + PARA.location.surface_altitude=PARA.location.initial_altitude; % this is dynamic and refers to the surface including snow + PARA.location.active_layer_depth_altitude = nan; % defined at runtime + PARA.location.water_table_altitude = nan; % defined at runtime + % thresholds + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.relative_maxSnow ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.location.altitude + PARA.snow.relative_maxSnow ]; + end +%tsvd + PARA.location.latitude = 72.376; % [deg] < - + PARA.location.longitude = 126.491; % [deg] < - + %PARA.location.GridCellSize = 1e6; % [m^2] < - + %PARA.location.TileFraction = 1e-2; + % parameters related to the site location + PARA.location.water_table_altitude = nan; % defined at runtime + + %initial temperature profile -> first column depth [m] -> second column temperature [degree C] + PARA.Tinitial = [ -2 5 ;... + 0 0 ;... + 2 -5 ;... + 10 -10 ;... + 25 -9 ;... + 100 -9 ;... + 2000 10 ]; + +% PARA.Tinitial = [ -2 5 ;... +% 0 0 ;... +% 2 -2 ;... +% 5 -7 ;... +% 10 -9 ;... +% 25 -9 ;... +% 100 -8 ;... +% 1100 10.2 ]; % the geothermal gradient for Qgeo=0.05W/m² and K=2.746W/Km is about 18.2 K/km + +% load natural constants (given in SI units) to PARA.constants + PARA = loadConstants( PARA ); + + %FORCING data mat-file + %PARA.forcing.filename='samoylov_ERA_obs_fitted_1979_2014_spinup.mat'; %must be in subfolder "forcing" and follow the conventions for CryoGrid 3 forcing files + PARA.forcing.filename='Samoylov_rcp85_1901_2300_CryoGrid_windModified.mat'; + %PARA.forcing.filename='CG3_CCLM_forcing_90_101'; + PARA.forcing.rain_fraction=1; + PARA.forcing.snow_fraction=1; + + % switches for modules + PARA.modules.infiltration=1; % true if infiltration into unfrozen ground occurs + PARA.modules.xice=0; % true if thaw subsicdence is enabled + PARA.modules.lateral=1; % true if adjacent realizations are run (this does not require actual lateral fluxes) +%tsvd extended for lateral switched off + if ~PARA.modules.lateral + PARA.modules.exchange_heat = 0; + PARA.modules.exchange_water = 0; + PARA.modules.exchange_snow = 0; + PARA.snow.maxSnow= [] ; % maximum snow depth that can be reached [m] - excess snow is removed in the model - if empty, no snow threshold + % in par mode this is replaced by PARA.ensemble.immobile_snow_height + elseif PARA.modules.lateral + % switches for lateral processes + PARA.modules.exchange_heat = 1; + PARA.modules.exchange_water = 0; %ttt + PARA.modules.exchange_snow = 0; %ttt + + %---------overwrites variables for each realization-------------------- + % this function must define everything that is realization-specific or dependent of all realizations + %tsvd PARA = get_parallel_variables( PARA ); + PARA = get_parallel_variables_batch( PARA,SETUP ); + end + + disp('Running experiment with xxxx -> indicate switches here') + % ------make output directory (name depends on parameters) ---------------- + saveDir = './runs'; + run_number= sprintf( 'WD%1.0f_LC%d_xH%d',[PARA.water.depth, 100*SETUP.LF, PARA.modules.exchange_heat] ) % water depth in m, lake coverage in % + + mkdir([ saveDir '/' run_number]); + + %tsvd ------redirect command line output to logfile --------------------------- + % if createLogFile +% diary(['./' run_number '/' run_number '_log.mat']); + diary([ saveDir '/' run_number '/' run_number '_log.mat']); + % end + + %-------------------------------------------------------------------------- + %-----------do not modify from here onwards-------------------------------- + %-------------------------------------------------------------------------- + [FORCING, success]=load_forcing_from_file(PARA); % load FORCING mat-file + + if ~success + warning('A problem with the Forcing occured.'); + end + + PARA = initializeParameters(PARA, FORCING); %set start time, etc. + + %----------------create and initialize the grids -------------------------- + GRID=makeGrids(PARA); %create all grids + GRID=createStratigraphy(PARA,GRID); %interpolate input stratigraphy to the soil grid (GRID.soil.*) + + %----- initializie excess ground ice -------------------------------------- + [GRID,PARA] = initializeExcessIce2(GRID,PARA); + + %----- initializie soil thermal properties -------------------------------- + GRID = initializeSoilThermalProperties(GRID, PARA); + + %------ initializie snow properties---------------------------------------- + GRID = initializeSnow(GRID); + + %---- initialize the surface energy balance struct ------------------------ + SEB = initializeSEB(); +%tsvd replace by new call lake scheme +% %---- initialize the water body module ------------------------------------ +% GRID = initializeLAKE(GRID); + +%---- initialize the lake scheme structs ---------------------------------- + [FLAKE GRID] = initializeLAKE(GRID, PARA); + %---- initialize temperature profile -------------------------------------- + T = inititializeTemperatureProfile_simple(GRID, PARA, FORCING); + + %---- modification for infiltration + wc=GRID.soil.cT_water; + GRID.soil.E_lb = find(PARA.soil.evaporationDepth==GRID.soil.soilGrid(:,1))-1; + GRID.soil.T_lb= find(PARA.soil.rootDepth==GRID.soil.soilGrid(:,1))-1; + + %---- preallocate temporary arrays for capacity and conductivity----------- + [c_cTgrid, k_cTgrid, k_Kgrid, lwc_cTgrid] = initializeConductivityCapacity(T,wc, GRID, PARA); % this is basically the same as "getThermalProperties" during integration, but without interpolation to K grid + + %---- energy and water balance initialization ----------------------------- + BALANCE = initializeBALANCE(T, wc, c_cTgrid, lwc_cTgrid, GRID, PARA); + + %---- temporary arrays for storage of lateral fluxes --> these could go into a LATERAL struct or TEMPORARY? +%nnn comment out for single mode... + water_fluxes = zeros( numlabs, 1 ); % total water flux in [m/s] from each worker to worker index + snow_fluxes = zeros( numlabs, 1 ); % total snow flux in [m SWE] per output interval from each worker to worker index + heat_fluxes = zeros( numlabs, 1); % total heat flux in [J] per output interval of all workers to worker index + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index + dE_dt_lateral_j_cor = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index, corrected for interp bias + xxx = zeros( length(GRID.general.cT_grid), 1); % cell-wise heat flux in [W/m^3]? of all workers to worker index, corrected for interp bias + + %__________________________________________________________________________ + %-------- provide arrays for data storage --------------------------------- + [t, TEMPORARY] = generateTemporary(T, PARA); + OUT = generateOUT(); + + disp('initialization successful'); + %iSaveSettings( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_settings.mat'] , FORCING, PARA, GRID) %tsvd non-interpolated forcing data saved! + iSaveSettings( [ saveDir '/' run_number '/' run_number '_settings.mat'] , FORCING, PARA, GRID) %tsvd non-interpolated forcing data saved! + + %% ________________________________________________________________________ + % Time Integration Routine I + % I + %_________________________________________________________________________I + + while t 0.5 * min( GRID.general.K_delta.^2 .* c_cTgrid ./ k_cTgrid ./ (GRID.soil.cT_domain + GRID.snow.cT_domain) ) ./ (24.*3600) + warning( 'numerical stability not guaranteed' ); + end + + %------ update T array ------------------------------------------------ + % account for vertical heat fluxes from ground heat flux and heat conduction + T = T + SEB.dE_dt./c_cTgrid./GRID.general.K_delta.*timestep.*24.*3600; + % account for lateral heat fluxes + T = T + dE_dt_lateral./c_cTgrid.*timestep.*24.*3600; % no division by K_delta necessary as dE_dt_lateral in [ J / m^3 / s ] + % set grid cells in air to air temperature + T(GRID.air.cT_domain)=FORCING.i.Tair; + + if max((T<-100))==1; disp('dwd'); end + + %------- water body module -------------------------------------------- +%tsvd T = mixingWaterBody(T, GRID); % zzz check whether this is ok to switch off + %------- snow cover module -------------------------------------------- + [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_cTgrid, timestep, BALANCE); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + + %------- infiltration module------------------------------------------- + if PARA.modules.infiltration + lateral_water_flux = nansum( water_fluxes ); % lateral fluxes to/from other workers in [m/s] + [wc, GRID, BALANCE] = CryoGridInfiltration(T, wc, dwc_dt, timestep, GRID, PARA, FORCING, BALANCE, lateral_water_flux); + end +%tsvd + %------- water body module -------------------------------------------- + if timestep>0 && ( ~isempty(GRID.lake.water.cT_domain_ub) || ~isempty(GRID.lake.ice.cT_domain_ub) ) + %ice cover + [T GRID FLAKE] = cryoGridIceCover(GRID, SEB, FLAKE, T, c_cTgrid, timestep); + %FLAKE + if isempty(GRID.lake.ice.cT_domain_ub) && sum(GRID.lake.water.cT_domain)>=3 + %FLAKE is used if no ice cells exist + [T GRID FLAKE] = cryoGridFLAKE(FLAKE, GRID, SEB, PARA, T, T_old, timestep, k_Kgrid, SEB.dE_dt, SEB.dE_dt_SEB); + else + %updated FLAKE variables also when FLAKE is not used + FLAKE.t_bot_n_flk = T(GRID.lake.water.cT_domain_lb) + 273.15; + %set mixed layerdepth to zero + FLAKE.h_ml_n_flk = 0; + end + GRID = updateGRID_flake(GRID); + end + %--------- buoyancy calculation in block fields------------------------ + %T = convectionInBlocks(T, c_cTgrid, GRID) %not available + % @ ALEX: here the calculations of the excess ice module take place + % (uncomment this line to "activate" the module). Note that the + % stratigraphy must be modified such that excess ground ice is present + % in order to make the module "work" + + %------- excess ice module -------------------------------------------- + if PARA.modules.xice && ~PARA.modules.infiltration + warning( 'energy and water balances are not correct for this combination of modules'); % zzz ... + [GRID, PARA] = excessGroundIce(T, GRID, PARA); +%tsvd version Flake [GRID, PARA, wc] = excessGroundIce(T, GRID, PARA); + % assure wc has correct length + wc = wc( end-sum(GRID.soil.cT_domain)+1 : end ); +%tsvd wc( end-sum(GRID.soil.cT_domain)+1 : end ); % make vector dims consistent + elseif PARA.modules.xice && PARA.modules.infiltration + [GRID, PARA, wc, meltwaterGroundIce] = excessGroundIceInfiltration(T, wc, GRID, PARA); +%tsvd [GRID, PARA, wc] = excessGroundIceInfiltration(T, wc, GRID, PARA); + GRID = updateGRID_excessiceInfiltration2(meltwaterGroundIce, GRID); + end + + %------- update Lstar for next time step ------------------------------ + SEB = L_star(FORCING, PARA, SEB); + + %------- update auxiliary state variables + PARA.location.altitude = getAltitude( PARA, GRID ); + PARA.location.surface_altitude = getSurfaceAltitude( PARA, GRID ); + PARA.location.active_layer_depth_altitude = getActiveLayerDepthAltitude( PARA, GRID, T ); + PARA.location.water_table_altitude = getWaterTableAltitude(T, wc, GRID, PARA); + + %------- update threshold variables if no lateral exchange processes occur, otherwise updated at sync time + if ~PARA.modules.lateral + PARA.location.absolute_maxWater_altitude = PARA.location.altitude + PARA.soil.relative_maxWater; + if isempty( PARA.snow.maxSnow ) + %tsvd if isempty( PARA.ensemble.immobile_snow_height ) + PARA.location.absolute_maxSnow_altitude = []; + else + PARA.location.absolute_maxSnow_altitude = [ PARA.ensemble.altitude + PARA.snow.relative_maxSnow ]; + end + end + %------- water balance calculations ----------------------------------- + % rainfall + BALANCE.water.dp_rain = BALANCE.water.dp_rain + FORCING.i.rainfall.*timestep; %sum up rainfall in [mm] per output interval + % snowfall + BALANCE.water.dp_snow = BALANCE.water.dp_snow + FORCING.i.snowfall.*timestep; %sum up snowfall in [mm] SWE per output interval + + %------- lateral exchange module -------------------------------------- + % all functions called in this block should go into /modules/cryoGridLateral + % calling PARA.ensemble is only allowed here + if PARA.modules.lateral + if t==TEMPORARY.syncTime %communication between workers + disp('CryoGridLateral: sync - start'); + labBarrier(); %common start + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + % heat exchange module + if PARA.modules.exchange_heat + labBarrier(); + heat_fluxes = zeros( number_of_realizations, 1); + % check preconditions + precondition_heatExchange = true; %no specific conditions so far + if precondition_heatExchange + %WRAPPER + disp('sync - exchanging heat'); + % calculate lateral heat fluxes + dE_dt_lateral = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + % zzz not needed!? dE_dt_lateral_j_cor = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + % xxx = zeros( length(GRID.general.cT_grid), 1); %in [J/m^3/s] + PACKAGE_heatExchange.T = T; + PACKAGE_heatExchange.cT_grid = GRID.general.cT_grid; + PACKAGE_heatExchange.k_cTgrid = k_cTgrid; + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_heatExchange, j, 1); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_heatExchange_j = labReceive(j, 1); + [dE_dt_lateral_j, BALANCE] = calculateLateralHeatFluxes(T, k_cTgrid, PACKAGE_heatExchange_j,GRID, PARA, BALANCE, j); % contribution from worker j to worker index + % now down after correction heat_fluxes(j) = nansum( dE_dt_lateral_j .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes + % dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations + end + end +%tsvd correct for biases in dE_dt_lateral (due to interpolation?), by using mean value for pairwise heat exchange + labBarrier(); + for j=1:number_of_realizations + if j~=index + %yyy2=dE_dt_lateral_j + labSend( nansum(dE_dt_lateral_j), j, 2); + end + end + for j=1:number_of_realizations + if j~=index + xxx = labReceive(j, 2); %ttt rm xxx yyy .... if not needed... + %dE_dt_lateral_j_cor = -xxx/nansum(dE_dt_lateral_j) * dE_dt_lateral_j; % scale...xxx (fluxes have opposite sign) + dE_dt_lateral_j_cor = (-xxx+nansum(dE_dt_lateral_j))/(2*nansum(dE_dt_lateral_j)) * dE_dt_lateral_j; % scale dE_dt lateral to mean value between workers (fluxes have opposite sign) + heat_fluxes(j) = nansum( dE_dt_lateral_j_cor .* GRID.general.K_delta ); % in [J / m^2 s ], only for tracking the overall heat fluxes +% % dE_dt_lateral = dE_dt_lateral + dE_dt_lateral_j; % sum up contributions from all realizations + % dE_dt_lateral_cor = dE_dt_lateral_cor + dE_dt_lateral_j_cor; % sum up contributions from all realizations - here on two workers... + dE_dt_lateral = dE_dt_lateral_j_cor; % if more than two workers, need to sum up here.... xxx zzz + end + end + end + end + + % water exchange module + if PARA.modules.exchange_water + labBarrier(); + water_fluxes = zeros( number_of_realizations, 1 ); % in [m/s] + % check preconditions + precondition_waterExchange = checkPreconditionWaterExchange( T, GRID ); + if precondition_waterExchange + % WRAPPER + disp('sync - exchanging water'); + % calculate lateral water fluxes + PACKAGE_waterExchange.water_table_altitude = PARA.ensemble.water_table_altitude(index); + PACKAGE_waterExchange.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + PACKAGE_waterExchange.infiltration_condition = T(GRID.soil.cT_domain_ub)>0 && isempty(GRID.snow.cT_domain_ub); %jjj zzz + for j=1:number_of_realizations + if j~=index + labSend( PACKAGE_waterExchange, j, 3); + end + end + for j=1:number_of_realizations + if j~=index + PACKAGE_waterExchange_j = labReceive(j, 3); + % JAN: for now: assume DarcyFlux and distribute over sync time step (no check for available water, missing water tracked in BALANCE.dm_lacking) + water_fluxes(j) = calculateLateralWaterFluxes( T, PACKAGE_waterExchange_j, GRID, PARA, j); + end + end + % for debugging: print water flux per column + waterflux = nansum( water_fluxes.*PARA.technical.syncTimeStep.*24.*3600 ); % in m + fprintf('Water flux to worker %d = %f mm \n', [index, waterflux*1000] ); + end + + end + + % snow exchange module + if PARA.modules.exchange_snow + labBarrier(); + % check preconditions + precondition_snowExchange = checkPreconditionSnowExchange( GRID, PARA ); + if precondition_snowExchange + disp('sync - exchanging snow'); + % calculate terrain index with updated surface_altitudes + PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.surface_altitude, PARA.ensemble.weight); + + % calculate mobile snow + % WRAPPER + mobile_snow = zeros( 1, number_of_realizations ); + my_mobile_snow = 0; + meltingConditions_index = sum(GRID.snow.Snow_w)>0 || sum(T(GRID.snow.cT_domain)>0)>0; %snow is assumed to be immobile under melting conditions CHECK WITH SNOW MODULE + if ~isempty(GRID.snow.cT_domain_ub) && ~meltingConditions_index % current realization has snow cover and no melting conditions + i=0; + while (abs( GRID.general.K_grid(GRID.snow.cT_domain_ub+i)-GRID.general.K_grid(GRID.snow.cT_domain_lb+1) )... % snow only mobile above realization-specific threshold + > PARA.ensemble.immobile_snow_height(index)+GRID.general.K_delta(GRID.snow.cT_domain_ub)) ... % if upper cell is drifted away, immobile snow height remains + && (PARA.ensemble.initial_altitude(index)-GRID.general.K_grid(GRID.snow.cT_domain_ub+i) ... % snow only mobile above lowermost surface altitude + snowCellSize (to prevent oscillations) + - (min( PARA.ensemble.surface_altitude )+GRID.snow.snowCellSize) > 1e-6 ) + my_mobile_snow = my_mobile_snow + (GRID.snow.Snow_i(GRID.snow.cT_domain_ub+i)); %only "ice" mobile + i=i+1; + end + end + mobile_snow(index) = my_mobile_snow; + % exchange mobile snow amounts + for j=1:number_of_realizations + if j~=index + % send mobile snow amount in [m SWE] + labSend( mobile_snow(index), j, 4 ); + end + end + for j=1:number_of_realizations + if j~=index + % receive mobile snow amount [m SWE] + mobile_snow(j) = labReceive(j, 4); + end + end + % calculate lateral snow fluxes + my_snow_change = calculateLateralSnowFluxes2( mobile_snow, PARA ); + % apply lateral snow fluxes directly + if my_snow_change ~= 0 + [T, GRID] = applyLateralSnowFluxes( T, PARA, GRID, FORCING, my_snow_change ); + [GRID, T, BALANCE] = updateGRID_snow(T, GRID, PARA, BALANCE); + BALANCE.water.dr_lateralSnow = BALANCE.water.dr_lateralSnow + my_snow_change ; + end + + snow_fluxes = zeros( numlabs , 1 ); + snow_fluxes(index) = my_snow_change ./ (PARA.technical.syncTimeStep.*3600.*24); %this is only to have comparable output to other fluxes + fprintf('Snow flux to worker %d = %f mm SWE \n', [index, my_snow_change*1000] ); + + end + end + + labBarrier(); + PARA = updateAuxiliaryVariablesAndCommonThresholds(T, wc, GRID, PARA) ; + + TEMPORARY.syncTime=round((TEMPORARY.syncTime + PARA.technical.syncTimeStep)./PARA.technical.syncTimeStep).*PARA.technical.syncTimeStep; + disp('sync - done'); + end + end + + + %------- next time step ----------------------------------------------- + t=t+timestep; + %---------- sum up + OUTPUT ------------------------------------------- + %nnn + [TEMPORARY, OUT, BALANCE] = sum_up_output_store(t, T, wc, lwc_cTgrid(GRID.soil.cT_domain), timestep, TEMPORARY, BALANCE, PARA, GRID, SEB, OUT, saveDir, run_number, water_fluxes, snow_fluxes, heat_fluxes); + end + + % save final state and output at t=endtime +%iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_output' datestr(t,'yyyy') '.mat'], OUT) +%iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + +%iSaveOUT( [ saveDir '/' run_number '/' run_number '_output' datestr(t,'yyyy') '.mat'], OUT) +%iSaveState( [ saveDir '/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat'], T, wc, t, SEB, PARA, GRID) + +%iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(index) '_altitudes_vs_time_' datestr(t,'yyyy') '.png'], OUT, PARA ); +end + +if number_of_realizations>1 + delete(gcp('nocreate')) +end +%tsvd +dsave('Workspace') % save all distributed variables + +disp('Done.'); + diff --git a/modules/cryoGridLateral/get_parallel_variables_batch.m b/modules/cryoGridLateral/get_parallel_variables_batch.m new file mode 100644 index 0000000..5cd8786 --- /dev/null +++ b/modules/cryoGridLateral/get_parallel_variables_batch.m @@ -0,0 +1,91 @@ +function PARA = get_parallel_variables(PARA,SETUP) + + index = labindex; + + % auxiliary calculations for circular geometry + L_F = SETUP.LF; % landscape Lake Fraction + radius = SETUP.LR; % Lake radius in [m] + perimeter = 2*pi.*radius; % in [m] + distance = sqrt(pi./(4*L_F)) * radius; % in [m] + %distance = 2.*radius; + % geometric relations +% PARA.ensemble.distanceBetweenPoints = diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members + PARA.ensemble.distanceBetweenPoints = distance .* ( ones(numlabs) - eye(numlabs) ); %in m; put 0 for all non-connected ensemble members; %zzz needed? + %%%PARA.ensemble.distanceBetweenPoints = distance ; %in m; put 0 for all non-connected ensemble members; %zzz needed? + % PARA.ensemble.weight = [1, 1];%[2, 1, 1]; + %%%PARA.ensemble.weight = [radius/(PARA.ensemble.distanceBetweenPoints+radius),PARA.ensemble.distanceBetweenPoints/(PARA.ensemble.distanceBetweenPoints+radius)]; % weight keff by length radius and distance + PARA.ensemble.weight = [radius/(distance+radius),distance/(distance+radius)]; % weight keff by length radius and distance + + %area = pi.*radius^2; % in [m^2] + %area = [pi.*radius^2 , pi.*(PARA.ensemble.distanceBetweenPoints^2-radius^2); % in [m^2] + %PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 zzz jjj ??? + + PARA.ensemble.area = [pi.*radius^2 , pi.*(distance^2-radius^2)]; % in [m^2] + + % topographical relations + %tsvd PARA.ensemble.initial_altitude = [20.0, 20.5]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids +% PARA.ensemble.initial_altitude = [20.0, 20.0]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + PARA.ensemble.initial_altitude = [0., 0.]; %[20.0, 21.0, 20.5]; %in m a.s.l., this is the reference for the "zero" position of the grids + + PARA.ensemble.altitude = PARA.ensemble.initial_altitude; + PARA.ensemble.surface_altitude = PARA.ensemble.initial_altitude; + + % parameters related to heat exchange + PARA.ensemble.thermal_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); % [ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; % + + % parameters related to water exchange + PARA.ensemble.external_water_flux=[0, 0 ] ; % 0]; %in m/day + PARA.ensemble.hydraulic_conductivity= PARA.soil.hydraulic_conductivity * ( ones(numlabs) - eye(numlabs ) );%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; %in m/sec % [Roth: 1e-5 for saturated silt, 2.2e-5 for saturated sand] + PARA.ensemble.water_table_altitude = PARA.ensemble.altitude; %initialize somehow; + + %PARA.ensemble.max_water_flux= [0 0]; %in m water equivalent + PARA.ensemble.hydraulic_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) );%[ 0, 1, 0 ; 1, 0, 1 ; 0, 1, 0 ]; + PARA.ensemble.active_layer_depth_altitude = [NaN NaN NaN]; + PARA.ensemble.hydraulicDistance = PARA.ensemble.distanceBetweenPoints; + + % parameters related to snow exchange + %PARA.ensemble.snow_diffusivity = PARA.snow.diffusivity; + %PARA.ensemble.relative_max_snow_height = 0.2; + PARA.ensemble.immobile_snow_height = [0.1, 0.1 ]; %, 0.2 ]; %in m %this replaces PARA.snow.maxSnow ? zzz + PARA.ensemble.terrain_index_snow = calculateTerrainIndexSnow(PARA.ensemble.altitude, PARA.ensemble.weight); + PARA.ensemble.snow_contact_length = perimeter .* ( ones(numlabs) - eye(numlabs ) ); + + % location-specific static + PARA.location.initial_altitude = PARA.ensemble.initial_altitude(index); + PARA.soil.externalWaterFlux = PARA.ensemble.external_water_flux(index); + % location-specific dynamic auxiliary variables + PARA.location.area = PARA.ensemble.area(index); + PARA.location.altitude = PARA.ensemble.altitude(index); + PARA.location.surface_altitude = PARA.ensemble.surface_altitude(index); + PARA.location.water_table_altitude = PARA.ensemble.water_table_altitude(index); + PARA.location.active_layer_depth_altitude = PARA.ensemble.active_layer_depth_altitude(index); + % location-specific dynamic common thresholds + PARA.location.absolute_maxWater_altitude = [max( PARA.ensemble.altitude ) + PARA.soil.relative_maxWater]; + PARA.location.absolute_maxSnow_altitude = [max( PARA.ensemble.altitude ) + PARA.snow.relative_maxSnow]; + + % soil stratigraphy + % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer extends until the end of the model domain + % column 2: volumetric water+ice content; column 3: volumetric mineral content; column 4: volumetric organic content; + % column 5: code for soil type: 1: sand, 2: silt + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + + % default stratigraphy used in publication: +PARA.soil.layer_properties={[ 0.0 0.60 0.10 0.15 1 0.75;... % Non-Lake + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ], ... + % + [ 0.0 0.65 0.3 0.05 2 0.65;... % Lake + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]}; + + PARA.soil.layer_properties = PARA.soil.layer_properties{index}; + + % different initial conditions + + PARA.Tinitial=[SETUP.Tini(:,1) SETUP.Tini(:,1+index)]; + + PARA.water.depth = [0.,SETUP.LD]; + PARA.water.depth = PARA.water.depth(index); +end diff --git a/run_batch_CryoGrid3_lake.m b/run_batch_CryoGrid3_lake.m new file mode 100644 index 0000000..746455f --- /dev/null +++ b/run_batch_CryoGrid3_lake.m @@ -0,0 +1,109 @@ +% run CryoGrid3 in batch modus +clear all; close all; delete( gcp('nocreate') ); +add_modules; % this is not called in the main script anymore! +% default setup +SETUP = {}; % auxiliary struct containing parameters which are often varied. this struct is passed as an argument to the main script. + +parallel.defaultClusterProfile('local'); c = parcluster(); delete( c.Jobs ); % jjj ? +jobName = 'Lateral_Heat_Lake'; +jobs = {}; + +%% shallow lake (1-3: SSW, 4-6:MSW) +SETUP.LD = 1; % lake depth in meter +SETUP.Tini = [ -5 15 15;... % SSW setting + 0 10 6;... % surface + 1 -3 6;... % lake bottom + 2 -4 0;... % talik depth + 10 -7 -5;... + 20 -10 -10;... + 100 -10 -10;... + 2000 10 10]; +% SSW + SETUP.LR = 10; % lake depth in meter +% 1) SSW (LD 1m) LC=0.1 +i=1; % counter for the jobs +SETUP.LF= 0.1; % lake landscape coverage +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +% 2) SSW (LD 1m) LC=0.25 +i=2; +SETUP.LF= 0.25; +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +% % 3) SSW (LD 1m) LC=0.5 +% i=3; +% SETUP.LF= 0.5; +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% +% % MSW +% SETUP.LR = 100; % lake depth in meter +% % 4) MSW (LD 1m) LC=0.1 +% i=1; % counter for the jobs +% SETUP.LF= 0.1; % lake landscape coverage +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% % 5) MSW (LD 1m) LC=0.25 +% i=2; +% SETUP.LF= 0.25; +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% % 6) MSW (LD 1m) LC=0.5 +% i=3; +% SETUP.LF= 0.5; +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% +% %% deep lake (7-9: SSW, 10-12: MSW) +% SETUP.LD = 5; % lake depth in meter +% Tini = [ -5 15 15;... % MSW setting for summer +% 0 10 5;... % soil surface +% 5 -3 5;... % lake bottom +% 8 -6 0;... % talik depth +% 20 -10 -9;... +% 100 -10 -10;... +% 2000 10 10]; +% +% % SSW +% SETUP.LR = 10; % lake depth in meter +% % 7) SSW (LD 1m) LC=0.1 +% i=1; % counter for the jobs +% SETUP.LF= 0.1; % lake landscape coverage +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% % 8) SSW (LD 1m) LC=0.25 +% i=2; +% SETUP.LF= 0.25; +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% % 9) SSW (LD 1m) LC=0.5 +% i=3; +% SETUP.LF= 0.5; +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% +% % MSW +% SETUP.LR = 100; % lake depth in meter +% % 10) MSW (LD 1m) LC=0.1 +% i=1; % counter for the jobs +% SETUP.LF= 0.1; % lake landscape coverage +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% % 11) MSW (LD 1m) LC=0.25 +% i=2; +% SETUP.LF= 0.25; +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% % 12) MSW (LD 1m) LC=0.5 +% i=3; +% SETUP.LF= 0.5; +% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +% disp( [datestr(now) ': created job ',num2str(i) ] ); +% %% +% +% +% % to watch the status use c.Jobs(i)(.Tasks) or jobs{i}(.Tasks) +% % j = batch('CryoGrid3_xice_mpi','Pool',3,'CaptureDiary',true); +% % wait(j); % Wait for the job to finish +% % diary(j) % Display the diary +% % load(j) % Load job workspace data into client workspace From 7dfebc88cf5b55bc2b99f84424442804320f9a73 Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Mon, 25 Jun 2018 18:15:17 +0200 Subject: [PATCH 43/45] lateral heat exchange scaled to mean value (already in prev commit) --- modules/cryoGridLake/heatConductionLateral.m | 16 ---- modules/cryoGridLake/initializeLAKE.m | 2 +- .../calculateLateralHeatFluxes.m | 9 +- .../calculateTerrainIndexSnow.m | 5 +- .../cryoGridLateral/get_parallel_variables.m | 96 ++++++++++++++----- modules/cryoGridTechnical/makeGrids.m | 4 +- .../cryoGridTechnical/sum_up_output_store.m | 8 +- 7 files changed, 90 insertions(+), 50 deletions(-) delete mode 100644 modules/cryoGridLake/heatConductionLateral.m diff --git a/modules/cryoGridLake/heatConductionLateral.m b/modules/cryoGridLake/heatConductionLateral.m deleted file mode 100644 index c905833..0000000 --- a/modules/cryoGridLake/heatConductionLateral.m +++ /dev/null @@ -1,16 +0,0 @@ -function [dE_dt_cond dE_dt_lateral T_lateral]=heatConductionLateral(dE_dt_cond,T,k_temp,GRID,REF,FLAKE,t) - -[~, idx]=min(abs(REF.load.OUT.timestamp-t)); -T_lateral=REF.load.OUT.cryoGrid3(:,idx); - -%Estimated lateral heat flux. This procedure assumes that the thermal regime -%of the ground is not affected by the lake in a distance of about 2 twice -%the diameter of the lake. Assuming a circular lake shape, the lake has -%an effetive cross section with the soil domain of pi. Thus, the lateral -%heat flux per m^2 scales with (3.14.*FLAKE.fetch.*GRID.general.K_delta)./(3.14./4.*FLAKE.fetch.^2) - -dE_dt_lateral = k_temp.*(T_lateral-T)./(2.*FLAKE.fetch) .* 4.*GRID.general.K_delta./FLAKE.fetch; -dE_dt_lateral(~GRID.soil.cT_domain | T>0)=0; %exclude talik from lateral heat flux - -dE_dt_cond=dE_dt_cond+dE_dt_lateral; - diff --git a/modules/cryoGridLake/initializeLAKE.m b/modules/cryoGridLake/initializeLAKE.m index de8cbb3..5a4a5b7 100644 --- a/modules/cryoGridLake/initializeLAKE.m +++ b/modules/cryoGridLake/initializeLAKE.m @@ -22,7 +22,7 @@ FLAKE.q_w_flk=0; FLAKE.q_bot_flk=0; -FLAKE.fetch=100; +%tsvd FLAKE.fetch=100; not used anymore FLAKE.depth_w=PARA.water.depth; FLAKE.d_h_ice_dt = 0; FLAKE.q_ice_water = 0; diff --git a/modules/cryoGridLateral/calculateLateralHeatFluxes.m b/modules/cryoGridLateral/calculateLateralHeatFluxes.m index d788fdd..24105f1 100644 --- a/modules/cryoGridLateral/calculateLateralHeatFluxes.m +++ b/modules/cryoGridLateral/calculateLateralHeatFluxes.m @@ -6,14 +6,19 @@ % change to absolute altitude grid altitude_cTgrid_index = -GRID.general.cT_grid + PARA.ensemble.initial_altitude(index); - % determine the contact domain distance_index_j = PARA.ensemble.distanceBetweenPoints(j, index); weight_index = PARA.ensemble.weight(index); weight_j = PARA.ensemble.weight(j); contact_length_index_j = PARA.ensemble.thermal_contact_length(j, index); %tsvd allow for heat exchange over full vertical profile contact_altitude = min( [ PARA.ensemble.altitude(j), PARA.ensemble.altitude(index) ] ) - distance_index_j; %below this depth, grid cells will exchange heat - contact_altitude = min( [ PARA.ensemble.altitude(j), PARA.ensemble.altitude(index) ] ); %below this depth, grid cells will exchange heat + % determine the contact domain +% contact_altitude = min( [ PARA.ensemble.altitude(j), PARA.ensemble.altitude(index) ] ); %below this depth, grid cells will exchange heat + contact_altitude = 0.; % ttt temporal fix zzz contact_domain = altitude_cTgrid_index <= contact_altitude; %all cells in the current ensemble member + +% save uuu.mat contact_domain +% assert( 1==0, 'stop here') + % interpolate j-values to index-grid altitude_cTgrid_j = -PACKAGE_heatExchange_j.cT_grid + PARA.ensemble.initial_altitude(j); diff --git a/modules/cryoGridLateral/calculateTerrainIndexSnow.m b/modules/cryoGridLateral/calculateTerrainIndexSnow.m index 6d8abfb..f1a4407 100644 --- a/modules/cryoGridLateral/calculateTerrainIndexSnow.m +++ b/modules/cryoGridLateral/calculateTerrainIndexSnow.m @@ -1,5 +1,8 @@ function terrain_index_snow_final = calculateTerrainIndexSnow(altitudes, weight) -% +%tsvd +weight_fix = [1, 1]; % temporal fix zzz ttt +weight=weight_fix; + snowCellSize = 0.025; allAltitudes=[]; for i=1:size(weight,2) diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index c36187f..d893bb6 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -7,15 +7,19 @@ radius = 10; % in [m] perimeter = 2*pi.*radius; % in [m] distance = sqrt(pi./(4*F_L)) * radius; % in [m] + %distance = 2.*radius; % geometric relations % PARA.ensemble.distanceBetweenPoints = diameter .* ( ones(numlabs) - eye(numlabs) );% [0, 4, 4; 4, 0, 4 ; 4, 4, 0]; %in m; put 0 for all non-connected ensemble members PARA.ensemble.distanceBetweenPoints = distance .* ( ones(numlabs) - eye(numlabs) ); %in m; put 0 for all non-connected ensemble members; %zzz needed? - PARA.ensemble.weight = [1, 1];%[2, 1, 1]; -% PARA.ensemble.weight = [radius/(PARA.ensemble.distanceBetweenPoints+radius),PARA.ensemble.distanceBetweenPoints/(PARA.ensemble.distanceBetweenPoints+radius)]; % weight keff by length radius and distance + %%%PARA.ensemble.distanceBetweenPoints = distance ; %in m; put 0 for all non-connected ensemble members; %zzz needed? + % PARA.ensemble.weight = [1, 1];%[2, 1, 1]; + %%%PARA.ensemble.weight = [radius/(PARA.ensemble.distanceBetweenPoints+radius),PARA.ensemble.distanceBetweenPoints/(PARA.ensemble.distanceBetweenPoints+radius)]; % weight keff by length radius and distance + PARA.ensemble.weight = [radius/(distance+radius),distance/(distance+radius)]; % weight keff by length radius and distance - % area = pi.*(diameter./2)^2; % in [m^2] + %area = pi.*radius^2; % in [m^2] %area = [pi.*radius^2 , pi.*(PARA.ensemble.distanceBetweenPoints^2-radius^2); % in [m^2] -% PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 zzz jjj ??? + %PARA.ensemble.area = PARA.ensemble.weight.*area; % in m^2 zzz jjj ??? + PARA.ensemble.area = [pi.*radius^2 , pi.*(distance^2-radius^2)]; % in [m^2] % topographical relations @@ -63,7 +67,19 @@ % column 1: start depth of layer (first layer must start with 0) - each layer extends until the beginning of the next layer, the last layer extends until the end of the model domain % column 2: volumetric water+ice content; column 3: volumetric mineral content; column 4: volumetric organic content; % column 5: code for soil type: 1: sand, 2: silt - % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + % column 6: natural porosity - should be the same as 1-mineral-organic if no ground subsidence/thermokarst occurs + + + % default stratigraphy used in publication: + PARA.soil.layer_properties={[ 0.0 0.60 0.10 0.15 1 0.75;... % Non-Lake + 0.15 0.65 0.3 0.05 2 0.65;... + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ], ... + % + [ 0.0 0.65 0.3 0.05 2 0.65;... % Lake + 0.9 0.65 0.3 0.05 1 0.65;... + 9.0 0.30 0.70 0.00 1 0.30 ]}; + % PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % center stratigraphy without excess ice % 1.0 0.5 0.5 0.00 1 0.50 ;... % 10.0 0.25 0.75 0.00 1 0.25 ] , ... @@ -75,14 +91,24 @@ % 10.0 0.25 0.75 0.00 1 0.25 ]}; - PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (no excess ice) - 1.0 0.5 0.5 0.00 1 0.50 ;... - 10.0 0.25 0.75 0.00 1 0.25 ], ... - - [0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy - 1.0 0.5 0.5 0.00 1 0.50 ;... - 10.0 0.25 0.75 0.00 1 0.25 ]}; - +% PARA.soil.layer_properties = {[0.0 0.5 0.5 0.00 1 0.50 ;... % non-lake stratigraphy (no excess ice) +% 1.0 0.5 0.5 0.00 1 0.50 ;... +% 10.0 0.25 0.75 0.00 1 0.25 ], ... +% +% [0.0 0.5 0.5 0.00 1 0.50 ;... % lake stratigraphy +% 1.0 0.5 0.5 0.00 1 0.50 ;... +% 10.0 0.25 0.75 0.00 1 0.25 ]}; + + +% PARA.soil.layer_properties = {[0.0 0.4 0.1 0.15 1 0.75 ;... % non-lake stratigraphy (~Langer JGR15) +% % 0.2 0.65 0.3 0.05 2 0.65 ;... +% 1.0 0.65 0.3 0.05 1 0.65 ;... +% 10.0 0.3 0.7 0.00 1 0.3 ], ... +% % +% [0.0 0.4 0.1 0.15 1 0.75 ;... % lake stratigraphy +% 1.0 0.65 0.3 0.05 1 0.65 ;... +% 10.0 0.3 0.7 0.00 1 0.3 ]}; + %todotodo read parameters from file! % PARA.soil.layer_properties = {[0.0 0.5 0.5 0.25 1 0.50 ;... % reference case - Langer 2015 % 0.2 0.5 0.5 0.00 1 0.50 ;... @@ -119,13 +145,39 @@ PARA.soil.layer_properties = PARA.soil.layer_properties{index}; % different initial conditions - PARA.Tinitial = [-5 5 5;... - 0 -5 -2;... - 1 -5 -1;... - 10 -8 0;... - 20 -10 0;... - 100 -10 1;... +% PARA.Tinitial = [-5 5 5;... +% 0 -5 -2;... +% 1 -5 -1;... +% 10 -8 0;... +% 20 -10 0;... +% 100 -10 1;... +% 2000 10 10]; + +% PARA.Tinitial = [-5 5 5;... +% 0 -5 4;... +% 1 -5 1;... +% 10 -8 0;... +% 20 -10 0;... +% 100 -10 1;... +% 2000 10 10]; + + PARA.Tinitial = [ -5 10 10;... % SSW setting + 0 0 6;... + 0.9 -3 6;... + 2 -4 0;... + 10 -7 -5;... + 20 -10 -10;... + 100 -10 -10;... 2000 10 10]; + +% PARA.Tinitial = [ -5 10 10;... % MSW setting +% 0 0 5;... +% 6 -3 4;... +% 10 -7 0;... +% 20 -10 -9;... +% 100 -10 -10;... +% 2000 10 10]; + % PARA.Tinitial = [-5 10 10;... this profile can cause model crashes in mpi... % 0 0 0;... % 5 -5 -5;... @@ -135,11 +187,7 @@ PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; -%tsvd set lake depths for workers -% PARA.water.depth = [1.,0.]; - -% PARA.water.depth = [0.,0.]; % non-lake setting - PARA.water.depth = [0.,0.9]; % non-lake and small-sized water body (SSW) + PARA.water.depth = [0.,1.]; % non-lake and small-sized water body (SSW) %PARA.water.depth = [0.,6.]; % non-lake and medium-sized water body (MSW) PARA.water.depth = PARA.water.depth(index); diff --git a/modules/cryoGridTechnical/makeGrids.m b/modules/cryoGridTechnical/makeGrids.m index 6a5fc62..843f31e 100644 --- a/modules/cryoGridTechnical/makeGrids.m +++ b/modules/cryoGridTechnical/makeGrids.m @@ -3,7 +3,9 @@ GRID.snow.snowCellSize=PARA.technical.SWEperCell/(PARA.snow.rho_snow/PARA.constants.rho_w); % only used to calculate length initial air grid... GRID.snow.snowGrid=[-1.*(PARA.technical.maxSWE./(PARA.technical.SWEperCell)+2).*GRID.snow.snowCellSize:GRID.snow.snowCellSize:-GRID.snow.snowCellSize]'; %tsvd LAKE grid -GRID.lake.water.waterGrid=[0:0.02:PARA.water.depth-0.02]'; %with water (it is recommended to use a grid resolution of about 2cm) +%GRID.lake.water.waterGrid=[0:0.02:PARA.water.depth-0.02]'; %with water (it is recommended to use a grid resolution of about 2cm) +GRID.lake.water.waterGrid=[0:0.04:PARA.water.depth-0.04]'; %with water (it is recommended to use a grid resolution of about 2cm) + %GRID.lake.water.waterGrid=[]'; %no water if ~isempty(GRID.lake.water.waterGrid) GRID.soil.soilGrid=PARA.technical.subsurfaceGrid + (2*GRID.lake.water.waterGrid(end)-GRID.lake.water.waterGrid(end-1)); diff --git a/modules/cryoGridTechnical/sum_up_output_store.m b/modules/cryoGridTechnical/sum_up_output_store.m index 9d0ec44..c2695df 100644 --- a/modules/cryoGridTechnical/sum_up_output_store.m +++ b/modules/cryoGridTechnical/sum_up_output_store.m @@ -183,13 +183,11 @@ disp([datestr(now,'yyyy-mm-dd HH:MM:SS'),': at ', datestr(t), ', Average timestep: ', num2str(TEMPORARY.timestep_out), ' seconds']) TEMPORARY.outputTime=round((TEMPORARY.outputTime+PARA.technical.outputTimestep)./PARA.technical.outputTimestep).*PARA.technical.outputTimestep; - - %ooo index=1 - + %write output files if round((t-TEMPORARY.saveTime).*48)==0 - iSaveOUT( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_output' datestr(t,'yyyy') '.mat' ], OUT); - iSaveState( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_finalState' datestr(t,'yyyy') '.mat' ], T, wc, t, SEB, PARA, GRID); + iSaveOUT( [ saveDir '/' run_number '/' run_number '_' datestr(t,'yyyy') '.mat' ], OUT); + iSaveState( [ saveDir '/' run_number '/' run_number '_finalState' datestr(t,'yyyy') '.mat' ], T, wc, t, SEB, PARA, GRID); %ttt iPlotAltitudes( [ saveDir '/' run_number '/' run_number '_realization' num2str(labindex) '_altitudes_vs_time_' datestr(t,'yyyy') '.png' ], OUT, PARA ); OUT = generateOUT(); TEMPORARY.saveTime=datenum(str2num(datestr(t,'yyyy'))+1, str2num(datestr(t,'mm')), str2num(datestr(t,'dd')), str2num(datestr(t,'HH')), str2num(datestr(t,'MM')), 0); From e61dc8953f1affa597fba9eda1d719397af7a50a Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Wed, 18 Jul 2018 13:33:02 +0200 Subject: [PATCH 44/45] EUCOP version --- CryoGrid3_lake.m | 42 ++++---- CryoGrid3_lake_batch.m | 19 ++-- analysis/Tprofiles_04.m | 67 ++++++++++++ analysis/analysis_Tz_12.m | 181 ++++++++++++++++++++++++++++++++ analysis/plot_T_14.m | 210 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 484 insertions(+), 35 deletions(-) create mode 100644 analysis/Tprofiles_04.m create mode 100644 analysis/analysis_Tz_12.m create mode 100644 analysis/plot_T_14.m diff --git a/CryoGrid3_lake.m b/CryoGrid3_lake.m index d283de1..2710d74 100644 --- a/CryoGrid3_lake.m +++ b/CryoGrid3_lake.m @@ -1,4 +1,3 @@ -% ------------------------------------------------------------------------- % CryoGRID3 % main script for running the model % @@ -17,14 +16,15 @@ par_mode = 1; % parallel mode off/on if(par_mode==1) - delete(gcp('nocreate')) % useful to restart from a crash + delete(gcp('nocreate')) % must be off in batch mode end add_modules; %adds required modules number_of_realizations=2; % specify number of workers -if number_of_realizations>1 - parpool(number_of_realizations); + +if number_of_realizations>1 && isempty( gcp('nocreate') ) + parpool(number_of_realizations); % must not be invoked here in batch mode end spmd %zzz use function calls to calls below to enable debugging in par mode! @@ -68,8 +68,7 @@ PARA.soil.mobileWaterDomain=[0 10.0]; % soil domain where water from excess ice melt is mobile -> start and end [m] - if empty water is not mobile PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up jjj zzz PARA.soil.hydraulic_conductivity = 1e-5; - PARA = loadSoilTypes( PARA ); - + PARA = loadSoilTypes( PARA ); % parameters related to snow PARA.snow.max_albedo=0.85; % albedo of fresh snow PARA.snow.min_albedo=0.5; % albedo of old snow @@ -104,9 +103,10 @@ PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1970, 6, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1999, 12, 31); % endtime of the simulation - if empty end at last value of time series - PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [day- here 0.1 seconds + PARA.technical.starttime=datenum(2010, 6, 1); % starttime of the simulation - if empty start from first value of time series + PARA.technical.endtime=datenum(2099, 12, 30); % endtime of the simulation - if empty end at last value of time series + %PARA.technical.endtime = SETUP.endtime; % endtime of the simulation - if empty end at last value of time series + PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds %tsvd PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K PARA.technical.targetDeltaE=1e6; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K lll DeltaE increased by 1 order of M @@ -118,7 +118,7 @@ PARA.technical.waterCellSize=0.02; % default size of a newly added water cell when water ponds below water table [m] %default grid used for publications and testing of water balance: - %PARA.technical.subsurfaceGrid = [[0:0.02:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] + %tsvd PARA.technical.subsurfaceGrid = [[0:0.02:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] PARA.technical.subsurfaceGrid = [[0:0.04:4], [4.1:0.1:10], [10.2:0.2:20], [21:1:30], [35:5:50], [60:10:100], [200:100:1000]]'; % the subsurface K-grid in [m] PARA.location.area=1.0; @@ -192,24 +192,21 @@ %---------overwrites variables for each realization-------------------- % this function must define everything that is realization-specific or dependent of all realizations PARA = get_parallel_variables( PARA ); + %PARA = get_parallel_variables_batch( PARA,SETUP ); end disp('Running experiment with xxxx -> indicate switches here') % ------make output directory (name depends on parameters) ---------------- - saveDir = './runs'; -% run_number = sprintf( [ 'Lake-MPI_' datestr( PARA.technical.starttime, 'yyyymm' ) '-' datestr(PARA.technical.endtime, 'yyyymm' ) , ... -% PARA.modules.exchange_heat, PARA.modules.exchange_water, PARA.modules.exchange_snow, PARA.forcing.rain_fraction, PARA.forcing.snow_fraction, index ] ) - %run_number= sprintf( 'SSW-NL_xH%d_xW%d_xS%d_infil%d_xice%d_rF%d_sF%d_i%d' , ... + saveDir = './runs_RCP85'; + run_number= sprintf( 'WD%d_LD%d_LR%d_LF%d',[PARA.water.depth,5,10,25] ) % water depth in m, lake coverage in % + %run_number= sprintf( 'WD%d_LD%d_LR%d_LF%d',[PARA.water.depth, PARA.water.depth, SETUP.LR, 100*SETUP.LF] ) % water depth in m, lake coverage in % + %run_number= sprintf( 'WD%1.0f_xH%d',[PARA.water.depth,PARA.modules.exchange_heat] ) - run_number= sprintf( 'WD%1.0f_xH%d',[PARA.water.depth,PARA.modules.exchange_heat] ) -% run_number= sprintf( 'SSW_xH%d_WD%3.1f_i%d',[PARA.modules.exchange_heat,PARA.water.depth,index ] ); - mkdir([ saveDir '/' run_number]); - %tsvd ------redirect command line output to logfile --------------------------- + %tsvd ------redirect command line output to logfile (does not work here in batch/parallel mode (use diary(job{jobnumber}) instead) % if createLogFile -% diary(['./' run_number '/' run_number '_log.mat']); - diary([ saveDir '/' run_number '/' run_number '_log.mat']); + % diary([ saveDir '/' run_number '/' run_number '_log.mat']); % end %-------------------------------------------------------------------------- @@ -579,8 +576,7 @@ disp('sync - done'); end end - - + %------- next time step ----------------------------------------------- t=t+timestep; %---------- sum up + OUTPUT ------------------------------------------- @@ -602,7 +598,7 @@ delete(gcp('nocreate')) end %tsvd -dsave('Workspace') % save all distributed variables +%dsave([ saveDir '/' run_number '/' run_number '_Workspace']) % save all distributed variables disp('Done.'); diff --git a/CryoGrid3_lake_batch.m b/CryoGrid3_lake_batch.m index cb4d41c..eddf074 100644 --- a/CryoGrid3_lake_batch.m +++ b/CryoGrid3_lake_batch.m @@ -20,7 +20,7 @@ function CryoGrid3_lake_batch(SETUP) % delete(gcp('nocreate')) % must be off in batch mode end -% add_modules; %adds required modules +add_modules; %adds required modules number_of_realizations=2; % specify number of workers @@ -28,8 +28,6 @@ function CryoGrid3_lake_batch(SETUP) parpool(number_of_realizations); % must not be invoked here in batch mode end -% zzz addAttachedFiles(gcp,' - spmd %zzz use function calls to calls below to enable debugging in par mode! index=labindex; %number identifying the process; change this to e.g. 1 for single realization (non-parallel) run %nnn index=1 @@ -72,10 +70,6 @@ function CryoGrid3_lake_batch(SETUP) PARA.soil.relative_maxWater=0.; % depth at which a water table will form [m] - above excess water is removed, below it pools up jjj zzz PARA.soil.hydraulic_conductivity = 1e-5; PARA = loadSoilTypes( PARA ); -%%%% tsvd now done here as otherwise problem in batch mode specify one soil type per row: residualWC [%], fieldCapacity [%], alpha [1/m], n -% PARA.soil.soilTypes = [ [ 0.00, PARA.soil.fieldCapacity, 4.00, 2.0 ]; ... % sand -% [ 0.05, PARA.soil.fieldCapacity, 0.65, 1.7 ]; ... % silt -% [ 0.00, 0.00 , 4.00, 2.0 ] ]; % pond (freeze curve of sand but fieldCapacity = 0) % parameters related to snow PARA.snow.max_albedo=0.85; % albedo of fresh snow @@ -111,8 +105,9 @@ function CryoGrid3_lake_batch(SETUP) PARA.technical.SWEperCell=0.005; % SWE per grid cell in [m] - determines size of snow grid cells PARA.technical.maxSWE=0.4; % in [m] SWE PARA.technical.arraySizeT=5002; % number of values in the look-up tables for conductivity and capacity - PARA.technical.starttime=datenum(1970, 6, 1); % starttime of the simulation - if empty start from first value of time series - PARA.technical.endtime=datenum(1970, 6, 10); % endtime of the simulation - if empty end at last value of time series + PARA.technical.starttime=datenum(2000, 6, 1); % starttime of the simulation - if empty start from first value of time series + %PARA.technical.endtime=datenum(1970, 6, 10); % endtime of the simulation - if empty end at last value of time series + PARA.technical.endtime = SETUP.endtime; % endtime of the simulation - if empty end at last value of time series PARA.technical.minTimestep=0.1 ./ 3600 ./ 24; % smallest possible time step in [days] - here 0.1 seconds PARA.technical.maxTimestep=300 ./ 3600 ./ 24; % largest possible time step in [days] - here 300 seconds %tsvd PARA.technical.targetDeltaE=1e5; % maximum energy change of a grid cell between time steps in [J/m3] %1e5 corresponds to heating of pure water by 0.025 K @@ -205,14 +200,14 @@ function CryoGrid3_lake_batch(SETUP) disp('Running experiment with xxxx -> indicate switches here') % ------make output directory (name depends on parameters) ---------------- saveDir = './runs'; - run_number= sprintf( 'WD%1.0f_LC%d_xH%d',[PARA.water.depth, 100*SETUP.LF, PARA.modules.exchange_heat] ) % water depth in m, lake coverage in % + run_number= sprintf( 'WD%d_LD%d_LR%d_LF%d',[PARA.water.depth, SETUP.LD, SETUP.LR, 100*SETUP.LF] ) % water depth in m, lake coverage in % mkdir([ saveDir '/' run_number]); %tsvd ------redirect command line output to logfile --------------------------- % if createLogFile % diary(['./' run_number '/' run_number '_log.mat']); - diary([ saveDir '/' run_number '/' run_number '_log.mat']); +% diary([ saveDir '/' run_number '/' run_number '_log.mat']); % end %-------------------------------------------------------------------------- @@ -605,7 +600,7 @@ function CryoGrid3_lake_batch(SETUP) delete(gcp('nocreate')) end %tsvd -dsave('Workspace') % save all distributed variables +%dsave([ saveDir '/' run_number '/' run_number '_Workspace']) % save all distributed variables disp('Done.'); diff --git a/analysis/Tprofiles_04.m b/analysis/Tprofiles_04.m new file mode 100644 index 0000000..c38e0da --- /dev/null +++ b/analysis/Tprofiles_04.m @@ -0,0 +1,67 @@ +% T_NL and T_L profiles + +%filespec='MSW_xH1_xW0_xS0_infil1_xice0_rF1_sF1'; +%filespec_b='MSW_xH0_xW0_xS0_infil1_xice0_rF1_sF1'; % no lateral heat exchange +filespec='xH1'; +filespec_b='xH0'; +yearspec='1971'; + +Tini_ssw=[0 1 2 10 20 100 2000; 10 -3 -4 -7 -10 -10 10; 6 6 0 -5 -10 -10 10]; +Tini_msw=[0 5 8 20 100 2000; 10 -3 -6 -10 -10 10; 5 5 0 -9 -10 10]; +Tini=Tini_ssw'; + +%% Non_Lake +% with lateral exchange +%outputfile1 = ['../runs/',filespec,'_i1/',filespec,'_i1_realization1_output',yearspec]; configfile1 = ['../runs/',filespec,'_i1/',filespec,'_i1_settings']; +outputfile1 = ['../runs/WD0_',filespec,'/WD0_',filespec,'_output',yearspec]; configfile1 = ['../runs/WD0_',filespec,'/WD0_',filespec,'_settings']; +load(outputfile1); load(configfile1); +Soil_NL_ub = GRID.soil.cT_domain_ub; Soil_NL_lb = GRID.soil.cT_domain_lb; +zgeneral_NL=GRID.general.cT_grid; zsoil_NL = GRID.general.cT_grid(Soil_NL_ub:Soil_NL_lb); +[~, z10m_NL]=min(abs(zgeneral_NL-10)); [~, z15m_NL]=min(abs(zgeneral_NL-15)); [~, z20m_NL]=min(abs(zgeneral_NL-20)); + +T_NL=OUT.cryoGrid3; T_NLtm = mean(T_NL,2); + +% wo lateral exchange +%outputfile1b = ['../runs/noLateral/runs/',filespec_b,'_i1/',filespec_b,'_i1_realization1_output',yearspec]; configfile1b = ['../runs/noLateral/runs/',filespec_b,'_i1/',filespec_b,'_i1_settings']; +outputfile1b = ['../runs/noLateral/runs/WD0_',filespec_b,'/WD0_',filespec_b,'_output',yearspec]; configfile1b = ['../runs/noLateral/runs/WD0_',filespec_b,'/WD0_',filespec_b,'_settings']; +load(outputfile1b); load(configfile1b); + +T_NL_xH0=OUT.cryoGrid3; T_NLtm_xH0 = mean(T_NL_xH0,2); % no lateral heat exchange + +%% LAKE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%outputfile2 = ['../runs/',filespec,'_i2/',filespec,'_i2_realization2_output',yearspec]; configfile2 = ['../runs/',filespec,'_i2/',filespec,'_i2_settings']; +outputfile2 = ['../runs/WD1_',filespec,'/WD1_',filespec,'_output',yearspec]; configfile2 = ['../runs/WD1_',filespec,'/WD1_',filespec,'_settings']; +load(outputfile2); load(configfile2) + +n_LakeLayers=nansum(GRID.lake.water.cT_domain)+nansum(GRID.lake.ice.cT_domain); +Lake_ub = GRID.soil.cT_domain_ub-n_LakeLayers; Lake_lb = GRID.soil.cT_domain_ub-1; +Soil_L_ub = GRID.soil.cT_domain_ub; +zgeneral_L=GRID.general.cT_grid; +zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); +[~, z10m_L]=min(abs(zgeneral_L-10)); [~, z15m_L]=min(abs(zgeneral_L-15)); [~, z20m_L]=min(abs(zgeneral_L-20)); + +T_L=OUT.cryoGrid3; T_Ltm = mean(T_L,2); + +% wo lateral exchange +outputfile2b = ['../runs/noLateral/runs/WD1_',filespec_b,'/WD1_',filespec_b,'_output',yearspec]; configfile2b = ['../runs/noLateral/runs/WD1_',filespec_b,'/WD1_',filespec_b,'_settings']; +load(outputfile2b); load(configfile2b); + +T_L_xH0=OUT.cryoGrid3; T_Ltm_xH0 = mean(T_L_xH0,2); + +%% +ti=100; +figure + subplot(1,2,1) +plot(T_L(Lake_ub:z20m_L,ti),zgeneral_L(Lake_ub:z20m_L),'b',T_NL(Soil_NL_ub:z20m_NL,ti),zgeneral_NL(Soil_NL_ub:z20m_NL),'g', ... + T_L_xH0(Lake_ub:z20m_L,ti),zgeneral_L(Lake_ub:z20m_L),'b--',T_NL_xH0(Soil_NL_ub:z20m_NL,ti),zgeneral_NL(Soil_NL_ub:z20m_NL),'g--') +hold on; plot(Tini(1:5,2),Tini(1:5,1),'g*',Tini(1:5,3),Tini(1:5,1),'b*'); hold off + legend('L','NL','Location','SouthWest'); title(['T(z) at ti ',num2str(filespec(1:3)),' ',num2str(yearspec)]) +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on +axis([-30 10 -inf inf]) + subplot(1,2,2) +plot(T_Ltm(Lake_ub:z20m_L),zgeneral_L(Lake_ub:z20m_L),'b',T_NLtm(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'g', ... + T_Ltm_xH0(Lake_ub:z20m_L),zgeneral_L(Lake_ub:z20m_L),'b--',T_NLtm_xH0(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'g--') +hold on; plot(Tini(1:5,2),Tini(1:5,1),'g*',Tini(1:5,3),Tini(1:5,1),'b*'); hold off +legend('L','NL','Location','SouthWest'); title(['T(z) annual mean ',num2str(filespec(1:3)),' ',num2str(yearspec)]) +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on +axis([-30 10 -inf inf]) diff --git a/analysis/analysis_Tz_12.m b/analysis/analysis_Tz_12.m new file mode 100644 index 0000000..6afe6af --- /dev/null +++ b/analysis/analysis_Tz_12.m @@ -0,0 +1,181 @@ +% T_NL and T_L profiles + +load_data=1; % load data which were generated on cluster + +if load_data == 1 % zzz ... update data on cluster.... + load Data_Tz +else + Tini_ssw=[0 1 2 10 20 100 2000; 10 -3 -4 -7 -10 -10 10; 6 6 0 -5 -10 -10 10]; + Tini_msw=[0 5 8 20 100 2000; 10 -3 -6 -10 -10 10; 5 5 0 -9 -10 10]; + Tini=Tini_ssw'; + + yearspec='2012'; + + LD=[1 5]; + LR=[10 100]; + LF=[10 25 50]; + + n=0; % run index loop + for i=1:length(LD) % loop over exps + for j=1:length(LR) + for k=1:length(LF) + n=n+1; + expspec_NL=['WD0_LD',num2str(LD(i)),'_LR',num2str(LR(j)),'_LF',num2str(LF(k))]; % experiment specifier non Lake + expspec_L=['WD',num2str(LD(i)),'_LD',num2str(LD(i)),'_LR',num2str(LR(j)),'_LF',num2str(LF(k))]; + % experiment specifier lake + % NL + outputfile_NL = ['../runs/',expspec_NL,'/',expspec_NL,'_',yearspec]; + outputfile_NL_nolat = ['../../CryoGrid3_noLateral/runs/',expspec_NL,'/',expspec_NL,'_',yearspec]; + configfile_NL = ['../runs/',expspec_NL,'/',expspec_NL,'_settings']; + % Lake + outputfile_L = ['../runs/',expspec_L,'/',expspec_L,'_',yearspec]; + outputfile_L_nolat = ['../../CryoGrid3_noLateral/runs/',expspec_L,'/',expspec_L,'_',yearspec]; + configfile_L = ['../runs/',expspec_L,'/',expspec_L,'_settings']; + % 1.) z levels + if(n==1) + load(configfile_NL); % NL + Soil_NL_ub = GRID.soil.cT_domain_ub; Soil_NL_lb = GRID.soil.cT_domain_lb; + zgeneral_NL=GRID.general.cT_grid; zsoil_NL = GRID.general.cT_grid(Soil_NL_ub:Soil_NL_lb); + [~, z20m_NL]=min(abs(zgeneral_NL-30)); + + load(configfile_L); % Lake 1m + n_LakeLayers=nansum(GRID.lake.water.cT_domain)+nansum(GRID.lake.ice.cT_domain); + Lake_1m_ub = GRID.soil.cT_domain_ub-n_LakeLayers; Lake_1m_lb = GRID.soil.cT_domain_ub-1; + zgeneral_L1m=GRID.general.cT_grid; + [~, z20m_L1m]=min(abs(zgeneral_L1m-30)); + elseif(n==7) + load(configfile_L); % Lake 5m + n_LakeLayers=nansum(GRID.lake.water.cT_domain)+nansum(GRID.lake.ice.cT_domain); + Lake_5m_ub = GRID.soil.cT_domain_ub-n_LakeLayers; Lake_5m_lb = GRID.soil.cT_domain_ub-1; + zgeneral_L5m=GRID.general.cT_grid; + [~, z20m_L5m]=min(abs(zgeneral_L5m-30)); + end + % 2.) generate T data + % non Lake + load(outputfile_NL); + T_NL=OUT.cryoGrid3; T_NLtm = mean(T_NL,2); + eval(['T_',expspec_NL,'=T_NLtm;']); + % no lateral heat flux + load(outputfile_NL_nolat); + T_NL=OUT.cryoGrid3; T_NLtm = mean(T_NL,2); + eval(['T_',expspec_NL,'_nolat=T_NLtm;']); + % Lake + load(outputfile_L); + T_L=OUT.cryoGrid3; T_Ltm = mean(T_L,2); + eval(['T_',expspec_L,'=T_Ltm;']); + % no lateral heat flux + load(outputfile_L_nolat); + T_L=OUT.cryoGrid3; T_Ltm = mean(T_L,2); + eval(['T_',expspec_L,'_nolat=T_Ltm;']); + end + end +end +save Data_Tz T* z* Lake_* yearspec expspec* Soil_NL_ub L* +end + +%% +figure(1) % LD 1m + subplot(1,2,1) +% SSW (LR 10m) +hold on +% LF 0.25 +plot(T_WD0_LD1_LR10_LF25(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD1_LD1_LR10_LF25(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b') +% LF 0.1 +plot(T_WD0_LD1_LR10_LF10(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k:',T_WD1_LD1_LR10_LF10(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b:') % WD0 is non Lake! +% LF 0.5 +plot(T_WD0_LD1_LR10_LF50(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k--',T_WD1_LD1_LR10_LF50(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b--') +% no lateral exchange +%plot(T_WD0_LD1_LR10_LF25_nolat(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD1_LD1_LR10_LF25_nolat(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'c') +% initial T +%plot(Tini(1:5,2),Tini(1:5,1),'g*',Tini(1:5,3),Tini(1:5,1),'b*') +plot([-20 10],[LD(1) LD(1)],'b:','LineWidth',0.8) % lake depth level +hold off +legend('Soil','Lake','Location','SouthWest'); title(['lake radius ',num2str(LR(1)),'m']) % title(['LD',num2str(LD(1)),' LR',num2str(LR(1))]) +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on +axis([-20 10 0 10]) + + subplot(1,2,2) +% MSW (LR 100m) +hold on +plot(T_WD0_LD1_LR100_LF25(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD1_LD1_LR100_LF25(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b') +plot(T_WD0_LD1_LR100_LF10(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k:',T_WD1_LD1_LR100_LF10(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b:') +plot(T_WD0_LD1_LR100_LF50(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k--',T_WD1_LD1_LR100_LF50(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b--') +% no lateral exchange +%plot(T_WD0_LD1_LR100_LF25_nolat(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD1_LD1_LR100_LF25_nolat(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'c') +%plot(Tini(1:5,2),Tini(1:5,1),'g*',Tini(1:5,3),Tini(1:5,1),'b*') +plot([-20 10],[LD(1) LD(1)],'b:','LineWidth',0.8) % lake depth level +hold off +legend('Soil','Lake','Location','SouthWest'); title(['lake radius ',num2str(LR(2)),'m']) % title(['LD',num2str(LD(1)),' LR',num2str(LR(2))]) +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on +axis([-20 10 0 10]) + +print -dtiff Tz_LD1m + + +%% +figure(2) % LD 5m + subplot(1,2,1) +% SSW (LR 10m) +hold on +% LF 0.25 +plot(T_WD0_LD5_LR10_LF25(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD5_LD5_LR10_LF25(Lake_5m_ub:z20m_L5m),zgeneral_L5m(Lake_5m_ub:z20m_L5m),'b') +% LF 0.1 +plot(T_WD0_LD5_LR10_LF10(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k:',T_WD5_LD5_LR10_LF10(Lake_5m_ub:z20m_L5m),zgeneral_L5m(Lake_5m_ub:z20m_L5m),'b:') % WD0 is non Lake! +% LF 0.5 +plot(T_WD0_LD5_LR10_LF50(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k--',T_WD5_LD5_LR10_LF50(Lake_5m_ub:z20m_L5m),zgeneral_L5m(Lake_5m_ub:z20m_L5m),'b--') +% no lateral exchange +%plot(T_WD0_LD5_LR10_LF25_nolat(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD5_LD5_LR10_LF25_nolat(Lake_5m_ub:z20m_L5m),zgeneral_L5m(Lake_5m_ub:z20m_L5m),'c') +% initial T +%plot(Tini(1:5,2),Tini(1:5,1),'g*',Tini(1:5,3),Tini(1:5,1),'b*') +plot([-20 10],[LD(2) LD(2)],'b:','LineWidth',0.8) % lake depth level +hold off +legend('Soil','Lake','Location','SouthWest'); title(['lake radius ',num2str(LR(1)),'m']) % title(['LD',num2str(LD(1)),' LR',num2str(LR(1))]) +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on +axis([-20 10 0 10]) + + subplot(1,2,2) +% MSW (LR 100m) +hold on +plot(T_WD0_LD5_LR100_LF25(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD5_LD5_LR100_LF25(Lake_5m_ub:z20m_L5m),zgeneral_L5m(Lake_5m_ub:z20m_L5m),'b') +plot(T_WD0_LD5_LR100_LF10(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k:',T_WD5_LD5_LR100_LF10(Lake_5m_ub:z20m_L5m),zgeneral_L5m(Lake_5m_ub:z20m_L5m),'b:') +plot(T_WD0_LD5_LR100_LF50(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k--',T_WD5_LD5_LR100_LF50(Lake_5m_ub:z20m_L5m),zgeneral_L5m(Lake_5m_ub:z20m_L5m),'b--') +% no lateral exchange +%plot(T_WD0_LD5_LR100_LF25_nolat(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD1_LD1_LR100_LF25_nolat(Lake_5m_ub:z20m_L5m),zgeneral_L5m(Lake_5m_ub:z20m_L5m),'c') +%plot(Tini(1:5,2),Tini(1:5,1),'g*',Tini(1:5,3),Tini(1:5,1),'b*') +plot([-20 10],[LD(2) LD(2)],'b:','LineWidth',0.8) % lake depth level +hold off +legend('Soil','Lake','Location','SouthWest'); title(['lake radius ',num2str(LR(2)),'m']) % title(['LD',num2str(LD(1)),' LR',num2str(LR(2))]) +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on +axis([-20 10 0 10]) + +print -dtiff Tz_LD5m + + +%% +figure(3) % LD 1m + subplot(1,2,1) +% SSW (LR 10m) +hold on +% LF 0.25 +plot(T_WD0_LD1_LR10_LF25(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD1_LD1_LR10_LF25(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b') +% no lateral exchange +plot(T_WD0_LD1_LR10_LF25_nolat(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k--',T_WD1_LD1_LR10_LF25_nolat(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b--') +plot([-20 10],[LD(1) LD(1)],'b:','LineWidth',0.8) % lake depth level +hold off +legend('Soil','Lake','Location','SouthWest'); title(['lake radius ',num2str(LR(1)),'m']) % title(['LD',num2str(LD(1)),' LR',num2str(LR(1))]) +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on +axis([-20 10 0 10]) + + subplot(1,2,2) +% MSW (LR 100m) +hold on +plot(T_WD0_LD1_LR100_LF25(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k',T_WD1_LD1_LR100_LF25(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b') +% no lateral exchange +plot(T_WD0_LD1_LR100_LF25_nolat(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'k--',T_WD1_LD1_LR100_LF25_nolat(Lake_1m_ub:z20m_L1m),zgeneral_L1m(Lake_1m_ub:z20m_L1m),'b--') +plot([-20 10],[LD(1) LD(1)],'b:','LineWidth',0.8) % lake depth level +hold off +legend('Soil','Lake','Location','SouthWest'); title(['lake radius ',num2str(LR(2)),'m']) % title(['LD',num2str(LD(1)),' LR',num2str(LR(2))]) +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on +axis([-20 10 0 10]) + +print -dtiff Tz_LD1m_nolat diff --git a/analysis/plot_T_14.m b/analysis/plot_T_14.m new file mode 100644 index 0000000..3afe27c --- /dev/null +++ b/analysis/plot_T_14.m @@ -0,0 +1,210 @@ +% plot T timeseries for various depth + +%filespec='MSW_xH1_xW0_xS0_infil1_xice0_rF1_sF1'; +%filespec='MSW_xH1'; +filespec='LF25_xH1' +yearspec='2010'; + +% NL +outputfile1 = ['../runs/WD0_',filespec,'/WD0_',filespec,'_',yearspec]; +configfile1 = ['../runs/WD0_',filespec,'/WD0_',filespec,'_settings']; +% Lake +outputfile2 = ['../runs/WD5_',filespec,'/WD5_',filespec,'_',yearspec]; +configfile2 = ['../runs/WD5_',filespec,'/WD5_',filespec,'_settings']; + +% % NL +% outputfile1 = ['../runs/',filespec,'_i1/',filespec,'_i1_output',yearspec]; +% configfile1 = ['../runs/',filespec,'_i1/',filespec,'_i1_settings']; +% %Lake +% outputfile2 = ['../runs/',filespec,'_i2/',filespec,'_i2_output',yearspec]; +% configfile2 = ['../runs/',filespec,'_i2/',filespec,'_i2_settings']; + + +% outputfile1 = ['../runs/noLateral/runs/',filespec,'_i2/',filespec,'_i2_output',yearspec]; +% configfile1 = ['../runs/noLateral/runs/',filespec,'_i2/',filespec,'_i2_settings']; +% % Lake +% outputfile2 = ['../runs/noLateral/runs/',filespec,'_i1/',filespec,'_i1_output',yearspec]; +% configfile2 = ['../runs/noLateral/runs/',filespec,'_i1/',filespec,'_i1_settings']; + +%% Non_Lake +load(outputfile1); load(configfile1); +txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; +txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; + +%PARA=p1; GRID=g1; OUT=o1; +%z_soil=GRID.soil.soilGrid; ub_soil=GRID.soil.cT_domain_ub; +Soil_NL_ub = GRID.soil.cT_domain_ub; Soil_NL_lb = GRID.soil.cT_domain_lb; +zgeneral_NL=GRID.general.cT_grid; +zsoil_NL = GRID.general.cT_grid(Soil_NL_ub:Soil_NL_lb); +[~, z10m_NL]=min(abs(zgeneral_NL-10)); [~, z15m_NL]=min(abs(zgeneral_NL-15)); [~, z20m_NL]=min(abs(zgeneral_NL-20)); +dl=10; % number of lines to plot +dz= round(length(zgeneral_NL)/dl); +tstamp=OUT.timestamp; +T_NL=OUT.cryoGrid3; T_NLtm = mean(T_NL,2); +TSoil_NL=T_NL(Soil_NL_ub:Soil_NL_lb,:); +%TAir=T_NL(GRID.air.cT_domain_ub:GRID.air.cT_domain_lb,:); +TSnow=T_NL(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb,:); +TSnow_lb=T_NL(GRID.lake.water.cT_domain_ub-1,:); +%OUT.soil.topPosition +% Forcing +tspan=FORCING.data.t_span; [ ~ ,idx1 ] = min( abs( tstamp(1) - tspan )); [ ~ ,idx2 ] = min( abs( tstamp(end) - tspan )); +tstamp_forcing=FORCING.data.t_span(idx1:idx2); +Tair=FORCING.data.Tair(idx1:idx2); + +Qlat_NL=OUT.EB.Q_lateral; Qlat_NLtm = mean(Qlat_NL,2); + +%% +co=cool(dl); % new Color Order +set(groot,'defaultAxesColorOrder',co) + + figure(1) +plot(tstamp,T_NL) +grid on; datetick; xlabel('timestamp'); ylabel('T_{NL} (°C)'); grid on; +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +title(txt_forcing, 'Interpreter', 'none') + + figure(2) +%plot(tstamp,TAir,'b', +%tstamp,TSnow,'y',tstamp,TLakeWater,'b',tstamp,TLakeIce,'c',tstamp,TSoil,'g');plot(tstamp,TSnow,'k--',tstamp,TSoil(1:dz:end,:),'g') +plot(tstamp,TSoil_NL(1:dz:end,:),'g') +%hold on +% if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLakeWater(1:dz:end,:),'b'); end +% if(~isempty(GRID.lake.ice.cT_domain_ub)); plot(tstamp,TLakeIce(1:dz:end,:),'c'); end +% hold off +grid on; datetick; xlabel('timestamp'); ylabel('T Soil (°C)'); grid on; + +%% lateral heat fluxes +figure(4) +colormap(cool) +plot(tstamp,Qlat_NL(Soil_NL_ub:dz:end,:)) +%plot(tstamp,Qlat_NL(Soil_NL_ub:Soil_NL_ub+2,:)') +grid on; datetick; ylabel('Qlat NL (W/m2)') + +% figure(5) +% ti=100; z1=83; z2=300; +% subplot(1,2,1) +% plot(Qlat_NL(z1:z2,ti),zgeneral(z1:z2)) +% hold on; plot(Qlat_NLtm(z1:z2),zgeneral(z1:z2),'--'); hold off +% set(gca,'Ydir','reverse'); xlabel('Qlat Non-LAKE (W/m2)'); ylabel('z (m)'); grid on +% subplot(1,2,2) +% plot(T_L(z1:z2,ti)-T_NL(z1:z2,ti),zgeneral(z1:z2)) +% hold on; plot(T_Ltm(z1:z2)-T_NLtm(z1:z2),zgeneral(z1:z2),'--'); hold off +% set(gca,'Ydir','reverse'); xlabel('T_L-T_{NL} (°C)'); ylabel('z (m)'); grid on +% +% T_NL and T_L profiles +% figure(6) +% subplot(1,2,1) +% plot(T_L(z1:z2,ti),zgeneral(z1:z2)) +% hold on; plot(T_Ltm(z1:z2),zgeneral(z1:z2),'--'); hold off +% set(gca,'Ydir','reverse'); xlabel('T_L (°C)'); ylabel('z (m)'); grid on +% axis([-10 10 -inf inf]) +% subplot(1,2,2) +% plot(T_NL(z1:z2,ti),zgeneral(z1:z2)) +% hold on; plot(T_NLtm(z1:z2),zgeneral(z1:z2),'--'); hold off +% set(gca,'Ydir','reverse'); xlabel('T_{NL} (°C)'); ylabel('z (m)'); grid on +% axis([-10 10 -inf inf]) + + +%% LAKE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +load(outputfile2); load(configfile2); +txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; +txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; + +%PARA=p2; GRID=g2; OUT=o2; +n_LakeLayers=nansum(GRID.lake.water.cT_domain)+nansum(GRID.lake.ice.cT_domain); +Lake_ub = GRID.soil.cT_domain_ub-n_LakeLayers; +Lake_lb = GRID.soil.cT_domain_ub-1; +Soil_L_ub = GRID.soil.cT_domain_ub; +zgeneral_L=GRID.general.cT_grid; +zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); +[~, z10m_L]=min(abs(zgeneral_L-10)); [~, z15m_L]=min(abs(zgeneral_L-15)); [~, z20m_L]=min(abs(zgeneral_L-20)); +tstamp=OUT.timestamp; + +T_L=OUT.cryoGrid3; T_Ltm = mean(T_L,2); +TSoil_L=T_L(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb,:); %TLakeWater=T_L(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb,:); TLakeIce=T_L(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb,:); +%TAir=T_L(GRID.air.cT_domain_ub:GRID.air.cT_domain_lb,:); +TSnow=T_L(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb,:); +TSnow_lb=T_L(GRID.lake.water.cT_domain_ub-1,:); +TLake = T_L(Lake_ub:Lake_lb,:); +TLake_ub = T_L(GRID.soil.cT_domain_ub-n_LakeLayers,:); % uppermost lake layer +TLake_lb = T_L(GRID.soil.cT_domain_ub-1,:); % lowermost lake layer +TaboveLake = T_L(GRID.soil.cT_domain_ub-(n_LakeLayers+1),:); +TSoil_L_ub = T_L(GRID.soil.cT_domain_ub,:); + +Qlat_L=OUT.EB.Q_lateral; Qlat_Ltm = mean(Qlat_L,2); + +%% + figure(11) +plot(tstamp,T_L) +grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +title(txt_forcing, 'Interpreter', 'none') + + figure(12) % T Soil and T Lake +%plot(tstamp,TAir,'b', tstamp,TSnow,'y',tstamp,TLakeWater,'b',tstamp,TLakeIce,'c',tstamp,TSoil_L,'g') +%plot(tstamp,TSnow,'k--',tstamp,TSoil_L(1:dz:end,:),'g') +plot(tstamp,TSoil_L(1:dz:end,:),'g') +hold on +if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLake(1:dz:end,:),'b'); end +%if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLakeWater(1:dz:end,:),'b'); end +%if(~isempty(GRID.lake.ice.cT_domain_ub)); plot(tstamp,TLakeIce(1:dz:end,:),'c'); end +hold off +grid on; datetick; xlabel('timestamp'); ylabel('T (soil & lake)(°C)'); +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +title(txt_forcing, 'Interpreter', 'none') + +figure(13) % T Lake +%plot(tstamp,TLake(1:49:end,:),'b',tstamp,TaboveLake,'g',tstamp,TSoil_L_ub,'r') +plot(tstamp,TLake_ub,'b',tstamp,TLake_lb,'c',tstamp,TaboveLake,'mx',tstamp,TSoil_L_ub,'g') +legend('Tlake ub','Tlake lb','TaboveLake','TSoil ub') +hold on; plot(tstamp,TLake(1:10:end,:),'b--'); hold off +grid on; datetick; xlabel('timestamp'); ylabel('T (lake + ...)(°C)'); +xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) +title(txt_forcing, 'Interpreter', 'none') + + +%% lateral heat fluxes +ti=100; + +figure(14) +plot(tstamp,Qlat_L(Lake_ub:dz:end,:)') +grid on; datetick; ylabel('Qlat LAKE (W/m2)') +legend('1','2','3','4','5','6','7','8','9','10') + +figure(15) + subplot(1,2,1) +plot(Qlat_L(Lake_ub:end,ti),zgeneral_L(Lake_ub:end),'b--',Qlat_Ltm(Lake_ub:end),zgeneral_L(Lake_ub:end),'b'); +legend('ti','tm') +set(gca,'Ydir','reverse'); xlabel('Qlat LAKE (W/m2)'); ylabel('z (m)'); grid on; title([filespec,' ',yearspec]) + subplot(1,2,2) +% plot(T_L(z1:z2,ti)-T_NL(z1:z2,ti),zgeneral(z1:z2),'b--',T_Ltm(z1:z2)-T_NLtm(z1:z2),zgeneral(z1:z2),'b' is not on same depth!! +%legend('ti','tm') +%set(gca,'Ydir','reverse'); xlabel('T_L-T_{NL} (°C)'); ylabel('z (m)'); grid on + +% T_NL and T_L profiles +figure(16) + subplot(1,3,1) +plot(T_L(Lake_ub:end,ti),zgeneral_L(Lake_ub:end),'b--',T_Ltm(Lake_ub:end),zgeneral_L(Lake_ub:end),'b',T_NL(Soil_NL_ub:end,ti),zgeneral_NL(Soil_NL_ub:end),'g--',T_NLtm(Soil_NL_ub:end),zgeneral_NL(Soil_NL_ub:end),'g') +legend('L(ti)','L(tm)','NL(ti)','NL(tm)') +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on; title([filespec,' ',yearspec]) +axis([-12 10 -inf inf]) + subplot(1,3,2) +plot(T_L(Lake_ub:z20m_L,ti),zgeneral_L(Lake_ub:z20m_L),'b--',T_Ltm(Lake_ub:z20m_L),zgeneral_L(Lake_ub:z20m_L),'b',T_NL(Soil_NL_ub:z20m_NL,ti),zgeneral_NL(Soil_NL_ub:z20m_NL),'g--',T_NLtm(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'g') +legend('L(ti)','L(tm)','NL(ti)','NL(tm)') +set(gca,'Ydir','reverse'); xlabel('T (°C)'); ylabel('z (m)'); grid on + subplot(1,3,3) +plot(Qlat_L(Lake_ub:z20m_L,ti),zgeneral_L(Lake_ub:z20m_L),'b--',Qlat_Ltm(Lake_ub:z20m_L),zgeneral_L(Lake_ub:z20m_L),'b',-Qlat_NL(Soil_NL_ub:z20m_NL,ti),zgeneral_NL(Soil_NL_ub:z20m_NL),'g--',-Qlat_NLtm(Soil_NL_ub:z20m_NL),zgeneral_NL(Soil_NL_ub:z20m_NL),'g') +legend('L(ti)','L(tm)','-NL(ti)','-NL(tm)') +set(gca,'Ydir','reverse'); xlabel('Qlat (W/m2)'); ylabel('z (m)'); grid on + + +figure(17) % uppermost soil layer vs. uppermost lake layer +%plot(tstamp,T_NL(GRID.soil.cT_domain_ub-10:GRID.soil.cT_domain_ub,:),'g',tstamp,TLake_ub,'b') +plot(tstamp,TSoil_NL(1,:),'g',tstamp,T_L(Lake_ub,:),'b') +legend('top T(NL)','top T(lake)'); grid on; ylabel('T (°C)'); datetick + +figure(21) % check whether Qlat(L) = - Qlat(NL) +plot(Qlat_NL(Soil_NL_ub:Soil_NL_lb,ti)+Qlat_L(Lake_ub:Soil_NL_lb,ti),zgeneral_L(Lake_ub:Soil_NL_lb),'b--',Qlat_NLtm(Soil_NL_ub:Soil_NL_lb)+Qlat_Ltm(Lake_ub:Soil_NL_lb),zgeneral_L(Lake_ub:Soil_NL_lb),'b') +legend('ti','tm') +set(gca,'Ydir','reverse'); xlabel('Qlat LAKE + Qlat NL (W/m2)'); ylabel('z (m)'); grid on; %title([filespec,' ',yearspec]) +title(['Diff not on same level!!!! z integrated Qlat L+NL at ti ',num2str(nansum(Qlat_L(:,ti)) + nansum(Qlat_NL(:,ti)) ),' W/m2']) From 7cee82e1b0180fa7c1f80659ab99232b995c750e Mon Sep 17 00:00:00 2001 From: Thomas Schneider vD Date: Wed, 18 Jul 2018 13:35:43 +0200 Subject: [PATCH 45/45] =?UTF-8?q?latest=20EUC=C3=93P=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- analysis/plot_T_04.m | 117 ------------ .../cryoGridLateral/get_parallel_variables.m | 4 +- modules/cryoGridSnow/CryoGridSnow.m | 10 +- run_batch_CryoGrid3_lake.m | 171 ++++++++++-------- 4 files changed, 100 insertions(+), 202 deletions(-) delete mode 100644 analysis/plot_T_04.m diff --git a/analysis/plot_T_04.m b/analysis/plot_T_04.m deleted file mode 100644 index fdbce10..0000000 --- a/analysis/plot_T_04.m +++ /dev/null @@ -1,117 +0,0 @@ -% plot T timeseries for various depth - -% OUT=OUTS{2}.OUT; GRID=OUTS{2}.GRID; PARA=OUTS{2}.PARA - -%p1=PARA{1}; p2=PARA{2}; g1=GRID{1}; g2=GRID{2}; o1=OUT{1}; o2=OUT{2}; - -dz=10; % increment used to plot vertical levels -%% Non_Lake - -% no infil no ex no lake -% outputfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_output1980.mat' -% configfile1 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i1_realization1_settings.mat' -% outputfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_output1980.mat' -% configfile2 = '../runs/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2/LAKE-MPI_xH1_xW0_xS0_infil0_xice0_rF1_sF1_i2_realization2_settings.mat' -% -outputfile1 = '../runs/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_output1980.mat' -configfile1 = '../runs/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i1_realization1_settings.mat' -outputfile2 = '../runs/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2_realization2_output1980.mat' -configfile2 = '../runs/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2/LAKE-NonLake _xH1_xW0_xS0_infil1_xice0_rF1_sF1_i2_realization2_settings.mat' - -load(outputfile1); load(configfile1); - -%PARA=p1; GRID=g1; OUT=o1; -%z_soil=GRID.soil.soilGrid; ub_soil=GRID.soil.cT_domain_ub; -zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); -tstamp=OUT.timestamp; -T=OUT.cryoGrid3; TSoil=T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb,:); %TLakeWater=T(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb,:); TLakeIce=T(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb,:); -%OUT.soil.topPosition - -%TAir=T(GRID.air.cT_domain_ub:GRID.air.cT_domain_lb,:); - -TSnow=T(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb,:); -TSnow_lb=T(GRID.lake.water.cT_domain_ub-1,:); - -% Forcing - tspan=FORCING.data.t_span; -[ ~ ,idx1 ] = min( abs( tstamp(1) - tspan )); [ ~ ,idx2 ] = min( abs( tstamp(end) - tspan )); -tstamp_forcing=FORCING.data.t_span(idx1:idx2); -Tair=FORCING.data.Tair(idx1:idx2); - -txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; -txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; - - figure(1) -plot(tstamp,T) -grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; -xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) -title(txt_forcing, 'Interpreter', 'none') - - figure(2) -%plot(tstamp,TAir,'b', tstamp,TSnow,'y',tstamp,TLakeWater,'b',tstamp,TLakeIce,'c',tstamp,TSoil,'g') -%plot(tstamp,TSnow,'k--',tstamp,TSoil(1:dz:end,:),'g') -plot(tstamp,TSoil(1:dz:end,:),'g') -%hold on -% if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLakeWater(1:dz:end,:),'b'); end -% if(~isempty(GRID.lake.ice.cT_domain_ub)); plot(tstamp,TLakeIce(1:dz:end,:),'c'); end -% hold off -grid on; datetick; xlabel('timestamp'); ylabel('T Soil (°C)'); grid on; - -%% LAKE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%PARA=p2; GRID=g2; OUT=o2; -load(outputfile2); load(configfile2); -zsoil = GRID.general.cT_grid(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb); -tstamp=OUT.timestamp; -T=OUT.cryoGrid3; TSoil=T(GRID.soil.cT_domain_ub:GRID.soil.cT_domain_lb,:); %TLakeWater=T(GRID.lake.water.cT_domain_ub:GRID.lake.water.cT_domain_lb,:); TLakeIce=T(GRID.lake.ice.cT_domain_ub:GRID.lake.ice.cT_domain_lb,:); -%TAir=T(GRID.air.cT_domain_ub:GRID.air.cT_domain_lb,:); -TSnow=T(GRID.snow.cT_domain_ub:GRID.snow.cT_domain_lb,:); -TSnow_lb=T(GRID.lake.water.cT_domain_ub-1,:); -TLake = T(GRID.soil.cT_domain_ub-50:GRID.soil.cT_domain_ub-1,:); % lake 50 layers -Tx1 = T(GRID.soil.cT_domain_ub-51,:); -Tx2 = T(GRID.soil.cT_domain_ub+1,:); - - figure(11) -txt_setting=['Infil: ',num2str(PARA.modules.infiltration),' Xice: ',num2str(PARA.modules.xice),' heat ex: ',num2str(PARA.modules.exchange_heat),' water ex: ',num2str(PARA.modules.exchange_water),' snow ex: ',num2str(PARA.modules.exchange_snow), ' LakeDepth: ',num2str(PARA.water.depth)]; -txt_forcing=[PARA.forcing.filename(1:end-4),' (',num2str(PARA.forcing.rain_fraction),' ',num2str(PARA.forcing.snow_fraction),')']; -plot(tstamp,T) -grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); grid on; -xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) -title(txt_forcing, 'Interpreter', 'none') - - figure(12) -%plot(tstamp,TAir,'b', tstamp,TSnow,'y',tstamp,TLakeWater,'b',tstamp,TLakeIce,'c',tstamp,TSoil,'g') -%plot(tstamp,TSnow,'k--',tstamp,TSoil(1:dz:end,:),'g') -plot(tstamp,TSoil(1:dz:end,:),'g') -hold on -if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLake(1:dz:end,:),'b'); end -%if(~isempty(GRID.lake.water.cT_domain_ub)); plot(tstamp,TLakeWater(1:dz:end,:),'b'); end -%if(~isempty(GRID.lake.ice.cT_domain_ub)); plot(tstamp,TLakeIce(1:dz:end,:),'c'); end -hold off -grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); -xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) -title(txt_forcing, 'Interpreter', 'none') - -%% -%[ ~ ,idx ] = min( abs( datenum(1979, 7, 1 ) - OUT.timestamp() )) % find index of date - figure(30) -year=1980; -[~,tJan]=min(abs(datenum(year,1,1)-tstamp())); [~,tFeb]=min(abs(datenum(year,2,1)-tstamp())); [~,tMar]=min(abs(datenum(year,3,1)-tstamp())); [~,tApr]=min(abs(datenum(year,4,1)-tstamp())); [~,tMay]=min(abs(datenum(year,5,1)-tstamp())); [~,tJun]=min(abs(datenum(year,6,1)-tstamp())); -[~,tJul]=min(abs(datenum(year,7,1)-tstamp())); [~,tAug]=min(abs(datenum(year,8,1)-tstamp())); [~,tSep]=min(abs(datenum(year,9,1)-tstamp())); [~,tOct]=min(abs(datenum(year,4,10)-tstamp())); [~,tNov]=min(abs(datenum(year,5,11)-tstamp())); [~,tDec]=min(abs(datenum(year,12,1)-tstamp())); - -z2m=101; z10m=261; % corresponds to 2m, 10m -zend=z2m; -plot(TSoil(1:zend,tJan),zsoil(1:zend),TSoil(1:zend,tFeb),zsoil(1:zend),TSoil(1:zend,tMar),zsoil(1:zend),TSoil(1:zend,tApr),zsoil(1:zend),TSoil(1:zend,tMay),zsoil(1:zend),TSoil(1:zend,tJun),zsoil(1:zend),... - TSoil(1:zend,tJul),zsoil(1:zend),TSoil(1:zend,tAug),zsoil(1:zend),TSoil(1:zend,tSep),zsoil(1:zend),TSoil(1:zend,tOct),zsoil(1:zend),TSoil(1:zend,tNov),zsoil(1:zend),TSoil(1:zend,tDec),zsoil(1:zend)) -hold on; -set(gca,'Ydir','reverse'); xlabel('T'); ylabel('z'); grid on -legend(datestr(tstamp(tJan)),datestr(tstamp(tFeb)),datestr(tstamp(tMar)),datestr(tstamp(tApr)),datestr(tstamp(tMay)),datestr(tstamp(tJun)),datestr(tstamp(tJul)),datestr(tstamp(tAug)),datestr(tstamp(tSep)),datestr(tstamp(tOct)),datestr(tstamp(tNov)),datestr(tstamp(tDec))) - - -figure(99) -hold on -plot(tstamp,TLake(1:49:end,:),'b',tstamp,Tx1,'g',tstamp,Tx2,'r') -grid on; datetick -hold off -grid on; datetick; xlabel('timestamp'); ylabel('T (°C)'); -xxx=xlim; yyy=ylim; text(xxx(1),0.9*yyy(2),txt_setting) -title(txt_forcing, 'Interpreter', 'none') \ No newline at end of file diff --git a/modules/cryoGridLateral/get_parallel_variables.m b/modules/cryoGridLateral/get_parallel_variables.m index d893bb6..bb36a74 100644 --- a/modules/cryoGridLateral/get_parallel_variables.m +++ b/modules/cryoGridLateral/get_parallel_variables.m @@ -3,7 +3,7 @@ index = labindex; % auxiliary calculations for circular geometry - F_L = 0.5; % landscape Lake Fraction + F_L = 0.25; % landscape Lake Fraction radius = 10; % in [m] perimeter = 2*pi.*radius; % in [m] distance = sqrt(pi./(4*F_L)) * radius; % in [m] @@ -187,7 +187,7 @@ PARA.Tinitial=[PARA.Tinitial(:,1) PARA.Tinitial(:, 1+index)]; - PARA.water.depth = [0.,1.]; % non-lake and small-sized water body (SSW) + PARA.water.depth = [0.,5.]; % non-lake and small-sized water body (SSW) %PARA.water.depth = [0.,6.]; % non-lake and medium-sized water body (MSW) PARA.water.depth = PARA.water.depth(index); diff --git a/modules/cryoGridSnow/CryoGridSnow.m b/modules/cryoGridSnow/CryoGridSnow.m index ade2ffe..431a664 100644 --- a/modules/cryoGridSnow/CryoGridSnow.m +++ b/modules/cryoGridSnow/CryoGridSnow.m @@ -1,8 +1,9 @@ function [T, GRID, PARA, SEB, BALANCE] = CryoGridSnow(T, GRID, FORCING, SEB, PARA, c_temp, timestep, BALANCE) - +% zzz line 4 commented out now because of problem 7.7.2014!!! if(~isempty(GRID.lake.water.cT_domain_ub)) - assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); -% assert(GRID.lake.water.cT_domain_ub-GRID.snow.cT_domain_lb>1,'snow on lake!') +% assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake!'); + % disp('snow on lake!') +%%% assert(GRID.lake.water.cT_domain_ub-GRID.snow.cT_domain_lb>1,'snow on lake!') end if ~isempty(GRID.snow.cT_domain_ub) %snow cover already exitis @@ -96,7 +97,8 @@ end if(~isempty(GRID.lake.water.cT_domain_ub)) - assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake (2)!'); +% zzz commented out now for fix... assert(GRID.lake.water.cT_domain(GRID.lake.water.cT_domain_ub)+GRID.snow.cT_domain(GRID.lake.water.cT_domain_ub-1)<2,'snow on lake (2)!'); % assert(GRID.lake.water.cT_domain_ub-GRID.snow.cT_domain_lb>1,'snow on lake (2)!') +% disp('snow on lake 2') end end \ No newline at end of file diff --git a/run_batch_CryoGrid3_lake.m b/run_batch_CryoGrid3_lake.m index 746455f..8140fd4 100644 --- a/run_batch_CryoGrid3_lake.m +++ b/run_batch_CryoGrid3_lake.m @@ -1,14 +1,13 @@ % run CryoGrid3 in batch modus clear all; close all; delete( gcp('nocreate') ); -add_modules; % this is not called in the main script anymore! -% default setup +add_modules; % needs to be called in main.m ... (on cluster) SETUP = {}; % auxiliary struct containing parameters which are often varied. this struct is passed as an argument to the main script. parallel.defaultClusterProfile('local'); c = parcluster(); delete( c.Jobs ); % jjj ? jobName = 'Lateral_Heat_Lake'; jobs = {}; -%% shallow lake (1-3: SSW, 4-6:MSW) +%% shallow lake (1-3: SSW, 4-6:MSW) SETUP.LD = 1; % lake depth in meter SETUP.Tini = [ -5 15 15;... % SSW setting 0 10 6;... % surface @@ -19,89 +18,103 @@ 100 -10 -10;... 2000 10 10]; % SSW - SETUP.LR = 10; % lake depth in meter -% 1) SSW (LD 1m) LC=0.1 -i=1; % counter for the jobs + SETUP.LR = 10; % lake radius in meter +% 1) LD 1m LR 10m LC=0.1 +i=1; SETUP.LF= 0.1; % lake landscape coverage +SETUP.endtime = datenum(2015, 12, 31); jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); disp( [datestr(now) ': created job ',num2str(i) ] ); -% 2) SSW (LD 1m) LC=0.25 +% 2) LD 1m LR 10m LC=0.25 i=2; SETUP.LF= 0.25; +SETUP.endtime = datenum(2099, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +% 3) LD 1m LR 10m LC=0.5 +i=3; +SETUP.LF= 0.5; +SETUP.endtime = datenum(2015, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); + +% MSW + SETUP.LR = 100; % lake radius in meter +% 4) LD 1m LR 100m LC=0.1 +i=4; % counter for the jobs +SETUP.LF= 0.1; % lake landscape coverage +SETUP.endtime = datenum(2015, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +% 5) LD 1m LR 100m LC=0.25 +i=5; +SETUP.LF= 0.25; +SETUP.endtime = datenum(2099, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +% 6) LD 1m LR 100m LC=0.5 +i=6; +SETUP.LF= 0.5; +SETUP.endtime = datenum(2015, 12, 31); jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); disp( [datestr(now) ': created job ',num2str(i) ] ); -% % 3) SSW (LD 1m) LC=0.5 -% i=3; -% SETUP.LF= 0.5; -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% -% % MSW -% SETUP.LR = 100; % lake depth in meter -% % 4) MSW (LD 1m) LC=0.1 -% i=1; % counter for the jobs -% SETUP.LF= 0.1; % lake landscape coverage -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% % 5) MSW (LD 1m) LC=0.25 -% i=2; -% SETUP.LF= 0.25; -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% % 6) MSW (LD 1m) LC=0.5 -% i=3; -% SETUP.LF= 0.5; -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% -% %% deep lake (7-9: SSW, 10-12: MSW) -% SETUP.LD = 5; % lake depth in meter -% Tini = [ -5 15 15;... % MSW setting for summer -% 0 10 5;... % soil surface -% 5 -3 5;... % lake bottom -% 8 -6 0;... % talik depth -% 20 -10 -9;... -% 100 -10 -10;... -% 2000 10 10]; -% -% % SSW -% SETUP.LR = 10; % lake depth in meter -% % 7) SSW (LD 1m) LC=0.1 -% i=1; % counter for the jobs -% SETUP.LF= 0.1; % lake landscape coverage -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% % 8) SSW (LD 1m) LC=0.25 -% i=2; -% SETUP.LF= 0.25; -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% % 9) SSW (LD 1m) LC=0.5 -% i=3; -% SETUP.LF= 0.5; -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% -% % MSW -% SETUP.LR = 100; % lake depth in meter -% % 10) MSW (LD 1m) LC=0.1 -% i=1; % counter for the jobs -% SETUP.LF= 0.1; % lake landscape coverage -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% % 11) MSW (LD 1m) LC=0.25 -% i=2; -% SETUP.LF= 0.25; -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% % 12) MSW (LD 1m) LC=0.5 -% i=3; -% SETUP.LF= 0.5; -% jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); -% disp( [datestr(now) ': created job ',num2str(i) ] ); -% %% -% -% + +%% deep lake (7-9: SSW, 10-12: MSW) +SETUP.LD = 5; % lake depth in meter +SETUP.Tini = [ -5 15 15;... % MSW setting for summer + 0 10 5;... % soil surface + 5 -3 5;... % lake bottom + 8 -6 0;... % talik depth + 20 -10 -9;... + 100 -10 -10;... + 2000 10 10]; + +% SSW + SETUP.LR = 10; % lake depth in meter +% 7) LD 5m LR 10m LC=0.1 +i=7; +SETUP.LF= 0.1; % lake landscape coverage +SETUP.endtime = datenum(2015, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +% 8) LD 5m LR 10m LC=0.25 +i=8; +SETUP.LF= 0.25; +SETUP.endtime = datenum(2099, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +%9) LD 5m LR 10m LC=0.5 +i=9; +SETUP.LF= 0.5; +SETUP.endtime = datenum(2015, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); + +% MSW + SETUP.LR = 100; % lake depth in meter +% 10) LD 5m LR 100m LC=0.1 +i=10; % counter for the jobs +SETUP.LF= 0.1; % lake landscape coverage +SETUP.endtime = datenum(2015, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +% 11) LD 5m LR 100m LC=0.25 +i=11; +SETUP.LF= 0.25; +SETUP.endtime = datenum(2099, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +% 12) LD 5m LR 100m LC=0.5 +i=12; +SETUP.LF= 0.5; +SETUP.endtime = datenum(2015, 12, 31); +jobs{i} = batch( @CryoGrid3_lake_batch, 0, { SETUP }, 'CaptureDiary',true, 'Pool', 2 ); +disp( [datestr(now) ': created job ',num2str(i) ] ); +%% + +% delete(job) +% clear job + % % to watch the status use c.Jobs(i)(.Tasks) or jobs{i}(.Tasks) % % j = batch('CryoGrid3_xice_mpi','Pool',3,'CaptureDiary',true); % % wait(j); % Wait for the job to finish