libsim Versione 8.0.0

◆ vg6d_reduce()

subroutine, public vg6d_reduce ( type(volgrid6d), intent(in) vg6din,
type(volgrid6d), intent(out) vg6dout,
type(vol7d_level), dimension(:), intent(in) roundlevel,
type(vol7d_timerange), dimension(:), intent(in) roundtimerange,
logical, intent(in), optional merge )

Reduce some dimensions (level and timerage).

You can pass a volume and specify duplicated levels and timeranges in roundlevel and roundtimerange; you get unique levels and timeranges in output. If there are data on equal levels or timeranges, the first var present (at least one point) will be taken (order is by icreasing var index). you can specify merge and if there are data on equal levels or timeranges will be merged POINT BY POINT with priority for the first data found ordered by icreasing var index (require to decode all the data) Data are decoded only if needed so the output should be with or without voldata allocated

Parametri
[in]vg6dininput volume
[out]vg6doutoutput volume
[in]roundlevelnew level list to use for rounding
[in]roundtimerangenew timerange list to use for rounding
[in]mergeif there are data on equal levels or timeranges will be merged POINT BY POINT with priority for the first data found ordered by icreasing var index (require to decode all the data)

Definizione alla linea 3663 del file volgrid6d_class.F90.

3664! Copyright (C) 2010 ARPA-SIM <urpsim@smr.arpa.emr.it>
3665! authors:
3666! Davide Cesari <dcesari@arpa.emr.it>
3667! Paolo Patruno <ppatruno@arpa.emr.it>
3668
3669! This program is free software; you can redistribute it and/or
3670! modify it under the terms of the GNU General Public License as
3671! published by the Free Software Foundation; either version 2 of
3672! the License, or (at your option) any later version.
3673
3674! This program is distributed in the hope that it will be useful,
3675! but WITHOUT ANY WARRANTY; without even the implied warranty of
3676! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3677! GNU General Public License for more details.
3678
3679! You should have received a copy of the GNU General Public License
3680! along with this program. If not, see <http://www.gnu.org/licenses/>.
3681#include "config.h"
3682!> \defgroup volgrid6d Libsim package, volgrid6d library.
3683!! The libsim volgrid6d library contains classes for managing data on
3684!! regular rectangular grids, tipically the output of a numerical
3685!! weather prediction model, and for their import from a WMO GRIB file
3686!! of from other geophysical data file formats. In order to compile
3687!! and link programs using this library, you have to insert the
3688!! required \c USE statements in the program units involved, specify
3689!! the location of module files when compiling (tipically \c
3690!! -I/usr/lib/gfortran/modules or \c -I/usr/lib64/gfortran/modules or
3691!! \c -I/usr/include) and indicate the library name \c -lsim_volgrid6d
3692!! when linking, assuming that the library has been installed in a
3693!! default location.
3694
3695!> This module defines objects and methods for managing data volumes
3696!! on rectangular georeferenced grids. The data are accomodated in a
3697!! multi-dimensional array with 6 predefined dimensions. Different
3698!! geographic coordinates and projections are supported, mainly
3699!! inspired by grib coding standards. The \a volgrid6d object contains
3700!! information and data on an homogeneous grid definition, while
3701!! different grids are managed as arrays of \a volgrid6d objects.
3702!! Every object contains also an identificator of the grid (\a grid_id
3703!! object), carrying information about the driver used or which has to
3704!! be used for import/export from/to file. With the help of \a
3705!! gridinfo_def class, data can be imported and exported to the
3706!! supported formats, mainly grib1 and grib2 through grib_api and many
3707!! GIS-style formats through gdal.
3708!!
3709!! Simple example program \include example_vg6d_3.f90
3710!! Example of transformation from volgrid6d to volgrid6d \include example_vg6d_5.f90
3711!! Example of transformation from volgrid6d to vol7d \include example_vg6d_6.f90
3712!! Example of transformation from vol7d to volgrid6d \include example_vg6d_7.f90
3713!!
3714!!\ingroup volgrid6d
3715MODULE volgrid6d_class
3718USE vol7d_class
3720USE geo_proj_class
3721USE grid_class
3725USE log4fortran
3727USE grid_id_class
3730!USE file_utilities
3731#ifdef HAVE_DBALLE
3733#endif
3734IMPLICIT NONE
3735
3736character (len=255),parameter:: subcategory="volgrid6d_class"
3737
3738!> Object describing a rectangular, homogeneous gridded dataset
3739type volgrid6d
3740 type(griddim_def) :: griddim !< grid descriptor
3741 TYPE(datetime),pointer :: time(:) !< time dimension descriptor
3742 TYPE(vol7d_timerange),pointer :: timerange(:) !< timerange (forecast, analysis, statistically processed) dimension descriptor
3743 TYPE(vol7d_level),pointer :: level(:) !< vertical level dimension descriptor
3744 TYPE(volgrid6d_var),pointer :: var(:) !< physical variable dimension descriptor
3745 TYPE(grid_id),POINTER :: gaid(:,:,:,:) !< array of grid identifiers, carrying information about the driver for import/export from/to file, indices are: (level,time,timerange,var)
3746 REAL,POINTER :: voldati(:,:,:,:,:,:) !< array of data, indices are: (x,y,level,time,timerange,var)
3747 INTEGER :: time_definition !< time definition; 0=time is reference time ; 1=time is validity time
3748 TYPE(l4f_handle) :: category !< log4fortran category
3749end type volgrid6d
3750
3751!> Constructor, it creates a new instance of the object.
3752INTERFACE init
3753 MODULE PROCEDURE volgrid6d_init
3754END INTERFACE
3755
3756!> Destructor, it releases every information and memory buffer
3757!! associated with the object.
3758INTERFACE delete
3759 MODULE PROCEDURE volgrid6d_delete, volgrid6dv_delete
3760END INTERFACE
3761
3762!> Import an object dirctly from a native file, from a \a gridinfo object
3763!! or from a supported file format through a \a gridinfo object.
3764INTERFACE import
3765 MODULE PROCEDURE volgrid6d_read_from_file
3766 MODULE PROCEDURE import_from_gridinfo, import_from_gridinfovv, &
3767 volgrid6d_import_from_file
3768END INTERFACE
3769
3770!> Export an object dirctly to a native file, to a \a gridinfo object
3771!! or to a supported file format through a \a gridinfo object.
3772INTERFACE export
3773 MODULE PROCEDURE volgrid6d_write_on_file
3774 MODULE PROCEDURE export_to_gridinfo, export_to_gridinfov, export_to_gridinfovv,&
3775 volgrid6d_export_to_file
3776END INTERFACE
3777
3778! methods for computing transformations through an initialised
3779! grid_transform object, probably too low level to be interfaced
3780INTERFACE compute
3781 MODULE PROCEDURE volgrid6d_transform_compute, volgrid6d_v7d_transform_compute,&
3782 v7d_volgrid6d_transform_compute, v7d_v7d_transform_compute
3783END INTERFACE
3784
3785!> Transform between any combination of \a volgrid6d and \a vol7d objects
3786!! by means of a \a transform_def object describing the transformation.
3787INTERFACE transform
3788 MODULE PROCEDURE volgrid6d_transform, volgrid6dv_transform,&
3789 volgrid6d_v7d_transform, volgrid6dv_v7d_transform, v7d_volgrid6d_transform, &
3790 v7d_v7d_transform
3791END INTERFACE
3792
3793INTERFACE wind_rot
3794 MODULE PROCEDURE vg6d_wind_rot
3795END INTERFACE
3796
3797INTERFACE wind_unrot
3798 MODULE PROCEDURE vg6d_wind_unrot
3799END INTERFACE
3800
3801!> Display on standard output a description of the \a volgrid6d object
3802!! provided.
3803INTERFACE display
3804 MODULE PROCEDURE display_volgrid6d,display_volgrid6dv
3805END INTERFACE
3806
3807!> Reduce some dimensions (level and timerage) for semplification (rounding).
3808!! You can use this for simplify and use variables in computation like alchimia
3809!! where fields have to be on the same coordinate
3810!! examples:
3811!! means in time for short periods and istantaneous values
3812!! 2 meter and surface levels
3813!! If there are data on more then one almost equal levels or timeranges, the first var present (at least one point)
3814!! will be taken (order is by icreasing var index).
3815!! You can use predefined values for classic semplification
3816!! almost_equal_levels and almost_equal_timeranges
3817!! The level or timerange in output will be defined by the first element of level and timerange list
3818INTERFACE rounding
3819 MODULE PROCEDURE vg6d_rounding, vg6dv_rounding
3820END INTERFACE
3821
3822private
3823
3824PUBLIC volgrid6d,init,delete,export,import,compute,transform, &
3825 wind_rot,wind_unrot,vg6d_c2a,display,volgrid6d_alloc,volgrid6d_alloc_vol, &
3826 volgrid_get_vol_2d, volgrid_set_vol_2d, volgrid_get_vol_3d, volgrid_set_vol_3d
3827PUBLIC rounding, vg6d_reduce
3828
3829CONTAINS
3830
3831
3832!> Constructor, it creates a new instance of the object.
3833!! The constructor should be explicitly used only in rare cases,
3834!! \a volgrid6d objects are usually created through the \a import
3835!! interface.
3836SUBROUTINE volgrid6d_init(this, griddim, time_definition, categoryappend)
3837TYPE(volgrid6d) :: this !< object to be initialized
3838TYPE(griddim_def),OPTIONAL :: griddim !< grid descriptor
3839INTEGER,INTENT(IN),OPTIONAL :: time_definition !< 0=time is reference time; 1=time is validity time
3840CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
3841
3842character(len=512) :: a_name
3843
3844if (present(categoryappend))then
3845 call l4f_launcher(a_name,a_name_append=trim(subcategory)//"."//trim(categoryappend))
3846else
3847 call l4f_launcher(a_name,a_name_append=trim(subcategory))
3848endif
3849this%category=l4f_category_get_handle(a_name)
3850
3851#ifdef DEBUG
3852call l4f_category_log(this%category,l4f_debug,"init")
3853#endif
3854
3855call init(this%griddim)
3856
3857if (present(griddim))then
3858 call copy (griddim,this%griddim)
3859end if
3860
3861if(present(time_definition)) then
3862 this%time_definition = time_definition
3863else
3864 this%time_definition = 0 !default to reference time
3865end if
3866
3867nullify (this%time,this%timerange,this%level,this%var)
3868nullify (this%gaid,this%voldati)
3869
3870END SUBROUTINE volgrid6d_init
3871
3872
3873!> Allocate the dimension descriptors of the \a volgrid6d object.
3874!! This method allocates the horizontal grid descriptor and the one
3875!! dimensional arrays of the dimensions
3876!! - time
3877!! - vertical level
3878!! - timerange
3879!! - physical variable
3880!!
3881!! This method should be explicitly used only in rare cases, it is
3882!! usually called implicitly through the \a import interface.
3883SUBROUTINE volgrid6d_alloc(this, dim, ntime, nlevel, ntimerange, nvar, ini)
3884TYPE(volgrid6d),INTENT(inout) :: this !< object whose decriptors should be allocated
3885TYPE(grid_dim),INTENT(in),OPTIONAL :: dim !< horizontal grid size X, Y
3886INTEGER,INTENT(in),OPTIONAL :: ntime !< number of time levels
3887INTEGER,INTENT(in),OPTIONAL :: nlevel !< number of vertical levels
3888INTEGER,INTENT(in),OPTIONAL :: ntimerange !< number of different timeranges
3889INTEGER,INTENT(in),OPTIONAL :: nvar !< number of physical variables
3890LOGICAL,INTENT(in),OPTIONAL :: ini !< if provided and \c .TRUE., for each allocated dimension descriptor the constructor is called without extra parameters, thus initializing everything as missing value
3891
3892INTEGER :: i, stallo
3893LOGICAL :: linit
3894
3895#ifdef DEBUG
3896call l4f_category_log(this%category,l4f_debug,"alloc")
3897#endif
3898
3899IF (PRESENT(ini)) THEN
3900 linit = ini
3901ELSE
3902 linit = .false.
3903ENDIF
3904
3905
3906if (present(dim)) call copy (dim,this%griddim%dim)
3907
3908
3909IF (PRESENT(ntime)) THEN
3910 IF (ntime >= 0) THEN
3911 IF (ASSOCIATED(this%time)) DEALLOCATE(this%time)
3912#ifdef DEBUG
3913 call l4f_category_log(this%category,l4f_debug,"alloc ntime "//to_char(ntime))
3914#endif
3915 ALLOCATE(this%time(ntime),stat=stallo)
3916 if (stallo /=0)then
3917 call l4f_category_log(this%category,l4f_fatal,"allocating memory")
3918 CALL raise_fatal_error()
3919 end if
3920 IF (linit) THEN
3921 DO i = 1, ntime
3922 this%time(i) = datetime_miss
3923! CALL init(this%time(i)) ! senza argomento inizializza a zero non missing
3924 ! baco di datetime?
3925 ENDDO
3926 ENDIF
3927 ENDIF
3928ENDIF
3929IF (PRESENT(nlevel)) THEN
3930 IF (nlevel >= 0) THEN
3931 IF (ASSOCIATED(this%level)) DEALLOCATE(this%level)
3932#ifdef DEBUG
3933 call l4f_category_log(this%category,l4f_debug,"alloc nlevel "//to_char(nlevel))
3934#endif
3935 ALLOCATE(this%level(nlevel),stat=stallo)
3936 if (stallo /=0)then
3937 call l4f_category_log(this%category,l4f_fatal,"allocating memory")
3938 CALL raise_fatal_error()
3939 end if
3940 IF (linit) THEN
3941 DO i = 1, nlevel
3942 CALL init(this%level(i))
3943 ENDDO
3944 ENDIF
3945 ENDIF
3946ENDIF
3947IF (PRESENT(ntimerange)) THEN
3948 IF (ntimerange >= 0) THEN
3949 IF (ASSOCIATED(this%timerange)) DEALLOCATE(this%timerange)
3950#ifdef DEBUG
3951 call l4f_category_log(this%category,l4f_debug,"alloc ntimerange "//to_char(ntimerange))
3952#endif
3953 ALLOCATE(this%timerange(ntimerange),stat=stallo)
3954 if (stallo /=0)then
3955 call l4f_category_log(this%category,l4f_fatal,"allocating memory")
3956 CALL raise_fatal_error()
3957 end if
3958 IF (linit) THEN
3959 DO i = 1, ntimerange
3960 CALL init(this%timerange(i))
3961 ENDDO
3962 ENDIF
3963 ENDIF
3964ENDIF
3965IF (PRESENT(nvar)) THEN
3966 IF (nvar >= 0) THEN
3967 IF (ASSOCIATED(this%var)) DEALLOCATE(this%var)
3968#ifdef DEBUG
3969 call l4f_category_log(this%category,l4f_debug,"alloc nvar "//to_char(nvar))
3970#endif
3971 ALLOCATE(this%var(nvar),stat=stallo)
3972 if (stallo /=0)then
3973 call l4f_category_log(this%category,l4f_fatal,"allocating memory")
3974 CALL raise_fatal_error()
3975 end if
3976 IF (linit) THEN
3977 DO i = 1, nvar
3978 CALL init(this%var(i))
3979 ENDDO
3980 ENDIF
3981 ENDIF
3982ENDIF
3983
3984end SUBROUTINE volgrid6d_alloc
3985
3986
3987!> Allocate the data array of the \a volgrid6d object.
3988!! This method allocates the main 6-dimensional data array
3989!! \a this%voldati and the 4-dimensional \a grid_id array \a this%gaid
3990!! with a shape dictated by the previous call(s) to \a vol7d_alloc().
3991!! if any descriptor (except horizontal grid) has not been allocated
3992!! yet, it is allocated here with a size of 1. This method should be
3993!! explicitly used only in rare cases, it is usually called implicitly
3994!! through the \a import interface.
3995SUBROUTINE volgrid6d_alloc_vol(this, ini, inivol, decode)
3996TYPE(volgrid6d),INTENT(inout) :: this !< object whose decriptors should be allocated
3997LOGICAL,INTENT(in),OPTIONAL :: ini !< if provided and \c .TRUE., for each dimension descriptor not yet allocated and allocated here the constructor is called without extra parameters, thus initializing the element as missing value
3998LOGICAL,INTENT(in),OPTIONAL :: inivol !< if provided and \c .FALSE., the allocated volumes will not be initialized to missing values
3999LOGICAL,INTENT(in),OPTIONAL :: decode !< if provided and \c .TRUE., the \a this%voldati volume is allocated, otherwise only \a this%gaid will be allocated
4000
4001INTEGER :: stallo
4002LOGICAL :: linivol
4003
4004#ifdef DEBUG
4005call l4f_category_log(this%category,l4f_debug,"start alloc_vol")
4006#endif
4007
4008IF (PRESENT(inivol)) THEN ! opposite condition, cannot use optio_log
4009 linivol = inivol
4010ELSE
4011 linivol = .true.
4012ENDIF
4013
4014IF (this%griddim%dim%nx > 0 .AND. this%griddim%dim%ny > 0) THEN
4015! allocate dimension descriptors to a minimal size for having a
4016! non-null volume
4017 IF (.NOT. ASSOCIATED(this%var)) CALL volgrid6d_alloc(this, nvar=1, ini=ini)
4018 IF (.NOT. ASSOCIATED(this%time)) CALL volgrid6d_alloc(this, ntime=1, ini=ini)
4019 IF (.NOT. ASSOCIATED(this%level)) CALL volgrid6d_alloc(this, nlevel=1, ini=ini)
4020 IF (.NOT. ASSOCIATED(this%timerange)) CALL volgrid6d_alloc(this, ntimerange=1, ini=ini)
4021
4022 IF (optio_log(decode)) THEN
4023 IF (.NOT.ASSOCIATED(this%voldati)) THEN
4024#ifdef DEBUG
4025 CALL l4f_category_log(this%category,l4f_debug,"alloc voldati volume")
4026#endif
4027
4028 ALLOCATE(this%voldati(this%griddim%dim%nx,this%griddim%dim%ny,&
4029 SIZE(this%level), SIZE(this%time), &
4030 SIZE(this%timerange), SIZE(this%var)),stat=stallo)
4031 IF (stallo /= 0)THEN
4032 CALL l4f_category_log(this%category,l4f_fatal,"allocating memory")
4033 CALL raise_fatal_error()
4034 ENDIF
4035
4036! this is not really needed if we can check other flags for a full
4037! field missing values
4038 IF (linivol) this%voldati = rmiss
4039 this%voldati = rmiss
4040 ENDIF
4041 ENDIF
4042
4043 IF (.NOT.ASSOCIATED(this%gaid)) THEN
4044#ifdef DEBUG
4045 CALL l4f_category_log(this%category,l4f_debug,"alloc gaid volume")
4046#endif
4047 ALLOCATE(this%gaid(SIZE(this%level), SIZE(this%time), &
4048 SIZE(this%timerange), SIZE(this%var)),stat=stallo)
4049 IF (stallo /= 0)THEN
4050 CALL l4f_category_log(this%category,l4f_fatal,"allocating memory")
4051 CALL raise_fatal_error()
4052 ENDIF
4053
4054 IF (linivol) THEN
4055!!$ DO i=1 ,SIZE(this%gaid,1)
4056!!$ DO ii=1 ,SIZE(this%gaid,2)
4057!!$ DO iii=1 ,SIZE(this%gaid,3)
4058!!$ DO iiii=1 ,SIZE(this%gaid,4)
4059!!$ this%gaid(i,ii,iii,iiii) = grid_id_new() ! optimize?
4060!!$ ENDDO
4061!!$ ENDDO
4062!!$ ENDDO
4063!!$ ENDDO
4064
4065 this%gaid = grid_id_new()
4066 ENDIF
4067 ENDIF
4068
4069ELSE
4070 CALL l4f_category_log(this%category,l4f_fatal,'volgrid6d_alloc_vol: &
4071 &trying to allocate a volume with an invalid or unspecified horizontal grid')
4072 CALL raise_fatal_error()
4073ENDIF
4074
4075END SUBROUTINE volgrid6d_alloc_vol
4076
4077
4078!> Return a 2-d pointer to a x-y slice of a volume. This method works
4079!! both with volumes having allocated and non-allocated this%voldati
4080!! array, and it returns a pointer to a 2-d slice either from the
4081!! allocated this%voldati array or from the grid_id object on file or
4082!! in memory. In the second case the pointer should be either
4083!! ALLOCATE'd to the expected size or NULLIFY'ed, and if NULLIFY'ed,
4084!! it is allocated within the method, thus it will have to be
4085!! deallocated by the caller when not in use anymore. Since this
4086!! method may be called many times by a program, it is optimized for
4087!! speed and it does not make any check about the matching size of the
4088!! pointer and the array or about the allocation status of \a this, so
4089!! it should be called only when everything has been checked to be in
4090!! good shape.
4091SUBROUTINE volgrid_get_vol_2d(this, ilevel, itime, itimerange, ivar, voldati)
4092TYPE(volgrid6d),INTENT(in) :: this !< object from which the slice has to be retrieved
4093INTEGER,INTENT(in) :: ilevel !< index of vertical level of the slice
4094INTEGER,INTENT(in) :: itime !< index of time level of the slice
4095INTEGER,INTENT(in) :: itimerange !< index of timerange of the slice
4096INTEGER,INTENT(in) :: ivar !< index of physical variable of the slice
4097REAL,POINTER :: voldati(:,:) !< pointer to the data, if \a this%voldati is already allocated, it will just point to the requested slice, otherwise it will be allocated if and only if it is nullified on entry
4098
4099IF (ASSOCIATED(this%voldati)) THEN
4100 voldati => this%voldati(:,:,ilevel,itime,itimerange,ivar)
4101 RETURN
4102ELSE
4103 IF (.NOT.ASSOCIATED(voldati)) THEN
4104 ALLOCATE(voldati(this%griddim%dim%nx,this%griddim%dim%ny))
4105 ENDIF
4106 CALL grid_id_decode_data(this%gaid(ilevel,itime,itimerange,ivar), voldati)
4107ENDIF
4108
4109END SUBROUTINE volgrid_get_vol_2d
4110
4111
4112!> Return a 3-d pointer to a x-y-z slice of a volume. This method works
4113!! both with volumes having allocated and non-allocated this%voldati
4114!! array, and it returns a pointer to a 3-d slice either from the
4115!! allocated this%voldati array or from the grid_id object on file or
4116!! in memory. In the second case the pointer should be either
4117!! ALLOCATE'd to the expected size or NULLIFY'ed, and if NULLIFY'ed,
4118!! it is allocated within the method, thus it will have to be
4119!! deallocated by the caller when not in use anymore. Since this
4120!! method may be called many times by a program, it is optimized for
4121!! speed and it does not make any check about the matching size of the
4122!! pointer and the array or about the allocation status of \a this, so
4123!! it should be called only when everything has been checked to be in
4124!! good shape.
4125SUBROUTINE volgrid_get_vol_3d(this, itime, itimerange, ivar, voldati, zlist)
4126TYPE(volgrid6d),INTENT(in) :: this !< object from which the slice has to be retrieved
4127INTEGER,INTENT(in) :: itime !< index of time level of the slice
4128INTEGER,INTENT(in) :: itimerange !< index of timerange of the slice
4129INTEGER,INTENT(in) :: ivar !< index of physical variable of the slice
4130REAL,POINTER :: voldati(:,:,:) !< pointer to the data, if \a this%voldati is already allocated, it will just point to the requested slice, otherwise it will be allocated if and only if it is nullified on entry
4131LOGICAL,OPTIONAL,INTENT(out),ALLOCATABLE :: zlist(:) !< list of vertical level present in the data
4132
4133INTEGER :: ilevel
4134LOGICAL :: done
4135
4136IF (ASSOCIATED(this%voldati)) THEN
4137 voldati => this%voldati(:,:,:,itime,itimerange,ivar)
4138 IF (PRESENT(zlist)) zlist(:) = c_e(this%gaid(:,itime,itimerange,ivar))
4139 RETURN
4140ELSE
4141 IF (.NOT.ASSOCIATED(voldati)) THEN
4142 ALLOCATE(voldati(this%griddim%dim%nx,this%griddim%dim%ny,SIZE(this%level)))
4143 ENDIF
4144 IF (PRESENT(zlist)) THEN
4145 ALLOCATE(zlist(SIZE(this%level)))
4146 ENDIF
4147!$OMP PARALLEL DEFAULT(SHARED)
4148!$OMP MASTER
4149 DO ilevel = 1, SIZE(this%level)
4150!$OMP TASK FIRSTPRIVATE(ilevel),PRIVATE(done)
4151 CALL grid_id_decode_data(this%gaid(ilevel,itime,itimerange,ivar), &
4152 voldati(:,:,ilevel),done)
4153 IF (PRESENT(zlist)) zlist(ilevel) = done
4154!$OMP END TASK
4155 ENDDO
4156!$OMP END MASTER
4157!$OMP END PARALLEL
4158ENDIF
4159
4160END SUBROUTINE volgrid_get_vol_3d
4161
4162
4163!> Reset a 2-d x-y slice of a volume after the data have been modified.
4164!! This method works both with volumes having allocated and
4165!! non-allocated this%voldati array, and it updates the requested
4166!! slice. In case \a this%voldati is already allocated, this is a
4167!! no-operation while in the other case this method encodes the field
4168!! provided into the grid_id object on file or in memory. Since this
4169!! method may be called many times by a program, it is optimized for
4170!! speed and it does not make any check about the matching size of the
4171!! field and the array or about the allocation status of \a this, so
4172!! it should be called only when everything has been checked to be in
4173!! good shape.
4174SUBROUTINE volgrid_set_vol_2d(this, ilevel, itime, itimerange, ivar, voldati)
4175TYPE(volgrid6d),INTENT(inout) :: this !< object in which slice has to be updated
4176INTEGER,INTENT(in) :: ilevel !< index of vertical level of the slice
4177INTEGER,INTENT(in) :: itime !< index of time level of the slice
4178INTEGER,INTENT(in) :: itimerange !< index of timerange of the slice
4179INTEGER,INTENT(in) :: ivar !< index of physical variable of the slice
4180REAL,INTENT(in) :: voldati(:,:) !< updated values of the slice
4181
4182IF (ASSOCIATED(this%voldati)) THEN
4183 RETURN
4184ELSE
4185 CALL grid_id_encode_data(this%gaid(ilevel,itime,itimerange,ivar), voldati)
4186ENDIF
4187
4188END SUBROUTINE volgrid_set_vol_2d
4189
4190
4191!> Reset a 3-d x-y-z slice of a volume after the data have been modified.
4192!! This method works both with volumes having allocated and
4193!! non-allocated this%voldati array, and it updates the requested
4194!! slice. In case \a this%voldati is already allocated, this is a
4195!! no-operation while in the other case this method encodes the field
4196!! provided into the grid_id object on file or in memory. Since this
4197!! method may be called many times by a program, it is optimized for
4198!! speed and it does not make any check about the matching size of the
4199!! field and the array or about the allocation status of \a this, so
4200!! it should be called only when everything has been checked to be in
4201!! good shape.
4202SUBROUTINE volgrid_set_vol_3d(this, itime, itimerange, ivar, voldati)
4203TYPE(volgrid6d),INTENT(inout) :: this !< object in which slice has to be updated
4204INTEGER,INTENT(in) :: itime !< index of time level of the slice
4205INTEGER,INTENT(in) :: itimerange !< index of timerange of the slice
4206INTEGER,INTENT(in) :: ivar !< index of physical variable of the slice
4207REAL,INTENT(in) :: voldati(:,:,:) !< updated values of the slice
4208
4209INTEGER :: ilevel
4210
4211IF (ASSOCIATED(this%voldati)) THEN
4212 RETURN
4213ELSE
4214!$OMP PARALLEL DEFAULT(SHARED)
4215!$OMP MASTER
4216 DO ilevel = 1, SIZE(this%level)
4217!$OMP TASK FIRSTPRIVATE(ilevel)
4218 CALL grid_id_encode_data(this%gaid(ilevel,itime,itimerange,ivar), &
4219 voldati(:,:,ilevel))
4220!$OMP END TASK
4221 ENDDO
4222!$OMP END MASTER
4223!$OMP END PARALLEL
4224ENDIF
4225
4226END SUBROUTINE volgrid_set_vol_3d
4227
4228
4229!> Destructor, it releases every information and memory buffer
4230!! associated with the object. It should be called also for objects
4231!! crated through the \a import interface.
4232SUBROUTINE volgrid6d_delete(this)
4233TYPE(volgrid6d),INTENT(inout) :: this
4234
4235INTEGER :: i, ii, iii, iiii
4236
4237#ifdef DEBUG
4238call l4f_category_log(this%category,l4f_debug,"delete")
4239#endif
4240
4241if (associated(this%gaid))then
4242
4243 DO i=1 ,SIZE(this%gaid,1)
4244 DO ii=1 ,SIZE(this%gaid,2)
4245 DO iii=1 ,SIZE(this%gaid,3)
4246 DO iiii=1 ,SIZE(this%gaid,4)
4247 CALL delete(this%gaid(i,ii,iii,iiii))
4248 ENDDO
4249 ENDDO
4250 ENDDO
4251 ENDDO
4252 DEALLOCATE(this%gaid)
4253
4254end if
4255
4256call delete(this%griddim)
4257
4258! call delete(this%time)
4259! call delete(this%timerange)
4260! call delete(this%level)
4261! call delete(this%var)
4262
4263if (associated( this%time )) deallocate(this%time)
4264if (associated( this%timerange )) deallocate(this%timerange)
4265if (associated( this%level )) deallocate(this%level)
4266if (associated( this%var )) deallocate(this%var)
4267
4268if (associated(this%voldati))deallocate(this%voldati)
4269
4270
4271 !chiudo il logger
4272call l4f_category_delete(this%category)
4273
4274END SUBROUTINE volgrid6d_delete
4275
4276
4277!>\brief Scrittura su file di un volume Volgrid6d.
4278!! Scrittura su file unformatted di un intero volume Volgrid6d.
4279!! Il volume viene serializzato e scritto su file.
4280!! Il file puo' essere aperto opzionalmente dall'utente. Si possono passare
4281!! opzionalmente unità e nome del file altrimenti assegnati internamente a dei default; se assegnati internamente
4282!! tali parametri saranno in output.
4283!! Se non viene fornito il nome file viene utilizzato un file di default con nome pari al nome del programma in
4284!! esecuzione con postfisso ".vg6d".
4285!! Come parametro opzionale c'è la description che insieme alla data corrente viene inserita nell'header del file.
4286subroutine volgrid6d_write_on_file (this,unit,description,filename,filename_auto)
4287
4288TYPE(volgrid6d),INTENT(IN) :: this !< volume volgrid6d da scrivere
4289integer,optional,intent(inout) :: unit !< unità su cui scrivere; se passata =0 ritorna il valore rielaborato (default =rielaborato internamente con getlun )
4290character(len=*),intent(in),optional :: filename !< nome del file su cui scrivere
4291character(len=*),intent(out),optional :: filename_auto !< nome del file generato se "filename" è omesso
4292character(len=*),INTENT(IN),optional :: description !< descrizione del volume
4293
4294integer :: lunit
4295character(len=254) :: ldescription,arg,lfilename
4296integer :: ntime, ntimerange, nlevel, nvar
4297integer :: tarray(8)
4298logical :: opened,exist
4299
4300#ifdef DEBUG
4301call l4f_category_log(this%category,l4f_debug,"write on file")
4302#endif
4303
4304ntime=0
4305ntimerange=0
4306nlevel=0
4307nvar=0
4308
4309!call idate(im,id,iy)
4310call date_and_time(values=tarray)
4311call getarg(0,arg)
4312
4313if (present(description))then
4314 ldescription=description
4315else
4316 ldescription="Volgrid6d generated by: "//trim(arg)
4317end if
4318
4319if (.not. present(unit))then
4320 lunit=getunit()
4321else
4322 if (unit==0)then
4323 lunit=getunit()
4324 unit=lunit
4325 else
4326 lunit=unit
4327 end if
4328end if
4329
4330lfilename=trim(arg)//".vg6d"
4331if (index(arg,'/',back=.true.) > 0) lfilename=lfilename(index(arg,'/',back=.true.)+1 : )
4332
4333if (present(filename))then
4334 if (filename /= "")then
4335 lfilename=filename
4336 end if
4337end if
4338
4339if (present(filename_auto))filename_auto=lfilename
4340
4341
4342inquire(unit=lunit,opened=opened)
4343if (.not. opened) then
4344 inquire(file=lfilename,exist=exist)
4345 if (exist) CALL raise_error('file exist; cannot open new file')
4346 if (.not.exist) open (unit=lunit,file=lfilename,form="UNFORMATTED")
4347 !print *, "opened: ",lfilename
4348end if
4349
4350if (associated(this%time)) ntime=size(this%time)
4351if (associated(this%timerange)) ntimerange=size(this%timerange)
4352if (associated(this%level)) nlevel=size(this%level)
4353if (associated(this%var)) nvar=size(this%var)
4354
4355
4356write(unit=lunit)ldescription
4357write(unit=lunit)tarray
4358
4359call write_unit( this%griddim,lunit)
4360write(unit=lunit) ntime, ntimerange, nlevel, nvar
4361
4362!! prime 4 dimensioni
4363if (associated(this%time)) call write_unit(this%time, lunit)
4364if (associated(this%level)) write(unit=lunit)this%level
4365if (associated(this%timerange)) write(unit=lunit)this%timerange
4366if (associated(this%var)) write(unit=lunit)this%var
4367
4368
4369!! Volumi di valori dati
4370
4371if (associated(this%voldati)) write(unit=lunit)this%voldati
4372
4373if (.not. present(unit)) close(unit=lunit)
4374
4375end subroutine volgrid6d_write_on_file
4376
4377
4378!>\brief Lettura da file di un volume Volgrid6d.
4379!! Lettura da file unformatted di un intero volume Volgrid6d.
4380!! Questa subroutine comprende volgrid6d_alloc e volgrid6d_alloc_vol.
4381!! Il file puo' essere aperto opzionalmente dall'utente. Si possono passare
4382!! opzionalmente unità e nome del file altrimenti assegnati internamente a dei default; se assegnati internamente
4383!! tali parametri saranno in output.
4384subroutine volgrid6d_read_from_file (this,unit,filename,description,tarray,filename_auto)
4385
4386TYPE(volgrid6d),INTENT(OUT) :: this !< Volume volgrid6d da leggere
4387integer,intent(inout),optional :: unit !< unità su cui è stato aperto un file; se =0 rielaborato internamente (default = elaborato internamente con getunit)
4388character(len=*),INTENT(in),optional :: filename !< nome del file eventualmente da aprire (default = nome dell'eseguibile.v7d)
4389character(len=*),intent(out),optional :: filename_auto !< nome del file generato se "filename" è omesso
4390character(len=*),INTENT(out),optional :: description !< descrizione del volume letto
4391integer,intent(out),optional :: tarray(8) !< vettore come definito da "date_and_time" della data di scrittura del volume
4392
4393integer :: ntime, ntimerange, nlevel, nvar
4394
4395character(len=254) :: ldescription,lfilename,arg
4396integer :: ltarray(8),lunit
4397logical :: opened,exist
4398
4399#ifdef DEBUG
4400call l4f_category_log(this%category,l4f_debug,"read from file")
4401#endif
4402
4403call getarg(0,arg)
4404
4405if (.not. present(unit))then
4406 lunit=getunit()
4407else
4408 if (unit==0)then
4409 lunit=getunit()
4410 unit=lunit
4411 else
4412 lunit=unit
4413 end if
4414end if
4415
4416lfilename=trim(arg)//".vg6d"
4417if (index(arg,'/',back=.true.) > 0) lfilename=lfilename(index(arg,'/',back=.true.)+1 : )
4418
4419if (present(filename))then
4420 if (filename /= "")then
4421 lfilename=filename
4422 end if
4423end if
4424
4425if (present(filename_auto))filename_auto=lfilename
4426
4427
4428inquire(unit=lunit,opened=opened)
4429if (.not. opened) then
4430 inquire(file=lfilename,exist=exist)
4431 IF (.NOT. exist) CALL raise_fatal_error('file '//trim(lfilename)//' does not exist, cannot open')
4432 open (unit=lunit,file=lfilename,form="UNFORMATTED")
4433end if
4434
4435read(unit=lunit)ldescription
4436read(unit=lunit)ltarray
4437
4438call l4f_log(l4f_info,"Info: reading volgrid6d from file: "//trim(lfilename))
4439call l4f_log(l4f_info,"Info: description: "//trim(ldescription))
4440!call l4f_log("Info: written on ",ltarray)
4441
4442if (present(description))description=ldescription
4443if (present(tarray))tarray=ltarray
4444
4445
4446call read_unit( this%griddim,lunit)
4447read(unit=lunit) ntime, ntimerange, nlevel, nvar
4448
4449
4450call volgrid6d_alloc (this, &
4451 ntime=ntime, ntimerange=ntimerange, nlevel=nlevel, nvar=nvar)
4452
4453call volgrid6d_alloc_vol (this)
4454
4455if (associated(this%time)) call read_unit(this%time, lunit)
4456if (associated(this%level)) read(unit=lunit)this%level
4457if (associated(this%timerange)) read(unit=lunit)this%timerange
4458if (associated(this%var)) read(unit=lunit)this%var
4459
4460
4461!! Volumi di valori
4462
4463if (associated(this%voldati)) read(unit=lunit)this%voldati
4464
4465if (.not. present(unit)) close(unit=lunit)
4466
4467end subroutine volgrid6d_read_from_file
4468
4469
4470!> Import a single \a gridinfo object into a \a volgrid6d object.
4471!! This methods imports a single gridded field from a \a gridinfo
4472!! object into a \a volgrid6d object, inserting it into the
4473!! multidimensional structure of volgrid6d. The volgrid6d object must
4474!! have been already initialized and the dimensions specified with
4475!! volgrid6d_alloc(). If the \a force argument is missing or \a
4476!! .FALSE. , the volgrid6d object dimension descriptors (time,
4477!! timerange, vertical level, physical variable) must already have
4478!! space for the corresponding values coming from gridinfo, otherwise
4479!! the object will be rejected; this means that all the volgrid6d
4480!! dimension descriptors should be correctly assigned. If \a force is
4481!! \a .TRUE. , the gridinfo dimension descriptors that do not fit into
4482!! available descriptors in the \a volgrid6d structure, will be
4483!! accomodated in a empty (i.e. equal to missing value) descriptor, if
4484!! available, otherwise the gridinfo will be rejected. The
4485!! descriptor of the grid in the \a volgrid object is assigned to the
4486!! descriptor contained in \a gridinfo if it is missing in \a volgrid,
4487!! otherwise it is checked and the object is rejected if grids do not
4488!! match.
4489SUBROUTINE import_from_gridinfo(this, gridinfo, force, dup_mode, clone, &
4490 isanavar)
4491TYPE(volgrid6d),INTENT(inout) :: this !< object in which to import
4492TYPE(gridinfo_def),INTENT(in) :: gridinfo !< gridinfo object to be imported
4493LOGICAL,INTENT(in),OPTIONAL :: force !< if provided and \c .TRUE., the gridinfo is forced into an empty element of \a this, if required and possible
4494INTEGER,INTENT(in),OPTIONAL :: dup_mode !< determines the behavior in case of duplicate metadata: if \a dup_mode is not provided or 0, a duplicate field overwrites, if \a dup_mode is 1, duplicate fields are merged with priority to the last
4495LOGICAL , INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE. , clone the gaid's from \a gridinfo to \a this
4496LOGICAL,INTENT(IN),OPTIONAL :: isanavar !< if provides and \a .TRUE., the gridinfo object is treated as time-independent and replicated for every time and timerange
4497
4498CHARACTER(len=255) :: type
4499INTEGER :: itime0, itimerange0, itime1, itimerange1, itime, itimerange, &
4500 ilevel, ivar, ldup_mode
4501LOGICAL :: dup
4502TYPE(datetime) :: correctedtime
4503TYPE(vol7d_timerange) :: correctedtimerange
4504REAL,ALLOCATABLE :: tmpgrid(:,:)
4505
4506IF (PRESENT(dup_mode)) THEN
4507 ldup_mode = dup_mode
4508ELSE
4509 ldup_mode = 0
4510ENDIF
4511
4512call get_val(this%griddim,proj_type=type)
4513
4514#ifdef DEBUG
4515call l4f_category_log(this%category,l4f_debug,"import_from_gridinfo: "//trim(type))
4516#endif
4517
4518if (.not. c_e(type))then
4519 call copy(gridinfo%griddim, this%griddim)
4520! ho gia` fatto init, altrimenti non potrei fare la get_val(this%griddim)
4521! per cui meglio non ripetere
4522! call init(this,gridinfo%griddim,categoryappend)
4523 CALL volgrid6d_alloc_vol(this, ini=.true.) ! decode?
4524
4525else if (.not. (this%griddim == gridinfo%griddim ))then
4526
4527 CALL l4f_category_log(this%category,l4f_error, &
4528 "volgrid and gridinfo grid type or size are different, gridinfo rejected")
4529 CALL raise_error()
4530 RETURN
4531
4532end if
4533
4534! Cerco gli indici del campo da inserire, se non trovo metto nel primo missing
4535ilevel = index(this%level, gridinfo%level)
4536IF (ilevel == 0 .AND. optio_log(force)) THEN
4537 ilevel = index(this%level, vol7d_level_miss)
4538 IF (ilevel /= 0) this%level(ilevel) = gridinfo%level
4539ENDIF
4540
4541IF (ilevel == 0) THEN
4542 CALL l4f_category_log(this%category,l4f_error, &
4543 "volgrid6d: level not valid for volume, gridinfo rejected")
4544 CALL raise_error()
4545 RETURN
4546ENDIF
4547
4548IF (optio_log(isanavar)) THEN ! assign to all times and timeranges
4549 itime0 = 1
4550 itime1 = SIZE(this%time)
4551 itimerange0 = 1
4552 itimerange1 = SIZE(this%timerange)
4553ELSE ! usual case
4554 correctedtime = gridinfo%time
4555 IF (this%time_definition == 1 .OR. this%time_definition == 2) correctedtime = correctedtime + &
4556 timedelta_new(sec=gridinfo%timerange%p1)
4557 itime0 = index(this%time, correctedtime)
4558 IF (itime0 == 0 .AND. optio_log(force)) THEN
4559 itime0 = index(this%time, datetime_miss)
4560 IF (itime0 /= 0) this%time(itime0) = correctedtime
4561 ENDIF
4562 IF (itime0 == 0) THEN
4563 CALL l4f_category_log(this%category,l4f_error, &
4564 "volgrid6d: time not valid for volume, gridinfo rejected")
4565 CALL raise_error()
4566 RETURN
4567 ENDIF
4568 itime1 = itime0
4569
4570 correctedtimerange = gridinfo%timerange
4571 IF (this%time_definition == 2) correctedtimerange%p1 = 0
4572 itimerange0 = index(this%timerange, correctedtimerange)
4573 IF (itimerange0 == 0 .AND. optio_log(force)) THEN
4574 itimerange0 = index(this%timerange, vol7d_timerange_miss)
4575 IF (itimerange0 /= 0) this%timerange(itimerange0) = gridinfo%timerange
4576 ENDIF
4577 IF (itimerange0 == 0) THEN
4578 CALL l4f_category_log(this%category,l4f_error, &
4579 "volgrid6d: timerange not valid for volume, gridinfo rejected")
4580 CALL raise_error()
4581 RETURN
4582 ENDIF
4583 itimerange1 = itimerange0
4584ENDIF
4585
4586ivar = index(this%var, gridinfo%var)
4587IF (ivar == 0 .AND. optio_log(force)) THEN
4588 ivar = index(this%var, volgrid6d_var_miss)
4589 IF (ivar /= 0) this%var(ivar) = gridinfo%var
4590ENDIF
4591IF (ivar == 0) THEN
4592 CALL l4f_category_log(this%category,l4f_error, &
4593 "volgrid6d: var not valid for volume, gridinfo rejected")
4594 CALL raise_error()
4595 RETURN
4596ENDIF
4597
4598DO itimerange = itimerange0, itimerange1
4599 DO itime = itime0, itime1
4600 IF (ASSOCIATED(this%gaid)) THEN
4601 dup = .false.
4602 IF (c_e(this%gaid(ilevel,itime,itimerange,ivar))) THEN
4603 dup = .true.
4604 CALL l4f_category_log(this%category,l4f_warn,"gaid exist: grib duplicated")
4605! avoid memory leaks
4606 IF (optio_log(clone)) CALL delete(this%gaid(ilevel,itime,itimerange,ivar))
4607 ENDIF
4608
4609 IF (optio_log(clone)) THEN
4610 CALL copy(gridinfo%gaid, this%gaid(ilevel,itime,itimerange,ivar))
4611#ifdef DEBUG
4612 CALL l4f_category_log(this%category,l4f_debug,"cloning to a new gaid")
4613#endif
4614 ELSE
4615 this%gaid(ilevel,itime,itimerange,ivar) = gridinfo%gaid
4616 ENDIF
4617
4618 IF (ASSOCIATED(this%voldati))THEN
4619 IF (.NOT.dup .OR. ldup_mode == 0) THEN
4620 this%voldati(:,:,ilevel,itime,itimerange,ivar) = decode_gridinfo(gridinfo)
4621 ELSE IF (ldup_mode == 1) THEN
4622 tmpgrid = decode_gridinfo(gridinfo) ! f2003 automatic allocation
4623 WHERE(c_e(tmpgrid))
4624 this%voldati(:,:,ilevel,itime,itimerange,ivar) = tmpgrid(:,:)
4625 END WHERE
4626 ELSE IF (ldup_mode == 2) THEN
4627 WHERE(.NOT.c_e(this%voldati(:,:,ilevel,itime,itimerange,ivar)))
4628 this%voldati(:,:,ilevel,itime,itimerange,ivar) = decode_gridinfo(gridinfo)
4629 END WHERE
4630 ENDIF
4631 ENDIF
4632
4633 ELSE
4634 CALL l4f_category_log(this%category,l4f_error, &
4635 "gaid not allocated, you probably need to call volgrid6d_alloc_vol first")
4636 CALL raise_error()
4637 RETURN
4638 ENDIF
4639 ENDDO
4640ENDDO
4641
4642
4643END SUBROUTINE import_from_gridinfo
4644
4645
4646!> Export a single grid of a \a volgrid6d object to a \a gridinfo_def object.
4647!! A single 2d slice of a \a volgrid6d at a specified location is
4648!! written into a \a gridinfo_def object, including the \a grid_id
4649!! which can be used for the successive export to file.
4650SUBROUTINE export_to_gridinfo(this, gridinfo, itime, itimerange, ilevel, ivar, &
4651 gaid_template, clone)
4652TYPE(volgrid6d),INTENT(in) :: this !< volume to be exported
4653TYPE(gridinfo_def),INTENT(inout) :: gridinfo !< output gridinfo_def object
4654INTEGER :: itime !< index within \a this of the element to be exported for the time dimension
4655INTEGER :: itimerange !< index within \a this of the element to be exported for the timerange dimension
4656INTEGER :: ilevel !< index within \a this of the element to be exported for the vertical level dimension
4657INTEGER :: ivar !< index within \a this of the element to be exported for the variable dimension
4658TYPE(grid_id),INTENT(in),OPTIONAL :: gaid_template !< \a grid_id template to be used for output data replacing the one contained in \a this
4659LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE., clone the grid_id included in \a this rather than making a shallow copy
4660
4661TYPE(grid_id) :: gaid
4662LOGICAL :: usetemplate
4663REAL,POINTER :: voldati(:,:)
4664TYPE(datetime) :: correctedtime
4665
4666#ifdef DEBUG
4667CALL l4f_category_log(this%category,l4f_debug,"export_to_gridinfo")
4668#endif
4669
4670IF (.NOT.c_e(this%gaid(ilevel,itime,itimerange,ivar))) THEN
4671#ifdef DEBUG
4672 CALL l4f_category_log(this%category,l4f_debug,"empty gaid found, skipping export")
4673#endif
4674 RETURN
4675ENDIF
4676
4677usetemplate = .false.
4678IF (PRESENT(gaid_template)) THEN
4679 CALL copy(gaid_template, gaid)
4680#ifdef DEBUG
4681 CALL l4f_category_log(this%category,l4f_debug,"template cloned to a new gaid")
4682#endif
4683 usetemplate = c_e(gaid)
4684ENDIF
4685
4686IF (.NOT.usetemplate) THEN
4687 IF (optio_log(clone)) THEN
4688 CALL copy(this%gaid(ilevel,itime,itimerange,ivar), gaid)
4689#ifdef DEBUG
4690 CALL l4f_category_log(this%category,l4f_debug,"original gaid cloned to a new one")
4691#endif
4692 ELSE
4693 gaid = this%gaid(ilevel,itime,itimerange,ivar)
4694 ENDIF
4695ENDIF
4696
4697IF (this%time_definition == 1 .OR. this%time_definition == 2) THEN
4698 correctedtime = this%time(itime) - &
4699 timedelta_new(sec=this%timerange(itimerange)%p1)
4700ELSE
4701 correctedtime = this%time(itime)
4702ENDIF
4703
4704CALL init(gridinfo,gaid, this%griddim, correctedtime, this%timerange(itimerange), &
4705 this%level(ilevel), this%var(ivar))
4706
4707! reset the gridinfo, bad but necessary at this point for encoding the field
4708CALL export(gridinfo%griddim, gridinfo%gaid)
4709! encode the field
4710IF (ASSOCIATED(this%voldati)) THEN
4711 CALL encode_gridinfo(gridinfo, this%voldati(:,:,ilevel,itime,itimerange,ivar))
4712ELSE IF (usetemplate) THEN ! field must be forced into template in this case
4713 NULLIFY(voldati)
4714 CALL volgrid_get_vol_2d(this, ilevel, itime, itimerange, ivar, voldati)
4715 CALL encode_gridinfo(gridinfo, voldati)
4716 DEALLOCATE(voldati)
4717ENDIF
4718
4719END SUBROUTINE export_to_gridinfo
4720
4721
4722!> Import an array of \a gridinfo objects into an array of \a
4723!! volgrid6d objects.
4724!! This method imports an array of gridded fields from an \a
4725!! arrayof_gridinfo object into a suitable number of \a volgrid6d
4726!! objects. The number of \a volgrid6d allocated is determined by the
4727!! number of different grids encountered in \a arrayof_gridinfo.
4728!! Unlike the import for a single \a gridinfo, here the \a volgrid6d
4729!! object is a non-associated pointer to a 1-d array of uninitialized
4730!! objects, and all the dimension descriptors in each of the objects
4731!! are allocated and assigned within the method according to the data
4732!! contained in \a gridinfov.
4733!! If the \a anavar array argument is provided, all the input messages
4734!! whose variable maps to one of the B-table variables contained in \a
4735!! anavar are treated as time-independent (AKA anagraphic data,
4736!! station data, etc.), thus their time and timerange are ignored and
4737!! they are replicated for every time and timerange present in the
4738!! corresponding data volume.
4739SUBROUTINE import_from_gridinfovv(this, gridinfov, dup_mode, clone, decode, &
4740 time_definition, anavar, categoryappend)
4741TYPE(volgrid6d),POINTER :: this(:) !< object in which to import
4742TYPE(arrayof_gridinfo),INTENT(in) :: gridinfov !< array of gridinfo objects to be imported
4743INTEGER,INTENT(in),OPTIONAL :: dup_mode !< determines the behavior in case of duplicate metadata: if \a dup_mode is not provided or 0, a duplicate field overwrites, if \a dup_mode is 1, duplicate fields are merged with priority to the last
4744LOGICAL , INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE. , clone the gaid's from \a gridinfo to \a this
4745LOGICAL,INTENT(in),OPTIONAL :: decode !< if provided and \a .FALSE. the data volume in the elements of \a this is not allocated and successive work will be performed on grid_id's
4746INTEGER,INTENT(IN),OPTIONAL :: time_definition !< 0=time is reference time; 1=time is validity time
4747CHARACTER(len=*),INTENT(IN),OPTIONAL :: anavar(:) !< list of variables (B-table code equivalent) to be treated as time-independent data
4748CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
4749
4750INTEGER :: i, j, stallo
4751INTEGER :: ngrid, ntime, ntimerange, nlevel, nvar, ltime_definition
4752TYPE(l4f_handle) :: category
4753CHARACTER(len=512) :: a_name
4754TYPE(datetime),ALLOCATABLE :: correctedtime(:)
4755LOGICAL,ALLOCATABLE :: isanavar(:)
4756TYPE(vol7d_var) :: lvar
4757TYPE(vol7d_timerange),ALLOCATABLE :: correctedtimerange(:)
4758
4759! category temporanea (altrimenti non possiamo loggare)
4760if (present(categoryappend))then
4761 call l4f_launcher(a_name,a_name_append=trim(subcategory)//"."//trim(categoryappend))
4762else
4763 call l4f_launcher(a_name,a_name_append=trim(subcategory))
4764endif
4765category=l4f_category_get_handle(a_name)
4766
4767#ifdef DEBUG
4768call l4f_category_log(category,l4f_debug,"start import_from_gridinfovv")
4769#endif
4770
4771IF (PRESENT(time_definition)) THEN
4772 ltime_definition = max(min(time_definition, 2), 0)
4773ELSE
4774 ltime_definition = 0
4775ENDIF
4776
4777ngrid=count_distinct(gridinfov%array(1:gridinfov%arraysize)%griddim,back=.true.)
4778CALL l4f_category_log(category,l4f_info, t2c(ngrid)// &
4779 ' different grid definition(s) found in input data')
4780
4781ALLOCATE(this(ngrid),stat=stallo)
4782IF (stallo /= 0)THEN
4783 CALL l4f_category_log(category,l4f_fatal,"allocating memory")
4784 CALL raise_fatal_error()
4785ENDIF
4786DO i = 1, ngrid
4787 IF (PRESENT(categoryappend))THEN
4788 CALL init(this(i), time_definition=ltime_definition, categoryappend=trim(categoryappend)//"-vol"//t2c(i))
4789 ELSE
4790 CALL init(this(i), time_definition=ltime_definition, categoryappend="vol"//t2c(i))
4791 ENDIF
4792ENDDO
4793
4794this(:)%griddim=pack_distinct(gridinfov%array(1:gridinfov%arraysize)%griddim, &
4795 ngrid, back=.true.)
4796
4797! mark elements as ana variables (time-independent)
4798ALLOCATE(isanavar(gridinfov%arraysize))
4799isanavar(:) = .false.
4800IF (PRESENT(anavar)) THEN
4801 DO i = 1, gridinfov%arraysize
4802 DO j = 1, SIZE(anavar)
4803 lvar = convert(gridinfov%array(i)%var)
4804 IF (lvar%btable == anavar(j)) THEN
4805 isanavar(i) = .true.
4806 EXIT
4807 ENDIF
4808 ENDDO
4809 ENDDO
4810 CALL l4f_category_log(category,l4f_info,t2c(count(isanavar))//'/'// &
4811 t2c(gridinfov%arraysize)//' constant-data messages found in input data')
4812ENDIF
4813
4814IF (ltime_definition == 1 .OR. ltime_definition == 2) THEN ! verification time
4815 ALLOCATE(correctedtime(gridinfov%arraysize))
4816 correctedtime(:) = gridinfov%array(1:gridinfov%arraysize)%time
4817 DO i = 1, gridinfov%arraysize
4818 correctedtime(i) = correctedtime(i) + &
4819 timedelta_new(sec=gridinfov%array(i)%timerange%p1)
4820 ENDDO
4821ENDIF
4822IF (ltime_definition == 2) THEN ! set all to analysis
4823 ALLOCATE(correctedtimerange(gridinfov%arraysize))
4824 correctedtimerange(:) = gridinfov%array(1:gridinfov%arraysize)%timerange
4825 correctedtimerange(:)%p1 = 0
4826ENDIF
4827
4828DO i = 1, ngrid
4829 IF (PRESENT(anavar)) THEN
4830 j = count((this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4831 .AND. .NOT.isanavar(:))
4832 IF (j <= 0) THEN
4833 CALL l4f_category_log(category, l4f_fatal, 'grid n.'//t2c(i)// &
4834 ' has only constant data, this is not allowed')
4835 CALL l4f_category_log(category, l4f_fatal, 'please check anavar argument')
4836 CALL raise_fatal_error()
4837 ENDIF
4838 ENDIF
4839 IF (ltime_definition == 1 .OR. ltime_definition == 2) THEN ! verification time
4840 ntime = count_distinct(correctedtime, &
4841 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4842 .AND. .NOT.isanavar(:), back=.true.)
4843 ELSE
4844 ntime = count_distinct(gridinfov%array(1:gridinfov%arraysize)%time, &
4845 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4846 .AND. .NOT.isanavar(:), back=.true.)
4847 ENDIF
4848 IF (ltime_definition == 2) THEN ! set all to analysis
4849 ntimerange = count_distinct(correctedtimerange, &
4850 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4851 .AND. .NOT.isanavar(:), back=.true.)
4852 ELSE
4853 ntimerange = count_distinct(gridinfov%array(1:gridinfov%arraysize)%timerange, &
4854 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4855 .AND. .NOT.isanavar(:), back=.true.)
4856 ENDIF
4857 nlevel = count_distinct(gridinfov%array(1:gridinfov%arraysize)%level, &
4858 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim), &
4859 back=.true.)
4860 nvar = count_distinct(gridinfov%array(1:gridinfov%arraysize)%var, &
4861 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim), &
4862 back=.true.)
4863
4864#ifdef DEBUG
4865 CALL l4f_category_log(this(i)%category,l4f_debug,"alloc volgrid6d index: "//t2c(i))
4866#endif
4867
4868 CALL volgrid6d_alloc(this(i),this(i)%griddim%dim,ntime=ntime, &
4869 ntimerange=ntimerange,nlevel=nlevel,nvar=nvar)
4870
4871 IF (ltime_definition == 1 .OR. ltime_definition == 2) THEN ! verification time
4872 this(i)%time = pack_distinct(correctedtime, ntime, &
4873 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4874 .AND. .NOT.isanavar(:), back=.true.)
4875 ELSE
4876 this(i)%time = pack_distinct(gridinfov%array(1:gridinfov%arraysize)%time, ntime, &
4877 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4878 .AND. .NOT.isanavar(:), back=.true.)
4879 ENDIF
4880 CALL sort(this(i)%time)
4881
4882 IF (ltime_definition == 2) THEN ! set all to analysis
4883 this(i)%timerange = pack_distinct(correctedtimerange, ntimerange, &
4884 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4885 .AND. .NOT.isanavar(:), back=.true.)
4886 ELSE
4887 this(i)%timerange = pack_distinct(gridinfov%array(1:gridinfov%arraysize)%timerange, &
4888 ntimerange, mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
4889 .AND. .NOT.isanavar(:), back=.true.)
4890 ENDIF
4891 CALL sort(this(i)%timerange)
4892
4893 this(i)%level=pack_distinct(gridinfov%array(1:gridinfov%arraysize)%level, &
4894 nlevel,mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim), &
4895 back=.true.)
4896 CALL sort(this(i)%level)
4897
4898 this(i)%var=pack_distinct(gridinfov%array(1:gridinfov%arraysize)%var, nvar, &
4899 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim), &
4900 back=.true.)
4901
4902#ifdef DEBUG
4903 CALL l4f_category_log(this(i)%category,l4f_debug,"alloc_vol volgrid6d index: "//t2c(i))
4904#endif
4905 CALL volgrid6d_alloc_vol(this(i), decode=decode)
4906
4907ENDDO
4908
4909IF (ltime_definition == 1 .OR. ltime_definition == 2) DEALLOCATE(correctedtime)
4910IF (ltime_definition == 2) DEALLOCATE(correctedtimerange)
4911
4912DO i = 1, gridinfov%arraysize
4913
4914#ifdef DEBUG
4915 CALL l4f_category_log(category,l4f_debug,"import from gridinfov index: "//t2c(i))
4916 CALL l4f_category_log(category,l4f_info, &
4917 "to volgrid6d index: "//t2c(index(this%griddim, gridinfov%array(i)%griddim)))
4918#endif
4919
4920 CALL import(this(index(this%griddim, gridinfov%array(i)%griddim)), &
4921 gridinfov%array(i), dup_mode=dup_mode, clone=clone, isanavar=isanavar(i))
4922
4923ENDDO
4924
4925!chiudo il logger temporaneo
4926CALL l4f_category_delete(category)
4927
4928END SUBROUTINE import_from_gridinfovv
4929
4930
4931!> Export a \a volgrid6d object to an \a arrayof_gridinfo object.
4932!! The multidimensional \a volgrid6d structure is serialized into a
4933!! one-dimensional array of gridinfo_def objects, which is allocated
4934!! to the proper size if not already allocated, or it is extended
4935!! keeping the old data if any.
4936SUBROUTINE export_to_gridinfov(this, gridinfov, gaid_template, clone)
4937TYPE(volgrid6d),INTENT(inout) :: this !< volume to be exported
4938TYPE(arrayof_gridinfo),INTENT(inout) :: gridinfov !< output array of gridinfo_def objects
4939TYPE(grid_id),INTENT(in),OPTIONAL :: gaid_template !< \a grid_id template to be used for output data replacing the one contained in \a this
4940LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE., clone the grid_id included in \a this rather than making a shallow copy
4941
4942INTEGER :: i ,itime, itimerange, ilevel, ivar
4943INTEGER :: ntime, ntimerange, nlevel, nvar
4944TYPE(gridinfo_def) :: gridinfol
4945
4946#ifdef DEBUG
4947CALL l4f_category_log(this%category,l4f_debug,"start export_to_gridinfov")
4948#endif
4949
4950! this is necessary in order not to repeatedly and uselessly copy the
4951! same array of coordinates for each 2d grid during export, the
4952! side-effect is that the computed projection in this is lost
4953CALL dealloc(this%griddim%dim)
4954
4955i=0
4956ntime=size(this%time)
4957ntimerange=size(this%timerange)
4958nlevel=size(this%level)
4959nvar=size(this%var)
4960
4961DO itime=1,ntime
4962 DO itimerange=1,ntimerange
4963 DO ilevel=1,nlevel
4964 DO ivar=1,nvar
4965
4966 CALL init(gridinfol)
4967 CALL export(this, gridinfol, itime, itimerange, ilevel, ivar, &
4968 gaid_template=gaid_template, clone=clone)
4969 IF (c_e(gridinfol%gaid)) THEN
4970 CALL insert(gridinfov, gridinfol)
4971 ELSE
4972 CALL delete(gridinfol)
4973 ENDIF
4974
4975 ENDDO
4976 ENDDO
4977 ENDDO
4978ENDDO
4979
4980END SUBROUTINE export_to_gridinfov
4981
4982
4983!> Export an array of \a volgrid6d objects to an \a arrayof_gridinfo object.
4984!! The multidimensional \a volgrid6d structures are serialized into a
4985!! one-dimensional array of gridinfo_def objects, which is allocated
4986!! to the proper size if not already allocated, or it is extended
4987!! keeping the old data if any.
4988SUBROUTINE export_to_gridinfovv(this, gridinfov, gaid_template, clone)
4989!, &
4990! categoryappend)
4991TYPE(volgrid6d),INTENT(inout) :: this(:) !< volume array to be exported
4992TYPE(arrayof_gridinfo),INTENT(inout) :: gridinfov !< output array of gridinfo_def objects
4993TYPE(grid_id),INTENT(in),OPTIONAL :: gaid_template !< \a grid_id template to be used for output data replacing the one contained in \a this
4994LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE., clone the grid_id included in \a this rather than making a shallow copy
4995
4996INTEGER :: i
4997
4998DO i = 1, SIZE(this)
4999#ifdef DEBUG
5000 CALL l4f_category_log(this(i)%category,l4f_debug, &
5001 "export_to_gridinfovv grid index: "//t2c(i))
5002#endif
5003 CALL export(this(i), gridinfov, gaid_template=gaid_template, clone=clone)
5004ENDDO
5005
5006END SUBROUTINE export_to_gridinfovv
5007
5008
5009!> Import the content of a supported file (like grib or gdal-supported
5010!! format) into an array of \a volgrid6d objects. This method imports
5011!! a set of gridded fields from a file object into a suitable number
5012!! of \a volgrid6d objects. The data are imported by creating a
5013!! temporary \a gridinfo object, importing it into the \a volgrid6d
5014!! object cloning the gaid's and then destroying the gridinfo, so it
5015!! works similarly to volgrid6d_class::import_from_gridinfovv() method.
5016!! For a detailed explanation of the \a anavar argument, see the
5017!! documentation of volgrid6d_class::import_from_gridinfovv() method.
5018SUBROUTINE volgrid6d_import_from_file(this, filename, dup_mode, decode, &
5019 time_definition, anavar, categoryappend)
5020TYPE(volgrid6d),POINTER :: this(:) !< object in which to import
5021CHARACTER(len=*),INTENT(in) :: filename !< name of file from which to import
5022INTEGER,INTENT(in),OPTIONAL :: dup_mode !< determines the behavior in case of duplicate metadata: if \a dup_mode is not provided or 0, a duplicate field overwrites, if \a dup_mode is 1, duplicate fields are merged with priority to the last
5023LOGICAL,INTENT(in),OPTIONAL :: decode !< if provided and \a .FALSE. the data volume in the elements of \a this is not allocated and successive work will be performed on grid_id's
5024INTEGER,INTENT(IN),OPTIONAL :: time_definition !< 0=time is reference time; 1=time is validity time
5025CHARACTER(len=*),INTENT(IN),OPTIONAL :: anavar(:) !< list of variables (B-table code equivalent) to be treated as time-independent data
5026character(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
5027
5028TYPE(arrayof_gridinfo) :: gridinfo
5029TYPE(l4f_handle) :: category
5030CHARACTER(len=512) :: a_name
5031
5032NULLIFY(this)
5033
5034IF (PRESENT(categoryappend))THEN
5035 CALL l4f_launcher(a_name,a_name_append= &
5036 trim(subcategory)//"."//trim(categoryappend))
5037ELSE
5038 CALL l4f_launcher(a_name,a_name_append=trim(subcategory))
5039ENDIF
5040category=l4f_category_get_handle(a_name)
5041
5042CALL import(gridinfo, filename=filename, categoryappend=categoryappend)
5043
5044IF (gridinfo%arraysize > 0) THEN
5045
5046 CALL import(this, gridinfo, dup_mode=dup_mode, clone=.true., decode=decode, &
5047 time_definition=time_definition, anavar=anavar, &
5048 categoryappend=categoryappend)
5049
5050 CALL l4f_category_log(category,l4f_info,"deleting gridinfo")
5051 CALL delete(gridinfo)
5052
5053ELSE
5054 CALL l4f_category_log(category,l4f_info,"file does not contain gridded data")
5055ENDIF
5056
5057! close logger
5058CALL l4f_category_delete(category)
5059
5060END SUBROUTINE volgrid6d_import_from_file
5061
5062
5063!> High level method for exporting a volume array to file.
5064!! All the information contained into an array of \a volgrid6d
5065!! objects, i.e. dimension descriptors and data, is exported to a file
5066!! using the proper output driver (typically grib_api for grib
5067!! format). If a template is provided, it will determine the
5068!! characteristic of the output file, otherwise the \a grid_id
5069!! descriptors contained in the volgrid6d object will be used
5070SUBROUTINE volgrid6d_export_to_file(this, filename, gaid_template, categoryappend)
5071TYPE(volgrid6d) :: this(:) !< volume(s) to be exported
5072CHARACTER(len=*),INTENT(in) :: filename !< output file name
5073TYPE(grid_id),INTENT(in),OPTIONAL :: gaid_template !< template for the output file, if provided the grid_id information stored in the volgrid6d objects will be ignored
5074character(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
5075
5076TYPE(arrayof_gridinfo) :: gridinfo
5077TYPE(l4f_handle) :: category
5078CHARACTER(len=512) :: a_name
5079
5080IF (PRESENT(categoryappend)) THEN
5081 CALL l4f_launcher(a_name,a_name_append=trim(subcategory)//"."//trim(categoryappend))
5082ELSE
5083 CALL l4f_launcher(a_name,a_name_append=trim(subcategory))
5084ENDIF
5085category=l4f_category_get_handle(a_name)
5086
5087#ifdef DEBUG
5088CALL l4f_category_log(category,l4f_debug,"start export to file")
5089#endif
5090
5091CALL l4f_category_log(category,l4f_info,"writing volgrid6d to grib file: "//trim(filename))
5092
5093!IF (ASSOCIATED(this)) THEN
5094 CALL export(this, gridinfo, gaid_template=gaid_template, clone=.true.)
5095 IF (gridinfo%arraysize > 0) THEN
5096 CALL export(gridinfo, filename)
5097 CALL delete(gridinfo)
5098 ENDIF
5099!ELSE
5100! CALL l4f_category_log(category,L4F_INFO,"volume volgrid6d is not associated")
5101!ENDIF
5102
5103! close logger
5104CALL l4f_category_delete(category)
5105
5106END SUBROUTINE volgrid6d_export_to_file
5107
5108
5109!> Array destructor for \a volgrid6d class.
5110!! Delete an array of \a volgrid6d objects and deallocate the array
5111!! itself.
5112SUBROUTINE volgrid6dv_delete(this)
5113TYPE(volgrid6d),POINTER :: this(:) !< vector of volgrid6d object
5114
5115INTEGER :: i
5116
5117IF (ASSOCIATED(this)) THEN
5118 DO i = 1, SIZE(this)
5119#ifdef DEBUG
5120 CALL l4f_category_log(this(i)%category,l4f_debug, &
5121 "delete volgrid6d vector index: "//trim(to_char(i)))
5122#endif
5123 CALL delete(this(i))
5124 ENDDO
5125 DEALLOCATE(this)
5126ENDIF
5127
5128END SUBROUTINE volgrid6dv_delete
5129
5130
5131! Internal method for performing grid to grid computations
5132SUBROUTINE volgrid6d_transform_compute(this, volgrid6d_in, volgrid6d_out, &
5133 lev_out, var_coord_vol, clone)
5134TYPE(grid_transform),INTENT(in) :: this ! oggetto di trasformazione per il grigliato
5135type(volgrid6d), INTENT(in) :: volgrid6d_in ! oggetto da trasformare
5136type(volgrid6d), INTENT(inout) :: volgrid6d_out ! oggetto trasformato; deve essere completo (init, alloc, alloc_vol)
5137TYPE(vol7d_level),INTENT(in),OPTIONAL :: lev_out(:) ! vol7d_level object defining target vertical grid, for vertical interpolations
5138INTEGER,INTENT(in),OPTIONAL :: var_coord_vol ! index of variable defining vertical coordinate values in input volume
5139LOGICAL,INTENT(in),OPTIONAL :: clone ! se fornito e \c .TRUE., clona i gaid da volgrid6d_in a volgrid6d_out
5140
5141INTEGER :: ntime, ntimerange, inlevel, onlevel, nvar, &
5142 itime, itimerange, ilevel, ivar, levshift, levused, lvar_coord_vol, spos
5143REAL,POINTER :: voldatiin(:,:,:), voldatiout(:,:,:), coord_3d_in(:,:,:)
5144TYPE(vol7d_level) :: output_levtype
5145LOGICAL,ALLOCATABLE :: zlist(:)
5146
5147
5148#ifdef DEBUG
5149call l4f_category_log(volgrid6d_in%category,l4f_debug,"start volgrid6d_transform_compute")
5150#endif
5151
5152ntime=0
5153ntimerange=0
5154inlevel=0
5155onlevel=0
5156nvar=0
5157lvar_coord_vol = optio_i(var_coord_vol)
5158
5159if (associated(volgrid6d_in%time))then
5160 ntime=size(volgrid6d_in%time)
5161 volgrid6d_out%time=volgrid6d_in%time
5162end if
5163
5164if (associated(volgrid6d_in%timerange))then
5165 ntimerange=size(volgrid6d_in%timerange)
5166 volgrid6d_out%timerange=volgrid6d_in%timerange
5167end if
5168
5169IF (ASSOCIATED(volgrid6d_in%level))THEN
5170 inlevel=SIZE(volgrid6d_in%level)
5171ENDIF
5172IF (PRESENT(lev_out)) THEN
5173 onlevel=SIZE(lev_out)
5174 volgrid6d_out%level=lev_out
5175ELSE IF (ASSOCIATED(volgrid6d_in%level))THEN
5176 onlevel=SIZE(volgrid6d_in%level)
5177 volgrid6d_out%level=volgrid6d_in%level
5178ENDIF
5179
5180if (associated(volgrid6d_in%var))then
5181 nvar=size(volgrid6d_in%var)
5182 volgrid6d_out%var=volgrid6d_in%var
5183end if
5184! allocate once for speed
5185IF (.NOT.ASSOCIATED(volgrid6d_in%voldati)) THEN
5186 ALLOCATE(voldatiin(volgrid6d_in%griddim%dim%nx, volgrid6d_in%griddim%dim%ny, &
5187 inlevel))
5188ENDIF
5189IF (.NOT.ASSOCIATED(volgrid6d_out%voldati)) THEN
5190 ALLOCATE(voldatiout(volgrid6d_out%griddim%dim%nx, volgrid6d_out%griddim%dim%ny, &
5191 onlevel))
5192ENDIF
5193
5194CALL get_val(this, levshift=levshift, levused=levused)
5195spos = imiss
5196IF (c_e(lvar_coord_vol)) THEN
5197 CALL get_val(this%trans, output_levtype=output_levtype)
5198 IF (output_levtype%level1 == 103 .OR. output_levtype%level1 == 108) THEN
5199! here, unlike below, level (1,101) is not accepted because this is
5200! likely for pressure difference with surface 108, not 103
5201 spos = firsttrue(volgrid6d_in%level(:) == vol7d_level_new(1))
5202 IF (spos == 0) THEN
5203 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5204 'output level '//t2c(output_levtype%level1)// &
5205 ' requested, but height/press of surface not provided in volume')
5206 ENDIF
5207 IF (.NOT.c_e(levshift) .AND. .NOT.c_e(levused)) THEN
5208 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5209 'internal inconsistence, levshift and levused undefined when they should be')
5210 ENDIF
5211 ENDIF
5212ENDIF
5213
5214DO ivar=1,nvar
5215! IF (c_e(var_coord_vol)) THEN
5216! IF (ivar == var_coord_vol) CYCLE ! skip coordinate variable in output
5217! ENDIF
5218 DO itimerange=1,ntimerange
5219 DO itime=1,ntime
5220! skip empty columns where possible, improve
5221 IF (c_e(levshift) .AND. c_e(levused)) THEN
5222 IF (.NOT.any(c_e( &
5223 volgrid6d_in%gaid(levshift+1:levshift+levused,itime,itimerange,ivar) &
5224 ))) cycle
5225 ENDIF
5226 DO ilevel = 1, min(inlevel,onlevel)
5227! if present gaid copy it
5228 IF (c_e(volgrid6d_in%gaid(ilevel,itime,itimerange,ivar)) .AND. .NOT. &
5229 c_e(volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))) THEN
5230
5231 IF (optio_log(clone)) THEN
5232 CALL copy(volgrid6d_in%gaid(ilevel,itime,itimerange,ivar),&
5233 volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))
5234#ifdef DEBUG
5235 CALL l4f_category_log(volgrid6d_in%category,l4f_debug, &
5236 "cloning gaid, level "//t2c(ilevel))
5237#endif
5238 ELSE
5239 volgrid6d_out%gaid(ilevel,itime,itimerange,ivar) = &
5240 volgrid6d_in%gaid(ilevel,itime,itimerange,ivar)
5241 ENDIF
5242 ENDIF
5243 ENDDO
5244! if out level are more, we have to clone anyway
5245 DO ilevel = min(inlevel,onlevel) + 1, onlevel
5246 IF (c_e(volgrid6d_in%gaid(inlevel,itime,itimerange,ivar)) .AND. .NOT. &
5247 c_e(volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))) then
5248
5249 CALL copy(volgrid6d_in%gaid(inlevel,itime,itimerange,ivar),&
5250 volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))
5251#ifdef DEBUG
5252 CALL l4f_category_log(volgrid6d_in%category,l4f_debug, &
5253 "forced cloning gaid, level "//t2c(inlevel)//"->"//t2c(ilevel))
5254#endif
5255 ENDIF
5256 ENDDO
5257
5258 IF (c_e(lvar_coord_vol)) THEN
5259 NULLIFY(coord_3d_in)
5260 CALL volgrid_get_vol_3d(volgrid6d_in, itime, itimerange, lvar_coord_vol, &
5261 coord_3d_in)
5262 IF (c_e(spos)) THEN ! compute difference wrt surface coordinate
5263 IF (spos == 0) THEN ! error condition, set all to missing and goodnight
5264 coord_3d_in(:,:,levshift+1:levshift+levused) = rmiss
5265 ELSE
5266 DO ilevel = levshift+1, levshift+levused
5267 WHERE(c_e(coord_3d_in(:,:,ilevel)) .AND. c_e(coord_3d_in(:,:,spos)))
5268 coord_3d_in(:,:,ilevel) = coord_3d_in(:,:,ilevel) - &
5269 coord_3d_in(:,:,spos)
5270 ELSEWHERE
5271 coord_3d_in(:,:,ilevel) = rmiss
5272 END WHERE
5273 ENDDO
5274 ENDIF
5275 ENDIF
5276 ENDIF
5277 CALL volgrid_get_vol_3d(volgrid6d_in, itime, itimerange, ivar, &
5278 voldatiin, zlist)
5279 IF (ASSOCIATED(volgrid6d_out%voldati)) & ! improve!!!!
5280 CALL volgrid_get_vol_3d(volgrid6d_out, itime, itimerange, ivar, &
5281 voldatiout)
5282 IF (c_e(lvar_coord_vol)) THEN ! this is a vertint case, zlist is useless
5283 CALL compute(this, voldatiin, voldatiout, var=convert(volgrid6d_in%var(ivar)), &
5284 coord_3d_in=coord_3d_in(:,:,levshift+1:levshift+levused)) ! subset coord_3d_in
5285 ELSE
5286 CALL compute(this, voldatiin, voldatiout, var=convert(volgrid6d_in%var(ivar)), zlist=zlist)
5287 ENDIF
5288 CALL volgrid_set_vol_3d(volgrid6d_out, itime, itimerange, ivar, &
5289 voldatiout)
5290 ENDDO
5291 ENDDO
5292ENDDO
5293
5294IF (c_e(lvar_coord_vol)) THEN
5295 DEALLOCATE(coord_3d_in)
5296ENDIF
5297IF (.NOT.ASSOCIATED(volgrid6d_in%voldati)) THEN
5298 DEALLOCATE(voldatiin)
5299ENDIF
5300IF (.NOT.ASSOCIATED(volgrid6d_out%voldati)) THEN
5301 DEALLOCATE(voldatiout)
5302ENDIF
5303
5304
5305END SUBROUTINE volgrid6d_transform_compute
5306
5307
5308!> Performs the specified abstract transformation on the data provided.
5309!! The abstract transformation is specified by \a this parameter; the
5310!! corresponding specifical transformation (\a grid_transform object)
5311!! is created and destroyed internally. The output transformed object
5312!! is created internally and it does not require preliminary
5313!! initialisation.
5314SUBROUTINE volgrid6d_transform(this, griddim, volgrid6d_in, volgrid6d_out, &
5315 lev_out, volgrid6d_coord_in, maskgrid, maskbounds, clone, decode, categoryappend)
5316TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
5317TYPE(griddim_def),INTENT(in),OPTIONAL :: griddim !< griddim specifying the output grid (required by most transformation types)
5318TYPE(volgrid6d),INTENT(inout) :: volgrid6d_in !< object to be transformed, it is not modified, despite the INTENT(inout)
5319TYPE(volgrid6d),INTENT(out) :: volgrid6d_out !< transformed object, it does not require initialisation
5320TYPE(vol7d_level),INTENT(in),OPTIONAL,TARGET :: lev_out(:) !< vol7d_level object defining target vertical grid, for vertical interpolations
5321TYPE(volgrid6d),INTENT(in),OPTIONAL :: volgrid6d_coord_in !< object providing time constant input vertical coordinate for some kind of vertical interpolations
5322REAL,INTENT(in),OPTIONAL :: maskgrid(:,:) !< 2D field to be used for defining subareas according to its values, it must have the same shape as the field to be interpolated (for transformation subtype 'maskfill')
5323REAL,INTENT(in),OPTIONAL :: maskbounds(:) !< array of boundary values for defining a subset of valid points where the values of \a maskgrid are within the first and last value of \a maskbounds (for transformation type 'metamorphosis:maskfill')
5324LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \a .TRUE. , clone the \a gaid's from \a volgrid6d_in to \a volgrid6d_out
5325LOGICAL,INTENT(in),OPTIONAL :: decode !< determine whether the data in \a volgrid6d_out should be decoded or remain coded in gaid, if not provided, the decode status is taken from \a volgrid6d_in
5326CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
5327
5328TYPE(grid_transform) :: grid_trans
5329TYPE(vol7d_level),POINTER :: llev_out(:)
5330TYPE(vol7d_level) :: input_levtype, output_levtype
5331TYPE(vol7d_var) :: vcoord_var
5332INTEGER :: i, k, ntime, ntimerange, nlevel, nvar, var_coord_in, var_coord_vol, &
5333 cf_out, nxc, nyc, nxi, nyi, i3, i4, i5, i6, &
5334 ulstart, ulend, spos
5335REAL,ALLOCATABLE :: coord_3d_in(:,:,:)
5336TYPE(geo_proj) :: proj_in, proj_out
5337CHARACTER(len=80) :: trans_type
5338LOGICAL :: ldecode
5339LOGICAL,ALLOCATABLE :: mask_in(:)
5340
5341#ifdef DEBUG
5342call l4f_category_log(volgrid6d_in%category, l4f_debug, "start volgrid6d_transform")
5343#endif
5344
5345ntime=0
5346ntimerange=0
5347nlevel=0
5348nvar=0
5349
5350if (associated(volgrid6d_in%time)) ntime=size(volgrid6d_in%time)
5351if (associated(volgrid6d_in%timerange)) ntimerange=size(volgrid6d_in%timerange)
5352if (associated(volgrid6d_in%level)) nlevel=size(volgrid6d_in%level)
5353if (associated(volgrid6d_in%var)) nvar=size(volgrid6d_in%var)
5354
5355IF (ntime == 0 .OR. ntimerange == 0 .OR. nlevel == 0 .OR. nvar == 0) THEN
5356 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5357 "trying to transform an incomplete volgrid6d object, ntime="//t2c(ntime)// &
5358 ' ntimerange='//t2c(ntimerange)//' nlevel='//t2c(nlevel)//' nvar='//t2c(nvar))
5359 CALL init(volgrid6d_out) ! initialize to empty
5360 CALL raise_error()
5361 RETURN
5362ENDIF
5363
5364CALL get_val(this, trans_type=trans_type)
5365
5366! store desired output component flag and unrotate if necessary
5367cf_out = imiss
5368IF (PRESENT(griddim) .AND. (trans_type == 'inter' .OR. trans_type == 'boxinter' &
5369 .OR. trans_type == 'stencilinter')) THEN ! improve condition!!
5370 CALL get_val(volgrid6d_in%griddim, proj=proj_in)
5371 CALL get_val(griddim, component_flag=cf_out, proj=proj_out)
5372! if different projections wind components must be referred to geographical system
5373 IF (proj_in /= proj_out) CALL vg6d_wind_unrot(volgrid6d_in)
5374ELSE IF (PRESENT(griddim)) THEN ! just get component_flag, the rest is rubbish
5375 CALL get_val(griddim, component_flag=cf_out)
5376ENDIF
5377
5378
5379var_coord_in = imiss
5380var_coord_vol = imiss
5381IF (trans_type == 'vertint') THEN
5382 IF (PRESENT(lev_out)) THEN
5383
5384! if volgrid6d_coord_in provided and allocated, check that it fits
5385 IF (PRESENT(volgrid6d_coord_in)) THEN
5386 IF (ASSOCIATED(volgrid6d_coord_in%voldati)) THEN
5387
5388! strictly 1 time and 1 timerange
5389 IF (SIZE(volgrid6d_coord_in%voldati,4) /= 1 .OR. &
5390 SIZE(volgrid6d_coord_in%voldati,5) /= 1) THEN
5391 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5392 'volume providing constant input vertical coordinate must have &
5393 &only 1 time and 1 timerange')
5394 CALL init(volgrid6d_out) ! initialize to empty
5395 CALL raise_error()
5396 RETURN
5397 ENDIF
5398
5399! search for variable providing vertical coordinate
5400 CALL get_val(this, output_levtype=output_levtype)
5401 vcoord_var = vol7d_var_new(vol7d_level_to_var(output_levtype))
5402 IF (.NOT.c_e(vcoord_var)) THEN
5403 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5404 'requested output level type '//t2c(output_levtype%level1)// &
5405 ' does not correspond to any known physical variable for &
5406 &providing vertical coordinate')
5407 CALL init(volgrid6d_out) ! initialize to empty
5408 CALL raise_error()
5409 RETURN
5410 ENDIF
5411
5412 DO i = 1, SIZE(volgrid6d_coord_in%var)
5413 IF (convert(volgrid6d_coord_in%var(i)) == vcoord_var) THEN
5414 var_coord_in = i
5415 EXIT
5416 ENDIF
5417 ENDDO
5418
5419 IF (.NOT.c_e(var_coord_in)) THEN
5420 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5421 'volume providing constant input vertical coordinate contains no &
5422 &variables matching output level type '//t2c(output_levtype%level1))
5423 CALL init(volgrid6d_out) ! initialize to empty
5424 CALL raise_error()
5425 RETURN
5426 ENDIF
5427 CALL l4f_category_log(volgrid6d_in%category, l4f_info, &
5428 'Coordinate for vertint found in coord volume at position '// &
5429 t2c(var_coord_in))
5430
5431! check horizontal grid
5432! this is too strict (component flag and so on)
5433! IF (volgrid6d_coord_in%griddim /= volgrid6d_in%griddim) THEN
5434 CALL get_val(volgrid6d_coord_in%griddim, nx=nxc, ny=nyc)
5435 CALL get_val(volgrid6d_in%griddim, nx=nxi, ny=nyi)
5436 IF (nxc /= nxi .OR. nyc /= nyi) THEN
5437 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5438 'volume providing constant input vertical coordinate must have &
5439 &the same grid as the input')
5440 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5441 'vertical coordinate: '//t2c(nxc)//'x'//t2c(nyc)// &
5442 ', input volume: '//t2c(nxi)//'x'//t2c(nyi))
5443 CALL init(volgrid6d_out) ! initialize to empty
5444 CALL raise_error()
5445 RETURN
5446 ENDIF
5447
5448! check vertical coordinate system
5449 CALL get_val(this, input_levtype=input_levtype)
5450 mask_in = & ! implicit allocation
5451 (volgrid6d_coord_in%level(:)%level1 == input_levtype%level1) .AND. &
5452 (volgrid6d_coord_in%level(:)%level2 == input_levtype%level2)
5453 ulstart = firsttrue(mask_in)
5454 ulend = lasttrue(mask_in)
5455 IF (ulstart == 0 .OR. ulend == 0) THEN
5456 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5457 'coordinate file does not contain levels of type '// &
5458 t2c(input_levtype%level1)//'/'//t2c(input_levtype%level2)// &
5459 ' specified for input data')
5460 CALL init(volgrid6d_out) ! initialize to empty
5461 CALL raise_error()
5462 RETURN
5463 ENDIF
5464
5465 coord_3d_in = volgrid6d_coord_in%voldati(:,:,ulstart:ulend,1,1,var_coord_in) ! implicit allocation
5466! special case
5467 IF (output_levtype%level1 == 103 .OR. &
5468 output_levtype%level1 == 108) THEN ! surface coordinate needed
5469! allow coding of orography level as in Icon
5470 spos = firsttrue(volgrid6d_coord_in%level(:) == vol7d_level_new(level1=1) .OR. &
5471 volgrid6d_coord_in%level(:) == vol7d_level_new(level1=1, level2=101))
5472 IF (spos == 0) THEN
5473 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5474 'output level '//t2c(output_levtype%level1)// &
5475 ' requested, but height/press of surface not provided in coordinate file')
5476 CALL init(volgrid6d_out) ! initialize to empty
5477 CALL raise_error()
5478 RETURN
5479 ENDIF
5480 DO k = 1, SIZE(coord_3d_in,3)
5481 WHERE(c_e(coord_3d_in(:,:,k)) .AND. &
5482 c_e(volgrid6d_coord_in%voldati(:,:,spos,1,1,var_coord_in)))
5483 coord_3d_in(:,:,k) = coord_3d_in(:,:,k) - &
5484 volgrid6d_coord_in%voldati(:,:,spos,1,1,var_coord_in)
5485 ELSEWHERE
5486 coord_3d_in(:,:,k) = rmiss
5487 END WHERE
5488 ENDDO
5489 ENDIF
5490
5491 ENDIF
5492 ENDIF
5493
5494 IF (.NOT.c_e(var_coord_in)) THEN ! search for coordinate within volume
5495! search for variable providing vertical coordinate
5496 CALL get_val(this, output_levtype=output_levtype)
5497 vcoord_var = vol7d_var_new(vol7d_level_to_var(output_levtype))
5498 IF (c_e(vcoord_var)) THEN
5499 DO i = 1, SIZE(volgrid6d_in%var)
5500 IF (convert(volgrid6d_in%var(i)) == vcoord_var) THEN
5501 var_coord_vol = i
5502 EXIT
5503 ENDIF
5504 ENDDO
5505
5506 IF (c_e(var_coord_vol)) THEN
5507 CALL l4f_category_log(volgrid6d_in%category, l4f_info, &
5508 'Coordinate for vertint found in input volume at position '// &
5509 t2c(var_coord_vol))
5510 ENDIF
5511
5512 ENDIF
5513 ENDIF
5514
5515 CALL init(volgrid6d_out, griddim=volgrid6d_in%griddim, &
5516 time_definition=volgrid6d_in%time_definition, categoryappend=categoryappend)
5517 IF (c_e(var_coord_in)) THEN
5518 CALL init(grid_trans, this, lev_in=volgrid6d_in%level, lev_out=lev_out, &
5519 coord_3d_in=coord_3d_in, categoryappend=categoryappend)
5520 ELSE
5521 CALL init(grid_trans, this, lev_in=volgrid6d_in%level, lev_out=lev_out, &
5522 categoryappend=categoryappend)
5523 ENDIF
5524
5525 CALL get_val(grid_trans, output_level_auto=llev_out) ! get levels if auto-generated
5526 IF (.NOT.ASSOCIATED(llev_out)) llev_out => lev_out
5527 nlevel = SIZE(llev_out)
5528 ELSE
5529 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5530 'volgrid6d_transform: vertint requested but lev_out not provided')
5531 CALL init(volgrid6d_out) ! initialize to empty
5532 CALL raise_error()
5533 RETURN
5534 ENDIF
5535
5536ELSE
5537 CALL init(volgrid6d_out, griddim=griddim, &
5538 time_definition=volgrid6d_in%time_definition, categoryappend=categoryappend)
5539 CALL init(grid_trans, this, in=volgrid6d_in%griddim, out=volgrid6d_out%griddim, &
5540 maskgrid=maskgrid, maskbounds=maskbounds, categoryappend=categoryappend)
5541ENDIF
5542
5543
5544IF (c_e(grid_trans)) THEN ! transformation is valid
5545
5546 CALL volgrid6d_alloc(volgrid6d_out, ntime=ntime, nlevel=nlevel, &
5547 ntimerange=ntimerange, nvar=nvar)
5548
5549 IF (PRESENT(decode)) THEN ! explicitly set decode status
5550 ldecode = decode
5551 ELSE ! take it from input
5552 ldecode = ASSOCIATED(volgrid6d_in%voldati)
5553 ENDIF
5554! force decode if gaid is readonly
5555 decode_loop: DO i6 = 1,nvar
5556 DO i5 = 1, ntimerange
5557 DO i4 = 1, ntime
5558 DO i3 = 1, nlevel
5559 IF (c_e(volgrid6d_in%gaid(i3,i4,i5,i6))) THEN
5560 ldecode = ldecode .OR. grid_id_readonly(volgrid6d_in%gaid(i3,i4,i5,i6))
5561 EXIT decode_loop
5562 ENDIF
5563 ENDDO
5564 ENDDO
5565 ENDDO
5566 ENDDO decode_loop
5567
5568 IF (PRESENT(decode)) THEN
5569 IF (ldecode.NEQV.decode) THEN
5570 CALL l4f_category_log(volgrid6d_in%category, l4f_warn, &
5571 'volgrid6d_transform: decode status forced to .TRUE. because driver does not allow copy')
5572 ENDIF
5573 ENDIF
5574
5575 CALL volgrid6d_alloc_vol(volgrid6d_out, decode=ldecode)
5576
5577!ensure unproj was called
5578!call griddim_unproj(volgrid6d_out%griddim)
5579
5580 IF (trans_type == 'vertint') THEN
5581#ifdef DEBUG
5582 CALL l4f_category_log(volgrid6d_in%category, l4f_debug, &
5583 "volgrid6d_transform: vertint to "//t2c(nlevel)//" levels")
5584#endif
5585 CALL compute(grid_trans, volgrid6d_in, volgrid6d_out, lev_out=llev_out, &
5586 var_coord_vol=var_coord_vol, clone=clone)
5587 ELSE
5588 CALL compute(grid_trans, volgrid6d_in, volgrid6d_out, clone=clone)
5589 ENDIF
5590
5591 IF (cf_out == 0) THEN ! unrotated components are desired
5592 CALL wind_unrot(volgrid6d_out) ! unrotate if necessary
5593 ELSE IF (cf_out == 1) THEN ! rotated components are desired
5594 CALL wind_rot(volgrid6d_out) ! rotate if necessary
5595 ENDIF
5596
5597ELSE
5598! should log with grid_trans%category, but it is private
5599 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
5600 'volgrid6d_transform: transformation not valid')
5601 CALL raise_error()
5602ENDIF
5603
5604CALL delete (grid_trans)
5605
5606END SUBROUTINE volgrid6d_transform
5607
5608
5609!> Performs the specified abstract transformation on the arrays of
5610!! data provided. The abstract transformation is specified by \a this
5611!! parameter; the corresponding specifical transformation (\a
5612!! grid_transform object) is created and destroyed internally. The
5613!! output transformed object is created internally and it does not
5614!! require preliminary initialisation. According to the input data and
5615!! to the transformation type, the output array may have of one or
5616!! more \a volgrid6d elements on different grids.
5617SUBROUTINE volgrid6dv_transform(this, griddim, volgrid6d_in, volgrid6d_out, &
5618 lev_out, volgrid6d_coord_in, maskgrid, maskbounds, clone, decode, categoryappend)
5619TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
5620TYPE(griddim_def),INTENT(in),OPTIONAL :: griddim !< griddim specifying the output grid (required by most transformation types)
5621TYPE(volgrid6d),INTENT(inout) :: volgrid6d_in(:) !< object to be transformed, it is an array of volgrid6d objects, each of which will be transformed, it is not modified, despite the INTENT(inout)
5622TYPE(volgrid6d),POINTER :: volgrid6d_out(:) !< transformed object, it is a non associated pointer to an array of volgrid6d objects which will be allocated by the method
5623TYPE(vol7d_level),INTENT(in),OPTIONAL :: lev_out(:) !< vol7d_level object defining target vertical grid
5624TYPE(volgrid6d),INTENT(in),OPTIONAL :: volgrid6d_coord_in !< object providing time constant input vertical coordinate for some kind of vertical interpolations
5625REAL,INTENT(in),OPTIONAL :: maskgrid(:,:) !< 2D field to be used for defining subareas according to its values, it must have the same shape as the field to be interpolated (for transformation subtype 'maskfill')
5626REAL,INTENT(in),OPTIONAL :: maskbounds(:) !< array of boundary values for defining a subset of valid points where the values of \a maskgrid are within the first and last value of \a maskbounds (for transformation type 'metamorphosis:maskfill')
5627LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \a .TRUE. , clone the \a gaid's from \a volgrid6d_in to \a volgrid6d_out
5628LOGICAL,INTENT(in),OPTIONAL :: decode !< if provided and \a .FALSE. the data volume is not allocated, but work is performed on grid_id's
5629CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
5630
5631INTEGER :: i, stallo
5632
5633
5634allocate(volgrid6d_out(size(volgrid6d_in)),stat=stallo)
5635if (stallo /= 0)then
5636 call l4f_log(l4f_fatal,"allocating memory")
5637 call raise_fatal_error()
5638end if
5639
5640do i=1,size(volgrid6d_in)
5641 call transform(this, griddim, volgrid6d_in(i), volgrid6d_out(i), &
5642 lev_out=lev_out, volgrid6d_coord_in=volgrid6d_coord_in, &
5643 maskgrid=maskgrid, maskbounds=maskbounds, &
5644 clone=clone, decode=decode, categoryappend=categoryappend)
5645end do
5646
5647END SUBROUTINE volgrid6dv_transform
5648
5649
5650! Internal method for performing grid to sparse point computations
5651SUBROUTINE volgrid6d_v7d_transform_compute(this, volgrid6d_in, vol7d_out, &
5652 networkname, noconvert)
5653TYPE(grid_transform),INTENT(in) :: this ! oggetto di trasformazione per grigliato
5654type(volgrid6d), INTENT(in) :: volgrid6d_in ! oggetto da trasformare
5655type(vol7d), INTENT(inout) :: vol7d_out ! oggetto trasformato
5656CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname ! imposta il network in vol7d_out (default='generic')
5657LOGICAL,OPTIONAL,INTENT(in) :: noconvert !< do not try to match variable and convert values during transform
5658
5659INTEGER :: nntime, nana, ntime, ntimerange, nlevel, nvar, stallo
5660INTEGER :: itime, itimerange, ivar, inetwork
5661REAL,ALLOCATABLE :: voldatir_out(:,:,:)
5662TYPE(conv_func),POINTER :: c_func(:)
5663TYPE(datetime),ALLOCATABLE :: validitytime(:,:)
5664REAL,POINTER :: voldatiin(:,:,:)
5665
5666#ifdef DEBUG
5667call l4f_category_log(volgrid6d_in%category,l4f_debug,"start volgrid6d_v7d_transform_compute")
5668#endif
5669
5670ntime=0
5671ntimerange=0
5672nlevel=0
5673nvar=0
5674NULLIFY(c_func)
5675
5676if (present(networkname))then
5677 call init(vol7d_out%network(1),name=networkname)
5678else
5679 call init(vol7d_out%network(1),name='generic')
5680end if
5681
5682if (associated(volgrid6d_in%timerange))then
5683 ntimerange=size(volgrid6d_in%timerange)
5684 vol7d_out%timerange=volgrid6d_in%timerange
5685end if
5686
5687if (associated(volgrid6d_in%time))then
5688 ntime=size(volgrid6d_in%time)
5689
5690 if (vol7d_out%time_definition == volgrid6d_in%time_definition) then
5691
5692 ! i time sono definiti uguali: assegno
5693 vol7d_out%time=volgrid6d_in%time
5694
5695 else
5696 ! converto reference in validity
5697 allocate (validitytime(ntime,ntimerange),stat=stallo)
5698 if (stallo /=0)then
5699 call l4f_category_log(volgrid6d_in%category,l4f_fatal,"allocating memory")
5700 call raise_fatal_error()
5701 end if
5702
5703 do itime=1,ntime
5704 do itimerange=1,ntimerange
5705 if (vol7d_out%time_definition > volgrid6d_in%time_definition) then
5706 validitytime(itime,itimerange) = &
5707 volgrid6d_in%time(itime) + timedelta_new(sec=volgrid6d_in%timerange(itimerange)%p1)
5708 else
5709 validitytime(itime,itimerange) = &
5710 volgrid6d_in%time(itime) - timedelta_new(sec=volgrid6d_in%timerange(itimerange)%p1)
5711 end if
5712 end do
5713 end do
5714
5715 nntime = count_distinct(reshape(validitytime,(/ntime*ntimerange/)), back=.true.)
5716 vol7d_out%time=pack_distinct(reshape(validitytime,(/ntime*ntimerange/)), nntime,back=.true.)
5717
5718 end if
5719end if
5720
5721IF (ASSOCIATED(volgrid6d_in%level)) THEN
5722 nlevel = SIZE(volgrid6d_in%level)
5723 vol7d_out%level=volgrid6d_in%level
5724ENDIF
5725
5726IF (ASSOCIATED(volgrid6d_in%var)) THEN
5727 nvar = SIZE(volgrid6d_in%var)
5728 IF (.NOT. optio_log(noconvert)) THEN
5729 CALL vargrib2varbufr(volgrid6d_in%var, vol7d_out%dativar%r, c_func)
5730 ENDIF
5731ENDIF
5732
5733nana = SIZE(vol7d_out%ana)
5734
5735! allocate once for speed
5736IF (.NOT.ASSOCIATED(volgrid6d_in%voldati)) THEN
5737 ALLOCATE(voldatiin(volgrid6d_in%griddim%dim%nx, volgrid6d_in%griddim%dim%ny, &
5738 nlevel))
5739ENDIF
5740
5741ALLOCATE(voldatir_out(nana,1,nlevel),stat=stallo)
5742IF (stallo /= 0) THEN
5743 CALL l4f_category_log(volgrid6d_in%category,l4f_fatal,"allocating memory")
5744 CALL raise_fatal_error()
5745ENDIF
5746
5747inetwork=1
5748do itime=1,ntime
5749 do itimerange=1,ntimerange
5750! do ilevel=1,nlevel
5751 do ivar=1,nvar
5752
5753 !non è chiaro se questa sezione è utile o no
5754 !ossia il compute sotto sembra prevedere voldatir_out solo in out
5755!!$ if (vol7d_out%time_definition == volgrid6d_in%time_definition) then
5756!!$ voldatir_out=reshape(vol7d_out%voldatir(:,itime,ilevel,itimerange,ivar,inetwork),(/nana,1/))
5757!!$ else
5758!!$ voldatir_out=reshape(vol7d_out%voldatir(:,index(vol7d_out%time,validitytime(itime,ilevel)),ilevel,itimerange,ivar,inetwork),(/nana,1/))
5759!!$ end if
5760
5761 CALL volgrid_get_vol_3d(volgrid6d_in, itime, itimerange, ivar, &
5762 voldatiin)
5763
5764 CALL compute(this, voldatiin, voldatir_out, vol7d_out%dativar%r(ivar))
5765
5766 if (vol7d_out%time_definition == volgrid6d_in%time_definition) then
5767 vol7d_out%voldatir(:,itime,:,itimerange,ivar,inetwork) = &
5768 voldatir_out(:,1,:)
5769 else
5770 vol7d_out%voldatir(:,index(vol7d_out%time,validitytime(itime,itimerange)),:,itimerange,ivar,inetwork)=&
5771 reshape(voldatir_out,(/nana,nlevel/))
5772 end if
5773
5774! 1 indice della dimensione "anagrafica"
5775! 2 indice della dimensione "tempo"
5776! 3 indice della dimensione "livello verticale"
5777! 4 indice della dimensione "intervallo temporale"
5778! 5 indice della dimensione "variabile"
5779! 6 indice della dimensione "rete"
5780
5781 end do
5782! end do
5783 end do
5784end do
5785
5786deallocate(voldatir_out)
5787IF (.NOT.ASSOCIATED(volgrid6d_in%voldati)) THEN
5788 DEALLOCATE(voldatiin)
5789ENDIF
5790if (allocated(validitytime)) deallocate(validitytime)
5791
5792! Rescale valid data according to variable conversion table
5793IF (ASSOCIATED(c_func)) THEN
5794 DO ivar = 1, nvar
5795 CALL compute(c_func(ivar), vol7d_out%voldatir(:,:,:,:,ivar,:))
5796 ENDDO
5797 DEALLOCATE(c_func)
5798ENDIF
5799
5800end SUBROUTINE volgrid6d_v7d_transform_compute
5801
5802
5803!> Performs the specified abstract transformation on the data provided.
5804!! The abstract transformation is specified by \a this parameter; the
5805!! corresponding specifical transformation (\a grid_transform object)
5806!! is created and destroyed internally. The output transformed object
5807!! is created internally and it does not require preliminary
5808!! initialisation.
5809SUBROUTINE volgrid6d_v7d_transform(this, volgrid6d_in, vol7d_out, v7d, &
5810 maskgrid, maskbounds, networkname, noconvert, find_index, categoryappend)
5811TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
5812TYPE(volgrid6d),INTENT(inout) :: volgrid6d_in !< object to be transformed, it is not modified, despite the INTENT(inout)
5813TYPE(vol7d),INTENT(out) :: vol7d_out !< transformed object, it does not requires initialisation
5814TYPE(vol7d),INTENT(in),OPTIONAL :: v7d !< object containing a list of points over which transformation has to be done (required by some transformation types)
5815REAL,INTENT(in),OPTIONAL :: maskgrid(:,:) !< 2D field to be used for defining subareas according to its values, it must have the same shape as the field to be interpolated (for transformation type 'maskinter')
5816REAL,INTENT(in),OPTIONAL :: maskbounds(:) !< array of boundary values for defining subareas from the values of \a maskgrid, the number of subareas is SIZE(maskbounds) - 1, if not provided a default based on extreme values of \a makgrid is used
5817CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname !< set the output network name in vol7d_out (default='generic')
5818LOGICAL,OPTIONAL,INTENT(in) :: noconvert !< do not try to match variable and convert values during transform
5819PROCEDURE(basic_find_index),POINTER,OPTIONAL :: find_index
5820CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
5821
5822type(grid_transform) :: grid_trans
5823INTEGER :: ntime, ntimerange, nlevel, nvar, nana, time_definition, nnetwork, stallo
5824INTEGER :: itime, itimerange, inetwork
5825TYPE(datetime),ALLOCATABLE :: validitytime(:,:)
5826INTEGER,ALLOCATABLE :: point_index(:)
5827TYPE(vol7d) :: v7d_locana
5828
5829#ifdef DEBUG
5830call l4f_category_log(volgrid6d_in%category,l4f_debug,"start volgrid6d_v7d_transform")
5831#endif
5832
5833call vg6d_wind_unrot(volgrid6d_in)
5834
5835ntime=0
5836ntimerange=0
5837nlevel=0
5838nvar=0
5839nnetwork=1
5840
5841call get_val(this,time_definition=time_definition)
5842if (.not. c_e(time_definition)) then
5843 time_definition=1 ! default to validity time
5844endif
5845
5846IF (PRESENT(v7d)) THEN
5847 CALL vol7d_copy(v7d, v7d_locana)
5848ELSE
5849 CALL init(v7d_locana)
5850ENDIF
5851
5852if (associated(volgrid6d_in%timerange)) ntimerange=size(volgrid6d_in%timerange)
5853
5854if (associated(volgrid6d_in%time)) then
5855
5856 ntime=size(volgrid6d_in%time)
5857
5858 if (time_definition /= volgrid6d_in%time_definition) then
5859
5860 ! converto reference in validity
5861 allocate (validitytime(ntime,ntimerange),stat=stallo)
5862 if (stallo /=0)then
5863 call l4f_category_log(volgrid6d_in%category,l4f_fatal,"allocating memory")
5864 call raise_fatal_error()
5865 end if
5866
5867 do itime=1,ntime
5868 do itimerange=1,ntimerange
5869 if (time_definition > volgrid6d_in%time_definition) then
5870 validitytime(itime,itimerange) = &
5871 volgrid6d_in%time(itime) + timedelta_new(sec=volgrid6d_in%timerange(itimerange)%p1)
5872 else
5873 validitytime(itime,itimerange) = &
5874 volgrid6d_in%time(itime) - timedelta_new(sec=volgrid6d_in%timerange(itimerange)%p1)
5875 end if
5876 end do
5877 end do
5878
5879 ntime = count_distinct(reshape(validitytime,(/ntime*ntimerange/)), back=.true.)
5880 deallocate (validitytime)
5881
5882 end if
5883end if
5884
5885
5886if (associated(volgrid6d_in%level)) nlevel=size(volgrid6d_in%level)
5887if (associated(volgrid6d_in%var)) nvar=size(volgrid6d_in%var)
5888
5889CALL init(grid_trans, this, volgrid6d_in%griddim, v7d_locana, &
5890 maskgrid=maskgrid, maskbounds=maskbounds, find_index=find_index, &
5891 categoryappend=categoryappend)
5892CALL init (vol7d_out,time_definition=time_definition)
5893
5894IF (c_e(grid_trans)) THEN
5895
5896 nana=SIZE(v7d_locana%ana)
5897 CALL vol7d_alloc(vol7d_out, nana=nana, ntime=ntime, nlevel=nlevel, &
5898 ntimerange=ntimerange, ndativarr=nvar, nnetwork=nnetwork)
5899 vol7d_out%ana = v7d_locana%ana
5900
5901 CALL get_val(grid_trans, output_point_index=point_index)
5902 IF (ALLOCATED(point_index)) THEN
5903! check that size(point_index) == nana?
5904 CALL vol7d_alloc(vol7d_out, nanavari=1)
5905 CALL init(vol7d_out%anavar%i(1), 'B01192')
5906 ENDIF
5907
5908 CALL vol7d_alloc_vol(vol7d_out)
5909
5910 IF (ALLOCATED(point_index)) THEN
5911 DO inetwork = 1, nnetwork
5912 vol7d_out%volanai(:,1,inetwork) = point_index(:)
5913 ENDDO
5914 ENDIF
5915 CALL compute(grid_trans, volgrid6d_in, vol7d_out, networkname, noconvert)
5916ELSE
5917 CALL l4f_log(l4f_error, 'vg6d_v7d_transform: transformation not valid')
5918 CALL raise_error()
5919ENDIF
5920
5921CALL delete(grid_trans)
5922
5923#ifdef HAVE_DBALLE
5924! set variables to a conformal state
5925CALL vol7d_dballe_set_var_du(vol7d_out)
5926#endif
5927
5928CALL delete(v7d_locana)
5929
5930END SUBROUTINE volgrid6d_v7d_transform
5931
5932
5933!> Performs the specified abstract transformation on the arrays of
5934!! data provided. The abstract transformation is specified by \a this
5935!! parameter; the corresponding specifical transformation (\a
5936!! grid_transform object) is created and destroyed internally. The
5937!! output transformed object is created internally and it does not
5938!! require preliminary initialisation. The transformation performed on
5939!! each element of the input \a volgrid6d array object is merged into
5940!! a single \a vol7d output object.
5941SUBROUTINE volgrid6dv_v7d_transform(this, volgrid6d_in, vol7d_out, v7d, &
5942 maskgrid, maskbounds, networkname, noconvert, find_index, categoryappend)
5943TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
5944TYPE(volgrid6d),INTENT(inout) :: volgrid6d_in(:) !< object to be transformed, it is an array of volgrid6d objects, each of which will be transformed, it is not modified, despite the INTENT(inout)
5945TYPE(vol7d),INTENT(out) :: vol7d_out !< transformed object, it does not require initialisation
5946TYPE(vol7d),INTENT(in),OPTIONAL :: v7d !< object containing a list of points over which transformation has to be done (required by some transformation types)
5947REAL,INTENT(in),OPTIONAL :: maskgrid(:,:) !< 2D field to be used for defining subareas according to its values, it must have the same shape as the field to be interpolated (for transformation type 'maskinter')
5948REAL,INTENT(in),OPTIONAL :: maskbounds(:) !< array of boundary values for defining subareas from the values of \a maskgrid, the number of subareas is SIZE(maskbounds) - 1, if not provided a default based on extreme values of \a makgrid is used
5949CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname !< set the output network name in vol7d_out (default='generic')
5950LOGICAL,OPTIONAL,INTENT(in) :: noconvert !< do not try to match variable and convert values during transform
5951PROCEDURE(basic_find_index),POINTER,OPTIONAL :: find_index
5952CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
5953
5954integer :: i
5955TYPE(vol7d) :: v7dtmp
5956
5957
5958CALL init(v7dtmp)
5959CALL init(vol7d_out)
5960
5961DO i=1,SIZE(volgrid6d_in)
5962 CALL transform(this, volgrid6d_in(i), v7dtmp, v7d=v7d, &
5963 maskgrid=maskgrid, maskbounds=maskbounds, &
5964 networkname=networkname, noconvert=noconvert, find_index=find_index, &
5965 categoryappend=categoryappend)
5966 CALL vol7d_append(vol7d_out, v7dtmp)
5967ENDDO
5968
5969END SUBROUTINE volgrid6dv_v7d_transform
5970
5971
5972! Internal method for performing sparse point to grid computations
5973SUBROUTINE v7d_volgrid6d_transform_compute(this, vol7d_in, volgrid6d_out, networkname, gaid_template)
5974TYPE(grid_transform),INTENT(in) :: this ! object specifying the specific transformation
5975type(vol7d), INTENT(in) :: vol7d_in ! object to be transformed
5976type(volgrid6d), INTENT(inout) :: volgrid6d_out ! transformed object
5977CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname ! select the network to be processed from the \a vol7d input object, default the first network
5978TYPE(grid_id),OPTIONAL,INTENT(in) :: gaid_template ! the template (typically grib_api) to be associated with output data, it also helps in improving variable conversion
5979
5980integer :: nana, ntime, ntimerange, nlevel, nvar
5981INTEGER :: ilevel, itime, itimerange, ivar, inetwork
5982
5983REAL,POINTER :: voldatiout(:,:,:)
5984type(vol7d_network) :: network
5985TYPE(conv_func), pointer :: c_func(:)
5986!TODO category sarebbe da prendere da vol7d
5987#ifdef DEBUG
5988CALL l4f_category_log(volgrid6d_out%category, l4f_debug, &
5989 'start v7d_volgrid6d_transform_compute')
5990#endif
5991
5992ntime=0
5993ntimerange=0
5994nlevel=0
5995nvar=0
5996
5997IF (PRESENT(networkname)) THEN
5998 CALL init(network,name=networkname)
5999 inetwork = index(vol7d_in%network,network)
6000 IF (inetwork <= 0) THEN
6001 CALL l4f_category_log(volgrid6d_out%category,l4f_warn, &
6002 'network '//trim(networkname)//' not found, first network will be transformed')
6003 inetwork = 1
6004 ENDIF
6005ELSE
6006 inetwork = 1
6007ENDIF
6008
6009! no time_definition conversion implemented, output will be the same as input
6010if (associated(vol7d_in%time))then
6011 ntime=size(vol7d_in%time)
6012 volgrid6d_out%time=vol7d_in%time
6013end if
6014
6015if (associated(vol7d_in%timerange))then
6016 ntimerange=size(vol7d_in%timerange)
6017 volgrid6d_out%timerange=vol7d_in%timerange
6018end if
6019
6020if (associated(vol7d_in%level))then
6021 nlevel=size(vol7d_in%level)
6022 volgrid6d_out%level=vol7d_in%level
6023end if
6024
6025if (associated(vol7d_in%dativar%r))then
6026 nvar=size(vol7d_in%dativar%r)
6027 CALL varbufr2vargrib(vol7d_in%dativar%r, volgrid6d_out%var, c_func, gaid_template)
6028end if
6029
6030nana=SIZE(vol7d_in%voldatir, 1)
6031! allocate once for speed
6032IF (.NOT.ASSOCIATED(volgrid6d_out%voldati)) THEN
6033 ALLOCATE(voldatiout(volgrid6d_out%griddim%dim%nx, volgrid6d_out%griddim%dim%ny, &
6034 nlevel))
6035ENDIF
6036
6037DO ivar=1,nvar
6038 DO itimerange=1,ntimerange
6039 DO itime=1,ntime
6040
6041! clone the gaid template where I have data
6042 IF (PRESENT(gaid_template)) THEN
6043 DO ilevel = 1, nlevel
6044 IF (any(c_e(vol7d_in%voldatir(:,itime,ilevel,itimerange,ivar,inetwork)))) THEN
6045 CALL copy(gaid_template, volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))
6046 ELSE
6047 volgrid6d_out%gaid(ilevel,itime,itimerange,ivar) = grid_id_new()
6048 ENDIF
6049 ENDDO
6050 ENDIF
6051
6052! get data
6053 IF (ASSOCIATED(volgrid6d_out%voldati)) & ! improve!!!!
6054 CALL volgrid_get_vol_3d(volgrid6d_out, itime, itimerange, ivar, &
6055 voldatiout)
6056! do the interpolation
6057 CALL compute(this, &
6058 vol7d_in%voldatir(:,itime,:,itimerange,ivar,inetwork), voldatiout, &
6059 vol7d_in%dativar%r(ivar))
6060! rescale valid data according to variable conversion table
6061 IF (ASSOCIATED(c_func)) THEN
6062 CALL compute(c_func(ivar), voldatiout(:,:,:))
6063 ENDIF
6064! put data
6065 CALL volgrid_set_vol_3d(volgrid6d_out, itime, itimerange, ivar, &
6066 voldatiout)
6067
6068 ENDDO
6069 ENDDO
6070ENDDO
6071
6072IF (.NOT.ASSOCIATED(volgrid6d_out%voldati)) THEN
6073 DEALLOCATE(voldatiout)
6074ENDIF
6075IF (ASSOCIATED(c_func)) THEN
6076 DEALLOCATE(c_func)
6077ENDIF
6078
6079END SUBROUTINE v7d_volgrid6d_transform_compute
6080
6081
6082!> Performs the specified abstract transformation on the data provided.
6083!! The abstract transformation is specified by \a this parameter; the
6084!! corresponding specifical transformation (\a grid_transform object)
6085!! is created and destroyed internally. The output transformed object
6086!! is created internally and it does not require preliminary
6087!! initialisation.
6088SUBROUTINE v7d_volgrid6d_transform(this, griddim, vol7d_in, volgrid6d_out, &
6089 networkname, gaid_template, categoryappend)
6090TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
6091TYPE(griddim_def),INTENT(in),OPTIONAL :: griddim !< griddim specifying the output grid (required by most transformation types)
6092! TODO ripristinare intent(in) dopo le opportune modifiche in grid_class.F90
6093TYPE(vol7d),INTENT(inout) :: vol7d_in !< object to be transformed, it is not modified, despite the INTENT(inout)
6094TYPE(volgrid6d),INTENT(out) :: volgrid6d_out !< transformed object, it does not require initialisation
6095CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname !< select the network to be processed from the \a vol7d input object, default the first network
6096TYPE(grid_id),OPTIONAL,INTENT(in) :: gaid_template !< the template (typically grib_api) to be associated with output data, it also helps in improving variable conversion
6097CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
6098
6099type(grid_transform) :: grid_trans
6100integer :: ntime, ntimerange, nlevel, nvar
6101
6102
6103!TODO la category sarebbe da prendere da vol7d
6104!call l4f_category_log(vol7d_out%category,L4F_DEBUG,"start volgrid6d_transform")
6105
6106CALL vol7d_alloc_vol(vol7d_in) ! be safe
6107ntime=SIZE(vol7d_in%time)
6108ntimerange=SIZE(vol7d_in%timerange)
6109nlevel=SIZE(vol7d_in%level)
6110nvar=0
6111if (associated(vol7d_in%dativar%r)) nvar=size(vol7d_in%dativar%r)
6112
6113IF (nvar <= 0) THEN ! use vol7d category once it will be implemented
6114 CALL l4f_log(l4f_error, &
6115 "trying to transform a vol7d object incomplete or without real variables")
6116 CALL init(volgrid6d_out) ! initialize to empty
6117 CALL raise_error()
6118 RETURN
6119ENDIF
6120
6121CALL init(grid_trans, this, vol7d_in, griddim, categoryappend=categoryappend)
6122CALL init(volgrid6d_out, griddim, time_definition=vol7d_in%time_definition, &
6123 categoryappend=categoryappend)
6124
6125IF (c_e(grid_trans)) THEN
6126
6127 CALL volgrid6d_alloc(volgrid6d_out, griddim%dim, ntime=ntime, nlevel=nlevel, &
6128 ntimerange=ntimerange, nvar=nvar)
6129! can I avoid decode=.TRUE. here, using gaid_template?
6130 CALL volgrid6d_alloc_vol(volgrid6d_out, decode=.true.)
6131
6132 CALL compute(grid_trans, vol7d_in, volgrid6d_out, networkname, gaid_template)
6133
6134 CALL vg6d_wind_rot(volgrid6d_out)
6135ELSE
6136! should log with grid_trans%category, but it is private
6137 CALL l4f_log(l4f_error, 'v7d_vg6d_transform: transformation not valid')
6138 CALL raise_error()
6139ENDIF
6140
6141CALL delete(grid_trans)
6142
6143END SUBROUTINE v7d_volgrid6d_transform
6144
6145
6146! Internal method for performing sparse point to sparse point computations
6147SUBROUTINE v7d_v7d_transform_compute(this, vol7d_in, vol7d_out, lev_out, &
6148 var_coord_vol)
6149TYPE(grid_transform),INTENT(in) :: this ! oggetto di trasformazione per grigliato
6150type(vol7d), INTENT(in) :: vol7d_in ! oggetto da trasformare
6151type(vol7d), INTENT(inout) :: vol7d_out ! oggetto trasformato
6152TYPE(vol7d_level),INTENT(in),OPTIONAL :: lev_out(:) ! vol7d_level object defining target vertical grid, for vertical interpolations
6153INTEGER,INTENT(in),OPTIONAL :: var_coord_vol ! index of variable defining vertical coordinate values in input volume
6154
6155INTEGER :: itime, itimerange, ilevel, ivar, inetwork, &
6156 levshift, levused, lvar_coord_vol, spos
6157REAL,ALLOCATABLE :: coord_3d_in(:,:,:)
6158TYPE(vol7d_level) :: output_levtype
6159
6160lvar_coord_vol = optio_i(var_coord_vol)
6161vol7d_out%time(:) = vol7d_in%time(:)
6162vol7d_out%timerange(:) = vol7d_in%timerange(:)
6163IF (PRESENT(lev_out)) THEN
6164 vol7d_out%level(:) = lev_out(:)
6165ELSE
6166 vol7d_out%level(:) = vol7d_in%level(:)
6167ENDIF
6168vol7d_out%network(:) = vol7d_in%network(:)
6169IF (ASSOCIATED(vol7d_in%dativar%r)) THEN ! work only when real vars are available
6170 vol7d_out%dativar%r(:) = vol7d_in%dativar%r(:)
6171
6172 CALL get_val(this, levshift=levshift, levused=levused)
6173 spos = imiss
6174 IF (c_e(lvar_coord_vol)) THEN
6175 CALL get_val(this%trans, output_levtype=output_levtype)
6176 IF (output_levtype%level1 == 103 .OR. output_levtype%level1 == 108) THEN
6177 spos = firsttrue(vol7d_in%level(:) == vol7d_level_new(1))
6178 IF (spos == 0) THEN
6179 CALL l4f_log(l4f_error, &
6180 'output level '//t2c(output_levtype%level1)// &
6181 ' requested, but height/press of surface not provided in volume')
6182 ENDIF
6183 IF (.NOT.c_e(levshift) .AND. .NOT.c_e(levused)) THEN
6184 CALL l4f_log(l4f_error, &
6185 'internal inconsistence, levshift and levused undefined when they should be')
6186 ENDIF
6187 ALLOCATE(coord_3d_in(SIZE(vol7d_in%ana),1,SIZE(vol7d_in%level)))
6188 ENDIF
6189
6190 ENDIF
6191
6192 DO inetwork = 1, SIZE(vol7d_in%network)
6193 DO ivar = 1, SIZE(vol7d_in%dativar%r)
6194 DO itimerange = 1, SIZE(vol7d_in%timerange)
6195 DO itime = 1, SIZE(vol7d_in%time)
6196
6197! dirty trick to make voldatir look like a 2d-array of shape (nana,1)
6198 IF (c_e(lvar_coord_vol)) THEN
6199 IF (c_e(spos)) THEN ! compute difference wrt surface coordinate
6200 IF (spos == 0) THEN ! error condition, set all to missing and goodnight
6201 coord_3d_in(:,:,levshift+1:levshift+levused) = rmiss
6202 ELSE
6203 DO ilevel = levshift+1, levshift+levused
6204 WHERE(c_e(vol7d_in%voldatir(:,itime:itime,ilevel,itimerange,lvar_coord_vol,inetwork)) .AND. &
6205 c_e(vol7d_in%voldatir(:,itime:itime,spos,itimerange,lvar_coord_vol,inetwork)))
6206 coord_3d_in(:,:,ilevel) = vol7d_in%voldatir(:,itime:itime,ilevel,itimerange,lvar_coord_vol,inetwork) - &
6207 vol7d_in%voldatir(:,itime:itime,spos,itimerange,lvar_coord_vol,inetwork)
6208 ELSEWHERE
6209 coord_3d_in(:,:,ilevel) = rmiss
6210 END WHERE
6211 ENDDO
6212 ENDIF
6213 CALL compute(this, &
6214 vol7d_in%voldatir(:,itime,:,itimerange,ivar,inetwork), &
6215 vol7d_out%voldatir(:,itime:itime,:,itimerange,ivar,inetwork), &
6216 var=vol7d_in%dativar%r(ivar), &
6217 coord_3d_in=coord_3d_in)
6218 ELSE
6219 CALL compute(this, &
6220 vol7d_in%voldatir(:,itime,:,itimerange,ivar,inetwork), &
6221 vol7d_out%voldatir(:,itime:itime,:,itimerange,ivar,inetwork), &
6222 var=vol7d_in%dativar%r(ivar), &
6223 coord_3d_in=vol7d_in%voldatir(:,itime:itime,:,itimerange, &
6224 lvar_coord_vol,inetwork))
6225 ENDIF
6226 ELSE
6227 CALL compute(this, &
6228 vol7d_in%voldatir(:,itime,:,itimerange,ivar,inetwork), &
6229 vol7d_out%voldatir(:,itime:itime,:,itimerange,ivar,inetwork), &
6230 var=vol7d_in%dativar%r(ivar))
6231 ENDIF
6232 ENDDO
6233 ENDDO
6234 ENDDO
6235 ENDDO
6236
6237ENDIF
6238
6239END SUBROUTINE v7d_v7d_transform_compute
6240
6241
6242!> Performs the specified abstract transformation on the data provided.
6243!! The abstract transformation is specified by \a this parameter; the
6244!! corresponding specifical transformation (\a grid_transform object)
6245!! is created and destroyed internally. The output transformed object
6246!! is created internally and it does not require preliminary
6247!! initialisation. The success of the transformation can be checked
6248!! with the \a c_e method: c_e(vol7d_out).
6249SUBROUTINE v7d_v7d_transform(this, vol7d_in, vol7d_out, v7d, maskbounds, &
6250 lev_out, vol7d_coord_in, categoryappend)
6251TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
6252TYPE(vol7d),INTENT(inout) :: vol7d_in !< object to be transformed, it is not modified, despite the INTENT(inout)
6253TYPE(vol7d),INTENT(out) :: vol7d_out !< transformed object, it does not require initialisation
6254TYPE(vol7d),INTENT(in),OPTIONAL :: v7d !< object containing a list of points over which transformation has to be done (required by some transformation types)
6255REAL,INTENT(in),OPTIONAL :: maskbounds(:) !< array of boundary values for defining a subset of valid points where the values of \a maskgrid are within the first and last value of \a maskbounds (for transformation type 'metamorphosis:maskfill')
6256TYPE(vol7d_level),INTENT(in),OPTIONAL,TARGET :: lev_out(:) !< vol7d_level object defining target vertical grid, for vertical interpolations
6257TYPE(vol7d),INTENT(in),OPTIONAL :: vol7d_coord_in !< object providing time constant input vertical coordinate for some kind of vertical interpolations
6258CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
6259
6260INTEGER :: nvar, inetwork
6261TYPE(grid_transform) :: grid_trans
6262TYPE(vol7d_level),POINTER :: llev_out(:)
6263TYPE(vol7d_level) :: input_levtype, output_levtype
6264TYPE(vol7d_var) :: vcoord_var
6265REAL,ALLOCATABLE :: coord_3d_in(:,:,:)
6266INTEGER :: var_coord_in, var_coord_vol, i, k, ulstart, ulend, spos
6267INTEGER,ALLOCATABLE :: point_index(:)
6268TYPE(vol7d) :: v7d_locana, vol7d_tmpana
6269CHARACTER(len=80) :: trans_type
6270LOGICAL,ALLOCATABLE :: mask_in(:), point_mask(:)
6271
6272CALL vol7d_alloc_vol(vol7d_in) ! be safe
6273nvar=0
6274IF (ASSOCIATED(vol7d_in%dativar%r)) nvar=SIZE(vol7d_in%dativar%r)
6275
6276CALL init(v7d_locana)
6277IF (PRESENT(v7d)) v7d_locana = v7d
6278CALL init(vol7d_out, time_definition=vol7d_in%time_definition)
6279
6280CALL get_val(this, trans_type=trans_type)
6281
6282var_coord_vol = imiss
6283IF (trans_type == 'vertint') THEN
6284
6285 IF (PRESENT(lev_out)) THEN
6286
6287! if vol7d_coord_in provided and allocated, check that it fits
6288 var_coord_in = -1
6289 IF (PRESENT(vol7d_coord_in)) THEN
6290 IF (ASSOCIATED(vol7d_coord_in%voldatir) .AND. &
6291 ASSOCIATED(vol7d_coord_in%dativar%r)) THEN
6292
6293! strictly 1 time, 1 timerange and 1 network
6294 IF (SIZE(vol7d_coord_in%voldatir,2) /= 1 .OR. &
6295 SIZE(vol7d_coord_in%voldatir,4) /= 1 .OR. &
6296 SIZE(vol7d_coord_in%voldatir,6) /= 1) THEN
6297 CALL l4f_log(l4f_error, &
6298 'volume providing constant input vertical coordinate must have &
6299 &only 1 time, 1 timerange and 1 network')
6300 CALL raise_error()
6301 RETURN
6302 ENDIF
6303
6304! search for variable providing vertical coordinate
6305 CALL get_val(this, output_levtype=output_levtype)
6306 vcoord_var = vol7d_var_new(vol7d_level_to_var(output_levtype))
6307 IF (.NOT.c_e(vcoord_var)) THEN
6308 CALL l4f_log(l4f_error, &
6309 'requested output level type '//t2c(output_levtype%level1)// &
6310 ' does not correspond to any known physical variable for &
6311 &providing vertical coordinate')
6312 CALL raise_error()
6313 RETURN
6314 ENDIF
6315
6316 var_coord_in = index(vol7d_coord_in%dativar%r, vcoord_var)
6317
6318 IF (var_coord_in <= 0) THEN
6319 CALL l4f_log(l4f_error, &
6320 'volume providing constant input vertical coordinate contains no &
6321 &real variables matching output level type '//t2c(output_levtype%level1))
6322 CALL raise_error()
6323 RETURN
6324 ENDIF
6325 CALL l4f_log(l4f_info, &
6326 'Coordinate for vertint found in coord volume at position '// &
6327 t2c(var_coord_in))
6328
6329! check vertical coordinate system
6330 CALL get_val(this, input_levtype=input_levtype)
6331 mask_in = & ! implicit allocation
6332 (vol7d_coord_in%level(:)%level1 == input_levtype%level1) .AND. &
6333 (vol7d_coord_in%level(:)%level2 == input_levtype%level2)
6334 ulstart = firsttrue(mask_in)
6335 ulend = lasttrue(mask_in)
6336 IF (ulstart == 0 .OR. ulend == 0) THEN
6337 CALL l4f_log(l4f_error, &
6338 'coordinate file does not contain levels of type '// &
6339 t2c(input_levtype%level1)//'/'//t2c(input_levtype%level2)// &
6340 ' specified for input data')
6341 CALL raise_error()
6342 RETURN
6343 ENDIF
6344
6345 coord_3d_in = vol7d_coord_in%voldatir(:,1:1,ulstart:ulend,1,var_coord_in,1) ! dirty 1:1, implicit allocation
6346! special case
6347 IF (output_levtype%level1 == 103 &
6348 .OR. output_levtype%level1 == 108) THEN ! surface coordinate needed
6349 spos = firsttrue(vol7d_coord_in%level(:) == vol7d_level_new(1))
6350 IF (spos == 0) THEN
6351 CALL l4f_log(l4f_error, &
6352 'output level '//t2c(output_levtype%level1)// &
6353 ' requested, but height/press of surface not provided in coordinate file')
6354 CALL raise_error()
6355 RETURN
6356 ENDIF
6357 DO k = 1, SIZE(coord_3d_in,3)
6358 WHERE(c_e(coord_3d_in(:,:,k)) .AND. &
6359 c_e(vol7d_coord_in%voldatir(:,1:1,spos,1,var_coord_in,1)))
6360 coord_3d_in(:,:,k) = coord_3d_in(:,:,k) - &
6361 vol7d_coord_in%voldatir(:,1:1,spos,1,var_coord_in,1)
6362 ELSEWHERE
6363 coord_3d_in(:,:,k) = rmiss
6364 END WHERE
6365 ENDDO
6366 ENDIF
6367
6368 ENDIF
6369 ENDIF
6370
6371 IF (var_coord_in <= 0) THEN ! search for coordinate within volume
6372! search for variable providing vertical coordinate
6373 CALL get_val(this, output_levtype=output_levtype)
6374 vcoord_var = vol7d_var_new(vol7d_level_to_var(output_levtype))
6375 IF (c_e(vcoord_var)) THEN
6376 DO i = 1, SIZE(vol7d_in%dativar%r)
6377 IF (vol7d_in%dativar%r(i) == vcoord_var) THEN
6378 var_coord_vol = i
6379 EXIT
6380 ENDIF
6381 ENDDO
6382
6383 IF (c_e(var_coord_vol)) THEN
6384 CALL l4f_log(l4f_info, &
6385 'Coordinate for vertint found in input volume at position '// &
6386 t2c(var_coord_vol))
6387 ENDIF
6388
6389 ENDIF
6390 ENDIF
6391
6392 IF (var_coord_in > 0) THEN
6393 CALL init(grid_trans, this, lev_in=vol7d_in%level, lev_out=lev_out, &
6394 coord_3d_in=coord_3d_in, categoryappend=categoryappend)
6395 ELSE
6396 CALL init(grid_trans, this, lev_in=vol7d_in%level, lev_out=lev_out, &
6397 categoryappend=categoryappend)
6398 ENDIF
6399
6400 CALL get_val(grid_trans, output_level_auto=llev_out) ! get levels if auto-generated
6401 IF (.NOT.associated(llev_out)) llev_out => lev_out
6402
6403 IF (c_e(grid_trans)) then! .AND. nvar > 0) THEN
6404
6405 CALL vol7d_alloc(vol7d_out, nana=SIZE(vol7d_in%ana), &
6406 ntime=SIZE(vol7d_in%time), ntimerange=SIZE(vol7d_in%timerange), &
6407 nlevel=SIZE(llev_out), nnetwork=SIZE(vol7d_in%network), ndativarr=nvar)
6408 vol7d_out%ana(:) = vol7d_in%ana(:)
6409
6410 CALL vol7d_alloc_vol(vol7d_out)
6411
6412! no need to check c_e(var_coord_vol) here since the presence of
6413! this%coord_3d_in (external) has precedence over coord_3d_in internal
6414! in grid_transform_compute
6415 CALL compute(grid_trans, vol7d_in, vol7d_out, llev_out, &
6416 var_coord_vol=var_coord_vol)
6417 ELSE
6418 CALL l4f_log(l4f_error, 'v7d_v7d_transform: transformation not valid')
6419 CALL raise_error()
6420 ENDIF
6421 ELSE
6422 CALL l4f_log(l4f_error, &
6423 'v7d_v7d_transform: vertint requested but lev_out not provided')
6424 CALL raise_error()
6425 ENDIF
6426
6427ELSE
6428
6429 CALL init(grid_trans, this, vol7d_in, v7d_locana, maskbounds=maskbounds, &
6430 categoryappend=categoryappend)
6431! if this init is successful, I am sure that v7d_locana%ana is associated
6432
6433 IF (c_e(grid_trans)) then! .AND. nvar > 0) THEN
6434
6435 CALL vol7d_alloc(vol7d_out, nana=SIZE(v7d_locana%ana), &
6436 ntime=SIZE(vol7d_in%time), ntimerange=SIZE(vol7d_in%timerange), &
6437 nlevel=SIZE(vol7d_in%level), nnetwork=SIZE(vol7d_in%network), ndativarr=nvar)
6438 vol7d_out%ana = v7d_locana%ana
6439
6440 CALL get_val(grid_trans, point_mask=point_mask, output_point_index=point_index)
6441
6442 IF (ALLOCATED(point_index)) THEN
6443 CALL vol7d_alloc(vol7d_out, nanavari=1)
6444 CALL init(vol7d_out%anavar%i(1), 'B01192')
6445 ENDIF
6446
6447 CALL vol7d_alloc_vol(vol7d_out)
6448
6449 IF (ALLOCATED(point_index)) THEN
6450 DO inetwork = 1, SIZE(vol7d_in%network)
6451 vol7d_out%volanai(:,1,inetwork) = point_index(:)
6452 ENDDO
6453 ENDIF
6454 CALL compute(grid_trans, vol7d_in, vol7d_out)
6455
6456 IF (ALLOCATED(point_mask)) THEN ! keep full ana
6457 IF (SIZE(point_mask) /= SIZE(vol7d_in%ana)) THEN
6458 CALL l4f_log(l4f_warn, &
6459 'v7d_v7d_transform: inconsistency in point size: '//t2c(SIZE(point_mask)) &
6460 //':'//t2c(SIZE(vol7d_in%ana)))
6461 ELSE
6462#ifdef DEBUG
6463 CALL l4f_log(l4f_debug, 'v7d_v7d_transform: merging ana from in to out')
6464#endif
6465 CALL vol7d_copy(vol7d_in, vol7d_tmpana, &
6466 lana=point_mask, lnetwork=(/.true./), &
6467 ltime=(/.false./), ltimerange=(/.false./), llevel=(/.false./))
6468 CALL vol7d_append(vol7d_out, vol7d_tmpana)
6469 ENDIF
6470 ENDIF
6471
6472 ELSE
6473 CALL l4f_log(l4f_error, 'v7d_v7d_transform: transformation not valid')
6474 CALL raise_error()
6475 ENDIF
6476
6477ENDIF
6478
6479CALL delete (grid_trans)
6480IF (.NOT. PRESENT(v7d)) CALL delete(v7d_locana)
6481
6482END SUBROUTINE v7d_v7d_transform
6483
6484
6485!> Unrotate the wind components.
6486!! It converts u and v components of vector quantities relative to the
6487!! defined grid in the direction of increasing x and y coordinates to
6488!! u and v components relative to easterly and notherly direction. The
6489!! original fields are overwritten.
6490!! \todo Check and correct wind component flag (to be moved in
6491!! griddim_def?)
6492subroutine vg6d_wind_unrot(this)
6493type(volgrid6d) :: this !< object containing wind to be unrotated
6494
6495integer :: component_flag
6496
6497call get_val(this%griddim,component_flag=component_flag)
6498
6499if (component_flag == 1) then
6500 call l4f_category_log(this%category,l4f_info, &
6501 "unrotating vector components")
6502 call vg6d_wind__un_rot(this,.false.)
6503 call set_val(this%griddim,component_flag=0)
6504else
6505 call l4f_category_log(this%category,l4f_info, &
6506 "no need to unrotate vector components")
6507end if
6508
6509end subroutine vg6d_wind_unrot
6510
6511
6512!> Rotate the wind components.
6513!! It converts u and v components of vector quantities
6514!! relative to easterly and notherly direction to
6515!! defined grid in the direction of increasing x and y coordinates.
6516!! The original fields are overwritten.
6517subroutine vg6d_wind_rot(this)
6518type(volgrid6d) :: this !< object containing wind to be rotated
6519
6520integer :: component_flag
6521
6522call get_val(this%griddim,component_flag=component_flag)
6523
6524if (component_flag == 0) then
6525 call l4f_category_log(this%category,l4f_info, &
6526 "rotating vector components")
6527 call vg6d_wind__un_rot(this,.true.)
6528 call set_val(this%griddim,component_flag=1)
6529else
6530 call l4f_category_log(this%category,l4f_info, &
6531 "no need to rotate vector components")
6532end if
6533
6534end subroutine vg6d_wind_rot
6535
6536
6537! Generic UnRotate the wind components.
6538SUBROUTINE vg6d_wind__un_rot(this,rot)
6539TYPE(volgrid6d) :: this ! object containing wind to be (un)rotated
6540LOGICAL :: rot ! if .true. rotate else unrotate
6541
6542INTEGER :: i, j, k, l, a11, a12, a21, a22, stallo
6543double precision,pointer :: rot_mat(:,:,:)
6544real,allocatable :: tmp_arr(:,:)
6545REAL,POINTER :: voldatiu(:,:), voldativ(:,:)
6546INTEGER,POINTER :: iu(:), iv(:)
6547
6548IF (.NOT.ASSOCIATED(this%var)) THEN
6549 CALL l4f_category_log(this%category, l4f_error, &
6550 "trying to unrotate an incomplete volgrid6d object")
6551 CALL raise_fatal_error()
6552! RETURN
6553ENDIF
6554
6555CALL volgrid6d_var_hor_comp_index(this%var, iu, iv)
6556IF (.NOT.ASSOCIATED(iu)) THEN
6557 CALL l4f_category_log(this%category,l4f_error, &
6558 "unrotation impossible")
6559 CALL raise_fatal_error()
6560! RETURN
6561ENDIF
6562
6563! Temporary workspace
6564ALLOCATE(tmp_arr(this%griddim%dim%nx, this%griddim%dim%ny),stat=stallo)
6565IF (stallo /= 0) THEN
6566 CALL l4f_category_log(this%category, l4f_fatal, "allocating memory")
6567 CALL raise_fatal_error()
6568ENDIF
6569! allocate once for speed
6570IF (.NOT.ASSOCIATED(this%voldati)) THEN
6571 ALLOCATE(voldatiu(this%griddim%dim%nx, this%griddim%dim%ny), &
6572 voldativ(this%griddim%dim%nx, this%griddim%dim%ny))
6573ENDIF
6574
6575CALL griddim_unproj(this%griddim)
6576CALL wind_unrot(this%griddim, rot_mat)
6577
6578a11=1
6579if (rot)then
6580 a12=2
6581 a21=3
6582else
6583 a12=3
6584 a21=2
6585end if
6586a22=4
6587
6588DO l = 1, SIZE(iu)
6589 DO k = 1, SIZE(this%timerange)
6590 DO j = 1, SIZE(this%time)
6591 DO i = 1, SIZE(this%level)
6592! get data
6593 CALL volgrid_get_vol_2d(this, i, j, k, iu(l), voldatiu)
6594 CALL volgrid_get_vol_2d(this, i, j, k, iv(l), voldativ)
6595! convert units forward
6596! CALL compute(conv_fwd(iu(l)), voldatiu)
6597! CALL compute(conv_fwd(iv(l)), voldativ)
6598
6599! multiply wind components by rotation matrix
6600 WHERE(voldatiu /= rmiss .AND. voldativ /= rmiss)
6601 tmp_arr(:,:) = real(voldatiu(:,:)*rot_mat(:,:,a11) + &
6602 voldativ(:,:)*rot_mat(:,:,a12))
6603 voldativ(:,:) = real(voldatiu(:,:)*rot_mat(:,:,a21) + &
6604 voldativ(:,:)*rot_mat(:,:,a22))
6605 voldatiu(:,:) = tmp_arr(:,:)
6606 END WHERE
6607! convert units backward
6608! CALL uncompute(conv_fwd(iu(l)), voldatiu)
6609! CALL uncompute(conv_fwd(iv(l)), voldativ)
6610! put data
6611 CALL volgrid_set_vol_2d(this, i, j, k, iu(l), voldatiu)
6612 CALL volgrid_set_vol_2d(this, i, j, k, iv(l), voldativ)
6613 ENDDO
6614 ENDDO
6615 ENDDO
6616ENDDO
6617
6618IF (.NOT.ASSOCIATED(this%voldati)) THEN
6619 DEALLOCATE(voldatiu, voldativ)
6620ENDIF
6621DEALLOCATE(rot_mat, tmp_arr, iu, iv)
6622
6623END SUBROUTINE vg6d_wind__un_rot
6624
6625
6626!!$ try to understand the problem:
6627!!$
6628!!$ case:
6629!!$
6630!!$ 1) we have only one volume: we have to provide the direction of shift
6631!!$ compute H and traslate on it
6632!!$ 2) we have two volumes:
6633!!$ 1) volume U and volume V: compute H and traslate on it
6634!!$ 2) volume U/V and volume H : translate U/V on H
6635!!$ 3) we have tree volumes: translate U and V on H
6636!!$
6637!!$ strange cases:
6638!!$ 1) do not have U in volume U
6639!!$ 2) do not have V in volume V
6640!!$ 3) we have others variables more than U and V in volumes U e V
6641!!$
6642!!$
6643!!$ so the steps are:
6644!!$ 1) find the volumes
6645!!$ 2) define or compute H grid
6646!!$ 3) trasform the volumes in H
6647
6648!!$ N.B.
6649!!$ case 1) for only one vg6d (U or V) is not managed, but
6650!!$ the not pubblic subroutines will work but you have to know what you want to do
6651
6652
6653!> Convert grids type C to type A.
6654!! Use this to interpolate data from grid type C to grid type A
6655!! Grids type are defined by Arakawa.
6656!!
6657!! We need to find these types of area in a vg6d array
6658!! T area of points with temterature etc.
6659!! U area of points with u components of winds
6660!! V area of points with v components of winds
6661!!
6662!! this method works if it finds
6663!! two volumes:
6664!! 1) volume U and volume V: compute H and traslate on it
6665!! 2) volume U/V and volume H : translate U/V on H
6666!! three volumes: translate U and V on H
6667!!
6668!! try to work well on more datasets at once
6669subroutine vg6d_c2a (this)
6670
6671TYPE(volgrid6d),INTENT(inout) :: this(:) !< vettor of volumes volgrid6d to elaborate
6672
6673integer :: ngrid,igrid,jgrid,ugrid,vgrid,tgrid
6674doubleprecision :: xmin, xmax, ymin, ymax
6675doubleprecision :: xmin_t, xmax_t, ymin_t, ymax_t
6676doubleprecision :: step_lon_t,step_lat_t
6677character(len=80) :: type_t,type
6678TYPE(griddim_def):: griddim_t
6679
6680ngrid=size(this)
6681
6682do igrid=1,ngrid
6683
6684 call init(griddim_t)
6685
6686 call get_val(this(igrid)%griddim,xmin=xmin_t, xmax=xmax_t, ymin=ymin_t, ymax=ymax_t,proj_type=type_t)
6687 step_lon_t=(xmax_t-xmin_t)/dble(this(igrid)%griddim%dim%nx-1)
6688 step_lat_t=(ymax_t-ymin_t)/dble(this(igrid)%griddim%dim%ny-1)
6689
6690 do jgrid=1,ngrid
6691
6692 ugrid=imiss
6693 vgrid=imiss
6694 tgrid=imiss
6695
6696#ifdef DEBUG
6697 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: search U/V/T points:"//to_char(igrid)//to_char(jgrid))
6698 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: test delta: "//to_char(step_lon_t)//to_char(step_lat_t))
6699#endif
6700
6701 if (this(igrid)%griddim == this(jgrid)%griddim ) cycle
6702
6703 if (this(igrid)%griddim%dim%nx == this(jgrid)%griddim%dim%nx .and. &
6704 this(igrid)%griddim%dim%ny == this(jgrid)%griddim%dim%ny ) then
6705
6706 call get_val(this(jgrid)%griddim,xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax,proj_type=type)
6707
6708 if (type_t /= type )cycle
6709
6710#ifdef DEBUG
6711 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: test U "//&
6712 to_char(xmin)//to_char(xmax)//to_char(ymin)//to_char(ymax))
6713
6714 call l4f_category_log(this(igrid)%category,l4f_debug,"diff coordinate lon"//&
6715 to_char(abs(xmin - (xmin_t+step_lon_t/2.d0)))//&
6716 to_char(abs(xmax - (xmax_t+step_lon_t/2.d0))))
6717 call l4f_category_log(this(igrid)%category,l4f_debug,"diff coordinate lat"//&
6718 to_char(abs(ymin - (ymin_t+step_lat_t/2.d0)))//&
6719 to_char(abs(ymax - (ymax_t+step_lat_t/2.d0))))
6720#endif
6721
6722 if ( abs(xmin - (xmin_t+step_lon_t/2.d0)) < 1.d-3 .and. abs(xmax - (xmax_t+step_lon_t/2.d0)) < 1.d-3 ) then
6723 if ( abs(ymin - ymin_t) < 1.d-3 .and. abs(ymax - ymax_t) < 1.d-3 ) then
6724
6725#ifdef DEBUG
6726 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: found U")
6727#endif
6728 ugrid=jgrid
6729 tgrid=igrid
6730
6731 end if
6732 end if
6733
6734#ifdef DEBUG
6735 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: test V "//&
6736 to_char(xmin)//to_char(xmax)//to_char(ymin)//to_char(ymax))
6737#endif
6738
6739 if ( abs(ymin - (ymin_t+step_lat_t/2.d0)) < 1.d-3 .and. abs(ymax - (ymax_t+step_lat_t/2.d0)) < 1.d-3 ) then
6740 if ( abs(xmin - xmin_t) < 1.d-3 .and. abs(xmax - xmax_t) < 1.d-3 ) then
6741
6742#ifdef DEBUG
6743 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: found V")
6744#endif
6745 vgrid=jgrid
6746 tgrid=igrid
6747
6748 end if
6749 end if
6750
6751
6752 ! test if we have U and V
6753
6754#ifdef DEBUG
6755 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: test U and V"//&
6756 to_char(xmin_t)//to_char(xmax_t)//to_char(ymin_t)//to_char(ymax_t)//&
6757 to_char(xmin)//to_char(xmax)//to_char(ymin)//to_char(ymax))
6758
6759 call l4f_category_log(this(igrid)%category,l4f_debug,"UV diff coordinate lon"//&
6760 to_char(abs(xmin_t - xmin)-step_lon_t/2.d0)//&
6761 to_char(abs(xmax_t - xmax)-step_lon_t/2.d0))
6762 call l4f_category_log(this(igrid)%category,l4f_debug,"UV diff coordinate lat"//&
6763 to_char(abs(ymin_t - ymin) -step_lat_t/2.d0)//&
6764 to_char(abs(ymax_t - ymax)-step_lat_t/2.d0))
6765#endif
6766
6767 if ( abs(ymin - (ymin_t+step_lat_t/2.d0)) < 2.d-3 .and. abs(ymax - (ymax_t+step_lat_t/2.d0)) < 2.d-3 ) then
6768 if ( abs(xmin_t - (xmin+step_lon_t/2.d0)) < 2.d-3 .and. abs(xmax_t - (xmax+step_lon_t/2.d0)) < 2.d-3 ) then
6769
6770#ifdef DEBUG
6771 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: found U and V case up and right")
6772#endif
6773
6774 vgrid=jgrid
6775 ugrid=igrid
6776
6777 call init(griddim_t,xmin=xmin, xmax=xmax, ymin=ymin_t, ymax=ymax_t)
6778
6779 end if
6780 end if
6781 end if
6782
6783 ! abbiamo almeno due volumi: riportiamo U e/o V su T
6784 if (c_e(ugrid)) then
6785#ifdef DEBUG
6786 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid U points: interpolate U on T "//to_char(tgrid)//to_char(ugrid))
6787#endif
6788 if (c_e(tgrid))then
6789 call vg6d_c2a_grid(this(ugrid),this(tgrid)%griddim,cgrid=1)
6790 else
6791 call vg6d_c2a_grid(this(ugrid),griddim_t,cgrid=1)
6792 end if
6793 call vg6d_c2a_mat(this(ugrid),cgrid=1)
6794 end if
6795
6796 if (c_e(vgrid)) then
6797#ifdef DEBUG
6798 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid V points: interpolate V on T "//to_char(tgrid)//to_char(vgrid))
6799#endif
6800 if (c_e(tgrid))then
6801 call vg6d_c2a_grid(this(vgrid),this(tgrid)%griddim,cgrid=2)
6802 else
6803 call vg6d_c2a_grid(this(vgrid),griddim_t,cgrid=2)
6804 end if
6805 call vg6d_c2a_mat(this(vgrid),cgrid=2)
6806 end if
6807
6808 end do
6809
6810 call delete(griddim_t)
6811
6812end do
6813
6814
6815end subroutine vg6d_c2a
6816
6817
6818! Convert C grid to A grid
6819subroutine vg6d_c2a_grid(this,griddim_t,cgrid)
6820
6821type(volgrid6d),intent(inout) :: this ! object containing fields to be translated (U or V points)
6822type(griddim_def),intent(in),optional :: griddim_t ! object containing grid of T points
6823integer,intent(in) :: cgrid ! in C grid (Arakawa) we have 0=T,1=U,2=V points
6824
6825doubleprecision :: xmin, xmax, ymin, ymax
6826doubleprecision :: step_lon,step_lat
6827
6828
6829if (present(griddim_t)) then
6830
6831 call get_val(griddim_t,xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
6832 call set_val(this%griddim,xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
6833! improve grid definition precision
6834 CALL griddim_setsteps(this%griddim)
6835
6836else
6837
6838 select case (cgrid)
6839
6840 case(0)
6841
6842#ifdef DEBUG
6843 call l4f_category_log(this%category,l4f_debug,"C grid: T points, nothing to do")
6844#endif
6845 return
6846
6847 case (1)
6848
6849#ifdef DEBUG
6850 call l4f_category_log(this%category,l4f_debug,"C grid: U points, we need interpolation")
6851#endif
6852
6853 call get_val(this%griddim, xmin=xmin, xmax=xmax)
6854 step_lon=(xmax-xmin)/dble(this%griddim%dim%nx-1)
6855 xmin=xmin-step_lon/2.d0
6856 xmax=xmax-step_lon/2.d0
6857 call set_val(this%griddim, xmin=xmin, xmax=xmax)
6858! improve grid definition precision
6859 CALL griddim_setsteps(this%griddim)
6860
6861 case (2)
6862
6863#ifdef DEBUG
6864 call l4f_category_log(this%category,l4f_debug,"C grid: V points, we need interpolation")
6865#endif
6866
6867 call get_val(this%griddim, ymin=ymin, ymax=ymax)
6868 step_lat=(ymax-ymin)/dble(this%griddim%dim%ny-1)
6869 ymin=ymin-step_lat/2.d0
6870 ymax=ymax-step_lat/2.d0
6871 call set_val(this%griddim, ymin=ymin, ymax=ymax)
6872! improve grid definition precision
6873 CALL griddim_setsteps(this%griddim)
6874
6875 case default
6876
6877 call l4f_category_log(this%category,l4f_fatal,"C grid type not known")
6878 call raise_fatal_error ()
6879
6880 end select
6881
6882end if
6883
6884
6885call griddim_unproj(this%griddim)
6886
6887
6888end subroutine vg6d_c2a_grid
6889
6890! Convert C grid to A grid
6891subroutine vg6d_c2a_mat(this,cgrid)
6892
6893type(volgrid6d),intent(inout) :: this ! object containing fields to be translated
6894integer,intent(in) :: cgrid ! in C grid (Arakawa) we have 0=T,1=U,2=V points
6895
6896INTEGER :: i, j, k, iv, stallo
6897REAL,ALLOCATABLE :: tmp_arr(:,:)
6898REAL,POINTER :: voldatiuv(:,:)
6899
6900
6901IF (cgrid == 0) RETURN ! nothing to do
6902IF (cgrid /= 1 .AND. cgrid /= 2) THEN ! wrong cgrid
6903 CALL l4f_category_log(this%category,l4f_fatal,"C grid type "// &
6904 trim(to_char(cgrid))//" not known")
6905 CALL raise_error()
6906 RETURN
6907ENDIF
6908
6909! Temporary workspace
6910ALLOCATE(tmp_arr(this%griddim%dim%nx, this%griddim%dim%ny),stat=stallo)
6911if (stallo /=0)then
6912 call l4f_log(l4f_fatal,"allocating memory")
6913 call raise_fatal_error()
6914end if
6915
6916! allocate once for speed
6917IF (.NOT.ASSOCIATED(this%voldati)) THEN
6918 ALLOCATE(voldatiuv(this%griddim%dim%nx, this%griddim%dim%ny), stat=stallo)
6919 IF (stallo /= 0) THEN
6920 CALL l4f_log(l4f_fatal,"allocating memory")
6921 CALL raise_fatal_error()
6922 ENDIF
6923ENDIF
6924
6925IF (cgrid == 1) THEN ! U points to H points
6926 DO iv = 1, SIZE(this%var)
6927 DO k = 1, SIZE(this%timerange)
6928 DO j = 1, SIZE(this%time)
6929 DO i = 1, SIZE(this%level)
6930 tmp_arr(:,:) = rmiss
6931 CALL volgrid_get_vol_2d(this, i, j, k, iv, voldatiuv)
6932
6933! West boundary extrapolation
6934 WHERE(voldatiuv(1,:) /= rmiss .AND. voldatiuv(2,:) /= rmiss)
6935 tmp_arr(1,:) = voldatiuv(1,:) - (voldatiuv(2,:) - voldatiuv(1,:)) / 2.
6936 END WHERE
6937
6938! Rest of the field
6939 WHERE(voldatiuv(1:this%griddim%dim%nx-1,:) /= rmiss .AND. &
6940 voldatiuv(2:this%griddim%dim%nx,:) /= rmiss)
6941 tmp_arr(2:this%griddim%dim%nx,:) = &
6942 (voldatiuv(1:this%griddim%dim%nx-1,:) + &
6943 voldatiuv(2:this%griddim%dim%nx,:)) / 2.
6944 END WHERE
6945
6946 voldatiuv(:,:) = tmp_arr
6947 CALL volgrid_set_vol_2d(this, i, j, k, iv, voldatiuv)
6948 ENDDO
6949 ENDDO
6950 ENDDO
6951 ENDDO
6952
6953ELSE IF (cgrid == 2) THEN ! V points to H points
6954 DO iv = 1, SIZE(this%var)
6955 DO k = 1, SIZE(this%timerange)
6956 DO j = 1, SIZE(this%time)
6957 DO i = 1, SIZE(this%level)
6958 tmp_arr(:,:) = rmiss
6959 CALL volgrid_get_vol_2d(this, i, j, k, iv, voldatiuv)
6960
6961! South boundary extrapolation
6962 WHERE(voldatiuv(:,1) /= rmiss .AND. voldatiuv(:,2) /= rmiss)
6963 tmp_arr(:,1) = voldatiuv(:,1) - (voldatiuv(:,2) - voldatiuv(:,1)) / 2.
6964 END WHERE
6965
6966! Rest of the field
6967 WHERE(voldatiuv(:,1:this%griddim%dim%ny-1) /= rmiss .AND. &
6968 voldatiuv(:,2:this%griddim%dim%ny) /= rmiss)
6969 tmp_arr(:,2:this%griddim%dim%ny) = &
6970 (voldatiuv(:,1:this%griddim%dim%ny-1) + &
6971 voldatiuv(:,2:this%griddim%dim%ny)) / 2.
6972 END WHERE
6973
6974 voldatiuv(:,:) = tmp_arr
6975 CALL volgrid_set_vol_2d(this, i, j, k, iv, voldatiuv)
6976 ENDDO
6977 ENDDO
6978 ENDDO
6979 ENDDO
6980ENDIF ! tertium non datur
6981
6982IF (.NOT.ASSOCIATED(this%voldati)) THEN
6983 DEALLOCATE(voldatiuv)
6984ENDIF
6985DEALLOCATE (tmp_arr)
6986
6987end subroutine vg6d_c2a_mat
6988
6989
6990!> \brief Display object on screen
6991!!
6992!! Show brief content on screen.
6993subroutine display_volgrid6d (this)
6994
6995TYPE(volgrid6d),intent(in) :: this !< object to display
6996integer :: i
6997
6998#ifdef DEBUG
6999call l4f_category_log(this%category,l4f_debug,"ora mostro gridinfo " )
7000#endif
7001
7002print*,"----------------------- volgrid6d display ---------------------"
7003call display(this%griddim)
7004
7005IF (ASSOCIATED(this%time))then
7006 print*,"---- time vector ----"
7007 print*,"elements=",size(this%time)
7008 do i=1, size(this%time)
7009 call display(this%time(i))
7010 end do
7011end IF
7012
7013IF (ASSOCIATED(this%timerange))then
7014 print*,"---- timerange vector ----"
7015 print*,"elements=",size(this%timerange)
7016 do i=1, size(this%timerange)
7017 call display(this%timerange(i))
7018 end do
7019end IF
7020
7021IF (ASSOCIATED(this%level))then
7022 print*,"---- level vector ----"
7023 print*,"elements=",size(this%level)
7024 do i=1, size(this%level)
7025 call display(this%level(i))
7026 end do
7027end IF
7028
7029IF (ASSOCIATED(this%var))then
7030 print*,"---- var vector ----"
7031 print*,"elements=",size(this%var)
7032 do i=1, size(this%var)
7033 call display(this%var(i))
7034 end do
7035end IF
7036
7037IF (ASSOCIATED(this%gaid))then
7038 print*,"---- gaid vector (present mask only) ----"
7039 print*,"elements=",shape(this%gaid)
7040 print*,c_e(reshape(this%gaid,(/SIZE(this%gaid)/)))
7041end IF
7042
7043print*,"--------------------------------------------------------------"
7044
7045
7046end subroutine display_volgrid6d
7047
7048
7049!> \brief Display vector of object on screen
7050!!
7051!! Show brief content on screen.
7052subroutine display_volgrid6dv (this)
7053
7054TYPE(volgrid6d),intent(in) :: this(:) !< vector of object to display
7055integer :: i
7056
7057print*,"----------------------- volgrid6d vector ---------------------"
7058
7059print*,"elements=",size(this)
7060
7061do i=1, size(this)
7062
7063#ifdef DEBUG
7064 call l4f_category_log(this(i)%category,l4f_debug,"ora mostro il vettore volgrid6d" )
7065#endif
7066
7067 call display(this(i))
7068
7069end do
7070print*,"--------------------------------------------------------------"
7071
7072end subroutine display_volgrid6dv
7073
7074
7075!> Reduce some dimensions (level and timerage) for semplification (rounding).
7076!! Vector version of vg6dv_rounding
7077subroutine vg6dv_rounding(vg6din,vg6dout,level,timerange,nostatproc,merge)
7078type(volgrid6d),intent(in) :: vg6din(:) !< input volume
7079type(volgrid6d),intent(out),pointer :: vg6dout(:) !> output volume
7080type(vol7d_level),intent(in),optional :: level(:) !< almost equal level list
7081type(vol7d_timerange),intent(in),optional :: timerange(:) !< almost equal timerange list
7082logical,intent(in),optional :: merge !< if there are data on more then one almost equal levels or timeranges will be merged POINT BY POINT with priority for the fird data found ordered by icreasing var index
7083logical,intent(in),optional :: nostatproc !< do not take in account statistical processing code in timerange and P2
7084
7085integer :: i
7086
7087allocate(vg6dout(size(vg6din)))
7088
7089do i = 1, size(vg6din)
7090 call vg6d_rounding(vg6din(i),vg6dout(i),level,timerange,nostatproc,merge)
7091end do
7092
7093end subroutine vg6dv_rounding
7094
7095!> Reduce some dimensions (level and timerage) for semplification (rounding).
7096!! You can use this for simplify and use variables in computation like alchimia
7097!! where fields have to be on the same coordinate
7098!! examples:
7099!! means in time for short periods and istantaneous values
7100!! 2 meter and surface levels
7101!! If there are data on more then one almost equal levels or timeranges, the first var present (at least one point)
7102!! will be taken (order is by icreasing var index).
7103!! You can use predefined values for classic semplification
7104!! almost_equal_levels and almost_equal_timeranges
7105!! The level or timerange in output will be defined by the first element of level and timerange list
7106subroutine vg6d_rounding(vg6din,vg6dout,level,timerange,nostatproc,merge)
7107type(volgrid6d),intent(in) :: vg6din !< input volume
7108type(volgrid6d),intent(out) :: vg6dout !> output volume
7109type(vol7d_level),intent(in),optional :: level(:) !< almost equal level list
7110type(vol7d_timerange),intent(in),optional :: timerange(:) !< almost equal timerange list
7111logical,intent(in),optional :: merge !< if there are data on more then one almost equal levels or timeranges
7112!! will be merged POINT BY POINT with priority for the fird data found ordered by icreasing var index
7113logical,intent(in),optional :: nostatproc !< do not take in account statistical processing code in timerange and P2
7114
7115integer :: ilevel,itimerange
7116type(vol7d_level) :: roundlevel(size(vg6din%level))
7117type(vol7d_timerange) :: roundtimerange(size(vg6din%timerange))
7118
7119roundlevel=vg6din%level
7120
7121if (present(level))then
7122 do ilevel = 1, size(vg6din%level)
7123 if ((any(vg6din%level(ilevel) .almosteq. level))) then
7124 roundlevel(ilevel)=level(1)
7125 end if
7126 end do
7127end if
7128
7129roundtimerange=vg6din%timerange
7130
7131if (present(timerange))then
7132 do itimerange = 1, size(vg6din%timerange)
7133 if ((any(vg6din%timerange(itimerange) .almosteq. timerange))) then
7134 roundtimerange(itimerange)=timerange(1)
7135 end if
7136 end do
7137end if
7138
7139!set istantaneous values everywere
7140!preserve p1 for forecast time
7141if (optio_log(nostatproc)) then
7142 roundtimerange(:)%timerange=254
7143 roundtimerange(:)%p2=0
7144end if
7145
7146
7147call vg6d_reduce(vg6din,vg6dout,roundlevel,roundtimerange,merge)
7148
7149end subroutine vg6d_rounding
7150
7151!> Reduce some dimensions (level and timerage).
7152!! You can pass a volume and specify duplicated levels and timeranges in roundlevel and roundtimerange;
7153!! you get unique levels and timeranges in output.
7154!! If there are data on equal levels or timeranges, the first var present (at least one point)
7155!! will be taken (order is by icreasing var index).
7156!! you can specify merge and if there are data on equal levels or timeranges will be merged POINT BY POINT
7157!! with priority for the first data found ordered by icreasing var index (require to decode all the data)
7158!! Data are decoded only if needed so the output should be with or without voldata allocated
7159subroutine vg6d_reduce(vg6din,vg6dout,roundlevel,roundtimerange,merge)
7160type(volgrid6d),intent(in) :: vg6din !< input volume
7161type(volgrid6d),intent(out) :: vg6dout !< output volume
7162type(vol7d_level),intent(in) :: roundlevel(:) !< new level list to use for rounding
7163type(vol7d_timerange),intent(in) :: roundtimerange(:) !< new timerange list to use for rounding
7164logical,intent(in),optional :: merge !< if there are data on equal levels or timeranges will be merged POINT BY POINT with priority for the first data found ordered by icreasing var index (require to decode all the data)
7165
7166integer :: nlevel,ntime,ntimerange,nvar,ilevel,itimerange,ivar,indl,indt,itime,nx,ny
7167real,allocatable :: vol2d(:,:)
7168
7169nx=vg6din%griddim%dim%nx
7170ny=vg6din%griddim%dim%ny
7171nlevel=count_distinct(roundlevel,back=.true.)
7172ntime=size(vg6din%time)
7173ntimerange=count_distinct(roundtimerange,back=.true.)
7174nvar=size(vg6din%var)
7175
7176call init(vg6dout, vg6din%griddim, vg6din%time_definition, categoryappend="generated by vg6d_reduce")
7177call volgrid6d_alloc(vg6dout, vg6din%griddim%dim, ntime, nlevel, ntimerange, nvar)
7178
7179if ( ASSOCIATED(vg6din%voldati) .or. optio_log(merge)) then
7180 call volgrid6d_alloc_vol(vg6dout,inivol=.true.,decode=.true.)
7181 allocate(vol2d(nx,ny))
7182else
7183 call volgrid6d_alloc_vol(vg6dout,inivol=.true.,decode=.false.)
7184end if
7185
7186vg6dout%time=vg6din%time
7187vg6dout%var=vg6din%var
7188vg6dout%timerange=pack_distinct(roundtimerange,ntimerange,back=.true.)
7189vg6dout%level=pack_distinct(roundlevel,nlevel,back=.true.)
7190! sort modified dimensions
7191CALL sort(vg6dout%timerange)
7192CALL sort(vg6dout%level)
7193
7194do ilevel=1,size(vg6din%level)
7195 indl=index(vg6dout%level,roundlevel(ilevel))
7196 do itimerange=1,size(vg6din%timerange)
7197 indt=index(vg6dout%timerange,roundtimerange(itimerange))
7198 do ivar=1, nvar
7199 do itime=1,ntime
7200
7201 if ( ASSOCIATED(vg6din%voldati)) then
7202 vol2d=vg6din%voldati(:,:,ilevel,itime,itimerange,ivar)
7203 end if
7204
7205 if (optio_log(merge)) then
7206
7207 if ( .not. ASSOCIATED(vg6din%voldati)) then
7208 CALL grid_id_decode_data(vg6din%gaid(ilevel,itime,itimerange,ivar), vol2d)
7209 end if
7210
7211 !! merge present data point by point
7212 where (.not. c_e(vg6dout%voldati(:,:,indl,itime,indt,ivar)))
7213
7214 vg6dout%voldati(:,:,indl,itime,indt,ivar)=vol2d
7215
7216 end where
7217 else if ( ASSOCIATED(vg6din%voldati)) then
7218 if (.not. any(c_e(vg6dout%voldati(:,:,indl,itime,indt,ivar))))then
7219 vg6dout%voldati(:,:,indl,itime,indt,ivar)=vol2d
7220 end if
7221 end if
7222
7223 if (c_e(vg6din%gaid(ilevel,itime,itimerange,ivar)).and. .not. c_e(vg6dout%gaid(indl,itime,indt,ivar)))then
7224 call copy (vg6din%gaid(ilevel,itime,itimerange,ivar), vg6dout%gaid(indl,itime,indt,ivar))
7225 end if
7226 end do
7227 end do
7228 end do
7229end do
7230
7231if ( ASSOCIATED(vg6din%voldati) .or. optio_log(merge)) then
7232 deallocate(vol2d)
7233end if
7234
7235end subroutine vg6d_reduce
7236
7237
7238end module volgrid6d_class
7239
7240
7241
7242!>\example example_vg6d_3.f90
7243!!\brief Programma esempio semplice per gridinfo e volgrid6d.
7244!!
7245!! Programma che importa da file un vettore di gridinfo poi lo importa in volgrid6d. Da volgrid6d viene di nuovo creato un vettore di gridinfo per poi exportare su file.
7246
7247!>\example example_vg6d_5.f90
7248!!\brief Programma trasformazione da volgrid6d a volgrid6d
7249!!
7250!! Legge grib da un file e li organizza in un vettore di strutture
7251!! volgrid6d mettendoli a disposizione per eventuali elaborazioni;
7252!! vengono poi riesportati a un file grib
7253
7254!>\example example_vg6d_8.f90
7255!! \brief Programma scrittura su file vettore di anagrafica
7256
7257!>\example example_vg6d_6.f90
7258!! \brief Programma trasformazione da volgrid6d a vol7d
7259
7260!>\example example_vg6d_7.f90
7261!! \brief Programma trasformazione da vol7d a volgrid6d
7262
7263!>\example example_vg6d_9.f90
7264!! \brief Example to create a grib editionNumber = 2 file from data generated in memory using a grib_api template
Method for inserting elements of the array at a desired position.
Operatore di valore assoluto di un intervallo.
Legge un oggetto datetime/timedelta o un vettore di oggetti datetime/timedelta da un file FORMATTED o...
Functions that return a trimmed CHARACTER representation of the input variable.
Restituiscono il valore dell'oggetto in forma di stringa stampabile.
Scrive un oggetto datetime/timedelta o un vettore di oggetti datetime/timedelta su un file FORMATTED ...
Copy an object, creating a fully new instance.
Method for returning the contents of the object.
Compute forward coordinate transformation from geographical system to projected system.
Method for setting the contents of the object.
Clone the object, creating a new independent instance of the object exactly equal to the starting one...
Decode and return the data array from a grid_id object associated to a gridinfo object.
Encode a data array into a grid_id object associated to a gridinfo object.
Index method.
Emit log message for a category with specific priority.
Convert a level type to a physical variable.
Destructor, it releases every information and memory buffer associated with the object.
Display on standard output a description of the volgrid6d object provided.
Export an object dirctly to a native file, to a gridinfo object or to a supported file format through...
Import an object dirctly from a native file, from a gridinfo object or from a supported file format t...
Constructor, it creates a new instance of the object.
Reduce some dimensions (level and timerage) for semplification (rounding).
Transform between any combination of volgrid6d and vol7d objects by means of a transform_def object d...
Apply the conversion function this to values.
This module defines usefull general purpose function and subroutine.
Classi per la gestione delle coordinate temporali.
Module for describing geographically referenced regular grids.
Module for defining the extension and coordinates of a rectangular georeferenced grid.
This module defines an abstract interface to different drivers for access to files containing gridded...
Module for defining transformations between rectangular georeferenced grids and between grids and spa...
Class for managing information about a single gridded georeferenced field, typically imported from an...
classe per la gestione del logging
Module for quickly interpreting the OPTIONAL parameters passed to a subprogram.
Classe per la gestione di un volume completo di dati osservati.
classe per import ed export di volumi da e in DB-All.e
Classe per la gestione dei livelli verticali in osservazioni meteo e affini.
Classe per la gestione degli intervalli temporali di osservazioni meteo e affini.
This module defines objects and methods for managing data volumes on rectangular georeferenced grids.
Class for managing physical variables in a grib 1/2 fashion.
Object describing a rectangular, homogeneous gridded dataset.

Generated with Doxygen.