libsim Versione 8.0.0
volgrid6d_var_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
20!> Class for managing physical variables in a grib 1/2 fashion.
21!! This module defines a class which can represent Earth-science
22!! related physical variables, following the classification scheme
23!! adopted by WMO for grib1 and grib2 parameter definition. It also
24!! defines some methods for mapping \a volgrid6d_var variables and
25!! converting the corresponding fields to a matching \a vol7d_var
26!! object defined in \a vol7d_var_class module, which, unlike the
27!! variables defined here, defines univocally a physical quantity.
28!!
29!! \ingroup volgrid6d
31USE kinds
37
38IMPLICIT NONE
39
40!> Definition of a physical variable in grib coding style.
41!! \a volgrid6d_var members are public, thus they can be freely
42!! altered, but it is advisable to set them through the
43!! volgrid6d_var_class::init constructor.
45 integer :: centre !< centre
46 integer :: category !< grib2: category / grib1: grib table version number
47 integer :: number !< parameter number
48 integer :: discipline !< grib2: discipline / grib1: 255
49 CHARACTER(len=65) :: description !< optional textual description of the variable
50 CHARACTER(len=24) :: unit !< optional textual description of the variable's unit
51END TYPE volgrid6d_var
52
53TYPE(volgrid6d_var),PARAMETER :: volgrid6d_var_miss= &
54 volgrid6d_var(imiss,imiss,imiss,imiss,cmiss,cmiss) !< missing value volgrid6d_var.
55
56TYPE(vol7d_var),PARAMETER :: vol7d_var_horstag(2) = (/ &
57 vol7d_var('B11003', '', '', 0, 0, 0, 0, 0, 0), &
58 vol7d_var('B11004', '', '', 0, 0, 0, 0, 0, 0) &
59 /)
60
61TYPE(vol7d_var),PARAMETER :: vol7d_var_horcomp(4) = (/ &! RESHAPE( (/ &
62 vol7d_var('B11003', '', '', 0, 0, 0, 0, 0, 0), &
63 vol7d_var('B11004', '', '', 0, 0, 0, 0, 0, 0), &
64 vol7d_var('B11200', '', '', 0, 0, 0, 0, 0, 0), &
65 vol7d_var('B11201', '', '', 0, 0, 0, 0, 0, 0) &
66/)
67!/), (/2,2/)) ! bug in gfortran
68
69!> Class defining a real conversion function between units. It is
70!! used to numerically convert a value expressed as a \a volgrid6d_var
71!! variable in a value expressed as a \a vol7d_var variable and
72!! vice-versa. At the moment only a linear conversion is
73!! supported. Objects of this class are returned only by the \a
74!! vargrib2varbufr \a varbufr2vargrib, and \a convert methods and are
75!! used in the \a convert and \a compute methods defined in this
76!! MODULE.
77TYPE conv_func
78 PRIVATE
79 REAL :: a, b
80END TYPE conv_func
81
82TYPE(conv_func), PARAMETER :: conv_func_miss=conv_func(rmiss,rmiss)
83TYPE(conv_func), PARAMETER :: conv_func_identity=conv_func(1.0,0.0)
84
85TYPE vg6d_v7d_var_conv
86 TYPE(volgrid6d_var) :: vg6d_var
87 TYPE(vol7d_var) :: v7d_var
88 TYPE(conv_func) :: c_func
89! aggiungere informazioni ad es. su rotazione del vento
90END TYPE vg6d_v7d_var_conv
91
92TYPE(vg6d_v7d_var_conv), PARAMETER :: vg6d_v7d_var_conv_miss= &
93 vg6d_v7d_var_conv(volgrid6d_var_miss, vol7d_var_miss, conv_func_miss)
94
95TYPE(vg6d_v7d_var_conv), ALLOCATABLE :: conv_fwd(:), conv_bwd(:)
96
97!> Initialize a \a volgrid6d_var object with the optional arguments provided.
98!! If an argument is not provided, the corresponding object member and
99!! those depending on it will be set to missing. For grib1-style
100!! variables, the \a discipline argument must be omitted, it will be
101!! set to 255 (grib missing value).
102!!
103!! \param this TYPE(volgrid6d_var),INTENT(INOUT) object to be initialized
104!! \param centre INTEGER,INTENT(in),OPTIONAL centre
105!! \param category INTEGER,INTENT(in),OPTIONAL grib2: category / grib1: grib table version number
106!! \param number INTEGER,INTENT(in),OPTIONAL parameter number
107!! \param discipline INTEGER,INTENT(in),OPTIONAL grib2: discipline / grib1: 255
108!! \param description CHARACTER(len=*),INTENT(in),OPTIONAL optional textual description of the variable
109!! \param unit CHARACTER(len=*),INTENT(in),OPTIONAL optional textual description of the variable's unit
110INTERFACE init
111 MODULE PROCEDURE volgrid6d_var_init
112END INTERFACE
113
114!> Destructor for the corresponding object, it assigns it to a missing value.
115!! \param this TYPE(volgrid6d_var) object to be destroyed
116INTERFACE delete
117 MODULE PROCEDURE volgrid6d_var_delete
118END INTERFACE
119
120INTERFACE c_e
121 MODULE PROCEDURE volgrid6d_var_c_e
122END INTERFACE
123
124
125!> Logical equality operators for objects of the classes \a
126!! volgrid6d_var and \a conv_func.
127!! They are all defined as \c ELEMENTAL thus work also on arrays of
128!! any shape.
129INTERFACE OPERATOR (==)
130 MODULE PROCEDURE volgrid6d_var_eq, conv_func_eq
131END INTERFACE
132
133!> Logical inequality operators for objects of the classes \a
134!! volgrid6d_var and \a conv_func.
135!! They are all defined as \c ELEMENTAL thus work also on arrays of
136!! any shape.
137INTERFACE OPERATOR (/=)
138 MODULE PROCEDURE volgrid6d_var_ne, conv_func_ne
139END INTERFACE
140
141#define VOL7D_POLY_TYPE TYPE(volgrid6d_var)
142#define VOL7D_POLY_TYPES _var6d
143#include "array_utilities_pre.F90"
144
145!> Display on the screen a brief content of object
146INTERFACE display
147 MODULE PROCEDURE display_volgrid6d_var
148END INTERFACE
149
150!> Compose two conversions into a single one.
151!! Unlike scalar multiplication (and like matrix multiplication) here
152!! a*b /= b*a. By convention, the second factor is applied first in
153!! the result.
154INTERFACE OPERATOR (*)
155 MODULE PROCEDURE conv_func_mult
156END INTERFACE OPERATOR (*)
157
158!> Apply the conversion function \a this to \a values.
159!! function version
160INTERFACE compute
161 MODULE PROCEDURE conv_func_compute
162END INTERFACE
163
164!> Apply the conversion function \a this to \a values.
165!! subroutine version
166INTERFACE convert
167 MODULE PROCEDURE varbufr2vargrib_convert, vargrib2varbufr_convert
168END INTERFACE
169
170PRIVATE
171PUBLIC volgrid6d_var, volgrid6d_var_miss, volgrid6d_var_new, init, delete, &
172 c_e, volgrid6d_var_normalize, &
173 OPERATOR(==), OPERATOR(/=), OPERATOR(*), &
174 count_distinct, pack_distinct, count_and_pack_distinct, &
175 map_distinct, map_inv_distinct, &
176 index, display, &
177 vargrib2varbufr, varbufr2vargrib, &
178 conv_func, conv_func_miss, compute, convert, &
179 volgrid6d_var_hor_comp_index, volgrid6d_var_is_hor_comp
180
181
182CONTAINS
183
184
185ELEMENTAL FUNCTION volgrid6d_var_new(centre, category, number, &
186 discipline, description, unit) RESULT(this)
187integer,INTENT(in),OPTIONAL :: centre !< centre
188integer,INTENT(in),OPTIONAL :: category !< grib2: category / grib1: grib table version number
189integer,INTENT(in),OPTIONAL :: number !< parameter number
190integer,INTENT(in),OPTIONAL :: discipline !< grib2: discipline
191CHARACTER(len=*),INTENT(in),OPTIONAL :: description !< textual description of the variable
192CHARACTER(len=*),INTENT(in),OPTIONAL :: unit !< textual description of the variable's unit
193
194TYPE(volgrid6d_var) :: this !< object to be initialised
195
196CALL init(this, centre, category, number, discipline, description, unit)
197
198END FUNCTION volgrid6d_var_new
199
200
201! documented in the interface
202ELEMENTAL SUBROUTINE volgrid6d_var_init(this, centre, category, number, discipline,description,unit)
203TYPE(volgrid6d_var),INTENT(INOUT) :: this ! object to be initialized
204INTEGER,INTENT(in),OPTIONAL :: centre ! centre
205INTEGER,INTENT(in),OPTIONAL :: category ! grib2: category / grib1: grib table version number
206INTEGER,INTENT(in),OPTIONAL :: number ! parameter number
207INTEGER,INTENT(in),OPTIONAL :: discipline ! grib2: discipline / grib1: 255
208CHARACTER(len=*),INTENT(in),OPTIONAL :: description ! optional textual description of the variable
209CHARACTER(len=*),INTENT(in),OPTIONAL :: unit ! optional textual description of the variable's unit
210
211IF (PRESENT(centre)) THEN
212 this%centre = centre
213ELSE
214 this%centre = imiss
215 this%category = imiss
216 this%number = imiss
217 this%discipline = imiss
218 RETURN
219ENDIF
220
221IF (PRESENT(category)) THEN
222 this%category = category
223ELSE
224 this%category = imiss
225 this%number = imiss
226 this%discipline = imiss
227 RETURN
228ENDIF
229
230
231IF (PRESENT(number)) THEN
232 this%number = number
233ELSE
234 this%number = imiss
235 this%discipline = imiss
236 RETURN
237ENDIF
239! se sono arrivato fino a qui ho impostato centre, category e number
240!per il grib 1 manca discipline e imposto 255 (missing del grib2)
242IF (PRESENT(discipline)) THEN
243 this%discipline = discipline
244ELSE
245 this%discipline = 255
246ENDIF
247
248IF (PRESENT(description)) THEN
249 this%description = description
250ELSE
251 this%description = cmiss
252ENDIF
253
254IF (PRESENT(unit)) THEN
255 this%unit = unit
256ELSE
257 this%unit = cmiss
258ENDIF
259
260
261
262END SUBROUTINE volgrid6d_var_init
263
264
265! documented in the interface
266SUBROUTINE volgrid6d_var_delete(this)
267TYPE(volgrid6d_var),INTENT(INOUT) :: this
268
269this%centre = imiss
270this%category = imiss
271this%number = imiss
272this%discipline = imiss
273this%description = cmiss
274this%unit = cmiss
275
276END SUBROUTINE volgrid6d_var_delete
277
278
279ELEMENTAL FUNCTION volgrid6d_var_c_e(this) RESULT(c_e)
280TYPE(volgrid6d_var),INTENT(IN) :: this
281LOGICAL :: c_e
282c_e = this /= volgrid6d_var_miss
283END FUNCTION volgrid6d_var_c_e
284
285
286ELEMENTAL FUNCTION volgrid6d_var_eq(this, that) RESULT(res)
287TYPE(volgrid6d_var),INTENT(IN) :: this, that
288LOGICAL :: res
289
290IF (this%discipline == that%discipline) THEN
291
292 IF (this%discipline == 255) THEN ! grib1, WMO tables are all equivalent
293 res = ((this%category == that%category) .OR. &
294 (this%category >= 1 .AND. this%category <=3 .AND. &
295 that%category >= 1 .AND. that%category <=3)) .AND. &
296 this%number == that%number
297
298 IF ((this%category >= 128 .AND. this%category <= 254) .OR. &
299 (this%number >= 128 .AND. this%number <= 254)) THEN
300 res = res .AND. this%centre == that%centre ! local definition, centre matters
301 ENDIF
302
303 ELSE ! grib2
304 res = this%category == that%category .AND. &
305 this%number == that%number
306
307 IF ((this%discipline >= 192 .AND. this%discipline <= 254) .OR. &
308 (this%category >= 192 .AND. this%category <= 254) .OR. &
309 (this%number >= 192 .AND. this%number <= 254)) THEN
310 res = res .AND. this%centre == that%centre ! local definition, centre matters
311 ENDIF
312 ENDIF
313
314ELSE ! different edition or different discipline
315 res = .false.
316ENDIF
318END FUNCTION volgrid6d_var_eq
319
320
321ELEMENTAL FUNCTION volgrid6d_var_ne(this, that) RESULT(res)
322TYPE(volgrid6d_var),INTENT(IN) :: this, that
323LOGICAL :: res
324
325res = .NOT.(this == that)
326
327END FUNCTION volgrid6d_var_ne
328
329
330#include "array_utilities_inc.F90"
331
332
333!> Display on the screen a brief content of \a volgrid6d_var object.
334SUBROUTINE display_volgrid6d_var(this)
335TYPE(volgrid6d_var),INTENT(in) :: this !< volgrid6d_var object to display
336
337print*,"GRIDVAR: ",this%centre,this%discipline,this%category,this%number
338
339END SUBROUTINE display_volgrid6d_var
340
341
342!> Convert a \a volgrid6d_var array object into a physically equivalent
343!! \a vol7d_var array object. This method converts a grib-like array
344!! of physical variables \a vargrib, to an array of unique, physically
345!! based, bufr-like variables \a varbufr. The output array must have
346!! enough room for the converted variables. The method additionally
347!! allocates a \a conv_func array object of the same size, which can
348!! successively be used to convert the numerical values of the fields
349!! associated to \a vargrib to the corresponding fields in the \a
350!! bufr-like representation. \a c_func will have to be deallocated by
351!! the calling procedure. If a conversion is not successful, the
352!! corresponding output variable is set to \a vol7d_var_miss and the
353!! conversion function to \a conv_func_miss.
354SUBROUTINE vargrib2varbufr(vargrib, varbufr, c_func)
355TYPE(volgrid6d_var),INTENT(in) :: vargrib(:) !< array of input grib-like variables
356TYPE(vol7d_var),INTENT(out) :: varbufr(:) !< array of output bufr-like variables
357TYPE(conv_func),POINTER :: c_func(:) !< pointer to an array of the corresponding \a conv_func objects, allocated in the method
358
359INTEGER :: i, n, stallo
360
361n = min(SIZE(varbufr), SIZE(vargrib))
362ALLOCATE(c_func(n),stat=stallo)
363IF (stallo /= 0) THEN
364 call l4f_log(l4f_fatal,"allocating memory")
365 call raise_fatal_error()
366ENDIF
367
368DO i = 1, n
369 varbufr(i) = convert(vargrib(i), c_func(i))
370ENDDO
371
372END SUBROUTINE vargrib2varbufr
373
374
375!> Convert a \a volgrid6d_var object into a physically equivalent
376!! \a vol7d_var object. This method returns a physically based,
377!! bufr-like representation of type \a vol7d_var of the grib-like
378!! input physical variable \a vargrib. The method optionally returns
379!! a \a conv_func object which can successively be used to convert the
380!! numerical values of the field associated to \a vargrib to the
381!! corresponding fields in the bufr-like representation. If the
382!! conversion is not successful, the output variable is
383!! set to \a vol7d_var_miss and the conversion function to \a
384!! conv_func_miss.
385FUNCTION vargrib2varbufr_convert(vargrib, c_func) RESULT(convert)
386TYPE(volgrid6d_var),INTENT(in) :: vargrib !< input grib-like variable
387TYPE(conv_func),INTENT(out),OPTIONAL :: c_func !< corresponding \a conv_func object
388TYPE(vol7d_var) :: convert
389
390INTEGER :: i
391
392IF (.NOT. ALLOCATED(conv_fwd)) CALL vg6d_v7d_var_conv_setup()
393
394DO i = 1, SIZE(conv_fwd)
395 IF (vargrib == conv_fwd(i)%vg6d_var) THEN
396 convert = conv_fwd(i)%v7d_var
397 IF (PRESENT(c_func)) c_func = conv_fwd(i)%c_func
398 RETURN
399 ENDIF
400ENDDO
401! not found
402convert = vol7d_var_miss
403IF (PRESENT(c_func)) c_func = conv_func_miss
404
405! set hint for backwards conversion
406convert%gribhint(:) = (/vargrib%centre, vargrib%category, vargrib%number, &
407 vargrib%discipline/)
408
409CALL l4f_log(l4f_warn, 'vargrib2varbufr: variable '// &
410 trim(to_char(vargrib%centre))//':'//trim(to_char(vargrib%category))//':'// &
411 trim(to_char(vargrib%number))//':'//trim(to_char(vargrib%discipline))// &
412 ' not found in table')
413
414END FUNCTION vargrib2varbufr_convert
416
417!> Convert a \a vol7d_var array object into a physically equivalent
418!! \a volgrid6d_var array object. This method converts a bufr-like
419!! array of physical variables \a vargrib, to an array of grib-like
420!! variables \a varbufr. Unlike the opposite method \a
421!! vargrib2varbufr, in this case the conversion is not uniqe and at
422!! the moment the first matching grib-like variable is chosen, without
423!! any control over the choice process. The output array must have
424!! enough room for the converted variables. The method additionally
425!! allocates a \a conv_func array object of the same size, which can
426!! successively be used to convert the numerical values of the fields
427!! associated to \a varbufr to the corresponding fields in the \a
428!! grib-like representation. \a c_func will have to be deallocated by
429!! the calling procedure. If a conversion is not successful, the
430!! corresponding output variable is set to \a volgrid6d_var_miss and
431!! the conversion function to \a conv_func_miss.
432SUBROUTINE varbufr2vargrib(varbufr, vargrib, c_func, grid_id_template)
433TYPE(vol7d_var),INTENT(in) :: varbufr(:) !< array of input bufr-like variables
434TYPE(volgrid6d_var),INTENT(out) :: vargrib(:) !< array of output grib-like variables
435TYPE(conv_func),POINTER :: c_func(:) !< pointer to an array of the corresponding \a conv_func objects, allocated in the method
436TYPE(grid_id),INTENT(in),OPTIONAL :: grid_id_template !< a template (typically grib_api) to which data will be finally exported, it helps in improving variable conversion
437
438INTEGER :: i, n, stallo
439
440n = min(SIZE(varbufr), SIZE(vargrib))
441ALLOCATE(c_func(n),stat=stallo)
442IF (stallo /= 0) THEN
443 CALL l4f_log(l4f_fatal,"allocating memory")
444 CALL raise_fatal_error()
445ENDIF
446
447DO i = 1, n
448 vargrib(i) = convert(varbufr(i), c_func(i), grid_id_template)
449ENDDO
450
451END SUBROUTINE varbufr2vargrib
452
453
454!> Convert a \a vol7d_var object into a physically equivalent
455!! \a volgrid6d_var object. This method returns a grib-like
456!! representation of type \a volgrid6d_var of the bufr-like input
457!! physical variable \a varbufr. Unlike the opposite \a convert
458!! method, in this case the conversion is not uniqe and at the moment
459!! the first matching grib-like variable is chosen, without any
460!! control over the choice process. The method optionally returns a
461!! \a conv_func object which can successively be used to convert the
462!! numerical values of the field associated to \a varbufr to the
463!! corresponding fields in the grib-like representation. If the
464!! conversion is not successful, the output variable is set to \a
465!! volgrid6d_var_miss and the conversion function to \a
466!! conv_func_miss.
467FUNCTION varbufr2vargrib_convert(varbufr, c_func, grid_id_template) RESULT(convert)
468TYPE(vol7d_var),INTENT(in) :: varbufr !< input bufr-like variable
469TYPE(conv_func),INTENT(out),OPTIONAL :: c_func !< corresponding \a conv_func object
470TYPE(grid_id),INTENT(in),OPTIONAL :: grid_id_template !< a template (typically grib_api) to which data will be finally exported, it helps in improving variable conversion
471TYPE(volgrid6d_var) :: convert
472
473INTEGER :: i
474#ifdef HAVE_LIBGRIBAPI
475INTEGER :: gaid, editionnumber, category, centre
476#endif
477
478IF (.NOT. ALLOCATED(conv_bwd)) CALL vg6d_v7d_var_conv_setup()
479
480#ifdef HAVE_LIBGRIBAPI
481editionnumber=255; category=255; centre=255
482#endif
483IF (PRESENT(grid_id_template)) THEN
484#ifdef HAVE_LIBGRIBAPI
485 gaid = grid_id_get_gaid(grid_id_template)
486 IF (c_e(gaid)) THEN
487 CALL grib_get(gaid, 'GRIBEditionNumber', editionnumber)
488 IF (editionnumber == 1) THEN
489 CALL grib_get(gaid,'gribTablesVersionNo',category)
490 ENDIF
491 CALL grib_get(gaid,'centre',centre)
492 ENDIF
493#endif
494ENDIF
495
496DO i = 1, SIZE(conv_bwd)
497 IF (varbufr == conv_bwd(i)%v7d_var) THEN
498#ifdef HAVE_LIBGRIBAPI
499 IF (editionnumber /= 255) THEN ! further check required (gaid present)
500 IF (editionnumber == 1) THEN
501 IF (conv_bwd(i)%vg6d_var%discipline /= 255) cycle ! wrong edition
502 ELSE IF (editionnumber == 2) THEN
503 IF (conv_bwd(i)%vg6d_var%discipline == 255) cycle ! wrong edition
504 ENDIF
505 IF (conv_bwd(i)%vg6d_var%centre /= 255 .AND. &
506 conv_bwd(i)%vg6d_var%centre /= centre) cycle ! wrong centre
507 ENDIF
508#endif
509 convert = conv_bwd(i)%vg6d_var
510 IF (PRESENT(c_func)) c_func = conv_bwd(i)%c_func
511 RETURN
512 ENDIF
513ENDDO
514! not found
515convert = volgrid6d_var_miss
516IF (PRESENT(c_func)) c_func = conv_func_miss
517
518! if hint available use it as a fallback
519IF (any(varbufr%gribhint /= imiss)) THEN
520 convert%centre = varbufr%gribhint(1)
521 convert%category = varbufr%gribhint(2)
522 convert%number = varbufr%gribhint(3)
523 convert%discipline = varbufr%gribhint(4)
524ENDIF
525
526CALL l4f_log(l4f_warn, 'varbufr2vargrib: variable '// &
527 trim(varbufr%btable)//" : "//trim(varbufr%description)//" : "//trim(varbufr%unit)// &
528 ' not found in table')
529
530END FUNCTION varbufr2vargrib_convert
531
532
533!> Normalize a variable definition converting it to the
534!! format (grib edition) specified in the (grib) template provided.
535!! This allows a basic grib1 <-> grib2 conversion provided that
536!! entries for both grib editions of the related variable are present
537!! in the static file \a vargrib2ufr.csv. If the \a c_func variable
538!! returned is not missing (i.e. /= conv_func_miss) the field value
539!! should be converted as well using the conv_func::compute method .
540SUBROUTINE volgrid6d_var_normalize(this, c_func, grid_id_template)
541TYPE(volgrid6d_var),INTENT(inout) :: this !< variable to normalize
542TYPE(conv_func),INTENT(out) :: c_func !< \a conv_func object to convert data
543TYPE(grid_id),INTENT(in) :: grid_id_template !< a template (typically grib_api) to which data will be finally exported, it helps in improving variable conversion
544
545LOGICAL :: eqed, eqcentre
546INTEGER :: gaid, editionnumber, centre
547TYPE(volgrid6d_var) :: tmpgrib
548TYPE(vol7d_var) :: tmpbufr
549TYPE(conv_func) tmpc_func1, tmpc_func2
550
551eqed = .true.
552eqcentre = .true.
553c_func = conv_func_miss
554
555#ifdef HAVE_LIBGRIBAPI
556gaid = grid_id_get_gaid(grid_id_template)
557IF (c_e(gaid)) THEN
558 CALL grib_get(gaid, 'GRIBEditionNumber', editionnumber)
559 CALL grib_get(gaid, 'centre', centre)
560 eqed = editionnumber == 1 .EQV. this%discipline == 255
561 eqcentre = centre == this%centre
562ENDIF
563#endif
564
565IF (eqed .AND. eqcentre) RETURN ! nothing to do
566
567tmpbufr = convert(this, tmpc_func1)
568tmpgrib = convert(tmpbufr, tmpc_func2, grid_id_template)
569
570IF (tmpgrib /= volgrid6d_var_miss) THEN
571! conversion back and forth successful, set also conversion function
572 this = tmpgrib
573 c_func = tmpc_func1 * tmpc_func2
574! set to missing in common case to avoid useless computation
575 IF (c_func == conv_func_identity) c_func = conv_func_miss
576ELSE IF (.NOT.eqed) THEN
577! conversion back and forth unsuccessful and grib edition incompatible, set to miss
578 this = tmpgrib
579ENDIF
580
581END SUBROUTINE volgrid6d_var_normalize
582
583
584! Private subroutine for reading forward and backward conversion tables
585! todo: better error handling
586SUBROUTINE vg6d_v7d_var_conv_setup()
587INTEGER :: un, i, n, stallo
588
589! forward, grib to bufr
590un = open_package_file('vargrib2bufr.csv', filetype_data)
591n=0
592DO WHILE(.true.)
593 READ(un,*,END=100)
594 n = n + 1
595ENDDO
596
597100 CONTINUE
598
599rewind(un)
600ALLOCATE(conv_fwd(n),stat=stallo)
601IF (stallo /= 0) THEN
602 CALL l4f_log(l4f_fatal,"allocating memory")
603 CALL raise_fatal_error()
604ENDIF
605
606conv_fwd(:) = vg6d_v7d_var_conv_miss
607CALL import_var_conv(un, conv_fwd)
608CLOSE(un)
609
610! backward, bufr to grib
611un = open_package_file('vargrib2bufr.csv', filetype_data)
612! use the same file for now
613!un = open_package_file('varbufr2grib.csv', filetype_data)
614n=0
615DO WHILE(.true.)
616 READ(un,*,END=300)
617 n = n + 1
618ENDDO
619
620300 CONTINUE
621
622rewind(un)
623ALLOCATE(conv_bwd(n),stat=stallo)
624IF (stallo /= 0) THEN
625 CALL l4f_log(l4f_fatal,"allocating memory")
626 CALL raise_fatal_error()
627end if
628
629conv_bwd(:) = vg6d_v7d_var_conv_miss
630CALL import_var_conv(un, conv_bwd)
631DO i = 1, n
632 conv_bwd(i)%c_func%a = 1./conv_bwd(i)%c_func%a
633 conv_bwd(i)%c_func%b = - conv_bwd(i)%c_func%b
634ENDDO
635CLOSE(un)
636
637CONTAINS
638
639SUBROUTINE import_var_conv(un, conv_type)
640INTEGER, INTENT(in) :: un
641TYPE(vg6d_v7d_var_conv), INTENT(out) :: conv_type(:)
642
643INTEGER :: i
644TYPE(csv_record) :: csv
645CHARACTER(len=1024) :: line
646CHARACTER(len=10) :: btable
647INTEGER :: centre, category, number, discipline
648
649DO i = 1, SIZE(conv_type)
650 READ(un,'(A)',END=200)line
651 CALL init(csv, line)
652 CALL csv_record_getfield(csv, btable)
653 CALL csv_record_getfield(csv) ! skip fields for description and unit,
654 CALL csv_record_getfield(csv) ! they correspond to grib information, not bufr Btable
655 CALL init(conv_type(i)%v7d_var, btable=btable)
656
657 CALL csv_record_getfield(csv, centre)
658 CALL csv_record_getfield(csv, category)
659 CALL csv_record_getfield(csv, number)
660 CALL csv_record_getfield(csv, discipline)
661 CALL init(conv_type(i)%vg6d_var, centre=centre, category=category, &
662 number=number, discipline=discipline) ! controllare l'ordine
663
664 CALL csv_record_getfield(csv, conv_type(i)%c_func%a)
665 CALL csv_record_getfield(csv, conv_type(i)%c_func%b)
666 CALL delete(csv)
667ENDDO
668
669200 CONTINUE
670
671END SUBROUTINE import_var_conv
672
673END SUBROUTINE vg6d_v7d_var_conv_setup
674
675
676ELEMENTAL FUNCTION conv_func_eq(this, that) RESULT(res)
677TYPE(conv_func),INTENT(IN) :: this, that
678LOGICAL :: res
679
680res = this%a == that%a .AND. this%b == that%b
681
682END FUNCTION conv_func_eq
683
684
685ELEMENTAL FUNCTION conv_func_ne(this, that) RESULT(res)
686TYPE(conv_func),INTENT(IN) :: this, that
687LOGICAL :: res
688
689res = .NOT.(this == that)
690
691END FUNCTION conv_func_ne
692
693
694FUNCTION conv_func_mult(this, that) RESULT(mult)
695TYPE(conv_func),INTENT(in) :: this
696TYPE(conv_func),INTENT(in) :: that
697
698TYPE(conv_func) :: mult
699
700IF (this == conv_func_miss .OR. that == conv_func_miss) THEN
701 mult = conv_func_miss
702ELSE
703 mult%a = this%a*that%a
704 mult%b = this%a*that%b+this%b
705ENDIF
706
707END FUNCTION conv_func_mult
708
709!> Apply the conversion function \a this to \a values.
710!! The numerical conversion (only linear at the moment) defined by the
711!! \a conv_func object \a this is applied to the \a values argument;
712!! the converted result is stored in place; missing values remain
713!! missing; if the conversion function is undefined (\a
714!! conv_func_miss) the values are unchanged. The method is \c
715!! ELEMENTAL, thus \a values can be also an array of any shape.
716ELEMENTAL SUBROUTINE conv_func_compute(this, values)
717TYPE(conv_func),INTENT(in) :: this !< object defining the conversion function
718REAL,INTENT(inout) :: values !< value to be converted in place
719
720IF (this /= conv_func_miss) THEN
721 IF (c_e(values)) values = values*this%a + this%b
722ELSE
723 values=rmiss
724ENDIF
725
726END SUBROUTINE conv_func_compute
727
728
729!> Locate variables which are horizontal components of a vector field.
730!! This method scans the \a volgrid6d_var array provided and locates
731!! pairs of variables which are x and y component of the same vector
732!! field. On exit, the arrays \x xind(:) and \a yind(:) are allocated
733!! to a size equal to the number of vector fields detected and their
734!! corresponding elements will point to x and y components of the same
735!! vector field. If inconsistencies are found, e.g. only one component
736!! is detected for a field, or more than one input variable define
737!! the same component, then \a xind and \a xind are nullified, thus an
738!! error condition can be tested as \c .NOT.ASSOCIATED(xind). If no
739!! vector fields are found then \a xind and \a xind are allocated to
740!! zero size. If \a xind and \a yind are \c ASSOCIATED() after return,
741!! they should be \c DEALLOCATEd by the calling procedure.
742SUBROUTINE volgrid6d_var_hor_comp_index(this, xind, yind)
743TYPE(volgrid6d_var),INTENT(in) :: this(:) !< array of volgrid6d_var objects (grib variable) to test
744INTEGER,POINTER :: xind(:), yind(:) !< output arrays of indices pointing to matching horizontal components, allocated by this method
745
746TYPE(vol7d_var) :: varbufr(size(this))
747TYPE(conv_func),POINTER :: c_func(:)
748INTEGER :: i, nv, counts(size(vol7d_var_horcomp))
749
750NULLIFY(xind, yind)
751counts(:) = 0
752
753CALL vargrib2varbufr(this, varbufr, c_func)
754
755DO i = 1, SIZE(vol7d_var_horcomp)
756 counts(i) = count(varbufr(:) == vol7d_var_horcomp(i))
757ENDDO
758
759IF (any(counts(1::2) > 1)) THEN
760 CALL l4f_log(l4f_warn, '> 1 variable refer to x component of the same field, (un)rotation impossible')
761 DEALLOCATE(c_func)
762 RETURN
763ENDIF
764IF (any(counts(2::2) > 1)) THEN
765 CALL l4f_log(l4f_warn, '> 1 variable refer to y component of the same field, (un)rotation impossible')
766 DEALLOCATE(c_func)
767 RETURN
768ENDIF
769
770! check that variables are paired and count pairs
771nv = 0
772DO i = 1, SIZE(vol7d_var_horcomp), 2
773 IF (counts(i) == 0 .AND. counts(i+1) > 0) THEN
774 CALL l4f_log(l4f_warn, 'variable '//trim(vol7d_var_horcomp(i+1)%btable)// &
775 ' present but the corresponding x-component '// &
776 trim(vol7d_var_horcomp(i)%btable)//' is missing, (un)rotation impossible')
777 RETURN
778 ELSE IF (counts(i+1) == 0 .AND. counts(i) > 0) THEN
779 CALL l4f_log(l4f_warn, 'variable '//trim(vol7d_var_horcomp(i)%btable)// &
780 ' present but the corresponding y-component '// &
781 trim(vol7d_var_horcomp(i+1)%btable)//' is missing, (un)rotation impossible')
782 RETURN
783 ENDIF
784 IF (counts(i) == 1 .AND. counts(i+1) == 1) nv = nv + 1
785ENDDO
786
787! repeat the loop storing indices
788ALLOCATE(xind(nv), yind(nv))
789nv = 0
790DO i = 1, SIZE(vol7d_var_horcomp), 2
791 IF (counts(i) == 1 .AND. counts(i+1) == 1) THEN
792 nv = nv + 1
793 xind(nv) = index(varbufr(:), vol7d_var_horcomp(i))
794 yind(nv) = index(varbufr(:), vol7d_var_horcomp(i+1))
795 ENDIF
796ENDDO
797DEALLOCATE(c_func)
798
799END SUBROUTINE volgrid6d_var_hor_comp_index
800
801
802!> Tests whether a variable is the horizontal component of a vector field.
803!! Returns \a .TRUE. if the corresponding variable is recognized as an
804!! horizontal component of a vector field; if it is the case the
805!! variable may need rotation in case of coordinate change.
806FUNCTION volgrid6d_var_is_hor_comp(this) RESULT(is_hor_comp)
807TYPE(volgrid6d_var),INTENT(in) :: this !< volgrid6d_var object (grib variable) to test
808LOGICAL :: is_hor_comp
809
810TYPE(vol7d_var) :: varbufr
811
812varbufr = convert(this)
813is_hor_comp = any(varbufr == vol7d_var_horcomp(:))
814
815END FUNCTION volgrid6d_var_is_hor_comp
816
817! before unstaggering??
818
819!IF (.NOT. ALLOCATED(conv_fwd)) CALL vg6d_v7d_var_conv_setup()
820!
821!call init(varu,btable="B11003")
822!call init(varv,btable="B11004")
823!
824! test about presence of u and v in standard table
825!if ( index(conv_fwd(:)%v7d_var,varu) == 0 .or. index(conv_fwd(:)%v7d_var,varv) == 0 )then
826! call l4f_category_log(this%category,L4F_FATAL, &
827! "variables B11003 and/or B11004 (wind components) not defined by vg6d_v7d_var_conv_setup")
828! CALL raise_error()
829! RETURN
830!end if
831!
832!if (associated(this%var))then
833! nvar=size(this%var)
834! allocate(varbufr(nvar),stat=stallo)
835! if (stallo /=0)then
836! call l4f_log(L4F_FATAL,"allocating memory")
837! call raise_fatal_error("allocating memory")
838! end if
839!
840! CALL vargrib2varbufr(this%var, varbufr)
841!ELSE
842! CALL l4f_category_log(this%category, L4F_ERROR, &
843! "trying to destagger an incomplete volgrid6d object")
844! CALL raise_error()
845! RETURN
846!end if
847!
848!nvaru=COUNT(varbufr==varu)
849!nvarv=COUNT(varbufr==varv)
850!
851!if (nvaru > 1 )then
852! call l4f_category_log(this%category,L4F_WARN, &
853! ">1 variables refer to u wind component, destaggering will not be done ")
854! DEALLOCATE(varbufr)
855! RETURN
856!endif
857!
858!if (nvarv > 1 )then
859! call l4f_category_log(this%category,L4F_WARN, &
860! ">1 variables refer to v wind component, destaggering will not be done ")
861! DEALLOCATE(varbufr)
862! RETURN
863!endif
864!
865!if (nvaru == 0 .and. nvarv == 0) then
866! call l4f_category_log(this%category,L4F_WARN, &
867! "no u or v wind component found in volume, nothing to do")
868! DEALLOCATE(varbufr)
869! RETURN
870!endif
871!
872!if (COUNT(varbufr/=varu .and. varbufr/=varv) > 0) then
873! call l4f_category_log(this%category,L4F_WARN, &
874! "there are variables different from u and v wind component in C grid")
875!endif
876
877
878END MODULE volgrid6d_var_class
Index method.
Apply the conversion function this to values.
Apply the conversion function this to values.
Destructor for the corresponding object, it assigns it to a missing value.
Display on the screen a brief content of object.
Initialize a volgrid6d_var object with the optional arguments provided.
Gestione degli errori.
Utilities for managing files.
This module defines an abstract interface to different drivers for access to files containing gridded...
Definition of constants to be used for declaring variables of a desired type.
Definition kinds.F90:245
Definitions of constants and functions for working with missing values.
Classe per la gestione delle variabili osservate da stazioni meteo e affini.
Class for managing physical variables in a grib 1/2 fashion.
Derived type associated to a block/message/record/band of gridded data coming from a file-like object...
Definisce una variabile meteorologica osservata o un suo attributo.
Class defining a real conversion function between units.
Definition of a physical variable in grib coding style.

Generated with Doxygen.