Changeset 4489 for LMDZ6/trunk/libf/phylmd/ecrad/easy_netcdf.F90
- Timestamp:
- Mar 31, 2023, 8:42:57 PM (15 months ago)
- Location:
- LMDZ6/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
LMDZ6/trunk
- Property svn:mergeinfo changed
/LMDZ6/branches/LMDZ_ECRad (added) merged: 4175,4177-4183,4188,4192,4200-4203,4355,4366,4387-4388,4390,4444,4482,4486,4488
- Property svn:mergeinfo changed
-
LMDZ6/trunk/libf/phylmd/ecrad/easy_netcdf.F90
r3908 r4489 35 35 ! a NetCDF file 36 36 type netcdf_file 37 integer :: ncid 37 integer :: ncid = -1! NetCDF file ID 38 38 integer :: iverbose ! Verbosity: 0 = report only fatal errors, 39 39 ! 1 = ...and warnings, … … 55 55 procedure :: create => create_netcdf_file 56 56 procedure :: close => close_netcdf_file 57 procedure :: is_open 57 58 procedure :: get_real_scalar 59 procedure :: get_int_scalar 58 60 procedure :: get_real_vector 59 procedure :: get_int eger_vector61 procedure :: get_int_vector 60 62 procedure :: get_real_matrix 61 63 procedure :: get_real_array3 … … 65 67 procedure :: get_real_array3_indexed 66 68 procedure :: get_real_array4 67 generic :: get => get_real_scalar, get_real_vector, & 69 procedure :: get_char_vector 70 procedure :: get_char_matrix 71 generic :: get => get_real_scalar, get_int_scalar, & 72 & get_real_vector, get_int_vector, & 68 73 & get_real_matrix, get_real_array3, & 69 & get_real_array4, get_integer_vector,&74 & get_real_array4, & 70 75 & get_real_scalar_indexed, get_real_vector_indexed, & 71 & get_real_matrix_indexed, get_real_array3_indexed 76 & get_real_matrix_indexed, get_real_array3_indexed, & 77 & get_char_vector, get_char_matrix 72 78 procedure :: get_real_scalar_attribute 73 79 procedure :: get_string_attribute … … 83 89 procedure :: put_real_scalar 84 90 procedure :: put_real_vector 91 procedure :: put_int_vector 85 92 procedure :: put_real_matrix 86 93 procedure :: put_real_array3 … … 91 98 & put_real_matrix, put_real_array3, & 92 99 & put_real_scalar_indexed, put_real_vector_indexed, & 93 & put_real_matrix_indexed 100 & put_real_matrix_indexed, put_int_vector 94 101 procedure :: set_verbose 95 102 procedure :: transpose_matrices … … 101 108 procedure :: attribute_exists 102 109 procedure :: global_attribute_exists 110 #ifdef NC_NETCDF4 111 procedure :: copy_dimensions 112 #endif 113 procedure :: copy_variable_definition 114 procedure :: copy_variable 103 115 procedure, private :: get_array_dimensions 104 116 procedure, private :: get_variable_id … … 257 269 end if 258 270 271 this%ncid = -1 272 259 273 end subroutine close_netcdf_file 260 274 … … 367 381 368 382 integer :: j, istatus 369 integer :: dimids(NF90_MAX_VAR_DIMS)383 integer :: idimids(NF90_MAX_VAR_DIMS) 370 384 371 385 istatus = nf90_inquire_variable(this%ncid, ivarid, & 372 & ndims=ndims, dimids= dimids)386 & ndims=ndims, dimids=idimids) 373 387 if (istatus /= NF90_NOERR) then 374 388 write(nulerr,'(a,i0,a,a)') '*** Error inquiring about NetCDF variable with id ', & … … 379 393 ndimlens(:) = 0 380 394 do j = 1,ndims 381 istatus = nf90_inquire_dimension(this%ncid, dimids(j), len=ndimlens(j))395 istatus = nf90_inquire_dimension(this%ncid, idimids(j), len=ndimlens(j)) 382 396 if (istatus /= NF90_NOERR) then 383 397 write(nulerr,'(a,i0,a,i0,a,a)') '*** Error reading length of dimension ', & … … 420 434 421 435 !--------------------------------------------------------------------- 436 ! Return true if file is open, false otherwise 437 function is_open(this) 438 class(netcdf_file) :: this 439 logical :: is_open 440 is_open = (this%ncid >= 0) 441 end function is_open 442 443 !--------------------------------------------------------------------- 422 444 ! Return the number of dimensions of variable with name var_name, or 423 445 ! -1 if the variable is not found … … 619 641 620 642 !--------------------------------------------------------------------- 643 ! Read an integer scalar 644 subroutine get_int_scalar(this, var_name, scalar) 645 class(netcdf_file) :: this 646 character(len=*), intent(in) :: var_name 647 integer, intent(out):: scalar 648 649 integer :: istatus 650 integer :: ivarid, ndims 651 integer :: ndimlens(NF90_MAX_VAR_DIMS) 652 integer :: j, ntotal 653 654 ! Inquire the ID, shape & size of the variable 655 call this%get_variable_id(var_name, ivarid) 656 call this%get_array_dimensions(ivarid, ndims, ndimlens) 657 658 ! Compute number of elements of the variable in the file 659 ntotal = 1 660 do j = 1, ndims 661 ntotal = ntotal * ndimlens(j) 662 end do 663 664 if (this%iverbose >= 3) then 665 write(nulout,'(a,a)',advance='no') ' Reading ', var_name 666 call this%print_variable_attributes(ivarid,nulout) 667 end if 668 669 ! Abort if the number of elements is anything other than 1 670 if (ntotal /= 1) then 671 write(nulerr,'(a,a,a,i0,a)') '*** Error reading NetCDF variable ', & 672 & var_name, ' with total length ', ntotal, ' as a scalar' 673 call my_abort('Error reading NetCDF file') 674 end if 675 676 ! Read variable 677 istatus = nf90_get_var(this%ncid, ivarid, scalar) 678 if (istatus /= NF90_NOERR) then 679 write(nulerr,'(a,a,a,a)') '*** Error reading NetCDF variable ', & 680 & var_name, ' as a scalar: ', trim(nf90_strerror(istatus)) 681 call my_abort('Error reading NetCDF file') 682 end if 683 684 end subroutine get_int_scalar 685 686 687 !--------------------------------------------------------------------- 621 688 ! Read a scalar from a larger array, where "index" indexes the most 622 689 ! slowly varying dimension 623 subroutine get_real_scalar_indexed(this, var_name, index, scalar)690 subroutine get_real_scalar_indexed(this, var_name, scalar, index) 624 691 class(netcdf_file) :: this 625 692 character(len=*), intent(in) :: var_name … … 676 743 677 744 !--------------------------------------------------------------------- 678 ! Read a 1D array into "vector", which must be allocatable and will679 ! be reallocated if necessary745 ! Read a 1D real array into "vector", which must be allocatable and 746 ! will be reallocated if necessary 680 747 subroutine get_real_vector(this, var_name, vector) 681 748 class(netcdf_file) :: this … … 734 801 735 802 !--------------------------------------------------------------------- 736 ! Read a 1D integer array into "vector", which must be allocatable803 ! Read a 1D character array into "vector", which must be allocatable 737 804 ! and will be reallocated if necessary 738 subroutine get_ integer_vector(this, var_name, vector)805 subroutine get_char_vector(this, var_name, vector) 739 806 class(netcdf_file) :: this 740 807 character(len=*), intent(in) :: var_name 741 integer, allocatable, intent(out) :: vector(:)808 character(len=1), allocatable, intent(out) :: vector(:) 742 809 743 810 integer :: n ! Length of vector … … 784 851 if (istatus /= NF90_NOERR) then 785 852 write(nulerr,'(a,a,a,a)') '*** Error reading NetCDF variable ', & 853 & var_name, ' as a vector of chars: ', trim(nf90_strerror(istatus)) 854 call my_abort('Error reading NetCDF file') 855 end if 856 857 end subroutine get_char_vector 858 859 860 !--------------------------------------------------------------------- 861 ! Read a 1D integer array into "vector", which must be allocatable 862 ! and will be reallocated if necessary 863 subroutine get_int_vector(this, var_name, vector) 864 865 class(netcdf_file) :: this 866 character(len=*), intent(in) :: var_name 867 integer, allocatable, intent(out) :: vector(:) 868 869 integer :: n ! Length of vector 870 integer :: istatus 871 integer :: ivarid, ndims 872 integer :: ndimlens(NF90_MAX_VAR_DIMS) 873 integer :: j 874 875 call this%get_variable_id(var_name, ivarid) 876 call this%get_array_dimensions(ivarid, ndims, ndimlens) 877 878 ! Ensure variable has only one dimension in the file 879 n = 1 880 do j = 1, ndims 881 n = n * ndimlens(j) 882 if (j > 1 .and. ndimlens(j) > 1) then 883 write(nulerr,'(a,a,a)') '*** Error reading NetCDF variable ', & 884 & var_name, & 885 & ' as a vector: all dimensions above the first must be singletons' 886 call my_abort('Error reading NetCDF file') 887 end if 888 end do 889 890 ! Reallocate if necessary 891 if (allocated(vector)) then 892 if (size(vector) /= n) then 893 if (this%iverbose >= 1) then 894 write(nulout,'(a,a)') ' Warning: resizing vector to read ', var_name 895 end if 896 deallocate(vector) 897 allocate(vector(n)) 898 end if 899 else 900 allocate(vector(n)) 901 end if 902 903 if (this%iverbose >= 3) then 904 write(nulout,'(a,a,a,i0,a)',advance='no') ' Reading ', var_name, '(', n, ')' 905 call this%print_variable_attributes(ivarid,nulout) 906 end if 907 908 ! Read variable 909 istatus = nf90_get_var(this%ncid, ivarid, vector) 910 if (istatus /= NF90_NOERR) then 911 write(nulerr,'(a,a,a,a)') '*** Error reading NetCDF variable ', & 786 912 & var_name, ' as an integer vector: ', trim(nf90_strerror(istatus)) 787 913 call my_abort('Error reading NetCDF file') 788 914 end if 789 915 790 end subroutine get_integer_vector 791 916 end subroutine get_int_vector 792 917 793 918 !--------------------------------------------------------------------- 794 919 ! Read a vector of data from a larger array; the vector must be 795 920 ! allocatable and will be reallocated if necessary 796 subroutine get_real_vector_indexed(this, var_name, index, vector)921 subroutine get_real_vector_indexed(this, var_name, vector, index) 797 922 class(netcdf_file) :: this 798 923 character(len=*), intent(in) :: var_name … … 975 1100 976 1101 !--------------------------------------------------------------------- 1102 ! Read 2D array of characters into "matrix", which must be 1103 ! allocatable and will be reallocated if necessary. Whether to 1104 ! transpose is specifed by the final optional argument, but can also 1105 ! be specified by the do_transpose_2d class data member. 1106 subroutine get_char_matrix(this, var_name, matrix, do_transp) 1107 class(netcdf_file) :: this 1108 character(len=*), intent(in) :: var_name 1109 character(len=1), allocatable, intent(inout) :: matrix(:,:) 1110 logical, optional, intent(in):: do_transp ! Transpose data? 1111 1112 character(len=1), allocatable:: tmp_matrix(:,:) 1113 integer :: ndimlen1, ndimlen2 1114 integer :: istatus 1115 integer :: ivarid, ndims 1116 integer :: ndimlens(NF90_MAX_VAR_DIMS) 1117 integer :: vstart(NF90_MAX_VAR_DIMS) 1118 integer :: vcount(NF90_MAX_VAR_DIMS) 1119 integer :: j, ntotal 1120 logical :: do_transpose 1121 1122 ! Decide whether to transpose the array 1123 if (present(do_transp)) then 1124 do_transpose = do_transp 1125 else 1126 do_transpose = this%do_transpose_2d 1127 end if 1128 1129 call this%get_variable_id(var_name, ivarid) 1130 call this%get_array_dimensions(ivarid, ndims, ndimlens) 1131 1132 ! Ensure the variable has no more than two non-singleton 1133 ! dimensions 1134 ntotal = 1 1135 do j = 1, ndims 1136 ntotal = ntotal * ndimlens(j) 1137 if (j > 2 .and. ndimlens(j) > 1) then 1138 write(nulerr,'(a,a,a)') '*** Error reading NetCDF variable ', & 1139 & var_name, & 1140 & ' as a matrix: all dimensions above the second must be singletons' 1141 call my_abort('Error reading NetCDF file') 1142 end if 1143 end do 1144 1145 ! Work out dimension lengths 1146 if (ndims >= 2) then 1147 ndimlen1 = ndimlens(1) 1148 ndimlen2 = ntotal/ndimlen1 1149 else 1150 ndimlen1 = ntotal 1151 ndimlen2 = 1 1152 end if 1153 1154 if (do_transpose) then 1155 ! Read and transpose 1156 allocate(tmp_matrix(ndimlen1, ndimlen2)) 1157 1158 ! Reallocate if necessary 1159 if (allocated(matrix)) then 1160 if (size(matrix,1) /= ndimlen2 .or. size(matrix,2) /= ndimlen1) then 1161 if (this%iverbose >= 1) then 1162 write(nulout,'(a,a)') ' Warning: resizing matrix to read ', var_name 1163 end if 1164 deallocate(matrix) 1165 allocate(matrix(ndimlen2, ndimlen1)) 1166 end if 1167 else 1168 allocate(matrix(ndimlen2, ndimlen1)) 1169 end if 1170 1171 if (this%iverbose >= 3) then 1172 write(nulout,'(a,a,a,i0,a,i0,a)',advance='no') ' Reading ', var_name, '(', & 1173 & ndimlen2, ',', ndimlen1, ')' 1174 call this%print_variable_attributes(ivarid,nulout) 1175 end if 1176 1177 istatus = nf90_get_var(this%ncid, ivarid, tmp_matrix) 1178 matrix = transpose(tmp_matrix) 1179 deallocate(tmp_matrix) 1180 else 1181 ! Read data without transposition 1182 1183 ! Reallocate if necessary 1184 if (allocated(matrix)) then 1185 if (size(matrix,1) /= ndimlen1 .or. size(matrix,2) /= ndimlen2) then 1186 if (this%iverbose >= 1) then 1187 write(nulout,'(a,a)') ' Warning: resizing matrix to read ', var_name 1188 end if 1189 allocate(matrix(ndimlen1, ndimlen2)) 1190 end if 1191 else 1192 allocate(matrix(ndimlen1, ndimlen2)) 1193 end if 1194 1195 if (this%iverbose >= 3) then 1196 write(nulout,'(a,a,a,i0,a,i0,a)',advance='no') ' Reading ', var_name, '(', & 1197 & ndimlen1, ',', ndimlen2, ')' 1198 call this%print_variable_attributes(ivarid,nulout) 1199 end if 1200 1201 vstart = 1 1202 vcount(1:2) = [ndimlen1,1] 1203 1204 do j = 1,ndimlen2 1205 vstart(2) = j 1206 istatus = nf90_get_var(this%ncid, ivarid, matrix(:,j), start=vstart, count=vcount) 1207 end do 1208 end if 1209 1210 if (istatus /= NF90_NOERR) then 1211 write(nulerr,'(a,a,a,a)') '*** Error reading NetCDF variable ', & 1212 & var_name, ' as a matrix of characters: ', trim(nf90_strerror(istatus)) 1213 call my_abort('Error reading NetCDF file') 1214 end if 1215 1216 end subroutine get_char_matrix 1217 1218 1219 !--------------------------------------------------------------------- 977 1220 ! Read matrix of data from a larger array, which must be allocatable 978 1221 ! and will be reallocated if necessary. Whether to transpose is 979 1222 ! specifed by the final optional argument, but can also be specified 980 1223 ! by the do_transpose_2d class data member. 981 subroutine get_real_matrix_indexed(this, var_name, index, matrix, do_transp)1224 subroutine get_real_matrix_indexed(this, var_name, matrix, index, do_transp) 982 1225 class(netcdf_file) :: this 983 1226 character(len=*), intent(in) :: var_name … … 1187 1430 if (this%iverbose >= 3) then 1188 1431 write(nulout,'(a,a,a,i0,i0,i0,a)',advance='no') ' Reading ', var_name, & 1189 & ' (permut eddimensions ', i_permute_3d, ')'1432 & ' (permuting dimensions ', i_permute_3d, ')' 1190 1433 call this%print_variable_attributes(ivarid,nulout) 1191 1434 end if … … 1235 1478 ! be allocatable and will be reallocated if necessary. Whether to 1236 1479 ! pemute is specifed by the final optional argument 1237 subroutine get_real_array3_indexed(this, var_name, index, var, ipermute)1480 subroutine get_real_array3_indexed(this, var_name, var, index, ipermute) 1238 1481 class(netcdf_file) :: this 1239 1482 character(len=*), intent(in) :: var_name … … 1331 1574 write(nulout,'(a,i0,a,a,a,i0,i0,i0,a)') ' Reading slice ', index, & 1332 1575 & ' of ', var_name, & 1333 & ' (permut eddimensions ', i_permute_3d, ')'1576 & ' (permuting dimensions ', i_permute_3d, ')' 1334 1577 end if 1335 1578 … … 1471 1714 if (this%iverbose >= 3) then 1472 1715 write(nulout,'(a,a,a,i0,i0,i0,a)',advance='no') ' Reading ', var_name, & 1473 & ' (permut eddimensions ', i_permute_4d, ')'1716 & ' (permuting dimensions ', i_permute_4d, ')' 1474 1717 call this%print_variable_attributes(ivarid,nulout) 1475 1718 end if … … 1549 1792 ! allocate(character(len=i_attr_len) :: attr_str) 1550 1793 if (len(attr_str) < i_attr_len) then 1551 write(nulerr,'(a,a)') '*** Error: not enough space to read attribute ', attr_name1794 write(nulerr,'(a,a)') '*** Not enough space to read attribute ', attr_name 1552 1795 call my_abort('Error reading NetCDF file') 1553 1796 end if … … 1577 1820 real(jprb), intent(out) :: attr 1578 1821 1579 integer :: i _attr_len, ivarid1822 integer :: ivarid 1580 1823 integer :: istatus 1581 integer :: j1582 1824 1583 1825 istatus = nf90_inq_varid(this%ncid, var_name, ivarid) … … 1624 1866 ! allocate(character(len=i_attr_len) :: attr_str) 1625 1867 if (len(attr_str) < i_attr_len) then 1626 write(nulerr,'(a,a)') '*** Error: not enough space to read global attribute ', attr_name1868 write(nulerr,'(a,a)') '*** Not enough space to read global attribute ', attr_name 1627 1869 call my_abort('Error reading NetCDF file') 1628 1870 end if … … 1652 1894 1653 1895 character(len=4000) :: attr_str 1654 integer :: i_attr_len1655 1896 integer :: istatus 1656 integer :: j1657 1897 1658 1898 if (this%iverbose >= 4) then 1659 1899 istatus = nf90_get_att(this%ncid, ivarid, 'long_name', attr_str) 1660 1900 if (istatus == NF90_NOERR) then 1661 write(iunit, '(a)') ':' 1662 write(iunit, '(a,a)', advance='no') ' ', trim(attr_str) 1901 write(iunit, '(a,a,a)', advance='no') ': "', trim(attr_str), '"' 1663 1902 istatus = nf90_get_att(this%ncid, ivarid, 'units', attr_str) 1664 1903 if (istatus == NF90_NOERR) then … … 1721 1960 ! names. 1722 1961 subroutine define_variable(this, var_name, dim1_name, dim2_name, dim3_name, & 1723 & long_name, units_str, comment_str, standard_name, is_double, & 1724 & data_type_name, fill_value, deflate_level, shuffle, chunksizes) 1962 & dim4_name, long_name, units_str, comment_str, & 1963 & standard_name, is_double, data_type_name, fill_value, & 1964 & deflate_level, shuffle, chunksizes, ndims) 1725 1965 class(netcdf_file) :: this 1726 1966 character(len=*), intent(in) :: var_name 1727 1967 character(len=*), intent(in), optional :: long_name, units_str, comment_str, standard_name 1728 character(len=*), intent(in), optional :: dim1_name, dim2_name, dim3_name 1968 character(len=*), intent(in), optional :: dim1_name, dim2_name, dim3_name, dim4_name 1729 1969 logical, intent(in), optional :: is_double 1730 1970 character(len=*), intent(in), optional :: data_type_name … … 1733 1973 logical, intent(in), optional :: shuffle ! Shuffle bytes before compression 1734 1974 integer, dimension(:), intent(in), optional :: chunksizes 1735 1736 integer :: istatus, ndims, ivarid 1975 integer, intent(in), optional :: ndims 1976 1977 integer :: istatus, ndims_local, ndims_input, ivarid 1737 1978 integer, dimension(NF90_MAX_VAR_DIMS) :: idimids 1738 1979 integer :: data_type 1739 1980 1740 if (present(dim1_name)) then 1981 ! Sometimes a program may not know at compile time the exact 1982 ! dimensions of a variable - if ndims is present then only up to 1983 ! that many dimensions will be defined 1984 ndims_input = 4 1985 if (present(ndims)) then 1986 ndims_input = ndims 1987 end if 1988 1989 if (present(dim1_name) .and. ndims_input >= 1) then 1741 1990 ! Variable is at least one dimensional 1742 ndims = 11991 ndims_local = 1 1743 1992 istatus = nf90_inq_dimid(this%ncid, dim1_name, idimids(1)) 1744 1993 if (istatus /= NF90_NOERR) then … … 1747 1996 call my_abort('Error writing NetCDF file') 1748 1997 end if 1749 if (present(dim2_name) ) then1998 if (present(dim2_name) .and. ndims_input >= 2) then 1750 1999 ! Variable is at least two dimensional 1751 ndims = 22000 ndims_local = 2 1752 2001 istatus = nf90_inq_dimid(this%ncid, dim2_name, idimids(2)) 1753 2002 if (istatus /= NF90_NOERR) then … … 1756 2005 call my_abort('Error writing NetCDF file') 1757 2006 end if 1758 if (present(dim3_name) ) then2007 if (present(dim3_name) .and. ndims_input >= 3) then 1759 2008 ! Variable is at least three dimensional 1760 ndims = 32009 ndims_local = 3 1761 2010 istatus = nf90_inq_dimid(this%ncid, dim3_name, idimids(3)) 1762 2011 if (istatus /= NF90_NOERR) then … … 1765 2014 call my_abort('Error writing NetCDF file') 1766 2015 end if 2016 if (present(dim4_name) .and. ndims_input >= 4) then 2017 ! Variable is at least three dimensional 2018 ndims_local = 4 2019 istatus = nf90_inq_dimid(this%ncid, dim4_name, idimids(4)) 2020 if (istatus /= NF90_NOERR) then 2021 write(nulerr,'(a,a,a,a)') '*** Error inquiring ID of dimension ', & 2022 & dim4_name, ': ', trim(nf90_strerror(istatus)) 2023 call my_abort('Error writing NetCDF file') 2024 end if 2025 end if 1767 2026 end if 1768 2027 end if 1769 2028 else 1770 2029 ! Variable is a scalar 1771 ndims = 02030 ndims_local = 0 1772 2031 end if 1773 2032 1774 2033 ! Read output precision from optional argument "is_double" if 1775 2034 ! present, otherwise from default output precision for this file 1776 data_type = NF90_FLOAT ! Default1777 2035 if (present(data_type_name)) then 1778 2036 if (data_type_name == 'double') then … … 1787 2045 data_type = NF90_FLOAT 1788 2046 else 1789 write(nulerr,'(a,a,a)') '*** Error: netCDF data type "', data_type_name, '" not supported'2047 write(nulerr,'(a,a,a)') '*** NetCDF data type "', data_type_name, '" not supported' 1790 2048 call my_abort('Error writing NetCDF file') 1791 2049 end if 1792 2050 else if (present(is_double)) then 2051 if (is_double) then 2052 data_type = NF90_DOUBLE 2053 else 2054 data_type = NF90_FLOAT 2055 end if 2056 else if (this%is_double_precision) then 1793 2057 data_type = NF90_DOUBLE 2058 else 2059 data_type = NF90_FLOAT 1794 2060 end if 1795 2061 1796 2062 ! Define variable 1797 2063 #ifdef NC_NETCDF4 1798 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids(1:ndims ), &2064 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids(1:ndims_local), & 1799 2065 & ivarid, deflate_level=deflate_level, shuffle=shuffle, chunksizes=chunksizes) 1800 2066 #else 1801 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids(1:ndims ), ivarid)2067 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids(1:ndims_local), ivarid) 1802 2068 #endif 1803 2069 if (istatus /= NF90_NOERR) then … … 1811 2077 istatus = nf90_put_att(this%ncid, ivarid, "long_name", long_name) 1812 2078 if (this%iverbose >= 4) then 1813 write(nulout,'(a,a,a,a)') ' Defining ',trim(var_name),': ',long_name 2079 write(nulout,'(a,a,a,a,a)', advance='no') ' Defining ',trim(var_name), & 2080 & ': "', long_name, '"' 1814 2081 end if 1815 2082 else 1816 2083 if (this%iverbose >= 4) then 1817 write(nulout,'(a,a)') ' Defining ',trim(var_name) 1818 end if 1819 end if 2084 write(nulout,'(a,a)', advance='no') ' Defining ',trim(var_name) 2085 end if 2086 end if 2087 1820 2088 if (present(units_str)) then 1821 2089 istatus = nf90_put_att(this%ncid, ivarid, "units", units_str) 1822 end if 2090 if (this%iverbose >= 4) then 2091 if (trim(units_str) == '1') then 2092 write(nulout, '(a)') ' (dimensionless)' 2093 else 2094 write(nulout, '(a,a,a)') ' (', trim(units_str), ')' 2095 end if 2096 end if 2097 else 2098 if (this%iverbose >= 4) then 2099 write(nulout, '(1x)') 2100 end if 2101 end if 2102 1823 2103 if (present(standard_name)) then 1824 2104 istatus = nf90_put_att(this%ncid, ivarid, "standard_name", standard_name) … … 1863 2143 subroutine put_global_attributes(this, title_str, inst_str, source_str, & 1864 2144 & comment_str, references_str, creator_name, creator_email_str, & 1865 & contributor_name, project_str, conventions_str )2145 & contributor_name, project_str, conventions_str, prior_history_str) 1866 2146 class(netcdf_file) :: this 1867 2147 … … 1872 2152 character(len=*), intent(in), optional :: contributor_name, project_str 1873 2153 character(len=*), intent(in), optional :: comment_str, conventions_str 1874 character(len=*), intent(in), optional :: references_str 2154 character(len=*), intent(in), optional :: references_str, prior_history_str 1875 2155 1876 2156 character(len=32) :: date_time_str … … 1887 2167 & time_vals(1), time_vals(2), time_vals(3), time_vals(5), time_vals(6), time_vals(7) 1888 2168 1889 history_str = trim(date_time_str) // ': ' // trim(command_line_str) 2169 if (present(prior_history_str)) then 2170 history_str = trim(prior_history_str) // new_line('a') & 2171 & // trim(date_time_str) // ': ' // trim(command_line_str) 2172 else 2173 history_str = trim(date_time_str) // ': ' // trim(command_line_str) 2174 end if 1890 2175 1891 2176 if (present(title_str)) i=nf90_put_att(this%ncid, NF90_GLOBAL, "title", title_str) … … 2057 2342 2058 2343 !--------------------------------------------------------------------- 2344 ! Save an integer vector with name var_name in the file 2345 subroutine put_int_vector(this, var_name, var) 2346 class(netcdf_file) :: this 2347 character(len=*), intent(in) :: var_name 2348 integer, intent(in) :: var(:) 2349 2350 integer :: ivarid, ndims, istatus 2351 integer(kind=jpib) :: ntotal 2352 integer :: ndimlens(NF90_MAX_VAR_DIMS) 2353 2354 call this%end_define_mode() 2355 2356 ! Check the vector is of the right length 2357 call this%get_variable_id(var_name, ivarid) 2358 call this%get_array_dimensions(ivarid, ndims, ndimlens, ntotal) 2359 if (ntotal /= size(var,kind=jpib)) then 2360 write(nulerr,'(a,i0,a,a,a,i0)') '*** Error: attempt to write vector of length ', & 2361 & size(var), ' to ', var_name, ' which has total length ', ntotal 2362 call my_abort('Error writing NetCDF file') 2363 end if 2364 2365 ! Save the vector 2366 istatus = nf90_put_var(this%ncid, ivarid, var) 2367 if (istatus /= NF90_NOERR) then 2368 write(nulerr,'(a,a,a,a)') '*** Error writing vector ', var_name, ': ', & 2369 & trim(nf90_strerror(istatus)) 2370 call my_abort('Error writing NetCDF file') 2371 end if 2372 2373 end subroutine put_int_vector 2374 2375 2376 !--------------------------------------------------------------------- 2059 2377 ! Save a vector slice with name var_name in the file 2060 subroutine put_real_vector_indexed(this, var_name, index, var)2378 subroutine put_real_vector_indexed(this, var_name, var, index2, index3) 2061 2379 class(netcdf_file) :: this 2062 2380 character(len=*), intent(in) :: var_name 2063 2381 real(jprb), intent(in) :: var(:) 2064 integer, intent(in) :: index 2382 integer, intent(in) :: index2 2383 integer, intent(in), optional :: index3 2065 2384 2066 2385 integer :: ivarid, ndims, istatus … … 2070 2389 integer :: vcount(NF90_MAX_VAR_DIMS) 2071 2390 2391 character(len=512) :: var_slice_name 2392 integer :: index_last 2393 2072 2394 call this%end_define_mode() 2073 2395 … … 2076 2398 call this%get_array_dimensions(ivarid, ndims, ndimlens, ntotal) 2077 2399 ntotal = ntotal / ndimlens(ndims) 2400 if (present(index3)) then 2401 ntotal = ntotal / ndimlens(ndims-1) 2402 index_last = index3 2403 write(var_slice_name,'(a,a,i0,a,i0,a)') var_name, '(:,', index2, ',', index3, ')' 2404 else 2405 index_last = index2 2406 write(var_slice_name,'(a,a,i0,a)') var_name, '(:,', index2, ')' 2407 end if 2408 2078 2409 if (ntotal /= size(var,kind=jpib)) then 2079 write(nulerr,'(a,i0,a,a, a,i0)') '*** Error: attempt to write vector of length ', &2080 & size(var), ' to slice of ', var_name, ' which has length ', ntotal2410 write(nulerr,'(a,i0,a,a,i0)') '*** Error: attempt to write vector of length ', & 2411 & size(var), ' to ', trim(var_slice_name), ' which has length ', ntotal 2081 2412 call my_abort('Error writing NetCDF file') 2082 2413 end if 2083 if (index < 1 .or. index> ndimlens(ndims)) then2084 write(nulerr,'(a, i0,a,a,a,i0)') '*** Error: attempt to write vector to slice', &2085 & index, ' of ', var_name, ' which has outer dimension ', ndimlens(ndims)2414 if (index_last < 1 .or. index_last > ndimlens(ndims)) then 2415 write(nulerr,'(a,a,a,i0)') '*** Error: attempt to write vector to ', & 2416 & trim(var_slice_name), ' which has outer dimension ', ndimlens(ndims) 2086 2417 call my_abort('Error writing NetCDF file') 2087 2418 end if … … 2089 2420 ! Save the vector 2090 2421 vstart(1:ndims-1) = 1 2091 vstart(ndims) = index2092 2422 vcount(1:ndims-1) = ndimlens(1:ndims-1) 2093 2423 vcount(ndims) = 1 2424 if (present(index3)) then 2425 vstart(ndims) = index3 2426 vstart(ndims-1) = index2 2427 vcount(ndims-1) = 1 2428 else 2429 vstart(ndims) = index2 2430 end if 2431 2094 2432 istatus = nf90_put_var(this%ncid, ivarid, var, start=vstart, count=vcount) 2095 2433 if (istatus /= NF90_NOERR) then 2096 write(nulerr,'(a,a,a,a)') '*** Error writing vector to ', var_name, ': ', &2097 & 2434 write(nulerr,'(a,a,a,a)') '*** Error writing vector to ', trim(var_slice_name), & 2435 & ': ', trim(nf90_strerror(istatus)) 2098 2436 call my_abort('Error writing NetCDF file') 2099 2437 end if … … 2171 2509 ! dimensions if either optional argument transp is .true., or the 2172 2510 ! transpose_matrices method has already been called. 2173 subroutine put_real_matrix_indexed(this, var_name, index, var, do_transp)2511 subroutine put_real_matrix_indexed(this, var_name, var, index3, index4, do_transp) 2174 2512 class(netcdf_file) :: this 2175 2513 character(len=*), intent(in) :: var_name 2176 2514 real(jprb), intent(in) :: var(:,:) 2177 integer, intent(in) :: index 2515 integer, intent(in) :: index3 2516 integer, intent(in), optional :: index4 2178 2517 2179 2518 real(jprb), allocatable :: var_transpose(:,:) 2180 logical, optional, intent(in) :: do_transp2519 logical, optional, intent(in) :: do_transp 2181 2520 2182 2521 integer :: ivarid, ndims, nvarlen, istatus … … 2186 2525 integer :: vcount(NF90_MAX_VAR_DIMS) 2187 2526 2527 character(len=512) :: var_slice_name 2528 2188 2529 logical :: do_transpose 2189 2530 … … 2204 2545 ! ntotal is zero then there must be an unlimited dimension) 2205 2546 ntotal = ntotal / ndimlens(ndims) 2547 if (present(index4)) then 2548 ntotal = ntotal / ndimlens(ndims-1) 2549 write(var_slice_name,'(a,a,i0,a,i0,a)') var_name, '(:,:,', index3, ',', index4, ')' 2550 else 2551 write(var_slice_name,'(a,a,i0,a)') var_name, '(:,:,', index3, ')' 2552 end if 2206 2553 if (ntotal /= size(var,kind=jpib) .and. ntotal /= 0) then 2207 2554 write(nulerr,'(a,i0,a,a,a,i0)') '*** Error: attempt to write matrix of total size ', & 2208 & nvarlen, ' to ', var_name, ' which has total size ', ntotal2555 & nvarlen, ' to ', trim(var_slice_name), ' which has total size ', ntotal 2209 2556 call my_abort('Error writing NetCDF file') 2210 2557 end if 2211 2558 2212 2559 vstart(1:ndims-1) = 1 2213 vstart(ndims) = index2214 2560 vcount(1:ndims-1) = ndimlens(1:ndims-1) 2215 2561 vcount(ndims) = 1 2562 if (present(index4)) then 2563 vstart(ndims) = index4 2564 vstart(ndims-1) = index3 2565 vcount(ndims-1) = 1 2566 else 2567 vstart(ndims) = index3 2568 end if 2216 2569 2217 2570 if (do_transpose) then 2218 2571 ! Save the matrix with transposition 2219 2572 if (this%iverbose >= 3) then 2220 write(nulout,'(a, i0,a,a,a)') ' Writing slice ', index, ' of ', var_name, &2573 write(nulout,'(a,a,a)') ' Writing ', trim(var_slice_name), & 2221 2574 & ' (transposing dimensions)' 2222 2575 end if … … 2228 2581 ! Save the matrix without transposition 2229 2582 if (this%iverbose >= 3) then 2230 write(nulout,'(a, i0,a,a)') ' Writing slice ', index, ' of ', var_name2583 write(nulout,'(a,a)') ' Writing ', trim(var_slice_name) 2231 2584 end if 2232 2585 istatus = nf90_put_var(this%ncid, ivarid, var, start=vstart, count=vcount) … … 2234 2587 2235 2588 if (istatus /= NF90_NOERR) then 2236 write(nulerr,'(a,a,a ,a)') '*** Error writing matrix ', var_name, &2589 write(nulerr,'(a,a,a)') '*** Error writing ', trim(var_slice_name), & 2237 2590 & ': ', trim(nf90_strerror(istatus)) 2238 2591 call my_abort('Error writing NetCDF file') … … 2291 2644 if (this%iverbose >= 3) then 2292 2645 write(nulout,'(a,a,a,i0,i0,i0,a)') ' Writing ', var_name, & 2293 & ' (permut eddimensions: ', i_permute_3d, ')'2646 & ' (permuting dimensions: ', i_permute_3d, ')' 2294 2647 end if 2295 2648 n_dimlens_permuted = (/ size(var,i_permute_3d(1)), & 2296 2649 & size(var,i_permute_3d(2)), & 2297 2650 & size(var,i_permute_3d(3)) /) 2298 if (this%iverbose >= 4) then 2299 write(nulout,'(a,i0,a,i0,a,i0,a,i0,a,i0,a,i0,a)') ' (', & 2300 & n_dimlens_permuted(1), ',', n_dimlens_permuted(2), & 2301 & ',', n_dimlens_permuted(3), ') -> (', ndimlens(1), & 2302 & ',', ndimlens(2), ',', ndimlens(3), ')' 2303 end if 2651 !! FIX: This makes it look like the dimensions have stayed the same 2652 ! if (this%iverbose >= 4) then 2653 ! write(nulout,'(a,i0,a,i0,a,i0,a,i0,a,i0,a,i0,a)') ' (', & 2654 ! & n_dimlens_permuted(1), ',', n_dimlens_permuted(2), & 2655 ! & ',', n_dimlens_permuted(3), ') -> (', ndimlens(1), & 2656 ! & ',', ndimlens(2), ',', ndimlens(3), ')' 2657 ! end if 2304 2658 allocate(var_permute(n_dimlens_permuted(1), & 2305 2659 & n_dimlens_permuted(2), n_dimlens_permuted(3))) … … 2326 2680 end subroutine put_real_array3 2327 2681 2682 2683 #ifdef NC_NETCDF4 2684 !--------------------------------------------------------------------- 2685 ! Copy dimensions from "infile" to "this" 2686 subroutine copy_dimensions(this, infile) 2687 class(netcdf_file) :: this 2688 type(netcdf_file), intent(in) :: infile 2689 2690 integer :: jdim 2691 integer :: ndims 2692 integer :: idimids(1024) 2693 integer :: dimlen 2694 character(len=512) :: dimname 2695 integer :: istatus 2696 integer :: include_parents 2697 2698 include_parents = 0 2699 2700 istatus = nf90_inq_dimids(infile%ncid, ndims, idimids, include_parents) 2701 if (istatus /= NF90_NOERR) then 2702 write(nulerr,'(a,a)') '*** Error reading dimensions of NetCDF file: ', & 2703 trim(nf90_strerror(istatus)) 2704 call my_abort('Error reading NetCDF file') 2705 end if 2706 2707 do jdim = 1,ndims 2708 istatus = nf90_inquire_dimension(infile%ncid, idimids(jdim), & 2709 & name=dimname, len=dimlen) 2710 if (istatus /= NF90_NOERR) then 2711 write(nulerr,'(a,a)') '*** Error reading NetCDF dimension properties: ', & 2712 trim(nf90_strerror(istatus)) 2713 call my_abort('Error reading NetCDF file') 2714 end if 2715 call this%define_dimension(trim(dimname), dimlen) 2716 end do 2717 2718 end subroutine copy_dimensions 2719 #endif 2720 2721 !--------------------------------------------------------------------- 2722 ! Copy variable definition and attributes from "infile" to "this" 2723 subroutine copy_variable_definition(this, infile, var_name) 2724 class(netcdf_file) :: this 2725 type(netcdf_file), intent(in) :: infile 2726 character(len=*), intent(in) :: var_name 2727 2728 #ifdef NC_NETCDF4 2729 integer :: deflate_level ! Compression: 0 (none) to 9 (most) 2730 logical :: shuffle ! Shuffle bytes before compression 2731 integer :: chunksizes(NF90_MAX_VAR_DIMS) 2732 #endif 2733 integer :: data_type 2734 integer :: ndims 2735 integer :: idimids_in(NF90_MAX_VAR_DIMS) 2736 integer :: idimids_out(NF90_MAX_VAR_DIMS) 2737 integer :: nattr 2738 character(len=512) :: attr_name 2739 character(len=512) :: dim_name 2740 2741 integer :: istatus 2742 integer :: ivarid_in, ivarid_out 2743 integer :: jattr, jdim 2744 2745 if (this%iverbose >= 4) then 2746 write(nulout,'(a,a)') ' Copying definition of ', trim(var_name) 2747 end if 2748 2749 ! Get variable ID from name 2750 istatus = nf90_inq_varid(infile%ncid, var_name, ivarid_in) 2751 if (istatus /= NF90_NOERR) then 2752 write(nulerr,'(a,i0,a)') '*** Error inquiring about NetCDF variable "', & 2753 & var_name, '": ', trim(nf90_strerror(istatus)) 2754 call my_abort('Error reading NetCDF file') 2755 end if 2756 2757 ! Get variable properties 2758 #ifdef NC_NETCDF4 2759 istatus = nf90_inquire_variable(infile%ncid, ivarid_in, xtype=data_type, ndims=ndims, & 2760 & dimids=idimids_in, chunksizes=chunksizes, deflate_level=deflate_level, & 2761 & shuffle=shuffle, natts=nattr) 2762 #else 2763 istatus = nf90_inquire_variable(infile%ncid, ivarid_in, xtype=data_type, ndims=ndims, & 2764 & dimids=idimids_in, natts=nattr) 2765 #endif 2766 if (istatus /= NF90_NOERR) then 2767 write(nulerr,'(a,a)') '*** Error reading NetCDF variable properties: ', & 2768 trim(nf90_strerror(istatus)) 2769 call my_abort('Error reading NetCDF file') 2770 end if 2771 2772 ! Map dimension IDs 2773 do jdim = 1,ndims 2774 istatus = nf90_inquire_dimension(infile%ncid, idimids_in(jdim), name=dim_name) 2775 if (istatus /= NF90_NOERR) then 2776 write(nulerr,'(a,a)') '*** Error reading NetCDF dimension name: ', & 2777 trim(nf90_strerror(istatus)) 2778 call my_abort('Error reading NetCDF file') 2779 end if 2780 2781 istatus = nf90_inq_dimid(this%ncid, trim(dim_name), idimids_out(jdim)) 2782 if (istatus /= NF90_NOERR) then 2783 write(nulerr,'(a,a)') '*** Error reading NetCDF dimension ID: ', & 2784 trim(nf90_strerror(istatus)) 2785 call my_abort('Error reading NetCDF file') 2786 end if 2787 end do 2788 2789 ! Create variable 2790 #ifdef NC_NETCDF4 2791 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids_out(1:ndims), & 2792 & ivarid_out, deflate_level=deflate_level, shuffle=shuffle, chunksizes=chunksizes(1:ndims)) 2793 #else 2794 istatus = nf90_def_var(this%ncid, var_name, data_type, idimids_out(1:ndims), ivarid_out) 2795 #endif 2796 if (istatus /= NF90_NOERR) then 2797 write(nulerr,'(a,a,a,a)') '*** Error defining variable "', var_name, & 2798 & '": ', trim(nf90_strerror(istatus)) 2799 call my_abort('Error writing NetCDF file') 2800 end if 2801 2802 ! Copy attributes 2803 do jattr = 1,nattr 2804 istatus = nf90_inq_attname(infile%ncid, ivarid_in, jattr, attr_name) 2805 if (istatus /= NF90_NOERR) then 2806 write(nulerr,'(a,a)') '*** Error reading attribute: ', & 2807 & trim(nf90_strerror(istatus)) 2808 call my_abort('Error reading NetCDF file') 2809 end if 2810 istatus = nf90_copy_att(infile%ncid, ivarid_in, trim(attr_name), & 2811 & this%ncid, ivarid_out) 2812 2813 end do 2814 2815 end subroutine copy_variable_definition 2816 2817 2818 !--------------------------------------------------------------------- 2819 ! Copy variable from "infile" to "this" 2820 subroutine copy_variable(this, infile, var_name) 2821 class(netcdf_file) :: this 2822 class(netcdf_file), intent(in) :: infile 2823 character(len=*), intent(in) :: var_name 2824 2825 integer :: ivarid_in, ivarid_out 2826 integer :: ndims 2827 integer :: ndimlens(NF90_MAX_VAR_DIMS) 2828 integer(kind=jpib) :: ntotal 2829 integer :: data_type 2830 integer :: istatus 2831 2832 ! We use the Fortran-77 functions because they don't check that 2833 ! the rank of the arguments is correct 2834 integer, external :: nf_get_var_double, nf_put_var_double 2835 integer, external :: nf_get_var_int, nf_put_var_int 2836 2837 real(kind=jprd), allocatable :: data_real(:) 2838 integer, allocatable :: data_int(:) 2839 2840 ! If we are in define mode, exit define mode 2841 call this%end_define_mode() 2842 2843 if (this%iverbose >= 4) then 2844 write(nulout,'(a,a)') ' Copying ', trim(var_name) 2845 end if 2846 2847 call infile%get_variable_id(var_name, ivarid_in) 2848 call infile%get_array_dimensions(ivarid_in, ndims, ndimlens, ntotal) 2849 istatus = nf90_inquire_variable(infile%ncid, ivarid_in, xtype=data_type) 2850 if (istatus /= NF90_NOERR) then 2851 write(nulerr,'(a,a,a,a)') '*** Error reading variable "', var_name, '": ', & 2852 & trim(nf90_strerror(istatus)) 2853 call my_abort('Error reading NetCDF file') 2854 end if 2855 2856 call infile%get_variable_id(var_name, ivarid_out) 2857 if (data_type == NF90_DOUBLE .or. data_type == NF90_FLOAT) then 2858 allocate(data_real(ntotal)) 2859 !istatus = nf90_get_var(infile%ncid, ivarid_in, data_real(1)) 2860 istatus = nf_get_var_double(infile%ncid, ivarid_in, data_real) 2861 if (istatus /= NF90_NOERR) then 2862 deallocate(data_real) 2863 write(nulerr,'(a,a,a,a)') '*** Error reading variable "', var_name, '": ', & 2864 & trim(nf90_strerror(istatus)) 2865 call my_abort('Error reading NetCDF file') 2866 end if 2867 2868 !istatus = nf90_put_var(this%ncid, ivarid_out, data_real) 2869 istatus = nf_put_var_double(this%ncid, ivarid_out, data_real) 2870 deallocate(data_real) 2871 if (istatus /= NF90_NOERR) then 2872 write(nulerr,'(a,a,a,a)') '*** Error writing variable "', var_name, '": ', & 2873 & trim(nf90_strerror(istatus)) 2874 call my_abort('Error writing NetCDF file') 2875 end if 2876 2877 else 2878 allocate(data_int(ntotal)) 2879 !istatus = nf90_get_var(infile%ncid, ivarid_in, data_int) 2880 istatus = nf_get_var_int(infile%ncid, ivarid_in, data_int) 2881 if (istatus /= NF90_NOERR) then 2882 deallocate(data_int) 2883 2884 write(nulerr,'(a,a,a,a)') '*** Error reading variable "', var_name, '": ', & 2885 & trim(nf90_strerror(istatus)) 2886 call my_abort('Error reading NetCDF file') 2887 end if 2888 2889 !istatus = nf90_put_var(this%ncid, ivarid_out, data_int) 2890 istatus = nf_put_var_int(this%ncid, ivarid_out, data_int) 2891 deallocate(data_int) 2892 if (istatus /= NF90_NOERR) then 2893 write(nulerr,'(a,a,a,a)') '*** Error writing variable "', var_name, '": ', & 2894 & trim(nf90_strerror(istatus)) 2895 call my_abort('Error writing NetCDF file') 2896 end if 2897 end if 2898 2899 end subroutine copy_variable 2900 2328 2901 end module easy_netcdf
Note: See TracChangeset
for help on using the changeset viewer.