libsim Versione 8.0.0

◆ vg6d_rounding()

subroutine vg6d_rounding ( type(volgrid6d), intent(in) vg6din,
type(volgrid6d), intent(out) vg6dout,
type(vol7d_level), dimension(:), intent(in), optional level,
type(vol7d_timerange), dimension(:), intent(in), optional timerange,
logical, intent(in), optional nostatproc,
logical, intent(in), optional merge )
private

Reduce some dimensions (level and timerage) for semplification (rounding).

You can use this for simplify and use variables in computation like alchimia where fields have to be on the same coordinate examples: means in time for short periods and istantaneous values 2 meter and surface levels If there are data on more then one almost equal levels or timeranges, the first var present (at least one point) will be taken (order is by icreasing var index). You can use predefined values for classic semplification almost_equal_levels and almost_equal_timeranges The level or timerange in output will be defined by the first element of level and timerange list

Parametri
[in]vg6dininput volume
[in]levelalmost equal level list
[in]timerangealmost equal timerange list
[in]mergeif 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
[in]nostatprocdo not take in account statistical processing code in timerange and P2

Definizione alla linea 3610 del file volgrid6d_class.F90.

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