FV3 Bundle
CRTM_AtmOptics_Define.f90
Go to the documentation of this file.
1 !
2 ! CRTM_AtmOptics_Define
3 !
4 ! Module defining the CRTM AtmOptics object.
5 !
6 !
7 ! CREATION HISTORY:
8 ! Written by: Paul van Delst, 11-Oct-2011
9 ! paul.vandelst@noaa.gov
10 !
11 
13 
14  ! -----------------
15  ! Environment setup
16  ! -----------------
17  ! Module use
18  USE type_kinds , ONLY: fp, long, double
21  OPERATOR(.equalto.), &
27  ! Disable implicit typing
28  IMPLICIT NONE
29 
30 
31  ! ------------
32  ! Visibilities
33  ! ------------
34  ! Everything private by default
35  PRIVATE
36  ! Datatypes
37  PUBLIC :: crtm_atmoptics_type
38  ! Operators
39  PUBLIC :: OPERATOR(==)
40  PUBLIC :: OPERATOR(-)
41  ! Procedures
43  PUBLIC :: crtm_atmoptics_destroy
44  PUBLIC :: crtm_atmoptics_create
45  PUBLIC :: crtm_atmoptics_zero
46  PUBLIC :: crtm_atmoptics_inspect
48  PUBLIC :: crtm_atmoptics_info
50  PUBLIC :: crtm_atmoptics_compare
52  PUBLIC :: crtm_atmoptics_readfile
53  PUBLIC :: crtm_atmoptics_writefile
54 
55 
56  ! ---------------------
57  ! Procedure overloading
58  ! ---------------------
59  INTERFACE OPERATOR(==)
60  MODULE PROCEDURE crtm_atmoptics_equal
61  END INTERFACE OPERATOR(==)
62 
63  INTERFACE OPERATOR(-)
64  MODULE PROCEDURE crtm_atmoptics_subtract
65  END INTERFACE OPERATOR(-)
66 
68  MODULE PROCEDURE scalar_inspect
69  MODULE PROCEDURE rank1_inspect
70  END INTERFACE crtm_atmoptics_inspect
71 
72  ! -----------------
73  ! Module parameters
74  ! -----------------
75  CHARACTER(*), PARAMETER :: module_version_id = &
76  '$Id: CRTM_AtmOptics_Define.f90 60152 2015-08-13 19:19:13Z paul.vandelst@noaa.gov $'
77  ! Release and version
78  INTEGER, PARAMETER :: atmoptics_release = 4 ! This determines structure and file formats.
79  ! Close status for write errors
80  CHARACTER(*), PARAMETER :: write_error_status = 'DELETE'
81  ! Literal constants
82  REAL(fp), PARAMETER :: zero = 0.0_fp
83  REAL(fp), PARAMETER :: one = 1.0_fp
84  ! String lengths
85  INTEGER, PARAMETER :: ml = 256 ! Message length
86  INTEGER, PARAMETER :: sl = 80 ! String length
87 
88 
89  ! ------------------------------
90  ! AtmOptics data type definition
91  ! ------------------------------
92  !:tdoc+:
94  ! Allocation indicator
95  LOGICAL :: is_allocated = .false.
96  ! Release information
97  INTEGER :: release = atmoptics_release
98  ! Dimensions
99  INTEGER :: n_layers = 0 ! K dimension
100  INTEGER :: n_legendre_terms = 0 ! Ic dimension
101  INTEGER :: n_phase_elements = 0 ! Ip dimension
102  ! ...Max. values to avoid unnecessary reallocation
103  INTEGER :: max_layers = 0 ! K-Max dimension
104  INTEGER :: max_legendre_terms = 0 ! Ic-Max dimension
105  INTEGER :: max_phase_elements = 0 ! Ip-Max dimension
106  ! Scalar components
107  LOGICAL :: include_scattering = .true.
108  INTEGER :: loffset = 0 ! Start position in array for Legendre coefficients
109  REAL(fp) :: scattering_optical_depth = zero
110  ! Array components
111  REAL(fp), ALLOCATABLE :: optical_depth(:) ! K-Max
112  REAL(fp), ALLOCATABLE :: single_scatter_albedo(:) ! K-Max
113  REAL(fp), ALLOCATABLE :: asymmetry_factor(:) ! K-Max
114  REAL(fp), ALLOCATABLE :: delta_truncation(:) ! K-Max
115  REAL(fp), ALLOCATABLE :: phase_coefficient(:,:,:) ! 0:Ic-Max x Ip-Max x K-Max
116  END TYPE crtm_atmoptics_type
117  !:tdoc-:
118 
119 
120 CONTAINS
121 
122 
123 !################################################################################
124 !################################################################################
125 !## ##
126 !## ## PUBLIC MODULE ROUTINES ## ##
127 !## ##
128 !################################################################################
129 !################################################################################
130 
131 !--------------------------------------------------------------------------------
132 !:sdoc+:
133 !
134 ! NAME:
135 ! CRTM_AtmOptics_Associated
136 !
137 ! PURPOSE:
138 ! Elemental function to test the status of the allocatable components
139 ! of the AtmOptics structure.
140 !
141 ! CALLING SEQUENCE:
142 ! Status = CRTM_AtmOptics_Associated( AtmOptics )
143 !
144 ! OBJECTS:
145 ! AtmOptics: Structure which is to have its member's
146 ! status tested.
147 ! UNITS: N/A
148 ! TYPE: CRTM_AtmOptics_type
149 ! DIMENSION: Scalar or any rank
150 ! ATTRIBUTES: INTENT(IN)
151 !
152 ! FUNCTION RESULT:
153 ! Status: The return value is a logical value indicating the
154 ! status of the NLTE members.
155 ! .TRUE. - if ANY of the AtmOptics allocatable members
156 ! are in use.
157 ! .FALSE. - if ALL of the AtmOptics allocatable members
158 ! are not in use.
159 ! UNITS: N/A
160 ! TYPE: LOGICAL
161 ! DIMENSION: Same as input
162 !
163 !:sdoc-:
164 !--------------------------------------------------------------------------------
165 
166  ELEMENTAL FUNCTION crtm_atmoptics_associated( self ) RESULT( status )
167  TYPE(crtm_atmoptics_type), INTENT(IN) :: self
168  LOGICAL :: status
169  status = self%Is_Allocated
170  END FUNCTION crtm_atmoptics_associated
171 
172 
173 !--------------------------------------------------------------------------------
174 !:sdoc+:
175 !
176 ! NAME:
177 ! CRTM_AtmOptics_Destroy
178 !
179 ! PURPOSE:
180 ! Elemental subroutine to re-initialize AtmOptics objects.
181 !
182 ! CALLING SEQUENCE:
183 ! CALL CRTM_AtmOptics_Destroy( AtmOptics )
184 !
185 ! OBJECTS:
186 ! AtmOptics: Re-initialized AtmOptics structure.
187 ! UNITS: N/A
188 ! TYPE: CRTM_AtmOptics_type
189 ! DIMENSION: Scalar or any rank
190 ! ATTRIBUTES: INTENT(OUT)
191 !
192 !:sdoc-:
193 !--------------------------------------------------------------------------------
194 
195  ELEMENTAL SUBROUTINE crtm_atmoptics_destroy( self )
196  TYPE(crtm_atmoptics_type), INTENT(OUT) :: self
197  self%Is_Allocated = .false.
198  self%n_Layers = 0
199  self%n_Legendre_Terms = 0
200  self%n_Phase_Elements = 0
201  self%Max_Layers = 0
202  self%Max_Legendre_Terms = 0
203  self%Max_Phase_Elements = 0
204  END SUBROUTINE crtm_atmoptics_destroy
205 
206 
207 !--------------------------------------------------------------------------------
208 !:sdoc+:
209 !
210 ! NAME:
211 ! CRTM_AtmOptics_Create
212 !
213 ! PURPOSE:
214 ! Elemental subroutine to create an instance of an AtmOptics object.
215 !
216 ! CALLING SEQUENCE:
217 ! CALL CRTM_AtmOptics_Create( AtmOptics , &
218 ! n_Layers , &
219 ! n_Legendre_Terms, &
220 ! n_Phase_Elements )
221 !
222 ! OBJECTS:
223 ! AtmOptics: AtmOptics object structure.
224 ! UNITS: N/A
225 ! TYPE: CRTM_AtmOptics_type
226 ! DIMENSION: Scalar or any rank
227 ! ATTRIBUTES: INTENT(IN OUT)
228 !
229 ! INPUTS:
230 ! n_Layers: Number of atmospheric layers.
231 ! Must be > 0
232 ! UNITS: N/A
233 ! TYPE: INTEGER
234 ! DIMENSION: Conformable with the AtmOptics object.
235 ! ATTRIBUTES: INTENT(IN)
236 !
237 ! n_Legendre_Terms: The number of Legendre polynomial terms for the
238 ! phase matrix.
239 ! Must be > 0
240 ! UNITS: N/A
241 ! TYPE: INTEGER
242 ! DIMENSION: Same as n_Layers input.
243 ! ATTRIBUTES: INTENT(IN)
244 !
245 ! n_Phase_Elements: The number of phase elements for the phase matrix.
246 ! Must be > 0
247 ! UNITS: N/A
248 ! TYPE: INTEGER
249 ! DIMENSION: Same as n_Layers input.
250 ! ATTRIBUTES: INTENT(IN)
251 !
252 ! COMMENTS:
253 ! Note the INTENT on the output AtmOptics argument is IN OUT rather than
254 ! just OUT. If the AtmOptics is already allocated to sufficient size for
255 ! the passed dimensions, no reallocation is performed, only the internal
256 ! dimension values are reset.
257 !
258 !:sdoc-:
259 !--------------------------------------------------------------------------------
260 
261  ELEMENTAL SUBROUTINE crtm_atmoptics_create( &
262  self , & ! Output
263  n_Layers , & ! Input
264  n_Legendre_Terms, & ! Input
265  n_Phase_Elements ) ! Input
266  ! Arguments
267  TYPE(crtm_atmoptics_type), INTENT(IN OUT) :: self
268  INTEGER , INTENT(IN) :: n_layers
269  INTEGER , INTENT(IN) :: n_legendre_terms
270  INTEGER , INTENT(IN) :: n_phase_elements
271  ! Local variables
272  INTEGER :: alloc_stat
273 
274  ! Check input
275  IF ( n_layers < 1 .OR. &
276  n_legendre_terms < 1 .OR. &
277  n_phase_elements < 1 ) THEN
278  CALL crtm_atmoptics_destroy( self )
279  RETURN
280  END IF
281 
282  ! Check the allocation status
283  IF ( crtm_atmoptics_associated( self ) ) THEN
284  ! ...Does it need to be reallocated?
285  IF ( self%Max_Layers < n_layers .OR. &
286  self%Max_Legendre_Terms < n_legendre_terms .OR. &
287  self%Max_Phase_Elements < n_phase_elements ) THEN
288  CALL atmoptics_allocate( self, alloc_stat )
289  IF ( alloc_stat /= 0 ) RETURN
290  END IF
291  ELSE
292  ! ...Not allocated, so allocate it.
293  CALL atmoptics_allocate( self, alloc_stat )
294  IF ( alloc_stat /= 0 ) RETURN
295  END IF
296 
297  ! Initialise dimensions (but not arrays!)
298  self%n_Layers = n_layers
299  self%n_Legendre_Terms = n_legendre_terms
300  self%n_Phase_Elements = n_phase_elements
301 
302  ! Set allocation indicator
303  self%Is_Allocated = .true.
304 
305  CONTAINS
306 
307  PURE SUBROUTINE atmoptics_allocate(self,alloc_stat)
308  TYPE(crtm_atmoptics_type), INTENT(OUT) :: self
309  INTEGER , INTENT(OUT) :: alloc_stat
310  ! Allocate object
311  ALLOCATE( self%Optical_Depth( n_layers ), &
312  self%Single_Scatter_Albedo( n_layers ), &
313  self%Asymmetry_Factor( n_layers ), &
314  self%Delta_Truncation( n_layers ), &
315  self%Phase_Coefficient( 0:n_legendre_terms, n_phase_elements, n_layers ), &
316  stat = alloc_stat )
317  IF ( alloc_stat /= 0 ) RETURN
318  ! Set maximum dimension values
319  self%Max_Layers = n_layers
320  self%Max_Legendre_Terms = n_legendre_terms
321  self%Max_Phase_Elements = n_phase_elements
322  END SUBROUTINE atmoptics_allocate
323 
324  END SUBROUTINE crtm_atmoptics_create
325 
326 
327 !--------------------------------------------------------------------------------
328 !:sdoc+:
329 !
330 ! NAME:
331 ! CRTM_AtmOptics_Zero
332 !
333 ! PURPOSE:
334 ! Elemental subroutine to initialise the components of an AtmOptics
335 ! object to a value of zero.
336 !
337 ! CALLING SEQUENCE:
338 ! CALL CRTM_AtmOptics_Zero( AtmOptics )
339 !
340 ! OBJECTS:
341 ! AtmOptics: AtmOptics object which is to have its components
342 ! set to a zero value.
343 ! UNITS: N/A
344 ! TYPE: CRTM_AtmOptics_type
345 ! DIMENSION: Scalar or any rank
346 ! ATTRIBUTES: INTENT(IN OUT)
347 !
348 !:sdoc-:
349 !--------------------------------------------------------------------------------
350 
351  ELEMENTAL SUBROUTINE crtm_atmoptics_zero( self )
352  TYPE(crtm_atmoptics_type), INTENT(IN OUT) :: self
353  self%Scattering_Optical_Depth = zero
354  IF ( .NOT. crtm_atmoptics_associated( self ) ) RETURN
355  self%Optical_Depth = zero
356  self%Single_Scatter_Albedo = zero
357  self%Asymmetry_Factor = zero
358  self%Delta_Truncation = zero
359  self%Phase_Coefficient = zero
360  END SUBROUTINE crtm_atmoptics_zero
361 
362 
363 !--------------------------------------------------------------------------------
364 !:sdoc+:
365 !
366 ! NAME:
367 ! CRTM_AtmOptics_Inspect
368 !
369 ! PURPOSE:
370 ! Subroutine to print the contents of a AtmOptics object to stdout.
371 !
372 ! CALLING SEQUENCE:
373 ! CALL CRTM_AtmOptics_Inspect( AtmOptics )
374 !
375 ! OBJECTS:
376 ! AtmOptics: AtmOptics object to display.
377 ! UNITS: N/A
378 ! TYPE: CRTM_AtmOptics_type
379 ! DIMENSION: Scalar
380 ! ATTRIBUTES: INTENT(IN)
381 !
382 !:sdoc-:
383 !--------------------------------------------------------------------------------
384 
385  SUBROUTINE scalar_inspect(self)
386  TYPE(CRTM_AtmOptics_type), INTENT(IN) :: self
387  INTEGER :: ip, k
388  WRITE(*,'(1x,"AtmOptics OBJECT")')
389  ! Release/version info
390  WRITE(*,'(3x,"Release : ",i0)') self%Release
391  ! Dimensions
392  WRITE(*,'(3x,"n_Layers : ",i0," (of max. ",i0,")")') self%n_Layers , self%Max_Layers
393  WRITE(*,'(3x,"n_Legendre_Terms : ",i0," (of max. ",i0,")")') self%n_Legendre_Terms, self%Max_Legendre_Terms
394  WRITE(*,'(3x,"n_Phase_Elements : ",i0," (of max. ",i0,")")') self%n_Phase_Elements, self%Max_Phase_Elements
395  WRITE(*,'(3x,"Scattering Optical Depth : ",es13.6)') self%Scattering_Optical_Depth
396  IF ( .NOT. crtm_atmoptics_associated(self) ) RETURN
397  ! Dimension arrays
398  WRITE(*,'(3x,"Optical_Depth :")')
399  WRITE(*,'(5(1x,es13.6,:))') self%Optical_Depth(1:self%n_Layers)
400  WRITE(*,'(3x,"Single_Scatter_Albedo :")')
401  WRITE(*,'(5(1x,es13.6,:))') self%Single_Scatter_Albedo(1:self%n_Layers)
402  WRITE(*,'(3x,"Asymmetry_Factor :")')
403  WRITE(*,'(5(1x,es13.6,:))') self%Asymmetry_Factor(1:self%n_Layers)
404  WRITE(*,'(3x,"Delta_Truncation :")')
405  WRITE(*,'(5(1x,es13.6,:))') self%Delta_Truncation(1:self%n_Layers)
406  WRITE(*,'(3x,"Phase_Coefficient Legendre polynomial coefficients :")')
407  DO k = 1, self%n_Layers
408  DO ip = 1, self%n_Phase_Elements
409  WRITE(*,'(5x,"Layer: ",i0,"; Phase element: ",i0)') k, ip
410  WRITE(*,'(5(1x,es13.6,:))') self%Phase_Coefficient(0:self%n_Legendre_Terms,ip,k)
411  END DO
412  WRITE(*,*)
413  END DO
414  END SUBROUTINE scalar_inspect
415 
416  SUBROUTINE rank1_inspect( self )
417  TYPE(CRTM_AtmOptics_type), INTENT(IN) :: self(:)
418  INTEGER :: n, n_objects
419 
420  n_objects = SIZE(self)
421  DO n = 1, n_objects
422  WRITE(*, fmt='(1x,"OBJECT INDEX:",i0," - ")', advance='NO') n
423  CALL scalar_inspect(self(n))
424  END DO
425  END SUBROUTINE rank1_inspect
426 
427 
428 !----------------------------------------------------------------------------------
429 !:sdoc+:
430 !
431 ! NAME:
432 ! CRTM_AtmOptics_ValidRelease
433 !
434 ! PURPOSE:
435 ! Function to check the AtmOptics object Release value.
436 !
437 ! CALLING SEQUENCE:
438 ! IsValid = CRTM_AtmOptics_ValidRelease( AtmOptics )
439 !
440 ! OBJECTS:
441 ! AtmOptics: AtmOptics object for which the Release component
442 ! is to be checked.
443 ! UNITS: N/A
444 ! TYPE: CRTM_AtmOptics_type
445 ! DIMENSION: Scalar
446 ! ATTRIBUTES: INTENT(IN)
447 !
448 ! FUNCTION RESULT:
449 ! IsValid: Logical value defining the release validity.
450 ! UNITS: N/A
451 ! TYPE: LOGICAL
452 ! DIMENSION: Scalar
453 !
454 !:sdoc-:
455 !----------------------------------------------------------------------------------
456 
457  FUNCTION crtm_atmoptics_validrelease( self ) RESULT( IsValid )
458  ! Arguments
459  TYPE(crtm_atmoptics_type), INTENT(IN) :: self
460  ! Function result
461  LOGICAL :: isvalid
462  ! Local parameters
463  CHARACTER(*), PARAMETER :: routine_name = 'CRTM_AtmOptics_ValidRelease'
464  ! Local variables
465  CHARACTER(ML) :: msg
466 
467  ! Set up
468  isvalid = .true.
469 
470 
471  ! Check release is not too old
472  IF ( self%Release < atmoptics_release ) THEN
473  isvalid = .false.
474  WRITE( msg,'("An AtmOptics data update is needed. ", &
475  &"AtmOptics release is ",i0,". Valid release is ",i0,"." )' ) &
476  self%Release, atmoptics_release
477  CALL display_message( routine_name, msg, information ); RETURN
478  END IF
479 
480 
481  ! Check release is not too new
482  IF ( self%Release > atmoptics_release ) THEN
483  isvalid = .false.
484  WRITE( msg,'("An AtmOptics software update is needed. ", &
485  &"AtmOptics release is ",i0,". Valid release is ",i0,"." )' ) &
486  self%Release, atmoptics_release
487  CALL display_message( routine_name, msg, information ); RETURN
488  END IF
489 
490  END FUNCTION crtm_atmoptics_validrelease
491 
492 
493 !--------------------------------------------------------------------------------
494 !:sdoc+:
495 !
496 ! NAME:
497 ! CRTM_AtmOptics_Info
498 !
499 ! PURPOSE:
500 ! Subroutine to return a string containing version and dimension
501 ! information about an AtmOptics object.
502 !
503 ! CALLING SEQUENCE:
504 ! CALL CRTM_AtmOptics_Info( AtmOptics, Info )
505 !
506 ! OBJECTS:
507 ! AtmOptics: AtmOptics object about which info is required.
508 ! UNITS: N/A
509 ! TYPE: CRTM_AtmOptics_type
510 ! DIMENSION: Scalar
511 ! ATTRIBUTES: INTENT(IN)
512 !
513 ! OUTPUTS:
514 ! Info: String containing version and dimension information
515 ! about the AtmOptics object.
516 ! UNITS: N/A
517 ! TYPE: CHARACTER(*)
518 ! DIMENSION: Scalar
519 ! ATTRIBUTES: INTENT(OUT)
520 !
521 !:sdoc-:
522 !--------------------------------------------------------------------------------
523 
524  SUBROUTINE crtm_atmoptics_info( self, Info )
525  ! Arguments
526  TYPE(crtm_atmoptics_type), INTENT(IN) :: self
527  CHARACTER(*), INTENT(OUT) :: info
528  ! Parameters
529  INTEGER, PARAMETER :: carriage_return = 13
530  INTEGER, PARAMETER :: linefeed = 10
531  ! Local variables
532  CHARACTER(2000) :: long_string
533 
534  ! Write the required data to the local string
535  WRITE( long_string, &
536  '(a,1x,"AtmOptics RELEASE: ",i2,3x, &
537  &"N_LAYERS=",i0,2x,&
538  &"N_LEGENDRE_TERMS=",i0,2x,&
539  &"N_PHASE_ELEMENTS=",i0 )' ) &
540  achar(carriage_return)//achar(linefeed), &
541  self%Release, &
542  self%n_Layers, &
543  self%n_Legendre_Terms, &
544  self%n_Phase_Elements
545 
546  ! Trim the output based on the
547  ! dummy argument string length
548  info = long_string(1:min(len(info), len_trim(long_string)))
549 
550  END SUBROUTINE crtm_atmoptics_info
551 
552 
553 !--------------------------------------------------------------------------------
554 !:sdoc+:
555 !
556 ! NAME:
557 ! CRTM_AtmOptics_DefineVersion
558 !
559 ! PURPOSE:
560 ! Subroutine to return the module version information.
561 !
562 ! CALLING SEQUENCE:
563 ! CALL CRTM_AtmOptics_DefineVersion( Id )
564 !
565 ! OUTPUTS:
566 ! Id: Character string containing the version Id information
567 ! for the module.
568 ! UNITS: N/A
569 ! TYPE: CHARACTER(*)
570 ! DIMENSION: Scalar
571 ! ATTRIBUTES: INTENT(OUT)
572 !
573 !:sdoc-:
574 !--------------------------------------------------------------------------------
575 
576  SUBROUTINE crtm_atmoptics_defineversion( Id )
577  CHARACTER(*), INTENT(OUT) :: id
578  id = module_version_id
579  END SUBROUTINE crtm_atmoptics_defineversion
580 
581 
582 !--------------------------------------------------------------------------------
583 !:sdoc+:
584 ! NAME:
585 ! CRTM_AtmOptics_Compare
586 !
587 ! PURPOSE:
588 ! Elemental function to compare two CRTM_AtmOptics objects to within
589 ! a user specified number of significant figures.
590 !
591 ! CALLING SEQUENCE:
592 ! is_comparable = CRTM_AtmOptics_Compare( x, y, n_SigFig=n_SigFig )
593 !
594 ! OBJECTS:
595 ! x, y: Two CRTM AtmOptics objects to be compared.
596 ! UNITS: N/A
597 ! TYPE: CRTM_AtmOptics_type
598 ! DIMENSION: Scalar or any rank
599 ! ATTRIBUTES: INTENT(IN)
600 !
601 ! OPTIONAL INPUTS:
602 ! n_SigFig: Number of significant figures to compare floating point
603 ! components.
604 ! UNITS: N/A
605 ! TYPE: INTEGER
606 ! DIMENSION: Scalar or same as input
607 ! ATTRIBUTES: INTENT(IN), OPTIONAL
608 !
609 ! FUNCTION RESULT:
610 ! is_equal: Logical value indicating whether the inputs are equal.
611 ! UNITS: N/A
612 ! TYPE: LOGICAL
613 ! DIMENSION: Same as inputs.
614 !:sdoc-:
615 !--------------------------------------------------------------------------------
616 
617  ELEMENTAL FUNCTION crtm_atmoptics_compare( &
618  x, &
619  y, &
620  n_SigFig ) &
621  result( is_comparable )
622  TYPE(crtm_atmoptics_type), INTENT(IN) :: x, y
623  INTEGER, OPTIONAL, INTENT(IN) :: n_sigfig
624  LOGICAL :: is_comparable
625  ! Variables
626  INTEGER :: ic, ip, k
627  INTEGER :: n
628 
629  ! Set up
630  is_comparable = .false.
631  IF ( PRESENT(n_sigfig) ) THEN
632  n = abs(n_sigfig)
633  ELSE
634  n = default_n_sigfig
635  END IF
636 
637  ! Check the structure association status
638  IF ( (.NOT. crtm_atmoptics_associated(x)) .OR. &
639  (.NOT. crtm_atmoptics_associated(y)) ) RETURN
640 
641  ! Check dimensions
642  IF ( (x%n_Layers /= y%n_Layers ) .OR. &
643  (x%n_Legendre_Terms /= y%n_Legendre_Terms) .OR. &
644  (x%n_Phase_Elements /= y%n_Phase_Elements) ) RETURN
645 
646  ! Check scalar components
647  IF ( (x%Include_Scattering .NEQV. y%Include_Scattering ) .OR. &
648  (x%lOffset /= y%lOffset ) .OR. &
649  (.NOT. compares_within_tolerance(x%Scattering_Optical_Depth,&
650  y%Scattering_Optical_Depth, n)) ) RETURN
651 
652 
653  ! Check floating point arrays
654  k = x%n_Layers
655  ip = x%n_Phase_Elements
656  ic = x%n_Legendre_Terms
657  IF ( (.NOT. all(compares_within_tolerance( &
658  x%Optical_Depth(1:k), &
659  y%Optical_Depth(1:k), &
660  n ))) .OR. &
661  (.NOT. all(compares_within_tolerance( &
662  x%Single_Scatter_Albedo(1:k), &
663  y%Single_Scatter_Albedo(1:k), &
664  n ))) .OR. &
665  (.NOT. all(compares_within_tolerance( &
666  x%Asymmetry_Factor(1:k), &
667  y%Asymmetry_Factor(1:k), &
668  n ))) .OR. &
669  (.NOT. all(compares_within_tolerance( &
670  x%Delta_Truncation(1:k), &
671  y%Delta_Truncation(1:k), &
672  n ))) .OR. &
673  (.NOT. all(compares_within_tolerance( &
674  x%Phase_Coefficient(0:ic,1:ip,1:k), &
675  y%Phase_Coefficient(0:ic,1:ip,1:k), &
676  n ))) ) RETURN
677 
678 
679  ! If we get here, the structures are comparable
680  is_comparable = .true.
681 
682  END FUNCTION crtm_atmoptics_compare
683 
684 
685 !------------------------------------------------------------------------------
686 !:sdoc+:
687 !
688 ! NAME:
689 ! CRTM_AtmOptics_InquireFile
690 !
691 ! PURPOSE:
692 ! Function to inquire AtmOptics object files.
693 !
694 ! CALLING SEQUENCE:
695 ! Error_Status = CRTM_AtmOptics_InquireFile( &
696 ! Filename , &
697 ! n_Objects = n_Objects, &
698 ! Release = Release )
699 !
700 ! INPUTS:
701 ! Filename: Character string specifying the name of the
702 ! data file to inquire.
703 ! UNITS: N/A
704 ! TYPE: CHARACTER(*)
705 ! DIMENSION: Scalar
706 ! ATTRIBUTES: INTENT(IN)
707 !
708 ! OPTIONAL OUTPUTS:
709 ! n_Objects: Number of AtmOptics objects contained in the file.
710 ! UNITS: N/A
711 ! TYPE: INTEGER
712 ! DIMENSION: Scalar
713 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
714 !
715 ! Release: The data/file release number. Used to check
716 ! for data/software mismatch.
717 ! UNITS: N/A
718 ! TYPE: INTEGER
719 ! DIMENSION: Scalar
720 ! ATTRIBUTES: INTENT(OUT), OPTIONAL
721 !
722 ! FUNCTION RESULT:
723 ! Error_Status: The return value is an integer defining the error
724 ! status. The error codes are defined in the
725 ! Message_Handler module.
726 ! If == SUCCESS the file inquire was successful
727 ! == FAILURE an unrecoverable error occurred.
728 ! UNITS: N/A
729 ! TYPE: INTEGER
730 ! DIMENSION: Scalar
731 !
732 !:sdoc-:
733 !------------------------------------------------------------------------------
734 
735  FUNCTION crtm_atmoptics_inquirefile( &
736  Filename , & ! Input
737  n_Objects, & ! Optional output
738  Release , & ! Optional output
739  Title , & ! Optional output
740  History , & ! Optional output
741  Comment ) & ! Optional output
742  result( err_stat )
743  ! Arguments
744  CHARACTER(*), INTENT(IN) :: filename
745  INTEGER , OPTIONAL, INTENT(OUT) :: n_objects
746  INTEGER , OPTIONAL, INTENT(OUT) :: release
747  CHARACTER(*), OPTIONAL, INTENT(OUT) :: title
748  CHARACTER(*), OPTIONAL, INTENT(OUT) :: history
749  CHARACTER(*), OPTIONAL, INTENT(OUT) :: comment
750  ! Function result
751  INTEGER :: err_stat
752  ! Function parameters
753  CHARACTER(*), PARAMETER :: routine_name = 'CRTM_AtmOptics_InquireFile'
754  ! Function variables
755  CHARACTER(ML) :: msg
756  CHARACTER(ML) :: io_msg
757  INTEGER :: io_stat
758  INTEGER :: fid
759  INTEGER :: n
760  TYPE(crtm_atmoptics_type) :: atmoptics
761 
762 
763  ! Setup
764  err_stat = success
765  ! ...Check that the file exists
766  IF ( .NOT. file_exists( filename ) ) THEN
767  msg = 'File '//trim(filename)//' not found.'
768  CALL inquire_cleanup(); RETURN
769  END IF
770 
771 
772  ! Open the file
773  err_stat = open_binary_file( filename, fid )
774  IF ( err_stat /= success ) THEN
775  msg = 'Error opening '//trim(filename)
776  CALL inquire_cleanup(); RETURN
777  END IF
778 
779 
780  ! Read the release
781  READ( fid, iostat=io_stat, iomsg=io_msg ) &
782  atmoptics%Release
783  IF ( io_stat /= 0 ) THEN
784  msg = 'Error reading Release - '//trim(io_msg)
785  CALL inquire_cleanup(); RETURN
786  END IF
787  IF ( .NOT. crtm_atmoptics_validrelease( atmoptics ) ) THEN
788  msg = 'AtmOptics Release check failed.'
789  CALL inquire_cleanup(); RETURN
790  END IF
791 
792 
793  ! Read the number of objects
794  READ( fid, iostat=io_stat,iomsg=io_msg ) n
795  IF ( io_stat /= 0 ) THEN
796  msg = 'Error reading dimensions from '//trim(filename)//' - '//trim(io_msg)
797  CALL inquire_cleanup(); RETURN
798  END IF
799 
800 
801  ! Read the global attributes
802  err_stat = readgatts_binary_file( &
803  fid, &
804  title = title , &
805  history = history, &
806  comment = comment )
807  IF ( err_stat /= success ) THEN
808  msg = 'Error reading global attributes'
809  CALL inquire_cleanup(); RETURN
810  END IF
811 
812 
813  ! Close the file
814  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
815  IF ( io_stat /= 0 ) THEN
816  msg = 'Error closing '//trim(filename)//' - '//trim(io_msg)
817  CALL inquire_cleanup(); RETURN
818  END IF
819 
820 
821  ! Assign the return arguments
822  IF ( PRESENT(n_objects) ) n_objects = n
823  IF ( PRESENT(release ) ) release = atmoptics%Release
824 
825  CONTAINS
826 
827  SUBROUTINE inquire_cleanup()
828  IF ( file_open(fid) ) THEN
829  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
830  IF ( io_stat /= 0 ) &
831  msg = trim(msg)//'; Error closing input file during error cleanup - '//trim(io_msg)
832  END IF
833  err_stat = failure
834  CALL display_message( routine_name, msg, err_stat )
835  END SUBROUTINE inquire_cleanup
836 
837  END FUNCTION crtm_atmoptics_inquirefile
838 
839 
840 !--------------------------------------------------------------------------------
841 !:sdoc+:
842 !
843 ! NAME:
844 ! CRTM_AtmOptics_ReadFile
845 !
846 ! PURPOSE:
847 ! Function to read AtmOptics object files.
848 !
849 ! CALLING SEQUENCE:
850 ! Error_Status = CRTM_AtmOptics_ReadFile( &
851 ! AtmOptics , &
852 ! Filename , &
853 ! No_Close = No_Close, &
854 ! Quiet = Quiet )
855 !
856 ! OBJECTS:
857 ! AtmOptics: AtmOptics object array containing the data read from file.
858 ! UNITS: N/A
859 ! TYPE: CRTM_AtmOptics_type
860 ! DIMENSION: Rank-1
861 ! ATTRIBUTES: INTENT(OUT), ALLOCATABLE
862 !
863 ! INPUTS:
864 ! Filename: Character string specifying the name of a
865 ! AtmOptics data file to read.
866 ! UNITS: N/A
867 ! TYPE: CHARACTER(*)
868 ! DIMENSION: Scalar
869 ! ATTRIBUTES: INTENT(IN)
870 !
871 ! OPTIONAL INPUTS:
872 ! No_Close: Set this logical argument to *NOT* close the datafile
873 ! upon exiting this routine. This option is required if
874 ! the AtmOptics data is embedded within another file.
875 ! If == .FALSE., File is closed upon function exit [DEFAULT].
876 ! == .TRUE., File is NOT closed upon function exit
877 ! If not specified, default is .FALSE.
878 ! UNITS: N/A
879 ! TYPE: LOGICAL
880 ! DIMENSION: Scalar
881 ! ATTRIBUTES: INTENT(IN), OPTIONAL
882 !
883 ! Quiet: Set this logical argument to suppress INFORMATION
884 ! messages being printed to stdout
885 ! If == .FALSE., INFORMATION messages are OUTPUT [DEFAULT].
886 ! == .TRUE., INFORMATION messages are SUPPRESSED.
887 ! If not specified, default is .FALSE.
888 ! UNITS: N/A
889 ! TYPE: LOGICAL
890 ! DIMENSION: Scalar
891 ! ATTRIBUTES: INTENT(IN), OPTIONAL
892 !
893 ! FUNCTION RESULT:
894 ! Error_Status: The return value is an integer defining the error status.
895 ! The error codes are defined in the Message_Handler module.
896 ! If == SUCCESS, the file read was successful
897 ! == FAILURE, an unrecoverable error occurred.
898 ! UNITS: N/A
899 ! TYPE: INTEGER
900 ! DIMENSION: Scalar
901 !
902 !:sdoc-:
903 !------------------------------------------------------------------------------
904 
905  FUNCTION crtm_atmoptics_readfile( &
906  AtmOptics, & ! Output
907  Filename , & ! Input
908  No_Close , & ! Optional input
909  Quiet , & ! Optional input
910  Title , & ! Optional output
911  History , & ! Optional output
912  Comment , & ! Optional output
913  Debug ) & ! Optional input (Debug output control)
914  result( err_stat )
915  ! Arguments
916  TYPE(crtm_atmoptics_type), ALLOCATABLE, INTENT(OUT) :: atmoptics(:)
917  CHARACTER(*), INTENT(IN) :: filename
918  LOGICAL, OPTIONAL, INTENT(IN) :: no_close
919  LOGICAL, OPTIONAL, INTENT(IN) :: quiet
920  CHARACTER(*), OPTIONAL, INTENT(OUT) :: title
921  CHARACTER(*), OPTIONAL, INTENT(OUT) :: history
922  CHARACTER(*), OPTIONAL, INTENT(OUT) :: comment
923  LOGICAL, OPTIONAL, INTENT(IN) :: debug
924  ! Function result
925  INTEGER :: err_stat
926  ! Function parameters
927  CHARACTER(*), PARAMETER :: routine_name = 'CRTM_AtmOptics_ReadFile'
928  ! Function variables
929  CHARACTER(ML) :: msg
930  CHARACTER(ML) :: count_msg
931  CHARACTER(ML) :: io_msg
932  LOGICAL :: close_file
933  LOGICAL :: noisy
934  INTEGER :: io_stat
935  INTEGER :: alloc_stat
936  INTEGER :: fid
937  INTEGER :: n, n_objects
938  TYPE(crtm_atmoptics_type) :: dummy
939 
940  ! Setup
941  err_stat = success
942  ! ...Check No_Close argument
943  close_file = .true.
944  IF ( PRESENT(no_close) ) close_file = .NOT. no_close
945  ! ...Check Quiet argument
946  noisy = .true.
947  IF ( PRESENT(quiet) ) noisy = .NOT. quiet
948  ! ...Override Quiet settings if debug set.
949  IF ( PRESENT(debug) ) THEN
950  IF ( debug ) noisy = .true.
951  END IF
952 
953 
954  ! Check if the file is open.
955  IF ( file_open( filename ) ) THEN
956  ! ...Inquire for the logical unit number
957  INQUIRE( file=filename, number=fid )
958  ! ...Ensure it's valid
959  IF ( fid < 0 ) THEN
960  msg = 'Error inquiring '//trim(filename)//' for its FileID'
961  CALL read_cleanup(); RETURN
962  END IF
963  ELSE
964  ! ...Open the file if it exists
965  IF ( file_exists( filename ) ) THEN
966  err_stat = open_binary_file( filename, fid )
967  IF ( err_stat /= success ) THEN
968  msg = 'Error opening '//trim(filename)
969  CALL read_cleanup(); RETURN
970  END IF
971  ELSE
972  msg = 'File '//trim(filename)//' not found.'
973  CALL read_cleanup(); RETURN
974  END IF
975  END IF
976 
977 
978  ! Read and check the release and version
979  READ( fid, iostat=io_stat, iomsg=io_msg ) &
980  dummy%Release
981  IF ( io_stat /= 0 ) THEN
982  msg = 'Error reading Release/Version - '//trim(io_msg)
983  CALL read_cleanup(); RETURN
984  END IF
985  IF ( .NOT. crtm_atmoptics_validrelease( dummy ) ) THEN
986  msg = 'Release check failed.'
987  CALL read_cleanup(); RETURN
988  END IF
989 
990 
991  ! Read the number of objects
992  READ( fid, iostat=io_stat,iomsg=io_msg ) n_objects
993  IF ( io_stat /= 0 ) THEN
994  msg = 'Error reading dimensions from '//trim(filename)//' - '//trim(io_msg)
995  CALL read_cleanup(); RETURN
996  END IF
997 
998 
999  ! Allocate the output array
1000  ALLOCATE( atmoptics(n_objects), stat=alloc_stat )
1001  IF ( alloc_stat /= 0 ) THEN
1002  msg = 'Error allocating output object array'
1003  CALL read_cleanup(); RETURN
1004  END IF
1005 
1006 
1007  ! Read the global attributes
1008  err_stat = readgatts_binary_file( &
1009  fid, &
1010  title = title , &
1011  history = history, &
1012  comment = comment )
1013  IF ( err_stat /= success ) THEN
1014  msg = 'Error reading global attributes'
1015  CALL read_cleanup(); RETURN
1016  END IF
1017 
1018 
1019  ! Loop over all the objects
1020  read_loop: DO n = 1, n_objects
1021 
1022 
1023  ! Generate count message for error output
1024  WRITE(count_msg,'("for object (",i0,")")') n
1025 
1026 
1027  ! Read the dimensions
1028  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1029  dummy%n_Layers , &
1030  dummy%n_Legendre_Terms, &
1031  dummy%n_Phase_Elements
1032  IF ( io_stat /= 0 ) THEN
1033  msg = 'Error reading dimensions '//trim(count_msg)//' from '//&
1034  trim(filename)//' - '//trim(io_msg)
1035  CALL read_cleanup(); RETURN
1036  END IF
1037  ! ...Allocate the object
1038  CALL crtm_atmoptics_create( &
1039  atmoptics(n) , &
1040  dummy%n_Layers , &
1041  dummy%n_Legendre_Terms, &
1042  dummy%n_Phase_Elements )
1043  IF ( .NOT. crtm_atmoptics_associated( atmoptics(n) ) ) THEN
1044  msg = 'Allocation failed '//trim(count_msg)
1045  CALL read_cleanup(); RETURN
1046  END IF
1047 
1048 
1049  ! Read the data
1050  ! ...Read the scalar data
1051  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1052  atmoptics(n)%Scattering_Optical_Depth
1053  IF ( io_stat /= 0 ) THEN
1054  msg = 'Error reading scalar data '//trim(count_msg)//' from '//&
1055  trim(filename)//' - '//trim(io_msg)
1056  CALL read_cleanup(); RETURN
1057  END IF
1058  ! ...Read the profile data
1059  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1060  atmoptics(n)%Optical_Depth , &
1061  atmoptics(n)%Single_Scatter_Albedo, &
1062  atmoptics(n)%Asymmetry_Factor , &
1063  atmoptics(n)%Delta_Truncation
1064  IF ( io_stat /= 0 ) THEN
1065  msg = 'Error reading profile data '//trim(count_msg)//' from '//&
1066  trim(filename)//' - '//trim(io_msg)
1067  CALL read_cleanup(); RETURN
1068  END IF
1069  ! ...Read the scattering phase matrix coefficients
1070  READ( fid, iostat=io_stat, iomsg=io_msg ) &
1071  atmoptics(n)%Phase_Coefficient
1072  IF ( io_stat /= 0 ) THEN
1073  msg = 'Error reading phase matrix coefficients '//trim(count_msg)//' from '//&
1074  trim(filename)//' - '//trim(io_msg)
1075  CALL read_cleanup(); RETURN
1076  END IF
1077 
1078  END DO read_loop
1079 
1080 
1081  ! Close the file
1082  IF ( close_file ) THEN
1083  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1084  IF ( io_stat /= 0 ) THEN
1085  msg = 'Error closing '//trim(filename)//' - '//trim(io_msg)
1086  CALL read_cleanup(); RETURN
1087  END IF
1088  END IF
1089 
1090 
1091  ! Output an info message
1092  IF ( noisy ) THEN
1093  WRITE( msg,'("Number of objects read from ",a,": ",i0)' ) trim(filename), n_objects
1094  CALL display_message( routine_name, msg, information )
1095  END IF
1096 
1097  CONTAINS
1098 
1099  SUBROUTINE read_cleanup()
1100  IF ( file_open(filename) ) THEN
1101  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1102  IF ( io_stat /= 0 ) &
1103  msg = trim(msg)//'; Error closing input file during error cleanup - '//trim(io_msg)
1104  END IF
1105  IF ( ALLOCATED(atmoptics) ) THEN
1106  DEALLOCATE( atmoptics, stat=alloc_stat )
1107  IF ( alloc_stat /= 0 ) &
1108  msg = trim(msg)//'; Error deallocating object array during error cleanup'
1109  END IF
1110  err_stat = failure
1111  CALL display_message( routine_name, msg, err_stat )
1112  END SUBROUTINE read_cleanup
1113 
1114  END FUNCTION crtm_atmoptics_readfile
1115 
1116 
1117 !--------------------------------------------------------------------------------
1118 !:sdoc+:
1119 !
1120 ! NAME:
1121 ! CRTM_AtmOptics_WriteFile
1122 !
1123 ! PURPOSE:
1124 ! Function to write AtmOptics object files.
1125 !
1126 ! CALLING SEQUENCE:
1127 ! Error_Status = CRTM_AtmOptics_WriteFile( &
1128 ! AtmOptics , &
1129 ! Filename , &
1130 ! No_Close = No_Close, &
1131 ! Quiet = Quiet )
1132 !
1133 ! OBJECTS:
1134 ! AtmOptics: AtmOptics object array containing the data to write to file.
1135 ! UNITS: N/A
1136 ! TYPE: CRTM_AtmOptics_type
1137 ! DIMENSION: Rank-1
1138 ! ATTRIBUTES: INTENT(IN)
1139 !
1140 ! INPUTS:
1141 ! Filename: Character string specifying the name of a
1142 ! AtmOptics format data file to write.
1143 ! UNITS: N/A
1144 ! TYPE: CHARACTER(*)
1145 ! DIMENSION: Scalar
1146 ! ATTRIBUTES: INTENT(IN)
1147 !
1148 ! OPTIONAL INPUTS:
1149 ! No_Close: Set this logical argument to *NOT* close the datafile
1150 ! upon exiting this routine. This option is required if
1151 ! the AtmOptics data is to be embedded within another file.
1152 ! If == .FALSE., File is closed upon function exit [DEFAULT].
1153 ! == .TRUE., File is NOT closed upon function exit
1154 ! If not specified, default is .FALSE.
1155 ! UNITS: N/A
1156 ! TYPE: LOGICAL
1157 ! DIMENSION: Scalar
1158 ! ATTRIBUTES: INTENT(IN), OPTIONAL
1159 !
1160 ! Quiet: Set this logical argument to suppress INFORMATION
1161 ! messages being printed to stdout
1162 ! If == .FALSE., INFORMATION messages are OUTPUT [DEFAULT].
1163 ! == .TRUE., INFORMATION messages are SUPPRESSED.
1164 ! If not specified, default is .FALSE.
1165 ! UNITS: N/A
1166 ! TYPE: LOGICAL
1167 ! DIMENSION: Scalar
1168 ! ATTRIBUTES: INTENT(IN), OPTIONAL
1169 !
1170 ! FUNCTION RESULT:
1171 ! Error_Status: The return value is an integer defining the error status.
1172 ! The error codes are defined in the Message_Handler module.
1173 ! If == SUCCESS, the file write was successful
1174 ! == FAILURE, an unrecoverable error occurred.
1175 ! UNITS: N/A
1176 ! TYPE: INTEGER
1177 ! DIMENSION: Scalar
1178 !
1179 !:sdoc-:
1180 !------------------------------------------------------------------------------
1181 
1182  FUNCTION crtm_atmoptics_writefile( &
1183  AtmOptics, & ! Input
1184  Filename , & ! Input
1185  No_Close , & ! Optional input
1186  Quiet , & ! Optional input
1187  Title , & ! Optional input
1188  History , & ! Optional input
1189  Comment , & ! Optional input
1190  Debug ) & ! Optional input (Debug output control)
1191  result( err_stat )
1192  ! Arguments
1193  TYPE(crtm_atmoptics_type), INTENT(IN) :: atmoptics(:)
1194  CHARACTER(*), INTENT(IN) :: filename
1195  LOGICAL, OPTIONAL, INTENT(IN) :: no_close
1196  LOGICAL, OPTIONAL, INTENT(IN) :: quiet
1197  CHARACTER(*), OPTIONAL, INTENT(IN) :: title
1198  CHARACTER(*), OPTIONAL, INTENT(IN) :: history
1199  CHARACTER(*), OPTIONAL, INTENT(IN) :: comment
1200  LOGICAL, OPTIONAL, INTENT(IN) :: debug
1201  ! Function result
1202  INTEGER :: err_stat
1203  ! Function parameters
1204  CHARACTER(*), PARAMETER :: routine_name = 'CRTM_AtmOptics_WriteFile'
1205  ! Function variables
1206  CHARACTER(ML) :: msg
1207  CHARACTER(ML) :: count_msg
1208  CHARACTER(ML) :: io_msg
1209  LOGICAL :: close_file
1210  LOGICAL :: noisy
1211  INTEGER :: io_stat
1212  INTEGER :: fid
1213  INTEGER :: n, n_objects
1214 
1215 
1216  ! Setup
1217  err_stat = success
1218  ! ...Check No_Close argument
1219  close_file = .true.
1220  IF ( PRESENT(no_close) ) close_file = .NOT. no_close
1221  ! ...Check Quiet argument
1222  noisy = .true.
1223  IF ( PRESENT(quiet) ) noisy = .NOT. quiet
1224  ! ...Override Quiet settings if debug set.
1225  IF ( PRESENT(debug) ) THEN
1226  IF ( debug ) noisy = .true.
1227  END IF
1228  ! ...Check there is data to write
1229  IF ( .NOT. all(crtm_atmoptics_associated( atmoptics )) ) THEN
1230  msg = 'Unassociated objects in input array.'
1231  CALL write_cleanup(); RETURN
1232  END IF
1233  n_objects= SIZE(atmoptics)
1234 
1235 
1236  ! Check if the file is open.
1237  IF ( file_open( filename ) ) THEN
1238  ! ...Inquire for the logical unit number
1239  INQUIRE( file=filename, number=fid )
1240  ! ...Ensure it's valid
1241  IF ( fid < 0 ) THEN
1242  msg = 'Error inquiring '//trim(filename)//' for its FileID'
1243  CALL write_cleanup(); RETURN
1244  END IF
1245  ELSE
1246  ! ...Open the file for output
1247  err_stat = open_binary_file( filename, fid, for_output=.true. )
1248  IF ( err_stat /= success ) THEN
1249  msg = 'Error opening '//trim(filename)
1250  CALL write_cleanup(); RETURN
1251  END IF
1252  END IF
1253 
1254 
1255  ! Write the release
1256  WRITE( fid, iostat=io_stat, iomsg=io_msg ) atmoptics_release
1257  IF ( io_stat /= 0 ) THEN
1258  msg = 'Error writing Release - '//trim(io_msg)
1259  CALL write_cleanup(); RETURN
1260  END IF
1261 
1262 
1263  ! Write the number of objects
1264  WRITE( fid, iostat=io_stat,iomsg=io_msg ) SIZE(atmoptics)
1265  IF ( io_stat /= 0 ) THEN
1266  msg = 'Error writing dimensions to '//trim(filename)//' - '//trim(io_msg)
1267  CALL write_cleanup(); RETURN
1268  END IF
1269 
1270 
1271  ! Write the global attributes
1272  err_stat = writegatts_binary_file( &
1273  fid, &
1274  write_module = module_version_id, &
1275  title = title , &
1276  history = history, &
1277  comment = comment )
1278  IF ( err_stat /= success ) THEN
1279  msg = 'Error writing global attributes'
1280  CALL write_cleanup(); RETURN
1281  END IF
1282 
1283 
1284  ! Loop over all the objects
1285  write_loop: DO n = 1, n_objects
1286 
1287 
1288  ! Generate count message for error output
1289  WRITE(count_msg,'("for object (",i0,")")') n
1290 
1291 
1292  ! Write the dimensions
1293  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1294  atmoptics(n)%n_Layers , &
1295  atmoptics(n)%n_Legendre_Terms, &
1296  atmoptics(n)%n_Phase_Elements
1297  IF ( io_stat /= 0 ) THEN
1298  msg = 'Error writing dimensions '//trim(count_msg)//' to '//&
1299  trim(filename)//' - '//trim(io_msg)
1300  CALL write_cleanup(); RETURN
1301  END IF
1302 
1303 
1304  ! Write the data
1305  ! ...Write the scalar data
1306  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1307  atmoptics(n)%Scattering_Optical_Depth
1308  IF ( io_stat /= 0 ) THEN
1309  msg = 'Error writing scalar data '//trim(count_msg)//' to '//&
1310  trim(filename)//' - '//trim(io_msg)
1311  CALL write_cleanup(); RETURN
1312  END IF
1313  ! ...Write the profile data
1314  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1315  atmoptics(n)%Optical_Depth(1:atmoptics(n)%n_Layers) , &
1316  atmoptics(n)%Single_Scatter_Albedo(1:atmoptics(n)%n_Layers), &
1317  atmoptics(n)%Asymmetry_Factor(1:atmoptics(n)%n_Layers) , &
1318  atmoptics(n)%Delta_Truncation(1:atmoptics(n)%n_Layers)
1319  IF ( io_stat /= 0 ) THEN
1320  msg = 'Error writing profile data '//trim(count_msg)//' to '//&
1321  trim(filename)//' - '//trim(io_msg)
1322  CALL write_cleanup(); RETURN
1323  END IF
1324  ! ...Write the scattering phase matrix coefficients
1325  WRITE( fid, iostat=io_stat, iomsg=io_msg ) &
1326  atmoptics(n)%Phase_Coefficient(0:atmoptics(n)%n_Legendre_Terms, &
1327  1:atmoptics(n)%n_Phase_Elements, &
1328  1:atmoptics(n)%n_Layers)
1329  IF ( io_stat /= 0 ) THEN
1330  msg = 'Error writing phase matrix coefficients '//trim(count_msg)//' to '//&
1331  trim(filename)//' - '//trim(io_msg)
1332  CALL write_cleanup(); RETURN
1333  END IF
1334 
1335  END DO write_loop
1336 
1337 
1338  ! Close the file
1339  IF ( close_file ) THEN
1340  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1341  IF ( io_stat /= 0 ) THEN
1342  msg = 'Error closing '//trim(filename)//' - '//trim(io_msg)
1343  CALL write_cleanup(); RETURN
1344  END IF
1345  END IF
1346 
1347 
1348  ! Output an info message
1349  IF ( noisy ) THEN
1350  WRITE( msg,'("Number of objects written to ",a,": ",i0)' ) trim(filename), n_objects
1351  CALL display_message( routine_name, msg, information )
1352  END IF
1353 
1354  CONTAINS
1355 
1356  SUBROUTINE write_cleanup()
1357  IF ( file_open(filename) ) THEN
1358  CLOSE( fid, iostat=io_stat, iomsg=io_msg )
1359  IF ( io_stat /= 0 ) &
1360  msg = trim(msg)//'; Error closing output file during error cleanup - '//trim(io_msg)
1361  END IF
1362  err_stat = failure
1363  CALL display_message( routine_name, msg, err_stat )
1364  END SUBROUTINE write_cleanup
1365 
1366  END FUNCTION crtm_atmoptics_writefile
1367 
1368 
1369 !################################################################################
1370 !################################################################################
1371 !## ##
1372 !## ## PRIVATE PROCEDURES ## ##
1373 !## ##
1374 !################################################################################
1375 !################################################################################
1376 
1377 !--------------------------------------------------------------------------------
1378 !
1379 ! NAME:
1380 ! CRTM_AtmOptics_Equal
1381 !
1382 ! PURPOSE:
1383 ! Elemental function to test the equality of two AtmOptics objects.
1384 ! Used in OPERATOR(==) interface block.
1385 !
1386 ! CALLING SEQUENCE:
1387 ! is_equal = CRTM_AtmOptics_Equal( x, y )
1388 !
1389 ! or
1390 !
1391 ! IF ( x == y ) THEN
1392 ! ...
1393 ! END IF
1394 !
1395 ! OBJECTS:
1396 ! x, y: Two AtmOptics objects to be compared.
1397 ! UNITS: N/A
1398 ! TYPE: CRTM_AtmOptics_type
1399 ! DIMENSION: Scalar or any rank
1400 ! ATTRIBUTES: INTENT(IN)
1401 !
1402 ! FUNCTION RESULT:
1403 ! is_equal: Logical value indicating whether the inputs are equal.
1404 ! UNITS: N/A
1405 ! TYPE: LOGICAL
1406 ! DIMENSION: Same as inputs.
1407 !
1408 !--------------------------------------------------------------------------------
1409 
1410  ELEMENTAL FUNCTION crtm_atmoptics_equal( x, y ) RESULT( is_equal )
1411  TYPE(crtm_atmoptics_type), INTENT(IN) :: x, y
1412  LOGICAL :: is_equal
1413 
1414  ! Set up
1415  is_equal = .false.
1416 
1417  ! Check the object association status
1418  IF ( (.NOT. crtm_atmoptics_associated(x)) .OR. &
1419  (.NOT. crtm_atmoptics_associated(y)) ) RETURN
1420 
1421  ! Check contents
1422  ! ...Release/version info
1423  IF ( (x%Release /= y%Release) ) RETURN
1424  ! ...Dimensions
1425  IF ( (x%n_Layers /= y%n_Layers ) .OR. &
1426  (x%n_Legendre_Terms /= y%n_Legendre_Terms) .OR. &
1427  (x%n_Phase_Elements /= y%n_Phase_Elements) ) RETURN
1428  ! ...Scalar data
1429  IF ( x%Scattering_Optical_Depth .equalto. y%Scattering_Optical_Depth ) &
1430  is_equal = .true.
1431  ! ...Array data
1432  is_equal = is_equal .AND. &
1433  all(x%Optical_Depth(1:x%n_Layers) .equalto. y%Optical_Depth(1:y%n_Layers) ) .AND. &
1434  all(x%Single_Scatter_Albedo(1:x%n_Layers) .equalto. y%Single_Scatter_Albedo(1:y%n_Layers)) .AND. &
1435  all(x%Asymmetry_Factor(1:x%n_Layers) .equalto. y%Asymmetry_Factor(1:y%n_Layers) ) .AND. &
1436  all(x%Delta_Truncation(1:x%n_Layers) .equalto. y%Delta_Truncation(1:y%n_Layers) ) .AND. &
1437  all(x%Phase_Coefficient(0:x%n_Legendre_Terms, 1:x%n_Phase_Elements, 1:x%n_Layers) .equalto. &
1438  y%Phase_Coefficient(0:y%n_Legendre_Terms, 1:y%n_Phase_Elements, 1:y%n_Layers) )
1439 
1440  END FUNCTION crtm_atmoptics_equal
1441 
1442 
1443 !--------------------------------------------------------------------------------
1444 !
1445 ! NAME:
1446 ! CRTM_AtmOptics_Subtract
1447 !
1448 ! PURPOSE:
1449 ! Pure function to subtract two CRTM AtmOptics objects.
1450 ! Used in OPERATOR(-) interface block.
1451 !
1452 ! CALLING SEQUENCE:
1453 ! aodiff = CRTM_AtmOptics_Subtract( ao1, ao2 )
1454 !
1455 ! or
1456 !
1457 ! aodiff = ao1 - ao2
1458 !
1459 !
1460 ! INPUTS:
1461 ! ao1, ao2: The AtmOptics objects to difference.
1462 ! UNITS: N/A
1463 ! TYPE: CRTM_AtmOptics_type
1464 ! DIMENSION: Scalar
1465 ! ATTRIBUTES: INTENT(IN OUT)
1466 !
1467 ! RESULT:
1468 ! aodiff: AtmOptics object containing the differenced components.
1469 ! UNITS: N/A
1470 ! TYPE: CRTM_AtmOptics_type
1471 ! DIMENSION: Scalar
1472 !
1473 !--------------------------------------------------------------------------------
1474 
1475  ELEMENTAL FUNCTION crtm_atmoptics_subtract( ao1, ao2 ) RESULT( aodiff )
1476  TYPE(crtm_atmoptics_type), INTENT(IN) :: ao1, ao2
1477  TYPE(crtm_atmoptics_type) :: aodiff
1478  INTEGER :: ic, ip, k
1479 
1480  ! Check input
1481  ! ...If input structures not allocated, do nothing
1482  IF ( (.NOT. crtm_atmoptics_associated(ao1)) .OR. &
1483  (.NOT. crtm_atmoptics_associated(ao2)) ) RETURN
1484  ! ...If input structure for different sizes, do nothing
1485  IF ( ao1%n_Layers /= ao2%n_Layers .OR. &
1486  ao1%n_Legendre_Terms /= ao2%n_Legendre_Terms .OR. &
1487  ao1%n_Phase_Elements /= ao2%n_Phase_Elements ) RETURN
1488  ! ...If input structure for different scattering setup, do nothing
1489  IF ( (ao1%Include_Scattering .NEQV. ao2%Include_Scattering ) .AND. &
1490  (ao1%lOffset /= ao2%lOffset ) ) RETURN
1491 
1492  ! Copy the first structure
1493  aodiff = ao1
1494 
1495  ! And subtract the second one's components from it
1496  ! ...The scalar values
1497  aodiff%Scattering_Optical_Depth = aodiff%Scattering_Optical_Depth - ao2%Scattering_Optical_Depth
1498  ! ...The arrays
1499  k = aodiff%n_Layers
1500  ip = aodiff%n_Phase_Elements
1501  ic = aodiff%n_Legendre_Terms
1502  aodiff%Optical_Depth(1:k) = aodiff%Optical_Depth(1:k) - ao2%Optical_Depth(1:k)
1503  aodiff%Single_Scatter_Albedo(1:k) = aodiff%Single_Scatter_Albedo(1:k) - ao2%Single_Scatter_Albedo(1:k)
1504  aodiff%Asymmetry_Factor(1:k) = aodiff%Asymmetry_Factor(1:k) - ao2%Asymmetry_Factor(1:k)
1505  aodiff%Delta_Truncation(1:k) = aodiff%Delta_Truncation(1:k) - ao2%Delta_Truncation(1:k)
1506  aodiff%Phase_Coefficient(0:ic,1:ip,1:k) = aodiff%Phase_Coefficient(0:ic,1:ip,1:k) - ao2%Phase_Coefficient(0:ic,1:ip,1:k)
1507 
1508  END FUNCTION crtm_atmoptics_subtract
1509 
1510 END MODULE crtm_atmoptics_define
integer, parameter, public failure
subroutine, public crtm_atmoptics_info(self, Info)
elemental logical function crtm_atmoptics_equal(x, y)
integer, parameter atmoptics_release
integer, parameter, public long
Definition: Type_Kinds.f90:76
logical function, public crtm_atmoptics_validrelease(self)
integer, parameter, public fp
Definition: Type_Kinds.f90:124
pure subroutine atmoptics_allocate(self, alloc_stat)
elemental type(crtm_atmoptics_type) function crtm_atmoptics_subtract(ao1, ao2)
integer function, public crtm_atmoptics_inquirefile(Filename, n_Objects, Release, Title, History, Comment)
integer function, public readgatts_binary_file(fid, Write_Module, Created_On, Title, History, Comment)
integer, parameter, public double
Definition: Type_Kinds.f90:106
elemental subroutine, public crtm_atmoptics_destroy(self)
subroutine inquire_cleanup()
elemental logical function, public crtm_atmoptics_associated(self)
elemental subroutine, public crtm_atmoptics_zero(self)
subroutine read_cleanup()
integer function, public crtm_atmoptics_writefile(AtmOptics, Filename, No_Close, Quiet, Title, History, Comment, Debug)
subroutine write_cleanup()
elemental logical function, public crtm_atmoptics_compare(x, y, n_SigFig)
integer function, public open_binary_file(Filename, FileID, For_Output, No_Check)
recursive subroutine, public display_message(Routine_Name, Message, Error_State, Message_Log)
elemental subroutine, public crtm_atmoptics_create(self, n_Layers, n_Legendre_Terms, n_Phase_Elements)
character(*), parameter module_version_id
character(*), parameter write_error_status
integer, parameter, public default_n_sigfig
integer function, public writegatts_binary_file(fid, Write_Module, Created_On, Title, History, Comment)
integer function, public crtm_atmoptics_readfile(AtmOptics, Filename, No_Close, Quiet, Title, History, Comment, Debug)
#define min(a, b)
Definition: mosaic_util.h:32
integer, parameter, public success
subroutine, public crtm_atmoptics_defineversion(Id)
integer, parameter, public information