Path: blob/devel/misc/netcdf/src/GridDataMapper/NetCDFGridUtils.f90
3206 views
!------------------------------------------------------------------------------1! Vili Forsell2! Created: 13.6.20113! Last Modified: 13.7.20114!------------------------------------------------------------------------------5! Contains tools for6! - getting the essential information on the uniform NetCDF grid; GetNetCDFGridParameters()7! - adjusting the grid parameters on basis of a mask; Focus2DNetCDFGrid()8!------------------------------------------------------------------------------910MODULE NetCDFGridUtils11USE DefUtils, ONLY: dp12USE NetCDF13USE Messages14USE NetCDFGeneralUtils, ONLY: G_Error15IMPLICIT NONE1617!--- A type for defining an uniform grid (to simplify parameter passing)18TYPE UniformGrid_t19REAL(KIND=dp), ALLOCATABLE :: x0(:), & ! Lower left corner of grid20dx(:), & ! Uniform difference between points21x1(:), & ! Upper right corner of grid22Eps(:) ! Error tolerance for overshooting bounds23INTEGER, ALLOCATABLE :: nmax(:), & ! Amount of points24const_vals(:) ! NetCDF data values for constants25INTEGER :: dims ! Amount of used dimensions26INTEGER :: coord_count ! Amount of used coordinates from the used dimensions27REAL(KIND=dp), ALLOCATABLE :: scale(:), & ! Scales an Elmer point into this grid by multiplying with this...28move(:) ! ... and moving by this29LOGICAL :: is_def ! True, if size is non-zero, else not defined and false30INTEGER, ALLOCATABLE :: access_perm(:) ! The proper NetCDF access order, indexed by first coordinates, then constants31INTEGER, ALLOCATABLE :: Elmer_perm(:) ! Transforms Elmer coordinate order to the NetCDF Coordinate order32END TYPE UniformGrid_t3334CONTAINS3536!------------------ PrintGrid() ------------------------------------37!--- Prints the Uniform Grid contents to stdout38SUBROUTINE PrintGrid( GRID, ID )39!-------------------------------------------------------------------40IMPLICIT NONE41TYPE(UniformGrid_t), INTENT(IN) :: GRID42INTEGER, INTENT(IN) :: ID ! Numeric name for the grid43INTEGER :: loop4445PRINT *, 'dims ', Grid % dims46PRINT *, 'coordinate count ', Grid % coord_count47IF ( GRID % IS_DEF ) THEN48PRINT *, 'x0 ', Grid % x049PRINT *, 'dx ', Grid % dx50PRINT *, 'nmax ', Grid % nmax51PRINT *, 'x1 ', Grid % x152PRINT *, 'eps ', Grid % eps53PRINT *, 'scale ', Grid % scale54PRINT *, 'move ', Grid % move55PRINT *, 'const vals ', Grid % const_vals56PRINT *, 'access perm ', Grid % access_perm57PRINT *, 'Elmer perm ', Grid % Elmer_perm5859PRINT *,'NetCDF (Uniform) Grid Bounding Box ',ID,':'60DO loop = 1,size( GRID % x0, 1),161PRINT '(A,I3,A,F20.2,F20.2)','Coordinate ', loop,':',GRID % X0(loop),GRID % X1(loop)62END DO63END IF6465END SUBROUTINE PrintGrid666768!------------------ InitGrid() -------------------------------------69!--- Initializes the contents of a grid70SUBROUTINE InitGrid( Grid, DIMS, COORDS )71!-------------------------------------------------------------------72USE Messages73IMPLICIT NONE74TYPE(UniformGrid_t), INTENT(INOUT) :: Grid75INTEGER, INTENT(IN) :: DIMS, COORDS76INTEGER :: alloc_stat7778Grid % is_def = .TRUE.79Grid % dims = DIMS80Grid % coord_count = COORDS81IF ( DIMS .LE. 0 ) THEN82Grid % is_def = .FALSE.83RETURN84END IF8586ALLOCATE (Grid % x0(COORDS),Grid % dx(COORDS),Grid % nmax(COORDS),Grid % x1(COORDS),&87Grid % eps(COORDS),Grid % scale(COORDS),Grid % move(COORDS),&88Grid % const_vals((DIMS-COORDS)),Grid % access_perm(DIMS),&89Grid % Elmer_perm(COORDS), STAT=alloc_stat)90IF ( alloc_stat .NE. 0 ) THEN91CALL Fatal('GridDataMapper','Memory ran out!')92END IF9394Grid % x0 = 0.0_dp95Grid % dx = 0.0_dp96Grid % nmax = 097Grid % x1 = 0.0_dp98Grid % eps = 0.0_dp99! With these initializations: 1*x(:) + 0 = x(:) ; i.e. doesn't modify100Grid % scale = 1.0_dp ! Default: no effect101Grid % move = 0.0_dp ! Default: no effect102Grid % const_vals = 0103Grid % access_perm = 0 ! Unusable index104Grid % Elmer_perm = 0 ! -"-105106END SUBROUTINE InitGrid107108!------------------ GetNetCDFGridParameters() ----------------------109!--- Takes the limits for the uniform grid of NetCDF110!--- (x0,y0,z0,...) is the lower left corner, (dx,dy,dz,...) contains the associated step sizes,111!--- and (nxmax,nymax,nzmax,...) are the amounts of steps112SUBROUTINE GetNetCDFGridParameters( NCID,Grid,DIM_IDS,DIM_LENS )113!-------------------------------------------------------------------114115IMPLICIT NONE116INTEGER, INTENT(IN) :: NCID117TYPE(UniformGrid_t), INTENT(INOUT) :: Grid118INTEGER, INTENT(IN) :: DIM_IDS(:),DIM_LENS(:)119REAL(KIND=dp) :: first(1),first_two(2)120INTEGER :: ind, status, ind_vec(1),count_vec(1)121122! Takes the first two values of all grid dimensions to determine the whole grid123ind_vec = 1124count_vec = 1125first = 0126first_two = 0127128! Takes the first two values for each dimension, saves the information necessary for reconstructing the grid129! Assumes the NetCDF grid is uniform, the indexing of the dimensions enabled via the usual convention of variables with same names130DO ind = 1,GRID % COORD_COUNT,1131132! If the only value on a dimension, there is no dx and only one value can be taken133IF (DIM_LENS(ind) .EQ. 1) THEN134CALL Warn('GridDataMapper','Scalar dimension encountered; No obtainable difference')135count_vec = 1136first = 0137Grid % dx(ind) = 0138status = NF90_GET_VAR(NCID,DIM_IDS(ind),first,ind_vec,count_vec)139ELSE140count_vec = 2141first_two = 0142status = NF90_GET_VAR(NCID,DIM_IDS(ind),first_two,ind_vec,count_vec)143END IF144IF ( G_ERROR(status,'NetCDF dimension values access failed.') ) THEN145CALL abort()146END IF147148IF ( DIM_LENS(ind) .GT. 1 ) THEN149Grid % x0(ind) = first_two(1)150Grid % dx(ind) = first_two(2) - first_two(1)151ELSE152Grid % x0(ind) = first(1)153Grid % dx(ind) = 0154END IF155Grid % nmax(ind) = DIM_LENS(ind)156END DO157158END SUBROUTINE GetNetCDFGridParameters159160161!------------------ FocusNetCDFGrid ----------------------162!--- Tightens the original bounding box until it touches the masked area163SUBROUTINE Focus2DNetCDFGrid( NCID,MASK_VAR,MASK_LIMIT,Grid,TIME,DIM_LENS )164!-------------------------------------------------------------------165IMPLICIT NONE166INTEGER, INTENT(IN) :: NCID,DIM_LENS(:)167TYPE(UniformGrid_t), INTENT(INOUT) :: Grid168REAL(KIND=dp) :: i_bl(2), i_br(2), i_ul(2), i_ur(2) ! Indices for the grid boundaries169CHARACTER(len = *), INTENT(IN) :: MASK_VAR ! The variable for catching the masking data from NetCDF170REAL(KIND=dp), INTENT(IN) :: MASK_LIMIT ! The limiting value which decides the mask has been reached171INTEGER, INTENT(IN) :: TIME ! Used time instance172173REAL(KIND=dp), ALLOCATABLE :: scan_horizontal(:), scan_vertical(:) ! Scanning lines of differing dimensions174INTEGER :: low_limits(2,4), high_limits(2,4),i0(2),i1(2),line,mask_ind, alloc_stat ! The lowest and highest limits for each scanning line175INTEGER :: status, mask_id, index_vector(3), count_vert(3), count_horiz(3) ! For NetCDF access to the mask176LOGICAL :: is_vert(4), finished(4) ! True if the scanning line has reached the data mask177178status = NF90_INQ_VARID(NCID,MASK_VAR,mask_id)179IF ( G_Error(status,'NetCDF mask variable name not found.') ) THEN180CALL abort()181END IF182183index_vector = 1 ! Specialize later on184! Counts over one time value185count_vert = (/ 1,DIM_LENS(2),1 /) ! Vertical scanning line count186count_horiz = (/ DIM_LENS(1),1,1 /) ! Horizontal scanning line count187finished = .FALSE.188is_vert = .FALSE.189is_vert(1) = .TRUE. ! left scanning line is vertical190is_vert(3) = .TRUE. ! right scanning line is vertical191i0(:) = (/1,1/) ! Indices for lower left corner192i1(:) = Grid % nmax(1:Grid % COORD_COUNT) ! Indices for upper right corner193IF ( (i0(1) .EQ. i1(1)) .AND. (i0(2) .EQ. i1(2)) ) RETURN ! Does nothing if there is nothing to mask194195! Allocates the scanning lines ; cannot avoid using at most the dimension sizes amount of memory at some point,196! and memory allocation/deallocation to accomodate for changing sizes would be slow, so of constant size.197ALLOCATE (scan_horizontal(DIM_LENS(1)), scan_vertical(DIM_LENS(2)), STAT = alloc_stat)198IF ( alloc_stat .NE. 0 ) THEN199CALL Fatal('GridDataMapper','Scanning line memory allocation failed')200END IF201202! Collect the four corners of the grid (b - bottom, l - left, u - up, r - right)203i_bl(:) = i0(:)204i_br(1) = i1(1)205i_br(2) = i0(2)206i_ul(1) = i0(1)207i_ul(2) = i1(2)208i_ur(:) = i1(:)209210! Initialize low_limits and high_limits with the input grid points211! ORDER of scanning lines: Left, down, right, up.212low_limits(:,1) = i_bl(:)213low_limits(:,2) = i_bl(:)214low_limits(:,3) = i_br(:)215low_limits(:,4) = i_ul(:)216217high_limits(:,1) = i_ul(:)218high_limits(:,2) = i_br(:)219high_limits(:,3) = i_ur(:)220high_limits(:,4) = i_ur(:)221222! Tunes each scanning line at a time to find the suitable rectangular grid region223DO line = 1,size(finished),1224225! Chooses the right line type, fills it with data, finds the mask, updates the limits of the intersecting lines226IF ( is_vert(line) ) THEN ! 1) A vertical line227228! Focuses the boundary until it's done229DO WHILE (.NOT. finished(line) )230231! A) Gather data for scanning232! The x and time invariant during the search233index_vector = (/low_limits(1,line),1,1/)234235status = NF90_GET_VAR(NCID,mask_id,scan_vertical,index_vector,count_vert)236IF ( G_ERROR(status,'NetCDF mask variable access failed.') ) THEN237CALL abort()238END IF239240! B) The scan for the mask along y coordinate241DO mask_ind = 1,dim_lens(2)242! If reaches the mask, the current line is finished243IF ( scan_vertical(mask_ind) .GT. MASK_LIMIT ) THEN244finished(line) = .TRUE.245EXIT246END IF247END DO248249! C) Every vertical line out of the box handled, tighten the box250IF ( .NOT. finished(line) ) THEN251IF ( line .EQ. 1 ) THEN ! Left line moves to right252low_limits(1,line) = low_limits(1,line) + 1253high_limits(1,line) = high_limits(1,line) + 1254ELSE ! Right line moves to left255low_limits(1,line) = low_limits(1,line) - 1256high_limits(1,line) = high_limits(1,line) - 1257END IF258END IF259260! D) Finishing criteria, if no mask found (left and right vertical lines reach each other)261IF ( low_limits(1,1) .EQ. low_limits(1,3) ) THEN262finished(1) = .TRUE.263finished(3) = .TRUE.264END IF265END DO266267! E) Vertical line's x coordinates restrain the intersecting horizontal lines268IF ( line .EQ. 1 ) THEN ! Left vertical scanning line269low_limits(1,2) = low_limits(1,line) ! Down horizontal, low270low_limits(1,4) = low_limits(1,line) ! Up horizontal, low271ELSE ! Right vertical scanning line272high_limits(1,2) = low_limits(1,line) ! Down horizontal, high273high_limits(1,4) = low_limits(1,line) ! Up horizontal, high274END IF275276ELSE ! 2) A horizontal line277278! Focuses the boundary until it's done279DO WHILE (.NOT. finished(line) )280281! A) Gather data for scanning282! The y and time invariant during the search283index_vector = (/1,low_limits(2,line),1/)284285status = NF90_GET_VAR(NCID,mask_id,scan_horizontal,index_vector,count_horiz)286IF ( G_ERROR(status,'NetCDF mask variable access failed.') ) THEN287CALL abort()288END IF289290! B) The scan for the mask291DO mask_ind = 1,dim_lens(1)292IF ( scan_horizontal(mask_ind) .GT. MASK_LIMIT ) THEN293finished(line) = .TRUE.294EXIT295END IF296END DO297298! C) Every horizontal line out of the box has been handled299IF ( .NOT. finished(line) ) THEN300IF ( line .EQ. 2 ) THEN ! Lower line moves up301low_limits(2,line) = low_limits(2,line) + 1302high_limits(2,line) = high_limits(2,line) + 1303ELSE ! Upper line moves down304low_limits(2,line) = low_limits(2,line) - 1305high_limits(2,line) = high_limits(2,line) - 1306END IF307END IF308309! D) Finishing criteria, if no mask found (upper and lower horizontal line reach each other)310IF ( low_limits(2,2) .EQ. low_limits(2,4) ) THEN311finished(2) = .TRUE.312finished(4) = .TRUE.313END IF314END DO315316! E) Horizontal line's y coordinates restrain the intersecting vertical lines317IF ( line .EQ. 2 ) THEN ! Lower horizontal scanning line318low_limits(2,1) = low_limits(2,line) ! Left vertical, low319low_limits(2,3) = low_limits(2,line) ! Right vertical, low320ELSE ! Upper horizontal scanning line321high_limits(2,1) = low_limits(2,line) ! Left vertical, high322high_limits(2,3) = low_limits(2,line) ! Right vertical, high323END IF324325END IF326327END DO328329!---- Finally, updates the values330i0(:) = low_limits(:,1)331i1(:) = high_limits(:,4)332Grid % x0(1:Grid % COORD_COUNT) = Grid % x0(1:Grid % COORD_COUNT) + (i0(:) - 1)* Grid % DX(1:Grid % COORD_COUNT)333Grid % nmax(1:Grid % COORD_COUNT) = i1(:) - i0(:) + 1334335WRITE (Message,'(A)') '2D grid focusing complete:'336CALL Info('GridDataMapper', Message)337WRITE (Message,'(A,2(I5),A,2(I5))') 'Lower left indices: ', i0, ' upper right indices: ', i1338CALL Info('GridDataMapper', Message)339WRITE (Message,'(A,2(F14.1),A,2(I5))') 'x0: ', Grid % x0, ' nmax: ', Grid % nmax340CALL Info('GridDataMapper', Message)341342END SUBROUTINE Focus2DNetCDFGrid343344END MODULE NetCDFGridUtils345346347