diff --git a/config_file_crib.txt b/config_file_crib.txt index 45f5c81d..1859ad40 100644 --- a/config_file_crib.txt +++ b/config_file_crib.txt @@ -1,7 +1,7 @@ -WorkDir=/home/jovyan/private/ +WorkDir=/home/jovyan/private/Test/ SoilPropertyPath=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/SoilProperty/ ForcingPath=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/Plumber2_data/ -Location=AU-DaS +Location=US-Bo1 directional=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/directional/ fluspect_parameters=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/fluspect_parameters/ leafangles=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/leafangles/ @@ -9,7 +9,7 @@ radiationdata=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/radiationdata/ soil_spectrum=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/soil_spectrum/ input_data=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/input_data.xlsx InitialConditionPath=/data/shared/EcoExtreML/STEMMUS_SCOPEv1.0.0/input/Initial_condition/ -StartTime=2001-01-01T00:00 -EndTime=2001-01-02T00:00 -InputPath= -OutputPath= \ No newline at end of file +StartTime=2001-04-22T00:00 +EndTime=2001-04-23T00:00 +InputPath=../../input/US-Bo1_2024-09-18-1011/ +OutputPath=../../output/ diff --git a/example_data/input_data.xlsx b/example_data/input_data.xlsx new file mode 100644 index 00000000..99b631a2 Binary files /dev/null and b/example_data/input_data.xlsx differ diff --git a/example_data/input_soilLayThick.csv b/example_data/input_soilLayThick.csv index bca17029..0460d3d9 100644 --- a/example_data/input_soilLayThick.csv +++ b/example_data/input_soilLayThick.csv @@ -1,61 +1,61 @@ -NL,LayThick (cm),RootDepth (cm) -1,1,450 -2,1, -3,1, -4,2, -5,2, -6,2, -7,2, -8,2, -9,2, -10,2, -11,2, -12,2, -13,2, -14,2, -15,2.5, -16,2.5, -17,2.5, -18,2.5, -19,5, -20,5, -21,5, -22,5, -23,5, -24,10, -25,10, -26,10, -27,10, -28,10, -29,10, -30,10, -31,10, -32,10, -33,10, -34,10, -35,10, -36,10, -37,10, -38,10, -39,10, -40,10, -41,15, -42,15, -43,20, -44,20, -45,20, -46,20, -47,20, -48,20, -49,20, -50,20, -51,20, -52,20, -53,20, -54,20, -55,25, -56,25, -57,25, -58,25, -59,25, -60,25, +NL,LayThick (cm),RootDepth (cm) +1,1,450 +2,1, +3,1, +4,2, +5,2, +6,2, +7,2, +8,2, +9,2, +10,2, +11,2, +12,2, +13,2, +14,2, +15,2.5, +16,2.5, +17,2.5, +18,2.5, +19,5, +20,5, +21,5, +22,5, +23,5, +24,10, +25,10, +26,10, +27,10, +28,10, +29,10, +30,10, +31,10, +32,10, +33,10, +34,10, +35,10, +36,10, +37,10, +38,10, +39,10, +40,10, +41,15, +42,15, +43,20, +44,20, +45,20, +46,20, +47,20, +48,20, +49,20, +50,20, +51,20, +52,20, +53,20, +54,20, +55,25, +56,25, +57,25, +58,25, +59,25, +60,25, diff --git a/example_data/plant_growth/CropD.crp b/example_data/plant_growth/CropD.crp new file mode 100644 index 00000000..14da3301 --- /dev/null +++ b/example_data/plant_growth/CropD.crp @@ -0,0 +1,183 @@ +*********************************************************************************************** +* Filename: Maize.CRP +* Contents: SWAP 3.2 - Data for detailed crop model +*********************************************************************************************** +*c Grain maize (Zea mays L.) +*********************************************************************************************** + +*** PLANT GROWTH SECTION *** + +*********************************************************************************************** +* Part 1: Crop development + + CSTART = 1 ! Start time step of crop growth + CEND = 9073 ! End time step of crop growth + TSTEP = 0.5 ! Time step of the simulation, [0..1 hour] + TSUMEA = 950.00 ! Temperature sum from emergence to anthesis, [0..10000 C, R] + TSUMAM = 880.00 ! Temperature sum from anthesis to maturity [0..10000 C, R] + +* List increase in temperature sum [0..60 C, R] as function of daily average temp. [0..100 C, R] +* TAV DTSM (maximum 15 records) + DTSMTB = + 0.00 0.00 + 10.00 0.00 + 30.00 20.00 + 45.00 20.00 +* End of Table + + DVSEND = 2.00 ! development stage at harvest [-] +*********************************************************************************************** + +*********************************************************************************************** +* Part 2: Initial values + + TDWI = 20.000 ! Initial total crop dry weight [0..10000 kg/ha, R] + LAIEM = 0.3 ! Leaf area index at emergence [0..10 m2/m2, R] + PHEM = 0.1 ! plant height at emergence [0..10 m, R] + RGRLAI = 0.05! Maximum relative increase in LAI [0..1 m2/m2/d, R] +*********************************************************************************************** + +*********************************************************************************************** +* Part 3: Green surface area + + SPA = 0.0000 ! Specific pod area [0..1 ha/kg, R] + SSA = 0.0000 ! Specific stem area [0..1 ha/kg, R] + SPAN = 35.00 ! Life span under leaves under optimum conditions, [0..366 d, R] + LAICR = 6.00 ! The criteriation of LAI which affect the potential death rate due to self-shading, [0..10 m2/m2, R] + TBASE = 10.00 ! Lower threshold temperature for ageing of leaves ,[-10..30 C, R] + +* List specific leaf area [0..1 ha/kg, R] as function of devel. stage [0..2, R] + +* DVS SLA (maximum 15 records) + SLATB = + 0.0000 0.0015 + 0.3000 0.0015 + 1.0000 0.0015 + 1.2500 0.0015 + 2.0000 0.0015 +* End of Table +*********************************************************************************************** + +*********************************************************************************************** +* Part 4: Plant height growth + + STN = 40000 ! Number of stems [1..10000 /ha, I] + STD = 25.0 ! Density of stems [0.1..10 kg/m3, R] + PHCoeff = 1.22 ! Coeffcient of plant height, [1..2 , R] + +* List specific stems radius [0..1 m, R] as function of devel. stage [0..2, R] + +* DVS STR (maximum 15 records) + STRTB = + 0.0000 0.020 + 0.6000 0.021 + 1.3000 0.025 + 2.0000 0.025 +* End of Table +*********************************************************************************************** + +*********************************************************************************************** +* Part 5: Conversion of assimilates into biomass +* + CVL = 0.6900 ! Efficiency of conversion into leaves, [0..1 kg/kg, R] + CVO = 0.7500 ! Efficiency of conversion into storage organs, [0..1 kg/kg, R] + CVR = 0.6900 ! Efficiency of conversion into roots, [0..1 kg/kg, R] + CVS = 0.7200 ! Efficiency of conversion into stems, [0..1 kg/kg, R] +*********************************************************************************************** + +*********************************************************************************************** +* Part 6: Partitioning + +* List fraction of total dry matter increase partitioned to the roots [kg/kg, R] +* as function of development stage [0..2 -, R] +* DVS FR (maximum 15 records) + FRTB = + 0.00 0.90 + 0.30 0.50 + 1.00 0.00 + 2.00 0.00 +* End of table + +* List fraction of total above ground dry matter incr. part. to the leaves [kg/kg, R] +* as function of development stage [0..2 -, R] + +* DVS FL (maximum 15 records) + FLTB = + 0.0000 0.6000 + 0.7000 0.5000 + 0.7500 0.1000 + 0.9000 0.1000 + 1.0000 0.1000 + 1.0500 0.0000 + 2.0000 0.0000 +* End of table + +* List fraction of total above ground dry matter incr. part. to the stems [kg/kg, R] +* as function of development stage [0..2 -, R] + +* DVS FS (maximum 15 records) + FSTB = + 0.0000 0.4000 + 0.7000 0.5000 + 0.7500 0.9000 + 0.9000 0.9000 + 1.0000 0.9000 + 1.0500 0.0000 + 2.0000 0.0000 +* End of table + +* List fraction of total above ground dry matter incr. part. to the st. organs [kg/kg, R] +* as function of development stage [0..2 -, R] + +* DVS FO (maximum 15 records) + FOTB = + 0.0000 0.0000 + 0.9000 0.0000 + 1.0000 0.0000 + 1.0500 1.0000 + 2.0000 1.0000 +* End of table +*********************************************************************************************** + +*********************************************************************************************** +* Part 7: Death rates + + PERDL = 0.010 ! Maximum rel. death rate of leaves due to water stress [0..3 /d, R] + +* List relative death rates of roots [kg/kg/d] as function of dev. stage [0..2 -, R] +* DVS RDRR (maximum 15 records) + RDRRTB = + 0.0000 0.0000 + 1.5000 0.0000 + 1.5001 0.0200 + 2.0000 0.0200 +* End of table + +* List relative death rates of stems [kg/kg/d] as function of dev. stage [0..2 -, R] +* DVS RDRS (maximum 15 records) + RDRSTB = + 0.0000 0.0000 + 0.9000 0.0020 + 1.2500 0.0020 + 2.0000 0.0030 +* End of table +*********************************************************************************************** + +*********************************************************************************************** +* Part 8: Root density distribution and root growth +* +* List relative root density [0..1 -, R], as function of rel. rooting depth [0..1 -, R]: +* RD RDC (maximum 11 records) + RDCTB = + 0.00 1.00 + 1.00 1.00 +* End of table +* + RDI = 10.00 ! Initial rooting depth, [0..1000 cm, R] + RRI = 1.20 ! Maximum daily increase in rooting depth, [0..100 cm/d, R] + RDC = 80.00 ! Maximum rooting depth crop/cultivar, [0..1000 cm, R] +* +************************************************************************************ + + +* End of .crp file ! \ No newline at end of file diff --git a/src/+init/setBoundaryCondition.m b/src/+init/setBoundaryCondition.m index f65b0c84..b2520967 100644 --- a/src/+init/setBoundaryCondition.m +++ b/src/+init/setBoundaryCondition.m @@ -82,10 +82,10 @@ % 3 --Zero temperature gradient; NBCTB = 1; - if nanmean(Ta_msr) < 0 + if mean(Ta_msr, 'omitnan') < 0 BCTB = 0; % 9 8.1 else - BCTB = nanmean(Ta_msr); + BCTB = mean(Ta_msr, 'omitnan'); end end if ModelSettings.Soilairefc == 1 diff --git a/src/+io/bin_to_csv.m b/src/+io/bin_to_csv.m index 5bc13136..fb892666 100644 --- a/src/+io/bin_to_csv.m +++ b/src/+io/bin_to_csv.m @@ -91,6 +91,15 @@ function bin_to_csv(fnames, n_col, ns, options, SoilLayer, GroundwaterSettings, Sim_qtot_units = repelem({'cm s-1'}, length(depth)); write_output(Sim_qtot_names, Sim_qtot_units, fnames.Sim_qtot_file, n_col.Sim_qtot, ns, true); + %% output the vegetation dynamic results Danyang Yu + if options.calc_vegetation_dynamic + cropgrowth_names = {'DOY', 'DVS', 'LAI', ... + 'PH', 'Sfactor', 'RootDM', 'LeafDM', 'StemDM', 'OrganDM', 'RootDeath', 'LeafDeath', 'StemDeath'}; + cropgrowth_units = {'day', '-', 'm2/m2', ... + 'cm', '-', 'kg/ha', 'kg/ha', 'kg/ha', 'kg/ha', 'kg/ha', 'kg/ha', 'kg/ha'}; + write_output(cropgrowth_names, cropgrowth_units, fnames.cropgrowth_file, n_col.cropgrowth, ns); + end + if options.calc_fluor write_output({'fluorescence per simulation for wavelengths of 640 to 850 nm, with 1 nm resolution'}, {'W m-2 um-1 sr-1'}, ... fnames.fluorescence_file, n_col.fluorescence, ns, true); diff --git a/src/+io/create_output_files_binary.m b/src/+io/create_output_files_binary.m index 76695055..0e5e2dbc 100644 --- a/src/+io/create_output_files_binary.m +++ b/src/+io/create_output_files_binary.m @@ -108,6 +108,11 @@ fnames.spectrum_hemis_thermal_file = fullfile(Output_dir, 'spectrum_hemis_thermal.bin'); % spectrum hemispherically integrated end + % Create cropgrowth file + if options.calc_vegetation_dynamic + fnames.cropgrowth_file = fullfile(Output_dir, 'cropgrowth.bin'); % crop growth simulation ydy + end + % Create empty files for appending structfun(@(x) fopen(x, 'w'), fnames, 'UniformOutput', false); fclose("all"); diff --git a/src/+io/loadSoilInitialValues.m b/src/+io/loadSoilInitialValues.m index 94aaa06f..63285173 100644 --- a/src/+io/loadSoilInitialValues.m +++ b/src/+io/loadSoilInitialValues.m @@ -68,10 +68,10 @@ InitT6 = 0; Tss = InitT0; end - if nanmean(Ta_msr) < 0 + if mean(Ta_msr, 'omitnan') < 0 BtmT = 0; % 9 8.1 else - BtmT = nanmean(Ta_msr); + BtmT = mean(Ta_msr, 'omitnan'); end if InitX0 > SaturatedMC(1) || InitX1 > SaturatedMC(1) || InitX2 > SaturatedMC(2) || ... InitX3 > SaturatedMC(3) || InitX4 > SaturatedMC(4) || InitX5 > SaturatedMC(5) || InitX6 > SaturatedMC(6) diff --git a/src/+io/output_data_binary.m b/src/+io/output_data_binary.m index d5a918d4..ab07a6a4 100644 --- a/src/+io/output_data_binary.m +++ b/src/+io/output_data_binary.m @@ -1,7 +1,7 @@ function n_col = output_data_binary(f, k, xyt, rad, canopy, ScopeParameters, vi, vmax, options, fluxes, meteo, iter, thermal, ... spectral, gap, profiles, Sim_Theta_U, Sim_Temp, Trap, Evap, WaterStress, WaterPotential, ... Sim_hh, Sim_qlh, Sim_qlt, Sim_qvh, Sim_qvt, Sim_qla, Sim_qva, Sim_qtot, ... - ForcingData, RS, RWUs, RWUg) + ForcingData, RS, RWUs, RWUg, crop_output) %% OUTPUT DATA % author C. Van der Tol @@ -39,6 +39,13 @@ n_col.Sim_Temp = length(Sim_Temp_out); fwrite(f.Sim_Temp_file, Sim_Temp_out, 'double'); + %% Crop growth + if options.calc_vegetation_dynamic == 1 + cropgrowth_out = crop_output(k, :); + n_col.cropgrowth = length(cropgrowth_out); + fwrite(f.cropgrowth_file, cropgrowth_out, 'double'); + end + %% Water stress factor waterStressFactor_out = [k xyt.year(k) xyt.t(k) WaterStress.soil]; n_col.waterStressFactor = length(waterStressFactor_out); diff --git a/src/+wofost/WofostRead.m b/src/+wofost/WofostRead.m new file mode 100644 index 00000000..cd871f8f --- /dev/null +++ b/src/+wofost/WofostRead.m @@ -0,0 +1,54 @@ +function [wofost] = WofostRead(path_input) + %{ + function WofostRead.m loads plant growth parameters + from file "CropD.crp" in the input folder. + + authors: Danyang Yu (yudanyang123@gmail.com) + date: 2025/01/01 + %} + + % Read lines from the file + PlantGrowthFile = [path_input, 'plant_growth/CropD.crp']; + fid = fopen(PlantGrowthFile); + + % process it line by line + while true + tline = fgetl(fid); + + % remove empty and note line + if ~isempty(tline) & tline(1) ~= '*' + % judge whether the string contain the table value + if contains(tline, '=') + s = regexp(tline, '=', 'split'); + vname = strtrim(char(s(1))); + % assign value + if ~isempty(char(s(2))) + values = regexp(char(s(2)), '!', 'split'); + value = str2num(strtrim(char(values(1)))); + wofost.(vname) = value; % save parameters in wofost struct + end + else + % save tabel value + i = 1; + table_value = []; + while ~isempty(tline) & tline(1) ~= '*' + s = strsplit(strtrim(tline)); + table_value(i, 1) = str2num(strtrim(char(s(1)))); + table_value(i, 2) = str2num(strtrim(char(s(2)))); + i = i + 1; + tline = fgetl(fid); + % disp(tline); + end + + wofost.(vname) = table_value; + end + end + + % end of file + if contains(tline, '* End of .crp file !') + break + end + % disp(tline); + end + +end diff --git a/src/+wofost/afgen.m b/src/+wofost/afgen.m new file mode 100644 index 00000000..25520487 --- /dev/null +++ b/src/+wofost/afgen.m @@ -0,0 +1,16 @@ +function [output] = afgen(table, x) + %{ + function afgen.m intercept the value in the table + authors: Danyang Yu (yudanyang123@gmail.com) + date: 2025/01/01 + %} + + if x < table(1, 1) || x > table(end, 1) + print('the value of developemnt stage is mistaken'); + else + dvslist = table(:, 1).'; + loc = discretize([x], [-Inf dvslist Inf]); + slope = (table(loc, 2) - table(loc - 1, 2)) / (table(loc, 1) - table(loc - 1, 1)); + output = table(loc - 1, 2) + slope * (x - table(loc - 1, 1)); + end +end diff --git a/src/+wofost/cropgrowth.m b/src/+wofost/cropgrowth.m new file mode 100644 index 00000000..9ed2ed2a --- /dev/null +++ b/src/+wofost/cropgrowth.m @@ -0,0 +1,351 @@ +function [crop_output, state_vars] = cropgrowth(crop_output, state_vars, meteo, WofostPar, Anet, WaterStressFactor, xyt, KT, Dur_tot) + %{ + function cropgrowth.m simulate the growth of vegetation + + authors: Danyang Yu (yudanyang123@gmail.com) + date: 2025/01/01 + reference: SWAP version 3.2. Theory description and user manual (Page 147-163) + + Table of contents of the function + 1. Initilize crop growth paramters + 2. Calculate the phenological development + 3. Calculate the growth rate of different plant organs + 4. Output the crop growth variables + + Input: + Tsum Temperature sum from emergence to the simulated day + tdwi Initial total crop dry weight + laiem Leaf area index at emergence + f(r,l,s,o) The fraction of dry matter to root, leaf, stem, storage + tadw Initial total crop dry weight + lvage leaf age + lv save leaf dry matter at different steps + spa Specific pod area + ssa Specific stem area + sla specific leaf area + Anet_sum the sum of net assimilation + dmi converted dry matter at step KT + admi above-ground dry matter + grrt growth rate of root, similar for the other organs + drrt death rate of root, similar for the other organs + WofostPar Wofost parameters, the definitions are in CropD.crp + + Output: + dvs Developement of stage + lai leaf area index + ph Plant height + wrt dry matter weight of root + wlv dry matter weight of leaves + wst dry matter weight of stem + wso dry matter weight of storage organ + dwrt dry matter weight of dead root + dwlv dry matter weight of dead leaves + dwst dry matter weight of dead stem + %} + + %% 1. initilization + if KT == WofostPar.CSTART + % initial value of crop parameters + Tsum = 0; + dvs = 0; + tdwi = WofostPar.TDWI; + laiem = WofostPar.LAIEM; + ph = 0; + + frtb = WofostPar.FRTB; + fltb = WofostPar.FLTB; + fstb = WofostPar.FSTB; + fotb = WofostPar.FOTB; + + fr = wofost.afgen(frtb, dvs); + fl = wofost.afgen(fltb, dvs); + fs = wofost.afgen(fstb, dvs); + fo = wofost.afgen(fotb, dvs); + + ssa = WofostPar.SSA; + spa = WofostPar.SPA; + + % initial state variables of the crop + tadw = (1 - fr) * tdwi; + wrt = fr * tdwi; + wlv = fl * tadw; + wst = fs * tadw; + wso = fo * tadw; + + dwrt = 0.0; + dwlv = 0.0; + dwst = 0.0; + + sla = zeros(Dur_tot + 1, 1); + lvage = zeros(Dur_tot + 1, 1); + lv = zeros(Dur_tot + 1, 1); + sla(1) = wofost.afgen(WofostPar.SLATB, dvs); + lv(1) = wlv; + lvage(1) = 0.0; + ilvold = 1; + + lasum = laiem; + laiexp = laiem; + glaiex = 0; + laimax = laiem; + lai = lasum + ssa * wst + spa * wso; + Anet_sum = 0; + lai_delta = 0; + + else + % Unpack state variables + dvs = state_vars.dvs; + wrt = state_vars.wrt; + wlv = state_vars.wlv; + wst = state_vars.wst; + wso = state_vars.wso; + + dwrt = state_vars.dwrt; + dwlv = state_vars.dwlv; + dwst = state_vars.dwst; + + sla = state_vars.sla; + lvage = state_vars.lvage; + lv = state_vars.lv; + lasum = state_vars.lasum; + laiexp = state_vars.laiexp; + lai = state_vars.lai; + + ph = state_vars.ph; + Anet_sum = state_vars.Anet_sum; + lai_delta = state_vars.lai_delta; + end + + %% 1. phenological development + delt = WofostPar.TSTEP / 24; + tav = max(0, meteo.Ta); + dtsum = wofost.afgen(WofostPar.DTSMTB, tav); + + if dvs <= 1 % vegetative stage + dvs = dvs + dtsum * delt / WofostPar.TSUMEA; + else + dvs = dvs + dtsum * delt / WofostPar.TSUMAM; + end + + %% 2. dry matter increase + frtb = WofostPar.FRTB; + fltb = WofostPar.FLTB; + fstb = WofostPar.FSTB; + fotb = WofostPar.FOTB; + + fr = wofost.afgen(frtb, dvs); + fl = wofost.afgen(fltb, dvs); + fs = wofost.afgen(fstb, dvs); + fo = wofost.afgen(fotb, dvs); + + fcheck = fr + (fl + fs + fo) * (1.0 - fr) - 1.0; % check on partitions + if abs(fcheck) > 0.0001 + print('The sum of partitioning factors for leaves, stems and storage organs is not equal to one at development stage'); + return + end + + cvf = 1.0 / ((fl / WofostPar.CVL + fs / WofostPar.CVS + fo / WofostPar.CVO) * (1.0 - fr) + fr / WofostPar.CVR); + asrc = Anet * 30 / 1000000000 * 10000 * 3600 * WofostPar.TSTEP; % [umol m-2 s-1] to [kg CH2O ha-1]; + dmi = cvf * asrc; + + %% 3. Growth rate by root + % root extension + % rr = min(WofostPar.RDM - WofostPar.RD,WofostPar.RRI); + admi = (1.0 - fr) * dmi; + grrt = fr * dmi; + drrt = wrt * wofost.afgen(WofostPar.RDRRTB, dvs) * delt; + gwrt = grrt - drrt; + + %% 4. Growth rate by stem + % growth rate stems + grst = fs * admi; + % death rate stems + drst = wofost.afgen(WofostPar.RDRSTB, dvs) * wst * delt; + % net growth rate stems + gwst = grst - drst; + + % growth of plant height + str = wofost.afgen(WofostPar.STRTB, dvs); + phnew = wst / (WofostPar.STN * WofostPar.STD * pi * str * str) * WofostPar.PHCoeff + WofostPar.PHEM; + if phnew >= ph + ph = phnew; + end + + %% 5. Growth rate by organs + gwso = fo * admi; + + %% 6. Growth rate by leave + % weight of new leaves + grlv = fl * admi; + + % death of leaves due to water stress or high lai + if abs(lai) < 0.1 + dslv1 = 0; + else + sfactor = WaterStressFactor.soil; + dslv1 = wlv * (1.0 - sfactor) * WofostPar.PERDL * delt; + end + + laicr = WofostPar.LAICR; + dslv2 = wlv * max(0, 0.03 * (lai - laicr) / laicr); + dslv = max(dslv1, dslv2); + + % death of leaves due to exceeding life span + % first: leaf death due to water stress or high lai is imposed on array + % until no more leaves have to die or all leaves are gone + rest = dslv; + i1 = KT; + iday = ceil(KT * delt); + + while rest > lv(i1) && i1 >= 1 + rest = rest - lv(i1); + i1 = i1 - 1; + end + + % then: check if some of the remaining leaves are older than span, + % sum their weights + dalv = 0.0; + if lvage(i1) > WofostPar.SPAN && rest > 0 && i1 >= 1 + dalv = lv(i1) - rest; + rest = 0; + i1 = i1 - 1; + end + + while i1 >= 1 && lvage(i1) > WofostPar.SPAN + dalv = dalv + lv(i1); + i1 = i1 - 1; + end + + % final death rate + drlv = dslv + dalv; + + % calculation of specific leaf area in case of exponential growth: + slat = wofost.afgen(WofostPar.SLATB, dvs); + if laiexp < 6 + dteff = max(0, tav - WofostPar.TBASE); % effective temperature + glaiex = laiexp * WofostPar.RGRLAI * dteff * delt; % exponential growth + laiexp = laiexp + glaiex; + + glasol = grlv * slat; % source-limited growth + gla = min(glaiex, glasol); + % gla = max(0,gla); + + slat = gla / grlv; + if isnan(slat) + slat = 0; + end + % if grlv>=0 + % slat = gla/grlv; % the actual sla value + % else + % slat = 0; + % end + end + + % update the information of leave + dslvt = dslv; + i1 = KT; + while dslvt > 0 && i1 >= 1 % water stress and high lai + if dslvt >= lv(i1) + dslvt = dslvt - lv(i1); + lv(i1) = 0.0; + i1 = i1 - 1; + else + lv(i1) = lv(i1) - dslvt; + dslvt = 0.0; + end + end + + while lvage(i1) >= WofostPar.SPAN && i1 >= 1 % leaves older than span die + lv(i1) = 0; + i1 = i1 - 1; + end + + ilvold = KT; % oldest class with leaves + fysdel = max(0.0d0, (tav - WofostPar.TBASE) / (35.0 - WofostPar.TBASE)); % physiologic ageing of leaves per time step + + for i1 = ilvold:-1:1 % shifting of contents, updating of physiological age + lv(i1 + 1) = lv(i1); + sla(i1 + 1) = sla(i1); + lvage(i1 + 1) = lvage(i1) + fysdel * delt; + end + ilvold = ilvold + 1; + + lv(1) = grlv; + sla(1) = slat; + lvage(1) = 0.0; + + % calculation of new leaf area and weight + lasum = 0.0; + wlv = 0.0; + for i1 = 1:ilvold + lasum = lasum + lv(i1) * sla(i1); + wlv = wlv + lv(i1); + end + lasum = max(0, lasum); + wlv = max(0, wlv); + + %% 7. integrals of the crop + % dry weight of living plant organs + wrt = wrt + gwrt; + wst = wst + gwst; + wso = wso + gwso; + + % total above ground biomass + tadw = wlv + wst + wso; + + % dry weight of dead plant organs (roots,leaves & stems) + dwrt = dwrt + drrt; + dwlv = dwlv + drlv; + dwst = dwst + drst; + + % dry weight of dead and living plant organs + twrt = wrt + dwrt; + twlv = wlv + dwlv; + twst = wst + dwst; + cwdm = twlv + twst + wso; + + % leaf area index + lai = WofostPar.LAIEM + lasum + WofostPar.SSA * wst + WofostPar.SPA * wso; + + Anet_sum = Anet_sum + Anet; % assume LAI not changed with the respiration + if Anet_sum < 0 && KT > 1 % the consumed biomass are the assimilated one at daytime + lai_delta = lai_delta + grlv * slat; + lai = lai - lai_delta; + elseif Anet_sum >= 0 && Anet >= 0 + Anet_sum = 0; + lai_delta = 0; + end + + %% 8. integrals of the crop + crop_output(KT, 1) = xyt.t(KT, 1); % Day of the year + crop_output(KT, 2) = dvs; % Development of stage + crop_output(KT, 3) = lai; % LAI + crop_output(KT, 4) = ph; % Plant height + crop_output(KT, 5) = sfactor; % Water stress + crop_output(KT, 6) = wrt; % Dry matter of root + crop_output(KT, 7) = wlv; % Dry matter of leaves + crop_output(KT, 8) = wst; % Dry matter of stem + crop_output(KT, 9) = wso; % Dry matter of organ + crop_output(KT, 10) = dwrt; % Dry matter of deadleaves + crop_output(KT, 11) = dwlv; % Dry matter of dead stem + crop_output(KT, 12) = dwst; % Dry matter of dead organ + + %% 9. Pack updated state variables + state_vars.dvs = dvs; + state_vars.wrt = wrt; + state_vars.wlv = wlv; + state_vars.wst = wst; + state_vars.wso = wso; + state_vars.dwrt = dwrt; + state_vars.dwlv = dwlv; + state_vars.dwst = dwst; + state_vars.sla = sla; + state_vars.lvage = lvage; + state_vars.lv = lv; + state_vars.lasum = lasum; + state_vars.laiexp = laiexp; + state_vars.lai = lai; + state_vars.ph = ph; + state_vars.Anet_sum = Anet_sum; + state_vars.lai_delta = lai_delta; +end diff --git a/src/STEMMUS_SCOPE.m b/src/STEMMUS_SCOPE.m index 1db95466..9c1cb299 100644 --- a/src/STEMMUS_SCOPE.m +++ b/src/STEMMUS_SCOPE.m @@ -198,7 +198,15 @@ [rho, tau, rs] = deal(zeros(nwlP + nwlT, 1)); - %% 11. load time series data + %% 11. Define plant growth parameters + if options.calc_vegetation_dynamic == 1 + % global crop_output + WofostPar = wofost.WofostRead(path_input); + crop_output = zeros(TimeProperties.Dur_tot, 12); + state_vars = struct(); + end + + %% 12. load time series data ScopeParametersNames = fieldnames(ScopeParameters); if options.simulation == 1 vi = ones(length(ScopeParametersNames), 1); @@ -208,7 +216,7 @@ soil = struct; end - %% 12. preparations + %% 13. preparations if options.simulation == 1 diff_tmin = abs(xyt.t - xyt.startDOY); diff_tmax = abs(xyt.t - xyt.endDOY); @@ -242,7 +250,7 @@ atmfile = [path_input 'radiationdata/' char(F(4).FileName(1))]; atmo.M = helpers.aggreg(atmfile, spectral.SCOPEspec); - %% 13. create output files and + %% 14. create output files and [Output_dir, fnames] = io.create_output_files_binary(parameter_file, SiteProperties.sitename, path_of_code, path_input, path_output, spectral, options); %% Initialize Temperature, Matric potential and soil air pressure. @@ -374,6 +382,8 @@ % Will do one timestep in "update mode", and run until the end if in "full run" mode. while KT < endTime KT = KT + 1; % Counting Number of timesteps + fprintf(strcat('\n KT = ', num2str(KT), ' \r')); + if KT > 1 && Delt_t > (TEND - TIME) Delt_t = TEND - TIME; % If Delt_t is changed due to excessive change of state variables, the judgement of the last time step is excuted. end @@ -420,6 +430,18 @@ if options.simulation == 0 vi(vmax == telmax) = k; end + + % using simulated LAI and PH to substitute prescribed LAI + if options.calc_vegetation_dynamic == 1 && KT >= WofostPar.CSTART && KT <= WofostPar.CEND + if KT == WofostPar.CSTART + ScopeParameters.LAI(KT) = WofostPar.LAIEM; % initial LAI + ScopeParameters.hc(KT) = WofostPar.PHEM; % initial PH + elseif KT > WofostPar.CSTART + ScopeParameters.LAI(KT) = crop_output(KT - 1, 3); % substitute LAI + ScopeParameters.hc(KT) = crop_output(KT - 1, 4); % substitute PH + end + end + [soil, leafbio, canopy, meteo, angles, xyt] = io.select_input(ScopeParameters, SoilVariables.Theta_LL, vi, canopy, options, xyt, soil); if options.simulation ~= 1 fprintf('simulation %i ', k); @@ -542,6 +564,17 @@ end end end + + % calculate the plant growth process + if options.calc_vegetation_dynamic == 1 && KT >= WofostPar.CSTART && KT <= WofostPar.CEND % vegetation growth process + Anet = fluxes.Actot; + if isnan(Anet) || Anet < -2 % limit value of Anet + Anet = 0; + fluxes.Actot = Anet; + end + [crop_output, state_vars] = wofost.cropgrowth(crop_output, state_vars, meteo, WofostPar, Anet, WaterStressFactor, xyt, KT, TimeProperties.Dur_tot); + end + if options.simulation == 2 && telmax > 1 vi = helpers.count(nvars, vi, vmax, 1); end @@ -799,7 +832,7 @@ n_col = io.output_data_binary(file_ids, k, xyt, rad, canopy, ScopeParameters, vi, vmax, options, fluxes, ... meteo, iter, thermal, spectral, gap, profiles, Sim_Theta_U, Sim_Temp, Trap, ... Evap, WaterStressFactor, WaterPotential, Sim_hh, Sim_qlh, Sim_qlt, Sim_qvh, ... - Sim_qvt, Sim_qla, Sim_qva, Sim_qtot, ForcingData, RS, RWUs, RWUg); + Sim_qvt, Sim_qla, Sim_qva, Sim_qtot, ForcingData, RS, RWUs, RWUg, crop_output); fclose("all"); end end