libsim  Versione8.0.0
grid_transform_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 
19 #include "config.h"
20 
217 USE vol7d_class
218 USE err_handling
219 USE geo_proj_class
220 USE grid_class
221 USE grid_dim_class
222 USE optional_values
223 USE array_utilities
225 USE simple_stat
226 USE log4fortran
227 IMPLICIT NONE
228 
229 CHARACTER(len=255),PARAMETER:: subcategory="grid_transform_class"
230 
231 ! information for interpolation aver a rectangular area
232 TYPE area_info
233  double precision :: boxdx ! longitudinal/x extension of the box for box interpolation, default the target x grid step
234  double precision :: boxdy ! latitudinal/y extension of the box for box interpolation, default the target y grid step
235  double precision :: radius ! radius in gridpoints for stencil interpolation
236 END TYPE area_info
237 
238 ! information for statistical processing of interpoland data
239 TYPE stat_info
240  DOUBLE PRECISION :: percentile ! percentile [0,100] of the distribution of points in the box to use as interpolated value, if missing, the average is used, if 0.or 100. the MIN() and MAX() are used as a shortcut
241 END TYPE stat_info
242 
243 ! information for point interval
244 TYPE interval_info
245  REAL :: gt=rmiss ! lower limit of interval, missing for -inf
246  REAL :: lt=rmiss ! upper limit of interval, missing for +inf
247  LOGICAL :: ge=.true. ! if true >= otherwise >
248  LOGICAL :: le=.true. ! if true <= otherwise <
249 END TYPE interval_info
250 
251 ! rectangle index information
252 type rect_ind
253  INTEGER :: ix ! index of initial point of new grid on x
254  INTEGER :: iy ! index of initial point of new grid on y
255  INTEGER :: fx ! index of final point of new grid on x
256  INTEGER :: fy ! index of final point of new grid on y
257 end type rect_ind
258 
259 ! rectangle coord information
260 type rect_coo
261  DOUBLEPRECISION ilon ! coordinate of initial point of new grid on x
262  DOUBLEPRECISION ilat ! coordinate of initial point of new grid on y
263  DOUBLEPRECISION flon ! coordinate of final point of new grid on x
264  DOUBLEPRECISION flat ! coordinate of final point of new grid on y
265 end type rect_coo
266 
267 ! box information
268 type box_info
269  INTEGER :: npx ! number of points along x direction
270  INTEGER :: npy ! number of points along y direction
271 end type box_info
272 
273 ! Vertical interpolation information.
274 ! The input vertical coordinate can be indicated either as the value
275 ! of the vertical level (so that it will be the same on every point
276 ! at a given vertical level), or as the value of a specified variable
277 ! at each point in space (so that it will depend on the horizontal
278 ! position too).
279 TYPE vertint
280 ! CHARACTER(len=80) :: sub_type ! subtype of transformation, can be \c 'linear'
281  TYPE(vol7d_level) :: input_levtype ! type of vertical level of input data (only type of first and second surface are used, level values are ignored)
282  TYPE(vol7d_var) :: input_coordvar ! variable that defines the vertical coordinate in the input volume, if missing, the value of the vertical level is used
283  TYPE(vol7d_level) :: output_levtype ! type of vertical level of output data (only type of first and second surface are used, level values are ignored)
284 END TYPE vertint
285 
291 TYPE transform_def
292  PRIVATE
293  CHARACTER(len=80) :: trans_type ! type of transformation, can be \c 'zoom', \c 'boxregrid', \c 'inter', \c 'vertint' ...
294  CHARACTER(len=80) :: sub_type ! subtype of transformation, can be \c 'linear'
295  LOGICAL :: extrap ! enable elaboration outside data bounding box
296  TYPE(rect_ind) :: rect_ind ! rectangle information by index
297  TYPE(rect_coo) :: rect_coo ! rectangle information by coordinates
298  TYPE(area_info) :: area_info !
299  TYPE(arrayof_georef_coord_array) :: poly ! polygon information
300  TYPE(stat_info) :: stat_info !
301  TYPE(interval_info) :: interval_info !
302  TYPE(box_info) :: box_info ! boxregrid specification
303  TYPE(vertint) :: vertint ! vertical interpolation specification
304  INTEGER :: time_definition ! time definition for interpolating to sparse points
305  TYPE(l4f_handle) :: category ! category for log4fortran
306 END TYPE transform_def
307 
308 
315 TYPE grid_transform
316  PRIVATE
317  TYPE(transform_def),PUBLIC :: trans ! type of transformation required
318  INTEGER :: innx = imiss
319  INTEGER :: inny = imiss
320  INTEGER :: innz = imiss
321  INTEGER :: outnx = imiss
322  INTEGER :: outny = imiss
323  INTEGER :: outnz = imiss
324  INTEGER :: levshift = imiss
325  INTEGER :: levused = imiss
326  INTEGER :: iniox,inioy,infox,infoy,outinx,outiny,outfnx,outfny
327  INTEGER,POINTER :: inter_index_x(:,:) => null()
328  INTEGER,POINTER :: inter_index_y(:,:) => null()
329  INTEGER,POINTER :: inter_index_z(:) => null()
330  INTEGER,POINTER :: point_index(:,:) => null()
331  DOUBLE PRECISION,POINTER :: inter_x(:,:) => null()
332  DOUBLE PRECISION,POINTER :: inter_y(:,:) => null()
333  DOUBLE PRECISION,POINTER :: inter_xp(:,:) => null()
334  DOUBLE PRECISION,POINTER :: inter_yp(:,:) => null()
335  DOUBLE PRECISION,POINTER :: inter_zp(:) => null()
336  DOUBLE PRECISION,POINTER :: vcoord_in(:) => null()
337  DOUBLE PRECISION,POINTER :: vcoord_out(:) => null()
338  LOGICAL,POINTER :: point_mask(:,:) => null()
339  LOGICAL,POINTER :: stencil(:,:) => null()
340  REAL,ALLOCATABLE :: coord_3d_in(:,:,:)
341  REAL,ALLOCATABLE :: val_mask(:,:)
342  REAL :: val1 = rmiss
343  REAL :: val2 = rmiss
344  LOGICAL :: recur = .false.
345  LOGICAL :: dolog = .false. ! must compute log() of vert coord before vertint
346 
347 ! type(volgrid6d) :: input_vertcoordvol ! volume which provides the input vertical coordinate if separated from the data volume itself (for vertint) cannot be here because of cross-use, should be an argument of compute
348 ! type(vol7d_level), pointer :: output_vertlevlist(:) ! list of vertical levels of output data (for vertint) can be here or an argument of compute, how to do?
349  TYPE(vol7d_level),POINTER :: output_level_auto(:) => null() ! array of auto-generated levels, stored for successive query
350  TYPE(l4f_handle) :: category ! category for log4fortran
351  LOGICAL :: valid = .false. ! the transformation has been successfully initialised
352  PROCEDURE(basic_find_index),NOPASS,POINTER :: find_index => basic_find_index ! allow a local implementation of find_index
353 END TYPE grid_transform
354 
355 
357 INTERFACE init
358  MODULE PROCEDURE transform_init, grid_transform_levtype_levtype_init, &
359  grid_transform_init, &
360  grid_transform_grid_vol7d_init, grid_transform_vol7d_grid_init, &
361  grid_transform_vol7d_vol7d_init
362 END INTERFACE
363 
365 INTERFACE delete
366  MODULE PROCEDURE transform_delete, grid_transform_delete
367 END INTERFACE
368 
370 INTERFACE get_val
371  MODULE PROCEDURE transform_get_val, grid_transform_get_val
372 END INTERFACE
373 
376 INTERFACE compute
377  MODULE PROCEDURE grid_transform_compute, grid_transform_v7d_grid_compute
378 END INTERFACE
379 
382 INTERFACE c_e
383  MODULE PROCEDURE grid_transform_c_e
384 END INTERFACE
385 
386 PRIVATE
387 PUBLIC init, delete, get_val, compute, c_e
389 PUBLIC interval_info, interval_info_new, interval_info_valid, basic_find_index
390 
391 CONTAINS
392 
393 
394 FUNCTION interval_info_new(interv_gt, interv_ge, interv_lt, interv_le) RESULT(this)
395 REAL,INTENT(in),OPTIONAL :: interv_gt
396 REAL,INTENT(in),OPTIONAL :: interv_ge
397 REAL,INTENT(in),OPTIONAL :: interv_lt
398 REAL,INTENT(in),OPTIONAL :: interv_le
399 
400 TYPE(interval_info) :: this
401 
402 IF (PRESENT(interv_gt)) THEN
403  IF (c_e(interv_gt)) THEN
404  this%gt = interv_gt
405  this%ge = .false.
406  ENDIF
407 ENDIF
408 IF (PRESENT(interv_ge)) THEN
409  IF (c_e(interv_ge)) THEN
410  this%gt = interv_ge
411  this%ge = .true.
412  ENDIF
413 ENDIF
414 IF (PRESENT(interv_lt)) THEN
415  IF (c_e(interv_lt)) THEN
416  this%lt = interv_lt
417  this%le = .false.
418  ENDIF
419 ENDIF
420 IF (PRESENT(interv_le)) THEN
421  IF (c_e(interv_le)) THEN
422  this%lt = interv_le
423  this%le = .true.
424  ENDIF
425 ENDIF
426 
427 END FUNCTION interval_info_new
428 
429 ! Private method for testing whether \a val is included in \a this
430 ! interval taking into account all cases, zero, one or two extremes,
431 ! strict or non strict inclusion, empty interval, etc, while no check
432 ! is made for val being missing. Returns 1.0 if val is in interval and
433 ! 0.0 if not.
434 ELEMENTAL FUNCTION interval_info_valid(this, val)
435 TYPE(interval_info),INTENT(in) :: this
436 REAL,INTENT(in) :: val
437 
438 REAL :: interval_info_valid
439 
440 interval_info_valid = 1.0
441 
442 IF (c_e(this%gt)) THEN
443  IF (val < this%gt) interval_info_valid = 0.0
444  IF (.NOT.this%ge) THEN
445  IF (val == this%gt) interval_info_valid = 0.0
446  ENDIF
447 ENDIF
448 IF (c_e(this%lt)) THEN
449  IF (val > this%lt) interval_info_valid = 0.0
450  IF (.NOT.this%le) THEN
451  IF (val == this%lt) interval_info_valid = 0.0
452  ENDIF
453 ENDIF
454 
455 END FUNCTION interval_info_valid
456 
463 SUBROUTINE transform_init(this, trans_type, sub_type, &
464  ix, iy, fx, fy, ilon, ilat, flon, flat, &
465  npx, npy, boxdx, boxdy, radius, poly, percentile, &
466  interv_gt, interv_ge, interv_lt, interv_le, &
467  extrap, time_definition, &
468  input_levtype, input_coordvar, output_levtype, categoryappend)
469 TYPE(transform_def),INTENT(out) :: this
470 CHARACTER(len=*) :: trans_type
471 CHARACTER(len=*) :: sub_type
472 INTEGER,INTENT(in),OPTIONAL :: ix
473 INTEGER,INTENT(in),OPTIONAL :: iy
474 INTEGER,INTENT(in),OPTIONAL :: fx
475 INTEGER,INTENT(in),OPTIONAL :: fy
476 DOUBLEPRECISION,INTENT(in),OPTIONAL :: ilon
477 DOUBLEPRECISION,INTENT(in),OPTIONAL :: ilat
478 DOUBLEPRECISION,INTENT(in),OPTIONAL :: flon
479 DOUBLEPRECISION,INTENT(in),OPTIONAL :: flat
480 INTEGER,INTENT(IN),OPTIONAL :: npx
481 INTEGER,INTENT(IN),OPTIONAL :: npy
482 DOUBLEPRECISION,INTENT(in),OPTIONAL :: boxdx
483 DOUBLEPRECISION,INTENT(in),OPTIONAL :: boxdy
484 DOUBLEPRECISION,INTENT(in),OPTIONAL :: radius
485 TYPE(arrayof_georef_coord_array),OPTIONAL :: poly
486 DOUBLEPRECISION,INTENT(in),OPTIONAL :: percentile
487 REAL,INTENT(in),OPTIONAL :: interv_gt
488 REAL,INTENT(in),OPTIONAL :: interv_ge
489 REAL,INTENT(in),OPTIONAL :: interv_lt
490 REAL,INTENT(in),OPTIONAL :: interv_le
491 LOGICAL,INTENT(IN),OPTIONAL :: extrap
492 INTEGER,INTENT(IN),OPTIONAL :: time_definition
493 TYPE(vol7d_level),INTENT(IN),OPTIONAL :: input_levtype
494 TYPE(vol7d_var),INTENT(IN),OPTIONAL :: input_coordvar
495 TYPE(vol7d_level),INTENT(IN),OPTIONAL :: output_levtype
496 character(len=*),INTENT(in),OPTIONAL :: categoryappend
497 
498 character(len=512) :: a_name
499 
500 IF (PRESENT(categoryappend)) THEN
501  CALL l4f_launcher(a_name,a_name_append=trim(subcategory)//"."// &
502  trim(categoryappend))
503 ELSE
504  CALL l4f_launcher(a_name,a_name_append=trim(subcategory))
505 ENDIF
506 this%category=l4f_category_get_handle(a_name)
507 
508 this%trans_type = trans_type
509 this%sub_type = sub_type
510 
511 CALL optio(extrap,this%extrap)
512 
513 call optio(ix,this%rect_ind%ix)
514 call optio(iy,this%rect_ind%iy)
515 call optio(fx,this%rect_ind%fx)
516 call optio(fy,this%rect_ind%fy)
517 
518 call optio(ilon,this%rect_coo%ilon)
519 call optio(ilat,this%rect_coo%ilat)
520 call optio(flon,this%rect_coo%flon)
521 call optio(flat,this%rect_coo%flat)
522 
523 CALL optio(boxdx,this%area_info%boxdx)
524 CALL optio(boxdy,this%area_info%boxdy)
525 CALL optio(radius,this%area_info%radius)
526 IF (PRESENT(poly)) this%poly = poly
527 CALL optio(percentile,this%stat_info%percentile)
528 
529 this%interval_info = interval_info_new(interv_gt, interv_ge, interv_lt, interv_le)
530 
531 CALL optio(npx,this%box_info%npx)
532 CALL optio(npy,this%box_info%npy)
533 
534 IF (PRESENT(input_levtype)) THEN
535  this%vertint%input_levtype = input_levtype
536 ELSE
537  this%vertint%input_levtype = vol7d_level_miss
538 ENDIF
539 IF (PRESENT(input_coordvar)) THEN
540  this%vertint%input_coordvar = input_coordvar
541 ELSE
542  this%vertint%input_coordvar = vol7d_var_miss
543 ENDIF
544 IF (PRESENT(output_levtype)) THEN
545  this%vertint%output_levtype = output_levtype
546 ELSE
547  this%vertint%output_levtype = vol7d_level_miss
548 ENDIF
549 
550 call optio(time_definition,this%time_definition)
551 if (c_e(this%time_definition) .and. &
552  (this%time_definition < 0 .OR. this%time_definition > 2))THEN
553  call l4f_category_log(this%category,l4f_error,"Error time_definition invalid: "//to_char(this%time_definition))
554  call raise_fatal_error()
555 end if
556 
557 
558 IF (this%trans_type == 'zoom') THEN
559 
560  IF (this%sub_type == 'coord' .OR. this%sub_type == 'projcoord')THEN
561 
562  if (c_e(this%rect_coo%ilon) .and. c_e(this%rect_coo%ilat) .and. &
563  c_e(this%rect_coo%flon) .and. c_e(this%rect_coo%flat)) then ! coordinates given
564 
565 !check
566  if ( this%rect_coo%ilon > this%rect_coo%flon .or. &
567  this%rect_coo%ilat > this%rect_coo%flat ) then
569  call l4f_category_log(this%category,l4f_error, &
570  "invalid zoom coordinates: ")
571  call l4f_category_log(this%category,l4f_error, &
572  trim(to_char(this%rect_coo%ilon))//'/'// &
573  trim(to_char(this%rect_coo%flon)))
574  call l4f_category_log(this%category,l4f_error, &
575  trim(to_char(this%rect_coo%ilat))//'/'// &
576  trim(to_char(this%rect_coo%flat)))
577  call raise_fatal_error()
578  end if
579 
580  else
581 
582  call l4f_category_log(this%category,l4f_error,"zoom: coord parameters missing")
583  call raise_fatal_error()
584 
585  end if
586 
587  else if (this%sub_type == 'coordbb')then
588 
589  if (c_e(this%rect_coo%ilon) .and. c_e(this%rect_coo%ilat) .and. &
590  c_e(this%rect_coo%flon) .and. c_e(this%rect_coo%flat)) then ! coordinates given
591  else
592 
593  call l4f_category_log(this%category,l4f_error,"zoom: coordbb parameters missing")
594  call raise_fatal_error()
595 
596  end if
597 
598  else if (this%sub_type == 'index')then
599 
600  IF (c_e(this%rect_ind%ix) .AND. c_e(this%rect_ind%iy) .AND. &
601  c_e(this%rect_ind%fx) .AND. c_e(this%rect_ind%fy)) THEN
602 
603 ! check
604  IF (this%rect_ind%ix > this%rect_ind%fx .OR. &
605  this%rect_ind%iy > this%rect_ind%fy) THEN
606 
607  CALL l4f_category_log(this%category,l4f_error,'invalid zoom indices: ')
608  CALL l4f_category_log(this%category,l4f_error, &
609  trim(to_char(this%rect_ind%ix))//'/'// &
610  trim(to_char(this%rect_ind%fx)))
611  CALL l4f_category_log(this%category,l4f_error, &
612  trim(to_char(this%rect_ind%iy))//'/'// &
613  trim(to_char(this%rect_ind%fy)))
614 
615  CALL raise_fatal_error()
616  ENDIF
617 
618  ELSE
619 
620  CALL l4f_category_log(this%category,l4f_error,&
621  'zoom: index parameters ix, iy, fx, fy not provided')
622  CALL raise_fatal_error()
623 
624  ENDIF
625 
626  ELSE
627  CALL sub_type_error()
628  RETURN
629  END IF
630 
631 ELSE IF (this%trans_type == 'inter' .OR. this%trans_type == 'intersearch') THEN
632 
633  IF (this%sub_type == 'near' .OR. this%sub_type == 'bilin' .OR. &
634  this%sub_type == 'linear' .OR. this%sub_type == 'shapiro_near') THEN
635 ! nothing to do here
636  ELSE
637  CALL sub_type_error()
638  RETURN
639  ENDIF
640 
641 ELSE IF (this%trans_type == 'boxregrid' .OR. this%trans_type == 'boxinter' .OR. &
642  this%trans_type == 'polyinter' .OR. this%trans_type == 'maskinter' .OR. &
643  this%trans_type == 'stencilinter') THEN
644 
645  IF (this%trans_type == 'boxregrid') THEN
646  IF (c_e(this%box_info%npx) .AND. c_e(this%box_info%npy)) THEN
647  IF (this%box_info%npx <= 0 .OR. this%box_info%npy <= 0 ) THEN
648  CALL l4f_category_log(this%category,l4f_error,'boxregrid: invalid parameters '//&
649  trim(to_char(this%box_info%npx))//' '//trim(to_char(this%box_info%npy)))
650  CALL raise_fatal_error()
651  ENDIF
652  ELSE
653  CALL l4f_category_log(this%category,l4f_error, &
654  'boxregrid: parameters npx, npy missing')
655  CALL raise_fatal_error()
656  ENDIF
657  ENDIF
658 
659  IF (this%trans_type == 'polyinter') THEN
660  IF (this%poly%arraysize <= 0) THEN
661  CALL l4f_category_log(this%category,l4f_error, &
662  "polyinter: poly parameter missing or empty")
663  CALL raise_fatal_error()
664  ENDIF
665  ENDIF
666 
667  IF (this%trans_type == 'stencilinter') THEN
668  IF (.NOT.c_e(this%area_info%radius)) THEN
669  CALL l4f_category_log(this%category,l4f_error, &
670  "stencilinter: radius parameter missing")
671  CALL raise_fatal_error()
672  ENDIF
673  ENDIF
674 
675  IF (this%sub_type == 'average' .OR. this%sub_type == 'stddev' &
676  .OR. this%sub_type == 'stddevnm1') THEN
677  this%stat_info%percentile = rmiss
678  ELSE IF (this%sub_type == 'max') THEN
679  this%stat_info%percentile = 101.
680  ELSE IF (this%sub_type == 'min') THEN
681  this%stat_info%percentile = -1.
682  ELSE IF (this%sub_type == 'percentile') THEN
683  IF (.NOT.c_e(this%stat_info%percentile)) THEN
684  CALL l4f_category_log(this%category,l4f_error,trim(this%trans_type)// &
685  ':percentile: percentile value not provided')
686  CALL raise_fatal_error()
687  ELSE IF (this%stat_info%percentile >= 100.) THEN
688  this%sub_type = 'max'
689  ELSE IF (this%stat_info%percentile <= 0.) THEN
690  this%sub_type = 'min'
691  ENDIF
692  ELSE IF (this%sub_type == 'frequency') THEN
693  IF (.NOT.c_e(this%interval_info%gt) .AND. .NOT.c_e(this%interval_info%gt)) THEN
694  CALL l4f_category_log(this%category,l4f_error,trim(this%trans_type)// &
695  ':frequency: lower and/or upper limit not provided')
696  CALL raise_fatal_error()
697  ENDIF
698  ELSE
699  CALL sub_type_error()
700  RETURN
701  ENDIF
702 
703 ELSE IF (this%trans_type == 'maskgen')THEN
704 
705  IF (this%sub_type == 'poly') THEN
706 
707  IF (this%poly%arraysize <= 0) THEN
708  CALL l4f_category_log(this%category,l4f_error,"maskgen:poly poly parameter missing or empty")
709  CALL raise_fatal_error()
710  ENDIF
711 
712  ELSE IF (this%sub_type == 'grid') THEN
713 ! nothing to do for now
714 
715  ELSE
716  CALL sub_type_error()
717  RETURN
718  ENDIF
719 
720 ELSE IF (this%trans_type == 'vertint') THEN
721 
722  IF (this%vertint%input_levtype == vol7d_level_miss) THEN
723  CALL l4f_category_log(this%category,l4f_error, &
724  'vertint parameter input_levtype not provided')
725  CALL raise_fatal_error()
726  ENDIF
727 
728  IF (this%vertint%output_levtype == vol7d_level_miss) THEN
729  CALL l4f_category_log(this%category,l4f_error, &
730  'vertint parameter output_levtype not provided')
731  CALL raise_fatal_error()
732  ENDIF
733 
734  IF (this%sub_type == 'linear' .OR. this%sub_type == 'linearsparse') THEN
735 ! nothing to do here
736  ELSE
737  CALL sub_type_error()
738  RETURN
739  ENDIF
740 
741 ELSE IF (this%trans_type == 'metamorphosis') THEN
742 
743  IF (this%sub_type == 'all') THEN
744 ! nothing to do here
745  ELSE IF (this%sub_type == 'coordbb')THEN
746 
747  IF (c_e(this%rect_coo%ilon) .AND. c_e(this%rect_coo%ilat) .AND. &
748  c_e(this%rect_coo%flon) .AND. c_e(this%rect_coo%flat)) THEN ! coordinates given
749  ELSE
750 
751  CALL l4f_category_log(this%category,l4f_error,"metamorphosis: coordbb parameters missing")
752  CALL raise_fatal_error()
753 
754  ENDIF
755 
756  ELSE IF (this%sub_type == 'poly')THEN
757 
758  IF (this%poly%arraysize <= 0) THEN
759  CALL l4f_category_log(this%category,l4f_error,"metamorphosis:poly: poly parameter missing or empty")
760  CALL raise_fatal_error()
761  ENDIF
762 
763  ELSE IF (this%sub_type == 'mask' .OR. this%sub_type == 'maskvalid' .OR. &
764  this%sub_type == 'maskinvalid' .OR. this%sub_type == 'setinvalidto' .OR. &
765  this%sub_type == 'settoinvalid' .OR. this%sub_type == 'lemaskinvalid' .OR. &
766  this%sub_type == 'ltmaskinvalid' .OR. this%sub_type == 'gemaskinvalid' .OR. &
767  this%sub_type == 'gtmaskinvalid' .OR. this%sub_type == 'index') THEN
768 ! nothing to do here
769  ELSE
770  CALL sub_type_error()
771  RETURN
772  ENDIF
773 
774 ELSE
775  CALL trans_type_error()
776  RETURN
777 ENDIF
778 
779 CONTAINS
780 
781 SUBROUTINE sub_type_error()
782 
783 CALL l4f_category_log(this%category, l4f_error, trim(this%trans_type) &
784  //': sub_type '//trim(this%sub_type)//' is not defined')
785 CALL raise_fatal_error()
786 
787 END SUBROUTINE sub_type_error
788 
789 SUBROUTINE trans_type_error()
790 
791 CALL l4f_category_log(this%category, l4f_error, 'trans_type '//this%trans_type &
792  //' is not defined')
793 CALL raise_fatal_error()
794 
795 END SUBROUTINE trans_type_error
796 
797 
798 END SUBROUTINE transform_init
799 
800 
804 SUBROUTINE transform_delete(this)
805 TYPE(transform_def),INTENT(inout) :: this
806 
807 this%trans_type=cmiss
808 this%sub_type=cmiss
809 
810 this%rect_ind%ix=imiss
811 this%rect_ind%iy=imiss
812 this%rect_ind%fx=imiss
813 this%rect_ind%fy=imiss
814 
815 this%rect_coo%ilon=dmiss
816 this%rect_coo%ilat=dmiss
817 this%rect_coo%flon=dmiss
818 this%rect_coo%flat=dmiss
819 
820 this%box_info%npx=imiss
821 this%box_info%npy=imiss
822 
823 this%extrap=.false.
824 
825 !chiudo il logger
826 CALL l4f_category_delete(this%category)
827 
828 END SUBROUTINE transform_delete
829 
830 
832 SUBROUTINE transform_get_val(this, time_definition, trans_type, sub_type, &
833  input_levtype, output_levtype)
834 type(transform_def),intent(in) :: this
835 INTEGER,INTENT(out),OPTIONAL :: time_definition
836 CHARACTER(len=*),INTENT(out),OPTIONAL :: trans_type
837 CHARACTER(len=*),INTENT(out),OPTIONAL :: sub_type
838 TYPE(vol7d_level),INTENT(out),OPTIONAL :: input_levtype
839 
840 TYPE(vol7d_level),INTENT(out),OPTIONAL :: output_levtype
841 
842 
843 IF (PRESENT(time_definition)) time_definition=this%time_definition
844 IF (PRESENT(trans_type)) trans_type = this%trans_type
845 IF (PRESENT(sub_type)) sub_type = this%sub_type
846 IF (PRESENT(input_levtype)) input_levtype = this%vertint%input_levtype
847 IF (PRESENT(output_levtype)) output_levtype = this%vertint%output_levtype
848 
849 
850 END SUBROUTINE transform_get_val
851 
852 
896 SUBROUTINE grid_transform_levtype_levtype_init(this, trans, lev_in, lev_out, &
897  coord_3d_in, categoryappend)
898 TYPE(grid_transform),INTENT(out) :: this
899 TYPE(transform_def),INTENT(in) :: trans
900 TYPE(vol7d_level),INTENT(in) :: lev_in(:)
901 TYPE(vol7d_level),INTENT(in) :: lev_out(:)
902 REAL,INTENT(inout),OPTIONAL,ALLOCATABLE :: coord_3d_in(:,:,:)
903 CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend
904 
905 DOUBLE PRECISION :: coord_in(SIZE(lev_in))
906 DOUBLE PRECISION,ALLOCATABLE :: coord_out(:)
907 LOGICAL :: mask_in(SIZE(lev_in))
908 LOGICAL,ALLOCATABLE :: mask_out(:)
909 LOGICAL :: dolog
910 INTEGER :: i, j, icache, inused, istart, iend, ostart, oend
911 
912 
913 CALL grid_transform_init_common(this, trans, categoryappend)
914 #ifdef DEBUG
915 CALL l4f_category_log(this%category, l4f_debug, "grid_transform vertint")
916 #endif
917 
918 IF (this%trans%trans_type == 'vertint') THEN
919 
920  IF (c_e(trans%vertint%input_levtype%level2) .AND. &
921  trans%vertint%input_levtype%level1 /= trans%vertint%input_levtype%level2) THEN
922  CALL l4f_category_log(this%category, l4f_error, &
923  'vertint: input upper and lower surface must be of the same type, '// &
924  t2c(trans%vertint%input_levtype%level1)//'/='// &
925  t2c(trans%vertint%input_levtype%level2))
926  CALL raise_error()
927  RETURN
928  ENDIF
929  IF (c_e(trans%vertint%output_levtype%level2) .AND. &
930  trans%vertint%output_levtype%level1 /= trans%vertint%output_levtype%level2) THEN
931  CALL l4f_category_log(this%category, l4f_error, &
932  'vertint: output upper and lower surface must be of the same type'// &
933  t2c(trans%vertint%output_levtype%level1)//'/='// &
934  t2c(trans%vertint%output_levtype%level2))
935  CALL raise_error()
936  RETURN
937  ENDIF
938 
939  mask_in(:) = (lev_in(:)%level1 == trans%vertint%input_levtype%level1) .AND. &
940  (lev_in(:)%level2 == trans%vertint%input_levtype%level2)
941  CALL make_vert_coord(lev_in, mask_in, coord_in, dolog)
942  this%innz = SIZE(lev_in)
943  istart = firsttrue(mask_in)
944  iend = lasttrue(mask_in)
945  inused = iend - istart + 1
946  IF (inused /= count(mask_in)) THEN
947  CALL l4f_category_log(this%category, l4f_error, &
948  'grid_transform_levtype_levtype_init: input levels badly sorted '//&
949  t2c(inused)//'/'//t2c(count(mask_in)))
950  CALL raise_error()
951  RETURN
952  ENDIF
953  this%levshift = istart-1
954  this%levused = inused
955 
956  IF (trans%vertint%input_levtype%level1 /= trans%vertint%output_levtype%level1) THEN
957 #ifdef DEBUG
958  CALL l4f_category_log(this%category, l4f_debug, &
959  'vertint: different input and output level types '// &
960  t2c(trans%vertint%input_levtype%level1)//' '// &
961  t2c(trans%vertint%output_levtype%level1))
962 #endif
963 
964  ALLOCATE(mask_out(SIZE(lev_out)), this%vcoord_out(SIZE(lev_out)))
965  mask_out(:) = (lev_out(:)%level1 == trans%vertint%output_levtype%level1) .AND. &
966  (lev_out(:)%level2 == trans%vertint%output_levtype%level2)
967  CALL make_vert_coord(lev_out, mask_out, this%vcoord_out, dolog)
968  this%outnz = SIZE(mask_out)
969  DEALLOCATE(mask_out)
970 
971  IF (.NOT.PRESENT(coord_3d_in)) THEN
972  CALL l4f_category_log(this%category, l4f_warn, &
973  'vertint: different input and output level types &
974  &and no coord_3d_in, expecting vert. coord. in volume')
975  this%dolog = dolog ! a little bit dirty, I must compute log later
976  ELSE
977  IF (SIZE(coord_3d_in,3) /= inused) THEN
978  CALL l4f_category_log(this%category, l4f_error, &
979  'vertint: vertical size of coord_3d_in (vertical coordinate) &
980  &different from number of input levels suitable for interpolation')
981  CALL l4f_category_log(this%category, l4f_error, &
982  'coord_3d_in: '//t2c(SIZE(coord_3d_in,3))// &
983  ', input levels for interpolation: '//t2c(inused))
984  CALL raise_error()
985  RETURN
986  ENDIF
987 
988  CALL move_alloc(coord_3d_in, this%coord_3d_in) ! steal allocation
989  IF (dolog) THEN
990  WHERE(c_e(this%coord_3d_in) .AND. this%coord_3d_in > 0.0)
991  this%coord_3d_in = log(this%coord_3d_in)
992  ELSE WHERE
993  this%coord_3d_in = rmiss
994  END WHERE
995  ENDIF
996  ENDIF
997 
998  this%valid = .true. ! warning, no check of subtype
999 
1000  ELSE
1001 ! here we assume that valid levels are contiguous and ordered
1002 
1003 #ifdef DEBUG
1004  CALL l4f_category_log(this%category, l4f_debug, &
1005  'vertint: equal input and output level types '// &
1006  t2c(trans%vertint%input_levtype%level1))
1007 #endif
1008 
1009  IF (SIZE(lev_out) > 0) THEN ! output level list provided
1010  ALLOCATE(mask_out(SIZE(lev_out)), coord_out(SIZE(lev_out)))
1011  mask_out(:) = (lev_out(:)%level1 == trans%vertint%output_levtype%level1) .AND. &
1012  (lev_out(:)%level2 == trans%vertint%output_levtype%level2)
1013  CALL make_vert_coord(lev_out, mask_out, coord_out, dolog)
1014 
1015  ELSE ! output level list not provided, try to autogenerate
1016  IF (c_e(trans%vertint%input_levtype%level2) .AND. &
1017  .NOT.c_e(trans%vertint%output_levtype%level2)) THEN ! full -> half
1018  IF (trans%vertint%output_levtype%level1 == 105 .OR. &
1019  trans%vertint%output_levtype%level1 == 150) THEN
1020  ALLOCATE(this%output_level_auto(inused-1))
1021  CALL l4f_category_log(this%category,l4f_info, &
1022  'grid_transform_levtype_levtype_init: autogenerating '//t2c(inused-1) &
1023  //'/'//t2c(iend-istart)//' output levels (f->h)')
1024  DO i = istart, iend - 1
1025  CALL init(this%output_level_auto(i-istart+1), &
1026  trans%vertint%input_levtype%level1, lev_in(i)%l2)
1027  ENDDO
1028  ELSE
1029  CALL l4f_category_log(this%category, l4f_error, &
1030  'grid_transform_levtype_levtype_init: automatic generation of output levels &
1031  &available only for hybrid levels')
1032  CALL raise_error()
1033  RETURN
1034  ENDIF
1035  ELSE IF (.NOT.c_e(trans%vertint%input_levtype%level2) .AND. &
1036  c_e(trans%vertint%output_levtype%level2)) THEN ! half -> full
1037  ALLOCATE(this%output_level_auto(inused-1))
1038  IF (trans%vertint%output_levtype%level1 == 105 .OR. &
1039  trans%vertint%output_levtype%level1 == 150) THEN
1040  CALL l4f_category_log(this%category,l4f_info, &
1041  'grid_transform_levtype_levtype_init: autogenerating '//t2c(inused-1) &
1042  //'/'//t2c(iend-istart)//' output levels (h->f)')
1043  DO i = istart, iend - 1
1044  CALL init(this%output_level_auto(i-istart+1), trans%vertint%input_levtype%level1, &
1045  lev_in(i)%l1, trans%vertint%input_levtype%level1, &
1046  lev_in(i)%l1+1)
1047  ENDDO
1048  ELSE
1049  CALL l4f_category_log(this%category, l4f_error, &
1050  'grid_transform_levtype_levtype_init: automatic generation of output levels &
1051  &available only for hybrid levels')
1052  CALL raise_error()
1053  RETURN
1054  ENDIF
1055  ELSE
1056  CALL l4f_category_log(this%category, l4f_error, &
1057  'grid_transform_levtype_levtype_init: strange situation'// &
1058  to_char(c_e(trans%vertint%input_levtype%level2))//' '// &
1059  to_char(c_e(trans%vertint%output_levtype%level2)))
1060  CALL raise_error()
1061  RETURN
1062  ENDIF
1063  ALLOCATE(coord_out(inused-1), mask_out(inused-1))
1064  mask_out(:) = .true.
1065  CALL make_vert_coord(this%output_level_auto, mask_out, coord_out, dolog)
1066  ENDIF
1067 
1068  this%outnz = SIZE(mask_out)
1069  ostart = firsttrue(mask_out)
1070  oend = lasttrue(mask_out)
1071 
1072 ! set valid = .FALSE. here?
1073  IF (istart == 0) THEN
1074  CALL l4f_category_log(this%category, l4f_warn, &
1075  'grid_transform_levtype_levtype_init: &
1076  &input contains no vertical levels of type ('// &
1077  trim(to_char(trans%vertint%input_levtype%level1))//','// &
1078  trim(to_char(trans%vertint%input_levtype%level2))// &
1079  ') suitable for interpolation')
1080  RETURN
1081 ! iend = -1 ! for loops
1082  ELSE IF (istart == iend) THEN
1083  CALL l4f_category_log(this%category, l4f_warn, &
1084  'grid_transform_levtype_levtype_init: &
1085  &input contains only 1 vertical level of type ('// &
1086  trim(to_char(trans%vertint%input_levtype%level1))//','// &
1087  trim(to_char(trans%vertint%input_levtype%level2))// &
1088  ') suitable for interpolation')
1089  ENDIF
1090  IF (ostart == 0) THEN
1091  CALL l4f_category_log(this%category, l4f_warn, &
1092  'grid_transform_levtype_levtype_init: &
1093  &output contains no vertical levels of type ('// &
1094  trim(to_char(trans%vertint%output_levtype%level1))//','// &
1095  trim(to_char(trans%vertint%output_levtype%level2))// &
1096  ') suitable for interpolation')
1097  RETURN
1098 ! oend = -1 ! for loops
1099  ENDIF
1100 
1101 ! end of code common for all vertint subtypes
1102  IF (this%trans%sub_type == 'linear') THEN
1103 
1104  ALLOCATE(this%inter_index_z(this%outnz), this%inter_zp(this%outnz))
1105  this%inter_index_z(:) = imiss
1106  this%inter_zp(:) = dmiss
1107  IF (this%trans%extrap .AND. istart > 0) THEN
1108  WHERE(mask_out)
1109 ! extrapolate down by default
1110  this%inter_index_z(:) = istart
1111  this%inter_zp(:) = 1.0d0
1112  ENDWHERE
1113  ENDIF
1114 
1115  icache = istart + 1
1116  outlev: DO j = ostart, oend
1117  inlev: DO i = icache, iend
1118  IF (coord_in(i) >= coord_out(j)) THEN
1119  IF (coord_out(j) >= coord_in(i-1)) THEN
1120  this%inter_index_z(j) = i - 1
1121  this%inter_zp(j) = (coord_out(j)-coord_in(i-1)) / &
1122  (coord_in(i)-coord_in(i-1)) ! weight for (i)
1123  icache = i ! speedup next j iteration
1124  ENDIF
1125  cycle outlev ! found or extrapolated down
1126  ENDIF
1127  ENDDO inlev
1128 ! if I'm here I must extrapolate up
1129  IF (this%trans%extrap .AND. iend > 1) THEN
1130  this%inter_index_z(j) = iend - 1
1131  this%inter_zp(j) = 0.0d0
1132  ENDIF
1133  ENDDO outlev
1134 
1135  DEALLOCATE(coord_out, mask_out)
1136  this%valid = .true.
1137 
1138  ELSE IF (this%trans%sub_type == 'linearsparse') THEN
1139 ! just store vertical coordinates, dirty work is done later
1140  ALLOCATE(this%vcoord_in(this%levused), this%vcoord_out(SIZE(coord_out)))
1141  this%vcoord_in(:) = coord_in(this%levshift+1:this%levshift+this%levused)
1142  this%vcoord_out(:) = coord_out(:)
1143  DEALLOCATE(coord_out, mask_out)
1144  this%valid = .true.
1145 
1146  ENDIF
1147 
1148  ENDIF ! levels are different
1149 
1150 !ELSE IF (this%trans%trans_type == 'verttrans') THEN
1151 
1152 ENDIF
1153 
1154 END SUBROUTINE grid_transform_levtype_levtype_init
1155 
1156 
1157 ! internal subroutine for computing vertical coordinate values, for
1158 ! pressure-based coordinates the logarithm is computed
1159 SUBROUTINE make_vert_coord(lev, mask, coord, dolog)
1160 TYPE(vol7d_level),INTENT(in) :: lev(:)
1161 LOGICAL,INTENT(inout) :: mask(:)
1162 DOUBLE PRECISION,INTENT(out) :: coord(:)
1163 LOGICAL,INTENT(out) :: dolog
1164 
1165 INTEGER :: k
1166 DOUBLE PRECISION :: fact
1167 
1168 dolog = .false.
1169 k = firsttrue(mask)
1170 IF (k <= 0) RETURN
1171 coord(:) = dmiss
1172 
1173 IF (any(lev(k)%level1 == height_level)) THEN ! improve with a conversion table somewhere
1174  fact = 1.0d-3
1175 ELSE IF (any(lev(k)%level1 == thermo_level)) THEN
1176  fact = 1.0d-1
1177 ELSE IF (any(lev(k)%level1 == sigma_level)) THEN
1178  fact = 1.0d-4
1179 ELSE
1180  fact = 1.0d0
1181 ENDIF
1182 
1183 IF (c_e(lev(k)%level2) .AND. lev(k)%level1 == lev(k)%level2) THEN ! layer between 2 levels
1184  IF (lev(k)%level1 == 100 .OR. lev(k)%level1 == 108) THEN ! pressure, compute log
1185  WHERE(mask(:) .AND. lev(:)%l1 > 0 .AND. lev(:)%l2 > 0)
1186  coord(:) = (log(dble(lev(:)%l1)*fact) + log(dble(lev(:)%l2)*fact))*0.5d0
1187  END WHERE
1188  dolog = .true.
1189  ELSE
1190  WHERE(mask(:))
1191  coord(:) = (lev(:)%l1 + lev(:)%l2)*fact*0.5d0
1192  END WHERE
1193  ENDIF
1194 ELSE ! half level
1195  IF (lev(k)%level1 == 100 .OR. lev(k)%level1 == 108) THEN ! pressure, compute log
1196  WHERE(mask(:) .AND. lev(:)%l1 > 0)
1197  coord(:) = log(dble(lev(:)%l1)*fact)
1198  END WHERE
1199  dolog = .true.
1200  ELSE
1201  WHERE(mask(:))
1202  coord(:) = lev(:)%l1*fact
1203  END WHERE
1204  ENDIF
1205 ENDIF
1206 
1207 ! refine mask
1208 mask(:) = mask(:) .AND. c_e(coord(:))
1209 
1210 END SUBROUTINE make_vert_coord
1211 
1212 
1230 SUBROUTINE grid_transform_init(this, trans, in, out, maskgrid, maskbounds, &
1231  categoryappend)
1232 TYPE(grid_transform),INTENT(out) :: this
1233 TYPE(transform_def),INTENT(in) :: trans
1234 TYPE(griddim_def),INTENT(inout) :: in
1235 TYPE(griddim_def),INTENT(inout) :: out
1236 REAL,INTENT(in),OPTIONAL :: maskgrid(:,:)
1237 REAL,INTENT(in),OPTIONAL :: maskbounds(:)
1238 CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend
1239 
1240 INTEGER :: nx, ny, i, j, ix, iy, n, nm, nr, cf_i, cf_o, nprev, &
1241  xnmin, xnmax, ynmin, ynmax
1242 DOUBLE PRECISION :: xmin, xmax, ymin, ymax, steplon, steplat, &
1243  xmin_new, ymin_new, ellips_smaj_axis, ellips_flatt, r2
1244 TYPE(geo_proj) :: proj_in, proj_out
1245 TYPE(georef_coord) :: point
1246 LOGICAL,ALLOCATABLE :: point_mask(:,:)
1247 TYPE(griddim_def) :: lin, lout
1248 
1249 
1250 CALL grid_transform_init_common(this, trans, categoryappend)
1251 #ifdef DEBUG
1252 CALL l4f_category_log(this%category, l4f_debug, "grid_transform vg6d-vg6d")
1253 #endif
1254 
1255 ! output ellipsoid has to be the same as for the input (improve)
1256 CALL get_val(in, ellips_smaj_axis=ellips_smaj_axis, ellips_flatt=ellips_flatt)
1257 CALL set_val(out, ellips_smaj_axis=ellips_smaj_axis, ellips_flatt=ellips_flatt)
1258 
1259 IF (this%trans%trans_type == 'zoom') THEN
1260 
1261  IF (this%trans%sub_type == 'coord') THEN
1262 
1263  CALL griddim_zoom_coord(in, &
1264  this%trans%rect_coo%ilon, this%trans%rect_coo%ilat,&
1265  this%trans%rect_coo%flon, this%trans%rect_coo%flat,&
1266  this%trans%rect_ind%ix, this%trans%rect_ind%iy, &
1267  this%trans%rect_ind%fx, this%trans%rect_ind%fy)
1268 
1269  ELSE IF (this%trans%sub_type == 'projcoord') THEN
1270 
1271  CALL griddim_zoom_projcoord(in, &
1272  this%trans%rect_coo%ilon, this%trans%rect_coo%ilat,&
1273  this%trans%rect_coo%flon, this%trans%rect_coo%flat,&
1274  this%trans%rect_ind%ix, this%trans%rect_ind%iy, &
1275  this%trans%rect_ind%fx, this%trans%rect_ind%fy)
1276 
1277  ELSE IF (this%trans%sub_type == 'coordbb') THEN
1278 
1279 ! compute coordinates of input grid in geo system
1280  CALL copy(in, lin)
1281  CALL unproj(lin)
1282  CALL get_val(lin, nx=nx, ny=ny)
1283 
1284  ALLOCATE(point_mask(nx,ny))
1285  point_mask(:,:) = .false.
1286 
1287 ! mark points falling into requested bounding-box
1288  DO j = 1, ny
1289  DO i = 1, nx
1290 ! IF (geo_coord_inside_rectang())
1291  IF (lin%dim%lon(i,j) > this%trans%rect_coo%ilon .AND. &
1292  lin%dim%lon(i,j) < this%trans%rect_coo%flon .AND. &
1293  lin%dim%lat(i,j) > this%trans%rect_coo%ilat .AND. &
1294  lin%dim%lat(i,j) < this%trans%rect_coo%flat) THEN ! improve!
1295  point_mask(i,j) = .true.
1296  ENDIF
1297  ENDDO
1298  ENDDO
1299 
1300 ! determine cut indices keeping all points which fall inside b-b
1301  DO i = 1, nx
1302  IF (any(point_mask(i,:))) EXIT
1303  ENDDO
1304  this%trans%rect_ind%ix = i
1305  DO i = nx, this%trans%rect_ind%ix, -1
1306  IF (any(point_mask(i,:))) EXIT
1307  ENDDO
1308  this%trans%rect_ind%fx = i
1309 
1310  DO j = 1, ny
1311  IF (any(point_mask(:,j))) EXIT
1312  ENDDO
1313  this%trans%rect_ind%iy = j
1314  DO j = ny, this%trans%rect_ind%iy, -1
1315  IF (any(point_mask(:,j))) EXIT
1316  ENDDO
1317  this%trans%rect_ind%fy = j
1318 
1319  DEALLOCATE(point_mask)
1320 
1321  IF (this%trans%rect_ind%ix > this%trans%rect_ind%fx .OR. &
1322  this%trans%rect_ind%iy > this%trans%rect_ind%fy) THEN
1323 
1324  CALL l4f_category_log(this%category,l4f_error, &
1325  "zoom coordbb: no points inside bounding box "//&
1326  trim(to_char(this%trans%rect_coo%ilon))//","// &
1327  trim(to_char(this%trans%rect_coo%flon))//","// &
1328  trim(to_char(this%trans%rect_coo%ilat))//","// &
1329  trim(to_char(this%trans%rect_coo%flat)))
1330  CALL raise_error()
1331  RETURN
1332 
1333  ENDIF
1334  CALL delete(lin)
1335  ENDIF
1336 ! to do in all zoom cases
1337 
1338  CALL get_val(in, nx=nx, ny=ny, xmin=xmin, xmax=xmax, &
1339  ymin=ymin, ymax=ymax, dx=steplon, dy=steplat)
1340 
1341 ! old indices
1342  this%iniox = min(max(this%trans%rect_ind%ix,1),nx) ! iox
1343  this%inioy = min(max(this%trans%rect_ind%iy,1),ny) ! ioy
1344  this%infox = max(min(this%trans%rect_ind%fx,nx),1) ! fox
1345  this%infoy = max(min(this%trans%rect_ind%fy,ny),1) ! foy
1346 ! new indices
1347  this%outinx = min(max(2-this%trans%rect_ind%ix,1),nx) ! inx
1348  this%outiny = min(max(2-this%trans%rect_ind%iy,1),ny) ! iny
1349  this%outfnx = min(this%trans%rect_ind%fx,nx)-this%trans%rect_ind%ix+1 ! fnx
1350  this%outfny = min(this%trans%rect_ind%fy,ny)-this%trans%rect_ind%iy+1 ! fny
1351 
1352  xmin=xmin+steplon*(this%trans%rect_ind%ix-1)
1353  ymin=ymin+steplat*(this%trans%rect_ind%iy-1)
1354  xmax=xmax+steplon*(this%trans%rect_ind%fx-nx)
1355  ymax=ymax+steplat*(this%trans%rect_ind%fy-ny)
1356 
1357  CALL copy(in, out)
1358 ! deallocate coordinates if allocated because they will change
1359  CALL dealloc(out%dim)
1360 
1361  out%dim%nx = this%trans%rect_ind%fx - this%trans%rect_ind%ix + 1 ! newx
1362  out%dim%ny = this%trans%rect_ind%fy - this%trans%rect_ind%iy + 1 ! newy
1363  this%outnx = out%dim%nx
1364  this%outny = out%dim%ny
1365  this%innx = nx
1366  this%inny = ny
1367 
1368  CALL set_val(out, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
1369 
1370  this%valid = .true. ! warning, no check of subtype
1371 
1372 ELSE IF (this%trans%trans_type == 'boxregrid') THEN
1373 
1374  CALL get_val(in, nx=nx, ny=ny, xmin=xmin, xmax=xmax, &
1375  ymin=ymin, ymax=ymax, dx=steplon, dy=steplat)
1376 
1377  this%innx = nx
1378  this%inny = ny
1379 
1380 ! new grid
1381  xmin_new = xmin + (this%trans%box_info%npx - 1)*0.5d0*steplon
1382  ymin_new = ymin + (this%trans%box_info%npy - 1)*0.5d0*steplat
1383 
1384  CALL copy(in, out)
1385 ! deallocate coordinates if allocated because they will change
1386  CALL dealloc(out%dim)
1387 
1388  out%dim%nx = nx/this%trans%box_info%npx
1389  out%dim%ny = ny/this%trans%box_info%npy
1390  this%outnx = out%dim%nx
1391  this%outny = out%dim%ny
1392  steplon = steplon*this%trans%box_info%npx
1393  steplat = steplat*this%trans%box_info%npy
1394 
1395  CALL set_val(out, xmin=xmin_new, ymin=ymin_new, &
1396  xmax=xmin_new + dble(out%dim%nx-1)*steplon, dx=steplon, &
1397  ymax=ymin_new + dble(out%dim%ny-1)*steplat, dy=steplat)
1398 
1399  this%valid = .true. ! warning, no check of subtype
1400 
1401 ELSE IF (this%trans%trans_type == 'inter' .OR. this%trans%trans_type == 'intersearch') THEN
1402 
1403  CALL outgrid_setup() ! common setup for grid-generating methods
1404 
1405  IF (this%trans%sub_type == 'near' .OR. this%trans%sub_type == 'bilin'&
1406  .OR. this%trans%sub_type == 'shapiro_near') THEN
1407 
1408  CALL get_val(in, nx=this%innx, ny=this%inny, &
1409  xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
1410  CALL get_val(out, nx=this%outnx, ny=this%outny)
1411 
1412  ALLOCATE(this%inter_index_x(this%outnx,this%outny), &
1413  this%inter_index_y(this%outnx,this%outny))
1414  CALL copy(out, lout)
1415  CALL unproj(lout)
1416 
1417  IF (this%trans%sub_type == 'bilin') THEN
1418  CALL this%find_index(in, .false., &
1419  this%innx, this%inny, xmin, xmax, ymin, ymax, &
1420  lout%dim%lon, lout%dim%lat, this%trans%extrap, &
1421  this%inter_index_x, this%inter_index_y)
1422 
1423  ALLOCATE(this%inter_x(this%innx,this%inny), &
1424  this%inter_y(this%innx,this%inny))
1425  ALLOCATE(this%inter_xp(this%outnx,this%outny), &
1426  this%inter_yp(this%outnx,this%outny))
1427 
1428 ! compute coordinates of input grid
1429  CALL griddim_gen_coord(in, this%inter_x, this%inter_y)
1430 ! compute coordinates of output grid in input system
1431  CALL proj(in, lout%dim%lon, lout%dim%lat, this%inter_xp, this%inter_yp)
1432 
1433  ELSE ! near, shapiro_near
1434  CALL this%find_index(in, .true., &
1435  this%innx, this%inny, xmin, xmax, ymin, ymax, &
1436  lout%dim%lon, lout%dim%lat, this%trans%extrap, &
1437  this%inter_index_x, this%inter_index_y)
1438 
1439  IF (this%trans%trans_type == 'intersearch') THEN ! replicate code above
1440  ALLOCATE(this%inter_x(this%innx,this%inny), &
1441  this%inter_y(this%innx,this%inny))
1442  ALLOCATE(this%inter_xp(this%outnx,this%outny), &
1443  this%inter_yp(this%outnx,this%outny))
1444 
1445 ! compute coordinates of input grid
1446  CALL griddim_gen_coord(in, this%inter_x, this%inter_y)
1447 ! compute coordinates of output grid in input system
1448  CALL proj(in, lout%dim%lon, lout%dim%lat, this%inter_xp, this%inter_yp)
1449  ENDIF
1450  ENDIF
1451 
1452  CALL delete(lout)
1453  this%valid = .true.
1454  ENDIF
1455 
1456 ELSE IF (this%trans%trans_type == 'boxinter') THEN
1457 
1458  CALL outgrid_setup() ! common setup for grid-generating methods
1459  CALL get_val(in, nx=this%innx, ny=this%inny)
1460  CALL get_val(out, nx=this%outnx, ny=this%outny, &
1461  xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
1462 ! TODO now box size is ignored
1463 ! if box size not provided, use the actual grid step
1464  IF (.NOT.c_e(this%trans%area_info%boxdx)) &
1465  CALL get_val(out, dx=this%trans%area_info%boxdx)
1466  IF (.NOT.c_e(this%trans%area_info%boxdy)) &
1467  CALL get_val(out, dx=this%trans%area_info%boxdy)
1468 ! half size is actually needed
1469  this%trans%area_info%boxdx = this%trans%area_info%boxdx*0.5d0
1470  this%trans%area_info%boxdy = this%trans%area_info%boxdy*0.5d0
1471 ! unlike before, here index arrays must have the shape of input grid
1472  ALLOCATE(this%inter_index_x(this%innx,this%inny), &
1473  this%inter_index_y(this%innx,this%inny))
1474 
1475 ! compute coordinates of input grid in geo system
1476  CALL copy(in, lin)
1477  CALL unproj(lin)
1478 ! use find_index in the opposite way, here extrap does not make sense
1479  CALL this%find_index(out, .true., &
1480  this%outnx, this%outny, xmin, xmax, ymin, ymax, &
1481  lin%dim%lon, lin%dim%lat, .false., &
1482  this%inter_index_x, this%inter_index_y)
1483 
1484  CALL delete(lin)
1485  this%valid = .true. ! warning, no check of subtype
1486 
1487 ELSE IF (this%trans%trans_type == 'stencilinter') THEN
1488 
1489  CALL outgrid_setup() ! common setup for grid-generating methods
1490 ! from inter:near
1491  CALL get_val(in, nx=this%innx, ny=this%inny, &
1492  xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
1493  CALL get_val(out, nx=this%outnx, ny=this%outny)
1494 
1495  ALLOCATE (this%inter_index_x(this%outnx,this%outny), &
1496  this%inter_index_y(this%outnx,this%outny))
1497  CALL copy(out, lout)
1498  CALL unproj(lout)
1499  CALL this%find_index(in, .true., &
1500  this%innx, this%inny, xmin, xmax, ymin, ymax, &
1501  lout%dim%lon, lout%dim%lat, this%trans%extrap, &
1502  this%inter_index_x, this%inter_index_y)
1503 
1504 ! define the stencil mask
1505  nr = int(this%trans%area_info%radius) ! integer radius
1506  n = nr*2+1 ! n. of points
1507  nm = nr + 1 ! becomes index of center
1508  r2 = this%trans%area_info%radius**2
1509  ALLOCATE(this%stencil(n,n))
1510  this%stencil(:,:) = .true.
1511  DO iy = 1, n
1512  DO ix = 1, n
1513  IF ((ix-nm)**2+(iy-nm)**2 > r2) this%stencil(ix,iy) = .false.
1514  ENDDO
1515  ENDDO
1516 
1517 ! set to missing the elements of inter_index too close to the domain
1518 ! borders
1519  xnmin = nr + 1
1520  xnmax = this%innx - nr
1521  ynmin = nr + 1
1522  ynmax = this%inny - nr
1523  DO iy = 1, this%outny
1524  DO ix = 1, this%outnx
1525  IF (this%inter_index_x(ix,iy) < xnmin .OR. &
1526  this%inter_index_x(ix,iy) > xnmax .OR. &
1527  this%inter_index_y(ix,iy) < ynmin .OR. &
1528  this%inter_index_y(ix,iy) > ynmax) THEN
1529  this%inter_index_x(ix,iy) = imiss
1530  this%inter_index_y(ix,iy) = imiss
1531  ENDIF
1532  ENDDO
1533  ENDDO
1534 
1535 #ifdef DEBUG
1536  CALL l4f_category_log(this%category, l4f_debug, &
1537  'stencilinter: stencil size '//t2c(n*n))
1538  CALL l4f_category_log(this%category, l4f_debug, &
1539  'stencilinter: stencil points '//t2c(count(this%stencil)))
1540 #endif
1541 
1542  CALL delete(lout)
1543  this%valid = .true. ! warning, no check of subtype
1544 
1545 ELSE IF (this%trans%trans_type == 'maskgen') THEN
1546 
1547  IF (this%trans%sub_type == 'poly') THEN
1548 
1549  CALL copy(in, out)
1550  CALL get_val(in, nx=this%innx, ny=this%inny)
1551  this%outnx = this%innx
1552  this%outny = this%inny
1553 
1554 ! unlike before, here index arrays must have the shape of input grid
1555  ALLOCATE(this%inter_index_x(this%innx,this%inny), &
1556  this%inter_index_y(this%innx,this%inny))
1557  this%inter_index_x(:,:) = imiss
1558  this%inter_index_y(:,:) = 1
1559 
1560 ! compute coordinates of input grid in geo system
1561  CALL unproj(out) ! should be unproj(lin)
1562 
1563  nprev = 1
1564 !$OMP PARALLEL DEFAULT(SHARED)
1565 !$OMP DO PRIVATE(j, i, n, point) FIRSTPRIVATE(nprev)
1566  DO j = 1, this%inny
1567  inside_x: DO i = 1, this%innx
1568  point = georef_coord_new(x=out%dim%lon(i,j), y=out%dim%lat(i,j))
1569 
1570  DO n = nprev, this%trans%poly%arraysize ! optimize starting from last matched polygon
1571  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
1572  this%inter_index_x(i,j) = n
1573  nprev = n
1574  cycle inside_x
1575  ENDIF
1576  ENDDO
1577  DO n = nprev-1, 1, -1 ! test the other polygons
1578  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
1579  this%inter_index_x(i,j) = n
1580  nprev = n
1581  cycle inside_x
1582  ENDIF
1583  ENDDO
1584 
1585 ! CALL delete(point) ! speedup
1586  ENDDO inside_x
1587  ENDDO
1588 !$OMP END PARALLEL
1589 
1590  ELSE IF (this%trans%sub_type == 'grid') THEN
1591 ! here out(put grid) is abused for indicating the box-generating grid
1592 ! but the real output grid is the input grid
1593  CALL copy(out, lout) ! save out for local use
1594  CALL delete(out) ! needed before copy
1595  CALL copy(in, out)
1596  CALL get_val(in, nx=this%innx, ny=this%inny)
1597  this%outnx = this%innx
1598  this%outny = this%inny
1599  CALL get_val(lout, nx=nx, ny=ny, &
1600  xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
1601 
1602 ! unlike before, here index arrays must have the shape of input grid
1603  ALLOCATE(this%inter_index_x(this%innx,this%inny), &
1604  this%inter_index_y(this%innx,this%inny))
1605 
1606 ! compute coordinates of input/output grid in geo system
1607  CALL unproj(out)
1608 
1609 ! use find_index in the opposite way, here extrap does not make sense
1610  CALL this%find_index(lout, .true., &
1611  nx, ny, xmin, xmax, ymin, ymax, &
1612  out%dim%lon, out%dim%lat, .false., &
1613  this%inter_index_x, this%inter_index_y)
1614 ! transform indices to 1-d for mask generation
1615  WHERE(c_e(this%inter_index_x(:,:)))
1616  this%inter_index_x(:,:) = this%inter_index_x(:,:) + &
1617  (this%inter_index_y(:,:)-1)*nx
1618  END WHERE
1619 
1620  CALL delete(lout)
1621  ENDIF
1622 
1623  this%valid = .true.
1624 
1625 ELSE IF (this%trans%trans_type == 'polyinter') THEN
1626 
1627 ! this is the only difference wrt maskgen:poly
1628  this%recur = .true. ! grid-to-grid polyinter is done in two steps!
1629 
1630  CALL copy(in, out)
1631  CALL get_val(in, nx=this%innx, ny=this%inny)
1632  this%outnx = this%innx
1633  this%outny = this%inny
1634 
1635 ! unlike before, here index arrays must have the shape of input grid
1636  ALLOCATE(this%inter_index_x(this%innx,this%inny), &
1637  this%inter_index_y(this%innx,this%inny))
1638  this%inter_index_x(:,:) = imiss
1639  this%inter_index_y(:,:) = 1
1640 
1641 ! compute coordinates of input grid in geo system
1642  CALL unproj(out) ! should be unproj(lin)
1643 
1644  nprev = 1
1645 !$OMP PARALLEL DEFAULT(SHARED)
1646 !$OMP DO PRIVATE(j, i, n, point) FIRSTPRIVATE(nprev)
1647  DO j = 1, this%inny
1648  inside_x_2: DO i = 1, this%innx
1649  point = georef_coord_new(x=out%dim%lon(i,j), y=out%dim%lat(i,j))
1650 
1651  DO n = nprev, this%trans%poly%arraysize ! optimize starting from last matched polygon
1652  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
1653  this%inter_index_x(i,j) = n
1654  nprev = n
1655  cycle inside_x_2
1656  ENDIF
1657  ENDDO
1658  DO n = nprev-1, 1, -1 ! test the other polygons
1659  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
1660  this%inter_index_x(i,j) = n
1661  nprev = n
1662  cycle inside_x_2
1663  ENDIF
1664  ENDDO
1665 
1666 ! CALL delete(point) ! speedup
1667  ENDDO inside_x_2
1668  ENDDO
1669 !$OMP END PARALLEL
1670 
1671  this%valid = .true. ! warning, no check of subtype
1672 
1673 ELSE IF (this%trans%trans_type == 'metamorphosis') THEN
1674 
1675  CALL copy(in, out)
1676  CALL get_val(in, nx=this%innx, ny=this%inny)
1677  this%outnx = this%innx
1678  this%outny = this%inny
1679 
1680  IF (this%trans%sub_type == 'maskvalid' .OR. this%trans%sub_type == 'maskinvalid') THEN
1681 
1682  IF (.NOT.PRESENT(maskgrid)) THEN
1683  CALL l4f_category_log(this%category,l4f_error, &
1684  'grid_transform_init maskgrid argument missing for metamorphosis:'// &
1685  trim(this%trans%sub_type)//' transformation')
1686  CALL raise_error()
1687  RETURN
1688  ENDIF
1689 
1690  IF (this%innx /= SIZE(maskgrid,1) .OR. this%inny /= SIZE(maskgrid,2)) THEN
1691  CALL l4f_category_log(this%category,l4f_error, &
1692  'grid_transform_init mask non conformal with input field')
1693  CALL l4f_category_log(this%category,l4f_error, &
1694  'mask: '//t2c(SIZE(maskgrid,1))//'x'//t2c(SIZE(maskgrid,2))// &
1695  ' input field:'//t2c(this%innx)//'x'//t2c(this%inny))
1696  CALL raise_error()
1697  RETURN
1698  ENDIF
1699 
1700  ALLOCATE(this%point_mask(this%innx,this%inny))
1701 
1702  IF (this%trans%sub_type == 'maskvalid') THEN
1703 ! behavior depends on the presence/usability of maskbounds,
1704 ! simplified wrt its use in metamorphosis:mask
1705  IF (.NOT.PRESENT(maskbounds)) THEN
1706  this%point_mask(:,:) = c_e(maskgrid(:,:))
1707  ELSE IF (SIZE(maskbounds) < 2) THEN
1708  this%point_mask(:,:) = c_e(maskgrid(:,:))
1709  ELSE
1710  this%point_mask(:,:) = c_e(maskgrid(:,:)) .AND. &
1711  maskgrid(:,:) > maskbounds(1) .AND. &
1712  maskgrid(:,:) <= maskbounds(SIZE(maskbounds))
1713  ENDIF
1714  ELSE ! reverse condition
1715  this%point_mask(:,:) = .NOT.c_e(maskgrid(:,:))
1716  ENDIF
1717 
1718  this%valid = .true.
1719 
1720  ELSE IF (this%trans%sub_type == 'lemaskinvalid' .OR. &
1721  this%trans%sub_type == 'ltmaskinvalid' .OR. &
1722  this%trans%sub_type == 'gemaskinvalid' .OR. &
1723  this%trans%sub_type == 'gtmaskinvalid') THEN
1724 ! here i can only store field for computing mask runtime
1725 
1726  this%val_mask = maskgrid
1727  this%valid = .true.
1728 
1729  ELSE IF (this%trans%sub_type == 'setinvalidto') THEN
1730 
1731  IF (.NOT.PRESENT(maskbounds)) THEN
1732  CALL l4f_category_log(this%category,l4f_error, &
1733  'grid_transform_init maskbounds missing for metamorphosis:'// &
1734  trim(this%trans%sub_type)//' transformation')
1735  RETURN
1736  ELSE IF (SIZE(maskbounds) < 1) THEN
1737  CALL l4f_category_log(this%category,l4f_error, &
1738  'grid_transform_init maskbounds empty for metamorphosis:'// &
1739  trim(this%trans%sub_type)//' transformation')
1740  RETURN
1741  ELSE
1742  this%val1 = maskbounds(1)
1743 #ifdef DEBUG
1744  CALL l4f_category_log(this%category, l4f_debug, &
1745  "grid_transform_init setting invalid data to "//t2c(this%val1))
1746 #endif
1747  ENDIF
1748 
1749  this%valid = .true.
1750 
1751  ELSE IF (this%trans%sub_type == 'settoinvalid') THEN
1752 
1753  IF (.NOT.PRESENT(maskbounds)) THEN
1754  CALL l4f_category_log(this%category,l4f_error, &
1755  'grid_transform_init maskbounds missing for metamorphosis:'// &
1756  trim(this%trans%sub_type)//' transformation')
1757  CALL raise_error()
1758  RETURN
1759  ELSE IF (SIZE(maskbounds) < 2) THEN
1760  CALL l4f_category_log(this%category,l4f_error, &
1761  'grid_transform_init maskbounds must have at least 2 elements for metamorphosis:'// &
1762  trim(this%trans%sub_type)//' transformation')
1763  CALL raise_error()
1764  RETURN
1765  ELSE
1766  this%val1 = maskbounds(1)
1767  this%val2 = maskbounds(SIZE(maskbounds))
1768 #ifdef DEBUG
1769  CALL l4f_category_log(this%category, l4f_debug, &
1770  "grid_transform_init setting to invalid interval ]"//t2c(this%val1)//','// &
1771  t2c(this%val2)//']')
1772 #endif
1773  ENDIF
1774 
1775  this%valid = .true.
1776 
1777  ENDIF
1778 
1779 ENDIF
1780 
1781 CONTAINS
1782 
1783 ! local subroutine to be called by all methods interpolating to a new
1784 ! grid, no parameters passed, used as a macro to avoid repeating code
1785 SUBROUTINE outgrid_setup()
1786 
1787 ! set increments in new grid in order for all the baraque to work
1788 CALL griddim_setsteps(out)
1789 ! check component flag
1790 CALL get_val(in, proj=proj_in, component_flag=cf_i)
1791 CALL get_val(out, proj=proj_out, component_flag=cf_o)
1792 IF (proj_in == proj_out) THEN
1793 ! same projection: set output component flag equal to input regardless
1794 ! of its value
1795  CALL set_val(out, component_flag=cf_i)
1796 ELSE
1797 ! different projection, interpolation possible only with vector data
1798 ! referred to geograpical axes
1799  IF (cf_i == 1) THEN
1800  CALL l4f_category_log(this%category,l4f_warn, &
1801  'trying to interpolate a grid with component flag 1 to a grid on a different projection')
1802  CALL l4f_category_log(this%category,l4f_warn, &
1803  'vector fields will probably be wrong')
1804  ELSE
1805  CALL set_val(out, component_flag=cf_i)
1806  ENDIF
1807 ENDIF
1808 ! rotate the input grid by n*360 degrees to bring it closer to the output grid
1809 CALL griddim_set_central_lon(in, griddim_central_lon(out))
1810 
1811 END SUBROUTINE outgrid_setup
1812 
1813 END SUBROUTINE grid_transform_init
1814 
1815 
1858 SUBROUTINE grid_transform_grid_vol7d_init(this, trans, in, v7d_out, &
1859  maskgrid, maskbounds, find_index, categoryappend)
1860 TYPE(grid_transform),INTENT(out) :: this
1861 TYPE(transform_def),INTENT(in) :: trans
1862 TYPE(griddim_def),INTENT(in) :: in
1863 TYPE(vol7d),INTENT(inout) :: v7d_out
1864 REAL,INTENT(in),OPTIONAL :: maskgrid(:,:)
1865 REAL,INTENT(in),OPTIONAL :: maskbounds(:)
1866 PROCEDURE(basic_find_index),POINTER,OPTIONAL :: find_index
1867 CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend
1868 
1869 INTEGER :: ix, iy, n, nm, nr, nprev, nmaskarea, xnmin, xnmax, ynmin, ynmax, &
1870  time_definition
1871 DOUBLE PRECISION :: xmin, xmax, ymin, ymax, r2, lonref
1872 DOUBLE PRECISION,ALLOCATABLE :: lon1(:), lat1(:), lon(:,:), lat(:,:)
1873 REAL,ALLOCATABLE :: lmaskbounds(:)
1874 TYPE(georef_coord) :: point
1875 TYPE(griddim_def) :: lin
1876 !$ INTEGER :: outnx
1877 
1878 IF (PRESENT(find_index)) THEN ! move in init_common?
1879  IF (ASSOCIATED(find_index)) THEN
1880  this%find_index => find_index
1881  ENDIF
1882 ENDIF
1883 CALL grid_transform_init_common(this, trans, categoryappend)
1884 #ifdef DEBUG
1885 CALL l4f_category_log(this%category, l4f_debug, "grid_transform vg6d-v7d")
1886 #endif
1887 
1888 ! used after in some transformations
1889 CALL get_val(trans, time_definition=time_definition)
1890 IF (.NOT. c_e(time_definition)) THEN
1891  time_definition=1 ! default to validity time
1892 ENDIF
1893 
1894 IF (this%trans%trans_type == 'inter') THEN
1895 
1896  IF (this%trans%sub_type == 'near' .OR. this%trans%sub_type == 'bilin' &
1897  .OR. this%trans%sub_type == 'shapiro_near') THEN
1898 
1899  CALL copy(in, lin)
1900  CALL get_val(lin, nx=this%innx, ny=this%inny)
1901  this%outnx = SIZE(v7d_out%ana)
1902  this%outny = 1
1903 
1904  ALLOCATE (this%inter_index_x(this%outnx,this%outny),&
1905  this%inter_index_y(this%outnx,this%outny))
1906  ALLOCATE(lon(this%outnx,1),lat(this%outnx,1))
1907 
1908  CALL getval(v7d_out%ana(:)%coord,lon=lon(:,1),lat=lat(:,1))
1909 ! equalize in/out coordinates
1910  lonref = 0.5d0*(maxval(lon(:,1), mask=c_e(lon(:,1))) + minval(lon(:,1), mask=c_e(lon(:,1))))
1911  CALL griddim_set_central_lon(lin, lonref)
1912  CALL get_val(lin, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
1913 
1914  IF (this%trans%sub_type == 'bilin') THEN
1915  CALL this%find_index(lin, .false., &
1916  this%innx, this%inny, xmin, xmax, ymin, ymax, &
1917  lon, lat, this%trans%extrap, &
1918  this%inter_index_x, this%inter_index_y)
1919 
1920  ALLOCATE(this%inter_x(this%innx,this%inny),this%inter_y(this%innx,this%inny))
1921  ALLOCATE(this%inter_xp(this%outnx,this%outny),this%inter_yp(this%outnx,this%outny))
1922 
1923  CALL griddim_gen_coord(lin, this%inter_x, this%inter_y)
1924  CALL proj(lin, lon, lat, this%inter_xp, this%inter_yp)
1925 
1926  ELSE ! near shapiro_near
1927  CALL this%find_index(lin, .true., &
1928  this%innx, this%inny, xmin, xmax, ymin, ymax, &
1929  lon, lat, this%trans%extrap, &
1930  this%inter_index_x, this%inter_index_y)
1931 
1932  IF (this%trans%trans_type == 'intersearch') THEN ! replicate code above
1933  ALLOCATE(this%inter_x(this%innx,this%inny),this%inter_y(this%innx,this%inny))
1934  ALLOCATE(this%inter_xp(this%outnx,this%outny),this%inter_yp(this%outnx,this%outny))
1935 
1936  CALL griddim_gen_coord(lin, this%inter_x, this%inter_y)
1937  CALL proj(lin, lon, lat, this%inter_xp, this%inter_yp)
1938  ENDIF
1939  ENDIF
1940 
1941  DEALLOCATE(lon,lat)
1942  CALL delete(lin)
1943 
1944  this%valid = .true.
1945 
1946  ENDIF
1947 
1948 ELSE IF (this%trans%trans_type == 'polyinter') THEN
1949 
1950  CALL get_val(in, nx=this%innx, ny=this%inny)
1951 ! unlike before, here index arrays must have the shape of input grid
1952  ALLOCATE(this%inter_index_x(this%innx,this%inny), &
1953  this%inter_index_y(this%innx,this%inny))
1954  this%inter_index_x(:,:) = imiss
1955  this%inter_index_y(:,:) = 1
1956 
1957 ! compute coordinates of input grid in geo system
1958  CALL copy(in, lin)
1959  CALL unproj(lin)
1960 
1961  this%outnx = this%trans%poly%arraysize
1962  this%outny = 1
1963  CALL delete(v7d_out) ! required to avoid leaks because intent(inout), dangerous
1964  CALL init(v7d_out, time_definition=time_definition)
1965  CALL vol7d_alloc(v7d_out, nana=this%outnx)
1966 
1967 ! equalize in/out coordinates
1968  ALLOCATE(lon(this%outnx,1))
1969  CALL getval(v7d_out%ana(:)%coord,lon=lon(:,1))
1970  lonref = 0.5d0*(maxval(lon(:,1), mask=c_e(lon(:,1))) + minval(lon(:,1), mask=c_e(lon(:,1))))
1971  CALL griddim_set_central_lon(lin, lonref)
1972  DEALLOCATE(lon)
1973 
1974 ! setup output point list, equal to average of polygon points
1975 ! warning, in case of concave areas points may coincide!
1976  CALL poly_to_coordinates(this%trans%poly, v7d_out)
1977 
1978  nprev = 1
1979 !$OMP PARALLEL DEFAULT(SHARED)
1980 !$OMP DO PRIVATE(iy, ix, n, point) FIRSTPRIVATE(nprev)
1981  DO iy = 1, this%inny
1982  inside_x: DO ix = 1, this%innx
1983  point = georef_coord_new(x=lin%dim%lon(ix,iy), y=lin%dim%lat(ix,iy))
1984 
1985  DO n = nprev, this%trans%poly%arraysize ! optimize starting from last matched polygon
1986  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
1987  this%inter_index_x(ix,iy) = n
1988  nprev = n
1989  cycle inside_x
1990  ENDIF
1991  ENDDO
1992  DO n = nprev-1, 1, -1 ! test the other polygons
1993  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
1994  this%inter_index_x(ix,iy) = n
1995  nprev = n
1996  cycle inside_x
1997  ENDIF
1998  ENDDO
1999 
2000 ! CALL delete(point) ! speedup
2001  ENDDO inside_x
2002  ENDDO
2003 !$OMP END PARALLEL
2004 
2005 #ifdef DEBUG
2006  DO n = 1, this%trans%poly%arraysize
2007  CALL l4f_category_log(this%category, l4f_debug, &
2008  'Polygon: '//t2c(n)//' grid points: '// &
2009  t2c(count(this%inter_index_x(:,:) == n)))
2010  ENDDO
2011 #endif
2012 
2013  CALL delete(lin)
2014  this%valid = .true. ! warning, no check of subtype
2015 
2016 ELSE IF (this%trans%trans_type == 'stencilinter') THEN
2017 
2018 ! from inter:near
2019  CALL copy(in, lin)
2020  CALL get_val(lin, nx=this%innx, ny=this%inny)
2021  this%outnx = SIZE(v7d_out%ana)
2022  this%outny = 1
2023 
2024  ALLOCATE (this%inter_index_x(this%outnx,this%outny),&
2025  this%inter_index_y(this%outnx,this%outny))
2026  ALLOCATE(lon(this%outnx,1),lat(this%outnx,1))
2027 
2028  CALL getval(v7d_out%ana(:)%coord,lon=lon(:,1),lat=lat(:,1))
2029 ! equalize in/out coordinates
2030  lonref = 0.5d0*(maxval(lon(:,1), mask=c_e(lon(:,1))) + minval(lon(:,1), mask=c_e(lon(:,1))))
2031  CALL griddim_set_central_lon(lin, lonref)
2032 
2033  CALL get_val(lin, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
2034 
2035  CALL this%find_index(lin, .true., &
2036  this%innx, this%inny, xmin, xmax, ymin, ymax, &
2037  lon, lat, this%trans%extrap, &
2038  this%inter_index_x, this%inter_index_y)
2039 
2040 ! define the stencil mask
2041  nr = int(this%trans%area_info%radius) ! integer radius
2042  n = nr*2+1 ! n. of points
2043  nm = nr + 1 ! becomes index of center
2044  r2 = this%trans%area_info%radius**2
2045  ALLOCATE(this%stencil(n,n))
2046  this%stencil(:,:) = .true.
2047  DO iy = 1, n
2048  DO ix = 1, n
2049  IF ((ix-nm)**2+(iy-nm)**2 > r2) this%stencil(ix,iy) = .false.
2050  ENDDO
2051  ENDDO
2052 
2053 ! set to missing the elements of inter_index too close to the domain
2054 ! borders
2055  xnmin = nr + 1
2056  xnmax = this%innx - nr
2057  ynmin = nr + 1
2058  ynmax = this%inny - nr
2059  DO iy = 1, this%outny
2060  DO ix = 1, this%outnx
2061  IF (this%inter_index_x(ix,iy) < xnmin .OR. &
2062  this%inter_index_x(ix,iy) > xnmax .OR. &
2063  this%inter_index_y(ix,iy) < ynmin .OR. &
2064  this%inter_index_y(ix,iy) > ynmax) THEN
2065  this%inter_index_x(ix,iy) = imiss
2066  this%inter_index_y(ix,iy) = imiss
2067  ENDIF
2068  ENDDO
2069  ENDDO
2070 
2071 #ifdef DEBUG
2072  CALL l4f_category_log(this%category, l4f_debug, &
2073  'stencilinter: stencil size '//t2c(n*n))
2074  CALL l4f_category_log(this%category, l4f_debug, &
2075  'stencilinter: stencil points '//t2c(count(this%stencil)))
2076 #endif
2077 
2078  DEALLOCATE(lon,lat)
2079  CALL delete(lin)
2080 
2081  this%valid = .true. ! warning, no check of subtype
2082 
2083 ELSE IF (this%trans%trans_type == 'maskinter') THEN
2084 
2085  IF (.NOT.PRESENT(maskgrid)) THEN
2086  CALL l4f_category_log(this%category,l4f_error, &
2087  'grid_transform_init maskgrid argument missing for maskinter transformation')
2088  CALL raise_fatal_error()
2089  ENDIF
2090 
2091  CALL get_val(in, nx=this%innx, ny=this%inny)
2092  IF (this%innx /= SIZE(maskgrid,1) .OR. this%inny /= SIZE(maskgrid,2)) THEN
2093  CALL l4f_category_log(this%category,l4f_error, &
2094  'grid_transform_init mask non conformal with input field')
2095  CALL l4f_category_log(this%category,l4f_error, &
2096  'mask: '//t2c(SIZE(maskgrid,1))//'x'//t2c(SIZE(maskgrid,2))// &
2097  ' input field:'//t2c(this%innx)//'x'//t2c(this%inny))
2098  CALL raise_fatal_error()
2099  ENDIF
2100 ! unlike before, here index arrays must have the shape of input grid
2101  ALLOCATE(this%inter_index_x(this%innx,this%inny), &
2102  this%inter_index_y(this%innx,this%inny))
2103  this%inter_index_x(:,:) = imiss
2104  this%inter_index_y(:,:) = 1
2105 
2106 ! generate the subarea boundaries according to maskgrid and maskbounds
2107  CALL gen_mask_class()
2108 
2109 ! compute coordinates of input grid in geo system
2110  CALL copy(in, lin)
2111  CALL unproj(lin)
2112 
2113 !$OMP PARALLEL DEFAULT(SHARED)
2114 !$OMP DO PRIVATE(iy, ix, n)
2115  DO iy = 1, this%inny
2116  DO ix = 1, this%innx
2117  IF (c_e(maskgrid(ix,iy))) THEN
2118  IF (maskgrid(ix,iy) <= lmaskbounds(nmaskarea+1)) THEN
2119  DO n = nmaskarea, 1, -1
2120  IF (maskgrid(ix,iy) > lmaskbounds(n)) THEN
2121  this%inter_index_x(ix,iy) = n
2122  EXIT
2123  ENDIF
2124  ENDDO
2125  ENDIF
2126  ENDIF
2127  ENDDO
2128  ENDDO
2129 !$OMP END PARALLEL
2130 
2131  this%outnx = nmaskarea
2132  this%outny = 1
2133  CALL delete(v7d_out) ! required to avoid leaks because intent(inout), dangerous
2134  CALL init(v7d_out, time_definition=time_definition)
2135  CALL vol7d_alloc(v7d_out, nana=nmaskarea)
2136 
2137 ! setup output point list, equal to average of polygon points
2138 ! warning, in case of concave areas points may coincide!
2139  DO n = 1, nmaskarea
2140  CALL init(v7d_out%ana(n), &
2141  lon=stat_average(pack(lin%dim%lon(:,:), &
2142  mask=(this%inter_index_x(:,:) == n))), &
2143  lat=stat_average(pack(lin%dim%lat(:,:), &
2144  mask=(this%inter_index_x(:,:) == n))))
2145  ENDDO
2146 
2147  CALL delete(lin)
2148  this%valid = .true. ! warning, no check of subtype
2149 
2150 ELSE IF (this%trans%trans_type == 'metamorphosis') THEN
2151 
2152 ! common to all metamorphosis subtypes
2153 ! compute coordinates of input grid in geo system
2154  CALL copy(in, lin)
2155  CALL unproj(lin)
2156 
2157  CALL get_val(in, nx=this%innx, ny=this%inny)
2158 ! allocate index array
2159  ALLOCATE(this%point_index(this%innx,this%inny))
2160  this%point_index(:,:) = imiss
2161 ! setup output coordinates
2162  IF (this%trans%sub_type /= 'index') THEN ! improve!
2163  CALL delete(v7d_out) ! required to avoid leaks because intent(inout), dangerous
2164  CALL init(v7d_out, time_definition=time_definition)
2165  ENDIF
2166 
2167  IF (this%trans%sub_type == 'all' ) THEN
2168 
2169  this%outnx = this%innx*this%inny
2170  this%outny = 1
2171  CALL vol7d_alloc(v7d_out, nana=this%outnx)
2172 
2173  n = 0
2174  DO iy=1,this%inny
2175  DO ix=1,this%innx
2176  CALL init(v7d_out%ana((iy-1)*this%innx+ix), &
2177  lon=lin%dim%lon(ix,iy),lat=lin%dim%lat(ix,iy))
2178  n = n + 1
2179  this%point_index(ix,iy) = n
2180  ENDDO
2181  ENDDO
2182 
2183  this%valid = .true.
2184 
2185  ELSE IF (this%trans%sub_type == 'coordbb' ) THEN
2186 
2187 ! count and mark points falling into requested bounding-box
2188  this%outnx = 0
2189  this%outny = 1
2190  DO iy = 1, this%inny
2191  DO ix = 1, this%innx
2192 ! IF (geo_coord_inside_rectang()
2193  IF (lin%dim%lon(ix,iy) > this%trans%rect_coo%ilon .AND. &
2194  lin%dim%lon(ix,iy) < this%trans%rect_coo%flon .AND. &
2195  lin%dim%lat(ix,iy) > this%trans%rect_coo%ilat .AND. &
2196  lin%dim%lat(ix,iy) < this%trans%rect_coo%flat) THEN ! improve!
2197  this%outnx = this%outnx + 1
2198  this%point_index(ix,iy) = this%outnx
2199  ENDIF
2200  ENDDO
2201  ENDDO
2202 
2203  IF (this%outnx <= 0) THEN
2204  CALL l4f_category_log(this%category,l4f_warn, &
2205  "metamorphosis:coordbb: no points inside bounding box "//&
2206  trim(to_char(this%trans%rect_coo%ilon))//","// &
2207  trim(to_char(this%trans%rect_coo%flon))//","// &
2208  trim(to_char(this%trans%rect_coo%ilat))//","// &
2209  trim(to_char(this%trans%rect_coo%flat)))
2210  ENDIF
2211 
2212  CALL vol7d_alloc(v7d_out, nana=this%outnx)
2213 
2214 ! collect coordinates of points falling into requested bounding-box
2215  n = 0
2216  DO iy = 1, this%inny
2217  DO ix = 1, this%innx
2218  IF (c_e(this%point_index(ix,iy))) THEN
2219  n = n + 1
2220  CALL init(v7d_out%ana(n), &
2221  lon=lin%dim%lon(ix,iy), lat=lin%dim%lat(ix,iy))
2222  ENDIF
2223  ENDDO
2224  ENDDO
2225 
2226  this%valid = .true.
2227 
2228  ELSE IF (this%trans%sub_type == 'poly' ) THEN
2229 
2230 ! count and mark points falling into requested polygon
2231 #ifdef _OPENMP
2232  outnx = 0
2233 #else
2234  this%outnx = 0
2235 #endif
2236  this%outny = 1
2237 
2238 ! this OMP block has to be checked
2239 !$OMP PARALLEL DEFAULT(SHARED)
2240 !$OMP DO PRIVATE(iy, ix, point, n), REDUCTION(+:outnx)
2241  DO iy = 1, this%inny
2242  DO ix = 1, this%innx
2243  point = georef_coord_new(x=lin%dim%lon(ix,iy), y=lin%dim%lat(ix,iy))
2244  DO n = 1, this%trans%poly%arraysize
2245  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
2246 #ifdef _OPENMP
2247  outnx = outnx + 1
2248 #else
2249  this%outnx = this%outnx + 1
2250 #endif
2251  this%point_index(ix,iy) = n
2252  EXIT
2253  ENDIF
2254  ENDDO
2255 ! CALL delete(point) ! speedup
2256  ENDDO
2257  ENDDO
2258 !$OMP END PARALLEL
2259 !$ this%outnx = outnx
2260  IF (this%outnx <= 0) THEN
2261  CALL l4f_category_log(this%category,l4f_warn, &
2262  "metamorphosis:poly: no points inside polygons")
2263  ENDIF
2264 
2265  CALL vol7d_alloc(v7d_out, nana=this%outnx)
2266 ! collect coordinates of points falling into requested polygon
2267  n = 0
2268  DO iy = 1, this%inny
2269  DO ix = 1, this%innx
2270  IF (c_e(this%point_index(ix,iy))) THEN
2271  n = n + 1
2272  CALL init(v7d_out%ana(n), &
2273  lon=lin%dim%lon(ix,iy), lat=lin%dim%lat(ix,iy))
2274  ENDIF
2275  ENDDO
2276  ENDDO
2277 
2278  this%valid = .true.
2279 
2280  ELSE IF (this%trans%sub_type == 'mask' ) THEN
2281 
2282  IF (.NOT.PRESENT(maskgrid)) THEN
2283  CALL l4f_category_log(this%category,l4f_error, &
2284  'grid_transform_init maskgrid argument missing for metamorphosis:mask transformation')
2285  CALL raise_error()
2286  RETURN
2287  ENDIF
2288 
2289  IF (this%innx /= SIZE(maskgrid,1) .OR. this%inny /= SIZE(maskgrid,2)) THEN
2290  CALL l4f_category_log(this%category,l4f_error, &
2291  'grid_transform_init mask non conformal with input field')
2292  CALL l4f_category_log(this%category,l4f_error, &
2293  'mask: '//t2c(SIZE(maskgrid,1))//'x'//t2c(SIZE(maskgrid,2))// &
2294  ' input field:'//t2c(this%innx)//'x'//t2c(this%inny))
2295  CALL raise_error()
2296  RETURN
2297  ENDIF
2298 
2299 ! generate the subarea boundaries according to maskgrid and maskbounds
2300  CALL gen_mask_class()
2301 
2302 #ifdef _OPENMP
2303  outnx = 0
2304 #else
2305  this%outnx = 0
2306 #endif
2307  this%outny = 1
2308 
2309 ! this OMP block has to be checked
2310 !$OMP PARALLEL DEFAULT(SHARED)
2311 !$OMP DO PRIVATE(iy, ix), REDUCTION(+:outnx)
2312  DO iy = 1, this%inny
2313  DO ix = 1, this%innx
2314  IF (c_e(maskgrid(ix,iy))) THEN
2315  IF (maskgrid(ix,iy) <= lmaskbounds(nmaskarea+1)) THEN
2316  DO n = nmaskarea, 1, -1
2317  IF (maskgrid(ix,iy) > lmaskbounds(n)) THEN
2318 #ifdef _OPENMP
2319  outnx = outnx + 1
2320 #else
2321  this%outnx = this%outnx + 1
2322 #endif
2323  this%point_index(ix,iy) = n
2324  EXIT
2325  ENDIF
2326  ENDDO
2327  ENDIF
2328  ENDIF
2329  ENDDO
2330  ENDDO
2331 !$OMP END PARALLEL
2332 !$ this%outnx = outnx
2333 
2334  IF (this%outnx <= 0) THEN
2335  CALL l4f_category_log(this%category,l4f_warn, &
2336  "grid_transform_init no points inside mask for metamorphosis:mask transformation")
2337  ENDIF
2338 #ifdef DEBUG
2339  DO n = 1, nmaskarea
2340  CALL l4f_category_log(this%category,l4f_info, &
2341  "points in subarea "//t2c(n)//": "// &
2342  t2c(count(this%point_index(:,:) == n)))
2343  ENDDO
2344 #endif
2345  CALL vol7d_alloc(v7d_out, nana=this%outnx)
2346 ! collect coordinates of points falling into requested polygon
2347  n = 0
2348  DO iy = 1, this%inny
2349  DO ix = 1, this%innx
2350  IF (c_e(this%point_index(ix,iy))) THEN
2351  n = n + 1
2352  CALL init(v7d_out%ana(n),lon=lin%dim%lon(ix,iy),lat=lin%dim%lat(ix,iy))
2353  ENDIF
2354  ENDDO
2355  ENDDO
2356 
2357  this%valid = .true.
2358 
2359  ELSE IF (this%trans%sub_type == 'index') THEN
2360  this%outnx = SIZE(v7d_out%ana)
2361  this%outny = 1
2362 
2363 ! collect points having requested index
2364 ! check that v7d_out has just 1 variable B01192 (index)
2365  IF (any(c_e(lin%dim%lon))) THEN ! here we set also coordinates, find a more efficient way to check
2366  DO n = 1, SIZE(v7d_out%ana)
2367  iy = (v7d_out%volanai(n,1,1) - 1)/this%innx + 1
2368  ix = v7d_out%volanai(n,1,1) - (iy-1)*this%innx
2369  this%point_index(ix,iy) = v7d_out%volanai(n,1,1)
2370  CALL init(v7d_out%ana(n), &
2371  lon=lin%dim%lon(ix,iy), lat=lin%dim%lat(ix,iy)) ! (re)set coordinates from truth
2372  ENDDO
2373  ELSE ! here we trust coordinates from input
2374  DO n = 1, SIZE(v7d_out%ana)
2375  iy = (v7d_out%volanai(n,1,1) - 1)/this%innx + 1
2376  ix = v7d_out%volanai(n,1,1) - (iy-1)*this%innx
2377  this%point_index(ix,iy) = v7d_out%volanai(n,1,1)
2378  ENDDO
2379  ENDIF
2380  this%valid = .true.
2381  ENDIF
2382  CALL delete(lin)
2383 ENDIF
2384 
2385 CONTAINS
2386 
2387 SUBROUTINE gen_mask_class()
2388 REAL :: startmaskclass, mmin, mmax
2389 INTEGER :: i
2390 
2391 IF (PRESENT(maskbounds)) THEN
2392  nmaskarea = SIZE(maskbounds) - 1
2393  IF (nmaskarea > 0) THEN
2394  lmaskbounds = maskbounds ! automatic f2003 allocation
2395  RETURN
2396  ELSE IF (nmaskarea == 0) THEN
2397  CALL l4f_category_log(this%category,l4f_warn, &
2398  'only one value provided for maskbounds, '//t2c(maskbounds(1)) &
2399  //', it will be ignored')
2400  CALL l4f_category_log(this%category,l4f_warn, &
2401  'at least 2 values are required for maskbounds')
2402  ENDIF
2403 ENDIF
2404 
2405 mmin = minval(maskgrid, mask=c_e(maskgrid))
2406 mmax = maxval(maskgrid, mask=c_e(maskgrid))
2407 
2408 nmaskarea = int(mmax - mmin + 1.5)
2409 startmaskclass = mmin - 0.5
2410 ! assign limits for each class
2411 ALLOCATE(lmaskbounds(nmaskarea+1))
2412 lmaskbounds(:) = (/(startmaskclass+REAL(i),i=0,nmaskarea)/)
2413 #ifdef DEBUG
2414 CALL l4f_category_log(this%category,l4f_debug, &
2415  'maskinter, '//t2c(nmaskarea)//' subareas defined, with boundaries:')
2416 DO i = 1, SIZE(lmaskbounds)
2417  CALL l4f_category_log(this%category,l4f_debug, &
2418  'maskinter '//t2c(i)//' '//t2c(lmaskbounds(i)))
2419 ENDDO
2420 #endif
2421 
2422 END SUBROUTINE gen_mask_class
2423 
2424 END SUBROUTINE grid_transform_grid_vol7d_init
2425 
2426 
2445 SUBROUTINE grid_transform_vol7d_grid_init(this, trans, v7d_in, out, categoryappend)
2446 TYPE(grid_transform),INTENT(out) :: this
2447 TYPE(transform_def),INTENT(in) :: trans
2448 TYPE(vol7d),INTENT(in) :: v7d_in
2449 TYPE(griddim_def),INTENT(in) :: out
2450 character(len=*),INTENT(in),OPTIONAL :: categoryappend
2451 
2452 INTEGER :: nx, ny
2453 DOUBLE PRECISION :: xmin, xmax, ymin, ymax, lonref
2454 DOUBLE PRECISION,ALLOCATABLE :: lon(:,:),lat(:,:)
2455 TYPE(griddim_def) :: lout
2456 
2457 
2458 CALL grid_transform_init_common(this, trans, categoryappend)
2459 #ifdef DEBUG
2460 CALL l4f_category_log(this%category, l4f_debug, "grid_transform v7d-vg6d")
2461 #endif
2462 
2463 IF (this%trans%trans_type == 'inter') THEN
2464 
2465  IF ( this%trans%sub_type == 'linear' ) THEN
2466 
2467  this%innx=SIZE(v7d_in%ana)
2468  this%inny=1
2469  ALLOCATE(lon(this%innx,1),lat(this%innx,1))
2470  ALLOCATE(this%inter_xp(this%innx,this%inny),this%inter_yp(this%innx,this%inny))
2471  CALL getval(v7d_in%ana(:)%coord,lon=lon(:,1),lat=lat(:,1))
2472 
2473  CALL copy (out, lout)
2474 ! equalize in/out coordinates
2475  lonref = 0.5d0*(maxval(lon(:,1), mask=c_e(lon(:,1))) + minval(lon(:,1), mask=c_e(lon(:,1))))
2476  CALL griddim_set_central_lon(lout, lonref)
2477 
2478  CALL get_val(lout, nx=nx, ny=ny)
2479  this%outnx=nx
2480  this%outny=ny
2481  ALLOCATE(this%inter_x(this%outnx,this%outny),this%inter_y(this%outnx,this%outny))
2482 
2483  CALL get_val(lout, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
2484  CALL proj(lout, lon, lat, this%inter_xp, this%inter_yp)
2485  CALL griddim_gen_coord(lout, this%inter_x, this%inter_y)
2486 
2487  DEALLOCATE(lon,lat)
2488  CALL delete(lout)
2489 
2490  this%valid = .true.
2491 
2492  ENDIF
2493 
2494 ELSE IF (this%trans%trans_type == 'boxinter') THEN
2495 
2496  this%innx=SIZE(v7d_in%ana)
2497  this%inny=1
2498 ! index arrays must have the shape of input grid
2499  ALLOCATE(lon(this%innx,1),lat(this%innx,1))
2500  ALLOCATE(this%inter_index_x(this%innx,this%inny), &
2501  this%inter_index_y(this%innx,this%inny))
2502 ! get coordinates of input grid in geo system
2503  CALL getval(v7d_in%ana(:)%coord,lon=lon(:,1),lat=lat(:,1))
2504 
2505  CALL copy (out, lout)
2506 ! equalize in/out coordinates
2507  lonref = 0.5d0*(maxval(lon(:,1), mask=c_e(lon(:,1))) + minval(lon(:,1), mask=c_e(lon(:,1))))
2508  CALL griddim_set_central_lon(lout, lonref)
2509 
2510  CALL get_val(lout, nx=this%outnx, ny=this%outny, &
2511  xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax)
2512 ! TODO now box size is ignored
2513 ! if box size not provided, use the actual grid step
2514  IF (.NOT.c_e(this%trans%area_info%boxdx)) &
2515  CALL get_val(out, dx=this%trans%area_info%boxdx)
2516  IF (.NOT.c_e(this%trans%area_info%boxdy)) &
2517  CALL get_val(out, dx=this%trans%area_info%boxdy)
2518 ! half size is actually needed
2519  this%trans%area_info%boxdx = this%trans%area_info%boxdx*0.5d0
2520  this%trans%area_info%boxdy = this%trans%area_info%boxdy*0.5d0
2521 
2522 ! use find_index in the opposite way, here extrap does not make sense
2523  CALL this%find_index(lout, .true., &
2524  this%outnx, this%outny, xmin, xmax, ymin, ymax, &
2525  lon, lat, .false., &
2526  this%inter_index_x, this%inter_index_y)
2527 
2528  DEALLOCATE(lon,lat)
2529  CALL delete(lout)
2530 
2531  this%valid = .true. ! warning, no check of subtype
2532 
2533 ENDIF
2534 
2535 END SUBROUTINE grid_transform_vol7d_grid_init
2536 
2537 
2572 SUBROUTINE grid_transform_vol7d_vol7d_init(this, trans, v7d_in, v7d_out, &
2573  maskbounds, categoryappend)
2574 TYPE(grid_transform),INTENT(out) :: this
2575 TYPE(transform_def),INTENT(in) :: trans
2576 TYPE(vol7d),INTENT(in) :: v7d_in
2577 TYPE(vol7d),INTENT(inout) :: v7d_out
2578 REAL,INTENT(in),OPTIONAL :: maskbounds(:)
2579 CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend
2580 
2581 INTEGER :: i, n
2582 DOUBLE PRECISION,ALLOCATABLE :: lon(:), lat(:)
2583 ! temporary, improve!!!!
2584 DOUBLE PRECISION :: lon1, lat1
2585 TYPE(georef_coord) :: point
2586 
2587 
2588 CALL grid_transform_init_common(this, trans, categoryappend)
2589 #ifdef DEBUG
2590 CALL l4f_category_log(this%category, l4f_debug, "grid_transform v7d-v7d")
2591 #endif
2592 
2593 IF (this%trans%trans_type == 'inter') THEN
2594 
2595  IF ( this%trans%sub_type == 'linear' ) THEN
2596 
2597  CALL vol7d_alloc_vol(v7d_out) ! be safe
2598  this%outnx=SIZE(v7d_out%ana)
2599  this%outny=1
2600 
2601  this%innx=SIZE(v7d_in%ana)
2602  this%inny=1
2603 
2604  ALLOCATE(this%inter_xp(this%innx,this%inny),this%inter_yp(this%innx,this%inny))
2605  ALLOCATE(this%inter_x(this%outnx,this%outny),this%inter_y(this%outnx,this%outny))
2606 
2607  CALL getval(v7d_in%ana(:)%coord,lon=this%inter_xp(:,1),lat=this%inter_yp(:,1))
2608  CALL getval(v7d_out%ana(:)%coord,lon=this%inter_x(:,1),lat=this%inter_y(:,1))
2609 
2610  this%valid = .true.
2611 
2612  ENDIF
2613 
2614 ELSE IF (this%trans%trans_type == 'polyinter') THEN
2615 
2616  this%innx=SIZE(v7d_in%ana)
2617  this%inny=1
2618 ! unlike before, here index arrays must have the shape of input grid
2619  ALLOCATE(this%inter_index_x(this%innx,this%inny), &
2620  this%inter_index_y(this%innx,this%inny))
2621  this%inter_index_x(:,:) = imiss
2622  this%inter_index_y(:,:) = 1
2623 
2624  DO i = 1, SIZE(v7d_in%ana)
2625 ! temporary, improve!!!!
2626  CALL getval(v7d_in%ana(i)%coord,lon=lon1,lat=lat1)
2627  point = georef_coord_new(x=lon1, y=lat1)
2628 
2629  DO n = 1, this%trans%poly%arraysize
2630  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
2631  this%inter_index_x(i,1) = n
2632  EXIT
2633  ENDIF
2634  ENDDO
2635  ENDDO
2636 
2637  this%outnx=this%trans%poly%arraysize
2638  this%outny=1
2639  CALL vol7d_alloc(v7d_out, nana=this%outnx)
2640 
2641 ! setup output point list, equal to average of polygon points
2642 ! warning, in case of concave areas points may coincide!
2643  CALL poly_to_coordinates(this%trans%poly, v7d_out)
2644 
2645  this%valid = .true. ! warning, no check of subtype
2646 
2647 ELSE IF (this%trans%trans_type == 'metamorphosis') THEN
2648 
2649 ! common to all metamorphosis subtypes
2650  this%innx = SIZE(v7d_in%ana)
2651  this%inny = 1
2652 ! allocate index array
2653  ALLOCATE(this%point_index(this%innx,this%inny))
2654  this%point_index(:,:) = imiss
2655 
2656  IF (this%trans%sub_type == 'all' ) THEN
2657 
2658  CALL metamorphosis_all_setup()
2659 
2660  ELSE IF (this%trans%sub_type == 'coordbb' ) THEN
2661 
2662  ALLOCATE(lon(this%innx),lat(this%innx))
2663 
2664 ! count and mark points falling into requested bounding-box
2665  this%outnx = 0
2666  this%outny = 1
2667  CALL getval(v7d_in%ana(:)%coord,lon=lon,lat=lat)
2668  DO i = 1, this%innx
2669 ! IF (geo_coord_inside_rectang()
2670  IF (lon(i) > this%trans%rect_coo%ilon .AND. &
2671  lon(i) < this%trans%rect_coo%flon .AND. &
2672  lat(i) > this%trans%rect_coo%ilat .AND. &
2673  lat(i) < this%trans%rect_coo%flat) THEN ! improve!
2674  this%outnx = this%outnx + 1
2675  this%point_index(i,1) = this%outnx
2676  ENDIF
2677  ENDDO
2678 
2679  IF (this%outnx <= 0) THEN
2680  CALL l4f_category_log(this%category,l4f_warn, &
2681  "metamorphosis:coordbb: no points inside bounding box "//&
2682  trim(to_char(this%trans%rect_coo%ilon))//","// &
2683  trim(to_char(this%trans%rect_coo%flon))//","// &
2684  trim(to_char(this%trans%rect_coo%ilat))//","// &
2685  trim(to_char(this%trans%rect_coo%flat)))
2686  ENDIF
2687 
2688  CALL vol7d_alloc(v7d_out, nana=this%outnx)
2689 
2690 ! collect coordinates of points falling into requested bounding-box
2691  n = 0
2692  DO i = 1, this%innx
2693  IF (c_e(this%point_index(i,1))) THEN
2694  n = n + 1
2695  CALL init(v7d_out%ana(n),lon=lon(i),lat=lat(i))
2696  ENDIF
2697  ENDDO
2698  DEALLOCATE(lon, lat)
2699 
2700  this%valid = .true.
2701 
2702  ELSE IF (this%trans%sub_type == 'poly' ) THEN
2703 
2704 ! count and mark points falling into requested polygon
2705  this%outnx = 0
2706  this%outny = 1
2707  DO i = 1, this%innx
2708 ! temporary, improve!!!!
2709  CALL getval(v7d_in%ana(i)%coord,lon=lon1,lat=lat1)
2710  point = georef_coord_new(x=lon1, y=lat1)
2711  DO n = 1, this%trans%poly%arraysize
2712  IF (inside(point, this%trans%poly%array(n))) THEN ! stop at the first matching polygon
2713  this%outnx = this%outnx + 1
2714  this%point_index(i,1) = n
2715  EXIT
2716  ENDIF
2717  ENDDO
2718 ! CALL delete(point) ! speedup
2719  ENDDO
2720 
2721  IF (this%outnx <= 0) THEN
2722  CALL l4f_category_log(this%category,l4f_warn, &
2723  "metamorphosis:poly: no points inside polygons")
2724  ENDIF
2725 
2726  CALL vol7d_alloc(v7d_out, nana=this%outnx)
2727 
2728 ! collect coordinates of points falling into requested polygon
2729  n = 0
2730  DO i = 1, this%innx
2731  IF (c_e(this%point_index(i,1))) THEN
2732  n = n + 1
2733 ! temporary, improve!!!!
2734  CALL getval(v7d_in%ana(i)%coord,lon=lon1,lat=lat1)
2735  CALL init(v7d_out%ana(n),lon=lon1,lat=lat1)
2736  ENDIF
2737  ENDDO
2738 
2739  this%valid = .true.
2740 
2741  ELSE IF (this%trans%sub_type == 'setinvalidto' ) THEN
2742 
2743  IF (.NOT.PRESENT(maskbounds)) THEN
2744  CALL l4f_category_log(this%category,l4f_error, &
2745  'grid_transform_init maskbounds missing for metamorphosis:'// &
2746  trim(this%trans%sub_type)//' transformation')
2747  RETURN
2748  ELSE IF (SIZE(maskbounds) < 1) THEN
2749  CALL l4f_category_log(this%category,l4f_error, &
2750  'grid_transform_init maskbounds empty for metamorphosis:'// &
2751  trim(this%trans%sub_type)//' transformation')
2752  RETURN
2753  ELSE
2754  this%val1 = maskbounds(1)
2755 #ifdef DEBUG
2756  CALL l4f_category_log(this%category, l4f_debug, &
2757  "grid_transform_init setting invalid data to "//t2c(this%val1))
2758 #endif
2759  ENDIF
2760 
2761  CALL metamorphosis_all_setup()
2762 
2763  ELSE IF (this%trans%sub_type == 'settoinvalid' ) THEN
2764 
2765  IF (.NOT.PRESENT(maskbounds)) THEN
2766  CALL l4f_category_log(this%category,l4f_error, &
2767  'grid_transform_init maskbounds missing for metamorphosis:'// &
2768  trim(this%trans%sub_type)//' transformation')
2769  CALL raise_error()
2770  RETURN
2771  ELSE IF (SIZE(maskbounds) < 2) THEN
2772  CALL l4f_category_log(this%category,l4f_error, &
2773  'grid_transform_init maskbounds must have at least 2 elements for metamorphosis:'// &
2774  trim(this%trans%sub_type)//' transformation')
2775  CALL raise_error()
2776  RETURN
2777  ELSE
2778  this%val1 = maskbounds(1)
2779  this%val2 = maskbounds(SIZE(maskbounds))
2780 #ifdef DEBUG
2781  CALL l4f_category_log(this%category, l4f_debug, &
2782  "grid_transform_init setting to invalid interval ]"//t2c(this%val1)//','// &
2783  t2c(this%val2)//']')
2784 #endif
2785  ENDIF
2786 
2787  CALL metamorphosis_all_setup()
2788 
2789  ENDIF
2790 ENDIF
2791 
2792 CONTAINS
2793 
2794 ! common code to metamorphosis transformations conserving the number
2795 ! of points
2796 SUBROUTINE metamorphosis_all_setup()
2797 
2798 this%outnx = SIZE(v7d_in%ana)
2799 this%outny = 1
2800 this%point_index(:,1) = (/(i,i=1,this%innx)/)
2801 CALL vol7d_alloc(v7d_out, nana=SIZE(v7d_in%ana))
2802 v7d_out%ana = v7d_in%ana
2803 
2804 this%valid = .true.
2805 
2806 END SUBROUTINE metamorphosis_all_setup
2807 
2808 END SUBROUTINE grid_transform_vol7d_vol7d_init
2809 
2810 
2811 ! Private subroutine for performing operations common to all constructors
2812 SUBROUTINE grid_transform_init_common(this, trans, categoryappend)
2813 TYPE(grid_transform),INTENT(inout) :: this
2814 TYPE(transform_def),INTENT(in) :: trans
2815 CHARACTER(len=*),INTENT(in),OPTIONAL :: categoryappend
2816 
2817 CHARACTER(len=512) :: a_name
2818 
2819 IF (PRESENT(categoryappend)) THEN
2820  CALL l4f_launcher(a_name,a_name_append=trim(subcategory)//"."// &
2821  trim(categoryappend))
2822 ELSE
2823  CALL l4f_launcher(a_name,a_name_append=trim(subcategory))
2824 ENDIF
2825 this%category=l4f_category_get_handle(a_name)
2826 
2827 #ifdef DEBUG
2828 CALL l4f_category_log(this%category,l4f_debug,"start init_grid_transform")
2829 #endif
2830 
2831 this%trans=trans
2832 
2833 END SUBROUTINE grid_transform_init_common
2834 
2835 ! internal subroutine to correctly initialise the output coordinates
2836 ! with polygon centroid coordinates
2837 SUBROUTINE poly_to_coordinates(poly, v7d_out)
2838 TYPE(arrayof_georef_coord_array),intent(in) :: poly
2839 TYPE(vol7d),INTENT(inout) :: v7d_out
2840 
2841 INTEGER :: n, sz
2842 DOUBLE PRECISION,ALLOCATABLE :: lon(:), lat(:)
2843 
2844 DO n = 1, poly%arraysize
2845  CALL getval(poly%array(n), x=lon, y=lat)
2846  sz = min(SIZE(lon), SIZE(lat))
2847  IF (lon(1) == lon(sz) .AND. lat(1) == lat(sz)) THEN ! closed polygon
2848  sz = sz - 1
2849  ENDIF
2850  CALL init(v7d_out%ana(n), lon=stat_average(lon(1:sz)), lat=stat_average(lat(1:sz)))
2851 ENDDO
2852 
2853 END SUBROUTINE poly_to_coordinates
2854 
2858 SUBROUTINE grid_transform_delete(this)
2859 TYPE(grid_transform),INTENT(inout) :: this
2860 
2861 CALL delete(this%trans)
2862 
2863 this%innx=imiss
2864 this%inny=imiss
2865 this%outnx=imiss
2866 this%outny=imiss
2867 this%iniox=imiss
2868 this%inioy=imiss
2869 this%infox=imiss
2870 this%infoy=imiss
2871 this%outinx=imiss
2872 this%outiny=imiss
2873 this%outfnx=imiss
2874 this%outfny=imiss
2875 
2876 if (associated(this%inter_index_x)) deallocate (this%inter_index_x)
2877 if (associated(this%inter_index_y)) deallocate (this%inter_index_y)
2878 if (associated(this%inter_index_z)) deallocate (this%inter_index_z)
2879 if (associated(this%point_index)) deallocate (this%point_index)
2880 
2881 if (associated(this%inter_x)) deallocate (this%inter_x)
2882 if (associated(this%inter_y)) deallocate (this%inter_y)
2883 
2884 if (associated(this%inter_xp)) deallocate (this%inter_xp)
2885 if (associated(this%inter_yp)) deallocate (this%inter_yp)
2886 if (associated(this%inter_zp)) deallocate (this%inter_zp)
2887 if (associated(this%vcoord_in)) deallocate (this%vcoord_in)
2888 if (associated(this%vcoord_out)) deallocate (this%vcoord_out)
2889 if (associated(this%point_mask)) deallocate (this%point_mask)
2890 if (associated(this%stencil)) deallocate (this%stencil)
2891 if (associated(this%output_level_auto)) deallocate (this%output_level_auto)
2892 IF (ALLOCATED(this%coord_3d_in)) DEALLOCATE(this%coord_3d_in)
2893 this%valid = .false.
2894 
2895 ! close the logger
2896 call l4f_category_delete(this%category)
2897 
2898 END SUBROUTINE grid_transform_delete
2899 
2900 
2905 SUBROUTINE grid_transform_get_val(this, output_level_auto, point_mask, &
2906  point_index, output_point_index, levshift, levused)
2907 TYPE(grid_transform),INTENT(in) :: this
2908 TYPE(vol7d_level),POINTER,OPTIONAL :: output_level_auto(:)
2909 LOGICAL,INTENT(out),ALLOCATABLE,OPTIONAL :: point_mask(:)
2910 INTEGER,INTENT(out),ALLOCATABLE,OPTIONAL :: point_index(:)
2911 INTEGER,INTENT(out),ALLOCATABLE,OPTIONAL :: output_point_index(:)
2912 INTEGER,INTENT(out),OPTIONAL :: levshift
2913 INTEGER,INTENT(out),OPTIONAL :: levused
2914 
2915 INTEGER :: i
2916 
2917 IF (PRESENT(output_level_auto)) output_level_auto => this%output_level_auto
2918 IF (PRESENT(point_mask)) THEN
2919  IF (ASSOCIATED(this%point_index)) THEN
2920  point_mask = c_e(reshape(this%point_index, (/SIZE(this%point_index)/)))
2921  ENDIF
2922 ENDIF
2923 IF (PRESENT(point_index)) THEN
2924  IF (ASSOCIATED(this%point_index)) THEN
2925  point_index = reshape(this%point_index, (/SIZE(this%point_index)/))
2926  ENDIF
2927 ENDIF
2928 IF (PRESENT(output_point_index)) THEN
2929  IF (ASSOCIATED(this%point_index)) THEN
2930 ! metamorphosis, index is computed from input origin of output point
2931  output_point_index = pack(this%point_index(:,:), c_e(this%point_index))
2932  ELSE IF (this%trans%trans_type == 'polyinter' .OR. &
2933  this%trans%trans_type == 'maskinter') THEN
2934 ! other cases, index is order of output point
2935  output_point_index = (/(i,i=1,this%outnx)/)
2936  ENDIF
2937 ENDIF
2938 IF (PRESENT(levshift)) levshift = this%levshift
2939 IF (PRESENT(levused)) levused = this%levused
2940 
2941 END SUBROUTINE grid_transform_get_val
2942 
2943 
2946 FUNCTION grid_transform_c_e(this)
2947 TYPE(grid_transform),INTENT(in) :: this
2948 LOGICAL :: grid_transform_c_e
2949 
2950 grid_transform_c_e = this%valid
2951 
2952 END FUNCTION grid_transform_c_e
2953 
2954 
2964 RECURSIVE SUBROUTINE grid_transform_compute(this, field_in, field_out, var, &
2965  coord_3d_in, zlist)
2966 TYPE(grid_transform),INTENT(in),TARGET :: this
2967 REAL,INTENT(in) :: field_in(:,:,:)
2968 REAL,INTENT(out) :: field_out(:,:,:)
2969 TYPE(vol7d_var),INTENT(in),OPTIONAL :: var
2970 REAL,INTENT(in),OPTIONAL,TARGET :: coord_3d_in(:,:,:)
2971 LOGICAL,INTENT(in),OPTIONAL :: zlist(:)
2972 
2973 INTEGER :: i, j, k, l, m, s, ii, jj, ie, je, n, navg, kk, kkcache, kkup, kkdown, &
2974  kfound, kfoundin, inused, i1, i2, j1, j2, np, ns, ix, iy
2975 INTEGER,ALLOCATABLE :: nval(:,:)
2976 REAL :: z1,z2,z3,z4,z(4)
2977 DOUBLE PRECISION :: x1,x3,y1,y3,xp,yp, disttmp, dist
2978 INTEGER :: innx, inny, innz, outnx, outny, outnz, vartype, nearcount
2979 REAL,ALLOCATABLE :: coord_in(:)
2980 LOGICAL,ALLOCATABLE :: mask_in(:)
2981 REAL,ALLOCATABLE :: val_in(:), field_tmp(:,:,:)
2982 REAL,POINTER :: coord_3d_in_act(:,:,:)
2983 TYPE(grid_transform) :: likethis
2984 LOGICAL :: alloc_coord_3d_in_act, nm1, optsearch, farenough
2985 CHARACTER(len=4) :: env_var
2986 LOGICAL,ALLOCATABLE :: lzlist(:)
2987 
2988 #ifdef DEBUG
2989 CALL l4f_category_log(this%category,l4f_debug,"start grid_transform_compute")
2990 #endif
2991 
2992 field_out(:,:,:) = rmiss
2993 
2994 IF (.NOT.this%valid) THEN
2995  CALL l4f_category_log(this%category,l4f_error, &
2996  "refusing to perform a non valid transformation")
2997  RETURN
2998 ENDIF
2999 
3000 IF (this%recur) THEN ! if recursive transformation, recur here and exit
3001 #ifdef DEBUG
3002  CALL l4f_category_log(this%category,l4f_debug, &
3003  "recursive transformation in grid_transform_compute")
3004 #endif
3005 
3006  IF (this%trans%trans_type == 'polyinter') THEN
3007  likethis = this
3008  likethis%recur = .false.
3009  likethis%outnx = this%trans%poly%arraysize
3010  likethis%outny = 1
3011  ALLOCATE(field_tmp(this%trans%poly%arraysize,1,SIZE(field_out,3)))
3012  CALL grid_transform_compute(likethis, field_in, field_tmp, var, coord_3d_in, zlist)
3013 
3014  DO k = 1, SIZE(field_out,3)
3015  DO j = 1, this%inny
3016  DO i = 1, this%innx
3017  IF (c_e(this%inter_index_x(i,j))) THEN
3018  field_out(i,j,k) = field_tmp(this%inter_index_x(i,j),this%inter_index_y(i,j),k)
3019  ENDIF
3020  ENDDO
3021  ENDDO
3022  ENDDO
3023  DEALLOCATE(field_tmp)
3024  ENDIF
3025 
3026  RETURN
3027 ENDIF
3028 
3029 vartype = var_ord
3030 IF (PRESENT(var)) THEN
3031  vartype = vol7d_vartype(var)
3032 ENDIF
3033 
3034 innx = SIZE(field_in,1); inny = SIZE(field_in,2); innz = SIZE(field_in,3)
3035 outnx = SIZE(field_out,1); outny = SIZE(field_out,2); outnz = SIZE(field_out,3)
3036 ALLOCATE(lzlist(innz))
3037 IF (PRESENT(zlist)) THEN
3038  lzlist(:) = zlist(:)
3039 ELSE
3040  lzlist(:) = .true.
3041 ENDIF
3042 
3043 ! check size of field_in, field_out
3044 IF (this%trans%trans_type == 'vertint') THEN ! vertical interpolation
3045 
3046  IF (innz /= this%innz) THEN
3047  CALL l4f_category_log(this%category,l4f_error,"vertical interpolation")
3048  CALL l4f_category_log(this%category,l4f_error,"inconsistent input shape: "//&
3049  t2c(this%innz)//" /= "//t2c(innz))
3050  CALL raise_error()
3051  RETURN
3052  ENDIF
3053 
3054  IF (outnz /= this%outnz) THEN
3055  CALL l4f_category_log(this%category,l4f_error,"vertical interpolation")
3056  CALL l4f_category_log(this%category,l4f_error,"inconsistent output shape: "//&
3057  t2c(this%outnz)//" /= "//t2c(outnz))
3058  CALL raise_error()
3059  RETURN
3060  ENDIF
3061 
3062  IF (innx /= outnx .OR. inny /= outny) THEN
3063  CALL l4f_category_log(this%category,l4f_error,"vertical interpolation")
3064  CALL l4f_category_log(this%category,l4f_error,"inconsistent hor. sizes: "//&
3065  t2c(innx)//","//t2c(inny)//" /= "//&
3066  t2c(outnx)//","//t2c(outny))
3067  CALL raise_error()
3068  RETURN
3069  ENDIF
3070 
3071 ELSE ! horizontal interpolation
3072 
3073  IF (innx /= this%innx .OR. inny /= this%inny) THEN
3074  CALL l4f_category_log(this%category,l4f_error,"horizontal interpolation")
3075  CALL l4f_category_log(this%category,l4f_error,"inconsistent input shape: "//&
3076  t2c(this%innx)//","//t2c(this%inny)//" /= "//&
3077  t2c(innx)//","//t2c(inny))
3078  CALL raise_error()
3079  RETURN
3080  ENDIF
3081 
3082  IF (outnx /= this%outnx .OR. outny /= this%outny) THEN
3083  CALL l4f_category_log(this%category,l4f_error,"horizontal interpolation")
3084  CALL l4f_category_log(this%category,l4f_error,"inconsistent output shape: "//&
3085  t2c(this%outnx)//","//t2c(this%outny)//" /= "//&
3086  t2c(outnx)//","//t2c(outny))
3087  CALL raise_error()
3088  RETURN
3089  ENDIF
3090 
3091  IF (innz /= outnz) THEN
3092  CALL l4f_category_log(this%category,l4f_error,"horizontal interpolation")
3093  CALL l4f_category_log(this%category,l4f_error,"inconsistent vert. sizes: "//&
3094  t2c(innz)//" /= "//t2c(outnz))
3095  CALL raise_error()
3096  RETURN
3097  ENDIF
3099 ENDIF
3100 
3101 #ifdef DEBUG
3102 call l4f_category_log(this%category,l4f_debug, &
3103  "start grid_transform_compute "//trim(this%trans%trans_type)//':'// &
3104  trim(this%trans%sub_type))
3105 #endif
3106 
3107 IF (this%trans%trans_type == 'zoom') THEN
3108 
3109  field_out(this%outinx:this%outfnx, &
3110  this%outiny:this%outfny,:) = &
3111  field_in(this%iniox:this%infox, &
3112  this%inioy:this%infoy,:)
3113 
3114 ELSE IF (this%trans%trans_type == 'boxregrid') THEN
3115 
3116  IF (this%trans%sub_type == 'average') THEN
3117  IF (vartype == var_dir360) THEN
3118  DO k = 1, innz
3119  IF (.NOT.lzlist(k)) cycle
3120  jj = 0
3121  DO j = 1, this%inny - this%trans%box_info%npy + 1, this%trans%box_info%npy
3122  je = j+this%trans%box_info%npy-1
3123  jj = jj+1
3124  ii = 0
3125  DO i = 1, this%innx - this%trans%box_info%npx + 1, this%trans%box_info%npx
3126  ie = i+this%trans%box_info%npx-1
3127  ii = ii+1
3128  navg = count(field_in(i:ie,j:je,k) /= rmiss)
3129  IF (navg > 0) THEN
3130  field_out(ii,jj,k) = find_prevailing_direction(field_in(i:ie,j:je,k), &
3131  0.0, 360.0, 5.0)
3132  ENDIF
3133  ENDDO
3134  ENDDO
3135  ENDDO
3136 
3137  ELSE
3138  DO k = 1, innz
3139  IF (.NOT.lzlist(k)) cycle
3140  jj = 0
3141  DO j = 1, this%inny - this%trans%box_info%npy + 1, this%trans%box_info%npy
3142  je = j+this%trans%box_info%npy-1
3143  jj = jj+1
3144  ii = 0
3145  DO i = 1, this%innx - this%trans%box_info%npx + 1, this%trans%box_info%npx
3146  ie = i+this%trans%box_info%npx-1
3147  ii = ii+1
3148  navg = count(field_in(i:ie,j:je,k) /= rmiss)
3149  IF (navg > 0) THEN
3150  field_out(ii,jj,k) = sum(field_in(i:ie,j:je,k), &
3151  mask=(field_in(i:ie,j:je,k) /= rmiss))/navg
3152  ENDIF
3153  ENDDO
3154  ENDDO
3155  ENDDO
3156 
3157  ENDIF
3158 
3159  ELSE IF (this%trans%sub_type == 'stddev' .OR. &
3160  this%trans%sub_type == 'stddevnm1') THEN
3161 
3162  IF (this%trans%sub_type == 'stddev') THEN
3163  nm1 = .false.
3164  ELSE
3165  nm1 = .true.
3166  ENDIF
3167 
3168  navg = this%trans%box_info%npx*this%trans%box_info%npy
3169  DO k = 1, innz
3170  IF (.NOT.lzlist(k)) cycle
3171  jj = 0
3172  DO j = 1, this%inny - this%trans%box_info%npy + 1, this%trans%box_info%npy
3173  je = j+this%trans%box_info%npy-1
3174  jj = jj+1
3175  ii = 0
3176  DO i = 1, this%innx - this%trans%box_info%npx + 1, this%trans%box_info%npx
3177  ie = i+this%trans%box_info%npx-1
3178  ii = ii+1
3179  field_out(ii,jj,k) = stat_stddev( &
3180  reshape(field_in(i:ie,j:je,k),(/navg/)), nm1=nm1)
3181  ENDDO
3182  ENDDO
3183  ENDDO
3184 
3185  ELSE IF (this%trans%sub_type == 'max') THEN
3186  DO k = 1, innz
3187  IF (.NOT.lzlist(k)) cycle
3188  jj = 0
3189  DO j = 1, this%inny - this%trans%box_info%npy + 1, this%trans%box_info%npy
3190  je = j+this%trans%box_info%npy-1
3191  jj = jj+1
3192  ii = 0
3193  DO i = 1, this%innx - this%trans%box_info%npx + 1, this%trans%box_info%npx
3194  ie = i+this%trans%box_info%npx-1
3195  ii = ii+1
3196  navg = count(field_in(i:ie,j:je,k) /= rmiss)
3197  IF (navg > 0) THEN
3198  field_out(ii,jj,k) = maxval(field_in(i:ie,j:je,k), &
3199  mask=(field_in(i:ie,j:je,k) /= rmiss))
3200  ENDIF
3201  ENDDO
3202  ENDDO
3203  ENDDO
3204 
3205  ELSE IF (this%trans%sub_type == 'min') THEN
3206  DO k = 1, innz
3207  IF (.NOT.lzlist(k)) cycle
3208  jj = 0
3209  DO j = 1, this%inny - this%trans%box_info%npy + 1, this%trans%box_info%npy
3210  je = j+this%trans%box_info%npy-1
3211  jj = jj+1
3212  ii = 0
3213  DO i = 1, this%innx - this%trans%box_info%npx + 1, this%trans%box_info%npx
3214  ie = i+this%trans%box_info%npx-1
3215  ii = ii+1
3216  navg = count(field_in(i:ie,j:je,k) /= rmiss)
3217  IF (navg > 0) THEN
3218  field_out(ii,jj,k) = minval(field_in(i:ie,j:je,k), &
3219  mask=(field_in(i:ie,j:je,k) /= rmiss))
3220  ENDIF
3221  ENDDO
3222  ENDDO
3223  ENDDO
3224 
3225  ELSE IF (this%trans%sub_type == 'percentile') THEN
3226 
3227  navg = this%trans%box_info%npx*this%trans%box_info%npy
3228  DO k = 1, innz
3229  IF (.NOT.lzlist(k)) cycle
3230  jj = 0
3231  DO j = 1, this%inny - this%trans%box_info%npy + 1, this%trans%box_info%npy
3232  je = j+this%trans%box_info%npy-1
3233  jj = jj+1
3234  ii = 0
3235  DO i = 1, this%innx - this%trans%box_info%npx + 1, this%trans%box_info%npx
3236  ie = i+this%trans%box_info%npx-1
3237  ii = ii+1
3238  field_out(ii:ii,jj,k) = stat_percentile( &
3239  reshape(field_in(i:ie,j:je,k),(/navg/)), &
3240  (/REAL(this%trans%stat_info%percentile)/))
3241  ENDDO
3242  ENDDO
3243  ENDDO
3244 
3245  ELSE IF (this%trans%sub_type == 'frequency') THEN
3246 
3247  DO k = 1, innz
3248  IF (.NOT.lzlist(k)) cycle
3249  jj = 0
3250  DO j = 1, this%inny - this%trans%box_info%npy + 1, this%trans%box_info%npy
3251  je = j+this%trans%box_info%npy-1
3252  jj = jj+1
3253  ii = 0
3254  DO i = 1, this%innx - this%trans%box_info%npx + 1, this%trans%box_info%npx
3255  ie = i+this%trans%box_info%npx-1
3256  ii = ii+1
3257  navg = count(field_in(i:ie,j:je,k) /= rmiss)
3258  IF (navg > 0) THEN
3259  field_out(ii,jj,k) = sum(interval_info_valid( &
3260  this%trans%interval_info, field_in(i:ie,j:je,k)), &
3261  mask=(field_in(i:ie,j:je,k) /= rmiss))/navg
3262  ENDIF
3263  ENDDO
3264  ENDDO
3265  ENDDO
3266 
3267  ENDIF
3268 
3269 ELSE IF (this%trans%trans_type == 'inter') THEN
3270 
3271  IF (this%trans%sub_type == 'near') THEN
3272 
3273  DO k = 1, innz
3274  IF (.NOT.lzlist(k)) cycle
3275  DO j = 1, this%outny
3276  DO i = 1, this%outnx
3277 
3278  IF (c_e(this%inter_index_x(i,j))) field_out(i,j,k) = &
3279  field_in(this%inter_index_x(i,j),this%inter_index_y(i,j),k)
3280 
3281  ENDDO
3282  ENDDO
3283  ENDDO
3284 
3285  ELSE IF (this%trans%sub_type == 'bilin') THEN
3286 
3287  DO k = 1, innz
3288  IF (.NOT.lzlist(k)) cycle
3289  DO j = 1, this%outny
3290  DO i = 1, this%outnx
3291 
3292  IF (c_e(this%inter_index_x(i,j))) THEN
3293 
3294  z1=field_in(this%inter_index_x(i,j),this%inter_index_y(i,j),k)
3295  z2=field_in(this%inter_index_x(i,j)+1,this%inter_index_y(i,j),k)
3296  z3=field_in(this%inter_index_x(i,j)+1,this%inter_index_y(i,j)+1,k)
3297  z4=field_in(this%inter_index_x(i,j),this%inter_index_y(i,j)+1,k)
3298 
3299  IF (c_e(z1) .AND. c_e(z2) .AND. c_e(z3) .AND. c_e(z4)) THEN
3300 
3301  x1=this%inter_x(this%inter_index_x(i,j),this%inter_index_y(i,j))
3302  y1=this%inter_y(this%inter_index_x(i,j),this%inter_index_y(i,j))
3303  x3=this%inter_x(this%inter_index_x(i,j)+1,this%inter_index_y(i,j)+1)
3304  y3=this%inter_y(this%inter_index_x(i,j)+1,this%inter_index_y(i,j)+1)
3305 
3306  xp=this%inter_xp(i,j)
3307  yp=this%inter_yp(i,j)
3308 
3309  field_out(i,j,k) = hbilin(z1,z2,z3,z4,x1,y1,x3,y3,xp,yp)
3310 
3311  ENDIF
3312  ENDIF
3313 
3314  ENDDO
3315  ENDDO
3316  ENDDO
3317  ELSE IF (this%trans%sub_type == 'shapiro_near') THEN
3318  DO k = 1, innz
3319  IF (.NOT.lzlist(k)) cycle
3320  DO j = 1, this%outny
3321  DO i = 1, this%outnx
3322 
3323  IF (c_e(this%inter_index_x(i,j))) THEN
3324 
3325  IF(this%inter_index_x(i,j)-1>0)THEN
3326  z(1) = field_in(this%inter_index_x(i,j)-1,this%inter_index_y(i,j) ,k)
3327  ELSE
3328  z(1) = rmiss
3329  END IF
3330  IF(this%inter_index_x(i,j)+1<=this%outnx)THEN
3331  z(3)=field_in(this%inter_index_x(i,j)+1,this%inter_index_y(i,j) ,k)
3332  ELSE
3333  z(3) = rmiss
3334  END IF
3335  IF(this%inter_index_y(i,j)+1<=this%outny)THEN
3336  z(2)=field_in(this%inter_index_x(i,j) ,this%inter_index_y(i,j)+1,k)
3337  ELSE
3338  z(2) = rmiss
3339  END IF
3340  IF(this%inter_index_y(i,j)-1>0)THEN
3341  z(4)=field_in(this%inter_index_x(i,j), this%inter_index_y(i,j)-1,k)
3342  ELSE
3343  z(4) = rmiss
3344  END IF
3345  field_out(i,j,k) = shapiro(z,field_in(this%inter_index_x(i,j),this%inter_index_y(i,j),k))
3346 
3347  ENDIF
3348 
3349  ENDDO
3350  ENDDO
3351  ENDDO
3352 
3353  ENDIF
3354 ELSE IF (this%trans%trans_type == 'intersearch') THEN
3355 
3356  likethis = this
3357  likethis%trans%trans_type = 'inter' ! fake type and make a recursive call to compute base field
3358  CALL grid_transform_compute(likethis, field_in, field_out, var, coord_3d_in, zlist)
3359  CALL getenv('LIBSIM_DISABLEOPTSEARCH', env_var)
3360  optsearch = len_trim(env_var) == 0
3361 
3362  DO k = 1, innz
3363  IF (.NOT.lzlist(k)) cycle
3364  IF ((.NOT.all(c_e(field_out(:,:,k)))) .AND. (any(c_e(field_in(:,:,k))))) THEN ! must fill some values
3365  DO j = 1, this%outny
3366  DO i = 1, this%outnx
3367  IF (.NOT.c_e(field_out(i,j,k))) THEN
3368  dist = huge(dist)
3369  nearcount = 0
3370  IF (optsearch) THEN ! optimized, error-prone algorithm
3371  ix = this%inter_index_x(i,j)
3372  iy = this%inter_index_y(i,j)
3373  DO s = 0, max(this%innx, this%inny)
3374  farenough = .true.
3375  DO m = iy-s, iy+s, max(2*s, 1) ! y loop on upper and lower frames
3376  IF (m < 1 .OR. m > this%inny) cycle
3377  DO l = max(1, ix-s), min(this%innx, ix+s) ! x loop on upper and lower frames
3378  disttmp = (this%inter_xp(i,j) - this%inter_x(l,m))**2 + (this%inter_yp(i,j) - this%inter_y(l,m))**2
3379  IF (c_e(field_in(l,m,k))) THEN
3380  IF (disttmp < dist) THEN
3381  dist = disttmp
3382  field_out(i,j,k) = field_in(l,m,k)
3383  nearcount = 1
3384  ELSE IF (disttmp == dist) THEN
3385  field_out(i,j,k) = field_out(i,j,k) + field_in(l,m,k)
3386  nearcount = nearcount + 1
3387  ENDIF
3388  ENDIF
3389  IF (disttmp < dist) farenough = .false.
3390  ENDDO
3391  ENDDO
3392  DO m = max(1, iy-s+1), min(this%inny, iy+s-1) ! y loop on left and right frames (avoid corners)
3393  DO l = ix-s, ix+s, 2*s ! x loop on left and right frames (exchange loops?)
3394  IF (l < 1 .OR. l > this%innx) cycle
3395  disttmp = (this%inter_xp(i,j) - this%inter_x(l,m))**2 + (this%inter_yp(i,j) - this%inter_y(l,m))**2
3396  IF (c_e(field_in(l,m,k))) THEN
3397  IF (disttmp < dist) THEN
3398  dist = disttmp
3399  field_out(i,j,k) = field_in(l,m,k)
3400  nearcount = 1
3401  ELSE IF (disttmp == dist) THEN
3402  field_out(i,j,k) = field_out(i,j,k) + field_in(l,m,k)
3403  nearcount = nearcount + 1
3404  ENDIF
3405  ENDIF
3406  IF (disttmp < dist) farenough = .false.
3407  ENDDO
3408  ENDDO
3409  IF (s > 0 .AND. farenough) EXIT ! nearest point found, do not trust the same point, in case of bilin it could be not the nearest
3410  ENDDO
3411  ELSE ! linear, simple, slow algorithm
3412  DO m = 1, this%inny
3413  DO l = 1, this%innx
3414  IF (c_e(field_in(l,m,k))) THEN
3415  disttmp = (this%inter_xp(i,j) - this%inter_x(l,m))**2 + (this%inter_yp(i,j) - this%inter_y(l,m))**2
3416  IF (disttmp < dist) THEN
3417  dist = disttmp
3418  field_out(i,j,k) = field_in(l,m,k)
3419  nearcount = 1
3420  ELSE IF (disttmp == dist) THEN
3421  field_out(i,j,k) = field_out(i,j,k) + field_in(l,m,k)
3422  nearcount = nearcount + 1
3423  ENDIF
3424  ENDIF
3425  ENDDO
3426  ENDDO
3427  ENDIF
3428 ! average points with same minimum distance
3429  IF (nearcount > 1) field_out(i,j,k) = field_out(i,j,k)/nearcount
3430  ENDIF
3431  ENDDO
3432  ENDDO
3433  ENDIF
3434  ENDDO
3435 
3436 ELSE IF (this%trans%trans_type == 'boxinter' &
3437  .OR. this%trans%trans_type == 'polyinter' &
3438  .OR. this%trans%trans_type == 'maskinter') THEN
3439 
3440  IF (this%trans%sub_type == 'average') THEN
3441 
3442  IF (vartype == var_dir360) THEN
3443  DO k = 1, innz
3444  IF (.NOT.lzlist(k)) cycle
3445  DO j = 1, this%outny
3446  DO i = 1, this%outnx
3447  field_out(i,j,k) = find_prevailing_direction(field_in(:,:,k), &
3448  0.0, 360.0, 5.0, &
3449  mask=this%inter_index_x(:,:) == i .AND. this%inter_index_y(:,:) == j)
3450  ENDDO
3451  ENDDO
3452  ENDDO
3453 
3454  ELSE
3455  ALLOCATE(nval(this%outnx, this%outny))
3456  field_out(:,:,:) = 0.0
3457  DO k = 1, innz
3458  IF (.NOT.lzlist(k)) cycle
3459  nval(:,:) = 0
3460  DO j = 1, this%inny
3461  DO i = 1, this%innx
3462  IF (c_e(this%inter_index_x(i,j)) .AND. c_e(field_in(i,j,k))) THEN
3463  field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k) = &
3464  field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k) + &
3465  field_in(i,j,k)
3466  nval(this%inter_index_x(i,j),this%inter_index_y(i,j)) = &
3467  nval(this%inter_index_x(i,j),this%inter_index_y(i,j)) + 1
3468  ENDIF
3469  ENDDO
3470  ENDDO
3471  WHERE (nval(:,:) /= 0)
3472  field_out(:,:,k) = field_out(:,:,k)/nval(:,:)
3473  ELSEWHERE
3474  field_out(:,:,k) = rmiss
3475  END WHERE
3476  ENDDO
3477  DEALLOCATE(nval)
3478  ENDIF
3479 
3480  ELSE IF (this%trans%sub_type == 'stddev' .OR. &
3481  this%trans%sub_type == 'stddevnm1') THEN
3482 
3483  IF (this%trans%sub_type == 'stddev') THEN
3484  nm1 = .false.
3485  ELSE
3486  nm1 = .true.
3487  ENDIF
3488  DO k = 1, innz
3489  IF (.NOT.lzlist(k)) cycle
3490  DO j = 1, this%outny
3491  DO i = 1, this%outnx
3492 ! da paura
3493  field_out(i:i,j,k) = stat_stddev( &
3494  reshape(field_in(:,:,k), (/SIZE(field_in(:,:,k))/)), &
3495  mask=reshape((this%inter_index_x == i .AND. &
3496  this%inter_index_y == j), (/SIZE(field_in(:,:,k))/)), nm1=nm1)
3497  ENDDO
3498  ENDDO
3499  ENDDO
3500 
3501  ELSE IF (this%trans%sub_type == 'max') THEN
3502 
3503  DO k = 1, innz
3504  IF (.NOT.lzlist(k)) cycle
3505  DO j = 1, this%inny
3506  DO i = 1, this%innx
3507  IF (c_e(this%inter_index_x(i,j)) .AND. c_e(field_in(i,j,k))) THEN
3508  IF (c_e(field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k))) THEN
3509  field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k) = &
3510  max(field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k), &
3511  field_in(i,j,k))
3512  ELSE
3513  field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k) = &
3514  field_in(i,j,k)
3515  ENDIF
3516  ENDIF
3517  ENDDO
3518  ENDDO
3519  ENDDO
3520 
3521 
3522  ELSE IF (this%trans%sub_type == 'min') THEN
3523 
3524  DO k = 1, innz
3525  IF (.NOT.lzlist(k)) cycle
3526  DO j = 1, this%inny
3527  DO i = 1, this%innx
3528  IF (c_e(this%inter_index_x(i,j)) .AND. c_e(field_in(i,j,k))) THEN
3529  IF (c_e(field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k))) THEN
3530  field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k) = &
3531  min(field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k), &
3532  field_in(i,j,k))
3533  ELSE
3534  field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k) = &
3535  field_in(i,j,k)
3536  ENDIF
3537  ENDIF
3538  ENDDO
3539  ENDDO
3540  ENDDO
3541 
3542  ELSE IF (this%trans%sub_type == 'percentile') THEN
3543 
3544  DO k = 1, innz
3545  IF (.NOT.lzlist(k)) cycle
3546  DO j = 1, this%outny
3547  DO i = 1, this%outnx
3548 ! da paura
3549  field_out(i:i,j,k) = stat_percentile( &
3550  reshape(field_in(:,:,k), (/SIZE(field_in(:,:,k))/)), &
3551  (/REAL(this%trans%stat_info%percentile)/), &
3552  mask=reshape((this%inter_index_x == i .AND. &
3553  this%inter_index_y == j), (/SIZE(field_in(:,:,k))/)))
3554  ENDDO
3555  ENDDO
3556  ENDDO
3557 
3558  ELSE IF (this%trans%sub_type == 'frequency') THEN
3559 
3560  ALLOCATE(nval(this%outnx, this%outny))
3561  DO k = 1, innz
3562  IF (.NOT.lzlist(k)) cycle
3563  field_out(:,:,k) = 0.0
3564  nval(:,:) = 0
3565  DO j = 1, this%inny
3566  DO i = 1, this%innx
3567  IF (c_e(this%inter_index_x(i,j)) .AND. c_e(field_in(i,j,k))) THEN
3568  field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k) = &
3569  field_out(this%inter_index_x(i,j),this%inter_index_y(i,j),k) + &
3570  interval_info_valid(this%trans%interval_info, field_in(i,j,k))
3571  nval(this%inter_index_x(i,j),this%inter_index_y(i,j)) = &
3572  nval(this%inter_index_x(i,j),this%inter_index_y(i,j)) + 1
3573  ENDIF
3574  ENDDO
3575  ENDDO
3576  WHERE (nval(:,:) /= 0)
3577  field_out(:,:,k) = field_out(:,:,k)/nval(:,:)
3578  ELSEWHERE
3579  field_out(:,:,k) = rmiss
3580  END WHERE
3581  ENDDO
3582  DEALLOCATE(nval)
3583 
3584  ENDIF
3585 
3586 ELSE IF (this%trans%trans_type == 'stencilinter') THEN
3587  np = SIZE(this%stencil,1)/2
3588  ns = SIZE(this%stencil)
3589 
3590  IF (this%trans%sub_type == 'average') THEN
3591 
3592  IF (vartype == var_dir360) THEN
3593  DO k = 1, innz
3594  IF (.NOT.lzlist(k)) cycle
3595  DO j = 1, this%outny
3596  DO i = 1, this%outnx
3597  IF (c_e(this%inter_index_x(i,j))) THEN
3598  i1 = this%inter_index_x(i,j) - np
3599  i2 = this%inter_index_x(i,j) + np
3600  j1 = this%inter_index_y(i,j) - np
3601  j2 = this%inter_index_y(i,j) + np
3602  field_out(i,j,k) = find_prevailing_direction(field_in(i1:i2,j1:j2,k), &
3603  0.0, 360.0, 5.0, &
3604  mask=this%stencil(:,:)) ! simpler and equivalent form
3605 ! mask=field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))
3606  ENDIF
3607  ENDDO
3608  ENDDO
3609  ENDDO
3610 
3611  ELSE
3612 !$OMP PARALLEL DEFAULT(SHARED)
3613 !$OMP DO PRIVATE(i, j, k, i1, i2, j1, j2, n)
3614  DO k = 1, innz
3615  IF (.NOT.lzlist(k)) cycle
3616  DO j = 1, this%outny
3617  DO i = 1, this%outnx
3618  IF (c_e(this%inter_index_x(i,j))) THEN
3619  i1 = this%inter_index_x(i,j) - np
3620  i2 = this%inter_index_x(i,j) + np
3621  j1 = this%inter_index_y(i,j) - np
3622  j2 = this%inter_index_y(i,j) + np
3623  n = count(field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))
3624  IF (n > 0) THEN
3625  field_out(i,j,k) = sum(field_in(i1:i2,j1:j2,k), &
3626  mask=field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))/n
3627  ENDIF
3628  ENDIF
3629  ENDDO
3630  ENDDO
3631  ENDDO
3632 !$OMP END PARALLEL
3633  ENDIF
3634 
3635  ELSE IF (this%trans%sub_type == 'stddev' .OR. &
3636  this%trans%sub_type == 'stddevnm1') THEN
3637 
3638  IF (this%trans%sub_type == 'stddev') THEN
3639  nm1 = .false.
3640  ELSE
3641  nm1 = .true.
3642  ENDIF
3643 
3644 !$OMP PARALLEL DEFAULT(SHARED)
3645 !$OMP DO PRIVATE(i, j, k, i1, i2, j1, j2)
3646  DO k = 1, innz
3647  IF (.NOT.lzlist(k)) cycle
3648  DO j = 1, this%outny
3649  DO i = 1, this%outnx
3650  IF (c_e(this%inter_index_x(i,j))) THEN
3651  i1 = this%inter_index_x(i,j) - np
3652  i2 = this%inter_index_x(i,j) + np
3653  j1 = this%inter_index_y(i,j) - np
3654  j2 = this%inter_index_y(i,j) + np
3655 ! da paura
3656  field_out(i:i,j,k) = stat_stddev( &
3657  reshape(field_in(i1:i2,j1:j2,k), (/ns/)), &
3658  mask=reshape(field_in(i1:i2,j1:j2,k) /= rmiss .AND. &
3659  this%stencil(:,:), (/ns/)), nm1=nm1)
3660  ENDIF
3661  ENDDO
3662  ENDDO
3663  ENDDO
3664 !$OMP END PARALLEL
3665 
3666  ELSE IF (this%trans%sub_type == 'max') THEN
3667 
3668 !$OMP PARALLEL DEFAULT(SHARED)
3669 !$OMP DO PRIVATE(i, j, k, i1, i2, j1, j2, n)
3670  DO k = 1, innz
3671  IF (.NOT.lzlist(k)) cycle
3672  DO j = 1, this%outny
3673  DO i = 1, this%outnx
3674  IF (c_e(this%inter_index_x(i,j))) THEN
3675  i1 = this%inter_index_x(i,j) - np
3676  i2 = this%inter_index_x(i,j) + np
3677  j1 = this%inter_index_y(i,j) - np
3678  j2 = this%inter_index_y(i,j) + np
3679  n = count(field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))
3680  IF (n > 0) THEN
3681  field_out(i,j,k) = maxval(field_in(i1:i2,j1:j2,k), &
3682  mask=field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))
3683  ENDIF
3684  ENDIF
3685  ENDDO
3686  ENDDO
3687  ENDDO
3688 !$OMP END PARALLEL
3689 
3690  ELSE IF (this%trans%sub_type == 'min') THEN
3691 
3692 !$OMP PARALLEL DEFAULT(SHARED)
3693 !$OMP DO PRIVATE(i, j, k, i1, i2, j1, j2, n)
3694  DO k = 1, innz
3695  IF (.NOT.lzlist(k)) cycle
3696  DO j = 1, this%outny
3697  DO i = 1, this%outnx
3698  IF (c_e(this%inter_index_x(i,j))) THEN
3699  i1 = this%inter_index_x(i,j) - np
3700  i2 = this%inter_index_x(i,j) + np
3701  j1 = this%inter_index_y(i,j) - np
3702  j2 = this%inter_index_y(i,j) + np
3703  n = count(field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))
3704  IF (n > 0) THEN
3705  field_out(i,j,k) = minval(field_in(i1:i2,j1:j2,k), &
3706  mask=field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))
3707  ENDIF
3708  ENDIF
3709  ENDDO
3710  ENDDO
3711  ENDDO
3712 !$OMP END PARALLEL
3713 
3714  ELSE IF (this%trans%sub_type == 'percentile') THEN
3715 
3716 !$OMP PARALLEL DEFAULT(SHARED)
3717 !$OMP DO PRIVATE(i, j, k, i1, i2, j1, j2)
3718  DO k = 1, innz
3719  IF (.NOT.lzlist(k)) cycle
3720  DO j = 1, this%outny
3721  DO i = 1, this%outnx
3722  IF (c_e(this%inter_index_x(i,j))) THEN
3723  i1 = this%inter_index_x(i,j) - np
3724  i2 = this%inter_index_x(i,j) + np
3725  j1 = this%inter_index_y(i,j) - np
3726  j2 = this%inter_index_y(i,j) + np
3727 ! da paura
3728  field_out(i:i,j,k) = stat_percentile( &
3729  reshape(field_in(i1:i2,j1:j2,k), (/ns/)), &
3730  (/REAL(this%trans%stat_info%percentile)/), &
3731  mask=reshape(field_in(i1:i2,j1:j2,k) /= rmiss .AND. &
3732  this%stencil(:,:), (/ns/)))
3733  ENDIF
3734  ENDDO
3735  ENDDO
3736  ENDDO
3737 !$OMP END PARALLEL
3738 
3739  ELSE IF (this%trans%sub_type == 'frequency') THEN
3740 
3741 !$OMP PARALLEL DEFAULT(SHARED)
3742 !$OMP DO PRIVATE(i, j, k, i1, i2, j1, j2, n)
3743  DO k = 1, innz
3744  IF (.NOT.lzlist(k)) cycle
3745  DO j = 1, this%outny
3746  DO i = 1, this%outnx
3747  IF (c_e(this%inter_index_x(i,j))) THEN
3748  i1 = this%inter_index_x(i,j) - np
3749  i2 = this%inter_index_x(i,j) + np
3750  j1 = this%inter_index_y(i,j) - np
3751  j2 = this%inter_index_y(i,j) + np
3752  n = count(field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))
3753  IF (n > 0) THEN
3754  field_out(i,j,k) = sum(interval_info_valid( &
3755  this%trans%interval_info, field_in(i1:i2,j1:j2,k)), &
3756  mask=field_in(i1:i2,j1:j2,k) /= rmiss .AND. this%stencil(:,:))/n
3757  ENDIF
3758  ENDIF
3759  ENDDO
3760  ENDDO
3761  ENDDO
3762 !$OMP END PARALLEL
3763 
3764  ENDIF
3765 
3766 ELSE IF (this%trans%trans_type == 'maskgen') THEN
3767 
3768  DO k = 1, innz
3769  WHERE(c_e(this%inter_index_x(:,:)))
3770  field_out(:,:,k) = REAL(this%inter_index_x(:,:))
3771  END WHERE
3772  ENDDO
3773 
3774 ELSE IF (this%trans%trans_type == 'metamorphosis') THEN
3775 
3776  IF (this%trans%sub_type == 'all') THEN
3777 
3778  field_out(:,:,:) = reshape(field_in(:,:,:), (/this%outnx,this%outny,innz/))
3779 
3780  ELSE IF (this%trans%sub_type == 'coordbb' .OR. this%trans%sub_type == 'poly' &
3781  .OR. this%trans%sub_type == 'mask' .OR. this%trans%sub_type == 'index') THEN
3782 
3783  DO k = 1, innz
3784  IF (.NOT.lzlist(k)) cycle
3785 ! this is to sparse-points only, so field_out(:,1,k) is acceptable
3786  field_out(:,1,k) = pack(field_in(:,:,k), c_e(this%point_index(:,:)))
3787  ENDDO
3788 
3789  ELSE IF (this%trans%sub_type == 'maskvalid' .OR. &
3790  this%trans%sub_type == 'maskinvalid') THEN
3791 
3792  DO k = 1, innz
3793  IF (.NOT.lzlist(k)) cycle
3794  WHERE (this%point_mask(:,:)) ! this is almost the same as the previous syntax
3795  field_out(:,:,k) = field_in(:,:,k) ! check which is more efficient
3796  END WHERE
3797  ENDDO
3798 
3799  ELSE IF (this%trans%sub_type == 'lemaskinvalid') THEN
3800 
3801  DO k = 1, innz
3802  IF (.NOT.lzlist(k)) cycle
3803  WHERE (c_e(field_in(:,:,k)) .AND. field_in(:,:,k) > this%val_mask(:,:))
3804  field_out(:,:,k) = field_in(:,:,k)
3805  ELSEWHERE
3806  field_out(:,:,k) = rmiss
3807  END WHERE
3808  ENDDO
3809 
3810  ELSE IF (this%trans%sub_type == 'ltmaskinvalid') THEN
3811 
3812  DO k = 1, innz
3813  IF (.NOT.lzlist(k)) cycle
3814  WHERE (c_e(field_in(:,:,k)) .AND. field_in(:,:,k) >= this%val_mask(:,:))
3815  field_out(:,:,k) = field_in(:,:,k)
3816  ELSEWHERE
3817  field_out(:,:,k) = rmiss
3818  END WHERE
3819  ENDDO
3820 
3821  ELSE IF (this%trans%sub_type == 'gemaskinvalid') THEN
3822 
3823  DO k = 1, innz
3824  IF (.NOT.lzlist(k)) cycle
3825  WHERE (c_e(field_in(:,:,k)) .AND. field_in(:,:,k) < this%val_mask(:,:))
3826  field_out(:,:,k) = field_in(:,:,k)
3827  ELSEWHERE
3828  field_out(:,:,k) = rmiss
3829  END WHERE
3830  ENDDO
3831 
3832  ELSE IF (this%trans%sub_type == 'gtmaskinvalid') THEN
3833 
3834  DO k = 1, innz
3835  IF (.NOT.lzlist(k)) cycle
3836  WHERE (c_e(field_in(:,:,k)) .AND. field_in(:,:,k) <= this%val_mask(:,:))
3837  field_out(:,:,k) = field_in(:,:,k)
3838  ELSEWHERE
3839  field_out(:,:,k) = rmiss
3840  END WHERE
3841  ENDDO
3842 
3843  ELSE IF (this%trans%sub_type == 'setinvalidto') THEN
3844 
3845  DO k = 1, innz
3846  IF (.NOT.lzlist(k)) cycle ! should i skip levels here?
3847  WHERE (c_e(field_in(:,:,k)))
3848  field_out(:,:,k) = field_in(:,:,k)
3849  ELSE WHERE
3850  field_out(:,:,k) = this%val1
3851  END WHERE
3852  ENDDO
3853 
3854  ELSE IF (this%trans%sub_type == 'settoinvalid') THEN
3855  IF (c_e(this%val1) .AND. c_e(this%val2)) THEN
3856  WHERE (c_e(field_in(:,:,:)) .AND. field_in(:,:,:) > this%val1 &
3857  .AND. field_in(:,:,:) <= this%val2)
3858  field_out(:,:,:) = rmiss
3859  ELSE WHERE
3860  field_out(:,:,:) = field_in(:,:,:)
3861  END WHERE
3862  ELSE IF (c_e(this%val1)) THEN
3863  WHERE (c_e(field_in(:,:,:)) .AND. field_in(:,:,:) > this%val1)
3864  field_out(:,:,:) = rmiss
3865  ELSE WHERE
3866  field_out(:,:,:) = field_in(:,:,:)
3867  END WHERE
3868  ELSE IF (c_e(this%val2)) THEN
3869  WHERE (c_e(field_in(:,:,:)) .AND. field_in(:,:,:) <= this%val2)
3870  field_out(:,:,:) = rmiss
3871  ELSE WHERE
3872  field_out(:,:,:) = field_in(:,:,:)
3873  END WHERE
3874  ENDIF
3875  ENDIF
3876 
3877 ELSE IF (this%trans%trans_type == 'vertint') THEN
3878 
3879  IF (this%trans%sub_type == 'linear') THEN
3880 
3881  alloc_coord_3d_in_act = .false.
3882  IF (ASSOCIATED(this%inter_index_z)) THEN
3883 
3884  DO k = 1, outnz
3885  IF (c_e(this%inter_index_z(k))) THEN
3886  z1 = REAL(this%inter_zp(k)) ! weight for k+1
3887  z2 = REAL(1.0D0 - this%inter_zp(k)) ! weight for k
3888  SELECT CASE(vartype)
3889 
3890  CASE(var_dir360)
3891  DO j = 1, inny
3892  DO i = 1, innx
3893  IF (c_e(field_in(i,j,this%inter_index_z(k))) .AND. &
3894  c_e(field_in(i,j,this%inter_index_z(k)+1))) THEN
3895  field_out(i,j,k) = &
3896  interp_var_360(field_in(i,j,this%inter_index_z(k)), &
3897  field_in(i,j,this%inter_index_z(k)+1), z1, z2)
3898  ENDIF
3899  ENDDO
3900  ENDDO
3901 
3902  CASE(var_press)
3903  DO j = 1, inny
3904  DO i = 1, innx
3905  IF (c_e(field_in(i,j,this%inter_index_z(k))) .AND. &
3906  c_e(field_in(i,j,this%inter_index_z(k)+1)) .AND. &
3907  field_in(i,j,this%inter_index_z(k)) > 0. .AND. &
3908  field_in(i,j,this%inter_index_z(k)+1) > 0.) THEN
3909  field_out(i,j,k) = exp( &
3910  log(field_in(i,j,this%inter_index_z(k)))*z2 + &
3911  log(field_in(i,j,this%inter_index_z(k)+1))*z1)
3912  ENDIF
3913  ENDDO
3914  ENDDO
3915 
3916  CASE default
3917  DO j = 1, inny
3918  DO i = 1, innx
3919  IF (c_e(field_in(i,j,this%inter_index_z(k))) .AND. &
3920  c_e(field_in(i,j,this%inter_index_z(k)+1))) THEN
3921  field_out(i,j,k) = &
3922  field_in(i,j,this%inter_index_z(k))*z2 + &
3923  field_in(i,j,this%inter_index_z(k)+1)*z1
3924  ENDIF
3925  ENDDO
3926  ENDDO
3927 
3928  END SELECT
3929 
3930  ENDIF
3931  ENDDO
3932 
3933  ELSE ! use coord_3d_in
3934 
3935  IF (ALLOCATED(this%coord_3d_in)) THEN
3936  coord_3d_in_act => this%coord_3d_in
3937 #ifdef DEBUG
3938  CALL l4f_category_log(this%category,l4f_debug, &
3939  "Using external vertical coordinate for vertint")
3940 #endif
3941  ELSE
3942  IF (PRESENT(coord_3d_in)) THEN
3943 #ifdef DEBUG
3944  CALL l4f_category_log(this%category,l4f_debug, &
3945  "Using internal vertical coordinate for vertint")
3946 #endif
3947  IF (this%dolog) THEN
3948  ALLOCATE(coord_3d_in_act(SIZE(coord_3d_in,1), &
3949  SIZE(coord_3d_in,2), SIZE(coord_3d_in,3)))
3950  alloc_coord_3d_in_act = .true.
3951  WHERE (c_e(coord_3d_in) .AND. coord_3d_in > 0.0)
3952  coord_3d_in_act = log(coord_3d_in)
3953  ELSEWHERE
3954  coord_3d_in_act = rmiss
3955  END WHERE
3956  ELSE
3957  coord_3d_in_act => coord_3d_in
3958  ENDIF
3959  ELSE
3960  CALL l4f_category_log(this%category,l4f_error, &
3961  "Missing internal and external vertical coordinate for vertint")
3962  CALL raise_error()
3963  RETURN
3964  ENDIF
3965  ENDIF
3966 
3967  inused = SIZE(coord_3d_in_act,3)
3968  IF (inused < 2) RETURN ! to avoid algorithm failure
3969  kkcache = 1
3970 
3971  DO k = 1, outnz
3972  IF (.NOT.c_e(this%vcoord_out(k))) cycle
3973  DO j = 1, inny
3974  DO i = 1, innx
3975  kfound = imiss
3976  DO kk = 1, max(inused-kkcache-1, kkcache) ! +-1
3977  kkup = kkcache + kk
3978  kkdown = kkcache - kk + 1
3979 
3980  IF (kkdown >= 1) THEN ! search down
3981  IF (this%vcoord_out(k) >= &
3982  min(coord_3d_in_act(i,j,kkdown), coord_3d_in_act(i,j,kkdown+1)) .AND. &
3983  this%vcoord_out(k) < &
3984  max(coord_3d_in_act(i,j,kkdown), coord_3d_in_act(i,j,kkdown+1))) THEN
3985  kkcache = kkdown
3986  kfoundin = kkcache
3987  kfound = kkcache + this%levshift
3988  EXIT ! kk
3989  ENDIF
3990  ENDIF
3991  IF (kkup < inused) THEN ! search up
3992  IF (this%vcoord_out(k) >= &
3993  min(coord_3d_in_act(i,j,kkup), coord_3d_in_act(i,j,kkup+1)) .AND. &
3994  this%vcoord_out(k) < &
3995  max(coord_3d_in_act(i,j,kkup), coord_3d_in_act(i,j,kkup+1))) THEN
3996  kkcache = kkup
3997  kfoundin = kkcache
3998  kfound = kkcache + this%levshift
3999  EXIT ! kk
4000  ENDIF
4001  ENDIF
4002 
4003  ENDDO
4004 
4005  IF (c_e(kfound)) THEN
4006  IF (c_e(field_in(i,j,kfound)) .AND. c_e(field_in(i,j,kfound+1))) THEN
4007  z1 = REAL((this%vcoord_out(k) - coord_3d_in_act(i,j,kfoundin))/ &
4008  (coord_3d_in_act(i,j,kfoundin+1) - coord_3d_in_act(i,j,kfoundin)))
4009  z2 = 1.0 - z1
4010  SELECT CASE(vartype)
4011 
4012  CASE(var_dir360)
4013  field_out(i,j,k) = &
4014  interp_var_360(field_in(i,j,kfound), field_in(i,j,kfound+1), z1, z2)
4015  CASE(var_press)
4016  field_out(i,j,k) = exp(log(field_in(i,j,kfound))*z2 + &
4017  log(field_in(i,j,kfound+1))*z1)
4018 
4019  CASE default
4020  field_out(i,j,k) = field_in(i,j,kfound)*z2 + field_in(i,j,kfound+1)*z1
4021  END SELECT
4022 
4023  ENDIF
4024  ELSE
4025  ENDIF
4026  ENDDO ! i
4027  ENDDO ! j
4028  ENDDO ! k
4029  IF (alloc_coord_3d_in_act) DEALLOCATE(coord_3d_in_act)
4030  ENDIF
4031 
4032  ELSE IF (this%trans%sub_type == 'linearsparse') THEN
4033 
4034 
4035  IF (.NOT.ASSOCIATED(this%vcoord_in) .AND. .NOT.PRESENT(coord_3d_in)) THEN
4036  CALL l4f_category_log(this%category,l4f_error, &
4037  "linearsparse interpolation, no input vert coord available")
4038  RETURN
4039  ENDIF
4040 
4041  ALLOCATE(coord_in(innz),val_in(innz),mask_in(innz))
4042  DO j = 1, inny
4043  DO i = 1, innx
4044 
4045  IF (ASSOCIATED(this%vcoord_in)) THEN
4046  mask_in = c_e(field_in(i,j,this%levshift+1:this%levshift+this%levused)) &
4047  .AND. c_e(this%vcoord_in(:))
4048  ELSE
4049  mask_in = c_e(field_in(i,j,this%levshift+1:this%levshift+this%levused)) &
4050  .AND. c_e(coord_3d_in(i,j,:))
4051  ENDIF
4052 
4053  IF (vartype == var_press) THEN
4054  mask_in(:) = mask_in(:) .AND. &
4055  (field_in(i,j,this%levshift+1:this%levshift+this%levused) > 0.0d0)
4056  ENDIF
4057  inused = count(mask_in)
4058  IF (inused > 1) THEN
4059  IF (ASSOCIATED(this%vcoord_in)) THEN
4060  coord_in(1:inused) = pack(this%vcoord_in(:), mask=mask_in)
4061  ELSE
4062  coord_in(1:inused) = pack(coord_3d_in(i,j,:), mask=mask_in)
4063  ENDIF
4064  IF (vartype == var_press) THEN
4065  val_in(1:inused) = log(pack( &
4066  field_in(i,j,this%levshift+1:this%levshift+this%levused), &
4067  mask=mask_in))
4068  ELSE
4069  val_in(1:inused) = pack( &
4070  field_in(i,j,this%levshift+1:this%levshift+this%levused), &
4071  mask=mask_in)
4072  ENDIF
4073  kkcache = 1
4074  DO k = 1, outnz
4075 
4076  kfound = imiss
4077  DO kk = 1, max(inused-kkcache-1, kkcache) ! +-1
4078  kkup = kkcache + kk
4079  kkdown = kkcache - kk + 1
4080 
4081  IF (kkdown >= 1) THEN ! search down
4082  IF (this%vcoord_out(k) >= &
4083  min(coord_in(kkdown), coord_in(kkdown+1)) .AND. &
4084  this%vcoord_out(k) < &
4085  max(coord_in(kkdown), coord_in(kkdown+1))) THEN
4086  kkcache = kkdown
4087  kfoundin = kkcache
4088  kfound = kkcache
4089  EXIT ! kk
4090  ENDIF
4091  ENDIF
4092  IF (kkup < inused) THEN ! search up
4093  IF (this%vcoord_out(k) >= &
4094  min(coord_in(kkup), coord_in(kkup+1)) .AND. &
4095  this%vcoord_out(k) < &
4096  max(coord_in(kkup), coord_in(kkup+1))) THEN
4097  kkcache = kkup
4098  kfoundin = kkcache
4099  kfound = kkcache
4100  EXIT ! kk
4101  ENDIF
4102  ENDIF
4103 
4104  ENDDO
4105 
4106  IF (c_e(kfound)) THEN
4107  z1 = REAL((this%vcoord_out(k) - coord_in(kfound-1))/ &
4108  (coord_in(kfound) - coord_in(kfound-1)))
4109  z2 = 1.0 - z1
4110  IF (vartype == var_dir360) THEN
4111  field_out(i,j,k) = &
4112  interp_var_360(val_in(kfound-1), val_in(kfound), z1, z2)
4113  ELSE IF (vartype == var_press) THEN
4114  field_out(i,j,k) = exp(val_in(kfound-1)*z2 + val_in(kfound)*z1)
4115  ELSE
4116  field_out(i,j,k) = val_in(kfound-1)*z2 + val_in(kfound)*z1
4117  ENDIF
4118  ENDIF
4119 
4120  ENDDO
4121 
4122  ENDIF
4123 
4124  ENDDO
4125  ENDDO
4126  DEALLOCATE(coord_in,val_in)
4127 
4128 
4129  ENDIF
4130 
4131 ELSE IF (this%trans%trans_type == '' .OR. this%trans%trans_type == 'none') THEN
4132 
4133  field_out(:,:,:) = field_in(:,:,:)
4134 
4135 ENDIF
4136 
4137 
4138 CONTAINS
4139 
4140 
4141 ! internal function for interpolating directions from 0 to 360 degree
4142 ! hope it is inlined by the compiler
4143 FUNCTION interp_var_360(v1, v2, w1, w2)
4144 REAL,INTENT(in) :: v1, v2, w1, w2
4145 REAL :: interp_var_360
4146 
4147 REAL :: lv1, lv2
4148 
4149 IF (abs(v1 - v2) > 180.) THEN
4150  IF (v1 > v2) THEN
4151  lv1 = v1 - 360.
4152  lv2 = v2
4153  ELSE
4154  lv1 = v1
4155  lv2 = v2 - 360.
4156  ENDIF
4157  interp_var_360 = modulo(lv1*w2 + lv2*w1, 360.)
4158 ELSE
4159  interp_var_360 = v1*w2 + v2*w1
4160 ENDIF
4161 
4162 END FUNCTION interp_var_360
4163 
4164 
4165 RECURSIVE FUNCTION find_prevailing_direction(v1, l, h, res, mask) RESULT(prev)
4166 REAL,INTENT(in) :: v1(:,:)
4167 REAL,INTENT(in) :: l, h, res
4168 LOGICAL,INTENT(in),OPTIONAL :: mask(:,:)
4169 REAL :: prev
4170 
4171 REAL :: m
4172 INTEGER :: nh, nl
4173 !REAL,PARAMETER :: res = 1.0
4174 
4175 m = (l + h)/2.
4176 IF ((h - l) <= res) THEN
4177  prev = m
4178  RETURN
4179 ENDIF
4180 
4181 IF (PRESENT(mask)) THEN
4182  nl = count(v1 >= l .AND. v1 < m .AND. mask)
4183  nh = count(v1 >= m .AND. v1 < h .AND. mask)
4184 ELSE
4185  nl = count(v1 >= l .AND. v1 < m)
4186  nh = count(v1 >= m .AND. v1 < h)
4187 ENDIF
4188 IF (nh > nl) THEN
4189  prev = find_prevailing_direction(v1, m, h, res)
4190 ELSE IF (nl > nh) THEN
4191  prev = find_prevailing_direction(v1, l, m, res)
4192 ELSE IF (nl == 0 .AND. nh == 0) THEN
4193  prev = rmiss
4194 ELSE
4195  prev = m
4196 ENDIF
4197 
4198 END FUNCTION find_prevailing_direction
4199 
4200 
4201 END SUBROUTINE grid_transform_compute
4202 
4203 
4209 SUBROUTINE grid_transform_v7d_grid_compute(this, field_in, field_out, var, &
4210  coord_3d_in)
4211 TYPE(grid_transform),INTENT(in) :: this
4212 REAL, INTENT(in) :: field_in(:,:)
4213 REAL, INTENT(out):: field_out(:,:,:)
4214 TYPE(vol7d_var),INTENT(in),OPTIONAL :: var
4215 REAL,INTENT(in),OPTIONAL,TARGET :: coord_3d_in(:,:,:)
4216 
4217 real,allocatable :: field_in_p(:),x_in_p(:),y_in_p(:)
4218 INTEGER :: inn_p, ier, k
4219 INTEGER :: innx, inny, innz, outnx, outny, outnz
4220 
4221 #ifdef DEBUG
4222 call l4f_category_log(this%category,l4f_debug,"start v7d_grid_transform_compute")
4223 #endif
4224 
4225 field_out(:,:,:) = rmiss
4226 
4227 IF (.NOT.this%valid) THEN
4228  call l4f_category_log(this%category,l4f_error, &
4229  "refusing to perform a non valid transformation")
4230  call raise_error()
4231  RETURN
4232 ENDIF
4233 
4234 innx = SIZE(field_in,1); inny = 1; innz = SIZE(field_in,2)
4235 outnx = SIZE(field_out,1); outny = SIZE(field_out,2); outnz = SIZE(field_out,3)
4236 
4237 ! check size of field_in, field_out
4238 IF (this%trans%trans_type == 'vertint') THEN ! vertical interpolation
4239 
4240  IF (innz /= this%innz) THEN
4241  CALL l4f_category_log(this%category,l4f_error,"vertical interpolation")
4242  CALL l4f_category_log(this%category,l4f_error,"inconsistent input shape: "//&
4243  t2c(this%innz)//" /= "//t2c(innz))
4244  CALL raise_error()
4245  RETURN
4246  ENDIF
4247 
4248  IF (outnz /= this%outnz) THEN
4249  CALL l4f_category_log(this%category,l4f_error,"vertical interpolation")
4250  CALL l4f_category_log(this%category,l4f_error,"inconsistent output shape: "//&
4251  t2c(this%outnz)//" /= "//t2c(outnz))
4252  CALL raise_error()
4253  RETURN
4254  ENDIF
4255 
4256  IF (innx /= outnx .OR. inny /= outny) THEN
4257  CALL l4f_category_log(this%category,l4f_error,"vertical interpolation")
4258  CALL l4f_category_log(this%category,l4f_error,"inconsistent hor. sizes: "//&
4259  t2c(innx)//","//t2c(inny)//" /= "//&
4260  t2c(outnx)//","//t2c(outny))
4261  CALL raise_error()
4262  RETURN
4263  ENDIF
4264 
4265 ELSE ! horizontal interpolation
4266 
4267  IF (innx /= this%innx .OR. inny /= this%inny) THEN
4268  CALL l4f_category_log(this%category,l4f_error,"horizontal interpolation")
4269  CALL l4f_category_log(this%category,l4f_error,"inconsistent input shape: "//&
4270  t2c(this%innx)//","//t2c(this%inny)//" /= "//&
4271  t2c(innx)//","//t2c(inny))
4272  CALL raise_error()
4273  RETURN
4274  ENDIF
4275 
4276  IF (outnx /= this%outnx .OR. outny /= this%outny) THEN
4277  CALL l4f_category_log(this%category,l4f_error,"horizontal interpolation")
4278  CALL l4f_category_log(this%category,l4f_error,"inconsistent output shape: "//&
4279  t2c(this%outnx)//","//t2c(this%outny)//" /= "//&
4280  t2c(outnx)//","//t2c(outny))
4281  CALL raise_error()
4282  RETURN
4283  ENDIF
4284 
4285  IF (innz /= outnz) THEN
4286  CALL l4f_category_log(this%category,l4f_error,"horizontal interpolation")
4287  CALL l4f_category_log(this%category,l4f_error,"inconsistent vert. sizes: "//&
4288  t2c(innz)//" /= "//t2c(outnz))
4289  CALL raise_error()
4290  RETURN
4291  ENDIF
4292 
4293 ENDIF
4294 
4295 #ifdef DEBUG
4296  call l4f_category_log(this%category,l4f_debug, &
4297  "start grid_transform_v7d_grid_compute "//trim(this%trans%trans_type)//':'// &
4298  trim(this%trans%sub_type))
4299 #endif
4300 
4301 IF (this%trans%trans_type == 'inter') THEN
4302 
4303  IF (this%trans%sub_type == 'linear') THEN
4304 
4305 #ifdef HAVE_LIBNGMATH
4306 ! optimization, allocate only once with a safe size
4307  ALLOCATE(field_in_p(innx*inny), x_in_p(innx*inny), y_in_p(innx*inny))
4308  DO k = 1, innz
4309  inn_p = count(c_e(field_in(:,k)))
4310 
4311  CALL l4f_category_log(this%category,l4f_info, &
4312  "Number of sparse data points: "//t2c(inn_p)//','//t2c(SIZE(field_in(:,k))))
4313 
4314  IF (inn_p > 2) THEN
4315 
4316  field_in_p(1:inn_p) = pack(field_in(:,k), c_e(field_in(:,k)))
4317  x_in_p(1:inn_p) = pack(this%inter_xp(:,1), c_e(field_in(:,k)))
4318  y_in_p(1:inn_p) = pack(this%inter_yp(:,1), c_e(field_in(:,k)))
4319 
4320  IF (.NOT.this%trans%extrap) THEN
4321  CALL nnseti('ext', 0) ! 0 = no extrapolation
4322  CALL nnsetr('nul', rmiss)
4323  ENDIF
4324 
4325  CALL natgrids(inn_p, x_in_p, y_in_p, field_in_p, & ! (1:inn_p) omitted
4326  this%outnx, this%outny, REAL(this%inter_x(:,1)), & ! no f90 interface
4327  REAL(this%inter_y(1,:)), field_out(1,1,k), ier)
4328 
4329  IF (ier /= 0) THEN
4330  CALL l4f_category_log(this%category,l4f_error, &
4331  "Error code from NCAR natgrids: "//t2c(ier))
4332  CALL raise_error()
4333  EXIT
4334  ENDIF ! exit loop to deallocate
4335  ELSE
4336 
4337  CALL l4f_category_log(this%category,l4f_info, &
4338  "insufficient data in gridded region to triangulate")
4339 
4340  ENDIF
4341  ENDDO
4342  DEALLOCATE(field_in_p, x_in_p, y_in_p)
4343 
4344 #else
4345  CALL l4f_category_log(this%category,l4f_error, &
4346  "libsim compiled without NATGRIDD (ngmath ncarg library)")
4347  CALL raise_error()
4348  RETURN
4349 #endif
4350 
4351  ENDIF
4352 
4353 ELSE IF (this%trans%trans_type == 'boxinter' .OR. &
4354  this%trans%trans_type == 'polyinter' .OR. &
4355  this%trans%trans_type == 'vertint' .OR. &
4356  this%trans%trans_type == 'metamorphosis') THEN ! use the grid-to-grid method
4357 
4358  CALL compute(this, &
4359  reshape(field_in, (/SIZE(field_in,1), 1, SIZE(field_in,2)/)), field_out, var, &
4360  coord_3d_in)
4361 
4362 ENDIF
4363 
4364 END SUBROUTINE grid_transform_v7d_grid_compute
4365 
4366 
4367 ! Bilinear interpolation
4368 ! Effettua interpolazione bilineare dati i valori nei punti 1,2,3,4 e
4369 ! le coordinate dei punti 1 e 3 oltre a quelle del punto p dove viene
4370 ! valutato il campo.
4371 !_____________________________________________________________
4372 ! disposizione punti
4373 ! 4 3
4374 !
4375 ! p
4376 !
4377 ! 1 2
4378 ! _____________________________________________________________
4379 ELEMENTAL FUNCTION hbilin (z1,z2,z3,z4,x1,y1,x3,y3,xp,yp) RESULT(zp)
4380 REAL,INTENT(in) :: z1,z2,z3,z4 ! Z values on the four points
4381 DOUBLE PRECISION,INTENT(in):: x1,y1 ! coordinate of the lower left point
4382 DOUBLE PRECISION,INTENT(in):: x3,y3 ! coordinate of the upper right point
4383 DOUBLE PRECISION,INTENT(in):: xp,yp ! coordinate of point where interpolate
4384 REAL :: zp
4385 
4386 REAL :: p1,p2
4387 REAL :: z5,z6
4388 
4389 
4390 p2 = REAL((yp-y1)/(y3-y1))
4391 p1 = REAL((xp-x1)/(x3-x1))
4392 
4393 z5 = (z4-z1)*p2+z1
4394 z6 = (z3-z2)*p2+z2
4395 
4396 zp = (z6-z5)*(p1)+z5
4397 
4398 END FUNCTION hbilin
4399 
4400 
4401 ! Shapiro filter of order 2
4402 FUNCTION shapiro (z,zp) RESULT(zs)
4403 !! z_smoothed(i,j) = z(i,j) * (1-S) + S * sum(z_vicini)/N
4404 !! = z(i,j) - S/N (N*z(i,j) - sum(z_vicini))
4405 REAL,INTENT(in) :: z(:) ! Z values on the four surrounding points
4406 REAL,INTENT(in) :: zp ! Z values on the central point
4407 REAL :: zs ! Z smoothed value on the central point
4408 INTEGER:: N
4409 
4410 IF(c_e(zp))THEN
4411  n = count(c_e(z))
4412  zs = zp - 0.5* ( n*zp - sum(z, c_e(z)) )/n
4413 ELSE
4414  zs = rmiss
4415 END IF
4416 
4417 END FUNCTION shapiro
4418 
4419 
4420 ! Locate index of requested point
4421 SUBROUTINE basic_find_index(this, near, nx, ny, xmin, xmax, ymin, ymax, &
4422  lon, lat, extrap, index_x, index_y)
4423 TYPE(griddim_def),INTENT(in) :: this ! griddim object (from grid)
4424 LOGICAL,INTENT(in) :: near ! near or bilin interpolation (determine wich point is requested)
4425 INTEGER,INTENT(in) :: nx,ny ! dimension (to grid)
4426 DOUBLE PRECISION,INTENT(in) :: xmin, xmax, ymin, ymax ! extreme coordinate (to grid)
4427 DOUBLE PRECISION,INTENT(in) :: lon(:,:),lat(:,:) ! target coordinate
4428 LOGICAL,INTENT(in) :: extrap ! extrapolate
4429 INTEGER,INTENT(out) :: index_x(:,:),index_y(:,:) ! index of point requested
4430 
4431 INTEGER :: lnx, lny
4432 DOUBLE PRECISION :: x(SIZE(lon,1),SIZE(lon,2)),y(SIZE(lon,1),SIZE(lon,2))
4433 
4434 IF (near) THEN
4435  CALL proj(this,lon,lat,x,y)
4436  index_x = nint((x-xmin)/((xmax-xmin)/dble(nx-1)))+1
4437  index_y = nint((y-ymin)/((ymax-ymin)/dble(ny-1)))+1
4438  lnx = nx
4439  lny = ny
4440 ELSE
4441  CALL proj(this,lon,lat,x,y)
4442  index_x = floor((x-xmin)/((xmax-xmin)/dble(nx-1)))+1
4443  index_y = floor((y-ymin)/((ymax-ymin)/dble(ny-1)))+1
4444  lnx = nx-1
4445  lny = ny-1
4446 ENDIF
4447 
4448 IF (extrap) THEN ! trim indices outside grid for extrapolation
4449  index_x = max(index_x, 1)
4450  index_y = max(index_y, 1)
4451  index_x = min(index_x, lnx)
4452  index_y = min(index_y, lny)
4453 ELSE ! nullify indices outside grid
4454  WHERE(index_x < 1 .OR. index_x > lnx .OR. index_y < 1 .OR. index_y > lny)
4455  index_x = imiss
4456  index_y = imiss
4457  END WHERE
4458 ENDIF
4459 
4460 END SUBROUTINE basic_find_index
4461 
4462 END MODULE grid_transform_class
Compute the output data array from input data array according to the defined transformation.
Compute the average of the random variable provided, taking into account missing data.
Definition: simple_stat.f90:39
Constructors of the corresponding objects.
Compute forward coordinate transformation from geographical system to projected system.
Compute the distance in m between two points.
Module for quickly interpreting the OPTIONAL parameters passed to a subprogram.
copy object
Compute a set of percentiles for a random variable.
Module for describing geographically referenced regular grids.
Definition: grid_class.F90:247
Represent data in a pretty string.
This module defines objects describing georeferenced sparse points possibly with topology and project...
Compute the standard deviation of the random variable provided, taking into account missing data...
Definition: simple_stat.f90:69
Determine whether a point lies inside a polygon or a rectangle.
Method for returning the contents of the object.
Generic subroutine for checking OPTIONAL parameters.
This object fully defines a transformation between a couple of particular griddim_def or vol7d object...
Compute backward coordinate transformation from projected system to geographical system.
Gestione degli errori.
Classe per la gestione di un volume completo di dati osservati.
Methods for returning the value of object members.
This module defines usefull general purpose function and subroutine.
Module for defining the extension and coordinates of a rectangular georeferenced grid.
Destructors of the corresponding objects.
Module for basic statistical computations taking into account missing data.
Definition: simple_stat.f90:25
classe per la gestione del logging
This object defines in an abstract way the type of transformation to be applied.
Module for defining transformations between rectangular georeferenced grids and between grids and spa...
Method for setting the contents of the object.
Emit log message for a category with specific priority.

Generated with Doxygen.