libsim Versione 8.0.0

◆ inssor_ttr_mapper()

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

Sorts into increasing order (Insertion sort) Sorts XDONT into increasing order (Insertion sort) This subroutine uses insertion sort.

It does not use any work array and is faster when XDONT is of very small size (< 20), or already almost sorted, so it is used in a final pass when the partial quicksorting has left a sequence of small subsets and that sorting is only necessary within each subset to complete the process. Michel Olagnon - Apr. 2000

Definizione alla linea 1626 del file stat_proc_engine.F90.

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