libsim Versione 8.0.0
stat_proc_engine.F90
1! Copyright (C) 2010 ARPA-SIM <urpsim@smr.arpa.emr.it>
2! authors:
3! Davide Cesari <dcesari@arpa.emr.it>
4! Paolo Patruno <ppatruno@arpa.emr.it>
5
6! This program is free software; you can redistribute it and/or
7! modify it under the terms of the GNU General Public License as
8! published by the Free Software Foundation; either version 2 of
9! the License, or (at your option) any later version.
10
11! This program is distributed in the hope that it will be useful,
12! but WITHOUT ANY WARRANTY; without even the implied warranty of
13! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14! GNU General Public License for more details.
15
16! You should have received a copy of the GNU General Public License
17! along with this program. If not, see <http://www.gnu.org/licenses/>.
18#include "config.h"
19!> This module contains functions that are only for internal use of
20!! the library. It should not be used by user procedures because it is
21!! subject to change
22!! \ingroup vol7d
26IMPLICIT NONE
27
28! per ogni elemento i,j dell'output, definire n elementi di input ad
29! esso contribuenti (arrayof_ttr_mapper) con le seguenti informazioni
30TYPE ttr_mapper
31 INTEGER :: it=imiss ! k
32 INTEGER :: itr=imiss ! l
33 INTEGER :: extra_info=imiss ! dtratio for intervals, extreme for point in time
34 TYPE(datetime) :: time=datetime_miss ! time for point in time
35END TYPE ttr_mapper
36
37INTERFACE OPERATOR (==)
38 MODULE PROCEDURE ttr_mapper_eq
39END INTERFACE
40
41INTERFACE OPERATOR (/=)
42 MODULE PROCEDURE ttr_mapper_ne
43END INTERFACE
44
45INTERFACE OPERATOR (>)
46 MODULE PROCEDURE ttr_mapper_gt
47END INTERFACE
48
49INTERFACE OPERATOR (<)
50 MODULE PROCEDURE ttr_mapper_lt
51END INTERFACE
52
53INTERFACE OPERATOR (>=)
54 MODULE PROCEDURE ttr_mapper_ge
55END INTERFACE
56
57INTERFACE OPERATOR (<=)
58 MODULE PROCEDURE ttr_mapper_le
59END INTERFACE
60
61#undef VOL7D_POLY_TYPE
62#undef VOL7D_POLY_TYPES
63#undef ENABLE_SORT
64#define VOL7D_POLY_TYPE TYPE(ttr_mapper)
65#define VOL7D_POLY_TYPES _ttr_mapper
66#define ENABLE_SORT
67#include "array_utilities_pre.F90"
68
69#define ARRAYOF_ORIGTYPE TYPE(ttr_mapper)
70#define ARRAYOF_TYPE arrayof_ttr_mapper
71#define ARRAYOF_ORIGEQ 1
72#define ARRAYOF_ORIGGT 1
73#include "arrayof_pre.F90"
74! from arrayof
75
76TYPE,PRIVATE :: ttr_decoder
77 TYPE(datetime) :: pstart=datetime_miss
78 TYPE(datetime) :: pend=datetime_miss
79 TYPE(datetime) :: reftime=datetime_miss
80 LOGICAL :: isana=.false.
81END TYPE ttr_decoder
82
83CONTAINS
84
85! simplified comparisons only on time
86ELEMENTAL FUNCTION ttr_mapper_eq(this, that) RESULT(res)
87TYPE(ttr_mapper),INTENT(IN) :: this, that
88LOGICAL :: res
89
90res = this%time == that%time
91
92END FUNCTION ttr_mapper_eq
93
94ELEMENTAL FUNCTION ttr_mapper_ne(this, that) RESULT(res)
95TYPE(ttr_mapper),INTENT(IN) :: this, that
96LOGICAL :: res
97
98res = this%time /= that%time
99
100END FUNCTION ttr_mapper_ne
101
102ELEMENTAL FUNCTION ttr_mapper_gt(this, that) RESULT(res)
103TYPE(ttr_mapper),INTENT(IN) :: this, that
104LOGICAL :: res
105
106res = this%time > that%time
107
108END FUNCTION ttr_mapper_gt
109
110ELEMENTAL FUNCTION ttr_mapper_lt(this, that) RESULT(res)
111TYPE(ttr_mapper),INTENT(IN) :: this, that
112LOGICAL :: res
113
114res = this%time < that%time
115
116END FUNCTION ttr_mapper_lt
117
118ELEMENTAL FUNCTION ttr_mapper_ge(this, that) RESULT(res)
119TYPE(ttr_mapper),INTENT(IN) :: this, that
120LOGICAL :: res
121
122res = this%time >= that%time
123
124END FUNCTION ttr_mapper_ge
125
126ELEMENTAL FUNCTION ttr_mapper_le(this, that) RESULT(res)
127TYPE(ttr_mapper),INTENT(IN) :: this, that
128LOGICAL :: res
129
130res = this%time <= that%time
131
132END FUNCTION ttr_mapper_le
133
134#include "arrayof_post.F90"
135#include "array_utilities_inc.F90"
136
137
138! common operations for statistical processing by differences
139SUBROUTINE recompute_stat_proc_diff_common(itime, itimerange, stat_proc, step, &
140 otime, otimerange, map_tr, f, keep_tr, time_definition, full_steps, &
141 start)
142TYPE(datetime),INTENT(in) :: itime(:)
143TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
144INTEGER,INTENT(in) :: stat_proc
145TYPE(timedelta),INTENT(in) :: step
146TYPE(datetime),POINTER :: otime(:)
147TYPE(vol7d_timerange),POINTER :: otimerange(:)
148INTEGER,ALLOCATABLE,INTENT(out) :: map_tr(:,:,:,:,:), f(:), keep_tr(:,:,:)
149INTEGER :: nitr
150LOGICAL,ALLOCATABLE :: mask_timerange(:)
151INTEGER,INTENT(in) :: time_definition
152LOGICAL,INTENT(in),OPTIONAL :: full_steps
153TYPE(datetime),INTENT(in),OPTIONAL :: start
154
155INTEGER :: i, j, k, l, dirtyrep
156INTEGER :: steps
157LOGICAL :: lfull_steps, useful
158TYPE(datetime) :: lstart, tmptime ! pstart1, pstart2, pend1, pend2, reftime1, reftime2
159TYPE(vol7d_timerange) :: tmptimerange
160TYPE(arrayof_datetime) :: a_otime
161TYPE(arrayof_vol7d_timerange) :: a_otimerange
162TYPE(timedelta) :: start_delta
163TYPE(ttr_decoder),ALLOCATABLE :: ttr_d(:,:)
164
165! compute length of cumulation step in seconds
166CALL getval(step, asec=steps)
167
168lstart = datetime_miss
169IF (PRESENT(start)) lstart = start
170lfull_steps = optio_log(full_steps)
171
172! create a mask of suitable timeranges
173ALLOCATE(mask_timerange(SIZE(itimerange)))
174mask_timerange(:) = itimerange(:)%timerange == stat_proc &
175 .AND. itimerange(:)%p1 /= imiss .AND. itimerange(:)%p2 /= imiss &
176 .AND. itimerange(:)%p1 >= 0 &
177 .AND. itimerange(:)%p2 > 0
178
179IF (lfull_steps .AND. steps /= 0) THEN ! keep only timeranges defining intervals ending at integer forecast steps or analysis timeranges
180 mask_timerange(:) = mask_timerange(:) .AND. &
181 (itimerange(:)%p1 == 0 .OR. & ! all analyses
182 mod(itimerange(:)%p1, steps) == 0 .OR. & ! end time is mod step
183 mod(itimerange(:)%p1 - itimerange(:)%p2, steps) == 0) ! start time is mod step
184ENDIF
185! mask_timerange includes all candidate timeranges
186
187nitr = count(mask_timerange)
188ALLOCATE(f(nitr))
189j = 1
190DO i = 1, nitr
191 DO WHILE(.NOT.mask_timerange(j))
192 j = j + 1
193 ENDDO
194 f(i) = j
195 j = j + 1
196ENDDO
197
198ALLOCATE(map_tr(nitr, SIZE(itime), nitr, SIZE(itime), 2))
199map_tr(:,:,:,:,:) = imiss
200
201! precompute ttr
202ALLOCATE(ttr_d(nitr,SIZE(itime)))
203DO l = 1, SIZE(itime)
204 DO k = 1, nitr
205 CALL ttr_decoder_decode(itime(l), itimerange(f(k)), &
206 time_definition, ttr_d(k,l))
207 IF (ttr_d(k,l)%reftime == ttr_d(k,l)%pend) ttr_d(k,l)%isana = .true.
208 ENDDO
209ENDDO
210
211! now we have to evaluate time/timerage pairs which do not need processing
212ALLOCATE(keep_tr(nitr, SIZE(itime), 2))
213CALL compute_keep_tr()
214
215! scan through all possible combinations of time and timerange
216DO dirtyrep = 1, 2
217 IF (dirtyrep == 2) THEN ! dirty and expensive trick for sorting descriptors
218 CALL packarray(a_otime)
219 CALL packarray(a_otimerange)
220 CALL sort(a_otime%array)
221 CALL sort(a_otimerange%array)
222 ENDIF
223 DO l = 1, SIZE(itime)
224 DO k = 1, nitr
225! CALL time_timerange_get_period(itime(l), itimerange(f(k)), &
226! time_definition, pstart2, pend2, reftime2)
227
228 DO j = 1, SIZE(itime)
229 DO i = 1, nitr
230 useful = .false.
231! CALL time_timerange_get_period(itime(j), itimerange(f(i)), &
232! time_definition, pstart1, pend1, reftime1)
233! tmptimerange = vol7d_timerange_new(timerange=stat_proc)
234
235! IF (ttr_d(k,l)%reftime == ttr_d(k,l)%pend .AND. ttr_d(i,j)%reftime == ttr_d(i,j)%pend) THEN ! analysis
236 IF (ttr_d(k,l)%isana .AND. ttr_d(i,j)%isana) THEN ! analysis
237 IF (ttr_d(k,l)%pstart == ttr_d(i,j)%pstart .AND. ttr_d(k,l)%pend > ttr_d(i,j)%pend) THEN ! =-|
238 CALL time_timerange_set_period(tmptime, tmptimerange, &
239 time_definition, stat_proc, ttr_d(i,j)%pend, ttr_d(k,l)%pend, ttr_d(k,l)%reftime)
240 IF (lfull_steps) THEN
241 IF (mod(ttr_d(k,l)%reftime, step) == timedelta_0) THEN
242 useful = .true.
243 ENDIF
244 ELSE
245 useful = .true.
246 ENDIF
247! keep only data after lstart
248 IF (c_e(lstart)) THEN
249 IF (lstart > ttr_d(i,j)%pend) useful = .false.
250 ENDIF
251
252 ELSE IF (ttr_d(k,l)%pstart < ttr_d(i,j)%pstart .AND. ttr_d(k,l)%pend == ttr_d(i,j)%pend) THEN ! -=|
253 CALL time_timerange_set_period(tmptime, tmptimerange, &
254 time_definition, stat_proc, ttr_d(k,l)%pstart, ttr_d(i,j)%pstart, ttr_d(i,j)%pstart)
255 IF (lfull_steps) THEN
256 IF (mod(ttr_d(i,j)%pstart, step) == timedelta_0) THEN
257 useful = .true.
258 ENDIF
259 ELSE
260 useful = .true.
261 ENDIF
262! keep only data after lstart
263 IF (c_e(lstart)) THEN
264 IF (lstart > ttr_d(k,l)%pstart) useful = .false.
265 ENDIF
266 ENDIF
267
268 ELSE IF (ttr_d(k,l)%reftime == ttr_d(i,j)%reftime) THEN ! forecast, same reftime
269 IF (lfull_steps) THEN
270 IF (c_e(lstart)) THEN
271! lstart shifts the interval for computing modulo step, this does not
272! remove data before lstart but just shifts the phase
273 start_delta = lstart-ttr_d(k,l)%reftime
274 ELSE
275 start_delta = timedelta_0
276 ENDIF
277 ENDIF
278
279 IF (ttr_d(k,l)%pstart == ttr_d(i,j)%pstart .AND. ttr_d(k,l)%pend > ttr_d(i,j)%pend) THEN ! |=-
280 CALL time_timerange_set_period(tmptime, tmptimerange, &
281 time_definition, stat_proc, ttr_d(i,j)%pend, ttr_d(k,l)%pend, ttr_d(k,l)%reftime)
282 IF (lfull_steps) THEN
283 IF (mod(ttr_d(k,l)%pend-ttr_d(k,l)%reftime-start_delta, step) == timedelta_0) THEN
284 useful = .true.
285 ENDIF
286 ELSE
287 useful = .true.
288 ENDIF
289! keep only data after lstart
290 IF (c_e(lstart)) THEN
291 IF (lstart > ttr_d(i,j)%pend) useful = .false.
292 ENDIF
294 ELSE IF (ttr_d(k,l)%pstart < ttr_d(i,j)%pstart .AND. ttr_d(k,l)%pend == ttr_d(i,j)%pend) THEN ! |-=
295 CALL time_timerange_set_period(tmptime, tmptimerange, &
296 time_definition, stat_proc, ttr_d(k,l)%pstart, ttr_d(i,j)%pstart, ttr_d(k,l)%reftime)
297 IF (lfull_steps) THEN
298 IF (mod(ttr_d(i,j)%pstart-ttr_d(k,l)%reftime-start_delta, step) == timedelta_0) THEN
299 useful = .true.
300 ENDIF
301 ELSE
302 useful = .true.
303 ENDIF
304! keep only data after lstart
305 IF (c_e(lstart)) THEN
306 IF (lstart > ttr_d(k,l)%pstart) useful = .false.
307 ENDIF
308
309 ENDIF
310 ENDIF
311 useful = useful .AND. tmptime /= datetime_miss .AND. &
312 tmptimerange /= vol7d_timerange_miss .AND. tmptimerange%p2 == steps
313
314 IF (useful) THEN ! add a_otime, a_otimerange
315 map_tr(i,j,k,l,1) = append_unique(a_otime, tmptime)
316 map_tr(i,j,k,l,2) = append_unique(a_otimerange, tmptimerange)
317 ENDIF
318 ENDDO
319 ENDDO
320 ENDDO
321 ENDDO
322ENDDO
323
324! we have to repeat the computation with sorted arrays
325CALL compute_keep_tr()
326
327otime => a_otime%array
328otimerange => a_otimerange%array
329! delete local objects keeping the contents
330CALL delete(a_otime, nodealloc=.true.)
331CALL delete(a_otimerange, nodealloc=.true.)
332
333#ifdef DEBUG
334CALL l4f_log(l4f_debug, &
335 'recompute_stat_proc_diff, map_tr: '//t2c((SIZE(map_tr,1)))//', '// &
336 t2c((SIZE(map_tr,2)))//', '// &
337 t2c((SIZE(map_tr,3)))//', '// &
338 t2c((SIZE(map_tr,4))))
339CALL l4f_log(l4f_debug, &
340 'recompute_stat_proc_diff, map_tr: '//t2c((SIZE(map_tr))/2)//', '// &
341 t2c(count(c_e(map_tr))/2))
342CALL l4f_log(l4f_debug, &
343 'recompute_stat_proc_diff, nitr: '//t2c(nitr))
344CALL l4f_log(l4f_debug, &
345 'recompute_stat_proc_diff, good timeranges: '//t2c(count(c_e(keep_tr))/2))
346CALL l4f_log(l4f_debug, &
347 'recompute_stat_proc_diff, output times: '//t2c(SIZE(otime)))
348CALL l4f_log(l4f_debug, &
349 'recompute_stat_proc_diff, output timeranges: '//t2c(SIZE(otimerange)))
350#endif
352CONTAINS
353
354SUBROUTINE compute_keep_tr()
355INTEGER :: start_deltas
357keep_tr(:,:,:) = imiss
358DO l = 1, SIZE(itime)
359 itrloop: DO k = 1, nitr
360 IF (itimerange(f(k))%p2 == steps) THEN
361! CALL time_timerange_get_period(itime(l), itimerange(f(k)), &
362! time_definition, pstart2, pend2, reftime2)
363 useful = .false.
364! keep only data after lstart
365 IF (c_e(lstart)) THEN
366 IF (lstart > ttr_d(k,l)%pstart) cycle itrloop
367 ENDIF
368 IF (ttr_d(k,l)%reftime == ttr_d(k,l)%pend) THEN ! analysis
369 IF (c_e(lstart)) THEN ! in analysis mode start wins over full_steps
370 IF (mod(ttr_d(k,l)%reftime-lstart, step) == timedelta_0) THEN
371 useful = .true.
372 ENDIF
373 ELSE IF (lfull_steps) THEN
374 IF (mod(ttr_d(k,l)%reftime, step) == timedelta_0) THEN
375 useful = .true.
376 ENDIF
377 ELSE
378 useful = .true.
379 ENDIF
380 ELSE ! forecast
381 IF (lfull_steps) THEN
382! same as above for start_delta, but in seconds and not in timerange/timedelta units
383 IF (c_e(lstart)) THEN
384 start_deltas = timedelta_getamsec(lstart-ttr_d(k,l)%reftime)/1000_int_ll
385 ELSE
386 start_deltas = 0
387 ENDIF
388 IF (mod(itimerange(f(k))%p1 - start_deltas, steps) == 0) THEN
389 useful = .true.
390 ENDIF
391 ELSE
392 useful = .true.
393 ENDIF
394 ENDIF
395 IF (useful) THEN
396! CALL time_timerange_set_period(tmptime, tmptimerange, &
397! time_definition, stat_proc, pstart2, pend2, reftime2)
398 keep_tr(k,l,1) = append_unique(a_otime, itime(l))
399 keep_tr(k,l,2) = append_unique(a_otimerange, itimerange(f(k)))
400 ENDIF
401 ENDIF
402 ENDDO itrloop
403ENDDO
404
405END SUBROUTINE compute_keep_tr
406
407END SUBROUTINE recompute_stat_proc_diff_common
408
409
410! common operations for statistical processing by metamorphosis
411SUBROUTINE compute_stat_proc_metamorph_common(istat_proc, itimerange, ostat_proc, &
412 otimerange, map_tr)
413INTEGER,INTENT(in) :: istat_proc
414TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
415INTEGER,INTENT(in) :: ostat_proc
416TYPE(vol7d_timerange),POINTER :: otimerange(:)
417INTEGER,POINTER :: map_tr(:)
418
419INTEGER :: i
420LOGICAL :: tr_mask(SIZE(itimerange))
421
422IF (SIZE(itimerange) == 0) THEN ! avoid segmentation fault in case of empty volume
423 ALLOCATE(otimerange(0), map_tr(0))
424 RETURN
425ENDIF
426
427! useful timeranges
428tr_mask(:) = itimerange(:)%timerange == istat_proc .AND. itimerange(:)%p2 /= imiss &
429 .AND. itimerange(:)%p2 /= 0 ! .AND. itimerange(:)%p1 == 0
430ALLOCATE(otimerange(count(tr_mask)), map_tr(count(tr_mask)))
431
432otimerange = pack(itimerange, mask=tr_mask)
433otimerange(:)%timerange = ostat_proc
434map_tr = pack((/(i,i=1,SIZE(itimerange))/), mask=tr_mask)
435
436END SUBROUTINE compute_stat_proc_metamorph_common
437
438
439! common operations for statistical processing by aggregation
440SUBROUTINE recompute_stat_proc_agg_common(itime, itimerange, stat_proc, tri, &
441 step, time_definition, otime, otimerange, map_ttr, dtratio, start, full_steps)
442TYPE(datetime),INTENT(in) :: itime(:)
443TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
444INTEGER,INTENT(in) :: stat_proc
445INTEGER,INTENT(in) :: tri
446TYPE(timedelta),INTENT(in) :: step
447INTEGER,INTENT(in) :: time_definition
448TYPE(datetime),POINTER :: otime(:)
449TYPE(vol7d_timerange),POINTER :: otimerange(:)
450TYPE(arrayof_ttr_mapper),POINTER :: map_ttr(:,:)
451INTEGER,POINTER,OPTIONAL :: dtratio(:)
452TYPE(datetime),INTENT(in),OPTIONAL :: start
453LOGICAL,INTENT(in),OPTIONAL :: full_steps
454
455INTEGER :: i, j, k, l, na, nf, n
456INTEGER :: steps, p1, maxp1, maxp2, minp1mp2, dstart, msteps
457INTEGER(kind=int_ll) :: stepms, mstepms
458LOGICAL :: lforecast
459TYPE(datetime) :: lstart, lend, pstart1, pstart2, pend1, pend2, reftime1, reftime2, tmptime
460TYPE(arrayof_datetime) :: a_otime
461TYPE(arrayof_vol7d_timerange) :: a_otimerange
462TYPE(arrayof_integer) :: a_dtratio
463LOGICAL,ALLOCATABLE :: mask_timerange(:) ! improve !!!!
464TYPE(ttr_mapper) :: lmapper
465CHARACTER(len=8) :: env_var
466LOGICAL :: climat_behavior
467
468
469! enable bad behavior for climat database (only for instantaneous data)
470env_var = ''
471CALL getenv('LIBSIM_CLIMAT_BEHAVIOR', env_var)
472climat_behavior = len_trim(env_var) > 0 .AND. .NOT.PRESENT(dtratio)
473
474! compute length of cumulation step in seconds
475CALL getval(timedelta_depop(step), asec=steps)
476
477! create a mask of suitable timeranges
478ALLOCATE(mask_timerange(SIZE(itimerange)))
479mask_timerange(:) = itimerange(:)%timerange == tri &
480 .AND. itimerange(:)%p1 /= imiss .AND. itimerange(:)%p1 >= 0
481
482IF (PRESENT(dtratio)) THEN
483 WHERE(itimerange(:)%p2 > 0 .AND. itimerange(:)%p2 /= imiss) ! for avoiding FPE MOD(steps, 0)
484 mask_timerange(:) = mask_timerange(:) .AND. mod(steps, itimerange(:)%p2) == 0
485 ELSEWHERE
486 mask_timerange(:) = .false.
487 END WHERE
488ELSE ! instantaneous
489 mask_timerange(:) = mask_timerange(:) .AND. itimerange(:)%p2 == 0
490ENDIF
491
492#ifdef DEBUG
493CALL l4f_log(l4f_debug, &
494 '(re)compute_stat_proc_agg, number of useful timeranges before choosing analysis/forecast: '// &
495 t2c(count(mask_timerange)))
496#endif
497
498! euristically determine whether we are dealing with an
499! analysis/observation or a forecast dataset
500na = count(mask_timerange(:) .AND. itimerange(:)%p1 == 0)
501nf = count(mask_timerange(:) .AND. itimerange(:)%p1 > 0)
502lforecast = nf >= na
503#ifdef DEBUG
504CALL l4f_log(l4f_debug, &
505 'recompute_stat_proc_agg, na: '//t2c(na)//', nf: '//t2c(nf))
506#endif
507
508! keep only timeranges of one type (really necessary?)
509IF (lforecast) THEN
510 CALL l4f_log(l4f_info, &
511 'recompute_stat_proc_agg, processing in forecast mode')
512ELSE
513 mask_timerange(:) = mask_timerange(:) .AND. itimerange(:)%p1 == 0
514 CALL l4f_log(l4f_info, &
515 'recompute_stat_proc_agg, processing in analysis mode')
516ENDIF
517
518#ifdef DEBUG
519CALL l4f_log(l4f_debug, &
520 '(re)compute_stat_proc_agg, number of useful timeranges: '// &
521 t2c(count(mask_timerange)))
522#endif
523
524IF (SIZE(itime) == 0 .OR. count(mask_timerange) == 0) THEN ! avoid segmentation fault in case of empty volume
525 ALLOCATE(otime(0), otimerange(0), map_ttr(0,0))
526 IF (PRESENT(dtratio)) ALLOCATE(dtratio(0))
527 RETURN
528ENDIF
529
530! determine start and end of processing period, should work with p2==0
531lstart = datetime_miss
532IF (PRESENT(start)) lstart = start
533lend = itime(SIZE(itime))
534! compute some quantities
535maxp1 = maxval(itimerange(:)%p1, mask=mask_timerange)
536maxp2 = maxval(itimerange(:)%p2, mask=mask_timerange)
537minp1mp2 = minval(itimerange(:)%p1 - itimerange(:)%p2, mask=mask_timerange)
538IF (time_definition == 0) THEN ! reference time
539 lend = lend + timedelta_new(sec=maxp1)
540ENDIF
541! extend interval at the end in order to include all the data in case
542! frac_valid<1; must use < and not <= in the DO WHILE loops some lines
543! below in order to exclude the last full interval which would be empty
544lend = lend + step
545IF (lstart == datetime_miss) THEN ! autodetect
546 lstart = itime(1)
547! if autodetected, adjust to obtain real absolute start of data
548 IF (time_definition == 0) THEN ! reference time
549 lstart = lstart + timedelta_new(sec=minp1mp2)
550 ELSE ! verification time
551! go back to start of longest processing interval
552 lstart = lstart - timedelta_new(sec=maxp2)
553 ENDIF
554! apply full_steps in analysis mode and when start is not specified
555! (start by itself in analysis mode implies full_steps with respect to
556! start instead of absolute full steps), todo in forecast mode
557 IF (optio_log(full_steps) .AND. .NOT.lforecast) THEN
558 lstart = lstart - (mod(lstart, step)) ! round to step, (should be MODULO, not MOD)
559 ENDIF
560ENDIF
561
562#ifdef DEBUG
563CALL l4f_log(l4f_debug, &
564 'recompute_stat_proc_agg, processing period: '//t2c(lstart)//' - '//t2c(lend))
565#endif
567! create output time and timerange lists
568
569IF (lforecast) THEN ! forecast mode
570 IF (time_definition == 0) THEN ! reference time
571 CALL insert(a_otime, itime) ! should I limit to elements itime >= lstart?
572
573! apply start shift to timerange, not to reftime
574! why did we use itime(SIZE(itime)) (last ref time)?
575! CALL getval(lstart-itime(SIZE(itime)), asec=dstart)
576 CALL getval(lstart-itime(1), asec=dstart)
577! allow starting before first reftime but restrict dtstart to -steps
578! dstart = MAX(0, dstart)
579 IF (dstart < 0) dstart = mod(dstart, steps)
580 DO p1 = steps + dstart, maxp1, steps
581 CALL insert_unique(a_otimerange, vol7d_timerange_new(stat_proc, p1, steps))
582 ENDDO
583
584 ELSE ! verification time
585
586! verification time in forecast mode is the ugliest case, because we
587! don't know a priori how many different (thus incompatible) reference
588! times we have, so some assumption of regularity has to be made. For
589! this reason msteps, the minimum step between two times, is
590! computed. We choose to compute it as a difference between itime
591! elements, it could be also computed as difference of itimerange%p1
592! elements. But what if it is not modulo steps?
593 mstepms = steps*1000_int_ll
594 DO i = 2, SIZE(itime)
595 CALL getval(itime(i)-itime(i-1), amsec=stepms)
596 IF (stepms > 0_int_ll .AND. stepms < mstepms) THEN
597 msteps = stepms/1000_int_ll
598 IF (mod(steps, msteps) == 0) mstepms = stepms
599 ENDIF
600 ENDDO
601 msteps = mstepms/1000_int_ll
602
603 tmptime = lstart + step
604 DO WHILE(tmptime < lend) ! < since lend has been extended
605 CALL insert_unique(a_otime, tmptime)
606 tmptime = tmptime + step
607 ENDDO
609! in next loop, we used initially steps instead of msteps (see comment
610! above), this gave much less combinations of time/timeranges with
611! possible empty output; we start from msteps instead of steps in
612! order to include partial initial intervals in case frac_valid<1;
613! however, as a gemeral rule, for aggregation of forecasts it's better
614! to use reference time
615 DO p1 = msteps, maxp1, msteps
616 CALL insert_unique(a_otimerange, vol7d_timerange_new(stat_proc, p1, steps))
617 ENDDO
618
619 ENDIF
620
621ELSE ! analysis mode
622 tmptime = lstart + step
623 DO WHILE(tmptime < lend) ! < since lend has been extended
624 CALL insert_unique(a_otime, tmptime)
625 tmptime = tmptime + step
626 ENDDO
627 CALL insert_unique(a_otimerange, vol7d_timerange_new(stat_proc, 0, steps))
628
629ENDIF
630
631CALL packarray(a_otime)
632CALL packarray(a_otimerange)
633otime => a_otime%array
634otimerange => a_otimerange%array
635CALL sort(otime)
636CALL sort(otimerange)
637! delete local objects keeping the contents
638CALL delete(a_otime, nodealloc=.true.)
639CALL delete(a_otimerange, nodealloc=.true.)
640
641#ifdef DEBUG
642CALL l4f_log(l4f_debug, &
643 'recompute_stat_proc_agg, output time and timerange: '//&
644 t2c(SIZE(otime))//', '//t2c(size(otimerange)))
645#endif
646
647IF (PRESENT(dtratio)) THEN
648! count the possible i/o interval ratios
649 DO k = 1, SIZE(itimerange)
650 IF (itimerange(k)%p2 /= 0) &
651 CALL insert_unique(a_dtratio, steps/itimerange(k)%p2) ! guaranteed to be integer
652 ENDDO
653 CALL packarray(a_dtratio)
654 dtratio => a_dtratio%array
655 CALL sort(dtratio)
656! delete local object keeping the contents
657 CALL delete(a_dtratio, nodealloc=.true.)
658
659#ifdef DEBUG
660 CALL l4f_log(l4f_debug, &
661 'recompute_stat_proc_agg, found '//t2c(size(dtratio))// &
662 ' possible aggregation ratios, from '// &
663 t2c(dtratio(1))//' to '//t2c(dtratio(SIZE(dtratio))))
664#endif
665
666 ALLOCATE(map_ttr(SIZE(otime),SIZE(otimerange)))
667 do_itimerange1: DO l = 1, SIZE(itimerange)
668 IF (.NOT.mask_timerange(l)) cycle do_itimerange1
669 do_itime1: DO k = 1, SIZE(itime)
670 CALL time_timerange_get_period(itime(k), itimerange(l), &
671 time_definition, pstart1, pend1, reftime1)
672 do_otimerange1: DO j = 1, SIZE(otimerange)
673 do_otime1: DO i = 1, SIZE(otime)
674 CALL time_timerange_get_period_pop(otime(i), otimerange(j), step, &
675 time_definition, pstart2, pend2, reftime2)
676 IF (lforecast) THEN
677 IF (reftime1 /= reftime2) cycle do_otime1
678 ENDIF
679
680 IF (pstart1 >= pstart2 .AND. pend1 <= pend2 .AND. &
681 mod(pstart1-pstart2, pend1-pstart1) == timedelta_0) THEN ! useful
682 lmapper%it = k
683 lmapper%itr = l
684 lmapper%extra_info = steps/itimerange(l)%p2 ! dtratio, guaranteed to be integer
685 n = append(map_ttr(i,j), lmapper)
686 cycle do_itime1 ! can contribute only to a single interval
687 ENDIF
688 ENDDO do_otime1
689 ENDDO do_otimerange1
690 ENDDO do_itime1
691 ENDDO do_itimerange1
692
693ELSE
694
695 ALLOCATE(map_ttr(SIZE(otime),SIZE(otimerange)))
696 do_itimerange2: DO l = 1, SIZE(itimerange)
697 IF (.NOT.mask_timerange(l)) cycle do_itimerange2
698 do_itime2: DO k = 1, SIZE(itime)
699 CALL time_timerange_get_period(itime(k), itimerange(l), &
700 time_definition, pstart1, pend1, reftime1)
701 do_otimerange2: DO j = 1, SIZE(otimerange)
702 do_otime2: DO i = 1, SIZE(otime)
703 CALL time_timerange_get_period_pop(otime(i), otimerange(j), step, &
704 time_definition, pstart2, pend2, reftime2)
705 IF (lforecast) THEN
706 IF (reftime1 /= reftime2) cycle do_otime2
707 ENDIF
708
709 IF (climat_behavior .AND. pstart1 == pstart2) cycle do_otime2
710 IF (pstart1 >= pstart2 .AND. pend1 <= pend2) THEN ! useful
711 lmapper%it = k
712 lmapper%itr = l
713 IF (pstart1 == pstart2) THEN
714 lmapper%extra_info = 1 ! start of interval
715 ELSE IF (pend1 == pend2) THEN
716 lmapper%extra_info = 2 ! end of interval
717 ELSE
718 lmapper%extra_info = imiss
719 ENDIF
720 lmapper%time = pstart1 ! = pend1, order by time?
721 n = insert_sorted(map_ttr(i,j), lmapper, .true., .true.)
722! no CYCLE, a single input can contribute to multiple output intervals
723 ENDIF
724 ENDDO do_otime2
725 ENDDO do_otimerange2
726 ENDDO do_itime2
727 ENDDO do_itimerange2
728
729ENDIF
730
731END SUBROUTINE recompute_stat_proc_agg_common
732
733
734SUBROUTINE compute_stat_proc_agg_sw(vertime, pstart, pend, time_mask, &
735 max_step, weights)
736TYPE(datetime),INTENT(in) :: vertime(:)
737TYPE(datetime),INTENT(in) :: pstart
738TYPE(datetime),INTENT(in) :: pend
739LOGICAL,INTENT(in) :: time_mask(:)
740TYPE(timedelta),OPTIONAL,INTENT(out) :: max_step
741DOUBLE PRECISION,OPTIONAL,INTENT(out) :: weights(:)
742
743INTEGER :: i, nt
744TYPE(datetime),ALLOCATABLE :: lvertime(:)
745TYPE(datetime) :: half, nexthalf
746INTEGER(kind=int_ll) :: dt, tdt
747
748nt = count(time_mask)
749ALLOCATE(lvertime(nt))
750lvertime = pack(vertime, mask=time_mask)
751
752IF (PRESENT(max_step)) THEN
753! new way
754! max_step = timedelta_0
755! DO i = 1, nt - 1
756! IF (lvertime(i+1) - lvertime(i) > max_step) &
757! max_step = lvertime(i+1) - lvertime(i)
758! ENDDO
759! IF (lvertime(1) - pstart > max_step) max_step = lvertime(1) - pstart
760! IF (pend - lvertime(nt) > max_step) max_step = pend - lvertime(nt)
761! old way
762 IF (nt == 1) THEN
763 max_step = pend - pstart
764 ELSE
765 half = lvertime(1) + (lvertime(2) - lvertime(1))/2
766 max_step = half - pstart
767 DO i = 2, nt - 1
768 nexthalf = lvertime(i) + (lvertime(i+1) - lvertime(i))/2
769 IF (nexthalf - half > max_step) max_step = nexthalf - half
770 half = nexthalf
771 ENDDO
772 IF (pend - half > max_step) max_step = pend - half
773 ENDIF
774
775ENDIF
776
777IF (PRESENT(weights)) THEN
778 IF (nt == 1) THEN
779 weights(1) = 1.0
780 ELSE
781 CALL getval(pend - pstart, amsec=tdt)
782 half = lvertime(1) + (lvertime(2) - lvertime(1))/2
783 CALL getval(half - pstart, amsec=dt)
784 weights(1) = dble(dt)/dble(tdt)
785 DO i = 2, nt - 1
786 nexthalf = lvertime(i) + (lvertime(i+1) - lvertime(i))/2
787 CALL getval(nexthalf - half, amsec=dt)
788 weights(i) = dble(dt)/dble(tdt)
789 half = nexthalf
790 ENDDO
791 CALL getval(pend - half, amsec=dt)
792 weights(nt) = dble(dt)/dble(tdt)
793 ENDIF
794ENDIF
795
796END SUBROUTINE compute_stat_proc_agg_sw
797
798! get start of period, end of period and reference time from time,
799! timerange, according to time_definition.
800SUBROUTINE time_timerange_get_period(time, timerange, time_definition, &
801 pstart, pend, reftime)
802TYPE(datetime),INTENT(in) :: time
803TYPE(vol7d_timerange),INTENT(in) :: timerange
804INTEGER,INTENT(in) :: time_definition
805TYPE(datetime),INTENT(out) :: reftime
806TYPE(datetime),INTENT(out) :: pstart
807TYPE(datetime),INTENT(out) :: pend
808
809TYPE(timedelta) :: p1, p2
810
811
812p1 = timedelta_new(sec=timerange%p1) ! end of period
813p2 = timedelta_new(sec=timerange%p2) ! length of period
814
815IF (time == datetime_miss .OR. .NOT.c_e(timerange%p1) .OR. .NOT.c_e(timerange%p2) .OR. &
816! (timerange%p1 > 0 .AND. timerange%p1 < timerange%p2) .OR. &
817 timerange%p1 < 0 .OR. timerange%p2 < 0) THEN ! is this too pedantic and slow?
818 pstart = datetime_miss
819 pend = datetime_miss
820 reftime = datetime_miss
821 RETURN
822ENDIF
823
824IF (time_definition == 0) THEN ! time == reference time
825 reftime = time
826 pend = time + p1
827 pstart = pend - p2
828ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
829 pend = time
830 pstart = time - p2
831 reftime = time - p1
832ELSE
833 pstart = datetime_miss
834 pend = datetime_miss
835 reftime = datetime_miss
836ENDIF
837
838END SUBROUTINE time_timerange_get_period
839
840
841! get start of period, end of period and reference time from time,
842! timerange, according to time_definition.
843SUBROUTINE ttr_decoder_decode(time, timerange, time_definition, decoded)
844TYPE(datetime),INTENT(in) :: time
845TYPE(vol7d_timerange),INTENT(in) :: timerange
846INTEGER,INTENT(in) :: time_definition
847TYPE(ttr_decoder),INTENT(out) :: decoded
848
849TYPE(timedelta) :: p1, p2
850
851
852p1 = timedelta_new(sec=timerange%p1) ! end of period
853p2 = timedelta_new(sec=timerange%p2) ! length of period
854
855IF (time == datetime_miss .OR. .NOT.c_e(timerange%p1) .OR. .NOT.c_e(timerange%p2) .OR. &
856! (timerange%p1 > 0 .AND. timerange%p1 < timerange%p2) .OR. &
857 timerange%p1 < 0 .OR. timerange%p2 < 0) THEN ! is this too pedantic and slow?
858 decoded%pstart = datetime_miss
859 decoded%pend = datetime_miss
860 decoded%reftime = datetime_miss
861 RETURN
862ENDIF
863
864IF (time_definition == 0) THEN ! time == reference time
865 decoded%reftime = time
866 decoded%pend = time + p1
867 decoded%pstart = decoded%pend - p2
868ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
869 decoded%pend = time
870 decoded%pstart = time - p2
871 decoded%reftime = time - p1
872ELSE
873 decoded%pstart = datetime_miss
874 decoded%pend = datetime_miss
875 decoded%reftime = datetime_miss
876ENDIF
877
878END SUBROUTINE ttr_decoder_decode
879
880
881! get start of period, end of period and reference time from time,
882! timerange, according to time_definition. step is taken separately
883! from timerange and can be "popular"
884SUBROUTINE time_timerange_get_period_pop(time, timerange, step, time_definition, &
885 pstart, pend, reftime)
886TYPE(datetime),INTENT(in) :: time
887TYPE(vol7d_timerange),INTENT(in) :: timerange
888TYPE(timedelta),INTENT(in) :: step
889INTEGER,INTENT(in) :: time_definition
890TYPE(datetime),INTENT(out) :: reftime
891TYPE(datetime),INTENT(out) :: pstart
892TYPE(datetime),INTENT(out) :: pend
893
894TYPE(timedelta) :: p1
895
896
897p1 = timedelta_new(sec=timerange%p1) ! end of period
898
899IF (time == datetime_miss .OR. .NOT.c_e(timerange%p1) .OR. .NOT.c_e(timerange%p2) .OR. &
900! (timerange%p1 > 0 .AND. timerange%p1 < timerange%p2) .OR. &
901 timerange%p1 < 0 .OR. timerange%p2 < 0) THEN ! is this too pedantic and slow?
902 pstart = datetime_miss
903 pend = datetime_miss
904 reftime = datetime_miss
905 RETURN
906ENDIF
907
908IF (time_definition == 0) THEN ! time == reference time
909 reftime = time
910 pend = time + p1
911 pstart = pend - step
912ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
913 pend = time
914 pstart = time - step
915 reftime = time - p1
916ELSE
917 pstart = datetime_miss
918 pend = datetime_miss
919 reftime = datetime_miss
920ENDIF
921
922END SUBROUTINE time_timerange_get_period_pop
923
924
925! get start of period, end of period and reference time from time,
926! timerange, according to time_definition. step is taken separately
927! from timerange and can be "popular"
928SUBROUTINE ttr_decoder_decode_pop(time, timerange, step, time_definition, decoded)
929TYPE(datetime),INTENT(in) :: time
930TYPE(vol7d_timerange),INTENT(in) :: timerange
931TYPE(timedelta),INTENT(in) :: step
932INTEGER,INTENT(in) :: time_definition
933TYPE(ttr_decoder),INTENT(out) :: decoded
934
935TYPE(timedelta) :: p1
936
937
938p1 = timedelta_new(sec=timerange%p1) ! end of period
939
940IF (time == datetime_miss .OR. .NOT.c_e(timerange%p1) .OR. .NOT.c_e(timerange%p2) .OR. &
941! (timerange%p1 > 0 .AND. timerange%p1 < timerange%p2) .OR. &
942 timerange%p1 < 0 .OR. timerange%p2 < 0) THEN ! is this too pedantic and slow?
943 decoded%pstart = datetime_miss
944 decoded%pend = datetime_miss
945 decoded%reftime = datetime_miss
946 RETURN
947ENDIF
948
949IF (time_definition == 0) THEN ! time == reference time
950 decoded%reftime = time
951 decoded%pend = time + p1
952 decoded%pstart = decoded%pend - step
953ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
954 decoded%pend = time
955 decoded%pstart = time - step
956 decoded%reftime = time - p1
957ELSE
958 decoded%pstart = datetime_miss
959 decoded%pend = datetime_miss
960 decoded%reftime = datetime_miss
961ENDIF
962
963END SUBROUTINE ttr_decoder_decode_pop
964
965
966! set time, timerange%p1, timerange%p2 according to pstart, pend,
967! reftime and time_definition.
968SUBROUTINE time_timerange_set_period(time, timerange, time_definition, &
969 stat_proc, pstart, pend, reftime)
970TYPE(datetime),INTENT(out) :: time
971TYPE(vol7d_timerange),INTENT(out) :: timerange
972INTEGER,INTENT(in) :: time_definition
973INTEGER,INTENT(in) :: stat_proc
974TYPE(datetime),INTENT(in) :: pstart
975TYPE(datetime),INTENT(in) :: pend
976TYPE(datetime),INTENT(in) :: reftime
977
978TYPE(timedelta) :: p1, p2
979INTEGER(kind=int_ll) :: dmsec
980
981
982IF (time_definition == 0) THEN ! time == reference time
983 time = reftime
984 p1 = pend - reftime
985 p2 = pend - pstart
986ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
987 time = pend
988 p1 = pend - reftime
989 p2 = pend - pstart
990ELSE
991 time = datetime_miss
992ENDIF
993
994timerange%timerange = stat_proc
995IF (time /= datetime_miss) THEN
996 CALL getval(p1, amsec=dmsec) ! end of period
997 timerange%p1 = int(dmsec/1000_int_ll)
998 CALL getval(p2, amsec=dmsec) ! length of period
999 timerange%p2 = int(dmsec/1000_int_ll)
1000ELSE
1001 timerange%p1 = imiss
1002 timerange%p2 = imiss
1003ENDIF
1004
1005END SUBROUTINE time_timerange_set_period
1006
1007
1008END MODULE stat_proc_engine
Restituiscono il valore dell'oggetto nella forma desiderata.
Operatore di resto della divisione.
Functions that return a trimmed CHARACTER representation of the input variable.
Index method.
Quick method to append an element to the array.
Destructor for finalizing an array object.
Index method with sorted array.
Method for inserting elements of the array at a desired position.
Method for packing the array object reducing at a minimum the memory occupation, without destroying i...
Method for removing elements of the array at a desired position.
Classi per la gestione delle coordinate temporali.
This module contains functions that are only for internal use of the library.
Classe per la gestione di un volume completo di dati osservati.
Derived type defining a dynamically extensible array of TYPE(datetime) elements.
Class for expressing an absolute time value.
Class for expressing a relative time interval.
Derived type defining a dynamically extensible array of TYPE(ttr_mapper) elements.

Generated with Doxygen.