Changeset 3557 for palm/trunk/UTIL/inifor/src/inifor_transform.f90
- Timestamp:
- Nov 22, 2018 4:01:22 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
palm/trunk/UTIL/inifor/src/inifor_transform.f90
r3537 r3557 26 26 ! ----------------- 27 27 ! $Id$ 28 ! Updated documentation 29 ! 30 ! 31 ! 3537 2018-11-20 10:53:14Z eckhard 28 32 ! bugfix: working precision added 29 33 ! … … 52 56 ! Authors: 53 57 ! -------- 54 ! @author Eckhard Kadasch58 !> @author Eckhard Kadasch (Deutscher Wetterdienst, Offenbach) 55 59 ! 56 60 ! Description: … … 110 114 DO k = nz, LBOUND(out_arr, 3), -1 111 115 112 ! TODO: Remove IF clause and extrapolate based on a critical vertical 113 ! TODO: index marking the lower bound of COSMO-DE data coverage. 114 ! Check for negative interpolation weights indicating grid points 115 ! below COSMO-DE domain and extrapolate from the top in such cells. 116 ! 117 !-- TODO: Remove IF clause and extrapolate based on a critical vertical 118 !-- TODO: index marking the lower bound of COSMO-DE data coverage. 119 !-- Check for negative interpolation weights indicating grid points 120 !-- below COSMO-DE domain and extrapolate from the top in such cells. 116 121 IF (outgrid % w_verti(i,j,k,1) < -1.0_dp .AND. k < nz) THEN 117 122 out_arr(i,j,k) = out_arr(i,j,k+1) … … 155 160 !------------------------------------------------------------------------------! 156 161 SUBROUTINE interpolate_2d(invar, outvar, outgrid, ncvar) 157 ! I index 0-based for the indices of the outvar to be consistent with the 158 ! outgrid indices and interpolation weights. 162 ! 163 !-- I index 0-based for the indices of the outvar to be consistent with the 164 !-- outgrid indices and interpolation weights. 159 165 TYPE(grid_definition), INTENT(IN) :: outgrid 160 166 REAL(dp), INTENT(IN) :: invar(0:,0:,0:) … … 164 170 INTEGER :: i, j, k, l 165 171 166 ! TODO: check if input dimensions are consistent, i.e. ranges are correct 167 IF (UBOUND(outvar, 3) .GT. UBOUND(invar, 3)) THEN 172 ! 173 !-- TODO: check if input dimensions are consistent, i.e. ranges are correct 174 IF ( UBOUND(outvar, 3) .GT. UBOUND(invar, 3) ) THEN 168 175 message = "Output array for '" // TRIM(ncvar % name) // "' has ' more levels (" // & 169 176 TRIM(str(UBOUND(outvar, 3))) // ") than input variable ("//& … … 190 197 191 198 199 !------------------------------------------------------------------------------! 200 ! Description: 201 ! ------------ 202 !> Compute the horizontal average of the in_arr(:,:,:) and store it in 203 !> out_arr(:) 204 !------------------------------------------------------------------------------! 192 205 SUBROUTINE average_2d(in_arr, out_arr, ii, jj) 193 206 REAL(dp), INTENT(IN) :: in_arr(0:,0:,0:) … … 200 213 IF (SIZE(ii) .NE. SIZE(jj)) THEN 201 214 message = "Length of 'ii' and 'jj' index lists do not match." // & 202 NEW_LINE(' ') // "ii has " // str(SIZE(ii)) // " elements, " // 215 NEW_LINE(' ') // "ii has " // str(SIZE(ii)) // " elements, " // & 203 216 NEW_LINE(' ') // "jj has " // str(SIZE(jj)) // "." 204 217 CALL abort('average_2d', message) … … 211 224 i = ii(l) 212 225 j = jj(l) 213 out_arr(k) = out_arr(k) +& 214 in_arr(i, j, k) 226 out_arr(k) = out_arr(k) + in_arr(i, j, k) 215 227 END DO 216 228 … … 223 235 224 236 237 !------------------------------------------------------------------------------! 238 ! Description: 239 ! ------------ 240 !> Three-dimensional interpolation driver. Interpolates from the source_array to 241 !> the given palm_grid. 242 !> 243 !> The routine separates horizontal and vertical 244 !> interpolation. In the horizontal interpolation step, the source_array data is 245 !> interpolated along COSMO grid levels onto the intermediate grid (vertically 246 !> as coarse as COSMO, horizontally as fine as PALM). 247 !------------------------------------------------------------------------------! 225 248 SUBROUTINE interpolate_3d(source_array, palm_array, palm_intermediate, palm_grid) 226 249 TYPE(grid_definition), INTENT(IN) :: palm_intermediate, palm_grid … … 232 255 nx = palm_intermediate % nx 233 256 ny = palm_intermediate % ny 234 nlev = palm_intermediate % nz ! nlev 235 236 ! Interpolate from COSMO-DE to intermediate grid. Allocating with one 237 ! less point in the vertical, since scalars like T have 50 instead of 51 238 ! points in COSMO-DE. 257 nlev = palm_intermediate % nz 258 259 ! 260 !-- Interpolate from COSMO to intermediate grid. Allocating with one 261 !-- less point in the vertical, since scalars like T have 50 instead of 51 262 !-- points in COSMO. 239 263 ALLOCATE(intermediate_array(0:nx, 0:ny, 0:nlev-1)) ! 240 264 241 265 CALL interpolate_2d(source_array, intermediate_array, palm_intermediate) 242 266 243 ! Interpolate from intermediate grid to palm_grid grid, includes 244 ! extrapolation for cells below COSMO-DE domain. 267 ! 268 !-- Interpolate from intermediate grid to palm_grid grid, includes 269 !-- extrapolation for cells below COSMO domain. 245 270 CALL interpolate_1d(intermediate_array, palm_array, palm_grid) 246 271 … … 250 275 251 276 277 !------------------------------------------------------------------------------! 278 ! Description: 279 ! ------------ 280 !> Average data horizontally from the source_array over the region given by the 281 !> averaging grid 'avg_grid' and store the result in 'profile_array'. 282 !------------------------------------------------------------------------------! 252 283 SUBROUTINE average_profile(source_array, profile_array, avg_grid) 253 284 TYPE(grid_definition), INTENT(IN) :: avg_grid … … 265 296 j_source = avg_grid % jjj(l) 266 297 267 DO k_profile = avg_grid % k_min, UBOUND(profile_array, 1) ! PALM levels 268 269 DO m = 1, 2 ! vertical interpolation neighbours 298 ! 299 !-- Loop over PALM levels 300 DO k_profile = avg_grid % k_min, UBOUND(profile_array, 1) 301 302 ! 303 !-- Loop over vertical interpolation neighbours 304 DO m = 1, 2 270 305 271 306 k_source = avg_grid % kkk(l, k_profile, m) … … 274 309 + avg_grid % w(l, k_profile, m) & 275 310 * source_array(i_source, j_source, k_source) 276 277 END DO ! m, vertical interpolation neighbours 278 279 END DO ! k_profile, PALM levels 280 281 END DO ! l, horizontal neighbours 311 ! 312 !-- Loop over vertical interpolation neighbours m 313 END DO 314 315 ! 316 !-- Loop over PALM levels k_profile 317 END DO 318 319 ! 320 !-- Loop over horizontal neighbours l 321 END DO 282 322 283 323 ni_columns = 1.0_dp / avg_grid % n_columns 284 324 profile_array(:) = profile_array(:) * ni_columns 285 325 286 ! Extrapolate constant to the bottom 326 ! 327 !-- Constant extrapolation to the bottom 287 328 profile_array(1:avg_grid % k_min-1) = profile_array(avg_grid % k_min) 288 329 … … 290 331 291 332 333 !------------------------------------------------------------------------------! 334 ! Description: 335 ! ------------ 336 !> Extrapolates density linearly from the level 'k_min' downwards. 337 !------------------------------------------------------------------------------! 292 338 SUBROUTINE extrapolate_density(rho, avg_grid) 293 339 REAL(dp), DIMENSION(:), INTENT(INOUT) :: rho … … 308 354 309 355 356 !------------------------------------------------------------------------------! 357 ! Description: 358 ! ------------ 359 !> Driver for extrapolating pressure from PALM level k_min downwards 360 !------------------------------------------------------------------------------! 310 361 SUBROUTINE extrapolate_pressure(p, rho, avg_grid) 311 362 REAL(dp), DIMENSION(:), INTENT(IN) :: rho … … 405 456 REAL(dp) :: ri 406 457 407 ! TODO check dimensions of lat/lon and y/x match 458 ! 459 !-- TODO check dimensions of lat/lon and y/x match 408 460 409 461 ri = 1.0_dp / r … … 438 490 REAL(dp) :: ri 439 491 440 ! If this elemental function is called with a large array as xy, it is 441 ! computationally more efficient to precompute the inverse radius and 442 ! then muliply. 492 ! 493 !-- If this elemental function is called with a large array as xy, it is 494 !-- computationally more efficient to precompute the inverse radius and 495 !-- then muliply. 443 496 ri = 1.0_dp / r 444 497 … … 448 501 449 502 503 !------------------------------------------------------------------------------! 504 ! Description: 505 ! ------------ 506 !> For a rotated-pole system with the origin at geographical latitude 'phi_c', 507 !> compute the geographical latitude of its rotated north pole. 508 !------------------------------------------------------------------------------! 450 509 REAL(dp) FUNCTION phic_to_phin(phi_c) 451 510 REAL(dp), INTENT(IN) :: phi_c … … 456 515 457 516 517 !------------------------------------------------------------------------------! 518 ! Description: 519 ! ------------ 520 !> For a rotated-pole system with the origin at geographical latitude 'phi_c' 521 !> and longitude 'lam_c', compute the geographical longitude of its rotated 522 !> north pole. 523 !------------------------------------------------------------------------------! 458 524 REAL(dp) FUNCTION lamc_to_lamn(phi_c, lam_c) 459 525 REAL(dp), INTENT(IN) :: phi_c, lam_c … … 467 533 468 534 535 !------------------------------------------------------------------------------! 536 ! Description: 537 ! ------------ 538 !> Set gamma according to whether PALM domain is in the northern or southern 539 !> hemisphere of the COSMO rotated-pole system. Gamma assumes either the 540 !> value 0 or PI and is needed to work around around a bug in the 541 !> rotated-pole coordinate transformations. 542 !------------------------------------------------------------------------------! 469 543 REAL(dp) FUNCTION gamma_from_hemisphere(phi_cg, phi_ref) 470 REAL(dp), INTENT(IN) :: phi_cg, phi_ref 471 LOGICAL :: palm_centre_is_south_of_cosmo_origin 472 473 palm_centre_is_south_of_cosmo_origin = (phi_cg < phi_ref) 474 475 IF (palm_centre_is_south_of_cosmo_origin) THEN 544 REAL(dp), INTENT(IN) :: phi_cg 545 REAL(dp), INTENT(IN) :: phi_ref 546 547 LOGICAL :: palm_origin_is_south_of_cosmo_origin 548 549 palm_origin_is_south_of_cosmo_origin = (phi_cg < phi_ref) 550 551 IF (palm_origin_is_south_of_cosmo_origin) THEN 476 552 gamma_from_hemisphere = PI 477 553 ELSE … … 550 626 551 627 628 !------------------------------------------------------------------------------! 629 ! Description: 630 ! ------------ 631 !> Rotate the given vector field (x(:), y(:)) by the given 'angle'. 632 !------------------------------------------------------------------------------! 552 633 SUBROUTINE rotate_vector_field(x, y, angle) 553 634 REAL(dp), DIMENSION(:), INTENT(INOUT) :: x, y !< x and y coodrinate in arbitrary units … … 559 640 sine = SIN(angle * TO_RADIANS) 560 641 cosine = COS(angle * TO_RADIANS) 561 ! RESAHPE() fills columns first, so the rotation matrix becomes 562 ! 563 ! rotation = [ cosine -sine ] 564 ! [ sine cosine ] 642 ! 643 !-- RESAHPE() fills columns first, so the rotation matrix becomes 644 !-- 645 !-- rotation = [ cosine -sine ] 646 !-- [ sine cosine ] 565 647 rotation = RESHAPE( (/cosine, sine, -sine, cosine/), (/2, 2/) ) 566 648 … … 588 670 !> Datenbanken des DWD. 589 671 !> https://www.dwd.de/SharedDocs/downloads/DE/modelldokumentationen/nwv/cosmo_d2/cosmo_d2_dbbeschr_aktuell.pdf?__blob=publicationFile&v=2 590 ! >672 !------------------------------------------------------------------------------! 591 673 FUNCTION meridian_convergence_rotated(phi_n, lam_n, phi_g, lam_g) & 592 674 RESULT(delta) … … 664 746 DO j = 0, UBOUND(palm_clon, 2)!palm_grid % ny 665 747 DO i = 0, UBOUND(palm_clon, 1)!palm_grid % nx 666 ! Compute the floating point index corrseponding to PALM-4U grid point 667 ! location along target grid (COSMO-DE) axes. 748 ! 749 !-- Compute the floating point index corrseponding to PALM-4U grid point 750 !-- location along target grid (COSMO-DE) axes. 668 751 lonpos = (palm_clon(i,j) - lon0) * cosmo_dxi 669 752 latpos = (palm_clat(i,j) - lat0) * cosmo_dyi … … 693 776 694 777 778 !------------------------------------------------------------------------------! 779 ! Description: 780 ! ------------ 781 !> Computes linear vertical interpolation neighbour indices and weights for each 782 !> column of the given palm grid. 783 !------------------------------------------------------------------------------! 695 784 SUBROUTINE find_vertical_neighbours_and_weights_interp( palm_grid, & 696 785 palm_intermediate ) … … 709 798 nlev = palm_intermediate % nz 710 799 711 ! in each column of the fine grid, find vertical neighbours of every cell 800 ! 801 !-- in each column of the fine grid, find vertical neighbours of every cell 712 802 DO j = 0, ny 713 803 DO i = 0, nx … … 718 808 column_top = palm_intermediate % h(i,j,nlev) 719 809 720 ! scan through palm_grid column and set neighbour indices in 721 ! case current_height is either below column_base, in the current 722 ! cell, or above column_top. Keep increasing current cell index until 723 ! the current cell overlaps with the current_height. 810 ! 811 !-- scan through palm_grid column and set neighbour indices in 812 !-- case current_height is either below column_base, in the current 813 !-- cell, or above column_top. Keep increasing current cell index until 814 !-- the current cell overlaps with the current_height. 724 815 DO k = 1, nz 725 816 726 ! Memorize the top and bottom boundaries of the coarse cell and the 727 ! current height within it 817 ! 818 !-- Memorize the top and bottom boundaries of the coarse cell and the 819 !-- current height within it 728 820 current_height = palm_grid % z(k) + palm_grid % z0 729 821 h_top = palm_intermediate % h(i,j,k_intermediate+1) … … 738 830 ) 739 831 740 ! set default weights 832 ! 833 !-- set default weights 741 834 palm_grid % w_verti(i,j,k,1:2) = 0.0_dp 742 835 … … 755 848 756 849 ELSE 757 ! cycle through intermediate levels until current 758 ! intermediate-grid cell overlaps with current_height 850 ! 851 !-- cycle through intermediate levels until current 852 !-- intermediate-grid cell overlaps with current_height 759 853 DO WHILE (.NOT. point_is_in_current_cell .AND. k_intermediate <= nlev-1) 760 854 k_intermediate = k_intermediate + 1 … … 777 871 palm_grid % kk(i,j,k,2) = k_intermediate + 1 778 872 779 ! copmute vertical weights 873 ! 874 !-- compute vertical weights 780 875 weight = (h_top - current_height) / (h_top - h_bottom) 781 876 palm_grid % w_verti(i,j,k,1) = weight … … 791 886 792 887 888 !------------------------------------------------------------------------------! 889 ! Description: 890 ! ------------ 891 !> Computes linear vertical interpolation neighbour indices and weights for each 892 !> column of the given averaging grid. 893 !> 894 !> The difference to the _interp variant of this routine lies in how columns 895 !> are adressed. While the _interp variant loops over all PALM grid columns 896 !> given by combinations of all index indices (i,j), this routine loops over a 897 !> subset of COSMO columns, which are sequantlially stored in the index lists 898 !> iii(:) and jjj(:). 899 !------------------------------------------------------------------------------! 793 900 SUBROUTINE find_vertical_neighbours_and_weights_average( avg_grid ) 794 901 TYPE(grid_definition), INTENT(INOUT) :: avg_grid … … 805 912 nlev = SIZE(avg_grid % cosmo_h, 3) 806 913 807 ! in each column of the fine grid, find vertical neighbours of every cell 914 ! 915 !-- in each column of the fine grid, find vertical neighbours of every cell 808 916 DO l = 1, avg_grid % n_columns 809 917 … … 814 922 column_top = avg_grid % cosmo_h(i,j,nlev) 815 923 816 ! scan through avg_grid column until and set neighbour indices in 817 ! case current_height is either below column_base, in the current 818 ! cell, or above column_top. Keep increasing current cell index until 819 ! the current cell overlaps with the current_height. 924 ! 925 !-- scan through avg_grid column until and set neighbour indices in 926 !-- case current_height is either below column_base, in the current 927 !-- cell, or above column_top. Keep increasing current cell index until 928 !-- the current cell overlaps with the current_height. 820 929 k_intermediate = 1 !avg_grid % cosmo_h is indezed 1-based. 821 930 DO k_palm = 1, avg_grid % nz 822 931 823 ! Memorize the top and bottom boundaries of the coarse cell and the 824 ! current height within it 932 ! 933 !-- Memorize the top and bottom boundaries of the coarse cell and the 934 !-- current height within it 825 935 current_height = avg_grid % z(k_palm) + avg_grid % z0 826 936 h_top = avg_grid % cosmo_h(i,j,k_intermediate+1) 827 937 h_bottom = avg_grid % cosmo_h(i,j,k_intermediate) 828 938 829 point_is_above_grid = (current_height > column_top) !22000m, very unlikely 939 ! 940 !-- COSMO column top is located at 22000m, point_is_above_grid is very 941 !-- unlikely. 942 point_is_above_grid = (current_height > column_top) 830 943 point_is_below_grid = (current_height < column_base) 831 944 … … 835 948 ) 836 949 837 ! set default weights 950 ! 951 !-- set default weights 838 952 avg_grid % w(l,k_palm,1:2) = 0.0_dp 839 953 … … 852 966 avg_grid % k_min = MAX(k_palm + 1, avg_grid % k_min) 853 967 ELSE 854 ! cycle through intermediate levels until current 855 ! intermediate-grid cell overlaps with current_height 968 ! 969 !-- cycle through intermediate levels until current 970 !-- intermediate-grid cell overlaps with current_height 856 971 DO WHILE (.NOT. point_is_in_current_cell .AND. k_intermediate <= nlev-1) 857 972 k_intermediate = k_intermediate + 1 … … 865 980 END DO 866 981 867 ! k_intermediate = 48 indicates the last section (indices 48 and 49), i.e. 868 ! k_intermediate = 49 is not the beginning of a valid cell. 982 ! 983 !-- k_intermediate = 48 indicates the last section (indices 48 and 49), i.e. 984 !-- k_intermediate = 49 is not the beginning of a valid cell. 869 985 IF (k_intermediate > nlev-1) THEN 870 986 message = "Index " // TRIM(str(k_intermediate)) // & … … 876 992 avg_grid % kkk(l,k_palm,2) = k_intermediate + 1 877 993 878 ! copmute vertical weights 994 ! 995 !-- compute vertical weights 879 996 weight = (h_top - current_height) / (h_top - h_bottom) 880 997 avg_grid % w(l,k_palm,1) = weight … … 882 999 END IF 883 1000 884 END DO ! k, PALM levels 885 END DO ! l, averaging columns 1001 ! 1002 !-- Loop over PALM levels k 1003 END DO 1004 1005 ! 1006 !-- Loop over averaging columns l 1007 END DO 886 1008 887 1009 END SUBROUTINE find_vertical_neighbours_and_weights_average … … 931 1053 ! ii(i,j,1/2) ii(i,j,3/4) 932 1054 ! 1055 !------------------------------------------------------------------------------! 933 1056 SUBROUTINE compute_horizontal_interp_weights(cosmo_lat, cosmo_lon, & 934 1057 palm_clat, palm_clon, palm_ii, palm_jj, palm_w_horiz) … … 950 1073 DO i = 0, UBOUND(palm_clon, 1) 951 1074 952 ! weight in lambda direction 1075 ! 1076 !-- weight in lambda direction 953 1077 wl = ( cosmo_lon(palm_ii(i,j,4)) - palm_clon(i,j) ) * cosmo_dxi 954 1078 955 ! weight in phi direction 1079 ! 1080 !-- weight in phi direction 956 1081 wp = ( cosmo_lat(palm_jj(i,j,2)) - palm_clat(i,j) ) * cosmo_dyi 957 1082 … … 988 1113 !> COSMO-DE the velocity points are staggared one half grid spaceing up-grid 989 1114 !> which means the first centre point has to be omitted and is set to zero. 1115 !------------------------------------------------------------------------------! 990 1116 SUBROUTINE centre_velocities(u_face, v_face, u_centre, v_centre) 991 1117 REAL(dp), DIMENSION(0:,0:,0:), INTENT(IN) :: u_face, v_face … … 1004 1130 1005 1131 1132 !------------------------------------------------------------------------------! 1133 ! Description: 1134 ! ------------ 1135 !> Compute the geographical latitude of a point given in rotated-pole cordinates 1136 !------------------------------------------------------------------------------! 1006 1137 FUNCTION phirot2phi (phirot, rlarot, polphi, pollam, polgam) 1007 1138 … … 1041 1172 1042 1173 1174 !------------------------------------------------------------------------------! 1175 ! Description: 1176 ! ------------ 1177 !> Compute the geographical latitude of a point given in rotated-pole cordinates 1178 !------------------------------------------------------------------------------! 1043 1179 FUNCTION phi2phirot (phi, rla, polphi, pollam) 1044 1180 … … 1072 1208 1073 1209 1210 !------------------------------------------------------------------------------! 1211 ! Description: 1212 ! ------------ 1213 !> Compute the geographical longitude of a point given in rotated-pole cordinates 1214 !------------------------------------------------------------------------------! 1074 1215 FUNCTION rlarot2rla(phirot, rlarot, polphi, pollam, polgam) 1075 1216 … … 1123 1264 1124 1265 1266 !------------------------------------------------------------------------------! 1267 ! Description: 1268 ! ------------ 1269 !> Compute the rotated-pole longitude of a point given in geographical cordinates 1270 !------------------------------------------------------------------------------! 1125 1271 FUNCTION rla2rlarot ( phi, rla, polphi, pollam, polgam ) 1126 1272 … … 1162 1308 1163 1309 1310 !------------------------------------------------------------------------------! 1311 ! Description: 1312 ! ------------ 1313 !> Rotate the given velocity vector (u,v) from the geographical to the 1314 !> rotated-pole system 1315 !------------------------------------------------------------------------------! 1164 1316 SUBROUTINE uv2uvrot(u, v, rlat, rlon, pollat, pollon, urot, vrot) 1165 1317 … … 1187 1339 1188 1340 1341 !------------------------------------------------------------------------------! 1342 ! Description: 1343 ! ------------ 1344 !> Rotate the given velocity vector (urot, vrot) from the rotated-pole to the 1345 !> geographical system 1346 !------------------------------------------------------------------------------! 1189 1347 SUBROUTINE uvrot2uv (urot, vrot, rlat, rlon, pollat, pollon, u, v) 1190 1348
Note: See TracChangeset
for help on using the changeset viewer.