FV3 Bundle
SEcategory_Define.f90
Go to the documentation of this file.
1 !
2 ! SEcategory_Define
3 !
4 ! Module defining the SEcategory object.
5 !
6 !
7 ! CREATION HISTORY:
8 ! Written by: Paul van Delst, 17-Aug-2011
9 ! paul.vandelst@noaa.gov
10 
12 
13  ! -----------------
14  ! Environment setup
15  ! -----------------
16  ! Module use
17  USE type_kinds , ONLY: fp, long, double
19  USE compare_float_numbers, ONLY: OPERATOR(.equalto.)
26  ! Disable implicit typing
27  IMPLICIT NONE
28 
29 
30  ! ------------
31  ! Visibilities
32  ! ------------
33  ! Everything private by default
34  PRIVATE
35  ! Parameters
36  PUBLIC :: secategory_datatype
37  ! Datatypes
38  PUBLIC :: secategory_type
39  ! Operators
40  PUBLIC :: OPERATOR(==)
41  ! Procedures
42  PUBLIC :: secategory_associated
43  PUBLIC :: secategory_destroy
44  PUBLIC :: secategory_create
45  PUBLIC :: secategory_inspect
46  PUBLIC :: secategory_validrelease
47  PUBLIC :: secategory_info
48  PUBLIC :: secategory_name
49  PUBLIC :: secategory_index
50  PUBLIC :: secategory_defineversion
51  PUBLIC :: secategory_setvalue
52  PUBLIC :: secategory_getvalue
53  PUBLIC :: secategory_inquirefile
54  PUBLIC :: secategory_readfile
55  PUBLIC :: secategory_writefile
56 
57 
58  ! ---------------------
59  ! Procedure overloading
60  ! ---------------------
61  INTERFACE OPERATOR(==)
62  MODULE PROCEDURE secategory_equal
63  END INTERFACE OPERATOR(==)
64 
65 
66  ! -----------------
67  ! Module parameters
68  ! -----------------
69  CHARACTER(*), PARAMETER :: module_version_id = &
70  '$Id: SEcategory_Define.f90 60152 2015-08-13 19:19:13Z paul.vandelst@noaa.gov $'
71  ! Datatype information
72  CHARACTER(*), PARAMETER :: secategory_datatype = 'SEcategory'
73  ! Release and version
74  INTEGER, PARAMETER :: secategory_release = 3 ! This determines structure and file formats.
75  INTEGER, PARAMETER :: secategory_version = 1 ! This is just the default data version.
76  ! Close status for write errors
77  CHARACTER(*), PARAMETER :: write_error_status = 'DELETE'
78  ! Literal constants
79  REAL(fp), PARAMETER :: zero = 0.0_fp
80  REAL(fp), PARAMETER :: one = 1.0_fp
81  ! String lengths
82  INTEGER, PARAMETER :: ml = 256 ! Message length
83  INTEGER, PARAMETER :: sl = 80 ! String length
84 
85 
86  ! ----------------------------------
87  ! SEcategory data type definitions
88  ! ----------------------------------
89  !:tdoc+:
91  ! Allocation indicator
92  LOGICAL :: is_allocated = .false.
93  ! Datatype information
94  CHARACTER(SL) :: datatype_name = secategory_datatype
95  ! Release and version information
96  INTEGER(Long) :: release = secategory_release
97  INTEGER(Long) :: version = secategory_version
98  ! Surface classification name
99  CHARACTER(SL) :: classification_name = ''
100  ! Dimensions
101  INTEGER(Long) :: string_length = sl
102  INTEGER(Long) :: n_frequencies = 0 ! L dim.
103  INTEGER(Long) :: n_surface_types = 0 ! N dim.
104  ! Dimensional vectors
105  REAL(Double), ALLOCATABLE :: frequency(:) ! Lx1
106  CHARACTER(SL), ALLOCATABLE :: surface_type(:) ! Nx1
107  ! Surface type validity array
108  LOGICAL, ALLOCATABLE :: surface_type_isvalid(:) ! Nx1
109  ! Reflectance LUT data
110  REAL(Double), ALLOCATABLE :: reflectance(:,:) ! LxN
111  END TYPE secategory_type
112  !:tdoc-:
113 
114 
115 CONTAINS
116 
117 
118 !################################################################################
119 !################################################################################
120 !## ##
121 !## ## PUBLIC PROCEDURES ## ##
122 !## ##
123 !################################################################################
124 !################################################################################
125 
126 !--------------------------------------------------------------------------------
127 !:sdoc+:
128 !
129 ! NAME:
130 ! SEcategory_Associated
131 !
132 ! PURPOSE:
133 ! Elemental function to test the status of the allocatable components
134 ! of the SEcategory structure.
135 !
136 ! CALLING SEQUENCE:
137 ! Status = SEcategory_Associated( SEcategory )
138 !
139 ! OBJECTS:
140 ! SEcategory: Structure which is to have its member's
141 ! status tested.
142 ! UNITS: N/A
143 ! TYPE: SEcategory_type
144 ! DIMENSION: Scalar or any rank
145 ! ATTRIBUTES: INTENT(IN)
146 !
147 ! FUNCTION RESULT:
148 ! Status: The return value is a logical value indicating the
149 ! status of the NLTE members.
150 ! .TRUE. - if ANY of the SEcategory allocatable members
151 ! are in use.
152 ! .FALSE. - if ALL of the SEcategory allocatable members
153 ! are not in use.
154 ! UNITS: N/A
155 ! TYPE: LOGICAL
156 ! DIMENSION: Same as input
157 !
158 !:sdoc-:
159 !--------------------------------------------------------------------------------
160 
161  ELEMENTAL FUNCTION secategory_associated( self ) RESULT( Status )
162  TYPE(secategory_type), INTENT(IN) :: self
163  LOGICAL :: status
164  status = self%Is_Allocated
165  END FUNCTION secategory_associated
166 
167 
168 !--------------------------------------------------------------------------------
169 !:sdoc+:
170 !
171 ! NAME:
172 ! SEcategory_Destroy
173 !
174 ! PURPOSE:
175 ! Elemental subroutine to re-initialize SEcategory objects.
176 !
177 ! CALLING SEQUENCE:
178 ! CALL SEcategory_Destroy( SEcategory )
179 !
180 ! OBJECTS:
181 ! SEcategory: Re-initialized SEcategory structure.
182 ! UNITS: N/A
183 ! TYPE: SEcategory_type
184 ! DIMENSION: Scalar or any rank
185 ! ATTRIBUTES: INTENT(OUT)
186 !
187 !:sdoc-:
188 !--------------------------------------------------------------------------------
189 
190  ELEMENTAL SUBROUTINE secategory_destroy( self )
191  TYPE(secategory_type), INTENT(OUT) :: self
192  self%Is_Allocated = .false.
193  self%n_Frequencies = 0
194  self%n_Surface_Types = 0
195  END SUBROUTINE secategory_destroy
196 
197 
198 !--------------------------------------------------------------------------------
199 !:sdoc+:
200 !
201 ! NAME:
202 ! SEcategory_Create
203 !
204 ! PURPOSE:
205 ! Elemental subroutine to create an instance of an SEcategory object.
206 !
207 ! CALLING SEQUENCE:
208 ! CALL SEcategory_Create( SEcategory , &
209 ! n_Frequencies , &
210 ! n_Surface_Types )
211 !
212 ! OBJECTS:
213 ! SEcategory: SEcategory object structure.
214 ! UNITS: N/A
215 ! TYPE: SEcategory_type
216 ! DIMENSION: Scalar or any rank
217 ! ATTRIBUTES: INTENT(OUT)
218 !
219 ! INPUTS:
220 ! n_Frequencies: Number of spectral frequencies for which there are
221 ! reflectance data.
222 ! Must be > 0.
223 ! UNITS: N/A
224 ! TYPE: INTEGER
225 ! DIMENSION: Conformable with the SEcategory object
226 ! ATTRIBUTES: INTENT(IN)
227 !
228 ! n_Surface_Types: Number of land surface types for which is are
229 ! reflectance data.
230 ! Must be > 0.
231 ! UNITS: N/A
232 ! TYPE: INTEGER
233 ! DIMENSION: Conformable with the SEcategory object
234 ! ATTRIBUTES: INTENT(IN)
235 !
236 !:sdoc-:
237 !--------------------------------------------------------------------------------
238 
239  ELEMENTAL SUBROUTINE secategory_create( &
240  self , & ! Output
241  n_Frequencies , & ! Input
242  n_Surface_Types ) ! Input
243  ! Arguments
244  TYPE(secategory_type), INTENT(OUT) :: self
245  INTEGER , INTENT(IN) :: n_frequencies
246  INTEGER , INTENT(IN) :: n_surface_types
247  ! Local variables
248  INTEGER :: alloc_stat
249 
250  ! Check input
251  IF ( n_frequencies < 1 .OR. &
252  n_surface_types < 1 ) RETURN
253 
254 
255  ! Perform the allocation
256  ALLOCATE( self%Surface_Type_IsValid( n_surface_types ), &
257  self%Frequency( n_frequencies ), &
258  self%Surface_Type( n_surface_types ), &
259  self%Reflectance( n_frequencies, n_surface_types ), &
260  stat = alloc_stat )
261  IF ( alloc_stat /= 0 ) RETURN
262 
263 
264  ! Initialise
265  ! ...Dimensions
266  self%n_Frequencies = n_frequencies
267  self%n_Surface_Types = n_surface_types
268  ! ...Arrays
269  self%Surface_Type_IsValid = .true.
270  self%Frequency = zero
271  self%Surface_Type = ''
272  self%Reflectance = zero
273 
274  ! Set allocation indicator
275  self%Is_Allocated = .true.
276 
277  END SUBROUTINE secategory_create
278 
279 
280 !--------------------------------------------------------------------------------
281 !:sdoc+:
282 !
283 ! NAME:
284 ! SEcategory_Inspect
285 !
286 ! PURPOSE:
287 ! Subroutine to print the contents of a SEcategory object to stdout.
288 !
289 ! CALLING SEQUENCE:
290 ! CALL SEcategory_Inspect( SEcategory )
291 !
292 ! OBJECTS:
293 ! SEcategory: SEcategory object to display.
294 ! UNITS: N/A
295 ! TYPE: SEcategory_type
296 ! DIMENSION: Scalar
297 ! ATTRIBUTES: INTENT(IN)
298 !
299 !:sdoc-:
300 !--------------------------------------------------------------------------------
301 
302  SUBROUTINE secategory_inspect( self)
303  TYPE(secategory_type), INTENT(IN) :: self
304  INTEGER :: n
305  WRITE(*,'(1x,"SEcategory OBJECT")')
306  ! Release/version info
307  WRITE(*,'(3x,"Release.Version :",1x,i0,".",i0)') self%Release, self%Version
308  ! Surface classification name
309  WRITE(*,'(3x,"Classification_Name :",1x,a)') trim(self%Classification_Name)
310  ! Dimensions
311  WRITE(*,'(3x,"n_Frequencies :",1x,i0)') self%n_Frequencies
312  WRITE(*,'(3x,"n_Surface_Types :",1x,i0)') self%n_Surface_Types
313  IF ( .NOT. secategory_associated(self) ) RETURN
314  ! Dimension arrays
315  WRITE(*,'(3x,"Frequency :")')
316  WRITE(*,'(5(1x,es13.6,:))') self%Frequency
317  WRITE(*,'(3x,"Surface_Type - (IsValid) :")')
318  DO n = 1, self%n_Surface_Types
319  WRITE(*,'(5x,a," - (",l1,")")') trim(self%Surface_Type(n)), self%Surface_Type_IsValid(n)
320  END DO
321  ! Reflectance array
322  WRITE(*,'(3x,"Reflectance :")')
323  DO n = 1, self%n_Surface_Types
324  WRITE(*,'(5x,a)') self%Surface_Type(n)
325  WRITE(*,'(5(1x,es13.6,:))') self%Reflectance(:,n)
326  END DO
327  END SUBROUTINE secategory_inspect
328 
329 
330 
331 !----------------------------------------------------------------------------------
332 !:sdoc+:
333 !
334 ! NAME:
335 ! SEcategory_ValidRelease
336 !
337 ! PURPOSE:
338 ! Function to check the SEcategory Release value.
339 !
340 ! CALLING SEQUENCE:
341 ! IsValid = SEcategory_ValidRelease( SEcategory )
342 !
343 ! INPUTS:
344 ! SEcategory: SEcategory object for which the Release component
345 ! is to be checked.
346 ! UNITS: N/A
347 ! TYPE: SEcategory_type
348 ! DIMENSION: Scalar
349 ! ATTRIBUTES: INTENT(IN)
350 !
351 ! FUNCTION RESULT:
352 ! IsValid: Logical value defining the release validity.
353 ! UNITS: N/A
354 ! TYPE: LOGICAL
355 ! DIMENSION: Scalar
356 !
357 !:sdoc-:
358 !----------------------------------------------------------------------------------
359 
360  FUNCTION secategory_validrelease( self ) RESULT( IsValid )
361  ! Arguments
362  TYPE(secategory_type), INTENT(IN) :: self
363  ! Function result
364  LOGICAL :: isvalid
365  ! Local parameters
366  CHARACTER(*), PARAMETER :: routine_name = 'SEcategory_ValidRelease'
367  ! Local variables
368  CHARACTER(ML) :: msg
369 
370  ! Set up
371  isvalid = .true.
372 
373 
374  ! Check release is not too old
375  IF ( self%Release < secategory_release ) THEN
376  isvalid = .false.
377  WRITE( msg,'("An SEcategory data update is needed. ", &
378  &"SEcategory release is ",i0,". Valid release is ",i0,"." )' ) &
379  self%Release, secategory_release
380  CALL display_message( routine_name, msg, information ); RETURN
381  END IF
382 
383 
384  ! Check release is not too new
385  IF ( self%Release > secategory_release ) THEN
386  isvalid = .false.
387  WRITE( msg,'("An SEcategory software update is needed. ", &
388  &"SEcategory release is ",i0,". Valid release is ",i0,"." )' ) &
389  self%Release, secategory_release
390  CALL display_message( routine_name, msg, information ); RETURN
391  END IF
392 
393  END FUNCTION secategory_validrelease
394 
395 
396 !--------------------------------------------------------------------------------
397 !:sdoc+:
398 !
399 ! NAME:
400 ! SEcategory_Info
401 !
402 ! PURPOSE:
403 ! Subroutine to return a string containing version and dimension
404 ! information about a SEcategory object.
405 !
406 ! CALLING SEQUENCE:
407 ! CALL SEcategory_Info( SEcategory, Info )
408 !
409 ! OBJECTS:
410 ! SEcategory: SEcategory object about which info is required.
411 ! UNITS: N/A
412 ! TYPE: SEcategory_type
413 ! DIMENSION: Scalar
414 ! ATTRIBUTES: INTENT(IN)
415 !
416 ! OUTPUTS:
417 ! Info: String containing version and dimension information
418 ! about the SEcategory object.
419 ! UNITS: N/A
420 ! TYPE: CHARACTER(*)
421 ! DIMENSION: Scalar
422 ! ATTRIBUTES: INTENT(OUT)
423 !
424 !:sdoc-:
425 !--------------------------------------------------------------------------------
426 
427  SUBROUTINE secategory_info( self, Info )
428  ! Arguments
429  TYPE(secategory_type), INTENT(IN) :: self
430  CHARACTER(*), INTENT(OUT) :: info
431  ! Parameters
432  INTEGER, PARAMETER :: carriage_return = 13
433  INTEGER, PARAMETER :: linefeed = 10
434  ! Local variables
435  CHARACTER(2000) :: long_string
436 
437  ! Write the required data to the local string
438  WRITE( long_string, &
439  '(a,1x,"SEcategory RELEASE.VERSION: ",i2,".",i2.2,a,3x, &
440  &"CLASSIFICATION: ",a,",",2x,&
441  &"N_FREQUENCIES=",i0,2x,&
442  &"N_SURFACE_TYPES=",i0 )' ) &
443  achar(carriage_return)//achar(linefeed), &
444  self%Release, self%Version, &
445  achar(carriage_return)//achar(linefeed), &
446  trim(self%Classification_Name), &
447  self%n_Frequencies, &
448  self%n_Surface_Types
449 
450  ! Trim the output based on the
451  ! dummy argument string length
452  info = long_string(1:min(len(info), len_trim(long_string)))
453 
454  END SUBROUTINE secategory_info
455 
456 
457 !--------------------------------------------------------------------------------
458 !:sdoc+:
459 !
460 ! NAME:
461 ! SEcategory_Name
462 !
463 ! PURPOSE:
464 ! Pure function to return the datatype name of an SEcategory object.
465 !
466 ! CALLING SEQUENCE:
467 ! datatype_name = SEcategory_Name( SEcategory )
468 !
469 ! OBJECTS:
470 ! SEcategory: SEcategory object structure.
471 ! UNITS: N/A
472 ! TYPE: SEcategory_type
473 ! DIMENSION: Scalar
474 ! ATTRIBUTES: INTENT(IN)
475 !
476 ! FUNCTION RESULT:
477 ! Status: The return value is a the character string containing
478 ! the datatype name of the structure.
479 ! UNITS: N/A
480 ! TYPE: CHARACTER
481 ! DIMENSION: Scalar
482 !
483 !:sdoc-:
484 !--------------------------------------------------------------------------------
485 
486  PURE FUNCTION secategory_name( self ) RESULT( datatype_name )
487  ! Arguments
488  TYPE(secategory_type), INTENT(IN) :: self
489  ! Function result
490  CHARACTER(LEN(self%Datatype_Name)) :: datatype_name
491 
492  datatype_name = self%Datatype_Name
493 
494  END FUNCTION secategory_name
495 
496 
497 !--------------------------------------------------------------------------------
498 !:sdoc+:
499 !
500 ! NAME:
501 ! SEcategory_Index
502 !
503 ! PURPOSE:
504 ! Pure function to return the index of a particular surface type
505 ! in the SEcategory object.
506 !
507 ! CALLING SEQUENCE:
508 ! idx = SEcategory_Index( SEcategory, Surface_Type )
509 !
510 ! OBJECTS:
511 ! SEcategory: Valid, allocated SEcategory object from which
512 ! the surface type index is to be retrieved.
513 ! UNITS: N/A
514 ! TYPE: SEcategory_type
515 ! DIMENSION: Scalar
516 ! ATTRIBUTES: INTENT(IN)
517 !
518 ! INPUTS:
519 ! Surface_Type: Character string containing the name of the
520 ! surface type for which the index is required.
521 ! UNITS: N/A
522 ! TYPE: CHARACTER(*)
523 ! DIMENSION: Scalar
524 ! ATTRIBUTES: INTENT(IN)
525 !
526 ! FUNCTION RESULT:
527 ! idx: The index along the surface type dimension corresponding
528 ! to the requested surface type name.
529 ! If no surface type match is found, the value 0 is returned.
530 ! UNITS: N/A
531 ! TYPE: INTEGER
532 ! DIMENSION: Scalar
533 !
534 !:sdoc-:
535 !--------------------------------------------------------------------------------
536 
537  PURE FUNCTION secategory_index( &
538  self , & ! Input
539  Surface_Type ) & ! Input
540  result( idx )
541  ! Arguments
542  TYPE(secategory_type), INTENT(IN) :: self
543  CHARACTER(*) , INTENT(IN) :: surface_type
544  ! Function result
545  INTEGER :: idx
546  ! Local variables
547  INTEGER :: i
548 
549  ! Setup
550  idx = 0
551  IF ( .NOT. secategory_associated(self) ) RETURN
552 
553  ! Match surface type and assign
554  DO i = 1, self%n_Surface_Types
555  IF ( self%Surface_Type(i) == surface_type ) THEN
556  idx = i
557  RETURN
558  END IF
559  END DO
560 
561  END FUNCTION secategory_index
562 
563 
564 !--------------------------------------------------------------------------------
565 !:sdoc+:
566 !
567 ! NAME:
568 ! SEcategory_DefineVersion
569 !
570 ! PURPOSE:
571 ! Subroutine to return the module version information.
572 !
573 ! CALLING SEQUENCE:
574 ! CALL SEcategory_DefineVersion( Id )
575 !
576 ! OUTPUTS:
577 ! Id: Character string containing the version Id information
578 ! for the module.
579 ! UNITS: N/A
580 ! TYPE: CHARACTER(*)
581 ! DIMENSION: Scalar
582 ! ATTRIBUTES: INTENT(OUT)
583 !
584 !:sdoc-:
585 !--------------------------------------------------------------------------------
586 
587  SUBROUTINE secategory_defineversion( Id )
588  CHARACTER(*), INTENT(OUT) :: id
589  id = module_version_id
590  END SUBROUTINE secategory_defineversion
591 
592 
593 
594 !--------------------------------------------------------------------------------
595 !:sdoc+:
596 !
597 ! NAME:
598 ! SEcategory_SetValue
599 !
600 ! PURPOSE:
601 ! Subroutine to set the contents of a valid SEcategory object.
602 !
603 ! CALLING SEQUENCE:
604 ! CALL SEcategory_SetValue( SEcategory, &
605 ! Version = Version , &
606 ! Classification_Name = Classification_Name , &
607 ! Frequency = Frequency , &
608 ! Surface_Type = Surface_Type , &
609 ! Surface_Type_IsValid = Surface_Type_IsValid, &
610 ! Reflectance = Reflectance )
611 !
612 ! OBJECTS:
613 ! SEcategory: Valid, allocated SEcategory object for which
614 ! values are to be set.
615 ! UNITS: N/A
616 ! TYPE: SEcategory_type
617 ! DIMENSION: Scalar
618 ! ATTRIBUTES: INTENT(IN OUT)
619 !
620 ! OPTIONAL INPUTS:
621 ! Version: Integer indicating the data version. If not specified
622 ! the value of the module parameter SECATEGORY_VERSION
623 ! is used.
624 ! UNITS: N/A
625 ! TYPE: INTEGER
626 ! DIMENSION: Scalar
627 ! ATTRIBUTES: INTENT(IN), OPTIONAL
628 !
629 ! Classification_Name: String identifying the classification system used
630 ! for the surface types.
631 ! UNITS: N/A
632 ! TYPE: INTEGER
633 ! DIMENSION: Scalar
634 ! ATTRIBUTES: INTENT(IN), OPTIONAL
635 !
636 ! Frequency: Real array to which the Frequency component of the
637 ! SEcategory object is to be set. The size of the
638 ! input must match the allocated size of the component,
639 ! otherwise all the component values are set to zero.
640 ! UNITS: N/A
641 ! TYPE: REAL(fp)
642 ! DIMENSION: Rank-1 (L)
643 ! ATTRIBUTES: INTENT(IN), OPTIONAL
644 !
645 ! Surface_Type: Character array to which the Surface_Type component
646 ! of the SEcategory object is to be set. The size of the
647 ! input must match the allocated size of the component,
648 ! otherwise all the component values are set to a blank string.
649 ! UNITS: N/A
650 ! TYPE: CHARACTER(*)
651 ! DIMENSION: Rank-1 (N)
652 ! ATTRIBUTES: INTENT(IN), OPTIONAL
653 !
654 ! Surface_Type_IsValid: Logical array to specify if a particular surface type is
655 ! valid for the context in which it is to be used.
656 ! UNITS: N/A
657 ! TYPE: LOGICAL
658 ! DIMENSION: Rank-1 (N)
659 ! ATTRIBUTES: INTENT(IN), OPTIONAL
660 !
661 ! Reflectance: Real array to which the Reflectance component of the
662 ! SEcategory object is to be set. The size of the
663 ! input must match the allocated size of the component,
664 ! otherwise all the component values are set to zero.
665 ! UNITS: N/A
666 ! TYPE: REAL(fp)
667 ! DIMENSION: Rank-2 (L x N)
668 ! ATTRIBUTES: INTENT(IN), OPTIONAL
669 !
670 !:sdoc-:
671 !--------------------------------------------------------------------------------
672 
673  SUBROUTINE secategory_setvalue( &
674  self , & ! Input
675  Version , & ! Optional input
676  Classification_Name , & ! Optional input
677  Frequency , & ! Optional input
678  Surface_Type , & ! Optional input
679  Surface_Type_IsValid, & ! Optional input
680  Reflectance ) ! Optional input
681  ! Arguments
682  TYPE(secategory_type) , INTENT(IN OUT) :: self
683  INTEGER , OPTIONAL, INTENT(IN) :: version
684  CHARACTER(*), OPTIONAL, INTENT(IN) :: classification_name
685  REAL(fp) , OPTIONAL, INTENT(IN) :: frequency(:)
686  CHARACTER(*), OPTIONAL, INTENT(IN) :: surface_type(:)
687  LOGICAL , OPTIONAL, INTENT(IN) :: surface_type_isvalid(:)
688  REAL(fp) , OPTIONAL, INTENT(IN) :: reflectance(:,:)
689 
690  IF ( .NOT. secategory_associated(self) ) RETURN
691 
692  IF ( PRESENT(version) ) self%Version = version
693  IF ( PRESENT(classification_name) ) self%Classification_Name = classification_name
694 
695  IF ( PRESENT(frequency) ) THEN
696  IF ( SIZE(frequency) == self%n_Frequencies ) THEN
697  self%Frequency = frequency
698  ELSE
699  self%Frequency = zero
700  END IF
701  END IF
702 
703  IF ( PRESENT(surface_type) ) THEN
704  IF ( SIZE(surface_type) == self%n_Surface_Types ) THEN
705  self%Surface_Type = surface_type
706  ELSE
707  self%Surface_Type = ''
708  END IF
709  END IF
710 
711  IF ( PRESENT(surface_type_isvalid) ) THEN
712  IF ( SIZE(surface_type_isvalid) == self%n_Surface_Types ) THEN
713  self%Surface_Type_IsValid = surface_type_isvalid
714  ELSE
715  self%Surface_Type_IsValid = .false.
716  END IF
717  END IF
718 
719  IF ( PRESENT(reflectance) ) THEN
720  IF ( SIZE(reflectance,dim=1) == self%n_Frequencies .AND. &
721  SIZE(reflectance,dim=2) == self%n_Surface_Types ) THEN
722  self%Reflectance = reflectance
723  ELSE
724  self%Reflectance = zero
725  END IF
726  END IF
727 
728  END SUBROUTINE secategory_setvalue
729 
730 
731 !--------------------------------------------------------------------------------
732 !:sdoc+:
733 !
734 ! NAME:
735 ! SEcategory_GetValue
736 !
737 ! PURPOSE:
738 ! Subroutine to get the contents of a valid SEcategory object.
739 !
740 ! CALLING SEQUENCE:
741 ! CALL SEcategory_GetValue( SEcategory, &
742 ! Surface_Type_ToGet = Surface_Type_ToGet , &
743 ! Version = Version , &
744 ! Classification_Name = Classification_Name , &
745 ! n_Frequencies = n_Frequencies , &
746 ! n_Surface_Types = n_Surface_Types , &
747 ! Frequency = Frequency , &
748 ! Surface_Type = Surface_Type , &
749 ! Surface_Type_IsValid = Surface_Type_IsValid, &
750 ! Reflectance = Reflectance , &
751 ! Surface_Reflectance = Surface_Reflectance )
752 !
753 ! OBJECTS:
754 ! SEcategory: Valid, allocated SEcategory object from which
755 ! values are to be retrieved.
756 ! UNITS: N/A
757 ! TYPE: SEcategory_type
758 ! DIMENSION: Scalar
759 ! ATTRIBUTES: INTENT(IN)
760 !
761 ! OPTIONAL INPUTS:
762 ! Surface_Type_ToGet: Character string containing a valid surface type
763 ! name in the SEcategory object.
764 ! NOTE: - This argument is used in conjuction with
765 ! the Surface_Reflectance dummy output
766 ! argument to retrieve the reflectance of a
767 ! particular surface type.
768 ! - This argument is ignored if the optional
769 ! Surface_Reflectance argument is not also
770 ! provided.
771 ! UNITS: N/A
772 ! TYPE: CHARACTER(*)
773 ! DIMENSION: Scalar
774 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
775 !
776 ! OPTIONAL OUTPUTS:
777 ! Version: Integer indicating the data version of the object.
778 ! UNITS: N/A
779 ! TYPE: INTEGER
780 ! DIMENSION: Scalar
781 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
782 !
783 ! Classification_Name: String identifying the classification system used
784 ! for the surface types.
785 ! UNITS: N/A
786 ! TYPE: INTEGER
787 ! DIMENSION: Scalar
788 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
789 !
790 ! Frequency: Real array to which the Frequency component of the
791 ! SEcategory object will be assigned. The actual
792 ! argument must be declared as allocatable.
793 ! UNITS: N/A
794 ! TYPE: REAL(fp)
795 ! DIMENSION: Rank-1 (L)
796 ! ATTRIBUTES: INTENT(OUT), OPTIONAL, ALLOCATABLE
797 !
798 ! Surface_Type: Character array to which the Surface_Type component
799 ! of the SEcategory object will be assigned. The actual
800 ! argument must be declared as allocatable.
801 ! UNITS: N/A
802 ! TYPE: CHARACTER(*)
803 ! DIMENSION: Rank-1 (N)
804 ! ATTRIBUTES: INTENT(OUT), OPTIONAL, ALLOCATABLE
805 !
806 ! Surface_Type_IsValid: Logical array that specifies if a particular surface
807 ! type is valid for the context in which it is to be used.
808 ! UNITS: N/A
809 ! TYPE: LOGICAL
810 ! DIMENSION: Rank-1 (N)
811 ! ATTRIBUTES: INTENT(IN), OPTIONAL, ALLOCATABLE
812 !
813 ! Reflectance: Real array to which the Reflectance component of the
814 ! SEcategory object will be assigned. The actual
815 ! argument must be declared as allocatable.
816 ! UNITS: N/A
817 ! TYPE: REAL(fp)
818 ! DIMENSION: Rank-2 (L x N)
819 ! ATTRIBUTES: INTENT(OUT), OPTIONAL, ALLOCATABLE
820 !
821 ! Surface_Reflectance: Real array to which the Reflectance component for a
822 ! given surface type in SEcategory object will be
823 ! assigned. The actual argument must be declared as
824 ! allocatable.
825 ! NOTE: - This argument is used in conjuction with
826 ! the Surface_Type_ToGet dummy input
827 ! argument to retrieve the reflectance of a
828 ! particular surface type.
829 ! - This argument is ignored if the optional
830 ! Surface_Type_ToGet argument is not
831 ! also provided.
832 ! UNITS: N/A
833 ! TYPE: REAL(fp)
834 ! DIMENSION: Rank-1 (L)
835 ! ATTRIBUTES: INTENT(OUT), OPTIONAL, ALLOCATABLE
836 !
837 !:sdoc-:
838 !--------------------------------------------------------------------------------
839 
840  SUBROUTINE secategory_getvalue( &
841  self , & ! Input
842  Surface_Type_ToGet , & ! Optional input
843  Version , & ! Optional output
844  Classification_Name , & ! Optional output
845  n_Frequencies , & ! Optional output
846  n_Surface_Types , & ! Optional output
847  Frequency , & ! Optional output
848  Surface_Type , & ! Optional output
849  Surface_Type_IsValid, & ! Optional output
850  Reflectance , & ! Optional output
851  Surface_Reflectance ) ! Optional output
852  ! Arguments
853  TYPE(secategory_type), INTENT(IN) :: self
854  CHARACTER(*), OPTIONAL, INTENT(IN) :: surface_type_toget
855  INTEGER , OPTIONAL, INTENT(OUT) :: version
856  CHARACTER(*), OPTIONAL, INTENT(OUT) :: classification_name
857  INTEGER , OPTIONAL, INTENT(OUT) :: n_frequencies
858  INTEGER , OPTIONAL, INTENT(OUT) :: n_surface_types
859  REAL(fp) , ALLOCATABLE, OPTIONAL, INTENT(OUT) :: frequency(:)
860  CHARACTER(*), ALLOCATABLE, OPTIONAL, INTENT(OUT) :: surface_type(:)
861  LOGICAL , ALLOCATABLE, OPTIONAL, INTENT(OUT) :: surface_type_isvalid(:)
862  REAL(fp) , ALLOCATABLE, OPTIONAL, INTENT(OUT) :: reflectance(:,:)
863  REAL(fp) , ALLOCATABLE, OPTIONAL, INTENT(OUT) :: surface_reflectance(:)
864  ! Local variables
865  INTEGER :: i
866 
867  IF ( .NOT. secategory_associated(self) ) RETURN
868 
869  IF ( PRESENT(version ) ) version = self%Version
870  IF ( PRESENT(classification_name) ) classification_name = self%Classification_Name
871  IF ( PRESENT(n_frequencies ) ) n_frequencies = self%n_Frequencies
872  IF ( PRESENT(n_surface_types ) ) n_surface_types = self%n_Surface_Types
873 
874  IF ( PRESENT(frequency) ) THEN
875  ALLOCATE(frequency(self%n_Frequencies))
876  frequency = self%Frequency
877  END IF
878 
879  IF ( PRESENT(surface_type) ) THEN
880  ALLOCATE(surface_type(self%n_Surface_Types))
881  surface_type = self%Surface_Type
882  END IF
883 
884  IF ( PRESENT(surface_type_isvalid) ) THEN
885  ALLOCATE(surface_type_isvalid(self%n_Surface_Types))
886  surface_type_isvalid = self%Surface_Type_IsValid
887  END IF
888 
889  IF ( PRESENT(reflectance) ) THEN
890  ALLOCATE(reflectance(self%n_Frequencies, self%n_Surface_Types))
891  reflectance = self%Reflectance
892  END IF
893 
894  IF ( PRESENT(surface_type_toget) .AND. PRESENT(surface_reflectance) ) THEN
895  ! Match surface type and assign
896  i = secategory_index(self,surface_type_toget)
897  IF ( i > 0 ) THEN
898  ALLOCATE(surface_reflectance(self%n_Frequencies))
899  surface_reflectance = self%Reflectance(:,i)
900  END IF
901  END IF
902 
903  END SUBROUTINE secategory_getvalue
904 
905 
906 !------------------------------------------------------------------------------
907 !:sdoc+:
908 !
909 ! NAME:
910 ! SEcategory_InquireFile
911 !
912 ! PURPOSE:
913 ! Function to inquire SEcategory object files.
914 !
915 ! CALLING SEQUENCE:
916 ! Error_Status = SEcategory_InquireFile( &
917 ! Filename , &
918 ! n_Frequencies = n_Frequencies , &
919 ! n_Surface_Types = n_Surface_Types, &
920 ! Release = Release , &
921 ! Version = Version )
922 !
923 ! INPUTS:
924 ! Filename: Character string specifying the name of the
925 ! data file to inquire.
926 ! UNITS: N/A
927 ! TYPE: CHARACTER(*)
928 ! DIMENSION: Scalar
929 ! ATTRIBUTES: INTENT(IN)
930 !
931 ! OPTIONAL OUTPUTS:
932 ! n_Frequencies: Number of spectral frequencies for which there are
933 ! reflectance data.
934 ! UNITS: N/A
935 ! TYPE: INTEGER
936 ! DIMENSION: Scalar
937 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
938 !
939 ! n_Surface_Types: Number of land surface types for which is are
940 ! reflectance data.
941 ! UNITS: N/A
942 ! TYPE: INTEGER
943 ! DIMENSION: Scalar
944 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
945 !
946 ! Release: The data/file release number. Used to check
947 ! for data/software mismatch.
948 ! UNITS: N/A
949 ! TYPE: INTEGER
950 ! DIMENSION: Scalar
951 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
952 !
953 ! Version: The data/file version number. Used for
954 ! purposes only in identifying the dataset for
955 ! a particular release.
956 ! UNITS: N/A
957 ! TYPE: INTEGER
958 ! DIMENSION: Scalar
959 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
960 !
961 ! FUNCTION RESULT:
962 ! Error_Status: The return value is an integer defining the error
963 ! status. The error codes are defined in the
964 ! Message_Handler module.
965 ! If == SUCCESS the file inquire was successful
966 ! == FAILURE an unrecoverable error occurred.
967 ! UNITS: N/A
968 ! TYPE: INTEGER
969 ! DIMENSION: Scalar
970 !
971 !:sdoc-:
972 !------------------------------------------------------------------------------
973 
974  FUNCTION secategory_inquirefile( &
975  Filename , & ! Input
976  n_Frequencies , & ! Optional output
977  n_Surface_Types, & ! Optional output
978  Release , & ! Optional output
979  Version , & ! Optional output
980  Title , & ! Optional output
981  History , & ! Optional output
982  Comment ) & ! Optional output
983  result( err_stat )
984  ! Arguments
985  CHARACTER(*), INTENT(IN) :: filename
986  INTEGER , OPTIONAL, INTENT(OUT) :: n_frequencies
987  INTEGER , OPTIONAL, INTENT(OUT) :: n_surface_types
988  INTEGER , OPTIONAL, INTENT(OUT) :: release
989  INTEGER , OPTIONAL, INTENT(OUT) :: version
990  CHARACTER(*), OPTIONAL, INTENT(OUT) :: title
991  CHARACTER(*), OPTIONAL, INTENT(OUT) :: history
992  CHARACTER(*), OPTIONAL, INTENT(OUT) :: comment
993  ! Function result
994  INTEGER :: err_stat
995  ! Function parameters
996  CHARACTER(*), PARAMETER :: routine_name = 'SEcategory_InquireFile'
997  ! Function variables
998  CHARACTER(ML) :: msg
999  CHARACTER(ML) :: io_msg
1000  INTEGER :: io_stat
1001  INTEGER :: fid
1002  TYPE(secategory_type) :: secategory
1003 
1004 
1005  ! Setup
1006  err_stat = success
1007  ! ...Check that the file exists
1008  IF ( .NOT. file_exists( filename ) ) THEN
1009  msg = 'File '//trim(filename)//' not found.'
1010  CALL inquire_cleanup(); RETURN
1011  END IF
1012 
1013 
1014  ! Open the file
1015  err_stat = open_binary_file( filename, fid )
1016  IF ( err_stat /= success ) THEN
1017  msg = 'Error opening '//trim(filename)
1018  CALL inquire_cleanup(); RETURN
1019  END IF
1020 
1021 
1022  ! Read and check the datatype name
1023  err_stat = read_datatype( fid, secategory%Datatype_name )
1024  IF ( err_stat /= success ) THEN
1025  msg = 'Error reading Datatype_Name'
1026  CALL inquire_cleanup(); RETURN
1027  END IF
1028  IF ( trim(secategory%Datatype_Name) /= secategory_datatype ) THEN
1029  msg = secategory_datatype//' datatype name check failed.'
1030  CALL inquire_cleanup(); RETURN
1031  END IF
1032 
1033 
1034  ! Read the release and version
1035  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1036  secategory%Release, &
1037  secategory%Version
1038  IF ( io_stat /= 0 ) THEN
1039  msg = 'Error reading Release/Version - '//trim(io_msg)
1040  CALL inquire_cleanup(); RETURN
1041  END IF
1042  IF ( .NOT. secategory_validrelease( secategory ) ) THEN
1043  msg = 'SEcategory Release check failed.'
1044  CALL inquire_cleanup(); RETURN
1045  END IF
1046 
1047 
1048  ! Read the dimensions
1049  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1050  secategory%n_Frequencies , &
1051  secategory%n_Surface_Types
1052  IF ( io_stat /= 0 ) THEN
1053  msg = 'Error reading dimension values from '//trim(filename)//' - '//trim(io_msg)
1054  CALL inquire_cleanup(); RETURN
1055  END IF
1056 
1057 
1058  ! Read the global attributes
1059  err_stat = readgatts_binary_file( &
1060  fid, &
1061  title = title , &
1062  history = history, &
1063  comment = comment )
1064  IF ( err_stat /= success ) THEN
1065  msg = 'Error reading global attributes'
1066  CALL inquire_cleanup(); RETURN
1067  END IF
1068 
1069 
1070  ! Close the file
1071  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1072  IF ( io_stat /= 0 ) THEN
1073  msg = 'Error closing '//trim(filename)//' - '//trim(io_msg)
1074  CALL inquire_cleanup(); RETURN
1075  END IF
1076 
1077 
1078  ! Assign the return arguments
1079  IF ( PRESENT(n_frequencies ) ) n_frequencies = secategory%n_Frequencies
1080  IF ( PRESENT(n_surface_types) ) n_surface_types = secategory%n_Surface_Types
1081  IF ( PRESENT(release ) ) release = secategory%Release
1082  IF ( PRESENT(version ) ) version = secategory%Version
1083 
1084  CONTAINS
1085 
1086  SUBROUTINE inquire_cleanup()
1087  ! Close file if necessary
1088  IF ( file_open(fid) ) THEN
1089  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1090  IF ( io_stat /= 0 ) &
1091  msg = trim(msg)//'; Error closing input file during error cleanup - '//trim(io_msg)
1092  END IF
1093  ! Set error status and print error message
1094  err_stat = failure
1095  CALL display_message( routine_name, msg, err_stat )
1096  END SUBROUTINE inquire_cleanup
1097 
1098  END FUNCTION secategory_inquirefile
1099 
1100 
1101 !--------------------------------------------------------------------------------
1102 !:sdoc+:
1103 !
1104 ! NAME:
1105 ! SEcategory_ReadFile
1106 !
1107 ! PURPOSE:
1108 ! Function to read SEcategory object files.
1109 !
1110 ! CALLING SEQUENCE:
1111 ! Error_Status = SEcategory_ReadFile( &
1112 ! SEcategory , &
1113 ! Filename , &
1114 ! No_Close = No_Close, &
1115 ! Quiet = Quiet )
1116 !
1117 ! OBJECTS:
1118 ! SEcategory: SEcategory object containing the data read from file.
1119 ! UNITS: N/A
1120 ! TYPE: SEcategory_type
1121 ! DIMENSION: Scalar
1122 ! ATTRIBUTES: INTENT(OUT)
1123 !
1124 ! INPUTS:
1125 ! Filename: Character string specifying the name of a
1126 ! SEcategory data file to read.
1127 ! UNITS: N/A
1128 ! TYPE: CHARACTER(*)
1129 ! DIMENSION: Scalar
1130 ! ATTRIBUTES: INTENT(IN)
1131 !
1132 ! OPTIONAL INPUTS:
1133 ! No_Close: Set this logical argument to *NOT* close the datafile
1134 ! upon exiting this routine. This option is required if
1135 ! the SEcategory data is embedded within another file.
1136 ! If == .FALSE., File is closed upon function exit [DEFAULT].
1137 ! == .TRUE., File is NOT closed upon function exit
1138 ! If not specified, default is .FALSE.
1139 ! UNITS: N/A
1140 ! TYPE: LOGICAL
1141 ! DIMENSION: Scalar
1142 ! ATTRIBUTES: INTENT(IN), OPTIONAL
1143 !
1144 ! Quiet: Set this logical argument to suppress INFORMATION
1145 ! messages being printed to stdout
1146 ! If == .FALSE., INFORMATION messages are OUTPUT [DEFAULT].
1147 ! == .TRUE., INFORMATION messages are SUPPRESSED.
1148 ! If not specified, default is .FALSE.
1149 ! UNITS: N/A
1150 ! TYPE: LOGICAL
1151 ! DIMENSION: Scalar
1152 ! ATTRIBUTES: INTENT(IN), OPTIONAL
1153 !
1154 ! FUNCTION RESULT:
1155 ! Error_Status: The return value is an integer defining the error status.
1156 ! The error codes are defined in the Message_Handler module.
1157 ! If == SUCCESS, the file read was successful
1158 ! == FAILURE, an unrecoverable error occurred.
1159 ! UNITS: N/A
1160 ! TYPE: INTEGER
1161 ! DIMENSION: Scalar
1162 !
1163 !:sdoc-:
1164 !------------------------------------------------------------------------------
1165 
1166  FUNCTION secategory_readfile( &
1167  SEcategory, & ! Output
1168  Filename , & ! Input
1169  No_Close , & ! Optional input
1170  Quiet , & ! Optional input
1171  Title , & ! Optional output
1172  History , & ! Optional output
1173  Comment , & ! Optional output
1174  Debug ) & ! Optional input (Debug output control)
1175  result( err_stat )
1176  ! Arguments
1177  TYPE(secategory_type), INTENT(OUT) :: secategory
1178  CHARACTER(*), INTENT(IN) :: filename
1179  LOGICAL, OPTIONAL, INTENT(IN) :: no_close
1180  LOGICAL, OPTIONAL, INTENT(IN) :: quiet
1181  CHARACTER(*), OPTIONAL, INTENT(OUT) :: title
1182  CHARACTER(*), OPTIONAL, INTENT(OUT) :: history
1183  CHARACTER(*), OPTIONAL, INTENT(OUT) :: comment
1184  LOGICAL, OPTIONAL, INTENT(IN) :: debug
1185  ! Function result
1186  INTEGER :: err_stat
1187  ! Function parameters
1188  CHARACTER(*), PARAMETER :: routine_name = 'SEcategory_ReadFile'
1189  ! Function variables
1190  CHARACTER(ML) :: msg
1191  CHARACTER(ML) :: io_msg
1192  LOGICAL :: close_file
1193  LOGICAL :: noisy
1194  INTEGER :: io_stat
1195  INTEGER :: fid
1196  TYPE(secategory_type) :: dummy
1197 
1198  ! Setup
1199  err_stat = success
1200  ! ...Check No_Close argument
1201  close_file = .true.
1202  IF ( PRESENT(no_close) ) close_file = .NOT. no_close
1203  ! ...Check Quiet argument
1204  noisy = .true.
1205  IF ( PRESENT(quiet) ) noisy = .NOT. quiet
1206  ! ...Override Quiet settings if debug set.
1207  IF ( PRESENT(debug) ) THEN
1208  IF ( debug ) noisy = .true.
1209  END IF
1210 
1211 
1212  ! Check if the file is open.
1213  IF ( file_open( filename ) ) THEN
1214  ! ...Inquire for the logical unit number
1215  INQUIRE( file=filename, number=fid )
1216  ! ...Ensure it's valid
1217  IF ( fid < 0 ) THEN
1218  msg = 'Error inquiring '//trim(filename)//' for its FileID'
1219  CALL read_cleanup(); RETURN
1220  END IF
1221  ELSE
1222  ! ...Open the file if it exists
1223  IF ( file_exists( filename ) ) THEN
1224  err_stat = open_binary_file( filename, fid )
1225  IF ( err_stat /= success ) THEN
1226  msg = 'Error opening '//trim(filename)
1227  CALL read_cleanup(); RETURN
1228  END IF
1229  ELSE
1230  msg = 'File '//trim(filename)//' not found.'
1231  CALL read_cleanup(); RETURN
1232  END IF
1233  END IF
1234 
1235 
1236  ! Read and check the datatype name
1237  err_stat = read_datatype( fid, dummy%Datatype_name )
1238  IF ( err_stat /= success ) THEN
1239  msg = 'Error reading Datatype_Name'
1240  CALL read_cleanup(); RETURN
1241  END IF
1242  IF ( trim(dummy%Datatype_Name) /= secategory_datatype ) THEN
1243  msg = secategory_datatype//' datatype name check failed.'
1244  CALL read_cleanup(); RETURN
1245  END IF
1246 
1247 
1248  ! Read and check the release and version
1249  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1250  dummy%Release, &
1251  dummy%Version
1252  IF ( io_stat /= 0 ) THEN
1253  msg = 'Error reading Release/Version - '//trim(io_msg)
1254  CALL read_cleanup(); RETURN
1255  END IF
1256  IF ( .NOT. secategory_validrelease( dummy ) ) THEN
1257  msg = 'SEcategory Release check failed.'
1258  CALL read_cleanup(); RETURN
1259  END IF
1260 
1261 
1262  ! Read the dimensions
1263  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1264  dummy%n_Frequencies , &
1265  dummy%n_Surface_Types
1266  IF ( io_stat /= 0 ) THEN
1267  msg = 'Error reading data dimensions - '//trim(io_msg)
1268  CALL read_cleanup(); RETURN
1269  END IF
1270  ! ...Allocate the object
1271  CALL secategory_create( &
1272  secategory , &
1273  dummy%n_Frequencies , &
1274  dummy%n_Surface_Types )
1275  IF ( .NOT. secategory_associated( secategory ) ) THEN
1276  msg = 'SEcategory object allocation failed.'
1277  CALL read_cleanup(); RETURN
1278  END IF
1279  ! ...Explicitly assign the version number
1280  secategory%Version = dummy%Version
1281 
1282 
1283  ! Read the global attributes
1284  err_stat = readgatts_binary_file( &
1285  fid, &
1286  title = title , &
1287  history = history, &
1288  comment = comment )
1289  IF ( err_stat /= success ) THEN
1290  msg = 'Error reading global attributes'
1291  CALL read_cleanup(); RETURN
1292  END IF
1293 
1294 
1295  ! Read the surface classification name
1296  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1297  secategory%Classification_Name
1298  IF ( io_stat /= 0 ) THEN
1299  msg = 'Error reading classification name - '//trim(io_msg)
1300  CALL read_cleanup(); RETURN
1301  END IF
1302 
1303 
1304  ! Read the coefficient data
1305  ! ...Read the surface type names
1306  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1307  secategory%Surface_Type
1308  IF ( io_stat /= 0 ) THEN
1309  msg = 'Error reading surface type names - '//trim(io_msg)
1310  CALL read_cleanup(); RETURN
1311  END IF
1312  ! ...Read the surface type validity array
1313  err_stat = readlogical_binary_file( fid, secategory%Surface_Type_IsValid )
1314  IF ( err_stat /= success ) THEN
1315  msg = 'Error reading surface type validity array'
1316  CALL read_cleanup(); RETURN
1317  END IF
1318  ! ...Read the dimensional vectors
1319  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1320  secategory%Frequency
1321  IF ( io_stat /= 0 ) THEN
1322  msg = 'Error reading dimensional vectors - '//trim(io_msg)
1323  CALL read_cleanup(); RETURN
1324  END IF
1325  ! ...Read the reflectance data
1326  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1327  secategory%Reflectance
1328  IF ( io_stat /= 0 ) THEN
1329  msg = 'Error reading reflectance data - '//trim(io_msg)
1330  CALL read_cleanup(); RETURN
1331  END IF
1332 
1333 
1334  ! Close the file
1335  IF ( close_file ) THEN
1336  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1337  IF ( io_stat /= 0 ) THEN
1338  msg = 'Error closing '//trim(filename)//' - '//trim(io_msg)
1339  CALL read_cleanup(); RETURN
1340  END IF
1341  END IF
1342 
1343 
1344  ! Output an info message
1345  IF ( noisy ) THEN
1346  CALL secategory_info( secategory, msg )
1347  CALL display_message( routine_name, 'FILE: '//trim(filename)//'; '//trim(msg), information )
1348  END IF
1349 
1350  CONTAINS
1351 
1352  SUBROUTINE read_cleanup()
1353  IF ( file_open(filename) ) THEN
1354  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1355  IF ( io_stat /= 0 ) &
1356  msg = trim(msg)//'; Error closing input file during error cleanup - '//trim(io_msg)
1357  END IF
1358  CALL secategory_destroy( secategory )
1359  err_stat = failure
1360  CALL display_message( routine_name, msg, err_stat )
1361  END SUBROUTINE read_cleanup
1362 
1363  END FUNCTION secategory_readfile
1364 
1365 
1366 !--------------------------------------------------------------------------------
1367 !:sdoc+:
1368 !
1369 ! NAME:
1370 ! SEcategory_WriteFile
1371 !
1372 ! PURPOSE:
1373 ! Function to write SEcategory object files.
1374 !
1375 ! CALLING SEQUENCE:
1376 ! Error_Status = SEcategory_WriteFile( &
1377 ! SEcategory , &
1378 ! Filename , &
1379 ! No_Close = No_Close, &
1380 ! Quiet = Quiet )
1381 !
1382 ! OBJECTS:
1383 ! SEcategory: SEcategory object containing the data to write to file.
1384 ! UNITS: N/A
1385 ! TYPE: SEcategory_type
1386 ! DIMENSION: Scalar
1387 ! ATTRIBUTES: INTENT(IN)
1388 !
1389 ! INPUTS:
1390 ! Filename: Character string specifying the name of a
1391 ! SEcategory format data file to write.
1392 ! UNITS: N/A
1393 ! TYPE: CHARACTER(*)
1394 ! DIMENSION: Scalar
1395 ! ATTRIBUTES: INTENT(IN)
1396 !
1397 ! OPTIONAL INPUTS:
1398 ! No_Close: Set this logical argument to *NOT* close the datafile
1399 ! upon exiting this routine. This option is required if
1400 ! the SEcategory data is to be embedded within another file.
1401 ! If == .FALSE., File is closed upon function exit [DEFAULT].
1402 ! == .TRUE., File is NOT closed upon function exit
1403 ! If not specified, default is .FALSE.
1404 ! UNITS: N/A
1405 ! TYPE: LOGICAL
1406 ! DIMENSION: Scalar
1407 ! ATTRIBUTES: INTENT(IN), OPTIONAL
1408 !
1409 ! Quiet: Set this logical argument to suppress INFORMATION
1410 ! messages being printed to stdout
1411 ! If == .FALSE., INFORMATION messages are OUTPUT [DEFAULT].
1412 ! == .TRUE., INFORMATION messages are SUPPRESSED.
1413 ! If not specified, default is .FALSE.
1414 ! UNITS: N/A
1415 ! TYPE: LOGICAL
1416 ! DIMENSION: Scalar
1417 ! ATTRIBUTES: INTENT(IN), OPTIONAL
1418 !
1419 ! FUNCTION RESULT:
1420 ! Error_Status: The return value is an integer defining the error status.
1421 ! The error codes are defined in the Message_Handler module.
1422 ! If == SUCCESS, the file write was successful
1423 ! == FAILURE, an unrecoverable error occurred.
1424 ! UNITS: N/A
1425 ! TYPE: INTEGER
1426 ! DIMENSION: Scalar
1427 !
1428 !:sdoc-:
1429 !------------------------------------------------------------------------------
1430 
1431  FUNCTION secategory_writefile( &
1432  SEcategory, & ! Input
1433  Filename , & ! Input
1434  No_Close , & ! Optional input
1435  Quiet , & ! Optional input
1436  Title , & ! Optional input
1437  History , & ! Optional input
1438  Comment , & ! Optional input
1439  Debug ) & ! Optional input (Debug output control)
1440  result( err_stat )
1441  ! Arguments
1442  TYPE(secategory_type), INTENT(IN) :: secategory
1443  CHARACTER(*), INTENT(IN) :: filename
1444  LOGICAL, OPTIONAL, INTENT(IN) :: no_close
1445  LOGICAL, OPTIONAL, INTENT(IN) :: quiet
1446  CHARACTER(*), OPTIONAL, INTENT(IN) :: title
1447  CHARACTER(*), OPTIONAL, INTENT(IN) :: history
1448  CHARACTER(*), OPTIONAL, INTENT(IN) :: comment
1449  LOGICAL, OPTIONAL, INTENT(IN) :: debug
1450  ! Function result
1451  INTEGER :: err_stat
1452  ! Function parameters
1453  CHARACTER(*), PARAMETER :: routine_name = 'SEcategory_WriteFile'
1454  ! Function variables
1455  CHARACTER(ML) :: msg
1456  CHARACTER(ML) :: io_msg
1457  LOGICAL :: close_file
1458  LOGICAL :: noisy
1459  INTEGER :: io_stat
1460  INTEGER :: fid
1461 
1462 
1463  ! Setup
1464  err_stat = success
1465  ! ...Check No_Close argument
1466  close_file = .true.
1467  IF ( PRESENT(no_close) ) close_file = .NOT. no_close
1468  ! ...Check Quiet argument
1469  noisy = .true.
1470  IF ( PRESENT(quiet) ) noisy = .NOT. quiet
1471  ! ...Override Quiet settings if debug set.
1472  IF ( PRESENT(debug) ) THEN
1473  IF ( debug ) noisy = .true.
1474  END IF
1475  ! ...Check there is data to write
1476  IF ( .NOT. secategory_associated( secategory ) ) THEN
1477  msg = 'SEcategory object is empty.'
1478  CALL write_cleanup(); RETURN
1479  END IF
1480 
1481 
1482  ! Check if the file is open.
1483  IF ( file_open( filename ) ) THEN
1484  ! ...Inquire for the logical unit number
1485  INQUIRE( file=filename, number=fid )
1486  ! ...Ensure it's valid
1487  IF ( fid < 0 ) THEN
1488  msg = 'Error inquiring '//trim(filename)//' for its FileID'
1489  CALL write_cleanup(); RETURN
1490  END IF
1491  ELSE
1492  ! ...Open the file for output
1493  err_stat = open_binary_file( filename, fid, for_output=.true. )
1494  IF ( err_stat /= success ) THEN
1495  msg = 'Error opening '//trim(filename)
1496  CALL write_cleanup(); RETURN
1497  END IF
1498  END IF
1499 
1500 
1501  ! Write the datatype name
1502  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1503  len(secategory%Datatype_Name)
1504  IF ( io_stat /= 0 ) THEN
1505  msg = 'Error writing Datatype_Name length - '//trim(io_msg)
1506  CALL write_cleanup(); RETURN
1507  END IF
1508  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1509  secategory%Datatype_Name
1510  IF ( io_stat /= 0 ) THEN
1511  msg = 'Error writing Datatype_Name - '//trim(io_msg)
1512  CALL write_cleanup(); RETURN
1513  END IF
1514 
1515 
1516  ! Write the release and version
1517  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1518  secategory%Release, &
1519  secategory%Version
1520  IF ( io_stat /= 0 ) THEN
1521  msg = 'Error writing Release/Version - '//trim(io_msg)
1522  CALL write_cleanup(); RETURN
1523  END IF
1524 
1525 
1526  ! Write the dimensions
1527  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1528  secategory%n_Frequencies , &
1529  secategory%n_Surface_Types
1530  IF ( io_stat /= 0 ) THEN
1531  msg = 'Error writing data dimensions - '//trim(io_msg)
1532  CALL write_cleanup(); RETURN
1533  END IF
1534 
1535 
1536  ! Write the global attributes
1537  err_stat = writegatts_binary_file( &
1538  fid, &
1539  write_module = module_version_id, &
1540  title = title , &
1541  history = history, &
1542  comment = comment )
1543  IF ( err_stat /= success ) THEN
1544  msg = 'Error writing global attributes'
1545  CALL write_cleanup(); RETURN
1546  END IF
1547 
1548 
1549  ! Write the surface classification name
1550  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1551  secategory%Classification_Name
1552  IF ( io_stat /= 0 ) THEN
1553  msg = 'Error writing classification name - '//trim(io_msg)
1554  CALL write_cleanup(); RETURN
1555  END IF
1556 
1557 
1558  ! Write the coefficient data
1559  ! ...Write the surface type names
1560  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1561  secategory%Surface_Type
1562  IF ( io_stat /= 0 ) THEN
1563  msg = 'Error writing surface type names - '//trim(io_msg)
1564  CALL write_cleanup(); RETURN
1565  END IF
1566  ! ...Write the surface type validity array
1567  err_stat = writelogical_binary_file( fid, secategory%Surface_Type_IsValid )
1568  IF ( err_stat /= success ) THEN
1569  msg = 'Error writing surface type validity array'
1570  CALL write_cleanup(); RETURN
1571  END IF
1572  ! ...Write the dimensional vectors
1573  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1574  secategory%Frequency
1575  IF ( io_stat /= 0 ) THEN
1576  msg = 'Error writing dimensional vectors - '//trim(io_msg)
1577  CALL write_cleanup(); RETURN
1578  END IF
1579  ! ...Write the reflectance data
1580  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1581  secategory%Reflectance
1582  IF ( io_stat /= 0 ) THEN
1583  msg = 'Error writing reflectance data - '//trim(io_msg)
1584  CALL write_cleanup(); RETURN
1585  END IF
1586 
1587 
1588  ! Close the file
1589  IF ( close_file ) THEN
1590  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1591  IF ( io_stat /= 0 ) THEN
1592  msg = 'Error closing '//trim(filename)//' - '//trim(io_msg)
1593  CALL write_cleanup(); RETURN
1594  END IF
1595  END IF
1596 
1597 
1598  ! Output an info message
1599  IF ( noisy ) THEN
1600  CALL secategory_info( secategory, msg )
1601  CALL display_message( routine_name, 'FILE: '//trim(filename)//'; '//trim(msg), information )
1602  END IF
1603 
1604  CONTAINS
1605 
1606  SUBROUTINE write_cleanup()
1607  IF ( file_open(filename) ) THEN
1608  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1609  IF ( io_stat /= 0 ) &
1610  msg = trim(msg)//'; Error closing output file during error cleanup - '//trim(io_msg)
1611  END IF
1612  err_stat = failure
1613  CALL display_message( routine_name, msg, err_stat )
1614  END SUBROUTINE write_cleanup
1615 
1616  END FUNCTION secategory_writefile
1617 
1618 
1619 !################################################################################
1620 !################################################################################
1621 !## ##
1622 !## ## PRIVATE PROCEDURES ## ##
1623 !## ##
1624 !################################################################################
1625 !################################################################################
1626 
1627 !--------------------------------------------------------------------------------
1628 !
1629 ! NAME:
1630 ! SEcategory_Equal
1631 !
1632 ! PURPOSE:
1633 ! Elemental function to test the equality of two SEcategory objects.
1634 ! Used in OPERATOR(==) interface block.
1635 !
1636 ! CALLING SEQUENCE:
1637 ! is_equal = SEcategory_Equal( x, y )
1638 !
1639 ! or
1640 !
1641 ! IF ( x == y ) THEN
1642 ! ...
1643 ! END IF
1644 !
1645 ! OBJECTS:
1646 ! x, y: Two SEcategory objects to be compared.
1647 ! UNITS: N/A
1648 ! TYPE: SEcategory_type
1649 ! DIMENSION: Scalar or any rank
1650 ! ATTRIBUTES: INTENT(IN)
1651 !
1652 ! FUNCTION RESULT:
1653 ! is_equal: Logical value indicating whether the inputs are equal.
1654 ! UNITS: N/A
1655 ! TYPE: LOGICAL
1656 ! DIMENSION: Same as inputs.
1657 !
1658 !--------------------------------------------------------------------------------
1659 
1660  ELEMENTAL FUNCTION secategory_equal( x, y ) RESULT( is_equal )
1661  TYPE(secategory_type), INTENT(IN) :: x, y
1662  LOGICAL :: is_equal
1663 
1664  ! Set up
1665  is_equal = .false.
1666 
1667  ! Check the object association status
1668  IF ( (.NOT. secategory_associated(x)) .OR. &
1669  (.NOT. secategory_associated(y)) ) RETURN
1670 
1671  ! Check contents
1672  ! ...Release/version info
1673  IF ( (x%Release /= y%Release) .OR. &
1674  (x%Version /= y%Version) ) RETURN
1675  ! ...Classification name
1676  IF ( (x%Classification_Name /= y%Classification_Name) ) RETURN
1677  ! ...Dimensions
1678  IF ( (x%n_Frequencies /= y%n_Frequencies ) .OR. &
1679  (x%n_Surface_Types /= y%n_Surface_Types ) ) RETURN
1680  ! ...Arrays
1681  IF ( all(x%Frequency .equalto. y%Frequency ) .AND. &
1682  all(x%Surface_Type == y%Surface_Type ) .AND. &
1683  all(x%Reflectance .equalto. y%Reflectance ) ) &
1684  is_equal = .true.
1685 
1686  END FUNCTION secategory_equal
1687 
1688 
1689  ! Function to read the datatype name from file
1690 
1691  FUNCTION read_datatype( fid, datatype_name ) RESULT( err_stat )
1692  ! Arguments
1693  INTEGER , INTENT(IN) :: fid
1694  CHARACTER(*), INTENT(OUT) :: datatype_name
1695  ! Function result
1696  INTEGER :: err_stat
1697  ! Local variables
1698  CHARACTER(1), ALLOCATABLE :: dummy(:)
1699  INTEGER :: i, strlen
1700  INTEGER :: io_stat
1701  INTEGER :: alloc_stat
1702 
1703  ! Set up
1704  err_stat = failure
1705  datatype_name = ''
1706 
1707  ! Get the string length
1708  READ( fid, iostat=io_stat ) strlen
1709  IF ( io_stat /= 0 ) RETURN
1710 
1711  ! Allocate dummy string array
1712  ALLOCATE( dummy(strlen), stat=alloc_stat )
1713  IF ( alloc_stat /= 0 ) RETURN
1714 
1715  ! Read the string into the dummy array
1716  READ( fid, iostat=io_stat ) dummy
1717  IF ( io_stat /= 0 ) RETURN
1718 
1719  ! Transfer array into string
1720  DO i = 1, min(strlen,len(datatype_name))
1721  datatype_name(i:i) = dummy(i)
1722  END DO
1723 
1724  ! Done
1725  err_stat = success
1726  END FUNCTION read_datatype
1727 
1728 END MODULE secategory_define
integer function read_datatype(fid, datatype_name)
integer, parameter, public failure
subroutine, public secategory_info(self, Info)
integer, parameter, public strlen
real(fp), parameter, public zero
integer, parameter, public long
Definition: Type_Kinds.f90:76
integer function, public secategory_writefile(SEcategory, Filename, No_Close, Quiet, Title, History, Comment, Debug)
integer function, public secategory_readfile(SEcategory, Filename, No_Close, Quiet, Title, History, Comment, Debug)
integer, parameter, public fp
Definition: Type_Kinds.f90:124
pure character(len(self%datatype_name)) function, public secategory_name(self)
integer function, public readgatts_binary_file(fid, Write_Module, Created_On, Title, History, Comment)
integer, parameter, public double
Definition: Type_Kinds.f90:106
elemental logical function, public secategory_associated(self)
elemental logical function secategory_equal(x, y)
subroutine inquire_cleanup()
logical function, public secategory_validrelease(self)
subroutine read_cleanup()
subroutine write_cleanup()
integer, parameter secategory_version
integer function, public open_binary_file(Filename, FileID, For_Output, No_Check)
real(fp), parameter, public one
recursive subroutine, public display_message(Routine_Name, Message, Error_State, Message_Log)
pure integer function, public secategory_index(self, Surface_Type)
subroutine, public secategory_defineversion(Id)
elemental subroutine, public secategory_destroy(self)
subroutine, public secategory_inspect(self)
integer, parameter sl
integer, parameter secategory_release
character(*), parameter, public secategory_datatype
integer function, public secategory_inquirefile(Filename, n_Frequencies, n_Surface_Types, Release, Version, Title, History, Comment)
integer function, public writegatts_binary_file(fid, Write_Module, Created_On, Title, History, Comment)
subroutine, public secategory_setvalue(self, Version, Classification_Name, Frequency, Surface_Type, Surface_Type_IsValid, Reflectance)
character(*), parameter write_error_status
character(*), parameter module_version_id
subroutine, public secategory_getvalue(self, Surface_Type_ToGet, Version, Classification_Name, n_Frequencies, n_Surface_Types, Frequency, Surface_Type, Surface_Type_IsValid, Reflectance, Surface_Reflectance)
#define min(a, b)
Definition: mosaic_util.h:32
integer, parameter, public success
elemental subroutine, public secategory_create(self, n_Frequencies, n_Surface_Types)
integer, parameter, public information
integer, parameter ml