5.13.3-dev0
mHM
The mesoscale Hydrological Model
Loading...
Searching...
No Matches
mo_read_spatial_data.f90
Go to the documentation of this file.
1!> \file mo_read_spatial_data.f90
2!> \brief \copybrief mo_read_spatial_data
3!> \details \copydetails mo_read_spatial_data
4
5!> \brief Reads spatial input data.
6!> \details This module is to read spatial input data, e.g. dem, aspect, flow direction.
7!! The module provides a subroutine for ASCII files.
8!! (Subroutine for NetCDF files will come with release 5.1).
9!! The data are read from the specified directory.
10!> \authors Juliane Mai
11!> \date Dec 2012
12!> \copyright Copyright 2005-\today, the mHM Developers, Luis Samaniego, Sabine Attinger: All rights reserved.
13!! mHM is released under the LGPLv3+ license \license_note
14!> \ingroup f_common
16
17 ! This module provides routines to read spatial data.
18
19 ! Written Juliane Mai, Jan 2013
20 ! Modified
21
22 USE mo_kind, ONLY : i4, dp
23 USE mo_os, ONLY : check_path_isfile
24 USE mo_message, only: error_message
25 use mo_string_utils, only : num2str
26
27 IMPLICIT NONE
29 PUBLIC :: read_header_ascii ! Reads header of ASCII files
30 PUBLIC :: read_spatial_data_nc_or_ascii ! Reads netcdf and ASCII files
31 PUBLIC :: read_spatial_data_nc ! Reads netcdf files
32 PUBLIC :: read_spatial_data_ascii ! Reads ASCII files
33
34
35 ! ------------------------------------------------------------------
36
37 ! NAME
38 ! read_spatial_data_nc_or_ascii
39
40 ! PURPOSE
41 !> \brief Reads spatial data files of nc or ASCII format.
42
43 !> \details Reads spatial input data, e.g. dem, aspect, flow direction.
44
45 ! HISTORY
46 !> \authors Simon Lüdke
47
48 !> \date June 2025
49
53
54 ! ------------------------------------------------------------------
55
56 ! NAME
57 ! read_spatial_data_nc
58
59 ! PURPOSE
60 !> \brief Reads spatial data files of nc format.
61
62 !> \details Reads spatial input data, e.g. dem, aspect, flow direction.
63
64 ! HISTORY
65 !> \authors Simon Lüdke
66
67 !> \date June 2025
68
71 END INTERFACE read_spatial_data_nc
72
73 ! ------------------------------------------------------------------
74
75 ! NAME
76 ! read_spatial_data_ascii
77
78 ! PURPOSE
79 !> \brief Reads spatial data files of ASCII format.
80
81 !> \details Reads spatial input data, e.g. dem, aspect, flow direction.
82
83 ! HISTORY
84 !> \authors Juliane Mai
85
86 !> \date Jan 2013
87
88 ! Modifications:
89 ! Matthias Zink Feb 2013 - , added interface and routine for datatype i4
90 ! David Schaefer Mar 2015 - , removed double allocation of temporary data
91 ! Robert Schweppe Jun 2018 - refactoring and reformatting
92
95 END INTERFACE read_spatial_data_ascii
96
97 public :: check_header
98
99
100
101 ! ------------------------------------------------------------------
102
103 PRIVATE
104
105 ! ------------------------------------------------------------------
106
107CONTAINS
108
109 ! ------------------------------------------------------------------
110
111 ! NAME
112 ! read_spatial_data_ascii_dp
113
114 ! PURPOSE
115 !> \brief TODO: add description
116
117 !> \details TODO: add description
118
119 ! INTENT(IN)
120 !> \param[in] "character(len = *) :: filename" filename with location
121 !> \param[in] "integer(i4) :: fileunit" unit for opening the file
122 !> \param[in] "integer(i4) :: header_nCols" number of columns of data fields:
123 !> \param[in] "integer(i4) :: header_nRows" number of rows of data fields:
124 !> \param[in] "real(dp) :: header_xllcorner" header read in lower left corner
125 !> \param[in] "real(dp) :: header_yllcorner" header read in lower left corner
126 !> \param[in] "real(dp) :: header_cellsize" header read in cellsize
127
128 ! INTENT(OUT)
129 !> \param[out] "real(dp), dimension(:, :) :: data" data
130 !> \param[out] "logical, dimension(:, :) :: mask" mask
131
132 ! HISTORY
133 !> \authors Robert Schweppe
134
135 !> \date Jun 2018
136
137 ! Modifications:
138
139 subroutine read_spatial_data_ascii_dp(filename, fileunit, header_ncols, header_nrows, header_xllcorner, &
140 header_yllcorner, header_cellsize, data, mask)
141 implicit none
142
143 ! filename with location
144 character(len = *), intent(in) :: filename
145
146 ! unit for opening the file
147 integer(i4), intent(in) :: fileunit
148
149 ! number of rows of data fields:
150 integer(i4), intent(in) :: header_nRows
151
152 ! number of columns of data fields:
153 integer(i4), intent(in) :: header_nCols
154
155 ! header read in lower left corner
156 real(dp), intent(in) :: header_xllcorner
157
158 ! header read in lower left corner
159 real(dp), intent(in) :: header_yllcorner
160
161 ! header read in cellsize
162 real(dp), intent(in) :: header_cellsize
163
164 ! data
165 real(dp), dimension(:, :), allocatable, intent(out) :: data
166
167 ! mask
168 logical, dimension(:, :), allocatable, intent(out) :: mask
169
170 ! number of rows of data fields:
171 integer(i4) :: file_nRows
172
173 ! number of columns of data fields:
174 integer(i4) :: file_nCols
175
176 ! file read in lower left corner
177 real(dp) :: file_xllcorner
178
179 ! file read in lower left corner
180 real(dp) :: file_yllcorner
181
182 ! file read in cellsize
183 real(dp) :: file_cellsize
184
185 ! file read in nodata value
186 real(dp) :: file_nodata
187
188 integer(i4) :: i, j
189
190 ! data
191 real(dp), dimension(:, :), allocatable :: tmp_data
192
193 ! mask
194 logical, dimension(:, :), allocatable :: tmp_mask
195
196 call read_header_ascii(filename, fileunit, &
197 file_ncols, file_nrows, &
198 file_xllcorner, file_yllcorner, file_cellsize, file_nodata)
199 call check_header(file_ncols, file_nrows, file_xllcorner, file_yllcorner, file_cellsize, &
200 header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize)
201 ! allocation and initialization of matrices
202 allocate(tmp_data(file_nrows, file_ncols))
203 tmp_data = file_nodata
204 allocate(tmp_mask(file_nrows, file_ncols))
205 tmp_mask = .true.
206
207
208 !checking whether the file exists
209 call check_path_isfile(path = filename, raise=.true.)
210 ! read in
211 ! recl is only a rough estimate on bytes per line in the ascii
212 ! default for nag: recl=1024(byte) which is not enough for 100s of columns
213 open (unit = fileunit, file = filename, action = 'read', status = 'old', recl = 48 * file_ncols)
214 ! (a) skip header
215 do i = 1, 6
216 read(fileunit, *)
217 end do
218 ! (b) read data
219 do i = 1, file_nrows
220 read(fileunit, *) (tmp_data(i, j), j = 1, file_ncols)
221 end do
222 close(fileunit)
223
224 ! set mask .false. if nodata value appeared
225 where (abs(tmp_data - file_nodata) .lt. tiny(1.0_dp))
226 tmp_mask = .false.
227 end where
228
229 ! transpose of data due to longitude-latitude ordering
230 allocate(data(file_ncols, file_nrows))
231 data = transpose(tmp_data)
232 deallocate(tmp_data)
233
234 allocate(mask(file_ncols, file_nrows))
235 mask = transpose(tmp_mask)
236 deallocate(tmp_mask)
237
238 end subroutine read_spatial_data_ascii_dp
239
240 ! NAME
241 ! read_spatial_data_ascii_i4
242
243 ! PURPOSE
244 !> \brief TODO: add description
245
246 !> \details TODO: add description
247
248 ! INTENT(IN)
249 !> \param[in] "character(len = *) :: filename" filename with location
250 !> \param[in] "integer(i4) :: fileunit" unit for opening the file
251 !> \param[in] "integer(i4) :: header_nCols" number of columns of data fields:
252 !> \param[in] "integer(i4) :: header_nRows" number of rows of data fields:
253 !> \param[in] "real(dp) :: header_xllcorner" header read in lower left corner
254 !> \param[in] "real(dp) :: header_yllcorner" header read in lower left corner
255 !> \param[in] "real(dp) :: header_cellsize" header read in cellsize
256
257 ! INTENT(OUT)
258 !> \param[out] "integer(i4), dimension(:, :) :: data" data
259 !> \param[out] "logical, dimension(:, :) :: mask" mask
260
261 ! HISTORY
262 !> \authors Robert Schweppe
263
264 !> \date Jun 2018
265
266 ! Modifications:
267
268 subroutine read_spatial_data_ascii_i4(filename, fileunit, header_ncols, header_nrows, header_xllcorner, &
269 header_yllcorner, header_cellsize, data, mask)
270 implicit none
271
272 ! filename with location
273 character(len = *), intent(in) :: filename
274
275 ! unit for opening the file
276 integer(i4), intent(in) :: fileunit
277
278 ! number of rows of data fields:
279 integer(i4), intent(in) :: header_nRows
280
281 ! number of columns of data fields:
282 integer(i4), intent(in) :: header_nCols
283
284 ! header read in lower left corner
285 real(dp), intent(in) :: header_xllcorner
286
287 ! header read in lower left corner
288 real(dp), intent(in) :: header_yllcorner
289
290 ! header read in cellsize
291 real(dp), intent(in) :: header_cellsize
292
293 ! data
294 integer(i4), dimension(:, :), allocatable, intent(out) :: data
295
296 ! mask
297 logical, dimension(:, :), allocatable, intent(out) :: mask
298
299 ! number of rows of data fields:
300 integer(i4) :: file_nRows
301
302 ! number of columns of data fields:
303 integer(i4) :: file_nCols
304
305 ! file read in lower left corner
306 real(dp) :: file_xllcorner
307
308 ! file read in lower left corner
309 real(dp) :: file_yllcorner
310
311 ! file read in cellsize
312 real(dp) :: file_cellsize
313
314 ! file read in nodata value
315 real(dp) :: file_nodata
316
317 integer(i4) :: i, j
318
319 ! data
320 integer(i4), dimension(:, :), allocatable :: tmp_data
321
322 ! mask
323 logical, dimension(:, :), allocatable :: tmp_mask
324
325 call read_header_ascii(filename, fileunit, &
326 file_ncols, file_nrows, &
327 file_xllcorner, file_yllcorner, file_cellsize, file_nodata)
328 call check_header(file_ncols, file_nrows, file_xllcorner, file_yllcorner, file_cellsize, &
329 header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize)
330 ! allocation and initialization of matrices
331 allocate(tmp_data(file_nrows, file_ncols))
332 tmp_data = int(file_nodata, i4)
333 allocate(tmp_mask(file_nrows, file_ncols))
334 tmp_mask = .true.
335
336 !checking whether the file exists
337 call check_path_isfile(path = filename, raise=.true.)
338 ! read in
339 ! recl is only a rough estimate on bytes per line in the ascii
340 ! default for nag: recl=1024(byte) which is not enough for 100s of columns
341 open (unit = fileunit, file = filename, action = 'read', status = 'old', recl = 48 * file_ncols)
342 ! (a) skip header
343 do i = 1, 6
344 read(fileunit, *)
345 end do
346 ! (b) read data
347 do i = 1, file_nrows
348 read(fileunit, *) (tmp_data(i, j), j = 1, file_ncols)
349 end do
350 close(fileunit)
351
352 ! set mask .false. if nodata value appeared
353 where (tmp_data .EQ. int(file_nodata, i4))
354 tmp_mask = .false.
355 end where
356
357 ! transpose of data due to longitude-latitude ordering
358 allocate(data(file_ncols, file_nrows))
359 data = transpose(tmp_data)
360 deallocate(tmp_data)
361
362 allocate(mask(file_ncols, file_nrows))
363 mask = transpose(tmp_mask)
364 deallocate(tmp_mask)
365
366 end subroutine read_spatial_data_ascii_i4
367
368 ! ------------------------------------------------------------------
369
370 ! NAME
371 ! read_header_ascii
372
373 ! PURPOSE
374 !> \brief Reads header lines of ASCII files.
375
376 !> \details Reads header lines of ASCII files, e.g. dem, aspect, flow direction.
377
378 ! INTENT(IN)
379 !> \param[in] "character(len = *) :: filename" Name of file and its location
380 !> \param[in] "integer(i4) :: fileunit" File unit for open file
381
382 ! INTENT(OUT)
383 !> \param[out] "integer(i4) :: header_nCols" Reference number of columns
384 !> \param[out] "integer(i4) :: header_nRows" Reference number of rows
385 !> \param[out] "real(dp) :: header_xllcorner" Reference lower left corner (x)
386 !> \param[out] "real(dp) :: header_yllcorner" Reference lower left corner (y)
387 !> \param[out] "real(dp) :: header_cellsize" Reference cell size [m]
388 !> \param[out] "real(dp) :: header_nodata" Reference nodata value
389
390 ! HISTORY
391 !> \authors Juliane Mai
392
393 !> \date Jan 2013
394
395 ! Modifications:
396 ! Robert Schweppe Jun 2018 - refactoring and reformatting
397
398 subroutine read_header_ascii(filename, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, &
399 header_cellsize, header_nodata)
401 implicit none
402
403 ! Name of file and its location
404 character(len = *), intent(in) :: filename
405
406 ! File unit for open file
407 integer(i4), intent(in) :: fileunit
408
409 ! Reference number of rows
410 integer(i4), intent(out) :: header_nrows
411
412 ! Reference number of columns
413 integer(i4), intent(out) :: header_ncols
414
415 ! Reference lower left corner (x)
416 real(dp), intent(out) :: header_xllcorner
417
418 ! Reference lower left corner (y)
419 real(dp), intent(out) :: header_yllcorner
420
421 ! Reference cell size [m]
422 real(dp), intent(out) :: header_cellsize
423
424 ! Reference nodata value
425 real(dp), intent(out) :: header_nodata
426
427 character(5) :: dummy
428 integer(i4) :: io
429
430 !checking whether the file exists
431 call check_path_isfile(path = filename, raise=.true.)
432 ! reading header from a file
433 open (unit = fileunit, file = filename, status = 'old')
434 read (fileunit, *) dummy, header_ncols
435 read (fileunit, *) dummy, header_nrows
436 read (fileunit, *) dummy, header_xllcorner
437 read (fileunit, *) dummy, header_yllcorner
438 read (fileunit, *) dummy, header_cellsize
439 read (fileunit, *, iostat=io) dummy, header_nodata
440 ! EOF reached (nodata not present, use default value)
441 if (io < 0) header_nodata = nodata_dp
442 close(fileunit)
443 dummy = dummy // '' ! only to avoid warning
444
445 end subroutine read_header_ascii
446
447 subroutine check_header(ncols, nrows, xllcorner, yllcorner, &
448 cellsize, ref_ncols, ref_nrows, ref_xllcorner, ref_yllcorner, ref_cellsize, &
449 tolerance, context)
450
451 use mo_kind, only : dp, i4
452 use mo_message, only : error_message
453 use mo_string_utils, only : num2str
455
456 implicit none
457
458 integer(i4), intent(in) :: ncols
459 integer(i4), intent(in) :: nrows
460 real(dp), intent(in) :: xllcorner
461 real(dp), intent(in) :: yllcorner
462 real(dp), intent(in) :: cellsize
463 integer(i4), intent(in) :: ref_nrows
464 integer(i4), intent(in) :: ref_ncols
465 real(dp), intent(in) :: ref_xllcorner
466 real(dp), intent(in) :: ref_yllcorner
467 real(dp), intent(in) :: ref_cellsize
468 real(dp), intent(in), optional :: tolerance
469 character(*), intent(in), optional :: context
470
471 real(dp) :: tol_local
472 character(len=:), allocatable :: err_message
473
474 if (present(tolerance)) then
475 tol_local = tolerance
476 else
477 tol_local = defaulttolerance_dp
478 end if
479
480 err_message = ''
481 if ((ref_ncols .ne. ncols)) then
482 err_message = err_message // 'read_spatial_data_ascii: ncols mismatch file='// &
483 trim(num2str(ncols))//' expected='//trim(num2str(ref_ncols))// &
484 new_line('a')
485 end if
486 if ((nrows .ne. ref_nrows)) then
487 err_message = err_message // 'read_spatial_data_ascii: nrows mismatch file='// &
488 trim(num2str(nrows))//' expected='//trim(num2str(ref_nrows))// &
489 new_line('a')
490 end if
491 if ((abs(xllcorner - ref_xllcorner) .gt. tol_local)) then
492 err_message = err_message // 'read_spatial_data_ascii: xllcorner mismatch file='// &
493 trim(num2str(xllcorner, '(G32.16)'))//' expected='// &
494 trim(num2str(ref_xllcorner, '(G32.16)'))// &
495 new_line('a')
496 end if
497 if ((abs(yllcorner - ref_yllcorner) .gt. tol_local)) then
498 err_message = err_message // 'read_spatial_data_ascii: yllcorner mismatch file='// &
499 trim(num2str(yllcorner, '(G32.16)'))//' expected='// &
500 trim(num2str(ref_yllcorner, '(G32.16)'))// &
501 new_line('a')
502 end if
503 if ((abs(cellsize - ref_cellsize) .gt. tol_local)) then
504 err_message = err_message // 'read_spatial_data_ascii: cellsize mismatch file='// &
505 trim(num2str(cellsize, '(G32.16)'))//' expected='// &
506 trim(num2str(ref_cellsize, '(G32.16)'))// &
507 new_line('a')
508 end if
509
510 if (len_trim(err_message) > 0) then
511 if (present(context)) then
512 err_message = trim(context) // new_line('a') // err_message
513 end if
514 call error_message(trim(err_message))
515 end if
516
517 end subroutine check_header
518
519 !> \brief Read header information from either NetCDF or ASCII depending on file name/presence.
520 !> \authors Simon Lüdke
521 !> \date Feb 2025
522 subroutine read_header_nc_or_ascii(filepath, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, &
523 header_cellsize, header_nodata, varName)
524 use mo_os, only : path_root, path_isfile
525 implicit none
526 character(len=*), intent(in) :: filepath
527 integer(i4), intent(in) :: fileunit
528 integer(i4), intent(out) :: header_ncols, header_nrows
529 real(dp), intent(out) :: header_xllcorner, header_yllcorner, header_cellsize, header_nodata
530 character(len=*), intent(in), optional :: varname
531
532 character(len=:), allocatable :: ncname
533 character(len=:), allocatable :: trimmed
534 integer(i4) :: len_path
535 logical :: is_nc
536
537 trimmed = trim(filepath)
538 len_path = len_trim(trimmed)
539 is_nc = .false.
540 if (len_path >= 3) then
541 if ((trimmed(len_path-2:len_path) == '.nc') .or. (trimmed(len_path-2:len_path) == '.NC')) is_nc = .true.
542 end if
543
544 ncname = trimmed
545 if (.not. is_nc) ncname = path_root(trimmed) // '.nc'
546
547 if (is_nc .or. path_isfile(ncname)) then
548 call get_header_info_from_nc(ncname, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, &
549 header_cellsize, header_nodata, var=varname)
550 else
551 call read_header_ascii(trimmed, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, &
552 header_cellsize, header_nodata)
553 end if
554 end subroutine read_header_nc_or_ascii
555
556 !> \brief check if given axis is a uniform axis.
557 !> \authors Sebastian Müller
558 !> \date Mar 2024
559 subroutine check_uniform_axis(var, cellsize, origin, increasing, tol)
560 use mo_netcdf, only : ncvariable
561 use mo_utils, only: is_close
562 implicit none
563 type(ncvariable), intent(in) :: var !< NetCDF variable for corresponding axis
564 real(dp), optional, intent(out) :: cellsize !< cellsize of the uniform axis
565 real(dp), optional, intent(out) :: origin !< origin of the axis vertices
566 logical, optional, intent(out) :: increasing !< whether the axis has increasing values
567 real(dp), intent(in), optional :: tol !< tolerance for cell size comparisson (default: 1.e-7)
568 real(dp), dimension(:), allocatable :: axis
569 real(dp), dimension(:,:), allocatable :: bounds
570 real(dp) :: diff, tol_
571 integer(i4) :: i_ub, i_lb
572 logical :: has_bnds
573 type(ncvariable) :: bnds
574 character(len=256) :: name
575
576 call var%getData(axis)
577 if (var%hasAttribute("bounds")) then
578 has_bnds = .true.
579 call var%getAttribute("bounds", name)
580 bnds = var%parent%getVariable(trim(name))
581 call bnds%getData(bounds)
582 else
583 has_bnds = .false.
584 end if
585 ! store var name for error messages
586 name = var%getName()
587
588 tol_ = 1.e-7_dp
589 if ( present(tol) ) tol_ = tol
590
591 if (size(axis) == 0_i4) &
592 call error_message("check_uniform_axis: axis is empty: ", name)
593
594 if (size(axis) > 1_i4) then
595 diff = (axis(size(axis)) - axis(1)) / real(size(axis) - 1_i4, dp)
596 if (.not.all(is_close(axis(2:size(axis))-axis(1:size(axis)-1), diff, rtol=0.0_dp, atol=tol_))) &
597 call error_message("check_uniform_axis: given axis is not uniform: ", name)
598 else
599 if (.not. has_bnds) &
600 call error_message("check_uniform_axis: can't check axis of size 1 when no bounds are given: ", name)
601 diff = bounds(2,1) - bounds(1,1)
602 end if
603
604 if (has_bnds) then
605 ! be forgiving if the bounds don't have the same monotonicity as the axis (cf-convetion is hard)
606 i_lb = 1
607 i_ub = 2
608 if (size(bounds, dim=2)>1) then
609 if (.not. is_close(bounds(2,1), bounds(1,2), rtol=0.0_dp, atol=tol_) &
610 .and. is_close(bounds(1,1), bounds(2,2), rtol=0.0_dp, atol=tol_)) then
611 print *, "check_uniform_axis: bounds actually have wrong monotonicity: ", name
612 i_lb = 2
613 i_ub = 1
614 end if
615 end if
616 if (.not.all(is_close(bounds(i_ub,:)-bounds(i_lb,:), diff, rtol=0.0_dp, atol=tol_))) &
617 call error_message("check_uniform_axis: given bounds are not uniform: ", name)
618 if (.not.all(is_close(axis(:)-bounds(i_lb,:), 0.5_dp*diff, rtol=0.0_dp, atol=tol_))) &
619 call error_message("check_uniform_axis: given bounds are not centered around axis points: ", name)
620 end if
621
622 if ( present(cellsize) ) cellsize = abs(diff)
623 if ( present(origin) ) origin = minval(axis) - 0.5_dp * abs(diff)
624 if ( present(increasing) ) increasing = diff > 0.0_dp
625
626 end subroutine check_uniform_axis
627
628 !> \brief check if given variable is a x-axis.
629 !> \return `logical :: is_x_axis`
630 !> \authors Sebastian Müller
631 !> \date Mar 2024
632 logical function is_x_axis(var)
633 use mo_netcdf, only : ncvariable
634 implicit none
635 type(ncvariable), intent(in) :: var !< NetCDF variable to check
636 character(len=256) :: tmp_str
637
638 is_x_axis = .false.
639 if (var%hasAttribute("standard_name")) then
640 call var%getAttribute("standard_name", tmp_str)
641 if (trim(tmp_str) == "projection_x_coordinate") is_x_axis = .true.
642 else if (var%hasAttribute("axis")) then
643 call var%getAttribute("axis", tmp_str)
644 if (trim(tmp_str) == "X") is_x_axis = .true.
645 else if (var%hasAttribute("_CoordinateAxisType")) then
646 call var%getAttribute("_CoordinateAxisType", tmp_str)
647 if (trim(tmp_str) == "GeoX") is_x_axis = .true.
648 end if
649 end function is_x_axis
650
651 !> \brief check if given variable is a y-axis.
652 !> \return `logical :: is_y_axis`
653 !> \authors Sebastian Müller
654 !> \date Mar 2024
655 logical function is_y_axis(var)
656 use mo_netcdf, only : ncvariable
657 implicit none
658 type(ncvariable), intent(in) :: var !< NetCDF variable to check
659 character(len=256) :: tmp_str
660
661 is_y_axis = .false.
662 if (var%hasAttribute("standard_name")) then
663 call var%getAttribute("standard_name", tmp_str)
664 if (trim(tmp_str) == "projection_y_coordinate") is_y_axis = .true.
665 else if (var%hasAttribute("axis")) then
666 call var%getAttribute("axis", tmp_str)
667 if (trim(tmp_str) == "Y") is_y_axis = .true.
668 else if (var%hasAttribute("_CoordinateAxisType")) then
669 call var%getAttribute("_CoordinateAxisType", tmp_str)
670 if (trim(tmp_str) == "GeoY") is_y_axis = .true.
671 end if
672 end function is_y_axis
673
674!> \brief check if given variable is a lon coordinate.
675 !> \return `logical :: is_lon_coord`
676 !> \authors Sebastian Müller
677 !> \date Mar 2024
678 logical function is_lon_coord(var)
679 use mo_netcdf, only : ncvariable
680 implicit none
681 type(ncvariable), intent(in) :: var !< NetCDF variable to check
682 character(len=256) :: tmp_str
683
684 is_lon_coord = .false.
685 if (var%hasAttribute("standard_name")) then
686 call var%getAttribute("standard_name", tmp_str)
687 if (trim(tmp_str) == "longitude") is_lon_coord = .true.
688 else if (var%hasAttribute("units")) then
689 call var%getAttribute("units", tmp_str)
690 if (trim(tmp_str) == "degreeE") is_lon_coord = .true.
691 if (trim(tmp_str) == "degree_E") is_lon_coord = .true.
692 if (trim(tmp_str) == "degree_east") is_lon_coord = .true.
693 if (trim(tmp_str) == "degreesE") is_lon_coord = .true.
694 if (trim(tmp_str) == "degrees_E") is_lon_coord = .true.
695 if (trim(tmp_str) == "degrees_east") is_lon_coord = .true.
696 else if (var%hasAttribute("_CoordinateAxisType")) then
697 call var%getAttribute("_CoordinateAxisType", tmp_str)
698 if (trim(tmp_str) == "Lon") is_lon_coord = .true.
699 else if (var%hasAttribute("long_name")) then
700 call var%getAttribute("long_name", tmp_str)
701 if (trim(tmp_str) == "longitude") is_lon_coord = .true.
702 end if
703
704 end function is_lon_coord
705
706 !> \brief check if given variable is a lat coordinate.
707 !> \return `logical :: is_lat_coord`
708 !> \authors Sebastian Müller
709 !> \date Mar 2024
710 logical function is_lat_coord(var)
711 use mo_netcdf, only : ncvariable
712 implicit none
713 type(ncvariable), intent(in) :: var !< NetCDF variable to check
714 character(len=256) :: tmp_str
715
716 is_lat_coord = .false.
717 if (var%hasAttribute("standard_name")) then
718 call var%getAttribute("standard_name", tmp_str)
719 if (trim(tmp_str) == "latitude") is_lat_coord = .true.
720 else if (var%hasAttribute("units")) then
721 call var%getAttribute("units", tmp_str)
722 if (trim(tmp_str) == "degreeN") is_lat_coord = .true.
723 if (trim(tmp_str) == "degree_N") is_lat_coord = .true.
724 if (trim(tmp_str) == "degree_north") is_lat_coord = .true.
725 if (trim(tmp_str) == "degreesN") is_lat_coord = .true.
726 if (trim(tmp_str) == "degrees_N") is_lat_coord = .true.
727 if (trim(tmp_str) == "degrees_north") is_lat_coord = .true.
728 else if (var%hasAttribute("_CoordinateAxisType")) then
729 call var%getAttribute("_CoordinateAxisType", tmp_str)
730 if (trim(tmp_str) == "Lat") is_lat_coord = .true.
731 else if (var%hasAttribute("long_name")) then
732 call var%getAttribute("long_name", tmp_str)
733 if (trim(tmp_str) == "latitude") is_lat_coord = .true.
734 end if
735 end function is_lat_coord
736
737
738 !> \brief Read NetCDF header information (matching read_header_ascii signature)
739 !> \details Reads grid metadata (ncols, nrows, corner, cellsize, nodata) from a NetCDF file.
740 !> \authors Sebastian Müller, Simon Lüdke
741 !> \date Mar 2024 / Feb 2025
742 subroutine get_header_info_from_nc(ncname, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, &
743 header_cellsize, header_nodata, mask, var)
744 use mo_netcdf, only : ncdataset, ncvariable, ncdimension
745 use mo_utils, only : is_close
746 use mo_string_utils, only : num2str
747 implicit none
748 character(*), intent(in) :: ncname !< NetCDF filename
749 integer(i4), intent(in) :: fileunit !< Unused (kept for signature compatibility)
750 integer(i4), intent(out) :: header_ncols !< number of columns
751 integer(i4), intent(out) :: header_nrows !< number of rows
752 real(dp), intent(out) :: header_xllcorner !< lower left x
753 real(dp), intent(out) :: header_yllcorner !< lower left y
754 real(dp), intent(out) :: header_cellsize !< cell size
755 real(dp), intent(out) :: header_nodata !< nodata value
756 logical, optional, allocatable, dimension(:,:), intent(out) :: mask !< mask
757 character(*), intent(in), optional :: var !< optional variable name
758
759 type(ncdataset) :: nc
760 type(ncvariable) :: ncvar, xvar, yvar
761 type(ncdimension), dimension(:), allocatable :: dims
762 integer(i4) :: rnk, y_dir
763 integer(i4) :: bottom_up, top_down
764 real(dp) :: cs_x, cs_y, tol
765 logical :: y_inc, x_sph, y_sph, x_cart, y_cart, flip_y
766 integer(i4) :: keep_y
767 character(len=256) :: varname
768
769 keep_y = -1_i4
770 y_dir = keep_y
771
772 ! set defaults
773 tol = 1.e-7_dp
774 bottom_up = 1_i4
775 top_down = 0_i4
776
777 nc = ncdataset(ncname, "r")
778
779 if (present(var)) then
780 varname = trim(var)
781 else
782 varname = determine_data_var_name(nc, ncname)
783 end if
784
785 ncvar = nc%getVariable(varname)
786 rnk = ncvar%getRank()
787 if (rnk < 2) call error_message("grid % from_netcdf: given variable has too few dimensions: ", trim(nc%fname), ":", trim(varname))
788
789 dims = ncvar%getDimensions()
790 header_ncols = dims(1)%getLength()
791 header_nrows = dims(2)%getLength()
792 xvar = nc%getVariable(trim(dims(1)%getName()))
793 yvar = nc%getVariable(trim(dims(2)%getName()))
794
795 ! check if x/y axis are x/y/lon/lat by standard_name, units, axistype or long_name
796 if (is_x_axis(yvar).or.is_lon_coord(yvar).or.is_y_axis(xvar).or.is_lat_coord(xvar)) &
797 call error_message("grid % from_netcdf: variable seems to have wrong axis order (not y-x): ", trim(nc%fname), ":", trim(varname))
798
799 x_cart = is_x_axis(xvar)
800 y_cart = is_y_axis(yvar)
801 x_sph = is_lon_coord(xvar)
802 y_sph = is_lat_coord(yvar)
803
804 if (.not.(x_cart.or.x_sph)) &
805 call error_message("grid % from_netcdf: can't determine coordinate system from x-axis: ", trim(nc%fname), ":", trim(varname))
806 if (.not.(y_cart.or.y_sph)) &
807 call error_message("grid % from_netcdf: can't determine coordinate system from y-axis: ", trim(nc%fname), ":", trim(varname))
808 if (.not.(x_sph.eqv.y_sph)) &
809 call error_message("grid % from_netcdf: x and y axis seem to have different coordinate systems: ", trim(nc%fname), ":", trim(varname))
810
811 ! check axis uniformity and monotonicity
812 call check_uniform_axis(xvar, cellsize=cs_x, origin=header_xllcorner, tol=tol)
813 call check_uniform_axis(yvar, cellsize=cs_y, origin=header_yllcorner, increasing=y_inc, tol=tol)
814 if (y_dir == keep_y) then
815 y_dir = top_down
816 if (y_inc) y_dir = bottom_up
817 end if
818 ! check y_dir
819 if (.not.any(y_dir==[bottom_up, top_down])) &
820 call error_message("grid % from_netcdf: y-direction not valid: ", trim(num2str(y_dir)))
821
822 ! warn about flipping if present axis is not in desired direction
823 flip_y = y_inc.neqv.(y_dir==bottom_up)
824 if (flip_y) then
825 print *, "grid % from_netcdf: y axis direction is oposite to desired one (inefficient flipping). ", &
826 "You could flip the file beforehand with: 'cdo invertlat <ifile> <ofile>'. ", trim(nc%fname), ":", trim(varname)
827 end if
828 ! check cellsize in x and y direction
829 if (.not.is_close(cs_x, cs_y, rtol=0.0_dp, atol=tol)) &
830 call error_message("grid % from_netcdf: x and y axis have different cell sizes: ", trim(nc%fname), ":", trim(varname))
831 header_cellsize = cs_x
832
833 ! Determine no-data value
834 if (ncvar%hasAttribute("_FillValue")) then
835 call ncvar%getAttribute("_FillValue", header_nodata)
836 else if (ncvar%hasAttribute("missing_value")) then
837 call ncvar%getAttribute("missing_value", header_nodata)
838 else
839 call error_message('***ERROR: read_nc_header: missing _FillValue or missing_value attribute')
840 end if
841
842 call nc%close()
843 end subroutine get_header_info_from_nc
844
845 function determine_data_var_name(nc, ncname) result(varName)
846 use mo_netcdf, only : ncdataset, ncvariable
847 use mo_message, only : error_message
848 use mo_os, only : path_stem
849 class(ncdataset), intent(in) :: nc
850 character(len=*), intent(in) :: ncname
851 character(len=256) :: varname
852
853 type(ncvariable), dimension(:), allocatable :: vars
854 character(len=256), dimension(:), allocatable :: data_var_names
855 integer(i4) :: i, data_var_count, data_var_index
856 character(len=256) :: stem
857
858 varname = ''
859 vars = nc%getVariables()
860
861 data_var_count = 0
862 do i = 1, size(vars)
863 if (vars(i)%getNoDimensions() >= 2) data_var_count = data_var_count + 1
864 end do
865
866 if (data_var_count == 0) then
867 call error_message('read_spatial_data_nc: could not determine variable name for file: ' // trim(ncname))
868 end if
869
870 allocate(data_var_names(data_var_count))
871 data_var_index = 0
872 do i = 1, size(vars)
873 if (vars(i)%getNoDimensions() >= 2) then
874 data_var_index = data_var_index + 1
875 data_var_names(data_var_index) = trim(vars(i)%getName())
876 end if
877 end do
878
879 if (data_var_count == 1) then
880 varname = trim(data_var_names(1))
881 return
882 end if
883
884 stem = trim(path_stem(ncname))
885 do i = 1, data_var_count
886 if ((trim(data_var_names(i)) == stem) .or. (trim(data_var_names(i)) == 'data')) then
887 varname = trim(data_var_names(i))
888 return
889 end if
890 end do
891
892 call error_message('read_spatial_data_nc: variable name could not be determined for file: ' // trim(ncname))
893 end function determine_data_var_name
894
895
896 ! NAME
897 ! read_spatial_data_nc_i4
898
899 ! PURPOSE
900 !> \brief Read file from filepath. If there is a nc file with the correct name it is prefered over the asci file.
901
902 !> \details TODO: add description
903
904 ! HISTORY
905 !> \authors Simon Lüdke
906
907 !> \date June 2025
908 subroutine read_spatial_data_nc_i4(ncname, data, maskout, ncols, nrows, xllcorner, yllcorner, cellsize, nodata_value, varName)
909 use mo_netcdf, only : ncdataset, ncvariable
910 use mo_message, only : error_message
911 implicit none
912
913 character(len=*), intent(in) :: ncname
914 character(len=*), intent(in), optional :: varName
915 integer(i4), dimension(:, :), allocatable, intent(out) :: data
916 logical, optional, allocatable, dimension(:, :), intent(out) :: maskout
917 integer(i4), intent(out) :: ncols, nrows
918 real(dp), intent(out) :: xllcorner, yllcorner, cellsize
919 real(dp), intent(out) :: nodata_value
920
921 type(ncdataset) :: nc
922 type(ncvariable) :: var
923 integer(i4), allocatable :: var_shape(:), start(:), cnt(:)
924 character(len=256) :: varName_local
925
926 ! Open NetCDF dataset
927 nc = ncdataset(ncname, "r")
928
929 if (present(varname)) then
930 varname_local = trim(varname)
931 else
932 varname_local = determine_data_var_name(nc, ncname)
933 end if
934
935 ! Extract header info
936 call get_header_info_from_nc(ncname, 0_i4, ncols, nrows, xllcorner, yllcorner, cellsize, nodata_value, var=varname_local)
937
938 ! Retrieve variable
939 var = nc%getVariable(trim(varname_local))
940
941 ! Determine shape and prepare read extents
942 var_shape = var%getShape()
943 allocate(start(size(var_shape)), source=1_i4)
944 allocate(cnt(size(var_shape)), source=1_i4)
945 cnt(1:2) = var_shape(1:2)
946
947 ! Determine no-data value
948 if (var%hasAttribute("_FillValue")) then
949 call var%getAttribute("_FillValue", nodata_value)
950 else if (var%hasAttribute("missing_value")) then
951 call var%getAttribute("missing_value", nodata_value)
952 else
953 call error_message('***ERROR: read_nc_i4_data: missing _FillValue or missing_value attribute')
954 end if
955
956 ! Allocate and read data
957 allocate(data(var_shape(1), var_shape(2)))
958 call var%getData(data, start=start, cnt=cnt)
959
960 if (present(maskout)) then
961 allocate(maskout(var_shape(1), var_shape(2)))
962 maskout = abs(real(data, dp) - nodata_value) .gt. tiny(1.0_dp)
963 end if
964
965 call nc%close()
966 end subroutine read_spatial_data_nc_i4
967
968
969 ! NAME
970 ! read_spatial_data_nc_dp
971
972 ! PURPOSE
973 !> \brief Read file from filepath. If there is a nc file with the correct name it is prefered over the asci file.
974
975 !> \details TODO: add description
976
977 ! HISTORY
978 !> \authors Simon Lüdke
979
980 !> \date June 2025
981 subroutine read_spatial_data_nc_dp(ncname, data, maskout, ncols, nrows, xllcorner, yllcorner, cellsize, nodata_value, varName)
982 use mo_netcdf, only : ncdataset, ncvariable
983 use mo_message, only : error_message
984 implicit none
985
986 character(len=*), intent(in) :: ncname
987 character(len=*), intent(in), optional :: varName
988 real(dp), dimension(:, :), allocatable, intent(out) :: data
989 logical, optional, allocatable, dimension(:, :), intent(out) :: maskout
990 integer(i4), intent(out) :: ncols, nrows
991 real(dp), intent(out) :: xllcorner, yllcorner, cellsize
992 real(dp), intent(out) :: nodata_value
993
994 type(ncdataset) :: nc
995 type(ncvariable) :: var
996 integer(i4), allocatable :: var_shape(:), start(:), cnt(:)
997 character(len=256) :: varName_local
998
999 ! Open NetCDF dataset
1000 nc = ncdataset(ncname, "r")
1001
1002 if (present(varname)) then
1003 varname_local = trim(varname)
1004 else
1005 varname_local = determine_data_var_name(nc, ncname)
1006 end if
1007
1008 ! Extract header info
1009 call get_header_info_from_nc(ncname, 0_i4, ncols, nrows, xllcorner, yllcorner, cellsize, nodata_value, var=varname_local)
1010
1011 ! Retrieve variable
1012 var = nc%getVariable(trim(varname_local))
1013
1014 ! Determine shape and prepare read extents
1015 var_shape = var%getShape()
1016 allocate(start(size(var_shape)), source=1_i4)
1017 allocate(cnt(size(var_shape)), source=1_i4)
1018 cnt(1:2) = var_shape(1:2)
1019
1020 ! Determine no-data value
1021 if (var%hasAttribute("_FillValue")) then
1022 call var%getAttribute("_FillValue", nodata_value)
1023 else if (var%hasAttribute("missing_value")) then
1024 call var%getAttribute("missing_value", nodata_value)
1025 else
1026 call error_message('***ERROR: read_nc_i4_data: missing _FillValue or missing_value attribute')
1027 end if
1028
1029 ! Allocate and read data
1030 allocate(data(var_shape(1), var_shape(2)))
1031 call var%getData(data, start=start, cnt=cnt)
1032
1033 if (present(maskout)) then
1034 allocate(maskout(var_shape(1), var_shape(2)))
1035 maskout = abs(data - nodata_value) .gt. tiny(1.0_dp)
1036 end if
1037
1038 call nc%close()
1039 end subroutine read_spatial_data_nc_dp
1040
1041
1042
1043 ! NAME
1044 ! read_spatial_data_nc_or_ascii_dp
1045
1046 ! PURPOSE
1047 !> \brief Read file from filepath. If there is a nc file with the correct name it is prefered over the asci file.
1048
1049 !> \details TODO: add description
1050
1051 ! HISTORY
1052 !> \authors Simon Lüdke
1053
1054 !> \date June 2025
1055
1056 subroutine read_spatial_data_nc_or_ascii_dp(filepath, fileunit, header_ncols, header_nrows, header_xllcorner, &
1057 header_yllcorner, header_cellsize, data, maskout, &
1058 out_nCols, out_nRows, out_xllcorner, out_yllcorner, out_cellsize, out_nodata_value)
1059 use mo_os, only : path_root, path_isfile
1060 implicit none
1061
1062 ! filename with location
1063 character(len = *), intent(in) :: filepath
1064
1065 ! unit for opening the file
1066 integer(i4), intent(in) :: fileunit
1067
1068 ! number of rows of data fields:
1069 integer(i4), intent(in) :: header_nRows
1070
1071 ! number of columns of data fields:
1072 integer(i4), intent(in) :: header_nCols
1073
1074 ! header read in lower left corner
1075 real(dp), intent(in) :: header_xllcorner
1076
1077 ! header read in lower left corner
1078 real(dp), intent(in) :: header_yllcorner
1079
1080 ! header read in cellsize
1081 real(dp), intent(in) :: header_cellsize
1082
1083 ! data
1084 real(dp), dimension(:, :), allocatable, intent(out) :: data
1085
1086 ! mask
1087 logical, optional, dimension(:, :), allocatable, intent(out) :: maskout
1088
1089 ! number of rows of data fields:
1090 integer(i4), optional, intent(out) :: out_nRows
1091
1092 ! number of columns of data fields:
1093 integer(i4), optional, intent(out) :: out_nCols
1094
1095 ! header read in lower left corner
1096 real(dp), optional, intent(out) :: out_xllcorner
1097
1098 ! header read in lower left corner
1099 real(dp), optional, intent(out) :: out_yllcorner
1100
1101 ! header read in cellsize
1102 real(dp), optional, intent(out) :: out_cellsize
1103
1104 !
1105 real(dp), optional, intent(out) :: out_nodata_value
1106
1107 ! file exists
1108 real(dp) :: nodata_value
1109 integer(i4) :: nrows, ncols
1110 real(dp) :: xllcorner, yllcorner, cellsize
1111 character(len=:), allocatable :: ncname
1112
1113 ! Prefer explicit NetCDF path if it already ends with .nc, otherwise use sidecar .nc
1114 if (len_trim(filepath) >= 3) then
1115 if ((filepath(len_trim(filepath)-2:len_trim(filepath)) == '.nc') .or. (filepath(len_trim(filepath)-2:len_trim(filepath)) == '.NC')) then
1116 ncname = trim(filepath)
1117 else
1118 ncname = path_root(filepath) // '.nc'
1119 end if
1120 else
1121 ncname = path_root(filepath) // '.nc'
1122 end if
1123
1124 ! preferably use nc file if it exists alternatively the asci version
1125 ! print *, "Check if ", ncname, " existis: ", path_isfile(ncname)
1126 if (path_isfile(ncname)) then
1127 print *, "Read nc file: ", ncname
1128 call read_spatial_data_nc(ncname, data, maskout, ncols, nrows, xllcorner, yllcorner, cellsize, nodata_value)
1129 else
1130 print *, "Read ascii file: ", filepath
1131 if ((header_ncols /= 0_i4) .and. (header_nrows /= 0_i4)) then
1132 ncols = header_ncols
1133 nrows = header_nrows
1134 yllcorner = header_yllcorner
1135 xllcorner = header_xllcorner
1136 cellsize = header_cellsize
1137 else
1138 call read_header_ascii(filepath, fileunit, &
1139 ncols, nrows, xllcorner, &
1140 yllcorner, cellsize, nodata_value)
1141
1142 end if
1143 ! print *, "run ascii dp reading with ", filepath
1144 call read_spatial_data_ascii(filepath, fileunit, ncols, nrows, xllcorner, &
1145 yllcorner, cellsize, data, maskout)
1146 end if
1147 ! if header information is needed as output it is saved to the output variables
1148 if (present(out_ncols)) &
1149 out_ncols = ncols
1150 if (present(out_nrows)) &
1151 out_nrows = nrows
1152 if (present(out_xllcorner)) &
1153 out_xllcorner = xllcorner
1154 if (present(out_yllcorner)) &
1155 out_yllcorner = yllcorner
1156 if (present(out_cellsize)) &
1157 out_cellsize = cellsize
1158 if (present(out_nodata_value)) &
1159 out_nodata_value = nodata_value
1160
1162
1163 ! NAME
1164 ! read_spatial_data_nc_or_ascii_i4
1165
1166 ! PURPOSE
1167 !> \brief Read file from filepath. If there is a nc file with the correct name it is prefered over the asci file.
1168
1169 !> \details TODO: add description
1170
1171 ! HISTORY
1172 !> \authors Simon Lüdke
1173
1174 !> \date June 2025
1175
1176 subroutine read_spatial_data_nc_or_ascii_i4(filepath, fileunit, header_ncols, header_nrows, header_xllcorner, &
1177 header_yllcorner, header_cellsize, data, maskout, &
1178 out_nCols, out_nRows, out_xllcorner, out_yllcorner, out_cellsize, out_nodata_value)
1179 use mo_os, only : path_root, path_isfile
1180 implicit none
1181
1182 ! filename with location
1183 character(len = *), intent(in) :: filepath
1184
1185 ! unit for opening the file
1186 integer(i4), intent(in) :: fileunit
1187
1188 ! number of rows of data fields:
1189 integer(i4), intent(in) :: header_nRows
1190
1191 ! number of columns of data fields:
1192 integer(i4), intent(in) :: header_nCols
1193
1194 ! header read in lower left corner
1195 real(dp), intent(in) :: header_xllcorner
1196
1197 ! header read in lower left corner
1198 real(dp), intent(in) :: header_yllcorner
1199
1200 ! header read in cellsize
1201 real(dp), intent(in) :: header_cellsize
1202
1203 ! data
1204 integer(i4), dimension(:, :), allocatable, intent(out) :: data
1205
1206 ! mask
1207 logical, optional, dimension(:, :), allocatable, intent(out) :: maskout
1208
1209 ! number of rows of data fields:
1210 integer(i4), optional, intent(out) :: out_nRows
1211
1212 ! number of columns of data fields:
1213 integer(i4), optional, intent(out) :: out_nCols
1214
1215 ! header read in lower left corner
1216 real(dp), optional, intent(out) :: out_xllcorner
1217
1218 ! header read in lower left corner
1219 real(dp), optional, intent(out) :: out_yllcorner
1220
1221 ! header read in cellsize
1222 real(dp), optional, intent(out) :: out_cellsize
1223
1224 real(dp), optional, intent(out) :: out_nodata_value
1225
1226 ! file exists
1227 real(dp) :: nodata_value
1228 integer(i4) :: nrows, ncols
1229 real(dp) :: xllcorner, yllcorner, cellsize
1230 character(len=:), allocatable :: ncname
1231
1232 ! Prefer explicit NetCDF path if it already ends with .nc, otherwise use sidecar .nc
1233 if (len_trim(filepath) >= 3) then
1234 if ((filepath(len_trim(filepath)-2:len_trim(filepath)) == '.nc') .or. (filepath(len_trim(filepath)-2:len_trim(filepath)) == '.NC')) then
1235 ncname = trim(filepath)
1236 else
1237 ncname = path_root(filepath) // '.nc'
1238 end if
1239 else
1240 ncname = path_root(filepath) // '.nc'
1241 end if
1242
1243 ! preferably use nc file if it exists alternatively the asci version
1244 ! print *, "Check if ", ncname, " existis: ", path_isfile(ncname)
1245 if (path_isfile(ncname)) then
1246 print *, "Read nc file: ", ncname
1247 call read_spatial_data_nc(ncname, data, maskout, ncols, nrows, xllcorner, yllcorner, cellsize, nodata_value)
1248 else
1249 print *, "Read ascii file: ", filepath
1250 if ((header_ncols /= 0_i4) .and. (header_nrows /= 0_i4)) then
1251 ncols = header_ncols
1252 nrows = header_nrows
1253 yllcorner = header_yllcorner
1254 xllcorner = header_xllcorner
1255 cellsize = header_cellsize
1256 else
1257 call read_header_ascii(filepath, fileunit, &
1258 ncols, nrows, xllcorner, &
1259 yllcorner, cellsize, nodata_value)
1260
1261 end if
1262 ! print *, "run ascii i4 reading with ", filepath, " as ", ncname, " does not exists"
1263 call read_spatial_data_ascii(filepath, fileunit, ncols, nrows, xllcorner, &
1264 yllcorner, cellsize, data, maskout)
1265 end if
1266 ! if header information is needed as output it is saved to the output variables
1267 if (present(out_ncols)) &
1268 out_ncols = ncols
1269 if (present(out_nrows)) &
1270 out_nrows = nrows
1271 if (present(out_xllcorner)) &
1272 out_xllcorner = xllcorner
1273 if (present(out_yllcorner)) &
1274 out_yllcorner = yllcorner
1275 if (present(out_cellsize)) &
1276 out_cellsize = cellsize
1277 if (present(out_nodata_value)) &
1278 out_nodata_value = nodata_value
1280
1281
1282END MODULE mo_read_spatial_data
Reads spatial data files of ASCII format.
Reads spatial data files of nc or ASCII format.
Reads spatial data files of nc format.
Provides constants commonly used by mHM, mRM and MPR.
real(dp), parameter, public defaulttolerance_dp
real(dp), parameter, public nodata_dp
Reads spatial input data.
subroutine, public check_uniform_axis(var, cellsize, origin, increasing, tol)
check if given axis is a uniform axis.
subroutine read_spatial_data_nc_or_ascii_dp(filepath, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize, data, maskout, out_ncols, out_nrows, out_xllcorner, out_yllcorner, out_cellsize, out_nodata_value)
Read file from filepath.
logical function is_y_axis(var)
check if given variable is a y-axis.
subroutine read_spatial_data_ascii_i4(filename, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize, data, mask)
TODO: add description.
logical function is_lon_coord(var)
check if given variable is a lon coordinate.
subroutine read_spatial_data_ascii_dp(filename, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize, data, mask)
TODO: add description.
subroutine read_spatial_data_nc_i4(ncname, data, maskout, ncols, nrows, xllcorner, yllcorner, cellsize, nodata_value, varname)
Read file from filepath.
subroutine, public get_header_info_from_nc(ncname, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize, header_nodata, mask, var)
Read NetCDF header information (matching read_header_ascii signature)
subroutine read_spatial_data_nc_or_ascii_i4(filepath, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize, data, maskout, out_ncols, out_nrows, out_xllcorner, out_yllcorner, out_cellsize, out_nodata_value)
Read file from filepath.
logical function is_x_axis(var)
check if given variable is a x-axis.
logical function is_lat_coord(var)
check if given variable is a lat coordinate.
subroutine, public read_header_nc_or_ascii(filepath, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize, header_nodata, varname)
Read header information from either NetCDF or ASCII depending on file name/presence.
character(len=256) function determine_data_var_name(nc, ncname)
subroutine read_spatial_data_nc_dp(ncname, data, maskout, ncols, nrows, xllcorner, yllcorner, cellsize, nodata_value, varname)
Read file from filepath.
subroutine, public check_header(ncols, nrows, xllcorner, yllcorner, cellsize, ref_ncols, ref_nrows, ref_xllcorner, ref_yllcorner, ref_cellsize, tolerance, context)
subroutine, public read_header_ascii(filename, fileunit, header_ncols, header_nrows, header_xllcorner, header_yllcorner, header_cellsize, header_nodata)
Reads header lines of ASCII files.