libsim Versione 8.0.0
volgrid6d_class.F90
1! Copyright (C) 2010 ARPA-SIM <urpsim@smr.arpa.emr.it>
2! authors:
3! Davide Cesari <dcesari@arpa.emr.it>
4! Paolo Patruno <ppatruno@arpa.emr.it>
5
6! This program is free software; you can redistribute it and/or
7! modify it under the terms of the GNU General Public License as
8! published by the Free Software Foundation; either version 2 of
9! the License, or (at your option) any later version.
10
11! This program is distributed in the hope that it will be useful,
12! but WITHOUT ANY WARRANTY; without even the implied warranty of
13! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14! GNU General Public License for more details.
15
16! You should have received a copy of the GNU General Public License
17! along with this program. If not, see <http://www.gnu.org/licenses/>.
18#include "config.h"
19!> \defgroup volgrid6d Libsim package, volgrid6d library.
20!! The libsim volgrid6d library contains classes for managing data on
21!! regular rectangular grids, tipically the output of a numerical
22!! weather prediction model, and for their import from a WMO GRIB file
23!! of from other geophysical data file formats. In order to compile
24!! and link programs using this library, you have to insert the
25!! required \c USE statements in the program units involved, specify
26!! the location of module files when compiling (tipically \c
27!! -I/usr/lib/gfortran/modules or \c -I/usr/lib64/gfortran/modules or
28!! \c -I/usr/include) and indicate the library name \c -lsim_volgrid6d
29!! when linking, assuming that the library has been installed in a
30!! default location.
31
32!> This module defines objects and methods for managing data volumes
33!! on rectangular georeferenced grids. The data are accomodated in a
34!! multi-dimensional array with 6 predefined dimensions. Different
35!! geographic coordinates and projections are supported, mainly
36!! inspired by grib coding standards. The \a volgrid6d object contains
37!! information and data on an homogeneous grid definition, while
38!! different grids are managed as arrays of \a volgrid6d objects.
39!! Every object contains also an identificator of the grid (\a grid_id
40!! object), carrying information about the driver used or which has to
41!! be used for import/export from/to file. With the help of \a
42!! gridinfo_def class, data can be imported and exported to the
43!! supported formats, mainly grib1 and grib2 through grib_api and many
44!! GIS-style formats through gdal.
45!!
46!! Simple example program \include example_vg6d_3.f90
47!! Example of transformation from volgrid6d to volgrid6d \include example_vg6d_5.f90
48!! Example of transformation from volgrid6d to vol7d \include example_vg6d_6.f90
49!! Example of transformation from vol7d to volgrid6d \include example_vg6d_7.f90
50!!
51!!\ingroup volgrid6d
52MODULE volgrid6d_class
57USE geo_proj_class
58USE grid_class
67!USE file_utilities
68#ifdef HAVE_DBALLE
70#endif
71IMPLICIT NONE
72
73character (len=255),parameter:: subcategory="volgrid6d_class"
74
75!> Object describing a rectangular, homogeneous gridded dataset
76type volgrid6d
77 type(griddim_def) :: griddim !< grid descriptor
78 TYPE(datetime),pointer :: time(:) !< time dimension descriptor
79 TYPE(vol7d_timerange),pointer :: timerange(:) !< timerange (forecast, analysis, statistically processed) dimension descriptor
80 TYPE(vol7d_level),pointer :: level(:) !< vertical level dimension descriptor
81 TYPE(volgrid6d_var),pointer :: var(:) !< physical variable dimension descriptor
82 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)
83 REAL,POINTER :: voldati(:,:,:,:,:,:) !< array of data, indices are: (x,y,level,time,timerange,var)
84 INTEGER :: time_definition !< time definition; 0=time is reference time ; 1=time is validity time
85 TYPE(l4f_handle) :: category !< log4fortran category
86end type volgrid6d
87
88!> Constructor, it creates a new instance of the object.
89INTERFACE init
90 MODULE PROCEDURE volgrid6d_init
91END INTERFACE
92
93!> Destructor, it releases every information and memory buffer
94!! associated with the object.
95INTERFACE delete
96 MODULE PROCEDURE volgrid6d_delete, volgrid6dv_delete
97END INTERFACE
98
99!> Import an object dirctly from a native file, from a \a gridinfo object
100!! or from a supported file format through a \a gridinfo object.
101INTERFACE import
102 MODULE PROCEDURE volgrid6d_read_from_file
103 MODULE PROCEDURE import_from_gridinfo, import_from_gridinfovv, &
104 volgrid6d_import_from_file
105END INTERFACE
106
107!> Export an object dirctly to a native file, to a \a gridinfo object
108!! or to a supported file format through a \a gridinfo object.
109INTERFACE export
110 MODULE PROCEDURE volgrid6d_write_on_file
111 MODULE PROCEDURE export_to_gridinfo, export_to_gridinfov, export_to_gridinfovv,&
112 volgrid6d_export_to_file
113END INTERFACE
114
115! methods for computing transformations through an initialised
116! grid_transform object, probably too low level to be interfaced
117INTERFACE compute
118 MODULE PROCEDURE volgrid6d_transform_compute, volgrid6d_v7d_transform_compute,&
119 v7d_volgrid6d_transform_compute, v7d_v7d_transform_compute
120END INTERFACE
121
122!> Transform between any combination of \a volgrid6d and \a vol7d objects
123!! by means of a \a transform_def object describing the transformation.
124INTERFACE transform
125 MODULE PROCEDURE volgrid6d_transform, volgrid6dv_transform,&
126 volgrid6d_v7d_transform, volgrid6dv_v7d_transform, v7d_volgrid6d_transform, &
127 v7d_v7d_transform
128END INTERFACE
129
130INTERFACE wind_rot
131 MODULE PROCEDURE vg6d_wind_rot
132END INTERFACE
133
134INTERFACE wind_unrot
135 MODULE PROCEDURE vg6d_wind_unrot
136END INTERFACE
137
138!> Display on standard output a description of the \a volgrid6d object
139!! provided.
140INTERFACE display
141 MODULE PROCEDURE display_volgrid6d,display_volgrid6dv
142END INTERFACE
143
144!> Reduce some dimensions (level and timerage) for semplification (rounding).
145!! You can use this for simplify and use variables in computation like alchimia
146!! where fields have to be on the same coordinate
147!! examples:
148!! means in time for short periods and istantaneous values
149!! 2 meter and surface levels
150!! If there are data on more then one almost equal levels or timeranges, the first var present (at least one point)
151!! will be taken (order is by icreasing var index).
152!! You can use predefined values for classic semplification
153!! almost_equal_levels and almost_equal_timeranges
154!! The level or timerange in output will be defined by the first element of level and timerange list
155INTERFACE rounding
156 MODULE PROCEDURE vg6d_rounding, vg6dv_rounding
157END INTERFACE
158
159private
160
161PUBLIC volgrid6d,init,delete,export,import,compute,transform, &
162 wind_rot,wind_unrot,vg6d_c2a,display,volgrid6d_alloc,volgrid6d_alloc_vol, &
163 volgrid_get_vol_2d, volgrid_set_vol_2d, volgrid_get_vol_3d, volgrid_set_vol_3d
164PUBLIC rounding, vg6d_reduce
165
166CONTAINS
167
168
169!> Constructor, it creates a new instance of the object.
170!! The constructor should be explicitly used only in rare cases,
171!! \a volgrid6d objects are usually created through the \a import
172!! interface.
173SUBROUTINE volgrid6d_init(this, griddim, time_definition, categoryappend)
174TYPE(volgrid6d) :: this !< object to be initialized
175TYPE(griddim_def),OPTIONAL :: griddim !< grid descriptor
176INTEGER,INTENT(IN),OPTIONAL :: time_definition !< 0=time is reference time; 1=time is validity time
177CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
178
179character(len=512) :: a_name
180
181if (present(categoryappend))then
182 call l4f_launcher(a_name,a_name_append=trim(subcategory)//"."//trim(categoryappend))
183else
184 call l4f_launcher(a_name,a_name_append=trim(subcategory))
185endif
186this%category=l4f_category_get_handle(a_name)
187
188#ifdef DEBUG
189call l4f_category_log(this%category,l4f_debug,"init")
190#endif
191
192call init(this%griddim)
193
194if (present(griddim))then
195 call copy (griddim,this%griddim)
196end if
197
198if(present(time_definition)) then
199 this%time_definition = time_definition
200else
201 this%time_definition = 0 !default to reference time
202end if
203
204nullify (this%time,this%timerange,this%level,this%var)
205nullify (this%gaid,this%voldati)
206
207END SUBROUTINE volgrid6d_init
208
209
210!> Allocate the dimension descriptors of the \a volgrid6d object.
211!! This method allocates the horizontal grid descriptor and the one
212!! dimensional arrays of the dimensions
213!! - time
214!! - vertical level
215!! - timerange
216!! - physical variable
217!!
218!! This method should be explicitly used only in rare cases, it is
219!! usually called implicitly through the \a import interface.
220SUBROUTINE volgrid6d_alloc(this, dim, ntime, nlevel, ntimerange, nvar, ini)
221TYPE(volgrid6d),INTENT(inout) :: this !< object whose decriptors should be allocated
222TYPE(grid_dim),INTENT(in),OPTIONAL :: dim !< horizontal grid size X, Y
223INTEGER,INTENT(in),OPTIONAL :: ntime !< number of time levels
224INTEGER,INTENT(in),OPTIONAL :: nlevel !< number of vertical levels
225INTEGER,INTENT(in),OPTIONAL :: ntimerange !< number of different timeranges
226INTEGER,INTENT(in),OPTIONAL :: nvar !< number of physical variables
227LOGICAL,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
228
229INTEGER :: i, stallo
230LOGICAL :: linit
231
232#ifdef DEBUG
233call l4f_category_log(this%category,l4f_debug,"alloc")
234#endif
235
236IF (PRESENT(ini)) THEN
237 linit = ini
238ELSE
239 linit = .false.
240ENDIF
241
242
243if (present(dim)) call copy (dim,this%griddim%dim)
244
245
246IF (PRESENT(ntime)) THEN
247 IF (ntime >= 0) THEN
248 IF (ASSOCIATED(this%time)) DEALLOCATE(this%time)
249#ifdef DEBUG
250 call l4f_category_log(this%category,l4f_debug,"alloc ntime "//to_char(ntime))
251#endif
252 ALLOCATE(this%time(ntime),stat=stallo)
253 if (stallo /=0)then
254 call l4f_category_log(this%category,l4f_fatal,"allocating memory")
255 CALL raise_fatal_error()
256 end if
257 IF (linit) THEN
258 DO i = 1, ntime
259 this%time(i) = datetime_miss
260! CALL init(this%time(i)) ! senza argomento inizializza a zero non missing
261 ! baco di datetime?
262 ENDDO
263 ENDIF
264 ENDIF
265ENDIF
266IF (PRESENT(nlevel)) THEN
267 IF (nlevel >= 0) THEN
268 IF (ASSOCIATED(this%level)) DEALLOCATE(this%level)
269#ifdef DEBUG
270 call l4f_category_log(this%category,l4f_debug,"alloc nlevel "//to_char(nlevel))
271#endif
272 ALLOCATE(this%level(nlevel),stat=stallo)
273 if (stallo /=0)then
274 call l4f_category_log(this%category,l4f_fatal,"allocating memory")
275 CALL raise_fatal_error()
276 end if
277 IF (linit) THEN
278 DO i = 1, nlevel
279 CALL init(this%level(i))
280 ENDDO
281 ENDIF
282 ENDIF
283ENDIF
284IF (PRESENT(ntimerange)) THEN
285 IF (ntimerange >= 0) THEN
286 IF (ASSOCIATED(this%timerange)) DEALLOCATE(this%timerange)
287#ifdef DEBUG
288 call l4f_category_log(this%category,l4f_debug,"alloc ntimerange "//to_char(ntimerange))
289#endif
290 ALLOCATE(this%timerange(ntimerange),stat=stallo)
291 if (stallo /=0)then
292 call l4f_category_log(this%category,l4f_fatal,"allocating memory")
293 CALL raise_fatal_error()
294 end if
295 IF (linit) THEN
296 DO i = 1, ntimerange
297 CALL init(this%timerange(i))
298 ENDDO
299 ENDIF
300 ENDIF
301ENDIF
302IF (PRESENT(nvar)) THEN
303 IF (nvar >= 0) THEN
304 IF (ASSOCIATED(this%var)) DEALLOCATE(this%var)
305#ifdef DEBUG
306 call l4f_category_log(this%category,l4f_debug,"alloc nvar "//to_char(nvar))
307#endif
308 ALLOCATE(this%var(nvar),stat=stallo)
309 if (stallo /=0)then
310 call l4f_category_log(this%category,l4f_fatal,"allocating memory")
311 CALL raise_fatal_error()
312 end if
313 IF (linit) THEN
314 DO i = 1, nvar
315 CALL init(this%var(i))
316 ENDDO
317 ENDIF
318 ENDIF
319ENDIF
320
321end SUBROUTINE volgrid6d_alloc
322
323
324!> Allocate the data array of the \a volgrid6d object.
325!! This method allocates the main 6-dimensional data array
326!! \a this%voldati and the 4-dimensional \a grid_id array \a this%gaid
327!! with a shape dictated by the previous call(s) to \a vol7d_alloc().
328!! if any descriptor (except horizontal grid) has not been allocated
329!! yet, it is allocated here with a size of 1. This method should be
330!! explicitly used only in rare cases, it is usually called implicitly
331!! through the \a import interface.
332SUBROUTINE volgrid6d_alloc_vol(this, ini, inivol, decode)
333TYPE(volgrid6d),INTENT(inout) :: this !< object whose decriptors should be allocated
334LOGICAL,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
335LOGICAL,INTENT(in),OPTIONAL :: inivol !< if provided and \c .FALSE., the allocated volumes will not be initialized to missing values
336LOGICAL,INTENT(in),OPTIONAL :: decode !< if provided and \c .TRUE., the \a this%voldati volume is allocated, otherwise only \a this%gaid will be allocated
337
338INTEGER :: stallo
339LOGICAL :: linivol
340
341#ifdef DEBUG
342call l4f_category_log(this%category,l4f_debug,"start alloc_vol")
343#endif
344
345IF (PRESENT(inivol)) THEN ! opposite condition, cannot use optio_log
346 linivol = inivol
347ELSE
348 linivol = .true.
349ENDIF
350
351IF (this%griddim%dim%nx > 0 .AND. this%griddim%dim%ny > 0) THEN
352! allocate dimension descriptors to a minimal size for having a
353! non-null volume
354 IF (.NOT. ASSOCIATED(this%var)) CALL volgrid6d_alloc(this, nvar=1, ini=ini)
355 IF (.NOT. ASSOCIATED(this%time)) CALL volgrid6d_alloc(this, ntime=1, ini=ini)
356 IF (.NOT. ASSOCIATED(this%level)) CALL volgrid6d_alloc(this, nlevel=1, ini=ini)
357 IF (.NOT. ASSOCIATED(this%timerange)) CALL volgrid6d_alloc(this, ntimerange=1, ini=ini)
358
359 IF (optio_log(decode)) THEN
360 IF (.NOT.ASSOCIATED(this%voldati)) THEN
361#ifdef DEBUG
362 CALL l4f_category_log(this%category,l4f_debug,"alloc voldati volume")
363#endif
364
365 ALLOCATE(this%voldati(this%griddim%dim%nx,this%griddim%dim%ny,&
366 SIZE(this%level), SIZE(this%time), &
367 SIZE(this%timerange), SIZE(this%var)),stat=stallo)
368 IF (stallo /= 0)THEN
369 CALL l4f_category_log(this%category,l4f_fatal,"allocating memory")
370 CALL raise_fatal_error()
371 ENDIF
372
373! this is not really needed if we can check other flags for a full
374! field missing values
375 IF (linivol) this%voldati = rmiss
376 this%voldati = rmiss
377 ENDIF
378 ENDIF
379
380 IF (.NOT.ASSOCIATED(this%gaid)) THEN
381#ifdef DEBUG
382 CALL l4f_category_log(this%category,l4f_debug,"alloc gaid volume")
383#endif
384 ALLOCATE(this%gaid(SIZE(this%level), SIZE(this%time), &
385 SIZE(this%timerange), SIZE(this%var)),stat=stallo)
386 IF (stallo /= 0)THEN
387 CALL l4f_category_log(this%category,l4f_fatal,"allocating memory")
388 CALL raise_fatal_error()
389 ENDIF
390
391 IF (linivol) THEN
392!!$ DO i=1 ,SIZE(this%gaid,1)
393!!$ DO ii=1 ,SIZE(this%gaid,2)
394!!$ DO iii=1 ,SIZE(this%gaid,3)
395!!$ DO iiii=1 ,SIZE(this%gaid,4)
396!!$ this%gaid(i,ii,iii,iiii) = grid_id_new() ! optimize?
397!!$ ENDDO
398!!$ ENDDO
399!!$ ENDDO
400!!$ ENDDO
401
402 this%gaid = grid_id_new()
403 ENDIF
404 ENDIF
405
406ELSE
407 CALL l4f_category_log(this%category,l4f_fatal,'volgrid6d_alloc_vol: &
408 &trying to allocate a volume with an invalid or unspecified horizontal grid')
409 CALL raise_fatal_error()
410ENDIF
411
412END SUBROUTINE volgrid6d_alloc_vol
413
414
415!> Return a 2-d pointer to a x-y slice of a volume. This method works
416!! both with volumes having allocated and non-allocated this%voldati
417!! array, and it returns a pointer to a 2-d slice either from the
418!! allocated this%voldati array or from the grid_id object on file or
419!! in memory. In the second case the pointer should be either
420!! ALLOCATE'd to the expected size or NULLIFY'ed, and if NULLIFY'ed,
421!! it is allocated within the method, thus it will have to be
422!! deallocated by the caller when not in use anymore. Since this
423!! method may be called many times by a program, it is optimized for
424!! speed and it does not make any check about the matching size of the
425!! pointer and the array or about the allocation status of \a this, so
426!! it should be called only when everything has been checked to be in
427!! good shape.
428SUBROUTINE volgrid_get_vol_2d(this, ilevel, itime, itimerange, ivar, voldati)
429TYPE(volgrid6d),INTENT(in) :: this !< object from which the slice has to be retrieved
430INTEGER,INTENT(in) :: ilevel !< index of vertical level of the slice
431INTEGER,INTENT(in) :: itime !< index of time level of the slice
432INTEGER,INTENT(in) :: itimerange !< index of timerange of the slice
433INTEGER,INTENT(in) :: ivar !< index of physical variable of the slice
434REAL,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
435
436IF (ASSOCIATED(this%voldati)) THEN
437 voldati => this%voldati(:,:,ilevel,itime,itimerange,ivar)
438 RETURN
439ELSE
440 IF (.NOT.ASSOCIATED(voldati)) THEN
441 ALLOCATE(voldati(this%griddim%dim%nx,this%griddim%dim%ny))
442 ENDIF
443 CALL grid_id_decode_data(this%gaid(ilevel,itime,itimerange,ivar), voldati)
444ENDIF
445
446END SUBROUTINE volgrid_get_vol_2d
447
448
449!> Return a 3-d pointer to a x-y-z slice of a volume. This method works
450!! both with volumes having allocated and non-allocated this%voldati
451!! array, and it returns a pointer to a 3-d slice either from the
452!! allocated this%voldati array or from the grid_id object on file or
453!! in memory. In the second case the pointer should be either
454!! ALLOCATE'd to the expected size or NULLIFY'ed, and if NULLIFY'ed,
455!! it is allocated within the method, thus it will have to be
456!! deallocated by the caller when not in use anymore. Since this
457!! method may be called many times by a program, it is optimized for
458!! speed and it does not make any check about the matching size of the
459!! pointer and the array or about the allocation status of \a this, so
460!! it should be called only when everything has been checked to be in
461!! good shape.
462SUBROUTINE volgrid_get_vol_3d(this, itime, itimerange, ivar, voldati, zlist)
463TYPE(volgrid6d),INTENT(in) :: this !< object from which the slice has to be retrieved
464INTEGER,INTENT(in) :: itime !< index of time level of the slice
465INTEGER,INTENT(in) :: itimerange !< index of timerange of the slice
466INTEGER,INTENT(in) :: ivar !< index of physical variable of the slice
467REAL,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
468LOGICAL,OPTIONAL,INTENT(out),ALLOCATABLE :: zlist(:) !< list of vertical level present in the data
469
470INTEGER :: ilevel
471LOGICAL :: done
472
473IF (ASSOCIATED(this%voldati)) THEN
474 voldati => this%voldati(:,:,:,itime,itimerange,ivar)
475 IF (PRESENT(zlist)) zlist(:) = c_e(this%gaid(:,itime,itimerange,ivar))
476 RETURN
477ELSE
478 IF (.NOT.ASSOCIATED(voldati)) THEN
479 ALLOCATE(voldati(this%griddim%dim%nx,this%griddim%dim%ny,SIZE(this%level)))
480 ENDIF
481 IF (PRESENT(zlist)) THEN
482 ALLOCATE(zlist(SIZE(this%level)))
483 ENDIF
484!$OMP PARALLEL DEFAULT(SHARED)
485!$OMP MASTER
486 DO ilevel = 1, SIZE(this%level)
487!$OMP TASK FIRSTPRIVATE(ilevel),PRIVATE(done)
488 CALL grid_id_decode_data(this%gaid(ilevel,itime,itimerange,ivar), &
489 voldati(:,:,ilevel),done)
490 IF (PRESENT(zlist)) zlist(ilevel) = done
491!$OMP END TASK
492 ENDDO
493!$OMP END MASTER
494!$OMP END PARALLEL
495ENDIF
496
497END SUBROUTINE volgrid_get_vol_3d
498
499
500!> Reset a 2-d x-y slice of a volume after the data have been modified.
501!! This method works both with volumes having allocated and
502!! non-allocated this%voldati array, and it updates the requested
503!! slice. In case \a this%voldati is already allocated, this is a
504!! no-operation while in the other case this method encodes the field
505!! provided into the grid_id object on file or in memory. Since this
506!! method may be called many times by a program, it is optimized for
507!! speed and it does not make any check about the matching size of the
508!! field and the array or about the allocation status of \a this, so
509!! it should be called only when everything has been checked to be in
510!! good shape.
511SUBROUTINE volgrid_set_vol_2d(this, ilevel, itime, itimerange, ivar, voldati)
512TYPE(volgrid6d),INTENT(inout) :: this !< object in which slice has to be updated
513INTEGER,INTENT(in) :: ilevel !< index of vertical level of the slice
514INTEGER,INTENT(in) :: itime !< index of time level of the slice
515INTEGER,INTENT(in) :: itimerange !< index of timerange of the slice
516INTEGER,INTENT(in) :: ivar !< index of physical variable of the slice
517REAL,INTENT(in) :: voldati(:,:) !< updated values of the slice
518
519IF (ASSOCIATED(this%voldati)) THEN
520 RETURN
521ELSE
522 CALL grid_id_encode_data(this%gaid(ilevel,itime,itimerange,ivar), voldati)
523ENDIF
524
525END SUBROUTINE volgrid_set_vol_2d
526
527
528!> Reset a 3-d x-y-z slice of a volume after the data have been modified.
529!! This method works both with volumes having allocated and
530!! non-allocated this%voldati array, and it updates the requested
531!! slice. In case \a this%voldati is already allocated, this is a
532!! no-operation while in the other case this method encodes the field
533!! provided into the grid_id object on file or in memory. Since this
534!! method may be called many times by a program, it is optimized for
535!! speed and it does not make any check about the matching size of the
536!! field and the array or about the allocation status of \a this, so
537!! it should be called only when everything has been checked to be in
538!! good shape.
539SUBROUTINE volgrid_set_vol_3d(this, itime, itimerange, ivar, voldati)
540TYPE(volgrid6d),INTENT(inout) :: this !< object in which slice has to be updated
541INTEGER,INTENT(in) :: itime !< index of time level of the slice
542INTEGER,INTENT(in) :: itimerange !< index of timerange of the slice
543INTEGER,INTENT(in) :: ivar !< index of physical variable of the slice
544REAL,INTENT(in) :: voldati(:,:,:) !< updated values of the slice
545
546INTEGER :: ilevel
547
548IF (ASSOCIATED(this%voldati)) THEN
549 RETURN
550ELSE
551!$OMP PARALLEL DEFAULT(SHARED)
552!$OMP MASTER
553 DO ilevel = 1, SIZE(this%level)
554!$OMP TASK FIRSTPRIVATE(ilevel)
555 CALL grid_id_encode_data(this%gaid(ilevel,itime,itimerange,ivar), &
556 voldati(:,:,ilevel))
557!$OMP END TASK
558 ENDDO
559!$OMP END MASTER
560!$OMP END PARALLEL
561ENDIF
562
563END SUBROUTINE volgrid_set_vol_3d
564
565
566!> Destructor, it releases every information and memory buffer
567!! associated with the object. It should be called also for objects
568!! crated through the \a import interface.
569SUBROUTINE volgrid6d_delete(this)
570TYPE(volgrid6d),INTENT(inout) :: this
571
572INTEGER :: i, ii, iii, iiii
573
574#ifdef DEBUG
575call l4f_category_log(this%category,l4f_debug,"delete")
576#endif
577
578if (associated(this%gaid))then
579
580 DO i=1 ,SIZE(this%gaid,1)
581 DO ii=1 ,SIZE(this%gaid,2)
582 DO iii=1 ,SIZE(this%gaid,3)
583 DO iiii=1 ,SIZE(this%gaid,4)
584 CALL delete(this%gaid(i,ii,iii,iiii))
585 ENDDO
586 ENDDO
587 ENDDO
588 ENDDO
589 DEALLOCATE(this%gaid)
590
591end if
592
593call delete(this%griddim)
594
595! call delete(this%time)
596! call delete(this%timerange)
597! call delete(this%level)
598! call delete(this%var)
599
600if (associated( this%time )) deallocate(this%time)
601if (associated( this%timerange )) deallocate(this%timerange)
602if (associated( this%level )) deallocate(this%level)
603if (associated( this%var )) deallocate(this%var)
604
605if (associated(this%voldati))deallocate(this%voldati)
606
607
608 !chiudo il logger
609call l4f_category_delete(this%category)
610
611END SUBROUTINE volgrid6d_delete
612
613
614!>\brief Scrittura su file di un volume Volgrid6d.
615!! Scrittura su file unformatted di un intero volume Volgrid6d.
616!! Il volume viene serializzato e scritto su file.
617!! Il file puo' essere aperto opzionalmente dall'utente. Si possono passare
618!! opzionalmente unità e nome del file altrimenti assegnati internamente a dei default; se assegnati internamente
619!! tali parametri saranno in output.
620!! Se non viene fornito il nome file viene utilizzato un file di default con nome pari al nome del programma in
621!! esecuzione con postfisso ".vg6d".
622!! Come parametro opzionale c'è la description che insieme alla data corrente viene inserita nell'header del file.
623subroutine volgrid6d_write_on_file (this,unit,description,filename,filename_auto)
624
625TYPE(volgrid6d),INTENT(IN) :: this !< volume volgrid6d da scrivere
626integer,optional,intent(inout) :: unit !< unità su cui scrivere; se passata =0 ritorna il valore rielaborato (default =rielaborato internamente con getlun )
627character(len=*),intent(in),optional :: filename !< nome del file su cui scrivere
628character(len=*),intent(out),optional :: filename_auto !< nome del file generato se "filename" è omesso
629character(len=*),INTENT(IN),optional :: description !< descrizione del volume
630
631integer :: lunit
632character(len=254) :: ldescription,arg,lfilename
633integer :: ntime, ntimerange, nlevel, nvar
634integer :: tarray(8)
635logical :: opened,exist
636
637#ifdef DEBUG
638call l4f_category_log(this%category,l4f_debug,"write on file")
639#endif
640
641ntime=0
642ntimerange=0
643nlevel=0
644nvar=0
645
646!call idate(im,id,iy)
647call date_and_time(values=tarray)
648call getarg(0,arg)
649
650if (present(description))then
651 ldescription=description
652else
653 ldescription="Volgrid6d generated by: "//trim(arg)
654end if
655
656if (.not. present(unit))then
657 lunit=getunit()
658else
659 if (unit==0)then
660 lunit=getunit()
661 unit=lunit
662 else
663 lunit=unit
664 end if
665end if
666
667lfilename=trim(arg)//".vg6d"
668if (index(arg,'/',back=.true.) > 0) lfilename=lfilename(index(arg,'/',back=.true.)+1 : )
669
670if (present(filename))then
671 if (filename /= "")then
672 lfilename=filename
673 end if
674end if
675
676if (present(filename_auto))filename_auto=lfilename
677
678
679inquire(unit=lunit,opened=opened)
680if (.not. opened) then
681 inquire(file=lfilename,exist=exist)
682 if (exist) CALL raise_error('file exist; cannot open new file')
683 if (.not.exist) open (unit=lunit,file=lfilename,form="UNFORMATTED")
684 !print *, "opened: ",lfilename
685end if
686
687if (associated(this%time)) ntime=size(this%time)
688if (associated(this%timerange)) ntimerange=size(this%timerange)
689if (associated(this%level)) nlevel=size(this%level)
690if (associated(this%var)) nvar=size(this%var)
691
692
693write(unit=lunit)ldescription
694write(unit=lunit)tarray
695
696call write_unit( this%griddim,lunit)
697write(unit=lunit) ntime, ntimerange, nlevel, nvar
698
699!! prime 4 dimensioni
700if (associated(this%time)) call write_unit(this%time, lunit)
701if (associated(this%level)) write(unit=lunit)this%level
702if (associated(this%timerange)) write(unit=lunit)this%timerange
703if (associated(this%var)) write(unit=lunit)this%var
704
705
706!! Volumi di valori dati
707
708if (associated(this%voldati)) write(unit=lunit)this%voldati
709
710if (.not. present(unit)) close(unit=lunit)
711
712end subroutine volgrid6d_write_on_file
713
714
715!>\brief Lettura da file di un volume Volgrid6d.
716!! Lettura da file unformatted di un intero volume Volgrid6d.
717!! Questa subroutine comprende volgrid6d_alloc e volgrid6d_alloc_vol.
718!! Il file puo' essere aperto opzionalmente dall'utente. Si possono passare
719!! opzionalmente unità e nome del file altrimenti assegnati internamente a dei default; se assegnati internamente
720!! tali parametri saranno in output.
721subroutine volgrid6d_read_from_file (this,unit,filename,description,tarray,filename_auto)
722
723TYPE(volgrid6d),INTENT(OUT) :: this !< Volume volgrid6d da leggere
724integer,intent(inout),optional :: unit !< unità su cui è stato aperto un file; se =0 rielaborato internamente (default = elaborato internamente con getunit)
725character(len=*),INTENT(in),optional :: filename !< nome del file eventualmente da aprire (default = nome dell'eseguibile.v7d)
726character(len=*),intent(out),optional :: filename_auto !< nome del file generato se "filename" è omesso
727character(len=*),INTENT(out),optional :: description !< descrizione del volume letto
728integer,intent(out),optional :: tarray(8) !< vettore come definito da "date_and_time" della data di scrittura del volume
729
730integer :: ntime, ntimerange, nlevel, nvar
731
732character(len=254) :: ldescription,lfilename,arg
733integer :: ltarray(8),lunit
734logical :: opened,exist
735
736#ifdef DEBUG
737call l4f_category_log(this%category,l4f_debug,"read from file")
738#endif
739
740call getarg(0,arg)
741
742if (.not. present(unit))then
743 lunit=getunit()
744else
745 if (unit==0)then
746 lunit=getunit()
747 unit=lunit
748 else
749 lunit=unit
750 end if
751end if
752
753lfilename=trim(arg)//".vg6d"
754if (index(arg,'/',back=.true.) > 0) lfilename=lfilename(index(arg,'/',back=.true.)+1 : )
755
756if (present(filename))then
757 if (filename /= "")then
758 lfilename=filename
759 end if
760end if
761
762if (present(filename_auto))filename_auto=lfilename
763
764
765inquire(unit=lunit,opened=opened)
766if (.not. opened) then
767 inquire(file=lfilename,exist=exist)
768 IF (.NOT. exist) CALL raise_fatal_error('file '//trim(lfilename)//' does not exist, cannot open')
769 open (unit=lunit,file=lfilename,form="UNFORMATTED")
770end if
771
772read(unit=lunit)ldescription
773read(unit=lunit)ltarray
774
775call l4f_log(l4f_info,"Info: reading volgrid6d from file: "//trim(lfilename))
776call l4f_log(l4f_info,"Info: description: "//trim(ldescription))
777!call l4f_log("Info: written on ",ltarray)
778
779if (present(description))description=ldescription
780if (present(tarray))tarray=ltarray
781
782
783call read_unit( this%griddim,lunit)
784read(unit=lunit) ntime, ntimerange, nlevel, nvar
785
786
787call volgrid6d_alloc (this, &
788 ntime=ntime, ntimerange=ntimerange, nlevel=nlevel, nvar=nvar)
789
790call volgrid6d_alloc_vol (this)
791
792if (associated(this%time)) call read_unit(this%time, lunit)
793if (associated(this%level)) read(unit=lunit)this%level
794if (associated(this%timerange)) read(unit=lunit)this%timerange
795if (associated(this%var)) read(unit=lunit)this%var
796
797
798!! Volumi di valori
799
800if (associated(this%voldati)) read(unit=lunit)this%voldati
801
802if (.not. present(unit)) close(unit=lunit)
803
804end subroutine volgrid6d_read_from_file
805
806
807!> Import a single \a gridinfo object into a \a volgrid6d object.
808!! This methods imports a single gridded field from a \a gridinfo
809!! object into a \a volgrid6d object, inserting it into the
810!! multidimensional structure of volgrid6d. The volgrid6d object must
811!! have been already initialized and the dimensions specified with
812!! volgrid6d_alloc(). If the \a force argument is missing or \a
813!! .FALSE. , the volgrid6d object dimension descriptors (time,
814!! timerange, vertical level, physical variable) must already have
815!! space for the corresponding values coming from gridinfo, otherwise
816!! the object will be rejected; this means that all the volgrid6d
817!! dimension descriptors should be correctly assigned. If \a force is
818!! \a .TRUE. , the gridinfo dimension descriptors that do not fit into
819!! available descriptors in the \a volgrid6d structure, will be
820!! accomodated in a empty (i.e. equal to missing value) descriptor, if
821!! available, otherwise the gridinfo will be rejected. The
822!! descriptor of the grid in the \a volgrid object is assigned to the
823!! descriptor contained in \a gridinfo if it is missing in \a volgrid,
824!! otherwise it is checked and the object is rejected if grids do not
825!! match.
826SUBROUTINE import_from_gridinfo(this, gridinfo, force, dup_mode, clone, &
827 isanavar)
828TYPE(volgrid6d),INTENT(inout) :: this !< object in which to import
829TYPE(gridinfo_def),INTENT(in) :: gridinfo !< gridinfo object to be imported
830LOGICAL,INTENT(in),OPTIONAL :: force !< if provided and \c .TRUE., the gridinfo is forced into an empty element of \a this, if required and possible
831INTEGER,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
832LOGICAL , INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE. , clone the gaid's from \a gridinfo to \a this
833LOGICAL,INTENT(IN),OPTIONAL :: isanavar !< if provides and \a .TRUE., the gridinfo object is treated as time-independent and replicated for every time and timerange
834
835CHARACTER(len=255) :: type
836INTEGER :: itime0, itimerange0, itime1, itimerange1, itime, itimerange, &
837 ilevel, ivar, ldup_mode
838LOGICAL :: dup
839TYPE(datetime) :: correctedtime
840TYPE(vol7d_timerange) :: correctedtimerange
841REAL,ALLOCATABLE :: tmpgrid(:,:)
842
843IF (PRESENT(dup_mode)) THEN
844 ldup_mode = dup_mode
845ELSE
846 ldup_mode = 0
847ENDIF
848
849call get_val(this%griddim,proj_type=type)
850
851#ifdef DEBUG
852call l4f_category_log(this%category,l4f_debug,"import_from_gridinfo: "//trim(type))
853#endif
854
855if (.not. c_e(type))then
856 call copy(gridinfo%griddim, this%griddim)
857! ho gia` fatto init, altrimenti non potrei fare la get_val(this%griddim)
858! per cui meglio non ripetere
859! call init(this,gridinfo%griddim,categoryappend)
860 CALL volgrid6d_alloc_vol(this, ini=.true.) ! decode?
861
862else if (.not. (this%griddim == gridinfo%griddim ))then
863
864 CALL l4f_category_log(this%category,l4f_error, &
865 "volgrid and gridinfo grid type or size are different, gridinfo rejected")
866 CALL raise_error()
867 RETURN
868
869end if
870
871! Cerco gli indici del campo da inserire, se non trovo metto nel primo missing
872ilevel = index(this%level, gridinfo%level)
873IF (ilevel == 0 .AND. optio_log(force)) THEN
874 ilevel = index(this%level, vol7d_level_miss)
875 IF (ilevel /= 0) this%level(ilevel) = gridinfo%level
876ENDIF
877
878IF (ilevel == 0) THEN
879 CALL l4f_category_log(this%category,l4f_error, &
880 "volgrid6d: level not valid for volume, gridinfo rejected")
881 CALL raise_error()
882 RETURN
883ENDIF
884
885IF (optio_log(isanavar)) THEN ! assign to all times and timeranges
886 itime0 = 1
887 itime1 = SIZE(this%time)
888 itimerange0 = 1
889 itimerange1 = SIZE(this%timerange)
890ELSE ! usual case
891 correctedtime = gridinfo%time
892 IF (this%time_definition == 1 .OR. this%time_definition == 2) correctedtime = correctedtime + &
893 timedelta_new(sec=gridinfo%timerange%p1)
894 itime0 = index(this%time, correctedtime)
895 IF (itime0 == 0 .AND. optio_log(force)) THEN
896 itime0 = index(this%time, datetime_miss)
897 IF (itime0 /= 0) this%time(itime0) = correctedtime
898 ENDIF
899 IF (itime0 == 0) THEN
900 CALL l4f_category_log(this%category,l4f_error, &
901 "volgrid6d: time not valid for volume, gridinfo rejected")
902 CALL raise_error()
903 RETURN
904 ENDIF
905 itime1 = itime0
906
907 correctedtimerange = gridinfo%timerange
908 IF (this%time_definition == 2) correctedtimerange%p1 = 0
909 itimerange0 = index(this%timerange, correctedtimerange)
910 IF (itimerange0 == 0 .AND. optio_log(force)) THEN
911 itimerange0 = index(this%timerange, vol7d_timerange_miss)
912 IF (itimerange0 /= 0) this%timerange(itimerange0) = gridinfo%timerange
913 ENDIF
914 IF (itimerange0 == 0) THEN
915 CALL l4f_category_log(this%category,l4f_error, &
916 "volgrid6d: timerange not valid for volume, gridinfo rejected")
917 CALL raise_error()
918 RETURN
919 ENDIF
920 itimerange1 = itimerange0
921ENDIF
922
923ivar = index(this%var, gridinfo%var)
924IF (ivar == 0 .AND. optio_log(force)) THEN
925 ivar = index(this%var, volgrid6d_var_miss)
926 IF (ivar /= 0) this%var(ivar) = gridinfo%var
927ENDIF
928IF (ivar == 0) THEN
929 CALL l4f_category_log(this%category,l4f_error, &
930 "volgrid6d: var not valid for volume, gridinfo rejected")
931 CALL raise_error()
932 RETURN
933ENDIF
934
935DO itimerange = itimerange0, itimerange1
936 DO itime = itime0, itime1
937 IF (ASSOCIATED(this%gaid)) THEN
938 dup = .false.
939 IF (c_e(this%gaid(ilevel,itime,itimerange,ivar))) THEN
940 dup = .true.
941 CALL l4f_category_log(this%category,l4f_warn,"gaid exist: grib duplicated")
942! avoid memory leaks
943 IF (optio_log(clone)) CALL delete(this%gaid(ilevel,itime,itimerange,ivar))
944 ENDIF
945
946 IF (optio_log(clone)) THEN
947 CALL copy(gridinfo%gaid, this%gaid(ilevel,itime,itimerange,ivar))
948#ifdef DEBUG
949 CALL l4f_category_log(this%category,l4f_debug,"cloning to a new gaid")
950#endif
951 ELSE
952 this%gaid(ilevel,itime,itimerange,ivar) = gridinfo%gaid
953 ENDIF
954
955 IF (ASSOCIATED(this%voldati))THEN
956 IF (.NOT.dup .OR. ldup_mode == 0) THEN
957 this%voldati(:,:,ilevel,itime,itimerange,ivar) = decode_gridinfo(gridinfo)
958 ELSE IF (ldup_mode == 1) THEN
959 tmpgrid = decode_gridinfo(gridinfo) ! f2003 automatic allocation
960 WHERE(c_e(tmpgrid))
961 this%voldati(:,:,ilevel,itime,itimerange,ivar) = tmpgrid(:,:)
962 END WHERE
963 ELSE IF (ldup_mode == 2) THEN
964 WHERE(.NOT.c_e(this%voldati(:,:,ilevel,itime,itimerange,ivar)))
965 this%voldati(:,:,ilevel,itime,itimerange,ivar) = decode_gridinfo(gridinfo)
966 END WHERE
967 ENDIF
968 ENDIF
969
970 ELSE
971 CALL l4f_category_log(this%category,l4f_error, &
972 "gaid not allocated, you probably need to call volgrid6d_alloc_vol first")
973 CALL raise_error()
974 RETURN
975 ENDIF
976 ENDDO
977ENDDO
978
979
980END SUBROUTINE import_from_gridinfo
981
982
983!> Export a single grid of a \a volgrid6d object to a \a gridinfo_def object.
984!! A single 2d slice of a \a volgrid6d at a specified location is
985!! written into a \a gridinfo_def object, including the \a grid_id
986!! which can be used for the successive export to file.
987SUBROUTINE export_to_gridinfo(this, gridinfo, itime, itimerange, ilevel, ivar, &
988 gaid_template, clone)
989TYPE(volgrid6d),INTENT(in) :: this !< volume to be exported
990TYPE(gridinfo_def),INTENT(inout) :: gridinfo !< output gridinfo_def object
991INTEGER :: itime !< index within \a this of the element to be exported for the time dimension
992INTEGER :: itimerange !< index within \a this of the element to be exported for the timerange dimension
993INTEGER :: ilevel !< index within \a this of the element to be exported for the vertical level dimension
994INTEGER :: ivar !< index within \a this of the element to be exported for the variable dimension
995TYPE(grid_id),INTENT(in),OPTIONAL :: gaid_template !< \a grid_id template to be used for output data replacing the one contained in \a this
996LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE., clone the grid_id included in \a this rather than making a shallow copy
997
998TYPE(grid_id) :: gaid
999LOGICAL :: usetemplate
1000REAL,POINTER :: voldati(:,:)
1001TYPE(datetime) :: correctedtime
1002
1003#ifdef DEBUG
1004CALL l4f_category_log(this%category,l4f_debug,"export_to_gridinfo")
1005#endif
1006
1007IF (.NOT.c_e(this%gaid(ilevel,itime,itimerange,ivar))) THEN
1008#ifdef DEBUG
1009 CALL l4f_category_log(this%category,l4f_debug,"empty gaid found, skipping export")
1010#endif
1011 RETURN
1012ENDIF
1013
1014usetemplate = .false.
1015IF (PRESENT(gaid_template)) THEN
1016 CALL copy(gaid_template, gaid)
1017#ifdef DEBUG
1018 CALL l4f_category_log(this%category,l4f_debug,"template cloned to a new gaid")
1019#endif
1020 usetemplate = c_e(gaid)
1021ENDIF
1022
1023IF (.NOT.usetemplate) THEN
1024 IF (optio_log(clone)) THEN
1025 CALL copy(this%gaid(ilevel,itime,itimerange,ivar), gaid)
1026#ifdef DEBUG
1027 CALL l4f_category_log(this%category,l4f_debug,"original gaid cloned to a new one")
1028#endif
1029 ELSE
1030 gaid = this%gaid(ilevel,itime,itimerange,ivar)
1031 ENDIF
1032ENDIF
1033
1034IF (this%time_definition == 1 .OR. this%time_definition == 2) THEN
1035 correctedtime = this%time(itime) - &
1036 timedelta_new(sec=this%timerange(itimerange)%p1)
1037ELSE
1038 correctedtime = this%time(itime)
1039ENDIF
1040
1041CALL init(gridinfo,gaid, this%griddim, correctedtime, this%timerange(itimerange), &
1042 this%level(ilevel), this%var(ivar))
1043
1044! reset the gridinfo, bad but necessary at this point for encoding the field
1045CALL export(gridinfo%griddim, gridinfo%gaid)
1046! encode the field
1047IF (ASSOCIATED(this%voldati)) THEN
1048 CALL encode_gridinfo(gridinfo, this%voldati(:,:,ilevel,itime,itimerange,ivar))
1049ELSE IF (usetemplate) THEN ! field must be forced into template in this case
1050 NULLIFY(voldati)
1051 CALL volgrid_get_vol_2d(this, ilevel, itime, itimerange, ivar, voldati)
1052 CALL encode_gridinfo(gridinfo, voldati)
1053 DEALLOCATE(voldati)
1054ENDIF
1055
1056END SUBROUTINE export_to_gridinfo
1057
1058
1059!> Import an array of \a gridinfo objects into an array of \a
1060!! volgrid6d objects.
1061!! This method imports an array of gridded fields from an \a
1062!! arrayof_gridinfo object into a suitable number of \a volgrid6d
1063!! objects. The number of \a volgrid6d allocated is determined by the
1064!! number of different grids encountered in \a arrayof_gridinfo.
1065!! Unlike the import for a single \a gridinfo, here the \a volgrid6d
1066!! object is a non-associated pointer to a 1-d array of uninitialized
1067!! objects, and all the dimension descriptors in each of the objects
1068!! are allocated and assigned within the method according to the data
1069!! contained in \a gridinfov.
1070!! If the \a anavar array argument is provided, all the input messages
1071!! whose variable maps to one of the B-table variables contained in \a
1072!! anavar are treated as time-independent (AKA anagraphic data,
1073!! station data, etc.), thus their time and timerange are ignored and
1074!! they are replicated for every time and timerange present in the
1075!! corresponding data volume.
1076SUBROUTINE import_from_gridinfovv(this, gridinfov, dup_mode, clone, decode, &
1077 time_definition, anavar, categoryappend)
1078TYPE(volgrid6d),POINTER :: this(:) !< object in which to import
1079TYPE(arrayof_gridinfo),INTENT(in) :: gridinfov !< array of gridinfo objects to be imported
1080INTEGER,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
1081LOGICAL , INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE. , clone the gaid's from \a gridinfo to \a this
1082LOGICAL,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
1083INTEGER,INTENT(IN),OPTIONAL :: time_definition !< 0=time is reference time; 1=time is validity time
1084CHARACTER(len=*),INTENT(IN),OPTIONAL :: anavar(:) !< list of variables (B-table code equivalent) to be treated as time-independent data
1085CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
1086
1087INTEGER :: i, j, stallo
1088INTEGER :: ngrid, ntime, ntimerange, nlevel, nvar, ltime_definition
1089TYPE(l4f_handle) :: category
1090CHARACTER(len=512) :: a_name
1091TYPE(datetime),ALLOCATABLE :: correctedtime(:)
1092LOGICAL,ALLOCATABLE :: isanavar(:)
1093TYPE(vol7d_var) :: lvar
1094TYPE(vol7d_timerange),ALLOCATABLE :: correctedtimerange(:)
1095
1096! category temporanea (altrimenti non possiamo loggare)
1097if (present(categoryappend))then
1098 call l4f_launcher(a_name,a_name_append=trim(subcategory)//"."//trim(categoryappend))
1099else
1100 call l4f_launcher(a_name,a_name_append=trim(subcategory))
1101endif
1102category=l4f_category_get_handle(a_name)
1103
1104#ifdef DEBUG
1105call l4f_category_log(category,l4f_debug,"start import_from_gridinfovv")
1106#endif
1107
1108IF (PRESENT(time_definition)) THEN
1109 ltime_definition = max(min(time_definition, 2), 0)
1110ELSE
1111 ltime_definition = 0
1112ENDIF
1113
1114ngrid=count_distinct(gridinfov%array(1:gridinfov%arraysize)%griddim,back=.true.)
1115CALL l4f_category_log(category,l4f_info, t2c(ngrid)// &
1116 ' different grid definition(s) found in input data')
1117
1118ALLOCATE(this(ngrid),stat=stallo)
1119IF (stallo /= 0)THEN
1120 CALL l4f_category_log(category,l4f_fatal,"allocating memory")
1121 CALL raise_fatal_error()
1122ENDIF
1123DO i = 1, ngrid
1124 IF (PRESENT(categoryappend))THEN
1125 CALL init(this(i), time_definition=ltime_definition, categoryappend=trim(categoryappend)//"-vol"//t2c(i))
1126 ELSE
1127 CALL init(this(i), time_definition=ltime_definition, categoryappend="vol"//t2c(i))
1128 ENDIF
1129ENDDO
1130
1131this(:)%griddim=pack_distinct(gridinfov%array(1:gridinfov%arraysize)%griddim, &
1132 ngrid, back=.true.)
1133
1134! mark elements as ana variables (time-independent)
1135ALLOCATE(isanavar(gridinfov%arraysize))
1136isanavar(:) = .false.
1137IF (PRESENT(anavar)) THEN
1138 DO i = 1, gridinfov%arraysize
1139 DO j = 1, SIZE(anavar)
1140 lvar = convert(gridinfov%array(i)%var)
1141 IF (lvar%btable == anavar(j)) THEN
1142 isanavar(i) = .true.
1143 EXIT
1144 ENDIF
1145 ENDDO
1146 ENDDO
1147 CALL l4f_category_log(category,l4f_info,t2c(count(isanavar))//'/'// &
1148 t2c(gridinfov%arraysize)//' constant-data messages found in input data')
1149ENDIF
1150
1151IF (ltime_definition == 1 .OR. ltime_definition == 2) THEN ! verification time
1152 ALLOCATE(correctedtime(gridinfov%arraysize))
1153 correctedtime(:) = gridinfov%array(1:gridinfov%arraysize)%time
1154 DO i = 1, gridinfov%arraysize
1155 correctedtime(i) = correctedtime(i) + &
1156 timedelta_new(sec=gridinfov%array(i)%timerange%p1)
1157 ENDDO
1158ENDIF
1159IF (ltime_definition == 2) THEN ! set all to analysis
1160 ALLOCATE(correctedtimerange(gridinfov%arraysize))
1161 correctedtimerange(:) = gridinfov%array(1:gridinfov%arraysize)%timerange
1162 correctedtimerange(:)%p1 = 0
1163ENDIF
1164
1165DO i = 1, ngrid
1166 IF (PRESENT(anavar)) THEN
1167 j = count((this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1168 .AND. .NOT.isanavar(:))
1169 IF (j <= 0) THEN
1170 CALL l4f_category_log(category, l4f_fatal, 'grid n.'//t2c(i)// &
1171 ' has only constant data, this is not allowed')
1172 CALL l4f_category_log(category, l4f_fatal, 'please check anavar argument')
1173 CALL raise_fatal_error()
1174 ENDIF
1175 ENDIF
1176 IF (ltime_definition == 1 .OR. ltime_definition == 2) THEN ! verification time
1177 ntime = count_distinct(correctedtime, &
1178 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1179 .AND. .NOT.isanavar(:), back=.true.)
1180 ELSE
1181 ntime = count_distinct(gridinfov%array(1:gridinfov%arraysize)%time, &
1182 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1183 .AND. .NOT.isanavar(:), back=.true.)
1184 ENDIF
1185 IF (ltime_definition == 2) THEN ! set all to analysis
1186 ntimerange = count_distinct(correctedtimerange, &
1187 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1188 .AND. .NOT.isanavar(:), back=.true.)
1189 ELSE
1190 ntimerange = count_distinct(gridinfov%array(1:gridinfov%arraysize)%timerange, &
1191 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1192 .AND. .NOT.isanavar(:), back=.true.)
1193 ENDIF
1194 nlevel = count_distinct(gridinfov%array(1:gridinfov%arraysize)%level, &
1195 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim), &
1196 back=.true.)
1197 nvar = count_distinct(gridinfov%array(1:gridinfov%arraysize)%var, &
1198 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim), &
1199 back=.true.)
1200
1201#ifdef DEBUG
1202 CALL l4f_category_log(this(i)%category,l4f_debug,"alloc volgrid6d index: "//t2c(i))
1203#endif
1204
1205 CALL volgrid6d_alloc(this(i),this(i)%griddim%dim,ntime=ntime, &
1206 ntimerange=ntimerange,nlevel=nlevel,nvar=nvar)
1207
1208 IF (ltime_definition == 1 .OR. ltime_definition == 2) THEN ! verification time
1209 this(i)%time = pack_distinct(correctedtime, ntime, &
1210 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1211 .AND. .NOT.isanavar(:), back=.true.)
1212 ELSE
1213 this(i)%time = pack_distinct(gridinfov%array(1:gridinfov%arraysize)%time, ntime, &
1214 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1215 .AND. .NOT.isanavar(:), back=.true.)
1216 ENDIF
1217 CALL sort(this(i)%time)
1218
1219 IF (ltime_definition == 2) THEN ! set all to analysis
1220 this(i)%timerange = pack_distinct(correctedtimerange, ntimerange, &
1221 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1222 .AND. .NOT.isanavar(:), back=.true.)
1223 ELSE
1224 this(i)%timerange = pack_distinct(gridinfov%array(1:gridinfov%arraysize)%timerange, &
1225 ntimerange, mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim) &
1226 .AND. .NOT.isanavar(:), back=.true.)
1227 ENDIF
1228 CALL sort(this(i)%timerange)
1229
1230 this(i)%level=pack_distinct(gridinfov%array(1:gridinfov%arraysize)%level, &
1231 nlevel,mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim), &
1232 back=.true.)
1233 CALL sort(this(i)%level)
1234
1235 this(i)%var=pack_distinct(gridinfov%array(1:gridinfov%arraysize)%var, nvar, &
1236 mask=(this(i)%griddim == gridinfov%array(1:gridinfov%arraysize)%griddim), &
1237 back=.true.)
1238
1239#ifdef DEBUG
1240 CALL l4f_category_log(this(i)%category,l4f_debug,"alloc_vol volgrid6d index: "//t2c(i))
1241#endif
1242 CALL volgrid6d_alloc_vol(this(i), decode=decode)
1243
1244ENDDO
1245
1246IF (ltime_definition == 1 .OR. ltime_definition == 2) DEALLOCATE(correctedtime)
1247IF (ltime_definition == 2) DEALLOCATE(correctedtimerange)
1248
1249DO i = 1, gridinfov%arraysize
1250
1251#ifdef DEBUG
1252 CALL l4f_category_log(category,l4f_debug,"import from gridinfov index: "//t2c(i))
1253 CALL l4f_category_log(category,l4f_info, &
1254 "to volgrid6d index: "//t2c(index(this%griddim, gridinfov%array(i)%griddim)))
1255#endif
1256
1257 CALL import(this(index(this%griddim, gridinfov%array(i)%griddim)), &
1258 gridinfov%array(i), dup_mode=dup_mode, clone=clone, isanavar=isanavar(i))
1259
1260ENDDO
1261
1262!chiudo il logger temporaneo
1263CALL l4f_category_delete(category)
1265END SUBROUTINE import_from_gridinfovv
1266
1267
1268!> Export a \a volgrid6d object to an \a arrayof_gridinfo object.
1269!! The multidimensional \a volgrid6d structure is serialized into a
1270!! one-dimensional array of gridinfo_def objects, which is allocated
1271!! to the proper size if not already allocated, or it is extended
1272!! keeping the old data if any.
1273SUBROUTINE export_to_gridinfov(this, gridinfov, gaid_template, clone)
1274TYPE(volgrid6d),INTENT(inout) :: this !< volume to be exported
1275TYPE(arrayof_gridinfo),INTENT(inout) :: gridinfov !< output array of gridinfo_def objects
1276TYPE(grid_id),INTENT(in),OPTIONAL :: gaid_template !< \a grid_id template to be used for output data replacing the one contained in \a this
1277LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE., clone the grid_id included in \a this rather than making a shallow copy
1278
1279INTEGER :: i ,itime, itimerange, ilevel, ivar
1280INTEGER :: ntime, ntimerange, nlevel, nvar
1281TYPE(gridinfo_def) :: gridinfol
1282
1283#ifdef DEBUG
1284CALL l4f_category_log(this%category,l4f_debug,"start export_to_gridinfov")
1285#endif
1286
1287! this is necessary in order not to repeatedly and uselessly copy the
1288! same array of coordinates for each 2d grid during export, the
1289! side-effect is that the computed projection in this is lost
1290CALL dealloc(this%griddim%dim)
1291
1292i=0
1293ntime=size(this%time)
1294ntimerange=size(this%timerange)
1295nlevel=size(this%level)
1296nvar=size(this%var)
1297
1298DO itime=1,ntime
1299 DO itimerange=1,ntimerange
1300 DO ilevel=1,nlevel
1301 DO ivar=1,nvar
1302
1303 CALL init(gridinfol)
1304 CALL export(this, gridinfol, itime, itimerange, ilevel, ivar, &
1305 gaid_template=gaid_template, clone=clone)
1306 IF (c_e(gridinfol%gaid)) THEN
1307 CALL insert(gridinfov, gridinfol)
1308 ELSE
1309 CALL delete(gridinfol)
1310 ENDIF
1311
1312 ENDDO
1313 ENDDO
1314 ENDDO
1315ENDDO
1316
1317END SUBROUTINE export_to_gridinfov
1318
1319
1320!> Export an array of \a volgrid6d objects to an \a arrayof_gridinfo object.
1321!! The multidimensional \a volgrid6d structures are serialized into a
1322!! one-dimensional array of gridinfo_def objects, which is allocated
1323!! to the proper size if not already allocated, or it is extended
1324!! keeping the old data if any.
1325SUBROUTINE export_to_gridinfovv(this, gridinfov, gaid_template, clone)
1326!, &
1327! categoryappend)
1328TYPE(volgrid6d),INTENT(inout) :: this(:) !< volume array to be exported
1329TYPE(arrayof_gridinfo),INTENT(inout) :: gridinfov !< output array of gridinfo_def objects
1330TYPE(grid_id),INTENT(in),OPTIONAL :: gaid_template !< \a grid_id template to be used for output data replacing the one contained in \a this
1331LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \c .TRUE., clone the grid_id included in \a this rather than making a shallow copy
1332
1333INTEGER :: i
1334
1335DO i = 1, SIZE(this)
1336#ifdef DEBUG
1337 CALL l4f_category_log(this(i)%category,l4f_debug, &
1338 "export_to_gridinfovv grid index: "//t2c(i))
1339#endif
1340 CALL export(this(i), gridinfov, gaid_template=gaid_template, clone=clone)
1341ENDDO
1342
1343END SUBROUTINE export_to_gridinfovv
1344
1345
1346!> Import the content of a supported file (like grib or gdal-supported
1347!! format) into an array of \a volgrid6d objects. This method imports
1348!! a set of gridded fields from a file object into a suitable number
1349!! of \a volgrid6d objects. The data are imported by creating a
1350!! temporary \a gridinfo object, importing it into the \a volgrid6d
1351!! object cloning the gaid's and then destroying the gridinfo, so it
1352!! works similarly to volgrid6d_class::import_from_gridinfovv() method.
1353!! For a detailed explanation of the \a anavar argument, see the
1354!! documentation of volgrid6d_class::import_from_gridinfovv() method.
1355SUBROUTINE volgrid6d_import_from_file(this, filename, dup_mode, decode, &
1356 time_definition, anavar, categoryappend)
1357TYPE(volgrid6d),POINTER :: this(:) !< object in which to import
1358CHARACTER(len=*),INTENT(in) :: filename !< name of file from which to import
1359INTEGER,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
1360LOGICAL,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
1361INTEGER,INTENT(IN),OPTIONAL :: time_definition !< 0=time is reference time; 1=time is validity time
1362CHARACTER(len=*),INTENT(IN),OPTIONAL :: anavar(:) !< list of variables (B-table code equivalent) to be treated as time-independent data
1363character(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
1364
1365TYPE(arrayof_gridinfo) :: gridinfo
1366TYPE(l4f_handle) :: category
1367CHARACTER(len=512) :: a_name
1368
1369NULLIFY(this)
1370
1371IF (PRESENT(categoryappend))THEN
1372 CALL l4f_launcher(a_name,a_name_append= &
1373 trim(subcategory)//"."//trim(categoryappend))
1374ELSE
1375 CALL l4f_launcher(a_name,a_name_append=trim(subcategory))
1376ENDIF
1377category=l4f_category_get_handle(a_name)
1378
1379CALL import(gridinfo, filename=filename, categoryappend=categoryappend)
1380
1381IF (gridinfo%arraysize > 0) THEN
1382
1383 CALL import(this, gridinfo, dup_mode=dup_mode, clone=.true., decode=decode, &
1384 time_definition=time_definition, anavar=anavar, &
1385 categoryappend=categoryappend)
1386
1387 CALL l4f_category_log(category,l4f_info,"deleting gridinfo")
1388 CALL delete(gridinfo)
1389
1390ELSE
1391 CALL l4f_category_log(category,l4f_info,"file does not contain gridded data")
1392ENDIF
1393
1394! close logger
1395CALL l4f_category_delete(category)
1396
1397END SUBROUTINE volgrid6d_import_from_file
1398
1399
1400!> High level method for exporting a volume array to file.
1401!! All the information contained into an array of \a volgrid6d
1402!! objects, i.e. dimension descriptors and data, is exported to a file
1403!! using the proper output driver (typically grib_api for grib
1404!! format). If a template is provided, it will determine the
1405!! characteristic of the output file, otherwise the \a grid_id
1406!! descriptors contained in the volgrid6d object will be used
1407SUBROUTINE volgrid6d_export_to_file(this, filename, gaid_template, categoryappend)
1408TYPE(volgrid6d) :: this(:) !< volume(s) to be exported
1409CHARACTER(len=*),INTENT(in) :: filename !< output file name
1410TYPE(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
1411character(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
1412
1413TYPE(arrayof_gridinfo) :: gridinfo
1414TYPE(l4f_handle) :: category
1415CHARACTER(len=512) :: a_name
1416
1417IF (PRESENT(categoryappend)) THEN
1418 CALL l4f_launcher(a_name,a_name_append=trim(subcategory)//"."//trim(categoryappend))
1419ELSE
1420 CALL l4f_launcher(a_name,a_name_append=trim(subcategory))
1421ENDIF
1422category=l4f_category_get_handle(a_name)
1423
1424#ifdef DEBUG
1425CALL l4f_category_log(category,l4f_debug,"start export to file")
1426#endif
1427
1428CALL l4f_category_log(category,l4f_info,"writing volgrid6d to grib file: "//trim(filename))
1429
1430!IF (ASSOCIATED(this)) THEN
1431 CALL export(this, gridinfo, gaid_template=gaid_template, clone=.true.)
1432 IF (gridinfo%arraysize > 0) THEN
1433 CALL export(gridinfo, filename)
1434 CALL delete(gridinfo)
1435 ENDIF
1436!ELSE
1437! CALL l4f_category_log(category,L4F_INFO,"volume volgrid6d is not associated")
1438!ENDIF
1439
1440! close logger
1441CALL l4f_category_delete(category)
1442
1443END SUBROUTINE volgrid6d_export_to_file
1444
1445
1446!> Array destructor for \a volgrid6d class.
1447!! Delete an array of \a volgrid6d objects and deallocate the array
1448!! itself.
1449SUBROUTINE volgrid6dv_delete(this)
1450TYPE(volgrid6d),POINTER :: this(:) !< vector of volgrid6d object
1451
1452INTEGER :: i
1453
1454IF (ASSOCIATED(this)) THEN
1455 DO i = 1, SIZE(this)
1456#ifdef DEBUG
1457 CALL l4f_category_log(this(i)%category,l4f_debug, &
1458 "delete volgrid6d vector index: "//trim(to_char(i)))
1459#endif
1460 CALL delete(this(i))
1461 ENDDO
1462 DEALLOCATE(this)
1463ENDIF
1464
1465END SUBROUTINE volgrid6dv_delete
1466
1467
1468! Internal method for performing grid to grid computations
1469SUBROUTINE volgrid6d_transform_compute(this, volgrid6d_in, volgrid6d_out, &
1470 lev_out, var_coord_vol, clone)
1471TYPE(grid_transform),INTENT(in) :: this ! oggetto di trasformazione per il grigliato
1472type(volgrid6d), INTENT(in) :: volgrid6d_in ! oggetto da trasformare
1473type(volgrid6d), INTENT(inout) :: volgrid6d_out ! oggetto trasformato; deve essere completo (init, alloc, alloc_vol)
1474TYPE(vol7d_level),INTENT(in),OPTIONAL :: lev_out(:) ! vol7d_level object defining target vertical grid, for vertical interpolations
1475INTEGER,INTENT(in),OPTIONAL :: var_coord_vol ! index of variable defining vertical coordinate values in input volume
1476LOGICAL,INTENT(in),OPTIONAL :: clone ! se fornito e \c .TRUE., clona i gaid da volgrid6d_in a volgrid6d_out
1477
1478INTEGER :: ntime, ntimerange, inlevel, onlevel, nvar, &
1479 itime, itimerange, ilevel, ivar, levshift, levused, lvar_coord_vol, spos
1480REAL,POINTER :: voldatiin(:,:,:), voldatiout(:,:,:), coord_3d_in(:,:,:)
1481TYPE(vol7d_level) :: output_levtype
1482LOGICAL,ALLOCATABLE :: zlist(:)
1483
1484
1485#ifdef DEBUG
1486call l4f_category_log(volgrid6d_in%category,l4f_debug,"start volgrid6d_transform_compute")
1487#endif
1488
1489ntime=0
1490ntimerange=0
1491inlevel=0
1492onlevel=0
1493nvar=0
1494lvar_coord_vol = optio_i(var_coord_vol)
1495
1496if (associated(volgrid6d_in%time))then
1497 ntime=size(volgrid6d_in%time)
1498 volgrid6d_out%time=volgrid6d_in%time
1499end if
1500
1501if (associated(volgrid6d_in%timerange))then
1502 ntimerange=size(volgrid6d_in%timerange)
1503 volgrid6d_out%timerange=volgrid6d_in%timerange
1504end if
1505
1506IF (ASSOCIATED(volgrid6d_in%level))THEN
1507 inlevel=SIZE(volgrid6d_in%level)
1508ENDIF
1509IF (PRESENT(lev_out)) THEN
1510 onlevel=SIZE(lev_out)
1511 volgrid6d_out%level=lev_out
1512ELSE IF (ASSOCIATED(volgrid6d_in%level))THEN
1513 onlevel=SIZE(volgrid6d_in%level)
1514 volgrid6d_out%level=volgrid6d_in%level
1515ENDIF
1516
1517if (associated(volgrid6d_in%var))then
1518 nvar=size(volgrid6d_in%var)
1519 volgrid6d_out%var=volgrid6d_in%var
1520end if
1521! allocate once for speed
1522IF (.NOT.ASSOCIATED(volgrid6d_in%voldati)) THEN
1523 ALLOCATE(voldatiin(volgrid6d_in%griddim%dim%nx, volgrid6d_in%griddim%dim%ny, &
1524 inlevel))
1525ENDIF
1526IF (.NOT.ASSOCIATED(volgrid6d_out%voldati)) THEN
1527 ALLOCATE(voldatiout(volgrid6d_out%griddim%dim%nx, volgrid6d_out%griddim%dim%ny, &
1528 onlevel))
1529ENDIF
1530
1531CALL get_val(this, levshift=levshift, levused=levused)
1532spos = imiss
1533IF (c_e(lvar_coord_vol)) THEN
1534 CALL get_val(this%trans, output_levtype=output_levtype)
1535 IF (output_levtype%level1 == 103 .OR. output_levtype%level1 == 108) THEN
1536! here, unlike below, level (1,101) is not accepted because this is
1537! likely for pressure difference with surface 108, not 103
1538 spos = firsttrue(volgrid6d_in%level(:) == vol7d_level_new(1))
1539 IF (spos == 0) THEN
1540 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1541 'output level '//t2c(output_levtype%level1)// &
1542 ' requested, but height/press of surface not provided in volume')
1543 ENDIF
1544 IF (.NOT.c_e(levshift) .AND. .NOT.c_e(levused)) THEN
1545 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1546 'internal inconsistence, levshift and levused undefined when they should be')
1547 ENDIF
1548 ENDIF
1549ENDIF
1550
1551DO ivar=1,nvar
1552! IF (c_e(var_coord_vol)) THEN
1553! IF (ivar == var_coord_vol) CYCLE ! skip coordinate variable in output
1554! ENDIF
1555 DO itimerange=1,ntimerange
1556 DO itime=1,ntime
1557! skip empty columns where possible, improve
1558 IF (c_e(levshift) .AND. c_e(levused)) THEN
1559 IF (.NOT.any(c_e( &
1560 volgrid6d_in%gaid(levshift+1:levshift+levused,itime,itimerange,ivar) &
1561 ))) cycle
1562 ENDIF
1563 DO ilevel = 1, min(inlevel,onlevel)
1564! if present gaid copy it
1565 IF (c_e(volgrid6d_in%gaid(ilevel,itime,itimerange,ivar)) .AND. .NOT. &
1566 c_e(volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))) THEN
1567
1568 IF (optio_log(clone)) THEN
1569 CALL copy(volgrid6d_in%gaid(ilevel,itime,itimerange,ivar),&
1570 volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))
1571#ifdef DEBUG
1572 CALL l4f_category_log(volgrid6d_in%category,l4f_debug, &
1573 "cloning gaid, level "//t2c(ilevel))
1574#endif
1575 ELSE
1576 volgrid6d_out%gaid(ilevel,itime,itimerange,ivar) = &
1577 volgrid6d_in%gaid(ilevel,itime,itimerange,ivar)
1578 ENDIF
1579 ENDIF
1580 ENDDO
1581! if out level are more, we have to clone anyway
1582 DO ilevel = min(inlevel,onlevel) + 1, onlevel
1583 IF (c_e(volgrid6d_in%gaid(inlevel,itime,itimerange,ivar)) .AND. .NOT. &
1584 c_e(volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))) then
1585
1586 CALL copy(volgrid6d_in%gaid(inlevel,itime,itimerange,ivar),&
1587 volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))
1588#ifdef DEBUG
1589 CALL l4f_category_log(volgrid6d_in%category,l4f_debug, &
1590 "forced cloning gaid, level "//t2c(inlevel)//"->"//t2c(ilevel))
1591#endif
1592 ENDIF
1593 ENDDO
1594
1595 IF (c_e(lvar_coord_vol)) THEN
1596 NULLIFY(coord_3d_in)
1597 CALL volgrid_get_vol_3d(volgrid6d_in, itime, itimerange, lvar_coord_vol, &
1598 coord_3d_in)
1599 IF (c_e(spos)) THEN ! compute difference wrt surface coordinate
1600 IF (spos == 0) THEN ! error condition, set all to missing and goodnight
1601 coord_3d_in(:,:,levshift+1:levshift+levused) = rmiss
1602 ELSE
1603 DO ilevel = levshift+1, levshift+levused
1604 WHERE(c_e(coord_3d_in(:,:,ilevel)) .AND. c_e(coord_3d_in(:,:,spos)))
1605 coord_3d_in(:,:,ilevel) = coord_3d_in(:,:,ilevel) - &
1606 coord_3d_in(:,:,spos)
1607 ELSEWHERE
1608 coord_3d_in(:,:,ilevel) = rmiss
1609 END WHERE
1610 ENDDO
1611 ENDIF
1612 ENDIF
1613 ENDIF
1614 CALL volgrid_get_vol_3d(volgrid6d_in, itime, itimerange, ivar, &
1615 voldatiin, zlist)
1616 IF (ASSOCIATED(volgrid6d_out%voldati)) & ! improve!!!!
1617 CALL volgrid_get_vol_3d(volgrid6d_out, itime, itimerange, ivar, &
1618 voldatiout)
1619 IF (c_e(lvar_coord_vol)) THEN ! this is a vertint case, zlist is useless
1620 CALL compute(this, voldatiin, voldatiout, var=convert(volgrid6d_in%var(ivar)), &
1621 coord_3d_in=coord_3d_in(:,:,levshift+1:levshift+levused)) ! subset coord_3d_in
1622 ELSE
1623 CALL compute(this, voldatiin, voldatiout, var=convert(volgrid6d_in%var(ivar)), zlist=zlist)
1624 ENDIF
1625 CALL volgrid_set_vol_3d(volgrid6d_out, itime, itimerange, ivar, &
1626 voldatiout)
1627 ENDDO
1628 ENDDO
1629ENDDO
1630
1631IF (c_e(lvar_coord_vol)) THEN
1632 DEALLOCATE(coord_3d_in)
1633ENDIF
1634IF (.NOT.ASSOCIATED(volgrid6d_in%voldati)) THEN
1635 DEALLOCATE(voldatiin)
1636ENDIF
1637IF (.NOT.ASSOCIATED(volgrid6d_out%voldati)) THEN
1638 DEALLOCATE(voldatiout)
1639ENDIF
1640
1641
1642END SUBROUTINE volgrid6d_transform_compute
1643
1644
1645!> Performs the specified abstract transformation on the data provided.
1646!! The abstract transformation is specified by \a this parameter; the
1647!! corresponding specifical transformation (\a grid_transform object)
1648!! is created and destroyed internally. The output transformed object
1649!! is created internally and it does not require preliminary
1650!! initialisation.
1651SUBROUTINE volgrid6d_transform(this, griddim, volgrid6d_in, volgrid6d_out, &
1652 lev_out, volgrid6d_coord_in, maskgrid, maskbounds, clone, decode, categoryappend)
1653TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
1654TYPE(griddim_def),INTENT(in),OPTIONAL :: griddim !< griddim specifying the output grid (required by most transformation types)
1655TYPE(volgrid6d),INTENT(inout) :: volgrid6d_in !< object to be transformed, it is not modified, despite the INTENT(inout)
1656TYPE(volgrid6d),INTENT(out) :: volgrid6d_out !< transformed object, it does not require initialisation
1657TYPE(vol7d_level),INTENT(in),OPTIONAL,TARGET :: lev_out(:) !< vol7d_level object defining target vertical grid, for vertical interpolations
1658TYPE(volgrid6d),INTENT(in),OPTIONAL :: volgrid6d_coord_in !< object providing time constant input vertical coordinate for some kind of vertical interpolations
1659REAL,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')
1660REAL,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')
1661LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \a .TRUE. , clone the \a gaid's from \a volgrid6d_in to \a volgrid6d_out
1662LOGICAL,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
1663CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
1664
1665TYPE(grid_transform) :: grid_trans
1666TYPE(vol7d_level),POINTER :: llev_out(:)
1667TYPE(vol7d_level) :: input_levtype, output_levtype
1668TYPE(vol7d_var) :: vcoord_var
1669INTEGER :: i, k, ntime, ntimerange, nlevel, nvar, var_coord_in, var_coord_vol, &
1670 cf_out, nxc, nyc, nxi, nyi, i3, i4, i5, i6, &
1671 ulstart, ulend, spos
1672REAL,ALLOCATABLE :: coord_3d_in(:,:,:)
1673TYPE(geo_proj) :: proj_in, proj_out
1674CHARACTER(len=80) :: trans_type
1675LOGICAL :: ldecode
1676LOGICAL,ALLOCATABLE :: mask_in(:)
1677
1678#ifdef DEBUG
1679call l4f_category_log(volgrid6d_in%category, l4f_debug, "start volgrid6d_transform")
1680#endif
1681
1682ntime=0
1683ntimerange=0
1684nlevel=0
1685nvar=0
1686
1687if (associated(volgrid6d_in%time)) ntime=size(volgrid6d_in%time)
1688if (associated(volgrid6d_in%timerange)) ntimerange=size(volgrid6d_in%timerange)
1689if (associated(volgrid6d_in%level)) nlevel=size(volgrid6d_in%level)
1690if (associated(volgrid6d_in%var)) nvar=size(volgrid6d_in%var)
1691
1692IF (ntime == 0 .OR. ntimerange == 0 .OR. nlevel == 0 .OR. nvar == 0) THEN
1693 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1694 "trying to transform an incomplete volgrid6d object, ntime="//t2c(ntime)// &
1695 ' ntimerange='//t2c(ntimerange)//' nlevel='//t2c(nlevel)//' nvar='//t2c(nvar))
1696 CALL init(volgrid6d_out) ! initialize to empty
1697 CALL raise_error()
1698 RETURN
1699ENDIF
1700
1701CALL get_val(this, trans_type=trans_type)
1702
1703! store desired output component flag and unrotate if necessary
1704cf_out = imiss
1705IF (PRESENT(griddim) .AND. (trans_type == 'inter' .OR. trans_type == 'boxinter' &
1706 .OR. trans_type == 'stencilinter')) THEN ! improve condition!!
1707 CALL get_val(volgrid6d_in%griddim, proj=proj_in)
1708 CALL get_val(griddim, component_flag=cf_out, proj=proj_out)
1709! if different projections wind components must be referred to geographical system
1710 IF (proj_in /= proj_out) CALL vg6d_wind_unrot(volgrid6d_in)
1711ELSE IF (PRESENT(griddim)) THEN ! just get component_flag, the rest is rubbish
1712 CALL get_val(griddim, component_flag=cf_out)
1713ENDIF
1714
1715
1716var_coord_in = imiss
1717var_coord_vol = imiss
1718IF (trans_type == 'vertint') THEN
1719 IF (PRESENT(lev_out)) THEN
1720
1721! if volgrid6d_coord_in provided and allocated, check that it fits
1722 IF (PRESENT(volgrid6d_coord_in)) THEN
1723 IF (ASSOCIATED(volgrid6d_coord_in%voldati)) THEN
1724
1725! strictly 1 time and 1 timerange
1726 IF (SIZE(volgrid6d_coord_in%voldati,4) /= 1 .OR. &
1727 SIZE(volgrid6d_coord_in%voldati,5) /= 1) THEN
1728 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1729 'volume providing constant input vertical coordinate must have &
1730 &only 1 time and 1 timerange')
1731 CALL init(volgrid6d_out) ! initialize to empty
1732 CALL raise_error()
1733 RETURN
1734 ENDIF
1735
1736! search for variable providing vertical coordinate
1737 CALL get_val(this, output_levtype=output_levtype)
1738 vcoord_var = vol7d_var_new(vol7d_level_to_var(output_levtype))
1739 IF (.NOT.c_e(vcoord_var)) THEN
1740 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1741 'requested output level type '//t2c(output_levtype%level1)// &
1742 ' does not correspond to any known physical variable for &
1743 &providing vertical coordinate')
1744 CALL init(volgrid6d_out) ! initialize to empty
1745 CALL raise_error()
1746 RETURN
1747 ENDIF
1748
1749 DO i = 1, SIZE(volgrid6d_coord_in%var)
1750 IF (convert(volgrid6d_coord_in%var(i)) == vcoord_var) THEN
1751 var_coord_in = i
1752 EXIT
1753 ENDIF
1754 ENDDO
1755
1756 IF (.NOT.c_e(var_coord_in)) THEN
1757 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1758 'volume providing constant input vertical coordinate contains no &
1759 &variables matching output level type '//t2c(output_levtype%level1))
1760 CALL init(volgrid6d_out) ! initialize to empty
1761 CALL raise_error()
1762 RETURN
1763 ENDIF
1764 CALL l4f_category_log(volgrid6d_in%category, l4f_info, &
1765 'Coordinate for vertint found in coord volume at position '// &
1766 t2c(var_coord_in))
1767
1768! check horizontal grid
1769! this is too strict (component flag and so on)
1770! IF (volgrid6d_coord_in%griddim /= volgrid6d_in%griddim) THEN
1771 CALL get_val(volgrid6d_coord_in%griddim, nx=nxc, ny=nyc)
1772 CALL get_val(volgrid6d_in%griddim, nx=nxi, ny=nyi)
1773 IF (nxc /= nxi .OR. nyc /= nyi) THEN
1774 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1775 'volume providing constant input vertical coordinate must have &
1776 &the same grid as the input')
1777 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1778 'vertical coordinate: '//t2c(nxc)//'x'//t2c(nyc)// &
1779 ', input volume: '//t2c(nxi)//'x'//t2c(nyi))
1780 CALL init(volgrid6d_out) ! initialize to empty
1781 CALL raise_error()
1782 RETURN
1783 ENDIF
1784
1785! check vertical coordinate system
1786 CALL get_val(this, input_levtype=input_levtype)
1787 mask_in = & ! implicit allocation
1788 (volgrid6d_coord_in%level(:)%level1 == input_levtype%level1) .AND. &
1789 (volgrid6d_coord_in%level(:)%level2 == input_levtype%level2)
1790 ulstart = firsttrue(mask_in)
1791 ulend = lasttrue(mask_in)
1792 IF (ulstart == 0 .OR. ulend == 0) THEN
1793 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1794 'coordinate file does not contain levels of type '// &
1795 t2c(input_levtype%level1)//'/'//t2c(input_levtype%level2)// &
1796 ' specified for input data')
1797 CALL init(volgrid6d_out) ! initialize to empty
1798 CALL raise_error()
1799 RETURN
1800 ENDIF
1801
1802 coord_3d_in = volgrid6d_coord_in%voldati(:,:,ulstart:ulend,1,1,var_coord_in) ! implicit allocation
1803! special case
1804 IF (output_levtype%level1 == 103 .OR. &
1805 output_levtype%level1 == 108) THEN ! surface coordinate needed
1806! allow coding of orography level as in Icon
1807 spos = firsttrue(volgrid6d_coord_in%level(:) == vol7d_level_new(level1=1) .OR. &
1808 volgrid6d_coord_in%level(:) == vol7d_level_new(level1=1, level2=101))
1809 IF (spos == 0) THEN
1810 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1811 'output level '//t2c(output_levtype%level1)// &
1812 ' requested, but height/press of surface not provided in coordinate file')
1813 CALL init(volgrid6d_out) ! initialize to empty
1814 CALL raise_error()
1815 RETURN
1816 ENDIF
1817 DO k = 1, SIZE(coord_3d_in,3)
1818 WHERE(c_e(coord_3d_in(:,:,k)) .AND. &
1819 c_e(volgrid6d_coord_in%voldati(:,:,spos,1,1,var_coord_in)))
1820 coord_3d_in(:,:,k) = coord_3d_in(:,:,k) - &
1821 volgrid6d_coord_in%voldati(:,:,spos,1,1,var_coord_in)
1822 ELSEWHERE
1823 coord_3d_in(:,:,k) = rmiss
1824 END WHERE
1825 ENDDO
1826 ENDIF
1827
1828 ENDIF
1829 ENDIF
1830
1831 IF (.NOT.c_e(var_coord_in)) THEN ! search for coordinate within volume
1832! search for variable providing vertical coordinate
1833 CALL get_val(this, output_levtype=output_levtype)
1834 vcoord_var = vol7d_var_new(vol7d_level_to_var(output_levtype))
1835 IF (c_e(vcoord_var)) THEN
1836 DO i = 1, SIZE(volgrid6d_in%var)
1837 IF (convert(volgrid6d_in%var(i)) == vcoord_var) THEN
1838 var_coord_vol = i
1839 EXIT
1840 ENDIF
1841 ENDDO
1842
1843 IF (c_e(var_coord_vol)) THEN
1844 CALL l4f_category_log(volgrid6d_in%category, l4f_info, &
1845 'Coordinate for vertint found in input volume at position '// &
1846 t2c(var_coord_vol))
1847 ENDIF
1848
1849 ENDIF
1850 ENDIF
1851
1852 CALL init(volgrid6d_out, griddim=volgrid6d_in%griddim, &
1853 time_definition=volgrid6d_in%time_definition, categoryappend=categoryappend)
1854 IF (c_e(var_coord_in)) THEN
1855 CALL init(grid_trans, this, lev_in=volgrid6d_in%level, lev_out=lev_out, &
1856 coord_3d_in=coord_3d_in, categoryappend=categoryappend)
1857 ELSE
1858 CALL init(grid_trans, this, lev_in=volgrid6d_in%level, lev_out=lev_out, &
1859 categoryappend=categoryappend)
1860 ENDIF
1861
1862 CALL get_val(grid_trans, output_level_auto=llev_out) ! get levels if auto-generated
1863 IF (.NOT.ASSOCIATED(llev_out)) llev_out => lev_out
1864 nlevel = SIZE(llev_out)
1865 ELSE
1866 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1867 'volgrid6d_transform: vertint requested but lev_out not provided')
1868 CALL init(volgrid6d_out) ! initialize to empty
1869 CALL raise_error()
1870 RETURN
1871 ENDIF
1872
1873ELSE
1874 CALL init(volgrid6d_out, griddim=griddim, &
1875 time_definition=volgrid6d_in%time_definition, categoryappend=categoryappend)
1876 CALL init(grid_trans, this, in=volgrid6d_in%griddim, out=volgrid6d_out%griddim, &
1877 maskgrid=maskgrid, maskbounds=maskbounds, categoryappend=categoryappend)
1878ENDIF
1879
1880
1881IF (c_e(grid_trans)) THEN ! transformation is valid
1882
1883 CALL volgrid6d_alloc(volgrid6d_out, ntime=ntime, nlevel=nlevel, &
1884 ntimerange=ntimerange, nvar=nvar)
1885
1886 IF (PRESENT(decode)) THEN ! explicitly set decode status
1887 ldecode = decode
1888 ELSE ! take it from input
1889 ldecode = ASSOCIATED(volgrid6d_in%voldati)
1890 ENDIF
1891! force decode if gaid is readonly
1892 decode_loop: DO i6 = 1,nvar
1893 DO i5 = 1, ntimerange
1894 DO i4 = 1, ntime
1895 DO i3 = 1, nlevel
1896 IF (c_e(volgrid6d_in%gaid(i3,i4,i5,i6))) THEN
1897 ldecode = ldecode .OR. grid_id_readonly(volgrid6d_in%gaid(i3,i4,i5,i6))
1898 EXIT decode_loop
1899 ENDIF
1900 ENDDO
1901 ENDDO
1902 ENDDO
1903 ENDDO decode_loop
1904
1905 IF (PRESENT(decode)) THEN
1906 IF (ldecode.NEQV.decode) THEN
1907 CALL l4f_category_log(volgrid6d_in%category, l4f_warn, &
1908 'volgrid6d_transform: decode status forced to .TRUE. because driver does not allow copy')
1909 ENDIF
1910 ENDIF
1911
1912 CALL volgrid6d_alloc_vol(volgrid6d_out, decode=ldecode)
1913
1914!ensure unproj was called
1915!call griddim_unproj(volgrid6d_out%griddim)
1916
1917 IF (trans_type == 'vertint') THEN
1918#ifdef DEBUG
1919 CALL l4f_category_log(volgrid6d_in%category, l4f_debug, &
1920 "volgrid6d_transform: vertint to "//t2c(nlevel)//" levels")
1921#endif
1922 CALL compute(grid_trans, volgrid6d_in, volgrid6d_out, lev_out=llev_out, &
1923 var_coord_vol=var_coord_vol, clone=clone)
1924 ELSE
1925 CALL compute(grid_trans, volgrid6d_in, volgrid6d_out, clone=clone)
1926 ENDIF
1927
1928 IF (cf_out == 0) THEN ! unrotated components are desired
1929 CALL wind_unrot(volgrid6d_out) ! unrotate if necessary
1930 ELSE IF (cf_out == 1) THEN ! rotated components are desired
1931 CALL wind_rot(volgrid6d_out) ! rotate if necessary
1932 ENDIF
1933
1934ELSE
1935! should log with grid_trans%category, but it is private
1936 CALL l4f_category_log(volgrid6d_in%category, l4f_error, &
1937 'volgrid6d_transform: transformation not valid')
1938 CALL raise_error()
1939ENDIF
1940
1941CALL delete (grid_trans)
1942
1943END SUBROUTINE volgrid6d_transform
1944
1945
1946!> Performs the specified abstract transformation on the arrays of
1947!! data provided. The abstract transformation is specified by \a this
1948!! parameter; the corresponding specifical transformation (\a
1949!! grid_transform object) is created and destroyed internally. The
1950!! output transformed object is created internally and it does not
1951!! require preliminary initialisation. According to the input data and
1952!! to the transformation type, the output array may have of one or
1953!! more \a volgrid6d elements on different grids.
1954SUBROUTINE volgrid6dv_transform(this, griddim, volgrid6d_in, volgrid6d_out, &
1955 lev_out, volgrid6d_coord_in, maskgrid, maskbounds, clone, decode, categoryappend)
1956TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
1957TYPE(griddim_def),INTENT(in),OPTIONAL :: griddim !< griddim specifying the output grid (required by most transformation types)
1958TYPE(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)
1959TYPE(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
1960TYPE(vol7d_level),INTENT(in),OPTIONAL :: lev_out(:) !< vol7d_level object defining target vertical grid
1961TYPE(volgrid6d),INTENT(in),OPTIONAL :: volgrid6d_coord_in !< object providing time constant input vertical coordinate for some kind of vertical interpolations
1962REAL,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')
1963REAL,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')
1964LOGICAL,INTENT(in),OPTIONAL :: clone !< if provided and \a .TRUE. , clone the \a gaid's from \a volgrid6d_in to \a volgrid6d_out
1965LOGICAL,INTENT(in),OPTIONAL :: decode !< if provided and \a .FALSE. the data volume is not allocated, but work is performed on grid_id's
1966CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
1967
1968INTEGER :: i, stallo
1969
1970
1971allocate(volgrid6d_out(size(volgrid6d_in)),stat=stallo)
1972if (stallo /= 0)then
1973 call l4f_log(l4f_fatal,"allocating memory")
1974 call raise_fatal_error()
1975end if
1976
1977do i=1,size(volgrid6d_in)
1978 call transform(this, griddim, volgrid6d_in(i), volgrid6d_out(i), &
1979 lev_out=lev_out, volgrid6d_coord_in=volgrid6d_coord_in, &
1980 maskgrid=maskgrid, maskbounds=maskbounds, &
1981 clone=clone, decode=decode, categoryappend=categoryappend)
1982end do
1983
1984END SUBROUTINE volgrid6dv_transform
1985
1986
1987! Internal method for performing grid to sparse point computations
1988SUBROUTINE volgrid6d_v7d_transform_compute(this, volgrid6d_in, vol7d_out, &
1989 networkname, noconvert)
1990TYPE(grid_transform),INTENT(in) :: this ! oggetto di trasformazione per grigliato
1991type(volgrid6d), INTENT(in) :: volgrid6d_in ! oggetto da trasformare
1992type(vol7d), INTENT(inout) :: vol7d_out ! oggetto trasformato
1993CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname ! imposta il network in vol7d_out (default='generic')
1994LOGICAL,OPTIONAL,INTENT(in) :: noconvert !< do not try to match variable and convert values during transform
1995
1996INTEGER :: nntime, nana, ntime, ntimerange, nlevel, nvar, stallo
1997INTEGER :: itime, itimerange, ivar, inetwork
1998REAL,ALLOCATABLE :: voldatir_out(:,:,:)
1999TYPE(conv_func),POINTER :: c_func(:)
2000TYPE(datetime),ALLOCATABLE :: validitytime(:,:)
2001REAL,POINTER :: voldatiin(:,:,:)
2002
2003#ifdef DEBUG
2004call l4f_category_log(volgrid6d_in%category,l4f_debug,"start volgrid6d_v7d_transform_compute")
2005#endif
2006
2007ntime=0
2008ntimerange=0
2009nlevel=0
2010nvar=0
2011NULLIFY(c_func)
2012
2013if (present(networkname))then
2014 call init(vol7d_out%network(1),name=networkname)
2015else
2016 call init(vol7d_out%network(1),name='generic')
2017end if
2018
2019if (associated(volgrid6d_in%timerange))then
2020 ntimerange=size(volgrid6d_in%timerange)
2021 vol7d_out%timerange=volgrid6d_in%timerange
2022end if
2023
2024if (associated(volgrid6d_in%time))then
2025 ntime=size(volgrid6d_in%time)
2026
2027 if (vol7d_out%time_definition == volgrid6d_in%time_definition) then
2028
2029 ! i time sono definiti uguali: assegno
2030 vol7d_out%time=volgrid6d_in%time
2031
2032 else
2033 ! converto reference in validity
2034 allocate (validitytime(ntime,ntimerange),stat=stallo)
2035 if (stallo /=0)then
2036 call l4f_category_log(volgrid6d_in%category,l4f_fatal,"allocating memory")
2037 call raise_fatal_error()
2038 end if
2039
2040 do itime=1,ntime
2041 do itimerange=1,ntimerange
2042 if (vol7d_out%time_definition > volgrid6d_in%time_definition) then
2043 validitytime(itime,itimerange) = &
2044 volgrid6d_in%time(itime) + timedelta_new(sec=volgrid6d_in%timerange(itimerange)%p1)
2045 else
2046 validitytime(itime,itimerange) = &
2047 volgrid6d_in%time(itime) - timedelta_new(sec=volgrid6d_in%timerange(itimerange)%p1)
2048 end if
2049 end do
2050 end do
2051
2052 nntime = count_distinct(reshape(validitytime,(/ntime*ntimerange/)), back=.true.)
2053 vol7d_out%time=pack_distinct(reshape(validitytime,(/ntime*ntimerange/)), nntime,back=.true.)
2054
2055 end if
2056end if
2057
2058IF (ASSOCIATED(volgrid6d_in%level)) THEN
2059 nlevel = SIZE(volgrid6d_in%level)
2060 vol7d_out%level=volgrid6d_in%level
2061ENDIF
2062
2063IF (ASSOCIATED(volgrid6d_in%var)) THEN
2064 nvar = SIZE(volgrid6d_in%var)
2065 IF (.NOT. optio_log(noconvert)) THEN
2066 CALL vargrib2varbufr(volgrid6d_in%var, vol7d_out%dativar%r, c_func)
2067 ENDIF
2068ENDIF
2069
2070nana = SIZE(vol7d_out%ana)
2071
2072! allocate once for speed
2073IF (.NOT.ASSOCIATED(volgrid6d_in%voldati)) THEN
2074 ALLOCATE(voldatiin(volgrid6d_in%griddim%dim%nx, volgrid6d_in%griddim%dim%ny, &
2075 nlevel))
2076ENDIF
2077
2078ALLOCATE(voldatir_out(nana,1,nlevel),stat=stallo)
2079IF (stallo /= 0) THEN
2080 CALL l4f_category_log(volgrid6d_in%category,l4f_fatal,"allocating memory")
2081 CALL raise_fatal_error()
2082ENDIF
2083
2084inetwork=1
2085do itime=1,ntime
2086 do itimerange=1,ntimerange
2087! do ilevel=1,nlevel
2088 do ivar=1,nvar
2089
2090 !non è chiaro se questa sezione è utile o no
2091 !ossia il compute sotto sembra prevedere voldatir_out solo in out
2092!!$ if (vol7d_out%time_definition == volgrid6d_in%time_definition) then
2093!!$ voldatir_out=reshape(vol7d_out%voldatir(:,itime,ilevel,itimerange,ivar,inetwork),(/nana,1/))
2094!!$ else
2095!!$ voldatir_out=reshape(vol7d_out%voldatir(:,index(vol7d_out%time,validitytime(itime,ilevel)),ilevel,itimerange,ivar,inetwork),(/nana,1/))
2096!!$ end if
2097
2098 CALL volgrid_get_vol_3d(volgrid6d_in, itime, itimerange, ivar, &
2099 voldatiin)
2100
2101 CALL compute(this, voldatiin, voldatir_out, vol7d_out%dativar%r(ivar))
2102
2103 if (vol7d_out%time_definition == volgrid6d_in%time_definition) then
2104 vol7d_out%voldatir(:,itime,:,itimerange,ivar,inetwork) = &
2105 voldatir_out(:,1,:)
2106 else
2107 vol7d_out%voldatir(:,index(vol7d_out%time,validitytime(itime,itimerange)),:,itimerange,ivar,inetwork)=&
2108 reshape(voldatir_out,(/nana,nlevel/))
2109 end if
2110
2111! 1 indice della dimensione "anagrafica"
2112! 2 indice della dimensione "tempo"
2113! 3 indice della dimensione "livello verticale"
2114! 4 indice della dimensione "intervallo temporale"
2115! 5 indice della dimensione "variabile"
2116! 6 indice della dimensione "rete"
2117
2118 end do
2119! end do
2120 end do
2121end do
2122
2123deallocate(voldatir_out)
2124IF (.NOT.ASSOCIATED(volgrid6d_in%voldati)) THEN
2125 DEALLOCATE(voldatiin)
2126ENDIF
2127if (allocated(validitytime)) deallocate(validitytime)
2128
2129! Rescale valid data according to variable conversion table
2130IF (ASSOCIATED(c_func)) THEN
2131 DO ivar = 1, nvar
2132 CALL compute(c_func(ivar), vol7d_out%voldatir(:,:,:,:,ivar,:))
2133 ENDDO
2134 DEALLOCATE(c_func)
2135ENDIF
2136
2137end SUBROUTINE volgrid6d_v7d_transform_compute
2138
2139
2140!> Performs the specified abstract transformation on the data provided.
2141!! The abstract transformation is specified by \a this parameter; the
2142!! corresponding specifical transformation (\a grid_transform object)
2143!! is created and destroyed internally. The output transformed object
2144!! is created internally and it does not require preliminary
2145!! initialisation.
2146SUBROUTINE volgrid6d_v7d_transform(this, volgrid6d_in, vol7d_out, v7d, &
2147 maskgrid, maskbounds, networkname, noconvert, find_index, categoryappend)
2148TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
2149TYPE(volgrid6d),INTENT(inout) :: volgrid6d_in !< object to be transformed, it is not modified, despite the INTENT(inout)
2150TYPE(vol7d),INTENT(out) :: vol7d_out !< transformed object, it does not requires initialisation
2151TYPE(vol7d),INTENT(in),OPTIONAL :: v7d !< object containing a list of points over which transformation has to be done (required by some transformation types)
2152REAL,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')
2153REAL,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
2154CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname !< set the output network name in vol7d_out (default='generic')
2155LOGICAL,OPTIONAL,INTENT(in) :: noconvert !< do not try to match variable and convert values during transform
2156PROCEDURE(basic_find_index),POINTER,OPTIONAL :: find_index
2157CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
2158
2159type(grid_transform) :: grid_trans
2160INTEGER :: ntime, ntimerange, nlevel, nvar, nana, time_definition, nnetwork, stallo
2161INTEGER :: itime, itimerange, inetwork
2162TYPE(datetime),ALLOCATABLE :: validitytime(:,:)
2163INTEGER,ALLOCATABLE :: point_index(:)
2164TYPE(vol7d) :: v7d_locana
2165
2166#ifdef DEBUG
2167call l4f_category_log(volgrid6d_in%category,l4f_debug,"start volgrid6d_v7d_transform")
2168#endif
2169
2170call vg6d_wind_unrot(volgrid6d_in)
2171
2172ntime=0
2173ntimerange=0
2174nlevel=0
2175nvar=0
2176nnetwork=1
2177
2178call get_val(this,time_definition=time_definition)
2179if (.not. c_e(time_definition)) then
2180 time_definition=1 ! default to validity time
2181endif
2182
2183IF (PRESENT(v7d)) THEN
2184 CALL vol7d_copy(v7d, v7d_locana)
2185ELSE
2186 CALL init(v7d_locana)
2187ENDIF
2188
2189if (associated(volgrid6d_in%timerange)) ntimerange=size(volgrid6d_in%timerange)
2190
2191if (associated(volgrid6d_in%time)) then
2192
2193 ntime=size(volgrid6d_in%time)
2194
2195 if (time_definition /= volgrid6d_in%time_definition) then
2196
2197 ! converto reference in validity
2198 allocate (validitytime(ntime,ntimerange),stat=stallo)
2199 if (stallo /=0)then
2200 call l4f_category_log(volgrid6d_in%category,l4f_fatal,"allocating memory")
2201 call raise_fatal_error()
2202 end if
2203
2204 do itime=1,ntime
2205 do itimerange=1,ntimerange
2206 if (time_definition > volgrid6d_in%time_definition) then
2207 validitytime(itime,itimerange) = &
2208 volgrid6d_in%time(itime) + timedelta_new(sec=volgrid6d_in%timerange(itimerange)%p1)
2209 else
2210 validitytime(itime,itimerange) = &
2211 volgrid6d_in%time(itime) - timedelta_new(sec=volgrid6d_in%timerange(itimerange)%p1)
2212 end if
2213 end do
2214 end do
2215
2216 ntime = count_distinct(reshape(validitytime,(/ntime*ntimerange/)), back=.true.)
2217 deallocate (validitytime)
2218
2219 end if
2220end if
2221
2222
2223if (associated(volgrid6d_in%level)) nlevel=size(volgrid6d_in%level)
2224if (associated(volgrid6d_in%var)) nvar=size(volgrid6d_in%var)
2225
2226CALL init(grid_trans, this, volgrid6d_in%griddim, v7d_locana, &
2227 maskgrid=maskgrid, maskbounds=maskbounds, find_index=find_index, &
2228 categoryappend=categoryappend)
2229CALL init (vol7d_out,time_definition=time_definition)
2230
2231IF (c_e(grid_trans)) THEN
2232
2233 nana=SIZE(v7d_locana%ana)
2234 CALL vol7d_alloc(vol7d_out, nana=nana, ntime=ntime, nlevel=nlevel, &
2235 ntimerange=ntimerange, ndativarr=nvar, nnetwork=nnetwork)
2236 vol7d_out%ana = v7d_locana%ana
2237
2238 CALL get_val(grid_trans, output_point_index=point_index)
2239 IF (ALLOCATED(point_index)) THEN
2240! check that size(point_index) == nana?
2241 CALL vol7d_alloc(vol7d_out, nanavari=1)
2242 CALL init(vol7d_out%anavar%i(1), 'B01192')
2243 ENDIF
2244
2245 CALL vol7d_alloc_vol(vol7d_out)
2246
2247 IF (ALLOCATED(point_index)) THEN
2248 DO inetwork = 1, nnetwork
2249 vol7d_out%volanai(:,1,inetwork) = point_index(:)
2250 ENDDO
2251 ENDIF
2252 CALL compute(grid_trans, volgrid6d_in, vol7d_out, networkname, noconvert)
2253ELSE
2254 CALL l4f_log(l4f_error, 'vg6d_v7d_transform: transformation not valid')
2255 CALL raise_error()
2256ENDIF
2257
2258CALL delete(grid_trans)
2259
2260#ifdef HAVE_DBALLE
2261! set variables to a conformal state
2262CALL vol7d_dballe_set_var_du(vol7d_out)
2263#endif
2264
2265CALL delete(v7d_locana)
2266
2267END SUBROUTINE volgrid6d_v7d_transform
2268
2269
2270!> Performs the specified abstract transformation on the arrays of
2271!! data provided. The abstract transformation is specified by \a this
2272!! parameter; the corresponding specifical transformation (\a
2273!! grid_transform object) is created and destroyed internally. The
2274!! output transformed object is created internally and it does not
2275!! require preliminary initialisation. The transformation performed on
2276!! each element of the input \a volgrid6d array object is merged into
2277!! a single \a vol7d output object.
2278SUBROUTINE volgrid6dv_v7d_transform(this, volgrid6d_in, vol7d_out, v7d, &
2279 maskgrid, maskbounds, networkname, noconvert, find_index, categoryappend)
2280TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
2281TYPE(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)
2282TYPE(vol7d),INTENT(out) :: vol7d_out !< transformed object, it does not require initialisation
2283TYPE(vol7d),INTENT(in),OPTIONAL :: v7d !< object containing a list of points over which transformation has to be done (required by some transformation types)
2284REAL,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')
2285REAL,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
2286CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname !< set the output network name in vol7d_out (default='generic')
2287LOGICAL,OPTIONAL,INTENT(in) :: noconvert !< do not try to match variable and convert values during transform
2288PROCEDURE(basic_find_index),POINTER,OPTIONAL :: find_index
2289CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
2290
2291integer :: i
2292TYPE(vol7d) :: v7dtmp
2293
2294
2295CALL init(v7dtmp)
2296CALL init(vol7d_out)
2297
2298DO i=1,SIZE(volgrid6d_in)
2299 CALL transform(this, volgrid6d_in(i), v7dtmp, v7d=v7d, &
2300 maskgrid=maskgrid, maskbounds=maskbounds, &
2301 networkname=networkname, noconvert=noconvert, find_index=find_index, &
2302 categoryappend=categoryappend)
2303 CALL vol7d_append(vol7d_out, v7dtmp)
2304ENDDO
2305
2306END SUBROUTINE volgrid6dv_v7d_transform
2307
2308
2309! Internal method for performing sparse point to grid computations
2310SUBROUTINE v7d_volgrid6d_transform_compute(this, vol7d_in, volgrid6d_out, networkname, gaid_template)
2311TYPE(grid_transform),INTENT(in) :: this ! object specifying the specific transformation
2312type(vol7d), INTENT(in) :: vol7d_in ! object to be transformed
2313type(volgrid6d), INTENT(inout) :: volgrid6d_out ! transformed object
2314CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname ! select the network to be processed from the \a vol7d input object, default the first network
2315TYPE(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
2316
2317integer :: nana, ntime, ntimerange, nlevel, nvar
2318INTEGER :: ilevel, itime, itimerange, ivar, inetwork
2319
2320REAL,POINTER :: voldatiout(:,:,:)
2321type(vol7d_network) :: network
2322TYPE(conv_func), pointer :: c_func(:)
2323!TODO category sarebbe da prendere da vol7d
2324#ifdef DEBUG
2325CALL l4f_category_log(volgrid6d_out%category, l4f_debug, &
2326 'start v7d_volgrid6d_transform_compute')
2327#endif
2328
2329ntime=0
2330ntimerange=0
2331nlevel=0
2332nvar=0
2333
2334IF (PRESENT(networkname)) THEN
2335 CALL init(network,name=networkname)
2336 inetwork = index(vol7d_in%network,network)
2337 IF (inetwork <= 0) THEN
2338 CALL l4f_category_log(volgrid6d_out%category,l4f_warn, &
2339 'network '//trim(networkname)//' not found, first network will be transformed')
2340 inetwork = 1
2341 ENDIF
2342ELSE
2343 inetwork = 1
2344ENDIF
2345
2346! no time_definition conversion implemented, output will be the same as input
2347if (associated(vol7d_in%time))then
2348 ntime=size(vol7d_in%time)
2349 volgrid6d_out%time=vol7d_in%time
2350end if
2351
2352if (associated(vol7d_in%timerange))then
2353 ntimerange=size(vol7d_in%timerange)
2354 volgrid6d_out%timerange=vol7d_in%timerange
2355end if
2356
2357if (associated(vol7d_in%level))then
2358 nlevel=size(vol7d_in%level)
2359 volgrid6d_out%level=vol7d_in%level
2360end if
2361
2362if (associated(vol7d_in%dativar%r))then
2363 nvar=size(vol7d_in%dativar%r)
2364 CALL varbufr2vargrib(vol7d_in%dativar%r, volgrid6d_out%var, c_func, gaid_template)
2365end if
2366
2367nana=SIZE(vol7d_in%voldatir, 1)
2368! allocate once for speed
2369IF (.NOT.ASSOCIATED(volgrid6d_out%voldati)) THEN
2370 ALLOCATE(voldatiout(volgrid6d_out%griddim%dim%nx, volgrid6d_out%griddim%dim%ny, &
2371 nlevel))
2372ENDIF
2373
2374DO ivar=1,nvar
2375 DO itimerange=1,ntimerange
2376 DO itime=1,ntime
2377
2378! clone the gaid template where I have data
2379 IF (PRESENT(gaid_template)) THEN
2380 DO ilevel = 1, nlevel
2381 IF (any(c_e(vol7d_in%voldatir(:,itime,ilevel,itimerange,ivar,inetwork)))) THEN
2382 CALL copy(gaid_template, volgrid6d_out%gaid(ilevel,itime,itimerange,ivar))
2383 ELSE
2384 volgrid6d_out%gaid(ilevel,itime,itimerange,ivar) = grid_id_new()
2385 ENDIF
2386 ENDDO
2387 ENDIF
2388
2389! get data
2390 IF (ASSOCIATED(volgrid6d_out%voldati)) & ! improve!!!!
2391 CALL volgrid_get_vol_3d(volgrid6d_out, itime, itimerange, ivar, &
2392 voldatiout)
2393! do the interpolation
2394 CALL compute(this, &
2395 vol7d_in%voldatir(:,itime,:,itimerange,ivar,inetwork), voldatiout, &
2396 vol7d_in%dativar%r(ivar))
2397! rescale valid data according to variable conversion table
2398 IF (ASSOCIATED(c_func)) THEN
2399 CALL compute(c_func(ivar), voldatiout(:,:,:))
2400 ENDIF
2401! put data
2402 CALL volgrid_set_vol_3d(volgrid6d_out, itime, itimerange, ivar, &
2403 voldatiout)
2404
2405 ENDDO
2406 ENDDO
2407ENDDO
2408
2409IF (.NOT.ASSOCIATED(volgrid6d_out%voldati)) THEN
2410 DEALLOCATE(voldatiout)
2411ENDIF
2412IF (ASSOCIATED(c_func)) THEN
2413 DEALLOCATE(c_func)
2414ENDIF
2415
2416END SUBROUTINE v7d_volgrid6d_transform_compute
2417
2418
2419!> Performs the specified abstract transformation on the data provided.
2420!! The abstract transformation is specified by \a this parameter; the
2421!! corresponding specifical transformation (\a grid_transform object)
2422!! is created and destroyed internally. The output transformed object
2423!! is created internally and it does not require preliminary
2424!! initialisation.
2425SUBROUTINE v7d_volgrid6d_transform(this, griddim, vol7d_in, volgrid6d_out, &
2426 networkname, gaid_template, categoryappend)
2427TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
2428TYPE(griddim_def),INTENT(in),OPTIONAL :: griddim !< griddim specifying the output grid (required by most transformation types)
2429! TODO ripristinare intent(in) dopo le opportune modifiche in grid_class.F90
2430TYPE(vol7d),INTENT(inout) :: vol7d_in !< object to be transformed, it is not modified, despite the INTENT(inout)
2431TYPE(volgrid6d),INTENT(out) :: volgrid6d_out !< transformed object, it does not require initialisation
2432CHARACTER(len=*),OPTIONAL,INTENT(in) :: networkname !< select the network to be processed from the \a vol7d input object, default the first network
2433TYPE(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
2434CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
2435
2436type(grid_transform) :: grid_trans
2437integer :: ntime, ntimerange, nlevel, nvar
2438
2439
2440!TODO la category sarebbe da prendere da vol7d
2441!call l4f_category_log(vol7d_out%category,L4F_DEBUG,"start volgrid6d_transform")
2442
2443CALL vol7d_alloc_vol(vol7d_in) ! be safe
2444ntime=SIZE(vol7d_in%time)
2445ntimerange=SIZE(vol7d_in%timerange)
2446nlevel=SIZE(vol7d_in%level)
2447nvar=0
2448if (associated(vol7d_in%dativar%r)) nvar=size(vol7d_in%dativar%r)
2449
2450IF (nvar <= 0) THEN ! use vol7d category once it will be implemented
2451 CALL l4f_log(l4f_error, &
2452 "trying to transform a vol7d object incomplete or without real variables")
2453 CALL init(volgrid6d_out) ! initialize to empty
2454 CALL raise_error()
2455 RETURN
2456ENDIF
2457
2458CALL init(grid_trans, this, vol7d_in, griddim, categoryappend=categoryappend)
2459CALL init(volgrid6d_out, griddim, time_definition=vol7d_in%time_definition, &
2460 categoryappend=categoryappend)
2461
2462IF (c_e(grid_trans)) THEN
2463
2464 CALL volgrid6d_alloc(volgrid6d_out, griddim%dim, ntime=ntime, nlevel=nlevel, &
2465 ntimerange=ntimerange, nvar=nvar)
2466! can I avoid decode=.TRUE. here, using gaid_template?
2467 CALL volgrid6d_alloc_vol(volgrid6d_out, decode=.true.)
2468
2469 CALL compute(grid_trans, vol7d_in, volgrid6d_out, networkname, gaid_template)
2470
2471 CALL vg6d_wind_rot(volgrid6d_out)
2472ELSE
2473! should log with grid_trans%category, but it is private
2474 CALL l4f_log(l4f_error, 'v7d_vg6d_transform: transformation not valid')
2475 CALL raise_error()
2476ENDIF
2477
2478CALL delete(grid_trans)
2479
2480END SUBROUTINE v7d_volgrid6d_transform
2481
2482
2483! Internal method for performing sparse point to sparse point computations
2484SUBROUTINE v7d_v7d_transform_compute(this, vol7d_in, vol7d_out, lev_out, &
2485 var_coord_vol)
2486TYPE(grid_transform),INTENT(in) :: this ! oggetto di trasformazione per grigliato
2487type(vol7d), INTENT(in) :: vol7d_in ! oggetto da trasformare
2488type(vol7d), INTENT(inout) :: vol7d_out ! oggetto trasformato
2489TYPE(vol7d_level),INTENT(in),OPTIONAL :: lev_out(:) ! vol7d_level object defining target vertical grid, for vertical interpolations
2490INTEGER,INTENT(in),OPTIONAL :: var_coord_vol ! index of variable defining vertical coordinate values in input volume
2491
2492INTEGER :: itime, itimerange, ilevel, ivar, inetwork, &
2493 levshift, levused, lvar_coord_vol, spos
2494REAL,ALLOCATABLE :: coord_3d_in(:,:,:)
2495TYPE(vol7d_level) :: output_levtype
2496
2497lvar_coord_vol = optio_i(var_coord_vol)
2498vol7d_out%time(:) = vol7d_in%time(:)
2499vol7d_out%timerange(:) = vol7d_in%timerange(:)
2500IF (PRESENT(lev_out)) THEN
2501 vol7d_out%level(:) = lev_out(:)
2502ELSE
2503 vol7d_out%level(:) = vol7d_in%level(:)
2504ENDIF
2505vol7d_out%network(:) = vol7d_in%network(:)
2506IF (ASSOCIATED(vol7d_in%dativar%r)) THEN ! work only when real vars are available
2507 vol7d_out%dativar%r(:) = vol7d_in%dativar%r(:)
2508
2509 CALL get_val(this, levshift=levshift, levused=levused)
2510 spos = imiss
2511 IF (c_e(lvar_coord_vol)) THEN
2512 CALL get_val(this%trans, output_levtype=output_levtype)
2513 IF (output_levtype%level1 == 103 .OR. output_levtype%level1 == 108) THEN
2514 spos = firsttrue(vol7d_in%level(:) == vol7d_level_new(1))
2515 IF (spos == 0) THEN
2516 CALL l4f_log(l4f_error, &
2517 'output level '//t2c(output_levtype%level1)// &
2518 ' requested, but height/press of surface not provided in volume')
2519 ENDIF
2520 IF (.NOT.c_e(levshift) .AND. .NOT.c_e(levused)) THEN
2521 CALL l4f_log(l4f_error, &
2522 'internal inconsistence, levshift and levused undefined when they should be')
2523 ENDIF
2524 ALLOCATE(coord_3d_in(SIZE(vol7d_in%ana),1,SIZE(vol7d_in%level)))
2525 ENDIF
2526
2527 ENDIF
2528
2529 DO inetwork = 1, SIZE(vol7d_in%network)
2530 DO ivar = 1, SIZE(vol7d_in%dativar%r)
2531 DO itimerange = 1, SIZE(vol7d_in%timerange)
2532 DO itime = 1, SIZE(vol7d_in%time)
2533
2534! dirty trick to make voldatir look like a 2d-array of shape (nana,1)
2535 IF (c_e(lvar_coord_vol)) THEN
2536 IF (c_e(spos)) THEN ! compute difference wrt surface coordinate
2537 IF (spos == 0) THEN ! error condition, set all to missing and goodnight
2538 coord_3d_in(:,:,levshift+1:levshift+levused) = rmiss
2539 ELSE
2540 DO ilevel = levshift+1, levshift+levused
2541 WHERE(c_e(vol7d_in%voldatir(:,itime:itime,ilevel,itimerange,lvar_coord_vol,inetwork)) .AND. &
2542 c_e(vol7d_in%voldatir(:,itime:itime,spos,itimerange,lvar_coord_vol,inetwork)))
2543 coord_3d_in(:,:,ilevel) = vol7d_in%voldatir(:,itime:itime,ilevel,itimerange,lvar_coord_vol,inetwork) - &
2544 vol7d_in%voldatir(:,itime:itime,spos,itimerange,lvar_coord_vol,inetwork)
2545 ELSEWHERE
2546 coord_3d_in(:,:,ilevel) = rmiss
2547 END WHERE
2548 ENDDO
2549 ENDIF
2550 CALL compute(this, &
2551 vol7d_in%voldatir(:,itime,:,itimerange,ivar,inetwork), &
2552 vol7d_out%voldatir(:,itime:itime,:,itimerange,ivar,inetwork), &
2553 var=vol7d_in%dativar%r(ivar), &
2554 coord_3d_in=coord_3d_in)
2555 ELSE
2556 CALL compute(this, &
2557 vol7d_in%voldatir(:,itime,:,itimerange,ivar,inetwork), &
2558 vol7d_out%voldatir(:,itime:itime,:,itimerange,ivar,inetwork), &
2559 var=vol7d_in%dativar%r(ivar), &
2560 coord_3d_in=vol7d_in%voldatir(:,itime:itime,:,itimerange, &
2561 lvar_coord_vol,inetwork))
2562 ENDIF
2563 ELSE
2564 CALL compute(this, &
2565 vol7d_in%voldatir(:,itime,:,itimerange,ivar,inetwork), &
2566 vol7d_out%voldatir(:,itime:itime,:,itimerange,ivar,inetwork), &
2567 var=vol7d_in%dativar%r(ivar))
2568 ENDIF
2569 ENDDO
2570 ENDDO
2571 ENDDO
2572 ENDDO
2573
2574ENDIF
2575
2576END SUBROUTINE v7d_v7d_transform_compute
2577
2578
2579!> Performs the specified abstract transformation on the data provided.
2580!! The abstract transformation is specified by \a this parameter; the
2581!! corresponding specifical transformation (\a grid_transform object)
2582!! is created and destroyed internally. The output transformed object
2583!! is created internally and it does not require preliminary
2584!! initialisation. The success of the transformation can be checked
2585!! with the \a c_e method: c_e(vol7d_out).
2586SUBROUTINE v7d_v7d_transform(this, vol7d_in, vol7d_out, v7d, maskbounds, &
2587 lev_out, vol7d_coord_in, categoryappend)
2588TYPE(transform_def),INTENT(in) :: this !< object specifying the abstract transformation
2589TYPE(vol7d),INTENT(inout) :: vol7d_in !< object to be transformed, it is not modified, despite the INTENT(inout)
2590TYPE(vol7d),INTENT(out) :: vol7d_out !< transformed object, it does not require initialisation
2591TYPE(vol7d),INTENT(in),OPTIONAL :: v7d !< object containing a list of points over which transformation has to be done (required by some transformation types)
2592REAL,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')
2593TYPE(vol7d_level),INTENT(in),OPTIONAL,TARGET :: lev_out(:) !< vol7d_level object defining target vertical grid, for vertical interpolations
2594TYPE(vol7d),INTENT(in),OPTIONAL :: vol7d_coord_in !< object providing time constant input vertical coordinate for some kind of vertical interpolations
2595CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend !< append this suffix to log4fortran namespace category
2596
2597INTEGER :: nvar, inetwork
2598TYPE(grid_transform) :: grid_trans
2599TYPE(vol7d_level),POINTER :: llev_out(:)
2600TYPE(vol7d_level) :: input_levtype, output_levtype
2601TYPE(vol7d_var) :: vcoord_var
2602REAL,ALLOCATABLE :: coord_3d_in(:,:,:)
2603INTEGER :: var_coord_in, var_coord_vol, i, k, ulstart, ulend, spos
2604INTEGER,ALLOCATABLE :: point_index(:)
2605TYPE(vol7d) :: v7d_locana, vol7d_tmpana
2606CHARACTER(len=80) :: trans_type
2607LOGICAL,ALLOCATABLE :: mask_in(:), point_mask(:)
2608
2609CALL vol7d_alloc_vol(vol7d_in) ! be safe
2610nvar=0
2611IF (ASSOCIATED(vol7d_in%dativar%r)) nvar=SIZE(vol7d_in%dativar%r)
2612
2613CALL init(v7d_locana)
2614IF (PRESENT(v7d)) v7d_locana = v7d
2615CALL init(vol7d_out, time_definition=vol7d_in%time_definition)
2616
2617CALL get_val(this, trans_type=trans_type)
2618
2619var_coord_vol = imiss
2620IF (trans_type == 'vertint') THEN
2621
2622 IF (PRESENT(lev_out)) THEN
2623
2624! if vol7d_coord_in provided and allocated, check that it fits
2625 var_coord_in = -1
2626 IF (PRESENT(vol7d_coord_in)) THEN
2627 IF (ASSOCIATED(vol7d_coord_in%voldatir) .AND. &
2628 ASSOCIATED(vol7d_coord_in%dativar%r)) THEN
2629
2630! strictly 1 time, 1 timerange and 1 network
2631 IF (SIZE(vol7d_coord_in%voldatir,2) /= 1 .OR. &
2632 SIZE(vol7d_coord_in%voldatir,4) /= 1 .OR. &
2633 SIZE(vol7d_coord_in%voldatir,6) /= 1) THEN
2634 CALL l4f_log(l4f_error, &
2635 'volume providing constant input vertical coordinate must have &
2636 &only 1 time, 1 timerange and 1 network')
2637 CALL raise_error()
2638 RETURN
2639 ENDIF
2640
2641! search for variable providing vertical coordinate
2642 CALL get_val(this, output_levtype=output_levtype)
2643 vcoord_var = vol7d_var_new(vol7d_level_to_var(output_levtype))
2644 IF (.NOT.c_e(vcoord_var)) THEN
2645 CALL l4f_log(l4f_error, &
2646 'requested output level type '//t2c(output_levtype%level1)// &
2647 ' does not correspond to any known physical variable for &
2648 &providing vertical coordinate')
2649 CALL raise_error()
2650 RETURN
2651 ENDIF
2652
2653 var_coord_in = index(vol7d_coord_in%dativar%r, vcoord_var)
2654
2655 IF (var_coord_in <= 0) THEN
2656 CALL l4f_log(l4f_error, &
2657 'volume providing constant input vertical coordinate contains no &
2658 &real variables matching output level type '//t2c(output_levtype%level1))
2659 CALL raise_error()
2660 RETURN
2661 ENDIF
2662 CALL l4f_log(l4f_info, &
2663 'Coordinate for vertint found in coord volume at position '// &
2664 t2c(var_coord_in))
2665
2666! check vertical coordinate system
2667 CALL get_val(this, input_levtype=input_levtype)
2668 mask_in = & ! implicit allocation
2669 (vol7d_coord_in%level(:)%level1 == input_levtype%level1) .AND. &
2670 (vol7d_coord_in%level(:)%level2 == input_levtype%level2)
2671 ulstart = firsttrue(mask_in)
2672 ulend = lasttrue(mask_in)
2673 IF (ulstart == 0 .OR. ulend == 0) THEN
2674 CALL l4f_log(l4f_error, &
2675 'coordinate file does not contain levels of type '// &
2676 t2c(input_levtype%level1)//'/'//t2c(input_levtype%level2)// &
2677 ' specified for input data')
2678 CALL raise_error()
2679 RETURN
2680 ENDIF
2681
2682 coord_3d_in = vol7d_coord_in%voldatir(:,1:1,ulstart:ulend,1,var_coord_in,1) ! dirty 1:1, implicit allocation
2683! special case
2684 IF (output_levtype%level1 == 103 &
2685 .OR. output_levtype%level1 == 108) THEN ! surface coordinate needed
2686 spos = firsttrue(vol7d_coord_in%level(:) == vol7d_level_new(1))
2687 IF (spos == 0) THEN
2688 CALL l4f_log(l4f_error, &
2689 'output level '//t2c(output_levtype%level1)// &
2690 ' requested, but height/press of surface not provided in coordinate file')
2691 CALL raise_error()
2692 RETURN
2693 ENDIF
2694 DO k = 1, SIZE(coord_3d_in,3)
2695 WHERE(c_e(coord_3d_in(:,:,k)) .AND. &
2696 c_e(vol7d_coord_in%voldatir(:,1:1,spos,1,var_coord_in,1)))
2697 coord_3d_in(:,:,k) = coord_3d_in(:,:,k) - &
2698 vol7d_coord_in%voldatir(:,1:1,spos,1,var_coord_in,1)
2699 ELSEWHERE
2700 coord_3d_in(:,:,k) = rmiss
2701 END WHERE
2702 ENDDO
2703 ENDIF
2704
2705 ENDIF
2706 ENDIF
2707
2708 IF (var_coord_in <= 0) THEN ! search for coordinate within volume
2709! search for variable providing vertical coordinate
2710 CALL get_val(this, output_levtype=output_levtype)
2711 vcoord_var = vol7d_var_new(vol7d_level_to_var(output_levtype))
2712 IF (c_e(vcoord_var)) THEN
2713 DO i = 1, SIZE(vol7d_in%dativar%r)
2714 IF (vol7d_in%dativar%r(i) == vcoord_var) THEN
2715 var_coord_vol = i
2716 EXIT
2717 ENDIF
2718 ENDDO
2719
2720 IF (c_e(var_coord_vol)) THEN
2721 CALL l4f_log(l4f_info, &
2722 'Coordinate for vertint found in input volume at position '// &
2723 t2c(var_coord_vol))
2724 ENDIF
2725
2726 ENDIF
2727 ENDIF
2728
2729 IF (var_coord_in > 0) THEN
2730 CALL init(grid_trans, this, lev_in=vol7d_in%level, lev_out=lev_out, &
2731 coord_3d_in=coord_3d_in, categoryappend=categoryappend)
2732 ELSE
2733 CALL init(grid_trans, this, lev_in=vol7d_in%level, lev_out=lev_out, &
2734 categoryappend=categoryappend)
2735 ENDIF
2736
2737 CALL get_val(grid_trans, output_level_auto=llev_out) ! get levels if auto-generated
2738 IF (.NOT.associated(llev_out)) llev_out => lev_out
2739
2740 IF (c_e(grid_trans)) then! .AND. nvar > 0) THEN
2741
2742 CALL vol7d_alloc(vol7d_out, nana=SIZE(vol7d_in%ana), &
2743 ntime=SIZE(vol7d_in%time), ntimerange=SIZE(vol7d_in%timerange), &
2744 nlevel=SIZE(llev_out), nnetwork=SIZE(vol7d_in%network), ndativarr=nvar)
2745 vol7d_out%ana(:) = vol7d_in%ana(:)
2746
2747 CALL vol7d_alloc_vol(vol7d_out)
2748
2749! no need to check c_e(var_coord_vol) here since the presence of
2750! this%coord_3d_in (external) has precedence over coord_3d_in internal
2751! in grid_transform_compute
2752 CALL compute(grid_trans, vol7d_in, vol7d_out, llev_out, &
2753 var_coord_vol=var_coord_vol)
2754 ELSE
2755 CALL l4f_log(l4f_error, 'v7d_v7d_transform: transformation not valid')
2756 CALL raise_error()
2757 ENDIF
2758 ELSE
2759 CALL l4f_log(l4f_error, &
2760 'v7d_v7d_transform: vertint requested but lev_out not provided')
2761 CALL raise_error()
2762 ENDIF
2763
2764ELSE
2765
2766 CALL init(grid_trans, this, vol7d_in, v7d_locana, maskbounds=maskbounds, &
2767 categoryappend=categoryappend)
2768! if this init is successful, I am sure that v7d_locana%ana is associated
2769
2770 IF (c_e(grid_trans)) then! .AND. nvar > 0) THEN
2771
2772 CALL vol7d_alloc(vol7d_out, nana=SIZE(v7d_locana%ana), &
2773 ntime=SIZE(vol7d_in%time), ntimerange=SIZE(vol7d_in%timerange), &
2774 nlevel=SIZE(vol7d_in%level), nnetwork=SIZE(vol7d_in%network), ndativarr=nvar)
2775 vol7d_out%ana = v7d_locana%ana
2776
2777 CALL get_val(grid_trans, point_mask=point_mask, output_point_index=point_index)
2778
2779 IF (ALLOCATED(point_index)) THEN
2780 CALL vol7d_alloc(vol7d_out, nanavari=1)
2781 CALL init(vol7d_out%anavar%i(1), 'B01192')
2782 ENDIF
2783
2784 CALL vol7d_alloc_vol(vol7d_out)
2785
2786 IF (ALLOCATED(point_index)) THEN
2787 DO inetwork = 1, SIZE(vol7d_in%network)
2788 vol7d_out%volanai(:,1,inetwork) = point_index(:)
2789 ENDDO
2790 ENDIF
2791 CALL compute(grid_trans, vol7d_in, vol7d_out)
2792
2793 IF (ALLOCATED(point_mask)) THEN ! keep full ana
2794 IF (SIZE(point_mask) /= SIZE(vol7d_in%ana)) THEN
2795 CALL l4f_log(l4f_warn, &
2796 'v7d_v7d_transform: inconsistency in point size: '//t2c(SIZE(point_mask)) &
2797 //':'//t2c(SIZE(vol7d_in%ana)))
2798 ELSE
2799#ifdef DEBUG
2800 CALL l4f_log(l4f_debug, 'v7d_v7d_transform: merging ana from in to out')
2801#endif
2802 CALL vol7d_copy(vol7d_in, vol7d_tmpana, &
2803 lana=point_mask, lnetwork=(/.true./), &
2804 ltime=(/.false./), ltimerange=(/.false./), llevel=(/.false./))
2805 CALL vol7d_append(vol7d_out, vol7d_tmpana)
2806 ENDIF
2807 ENDIF
2808
2809 ELSE
2810 CALL l4f_log(l4f_error, 'v7d_v7d_transform: transformation not valid')
2811 CALL raise_error()
2812 ENDIF
2813
2814ENDIF
2815
2816CALL delete (grid_trans)
2817IF (.NOT. PRESENT(v7d)) CALL delete(v7d_locana)
2818
2819END SUBROUTINE v7d_v7d_transform
2820
2821
2822!> Unrotate the wind components.
2823!! It converts u and v components of vector quantities relative to the
2824!! defined grid in the direction of increasing x and y coordinates to
2825!! u and v components relative to easterly and notherly direction. The
2826!! original fields are overwritten.
2827!! \todo Check and correct wind component flag (to be moved in
2828!! griddim_def?)
2829subroutine vg6d_wind_unrot(this)
2830type(volgrid6d) :: this !< object containing wind to be unrotated
2831
2832integer :: component_flag
2833
2834call get_val(this%griddim,component_flag=component_flag)
2835
2836if (component_flag == 1) then
2837 call l4f_category_log(this%category,l4f_info, &
2838 "unrotating vector components")
2839 call vg6d_wind__un_rot(this,.false.)
2840 call set_val(this%griddim,component_flag=0)
2841else
2842 call l4f_category_log(this%category,l4f_info, &
2843 "no need to unrotate vector components")
2844end if
2845
2846end subroutine vg6d_wind_unrot
2847
2848
2849!> Rotate the wind components.
2850!! It converts u and v components of vector quantities
2851!! relative to easterly and notherly direction to
2852!! defined grid in the direction of increasing x and y coordinates.
2853!! The original fields are overwritten.
2854subroutine vg6d_wind_rot(this)
2855type(volgrid6d) :: this !< object containing wind to be rotated
2856
2857integer :: component_flag
2858
2859call get_val(this%griddim,component_flag=component_flag)
2860
2861if (component_flag == 0) then
2862 call l4f_category_log(this%category,l4f_info, &
2863 "rotating vector components")
2864 call vg6d_wind__un_rot(this,.true.)
2865 call set_val(this%griddim,component_flag=1)
2866else
2867 call l4f_category_log(this%category,l4f_info, &
2868 "no need to rotate vector components")
2869end if
2870
2871end subroutine vg6d_wind_rot
2872
2873
2874! Generic UnRotate the wind components.
2875SUBROUTINE vg6d_wind__un_rot(this,rot)
2876TYPE(volgrid6d) :: this ! object containing wind to be (un)rotated
2877LOGICAL :: rot ! if .true. rotate else unrotate
2878
2879INTEGER :: i, j, k, l, a11, a12, a21, a22, stallo
2880double precision,pointer :: rot_mat(:,:,:)
2881real,allocatable :: tmp_arr(:,:)
2882REAL,POINTER :: voldatiu(:,:), voldativ(:,:)
2883INTEGER,POINTER :: iu(:), iv(:)
2884
2885IF (.NOT.ASSOCIATED(this%var)) THEN
2886 CALL l4f_category_log(this%category, l4f_error, &
2887 "trying to unrotate an incomplete volgrid6d object")
2888 CALL raise_fatal_error()
2889! RETURN
2890ENDIF
2891
2892CALL volgrid6d_var_hor_comp_index(this%var, iu, iv)
2893IF (.NOT.ASSOCIATED(iu)) THEN
2894 CALL l4f_category_log(this%category,l4f_error, &
2895 "unrotation impossible")
2896 CALL raise_fatal_error()
2897! RETURN
2898ENDIF
2899
2900! Temporary workspace
2901ALLOCATE(tmp_arr(this%griddim%dim%nx, this%griddim%dim%ny),stat=stallo)
2902IF (stallo /= 0) THEN
2903 CALL l4f_category_log(this%category, l4f_fatal, "allocating memory")
2904 CALL raise_fatal_error()
2905ENDIF
2906! allocate once for speed
2907IF (.NOT.ASSOCIATED(this%voldati)) THEN
2908 ALLOCATE(voldatiu(this%griddim%dim%nx, this%griddim%dim%ny), &
2909 voldativ(this%griddim%dim%nx, this%griddim%dim%ny))
2910ENDIF
2911
2912CALL griddim_unproj(this%griddim)
2913CALL wind_unrot(this%griddim, rot_mat)
2914
2915a11=1
2916if (rot)then
2917 a12=2
2918 a21=3
2919else
2920 a12=3
2921 a21=2
2922end if
2923a22=4
2924
2925DO l = 1, SIZE(iu)
2926 DO k = 1, SIZE(this%timerange)
2927 DO j = 1, SIZE(this%time)
2928 DO i = 1, SIZE(this%level)
2929! get data
2930 CALL volgrid_get_vol_2d(this, i, j, k, iu(l), voldatiu)
2931 CALL volgrid_get_vol_2d(this, i, j, k, iv(l), voldativ)
2932! convert units forward
2933! CALL compute(conv_fwd(iu(l)), voldatiu)
2934! CALL compute(conv_fwd(iv(l)), voldativ)
2935
2936! multiply wind components by rotation matrix
2937 WHERE(voldatiu /= rmiss .AND. voldativ /= rmiss)
2938 tmp_arr(:,:) = real(voldatiu(:,:)*rot_mat(:,:,a11) + &
2939 voldativ(:,:)*rot_mat(:,:,a12))
2940 voldativ(:,:) = real(voldatiu(:,:)*rot_mat(:,:,a21) + &
2941 voldativ(:,:)*rot_mat(:,:,a22))
2942 voldatiu(:,:) = tmp_arr(:,:)
2943 END WHERE
2944! convert units backward
2945! CALL uncompute(conv_fwd(iu(l)), voldatiu)
2946! CALL uncompute(conv_fwd(iv(l)), voldativ)
2947! put data
2948 CALL volgrid_set_vol_2d(this, i, j, k, iu(l), voldatiu)
2949 CALL volgrid_set_vol_2d(this, i, j, k, iv(l), voldativ)
2950 ENDDO
2951 ENDDO
2952 ENDDO
2953ENDDO
2954
2955IF (.NOT.ASSOCIATED(this%voldati)) THEN
2956 DEALLOCATE(voldatiu, voldativ)
2957ENDIF
2958DEALLOCATE(rot_mat, tmp_arr, iu, iv)
2959
2960END SUBROUTINE vg6d_wind__un_rot
2961
2962
2963!!$ try to understand the problem:
2964!!$
2965!!$ case:
2966!!$
2967!!$ 1) we have only one volume: we have to provide the direction of shift
2968!!$ compute H and traslate on it
2969!!$ 2) we have two volumes:
2970!!$ 1) volume U and volume V: compute H and traslate on it
2971!!$ 2) volume U/V and volume H : translate U/V on H
2972!!$ 3) we have tree volumes: translate U and V on H
2973!!$
2974!!$ strange cases:
2975!!$ 1) do not have U in volume U
2976!!$ 2) do not have V in volume V
2977!!$ 3) we have others variables more than U and V in volumes U e V
2978!!$
2979!!$
2980!!$ so the steps are:
2981!!$ 1) find the volumes
2982!!$ 2) define or compute H grid
2983!!$ 3) trasform the volumes in H
2984
2985!!$ N.B.
2986!!$ case 1) for only one vg6d (U or V) is not managed, but
2987!!$ the not pubblic subroutines will work but you have to know what you want to do
2988
2989
2990!> Convert grids type C to type A.
2991!! Use this to interpolate data from grid type C to grid type A
2992!! Grids type are defined by Arakawa.
2993!!
2994!! We need to find these types of area in a vg6d array
2995!! T area of points with temterature etc.
2996!! U area of points with u components of winds
2997!! V area of points with v components of winds
2998!!
2999!! this method works if it finds
3000!! two volumes:
3001!! 1) volume U and volume V: compute H and traslate on it
3002!! 2) volume U/V and volume H : translate U/V on H
3003!! three volumes: translate U and V on H
3004!!
3005!! try to work well on more datasets at once
3006subroutine vg6d_c2a (this)
3007
3008TYPE(volgrid6d),INTENT(inout) :: this(:) !< vettor of volumes volgrid6d to elaborate
3009
3010integer :: ngrid,igrid,jgrid,ugrid,vgrid,tgrid
3011doubleprecision :: xmin, xmax, ymin, ymax
3012doubleprecision :: xmin_t, xmax_t, ymin_t, ymax_t
3013doubleprecision :: step_lon_t,step_lat_t
3014character(len=80) :: type_t,type
3015TYPE(griddim_def):: griddim_t
3016
3017ngrid=size(this)
3018
3019do igrid=1,ngrid
3020
3021 call init(griddim_t)
3022
3023 call get_val(this(igrid)%griddim,xmin=xmin_t, xmax=xmax_t, ymin=ymin_t, ymax=ymax_t,proj_type=type_t)
3024 step_lon_t=(xmax_t-xmin_t)/dble(this(igrid)%griddim%dim%nx-1)
3025 step_lat_t=(ymax_t-ymin_t)/dble(this(igrid)%griddim%dim%ny-1)
3026
3027 do jgrid=1,ngrid
3028
3029 ugrid=imiss
3030 vgrid=imiss
3031 tgrid=imiss
3032
3033#ifdef DEBUG
3034 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: search U/V/T points:"//to_char(igrid)//to_char(jgrid))
3035 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: test delta: "//to_char(step_lon_t)//to_char(step_lat_t))
3036#endif
3037
3038 if (this(igrid)%griddim == this(jgrid)%griddim ) cycle
3039
3040 if (this(igrid)%griddim%dim%nx == this(jgrid)%griddim%dim%nx .and. &
3041 this(igrid)%griddim%dim%ny == this(jgrid)%griddim%dim%ny ) then
3043 call get_val(this(jgrid)%griddim,xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax,proj_type=type)
3044
3045 if (type_t /= type )cycle
3046
3047#ifdef DEBUG
3048 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: test U "//&
3049 to_char(xmin)//to_char(xmax)//to_char(ymin)//to_char(ymax))
3050
3051 call l4f_category_log(this(igrid)%category,l4f_debug,"diff coordinate lon"//&
3052 to_char(abs(xmin - (xmin_t+step_lon_t/2.d0)))//&
3053 to_char(abs(xmax - (xmax_t+step_lon_t/2.d0))))
3054 call l4f_category_log(this(igrid)%category,l4f_debug,"diff coordinate lat"//&
3055 to_char(abs(ymin - (ymin_t+step_lat_t/2.d0)))//&
3056 to_char(abs(ymax - (ymax_t+step_lat_t/2.d0))))
3057#endif
3058
3059 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
3060 if ( abs(ymin - ymin_t) < 1.d-3 .and. abs(ymax - ymax_t) < 1.d-3 ) then
3061
3062#ifdef DEBUG
3063 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: found U")
3064#endif
3065 ugrid=jgrid
3066 tgrid=igrid
3067
3068 end if
3069 end if
3070
3071#ifdef DEBUG
3072 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: test V "//&
3073 to_char(xmin)//to_char(xmax)//to_char(ymin)//to_char(ymax))
3074#endif
3075
3076 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
3077 if ( abs(xmin - xmin_t) < 1.d-3 .and. abs(xmax - xmax_t) < 1.d-3 ) then
3078
3079#ifdef DEBUG
3080 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: found V")
3081#endif
3082 vgrid=jgrid
3083 tgrid=igrid
3084
3085 end if
3086 end if
3087
3088
3089 ! test if we have U and V
3090
3091#ifdef DEBUG
3092 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: test U and V"//&
3093 to_char(xmin_t)//to_char(xmax_t)//to_char(ymin_t)//to_char(ymax_t)//&
3094 to_char(xmin)//to_char(xmax)//to_char(ymin)//to_char(ymax))
3095
3096 call l4f_category_log(this(igrid)%category,l4f_debug,"UV diff coordinate lon"//&
3097 to_char(abs(xmin_t - xmin)-step_lon_t/2.d0)//&
3098 to_char(abs(xmax_t - xmax)-step_lon_t/2.d0))
3099 call l4f_category_log(this(igrid)%category,l4f_debug,"UV diff coordinate lat"//&
3100 to_char(abs(ymin_t - ymin) -step_lat_t/2.d0)//&
3101 to_char(abs(ymax_t - ymax)-step_lat_t/2.d0))
3102#endif
3103
3104 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
3105 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
3106
3107#ifdef DEBUG
3108 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid: found U and V case up and right")
3109#endif
3110
3111 vgrid=jgrid
3112 ugrid=igrid
3113
3114 call init(griddim_t,xmin=xmin, xmax=xmax, ymin=ymin_t, ymax=ymax_t)
3115
3116 end if
3117 end if
3118 end if
3119
3120 ! abbiamo almeno due volumi: riportiamo U e/o V su T
3121 if (c_e(ugrid)) then
3122#ifdef DEBUG
3123 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid U points: interpolate U on T "//to_char(tgrid)//to_char(ugrid))
3124#endif
3125 if (c_e(tgrid))then
3126 call vg6d_c2a_grid(this(ugrid),this(tgrid)%griddim,cgrid=1)
3127 else
3128 call vg6d_c2a_grid(this(ugrid),griddim_t,cgrid=1)
3129 end if
3130 call vg6d_c2a_mat(this(ugrid),cgrid=1)
3131 end if
3132
3133 if (c_e(vgrid)) then
3134#ifdef DEBUG
3135 call l4f_category_log(this(igrid)%category,l4f_debug,"C grid V points: interpolate V on T "//to_char(tgrid)//to_char(vgrid))
3136#endif
3137 if (c_e(tgrid))then
3138 call vg6d_c2a_grid(this(vgrid),this(tgrid)%griddim,cgrid=2)
3139 else
3140 call vg6d_c2a_grid(this(vgrid),griddim_t,cgrid=2)
3141 end if
3142 call vg6d_c2a_mat(this(vgrid),cgrid=2)
3143 end if
3144
3145 end do
3146
3147 call delete(griddim_t)
3148
3149end do
3150
3151
3152end subroutine vg6d_c2a
3153
3154
3155! Convert C grid to A grid
3156subroutine vg6d_c2a_grid(this,griddim_t,cgrid)
3157
3158type(volgrid6d),intent(inout) :: this ! object containing fields to be translated (U or V points)
3159type(griddim_def),intent(in),optional :: griddim_t ! object containing grid of T points
3160integer,intent(in) :: cgrid ! in C grid (Arakawa) we have 0=T,1=U,2=V points
3161
3162doubleprecision :: xmin, xmax, ymin, ymax
3163doubleprecision :: step_lon,step_lat
3164
3165
3166if (present(griddim_t)) then
3167
3168 call get_val(griddim_t,xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
3169 call set_val(this%griddim,xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
3170! improve grid definition precision
3171 CALL griddim_setsteps(this%griddim)
3172
3173else
3174
3175 select case (cgrid)
3176
3177 case(0)
3178
3179#ifdef DEBUG
3180 call l4f_category_log(this%category,l4f_debug,"C grid: T points, nothing to do")
3181#endif
3182 return
3183
3184 case (1)
3185
3186#ifdef DEBUG
3187 call l4f_category_log(this%category,l4f_debug,"C grid: U points, we need interpolation")
3188#endif
3189
3190 call get_val(this%griddim, xmin=xmin, xmax=xmax)
3191 step_lon=(xmax-xmin)/dble(this%griddim%dim%nx-1)
3192 xmin=xmin-step_lon/2.d0
3193 xmax=xmax-step_lon/2.d0
3194 call set_val(this%griddim, xmin=xmin, xmax=xmax)
3195! improve grid definition precision
3196 CALL griddim_setsteps(this%griddim)
3197
3198 case (2)
3199
3200#ifdef DEBUG
3201 call l4f_category_log(this%category,l4f_debug,"C grid: V points, we need interpolation")
3202#endif
3203
3204 call get_val(this%griddim, ymin=ymin, ymax=ymax)
3205 step_lat=(ymax-ymin)/dble(this%griddim%dim%ny-1)
3206 ymin=ymin-step_lat/2.d0
3207 ymax=ymax-step_lat/2.d0
3208 call set_val(this%griddim, ymin=ymin, ymax=ymax)
3209! improve grid definition precision
3210 CALL griddim_setsteps(this%griddim)
3211
3212 case default
3213
3214 call l4f_category_log(this%category,l4f_fatal,"C grid type not known")
3215 call raise_fatal_error ()
3216
3217 end select
3218
3219end if
3220
3221
3222call griddim_unproj(this%griddim)
3223
3224
3225end subroutine vg6d_c2a_grid
3226
3227! Convert C grid to A grid
3228subroutine vg6d_c2a_mat(this,cgrid)
3229
3230type(volgrid6d),intent(inout) :: this ! object containing fields to be translated
3231integer,intent(in) :: cgrid ! in C grid (Arakawa) we have 0=T,1=U,2=V points
3232
3233INTEGER :: i, j, k, iv, stallo
3234REAL,ALLOCATABLE :: tmp_arr(:,:)
3235REAL,POINTER :: voldatiuv(:,:)
3236
3237
3238IF (cgrid == 0) RETURN ! nothing to do
3239IF (cgrid /= 1 .AND. cgrid /= 2) THEN ! wrong cgrid
3240 CALL l4f_category_log(this%category,l4f_fatal,"C grid type "// &
3241 trim(to_char(cgrid))//" not known")
3242 CALL raise_error()
3243 RETURN
3244ENDIF
3245
3246! Temporary workspace
3247ALLOCATE(tmp_arr(this%griddim%dim%nx, this%griddim%dim%ny),stat=stallo)
3248if (stallo /=0)then
3249 call l4f_log(l4f_fatal,"allocating memory")
3250 call raise_fatal_error()
3251end if
3252
3253! allocate once for speed
3254IF (.NOT.ASSOCIATED(this%voldati)) THEN
3255 ALLOCATE(voldatiuv(this%griddim%dim%nx, this%griddim%dim%ny), stat=stallo)
3256 IF (stallo /= 0) THEN
3257 CALL l4f_log(l4f_fatal,"allocating memory")
3258 CALL raise_fatal_error()
3259 ENDIF
3260ENDIF
3261
3262IF (cgrid == 1) THEN ! U points to H points
3263 DO iv = 1, SIZE(this%var)
3264 DO k = 1, SIZE(this%timerange)
3265 DO j = 1, SIZE(this%time)
3266 DO i = 1, SIZE(this%level)
3267 tmp_arr(:,:) = rmiss
3268 CALL volgrid_get_vol_2d(this, i, j, k, iv, voldatiuv)
3269
3270! West boundary extrapolation
3271 WHERE(voldatiuv(1,:) /= rmiss .AND. voldatiuv(2,:) /= rmiss)
3272 tmp_arr(1,:) = voldatiuv(1,:) - (voldatiuv(2,:) - voldatiuv(1,:)) / 2.
3273 END WHERE
3274
3275! Rest of the field
3276 WHERE(voldatiuv(1:this%griddim%dim%nx-1,:) /= rmiss .AND. &
3277 voldatiuv(2:this%griddim%dim%nx,:) /= rmiss)
3278 tmp_arr(2:this%griddim%dim%nx,:) = &
3279 (voldatiuv(1:this%griddim%dim%nx-1,:) + &
3280 voldatiuv(2:this%griddim%dim%nx,:)) / 2.
3281 END WHERE
3282
3283 voldatiuv(:,:) = tmp_arr
3284 CALL volgrid_set_vol_2d(this, i, j, k, iv, voldatiuv)
3285 ENDDO
3286 ENDDO
3287 ENDDO
3288 ENDDO
3289
3290ELSE IF (cgrid == 2) THEN ! V points to H points
3291 DO iv = 1, SIZE(this%var)
3292 DO k = 1, SIZE(this%timerange)
3293 DO j = 1, SIZE(this%time)
3294 DO i = 1, SIZE(this%level)
3295 tmp_arr(:,:) = rmiss
3296 CALL volgrid_get_vol_2d(this, i, j, k, iv, voldatiuv)
3297
3298! South boundary extrapolation
3299 WHERE(voldatiuv(:,1) /= rmiss .AND. voldatiuv(:,2) /= rmiss)
3300 tmp_arr(:,1) = voldatiuv(:,1) - (voldatiuv(:,2) - voldatiuv(:,1)) / 2.
3301 END WHERE
3302
3303! Rest of the field
3304 WHERE(voldatiuv(:,1:this%griddim%dim%ny-1) /= rmiss .AND. &
3305 voldatiuv(:,2:this%griddim%dim%ny) /= rmiss)
3306 tmp_arr(:,2:this%griddim%dim%ny) = &
3307 (voldatiuv(:,1:this%griddim%dim%ny-1) + &
3308 voldatiuv(:,2:this%griddim%dim%ny)) / 2.
3309 END WHERE
3310
3311 voldatiuv(:,:) = tmp_arr
3312 CALL volgrid_set_vol_2d(this, i, j, k, iv, voldatiuv)
3313 ENDDO
3314 ENDDO
3315 ENDDO
3316 ENDDO
3317ENDIF ! tertium non datur
3318
3319IF (.NOT.ASSOCIATED(this%voldati)) THEN
3320 DEALLOCATE(voldatiuv)
3321ENDIF
3322DEALLOCATE (tmp_arr)
3323
3324end subroutine vg6d_c2a_mat
3325
3326
3327!> \brief Display object on screen
3328!!
3329!! Show brief content on screen.
3330subroutine display_volgrid6d (this)
3331
3332TYPE(volgrid6d),intent(in) :: this !< object to display
3333integer :: i
3334
3335#ifdef DEBUG
3336call l4f_category_log(this%category,l4f_debug,"ora mostro gridinfo " )
3337#endif
3338
3339print*,"----------------------- volgrid6d display ---------------------"
3340call display(this%griddim)
3341
3342IF (ASSOCIATED(this%time))then
3343 print*,"---- time vector ----"
3344 print*,"elements=",size(this%time)
3345 do i=1, size(this%time)
3346 call display(this%time(i))
3347 end do
3348end IF
3349
3350IF (ASSOCIATED(this%timerange))then
3351 print*,"---- timerange vector ----"
3352 print*,"elements=",size(this%timerange)
3353 do i=1, size(this%timerange)
3354 call display(this%timerange(i))
3355 end do
3356end IF
3357
3358IF (ASSOCIATED(this%level))then
3359 print*,"---- level vector ----"
3360 print*,"elements=",size(this%level)
3361 do i=1, size(this%level)
3362 call display(this%level(i))
3363 end do
3364end IF
3365
3366IF (ASSOCIATED(this%var))then
3367 print*,"---- var vector ----"
3368 print*,"elements=",size(this%var)
3369 do i=1, size(this%var)
3370 call display(this%var(i))
3371 end do
3372end IF
3373
3374IF (ASSOCIATED(this%gaid))then
3375 print*,"---- gaid vector (present mask only) ----"
3376 print*,"elements=",shape(this%gaid)
3377 print*,c_e(reshape(this%gaid,(/SIZE(this%gaid)/)))
3378end IF
3379
3380print*,"--------------------------------------------------------------"
3381
3382
3383end subroutine display_volgrid6d
3384
3385
3386!> \brief Display vector of object on screen
3387!!
3388!! Show brief content on screen.
3389subroutine display_volgrid6dv (this)
3390
3391TYPE(volgrid6d),intent(in) :: this(:) !< vector of object to display
3392integer :: i
3393
3394print*,"----------------------- volgrid6d vector ---------------------"
3395
3396print*,"elements=",size(this)
3397
3398do i=1, size(this)
3399
3400#ifdef DEBUG
3401 call l4f_category_log(this(i)%category,l4f_debug,"ora mostro il vettore volgrid6d" )
3402#endif
3403
3404 call display(this(i))
3405
3406end do
3407print*,"--------------------------------------------------------------"
3408
3409end subroutine display_volgrid6dv
3410
3411
3412!> Reduce some dimensions (level and timerage) for semplification (rounding).
3413!! Vector version of vg6dv_rounding
3414subroutine vg6dv_rounding(vg6din,vg6dout,level,timerange,nostatproc,merge)
3415type(volgrid6d),intent(in) :: vg6din(:) !< input volume
3416type(volgrid6d),intent(out),pointer :: vg6dout(:) !> output volume
3417type(vol7d_level),intent(in),optional :: level(:) !< almost equal level list
3418type(vol7d_timerange),intent(in),optional :: timerange(:) !< almost equal timerange list
3419logical,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
3420logical,intent(in),optional :: nostatproc !< do not take in account statistical processing code in timerange and P2
3421
3422integer :: i
3423
3424allocate(vg6dout(size(vg6din)))
3425
3426do i = 1, size(vg6din)
3427 call vg6d_rounding(vg6din(i),vg6dout(i),level,timerange,nostatproc,merge)
3428end do
3429
3430end subroutine vg6dv_rounding
3431
3432!> Reduce some dimensions (level and timerage) for semplification (rounding).
3433!! You can use this for simplify and use variables in computation like alchimia
3434!! where fields have to be on the same coordinate
3435!! examples:
3436!! means in time for short periods and istantaneous values
3437!! 2 meter and surface levels
3438!! If there are data on more then one almost equal levels or timeranges, the first var present (at least one point)
3439!! will be taken (order is by icreasing var index).
3440!! You can use predefined values for classic semplification
3441!! almost_equal_levels and almost_equal_timeranges
3442!! The level or timerange in output will be defined by the first element of level and timerange list
3443subroutine vg6d_rounding(vg6din,vg6dout,level,timerange,nostatproc,merge)
3444type(volgrid6d),intent(in) :: vg6din !< input volume
3445type(volgrid6d),intent(out) :: vg6dout !> output volume
3446type(vol7d_level),intent(in),optional :: level(:) !< almost equal level list
3447type(vol7d_timerange),intent(in),optional :: timerange(:) !< almost equal timerange list
3448logical,intent(in),optional :: merge !< if there are data on more then one almost equal levels or timeranges
3449!! will be merged POINT BY POINT with priority for the fird data found ordered by icreasing var index
3450logical,intent(in),optional :: nostatproc !< do not take in account statistical processing code in timerange and P2
3451
3452integer :: ilevel,itimerange
3453type(vol7d_level) :: roundlevel(size(vg6din%level))
3454type(vol7d_timerange) :: roundtimerange(size(vg6din%timerange))
3455
3456roundlevel=vg6din%level
3457
3458if (present(level))then
3459 do ilevel = 1, size(vg6din%level)
3460 if ((any(vg6din%level(ilevel) .almosteq. level))) then
3461 roundlevel(ilevel)=level(1)
3462 end if
3463 end do
3464end if
3465
3466roundtimerange=vg6din%timerange
3467
3468if (present(timerange))then
3469 do itimerange = 1, size(vg6din%timerange)
3470 if ((any(vg6din%timerange(itimerange) .almosteq. timerange))) then
3471 roundtimerange(itimerange)=timerange(1)
3472 end if
3473 end do
3474end if
3475
3476!set istantaneous values everywere
3477!preserve p1 for forecast time
3478if (optio_log(nostatproc)) then
3479 roundtimerange(:)%timerange=254
3480 roundtimerange(:)%p2=0
3481end if
3482
3483
3484call vg6d_reduce(vg6din,vg6dout,roundlevel,roundtimerange,merge)
3485
3486end subroutine vg6d_rounding
3487
3488!> Reduce some dimensions (level and timerage).
3489!! You can pass a volume and specify duplicated levels and timeranges in roundlevel and roundtimerange;
3490!! you get unique levels and timeranges in output.
3491!! If there are data on equal levels or timeranges, the first var present (at least one point)
3492!! will be taken (order is by icreasing var index).
3493!! you can specify merge and if there are data on equal levels or timeranges will be merged POINT BY POINT
3494!! with priority for the first data found ordered by icreasing var index (require to decode all the data)
3495!! Data are decoded only if needed so the output should be with or without voldata allocated
3496subroutine vg6d_reduce(vg6din,vg6dout,roundlevel,roundtimerange,merge)
3497type(volgrid6d),intent(in) :: vg6din !< input volume
3498type(volgrid6d),intent(out) :: vg6dout !< output volume
3499type(vol7d_level),intent(in) :: roundlevel(:) !< new level list to use for rounding
3500type(vol7d_timerange),intent(in) :: roundtimerange(:) !< new timerange list to use for rounding
3501logical,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)
3502
3503integer :: nlevel,ntime,ntimerange,nvar,ilevel,itimerange,ivar,indl,indt,itime,nx,ny
3504real,allocatable :: vol2d(:,:)
3505
3506nx=vg6din%griddim%dim%nx
3507ny=vg6din%griddim%dim%ny
3508nlevel=count_distinct(roundlevel,back=.true.)
3509ntime=size(vg6din%time)
3510ntimerange=count_distinct(roundtimerange,back=.true.)
3511nvar=size(vg6din%var)
3512
3513call init(vg6dout, vg6din%griddim, vg6din%time_definition, categoryappend="generated by vg6d_reduce")
3514call volgrid6d_alloc(vg6dout, vg6din%griddim%dim, ntime, nlevel, ntimerange, nvar)
3515
3516if ( ASSOCIATED(vg6din%voldati) .or. optio_log(merge)) then
3517 call volgrid6d_alloc_vol(vg6dout,inivol=.true.,decode=.true.)
3518 allocate(vol2d(nx,ny))
3519else
3520 call volgrid6d_alloc_vol(vg6dout,inivol=.true.,decode=.false.)
3521end if
3522
3523vg6dout%time=vg6din%time
3524vg6dout%var=vg6din%var
3525vg6dout%timerange=pack_distinct(roundtimerange,ntimerange,back=.true.)
3526vg6dout%level=pack_distinct(roundlevel,nlevel,back=.true.)
3527! sort modified dimensions
3528CALL sort(vg6dout%timerange)
3529CALL sort(vg6dout%level)
3530
3531do ilevel=1,size(vg6din%level)
3532 indl=index(vg6dout%level,roundlevel(ilevel))
3533 do itimerange=1,size(vg6din%timerange)
3534 indt=index(vg6dout%timerange,roundtimerange(itimerange))
3535 do ivar=1, nvar
3536 do itime=1,ntime
3537
3538 if ( ASSOCIATED(vg6din%voldati)) then
3539 vol2d=vg6din%voldati(:,:,ilevel,itime,itimerange,ivar)
3540 end if
3541
3542 if (optio_log(merge)) then
3543
3544 if ( .not. ASSOCIATED(vg6din%voldati)) then
3545 CALL grid_id_decode_data(vg6din%gaid(ilevel,itime,itimerange,ivar), vol2d)
3546 end if
3547
3548 !! merge present data point by point
3549 where (.not. c_e(vg6dout%voldati(:,:,indl,itime,indt,ivar)))
3550
3551 vg6dout%voldati(:,:,indl,itime,indt,ivar)=vol2d
3552
3553 end where
3554 else if ( ASSOCIATED(vg6din%voldati)) then
3555 if (.not. any(c_e(vg6dout%voldati(:,:,indl,itime,indt,ivar))))then
3556 vg6dout%voldati(:,:,indl,itime,indt,ivar)=vol2d
3557 end if
3558 end if
3559
3560 if (c_e(vg6din%gaid(ilevel,itime,itimerange,ivar)).and. .not. c_e(vg6dout%gaid(indl,itime,indt,ivar)))then
3561 call copy (vg6din%gaid(ilevel,itime,itimerange,ivar), vg6dout%gaid(indl,itime,indt,ivar))
3562 end if
3563 end do
3564 end do
3565 end do
3566end do
3567
3568if ( ASSOCIATED(vg6din%voldati) .or. optio_log(merge)) then
3569 deallocate(vol2d)
3570end if
3571
3572end subroutine vg6d_reduce
3573
3574
3575end module volgrid6d_class
3576
3577
3578
3579!>\example example_vg6d_3.f90
3580!!\brief Programma esempio semplice per gridinfo e volgrid6d.
3582!! 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.
3583
3584!>\example example_vg6d_5.f90
3585!!\brief Programma trasformazione da volgrid6d a volgrid6d
3586!!
3587!! Legge grib da un file e li organizza in un vettore di strutture
3588!! volgrid6d mettendoli a disposizione per eventuali elaborazioni;
3589!! vengono poi riesportati a un file grib
3590
3591!>\example example_vg6d_8.f90
3592!! \brief Programma scrittura su file vettore di anagrafica
3593
3594!>\example example_vg6d_6.f90
3595!! \brief Programma trasformazione da volgrid6d a vol7d
3596
3597!>\example example_vg6d_7.f90
3598!! \brief Programma trasformazione da vol7d a volgrid6d
3599
3600!>\example example_vg6d_9.f90
3601!! \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.
Class for expressing an absolute time value.
This object completely describes a grid on a geographic projection.
Derived type describing the extension of a grid and the geographical coordinates of each point.
Derived type associated to a block/message/record/band of gridded data coming from a file-like object...
This object fully defines a transformation between a couple of particular griddim_def or vol7d object...
This object defines in an abstract way the type of transformation to be applied.
Derived type defining a dynamically extensible array of TYPE(gridinfo_def) elements.
Object describing a single gridded message/band.
Definisce un oggetto contenente i volumi anagrafica e dati e tutti i descrittori delle loro dimension...
Definisce il livello verticale di un'osservazione.
Definisce l'intervallo temporale di un'osservazione meteo.
Object describing a rectangular, homogeneous gridded dataset.
Class defining a real conversion function between units.
Definition of a physical variable in grib coding style.

Generated with Doxygen.