1 | ! ------------------------------------------------------------- |
---|
2 | ! MIE CODE designed for the LMD/GCM |
---|
3 | ! This code generates the look-up tables used by to GCM to |
---|
4 | ! compute the cloud scattering parameters in each grid box. |
---|
5 | ! |
---|
6 | ! Mie code: Bohren and Huffman (1983), modified by B.T.Draine |
---|
7 | ! Interface and integration: F. Montmessin |
---|
8 | ! Implementation into the LMD/GCM: J.-B. Madeleine 08W38 |
---|
9 | ! ------------------------------------------------------------- |
---|
10 | |
---|
11 | PROGRAM optpropgen |
---|
12 | use bhmie, only: bh_mie, s_size |
---|
13 | use math, only: pi |
---|
14 | |
---|
15 | IMPLICIT NONE |
---|
16 | |
---|
17 | ! ------------------------------------------------------------- |
---|
18 | ! PARAMETERS USED BY THE MIE CODE BEFORE CONVOLUTION | |
---|
19 | ! param_mie | |
---|
20 | ! ------------------------------------------------------------- |
---|
21 | character(len=*), parameter :: & |
---|
22 | optpropgen_version = '1.0.1' |
---|
23 | |
---|
24 | integer, parameter :: n_args = 2, n_opt_args = 2, file_name_size = 255 |
---|
25 | character(len=file_name_size) :: file_in, file_out |
---|
26 | character(len=file_name_size), dimension(n_args) :: args |
---|
27 | character(len=file_name_size), dimension(n_opt_args) :: opt_args |
---|
28 | doubleprecision :: & |
---|
29 | rmin, & ! Min. and max radius of the |
---|
30 | rmax ! interval in METERS |
---|
31 | |
---|
32 | INTEGER nsize, nsun ! Number of integration subintervals |
---|
33 | ! Useful when activice is true. |
---|
34 | ! Parameters for water ice: |
---|
35 | PARAMETER (nsize = 10000, nsun = 207) ! 127 VIS 81 IR |
---|
36 | |
---|
37 | ! ------------------------------------------------------------- |
---|
38 | |
---|
39 | doubleprecision QextMono(nsize, nsun), & |
---|
40 | QscatMono(nsize, nsun), gMono(nsize, nsun) |
---|
41 | doubleprecision CextMono(nsize, nsun), CscatMono(nsize, nsun) |
---|
42 | DOUBLE PRECISION radiustab(nsize) |
---|
43 | |
---|
44 | ! VARIABLES USED BY THE BHMIE CODE |
---|
45 | |
---|
46 | doubleprecision x(nsun) |
---|
47 | doubleprecision ni(nsun) |
---|
48 | doubleprecision nr(nsun) |
---|
49 | doubleprecision xf |
---|
50 | COMPLEX(kind=8) refrel |
---|
51 | INTEGER NANG |
---|
52 | COMPLEX(kind=8) S1(s_size), S2(s_size) |
---|
53 | |
---|
54 | doubleprecision QBACK |
---|
55 | |
---|
56 | ! VARIABLES USED FOR THE OUTPUT FILES |
---|
57 | |
---|
58 | CHARACTER(LEN = 5) radius_id |
---|
59 | |
---|
60 | ! ------------------------------------------------------------- |
---|
61 | ! PARAMETERS USED BY THE CONVOLUTION | |
---|
62 | ! param_conv | |
---|
63 | ! ------------------------------------------------------------- |
---|
64 | INTEGER nreff |
---|
65 | PARAMETER (nreff = 30) |
---|
66 | ! ------------------------------------------------------------- |
---|
67 | doubleprecision reff(nreff), nueff |
---|
68 | doubleprecision logvratreff |
---|
69 | DOUBLE PRECISION vratreff |
---|
70 | doubleprecision r_g, sigma_g |
---|
71 | DOUBLE PRECISION dfi |
---|
72 | DOUBLE PRECISION dfi_tmp(nsize + 1) |
---|
73 | doubleprecision radiusint(nsize + 1) |
---|
74 | doubleprecision Qext_tmp(nsun), omeg_tmp(nsun), g_tmp(nsun), pirr_tmp(nsun) |
---|
75 | doubleprecision Qscat_tmp(nsun) |
---|
76 | doubleprecision Cext_tmp(nsun), Cscat_tmp(nsun) |
---|
77 | |
---|
78 | doubleprecision :: Qextint(nsun, nreff) |
---|
79 | doubleprecision :: Qscatint(nsun, nreff) |
---|
80 | doubleprecision :: omegint(nsun, nreff) |
---|
81 | doubleprecision :: gint(nsun, nreff) |
---|
82 | |
---|
83 | ! Local variables |
---|
84 | |
---|
85 | doubleprecision Qext_mono(nsun, nsize), & |
---|
86 | Omeg_mono(nsun, nsize), & |
---|
87 | g_mono(nsun, nsize) |
---|
88 | DOUBLE PRECISION :: vrat |
---|
89 | |
---|
90 | INTEGER i, j, l |
---|
91 | |
---|
92 | call get_optpropgen_command_arguments(args, opt_args) |
---|
93 | |
---|
94 | write(*, '("Optpropgen ", A, /, "____", /)') optpropgen_version |
---|
95 | |
---|
96 | call main() |
---|
97 | |
---|
98 | contains |
---|
99 | subroutine get_optpropgen_command_arguments(args, opt_args) |
---|
100 | ! """ |
---|
101 | ! Retrieve the txt2h5 arguments that were passed on the command line when it was invoked. |
---|
102 | ! :param args: array storing the arguments |
---|
103 | ! """ |
---|
104 | implicit none |
---|
105 | |
---|
106 | character(len=file_name_size), dimension(:), intent(inout) :: args, opt_args |
---|
107 | |
---|
108 | character(len=file_name_size) :: arg |
---|
109 | integer :: i, j, n_args, n_opt_args |
---|
110 | |
---|
111 | j = 0 |
---|
112 | n_args = size(args) |
---|
113 | n_opt_args = size(opt_args) |
---|
114 | |
---|
115 | args(:) = '' |
---|
116 | opt_args(:) = '' |
---|
117 | |
---|
118 | do i = 1, command_argument_count() |
---|
119 | call get_command_argument(i, arg) |
---|
120 | |
---|
121 | if(trim(arg) == '-v' .or. trim(arg) == '--version') then |
---|
122 | write(*, '("Optropgen ", A)') optpropgen_version |
---|
123 | |
---|
124 | stop |
---|
125 | elseif(trim(arg) == '-h' .or. trim(arg) == '--help') then |
---|
126 | call print_help() |
---|
127 | |
---|
128 | stop |
---|
129 | else |
---|
130 | j = j + 1 |
---|
131 | end if |
---|
132 | |
---|
133 | if (len_trim(arg) == 0) then |
---|
134 | if (j < n_args) then |
---|
135 | write(*, '("Error: txt2h5 takes ", I0, " arguments but ", I0, " were given")') & |
---|
136 | n_args, j |
---|
137 | stop |
---|
138 | end if |
---|
139 | |
---|
140 | exit |
---|
141 | end if |
---|
142 | |
---|
143 | if(j > n_args) then |
---|
144 | opt_args(j - n_args) = trim(arg) |
---|
145 | |
---|
146 | if (j > n_args + n_opt_args) then |
---|
147 | write(*, '("Error: txt2h5 takes ", I0, " arguments but ", I0, " were given")') & |
---|
148 | n_args + n_opt_args, j |
---|
149 | |
---|
150 | stop |
---|
151 | end if |
---|
152 | else if (j > 0) then |
---|
153 | args(j) = trim(arg) |
---|
154 | end if |
---|
155 | end do |
---|
156 | end subroutine get_optpropgen_command_arguments |
---|
157 | |
---|
158 | subroutine main |
---|
159 | ! Initialization |
---|
160 | file_in = trim(args(1)) |
---|
161 | file_out = trim(args(2)) |
---|
162 | |
---|
163 | if(opt_args(1) /= '') then |
---|
164 | read(opt_args(1), *) rmin |
---|
165 | else |
---|
166 | rmin = 1d-7 |
---|
167 | end if |
---|
168 | |
---|
169 | if(opt_args(2) /= '') then |
---|
170 | read(opt_args(2), *) rmax |
---|
171 | else |
---|
172 | rmax = 1d-4 |
---|
173 | end if |
---|
174 | |
---|
175 | ! Main |
---|
176 | radiustab(1) = rmin |
---|
177 | radiustab(nsize) = rmax |
---|
178 | |
---|
179 | vrat = log(rmax / rmin) / dble(nsize - 1) * 3d0 |
---|
180 | vrat = exp(vrat) |
---|
181 | |
---|
182 | do i = 2, nsize - 1 |
---|
183 | radiustab(i) = radiustab(i - 1) * vrat**(1. / 3.) |
---|
184 | enddo |
---|
185 | |
---|
186 | write(*, '("Calculating for ", I0," particle radii between ", ES7.1, " and ", ES7.1, " m...")') & |
---|
187 | nsize, radiustab(1), radiustab(nsize) |
---|
188 | |
---|
189 | ! Number of angles between 0 and 90 degrees |
---|
190 | NANG = 10 |
---|
191 | |
---|
192 | ! ------------------------------------------------------------- |
---|
193 | ! OPTICAL INDICES: FILENAME | |
---|
194 | ! param_file | |
---|
195 | ! ------------------------------------------------------------- |
---|
196 | write(*, '("Reading relative refractive indices in file ''", A,"''")') & |
---|
197 | trim(file_in) |
---|
198 | |
---|
199 | OPEN(1, file=trim(file_in)) |
---|
200 | |
---|
201 | ! ------------------------------------------------------------- |
---|
202 | do l = 1, nsun |
---|
203 | ! do l = nsun, 1,-1 ! for Fe & Mg2SiO4 |
---|
204 | read(1, *) x(l), nr(l), ni(l) |
---|
205 | enddo |
---|
206 | close(1) |
---|
207 | |
---|
208 | write(*, '("Running BHMie...")') |
---|
209 | DO i = 1, nsize |
---|
210 | do l = 1, nsun |
---|
211 | refrel = cmplx(nr(l), ni(l), kind=8) |
---|
212 | xf = 2d0 * pi * radiustab(i) / x(l) |
---|
213 | call bh_mie(xf, refrel, NANG, S1, S2, & |
---|
214 | QextMono(i, l), QscatMono(i, l), QBACK, gMono(i, l)) |
---|
215 | CextMono(i, l) = QextMono(i, l) * pi * radiustab(i) * radiustab(i) |
---|
216 | CscatMono(i, l) = QscatMono(i, l) * pi * radiustab(i) * radiustab(i) |
---|
217 | Qext_mono(l, i) = QextMono(i, l) |
---|
218 | Omeg_mono(l, i) = QscatMono(i, l) / QextMono(i, l) |
---|
219 | g_mono(l, i) = gMono(i, l) |
---|
220 | enddo |
---|
221 | ENDDO |
---|
222 | |
---|
223 | ! ------------------------------------------------------------- |
---|
224 | ! PARAMETERS USED BY THE CONVOLUTION | |
---|
225 | ! param_conv | |
---|
226 | ! ------------------------------------------------------------- |
---|
227 | nueff = 0.3 ! Effective variance of the log-normal distr. !! |
---|
228 | reff(1) = rmin ! Minimum effective radius |
---|
229 | |
---|
230 | IF (nreff > 1) THEN |
---|
231 | reff(nreff) = rmax ! Maximum effective radius |
---|
232 | ! ------------------------------------------------------------- |
---|
233 | logvratreff = log(reff(nreff) / reff(1)) / float(nreff - 1) * 3. |
---|
234 | vratreff = exp(logvratreff) |
---|
235 | do i = 2, nreff - 1 |
---|
236 | reff(i) = reff(i - 1) * vratreff**(1. / 3.) |
---|
237 | enddo |
---|
238 | ENDIF |
---|
239 | |
---|
240 | ! Integration radius and effective variance |
---|
241 | |
---|
242 | radiusint(1) = 1.e-9 |
---|
243 | DO i = 2, nsize |
---|
244 | radiusint(i) = ((2. * vrat) / (vrat + 1.))**(1. / 3.) * & |
---|
245 | radiustab(i - 1) |
---|
246 | ENDDO |
---|
247 | radiusint(nsize + 1) = 1.e-2 |
---|
248 | |
---|
249 | ! Integration |
---|
250 | write(*, '("Integrating...")') |
---|
251 | DO j = 1, nreff |
---|
252 | sigma_g = log(1. + nueff) ! r_g and sigma_g are defined in |
---|
253 | r_g = exp(2.5 * sigma_g) ! [hansen_1974], "Light scattering in |
---|
254 | sigma_g = sqrt(sigma_g) ! planetary atmospheres", |
---|
255 | r_g = reff(j) / r_g ! Space Science Reviews 16 527-610. |
---|
256 | |
---|
257 | Qext_tmp(:) = 0. |
---|
258 | Qscat_tmp(:) = 0. |
---|
259 | omeg_tmp(:) = 0. |
---|
260 | g_tmp(:) = 0. |
---|
261 | pirr_tmp(:) = 0. |
---|
262 | Cext_tmp(:) = 0. |
---|
263 | Cscat_tmp(:) = 0. |
---|
264 | |
---|
265 | dfi_tmp(:) = log(radiusint(:) / r_g) / sqrt(2.) / sigma_g |
---|
266 | DO i = 1, nsize |
---|
267 | dfi = 0.5 * (erf(dfi_tmp(i + 1)) - erf(dfi_tmp(i))) |
---|
268 | |
---|
269 | DO l = 1, nsun |
---|
270 | Cext_tmp(l) = Cext_tmp(l) + CextMono(i, l) * dfi |
---|
271 | Cscat_tmp(l) = Cscat_tmp(l) + & |
---|
272 | CscatMono(i, l) * dfi |
---|
273 | Qext_tmp(l) = Qext_tmp(l) + & |
---|
274 | QextMono(i, l) * pi * radiustab(i) * radiustab(i) * dfi |
---|
275 | Qscat_tmp(l) = Qscat_tmp(l) + & |
---|
276 | QscatMono(i, l) * pi * radiustab(i) * radiustab(i) * dfi |
---|
277 | g_tmp(l) = g_tmp(l) + & |
---|
278 | gMono(i, l) * pi * radiustab(i) * radiustab(i) * & |
---|
279 | QscatMono(i, l) * dfi |
---|
280 | pirr_tmp(l) = pirr_tmp(l) + & |
---|
281 | pi * radiustab(i) * radiustab(i) * dfi |
---|
282 | ENDDO |
---|
283 | ENDDO |
---|
284 | |
---|
285 | DO l = 1, nsun |
---|
286 | Qextint(l, j) = Qext_tmp(l) / pirr_tmp(l) |
---|
287 | Qscatint(l, j) = Qscat_tmp(l) / pirr_tmp(l) |
---|
288 | omegint(l, j) = Qscat_tmp(l) / Qext_tmp(l) |
---|
289 | gint(l, j) = g_tmp(l) / Qscatint(l, j) / pirr_tmp(l) |
---|
290 | ENDDO |
---|
291 | |
---|
292 | ENDDO |
---|
293 | |
---|
294 | ! Writing the LMD/GCM output file |
---|
295 | ! ------------------------------- |
---|
296 | |
---|
297 | ! ------------------------------------------------------------- |
---|
298 | ! OUTPUT: FILENAME | |
---|
299 | ! param_output | |
---|
300 | ! ------------------------------------------------------------- |
---|
301 | write(*, '("Writting optical constants in file ''", A,"''")') & |
---|
302 | trim(file_out) |
---|
303 | OPEN(FILE=trim(file_out), UNIT = 60, & |
---|
304 | FORM = 'formatted', STATUS = 'replace') |
---|
305 | ! ------------------------------------------------------------- |
---|
306 | |
---|
307 | WRITE(UNIT = 60, FMT = '(a31)') '# Number of wavelengths (nwvl):' |
---|
308 | WRITE(UNIT = 60, FMT = '(i4)') nsun |
---|
309 | |
---|
310 | WRITE(UNIT = 60, FMT = '(a27)') '# Number of radius (nsize):' |
---|
311 | WRITE(UNIT = 60, FMT = '(i5)') nreff |
---|
312 | |
---|
313 | WRITE(UNIT = 60, FMT = '(a24)') '# Wavelength axis (wvl):' |
---|
314 | WRITE(UNIT = 60, FMT = '(5(1x,e12.6))') x |
---|
315 | |
---|
316 | WRITE(UNIT = 60, FMT = '(a30)') '# Particle size axis (radius):' |
---|
317 | WRITE(UNIT = 60, FMT = '(5(1x,e12.6))') reff |
---|
318 | |
---|
319 | WRITE(UNIT = 60, FMT = '(a29)') '# Extinction coef. Qext (ep):' |
---|
320 | DO j = 1, nreff |
---|
321 | WRITE(UNIT = radius_id, FMT = '(I5)') j |
---|
322 | WRITE(UNIT = 60, FMT = '(a21)') '# Radius number ' // radius_id |
---|
323 | WRITE(UNIT = 60, FMT = '(5(1x,e12.6))') Qextint(:, j) |
---|
324 | ENDDO |
---|
325 | |
---|
326 | WRITE(UNIT = 60, FMT = '(a28)') '# Single Scat Albedo (omeg):' |
---|
327 | DO j = 1, nreff |
---|
328 | WRITE(UNIT = radius_id, FMT = '(I5)') j |
---|
329 | WRITE(UNIT = 60, FMT = '(a21)') '# Radius number ' // radius_id |
---|
330 | WRITE(UNIT = 60, FMT = '(5(1x,e12.6))') omegint(:, j) |
---|
331 | ENDDO |
---|
332 | |
---|
333 | WRITE(UNIT = 60, FMT = '(a29)') '# Asymmetry Factor (gfactor):' |
---|
334 | DO j = 1, nreff |
---|
335 | WRITE(UNIT = radius_id, FMT = '(I5)') j |
---|
336 | WRITE(UNIT = 60, FMT = '(a21)') '# Radius number ' // radius_id |
---|
337 | WRITE(UNIT = 60, FMT = '(5(1x,e12.6))') gint(:, j) |
---|
338 | ENDDO |
---|
339 | |
---|
340 | CLOSE(60) |
---|
341 | ! ------------------------------------------------------------- |
---|
342 | write(*, '("Done")') |
---|
343 | end subroutine main |
---|
344 | |
---|
345 | subroutine print_help() |
---|
346 | implicit none |
---|
347 | |
---|
348 | character(len=*), parameter :: help_str = & |
---|
349 | "Usage: ./optpropgen.exe [options] path/to/refractive_index_file.dat path/to/output_file.ocst.txt & |
---|
350 | &[min_radius max_radius]"& |
---|
351 | //new_line('')//"& |
---|
352 | &Example: ./optpropgen.exe ../data/refractive_indices/optind_ice.dat & |
---|
353 | &../data/refractive_indices/optind_ice.dat 1e-7 1e-4"//new_line('')//"& |
---|
354 | &Options: "//new_line('')//"& |
---|
355 | & --help Display this information."//new_line('')//"& |
---|
356 | & --version Display software version information."//new_line('')//"& |
---|
357 | &"//new_line('')//"& |
---|
358 | &Refractive index ASCII (.dat) files must have 3 columns in the format:"//new_line('')//"& |
---|
359 | &wavelength(m) real_ref_rel imaginary_ref_rel"//new_line('')//"& |
---|
360 | &Where ref_rel is the complex refractive index of a sphere over the real index of the medium& |
---|
361 | &"//new_line('')//"& |
---|
362 | &Gitlab of the software:"//new_line('')//"& |
---|
363 | &<https://gitlab.obspm.fr/dblain/exorem>" |
---|
364 | |
---|
365 | write(*, '(A)') help_str |
---|
366 | end subroutine print_help |
---|
367 | END |
---|