File: neat.f90

package info (click to toggle)
neat 2.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, sid, trixie
  • size: 4,108 kB
  • sloc: f90: 7,385; python: 211; makefile: 78; sh: 64
file content (382 lines) | stat: -rw-r--r-- 14,336 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
! NEAT, the nebular abundance analysis tool
! (C) 2006- Roger Wesson, Dave Stock, Peter Scicluna
! NEAT incorporates aspects of several codes developed over decades at UCL:
! equib, by I. Howarth and S. Adams, updated significantly by B. Ercolano
! MIDAS scripts written by X-W. Liu for calculating recombination line abundances
! It also uses the quicksort algorithm as implemented in F90 by Alberto Ramos

! This program is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.

! This program is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! GNU General Public License for more details.

! You should have received a copy of the GNU General Public License
! along with this program.  If not, see <http://www.gnu.org/licenses/>.

program neat

        use mod_types
        use mod_globals
        use mod_resultarrays
        use mod_extinction
        use mod_quicksort
        use mod_abundIO
        use mod_atomicdata
        use mod_atomic_read
        use mod_recombination_lines
        use mod_linefinder
        use mod_hydrogen
        use mod_helium
        use mod_oii_diagnostics
        use mod_weights
        use mod_functions
        use mod_commandline
        use mod_output

        implicit none

        character :: switch_ext !switch for extinction laws
        character :: switch_he  !switch for helium atomic data
        character :: switch_icf !switch for which ICF scheme to use
        integer :: I, runs !runs = number of runs for randomiser

!file reading variables

        logical :: identifylines,identifyconfirm
        type(line),dimension(:), allocatable :: linelist
        type(line),dimension(:), allocatable :: linelist_original
        type(line),dimension(:,:), allocatable :: all_linelists
        integer :: listlength, ncols, strpos
        real(kind=dp) :: normalise

!results and result processing

        type(resultarray), dimension(:), allocatable :: all_results
        type(resultarray), dimension(1) :: iteration_result

!atomic data

        character(len=10), dimension(24) :: ionlist !list of ion names
        integer :: iion !# of ions in Ilines
        integer :: maxlevs,maxtemps
        type(atomic_data),allocatable :: atomicdata(:)
        real(kind=dp), dimension(:,:,:), allocatable :: heidata

!line indexing arrays - these contain the location within the main array of the lines of interest, plus levels and zones for CELs

        integer, dimension(3:40) :: H_Balmer
        integer, dimension(4:39) :: H_Paschen
        integer, dimension(44) :: HeI_lines
        integer, dimension(20,2:6) :: HeII_lines
        type(cel), dimension(88) :: ILs !todo: work out why this becomes undefined on entry if its shape is assumed

!extinction

        logical :: calculate_extinction
        real(kind=dp) :: meanextinction, R

!RP effect switch

        logical :: norp

!subtract recombination contribution to auroral lines switch - 1=no subtraction, 2=subtraction

        integer :: subtract_recombination

!diagnostics

        type(weightingarray) :: weights

!binning and uncertainties

        integer :: verbosity,nbins,nperbin

!OpenMP

        integer :: omp_get_num_threads

!diagnostic array

        type(diagnostic_array) :: diagnostics

! default values

        runs=1
        switch_ext="S" !Howarth 1983 Galactic law
        switch_he="P"  !Porter 2012 data
        switch_icf="D" !DI14 ICF
        filename=""
        outputdirectory=""
        meanextinction=0.D0
        diagnostics%lowtemp=0.D0
        diagnostics%lowdens=0.D0
        diagnostics%medtemp=0.D0
        diagnostics%meddens=0.D0
        diagnostics%hightemp=0.D0
        diagnostics%highdens=0.D0
        verbosity=3
        R=3.1
        identifylines=.false.
        identifyconfirm=.false.
        nbins=25
        normalise = 0.d0
        norp=.true.
        calculate_extinction=.true.
        subtract_recombination=1
        configfile=""
        defaultconfigfile=trim(PREFIX)//"/share/neat/default.cfg"
        outputformat="fits"

        iion=24 ! number of ions for which we can calculate abundances
                ! todo: calculate this automatically
                ! and replace it in calls to subroutines with getting the array size within the subroutine

        print *,"NEAT, the Nebular Empirical Analysis Tool"
        print *,"version ",VERSION
        print *
        print *,gettime(),"starting code"

        call readcommandline(runs,switch_ext,switch_he,switch_icf,meanextinction,diagnostics,verbosity,R,identifylines,identifyconfirm,nbins,norp,calculate_extinction,subtract_recombination,configfile,nperbin)

! set up filenames. if input file is FITS, output will be written to it. Output will be put in same directory as input by default.
! todo: allow non-FITS to be requested

        write (outputfilename,"(A)") filename(index(filename,"/",back=.true.)+1:len(trim(filename)))
        if (trim(outputfilename(index(outputfilename,".",.true.)+1:len(filename))).ne."fits") then
          outputfilename=trim(outputfilename)//".fits"
        endif

        if (trim(outputdirectory).eq."") then
          outputdirectory=trim(filename(1:index(filename,"/",.true.)))
        endif

        if (trim(outputdirectory).eq."") then
          outputdirectory="./"
        endif

        outputfilename=trim(outputdirectory)//"/"//trim(outputfilename)

! read in the line list, allocate original linelist array

        strpos=index(filename,".",.true.)+1
        if (trim(filename(strpos:len(filename))).eq."fit" .or. trim(filename(strpos:len(filename))).eq."fits".or.trim(filename(strpos:len(filename))).eq."FIT".or.trim(filename(strpos:len(filename))).eq."FITS") then
          call read_fits_linelist(linelist,listlength,ncols)
        else
          call read_text_linelist(linelist,listlength,ncols,runs)
        endif

        allocate (linelist_original(listlength))

! run line identifier if required

        if (identifylines) then
                call linefinder(linelist, listlength, identifyconfirm)
        endif

! normalise to Hbeta

        if (minval(abs(linelist(:)%wavelength - 4861.33)) .lt. 0.001) then
          normalise = 100.d0/linelist(minloc(abs(linelist(:)%wavelength - 4861.33),1))%intensity
        else
          print *,gettime(),"error: no H beta detected. No further analysis possible"
          call exit(201)
        endif

        linelist%intensity = linelist%intensity * normalise
        linelist%int_err = linelist%int_err * normalise
        linelist%blend_intensity = linelist%blend_intensity * normalise
        linelist%blend_int_err = linelist%blend_int_err * normalise

! check for and remove negative line fluxes and uncertainties

        if (minval(linelist%intensity) .lt. 0.) then
          where (linelist%intensity .lt. 0)
            linelist%intensity = 0.D0
          endwhere
        print *,gettime(),"warning: negative line fluxes set to zero"
        endif

        if (minval(linelist%int_err) .lt. 0.) then
          where (linelist%int_err .lt. 0)
            linelist%int_err = abs(linelist%int_err)
          endwhere
        print *,gettime(),"warning: negative flux uncertainties converted to positive"
        endif

        print *

! select reddening law, get flambda from functions if one of the five, otherwise read from file

        if (switch_ext == "S") then
                print *,gettime(),"using Howarth (1983) galactic extinction law"
        elseif (switch_ext == "H") then
                print *,gettime(),"using Howarth (1983) LMC extinction law"
        elseif (switch_ext == "C") then
                print *,gettime(),"using CCM (1989) galactic extinction law"
        elseif (switch_ext == "P") then
                print *,gettime(),"using Prevot et al. (1984) SMC extinction law"
        elseif (switch_ext == "F") then
                print *,gettime(),"using Fitzpatrick (1990) galactic extinction law"
        endif

        call get_flambda(linelist, switch_ext, R)

        if (switch_he == "S") then
                print *,gettime(),"using Smits (1996) He I emissivities"
        else
                print *,gettime(),"using Porter et al. (2012) He I emissivities"
        endif

        if (switch_ICF == "K") then
                print *,gettime(),"using Kingsburgh & Barlow (1994) ICF"
        elseif (switch_ICF == "D") then
                print *,gettime(),"using Delgado-Inglada et al. (2014) ICF"
        elseif (switch_ICF == "E") then
                print *,gettime(),"using Delgado-Inglada et al. (2014) ICF with classical icf(N)"
        else
                print *,gettime(),"using Peimbert et al. (1992) ICF"
        endif

        print *

! read the CEL data

        call read_celdata(ILs,ionlist)

! do line identifying here

        !first find H & He lines, and CELs
        call get_H(H_Balmer, H_Paschen, linelist)
        call get_Hei(Hei_lines, linelist)
        call get_Heii(Heii_lines, linelist)
        call get_cels(ILs,linelist)

! read in the weights to be used in the analysis.

        print *,gettime(),"reading in abundance analysis weights from ",trim(defaultconfigfile)
        call setweights(defaultconfigfile,weights,linelist,ILs,H_Balmer,H_Paschen,HeII_lines)
        if (configfile .ne. "") then
          print *,gettime(),"reading in abundance analysis weights from ",trim(configfile)
          print *,gettime(),"(defaults still apply for any weights not specified in this file)"
          call setweights(configfile,weights,linelist,ILs,H_Balmer,H_Paschen,HeII_lines)
        endif

!CELs read, can now read in atomic data

        print *,gettime(),"reading atomic data from ",trim(PREFIX),"/share/neat"
        allocate(atomicdata(iion))
        do I=1,iion
            atomicdata(I)%ion = ionlist(I)
            call read_atomic_data(atomicdata(I))
        enddo

!read ORL data
        call read_orl_data

!read hydrogen emissivities

        print *,gettime(),"reading H emissivities"
        call read_hydrogen

!read helium emissivities

        print *,gettime(),"reading He I emissivities"
        if (switch_he .eq. "P") then
          allocate(heidata(21,14,44))
          heidata = 0.D0
          call read_porter(heidata)
        elseif (switch_he .eq. "S") then
          allocate(heidata(3,6,44))
          heidata = 0.D0
          call read_smits(heidata)
        endif

        print *,gettime(),"reading He II emissivities"
        call read_heii

!read oii data for diagnostics

        print *,gettime(),"reading OII diagnostics data"
        call read_oii_diagnosticdata
        call read_oii_s2017

!find maximum #levels and temperatures - pass to equib to reduce footprint

        maxlevs = maxval(atomicdata%nlevs)
        maxtemps = maxval(atomicdata%ntemps)

!now check number of iterations.  If 1, line list is fine as is.  If more than one, randomize the fluxes

        allocate(all_results(runs))
        allocate(all_linelists(size(linelist),runs))

        if (runs == 1)then !calculates abundances without uncertainties
                print *
                print *,gettime(),"doing abundance calculations"

                call abundances(linelist, listlength, iteration_result, meanextinction, calculate_extinction, ILs, diagnostics,iion,atomicdata,maxlevs,maxtemps, heidata, switch_he, switch_icf, H_Balmer, H_Paschen, HeI_lines, HeII_lines, weights,subtract_recombination)

                all_results(1)=iteration_result(1) ! copy the iteration result to all_results to simplify the writing out of results later
                all_linelists(:,1)=linelist

                print *,gettime(),"finished abundance calculations"
        else if (runs .gt. 1)then

!save unrandomised line list

                linelist_original = linelist

                call init_random_seed()!sets seed for randomiser

                !main loop
!$OMP PARALLEL default(firstprivate) shared(all_linelists,listlength,norp,calculate_extinction,ILs,diagnostics,iion,atomicdata,maxlevs,maxtemps,switch_he,switch_icf,all_results,subtract_recombination)
!$OMP MASTER

                print *
                if (omp_get_num_threads().gt.1) then
                  print "(X,A10,X,A,I2,A)",gettime(),"starting Monte Carlo calculations, using ",omp_get_num_threads()," processors"
                else
                  print "(X,A10,X,A)",gettime(),"starting Monte Carlo calculations"
                endif
                print *,gettime(),"completed ",0,"%"
!$OMP END MASTER
!$OMP DO schedule(dynamic)
                do I=1,runs

                         if ( (10.0*dble(i)/dble(runs)) == int(10*i/runs) ) print *,gettime(),"completed ",100*i/runs,"%"
!                        print*, "iteration ", i, "of", runs

                        call randomizer(linelist, listlength, norp)
                        call abundances(linelist, listlength, iteration_result, meanextinction, calculate_extinction, ILs, diagnostics,iion,atomicdata,maxlevs,maxtemps, heidata, switch_he, switch_icf, H_Balmer, H_Paschen, HeI_lines, HeII_lines, weights, subtract_recombination)

                        !store all line and derived quantity in arrays
                        all_linelists(:,i)=linelist
                        all_results(i)=iteration_result(1)
                        !restore the unrandomized line list ready for the next iteration
                        linelist = linelist_original
                enddo
!$OMP END DO
!$OMP END PARALLEL
        else
                print*, gettime(),"error: I didn't want to be a barber anyway. I wanted to be... a lumberjack!   Also, a positive number of runs helps.."
                call exit(103)
        endif

!now write out the line list and results files

        if (outputformat.eq."fits") then
          call write_fits(runs,listlength,ncols,all_linelists,all_results,nbins)
        elseif (outputformat.eq."text") then
          call write_output(runs,listlength,ncols,all_linelists,all_results,verbosity,nbins,subtract_recombination)
        endif

        print *
        print *,gettime(),"all done"
        print *

end program