Path: blob/devel/misc/netcdf/src/GridDataMapper/NetCDFInterpolate.f90
3206 views
!------------------------------------------------------------------------------1! Peter RÃ¥back, Vili Forsell2! Created: 13.6.20113! Last Modified: 13.7.20114!------------------------------------------------------------------------------5! This module contains functions for6! - interpolating NetCDF data for an Elmer grid point (incl. coordinate transformation); Interpolate()7! - coordinate transformations for an Elmer grid point8! o none by default (x,y,z) -> (x,y,z)9! o cs2cs interface with parameters defined in Solver Input File10! o cartesian-to-cylindrical transformation (x,y,z) -> (phi,r,z)11! - scaling Elmer mesh points to fit NetCDF data12!------------------------------------------------------------------------------13MODULE NetCDFInterpolate14USE DefUtils, ONLY: dp, MAX_NAME_LEN15USE NetCDFGeneralUtils, ONLY: GetFromNetCDF16USE Messages17IMPLICIT NONE1819INTERFACE20!--- For connecting the C code, which accesses the cs2cs21SUBROUTINE cs2cs_transform( coord, hasZ, isRad, elmer_proj, netcdf_proj, res ) BIND(c)22USE iso_c_binding2324!--- Input parameters25REAL(C_DOUBLE) :: coord(3)26INTEGER(C_INT), VALUE :: hasZ, isRad27CHARACTER(KIND=C_CHAR) :: elmer_proj(*), netcdf_proj(*)2829!--- Output parameters30REAL(C_DOUBLE) :: res(3)3132END SUBROUTINE cs2cs_transform33END INTERFACE3435LOGICAL :: DEBUG_INTERP = .FALSE.36PRIVATE :: GetSolutionInStencil, CoordinateTransformation, ScaleMeshPoint, ChooseInterpolation, GetScalar3738CONTAINS3940!------------------ LinearInterpolation() ---------------------41!--- Performs linear interpolation42!--------------------------------------------------------------43FUNCTION LinearInterpolation(x,u1,u2) RESULT(y)44USE DefUtils45IMPLICIT NONE46REAL(KIND=dp), INTENT(IN) :: u1(2),u2(2),x47REAL(KIND=dp) :: y4849y = (((u2(2) - u1(2))/(u2(1) - u1(1)))*(x-u1(1)))+u1(2)50END FUNCTION LinearInterpolation515253!------------------- BilinearInterpolation() -------------------54!--- Performs bilinear interpolation on a stencil (2x2 matrix of corner values)55!--- with given weights (a 2 dimensional vector)56!---------------------------------------------------------------57FUNCTION BiLinearInterpolation(stencil,weights) RESULT(y)58USE DefUtils59IMPLICIT NONE60REAL(KIND=dp), INTENT(IN) :: stencil(2,2), weights(2)61REAL(KIND=dp) :: y6263y = stencil(1,1)*(1-weights(1))*(1-weights(2)) + &64stencil(2,1)*weights(1)*(1-weights(2)) + &65stencil(1,2)*(1-weights(1))*weights(2) + &66stencil(2,2)*weights(1)*weights(2)6768END FUNCTION BiLinearInterpolation6970!------------------- TrilinearInterpolation() -------------------71!--- Performs trilinear interpolation on a stencil (2x2x2 matrix of corner values)72!--- with given weights (a 3 dimensional vector)73!---------------------------------------------------------------74FUNCTION TriLinearInterpolation(stencil,weights) RESULT(y)75USE DefUtils76IMPLICIT NONE77REAL(KIND=dp), INTENT(IN) :: stencil(2,2,2), weights(3)78REAL(KIND=dp) :: val1,val2,y7980val1 = BiLinearInterpolation(stencil(:,:,1),weights(1:2))81val2 = BiLinearInterpolation(stencil(:,:,2),weights(1:2))82y = val1*(1-weights(3)) + val2*weights(3)8384END FUNCTION TriLinearInterpolation8586!------------------ Interpolate() -----------------------------87!--- Takes and interpolates one Elmer grid point to match NetCDF data; includes coordinate transformation88!--- ASSUMES INPUT DIMENSIONS AGREE89!--------------------------------------------------------------90FUNCTION Interpolate(SOLVER,NCID,VAR_ID,DIM_LENS,GRID,&91TIME,TIME_IND,interp_val,COORD_SYSTEM,X) RESULT( success )92USE DefUtils, ONLY: Solver_t93USE NetCDFGridUtils, ONLY: UniformGrid_t94USE NetCDFGeneralUtils, ONLY: TimeType_t95IMPLICIT NONE9697!------------------------------------------------------------------------------98! ARGUMENTS99!------------------------------------------------------------------------------100TYPE(Solver_t), INTENT(IN) :: SOLVER101TYPE(UniformGrid_t), INTENT(IN) :: GRID102TYPE(TimeType_t), INTENT(IN) :: TIME103INTEGER, INTENT(IN) :: NCID,DIM_LENS(:),TIME_IND,VAR_ID104CHARACTER(len = *), INTENT(IN) :: COORD_SYSTEM105REAL(KIND=dp), INTENT(INOUT) :: interp_val ! Final Elmer point and interpolated value106REAL(KIND=dp), OPTIONAL, INTENT(IN) :: X(:)107LOGICAL :: success ! Return value108109!------------------------------------------------------------------------------110! VARIABLES111!------------------------------------------------------------------------------112INTEGER :: alloc_stat, i113INTEGER, ALLOCATABLE :: ind(:)114REAL(KIND=dp), ALLOCATABLE :: Xf(:)115116IF ( PRESENT(X) .AND. GRID % COORD_COUNT .GT. 0 ) THEN117!------------------------------------------------------------------------------118! Uses Elmer coordinates119!------------------------------------------------------------------------------120ALLOCATE (ind(GRID % DIMS), Xf(size(X)), STAT = alloc_stat)121IF ( alloc_stat .NE. 0 ) THEN122CALL Fatal('GridDataMapper','Interpolation vectors memory allocation failed')123END IF124125!--- 1) Coordinate mapping from Elmer (x,y) to the one used by NetCDF126Xf = CoordinateTransformation( SOLVER, X, COORD_SYSTEM )127128!--- 2) Scaling, if applicable129! NOTE! By default the SCALE consists of 1's, and MOVE 0's; hence, nothing happens130! without user specifically specifying so131Xf = GRID % SCALE(:)*Xf + GRID % MOVE(:) ! Scales the mesh point within the NetCDF grid132133!--- 3) Index estimation134! Find the (i,j) indices [1,...,max]135! Calculates the normalized difference vector;136! i.e. the distance/indices to Elmer grid point x from the leftmost points of the NetCDF bounding box137ind(1:GRID % COORD_COUNT) = CEILING( ( Xf(:) - GRID % X0(:) ) / GRID % DX(:) )138ind((GRID % COORD_COUNT+1):GRID % DIMS) = GRID % CONST_VALS139140! This could be done better, one could apply extrapolation141! with a narrow layer.142DO i = 1,size(Xf,1),1 ! NOTE: Does not modify the constant dimensions143144! Checks that the estimated index is within the bounding box145IF( ind(i) < 1 .OR. ind(i) >= GRID % NMAX(i) ) THEN146147! If it's smaller than the leftmost index, but within tolerance (Eps), set it to lower bound; and vice versa148IF( Xf(i) <= GRID % X0(i) .AND. Xf(i) >= GRID % X0(i) - GRID % EPS(i) ) THEN149ind(i) = 1150ELSE IF( Xf(i) >= GRID % X1(i) .AND. Xf(i) <= GRID % X1(i) + GRID % EPS(i) ) THEN151ind(i) = GRID % NMAX(i)152ELSE ! The index is too far to be salvaged153WRITE (Message, '(A,F14.3,A,(F14.3),A,F14.3,A,I3,A,F14.3,A,F14.6,A)') &154'Adjusted Elmer value is out of NetCDF bounds: ',&155GRID % X0(i), ' <= ',Xf(i), ' <= ', GRID % X1(i), &156' over dimension ',i,' and originating from ', X(i),' despite error tolerance epsilon: ', GRID % EPS(i), '.'157CALL Warn( 'GridDataMapper',Message)158success = .FALSE.159RETURN160END IF161END IF162END DO163164!--- 4) Choose and perform interpolation165interp_val = ChooseInterpolation(NCID,VAR_ID,GRID,TIME,Xf,IND,TIME_IND,DIM_LENS)166167ELSE168!------------------------------------------------------------------------------169! No Elmer coordinates (only constants/time)170!------------------------------------------------------------------------------171CALL GetScalar(NCID,VAR_ID,GRID,TIME,TIME_IND,DIM_LENS,interp_val)172173END IF174175success = .TRUE.176177END FUNCTION Interpolate178179!----------------- ChooseInterpolation() ----------------------180!--- Chooses the appropriate weighting, stencil and interpolation method181FUNCTION ChooseInterpolation(NCID,VAR_ID,GRID,TIME,X_VAL,X_IND,TIME_IND,DIM_LENS) RESULT(interp_val)182!--------------------------------------------------------------183USE NetCDFGridUtils, ONLY: UniformGrid_t184USE NetCDFGeneralUtils, ONLY: TimeType_t185IMPLICIT NONE186187!------------------------------------------------------------------------------188! ARGUMENTS189!------------------------------------------------------------------------------190INTEGER, INTENT(IN) :: NCID, VAR_ID, X_IND(:), DIM_LENS(:), TIME_IND191TYPE(UniformGrid_t), INTENT(IN) :: GRID192TYPE(TimeType_t), INTENT(IN) :: TIME193REAL(KIND=dp), INTENT(IN) :: X_VAL(:)194REAL(KIND=dp) :: interp_val ! The output195196!------------------------------------------------------------------------------197! VARIABLES198!------------------------------------------------------------------------------199INTEGER :: alloc_stat, loop200INTEGER :: actual_size, & ! The actual amount of stencil values201actual_dims ! How many dimensions remain in use202INTEGER :: last_loc ! Latest location on the array203LOGICAL :: changed ! True, if the stencil has been changed204INTEGER, ALLOCATABLE :: sizes(:) ! Possibly differing sizes of the stencils205REAL(KIND=dp), ALLOCATABLE :: xi(:), weights(:), stencil_data(:)206REAL(KIND=dp) :: u1(2),u2(2) ! For 1D (linear) interpolation207REAL(KIND=dp), ALLOCATABLE :: stencilLine(:),stencilSqr(:,:),stencilCube(:,:,:) ! Adjusted if seems to over-index208209!------------------------------------------------------------------------------210! INITIALIZATIONS211!------------------------------------------------------------------------------212changed = .FALSE.213actual_size = 1214actual_dims = GRID % DIMS215216!--- Finds the locations which are on the edge of over-indexing, and limits them if necessary217ALLOCATE ( sizes(GRID % DIMS), STAT = alloc_stat )218IF ( alloc_stat .NE. 0 ) THEN219CALL Fatal('GridDataMapper','Memory ran out!')220END IF221sizes = 2222223DO loop = 1,size(X_IND,1)224IF ( X_IND(loop) .EQ. DIM_LENS(loop) ) THEN ! Ignore last dimensions225sizes(loop) = 1226actual_dims = actual_dims - 1227changed = .TRUE.228END IF229actual_size = actual_size * sizes(loop) ! Calculates the actual size of the stencil230END DO231232!--- The sizes will change: need to allocate a temporary array for reshaping into a size suitable for interpolation233IF ( changed ) THEN234ALLOCATE ( stencil_data(actual_size), STAT = alloc_stat )235IF ( alloc_stat .NE. 0 ) THEN236CALL Fatal('GridDataMapper','Memory ran out!')237END IF238END IF239240!--- Allocates the weights and such241ALLOCATE ( xi(actual_dims), weights(actual_dims), STAT = alloc_stat )242IF ( alloc_stat .NE. 0 ) THEN243CALL Fatal('GridDataMapper','Memory ran out!')244END IF245246!------------------------------------------------------------------------------247! A) Calculating the weights for each used dimension248!------------------------------------------------------------------------------249last_loc = 1 ! The latest handled location of the modified vectors250DO loop = 1,size(sizes,1),1251! If the dimension is used, its size is larger than one (otherwise doesn't affect actual_size)252IF ( sizes(loop) .GT. 1 ) THEN253! The value of the estimated NetCDF grid point254xi(last_loc) = GRID % X0(loop) + (X_IND(loop)-1) * GRID % DX(loop)255256! Interpolation weights, which are the normalized differences of the estimation from the adjacent grid point257! Can be negative if ceil for indices brings the value of xi higher than x258!----------- Assume xi > x ------259! x0 + (ind-1)dx > x, where dx > 0260! <=> (ind-1)dx > x-x0261! <=> ind-1 > (x-x0)/dx262! <=> ceil((x-x0)/dx) > ((x-x0)/dx) + 1263! o Known (x-x0)/dx <= ceil((x-x0)/dx) < (x-x0)/dx+1264! => Contradicts; Ergo, range ok.265!--------------------------------266! p values should be within [0,1]267! 0 exactly when x = xi, 1 when (x-x0)/dx = ceil((x-x0)/dx) = ind268weights(last_loc) = (X_VAL(loop)-xi(last_loc))/GRID % DX(loop)269last_loc = last_loc + 1270END IF271END DO272273!------------------------------------------------------------------------------274! B) Obtaining the stencil values275!------------------------------------------------------------------------------276!--- (Must be in original dimensions for the data acquisition to, f.ex., match the contents of X_IND)277SELECT CASE ( GRID % DIMS )278CASE (1) !-- 1D279ALLOCATE ( stencilLine(sizes(1)), STAT = alloc_stat )280IF ( alloc_stat .NE. 0 ) THEN281CALL Fatal('GridDataMapper','Memory ran out!')282END IF283284CALL GetSolutionInStencil(NCID,VAR_ID,X_IND,TIME_IND,TIME,DIM_LENS,GRID % ACCESS_PERM,stencilLine = stencilLine)285IF ( changed ) stencil_data = RESHAPE(stencilLine,SHAPE(stencil_data))286287CASE (2) !-- 2D288ALLOCATE ( stencilSqr(sizes(1),sizes(2)), STAT = alloc_stat )289IF ( alloc_stat .NE. 0 ) THEN290CALL Fatal('GridDataMapper','Memory ran out!')291END IF292293! get data on stencil size(stencil)=(2,2), ind -vector describes the lower left corner294CALL GetSolutionInStencil(NCID,VAR_ID,X_IND,TIME_IND,TIME,DIM_LENS,GRID % ACCESS_PERM,stencilSqr = stencilSqr)295IF ( changed ) stencil_data = RESHAPE(stencilSqr,SHAPE(stencil_data))296297CASE (3) !-- 3D298299ALLOCATE ( stencilCube(sizes(1),sizes(2),sizes(3)), STAT = alloc_stat )300IF ( alloc_stat .NE. 0 ) THEN301CALL Fatal('GridDataMapper','Memory ran out!')302END IF303304CALL GetSolutionInStencil(NCID,VAR_ID,X_IND,TIME_IND,TIME,DIM_LENS,GRID % ACCESS_PERM,stencilCube = stencilCube)305IF ( changed ) stencil_data = RESHAPE(stencilCube,SHAPE(stencil_data))306307CASE DEFAULT !-- Error308CALL Fatal('GridDataMapper','Cannot handle more than three variable dimensions!')309END SELECT310311!------------------------------------------------------------------------------312! C) Interpolation313!------------------------------------------------------------------------------314!--- Allocates the interpolation arrays, if necessary315SELECT CASE ( actual_size )316CASE (1) ! Scalar317318! PRINT *, 'Scalar: ', stencil_data319!-- stencil_data contains it all320interp_val = stencil_data(1) ! NOTE: Returning a scalar follows only if changed is .TRUE.321322CASE (2) ! Line323324!--- Adjusts data/weights to proper size325IF ( changed ) THEN326! PRINT *, 'Line: ', stencil_data327ALLOCATE ( stencilLine(2), STAT = alloc_stat )328IF ( alloc_stat .NE. 0 ) THEN329CALL Fatal('GridDataMapper','Memory ran out!')330END IF331stencilLine = stencil_data332END IF333334!--- Linear interpolation335!--- Note: X_IND is the point in the lower left corner; so, in this case the leftmost point of the linear line336u1(1) = X_IND(1) ! Linear location from scalar x coord (integer),337u1(2) = stencilLine(1) ! interpolation for the corresponding value338u2(1) = X_IND(1) + 1 ! Same for the adjacent point before interpolation339u2(2) = stencilLine(2)340interp_val = LinearInterpolation((X_IND(1) + weights(1)),u1,u2)341342CASE (4) ! Square343344!--- Adjusts data/weights to proper size345IF ( changed ) THEN346! PRINT *, 'Square: ', stencil_data347ALLOCATE ( stencilSqr(2,2), STAT = alloc_stat )348IF ( alloc_stat .NE. 0 ) THEN349CALL Fatal('GridDataMapper','Memory ran out!')350END IF351stencilSqr = RESHAPE(stencil_data,SHAPE(stencilSqr))352END IF353354!--- Bilinear interpolation355interp_val = BiLinearInterpolation(stencilSqr,weights)356357CASE (8) ! Cube358359!--- Adjusts data/weights to proper size360IF ( changed ) THEN361! PRINT *, 'Cube: ', stencil_data362ALLOCATE ( stencilCube(2,2,2), STAT = alloc_stat )363IF ( alloc_stat .NE. 0 ) THEN364CALL Fatal('GridDataMapper','Memory ran out!')365END IF366stencilCube = RESHAPE(stencil_data,SHAPE(stencilCube))367END IF368369!--- Trilinear interpolation370interp_val = TriLinearInterpolation(stencilCube,weights)371372CASE DEFAULT ! Error373WRITE(Message,'(A,I5,A)') 'Cannot interpolate a stencil of size ', actual_size, '.'374CALL Fatal('GridDataMapper',Message)375376END SELECT377378END FUNCTION ChooseInterpolation379380!----------------- CoordinateTransformation() -----------------381!--- Transforms input coordinates into the given coordinate system382FUNCTION CoordinateTransformation( SOLVER, INPUT, COORD_SYSTEM ) RESULT( output )383!--------------------------------------------------------------384USE DefUtils, ONLY: dp, MAX_NAME_LEN, Solver_t, GetSolverParams, GetString, GetLogical385USE iso_c_binding, ONLY: C_NULL_CHAR386USE Messages387IMPLICIT NONE388389!--- Input arguments390TYPE(Solver_t), INTENT(IN) :: SOLVER391CHARACTER(*), INTENT(IN) :: COORD_SYSTEM ! Some coordinate392REAL(KIND=dp), INTENT(IN) :: INPUT(:) ! The input coordinates393394!--- Return value395REAL(KIND=dp), ALLOCATABLE :: output(:) ! The output coordinates396397!--- Others398REAL(KIND=dp) :: coord(3), res(3)399INTEGER :: alloc_stat, hasZcoord400LOGICAL :: found401CHARACTER(len=MAX_NAME_LEN) :: elmer, netcdf402403!--- DEBUG printout404! WRITE (*,*) 'Input ', input405406!--- Initializations407coord = 0408res = 0409ALLOCATE ( output(size(INPUT)), STAT = alloc_stat )410IF ( alloc_stat .NE. 0 ) THEN411CALL Fatal('GridDataMapper','Coordinate transformation memory allocation failed')412END IF413414!--- Selects the coordinate system transformation415SELECT CASE (COORD_SYSTEM)416417!--- CS2CS Coordinate transformation418CASE ('cs2cs')419! CALL Info('GridDataMapper', 'Applies cs2cs coordinate transformation between the Elmer and NetCDF values!')420421!-- Gathers the coordinate information422hasZcoord = 0423IF ( size(INPUT,1) .GE. 3 ) THEN424hasZcoord = 1425coord(1:3) = INPUT(1:3)426ELSE427coord(1:2) = INPUT(1:2)428END IF429430!--- DEBUG printout431! WRITE (*,*) 'Coordinates ', coord432433!--- Picks up the constant data from the Elmer Solver parameters434elmer = GetString(GetSolverParams(SOLVER),"CS2CS Elmer Projection", found)435IF ( .NOT. found ) THEN436CALL Fatal('GridDataMapper',&437'CS2CS Transformation did not find Elmer projection information "CS2CS Elmer Projection" from the Solver Input File')438END IF439440netcdf = GetString(GetSolverParams(SOLVER), "CS2CS NetCDF Projection", found)441IF ( .NOT. found ) THEN442CALL Fatal('GridDataMapper',&443'CS2CS Transformation did not find NetCDF projection information "CS2CS NetCDF Projection" from the Solver Input File')444END IF445446! //C_NULL_CHAR's terminate the given strings with nulls to enable C compatibility447IF ( GetLogical(GetSolverParams(SOLVER), "CS2CS Is Input Radians", found) .AND. found ) THEN448CALL cs2cs_transform( coord, hasZcoord, 1, elmer//C_NULL_CHAR, netcdf//C_NULL_CHAR, res) ! True; is in radians449ELSE450CALL cs2cs_transform( coord, hasZcoord, 0, elmer//C_NULL_CHAR, netcdf//C_NULL_CHAR, res) ! False; is in degrees by default451END IF452453!--- Sends the result as output454IF ( size(output,1) .GE. 3 ) THEN455output(1:3) = res(1:3)456ELSE457output(1:2) = res(1:2)458END IF459460!--- DEBUG printout461! WRITE (*,*) 'Result ', res, ' to out ', output462463CASE ('cylindrical')464! CALL Info('GridDataMapper','Applies cylindrical coordinate transformation to cartesian coordinates!')465466!--- Transforms 3D Elmer grid points to cylindrical coordinates (phi,r,z)467IF ( size(INPUT,1) .GE. 3) THEN468output(1) = atan2( INPUT(2), INPUT(1) ) ! phi angle value469output(2) = sqrt(INPUT(1)**2 + INPUT(2)**2) ! radius from the center of cylinder470output(3) = INPUT(3) ! Height from zero level471ELSE472CALL Fatal('GridDataMapper','Cylindrical coordinate transformation requires at least three dimensional Elmer grid.')473END IF474475!--- In default case, no coordinate transformation is applied476CASE DEFAULT477! WRITE (Message,'(A,A15,A)') 'No coordinate transformation applied: Unknown coordinate system "',&478! coord_system, '". Check Solver Input File and the variable "Coordinate System"'479! CALL Warn('GridDataMapper', Message)480output(:) = INPUT(:)481END SELECT482483END FUNCTION484485!------------------ ScaleMeshPoint() ------------------------486!--- Takes an Elmer mesh point and moves and scales it within the NetCDF grid487!--- Assumed that Elmer mesh and NetCDF grid should be 1:1, but aren't still completely matched488!--- NOTE: Can be optimized by calculating move(:) and scales(:) before interpolation (constant over a mesh/grid combo)489FUNCTION ScaleMeshPoint(X,X0,X1,X0E,X1E) RESULT( Xf )490!------------------------------------------------------------491USE Messages492USE DefUtils, ONLY: dp493IMPLICIT NONE494REAL(KIND=dp), INTENT(IN) :: X(:), &! The input Elmer point495X0(:), X1(:), & ! The limiting values (points) of NetCDF grid496X0E(:), X1E(:) ! The limiting values (points) of Elmer bounding box497REAL(KIND=dp), ALLOCATABLE :: Xf(:), & ! Scaled value; the output498move(:), & ! Moves the Elmer min value to the NetCDF min value499scales(:) ! Scales the grids to same value range (NetCDF constant, Elmer varies)500INTEGER :: alloc_stat ! For allocation501502!--- Initial checks and allocations503504! All sizes are the same505IF ( .NOT. ( (size(X) .EQ. size(X0)) .AND. (size(X0) .EQ. size(X1)) .AND. &506(size(X1) .EQ. size(X0E)) .AND. (size(X0E) .EQ. size(X1E)) ) ) THEN507CALL Fatal( 'GridDataMapper', 'Scaling input point sizes do not match!')508END IF509ALLOCATE ( Xf(size(X)), move(size(X)), scales(size(X)), STAT = alloc_stat )510IF ( alloc_stat .NE. 0 ) THEN511CALL Fatal('GridDataMapper','Memory ran out during scaling')512END IF513514Xf = 0515move = 0516scales = 0517!--- Calculates the modifications518519! First the scaling to same size (Eq. a( X1E(1)-X0E(1) ) = (X1(1)-X0(1)) ; ranges over a dimension are same. Solved for a, 1 if equal)520scales(:) = (X1(:)-X0(:))/(X1E(:)-X0E(:)) ! Note: "/" and "*" elementwise operations for arrays in Fortran521522! Second the vector to reach X0 from the scaled X0E (wherever it is)523move(:) = X0(:) - scales(:)*X0E(:) ! zero, if equal524525!--- Applies the modification526Xf(:) = scales(:)*X(:) + move(:)527528END FUNCTION ScaleMeshPoint529530!------------------ GetScalar() -------------------------------531!--- Gets a scalar value from NetCDF532SUBROUTINE GetScalar( NCID, VAR_ID, GRID, TIME, TIME_IND, DIM_LENS, scalar )533!--------------------------------------------------------------534USE NetCDFGeneralUtils, ONLY: TimeType_t, GetFromNetCDF535USE NetCDFGridUtils, ONLY: UniformGrid_t536USE DefUtils, ONLY: dp537IMPLICIT NONE538539!------------------------------------------------------------------------------540! ARGUMENTS541!------------------------------------------------------------------------------542INTEGER, INTENT(IN) :: NCID, VAR_ID, TIME_IND, DIM_LENS(:)543TYPE(UniformGrid_t), INTENT(IN) :: GRID544TYPE(TimeType_t), INTENT(IN) :: TIME545REAL(KIND=dp), INTENT(OUT) :: scalar546547!------------------------------------------------------------------------------548! VARIABLES549!------------------------------------------------------------------------------550REAL(KIND=dp), ALLOCATABLE :: data(:)551INTEGER, ALLOCATABLE :: singleton(:)552INTEGER :: alloc_stat553554!------------------------------------------------------------------------------555! Basic checks and data access with the constant values defined in the Grid556!------------------------------------------------------------------------------557ALLOCATE ( singleton(size(DIM_LENS)), STAT = alloc_stat )558IF ( alloc_stat .NE. 0 ) THEN559CALL Fatal('GridDataMapper','Memory ran out')560END IF561singleton = 1562563IF ( .NOT. GRID % IS_DEF ) CALL Fatal('GridDataMapper',&564'GetScalar requires a defined grid')565IF ( GRID % DIMS .LE. GRID % COORD_COUNT ) CALL Fatal('GridDataMapper',&566'GetScalar requires constant values for accessing NetCDF')567568IF ( GetFromNetCDF(NCID,VAR_ID,GRID % CONST_VALS(GRID % ACCESS_PERM(:)),&569TIME % low,TIME,DIM_LENS(GRID % ACCESS_PERM),data,singleton) ) THEN570scalar = data(1)571END IF572573END SUBROUTINE GetScalar574575!------------------ GetSolutionStencil() ----------------------576!--- Gets a square matrix starting from the lower left index, the size is defined by input matrix stencil577SUBROUTINE GetSolutionInStencil( NCID,VAR_ID,X_IND,TIME_IND,TIME,DIM_LENS,ACC_PERM,stencilLine,stencilSqr,stencilCube )578!--------------------------------------------------------------579USE NetCDFGeneralUtils, ONLY: TimeType_t, GetFromNetCDF580IMPLICIT NONE581582!--- Arguments583INTEGER, INTENT(IN) :: NCID,X_IND(:),TIME_IND,DIM_LENS(:),VAR_ID,ACC_PERM(:)584TYPE(TimeType_t), INTENT(IN) :: TIME585REAL(KIND=dp), OPTIONAL, INTENT(INOUT) :: stencilLine(:),stencilSqr(:,:),stencilCube(:,:,:)586587!--- Variables588INTEGER :: i,j,alloc_stat589REAL(KIND=dp), ALLOCATABLE :: data(:)590CHARACTER(len = 50) :: answ_format591592! WRITE (*,*) 'Stencil ', stencil(:,1), ' ; ', stencil(:,2) ,' X: ', X,' Y: ', Y593594!--- Checks that the input exists and is unique595IF ( PRESENT(stencilLine) .AND. (.NOT. (PRESENT(stencilSqr) .OR. PRESENT(stencilCube))) ) THEN !--- 1D596597! Queries the stencil from NetCDF with associated error checks598IF ( GetFromNetCDF(NCID,VAR_ID,X_IND(ACC_PERM(:)),&599TIME_IND,TIME,DIM_LENS(ACC_PERM(:)),data,SHAPE(stencilLine)) ) THEN600601stencilLine = RESHAPE(data,SHAPE(stencilLine))602IF ( DEBUG_INTERP ) THEN603!------ Debug printouts -------------------------604WRITE (*,*) 'STENCIL LINE:'605WRITE (answ_format, *) '(', size(stencilLine,1),'(F10.4))'606WRITE (*,answ_format) stencilLine(:)607!------------------------------------------------608END IF609END IF610611ELSE IF ( PRESENT(stencilSqr) .AND. (.NOT. (PRESENT(stencilLine) .OR. PRESENT(stencilCube))) ) THEN !--- 2D612613! Queries the stencil from NetCDF with associated error checks614IF ( GetFromNetCDF(NCID,VAR_ID,X_IND(ACC_PERM(:)),&615TIME_IND,TIME,DIM_LENS(ACC_PERM(:)),data,SHAPE(stencilSqr)) ) THEN616617stencilSqr = RESHAPE(data,SHAPE(stencilSqr))618IF ( DEBUG_INTERP ) THEN619!------ Debug printouts -------------------------620WRITE (*,*) 'STENCIL SQUARE:'621DO i = 1,size(stencilSqr,2)622WRITE (answ_format, *) '(', size(stencilSqr,1),'(F10.4))'623WRITE (*,answ_format) stencilSqr(:,i)624END DO625!------------------------------------------------626END IF627END IF628629ELSE IF ( PRESENT(stencilCube) .AND. (.NOT. (PRESENT(stencilSqr) .OR. PRESENT(stencilLine))) ) THEN !--- 3D630631! Queries the stencil from NetCDF with associated error checks632IF ( GetFromNetCDF(NCID,VAR_ID,X_IND(ACC_PERM(:)),&633TIME_IND,TIME,DIM_LENS(ACC_PERM(:)),data,SHAPE(stencilCube)) ) THEN634635stencilCube = RESHAPE(data,SHAPE(stencilCube))636IF ( DEBUG_INTERP ) THEN637!------ Debug printouts -------------------------638WRITE (*,*) 'STENCIL CUBE:'639DO j = 1,size(stencilCube,3)640DO i = 1,size(stencilCube,2)641WRITE (answ_format, *) '(', size(stencilCube,1),'(F10.4))'642WRITE (*,answ_format) stencilCube(:,i,j)643END DO644WRITE(*,'(A)') '----'645END DO646!------------------------------------------------647END IF648END IF649ELSE650CALL Fatal('GridDataMapper','Multiple, or no, stencils given for GetSolutionInStencil()!')651END IF652653END SUBROUTINE GetSolutionInStencil654655656END MODULE NetCDFInterpolate657658659