FV3 Bundle
Binary_File_Utility.f90
Go to the documentation of this file.
1 !
2 ! Binary_File_Utility
3 !
4 ! Module for utility routines for "Binary" datafiles (unformatted,
5 ! sequential) that conform to the required format.
6 !
7 !
8 ! CREATION HISTORY:
9 ! Written by: Paul van Delst, 12-Jun-2000
10 ! paul.vandelst@noaa.gov
11 !
12 
14 
15  ! ------------------
16  ! Environment set up
17  ! ------------------
18  ! Module use
19  USE type_kinds, ONLY: long, n_bytes_long
22  USE endian_utility, ONLY: swap_endian
23  ! Disable all implicit typing
24  IMPLICIT NONE
25 
26 
27  ! ------------
28  ! Visibilities
29  ! ------------
30  PRIVATE
31  PUBLIC :: open_binary_file
32  PUBLIC :: writegatts_binary_file
33  PUBLIC :: readgatts_binary_file
34  PUBLIC :: writelogical_binary_file
35  PUBLIC :: readlogical_binary_file
36 
37 
38  ! -------------------
39  ! Procedure overloads
40  ! -------------------
42  MODULE PROCEDURE writelogical_scalar
43  MODULE PROCEDURE writelogical_rank1
44  END INTERFACE writelogical_binary_file
45 
47  MODULE PROCEDURE readlogical_scalar
48  MODULE PROCEDURE readlogical_rank1
49  END INTERFACE readlogical_binary_file
50 
51 
52  ! ----------
53  ! Parameters
54  ! ----------
55  CHARACTER(*), PARAMETER :: module_version_id = &
56  '$Id: Binary_File_Utility.f90 60152 2015-08-13 19:19:13Z paul.vandelst@noaa.gov $'
57  ! Magic number header value for byte-swap checks
58  INTEGER(Long), PARAMETER :: magic_number = 123456789_long
59  ! Integer "logicals" for I/O
60  INTEGER(Long), PARAMETER :: false = 0_long
61  INTEGER(Long), PARAMETER :: true = 1_long
62  ! String lengths
63  INTEGER, PARAMETER :: ml = 256 ! For messages
64  INTEGER, PARAMETER :: gl = 5000 ! For local global attribute values
65  ! Global attribute names
66  CHARACTER(*), PARAMETER :: write_module_gattname = 'write_module'
67  CHARACTER(*), PARAMETER :: created_on_gattname = 'created_on'
68  CHARACTER(*), PARAMETER :: title_gattname = 'title'
69  CHARACTER(*), PARAMETER :: history_gattname = 'history'
70  CHARACTER(*), PARAMETER :: comment_gattname = 'comment'
71 
72 
73 CONTAINS
74 
75 
76 !################################################################################
77 !################################################################################
78 !## ##
79 !## ## PUBLIC MODULE ROUTINES ## ##
80 !## ##
81 !################################################################################
82 !################################################################################
83 
84 !--------------------------------------------------------------------------------
85 !:sdoc+:
86 !
87 ! NAME:
88 ! Open_Binary_File
89 !
90 ! PURPOSE:
91 ! Function to open unformatted, sequential access "Binary" files
92 !
93 ! CALLING SEQUENCE:
94 ! Error_Status = Open_Binary_File( Filename, &
95 ! FileID, &
96 ! For_Output = For_Output, &
97 ! No_Check = No_Check )
98 !
99 ! INPUTS:
100 ! Filename: Name of the Binary file to open.
101 ! UNITS: N/A
102 ! TYPE: CHARACTER(*)
103 ! DIMENSION: Scalar
104 ! ATTRIBUTES: INTENT(IN)
105 !
106 ! OPTIONAL INPUTS:
107 ! For_Output: Set this logical argument to open a new file for
108 ! writing. Default action is to open an existing file
109 ! for read access. Note, if the file already exists and
110 ! it is opened with this keyword set, the file is
111 ! overwritten.
112 ! If == .FALSE., existing file is opened for READ access (DEFAULT)
113 ! ACTION='READ', STATUS='OLD'
114 ! == .TRUE. , new file is opened for WRITE access.
115 ! ACTION='WRITE', STATUS='REPLACE'
116 ! UNITS: N/A
117 ! TYPE: LOGICAL
118 ! DIMENSION: Scalar
119 ! ATTRIBUTES: INTENT(IN), OPTIONAL
120 !
121 ! No_Check: Set this logical argument to suppress the byte-order
122 ! check made on an existing file by NOT reading the file
123 ! header magic number. Default action is to check the
124 ! file. This argument is ignored if the FOR_OUTPUT
125 ! optional argument is set.
126 ! If == .FALSE., existing file magic number is read and the
127 ! byte order is checked (DEFAULT)
128 ! == .TRUE., magic number is *NOT* read from file and
129 ! checked for validity.
130 ! UNITS: N/A
131 ! TYPE: LOGICAL
132 ! DIMENSION: Scalar
133 ! ATTRIBUTES: INTENT(IN), OPTIONAL
134 !
135 ! OUTPUTS:
136 ! FileID: File unit number.
137 ! UNITS: N/A
138 ! TYPE: INTEGER
139 ! DIMENSION: Scalar
140 ! ATTRIBUTES: INTENT(OUT)
141 !
142 ! FUNCTION RESULT:
143 ! Error_Status: The return value is an integer defining the
144 ! error status. The error codes are defined in
145 ! the Message_Handler module. Values returned by
146 ! this function are:
147 ! SUCCESS == file open was successful
148 ! FAILURE == an unrecoverable error occurred
149 ! UNITS: N/A
150 ! TYPE: INTEGER
151 ! DIMENSION: Scalar
152 !
153 !:sdoc-:
154 !--------------------------------------------------------------------------------
155 
156  FUNCTION open_binary_file( &
157  Filename, & ! Input
158  FileID, & ! Output
159  For_Output, & ! Optional input
160  No_Check ) & ! Optional input
161  result( err_stat )
162  ! Arguments
163  CHARACTER(*), INTENT(IN) :: filename
164  INTEGER, INTENT(OUT) :: fileid
165  LOGICAL, OPTIONAL, INTENT(IN) :: for_output
166  LOGICAL, OPTIONAL, INTENT(IN) :: no_check
167  ! Function result
168  INTEGER :: err_stat
169  ! Local parameters
170  CHARACTER(*), PARAMETER :: routine_name = 'Open_Binary_File'
171  ! Local variables
172  CHARACTER(ML) :: msg
173  CHARACTER(ML) :: io_msg
174  LOGICAL :: file_check
175  LOGICAL :: file_input
176  INTEGER :: io_stat
177  INTEGER(Long) :: magic_number_read
178  CHARACTER(7) :: file_status
179  CHARACTER(5) :: file_action
180 
181  ! Set up
182  err_stat = success
183  ! ...Check the For_Output argument
184  file_input = .true.
185  IF ( PRESENT(for_output) ) file_input = .NOT. for_output
186  ! ...Check the No_Check argument
187  file_check = file_input
188  IF ( PRESENT(no_check) ) file_check = (.NOT. no_check) .AND. file_input
189 
190 
191  ! Branch depending on type of file I/O
192  IF ( file_input ) THEN
193  ! Set OPEN keywords for READING
194  file_status = 'OLD'
195  file_action = 'READ'
196  ELSE
197  ! Set OPEN keywords for WRITING
198  file_status = 'REPLACE'
199  file_action = 'WRITE'
200  END IF
201 
202 
203  ! Check the file byte order
204  IF ( file_check ) THEN
205  err_stat = check_binary_file( filename )
206  IF ( err_stat /= success ) THEN
207  msg = 'Error checking '//trim(filename)//' file byte order'
208  CALL cleanup(); RETURN
209  END IF
210  END IF
211 
212 
213  ! Get a free unit number
214  fileid = get_lun()
215  IF ( fileid < 0 ) THEN
216  msg = 'Error obtaining file unit number for '//trim(filename)
217  CALL cleanup(); RETURN
218  END IF
219 
220 
221  ! Open the file
222  OPEN( fileid, file = filename , &
223  status = file_status , &
224  action = file_action , &
225  access = 'SEQUENTIAL' , &
226  form = 'UNFORMATTED', &
227  iostat = io_stat , &
228  iomsg = io_msg )
229  IF ( io_stat /= 0 ) THEN
230  msg = 'Error opening '//trim(filename)//' - '//trim(io_msg)
231  CALL cleanup(); RETURN
232  END IF
233 
234 
235  ! Skip past, or write the magic number
236  IF ( file_input ) THEN
237  READ( fileid, iostat=io_stat, iomsg=io_msg ) magic_number_read
238  IF ( io_stat /= 0 ) THEN
239  msg = 'Error reading magic number from '//trim(filename)//' - '//trim(io_msg)
240  CALL cleanup(); RETURN
241  END IF
242  ELSE
243  WRITE( fileid, iostat=io_stat, iomsg=io_msg ) magic_number
244  IF ( io_stat /= 0 ) THEN
245  msg = 'Error writing magic number to '//trim(filename)//' - '//trim(io_msg)
246  CALL cleanup(); RETURN
247  END IF
248  END IF
249 
250  CONTAINS
251 
252  SUBROUTINE cleanup()
253  IF ( file_open(filename) ) THEN
254  CLOSE( fileid, iostat=io_stat, iomsg=io_msg )
255  IF ( io_stat /= 0 ) &
256  msg = trim(msg)//'; Error closing file during error cleanup - '//trim(io_msg)
257  END IF
258  err_stat = failure
259  CALL display_message( routine_name, msg, err_stat )
260  END SUBROUTINE cleanup
261 
262  END FUNCTION open_binary_file
263 
264 
265 
266 
267 
268  ! Function to write standard global attributes to a Binary file.
269 
270  FUNCTION writegatts_binary_file( &
271  fid , & ! Input
272  Write_Module, & ! Optional input
273  Created_On , & ! Optional input
274  Title , & ! Optional input
275  History , & ! Optional input
276  Comment ) & ! Optional input
277  result( err_stat )
278  ! Arguments
279  INTEGER , INTENT(IN) :: fid
280  CHARACTER(*), OPTIONAL, INTENT(IN) :: write_module
281  CHARACTER(*), OPTIONAL, INTENT(IN) :: created_on
282  CHARACTER(*), OPTIONAL, INTENT(IN) :: title
283  CHARACTER(*), OPTIONAL, INTENT(IN) :: history
284  CHARACTER(*), OPTIONAL, INTENT(IN) :: comment
285  ! Function result
286  INTEGER :: err_stat
287  ! Local parameters
288  CHARACTER(*), PARAMETER :: routine_name = 'WriteGAtts_Binary_File'
289  ! Local variables
290  CHARACTER(ML) :: msg
291  CHARACTER(ML) :: io_msg
292  CHARACTER(8) :: cdate
293  CHARACTER(10) :: ctime
294  CHARACTER(5) :: czone
295  INTEGER :: io_stat
296 
297  ! Set up
298  err_stat = success
299  msg = ''
300 
301  ! Software ID
302  CALL writesinglegatt( write_module_gattname, gattvalue = write_module )
303  IF ( err_stat /= success ) RETURN
304 
305  ! Creation date/time
306  CALL date_and_time( cdate, ctime, czone )
307  IF ( PRESENT(created_on) ) THEN
308  CALL writesinglegatt( created_on_gattname, gattvalue = created_on )
309  ELSE
311  gattvalue = &
312  cdate(1:4)//'/'//cdate(5:6)//'/'//cdate(7:8)//', '// &
313  ctime(1:2)//':'//ctime(3:4)//':'//ctime(5:6)//' '// &
314  czone//'UTC')
315  END IF
316  IF ( err_stat /= success ) RETURN
317 
318 
319  ! The title
320  CALL writesinglegatt( title_gattname, gattvalue = title )
321  IF ( err_stat /= success ) RETURN
322 
323 
324  ! The history
325  CALL writesinglegatt( history_gattname, gattvalue = history )
326  IF ( err_stat /= success ) RETURN
327 
328 
329  ! The comment
330  CALL writesinglegatt( comment_gattname, gattvalue = comment )
331  IF ( err_stat /= success ) RETURN
332 
333  CONTAINS
334 
335  SUBROUTINE writesinglegatt(gattname, gattvalue)
336  CHARACTER(*), INTENT(IN) :: gattname
337  CHARACTER(*), OPTIONAL, INTENT(IN) :: gattvalue
338  INTEGER :: gattlen
339  CHARACTER(GL) :: l_gattvalue
340  ! Setup
341  l_gattvalue = ''
342  IF ( PRESENT(gattvalue) ) THEN
343  IF ( len_trim(gattvalue) /= 0 ) l_gattvalue = trim(gattname)//': '//trim(gattvalue)
344  END IF
345  gattlen = len_trim(l_gattvalue)
346  ! Write the string length
347  WRITE( fid, iostat=io_stat, iomsg=io_msg ) gattlen
348  IF ( io_stat /= 0 ) THEN
349  msg = 'Error writing '//trim(gattname)//' attribute length - '//trim(io_msg)
350  CALL writegatts_cleanup(); RETURN
351  END IF
352  IF ( gattlen == 0 ) RETURN
353  ! Write the attribute
354  WRITE( fid, iostat=io_stat, iomsg=io_msg ) trim(l_gattvalue)
355  IF ( io_stat /= 0 ) THEN
356  msg = 'Error writing '//trim(gattname)//' attribute - '//trim(io_msg)
357  CALL writegatts_cleanup(); RETURN
358  END IF
359  END SUBROUTINE writesinglegatt
360 
361  SUBROUTINE writegatts_cleanup()
362  IF ( file_open(fid) ) THEN
363  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
364  IF ( io_stat /= 0 ) &
365  msg = trim(msg)//'; Error closing output file during error cleanup - '//trim(io_msg)
366  END IF
367  err_stat = failure
368  CALL display_message( routine_name, msg, err_stat )
369  END SUBROUTINE writegatts_cleanup
370 
371  END FUNCTION writegatts_binary_file
372 
373 
374 
375  ! Function to read standard global attributes from a Binary file.
376 
377  FUNCTION readgatts_binary_file( &
378  fid , & ! Input
379  Write_Module, & ! Optional output
380  Created_On , & ! Optional output
381  Title , & ! Optional output
382  History , & ! Optional output
383  Comment ) & ! Optional output
384  result( err_stat )
385  ! Arguments
386  INTEGER , INTENT(IN) :: fid
387  CHARACTER(*), OPTIONAL, INTENT(OUT) :: write_module
388  CHARACTER(*), OPTIONAL, INTENT(OUT) :: created_on
389  CHARACTER(*), OPTIONAL, INTENT(OUT) :: title
390  CHARACTER(*), OPTIONAL, INTENT(OUT) :: history
391  CHARACTER(*), OPTIONAL, INTENT(OUT) :: comment
392  ! Function result
393  INTEGER :: err_stat
394  ! Local parameters
395  CHARACTER(*), PARAMETER :: routine_name = 'ReadGAtts_Binary_File'
396  ! Local variables
397  CHARACTER(ML) :: msg
398  CHARACTER(ML) :: io_msg
399  INTEGER :: io_stat
400 
401  ! Set up
402  err_stat = success
403  msg = ''
404 
405  !
406  ! Software ID
407  CALL readsinglegatt( write_module_gattname, gattvalue = write_module )
408  IF ( err_stat /= success ) RETURN
409 
410  ! Creation date/time
411  CALL readsinglegatt( created_on_gattname, gattvalue = created_on )
412  IF ( err_stat /= success ) RETURN
413 
414 
415  ! The title
416  CALL readsinglegatt( title_gattname, gattvalue = title )
417  IF ( err_stat /= success ) RETURN
418 
419 
420  ! The history
421  CALL readsinglegatt( history_gattname, gattvalue = history )
422  IF ( err_stat /= success ) RETURN
423 
424 
425  ! The comment
426  CALL readsinglegatt( comment_gattname, gattvalue = comment )
427  IF ( err_stat /= success ) RETURN
428 
429  CONTAINS
430 
431  SUBROUTINE readsinglegatt( gattname, gattvalue)
432  CHARACTER(*), INTENT(IN) :: gattname
433  CHARACTER(*), OPTIONAL, INTENT(OUT) :: gattvalue
434  INTEGER :: i, gattlen
435  CHARACTER(GL) :: l_gattvalue
436  ! Setup
437  IF ( PRESENT(gattvalue) ) gattvalue = ''
438  l_gattvalue = ''
439  ! Read the string length
440  READ( fid, iostat=io_stat, iomsg=io_msg ) gattlen
441  IF ( io_stat /= 0 ) THEN
442  msg = 'Error reading '//trim(gattname)//' attribute length - '//trim(io_msg)
443  CALL readgatts_cleanup(); RETURN
444  END IF
445  IF ( gattlen == 0 ) RETURN
446  ! Read the attribute
447  READ( fid, iostat=io_stat, iomsg=io_msg ) l_gattvalue(1:gattlen)
448  IF ( io_stat /= 0 ) THEN
449  msg = 'Error reading '//trim(gattname)//' attribute - '//trim(io_msg)
450  CALL readgatts_cleanup(); RETURN
451  END IF
452  ! Strip out the attribute name
453  IF ( PRESENT(gattvalue) ) THEN
454  i = index(l_gattvalue,': ')
455  gattvalue = l_gattvalue(i+2:gattlen)
456  END IF
457  END SUBROUTINE readsinglegatt
458 
459  SUBROUTINE readgatts_cleanup()
460  IF ( file_open(fid) ) THEN
461  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
462  IF ( io_stat /= 0 ) &
463  msg = trim(msg)//'; Error closing input file during error cleanup - '//trim(io_msg)
464  END IF
465  err_stat = failure
466  CALL display_message( routine_name, msg, err_stat )
467  END SUBROUTINE readgatts_cleanup
468 
469  END FUNCTION readgatts_binary_file
470 
471 
472 
473 
474  !
475  ! NAME:
476  ! ReadLogical_Binary_File
477  !
478  ! PURPOSE:
479  ! Utility function to read an integer "logical" value from file
480  !
481 
482  FUNCTION readlogical_scalar( &
483  fid, &
484  logical_value ) &
485  result( err_stat )
486  ! Arguments
487  INTEGER, INTENT(IN) :: fid
488  LOGICAL, INTENT(OUT) :: logical_value
489  ! Function result
490  INTEGER :: err_stat
491  ! Function parameters
492  CHARACTER(*), PARAMETER :: routine_name = 'ReadLogical_Binary_File(Scalar)'
493  ! Function variables
494  CHARACTER(ML) :: msg
495  CHARACTER(ML) :: io_msg
496  INTEGER :: io_stat
497  INTEGER(Long) :: logical_integer
498 
499  ! Setup
500  err_stat = success
501 
502  ! Read the integer
503  READ( fid,iostat=io_stat,iomsg=io_msg ) logical_integer
504  IF ( io_stat /= 0 ) THEN
505  err_stat = failure
506  msg = 'Error reading logical integer value - '//trim(io_msg)
507  CALL display_message( routine_name, msg, err_stat )
508  RETURN
509  END IF
510 
511  ! Convert integer to a logical value
512  logical_value = (logical_integer == true)
513 
514  END FUNCTION readlogical_scalar
515 
516  FUNCTION readlogical_rank1( &
517  fid, &
518  logical_value ) &
519  result( err_stat )
520  ! Arguments
521  INTEGER, INTENT(IN) :: fid
522  LOGICAL, INTENT(OUT) :: logical_value(:)
523  ! Function result
524  INTEGER :: err_stat
525  ! Function parameters
526  CHARACTER(*), PARAMETER :: routine_name = 'ReadLogical_Binary_File(Rank-1)'
527  ! Function variables
528  CHARACTER(ML) :: msg
529  CHARACTER(ML) :: io_msg
530  INTEGER :: io_stat
531  INTEGER(Long) :: logical_integer(size(logical_value))
532 
533  ! Setup
534  err_stat = success
535 
536  ! Read the integer
537  READ( fid,iostat=io_stat,iomsg=io_msg ) logical_integer
538  IF ( io_stat /= 0 ) THEN
539  err_stat = failure
540  msg = 'Error reading logical integer rank-1 array - '//trim(io_msg)
541  CALL display_message( routine_name, msg, err_stat )
542  RETURN
543  END IF
544 
545  ! Convert integer to a logical value
546  logical_value = (logical_integer == true)
547 
548  END FUNCTION readlogical_rank1
549 
550 
551  !
552  ! NAME:
553  ! WriteLogical_Binary_File
554  !
555  ! PURPOSE:
556  ! Utility function to write an integer "logical" value to file
557  !
558 
559  FUNCTION writelogical_scalar( &
560  fid, &
561  logical_value ) &
562  result( err_stat )
563  ! Arguments
564  INTEGER, INTENT(IN) :: fid
565  LOGICAL, INTENT(IN) :: logical_value
566  ! Function result
567  INTEGER :: err_stat
568  ! Function parameters
569  CHARACTER(*), PARAMETER :: routine_name = 'WriteLogical_Binary_File(Scalar)'
570  ! Function variables
571  CHARACTER(ML) :: msg
572  CHARACTER(ML) :: io_msg
573  INTEGER :: io_stat
574  INTEGER(Long) :: logical_integer
575 
576  ! Setup
577  err_stat = success
578 
579 
580  ! Convert the logical to an integer value
581  IF ( logical_value ) THEN
582  logical_integer = true
583  ELSE
584  logical_integer = false
585  END IF
586 
587 
588  ! Write the integer
589  WRITE( fid,iostat=io_stat,iomsg=io_msg ) logical_integer
590  IF ( io_stat /= 0 ) THEN
591  err_stat = failure
592  msg = 'Error writing logical integer - '//trim(io_msg)
593  CALL display_message( routine_name, msg, err_stat )
594  RETURN
595  END IF
596 
597  END FUNCTION writelogical_scalar
598 
599  FUNCTION writelogical_rank1( &
600  fid, &
601  logical_value ) &
602  result( err_stat )
603  ! Arguments
604  INTEGER, INTENT(IN) :: fid
605  LOGICAL, INTENT(IN) :: logical_value(:)
606  ! Function result
607  INTEGER :: err_stat
608  ! Function parameters
609  CHARACTER(*), PARAMETER :: routine_name = 'WriteLogical_Binary_File(Rank-1)'
610  ! Function variables
611  CHARACTER(ML) :: msg
612  CHARACTER(ML) :: io_msg
613  INTEGER :: io_stat
614  INTEGER(Long) :: logical_integer(size(logical_value))
615 
616  ! Setup
617  err_stat = success
618 
619 
620  ! Convert the logical to an integer value
621  WHERE ( logical_value )
622  logical_integer = true
623  ELSEWHERE
624  logical_integer = false
625  END WHERE
626 
627 
628  ! Write the integer
629  WRITE( fid,iostat=io_stat,iomsg=io_msg ) logical_integer
630  IF ( io_stat /= 0 ) THEN
631  err_stat = failure
632  msg = 'Error writing logical integer rank-1 array - '//trim(io_msg)
633  CALL display_message( routine_name, msg, err_stat )
634  RETURN
635  END IF
636 
637  END FUNCTION writelogical_rank1
638 
639 
640 
641 !################################################################################
642 !################################################################################
643 !## ##
644 !## ## PRIVATE MODULE ROUTINES ## ##
645 !## ##
646 !################################################################################
647 !################################################################################
648 
649 !--------------------------------------------------------------------------------
650 !
651 ! NAME:
652 ! Check_Binary_File
653 !
654 ! PURPOSE:
655 ! Function to determine if the unformatted Binary file is in the correct
656 ! byte order.
657 !
658 ! CALLING SEQUENCE:
659 ! Error_Status = Check_Binary_File( Filename )
660 !
661 ! INPUTS:
662 ! Filename: Name of the Binary file to check.
663 ! UNITS: N/A
664 ! TYPE: CHARACTER(*)
665 ! DIMENSION: Scalar
666 ! ATTRIBUTES: INTENT(IN)
667 !
668 ! OPTIONAL INPUTS:
669 ! Message_Log: Character string specifying a filename in which any
670 ! Messages will be logged. If not specified, or if an
671 ! error occurs opening the log file, the default action
672 ! is to output Messages to the screen.
673 ! UNITS: N/A
674 ! TYPE: CHARACTER(*)
675 ! DIMENSION: Scalar
676 ! ATTRIBUTES: INTENT(IN), OPTIONAL
677 !
678 ! FUNCTION RESULT:
679 ! Error_Status: The return value is an integer defining the
680 ! error status. The error codes are defined in
681 ! the Message_Handler module. Values returned by
682 ! this function are:
683 ! SUCCESS == file check was successful
684 ! FAILURE == - error occurred reading a file record,
685 ! - 8- and/or 32-bit integers not supported.
686 ! UNITS: N/A
687 ! TYPE: INTEGER
688 ! DIMENSION: Scalar
689 !
690 !--------------------------------------------------------------------------------
691 
692  FUNCTION check_binary_file( Filename ) RESULT( err_stat )
693  ! Arguments
694  CHARACTER(*), INTENT(IN) :: filename
695  ! Function result
696  INTEGER :: err_stat
697  ! Local parameters
698  CHARACTER(*), PARAMETER :: routine_name = 'Check_Binary_File'
699  ! Local variables
700  CHARACTER(ML) :: msg
701  CHARACTER(ML) :: io_msg
702  INTEGER :: fid
703  INTEGER :: io_stat
704  INTEGER(Long) :: magic_number_read
705  INTEGER(Long) :: magic_number_swapped
706 
707  ! Set up
708  err_stat = success
709 
710 
711  ! Check that 4-byte integers are supported
712  IF ( bit_size( 1_long ) /= 32 ) THEN
713  msg = '32-bit integers not supported. Unable to determine endian-ness'
714  CALL cleanup(); RETURN
715  END IF
716 
717 
718  ! Get a free unit number
719  fid = get_lun()
720  IF ( fid < 0 ) THEN
721  msg = 'Error obtaining file unit number for '//trim(filename)
722  CALL cleanup(); RETURN
723  END IF
724 
725 
726  ! Open the file as direct access
727  OPEN( fid, file = filename , &
728  status = 'OLD' , &
729  action = 'READ' , &
730  access = 'DIRECT' , &
731  form = 'UNFORMATTED', &
732  recl = n_bytes_long , &
733  iostat = io_stat , &
734  iomsg = io_msg )
735  IF ( io_stat /= 0 ) THEN
736  msg = 'Error opening '//trim(filename)//' - '//trim(io_msg)
737  CALL cleanup(); RETURN
738  END IF
739 
740 
741  ! Read the magic number
742  READ( fid, rec=2, iostat=io_stat, iomsg=io_msg ) magic_number_read
743  IF ( io_stat /= 0 ) THEN
744  msg = 'Error reading file magic number - '//trim(io_msg)
745  CALL cleanup(); RETURN
746  END IF
747 
748 
749  ! Close the file
750  CLOSE( fid )
751 
752 
753  ! Compare the magic numbers
754  IF ( magic_number_read /= magic_number ) THEN
755 
756  ! Byte swap the magic number
757  magic_number_swapped = swap_endian( magic_number_read )
758  IF ( magic_number_swapped /= magic_number ) THEN
759  msg = 'Unrecognised file format. Invalid magic number.'
760  CALL cleanup(); RETURN
761  END IF
762 
763  ! If we get here then the data does need to be byte-swapped
764  msg = 'Data file needs to be byte-swapped.'
765  CALL cleanup(); RETURN
766 
767  END IF
768 
769  CONTAINS
770 
771  SUBROUTINE cleanup()
772  IF ( file_open(filename) ) THEN
773  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
774  IF ( io_stat /= 0 ) &
775  msg = trim(msg)//'; Error closing file during error cleanup - '//trim(io_msg)
776  END IF
777  err_stat = failure
778  CALL display_message( routine_name, msg, err_stat )
779  END SUBROUTINE cleanup
780 
781  END FUNCTION check_binary_file
782 
783 END MODULE binary_file_utility
subroutine readgatts_cleanup()
subroutine readsinglegatt(gattname, gattvalue)
integer, parameter, public failure
integer, parameter, public warning
integer, parameter, public long
Definition: Type_Kinds.f90:76
character(*), parameter history_gattname
character(*), parameter title_gattname
subroutine cleanup()
integer function writelogical_scalar(fid, logical_value)
integer, parameter gl
integer function, public readgatts_binary_file(fid, Write_Module, Created_On, Title, History, Comment)
integer(long), parameter magic_number
integer(long), parameter true
integer, parameter ml
integer, parameter, public n_bytes_long
Definition: Type_Kinds.f90:82
integer function, public get_lun()
integer(long), parameter false
integer function check_binary_file(Filename)
integer function, public open_binary_file(Filename, FileID, For_Output, No_Check)
recursive subroutine, public display_message(Routine_Name, Message, Error_State, Message_Log)
subroutine writesinglegatt(gattname, gattvalue)
character(*), parameter write_module_gattname
character(*), parameter comment_gattname
character(*), parameter module_version_id
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> tlevel if(PRESENT(start_in) .AND. PRESENT(axsiz_in)) then if(size(start(! the data domain and compute domain must refer to the subdomain being passed ! In this ! since that attempts to gather all data on PE size(field%axes(:)) axsiz(i)
integer function, public writegatts_binary_file(fid, Write_Module, Created_On, Title, History, Comment)
character(*), parameter created_on_gattname
integer function writelogical_rank1(fid, logical_value)
subroutine writegatts_cleanup()
integer, parameter, public success
integer function readlogical_scalar(fid, logical_value)
integer function readlogical_rank1(fid, logical_value)