source: trunk/LMDZ.TITAN/libf/muphytitan/mmp_optics.f90 @ 1897

Last change on this file since 1897 was 1897, checked in by jvatant, 7 years ago

Making Titan's hazy again - part II
+ Major updates of J.Burgalat YAMMS library and optical coupling, including :
++ Added the routines for haze optics inside YAMMS
++ Calling rad. transf. with interactive haze is plugged
in but should stay unactive as long as the microphysics is
in test phase : cf "uncoupl_optic_haze" flag : true for now !
++ Also some sanity checks for negative tendencies and
some others upkeep of YAMMS model
+ Also added a temporary CPP key USE_QTEST in physiq_mod
that enables to have microphysical tendencies separated
from dynamics for debugging and test phases
-- JVO and JB

File size: 15.2 KB
Line 
1! Copyright 2017 Université de Reims Champagne-Ardenne
2! Contributor: J. Burgalat (GSMA, URCA)
3! email of the author : jeremie.burgalat@univ-reims.fr
4!
5! This software is a computer program whose purpose is to compute
6! microphysics processes using a two-moments scheme.
7!
8! This library is governed by the CeCILL license under French law and
9! abiding by the rules of distribution of free software.  You can  use,
10! modify and/ or redistribute the software under the terms of the CeCILL
11! license as circulated by CEA, CNRS and INRIA at the following URL
12! "http://www.cecill.info".
13!
14! As a counterpart to the access to the source code and  rights to copy,
15! modify and redistribute granted by the license, users are provided only
16! with a limited warranty  and the software's author,  the holder of the
17! economic rights,  and the successive licensors  have only  limited
18! liability.
19!
20! In this respect, the user's attention is drawn to the risks associated
21! with loading,  using,  modifying and/or developing or reproducing the
22! software by the user in light of its specific status of free software,
23! that may mean  that it is complicated to manipulate,  and  that  also
24! therefore means  that it is reserved for developers  and  experienced
25! professionals having in-depth computer knowledge. Users are therefore
26! encouraged to load and test the software's suitability as regards their
27! requirements in conditions enabling the security of their systems and/or
28! data to be ensured and,  more generally, to use and operate it in the
29! same conditions as regards security.
30!
31! The fact that you are presently reading this means that you have had
32! knowledge of the CeCILL license and that you accept its terms.
33
34!! file: mmp_optics.f90
35!! summary: Interface for YAMMS aerosols optical properties calculations.
36!! author: J. Burgalat
37!! date: 2017
38MODULE MMP_OPTICS
39  !! Optical properties of spherical/fractal aerosols using moments
40  !!
41  !!
42  !! The module contains an initialization function, [mmp_optics(module):mmp_init_aer_optics(function)],
43  !! that must be called before any calls of the other methods. On failure, it returns .false. and
44  !! consequently, all calls to the other methods will fail !
45  !!
46  !! If openMP is enabled the call to [mmp_optics(module):mmp_init_aer_optics(function)] should be
47  !! done by a single thread.
48  !!
49  !! Then the module provides 4 four public methods to compute optical properties in infrared and
50  !! visible channels as a function of moments of the size-distribution:
51  !!
52  !! - EXT, the total extinction opacity.
53  !! - SSA, the single scattering albedo.
54  !! - ASF, the asymetry factor.
55  !!
56  !! Fractals and spherical aerosols are calculated sperately, but each EXT, SSA and ASF should be added
57  !! to get the global optical properties.
58  USE MMP_GLOBALS
59  USE DATASETS
60
61  IMPLICIT NONE
62
63  PRIVATE
64  PUBLIC :: mmp_initialize_optics
65  PUBLIC :: mmp_sph_optics_vis,mmp_sph_optics_ir
66  PUBLIC :: mmp_fra_optics_vis,mmp_fra_optics_ir
67
68  ! OPTICAL PROPERTIES !
69
70  !> Extinction opacty table (spherical,IR).
71  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: ext_s_i
72  !> Single scattering albedo table (spherical,IR).
73  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: sca_s_i
74  !> Asymetry factor table (spherical,IR).
75  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: asf_s_i
76  !> Extinction opacty table (fractal,IR).
77  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: ext_f_i
78  !> Single scattering albedo table (fractal,IR).
79  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: sca_f_i
80  !> Asymetry factor table (fractal,IR).
81  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: asf_f_i
82
83  !> Extinction opacty table (spherical,VIS).
84  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: ext_s_v
85  !> Single scattering albedo table (spherical,VIS).
86  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: sca_s_v
87  !> Asymetry factor table (spherical,VIS).
88  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: asf_s_v
89  !> Extinction opacty table (fractal,VIS).
90  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: ext_f_v
91  !> Single scattering albedo table (fractal,VIS).
92  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: sca_f_v
93  !> Asymetry factor table (fractal,VIS).
94  REAL(kind=8), DIMENSION(:,:), ALLOCATABLE, SAVE :: asf_f_v
95
96
97  INTEGER, SAVE      :: mmp_nrc    = -1  !! Size of radius grid.
98
99  !> Characteristic radius grid
100  REAL(kind=8), DIMENSION(:), ALLOCATABLE, SAVE :: mmp_rc
101
102  CONTAINS
103
104  SUBROUTINE mmp_initialize_optics(path)
105    !! Initialize optics data for aerosols optical properties computation.
106    !!
107    !! @note
108    !! If the subroutine fails to initialize parameters, the run is aborted.
109    !!
110    !! @warning
111    !! The method assumes YAMMS model has been already intialized correctly !
112    !!
113    !! @warning
114    !! If OpenMP is activated, this subroutine must be called in an $OMP SINGLE statement as it
115    !! initializes global variables that are not thread private.
116    !!
117    !! '''
118    !! !$OMP SINGLE
119    !! call mmp_initialize(...)
120    !! !$OMP END SINGLE
121    CHARACTER(len=*), INTENT(in) :: path !! Path of NetCDF look-up tables file.
122    LOGICAL :: ret
123    WRITE(*,'(a)') "*** mmp_init_aer_optics speaking ***"
124    WRITE(*,'(a)') "I'm about to initialize look-up tables of aerosols optical properties."
125    WRITE(*,'(a)') "If something's wrong... I will abort the program !"
126    IF (.NOT.mm_ini) THEN
127      call abort_program(error("[mmp_init_aer_optics] Too bad mmp_initialize has not been called yet !",2))
128    ENDIF
129    !  look-up tables
130    ret = read_lookup_tables(path)
131    IF (.NOT.ret) &
132      call abort_program(error("[mmp_init_aer_optics] Failed to retrieve data.",2))
133  END SUBROUTINE mmp_initialize_optics
134
135  FUNCTION mmp_sph_optics_vis(M0,M3,iwn,ext,sca,ssa,asf) RESULT(ret)
136    !! Compute optical properties of the spherical mode in the visible range.
137    REAL(kind=mm_wp), INTENT(in)  :: M0  !! 0th order moment of the spherical mode (m-2).
138    REAL(kind=mm_wp), INTENT(in)  :: M3  !! 3rd order moment of the spherical mode (m3.m-2).
139    INTEGER, INTENT(in)           :: iwn !! Index of the wavenumber to compute
140    REAL(kind=mm_wp), INTENT(out) :: ext !! Extinction opacity.
141    REAL(kind=mm_wp), INTENT(out) :: sca !! Scattering.
142    REAL(kind=mm_wp), INTENT(out) :: ssa !! Single scattering albedo.
143    REAL(kind=mm_wp), INTENT(out) :: asf !! Asymetry factor.
144    LOGICAL                       :: ret !! true on success, false otherwise.
145    INTEGER          :: i,ridx
146    REAL(kind=mm_wp) :: rc1,rc2,rx,rc
147    ret = .false.
148    IF (mmp_nrc == -1) RETURN
149    ret = .true.
150    rc = mm_get_rcs(M0,M3)
151    ridx = mmp_nrc
152    DO i=1, mmp_nrc
153      IF (rc < mmp_rc(i)) THEN
154        ridx = i-1
155        EXIT
156      ENDIF
157    ENDDO
158    IF (ridx == 0) THEN
159      ! out of range lower bound
160      ext = ext_s_v(1,iwn)
161      sca = sca_s_v(1,iwn)
162      asf = asf_s_v(1,iwn)
163      ssa = sca/ext
164    ELSE IF (ridx == mmp_nrc) THEN
165      ! out of range upper bound
166      ext = ext_s_v(mmp_nrc,iwn)
167      sca = sca_s_v(mmp_nrc,iwn)
168      asf = asf_s_v(mmp_nrc,iwn)
169      ssa = sca/ext
170    ELSE
171      ! in range: interpolate
172      rc1 = mmp_rc(ridx) ; rc2 = mmp_rc(ridx+1)
173      rx = (rc-rc1)/(rc2-rc1)
174      ext = exp(log(ext_s_v(ridx,iwn))*(1d0-rx) + log(ext_s_v(ridx+1,iwn))*rx)
175      sca = exp(log(sca_s_v(ridx,iwn))*(1d0-rx) + log(sca_s_v(ridx+1,iwn))*rx)
176      asf = asf_s_v(ridx,iwn)*(1d0-rx) + asf_s_v(ridx+1,iwn)*rx
177      ssa = sca/ext
178    ENDIF
179    ! scale by M0
180    ext = ext * M0
181    RETURN
182  END FUNCTION mmp_sph_optics_vis
183
184  FUNCTION mmp_sph_optics_ir(M0,M3,iwn,ext,sca,ssa,asf) RESULT(ret)
185    !! Compute optical properties of the spherical mode in the infra-red range.
186    REAL(kind=mm_wp), INTENT(in)  :: M0  !! 0th order moment of the spherical mode (m-2).
187    REAL(kind=mm_wp), INTENT(in)  :: M3  !! 3rd order moment of the spherical mode (m3.m-2).
188    INTEGER, INTENT(in)           :: iwn !! Index of the wavenumber to compute
189    REAL(kind=mm_wp), INTENT(out) :: ext !! Extinction opacity.
190    REAL(kind=mm_wp), INTENT(out) :: sca !! Scattering.
191    REAL(kind=mm_wp), INTENT(out) :: ssa !! Single scattering albedo.
192    REAL(kind=mm_wp), INTENT(out) :: asf !! Asymetry factor.
193    LOGICAL                       :: ret !! true on success, false otherwise.
194    INTEGER          :: i,ridx
195    REAL(kind=mm_wp) :: rc1,rc2,rx,rc
196    ret = .false.
197    IF (mmp_nrc == -1) RETURN
198    ret = .true.
199    rc = mm_get_rcs(M0,M3)
200    ridx = mmp_nrc
201    DO i=1, mmp_nrc
202      IF (rc < mmp_rc(i)) THEN
203        ridx = i-1
204        EXIT
205      ENDIF
206    ENDDO
207    IF (ridx == 0) THEN
208      ! out of range lower bound
209      ext = ext_s_i(1,iwn)
210      sca = sca_s_i(1,iwn)
211      asf = asf_s_i(1,iwn)
212      ssa = sca/ext
213    ELSE IF (ridx == mmp_nrc) THEN
214      ! out of range upper bound
215      ext = ext_s_i(mmp_nrc,iwn)
216      sca = sca_s_i(mmp_nrc,iwn)
217      asf = asf_s_i(mmp_nrc,iwn)
218      ssa = sca/ext
219    ELSE
220      ! in range: interpolate
221      rc1 = mmp_rc(ridx) ; rc2 = mmp_rc(ridx+1)
222      rx = (rc-rc1)/(rc2-rc1)
223      ext = exp(log(ext_s_i(ridx,iwn))*(1d0-rx) + log(ext_s_i(ridx+1,iwn))*rx)
224      sca = exp(log(sca_s_i(ridx,iwn))*(1d0-rx) + log(sca_s_i(ridx+1,iwn))*rx)
225      asf = asf_s_i(ridx,iwn)*(1d0-rx) + asf_s_i(ridx+1,iwn)*rx
226      ssa = sca/ext
227    ENDIF
228    ! scale by M0
229    ext = ext * M0
230    RETURN
231  END FUNCTION mmp_sph_optics_ir
232
233  FUNCTION mmp_fra_optics_vis(M0,M3,iwn,ext,sca,ssa,asf) RESULT(ret)
234    !! Compute optical properties of the spherical mode in the visible range.
235    REAL(kind=mm_wp), INTENT(in)  :: M0  !! 0th order moment of the fractal mode (m-2).
236    REAL(kind=mm_wp), INTENT(in)  :: M3  !! 3rd order moment of the fractal mode (m3.m-2).
237    INTEGER, INTENT(in)           :: iwn !! Index of the wavenumber to compute.
238    REAL(kind=mm_wp), INTENT(out) :: ext !! Extinction opacity.
239    REAL(kind=mm_wp), INTENT(out) :: sca !! Scattering.
240    REAL(kind=mm_wp), INTENT(out) :: ssa !! Single scattering albedo.
241    REAL(kind=mm_wp), INTENT(out) :: asf !! Asymetry factor.
242    LOGICAL                       :: ret !! true on success, false otherwise.
243    INTEGER          :: i,ridx
244    REAL(kind=mm_wp) :: rc1,rc2,rx,rc
245    ret = .false.
246    IF (mmp_nrc == -1) RETURN
247    ret = .true.
248    rc = mm_get_rcs(M0,M3)
249    ridx = mmp_nrc
250    DO i=1, mmp_nrc
251      IF (rc < mmp_rc(i)) THEN
252        ridx = i-1
253        EXIT
254      ENDIF
255    ENDDO
256    IF (ridx == 0) THEN
257      ! out of range lower bound
258      ext = ext_f_v(1,iwn)
259      sca = sca_f_v(1,iwn)
260      asf = asf_f_v(1,iwn)
261      ssa = sca/ext
262    ELSE IF (ridx == mmp_nrc) THEN
263      ! out of range upper bound
264      ext = ext_f_v(mmp_nrc,iwn)
265      sca = sca_f_v(mmp_nrc,iwn)
266      asf = asf_f_v(mmp_nrc,iwn)
267      ssa = sca/ext
268    ELSE
269      ! in range: interpolate
270      rc1 = mmp_rc(ridx) ; rc2 = mmp_rc(ridx+1)
271      rx = (rc-rc1)/(rc2-rc1)
272      ext = exp(log(ext_f_v(ridx,iwn))*(1d0-rx) + log(ext_f_v(ridx+1,iwn))*rx)
273      sca = exp(log(sca_f_v(ridx,iwn))*(1d0-rx) + log(sca_f_v(ridx+1,iwn))*rx)
274      asf = asf_f_v(ridx,iwn)*(1d0-rx) + asf_f_v(ridx+1,iwn)*rx
275      ssa = sca/ext
276    ENDIF
277    ! scale by M0
278    ext = ext * M0
279    RETURN
280  END FUNCTION mmp_fra_optics_vis
281
282  FUNCTION mmp_fra_optics_ir(M0,M3,iwn,ext,sca,ssa,asf) RESULT(ret)
283    !! Compute optical properties of the spherical mode in the infra-red range.
284    REAL(kind=mm_wp), INTENT(in)  :: M0  !! 0th order moment of the spherical mode (m-2).
285    REAL(kind=mm_wp), INTENT(in)  :: M3  !! 3rd order moment of the spherical mode (m3.m-2).
286    INTEGER, INTENT(in)           :: iwn !! Index of the wavenumber to compute
287    REAL(kind=mm_wp), INTENT(out) :: ext !! Extinction opacity.
288    REAL(kind=mm_wp), INTENT(out) :: sca !! Scattering.
289    REAL(kind=mm_wp), INTENT(out) :: ssa !! Single scattering albedo.
290    REAL(kind=mm_wp), INTENT(out) :: asf !! Asymetry factor.
291    LOGICAL                       :: ret !! true on success, false otherwise.
292    INTEGER          :: i,ridx
293    REAL(kind=mm_wp) :: rc1,rc2,rx,rc
294    ret = .false.
295    IF (mmp_nrc == -1) RETURN
296    ret = .true.
297    rc = mm_get_rcs(M0,M3)
298    ridx = mmp_nrc
299    DO i=1, mmp_nrc
300      IF (rc < mmp_rc(i)) THEN
301        ridx = i-1
302        EXIT
303      ENDIF
304    ENDDO
305    IF (ridx == 0) THEN
306      ! out of range lower bound
307      ext = ext_f_i(1,iwn)
308      sca = sca_f_i(1,iwn)
309      asf = asf_f_i(1,iwn)
310      ssa = sca/ext
311    ELSE IF (ridx == mmp_nrc) THEN
312      ! out of range upper bound
313      ext = ext_f_i(mmp_nrc,iwn)
314      sca = sca_f_i(mmp_nrc,iwn)
315      asf = asf_f_i(mmp_nrc,iwn)
316      ssa = sca/ext
317    ELSE
318      ! in range: interpolate
319      rc1 = mmp_rc(ridx) ; rc2 = mmp_rc(ridx+1)
320      rx = (rc-rc1)/(rc2-rc1)
321      ext = exp(log(ext_f_i(ridx,iwn))*(1d0-rx) + log(ext_f_i(ridx+1,iwn))*rx)
322      sca = exp(log(sca_f_i(ridx,iwn))*(1d0-rx) + log(sca_f_i(ridx+1,iwn))*rx)
323      asf = asf_f_i(ridx,iwn)*(1d0-rx) + asf_f_i(ridx+1,iwn)*rx
324      ssa = sca/ext
325    ENDIF
326    ! scale by M0
327    ext = ext * M0
328    RETURN
329  END FUNCTION mmp_fra_optics_ir
330
331  FUNCTION read_lookup_tables(path) RESULT(ret)
332    !! Read look-up tables.
333    CHARACTER(len=*), INTENT(in) :: path !! Path of the look-up tables netcdf file.
334    LOGICAL                      :: ret  !! .true. on success, .false. otherwise.
335    REAL(kind=mm_wp), DIMENSION(:), ALLOCATABLE :: sigmas_vi,sigmas_ir
336
337    TYPE(DSET2D) :: dset
338    ! data(nrc,ni|nv)
339    ! INFRARED
340    ret = read_dset(path,"ext_s_i",dset)
341    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'ext_s_i' table" ; RETURN ; ENDIF
342    ext_s_i = dset%data ; sigmas_ir = dset%y ; mmp_rc = dset%x
343    ret = read_dset(path,"ext_f_i",dset)
344    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'ext_f_i' table" ; RETURN ; ENDIF
345    ext_f_i = dset%data
346    ret = read_dset(path,"sca_s_i",dset)
347    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'sca_s_i' table" ; RETURN ; ENDIF
348    sca_s_i = dset%data
349    ret = read_dset(path,"sca_f_i",dset)
350    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'sca_f_i' table" ; RETURN ; ENDIF
351    sca_f_i = dset%data
352    ret = read_dset(path,"asf_s_i",dset)
353    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'asf_s_i' table" ; RETURN ; ENDIF
354    asf_s_i = dset%data
355    ret = read_dset(path,"asf_f_i",dset)
356    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'asf_f_i' table" ; RETURN ; ENDIF
357    asf_f_i = dset%data
358    ! VISIBLE
359    ret = read_dset(path,"ext_s_v",dset)
360    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'ext_s_v' table" ; RETURN ; ENDIF
361    ext_s_v = dset%data ; sigmas_vi = dset%y
362    ret = read_dset(path,"ext_f_v",dset)
363    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'ext_f_v' table" ; RETURN ; ENDIF
364    ext_f_v = dset%data
365    ret = read_dset(path,"sca_s_v",dset)
366    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'sca_s_v' table" ; RETURN ; ENDIF
367    sca_s_v = dset%data
368    ret = read_dset(path,"sca_f_v",dset)
369    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'sca_f_v' table" ; RETURN ; ENDIF
370    sca_f_v = dset%data
371    ret = read_dset(path,"asf_s_v",dset)
372    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'asf_s_v' table" ; RETURN ; ENDIF
373    asf_s_v = dset%data
374    ret = read_dset(path,"asf_f_v",dset)
375    IF (.NOT.ret) THEN ; WRITE(*,'(a)') "[read_tables] cannot read 'asf_f_v' table" ; RETURN ; ENDIF
376    asf_f_v = dset%data
377    mmp_nrc = SIZE(mmp_rc)
378    ret = .true.
379    RETURN
380  END FUNCTION read_lookup_tables
381
382END MODULE MMP_OPTICS
383
Note: See TracBrowser for help on using the repository browser.