libsim  Versione8.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 
23 MODULE stat_proc_engine
25 USE vol7d_class
26 IMPLICIT 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
30 TYPE 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
35 END TYPE ttr_mapper
36 
37 INTERFACE OPERATOR (==)
38  MODULE PROCEDURE ttr_mapper_eq
39 END INTERFACE
40 
41 INTERFACE OPERATOR (/=)
42  MODULE PROCEDURE ttr_mapper_ne
43 END INTERFACE
44 
45 INTERFACE OPERATOR (>)
46  MODULE PROCEDURE ttr_mapper_gt
47 END INTERFACE
48 
49 INTERFACE OPERATOR (<)
50  MODULE PROCEDURE ttr_mapper_lt
51 END INTERFACE
52 
53 INTERFACE OPERATOR (>=)
54  MODULE PROCEDURE ttr_mapper_ge
55 END INTERFACE
56 
57 INTERFACE OPERATOR (<=)
58  MODULE PROCEDURE ttr_mapper_le
59 END 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 
76 TYPE,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.
81 END TYPE ttr_decoder
82 
83 CONTAINS
84 
85 ! simplified comparisons only on time
86 ELEMENTAL FUNCTION ttr_mapper_eq(this, that) RESULT(res)
87 TYPE(ttr_mapper),INTENT(IN) :: this, that
88 LOGICAL :: res
89 
90 res = this%time == that%time
91 
92 END FUNCTION ttr_mapper_eq
93 
94 ELEMENTAL FUNCTION ttr_mapper_ne(this, that) RESULT(res)
95 TYPE(ttr_mapper),INTENT(IN) :: this, that
96 LOGICAL :: res
97 
98 res = this%time /= that%time
99 
100 END FUNCTION ttr_mapper_ne
101 
102 ELEMENTAL FUNCTION ttr_mapper_gt(this, that) RESULT(res)
103 TYPE(ttr_mapper),INTENT(IN) :: this, that
104 LOGICAL :: res
105 
106 res = this%time > that%time
107 
108 END FUNCTION ttr_mapper_gt
109 
110 ELEMENTAL FUNCTION ttr_mapper_lt(this, that) RESULT(res)
111 TYPE(ttr_mapper),INTENT(IN) :: this, that
112 LOGICAL :: res
113 
114 res = this%time < that%time
115 
116 END FUNCTION ttr_mapper_lt
117 
118 ELEMENTAL FUNCTION ttr_mapper_ge(this, that) RESULT(res)
119 TYPE(ttr_mapper),INTENT(IN) :: this, that
120 LOGICAL :: res
121 
122 res = this%time >= that%time
123 
124 END FUNCTION ttr_mapper_ge
125 
126 ELEMENTAL FUNCTION ttr_mapper_le(this, that) RESULT(res)
127 TYPE(ttr_mapper),INTENT(IN) :: this, that
128 LOGICAL :: res
129 
130 res = this%time <= that%time
131 
132 END 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
139 SUBROUTINE recompute_stat_proc_diff_common(itime, itimerange, stat_proc, step, &
140  otime, otimerange, map_tr, f, keep_tr, time_definition, full_steps, &
141  start)
142 TYPE(datetime),INTENT(in) :: itime(:)
143 TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
144 INTEGER,INTENT(in) :: stat_proc
145 TYPE(timedelta),INTENT(in) :: step
146 TYPE(datetime),POINTER :: otime(:)
147 TYPE(vol7d_timerange),POINTER :: otimerange(:)
148 INTEGER,ALLOCATABLE,INTENT(out) :: map_tr(:,:,:,:,:), f(:), keep_tr(:,:,:)
149 INTEGER :: nitr
150 LOGICAL,ALLOCATABLE :: mask_timerange(:)
151 INTEGER,INTENT(in) :: time_definition
152 LOGICAL,INTENT(in),OPTIONAL :: full_steps
153 TYPE(datetime),INTENT(in),OPTIONAL :: start
154 
155 INTEGER :: i, j, k, l, dirtyrep
156 INTEGER :: steps
157 LOGICAL :: lfull_steps, useful
158 TYPE(datetime) :: lstart, tmptime ! pstart1, pstart2, pend1, pend2, reftime1, reftime2
159 TYPE(vol7d_timerange) :: tmptimerange
160 TYPE(arrayof_datetime) :: a_otime
161 TYPE(arrayof_vol7d_timerange) :: a_otimerange
162 TYPE(timedelta) :: start_delta
163 TYPE(ttr_decoder),ALLOCATABLE :: ttr_d(:,:)
164 
165 ! compute length of cumulation step in seconds
166 CALL getval(step, asec=steps)
167 
168 lstart = datetime_miss
169 IF (PRESENT(start)) lstart = start
170 lfull_steps = optio_log(full_steps)
171 
172 ! create a mask of suitable timeranges
173 ALLOCATE(mask_timerange(SIZE(itimerange)))
174 mask_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 
179 IF (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
184 ENDIF
185 ! mask_timerange includes all candidate timeranges
186 
187 nitr = count(mask_timerange)
188 ALLOCATE(f(nitr))
189 j = 1
190 DO i = 1, nitr
191  DO WHILE(.NOT.mask_timerange(j))
192  j = j + 1
193  ENDDO
194  f(i) = j
195  j = j + 1
196 ENDDO
197 
198 ALLOCATE(map_tr(nitr, SIZE(itime), nitr, SIZE(itime), 2))
199 map_tr(:,:,:,:,:) = imiss
200 
201 ! precompute ttr
202 ALLOCATE(ttr_d(nitr,SIZE(itime)))
203 DO 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
209 ENDDO
210 
211 ! now we have to evaluate time/timerage pairs which do not need processing
212 ALLOCATE(keep_tr(nitr, SIZE(itime), 2))
213 CALL compute_keep_tr()
214 
215 ! scan through all possible combinations of time and timerange
216 DO 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
293 
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
322 ENDDO
323 
324 ! we have to repeat the computation with sorted arrays
325 CALL compute_keep_tr()
326 
327 otime => a_otime%array
328 otimerange => a_otimerange%array
329 ! delete local objects keeping the contents
330 CALL delete(a_otime, nodealloc=.true.)
331 CALL delete(a_otimerange, nodealloc=.true.)
332 
333 #ifdef DEBUG
334 CALL 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))))
339 CALL l4f_log(l4f_debug, &
340  'recompute_stat_proc_diff, map_tr: '//t2c((SIZE(map_tr))/2)//', '// &
341  t2c(count(c_e(map_tr))/2))
342 CALL l4f_log(l4f_debug, &
343  'recompute_stat_proc_diff, nitr: '//t2c(nitr))
344 CALL l4f_log(l4f_debug, &
345  'recompute_stat_proc_diff, good timeranges: '//t2c(count(c_e(keep_tr))/2))
346 CALL l4f_log(l4f_debug, &
347  'recompute_stat_proc_diff, output times: '//t2c(SIZE(otime)))
348 CALL l4f_log(l4f_debug, &
349  'recompute_stat_proc_diff, output timeranges: '//t2c(SIZE(otimerange)))
350 #endif
351 
352 CONTAINS
353 
354 SUBROUTINE compute_keep_tr()
355 INTEGER :: start_deltas
357 keep_tr(:,:,:) = imiss
358 DO 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
403 ENDDO
404 
405 END SUBROUTINE compute_keep_tr
406 
407 END SUBROUTINE recompute_stat_proc_diff_common
408 
409 
410 ! common operations for statistical processing by metamorphosis
411 SUBROUTINE compute_stat_proc_metamorph_common(istat_proc, itimerange, ostat_proc, &
412  otimerange, map_tr)
413 INTEGER,INTENT(in) :: istat_proc
414 TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
415 INTEGER,INTENT(in) :: ostat_proc
416 TYPE(vol7d_timerange),POINTER :: otimerange(:)
417 INTEGER,POINTER :: map_tr(:)
418 
419 INTEGER :: i
420 LOGICAL :: tr_mask(SIZE(itimerange))
421 
422 IF (SIZE(itimerange) == 0) THEN ! avoid segmentation fault in case of empty volume
423  ALLOCATE(otimerange(0), map_tr(0))
424  RETURN
425 ENDIF
426 
427 ! useful timeranges
428 tr_mask(:) = itimerange(:)%timerange == istat_proc .AND. itimerange(:)%p2 /= imiss &
429  .AND. itimerange(:)%p2 /= 0 ! .AND. itimerange(:)%p1 == 0
430 ALLOCATE(otimerange(count(tr_mask)), map_tr(count(tr_mask)))
431 
432 otimerange = pack(itimerange, mask=tr_mask)
433 otimerange(:)%timerange = ostat_proc
434 map_tr = pack((/(i,i=1,SIZE(itimerange))/), mask=tr_mask)
435 
436 END SUBROUTINE compute_stat_proc_metamorph_common
437 
438 
439 ! common operations for statistical processing by aggregation
440 SUBROUTINE recompute_stat_proc_agg_common(itime, itimerange, stat_proc, tri, &
441  step, time_definition, otime, otimerange, map_ttr, dtratio, start, full_steps)
442 TYPE(datetime),INTENT(in) :: itime(:)
443 TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
444 INTEGER,INTENT(in) :: stat_proc
445 INTEGER,INTENT(in) :: tri
446 TYPE(timedelta),INTENT(in) :: step
447 INTEGER,INTENT(in) :: time_definition
448 TYPE(datetime),POINTER :: otime(:)
449 TYPE(vol7d_timerange),POINTER :: otimerange(:)
450 TYPE(arrayof_ttr_mapper),POINTER :: map_ttr(:,:)
451 INTEGER,POINTER,OPTIONAL :: dtratio(:)
452 TYPE(datetime),INTENT(in),OPTIONAL :: start
453 LOGICAL,INTENT(in),OPTIONAL :: full_steps
454 
455 INTEGER :: i, j, k, l, na, nf, n
456 INTEGER :: steps, p1, maxp1, maxp2, minp1mp2, dstart, msteps
457 INTEGER(kind=int_ll) :: stepms, mstepms
458 LOGICAL :: lforecast
459 TYPE(datetime) :: lstart, lend, pstart1, pstart2, pend1, pend2, reftime1, reftime2, tmptime
460 TYPE(arrayof_datetime) :: a_otime
461 TYPE(arrayof_vol7d_timerange) :: a_otimerange
462 TYPE(arrayof_integer) :: a_dtratio
463 LOGICAL,ALLOCATABLE :: mask_timerange(:) ! improve !!!!
464 TYPE(ttr_mapper) :: lmapper
465 CHARACTER(len=8) :: env_var
466 LOGICAL :: climat_behavior
467 
468 
469 ! enable bad behavior for climat database (only for instantaneous data)
470 env_var = ''
471 CALL getenv('LIBSIM_CLIMAT_BEHAVIOR', env_var)
472 climat_behavior = len_trim(env_var) > 0 .AND. .NOT.PRESENT(dtratio)
473 
474 ! compute length of cumulation step in seconds
475 CALL getval(timedelta_depop(step), asec=steps)
476 
477 ! create a mask of suitable timeranges
478 ALLOCATE(mask_timerange(SIZE(itimerange)))
479 mask_timerange(:) = itimerange(:)%timerange == tri &
480  .AND. itimerange(:)%p1 /= imiss .AND. itimerange(:)%p1 >= 0
481 
482 IF (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
488 ELSE ! instantaneous
489  mask_timerange(:) = mask_timerange(:) .AND. itimerange(:)%p2 == 0
490 ENDIF
491 
492 #ifdef DEBUG
493 CALL 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
500 na = count(mask_timerange(:) .AND. itimerange(:)%p1 == 0)
501 nf = count(mask_timerange(:) .AND. itimerange(:)%p1 > 0)
502 lforecast = nf >= na
503 #ifdef DEBUG
504 CALL l4f_log(l4f_debug, &
505  'recompute_stat_proc_agg, na: '//t2c(na)//', nf: '//t2c(nf))
506 #endif
508 ! keep only timeranges of one type (really necessary?)
509 IF (lforecast) THEN
510  CALL l4f_log(l4f_info, &
511  'recompute_stat_proc_agg, processing in forecast mode')
512 ELSE
513  mask_timerange(:) = mask_timerange(:) .AND. itimerange(:)%p1 == 0
514  CALL l4f_log(l4f_info, &
515  'recompute_stat_proc_agg, processing in analysis mode')
516 ENDIF
517 
518 #ifdef DEBUG
519 CALL l4f_log(l4f_debug, &
520  '(re)compute_stat_proc_agg, number of useful timeranges: '// &
521  t2c(count(mask_timerange)))
522 #endif
523 
524 IF (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
528 ENDIF
529 
530 ! determine start and end of processing period, should work with p2==0
531 lstart = datetime_miss
532 IF (PRESENT(start)) lstart = start
533 lend = itime(SIZE(itime))
534 ! compute some quantities
535 maxp1 = maxval(itimerange(:)%p1, mask=mask_timerange)
536 maxp2 = maxval(itimerange(:)%p2, mask=mask_timerange)
537 minp1mp2 = minval(itimerange(:)%p1 - itimerange(:)%p2, mask=mask_timerange)
538 IF (time_definition == 0) THEN ! reference time
539  lend = lend + timedelta_new(sec=maxp1)
540 ENDIF
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
544 lend = lend + step
545 IF (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
560 ENDIF
561 
562 #ifdef DEBUG
563 CALL l4f_log(l4f_debug, &
564  'recompute_stat_proc_agg, processing period: '//t2c(lstart)//' - '//t2c(lend))
565 #endif
566 
567 ! create output time and timerange lists
568 
569 IF (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
608 
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 
621 ELSE ! 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 
629 ENDIF
630 
631 CALL packarray(a_otime)
632 CALL packarray(a_otimerange)
633 otime => a_otime%array
634 otimerange => a_otimerange%array
635 CALL sort(otime)
636 CALL sort(otimerange)
637 ! delete local objects keeping the contents
638 CALL delete(a_otime, nodealloc=.true.)
639 CALL delete(a_otimerange, nodealloc=.true.)
640 
641 #ifdef DEBUG
642 CALL l4f_log(l4f_debug, &
643  'recompute_stat_proc_agg, output time and timerange: '//&
644  t2c(SIZE(otime))//', '//t2c(size(otimerange)))
645 #endif
646 
647 IF (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 
693 ELSE
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 
729 ENDIF
730 
731 END SUBROUTINE recompute_stat_proc_agg_common
732 
733 
734 SUBROUTINE compute_stat_proc_agg_sw(vertime, pstart, pend, time_mask, &
735  max_step, weights)
736 TYPE(datetime),INTENT(in) :: vertime(:)
737 TYPE(datetime),INTENT(in) :: pstart
738 TYPE(datetime),INTENT(in) :: pend
739 LOGICAL,INTENT(in) :: time_mask(:)
740 TYPE(timedelta),OPTIONAL,INTENT(out) :: max_step
741 DOUBLE PRECISION,OPTIONAL,INTENT(out) :: weights(:)
742 
743 INTEGER :: i, nt
744 TYPE(datetime),ALLOCATABLE :: lvertime(:)
745 TYPE(datetime) :: half, nexthalf
746 INTEGER(kind=int_ll) :: dt, tdt
747 
748 nt = count(time_mask)
749 ALLOCATE(lvertime(nt))
750 lvertime = pack(vertime, mask=time_mask)
751 
752 IF (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 
775 ENDIF
776 
777 IF (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
794 ENDIF
795 
796 END 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.
800 SUBROUTINE time_timerange_get_period(time, timerange, time_definition, &
801  pstart, pend, reftime)
802 TYPE(datetime),INTENT(in) :: time
803 TYPE(vol7d_timerange),INTENT(in) :: timerange
804 INTEGER,INTENT(in) :: time_definition
805 TYPE(datetime),INTENT(out) :: reftime
806 TYPE(datetime),INTENT(out) :: pstart
807 TYPE(datetime),INTENT(out) :: pend
808 
809 TYPE(timedelta) :: p1, p2
810 
811 
812 p1 = timedelta_new(sec=timerange%p1) ! end of period
813 p2 = timedelta_new(sec=timerange%p2) ! length of period
814 
815 IF (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
822 ENDIF
823 
824 IF (time_definition == 0) THEN ! time == reference time
825  reftime = time
826  pend = time + p1
827  pstart = pend - p2
828 ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
829  pend = time
830  pstart = time - p2
831  reftime = time - p1
832 ELSE
833  pstart = datetime_miss
834  pend = datetime_miss
835  reftime = datetime_miss
836 ENDIF
837 
838 END 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.
843 SUBROUTINE ttr_decoder_decode(time, timerange, time_definition, decoded)
844 TYPE(datetime),INTENT(in) :: time
845 TYPE(vol7d_timerange),INTENT(in) :: timerange
846 INTEGER,INTENT(in) :: time_definition
847 TYPE(ttr_decoder),INTENT(out) :: decoded
848 
849 TYPE(timedelta) :: p1, p2
850 
851 
852 p1 = timedelta_new(sec=timerange%p1) ! end of period
853 p2 = timedelta_new(sec=timerange%p2) ! length of period
854 
855 IF (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
862 ENDIF
863 
864 IF (time_definition == 0) THEN ! time == reference time
865  decoded%reftime = time
866  decoded%pend = time + p1
867  decoded%pstart = decoded%pend - p2
868 ELSE 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
872 ELSE
873  decoded%pstart = datetime_miss
874  decoded%pend = datetime_miss
875  decoded%reftime = datetime_miss
876 ENDIF
877 
878 END 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"
884 SUBROUTINE time_timerange_get_period_pop(time, timerange, step, time_definition, &
885  pstart, pend, reftime)
886 TYPE(datetime),INTENT(in) :: time
887 TYPE(vol7d_timerange),INTENT(in) :: timerange
888 TYPE(timedelta),INTENT(in) :: step
889 INTEGER,INTENT(in) :: time_definition
890 TYPE(datetime),INTENT(out) :: reftime
891 TYPE(datetime),INTENT(out) :: pstart
892 TYPE(datetime),INTENT(out) :: pend
893 
894 TYPE(timedelta) :: p1
895 
896 
897 p1 = timedelta_new(sec=timerange%p1) ! end of period
898 
899 IF (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
906 ENDIF
907 
908 IF (time_definition == 0) THEN ! time == reference time
909  reftime = time
910  pend = time + p1
911  pstart = pend - step
912 ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
913  pend = time
914  pstart = time - step
915  reftime = time - p1
916 ELSE
917  pstart = datetime_miss
918  pend = datetime_miss
919  reftime = datetime_miss
920 ENDIF
921 
922 END 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"
928 SUBROUTINE ttr_decoder_decode_pop(time, timerange, step, time_definition, decoded)
929 TYPE(datetime),INTENT(in) :: time
930 TYPE(vol7d_timerange),INTENT(in) :: timerange
931 TYPE(timedelta),INTENT(in) :: step
932 INTEGER,INTENT(in) :: time_definition
933 TYPE(ttr_decoder),INTENT(out) :: decoded
934 
935 TYPE(timedelta) :: p1
936 
937 
938 p1 = timedelta_new(sec=timerange%p1) ! end of period
939 
940 IF (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
947 ENDIF
948 
949 IF (time_definition == 0) THEN ! time == reference time
950  decoded%reftime = time
951  decoded%pend = time + p1
952  decoded%pstart = decoded%pend - step
953 ELSE 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
957 ELSE
958  decoded%pstart = datetime_miss
959  decoded%pend = datetime_miss
960  decoded%reftime = datetime_miss
961 ENDIF
962 
963 END SUBROUTINE ttr_decoder_decode_pop
964 
965 
966 ! set time, timerange%p1, timerange%p2 according to pstart, pend,
967 ! reftime and time_definition.
968 SUBROUTINE time_timerange_set_period(time, timerange, time_definition, &
969  stat_proc, pstart, pend, reftime)
970 TYPE(datetime),INTENT(out) :: time
971 TYPE(vol7d_timerange),INTENT(out) :: timerange
972 INTEGER,INTENT(in) :: time_definition
973 INTEGER,INTENT(in) :: stat_proc
974 TYPE(datetime),INTENT(in) :: pstart
975 TYPE(datetime),INTENT(in) :: pend
976 TYPE(datetime),INTENT(in) :: reftime
977 
978 TYPE(timedelta) :: p1, p2
979 INTEGER(kind=int_ll) :: dmsec
980 
981 
982 IF (time_definition == 0) THEN ! time == reference time
983  time = reftime
984  p1 = pend - reftime
985  p2 = pend - pstart
986 ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
987  time = pend
988  p1 = pend - reftime
989  p2 = pend - pstart
990 ELSE
991  time = datetime_miss
992 ENDIF
993 
994 timerange%timerange = stat_proc
995 IF (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)
1000 ELSE
1001  timerange%p1 = imiss
1002  timerange%p2 = imiss
1003 ENDIF
1004 
1005 END SUBROUTINE time_timerange_set_period
1006 
1007 
1008 END MODULE stat_proc_engine
Functions that return a trimmed CHARACTER representation of the input variable.
Class for expressing an absolute time value.
This module contains functions that are only for internal use of the library.
Classi per la gestione delle coordinate temporali.
Quick method to append an element to the array.
Method for packing the array object reducing at a minimum the memory occupation, without destroying i...
Restituiscono il valore dell&#39;oggetto nella forma desiderata.
Operatore di resto della divisione.
Classe per la gestione di un volume completo di dati osservati.
Class for expressing a relative time interval.
Destructor for finalizing an array object.
Method for inserting elements of the array at a desired position.

Generated with Doxygen.