SUEWS API Site
Documentation of SUEWS source code
suews_ctrl_input.f95
Go to the documentation of this file.
1!Reading one line of meteorological forcing data in.
2!Latest change:
3! Feb 2012, LJ: Input fluxes qh and qe changed _obs as well as qn1_obs ending
4! Oct 2014, LJ: Variables changed only be used in this part of code and these are passed to calling
5! function in MetArray.
6! Jan 2015, HCW: Precip_hr, wuh and LAI_hr changed for generic timesteps
7! Jan 2016, LJ: Removal of tabs
8! Feb 2017, HCW: Added file unit as argument so MetRead can be used for original met forcing file too
9! May 2018, TS: imporved the ability in downscaling datetime by introducing a datetime library
10! To Do:
11! - Check observed SM calculation
12!---------------------------------------------------------------------------------------------------
13SUBROUTINE metread(lfn, MetArray, InputmetFormat, ldown_option, NetRadiationMethod, &
14 SnowUse, SMDMethod, SoilDepthMeas, SoilRocks, SoilDensity, SmCap)
15
17
18 IMPLICIT NONE
19
20 !INPUT
21 REAL(KIND(1D0)), DIMENSION(24) :: MetArray !Array leaving the subroutine within
22 !each INTERVAL (defined in RunControl.nml)
23 ! - Met data now provided at a resolution of tstep, HCW Jan 2015
24
25 REAL(KIND(1D0)) :: SmCap, & !Volumetric/gravimetric soil moisture capacity
26 SoilDepthMeas, & !Measured soil depth
27 SoilRocks, & !Rocks on ground
28 SoilDensity !Density of soil
29
30 INTEGER :: InputmetFormat, & !Format of the meteorological forcing file
31 ldown_option, & !Method of calculating Ldown
32 NetRadiationMethod, & !Method of calculating Q*
33 SMDMethod, & !Method of measured soil moisture
34 SnowUse
35
36 ! Variables read in
37 REAL(KIND(1D0)) :: avkdn, & !Average downwelling shortwave radiation
38 avrh, & !Average relative humidity
39 avu1, & !Average wind speed
40 dectime, & !Decimal time
41 fcld_obs, & !Cloud fraction observed
42 iy, & !Year
43 id, & !Day
44 it, & !Hour
45 imin, & !Minute
46 kdiff, & !Diffuse shortwave radiation
47 kdir, & !Direct shortwave radiation
48 LAI_obs, & !Overall LAI of the study area
49 ldown_obs, & !Downwelling longwave radiation
50 Precip, & !Rainfall [mm]
51 Pres_hPa, & !Station air pressure in hPa
52 Pres_kPa, & !Station air pressure in kPa
53 snowFrac_obs, & !Observed surface fraction of snow (between 0 and 1)
54 qe_obs, & !Observed latent heat flux
55 qf_obs, & !Observed antrhropogeni heat flux
56 qh_obs, & !Observed sensible heat flux
57 qn1_obs, & !Observed net all-wave radiation
58 qs_obs, & !Observed storage heat flux
59 Temp_C, & !Air temperature
60 wdir, & !Wind direction
61 wu_m3, & !Water use provided in met forcing file [m3]
62 xsmd !Measured soil moisture deficit
63
64 INTEGER :: iostat_var, lfn
65
66 !-----------------------------------------------------------------------------------
67 !-----------------------------------------------------------------------------------
68
69 IF (inputmetformat == 0) THEN !Default format using LUMPS only
70
71 READ (lfn, *, iostat=iostat_var) iy, id, it, imin, qn1_obs, avu1, avrh, &
72 temp_c, wdir, pres_kpa, precip, avkdn, snowfrac_obs, ldown_obs, fcld_obs
73
74 !Set other variables needed while running SUEWS to zero
75 qf_obs = nan
76 qs_obs = nan
77 qh_obs = nan
78 qe_obs = nan
79 xsmd = -99999
80 kdiff = nan
81 kdir = nan
82 wdir = nan
83
84 ELSEIF (inputmetformat == 10) THEN !SUEWS reading
85 READ (lfn, *, iostat=iostat_var) iy, id, it, imin, qn1_obs, qh_obs, qe_obs, qs_obs, qf_obs, avu1, avrh, &
86 temp_c, pres_kpa, precip, avkdn, snowfrac_obs, ldown_obs, fcld_obs, &
87 wu_m3, xsmd, lai_obs, kdiff, kdir, wdir
88
89 !write(*,*) 'In LUMPS_MetRead (1)'
90 !write(*,*) 'imin',imin
91 !write(*,*) 'it',it
92 !write(*,*) 'id',id
93 !write(*,*) 'iy',iy
94
95 !Calculate observed soil moisture deficits from either volumetric or gravimetric SoilStates
96 IF (smdmethod == 1 .AND. xsmd /= -999) THEN !Soil moisture - volumetric
97 xsmd = (smcap - xsmd)*soildepthmeas*soilrocks
98 ELSEIF (smdmethod == 2 .AND. xsmd /= -999) THEN !Soil moisture -gravimetric
99 xsmd = (smcap - xsmd)*soildensity*soildepthmeas*soilrocks
100 ELSE
101 xsmd = -999
102 END IF
103
104 ELSE
105 CALL errorhint(55, 'RunControl.nml, InputMetFormat not usable.', notused, notused, inputmetformat)
106 END IF
107
108 !===============Meteorological variables reading done==========================
109 pres_hpa = pres_kpa*10. ! convert to hPa
110
111 ! get decimal time
112 dectime = id + it + imin/60.0
113
114 IF (iostat_var < 0) THEN
115 iostat_var = 0
116 CLOSE (lfn)
117 RETURN
118 END IF
119
120 IF (avkdn < 0) THEN
121 CALL errorhint(27, 'Met Data: avKdn - needed for StoreDrainPrm. resistance, If present, check file not tab delimited', &
122 avkdn, dectime, notusedi)
123 !sg removed this is causing the problems with resistances
124 ! AvKdn=0 !Solar radiation cannot be lower than 1
125 END IF
126
127 IF ((ldown_option == 1) .AND. (ldown_obs < 0)) THEN
128 CALL errorhint(27, 'Met Data: LWdn (ldown_obs) - impact Q* calc', ldown_obs, dectime, notusedi)
129
130 ELSEIF (ldown_option == 2) THEN
131 IF (fcld_obs == -999.0 .OR. fcld_obs < 0 .OR. fcld_obs > 1) THEN
132 CALL errorhint(27, 'Met Data: flcd_obs - impacts LW & Q* radiation', fcld_obs, dectime, notusedi)
133 END IF
134 END IF
135
136 IF (qn1_obs == -999 .AND. netradiationmethod == 0) THEN !If measured Q* is used and it is -999
137 CALL errorhint(27, 'Met Data: Q* - will impact everything', qn1_obs, dectime, notusedi)
138 END IF
139
140 IF (avu1 <= 0) THEN !If wind speed is negative
141 CALL errorhint(27, 'Met Data: avU1 - impacts aeroydnamic resistances', avu1, dectime, notusedi)
142 END IF
143
144 IF (temp_c < -50 .OR. temp_c > 60) THEN !If temperature unrealistic
145 CALL errorhint(27, 'Met Data: Temp_C - beyond what is expected', temp_c, dectime, notusedi)
146 END IF
147
148 IF (avrh > 100 .OR. avrh < 1) THEN !If relative humidity larger than 100%
149 CALL errorhint(27, 'Met Data: avRH - beyond what is expected', avrh, dectime, notusedi)
150 END IF
151
152 IF (pres_kpa < 80) THEN !If pressure too low
153 CALL errorhint(27, 'Met Data: Pres_kPa - too low - this could be fixed in model', pres_kpa, dectime, notusedi)
154 END IF
155
156 IF (precip < 0) THEN !If rain in negative, set it to zero
157 CALL errorhint(27, 'Met Data: Precip - less than 0', precip, dectime, notusedi)
158 END IF
159
160 IF (snowfrac_obs == nan) snowfrac_obs = 0
161
162 IF (snowuse == 0 .AND. (snowfrac_obs < 0 .OR. snowfrac_obs > 1)) THEN
163 CALL errorhint(27, 'Met Data: snow not between [0 1]', snowfrac_obs, dectime, notusedi)
164 END IF
165
166 IF (xsmd < 0 .AND. smdmethod == 1) THEN !If soil moisture deficit is zero
167 CALL errorhint(27, 'Met Data: xsmd - less than 0', xsmd, dectime, notusedi)
168 END IF
169
170 !Create an array to be printed out.
171 metarray(1:24) = (/iy, id, it, imin, qn1_obs, qh_obs, qe_obs, qs_obs, qf_obs, avu1, &
172 avrh, temp_c, pres_hpa, precip, avkdn, snowfrac_obs, ldown_obs, &
173 fcld_obs, wu_m3, xsmd, lai_obs, kdiff, kdir, wdir/)
174
175 !write(*,*) 'In LUMPS_MetRead (2)'
176 !write(*,*) 'imin',imin
177 !write(*,*) 'it',it
178 !write(*,*) 'id',id
179 !write(*,*) 'iy',iy
180
181 RETURN
182
183END SUBROUTINE metread
184
185! sg Feb 2012 -- moving all related suborutine together
186! subroutine run_control - checks that value is reasonable
187! subrotuine skipHeader - jumps over header rows in input files
188! Last modified:
189! LJ 27 Jan 2016 - Removal of tabs, cleaning of the code
190!------------------------------------------------------------
191
192!Information for the run
194 IMPLICIT NONE
195 CHARACTER(len=90), DIMENSION(14) :: text
196 INTEGER :: lim0 = 0, lim1 = 1, lim2 = 2, lim4 = 4, lim3 = 3, lim6 = 6, lim8 = 8, lim12 = 12, lfn_us
197 LOGICAL :: file_qs
198END MODULE run_info
199
200! run_control
201! called from: LUMPS_initial
202
203SUBROUTINE run_control(eval, LowerLimit, Upperlimit)
204 ! ver - determines if value to be read is an integer or real and returns the value
205 ! if ver=-9 - then use integer
206 USE run_info
207 IMPLICIT NONE
208 INTEGER :: eval, i, lowerlimit, upperlimit
209 CHARACTER(len=4) :: check
210
211 IF (file_qs) THEN
212101 READ (lfn_us, *) check
213 WRITE (*, *) check
214 DO i = 1, 3
215 IF (check(i:i) == "#") THEN
216 ! write(*,*)check(i:i),i,"check"
217 GOTO 101
218 ELSE
219 backspace(lfn_us)
220 READ (lfn_us, *) eval
221 !write(*,*)eval, TEXT(1)
222 EXIT
223 END IF
224 END DO
225 END IF
226
227 WRITE (12, 120) eval, text(1)
228
229 IF (eval < lowerlimit .OR. eval > upperlimit) THEN
230 WRITE (*, *) "Value out of range"
231 WRITE (*, *) eval, text(1)
232 stop
233 END IF
234
235 WRITE (*, 120) eval, text(1)
236120 FORMAT(i4, 2x, a90)
237
238 RETURN
239END SUBROUTINE run_control
240
241! Skip Headers------------------------------
242SUBROUTINE skipheader(lfn, skip)
244 IMPLICIT NONE
245
246 INTEGER :: skip, lfn, i
247 DO i = 1, skip
248 READ (lfn, *, err=201, iostat=ios_out)
249 END DO
250
251 RETURN
252
253201 reall = real(skip)
254 CALL errorhint(20, 'In SkipHeader subroutine.', reall, notused, ios_out)
255END SUBROUTINE skipheader
256
257!-------------------------------------------------------------------------
258SUBROUTINE inputheadercheck(FileName)
259 ! Checks columns in input files match the columns expected by model code
260 ! Model code columns are defined here
261 ! Latest update:
262 ! MH 21 Jun 2017 - Added parameters to SUEWS_AnthropogenicEmissions.txt
263 ! MH 16 Jun 2017 - Added SUEWS_BiogenCO2.txt
264 ! TS 02 Mar 2016 - AnOHM related variables added
265 ! LJ 27 Jan 2016 - Removal of tabs
266 ! LJ 07 July 2015 - snow albedo removed
267 ! HCW 12 Nov 2014
268 !-------------------------------------------------------------------------
269
270 USE allocatearray
273
274 IMPLICIT NONE
275
276 CHARACTER(len=50) :: FileName
277
278 ! ========== Define expected column names here ==========
279 ! =======================================================
280
281 ! ========== SUEWS_NonVeg.txt =============
282 headernonveg_reqd(ci_code) = "Code"
283 headernonveg_reqd(ci_albmin) = "AlbedoMin"
284 headernonveg_reqd(ci_albmax) = "AlbedoMax"
285 headernonveg_reqd(ci_emis) = "Emissivity"
286 headernonveg_reqd(ci_stormin) = "StorageMin"
287 headernonveg_reqd(ci_stormax) = "StorageMax"
288 headernonveg_reqd(ci_wetthresh) = "WetThreshold"
289 headernonveg_reqd(ci_statelimit) = "StateLimit"
290 headernonveg_reqd(ci_dreq) = "DrainageEq"
291 headernonveg_reqd(ci_drcoef1) = "DrainageCoef1"
292 headernonveg_reqd(ci_drcoef2) = "DrainageCoef2"
293 headernonveg_reqd(ci_soiltcode) = "SoilTypeCode"
294 headernonveg_reqd(ci_snowlimpat) = "SnowLimPatch"
295 headernonveg_reqd(ci_snowlimrem) = "SnowLimRemove"
296 headernonveg_reqd(ci_ohmcode_swet) = "OHMCode_SummerWet"
297 headernonveg_reqd(ci_ohmcode_sdry) = "OHMCode_SummerDry"
298 headernonveg_reqd(ci_ohmcode_wwet) = "OHMCode_WinterWet"
299 headernonveg_reqd(ci_ohmcode_wdry) = "OHMCode_WinterDry"
300 headernonveg_reqd(ci_ohmthresh_sw) = "OHMThresh_SW"
301 headernonveg_reqd(ci_ohmthresh_wd) = "OHMThresh_WD"
302 headernonveg_reqd(ci_estmcode) = "ESTMCode"
303 headernonveg_reqd(ci_cpanohm) = "AnOHM_Cp" ! AnOHM TS
304 headernonveg_reqd(ci_kkanohm) = "AnOHM_Kk" ! AnOHM TS
305 headernonveg_reqd(ci_chanohm) = "AnOHM_Ch" ! AnOHM TS
306
307 ! ========== SUEWS_Veg.txt ===============
308 headerveg_reqd(cp_code) = "Code"
309 headerveg_reqd(cp_albmin) = "AlbedoMin"
310 headerveg_reqd(cp_albmax) = "AlbedoMax"
311 headerveg_reqd(cp_emis) = "Emissivity"
312 headerveg_reqd(cp_stormin) = "StorageMin"
313 headerveg_reqd(cp_stormax) = "StorageMax"
314 headerveg_reqd(cp_wetthresh) = "WetThreshold"
315 headerveg_reqd(cp_statelimit) = "StateLimit"
316 headerveg_reqd(cp_dreq) = "DrainageEq"
317 headerveg_reqd(cp_drcoef1) = "DrainageCoef1"
318 headerveg_reqd(cp_drcoef2) = "DrainageCoef2"
319 headerveg_reqd(cp_soiltcode) = "SoilTypeCode"
320 headerveg_reqd(cp_snowlimpat) = "SnowLimPatch"
321 headerveg_reqd(cp_baset) = "BaseT"
322 headerveg_reqd(cp_basete) = "BaseTe"
323 headerveg_reqd(cp_gddfull) = "GDDFull"
324 headerveg_reqd(cp_sddfull) = "SDDFull"
325 headerveg_reqd(cp_laimin) = "LAIMin"
326 headerveg_reqd(cp_laimax) = "LAIMax"
327 headerveg_reqd(cp_porositymin) = "PorosityMin"
328 headerveg_reqd(cp_porositymax) = "PorosityMax"
329 headerveg_reqd(cp_gsmax) = "MaxConductance"
330 headerveg_reqd(cp_laieq) = "LAIEq"
331 headerveg_reqd(cp_leafgp1) = "LeafGrowthPower1"
332 headerveg_reqd(cp_leafgp2) = "LeafGrowthPower2"
333 headerveg_reqd(cp_leafop1) = "LeafOffPower1"
334 headerveg_reqd(cp_leafop2) = "LeafOffPower2"
335 headerveg_reqd(cp_ohmcode_swet) = "OHMCode_SummerWet"
336 headerveg_reqd(cp_ohmcode_sdry) = "OHMCode_SummerDry"
337 headerveg_reqd(cp_ohmcode_wwet) = "OHMCode_WinterWet"
338 headerveg_reqd(cp_ohmcode_wdry) = "OHMCode_WinterDry"
339 headerveg_reqd(cp_ohmthresh_sw) = "OHMThresh_SW"
340 headerveg_reqd(cp_ohmthresh_wd) = "OHMThresh_WD"
341 headerveg_reqd(cp_estmcode) = "ESTMCode"
342 headerveg_reqd(cp_cpanohm) = "AnOHM_Cp" ! AnOHM TS
343 headerveg_reqd(cp_kkanohm) = "AnOHM_Kk" ! AnOHM TS
344 headerveg_reqd(cp_chanohm) = "AnOHM_Ch" ! AnOHM TS
345 headerveg_reqd(cp_biogenco2code) = "BiogenCO2Code"
346
347 ! ========== SUEWS_Water.txt ==================
348 headerwater_reqd(cw_code) = "Code"
349 headerwater_reqd(cw_albmin) = "AlbedoMin"
350 headerwater_reqd(cw_albmax) = "AlbedoMax"
351 headerwater_reqd(cw_emis) = "Emissivity"
352 headerwater_reqd(cw_stormin) = "StorageMin"
353 headerwater_reqd(cw_stormax) = "StorageMax"
354 headerwater_reqd(cw_wetthresh) = "WetThreshold"
355 headerwater_reqd(cw_statelimit) = "StateLimit"
356 headerwater_reqd(cw_waterdepth) = "WaterDepth"
357 headerwater_reqd(cw_dreq) = "DrainageEq"
358 headerwater_reqd(cw_drcoef1) = "DrainageCoef1"
359 headerwater_reqd(cw_drcoef2) = "DrainageCoef2"
360 headerwater_reqd(cw_ohmcode_swet) = "OHMCode_SummerWet"
361 headerwater_reqd(cw_ohmcode_sdry) = "OHMCode_SummerDry"
362 headerwater_reqd(cw_ohmcode_wwet) = "OHMCode_WinterWet"
363 headerwater_reqd(cw_ohmcode_wdry) = "OHMCode_WinterDry"
364 headerwater_reqd(cw_ohmthresh_sw) = "OHMThresh_SW"
365 headerwater_reqd(cw_ohmthresh_wd) = "OHMThresh_WD"
366 headerwater_reqd(cw_estmcode) = "ESTMCode"
367 headerwater_reqd(cw_cpanohm) = "AnOHM_Cp" ! AnOHM TS
368 headerwater_reqd(cw_kkanohm) = "AnOHM_Kk" ! AnOHM TS
369 headerwater_reqd(cw_chanohm) = "AnOHM_Ch" ! AnOHM TS
370
371 ! ========== SUEWS_Snow.txt ===================
372 headersnow_reqd(cs_code) = "Code"
373 headersnow_reqd(cs_snowrmfactor) = "RadMeltFactor"
374 headersnow_reqd(cs_snowtmfactor) = "TempMeltFactor"
375 headersnow_reqd(cs_snowalbmin) = "AlbedoMin"
376 headersnow_reqd(cs_snowalbmax) = "AlbedoMax"
377 headersnow_reqd(cs_snowemis) = "Emissivity"
380 headersnow_reqd(cs_snowplimalb) = "PrecipLimAlb"
381 headersnow_reqd(cs_snowsdmin) = "SnowDensMin"
382 headersnow_reqd(cs_snowsdmax) = "SnowDensMax"
386 headersnow_reqd(cs_snowplimsnow) = "PrecipLimSnow"
387 headersnow_reqd(cs_ohmcode_swet) = "OHMCode_SummerWet"
388 headersnow_reqd(cs_ohmcode_sdry) = "OHMCode_SummerDry"
389 headersnow_reqd(cs_ohmcode_wwet) = "OHMCode_WinterWet"
390 headersnow_reqd(cs_ohmcode_wdry) = "OHMCode_WinterDry"
391 headersnow_reqd(cs_ohmthresh_sw) = "OHMThresh_SW"
392 headersnow_reqd(cs_ohmthresh_wd) = "OHMThresh_WD"
393 headersnow_reqd(cs_estmcode) = "ESTMCode"
394 headersnow_reqd(cs_cpanohm) = "AnOHM_Cp" ! AnOHM TS
395 headersnow_reqd(cs_kkanohm) = "AnOHM_Kk" ! AnOHM TS
396 headersnow_reqd(cs_chanohm) = "AnOHM_Ch" ! AnOHM TS
397
398 ! ========== SUEWS_Soil.txt ===================
399 headersoil_reqd(cso_code) = "Code"
400 headersoil_reqd(cso_soildepth) = "SoilDepth"
401 headersoil_reqd(cso_soilstcap) = "SoilStoreCap"
402 headersoil_reqd(cso_ksat) = "SatHydraulicCond"
403 headersoil_reqd(cso_soildens) = "SoilDensity"
404 headersoil_reqd(cso_soilinfrate) = "InfiltrationRate"
405 headersoil_reqd(cso_obssmdepth) = "OBS_SMDepth"
406 headersoil_reqd(cso_obssmmax) = "OBS_SMCap"
407 headersoil_reqd(cso_obssnrfrac) = "OBS_SoilNotRocks"
408
409 ! ========== SUEWS_Conductance.txt ============
410 headercond_reqd(cc_code) = "Code"
421 headercond_reqd(cc_gskmax) = "Kmax"
422 headercond_reqd(cc_gsmodel) = "gsModel"
423
424 ! ========== SUEWS_OHMCoefficients.txt ========
429
430 ! ========== SUEWS_ESTMCoefficients.txt ========
478 headerestmcoefficients_reqd(ce_alb_ibld) = "Internal_albedo"
479 headerestmcoefficients_reqd(ce_em_ibld) = "Internal_emissivity"
480 headerestmcoefficients_reqd(ce_ch_iwall) = "Internal_CHwall"
481 headerestmcoefficients_reqd(ce_ch_iroof) = "Internal_CHroof"
482 headerestmcoefficients_reqd(ce_ch_ibld) = "Internal_CHbld"
483
484 ! ========== SUEWS_AnthropogenicEmission.txt ======
495 headeranthropogenic_reqd(ca_ahslopeheating_wd) = "AHSlope_Heating_WD"
496 headeranthropogenic_reqd(ca_ahslopeheating_we) = "AHSlope_Heating_WE"
497 headeranthropogenic_reqd(ca_ahslopecooling_wd) = "AHSlope_Cooling_WD"
498 headeranthropogenic_reqd(ca_ahslopecooling_we) = "AHSlope_Cooling_WE"
499 headeranthropogenic_reqd(ca_tcriticheating_wd) = "TCritic_Heating_WD"
500 headeranthropogenic_reqd(ca_tcriticheating_we) = "TCritic_Heating_WE"
501 headeranthropogenic_reqd(ca_tcriticcooling_wd) = "TCritic_Cooling_WD"
502 headeranthropogenic_reqd(ca_tcriticcooling_we) = "TCritic_Cooling_WE"
503 headeranthropogenic_reqd(ca_enprofwd) = "EnergyUseProfWD"
504 headeranthropogenic_reqd(ca_enprofwe) = "EnergyUseProfWE"
505 headeranthropogenic_reqd(ca_co2mwd) = "ActivityProfWD"
506 headeranthropogenic_reqd(ca_co2mwe) = "ActivityProfWE"
517 headeranthropogenic_reqd(ca_frfossilfuel_nonheat) = "FrFossilFuel_NonHeat"
524
525 ! ========== SUEWS_Irrigation.txt =============
529 headerirrigation_reqd(cir_intwu) = "InternalWaterUse"
545 headerirrigation_reqd(cir_daywatper1) = "DayWatPer(1)"
546 headerirrigation_reqd(cir_daywatper2) = "DayWatPer(2)"
547 headerirrigation_reqd(cir_daywatper3) = "DayWatPer(3)"
548 headerirrigation_reqd(cir_daywatper4) = "DayWatPer(4)"
549 headerirrigation_reqd(cir_daywatper5) = "DayWatPer(5)"
550 headerirrigation_reqd(cir_daywatper6) = "DayWatPer(6)"
551 headerirrigation_reqd(cir_daywatper7) = "DayWatPer(7)"
552
553 ! ========== SUEWS_Profiles.txt ===============
579
580 ! ========== SUEWS_WithinGridWaterDist.txt ====
591
592 ! ========== SUEWS_BiogenCO2.txt ======
593 headerbiogen_reqd(cb_code) = "Code"
594 headerbiogen_reqd(cb_alpha) = "alpha"
595 headerbiogen_reqd(cb_beta) = "beta"
596 headerbiogen_reqd(cb_theta) = "theta"
597 headerbiogen_reqd(cb_alpha_enh) = "alpha_enh"
598 headerbiogen_reqd(cb_beta_enh) = "beta_enh"
599 headerbiogen_reqd(cb_resp_a) = "resp_a"
600 headerbiogen_reqd(cb_resp_b) = "resp_b"
601 headerbiogen_reqd(cb_min_r) = "min_respi"
602
603 ! =======================================================
604
605 !write(*,*) 'Checking header for ', FileName
606 ! Check columns in input files match model code
607
608 IF (filename == 'SUEWS_NonVeg.txt') THEN
609 IF (any(headernonveg_file /= headernonveg_reqd)) THEN
611 WRITE (*, *) headernonveg_file
612 WRITE (*, *) headernonveg_reqd
613 CALL errorhint(56, 'Names or order of columns in SUEWS_NonVeg.txt does not match model code.', notused, notused, notusedi)
614 END IF
615
616 ELSEIF (filename == 'SUEWS_Veg.txt') THEN
617 IF (any(headerveg_file /= headerveg_reqd)) THEN
618 WRITE (*, *) headerveg_file == headerveg_reqd
619 CALL errorhint(56, 'Names or order of columns in SUEWS_Veg.txt does not match model code.', notused, notused, notusedi)
620 END IF
621
622 ELSEIF (filename == 'SUEWS_Water.txt') THEN
623 IF (any(headerwater_file /= headerwater_reqd)) THEN
624 WRITE (*, *) headerwater_file == headerwater_reqd
625 WRITE (*, *) headerwater_file
626 WRITE (*, *) headerwater_reqd
627 CALL errorhint(56, 'Names or order of columns in SUEWS_Water.txt does not match model code.', notused, notused, notusedi)
628 END IF
629
630 ELSEIF (filename == 'SUEWS_Snow.txt') THEN
631 IF (any(headersnow_file /= headersnow_reqd)) THEN
632 WRITE (*, *) headersnow_file == headersnow_reqd
633 CALL errorhint(56, 'Names or order of columns in SUEWS_Snow.txt does not match model code.', notused, notused, notusedi)
634 END IF
635
636 ELSEIF (filename == 'SUEWS_Soil.txt') THEN
637 IF (any(headersoil_file /= headersoil_reqd)) THEN
638 WRITE (*, *) headersoil_file == headersoil_reqd
639 CALL errorhint(56, 'Names or order of columns in SUEWS_Soil.txt does not match model code.', notused, notused, notusedi)
640 END IF
641
642 ELSEIF (filename == 'SUEWS_Conductance.txt') THEN
643 IF (any(headercond_file /= headercond_reqd)) THEN
644 WRITE (*, *) headercond_file == headercond_reqd
645 CALL errorhint(56, 'Names or order of columns in SUEWS_Cond.txt does not match model code.', notused, notused, notusedi)
646 END IF
647
648 ELSEIF (filename == 'SUEWS_OHMCoefficients.txt') THEN
651 CALL errorhint(56, 'Names or order of columns in SUEWS_OHMCoefficients.txt does not match model code.', &
653 END IF
654
655 ELSEIF (filename == 'SUEWS_ESTMCoefficients.txt') THEN
658 CALL errorhint(56, 'Names or order of columns in SUEWS_ESTMCoefficients.txt does not match model code.', &
660 END IF
661
662 ELSEIF (filename == 'SUEWS_AnthropogenicEmission.txt') THEN
665 CALL errorhint(56, 'Names or order of columns in SUEWS_AnthropogenicEmission.txt does not match model code.', &
667 END IF
668
669 ELSEIF (filename == 'SUEWS_Irrigation.txt') THEN
672 WRITE (*, *) headerirrigation_file
673 WRITE (*, *) headerirrigation_reqd
674 CALL errorhint(56, 'Names or order of columns in SUEWS_Irrigation.txt does not match model code.', &
676 END IF
677
678 ELSEIF (filename == 'SUEWS_Profiles.txt') THEN
681 CALL errorhint(56, 'Names or order of columns in SUEWS_Profiles.txt does not match model code.', &
683 END IF
684
685 ELSEIF (filename == 'SUEWS_WithinGridWaterDist.txt') THEN
688 CALL errorhint(56, 'Names or order of columns in SUEWS_WithinGridWaterDist.txt does not match model code.', &
690 END IF
691
692 ELSEIF (filename == 'SUEWS_BiogenCO2.txt') THEN
693 IF (any(headerbiogen_file /= headerbiogen_reqd)) THEN
695 CALL errorhint(56, 'Names or order of columns in SUEWS_BiogenCO2.txt does not match model code.', &
697 END IF
698
699 ELSE
700 WRITE (*, *) 'Problem in subroutine InputHeaderCheck. File header not specified in model code for ', filename
702
703 END IF
704
705END SUBROUTINE inputheadercheck
706
707!-------------------------------------------------------------------------
708!
709! TS 05 Jul 2018: No longer needed as interpolation is done through specific subroutines at each required instant
710!Interpolates hourly profiles provided in SUEWS_Profiles.txt
711! to resolution of the model timestep
712! HCW 06 Feb 2015
713!===================================================================================
714! SUBROUTINE SUEWS_InterpHourlyProfiles(Gridiv,TstepP_ID,SurfChar_HrProf)
715!
716! USE allocateArray
717! USE ColNamesInputFiles
718! USE sues_data
719!
720! IMPLICIT NONE
721!
722! INTEGER:: i,j, ii !Used to count over hours and sub-hourly timesteps
723! INTEGER:: Gridiv, TstepP_ID
724! INTEGER,DIMENSION(24):: SurfChar_HrProf
725! REAL(KIND(1d0)):: deltaProf !Change in hourly profiles per model timestep
726!
727! ! Copy value for first hour
728! TstepProfiles(Gridiv,TstepP_ID,1) = SurfaceChar(Gridiv,SurfChar_HrProf(1))
729! DO i=1,24
730! j = (i+1)
731! IF(i == 24) j = 1 !If last hour of day, loop round to first hour of day for interpolation
732! deltaProf = ((SurfaceChar(Gridiv,SurfChar_HrProf(j)) - SurfaceChar(Gridiv,SurfChar_HrProf(i))))/nsh_real
733! DO ii=1,nsh
734! IF((nsh*(i-1)+ii+1) < (23*nsh+nsh+1)) THEN
735! TstepProfiles(Gridiv,TstepP_ID,(nsh*(i-1)+ii+1)) = SurfaceChar(Gridiv,SurfChar_HrProf(i)) + deltaProf*ii
736! ENDIF
737! ENDDO
738! ENDDO
739!
740! endsubroutine SUEWS_InterpHourlyProfiles
741!===================================================================================
742
743!===================================================================================
744! get interpolated profile values at specified time
745! NO normalisation performed
746FUNCTION get_prof_spectime_inst(Hour, Min, Sec, Prof_24h) RESULT(Prof_CurrTime)
747
748 IMPLICIT NONE
749
750 INTEGER :: i, j !Used to count over hours and sub-hourly timesteps
751 INTEGER, INTENT(IN) :: hour, min, sec
752 INTEGER :: total_sec, secperhour
753 REAL(kind(1d0)), DIMENSION(0:23), INTENT(IN) :: prof_24h
754 REAL(kind(1d0)) :: deltaprof !Change in hourly profiles per model timestep
755 REAL(kind(1d0)) :: prof_currtime
756
757 total_sec = min*60 + sec
758 secperhour = 3600
759
760 i = hour
761 j = i + 1
762 IF (j == 24) j = 0
763
764 deltaprof = (prof_24h(j) - prof_24h(i))/secperhour
765 prof_currtime = prof_24h(hour) + deltaprof*total_sec
766
767END FUNCTION get_prof_spectime_inst
768
769!===================================================================================
770! get interpolated profile values at specified time
771! normalise so the AVERAGE of the multipliers is equal to 1
772FUNCTION get_prof_spectime_mean(Hour, Min, Sec, Prof_24h) RESULT(Prof_CurrTime)
773
774 IMPLICIT NONE
775
776 INTEGER :: i, j !Used to count over hours and sub-hourly timesteps
777 INTEGER, INTENT(IN) :: hour, min, sec
778 INTEGER :: total_sec, secperhour
779 REAL(kind(1d0)), DIMENSION(0:23), INTENT(IN) :: prof_24h
780 REAL(kind(1d0)), DIMENSION(0:23) :: prof_24h_mean
781 REAL(kind(1d0)) :: deltaprof !Change in hourly profiles per model timestep
782 REAL(kind(1d0)) :: prof_currtime
783
784 total_sec = min*60 + sec
785 secperhour = 3600
786
787 prof_24h_mean = merge(prof_24h/(sum(prof_24h)/SIZE(prof_24h, dim=1)), 0.d0, sum(prof_24h) /= 0) ! prevent zero-division
788 ! print*, Prof_24h_mean
789
790 i = hour
791 j = i + 1
792 IF (j == 24) j = 0
793
794 deltaprof = (prof_24h_mean(j) - prof_24h_mean(i))/secperhour
795
796 ! print*, deltaProf,total_sec
797 prof_currtime = prof_24h_mean(i) + deltaprof*total_sec
798
799END FUNCTION get_prof_spectime_mean
800
801!===================================================================================
802! get interpolated profile values at specified time
803! normalise so the SUM of the multipliers is equal to 1
804FUNCTION get_prof_spectime_sum(Hour, Min, Sec, Prof_24h, dt) RESULT(Prof_CurrTime)
805
806 IMPLICIT NONE
807
808 INTEGER :: i, j !Used to count over hours and sub-hourly timesteps
809 INTEGER, INTENT(IN) :: hour, min, sec, dt
810 INTEGER :: total_sec, secperhour
811 REAL(kind(1d0)), DIMENSION(0:23), INTENT(IN) :: prof_24h
812 REAL(kind(1d0)), DIMENSION(0:23) :: prof_24h_sum
813 REAL(kind(1d0)) :: deltaprof !Change in hourly profiles per model timestep
814 REAL(kind(1d0)) :: prof_currtime
815
816 total_sec = min*60 + sec
817 secperhour = 3600
818
819 prof_24h_sum = merge(prof_24h/(sum(prof_24h)), 0.d0, sum(prof_24h) /= 0) ! prevent zero-division
820
821 i = hour
822 j = i + 1
823 IF (j == 24) j = 0
824
825 deltaprof = (prof_24h_sum(j) - prof_24h_sum(i))/secperhour
826 prof_currtime = prof_24h_sum(hour) + deltaprof*total_sec
827 prof_currtime = prof_currtime*dt/secperhour
828
829END FUNCTION get_prof_spectime_sum
830!===================================================================================
831! TODO: #79 all the parameter tables can be stored using a custom dictionary for easier and more consistent access:
832! this package looks promising: https://github.com/zerothi/fdict
833
834! Subroutines for matching codes in the input files
835! could re-write as a generic function later...
836
837SUBROUTINE codematchohm(Gridiv, is, SWWD)
838 ! Matches OHM coefficients a1, a2, a3 via OHM codes
839 ! for summer/winter wet/dry conditions
840 ! HCW 03 Nov 2014
841 ! ---------------------------------------------------------
842
843 USE allocatearray
844 USE initial
847
848 IMPLICIT NONE
849
850 INTEGER :: gridiv
851 INTEGER :: is
852 CHARACTER(len=4) :: SWWD
853
854 iv5 = 0 ! Reset iv5 to zero
855
856 IF (swwd == 'SWet') THEN
857
860 EXIT
861 ELSEIF (iv5 == nlinesohmcoefficients) THEN
862 WRITE (*, *) 'Program stopped! OHM code (summer wet)', surfacechar(gridiv, c_ohmcode_swet(is)), &
863 'not found in OHM_Coefficients.txt for surface', is, '.'
864 CALL errorhint(57, 'Cannot find OHM code (summer wet)', surfacechar(gridiv, c_ohmcode_swet(is)), notused, notusedi)
865 END IF
866 END DO
867
868 ELSEIF (swwd == 'SDry') THEN
869
872 EXIT
873 ELSEIF (iv5 == nlinesohmcoefficients) THEN
874 WRITE (*, *) 'Program stopped! OHM code (summer dry)', surfacechar(gridiv, c_ohmcode_sdry(is)), &
875 'not found in OHM_Coefficients.txt for surface', is, '.'
876 CALL errorhint(57, 'Cannot find OHM code (summer dry)', surfacechar(gridiv, c_ohmcode_sdry(is)), notused, notusedi)
877 END IF
878 END DO
879
880 ELSEIF (swwd == 'WWet') THEN
881
884 EXIT
885 ELSEIF (iv5 == nlinesohmcoefficients) THEN
886 WRITE (*, *) 'Program stopped! OHM code (winter wet)', surfacechar(gridiv, c_ohmcode_wwet(is)), &
887 'not found in OHM_Coefficients.txt for surface', is, '.'
888 CALL errorhint(57, 'Cannot find OHM code (winter wet)', surfacechar(gridiv, c_ohmcode_wwet(is)), notused, notusedi)
889 END IF
890 END DO
891
892 ELSEIF (swwd == 'WDry') THEN
893
896 EXIT
897 ELSEIF (iv5 == nlinesohmcoefficients) THEN
898 WRITE (*, *) 'Program stopped! OHM code (winter dry)', surfacechar(gridiv, c_ohmcode_wdry(is)), &
899 'not found in OHM_Coefficients.txt for surface', is, '.'
900 CALL errorhint(57, 'Cannot find OHM code (winter dry)', surfacechar(gridiv, c_ohmcode_wdry(is)), notused, notusedi)
901 END IF
902 END DO
903
904 ELSE
905 WRITE (*, *) 'Problem with CodeMatchOHM (in SUEWS_CodeMatch.f95). ', swwd, ' not recognised. Needs to be one of: ', &
906 'SWet = Summer Wet, SDry = Summer Dry, WWet = WinterWet, WDry = Winter Dry. N.B. Case sensitive. '
907 stop
908 END IF
909
910 RETURN
911END SUBROUTINE codematchohm
912! ---------------------------------------------------------
913
914SUBROUTINE codematchestm(Gridiv, is)
915 ! Matches ESTM coefficients via ESTM code
916 ! Modified HCW 16 Jun 2016 - for SUEWS surface types
917 ! - removed summer/winter wet/dry option
918 ! S.O. 04 Feb 2016
919 ! ---------------------------------------------------------
920
921 USE allocatearray
922 USE initial
925
926 IMPLICIT NONE
927
928 INTEGER :: gridiv
929 INTEGER :: is
930
931 iv5 = 0 ! Reset iv5 to zero
932
934 IF (estmcoefficients_coeff(iv5, ce_code) == surfacechar(gridiv, c_estmcode(is))) THEN
935 EXIT
936 ELSEIF (iv5 == nlinesestmcoefficients) THEN
937 WRITE (*, *) 'Program stopped! ESTM code', surfacechar(gridiv, c_estmcode(is)), &
938 'not found in ESTM_Coefficients.txt for surface', is, '.'
939 CALL errorhint(57, 'Cannot find ESTM code', surfacechar(gridiv, c_estmcode(is)), notused, notusedi)
940 END IF
941 END DO
942
943 RETURN
944END SUBROUTINE codematchestm
945! ---------------------------------------------------------
946
947SUBROUTINE codematchestm_class(Gridiv, is, ii)
948 ! Matches ESTM coefficients via ESTM codes in SiteSelect for Paved and Bldgs ESTM classes
949 ! HCW 16 Jun 2016
950 ! ---------------------------------------------------------
951
952 USE allocatearray
953 USE initial
956
957 IMPLICIT NONE
958
959 INTEGER :: gridiv
960 INTEGER :: is, ii
961
962 iv5 = 0 ! Reset iv5 to zero
963
964 IF (is == bldgsurf) THEN
967 EXIT
968 ELSEIF (iv5 == nlinesestmcoefficients) THEN
969 WRITE (*, *) 'Program stopped! ESTM code', surfacechar(gridiv, c_code_estmclass_bldgs(ii)), &
970 'not found in ESTM_Coefficients.txt for surface', is, '.'
971 CALL errorhint(57, 'Cannot find ESTM code', surfacechar(gridiv, c_code_estmclass_bldgs(ii)), notused, notusedi)
972 END IF
973 END DO
974 ELSEIF (is == pavsurf) THEN
977 EXIT
978 ELSEIF (iv5 == nlinesestmcoefficients) THEN
979 WRITE (*, *) 'Program stopped! ESTM code', surfacechar(gridiv, c_code_estmclass_paved(ii)), &
980 'not found in ESTM_Coefficients.txt for surface', is, '.'
981 CALL errorhint(57, 'Cannot find ESTM code', surfacechar(gridiv, c_code_estmclass_paved(ii)), notused, notusedi)
982 END IF
983 END DO
984 ELSE
985 WRITE (*, *) 'Problem with CodeMatchESTM_Class (in SUEWS_ctrl_input.f95). ', is, ' not correct. Needs to be either ', &
986 '1 = Paved surfaced, 2 = Bldgs surfaces.'
987 stop
988 END IF
989 RETURN
990END SUBROUTINE codematchestm_class
991! ---------------------------------------------------------
992
993SUBROUTINE codematchprof(Gridiv, SurfaceCharCodeCol)
994 ! Matches Soil characteristics via codes in *SurfaceChar*
995 ! for energy use/water use/snow clearing
996 ! HCW 20 Nov 2014
997 ! ---------------------------------------------------------
998
999 USE allocatearray
1000 USE initial
1002 USE defaultnotused
1003
1004 IMPLICIT NONE
1005
1006 INTEGER :: Gridiv
1007 INTEGER :: SurfaceCharCodeCol
1008
1009 iv5 = 0 ! Reset iv5 to zero
1010
1011 DO iv5 = 1, nlinesprofiles
1012 IF (profiles_coeff(iv5, cpr_code) == surfacechar(gridiv, surfacecharcodecol)) THEN
1013 EXIT
1014 ELSEIF (iv5 == nlinesprofiles) THEN
1015 WRITE (*, *) 'Program stopped! Profile code ', surfacechar(gridiv, surfacecharcodecol), 'not found in SUEWS_Profiles.txt.'
1016 CALL errorhint(57, 'Cannot find code in SUEWS_Profiles.txt', surfacechar(gridiv, surfacecharcodecol), notused, notusedi)
1017 END IF
1018 END DO
1019
1020 RETURN
1021END SUBROUTINE codematchprof
1022! ---------------------------------------------------------
1023
1024SUBROUTINE codematchdist(rr, CodeCol, codeColSameSurf)
1025 ! Matches within-grid water distribution via codes
1026 ! Checks water cannot flow from one surface to the same surface
1027 ! Checks water distribution fractions sum to 1.
1028 ! HCW 10 Nov 2014
1029 ! ---------------------------------------------------------
1030
1031 USE allocatearray
1032 USE initial
1034 USE defaultnotused
1035
1036 IMPLICIT NONE
1037
1038 INTEGER :: rr
1039 INTEGER :: codeCol, codeColSameSurf
1040
1041 iv5 = 0 ! Reset iv5 to zero
1042
1043 DO iv5 = 1, nlineswgwaterdist
1044 IF (wgwaterdist_coeff(iv5, cwg_code) == siteselect(rr, codecol)) THEN
1045 EXIT
1046 ELSEIF (iv5 == nlineswgwaterdist) THEN
1047 WRITE (*, *) 'Program stopped! Within-grid water distribution code ', siteselect(rr, codecol), &
1048 'not found in SUEWS_WaterDistWithinGrid.txt.'
1049 CALL errorhint(57, 'Cannot find code in SUEWS_WaterDistWithinGrid.txt', siteselect(rr, codecol), notused, notusedi)
1050 END IF
1051 END DO
1052
1053 ! Check water flow to same surface is zero (previously in RunControlByGridByYear in SUEWS_Initial.f95)
1054 IF (wgwaterdist_coeff(iv5, codecolsamesurf) /= 0) THEN
1055 CALL errorhint(8, 'Diagonal elements should be zero as water cannot move from one surface to the same surface.', &
1056 wgwaterdist_coeff(iv5, codecolsamesurf), notused, notusedi)
1057 END IF
1058
1059 !! QUESTION: MODIFY THIS?
1060 ! Check water either moves to runoff or soilstore, but not to both
1061 ! Model returns an error if both ToRunoff and ToSoilStore are non-zero.
1062 !! - Probably should remove this...
1063 !! - Also look at SUEWS_translate, as the non-zero value goes into WaterDist
1065 CALL errorhint(9, 'One of these (ToRunoff,ToSoilStore) should be zero.', &
1067 END IF
1068
1069 !! Also do for water surface once implemented
1070 IF (codecol /= c_wgwatercode) THEN ! Except for Water surface
1071 ! Check total water distribution from each surface adds up to 1
1072 IF (sum(wgwaterdist_coeff(iv5, cwg_topaved:cwg_tosoilstore)) > 1.0000001 &
1073 .OR. sum(wgwaterdist_coeff(iv5, cwg_topaved:cwg_tosoilstore)) < 0.9999999) THEN
1074 CALL errorhint(8, 'Total water distribution from each surface should add up to 1.', &
1076 END IF
1077 END IF
1078
1079 RETURN
1080END SUBROUTINE codematchdist
1081! ---------------------------------------------------------
1082
1083SUBROUTINE codematchnonveg(rr, CodeCol)
1084 ! Matches Impervious characteristics via codes in SiteSelect
1085 ! HCW 20 Nov 2014
1086 ! ---------------------------------------------------------
1087
1088 USE allocatearray
1089 USE initial
1091 USE defaultnotused
1092
1093 IMPLICIT NONE
1094
1095 INTEGER :: rr
1096 INTEGER :: codeCol
1097
1098 iv5 = 0 ! Reset iv5 to zero
1099
1100 DO iv5 = 1, nlinesnonveg
1101 IF (nonveg_coeff(iv5, ci_code) == siteselect(rr, codecol)) THEN
1102 EXIT
1103 ELSEIF (iv5 == nlinesnonveg) THEN
1104 WRITE (*, *) 'Program stopped! NonVeg code ', siteselect(rr, codecol), 'not found in SUEWS_NonVeg.txt.'
1105 CALL errorhint(57, 'Cannot find code in SUEWS_NonVeg.txt', siteselect(rr, codecol), notused, notusedi)
1106 END IF
1107 END DO
1108
1109 RETURN
1110END SUBROUTINE codematchnonveg
1111! ---------------------------------------------------------
1112
1113SUBROUTINE codematchveg(rr, CodeCol)
1114 ! Matches Pervious characteristics via codes in SiteSelect
1115 ! HCW 20 Nov 2014
1116 ! ---------------------------------------------------------
1117
1118 USE allocatearray
1119 USE initial
1121 USE defaultnotused
1122
1123 IMPLICIT NONE
1124
1125 INTEGER :: rr
1126 INTEGER :: codeCol
1127
1128 iv5 = 0 ! Reset iv5 to zero
1129
1130 DO iv5 = 1, nlinesveg
1131 IF (veg_coeff(iv5, cp_code) == siteselect(rr, codecol)) THEN
1132 EXIT
1133 ELSEIF (iv5 == nlinesveg) THEN
1134 WRITE (*, *) 'Program stopped! Veg code ', siteselect(rr, codecol), 'not found in SUEWS_Vegs.txt.'
1135 CALL errorhint(57, 'Cannot find code in SUEWS_Veg.txt', siteselect(rr, codecol), notused, notusedi)
1136 END IF
1137 END DO
1138
1139 RETURN
1140END SUBROUTINE codematchveg
1141! ---------------------------------------------------------
1142
1143SUBROUTINE codematchwater(rr, CodeCol)
1144 ! Matches Water characteristics via codes in SiteSelect
1145 ! HCW 20 Nov 2014
1146 ! ---------------------------------------------------------
1147
1148 USE allocatearray
1149 USE initial
1151 USE defaultnotused
1152
1153 IMPLICIT NONE
1154
1155 INTEGER :: rr
1156 INTEGER :: codeCol
1157
1158 iv5 = 0 ! Reset iv5 to zero
1159
1160 DO iv5 = 1, nlineswater
1161 IF (water_coeff(iv5, cw_code) == siteselect(rr, codecol)) THEN
1162 EXIT
1163 ELSEIF (iv5 == nlineswater) THEN
1164 WRITE (*, *) 'Program stopped! Water code ', siteselect(rr, codecol), 'not found in SUEWS_Water.txt.'
1165 CALL errorhint(57, 'Cannot find code in SUEWS_Water.txt', siteselect(rr, codecol), notused, notusedi)
1166 END IF
1167 END DO
1168
1169 RETURN
1170END SUBROUTINE codematchwater
1171! ---------------------------------------------------------
1172
1173SUBROUTINE codematchsnow(rr, CodeCol)
1174 ! Matches Snow characteristics via codes in SiteSelect
1175 ! HCW 20 Nov 2014
1176 ! ---------------------------------------------------------
1177
1178 USE allocatearray
1179 USE initial
1181 USE defaultnotused
1182
1183 IMPLICIT NONE
1184
1185 INTEGER :: rr
1186 INTEGER :: codeCol
1187
1188 iv5 = 0 ! Reset iv5 to zero
1189
1190 DO iv5 = 1, nlinessnow
1191 IF (snow_coeff(iv5, cs_code) == siteselect(rr, codecol)) THEN
1192 EXIT
1193 ELSEIF (iv5 == nlinessnow) THEN
1194 WRITE (*, *) 'Program stopped! Snow code ', siteselect(rr, codecol), 'not found in SUEWS_Snow.txt.'
1195 CALL errorhint(57, 'Cannot find code in SUEWS_Snow.txt', siteselect(rr, codecol), notused, notusedi)
1196 END IF
1197 END DO
1198
1199 RETURN
1200END SUBROUTINE codematchsnow
1201! ---------------------------------------------------------
1202
1203SUBROUTINE codematchconductance(rr, CodeCol)
1204 ! Matches Conductance characteristics via codes in SiteSelect
1205 ! HCW 20 Nov 2014
1206 ! ---------------------------------------------------------
1207
1208 USE allocatearray
1209 USE initial
1211 USE defaultnotused
1212
1213 IMPLICIT NONE
1214
1215 INTEGER :: rr
1216 INTEGER :: codeCol
1217
1218 iv5 = 0 ! Reset iv5 to zero
1219
1220 DO iv5 = 1, nlinesconductance
1221 IF (conductance_coeff(iv5, cc_code) == siteselect(rr, codecol)) THEN
1222 EXIT
1223 ELSEIF (iv5 == nlinesconductance) THEN
1224 WRITE (*, *) 'Program stopped! Conductance code ', siteselect(rr, codecol), 'not found in SUEWS_Conductance.txt.'
1225 CALL errorhint(57, 'Cannot find code in SUEWS_Conductance.txt', siteselect(rr, codecol), notused, notusedi)
1226 END IF
1227 END DO
1228
1229 RETURN
1230END SUBROUTINE codematchconductance
1231! ---------------------------------------------------------
1232
1233SUBROUTINE codematchanthropogenic(rr, CodeCol)
1234 ! Matches AnthropogenicHeat characteristics via codes in SiteSelect
1235 ! HCW 20 Nov 2014
1236 ! MH 21 Jun 2017
1237 ! ---------------------------------------------------------
1238
1239 USE allocatearray
1240 USE initial
1242 USE defaultnotused
1243
1244 IMPLICIT NONE
1245
1246 INTEGER :: rr
1247 INTEGER :: codeCol
1248
1249 iv5 = 0 ! Reset iv5 to zero
1250
1251 DO iv5 = 1, nlinesanthropogenic
1252 IF (anthropogenic_coeff(iv5, ca_code) == siteselect(rr, codecol)) THEN
1253 EXIT
1254 ELSEIF (iv5 == nlinesanthropogenic) THEN
1255 WRITE (*, *) 'Program stopped! Anthropogenic code ', siteselect(rr, codecol), &
1256 'not found in SUEWS_AnthropogenicEmission.txt.'
1257 CALL errorhint(57, 'Cannot find code in SUEWS_AnthropogenicEmission.txt', &
1258 siteselect(rr, codecol), notused, notusedi)
1259 END IF
1260 END DO
1261
1262 RETURN
1263END SUBROUTINE codematchanthropogenic
1264! ---------------------------------------------------------
1265
1266SUBROUTINE codematchirrigation(rr, CodeCol)
1267 ! Matches Irrigation characteristics via codes in SiteSelect
1268 ! HCW 20 Nov 2014
1269 ! ---------------------------------------------------------
1270
1271 USE allocatearray
1272 USE initial
1274 USE defaultnotused
1275
1276 IMPLICIT NONE
1277
1278 INTEGER :: rr
1279 INTEGER :: codeCol
1280
1281 iv5 = 0 ! Reset iv5 to zero
1282
1283 DO iv5 = 1, nlinesirrigation
1284 IF (irrigation_coeff(iv5, cir_code) == siteselect(rr, codecol)) THEN
1285 EXIT
1286 ELSEIF (iv5 == nlinesirrigation) THEN
1287 WRITE (*, *) 'Program stopped! Irrigation code ', siteselect(rr, codecol), 'not found in SUEWS_Irrigation.txt.'
1288 CALL errorhint(57, 'Cannot find code in SUEWS_Irrigation.txt', siteselect(rr, codecol), notused, notusedi)
1289 END IF
1290 END DO
1291
1292 RETURN
1293END SUBROUTINE codematchirrigation
1294! ---------------------------------------------------------
1295
1296SUBROUTINE codematchsoil(Gridiv, SurfaceCharCodeCol)
1297 ! Matches Soil characteristics via codes in *SurfaceChar*
1298 ! HCW 20 Nov 2014
1299 ! ---------------------------------------------------------
1300
1301 USE allocatearray
1302 USE initial
1304 USE defaultnotused
1305
1306 IMPLICIT NONE
1307
1308 INTEGER :: Gridiv
1309 INTEGER :: SurfaceCharCodeCol
1310
1311 iv5 = 0 ! Reset iv5 to zero
1312
1313 DO iv5 = 1, nlinessoil
1314 IF (soil_coeff(iv5, cso_code) == surfacechar(gridiv, surfacecharcodecol)) THEN
1315 EXIT
1316 ELSEIF (iv5 == nlinessoil) THEN
1317 WRITE (*, *) 'Program stopped! Soil code ', surfacechar(gridiv, surfacecharcodecol), 'not found in SUEWS_Soil.txt.'
1318 CALL errorhint(57, 'Cannot find code in SUEWS_Soil.txt', surfacechar(gridiv, surfacecharcodecol), notused, notusedi)
1319 END IF
1320 END DO
1321
1322 RETURN
1323END SUBROUTINE codematchsoil
1324! ---------------------------------------------------------
1325
1326SUBROUTINE codematchbiogen(Gridiv, SurfaceCharCodeCol)
1327 ! Matches Biogen characteristics via codes in *SuraceChar*
1328 ! MH 16 Jun 2017
1329 ! ---------------------------------------------------------
1330
1331 USE allocatearray
1332 USE initial
1334 USE defaultnotused
1335
1336 IMPLICIT NONE
1337
1338 INTEGER :: Gridiv
1339 INTEGER :: SurfaceCharCodeCol
1340
1341 iv5 = 0 ! Reset iv5 to zero
1342
1343 DO iv5 = 1, nlinesbiogen
1344 IF (biogen_coeff(iv5, cb_code) == surfacechar(gridiv, surfacecharcodecol)) THEN
1345 EXIT
1346 ELSEIF (iv5 == nlinesbiogen) THEN
1347 WRITE (*, *) 'Program stopped! Biogen code ', surfacechar(gridiv, surfacecharcodecol), 'not found in SUEWS_BiogenCO2.txt.'
1348 CALL errorhint(57, 'Cannot find code in SUEWS_BiogenCO2.txt', surfacechar(gridiv, surfacecharcodecol), notused, notusedi)
1349 END IF
1350 END DO
1351
1352 RETURN
1353END SUBROUTINE codematchbiogen
1354! ---------------------------------------------------------
1355
1357 !========================================================================================
1358 ! Disaggregation of meteorological forcing data
1359 ! Code to disaggregate met forcing data from resolution provided to the model time-step
1360 ! Created: HCW 10 Feb 2017
1361 !
1362 ! ---- Key for MetDisaggMethod settings ----
1363 !10 -> linear disaggregation for timestamps representing the end of the averaging period
1364 !20 -> linear disaggregation for instantaneous variables (e.g. air temperature, humidity, pressure, wind speed in WFDEI dataset)
1365 !100 -> evenly distribute rainfall among all subintervals in a rainy interval
1366 !101 -> evenly distribute rainfall among RainAmongN subintervals in a rainy interval
1367 ! - requires RainAmongN to be set in RunControl.nml
1368 ! If KdownZen = 1 -> include additional zenith check in kdown disaggregation
1369 !
1370 ! N.B. wdir downscaling is currently not implemented
1371 !
1372 !========================================================================================
1373
1374 USE allocatearray
1376 USE data_in
1377 USE initial
1379
1380 IMPLICIT NONE
1381
1382CONTAINS
1383
1384 !======================================================================================
1385 SUBROUTINE disaggregatemet(iBlock, igrid)
1386 ! Subroutine to disaggregate met forcing data to model time-step
1387 ! HCW 10 Feb 2017
1388 !======================================================================================
1389
1390 USE sues_data
1391 USE defaultnotused
1392
1393 IMPLICIT NONE
1394
1395 INTEGER :: lunit = 100
1396 INTEGER :: tdiff !Time difference (in minutes) between first and second rows of original met forcing file
1397 INTEGER :: i, ii !counter
1398 INTEGER :: iBlock, igrid
1399 INTEGER, DIMENSION(NperTstepIn) :: seq1Nper
1400 INTEGER, DIMENSION(nsd) :: seq1nsd
1401 INTEGER, DIMENSION(nColumnsMetForcingData) :: MetDisaggMethod ! Stores method to use for disaggregating met data
1402 REAL(KIND(1D0)), DIMENSION(nColumnsMetForcingData) :: MetArrayOrig
1403 REAL(KIND(1D0)), DIMENSION(ReadLinesOrigMetData*NperTstepIn, ncolumnsMetForcingData) :: Met_tt
1404 REAL(KIND(1D0)), DIMENSION(ReadLinesOrigMetData*NperTstepIn) :: Met_tt_kdownAdj
1405 CHARACTER(LEN=9), DIMENSION(ncolumnsMetForcingData) :: HeaderMet
1406 CHARACTER(LEN=10*ncolumnsMetForcingData) :: HeaderMetOut
1407 ! REAL(KIND(1d0)),DIMENSION(ReadLinesOrigMetData):: dectimeOrig
1408 ! REAL(KIND(1d0)),DIMENSION(ReadLinesOrigMetData*Nper):: dectimeDscd, dectimeFast
1409 REAL(KIND(1D0)), DIMENSION(ReadLinesOrigMetData*NperTstepIn) :: dectimeFast
1410 REAL(KIND(1D0)), DIMENSION(ReadLinesOrigMetData*NperTstepIn) :: idectime ! sun position at middle of time-step before
1411
1412 ! INTEGER, DIMENSION(Nper):: temp_iy, temp_id, temp_ih, temp_im, temp_ihm ! temorary varaibles for disaggragation
1413 ! REAL(KIND(1d0)), DIMENSION(Nper):: temp_dectime ! temorary varaibles for disaggragation
1414 ! INTEGER :: Days_of_Year
1415 ! INTEGER, DIMENSION(Nper)::ndays_iy ! number of days in iy
1416
1417 ! Allocate and initialise arrays to receive original forcing data --------------------
1421 metfordisagg(:, :) = -999
1422 metfordisaggprev(:) = -999
1423 metfordisaggnext(:) = -999
1424 ! Initialise array to receive disaggregated data
1425 met_tt = -999
1426 ! Intialise disaggregation method
1427 metdisaggmethod = -999
1428
1429 ! Generate useful sequences
1430 seq1nper = (/(i, i=1, npertstepin, 1)/)
1431 seq1nsd = (/(i, i=1, nsd, 1)/)
1432
1433 ! Get methods to use for disaggregation from RunControl
1434 IF (diagnosedisagg == 1) WRITE (*, *) 'DisaggMethod: ', disaggmethod, 'RainDisaggMethod:', raindisaggmethod
1435 IF (disaggmethod == 1) THEN
1436 metdisaggmethod(:) = 10 !linear disaggregation of averages
1437 ELSEIF (disaggmethod == 2) THEN
1438 metdisaggmethod(:) = 20 !linear disaggregation of instantaneous values
1439 ELSEIF (disaggmethod == 3) THEN !WFDEI set up, where T, Q, pres, U are instantaneous
1440 metdisaggmethod(:) = 10 !linear disaggregation of averages
1441 metdisaggmethod(10:13) = 20 !linear disagg instantaneous values for U, RH, Tair, pres
1442 ELSE
1443 CALL errorhint(2, 'Problem in SUEWS_MetDisagg: DisaggMethod value should be 1, 2, or 3', &
1445 END IF
1446 ! Set rainfall
1447 metdisaggmethod(14) = raindisaggmethod
1448
1449 ! Read data ---------------------------------------------------------------------
1450 IF (diagnosedisagg == 1) WRITE (*, *) 'Reading file: ', trim(fileorigmet)
1451 OPEN (lunit, file=trim(fileorigmet), status='old')
1452 ! CALL skipHeader(lunit,SkipHeaderMet) !Skip header -> read header instead
1453 READ (lunit, *) headermet
1454 !write(*,*) HeaderMet
1455 ! Skip over lines that have already been read and downscaled
1456 IF (skippedlinesorig > 0) THEN
1457 DO i = 1, skippedlinesorig - 1 ! minus 1 here because last line of last block needs to be read again
1458 READ (lunit, *)
1459 END DO
1460 ! Read in last line of previous block
1461 CALL metread(lunit, metarrayorig, inputmetformat, ldown_option, netradiationmethod, &
1464 END IF
1465 ! print*, 'MetForDisagg',MetForDisagg(1:3,1:4)
1466 ! print*, 'ReadLinesOrigMetDataMax',ReadLinesOrigMetDataMax
1467 ! Read in current block
1468 DO i = 1, readlinesorigmetdatamax
1469 CALL metread(lunit, metarrayorig, inputmetformat, ldown_option, netradiationmethod, &
1471 metfordisagg(i, 1:ncolumnsmetforcingdata) = metarrayorig
1472 END DO
1473 ! print*, 'MetForDisagg',MetForDisagg(1:3,1:4)
1474 ! Read in first line of next block (except for last block)
1475 IF (iblock /= readblocksorigmetdata) THEN
1476 CALL metread(lunit, metarrayorig, inputmetformat, ldown_option, netradiationmethod, &
1479 END IF
1480 CLOSE (lunit)
1481
1482 ! Check resolution of original met forcing data -------------------------------------
1483 ! Find time difference (in minutes) between first and second row
1484 tdiff = int(metfordisagg(2, 4) - metfordisagg(1, 4)) !Try using minutes
1485 IF (tdiff == 0) tdiff = int(metfordisagg(2, 3) - metfordisagg(1, 3))*60 !If no difference in minutes, try using hours
1486 IF (tdiff < 0) THEN !If time difference is negative (e.g. change of day), instead use second and third row
1487 tdiff = int(metfordisagg(3, 4) - metfordisagg(2, 4))
1488 IF (tdiff == 0) tdiff = int(metfordisagg(3, 3) - metfordisagg(2, 3))*60 !If no difference in minutes, try using hours
1489 END IF
1490 ! Check actual resolution matches specified input resolution
1491 IF (tdiff /= resolutionfilesin/60) THEN
1492 CALL errorhint(2, 'Problem in SUEWS_MetDisagg: timestamps in met forcing file inconsistent with ResolutionFilesIn', &
1493 REAL(ResolutionFilesIn, KIND(1D0)), NotUsed, tdiff*60)
1494 END IF
1495
1496 ! Check file only contains a single year --------------------------------------------
1497 ! Very last data point is allowed to be (should be) timestamped with following year
1498 IF (any(metfordisagg(1:(readlinesorigmetdatamax - 1), 1) /= metfordisagg(1, 1))) THEN
1499 CALL errorhint(3, 'Problem in SUEWS_MetDisagg: multiple years found in original met forcing file.', &
1500 metfordisagg(1, 1), notused, notusedi)
1501 END IF
1502
1503 ! Disaggregate time columns ---------------------------------------------------------
1504 IF (diagnose == 1) WRITE (*, *) 'Disaggregating met forcing data (', trim(fileorigmet), ') to model time-step...'
1505
1507
1508 ! Disaggregate other columns --------------------------------------------------------
1509 DO ii = 5, ncolumnsmetforcingdata
1510 IF (ii == 14) THEN !Do something different for rainfall and snowfall (if present)
1511 IF (metdisaggmethod(14) == 100) THEN
1512 met_tt(:, 14) = disaggp_amongn(metfordisagg(:, 14), &
1514 IF (all(metfordisagg(:, 16) == -999)) THEN
1515 met_tt(:, 16) = -999
1516 ELSE
1517 met_tt(:, 16) = disaggp_amongn(metfordisagg(:, 16), &
1519 END IF
1520 ELSEIF (metdisaggmethod(14) == 101) THEN
1521 IF (rainamongn == -999) THEN
1522 CALL errorhint(2, 'Problem in SUEWS_MetDisagg: RainDisaggMethod requires RainAmongN', &
1523 REAL(RainAmongN, KIND(1D0)), NotUsed, RainDisaggMethod)
1524 ELSEIF (rainamongn > npertstepin) THEN
1525 CALL errorhint(2, 'Problem in SUEWS_MetDisagg: RainAmongN > Nper', &
1526 REAL(NperTstepIn, KIND(1D0)), NotUsed, RainAmongN)
1527 ELSE
1528 met_tt(:, 14) = disaggp_amongn(metfordisagg(:, 14), &
1529 rainamongn, npertstepin, readlinesorigmetdata, readlinesorigmetdatamax)
1530 IF (all(metfordisagg(:, 16) == -999)) THEN
1531 met_tt(:, 16) = -999
1532 ELSE
1533 met_tt(:, 16) = disaggp_amongn(metfordisagg(:, 16), &
1534 rainamongn, npertstepin, readlinesorigmetdata, readlinesorigmetdatamax)
1535 END IF
1536 END IF
1537 ELSEIF (metdisaggmethod(14) == 102) THEN
1538 IF (all(multrainamongn == -999)) THEN
1539 CALL errorhint(2, 'Problem in SUEWS_MetDisagg: RainDisaggMethod requires MultRainAmongN', &
1540 REAL(MultRainAmongN(1), KIND(1D0)), NotUsed, RainDisaggMethod)
1541 ELSEIF (all(multrainamongnupperi == -999)) THEN
1542 CALL errorhint(2, 'Problem in SUEWS_MetDisagg: RainDisaggMethod requires MultRainAmongNUpperI', &
1543 multrainamongnupperi(1), notused, raindisaggmethod)
1544 ELSEIF (any(multrainamongn > npertstepin)) THEN
1545 CALL errorhint(2, 'Problem in SUEWS_MetDisagg: MultRainAmongN > Nper', real(npertstepin, kind(1d0)), notused, &
1546 maxval(multrainamongn))
1547 ELSE
1548 met_tt(:, 14) = disaggp_amongnmult(metfordisagg(:, 14), multrainamongnupperi, multrainamongn, npertstepin, &
1550 IF (all(metfordisagg(:, 16) == -999)) THEN
1551 met_tt(:, 16) = -999
1552 ELSE
1553 met_tt(:, 16) = disaggp_amongnmult(metfordisagg(:, 16), multrainamongnupperi, multrainamongn, npertstepin, &
1555 END IF
1556 END IF
1557 ELSE
1558 WRITE (*, *) 'Disaggregation code for rain not recognised'
1559 END IF
1560 ELSEIF (ii == 24) THEN !wind direction disaggregation not coded yet...
1561 IF (any(metfordisagg(:, ii) /= -999)) THEN
1562 WRITE (*, *) 'Disaggregation of wind direction not currently implemented!'
1563 END IF
1564 ELSE
1565 IF (all(metfordisagg(:, ii) == -999)) THEN
1566 !IF(DiagnoseDisagg==1) write(*,*) 'No data for col.', ii
1567 met_tt(:, ii) = -999
1568 ELSE
1569 met_tt(:, ii) = disagg_lin(metfordisagg(:, ii), metfordisaggprev(ii), metfordisaggnext(ii), metdisaggmethod(ii), &
1570 npertstepin, readlinesorigmetdata, readlinesorigmetdatamax, iblock)
1571 END IF
1572 END IF
1573 END DO
1574
1575 ! Adjust kdown disaggregation using zenith angle
1576 IF (kdownzen == 1) THEN
1577 IF (diagnosedisagg == 1) WRITE (*, *) 'Adjusting disaggregated kdown using zenith angle'
1578 met_tt_kdownadj(:) = met_tt(:, 15)
1579 ! Translate location data from SurfaceChar to find solar angles
1580 lat = surfacechar(igrid, c_lat)
1581 lng = surfacechar(igrid, c_lng)
1582 timezone = surfacechar(igrid, c_tz)
1583 alt = surfacechar(igrid, c_alt)
1584 ! Calculate dectime at downscaled time-step
1585 dectimefast(:) = met_tt(:, 2) + met_tt(:, 3)/24.0 + met_tt(:, 4)/(60.0*24.0)
1586 idectime = dectimefast - halftimestep ! sun position at middle of timestep before
1587 DO i = 1, (readlinesorigmetdatamax*npertstepin)
1588 CALL narp_cal_sunposition(met_tt(i, 2), idectime(i), timezone, lat, lng, alt, azimuth, zenith_deg)
1589 ! If sun below horizon, set disaggregated kdown to zero
1590 IF (zenith_deg > 90) THEN
1591 !write(*,*) Met_tt(i,1:4)
1592 met_tt_kdownadj(i) = 0.0
1593 END IF
1594 END DO
1595 ! Redistribute kdown over each day
1596 DO i = 1, (readlinesorigmetdatamax*npertstepin/nsd) ! Loop over each day
1597 met_tt_kdownadj((i - 1)*nsd + seq1nsd) = &
1598 met_tt_kdownadj((i - 1)*nsd + seq1nsd) &
1599 *sum(met_tt((i - 1)*nsd + seq1nsd, 15)) &
1600 /sum(met_tt_kdownadj((i - 1)*nsd + seq1nsd))
1601 END DO
1602 ! Copy adjusted kdown back to Met_tt array
1603 met_tt(:, 15) = met_tt_kdownadj(:)
1604 END IF
1605
1606 ! Copy disaggregated data to MetForcingDataArray
1607 metforcingdata(:, 1:24, gridcounter) = met_tt(:, 1:24)
1608
1609 ! If snow is -999, set to zero (also in LUMPS_metRead.f95)
1610 IF (all(metforcingdata(:, 16, gridcounter) == -999)) metforcingdata(:, 16, gridcounter) = 0
1611
1612 ! Undo pressure conversion again for writing out
1613 met_tt(:, 13) = met_tt(:, 13)/10.0
1614
1615 ! Write out disaggregated file ------------------------------------------------------
1616 IF (keeptstepfilesin == 1) THEN
1617 IF (iblock == 1) THEN
1618 ! Prepare header
1619 DO i = 1, ncolumnsmetforcingdata
1620 IF (i == 1) THEN
1621 headermetout = adjustl(headermet(i))
1622 ELSE
1623 headermetout = trim(headermetout)//' '//adjustl(headermet(i))
1624 END IF
1625 END DO
1626 ! Write out header
1627 OPEN (78, file=trim(filedscdmet), err=112)
1628 WRITE (78, '(a)') headermetout
1629 ELSE
1630 OPEN (78, file=trim(filedscdmet), position='append') !,err=112)
1631 END IF
1632 ! Write out data
1633 DO i = 1, (readlinesorigmetdatamax*npertstepin)
1634 WRITE (78, 303) (int(met_tt(i, ii)), ii=1, 4), met_tt(i, 5:ncolumnsmetforcingdata)
1635 END DO
1636 !IF(iBlock == ReadBlocksOrigMetData) THEN
1637 ! WRITE(78,'(i2)') -9
1638 ! WRITE(78,'(i2)') -9
1639 !ENDIF
1640 CLOSE (78) !Close output file
1641 END IF
1642
1643303 FORMAT((i4, 1x), 3(i3, 1x), 9(f12.6, 1x), (f9.4, 1x), 10(f9.4, 1x)) !Allows 4 dp for rainfall
1644
1645 ! Deallocate arrays -----------------------------------------------------------------
1646 DEALLOCATE (metfordisagg)
1647 DEALLOCATE (metfordisaggprev)
1648 DEALLOCATE (metfordisaggnext)
1649
1650 RETURN
1651
1652112 CALL errorhint(52, trim(filedscdmet), notused, notused, notusedi)
1653
1654 END SUBROUTINE disaggregatemet
1655 !======================================================================================
1656
1657 !======================================================================================
1658 SUBROUTINE disaggregateestm(iBlock)
1659 ! Subroutine to disaggregate met forcing data to model time-step
1660 ! HCW 10 Feb 2017
1661 !======================================================================================
1662
1663 USE sues_data
1664 USE defaultnotused
1665
1666 IMPLICIT NONE
1667
1668 INTEGER :: lunit = 101
1669 INTEGER :: tdiff !Time difference (in minutes) between first and second rows of original met forcing file
1670 INTEGER :: i, ii !counter
1671 INTEGER :: iBlock
1672 INTEGER, DIMENSION(NperESTM) :: seq1NperESTM
1673 INTEGER, DIMENSION(nsd) :: seq1nsd
1674 INTEGER, DIMENSION(ncolsESTMdata) :: ESTMDisaggMethod ! Stores method to use for disaggregating met data
1675 REAL(KIND(1D0)), DIMENSION(ncolsESTMdata) :: ESTMArrayOrig
1676 REAL(KIND(1D0)), DIMENSION(ReadLinesOrigESTMData*NperESTM, ncolsESTMdata) :: ESTM_tt
1677 CHARACTER(LEN=9), DIMENSION(ncolsESTMdata) :: HeaderESTM
1678 CHARACTER(LEN=10*ncolsESTMdata) :: HeaderESTMOut
1679 ! REAL(KIND(1d0)),DIMENSION(ReadLinesOrigESTMData):: dectimeOrig
1680 ! REAL(KIND(1d0)),DIMENSION(ReadLinesOrigESTMData*NperESTM):: dectimeDscd
1681 INTEGER :: iostat_var
1682
1683 ! INTEGER, DIMENSION(NperESTM):: temp_iy, temp_id, temp_ih, temp_im, temp_ihm
1684
1685 ! Allocate and initialise arrays to receive original forcing data --------------------
1689 estmfordisagg(:, :) = -999
1690 estmfordisaggprev(:) = -999
1691 estmfordisaggnext(:) = -999
1692 ! Initialise array to receive disaggregated data
1693 estm_tt = -999
1694 ! Intialise disaggregation method
1695 estmdisaggmethod = -999
1696
1697 ! Generate useful sequences
1698 seq1nperestm = (/(i, i=1, nperestm, 1)/)
1699 seq1nsd = (/(i, i=1, nsd, 1)/)
1700
1701 ! Get methods to use for disaggregation from RunControl
1702 ! (N.B.DisaggMethodESTM is set as 1 or 2 in RunControl; ESTMDisaggMethod is array of ncolsESTMdata used here)
1703 IF (disaggmethodestm == 1) THEN
1704 estmdisaggmethod(:) = 10 !linear disaggregation of averages
1705 ELSEIF (disaggmethodestm == 2) THEN
1706 estmdisaggmethod(:) = 20 !linear disaggregation of instantaneous values
1707 ELSE
1708 CALL errorhint(2, 'Problem in SUEWS_ESTMDisagg: DisaggMethodESTM value should be 1 or 2', &
1710 END IF
1711
1712 ! Read data ---------------------------------------------------------------------
1713 IF (diagnosedisaggestm == 1) WRITE (*, *) 'Reading file: ', trim(fileorigestm)
1714 OPEN (lunit, file=trim(fileorigestm), status='old')
1715 ! CALL skipHeader(lunit,SkipHeaderMet) !Skip header -> read header instead
1716 READ (lunit, *) headerestm
1717 !write(*,*) HeaderMet
1718 ! Skip over lines that have already been read and downscaled
1719 IF (skippedlinesorigestm > 0) THEN
1720 DO i = 1, skippedlinesorigestm - 1 ! minus 1 here because last line of last block needs to be read again
1721 READ (lunit, *)
1722 END DO
1723 ! Read in last line of previous block
1724 READ (lunit, *, iostat=iostat_var) estmarrayorig
1725 estmfordisaggprev(1:ncolsestmdata) = estmarrayorig
1726 END IF
1727 ! Read in current block
1728 DO i = 1, readlinesorigestmdatamax
1729 READ (lunit, *, iostat=iostat_var) estmarrayorig
1730 estmfordisagg(i, 1:ncolsestmdata) = estmarrayorig
1731 END DO
1732 ! Read in first line of next block (except for last block)
1733 IF (iblock /= readblocksorigmetdata) THEN
1734 READ (lunit, *, iostat=iostat_var) estmarrayorig
1735 estmfordisaggnext(1:ncolsestmdata) = estmarrayorig
1736 END IF
1737 CLOSE (lunit)
1738
1739 ! Check resolution of original met forcing data -------------------------------------
1740 ! Find time difference (in minutes) between first and second row
1741 tdiff = int(estmfordisagg(2, 4) - estmfordisagg(1, 4)) !Try using minutes
1742 IF (tdiff == 0) tdiff = int(estmfordisagg(2, 3) - estmfordisagg(1, 3))*60 !If no difference in minutes, try using hours
1743 IF (tdiff < 0) THEN !If time difference is negative (e.g. change of day), instead use second and third row
1744 tdiff = int(estmfordisagg(3, 4) - estmfordisagg(2, 4))
1745 IF (tdiff == 0) tdiff = int(estmfordisagg(3, 3) - estmfordisagg(2, 3))*60 !If no difference in minutes, try using hours
1746 END IF
1747 ! Check actual resolution matches specified input resolution
1748 IF (tdiff /= resolutionfilesinestm/60) THEN
1749 CALL errorhint(2, 'Problem in SUEWS_ESTMDisagg: timestamps in ESTM forcing file inconsistent with ResolutionFilesInESTM', &
1750 REAL(ResolutionFilesInESTM, KIND(1D0)), NotUsed, tdiff*60)
1751 END IF
1752
1753 ! Disaggregate time columns ---------------------------------------------------------
1754 IF (diagnose == 1) THEN
1755 WRITE (*, *) 'Disaggregating ESTM forcing data (', trim(fileorigestm), ') to model time-step...'
1756 END IF
1758 ! ! Convert to dectime
1759 ! dectimeOrig = ESTMForDisagg(:,2) + ESTMForDisagg(:,3)/24.0 + ESTMForDisagg(:,4)/(60.0*24.0)
1760 !
1761 ! DO i=1,ReadLinesOrigESTMDataMax
1762 ! ! Downscale dectime using dectimeOrig(i) [becomes timestamp of last subinterval]
1763 ! dectimeDscd(NperESTM*(i-1)+Seq1NperESTM) = dectimeOrig(i) - (tstep/60.0)/(60.0*24.0)*(/(ii, ii=(NperESTM-1),0, -1)/)
1764 ! ! Convert to required formats
1765 ! temp_iy = INT(ESTMForDisagg(i,1)) !Copy year
1766 ! temp_id = FLOOR(dectimeDscd(NperESTM*(i-1)+Seq1NperESTM)) !DOY
1767 ! ! To avoid precision errors, round here
1768 ! ! - this should not be a problem as a difference of 1 = 1 min, so a difference of 0.001 << 1 min
1769 ! temp_ihm = NINT(((dectimeDscd(NperESTM*(i-1)+Seq1NperESTM) - temp_id/1.0)*60.0*24.0)*1000.0)/1000 !Minutes of the day (1440 max)
1770 ! temp_ih = (temp_ihm-MOD(temp_ihm,60))/60 !Hours
1771 ! temp_im = MOD(temp_ihm,60) !Minutes
1772 !
1773 ! IF(dectimeOrig(i) == 1.0000 .AND. i > 1) THEN !If year changes and it is not the beginning of the dataset
1774 ! WRITE(*,*) 'Year change encountered: ', dectimeOrig(i), dectimeOrig(i-1)
1775 ! ! Re-downscale dectime using dectimeOrig(i-1)
1776 ! dectimeDscd(NperESTM*(i-1)+Seq1NperESTM) = dectimeOrig(i-1) + (tstep/60.0)/(60.0*24.0)*Seq1NperESTM
1777 ! ! Convert to required formats
1778 ! temp_iy = INT(ESTMForDisagg(i,1)) !Copy year
1779 ! temp_id = FLOOR(dectimeDscd(NperESTM*(i-1)+Seq1NperESTM)) !DOY
1780 ! temp_ihm = NINT(((dectimeDscd(NperESTM*(i-1)+Seq1NperESTM) - temp_id/1.0)*60.0*24.0)*1000.0)/1000 !Mins of the day (1440 max)
1781 ! temp_ih = (temp_ihm-MOD(temp_ihm,60))/60 !Hours
1782 ! temp_im = MOD(temp_ihm,60) !Minutes
1783 ! ! Adjust year and DOY to account for year change
1784 ! temp_iy(1:(NperESTM-1)) = temp_iy(1:(NperESTM-1)) - 1 !Subtract 1 from year for all except final timestamp
1785 ! temp_id(NperESTM) = 1 !Set day for final timestamp to 1
1786 ! ENDIF
1787 !
1788 ! !IF(i==1 .or. i== ReadlinesOrigESTMDataMax) THEN
1789 ! ! write(*,*) temp_iy
1790 ! ! write(*,*) temp_id
1791 ! ! !write(*,*) temp_ihm
1792 ! ! write(*,*) temp_ih
1793 ! ! write(*,*) temp_im
1794 ! !ENDIF
1795 !
1796 ! ! Copy to ESTM_tt array
1797 ! ESTM_tt(NperESTM*(i-1)+Seq1NperESTM,1) = temp_iy
1798 ! ESTM_tt(NperESTM*(i-1)+Seq1NperESTM,2) = temp_id
1799 ! ESTM_tt(NperESTM*(i-1)+Seq1NperESTM,3) = temp_ih
1800 ! ESTM_tt(NperESTM*(i-1)+Seq1NperESTM,4) = temp_im
1801 !
1802 ! ENDDO
1803
1804 ! Disaggregate other columns --------------------------------------------------------
1805 ! All other columns are temperatures
1806 DO ii = 5, ncolsestmdata
1807 IF (all(estmfordisagg(:, ii) == -999)) THEN
1808 !IF(DiagnoseDisaggESTM==1) write(*,*) 'No data for col.', ii
1809 estm_tt(:, ii) = -999
1810 ELSE
1811 estm_tt(:, ii) = disagg_lin(estmfordisagg(:, ii), estmfordisaggprev(ii), estmfordisaggnext(ii), estmdisaggmethod(ii), &
1813 END IF
1814 END DO
1815
1816 ! Copy disaggregated data to MetForcingDataArray
1818
1819 ! Write out disaggregated file ------------------------------------------------------
1820 IF (keeptstepfilesin == 1) THEN
1821 IF (iblock == 1) THEN
1822 ! Prepare header
1823 DO i = 1, ncolsestmdata
1824 IF (i == 1) THEN
1825 headerestmout = adjustl(headerestm(i))
1826 ELSE
1827 headerestmout = trim(headerestmout)//' '//adjustl(headerestm(i))
1828 END IF
1829 END DO
1830 ! Write out header
1831 OPEN (78, file=trim(filedscdestm), err=113)
1832 WRITE (78, '(a)') headerestmout
1833 ELSE
1834 OPEN (78, file=trim(filedscdestm), position='append') !,err=113)
1835 END IF
1836 ! Write out data
1838 WRITE (78, 304) (int(estm_tt(i, ii)), ii=1, 4), estm_tt(i, 5:ncolsestmdata)
1839 END DO
1840 !IF(iBlock == ReadBlocksOrigMetData) THEN
1841 ! WRITE(78,'(i2)') -9
1842 ! WRITE(78,'(i2)') -9
1843 !ENDIF
1844 CLOSE (78) !Close output file
1845 END IF
1846
1847304 FORMAT((i4, 1x), 3(i3, 1x), 9(f9.4, 1x))
1848
1849 ! Deallocate arrays -----------------------------------------------------------------
1850 DEALLOCATE (estmfordisagg)
1851 DEALLOCATE (estmfordisaggprev)
1852 DEALLOCATE (estmfordisaggnext)
1853
1854 RETURN
1855
1856113 CALL errorhint(52, trim(filedscdestm), notused, notused, notusedi)
1857
1858 END SUBROUTINE disaggregateestm
1859 !======================================================================================
1860
1861 !======================================================================================
1862 SUBROUTINE disaggregatedatetime(DateTimeForDisagg, tstep, Nper, ReadLinesOrigMetDataMax, DateTimeDscd)
1863 USE datetime_module, ONLY: daysinyear
1864 IMPLICIT NONE
1865 INTEGER, INTENT(in) :: tstep, Nper, ReadLinesOrigMetDataMax
1866 REAL(KIND(1D0)), DIMENSION(ReadLinesOrigMetData, 4), INTENT(in) :: DateTimeForDisagg
1867 REAL(KIND(1D0)), DIMENSION(ReadLinesOrigMetData*Nper, 4), INTENT(out) :: DateTimeDscd
1868
1869 REAL(KIND(1D0)), DIMENSION(ReadLinesOrigMetData) :: dectimeOrig
1870 REAL(KIND(1D0)), DIMENSION(Nper) :: temp_dectime !temorary varaibles for disaggragation
1871 INTEGER, DIMENSION(Nper) :: temp_iy, temp_id, temp_ih, temp_im, temp_ihm ! temorary varaibles for disaggragation
1872 INTEGER, DIMENSION(Nper) :: ndays_iy ! number of days in iy
1873
1874 INTEGER :: i, ii
1875 INTEGER, DIMENSION(Nper) :: seq1Nper
1876
1877 ! Generate useful sequences
1878 seq1nper = (/(i, i=1, nper, 1)/)
1879 ! Convert to dectime
1880 ! dectimeOrig = MetForDisagg(:,2) + MetForDisagg(:,3)/24.0 + MetForDisagg(:,4)/(60.0*24.0)
1881 ! correct to dectime(year_start)=0 and dectime(year_end)=days of year (i.e., 365 or 366 if leap year) ! TS 09 May 2018
1882 dectimeorig = (datetimefordisagg(:, 2) - 1) + datetimefordisagg(:, 3)/24.0 + datetimefordisagg(:, 4)/(60.0*24.0)
1883
1884 DO i = 1, readlinesorigmetdatamax
1885
1886 ! Downscale dectime using dectimeOrig(i) [becomes timestamp of last subinterval]
1887 temp_dectime = dectimeorig(i) - (tstep/60.0)/(60.0*24.0)*(/(ii, ii=(nper - 1), 0, -1)/)
1888 temp_dectime = nint(temp_dectime*60*60*24)/(60*60*24*1.)
1889
1890 ! Convert to required formats
1891 ! get year: year-1 if dectime <0, copy `year` from metforcing otherwise
1892 temp_iy = merge(int(datetimefordisagg(i, 1)) - 1, int(datetimefordisagg(i, 1)), temp_dectime < 0)
1893
1894 ! get day of year:
1895 ndays_iy = daysinyear(temp_iy) ! get days of year for DOY correction when temp_dectime<0 during year-crossing
1896 temp_dectime = merge(temp_dectime + ndays_iy, temp_dectime, temp_dectime < 0) ! correct minus temp_dectime to positive values
1897 temp_id = floor(temp_dectime) + 1 !DOY
1898
1899 temp_ihm = nint((temp_dectime + 1 - temp_id/1.0)*60.0*24.0) !Minutes of the day (1440 max)
1900 temp_ih = (temp_ihm - mod(temp_ihm, 60))/60 !Hours
1901 temp_ih = merge(temp_ih, 0, mask=(temp_ih < 24))
1902 temp_im = mod(temp_ihm, 60) !Minutes
1903
1904 ! Copy to Met_tt array
1905 datetimedscd(nper*(i - 1) + seq1nper, 1) = temp_iy
1906 datetimedscd(nper*(i - 1) + seq1nper, 2) = temp_id
1907 datetimedscd(nper*(i - 1) + seq1nper, 3) = temp_ih
1908 datetimedscd(nper*(i - 1) + seq1nper, 4) = temp_im
1909
1910 END DO
1911
1912 END SUBROUTINE disaggregatedatetime
1913 !======================================================================================
1914
1915 ! Define functions here:
1916 FUNCTION disagg_lin(Slow, SlowPrev, SlowNext, DisaggType, Nper_loc, ReadLinesOrig_loc, ReadLinesOrigMax_loc, iBlock) RESULT(Fast)
1917
1918 USE defaultnotused
1919 USE sues_data
1920
1921 IMPLICIT NONE
1922
1923 INTEGER :: disaggtype !Type of disaggregation: 10 for averaged variables; 20 for instantaneous variables
1924 INTEGER :: nper_loc !Number of subintervals per interval (local Nper)
1925 INTEGER :: readlinesorig_loc, readlinesorigmax_loc !Number of lines to read in original file (local)
1926 INTEGER :: iblock
1927 REAL(kind(1d0)), DIMENSION(ReadLinesOrig_loc*Nper_loc) :: fast !Array to receive disaggregated data
1928 REAL(kind(1d0)), DIMENSION(ReadLinesOrig_loc) :: slow !Array to disaggregate
1929 REAL(kind(1d0)) :: slowprev, slownext
1930 INTEGER, DIMENSION(Nper_loc) :: fastrows !Group of rows that are filled with each iteration
1931 INTEGER, DIMENSION(FLOOR(Nper_loc/2.0)) :: firstrows10 !Rows at the beginning that are not filled during iteration (for averages)
1932 INTEGER, DIMENSION(Nper_loc - FLOOR(Nper_loc/2.0)) :: lastrows10 !Rows at the end that are not filled during iteration
1933 INTEGER, DIMENSION(Nper_loc) :: firstrows20 !Rows at the beginning that are not filled during iteration (for instantaneous)
1934 INTEGER, DIMENSION(Nper_loc) :: seq1nper_loc !1 to Nper_loc
1935 INTEGER :: xnper_loc !XNper_loc = 2 for even Nper_loc; XNper_loc=1 for odd Nper_loc
1936 INTEGER :: i, ii !counters
1937
1938 ! Calculate XNper_loc (differentiates between disaggregations with odd and even Nper_loc)
1939 IF (mod(nper_loc, 2) == 0) xnper_loc = 2
1940 IF (mod(nper_loc, 2) == 1) xnper_loc = 1
1941
1942 seq1nper_loc = (/(i, i=1, nper_loc, 1)/)
1943
1944 ! Setup counters for iteration
1945 IF (disaggtype == 10) THEN
1946 fastrows = floor(nper_loc/2.0) + seq1nper_loc ! Rows to create at model time-step
1947 firstrows10 = (/(i, i=1, (fastrows(1) - 1), 1)/) !For start of dataset
1948 lastrows10 = &
1949 (/(i, i=nper_loc*(readlinesorigmax_loc - 1 - 1) + fastrows(nper_loc) + 1, &
1950 (readlinesorigmax_loc*nper_loc), 1)/) ! For end of dataset
1951 ELSEIF (disaggtype == 20) THEN
1952 fastrows = nper_loc + seq1nper_loc !Rows to create at model time-step
1953 firstrows20 = (/(i, i=1, (fastrows(1) - 1), 1)/) !For start of dataset
1954 END IF
1955
1956 ! Initialise fast array to -999
1957 fast = -999
1958 ! Linearly disaggregate
1959 IF (disaggtype == 10) THEN !Averaged variables
1960 IF (diagnosedisagg == 1) WRITE (*, *) 'Linearly disaggregating averaged variable'
1961 DO i = 1, (readlinesorigmax_loc - 1)
1962 fast(nper_loc*(i - 1) + fastrows) = slow(i) - &
1963 (slow(i + 1) - slow(i))/(xnper_loc*nper_loc) + &
1964 (slow(i + 1) - slow(i))/nper_loc*(/(ii, ii=1, nper_loc, 1)/)
1965 END DO
1966
1967 ! For first few rows, use previous met block
1968 IF (iblock == 1) THEN
1969 fast(firstrows10) = fast(fastrows(1)) !Use repeat values at the start of the year
1970 ELSE
1971 fast(firstrows10) = slowprev - &
1972 (slow(1) - slowprev)/(xnper_loc*nper_loc) + &
1973 (slow(1) - slowprev)/nper_loc* &
1974 (/(ii, ii=(nper_loc - SIZE(firstrows10) + 1), nper_loc, 1)/)
1975 END IF
1976 ! For last few rows, use next met block
1977 IF (iblock == readblocksorigmetdata) THEN
1978 fast(lastrows10) = fast(nper_loc*(readlinesorigmax_loc - 1 - 1) + fastrows(nper_loc)) !Use repeat values at the end of the year
1979 ELSE
1980 fast(lastrows10) = slow(readlinesorigmax_loc) - &
1981 (slownext - slow(readlinesorigmax_loc))/(xnper_loc*nper_loc) + &
1982 (slownext - slow(readlinesorigmax_loc))/nper_loc* &
1983 (/(ii, ii=1, SIZE(lastrows10), 1)/)
1984 END IF
1985 ELSEIF (disaggtype == 20) THEN !Instantaneous variables
1986 IF (diagnosedisagg == 1) WRITE (*, *) 'Linearly disaggregating instantaneous variable'
1987 DO i = 1, (readlinesorigmax_loc - 1)
1988 fast(nper_loc*(i - 1) + fastrows) = (slow(i) + &
1989 (slow(i + 1) - slow(i))/nper_loc*2*(seq1nper_loc - 1) + &
1990 slow(i))/2
1991 END DO
1992 ! For first few rows, use previous met block
1993 IF (iblock == 1) THEN
1994 fast(firstrows20) = fast(fastrows(1)) !Use repeat values at the start of the year
1995 ELSE
1996 fast(firstrows20) = (slowprev + &
1997 (slow(1) - slowprev)/nper_loc*2* &
1998 ((/(ii, ii=(nper_loc - SIZE(firstrows20) + 1), nper_loc, 1)/) - 1) + &
1999 slowprev)/2
2000 END IF
2001 !! Last few rows are already filled for the instantaneous value disaggregation
2002 !IF(iBlock==ReadBlocksOrigMetData) THEN
2003 ! Fast(LastRows20) = Fast(Nper_loc*(ReadLinesOrigMax_loc-1-1)+FastRows(Nper_loc)) !Use repeat values at the end of the year
2004 !ELSE
2005 ! Fast(LastRows20) = (Slow(ReadLinesOrigMax_loc) + &
2006 ! (SlowNext-Slow(ReadLinesOrigMax_loc))/Nper_loc*2 * &
2007 ! ((/(ii, ii=1,SIZE(LastRows20), 1)/)-1) + &
2008 ! Slow(ReadLinesOrigMax_loc))/2
2009 !ENDIF
2010 END IF
2011
2012 IF (any(fast(1:readlinesorigmax_loc*nper_loc) == -999)) THEN
2013 WRITE (*, *) 'Problem: -999s (', count(fast(1:readlinesorigmax_loc*nper_loc) == -999), ') in disaggregated data.'
2014 CALL errorhint(13, 'Problem in SUEWS_MetDisagg: -999 values in disaggregated data.', notused, notused, notusedi)
2015 END IF
2016
2017 END FUNCTION disagg_lin
2018 !======================================================================================
2019
2020 !======================================================================================
2021 FUNCTION disaggp_amongn(Slow, amongN, Nper_loc, ReadLinesOrig_loc, ReadLinesOrigMax_loc) RESULT(Fast)
2022 ! Subroutine to disaggregate precipitation by evenly distributing among N subintervals
2023 ! (i.e. equal intensity in N subintervals)
2024 ! See Ward et al. (in review), meanN, 0.5N or 0.25N approach
2025 ! HCW 10 Feb 2017
2026 !======================================================================================
2027
2028 USE defaultnotused
2029 USE sues_data
2030
2031 IMPLICIT NONE
2032
2033 INTEGER :: amongn !Number of subintervals over which rain will be distributed
2034 INTEGER :: nper_loc !Number of subintervals per interval (local Nper)
2035 INTEGER :: readlinesorig_loc, readlinesorigmax_loc !Number of lines to read in original file (local)
2036 REAL(kind(1d0)), DIMENSION(ReadLinesOrig_loc*Nper_loc) :: fast !Array to receive disaggregated data
2037 REAL(kind(1d0)), DIMENSION(ReadLinesOrig_loc) :: slow !Array to disaggregate
2038 INTEGER, DIMENSION(:), ALLOCATABLE :: subintervals !Array of subintervals that contain rain
2039 INTEGER, DIMENSION(Nper_loc) :: seq1nper_loc !1 to Nper_loc
2040 INTEGER :: i
2041
2042 ! For each averaging period, get subintervals which will receive rain
2043 ALLOCATE (subintervals(amongn))
2044 subintervals(:) = -999
2045
2046 seq1nper_loc = (/(i, i=1, nper_loc, 1)/)
2047
2048 IF (diagnosedisagg == 1) WRITE (*, *) 'Distributing over ', amongn, ' subintervals for variable'
2049 ! If all subintervals are to contain rain, don't need to generate random numbers
2050 IF (amongn == nper_loc) THEN
2051 subintervals(:) = seq1nper_loc
2052 END IF
2053 IF (amongn > nper_loc) &
2054 CALL errorhint(2, 'Problem in SUEWS_MetDisagg: no. of rainy periods cannot exceed number of subintervals', &
2055 REAL(nper_loc, kind(1d0)), notused, amongn)
2056
2057 ! Initialise fast array to -999
2058 fast = -999
2059 DO i = 1, readlinesorigmax_loc
2060 fast(nper_loc*(i - 1) + seq1nper_loc) = 0 !Fill all subintervals with zeros initially
2061 IF (slow(i) > 0) THEN !If there is some rainfall during this interval...
2062 IF (amongn < nper_loc) THEN
2063 subintervals(:) = -999
2064 subintervals = randomsamples(amongn, nper_loc)
2065 END IF
2066 fast(nper_loc*(i - 1) + subintervals) = slow(i)/amongn
2067 END IF
2068 END DO
2069
2070 IF (any(fast(1:readlinesorigmax_loc*nper_loc) == -999)) THEN
2071 WRITE (*, *) 'Problem: -999s (', count(fast(1:readlinesorigmax_loc*nper_loc) == -999), ') in disaggregated data'
2072 CALL errorhint(13, 'Problem in SUEWS_MetDisagg: -999 values in disaggregated data.', notused, notused, notusedi)
2073 END IF
2074
2075 END FUNCTION disaggp_amongn
2076 !======================================================================================
2077
2078 !======================================================================================
2079 FUNCTION disaggp_amongnmult(Slow, multupperI, multamongN, Nper_loc, ReadLinesOrig_loc, ReadLinesOrigMax_loc) RESULT(Fast)
2080 ! Subroutine to disaggregate precipitation by evenly distributing among N subintervals
2081 ! (i.e. equal intensity in N subintervals) for different intensity bins
2082 ! Based on analsysis by Wen Gu
2083 ! HCW 21 Apr 2017
2084 !======================================================================================
2085
2086 USE defaultnotused
2087 USE sues_data
2088
2089 IMPLICIT NONE
2090
2091 REAL(kind(1d0)), DIMENSION(5) :: multupperi !Upper bound of intensity bin
2092 INTEGER, DIMENSION(5) :: multamongn !Number of subintervals over which rain will be distributed (array)
2093 INTEGER :: thisamongn !Number of subintervals over which rain will be distributed
2094 INTEGER :: nper_loc !Number of subintervals per interval (local Nper)
2095 INTEGER :: readlinesorig_loc, readlinesorigmax_loc !Number of lines to read in original file (local)
2096 REAL(kind(1d0)), DIMENSION(ReadLinesOrig_loc*Nper_loc) :: fast !Array to receive disaggregated data
2097 REAL(kind(1d0)), DIMENSION(ReadLinesOrig_loc) :: slow !Array to disaggregate
2098 INTEGER, DIMENSION(:), ALLOCATABLE :: subintervals !Array of subintervals that contain rain
2099 INTEGER, DIMENSION(Nper_loc) :: seq1nper_loc !1 to Nper_loc
2100 INTEGER :: i
2101
2102 seq1nper_loc = (/(i, i=1, nper_loc, 1)/)
2103
2104 IF (diagnosedisagg == 1) WRITE (*, *) 'Distributing over variable subintervals depending on intensity for variable'
2105
2106 ! Initialise fast array to -999
2107 fast = -999
2108 DO i = 1, readlinesorigmax_loc
2109 fast(nper_loc*(i - 1) + seq1nper_loc) = 0 !Fill all subintervals with zeros initially
2110 IF (slow(i) > 0) THEN !If there is some rainfall during this interval...
2111 !Use intensity in this interval to decide number of subintervals to fill with rain
2112 IF (slow(i) <= multupperi(1)) THEN
2113 thisamongn = multamongn(1)
2114 ELSEIF (slow(i) > multupperi(1) .AND. slow(i) <= multupperi(2)) THEN
2115 thisamongn = multamongn(2)
2116 ELSEIF (slow(i) > multupperi(2) .AND. slow(i) <= multupperi(3)) THEN
2117 thisamongn = multamongn(3)
2118 ELSEIF (slow(i) > multupperi(3) .AND. slow(i) <= multupperi(4)) THEN
2119 thisamongn = multamongn(4)
2120 ELSEIF (slow(i) > multupperi(4) .AND. slow(i) <= multupperi(5)) THEN
2121 thisamongn = multamongn(5)
2122 ELSEIF (slow(i) > multupperi(5)) THEN
2123 thisamongn = multamongn(5)
2124 CALL errorhint(4, 'Precip in met forcing file exceeds maxiumum MultRainAmongNUpperI', &
2125 slow(i), multrainamongnupperi(5), notusedi)
2126 END IF
2127
2128 ! For each averaging period, get subintervals which will receive rain
2129 ALLOCATE (subintervals(thisamongn))
2130 subintervals(:) = -999
2131
2132 IF (thisamongn > nper_loc) CALL errorhint(2, 'Problem in SUEWS_MetDisagg: no. of rainy periods cannot exceed '// &
2133 'number of subintervals', real(nper_loc, kind(1d0)), notused, thisamongn)
2134
2135 IF (thisamongn == nper_loc) THEN ! If all subintervals are to contain rain, don't need to generate random numbers
2136 subintervals(:) = seq1nper_loc
2137 ELSEIF (thisamongn < nper_loc) THEN
2138 subintervals = randomsamples(thisamongn, nper_loc)
2139 END IF
2140 fast(nper_loc*(i - 1) + subintervals) = slow(i)/thisamongn
2141 !write(*,*) Slow(i), thisamongN
2142 DEALLOCATE (subintervals)
2143 END IF
2144 END DO
2145
2146 IF (any(fast(1:readlinesorigmax_loc*nper_loc) == -999)) THEN
2147 WRITE (*, *) 'Problem: -999s (', count(fast(1:readlinesorigmax_loc*nper_loc) == -999), ') in disaggregated data'
2148 CALL errorhint(13, 'Problem in SUEWS_MetDisagg: -999 values in disaggregated data.', notused, notused, notusedi)
2149 END IF
2150
2151 END FUNCTION disaggp_amongnmult
2152 !======================================================================================
2153
2154 !======================================================================================
2155 FUNCTION randomsamples(N, OutOf) RESULT(Samples)
2156 ! Generates N/OutOf random samples without repeats
2157 ! e.g. for N = 3 and OutOf = 12, a possibility for Samples = 7,3,11
2158 ! HCW 10 Feb 2017
2159 !======================================================================================
2160
2161 IMPLICIT NONE
2162
2163 INTEGER :: i !counter
2164 INTEGER :: n !number of samples to return
2165 INTEGER :: outof !number to sample from
2166 INTEGER :: x !next sample to be added
2167 REAL(kind(1d0)) :: r !random number
2168 INTEGER, DIMENSION(:), ALLOCATABLE :: samples !Array to receive random samples
2169
2170 ! Allocate and initialise Samples
2171 ALLOCATE (samples(n))
2172 samples(:) = -999
2173
2174 ! Generate random sample (no repeats)
2175 i = 0 !Set counter to zero initially
2176 DO WHILE (any(samples == -999))
2177 CALL random_number(r)
2178 x = int(r*outof) + 1
2179 !write(*,*) X
2180 !write(*,*) COUNT(Samples == X)
2181 IF (count(samples == x) == 0) THEN
2182 ! Only keep if this subinterval has not already been selected
2183 i = i + 1
2184 samples(i) = x
2185 END IF
2186 !write(*,*) Samples
2187 END DO
2188
2189 END FUNCTION randomsamples
2190 !======================================================================================
2191
2192END MODULE metdisagg
2193!========================================================================================
real(kind(1d0)), dimension(:, :), allocatable biogen_coeff
integer, parameter bldgsurf
real(kind(1d0)), dimension(:, :), allocatable estmcoefficients_coeff
real(kind(1d0)), dimension(:, :), allocatable snow_coeff
real(kind(1d0)), dimension(:, :), allocatable siteselect
real(kind(1d0)), dimension(:, :), allocatable anthropogenic_coeff
integer, dimension(nsurfincsnow) c_ohmcode_wwet
character(len=20), dimension(ncolumnsnonveg) headernonveg_reqd
real(kind(1d0)), dimension(:, :), allocatable wgwaterdist_coeff
integer, parameter ncolsestmdata
character(len=20), dimension(ncolumnsanthropogenic) headeranthropogenic_reqd
character(len=20), dimension(ncolumnsnonveg) headernonveg_file
character(len=20), dimension(ncolumnswgwaterdist) headerwgwaterdist_file
real(kind(1d0)), dimension(:, :), allocatable metfordisagg
character(len=20), dimension(ncolumnswater) headerwater_reqd
integer, dimension(nsurfincsnow) c_ohmcode_sdry
integer, dimension(nsurfincsnow) c_ohmcode_swet
real(kind(1d0)), dimension(:), allocatable estmfordisaggprev
character(len=20), dimension(ncolumnswater) headerwater_file
character(len=20), dimension(ncolumnssnow) headersnow_file
character(len=20), dimension(ncolumnsveg) headerveg_file
real(kind(1d0)), dimension(:), allocatable metfordisaggnext
integer, parameter ncolumnsmetforcingdata
character(len=20), dimension(ncolumnsprofiles) headerprofiles_reqd
character(len=20), dimension(ncolumnssnow) headersnow_reqd
real(kind(1d0)), dimension(:), allocatable metfordisaggprev
real(kind(1d0)), dimension(:, :), allocatable water_coeff
integer, dimension(nsurfincsnow) c_ohmcode_wdry
real(kind(1d0)), dimension(:, :), allocatable nonveg_coeff
character(len=20), dimension(ncolumnsohmcoefficients) headerohmcoefficients_reqd
real(kind(1d0)), dimension(:, :), allocatable conductance_coeff
character(len=20), dimension(ncolumnssoil) headersoil_file
real(kind(1d0)), dimension(:, :, :), allocatable metforcingdata
character(len=20), dimension(ncolumnsirrigation) headerirrigation_reqd
character(len=20), dimension(ncolumnsanthropogenic) headeranthropogenic_file
real(kind(1d0)), dimension(:, :), allocatable surfacechar
character(len=20), dimension(ncolumnsveg) headerveg_reqd
character(len=20), dimension(ncolumnsbiogen) headerbiogen_reqd
character(len=20), dimension(ncolumnsohmcoefficients) headerohmcoefficients_file
real(kind(1d0)), dimension(:, :), allocatable estmfordisagg
real(kind(1d0)), dimension(:), allocatable estmfordisaggnext
real(kind(1d0)), dimension(:, :), allocatable profiles_coeff
character(len=20), dimension(ncolumnsprofiles) headerprofiles_file
character(len=20), dimension(ncolumnsconductance) headercond_reqd
integer, dimension(nsurfincsnow) c_estmcode
real(kind(1d0)), dimension(:, :), allocatable soil_coeff
character(len=20), dimension(ncolumnsirrigation) headerirrigation_file
real(kind(1d0)), dimension(:, :), allocatable ohmcoefficients_coeff
integer, parameter pavsurf
character(len=20), dimension(ncolumnsbiogen) headerbiogen_file
real(kind(1d0)), dimension(:, :), allocatable irrigation_coeff
character(len=20), dimension(ncolumnsconductance) headercond_file
character(len=20), dimension(ncolumnsestmcoefficients) headerestmcoefficients_reqd
character(len=20), dimension(ncolumnssoil) headersoil_reqd
character(len=20), dimension(ncolumnsestmcoefficients) headerestmcoefficients_file
real(kind(1d0)), dimension(:, :), allocatable veg_coeff
real(kind(1d0)), dimension(:, :, :), allocatable estmforcingdata
character(len=20), dimension(ncolumnswgwaterdist) headerwgwaterdist_reqd
integer, dimension(24) cpr_hours
integer, dimension(5) c_code_estmclass_bldgs
integer, dimension(3) c_code_estmclass_paved
character(len=150) filedscdestm
integer netradiationmethod
integer resolutionfilesin
real(kind(1d0)) timezone
integer resolutionfilesinestm
real(kind(1d0)), dimension(5) multrainamongnupperi
integer diagnosedisagg
integer, dimension(5) multrainamongn
real(kind(1d0)) lng
integer inputmetformat
integer keeptstepfilesin
integer disaggmethodestm
integer ldown_option
real(kind(1d0)) lat
character(len=150) filedscdmet
integer disaggmethod
real(kind(1d0)) zenith_deg
integer raindisaggmethod
integer diagnosedisaggestm
character(len=150) fileorigestm
real(kind(1d0)) alt
real(kind(1d0)) azimuth
character(len=150) fileorigmet
real(kind(1d0)) nan
real(kind(1d0)) notused
real(kind(1d0)) reall
integer nlinesirrigation
integer skippedlinesorig
integer nlinesohmcoefficients
integer gridcounter
integer nlinesprofiles
integer nlineswgwaterdist
integer nlineswater
integer nlinesestmcoefficients
integer nlinesconductance
integer readlinesorigestmdatamax
integer nlinesbiogen
integer readlinesorigmetdata
integer readlinesorigmetdatamax
integer nlinesanthropogenic
integer readlinesorigestmdata
integer skippedlinesorigestm
integer nlinesnonveg
integer readblocksorigmetdata
subroutine disaggregateestm(iblock)
real(kind(1d0)) function, dimension(readlinesorig_loc *nper_loc) disaggp_amongn(slow, amongn, nper_loc, readlinesorig_loc, readlinesorigmax_loc)
real(kind(1d0)) function, dimension(readlinesorig_loc *nper_loc) disaggp_amongnmult(slow, multupperi, multamongn, nper_loc, readlinesorig_loc, readlinesorigmax_loc)
subroutine disaggregatemet(iblock, igrid)
subroutine disaggregatedatetime(datetimefordisagg, tstep, nper, readlinesorigmetdatamax, datetimedscd)
integer function, dimension(:), allocatable randomsamples(n, outof)
real(kind(1d0)) function, dimension(readlinesorig_loc *nper_loc) disagg_lin(slow, slowprev, slownext, disaggtype, nper_loc, readlinesorig_loc, readlinesorigmax_loc, iblock)
subroutine narp_cal_sunposition(year, idectime, utc, locationlatitude, locationlongitude, locationaltitude, sunazimuth, sunzenith)
character(len=90), dimension(14) text
real(kind(1d0)) halftimestep
real(kind(1d0)) soildensity
real(kind(1d0)) soilrocks
real(kind(1d0)) smcap
real(kind(1d0)) soildepthmeas
subroutine errorhint(errh, problemfile, value, value2, valuei)
subroutine codematchwater(rr, codecol)
real(kind(1d0)) function get_prof_spectime_sum(hour, min, sec, prof_24h, dt)
subroutine codematchsnow(rr, codecol)
subroutine codematchestm_class(gridiv, is, ii)
subroutine codematchsoil(gridiv, surfacecharcodecol)
subroutine codematchveg(rr, codecol)
real(kind(1d0)) function get_prof_spectime_inst(hour, min, sec, prof_24h)
subroutine codematchnonveg(rr, codecol)
subroutine codematchdist(rr, codecol, codecolsamesurf)
subroutine run_control(eval, lowerlimit, upperlimit)
subroutine codematchconductance(rr, codecol)
real(kind(1d0)) function get_prof_spectime_mean(hour, min, sec, prof_24h)
subroutine codematchestm(gridiv, is)
subroutine codematchprof(gridiv, surfacecharcodecol)
subroutine metread(lfn, metarray, inputmetformat, ldown_option, netradiationmethod, snowuse, smdmethod, soildepthmeas, soilrocks, soildensity, smcap)
subroutine codematchanthropogenic(rr, codecol)
subroutine codematchohm(gridiv, is, swwd)
subroutine codematchirrigation(rr, codecol)
subroutine inputheadercheck(filename)
subroutine skipheader(lfn, skip)
subroutine codematchbiogen(gridiv, surfacecharcodecol)