libsim Versione 8.0.0

◆ sort_ttr_mapper()

subroutine sort_ttr_mapper ( type(ttr_mapper), dimension (:), intent(inout) xdont)

Sorts inline into ascending order - Quicksort Quicksort chooses a "pivot" in the set, and explores the array from both ends, looking for a value > pivot with the increasing index, for a value <= pivot with the decreasing index, and swapping them when it has found one of each.

The array is then subdivided in 2 ([3]) subsets: { values <= pivot} {pivot} {values > pivot} One then call recursively the program to sort each subset. When the size of the subarray is small enough or the maximum level of recursion is gained, one uses an insertion sort that is faster for very small sets.

Parametri
[in,out]xdontvector to sort inline

Definizione alla linea 1501 del file stat_proc_engine.F90.

1502! Copyright (C) 2010 ARPA-SIM <urpsim@smr.arpa.emr.it>
1503! authors:
1504! Davide Cesari <dcesari@arpa.emr.it>
1505! Paolo Patruno <ppatruno@arpa.emr.it>
1506
1507! This program is free software; you can redistribute it and/or
1508! modify it under the terms of the GNU General Public License as
1509! published by the Free Software Foundation; either version 2 of
1510! the License, or (at your option) any later version.
1511
1512! This program is distributed in the hope that it will be useful,
1513! but WITHOUT ANY WARRANTY; without even the implied warranty of
1514! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515! GNU General Public License for more details.
1516
1517! You should have received a copy of the GNU General Public License
1518! along with this program. If not, see <http://www.gnu.org/licenses/>.
1519#include "config.h"
1520!> This module contains functions that are only for internal use of
1521!! the library. It should not be used by user procedures because it is
1522!! subject to change
1523!! \ingroup vol7d
1524MODULE stat_proc_engine
1526USE vol7d_class
1527IMPLICIT NONE
1528
1529! per ogni elemento i,j dell'output, definire n elementi di input ad
1530! esso contribuenti (arrayof_ttr_mapper) con le seguenti informazioni
1531TYPE ttr_mapper
1532 INTEGER :: it=imiss ! k
1533 INTEGER :: itr=imiss ! l
1534 INTEGER :: extra_info=imiss ! dtratio for intervals, extreme for point in time
1535 TYPE(datetime) :: time=datetime_miss ! time for point in time
1536END TYPE ttr_mapper
1537
1538INTERFACE OPERATOR (==)
1539 MODULE PROCEDURE ttr_mapper_eq
1540END INTERFACE
1541
1542INTERFACE OPERATOR (/=)
1543 MODULE PROCEDURE ttr_mapper_ne
1544END INTERFACE
1545
1546INTERFACE OPERATOR (>)
1547 MODULE PROCEDURE ttr_mapper_gt
1548END INTERFACE
1549
1550INTERFACE OPERATOR (<)
1551 MODULE PROCEDURE ttr_mapper_lt
1552END INTERFACE
1553
1554INTERFACE OPERATOR (>=)
1555 MODULE PROCEDURE ttr_mapper_ge
1556END INTERFACE
1557
1558INTERFACE OPERATOR (<=)
1559 MODULE PROCEDURE ttr_mapper_le
1560END INTERFACE
1561
1562#undef VOL7D_POLY_TYPE
1563#undef VOL7D_POLY_TYPES
1564#undef ENABLE_SORT
1565#define VOL7D_POLY_TYPE TYPE(ttr_mapper)
1566#define VOL7D_POLY_TYPES _ttr_mapper
1567#define ENABLE_SORT
1568#include "array_utilities_pre.F90"
1569
1570#define ARRAYOF_ORIGTYPE TYPE(ttr_mapper)
1571#define ARRAYOF_TYPE arrayof_ttr_mapper
1572#define ARRAYOF_ORIGEQ 1
1573#define ARRAYOF_ORIGGT 1
1574#include "arrayof_pre.F90"
1575! from arrayof
1576
1577TYPE,PRIVATE :: ttr_decoder
1578 TYPE(datetime) :: pstart=datetime_miss
1579 TYPE(datetime) :: pend=datetime_miss
1580 TYPE(datetime) :: reftime=datetime_miss
1581 LOGICAL :: isana=.false.
1582END TYPE ttr_decoder
1583
1584CONTAINS
1585
1586! simplified comparisons only on time
1587ELEMENTAL FUNCTION ttr_mapper_eq(this, that) RESULT(res)
1588TYPE(ttr_mapper),INTENT(IN) :: this, that
1589LOGICAL :: res
1590
1591res = this%time == that%time
1592
1593END FUNCTION ttr_mapper_eq
1594
1595ELEMENTAL FUNCTION ttr_mapper_ne(this, that) RESULT(res)
1596TYPE(ttr_mapper),INTENT(IN) :: this, that
1597LOGICAL :: res
1598
1599res = this%time /= that%time
1600
1601END FUNCTION ttr_mapper_ne
1602
1603ELEMENTAL FUNCTION ttr_mapper_gt(this, that) RESULT(res)
1604TYPE(ttr_mapper),INTENT(IN) :: this, that
1605LOGICAL :: res
1606
1607res = this%time > that%time
1608
1609END FUNCTION ttr_mapper_gt
1610
1611ELEMENTAL FUNCTION ttr_mapper_lt(this, that) RESULT(res)
1612TYPE(ttr_mapper),INTENT(IN) :: this, that
1613LOGICAL :: res
1614
1615res = this%time < that%time
1616
1617END FUNCTION ttr_mapper_lt
1618
1619ELEMENTAL FUNCTION ttr_mapper_ge(this, that) RESULT(res)
1620TYPE(ttr_mapper),INTENT(IN) :: this, that
1621LOGICAL :: res
1622
1623res = this%time >= that%time
1624
1625END FUNCTION ttr_mapper_ge
1626
1627ELEMENTAL FUNCTION ttr_mapper_le(this, that) RESULT(res)
1628TYPE(ttr_mapper),INTENT(IN) :: this, that
1629LOGICAL :: res
1630
1631res = this%time <= that%time
1632
1633END FUNCTION ttr_mapper_le
1634
1635#include "arrayof_post.F90"
1636#include "array_utilities_inc.F90"
1637
1638
1639! common operations for statistical processing by differences
1640SUBROUTINE recompute_stat_proc_diff_common(itime, itimerange, stat_proc, step, &
1641 otime, otimerange, map_tr, f, keep_tr, time_definition, full_steps, &
1642 start)
1643TYPE(datetime),INTENT(in) :: itime(:)
1644TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
1645INTEGER,INTENT(in) :: stat_proc
1646TYPE(timedelta),INTENT(in) :: step
1647TYPE(datetime),POINTER :: otime(:)
1648TYPE(vol7d_timerange),POINTER :: otimerange(:)
1649INTEGER,ALLOCATABLE,INTENT(out) :: map_tr(:,:,:,:,:), f(:), keep_tr(:,:,:)
1650INTEGER :: nitr
1651LOGICAL,ALLOCATABLE :: mask_timerange(:)
1652INTEGER,INTENT(in) :: time_definition
1653LOGICAL,INTENT(in),OPTIONAL :: full_steps
1654TYPE(datetime),INTENT(in),OPTIONAL :: start
1655
1656INTEGER :: i, j, k, l, dirtyrep
1657INTEGER :: steps
1658LOGICAL :: lfull_steps, useful
1659TYPE(datetime) :: lstart, tmptime ! pstart1, pstart2, pend1, pend2, reftime1, reftime2
1660TYPE(vol7d_timerange) :: tmptimerange
1661TYPE(arrayof_datetime) :: a_otime
1662TYPE(arrayof_vol7d_timerange) :: a_otimerange
1663TYPE(timedelta) :: start_delta
1664TYPE(ttr_decoder),ALLOCATABLE :: ttr_d(:,:)
1665
1666! compute length of cumulation step in seconds
1667CALL getval(step, asec=steps)
1668
1669lstart = datetime_miss
1670IF (PRESENT(start)) lstart = start
1671lfull_steps = optio_log(full_steps)
1672
1673! create a mask of suitable timeranges
1674ALLOCATE(mask_timerange(SIZE(itimerange)))
1675mask_timerange(:) = itimerange(:)%timerange == stat_proc &
1676 .AND. itimerange(:)%p1 /= imiss .AND. itimerange(:)%p2 /= imiss &
1677 .AND. itimerange(:)%p1 >= 0 &
1678 .AND. itimerange(:)%p2 > 0
1679
1680IF (lfull_steps .AND. steps /= 0) THEN ! keep only timeranges defining intervals ending at integer forecast steps or analysis timeranges
1681 mask_timerange(:) = mask_timerange(:) .AND. &
1682 (itimerange(:)%p1 == 0 .OR. & ! all analyses
1683 mod(itimerange(:)%p1, steps) == 0 .OR. & ! end time is mod step
1684 mod(itimerange(:)%p1 - itimerange(:)%p2, steps) == 0) ! start time is mod step
1685ENDIF
1686! mask_timerange includes all candidate timeranges
1687
1688nitr = count(mask_timerange)
1689ALLOCATE(f(nitr))
1690j = 1
1691DO i = 1, nitr
1692 DO WHILE(.NOT.mask_timerange(j))
1693 j = j + 1
1694 ENDDO
1695 f(i) = j
1696 j = j + 1
1697ENDDO
1698
1699ALLOCATE(map_tr(nitr, SIZE(itime), nitr, SIZE(itime), 2))
1700map_tr(:,:,:,:,:) = imiss
1701
1702! precompute ttr
1703ALLOCATE(ttr_d(nitr,SIZE(itime)))
1704DO l = 1, SIZE(itime)
1705 DO k = 1, nitr
1706 CALL ttr_decoder_decode(itime(l), itimerange(f(k)), &
1707 time_definition, ttr_d(k,l))
1708 IF (ttr_d(k,l)%reftime == ttr_d(k,l)%pend) ttr_d(k,l)%isana = .true.
1709 ENDDO
1710ENDDO
1711
1712! now we have to evaluate time/timerage pairs which do not need processing
1713ALLOCATE(keep_tr(nitr, SIZE(itime), 2))
1714CALL compute_keep_tr()
1715
1716! scan through all possible combinations of time and timerange
1717DO dirtyrep = 1, 2
1718 IF (dirtyrep == 2) THEN ! dirty and expensive trick for sorting descriptors
1719 CALL packarray(a_otime)
1720 CALL packarray(a_otimerange)
1721 CALL sort(a_otime%array)
1722 CALL sort(a_otimerange%array)
1723 ENDIF
1724 DO l = 1, SIZE(itime)
1725 DO k = 1, nitr
1726! CALL time_timerange_get_period(itime(l), itimerange(f(k)), &
1727! time_definition, pstart2, pend2, reftime2)
1728
1729 DO j = 1, SIZE(itime)
1730 DO i = 1, nitr
1731 useful = .false.
1732! CALL time_timerange_get_period(itime(j), itimerange(f(i)), &
1733! time_definition, pstart1, pend1, reftime1)
1734! tmptimerange = vol7d_timerange_new(timerange=stat_proc)
1735
1736! IF (ttr_d(k,l)%reftime == ttr_d(k,l)%pend .AND. ttr_d(i,j)%reftime == ttr_d(i,j)%pend) THEN ! analysis
1737 IF (ttr_d(k,l)%isana .AND. ttr_d(i,j)%isana) THEN ! analysis
1738 IF (ttr_d(k,l)%pstart == ttr_d(i,j)%pstart .AND. ttr_d(k,l)%pend > ttr_d(i,j)%pend) THEN ! =-|
1739 CALL time_timerange_set_period(tmptime, tmptimerange, &
1740 time_definition, stat_proc, ttr_d(i,j)%pend, ttr_d(k,l)%pend, ttr_d(k,l)%reftime)
1741 IF (lfull_steps) THEN
1742 IF (mod(ttr_d(k,l)%reftime, step) == timedelta_0) THEN
1743 useful = .true.
1744 ENDIF
1745 ELSE
1746 useful = .true.
1747 ENDIF
1748! keep only data after lstart
1749 IF (c_e(lstart)) THEN
1750 IF (lstart > ttr_d(i,j)%pend) useful = .false.
1751 ENDIF
1752
1753 ELSE IF (ttr_d(k,l)%pstart < ttr_d(i,j)%pstart .AND. ttr_d(k,l)%pend == ttr_d(i,j)%pend) THEN ! -=|
1754 CALL time_timerange_set_period(tmptime, tmptimerange, &
1755 time_definition, stat_proc, ttr_d(k,l)%pstart, ttr_d(i,j)%pstart, ttr_d(i,j)%pstart)
1756 IF (lfull_steps) THEN
1757 IF (mod(ttr_d(i,j)%pstart, step) == timedelta_0) THEN
1758 useful = .true.
1759 ENDIF
1760 ELSE
1761 useful = .true.
1762 ENDIF
1763! keep only data after lstart
1764 IF (c_e(lstart)) THEN
1765 IF (lstart > ttr_d(k,l)%pstart) useful = .false.
1766 ENDIF
1767 ENDIF
1768
1769 ELSE IF (ttr_d(k,l)%reftime == ttr_d(i,j)%reftime) THEN ! forecast, same reftime
1770 IF (lfull_steps) THEN
1771 IF (c_e(lstart)) THEN
1772! lstart shifts the interval for computing modulo step, this does not
1773! remove data before lstart but just shifts the phase
1774 start_delta = lstart-ttr_d(k,l)%reftime
1775 ELSE
1776 start_delta = timedelta_0
1777 ENDIF
1778 ENDIF
1779
1780 IF (ttr_d(k,l)%pstart == ttr_d(i,j)%pstart .AND. ttr_d(k,l)%pend > ttr_d(i,j)%pend) THEN ! |=-
1781 CALL time_timerange_set_period(tmptime, tmptimerange, &
1782 time_definition, stat_proc, ttr_d(i,j)%pend, ttr_d(k,l)%pend, ttr_d(k,l)%reftime)
1783 IF (lfull_steps) THEN
1784 IF (mod(ttr_d(k,l)%pend-ttr_d(k,l)%reftime-start_delta, step) == timedelta_0) THEN
1785 useful = .true.
1786 ENDIF
1787 ELSE
1788 useful = .true.
1789 ENDIF
1790! keep only data after lstart
1791 IF (c_e(lstart)) THEN
1792 IF (lstart > ttr_d(i,j)%pend) useful = .false.
1793 ENDIF
1794
1795 ELSE IF (ttr_d(k,l)%pstart < ttr_d(i,j)%pstart .AND. ttr_d(k,l)%pend == ttr_d(i,j)%pend) THEN ! |-=
1796 CALL time_timerange_set_period(tmptime, tmptimerange, &
1797 time_definition, stat_proc, ttr_d(k,l)%pstart, ttr_d(i,j)%pstart, ttr_d(k,l)%reftime)
1798 IF (lfull_steps) THEN
1799 IF (mod(ttr_d(i,j)%pstart-ttr_d(k,l)%reftime-start_delta, step) == timedelta_0) THEN
1800 useful = .true.
1801 ENDIF
1802 ELSE
1803 useful = .true.
1804 ENDIF
1805! keep only data after lstart
1806 IF (c_e(lstart)) THEN
1807 IF (lstart > ttr_d(k,l)%pstart) useful = .false.
1808 ENDIF
1809
1810 ENDIF
1811 ENDIF
1812 useful = useful .AND. tmptime /= datetime_miss .AND. &
1813 tmptimerange /= vol7d_timerange_miss .AND. tmptimerange%p2 == steps
1814
1815 IF (useful) THEN ! add a_otime, a_otimerange
1816 map_tr(i,j,k,l,1) = append_unique(a_otime, tmptime)
1817 map_tr(i,j,k,l,2) = append_unique(a_otimerange, tmptimerange)
1818 ENDIF
1819 ENDDO
1820 ENDDO
1821 ENDDO
1822 ENDDO
1823ENDDO
1824
1825! we have to repeat the computation with sorted arrays
1826CALL compute_keep_tr()
1827
1828otime => a_otime%array
1829otimerange => a_otimerange%array
1830! delete local objects keeping the contents
1831CALL delete(a_otime, nodealloc=.true.)
1832CALL delete(a_otimerange, nodealloc=.true.)
1833
1834#ifdef DEBUG
1835CALL l4f_log(l4f_debug, &
1836 'recompute_stat_proc_diff, map_tr: '//t2c((SIZE(map_tr,1)))//', '// &
1837 t2c((SIZE(map_tr,2)))//', '// &
1838 t2c((SIZE(map_tr,3)))//', '// &
1839 t2c((SIZE(map_tr,4))))
1840CALL l4f_log(l4f_debug, &
1841 'recompute_stat_proc_diff, map_tr: '//t2c((SIZE(map_tr))/2)//', '// &
1842 t2c(count(c_e(map_tr))/2))
1843CALL l4f_log(l4f_debug, &
1844 'recompute_stat_proc_diff, nitr: '//t2c(nitr))
1845CALL l4f_log(l4f_debug, &
1846 'recompute_stat_proc_diff, good timeranges: '//t2c(count(c_e(keep_tr))/2))
1847CALL l4f_log(l4f_debug, &
1848 'recompute_stat_proc_diff, output times: '//t2c(SIZE(otime)))
1849CALL l4f_log(l4f_debug, &
1850 'recompute_stat_proc_diff, output timeranges: '//t2c(SIZE(otimerange)))
1851#endif
1852
1853CONTAINS
1854
1855SUBROUTINE compute_keep_tr()
1856INTEGER :: start_deltas
1857
1858keep_tr(:,:,:) = imiss
1859DO l = 1, SIZE(itime)
1860 itrloop: DO k = 1, nitr
1861 IF (itimerange(f(k))%p2 == steps) THEN
1862! CALL time_timerange_get_period(itime(l), itimerange(f(k)), &
1863! time_definition, pstart2, pend2, reftime2)
1864 useful = .false.
1865! keep only data after lstart
1866 IF (c_e(lstart)) THEN
1867 IF (lstart > ttr_d(k,l)%pstart) cycle itrloop
1868 ENDIF
1869 IF (ttr_d(k,l)%reftime == ttr_d(k,l)%pend) THEN ! analysis
1870 IF (c_e(lstart)) THEN ! in analysis mode start wins over full_steps
1871 IF (mod(ttr_d(k,l)%reftime-lstart, step) == timedelta_0) THEN
1872 useful = .true.
1873 ENDIF
1874 ELSE IF (lfull_steps) THEN
1875 IF (mod(ttr_d(k,l)%reftime, step) == timedelta_0) THEN
1876 useful = .true.
1877 ENDIF
1878 ELSE
1879 useful = .true.
1880 ENDIF
1881 ELSE ! forecast
1882 IF (lfull_steps) THEN
1883! same as above for start_delta, but in seconds and not in timerange/timedelta units
1884 IF (c_e(lstart)) THEN
1885 start_deltas = timedelta_getamsec(lstart-ttr_d(k,l)%reftime)/1000_int_ll
1886 ELSE
1887 start_deltas = 0
1888 ENDIF
1889 IF (mod(itimerange(f(k))%p1 - start_deltas, steps) == 0) THEN
1890 useful = .true.
1891 ENDIF
1892 ELSE
1893 useful = .true.
1894 ENDIF
1895 ENDIF
1896 IF (useful) THEN
1897! CALL time_timerange_set_period(tmptime, tmptimerange, &
1898! time_definition, stat_proc, pstart2, pend2, reftime2)
1899 keep_tr(k,l,1) = append_unique(a_otime, itime(l))
1900 keep_tr(k,l,2) = append_unique(a_otimerange, itimerange(f(k)))
1901 ENDIF
1902 ENDIF
1903 ENDDO itrloop
1904ENDDO
1905
1906END SUBROUTINE compute_keep_tr
1907
1908END SUBROUTINE recompute_stat_proc_diff_common
1909
1910
1911! common operations for statistical processing by metamorphosis
1912SUBROUTINE compute_stat_proc_metamorph_common(istat_proc, itimerange, ostat_proc, &
1913 otimerange, map_tr)
1914INTEGER,INTENT(in) :: istat_proc
1915TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
1916INTEGER,INTENT(in) :: ostat_proc
1917TYPE(vol7d_timerange),POINTER :: otimerange(:)
1918INTEGER,POINTER :: map_tr(:)
1919
1920INTEGER :: i
1921LOGICAL :: tr_mask(SIZE(itimerange))
1922
1923IF (SIZE(itimerange) == 0) THEN ! avoid segmentation fault in case of empty volume
1924 ALLOCATE(otimerange(0), map_tr(0))
1925 RETURN
1926ENDIF
1927
1928! useful timeranges
1929tr_mask(:) = itimerange(:)%timerange == istat_proc .AND. itimerange(:)%p2 /= imiss &
1930 .AND. itimerange(:)%p2 /= 0 ! .AND. itimerange(:)%p1 == 0
1931ALLOCATE(otimerange(count(tr_mask)), map_tr(count(tr_mask)))
1932
1933otimerange = pack(itimerange, mask=tr_mask)
1934otimerange(:)%timerange = ostat_proc
1935map_tr = pack((/(i,i=1,SIZE(itimerange))/), mask=tr_mask)
1936
1937END SUBROUTINE compute_stat_proc_metamorph_common
1938
1939
1940! common operations for statistical processing by aggregation
1941SUBROUTINE recompute_stat_proc_agg_common(itime, itimerange, stat_proc, tri, &
1942 step, time_definition, otime, otimerange, map_ttr, dtratio, start, full_steps)
1943TYPE(datetime),INTENT(in) :: itime(:)
1944TYPE(vol7d_timerange),INTENT(in) :: itimerange(:)
1945INTEGER,INTENT(in) :: stat_proc
1946INTEGER,INTENT(in) :: tri
1947TYPE(timedelta),INTENT(in) :: step
1948INTEGER,INTENT(in) :: time_definition
1949TYPE(datetime),POINTER :: otime(:)
1950TYPE(vol7d_timerange),POINTER :: otimerange(:)
1951TYPE(arrayof_ttr_mapper),POINTER :: map_ttr(:,:)
1952INTEGER,POINTER,OPTIONAL :: dtratio(:)
1953TYPE(datetime),INTENT(in),OPTIONAL :: start
1954LOGICAL,INTENT(in),OPTIONAL :: full_steps
1955
1956INTEGER :: i, j, k, l, na, nf, n
1957INTEGER :: steps, p1, maxp1, maxp2, minp1mp2, dstart, msteps
1958INTEGER(kind=int_ll) :: stepms, mstepms
1959LOGICAL :: lforecast
1960TYPE(datetime) :: lstart, lend, pstart1, pstart2, pend1, pend2, reftime1, reftime2, tmptime
1961TYPE(arrayof_datetime) :: a_otime
1962TYPE(arrayof_vol7d_timerange) :: a_otimerange
1963TYPE(arrayof_integer) :: a_dtratio
1964LOGICAL,ALLOCATABLE :: mask_timerange(:) ! improve !!!!
1965TYPE(ttr_mapper) :: lmapper
1966CHARACTER(len=8) :: env_var
1967LOGICAL :: climat_behavior
1968
1969
1970! enable bad behavior for climat database (only for instantaneous data)
1971env_var = ''
1972CALL getenv('LIBSIM_CLIMAT_BEHAVIOR', env_var)
1973climat_behavior = len_trim(env_var) > 0 .AND. .NOT.PRESENT(dtratio)
1974
1975! compute length of cumulation step in seconds
1976CALL getval(timedelta_depop(step), asec=steps)
1977
1978! create a mask of suitable timeranges
1979ALLOCATE(mask_timerange(SIZE(itimerange)))
1980mask_timerange(:) = itimerange(:)%timerange == tri &
1981 .AND. itimerange(:)%p1 /= imiss .AND. itimerange(:)%p1 >= 0
1982
1983IF (PRESENT(dtratio)) THEN
1984 WHERE(itimerange(:)%p2 > 0 .AND. itimerange(:)%p2 /= imiss) ! for avoiding FPE MOD(steps, 0)
1985 mask_timerange(:) = mask_timerange(:) .AND. mod(steps, itimerange(:)%p2) == 0
1986 ELSEWHERE
1987 mask_timerange(:) = .false.
1988 END WHERE
1989ELSE ! instantaneous
1990 mask_timerange(:) = mask_timerange(:) .AND. itimerange(:)%p2 == 0
1991ENDIF
1992
1993#ifdef DEBUG
1994CALL l4f_log(l4f_debug, &
1995 '(re)compute_stat_proc_agg, number of useful timeranges before choosing analysis/forecast: '// &
1996 t2c(count(mask_timerange)))
1997#endif
1998
1999! euristically determine whether we are dealing with an
2000! analysis/observation or a forecast dataset
2001na = count(mask_timerange(:) .AND. itimerange(:)%p1 == 0)
2002nf = count(mask_timerange(:) .AND. itimerange(:)%p1 > 0)
2003lforecast = nf >= na
2004#ifdef DEBUG
2005CALL l4f_log(l4f_debug, &
2006 'recompute_stat_proc_agg, na: '//t2c(na)//', nf: '//t2c(nf))
2007#endif
2008
2009! keep only timeranges of one type (really necessary?)
2010IF (lforecast) THEN
2011 CALL l4f_log(l4f_info, &
2012 'recompute_stat_proc_agg, processing in forecast mode')
2013ELSE
2014 mask_timerange(:) = mask_timerange(:) .AND. itimerange(:)%p1 == 0
2015 CALL l4f_log(l4f_info, &
2016 'recompute_stat_proc_agg, processing in analysis mode')
2017ENDIF
2018
2019#ifdef DEBUG
2020CALL l4f_log(l4f_debug, &
2021 '(re)compute_stat_proc_agg, number of useful timeranges: '// &
2022 t2c(count(mask_timerange)))
2023#endif
2024
2025IF (SIZE(itime) == 0 .OR. count(mask_timerange) == 0) THEN ! avoid segmentation fault in case of empty volume
2026 ALLOCATE(otime(0), otimerange(0), map_ttr(0,0))
2027 IF (PRESENT(dtratio)) ALLOCATE(dtratio(0))
2028 RETURN
2029ENDIF
2030
2031! determine start and end of processing period, should work with p2==0
2032lstart = datetime_miss
2033IF (PRESENT(start)) lstart = start
2034lend = itime(SIZE(itime))
2035! compute some quantities
2036maxp1 = maxval(itimerange(:)%p1, mask=mask_timerange)
2037maxp2 = maxval(itimerange(:)%p2, mask=mask_timerange)
2038minp1mp2 = minval(itimerange(:)%p1 - itimerange(:)%p2, mask=mask_timerange)
2039IF (time_definition == 0) THEN ! reference time
2040 lend = lend + timedelta_new(sec=maxp1)
2041ENDIF
2042! extend interval at the end in order to include all the data in case
2043! frac_valid<1; must use < and not <= in the DO WHILE loops some lines
2044! below in order to exclude the last full interval which would be empty
2045lend = lend + step
2046IF (lstart == datetime_miss) THEN ! autodetect
2047 lstart = itime(1)
2048! if autodetected, adjust to obtain real absolute start of data
2049 IF (time_definition == 0) THEN ! reference time
2050 lstart = lstart + timedelta_new(sec=minp1mp2)
2051 ELSE ! verification time
2052! go back to start of longest processing interval
2053 lstart = lstart - timedelta_new(sec=maxp2)
2054 ENDIF
2055! apply full_steps in analysis mode and when start is not specified
2056! (start by itself in analysis mode implies full_steps with respect to
2057! start instead of absolute full steps), todo in forecast mode
2058 IF (optio_log(full_steps) .AND. .NOT.lforecast) THEN
2059 lstart = lstart - (mod(lstart, step)) ! round to step, (should be MODULO, not MOD)
2060 ENDIF
2061ENDIF
2062
2063#ifdef DEBUG
2064CALL l4f_log(l4f_debug, &
2065 'recompute_stat_proc_agg, processing period: '//t2c(lstart)//' - '//t2c(lend))
2066#endif
2067
2068! create output time and timerange lists
2069
2070IF (lforecast) THEN ! forecast mode
2071 IF (time_definition == 0) THEN ! reference time
2072 CALL insert(a_otime, itime) ! should I limit to elements itime >= lstart?
2073
2074! apply start shift to timerange, not to reftime
2075! why did we use itime(SIZE(itime)) (last ref time)?
2076! CALL getval(lstart-itime(SIZE(itime)), asec=dstart)
2077 CALL getval(lstart-itime(1), asec=dstart)
2078! allow starting before first reftime but restrict dtstart to -steps
2079! dstart = MAX(0, dstart)
2080 IF (dstart < 0) dstart = mod(dstart, steps)
2081 DO p1 = steps + dstart, maxp1, steps
2082 CALL insert_unique(a_otimerange, vol7d_timerange_new(stat_proc, p1, steps))
2083 ENDDO
2084
2085 ELSE ! verification time
2086
2087! verification time in forecast mode is the ugliest case, because we
2088! don't know a priori how many different (thus incompatible) reference
2089! times we have, so some assumption of regularity has to be made. For
2090! this reason msteps, the minimum step between two times, is
2091! computed. We choose to compute it as a difference between itime
2092! elements, it could be also computed as difference of itimerange%p1
2093! elements. But what if it is not modulo steps?
2094 mstepms = steps*1000_int_ll
2095 DO i = 2, SIZE(itime)
2096 CALL getval(itime(i)-itime(i-1), amsec=stepms)
2097 IF (stepms > 0_int_ll .AND. stepms < mstepms) THEN
2098 msteps = stepms/1000_int_ll
2099 IF (mod(steps, msteps) == 0) mstepms = stepms
2100 ENDIF
2101 ENDDO
2102 msteps = mstepms/1000_int_ll
2103
2104 tmptime = lstart + step
2105 DO WHILE(tmptime < lend) ! < since lend has been extended
2106 CALL insert_unique(a_otime, tmptime)
2107 tmptime = tmptime + step
2108 ENDDO
2109
2110! in next loop, we used initially steps instead of msteps (see comment
2111! above), this gave much less combinations of time/timeranges with
2112! possible empty output; we start from msteps instead of steps in
2113! order to include partial initial intervals in case frac_valid<1;
2114! however, as a gemeral rule, for aggregation of forecasts it's better
2115! to use reference time
2116 DO p1 = msteps, maxp1, msteps
2117 CALL insert_unique(a_otimerange, vol7d_timerange_new(stat_proc, p1, steps))
2118 ENDDO
2119
2120 ENDIF
2121
2122ELSE ! analysis mode
2123 tmptime = lstart + step
2124 DO WHILE(tmptime < lend) ! < since lend has been extended
2125 CALL insert_unique(a_otime, tmptime)
2126 tmptime = tmptime + step
2127 ENDDO
2128 CALL insert_unique(a_otimerange, vol7d_timerange_new(stat_proc, 0, steps))
2129
2130ENDIF
2131
2132CALL packarray(a_otime)
2133CALL packarray(a_otimerange)
2134otime => a_otime%array
2135otimerange => a_otimerange%array
2136CALL sort(otime)
2137CALL sort(otimerange)
2138! delete local objects keeping the contents
2139CALL delete(a_otime, nodealloc=.true.)
2140CALL delete(a_otimerange, nodealloc=.true.)
2141
2142#ifdef DEBUG
2143CALL l4f_log(l4f_debug, &
2144 'recompute_stat_proc_agg, output time and timerange: '//&
2145 t2c(SIZE(otime))//', '//t2c(size(otimerange)))
2146#endif
2147
2148IF (PRESENT(dtratio)) THEN
2149! count the possible i/o interval ratios
2150 DO k = 1, SIZE(itimerange)
2151 IF (itimerange(k)%p2 /= 0) &
2152 CALL insert_unique(a_dtratio, steps/itimerange(k)%p2) ! guaranteed to be integer
2153 ENDDO
2154 CALL packarray(a_dtratio)
2155 dtratio => a_dtratio%array
2156 CALL sort(dtratio)
2157! delete local object keeping the contents
2158 CALL delete(a_dtratio, nodealloc=.true.)
2159
2160#ifdef DEBUG
2161 CALL l4f_log(l4f_debug, &
2162 'recompute_stat_proc_agg, found '//t2c(size(dtratio))// &
2163 ' possible aggregation ratios, from '// &
2164 t2c(dtratio(1))//' to '//t2c(dtratio(SIZE(dtratio))))
2165#endif
2166
2167 ALLOCATE(map_ttr(SIZE(otime),SIZE(otimerange)))
2168 do_itimerange1: DO l = 1, SIZE(itimerange)
2169 IF (.NOT.mask_timerange(l)) cycle do_itimerange1
2170 do_itime1: DO k = 1, SIZE(itime)
2171 CALL time_timerange_get_period(itime(k), itimerange(l), &
2172 time_definition, pstart1, pend1, reftime1)
2173 do_otimerange1: DO j = 1, SIZE(otimerange)
2174 do_otime1: DO i = 1, SIZE(otime)
2175 CALL time_timerange_get_period_pop(otime(i), otimerange(j), step, &
2176 time_definition, pstart2, pend2, reftime2)
2177 IF (lforecast) THEN
2178 IF (reftime1 /= reftime2) cycle do_otime1
2179 ENDIF
2180
2181 IF (pstart1 >= pstart2 .AND. pend1 <= pend2 .AND. &
2182 mod(pstart1-pstart2, pend1-pstart1) == timedelta_0) THEN ! useful
2183 lmapper%it = k
2184 lmapper%itr = l
2185 lmapper%extra_info = steps/itimerange(l)%p2 ! dtratio, guaranteed to be integer
2186 n = append(map_ttr(i,j), lmapper)
2187 cycle do_itime1 ! can contribute only to a single interval
2188 ENDIF
2189 ENDDO do_otime1
2190 ENDDO do_otimerange1
2191 ENDDO do_itime1
2192 ENDDO do_itimerange1
2193
2194ELSE
2195
2196 ALLOCATE(map_ttr(SIZE(otime),SIZE(otimerange)))
2197 do_itimerange2: DO l = 1, SIZE(itimerange)
2198 IF (.NOT.mask_timerange(l)) cycle do_itimerange2
2199 do_itime2: DO k = 1, SIZE(itime)
2200 CALL time_timerange_get_period(itime(k), itimerange(l), &
2201 time_definition, pstart1, pend1, reftime1)
2202 do_otimerange2: DO j = 1, SIZE(otimerange)
2203 do_otime2: DO i = 1, SIZE(otime)
2204 CALL time_timerange_get_period_pop(otime(i), otimerange(j), step, &
2205 time_definition, pstart2, pend2, reftime2)
2206 IF (lforecast) THEN
2207 IF (reftime1 /= reftime2) cycle do_otime2
2208 ENDIF
2209
2210 IF (climat_behavior .AND. pstart1 == pstart2) cycle do_otime2
2211 IF (pstart1 >= pstart2 .AND. pend1 <= pend2) THEN ! useful
2212 lmapper%it = k
2213 lmapper%itr = l
2214 IF (pstart1 == pstart2) THEN
2215 lmapper%extra_info = 1 ! start of interval
2216 ELSE IF (pend1 == pend2) THEN
2217 lmapper%extra_info = 2 ! end of interval
2218 ELSE
2219 lmapper%extra_info = imiss
2220 ENDIF
2221 lmapper%time = pstart1 ! = pend1, order by time?
2222 n = insert_sorted(map_ttr(i,j), lmapper, .true., .true.)
2223! no CYCLE, a single input can contribute to multiple output intervals
2224 ENDIF
2225 ENDDO do_otime2
2226 ENDDO do_otimerange2
2227 ENDDO do_itime2
2228 ENDDO do_itimerange2
2229
2230ENDIF
2231
2232END SUBROUTINE recompute_stat_proc_agg_common
2233
2234
2235SUBROUTINE compute_stat_proc_agg_sw(vertime, pstart, pend, time_mask, &
2236 max_step, weights)
2237TYPE(datetime),INTENT(in) :: vertime(:)
2238TYPE(datetime),INTENT(in) :: pstart
2239TYPE(datetime),INTENT(in) :: pend
2240LOGICAL,INTENT(in) :: time_mask(:)
2241TYPE(timedelta),OPTIONAL,INTENT(out) :: max_step
2242DOUBLE PRECISION,OPTIONAL,INTENT(out) :: weights(:)
2243
2244INTEGER :: i, nt
2245TYPE(datetime),ALLOCATABLE :: lvertime(:)
2246TYPE(datetime) :: half, nexthalf
2247INTEGER(kind=int_ll) :: dt, tdt
2248
2249nt = count(time_mask)
2250ALLOCATE(lvertime(nt))
2251lvertime = pack(vertime, mask=time_mask)
2252
2253IF (PRESENT(max_step)) THEN
2254! new way
2255! max_step = timedelta_0
2256! DO i = 1, nt - 1
2257! IF (lvertime(i+1) - lvertime(i) > max_step) &
2258! max_step = lvertime(i+1) - lvertime(i)
2259! ENDDO
2260! IF (lvertime(1) - pstart > max_step) max_step = lvertime(1) - pstart
2261! IF (pend - lvertime(nt) > max_step) max_step = pend - lvertime(nt)
2262! old way
2263 IF (nt == 1) THEN
2264 max_step = pend - pstart
2265 ELSE
2266 half = lvertime(1) + (lvertime(2) - lvertime(1))/2
2267 max_step = half - pstart
2268 DO i = 2, nt - 1
2269 nexthalf = lvertime(i) + (lvertime(i+1) - lvertime(i))/2
2270 IF (nexthalf - half > max_step) max_step = nexthalf - half
2271 half = nexthalf
2272 ENDDO
2273 IF (pend - half > max_step) max_step = pend - half
2274 ENDIF
2275
2276ENDIF
2277
2278IF (PRESENT(weights)) THEN
2279 IF (nt == 1) THEN
2280 weights(1) = 1.0
2281 ELSE
2282 CALL getval(pend - pstart, amsec=tdt)
2283 half = lvertime(1) + (lvertime(2) - lvertime(1))/2
2284 CALL getval(half - pstart, amsec=dt)
2285 weights(1) = dble(dt)/dble(tdt)
2286 DO i = 2, nt - 1
2287 nexthalf = lvertime(i) + (lvertime(i+1) - lvertime(i))/2
2288 CALL getval(nexthalf - half, amsec=dt)
2289 weights(i) = dble(dt)/dble(tdt)
2290 half = nexthalf
2291 ENDDO
2292 CALL getval(pend - half, amsec=dt)
2293 weights(nt) = dble(dt)/dble(tdt)
2294 ENDIF
2295ENDIF
2296
2297END SUBROUTINE compute_stat_proc_agg_sw
2298
2299! get start of period, end of period and reference time from time,
2300! timerange, according to time_definition.
2301SUBROUTINE time_timerange_get_period(time, timerange, time_definition, &
2302 pstart, pend, reftime)
2303TYPE(datetime),INTENT(in) :: time
2304TYPE(vol7d_timerange),INTENT(in) :: timerange
2305INTEGER,INTENT(in) :: time_definition
2306TYPE(datetime),INTENT(out) :: reftime
2307TYPE(datetime),INTENT(out) :: pstart
2308TYPE(datetime),INTENT(out) :: pend
2309
2310TYPE(timedelta) :: p1, p2
2311
2312
2313p1 = timedelta_new(sec=timerange%p1) ! end of period
2314p2 = timedelta_new(sec=timerange%p2) ! length of period
2315
2316IF (time == datetime_miss .OR. .NOT.c_e(timerange%p1) .OR. .NOT.c_e(timerange%p2) .OR. &
2317! (timerange%p1 > 0 .AND. timerange%p1 < timerange%p2) .OR. &
2318 timerange%p1 < 0 .OR. timerange%p2 < 0) THEN ! is this too pedantic and slow?
2319 pstart = datetime_miss
2320 pend = datetime_miss
2321 reftime = datetime_miss
2322 RETURN
2323ENDIF
2324
2325IF (time_definition == 0) THEN ! time == reference time
2326 reftime = time
2327 pend = time + p1
2328 pstart = pend - p2
2329ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
2330 pend = time
2331 pstart = time - p2
2332 reftime = time - p1
2333ELSE
2334 pstart = datetime_miss
2335 pend = datetime_miss
2336 reftime = datetime_miss
2337ENDIF
2338
2339END SUBROUTINE time_timerange_get_period
2340
2341
2342! get start of period, end of period and reference time from time,
2343! timerange, according to time_definition.
2344SUBROUTINE ttr_decoder_decode(time, timerange, time_definition, decoded)
2345TYPE(datetime),INTENT(in) :: time
2346TYPE(vol7d_timerange),INTENT(in) :: timerange
2347INTEGER,INTENT(in) :: time_definition
2348TYPE(ttr_decoder),INTENT(out) :: decoded
2349
2350TYPE(timedelta) :: p1, p2
2351
2352
2353p1 = timedelta_new(sec=timerange%p1) ! end of period
2354p2 = timedelta_new(sec=timerange%p2) ! length of period
2355
2356IF (time == datetime_miss .OR. .NOT.c_e(timerange%p1) .OR. .NOT.c_e(timerange%p2) .OR. &
2357! (timerange%p1 > 0 .AND. timerange%p1 < timerange%p2) .OR. &
2358 timerange%p1 < 0 .OR. timerange%p2 < 0) THEN ! is this too pedantic and slow?
2359 decoded%pstart = datetime_miss
2360 decoded%pend = datetime_miss
2361 decoded%reftime = datetime_miss
2362 RETURN
2363ENDIF
2364
2365IF (time_definition == 0) THEN ! time == reference time
2366 decoded%reftime = time
2367 decoded%pend = time + p1
2368 decoded%pstart = decoded%pend - p2
2369ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
2370 decoded%pend = time
2371 decoded%pstart = time - p2
2372 decoded%reftime = time - p1
2373ELSE
2374 decoded%pstart = datetime_miss
2375 decoded%pend = datetime_miss
2376 decoded%reftime = datetime_miss
2377ENDIF
2378
2379END SUBROUTINE ttr_decoder_decode
2380
2381
2382! get start of period, end of period and reference time from time,
2383! timerange, according to time_definition. step is taken separately
2384! from timerange and can be "popular"
2385SUBROUTINE time_timerange_get_period_pop(time, timerange, step, time_definition, &
2386 pstart, pend, reftime)
2387TYPE(datetime),INTENT(in) :: time
2388TYPE(vol7d_timerange),INTENT(in) :: timerange
2389TYPE(timedelta),INTENT(in) :: step
2390INTEGER,INTENT(in) :: time_definition
2391TYPE(datetime),INTENT(out) :: reftime
2392TYPE(datetime),INTENT(out) :: pstart
2393TYPE(datetime),INTENT(out) :: pend
2394
2395TYPE(timedelta) :: p1
2396
2397
2398p1 = timedelta_new(sec=timerange%p1) ! end of period
2399
2400IF (time == datetime_miss .OR. .NOT.c_e(timerange%p1) .OR. .NOT.c_e(timerange%p2) .OR. &
2401! (timerange%p1 > 0 .AND. timerange%p1 < timerange%p2) .OR. &
2402 timerange%p1 < 0 .OR. timerange%p2 < 0) THEN ! is this too pedantic and slow?
2403 pstart = datetime_miss
2404 pend = datetime_miss
2405 reftime = datetime_miss
2406 RETURN
2407ENDIF
2408
2409IF (time_definition == 0) THEN ! time == reference time
2410 reftime = time
2411 pend = time + p1
2412 pstart = pend - step
2413ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
2414 pend = time
2415 pstart = time - step
2416 reftime = time - p1
2417ELSE
2418 pstart = datetime_miss
2419 pend = datetime_miss
2420 reftime = datetime_miss
2421ENDIF
2422
2423END SUBROUTINE time_timerange_get_period_pop
2424
2425
2426! get start of period, end of period and reference time from time,
2427! timerange, according to time_definition. step is taken separately
2428! from timerange and can be "popular"
2429SUBROUTINE ttr_decoder_decode_pop(time, timerange, step, time_definition, decoded)
2430TYPE(datetime),INTENT(in) :: time
2431TYPE(vol7d_timerange),INTENT(in) :: timerange
2432TYPE(timedelta),INTENT(in) :: step
2433INTEGER,INTENT(in) :: time_definition
2434TYPE(ttr_decoder),INTENT(out) :: decoded
2435
2436TYPE(timedelta) :: p1
2437
2438
2439p1 = timedelta_new(sec=timerange%p1) ! end of period
2440
2441IF (time == datetime_miss .OR. .NOT.c_e(timerange%p1) .OR. .NOT.c_e(timerange%p2) .OR. &
2442! (timerange%p1 > 0 .AND. timerange%p1 < timerange%p2) .OR. &
2443 timerange%p1 < 0 .OR. timerange%p2 < 0) THEN ! is this too pedantic and slow?
2444 decoded%pstart = datetime_miss
2445 decoded%pend = datetime_miss
2446 decoded%reftime = datetime_miss
2447 RETURN
2448ENDIF
2449
2450IF (time_definition == 0) THEN ! time == reference time
2451 decoded%reftime = time
2452 decoded%pend = time + p1
2453 decoded%pstart = decoded%pend - step
2454ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
2455 decoded%pend = time
2456 decoded%pstart = time - step
2457 decoded%reftime = time - p1
2458ELSE
2459 decoded%pstart = datetime_miss
2460 decoded%pend = datetime_miss
2461 decoded%reftime = datetime_miss
2462ENDIF
2463
2464END SUBROUTINE ttr_decoder_decode_pop
2465
2466
2467! set time, timerange%p1, timerange%p2 according to pstart, pend,
2468! reftime and time_definition.
2469SUBROUTINE time_timerange_set_period(time, timerange, time_definition, &
2470 stat_proc, pstart, pend, reftime)
2471TYPE(datetime),INTENT(out) :: time
2472TYPE(vol7d_timerange),INTENT(out) :: timerange
2473INTEGER,INTENT(in) :: time_definition
2474INTEGER,INTENT(in) :: stat_proc
2475TYPE(datetime),INTENT(in) :: pstart
2476TYPE(datetime),INTENT(in) :: pend
2477TYPE(datetime),INTENT(in) :: reftime
2478
2479TYPE(timedelta) :: p1, p2
2480INTEGER(kind=int_ll) :: dmsec
2481
2482
2483IF (time_definition == 0) THEN ! time == reference time
2484 time = reftime
2485 p1 = pend - reftime
2486 p2 = pend - pstart
2487ELSE IF (time_definition == 1 .OR. time_definition == 2) THEN ! time == verification time
2488 time = pend
2489 p1 = pend - reftime
2490 p2 = pend - pstart
2491ELSE
2492 time = datetime_miss
2493ENDIF
2494
2495timerange%timerange = stat_proc
2496IF (time /= datetime_miss) THEN
2497 CALL getval(p1, amsec=dmsec) ! end of period
2498 timerange%p1 = int(dmsec/1000_int_ll)
2499 CALL getval(p2, amsec=dmsec) ! length of period
2500 timerange%p2 = int(dmsec/1000_int_ll)
2501ELSE
2502 timerange%p1 = imiss
2503 timerange%p2 = imiss
2504ENDIF
2505
2506END SUBROUTINE time_timerange_set_period
2507
2508
2509END 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.
Quick method to append an element to the array.
Destructor for finalizing an array object.
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...
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.

Generated with Doxygen.