OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
planck_functions.f90
Go to the documentation of this file.
2 
3 ! This module replaces a bunch of F77 code that has been causing us grief since time
4 ! immemorial. -- Gala Wind 3.30.17
5 
6  implicit none
7 
8  private
9 
10  public :: modis_planck, modis_bright
11 
12 ! Fundamental constants required for the monochromatic
13 ! Planck function routines PLANCK_M, PLANC_M, BRIGHT_M, BRITE_M
14 ! Taken from the NIST Reference on Constants, Units, and Uncertainty
15 
16 ! http://physics.nist.gov/cuu/Constants/
17 
18 ! See also:
19 
20 ! Mohr, P.J. and B.N. Taylor, "CODATA recommended values of the
21 ! fundamental physical constants: 1998", Reviews of Modern Physics,
22 ! Vol.72, No.2, 2000.
23 
24 ! ... Planck constant (Joule second)
25  real(8), parameter :: h = 6.62606876d-34
26 
27 ! ... Speed of light in vacuum (meters per second)
28  real(8), parameter :: c = 2.99792458d+08
29 
30 ! ... Boltzmann constant (Joules per Kelvin)
31  real(8), parameter :: k = 1.3806503d-23
32 
33 ! ... Derived constants
34  real(8), parameter :: c1 = 2.0d+0 * h * c * c
35  real(8), parameter :: c2 = (h * c) / k
36 
37 ! MODIS BANDS
38 ! 20, 21, 22, 23,
39 ! 24, 25, 27, 28,
40 ! 29, 30, 31, 32,
41 ! 33, 34, 35, 36,
42 ! ... Effective central wavenumbers (inverse centimeters)
43  real, parameter :: cwn_terra(16) = (/ 2.641775e+03, 2.505277e+03, 2.518028e+03, 2.465428e+03, &
44  2.235815e+03, 2.200346e+03, 1.477967e+03, 1.362737e+03, &
45  1.173190e+03, 1.027715e+03, 9.080884e+02, 8.315399e+02, &
46  7.483394e+02, 7.308963e+02, 7.188681e+02, 7.045367e+02 /)
47 
48 ! ... Temperature correction slopes (no units)
49  real, parameter :: tcs_terra(16) = (/ 9.993411e-01, 9.998646e-01, 9.998585e-01, 9.998682e-01, &
50  9.998820e-01, 9.998845e-01, 9.994878e-01, 9.994918e-01, &
51  9.995496e-01, 9.997399e-01, 9.995607e-01, 9.997256e-01, &
52  9.999161e-01, 9.999167e-01, 9.999192e-01, 9.999282e-01 /)
53 
54 ! ... Temperature correction intercepts (Kelvin)
55  real, parameter :: tci_terra(16) = (/ 4.770522e-01, 9.264053e-02, 9.756834e-02, 8.928794e-02, &
56  7.309468e-02, 7.061112e-02, 2.204659e-01, 2.045902e-01, &
57  1.599076e-01, 8.249532e-02, 1.302885e-01, 7.181662e-02, &
58  1.970605e-02, 1.912743e-02, 1.816222e-02, 1.579983e-02 /)
59 
60 
61  real, parameter :: cwn_aqua(16) = (/ 2.647409e+03, 2.511760e+03, 2.517908e+03, 2.462442e+03, &
62  2.248296e+03, 2.209547e+03, 1.474262e+03, 1.361626e+03, &
63  1.169626e+03, 1.028740e+03, 9.076813e+02, 8.308411e+02, &
64  7.482978e+02, 7.307766e+02, 7.182094e+02, 7.035007e+02 /)
65 
66  real, parameter :: tcs_aqua(16) = (/ 9.993363e-01, 9.998626e-01, 9.998627e-01, 9.998707e-01, &
67  9.998737e-01, 9.998770e-01, 9.995694e-01, 9.994867e-01, &
68  9.995270e-01, 9.997382e-01, 9.995270e-01, 9.997271e-01, &
69  9.999173e-01, 9.999070e-01, 9.999198e-01, 9.999233e-01 /)
70 
71  real, parameter :: tci_aqua(16) = (/ 4.818401e-01, 9.426663e-02, 9.458604e-02, 8.736613e-02, &
72  7.873285e-02, 7.550804e-02, 1.848769e-01, 2.064384e-01, &
73  1.674982e-01, 8.304364e-02, 1.343433e-01, 7.135051e-02, &
74  1.948513e-02, 2.131043e-02, 1.804156e-02, 1.683156e-02 /)
75 
76 !-----------------------------------------------------------------------
77 ! MAS BANDS
78 ! 30, 31, 42, 45, 46, 48, 49
79  real, parameter :: cwn_mas(7) = (/ 2652.519, 2551.02, 1170.411, 912.99, 830.77, 751.16, 723.96 /)
80  real, parameter :: tcs_mas(7) = (/ 0.99937, 0.99946, 0.99937, 0.99955, 0.99967, 0.99978, 0.99977 /)
81  real, parameter :: tci_mas(7) = (/ 0.44728, 0.43909, 0.22513, 0.13007, 0.087251, 0.05295, 0.053137 /)
82 
83 !-----------------------------------------------------------------------
84 ! MASTER BANDS
85 ! 30, 43, 47, 49 plus SHIS MAS-equivalent bands 48 and 49
86  real, parameter :: cwn_master(6) = (/ 2670.227, 1155.4015, 941.17, 820.51, 751.16, 723.96 /)
87  real, parameter :: tcs_master(6) = (/ 0.99944, 0.99934, 0.99937, 0.99963, 0.99978, 0.99977 /)
88  real, parameter :: tci_master(6) = (/ 0.41362, 0.23203, 0.18665, 0.094882, 0.05295, 0.053137 /)
89 
90 !-----------------------------------------------------------------------
91 ! SEVIRI BANDS
92 ! 3.9, 7.3, 8.5, 11., 12. and 13.4 um
93  real, parameter :: cwn_seviri(6) = (/ 2569.094, 1362.142, 1149.083, 930.659, 839.661, 746.27 /)
94  real, parameter :: tcs_seviri(6) = (/ 0.9959, 0.9991, 0.9996, 0.9983, 0.9988, 0.9981 /)
95  real, parameter :: tci_seviri(6) = (/ 3.471, 0.485, 0.181, 0.627, 0.397, 0.576 /)
96 
97 !-----------------------------------------------------------------------
98 ! VIIRS BANDS
99 ! 3., 7.3, 8.5, 11., 12. and 13.4 um
100  real, parameter :: cwn_viirs(5) = (/ 2708.3865, 2460.8193, 1166.1845, 935.10476, 845.79752 /)
101  real, parameter :: tcs_viirs(5) = (/ 0.999354, 0.999623, 0.999698, 0.998273, 0.998778 /)
102  real, parameter :: tci_viirs(5) = (/ 0.593537, 0.325879, 0.146942, 0.650338, 0.421701 /)
103 
104 !-----------------------------------------------------------------------
105 ! AMS BANDS
106 ! 3.7 and 10.2
107  real, parameter :: cwn_ams(2) = (/ 2656.04241, 979.9118 /)
108  real, parameter :: tcs_ams(2) = (/ 0.99942, 0.99778 /)
109  real, parameter :: tci_ams(2) = (/ 0.42667, 0.65987 /)
110 
111 !-----------------------------------------------------------------------
112 ! EMAS BANDS
113 ! 3.7, 6.7, 7.3, 8.5, 11, 12, 13.3, 13.6 and 13.9
114 ! 26, 27, 28, 30, 33, 34, 36, 37, 38
115  real, parameter :: cwn_emas(9) = (/ 2683.8433, 1492.5373, 1372.4951, 1167.6786, 903.9956, &
116  832.9168, 749.9062, 733.5681, 716.1784 /)
117 
118  real, parameter :: tcs_emas(9) = (/ 0.99932, 0.99938, 0.99925, 0.99977, 0.99985, &
119  0.99974, 0.99985, 0.99993, 0.99990 /)
120 
121  real, parameter :: tci_emas(9) = (/ 0.50705, 0.27642, 0.32168, 0.082686, 0.041587, &
122  0.069156, 0.036514, 0.017001, 0.022627 /)
123 
124 
125 
126 !------------------------------------------------------------------------
127 ! ASTER bands
128 ! 10, 11, 12, 13 and 14
129  real, parameter :: cwn_aster(5) = (/ 1208.1301, 1159.0481, 1102.0475, 939.39813, 886.77863 /)
130  real, parameter :: tcs_aster(5) = (/ 0.99967480, 0.99970657, 0.99965727, 0.99928176, 0.99941397 /)
131  real, parameter :: tci_aster(5) = (/ 0.12009826, 0.10460924, 0.11673445, 0.21520464, 0.16743699 /)
132 
133 !------------------------------------------------------------------------
134 ! AHI bands
135 ! 7-16
136  real, parameter :: cwn_ahi(10) = (/ 2575.7673, 1609.2411, 1442.0793, 1361.3868, &
137  1164.4431, 1038.1084, 961.3326, 890.7408, &
138  809.2418, 753.3690 /)
139 
140  real, parameter :: tcs_ahi(10) = (/ 0.99936, 0.99649, 0.99927, 0.99986, &
141  0.99963, 0.99971, 0.99971, 0.99938, &
142  0.99908, 0.99975 /)
143 
144  real, parameter :: tci_ahi(10) = (/ 0.45925, 1.62641, 0.30465, 0.05552, &
145  0.13189, 0.09194, 0.08686, 0.17399, &
146  0.23460, 0.05990 /)
147 
148 contains
149 
150  subroutine pick_a_band(platform_name, band, cwn, tcs, tci, cwn_array, tcs_array, tci_array)
151 
152 
153  character*(*), intent(in) :: platform_name
154  integer, intent(in) :: band
155  real, intent(inout) :: cwn, tcs, tci
156  real, dimension(:), intent(in), optional :: cwn_array, tcs_array, tci_array
157 
158  integer :: index
159 
160 ! if S-HIS data is present, we'll use defaults
161 ! Aircraft CWN, TCS and TCI can change randomly so we have defaults, but
162 ! will probably never use them.
163 
164  if (platform_name(1:6) == 'Master' .or. &
165  platform_name(1:6) == 'master' .or. &
166  platform_name(1:6) == 'MASTER') then
167 
168  if (band == 30) index = 1
169  if (band == 43) index = 2
170  if (band == 47) index = 3
171  if (band == 49) index = 4
172  if (band == 60) index = 5
173  if (band == 61) index = 6
174 
175  if (present(cwn_array) .and. band < 60) then
176  cwn = cwn_array(band)
177  tcs = tcs_array(band)
178  tci = tci_array(band)
179  else
180  cwn = cwn_master(index)
181  tcs = tcs_master(index)
182  tci = tci_master(index)
183  endif
184 
185  else if (platform_name(1:3) == 'Mas' .or. &
186  platform_name(1:3) == 'mas' .or. &
187  platform_name(1:3) == 'MAS') then
188 
189  if (band == 30) index = 1
190  if (band == 31) index = 2
191  if (band == 42) index = 3
192  if (band == 45) index = 4
193  if (band == 46) index = 5
194  if (band == 48 .or. band == 60) index = 6
195  if (band == 49 .or. band == 61) index = 7
196 
197  if (present(cwn_array) .and. band < 60) then
198  cwn = cwn_array(band)
199  tcs = tcs_array(band)
200  tci = tci_array(band)
201  else
202  cwn = cwn_mas(index)
203  tcs = tcs_mas(index)
204  tci = tci_mas(index)
205  endif
206 
207  else if (platform_name(1:6) == 'SEVIRI' .or. &
208  platform_name(1:6) == 'seviri' .or. &
209  platform_name(1:6) == 'Seviri') then
210 
211  if (band == 4) index = 1
212  if (band == 6) index = 2
213  if (band == 7) index = 3
214  if (band == 9) index = 4
215  if (band == 10) index = 5
216  if (band == 11) index = 6
217 
218  cwn = cwn_seviri(index)
219  tcs = tcs_seviri(index)
220  tci = tci_seviri(index)
221 
222  else if (platform_name(1:11) == 'NPP_:_VIIRS' .or. &
223  platform_name(1:3) == 'npp' .or. &
224  platform_name(1:5) == 'VIIRS' ) then
225  index = band - 11
226 
227  cwn = cwn_viirs(index)
228  tcs = tcs_viirs(index)
229  tci = tci_viirs(index)
230 
231  else if (platform_name(1:3) == 'AMS') then
232  if (band == 11) index = 1
233  if (band == 12) index = 2
234 
235  cwn = cwn_ams(index)
236  tcs = tcs_ams(index)
237  tci = tci_ams(index)
238 
239  else if (platform_name(1:4) == 'EMAS') then
240 
241  if (band == 26) index = 1
242  if (band == 27) index = 2
243  if (band == 28) index = 3
244  if (band == 30) index = 4
245  if (band == 33) index = 5
246  if (band == 34) index = 6
247  if (band == 36) index = 7
248  if (band == 37) index = 8
249  if (band == 38) index = 9
250 
251  if (present(cwn_array)) then
252  cwn = cwn_array(band)
253  tcs = tcs_array(band)
254  tci = tci_array(band)
255  else
256  cwn = cwn_emas(index)
257  tcs = tcs_emas(index)
258  tci = tci_emas(index)
259  endif
260 
261  else if (platform_name(1:5) == 'ASTER') then
262 
263  index = band - 9
264 
265  cwn = cwn_aster(index)
266  tcs = tcs_aster(index)
267  tci = tci_aster(index)
268 
269  else if (platform_name(1:3) == 'AHI') then
270 
271  index = band-6
272 
273  cwn = cwn_ahi(index)
274  tcs = tcs_ahi(index)
275  tci = tci_ahi(index)
276 
277  else
278 ! MODIS
279 ! ... Get index into coefficient arrays
280  if (band .le. 25) then
281  index = band - 19
282  else
283  index = band - 20
284  endif
285 
286  if (platform_name(1:5) == 'Terra' .or. &
287  platform_name(1:5) == 'terra' .or. &
288  platform_name(1:5) == 'TERRA') then
289  cwn = cwn_terra(index)
290  tcs = tcs_terra(index)
291  tci = tci_terra(index)
292  else if (platform_name(1:4) == 'Aqua' .or. &
293  platform_name(1:4) == 'aqua' .or. &
294  platform_name(1:4) == 'AQUA') then
295  cwn = cwn_aqua(index)
296  tcs = tcs_aqua(index)
297  tci = tci_aqua(index)
298  else
299  print*, "Invalid platform: ", trim(platform_name)
300  stop
301  endif
302 
303  endif
304 
305 
306  end subroutine pick_a_band
307 
308 
309 
310  REAL FUNCTION PLANCK_M(W, T)
311 
312 !-----------------------------------------------------------------------
313 !!F77
314 !
315 !!DESCRIPTION:
316 ! Compute monochromatic Planck radiance given brightness temperature
317 ! (Radiance units: Watts per square meter per steradian per micron)
318 !
319 !!INPUT PARAMETERS:
320 ! W (REAL) Wavelength (microns)
321 ! T (REAL) Brightness temperature (Kelvin)
322 !
323 !!OUTPUT PARAMETERS:
324 ! PLANCK_M (REAL) Monochromatic Planck radiance (Watts per
325 ! square meter per steradian per micron)
326 !
327 !!REVISION HISTORY:
328 !
329 !!TEAM-UNIQUE HEADER:
330 ! Liam.Gumley@ssec.wisc.edu
331 !
332 !!END
333 !-----------------------------------------------------------------------
334 
335  real, intent(in) :: w, t
336  real(8) :: ws
337 
338  planck_m = -1.0
339 
340  if (w <= 0.0 .or. t <= 0.0) return
341 
342 ! ... Convert wavelength to meters
343  ws = w * 1.0d-6
344 ! ... Compute Planck radiance
345  planck_m = sngl(1.0d-6 * (c1 / ws**5) / (exp(c2 / (ws * dble(t))) - 1.0d+0))
346 
347  END function planck_m
348 
349 ! same as planck_m, but the wavelength is in wavenumber instead of micron
350  REAL FUNCTION PLANC_M(V, T)
351 
352  real, intent(in) :: v, t
353  real(8) :: vs
354 
355  planc_m = -1.0
356 
357  if (v <= 0.0 .or. t <= 0.0) return
358 
359 ! ... Convert wavenumber to inverse meters
360  vs = 1.0d+2 * v
361 ! ... Compute Planck radiance
362  planc_m = sngl(1.0d+5 * (c1 * vs**3) / (exp(c2 * vs / dble(t)) - 1.0d+0))
363 
364  END function planc_m
365 
366 
367  REAL FUNCTION BRIGHT_M(W, R)
368 
369 !-----------------------------------------------------------------------
370 !!F77
371 !
372 !!DESCRIPTION:
373 ! Compute brightness temperature given monochromatic Planck radiance
374 ! (Radiance units: Watts per square meter per steradian per micron)
375 !
376 !!INPUT PARAMETERS:
377 ! W (REAL) Wavelength (microns)
378 ! R (REAL) Monochromatic Planck radiance (Watts per
379 ! square meter per steradian per micron)
380 !
381 !!OUTPUT PARAMETERS:
382 ! BRIGHT_M (REAL) Brightness temperature (Kelvin)
383 !
384 !!REVISION HISTORY:
385 !
386 !!TEAM-UNIQUE HEADER:
387 ! Liam.Gumley@ssec.wisc.edu
388 !
389 !!END
390 !-----------------------------------------------------------------------
391 
392  real, intent(in) :: w, r
393 
394  real(8) :: ws
395 
396  bright_m = -1.0
397 
398  if (w <= 0.0 .or. r <= 0.0) return
399 
400 ! ... Convert wavelength to meters
401  ws = w * 1.0d-6
402 ! ... Compute brightness temperature
403  bright_m = sngl(c2 / (ws * log(c1 / (1.0d+6 * dble(r) * ws**5) + 1.0d+0)))
404 
405  END function bright_m
406 
407 ! same as bright_m, only the wavelength is in wavenumber instead of microns
408  REAL FUNCTION BRITE_M(V, R)
409 
410  real, intent(in) :: v, r
411 
412  real(8) :: vs
413 
414  brite_m = -1.0
415 
416  if (v <= 0.0 .or. r <= 0.0) return
417 
418 ! ... Convert wavenumber to inverse meters
419  vs = 1.0d+2 * v
420 ! ... Compute brightness temperature
421  brite_m = sngl(c2 * vs / log(c1 * vs**3 / (1.0d-5 * dble(r)) + 1.0d+0))
422 
423  END function brite_m
424 
425 
426 
427 !-----------------------------------------------------------------------
428 !!F77
429 !
430 !!DESCRIPTION:
431 ! Compute brightness temperature for a MODIS infrared band
432 ! on Terra or Aqua.
433 !
434 ! Spectral responses for each IR detector were obtained from MCST:
435 ! ftp://mcstftp.gsfc.nasa.gov/pub/permanent/MCST in
436 ! directories PFM_L1B_LUT_4-30-99 and FM1_RSR_LUT_07-10-01
437 !
438 ! An average spectral response for each infrared band was
439 ! computed. The band-averaged spectral response data were used
440 ! to compute the effective central wavenumbers and temperature
441 ! correction coefficients included in this module.
442 !
443 ! NOTE: The plaform name ('Terra' or 'Aqua') is passed to this
444 ! function via the common block defined in 'platform_name.inc'.
445 !
446 !!INPUT PARAMETERS:
447 ! RAD (REAL) Planck radiance (units are determined by UNITS)
448 ! BAND (LONG) MODIS IR band number (20-25, 27-36)
449 ! UNITS (LONG) Flag defining radiance units
450 ! 0 => milliWatts per square meter per
451 ! steradian per inverse centimeter
452 ! 1 => Watts per square meter per
453 ! steradian per micron
454 !
455 !!OUTPUT PARAMETERS:
456 ! MODIS_BRIGHT Brightness temperature (Kelvin)
457 ! Note that a value of -1.0 is returned if
458 ! RAD .LE. 0.0, or BAND is not in range 20-25, 27-36.
459 !
460 !!REVISION HISTORY:
461 ! Liam.Gumley@ssec.wisc.edu
462 !
463 !!TEAM-UNIQUE HEADER:
464 ! Developed by the MODIS Group, CIMSS/SSEC, UW-Madison.
465 !
466 !!END
467 !-----------------------------------------------------------------------
468 
469 
470  REAL FUNCTION MODIS_BRIGHT(platform_name,RAD, BAND, UNITS, cwn_array, tcs_array, tci_array)
471 
472 
473  real, intent(in) :: rad
474  integer, intent(in) :: band, units
475  character*(*), intent(in) :: platform_name
476  real, dimension(:), intent(in), optional :: cwn_array, tcs_array, tci_array
477 
478  real :: cwn, tcs, tci
479 
480  modis_bright = -1.0
481 
482  if (present(cwn_array)) then
483  call pick_a_band(platform_name, band, cwn, tcs, tci, cwn_array=cwn_array, tcs_array=tcs_array, &
484  tci_array=tci_array)
485  else
486  call pick_a_band(platform_name, band, cwn, tcs, tci, cwn_array=cwn_array, tcs_array=tcs_array, &
487  tci_array=tci_array)
488  endif
489 
490 ! ... Compute brightness temperature
491  if (units == 1) then
492 ! ... Radiance units are
493 ! ... Watts per square meter per steradian per micron
494  modis_bright = (bright_m(1.0e+4 / cwn, rad) - tci) / tcs
495  else
496 ! ... Radiance units are
497 ! ... milliWatts per square meter per steradian per wavenumber
498  modis_bright = (brite_m(cwn, rad) - tci) / tcs
499  endif
500 
501  if (modis_bright == -1.) then
502  print*, "ERROR: Brightness temperature calculation: ", trim(platform_name), band, rad
503  endif
504 
505  end function modis_bright
506 
507 ! same thing except it will return the planck radiance
508 
509  REAL function modis_planck(platform_name, temp, band, units)
510 
511  real, intent(in) :: temp
512  integer, intent(in) :: band, units
513  character*(*), intent(in) :: platform_name
514 
515  real :: cwn, tcs, tci
516 
517  modis_planck = -1.0
518 
519  call pick_a_band(platform_name, band, cwn, tcs, tci)
520 
521 ! ... Compute Planck radiance
522 
523  if (units == 1) then
524 ! ... Radiance units are
525 ! ... Watts per square meter per steradian per micron
526  modis_planck = planck_m(1.0e+4 / cwn, temp * tcs + tci)
527  else
528 ! ... Radiance units are
529 ! ... milliWatts per square meter per steradian per wavenumber
530  modis_planck = planc_m(cwn, temp * tcs + tci)
531  endif
532 
533  if (modis_planck == -1.) then
534  print*, "ERROR: Planck radiance calculation: ", trim(platform_name), band, temp
535  endif
536 
537  end function modis_planck
538 
539 end module planck_functions
540 
541 
real function, public modis_bright(platform_name, RAD, BAND, UNITS, cwn_array, tcs_array, tci_array)
real function, public modis_planck(platform_name, TEMP, BAND, UNITS)
string & trim(string &s, const string &delimiters)
Definition: EnvsatUtil.cpp:29