MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_thermal_emission.t
Go to the documentation of this file.
1! module mod_thermal_emission -- synthesize emission flux of some
2! thermal lines
3! EUV lines database:
4! 'He_II_304' 'Fe_IX_171' 'Fe_XXIV_193' 'Fe_XIV_211' 'Fe_XVI_335'
5! 'Fe_XVIII_94' 'Fe_XXI_131'
6! subroutines:
7! get_EUV: get local EUV emission intensity (for 1d, 2d and 3d)
8! get_SXR: get local Soft X-ray emission intensity (for 1d, 2d and 3d)
9
12 use mod_geometry
13 use mod_physics
14 use mod_comm_lib, only: mpistop
15
16 implicit none
17
18 integer :: n_aia
19 double precision :: t_aia(1:101)
20 double precision :: f_94(1:101),f_131(1:101),f_171(1:101)
21 double precision :: f_193(1:101),f_211(1:101),f_304(1:101)
22 double precision :: f_335(1:101)
23 integer :: n_iris
24 double precision :: t_iris(1:41)
25 double precision :: f_1354(1:41)
26 integer :: n_eis
27 double precision :: t_eis1(1:60),t_eis2(1:60)
28 double precision :: f_263(1:60),f_264(1:60),f_192(1:60),f_255(1:60)
29
30
31 double precision :: vec_xi1(1:3),vec_xi2(1:3),vec_los(1:3)
32
33 data n_aia / 101 /
34
35 data t_aia / 4. , 4.05, 4.1, 4.15, 4.2, 4.25, 4.3, 4.35, &
36 4.4, 4.45, 4.5, 4.55, 4.6, 4.65, 4.7, 4.75, &
37 4.8, 4.85, 4.9, 4.95, 5. , 5.05, 5.1, 5.15, &
38 5.2, 5.25, 5.3, 5.35, 5.4, 5.45, 5.5, 5.55, &
39 5.6, 5.65, 5.7, 5.75, 5.8, 5.85, 5.9, 5.95, &
40 6. , 6.05, 6.1, 6.15, 6.2, 6.25, 6.3, 6.35, &
41 6.4, 6.45, 6.5, 6.55, 6.6, 6.65, 6.7, 6.75, &
42 6.8, 6.85, 6.9, 6.95, 7. , 7.05, 7.1, 7.15, &
43 7.2, 7.25, 7.3, 7.35, 7.4, 7.45, 7.5, 7.55, &
44 7.6, 7.65, 7.7, 7.75, 7.8, 7.85, 7.9, 7.95, &
45 8. , 8.05, 8.1, 8.15, 8.2, 8.25, 8.3, 8.35, &
46 8.4, 8.45, 8.5, 8.55, 8.6, 8.65, 8.7, 8.75, &
47 8.8, 8.85, 8.9, 8.95, 9. /
48
49 data f_94 / 4.25022959d-37, 4.35880298d-36, 3.57054296d-35, 2.18175426d-34, &
50 8.97592571d-34, 2.68512961d-33, 7.49559346d-33, 2.11603751d-32, &
51 5.39752853d-32, 1.02935904d-31, 1.33822307d-31, 1.40884290d-31, &
52 1.54933156d-31, 2.07543102d-31, 3.42026227d-31, 6.31171444d-31, &
53 1.16559416d-30, 1.95360497d-30, 2.77818735d-30, 3.43552578d-30, &
54 4.04061803d-30, 4.75470982d-30, 5.65553769d-30, 6.70595782d-30, &
55 7.80680354d-30, 8.93247715d-30, 1.02618156d-29, 1.25979030d-29, &
56 1.88526483d-29, 3.62448572d-29, 7.50553279d-29, 1.42337571d-28, &
57 2.37912813d-28, 3.55232305d-28, 4.84985757d-28, 6.20662827d-28, &
58 7.66193687d-28, 9.30403645d-28, 1.10519802d-27, 1.25786927d-27, &
59 1.34362634d-27, 1.33185242d-27, 1.22302081d-27, 1.05677973d-27, &
60 9.23064720d-28, 8.78570994d-28, 8.02397416d-28, 5.87681142d-28, &
61 3.82272695d-28, 3.11492649d-28, 3.85736090d-28, 5.98893519d-28, &
62 9.57553548d-28, 1.46650267d-27, 2.10365847d-27, 2.79406671d-27, &
63 3.39420087d-27, 3.71077520d-27, 3.57296767d-27, 2.95114380d-27, &
64 2.02913103d-27, 1.13361825d-27, 5.13405629d-28, 2.01305089d-28, &
65 8.15781482d-29, 4.28366817d-29, 3.08701543d-29, 2.68693906d-29, &
66 2.51764203d-29, 2.41773103d-29, 2.33996083d-29, 2.26997246d-29, &
67 2.20316143d-29, 2.13810001d-29, 2.07424438d-29, 2.01149189d-29, &
68 1.94980213d-29, 1.88917920d-29, 1.82963583d-29, 1.77116920d-29, &
69 1.71374392d-29, 1.65740593d-29, 1.60214447d-29, 1.54803205d-29, &
70 1.49510777d-29, 1.44346818d-29, 1.39322305d-29, 1.34441897d-29, &
71 1.29713709d-29, 1.25132618d-29, 1.20686068d-29, 1.14226584d-29, &
72 1.09866413d-29, 1.05635524d-29, 1.01532444d-29, 9.75577134d-30, &
73 9.37102736d-30, 8.99873335d-30, 8.63860172d-30, 8.29051944d-30, &
74 7.95414793d-30 /
75
76 data f_131 / 3.18403601d-37, 3.22254703d-36, 2.61657920d-35, &
77 1.59575286d-34, 6.65779556d-34, 2.07015132d-33, &
78 6.05768615d-33, 1.76074833d-32, 4.52633001d-32, &
79 8.57121883d-32, 1.09184271d-31, 1.10207963d-31, &
80 1.11371658d-31, 1.29105226d-31, 1.80385897d-31, &
81 3.27295431d-31, 8.92002136d-31, 3.15214579d-30, &
82 9.73440787d-30, 2.22709702d-29, 4.01788984d-29, &
83 6.27471832d-29, 8.91764995d-29, 1.18725647d-28, &
84 1.52888040d-28, 2.05082946d-28, 3.47651873d-28, &
85 8.80482184d-28, 2.66533063d-27, 7.05805149d-27, &
86 1.46072515d-26, 2.45282476d-26, 3.55303726d-26, &
87 4.59075911d-26, 5.36503515d-26, 5.68444094d-26, &
88 5.47222296d-26, 4.81119761d-26, 3.85959059d-26, &
89 2.80383406d-26, 1.83977650d-26, 1.11182849d-26, &
90 6.50748885d-27, 3.96843481d-27, 2.61876319d-27, &
91 1.85525324d-27, 1.39717024d-27, 1.11504283d-27, &
92 9.38169611d-28, 8.24801234d-28, 7.43331919d-28, &
93 6.74537063d-28, 6.14495760d-28, 5.70805277d-28, &
94 5.61219786d-28, 6.31981777d-28, 9.19747307d-28, &
95 1.76795732d-27, 3.77985446d-27, 7.43166191d-27, &
96 1.19785603d-26, 1.48234676d-26, 1.36673114d-26, &
97 9.61047146d-27, 5.61209353d-27, 3.04779780d-27, &
98 1.69378976d-27, 1.02113491d-27, 6.82223774d-28, &
99 5.02099099d-28, 3.99377760d-28, 3.36279037d-28, &
100 2.94767378d-28, 2.65740865d-28, 2.44396277d-28, &
101 2.28003967d-28, 2.14941419d-28, 2.04178995d-28, &
102 1.95031045d-28, 1.87011994d-28, 1.79777869d-28, &
103 1.73093957d-28, 1.66795789d-28, 1.60785455d-28, &
104 1.55002399d-28, 1.49418229d-28, 1.44022426d-28, &
105 1.38807103d-28, 1.33772767d-28, 1.28908404d-28, &
106 1.24196208d-28, 1.17437501d-28, 1.12854330d-28, &
107 1.08410498d-28, 1.04112003d-28, 9.99529904d-29, &
108 9.59358806d-29, 9.20512291d-29, 8.83009123d-29, &
109 8.46817043d-29, 8.11921928d-29 /
110
111 data f_171 / 2.98015581d-42, 1.24696230d-40, 3.37614652d-39, 5.64103034d-38, &
112 5.20550266d-37, 2.77785939d-36, 1.16283616d-35, 6.50007689d-35, &
113 9.96177399d-34, 1.89586076d-32, 2.10982799d-31, 1.36946479d-30, &
114 6.27396553d-30, 2.29955134d-29, 7.13430211d-29, 1.91024282d-28, &
115 4.35358848d-28, 7.94807808d-28, 1.07431875d-27, 1.08399488d-27, &
116 9.16212938d-28, 7.34715770d-28, 6.59246382d-28, 9.13541375d-28, &
117 2.05939035d-27, 5.08206555d-27, 1.10148083d-26, 2.01884662d-26, &
118 3.13578384d-26, 4.14367719d-26, 5.36067711d-26, 8.74170213d-26, &
119 1.64161233d-25, 2.94587860d-25, 4.76298332d-25, 6.91765639d-25, &
120 9.08825111d-25, 1.08496183d-24, 1.17440114d-24, 1.13943939d-24, &
121 9.71696981d-25, 7.09593688d-25, 4.31376399d-25, 2.12708486d-25, &
122 8.47429567d-26, 3.17608104d-26, 1.95898842d-26, 1.98064242d-26, &
123 1.67706555d-26, 8.99126003d-27, 3.29773878d-27, 1.28896127d-27, &
124 8.51169698d-28, 7.53520167d-28, 6.18268143d-28, 4.30034650d-28, &
125 2.78152409d-28, 1.95437088d-28, 1.65896278d-28, 1.68740181d-28, &
126 1.76054383d-28, 1.63978419d-28, 1.32880591d-28, 1.00833205d-28, &
127 7.82252806d-29, 6.36181741d-29, 5.34633869d-29, 4.58013864d-29, &
128 3.97833422d-29, 3.49414760d-29, 3.09790940d-29, 2.76786227d-29, &
129 2.48806269d-29, 2.24823367d-29, 2.04016653d-29, 1.85977413d-29, &
130 1.70367499d-29, 1.56966125d-29, 1.45570643d-29, 1.35964565d-29, &
131 1.27879263d-29, 1.21016980d-29, 1.15132499d-29, 1.09959628d-29, &
132 1.05307482d-29, 1.01040261d-29, 9.70657096d-30, 9.33214234d-30, &
133 8.97689427d-30, 8.63761192d-30, 8.31149879d-30, 7.85162401d-30, &
134 7.53828281d-30, 7.23559452d-30, 6.94341530d-30, 6.66137038d-30, &
135 6.38929156d-30, 6.12669083d-30, 5.87346434d-30, 5.62943622d-30, &
136 5.39435202d-30 /
137
138 data f_193 / 6.40066486d-32, 4.92737300d-31, 2.95342934d-30, 1.28061594d-29, &
139 3.47747667d-29, 5.88554792d-29, 7.72171179d-29, 9.75609282d-29, &
140 1.34318963d-28, 1.96252638d-28, 2.70163878d-28, 3.63192965d-28, &
141 5.28087341d-28, 8.37821446d-28, 1.39089159d-27, 2.31749718d-27, &
142 3.77510689d-27, 5.85198594d-27, 8.26021568d-27, 1.04870405d-26, &
143 1.25209374d-26, 1.47406787d-26, 1.77174067d-26, 2.24098537d-26, &
144 3.05926105d-26, 4.50018853d-26, 6.84720216d-26, 1.00595861d-25, &
145 1.30759222d-25, 1.36481773d-25, 1.15943558d-25, 1.01467304d-25, &
146 1.04092532d-25, 1.15071251d-25, 1.27416033d-25, 1.38463476d-25, &
147 1.47882726d-25, 1.57041238d-25, 1.69786224d-25, 1.94970397d-25, &
148 2.50332918d-25, 3.58321431d-25, 5.18061550d-25, 6.60405549d-25, &
149 6.64085365d-25, 4.83825816d-25, 2.40545020d-25, 8.59534098d-26, &
150 2.90920638d-26, 1.33204845d-26, 9.03933926d-27, 7.78910836d-27, &
151 7.29342321d-27, 7.40267022d-27, 8.05279981d-27, 8.13829291d-27, &
152 6.92634262d-27, 5.12521880d-27, 3.59527615d-27, 2.69617560d-27, &
153 2.84432713d-27, 5.06697306d-27, 1.01281903d-26, 1.63526978d-26, &
154 2.06759342d-26, 2.19482312d-26, 2.10050611d-26, 1.89837248d-26, &
155 1.66347131d-26, 1.43071097d-26, 1.21518419d-26, 1.02078343d-26, &
156 8.46936184d-27, 6.93015742d-27, 5.56973237d-27, 4.38951754d-27, &
157 3.38456457d-27, 2.55309556d-27, 1.88904224d-27, 1.38057546d-27, &
158 1.00718330d-27, 7.43581116d-28, 5.63562931d-28, 4.43359435d-28, &
159 3.63923535d-28, 3.11248143d-28, 2.75586846d-28, 2.50672237d-28, &
160 2.32419348d-28, 2.18325682d-28, 2.06834486d-28, 1.93497044d-28, &
161 1.84540751d-28, 1.76356504d-28, 1.68741425d-28, 1.61566157d-28, &
162 1.54754523d-28, 1.48249410d-28, 1.42020176d-28, 1.36045230d-28, &
163 1.30307965d-28 /
164
165 data f_211 / 4.74439912d-42, 1.95251522d-40, 5.19700194d-39, 8.53120166d-38, &
166 7.72745727d-37, 4.04158559d-36, 1.64853511d-35, 8.56295439d-35, &
167 1.17529722d-33, 2.16867729d-32, 2.40472264d-31, 1.56418133d-30, &
168 7.20032889d-30, 2.65838271d-29, 8.33196904d-29, 2.26128236d-28, &
169 5.24295811d-28, 9.77791121d-28, 1.35913489d-27, 1.43957785d-27, &
170 1.37591544d-27, 1.49029886d-27, 2.06183401d-27, 3.31440622d-27, &
171 5.42497318d-27, 8.41100374d-27, 1.17941366d-26, 1.49269794d-26, &
172 1.71506074d-26, 1.71266353d-26, 1.51434781d-26, 1.36766622d-26, &
173 1.33483562d-26, 1.36834518d-26, 1.45829002d-26, 1.62575306d-26, &
174 1.88773347d-26, 2.22026986d-26, 2.54930499d-26, 2.80758138d-26, &
175 3.06176409d-26, 3.62799792d-26, 5.13226109d-26, 8.46260744d-26, &
176 1.38486586d-25, 1.86192535d-25, 1.78007934d-25, 1.16548409d-25, &
177 5.89293257d-26, 2.69952884d-26, 1.24891081d-26, 6.41273176d-27, &
178 4.08282914d-27, 3.26463328d-27, 2.76230280d-27, 2.08986882d-27, &
179 1.37658470d-27, 8.48489381d-28, 5.19304217d-28, 3.19312514d-28, &
180 2.02968197d-28, 1.50171666d-28, 1.39164218d-28, 1.42448821d-28, &
181 1.41714519d-28, 1.33341059d-28, 1.20759270d-28, 1.07259692d-28, &
182 9.44895400d-29, 8.29030041d-29, 7.25440631d-29, 6.33479483d-29, &
183 5.51563757d-29, 4.79002469d-29, 4.14990482d-29, 3.59384972d-29, &
184 3.12010860d-29, 2.72624742d-29, 2.40734791d-29, 2.15543565d-29, &
185 1.95921688d-29, 1.80682882d-29, 1.68695662d-29, 1.59020936d-29, &
186 1.50940886d-29, 1.43956179d-29, 1.37731622d-29, 1.32049043d-29, &
187 1.26771875d-29, 1.21803879d-29, 1.17074716d-29, 1.10507836d-29, &
188 1.06022834d-29, 1.01703080d-29, 9.75436986d-30, 9.35349257d-30, &
189 8.96744546d-30, 8.59527489d-30, 8.23678940d-30, 7.89144480d-30, &
190 7.55891138d-30 /
191
192 data f_304 / 3.62695850d-32, 2.79969087d-31, 1.68340584d-30, 7.32681440d-30, &
193 1.99967770d-29, 3.41296785d-29, 4.55409104d-29, 5.94994635d-29, &
194 8.59864963d-29, 1.39787633d-28, 3.17701965d-28, 1.14474920d-27, &
195 4.44845958d-27, 1.54785841d-26, 4.70265345d-26, 1.24524365d-25, &
196 2.81535352d-25, 5.10093666d-25, 6.83545307d-25, 6.82110329d-25, &
197 5.66886188d-25, 4.36205513d-25, 3.29265688d-25, 2.49802368d-25, &
198 1.92527113d-25, 1.51058572d-25, 1.20596047d-25, 9.76884267d-26, &
199 7.89979266d-26, 6.18224289d-26, 4.67298332d-26, 3.57934505d-26, &
200 2.84535785d-26, 2.32853022d-26, 1.95228514d-26, 1.67880071d-26, &
201 1.47608785d-26, 1.32199691d-26, 1.20070960d-26, 1.09378177d-26, &
202 1.00031730d-26, 9.62434001d-27, 1.05063954d-26, 1.27267143d-26, &
203 1.45923057d-26, 1.36746707d-26, 1.03466970d-26, 6.97647829d-27, &
204 4.63141039d-27, 3.19031994d-27, 2.33373613d-27, 1.81589079d-27, &
205 1.48446917d-27, 1.26611478d-27, 1.12617468d-27, 1.03625148d-27, &
206 9.61400595d-28, 8.79016231d-28, 7.82612130d-28, 6.73762960d-28, &
207 5.59717956d-28, 4.53010243d-28, 3.65712196d-28, 3.00958686d-28, &
208 2.54011502d-28, 2.18102277d-28, 1.88736437d-28, 1.63817539d-28, &
209 1.42283147d-28, 1.23631916d-28, 1.07526003d-28, 9.36797928d-29, &
210 8.18565660d-29, 7.18152734d-29, 6.32523238d-29, 5.59513985d-29, &
211 4.96614048d-29, 4.42518826d-29, 3.95487628d-29, 3.54690294d-29, &
212 3.18953930d-29, 2.87720933d-29, 2.60186750d-29, 2.36011522d-29, &
213 2.14717806d-29, 1.95905217d-29, 1.79287981d-29, 1.64562262d-29, &
214 1.51489425d-29, 1.39876064d-29, 1.29496850d-29, 1.18665438d-29, &
215 1.10240474d-29, 1.02643099d-29, 9.57780996d-30, 8.95465151d-30, &
216 8.38950190d-30, 7.87283711d-30, 7.40136507d-30, 6.96804279d-30, &
217 6.56945323d-30 /
218
219 data f_335 / 2.46882661d-32, 1.89476632d-31, 1.13216502d-30, 4.89532008d-30, &
220 1.32745970d-29, 2.25390335d-29, 3.00511672d-29, 3.96035934d-29, &
221 5.77977656d-29, 8.58600736d-29, 1.14083000d-28, 1.48644411d-28, &
222 2.15788823d-28, 3.51628877d-28, 6.12200698d-28, 1.08184987d-27, &
223 1.85590697d-27, 2.91679107d-27, 3.94405396d-27, 4.63610680d-27, &
224 5.13824456d-27, 5.66602209d-27, 6.30009232d-27, 7.03422868d-27, &
225 7.77973918d-27, 8.32371831d-27, 8.56724316d-27, 8.62601374d-27, &
226 8.13308844d-27, 6.53188216d-27, 4.55197029d-27, 3.57590087d-27, &
227 3.59571707d-27, 4.03502770d-27, 4.54366411d-27, 4.96914990d-27, &
228 5.24601170d-27, 5.39979250d-27, 5.43023669d-27, 5.26235042d-27, &
229 4.91585495d-27, 4.52628362d-27, 4.13385020d-27, 3.67538967d-27, &
230 3.39939742d-27, 3.81284533d-27, 5.02332701d-27, 6.19438602d-27, &
231 6.49613071d-27, 6.04010475d-27, 5.24664275d-27, 4.37225997d-27, &
232 3.52957182d-27, 2.76212276d-27, 2.08473158d-27, 1.50850518d-27, &
233 1.04602472d-27, 7.13091243d-28, 5.34289645d-28, 5.21079581d-28, &
234 6.22246365d-28, 6.99555864d-28, 6.29665489d-28, 4.45077026d-28, &
235 2.67046793d-28, 1.52774686d-28, 9.18061770d-29, 6.09116074d-29, &
236 4.48562572d-29, 3.59463696d-29, 3.05820218d-29, 2.70766652d-29, &
237 2.46144034d-29, 2.27758450d-29, 2.13331183d-29, 2.01537836d-29, &
238 1.91566180d-29, 1.82893912d-29, 1.75167748d-29, 1.68136168d-29, &
239 1.61615595d-29, 1.55481846d-29, 1.49643236d-29, 1.44046656d-29, &
240 1.38657085d-29, 1.33459068d-29, 1.28447380d-29, 1.23615682d-29, &
241 1.18963296d-29, 1.14478976d-29, 1.10146637d-29, 1.04039479d-29, &
242 9.98611410d-30, 9.58205147d-30, 9.19202009d-30, 8.81551313d-30, &
243 8.45252127d-30, 8.10224764d-30, 7.76469090d-30, 7.43954323d-30, &
244 7.12653873d-30 /
245
246
247 data n_iris / 41 /
248
249 data t_iris / 4. , 4.1 , 4.2 , 4.3 , 4.40000001, &
250 4.50000001, 4.60000001, 4.70000001, 4.80000001, 4.90000001, &
251 5.00000001, 5.10000002, 5.20000002, 5.30000002, 5.40000002, &
252 5.50000002, 5.60000002, 5.70000003, 5.80000003, 5.90000003, &
253 6.00000003, 6.10000003, 6.20000003, 6.30000003, 6.40000004, &
254 6.50000004, 6.60000004, 6.70000004, 6.80000004, 6.90000004, &
255 7.00000004, 7.10000005, 7.20000005, 7.30000005, 7.40000005, &
256 7.50000005, 7.60000005, 7.70000006, 7.80000006, 7.90000006, &
257 8.00000006 /
258
259 data f_1354 / 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, &
260 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, &
261 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, &
262 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, &
263 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, &
264 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 1.09503647d-39, &
265 5.47214550d-36, 2.42433983d-33, 2.75295034d-31, 1.21929718d-29, &
266 2.48392125d-28, 2.33268145d-27, 8.68623633d-27, 1.00166284d-26, &
267 3.63126633d-27, 7.45174807d-28, 1.38224064d-28, 2.69270994d-29, &
268 5.53314977d-30, 1.15313092d-30, 2.34195788d-31, 4.48242942d-32, &
269 7.94976380d-33 /
270
271
272 data n_eis / 60 /
273
274 data t_eis1 / 1.99526231d+05, 2.23872114d+05, 2.51188643d+05, 2.81838293d+05, &
275 3.16227766d+05, 3.54813389d+05, 3.98107171d+05, 4.46683592d+05, &
276 5.01187234d+05, 5.62341325d+05, 6.30957344d+05, 7.07945784d+05, &
277 7.94328235d+05, 8.91250938d+05, 1.00000000d+06, 1.12201845d+06, &
278 1.25892541d+06, 1.41253754d+06, 1.58489319d+06, 1.77827941d+06, &
279 1.99526231d+06, 2.23872114d+06, 2.51188643d+06, 2.81838293d+06, &
280 3.16227766d+06, 3.54813389d+06, 3.98107171d+06, 4.46683592d+06, &
281 5.01187234d+06, 5.62341325d+06, 6.30957344d+06, 7.07945784d+06, &
282 7.94328235d+06, 8.91250938d+06, 1.00000000d+07, 1.12201845d+07, &
283 1.25892541d+07, 1.41253754d+07, 1.58489319d+07, 1.77827941d+07, &
284 1.99526231d+07, 2.23872114d+07, 2.51188643d+07, 2.81838293d+07, &
285 3.16227766d+07, 3.54813389d+07, 3.98107171d+07, 4.46683592d+07, &
286 5.01187234d+07, 5.62341325d+07, 6.30957344d+07, 7.07945784d+07, &
287 7.94328235d+07, 8.91250938d+07, 1.00000000d+08, 1.12201845d+08, &
288 1.25892541d+08, 1.41253754d+08, 1.58489319d+08, 1.77827941d+08 /
289
290 data t_eis2 / 1.99526231d+06, 2.23872114d+06, 2.51188643d+06, 2.81838293d+06, &
291 3.16227766d+06, 3.54813389d+06, 3.98107171d+06, 4.46683592d+06, &
292 5.01187234d+06, 5.62341325d+06, 6.30957344d+06, 7.07945784d+06, &
293 7.94328235d+06, 8.91250938d+06, 1.00000000d+07, 1.12201845d+07, &
294 1.25892541d+07, 1.41253754d+07, 1.58489319d+07, 1.77827941d+07, &
295 1.99526231d+07, 2.23872114d+07, 2.51188643d+07, 2.81838293d+07, &
296 3.16227766d+07, 3.54813389d+07, 3.98107171d+07, 4.46683592d+07, &
297 5.01187234d+07, 5.62341325d+07, 6.30957344d+07, 7.07945784d+07, &
298 7.94328235d+07, 8.91250938d+07, 1.00000000d+08, 1.12201845d+08, &
299 1.25892541d+08, 1.41253754d+08, 1.58489319d+08, 1.77827941d+08, &
300 1.99526231d+08, 2.23872114d+08, 2.51188643d+08, 2.81838293d+08, &
301 3.16227766d+08, 3.54813389d+08, 3.98107171d+08, 4.46683592d+08, &
302 5.01187234d+08, 5.62341325d+08, 6.30957344d+08, 7.07945784d+08, &
303 7.94328235d+08, 8.91250938d+08, 1.00000000d+09, 1.12201845d+09, &
304 1.25892541d+09, 1.41253754d+09, 1.58489319d+09, 1.77827941d+09 /
305
306 data f_263 / 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, &
307 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, &
308 0.00000000d+00, 4.46454917d-45, 3.26774829d-42, 1.25292566d-39, &
309 2.66922338d-37, 3.28497742d-35, 2.38677554d-33, 1.03937729d-31, &
310 2.75075687d-30, 4.47961733d-29, 4.46729177d-28, 2.64862689d-27, &
311 8.90863800d-27, 1.72437548d-26, 2.22217752d-26, 2.27999477d-26, &
312 2.08264363d-26, 1.78226687d-26, 1.45821699d-26, 1.14675379d-26, &
313 8.63082492d-27, 6.15925429d-27, 4.11252514d-27, 2.51530564d-27, &
314 1.37090986d-27, 6.42443134d-28, 2.48392636d-28, 7.59187874d-29, &
315 1.77852938d-29, 3.23945221d-30, 4.90533903d-31, 6.75458158d-32, &
316 9.06878868d-33, 1.23927474d-33, 1.75769395d-34, 2.60710914d-35, &
317 4.04318030d-36, 6.53500581d-37, 1.09365022d-37, 1.88383322d-38, &
318 3.31425233d-39, 5.90964084d-40, 1.06147549d-40, 1.90706170d-41, &
319 3.41331584d-42, 6.07310718d-43, 1.07364738d-43, 1.89085498d-44, &
320 3.32598922d-45, 5.87125640d-46, 0.00000000d+00, 0.00000000d+00 /
321
322 data f_264 / 0.00000000d+00, 2.81670057d-46, 1.28007268d-43, 2.54586603d-41, &
323 2.67887256d-39, 1.68413285d-37, 6.85702304d-36, 1.91797284d-34, &
324 3.84675839d-33, 5.69939170d-32, 6.36224608d-31, 5.39176489d-30, &
325 3.45478458d-29, 1.64848693d-28, 5.71476364d-28, 1.39909997d-27, &
326 2.37743056d-27, 2.86712530d-27, 2.65206348d-27, 2.07175767d-27, &
327 1.47866767d-27, 1.01087374d-27, 6.79605811d-28, 4.54746770d-28, &
328 3.04351751d-28, 2.03639149d-28, 1.35940991d-28, 9.01451939d-29, &
329 5.91289972d-29, 3.81821178d-29, 2.41434696d-29, 1.48871220d-29, &
330 8.93362094d-30, 5.21097445d-30, 2.95964719d-30, 1.64278748d-30, &
331 8.95571660d-31, 4.82096011d-31, 2.57390991d-31, 1.36821781d-31, &
332 7.27136350d-32, 3.87019426d-32, 2.06883430d-32, 1.11228884d-32, &
333 6.01883313d-33, 3.27790676d-33, 1.79805012d-33, 9.93085346d-34, &
334 5.52139556d-34, 3.08881387d-34, 1.73890315d-34, 9.84434964d-35, &
335 5.60603378d-35, 3.20626492d-35, 1.84111068d-35, 0.00000000d+00, &
336 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00 /
337
338 data f_192 / 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 4.35772105d-44, &
339 1.26162319d-41, 1.97471205d-39, 1.83409019d-37, 1.08206288d-35, &
340 4.27914363d-34, 1.17943846d-32, 2.32565755d-31, 3.33087991d-30, &
341 3.47013260d-29, 2.60375866d-28, 1.37737127d-27, 5.01053913d-27, &
342 1.23479810d-26, 2.11310542d-26, 2.71831513d-26, 2.89851163d-26, &
343 2.77312376d-26, 2.50025229d-26, 2.18323661d-26, 1.86980322d-26, &
344 1.58035034d-26, 1.31985651d-26, 1.08733133d-26, 8.81804906d-27, &
345 7.00417973d-27, 5.43356567d-27, 4.09857884d-27, 2.99651764d-27, &
346 2.11902962d-27, 1.45014127d-27, 9.62291023d-28, 6.21548647d-28, &
347 3.92807578d-28, 2.44230375d-28, 1.50167782d-28, 9.17611405d-29, &
348 5.58707641d-29, 3.40570915d-29, 2.08030862d-29, 1.27588676d-29, &
349 7.86535588d-30, 4.87646151d-30, 3.03888897d-30, 1.90578649d-30, &
350 1.20195947d-30, 7.61955060d-31, 4.85602199d-31, 3.11049969d-31, &
351 2.00087065d-31, 1.29223740d-31, 8.37422008d-32, 0.00000000d+00, &
352 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00 /
353
354 data f_255 / 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 1.76014287d-44, &
355 5.07057938d-42, 7.90473970d-40, 7.31852999d-38, 4.30709255d-36, &
356 1.70009061d-34, 4.67925160d-33, 9.21703546d-32, 1.31918676d-30, &
357 1.37393161d-29, 1.03102379d-28, 5.45694018d-28, 1.98699648d-27, &
358 4.90346776d-27, 8.40524725d-27, 1.08321456d-26, 1.15714525d-26, &
359 1.10905152d-26, 1.00155023d-26, 8.75799161d-27, 7.50935839d-27, &
360 6.35253533d-27, 5.30919268d-27, 4.37669455d-27, 3.55185164d-27, &
361 2.82347055d-27, 2.19257595d-27, 1.65589541d-27, 1.21224987d-27, &
362 8.58395132d-28, 5.88163935d-28, 3.90721447d-28, 2.52593407d-28, &
363 1.59739995d-28, 9.93802874d-29, 6.11343388d-29, 3.73711135d-29, &
364 2.27618743d-29, 1.38793199d-29, 8.48060787d-30, 5.20305940d-30, &
365 3.20867365d-30, 1.99011277d-30, 1.24064551d-30, 7.78310544d-31, &
366 4.91013681d-31, 3.11338381d-31, 1.98451675d-31, 1.27135460d-31, &
367 8.17917486d-32, 5.28280497d-32, 3.42357159d-32, 0.00000000d+00, &
368 0.00000000d+00, 0.00000000d+00, 0.00000000d+00, 0.00000000d+00 /
369
370 abstract interface
371 subroutine get_subr1(w,x,ixI^L,ixO^L,res)
373 integer, intent(in) :: ixI^L, ixO^L
374 double precision, intent(in) :: w(ixI^S,nw)
375 double precision, intent(in) :: x(ixI^S,1:ndim)
376 double precision, intent(out):: res(ixI^S)
377 end subroutine get_subr1
378
379 end interface
380
381 abstract interface
382 subroutine get_2var_subr_te(ixI^L, ixO^L, w, val1, val2)
384 integer, intent(in) :: ixI^L, ixO^L
385 double precision, intent(in) :: w(ixI^S, nw)
386 double precision, intent(out):: val1(ixI^S), val2(ixI^S)
387 end subroutine get_2var_subr_te
388 end interface
389
391
392 procedure(get_subr1), pointer, nopass :: get_rho => null()
393 procedure(get_subr1), pointer, nopass :: get_pthermal => null()
394 procedure(get_subr1), pointer, nopass :: get_var_rfactor => null()
395 procedure(get_2var_subr_te), pointer, nopass :: get_ne_nh => null()
396
397 end type te_fluid
398
400 integer :: igrid=0
401 integer :: level=0
402 integer :: rft=1
403 integer :: los_min=0
404 integer :: los_max=0
405 double precision, allocatable :: source(:^d&)
406 double precision, allocatable :: opacity(:^d&)
407 double precision, allocatable :: sourcev(:^d&)
408 double precision, allocatable :: xface1(:),xface2(:),xface3(:)
409 double precision, allocatable :: rface(:),thetaface(:),phiface(:)
410 double precision, allocatable :: rface2(:),theta_cos(:),phi_sin(:),phi_cos(:)
411 double precision :: box_min(1:3)=0.d0
412 double precision :: box_max(1:3)=0.d0
413 integer :: ixpmin1=1
414 integer :: ixpmax1=0
415 integer :: ixpmin2=1
416 integer :: ixpmax2=0
417 logical :: has_pixels=.false.
418 end type radsyn_euv_cache
419
420 character(len=std_len) :: ray_method_active='legacy'
421 logical :: sph_use_dda=.false.
422
423
424 contains
425
428
429 character(len=*), intent(in) :: datatype
430
431 if (trim(radiation_transfer) /= 'thin' .and. trim(radiation_transfer) /= 'thick') then
432 call mpistop("bad radiation_transfer")
433 endif
434
435 if (trim(dat_resolution_mode) /= 'nominal' .and. &
436 trim(dat_resolution_mode) /= 'minimum') then
437 call mpistop("dat_resolution_mode must be nominal or minimum")
438 endif
439
440 sph_use_dda=.false.
441 select case(trim(ray_method))
442 case('auto','')
443 if (datatype=='image_euv' .and. coordinate==spherical) then
444 ray_method_active='spherical'
445 sph_use_dda=.true.
446 else if (datatype=='image_euv' .and. dat_resolution .and. slab) then
447 ray_method_active='cart'
448 else
449 ray_method_active='legacy'
450 endif
451 case('legacy')
452 ray_method_active='legacy'
453 case('cart','cart_dda')
454 ray_method_active='cart'
455 case('spherical','sph_intersection')
456 ray_method_active='spherical'
457 case('sph_dda','spherical_dda')
458 ray_method_active='spherical'
459 sph_use_dda=.true.
460 case default
461 call mpistop("bad ray_method")
462 end select
463
464 if (trim(emission_model) /= 'auto' .and. trim(emission_model) /= 'euv_aia' .and. &
465 trim(emission_model) /= 'white_light' .and. trim(emission_model) /= 'radio_ff' .and. &
466 trim(emission_model) /= 'pseudo_current') then
467 call mpistop("bad emission_model")
468 endif
469
470 if ((output_tau .or. output_absorption_fraction) .and. trim(radiation_transfer) /= 'thick') then
471 call mpistop("tau and absorption-fraction output need thick transfer")
472 endif
473
474 if (radsyn_pixel_batch<1) then
475 call mpistop("radsyn_pixel_batch must be positive")
476 endif
478 call mpistop("radsyn_segment_batch_factor must be non-negative")
479 endif
480 if (radsyn_segment_memory_mb<=zero) then
481 call mpistop("radsyn_segment_memory_mb must be positive")
482 endif
484 call mpistop("radsyn_segment_comm_factor must be positive")
485 endif
486
487 if (instrument_postprocess) then
488 if (datatype /= 'image_euv' .or. .not. dat_resolution) then
489 call mpistop("instrument_postprocess currently needs dat-resolution EUV images")
490 endif
491 if (trim(ray_method_active) == 'spherical') then
492 call mpistop("instrument_postprocess is not yet supported for spherical rays")
493 endif
494 if (trim(emission_model) == 'pseudo_current') then
495 call mpistop("instrument_postprocess currently supports only EUV AIA or radio_ff images")
496 endif
497 if (trim(emission_model) == 'radio_ff' .and. radio_beam_fwhm<=zero) then
498 call mpistop("radio_ff instrument_postprocess needs radio_beam_fwhm > 0 arcsec")
499 endif
500 endif
501
502 select case(trim(emission_model))
503 case('auto')
504 continue
505 case('euv_aia')
506 if (datatype /= 'image_euv' .and. datatype /= 'spectrum_euv') then
507 call mpistop("emission_model=euv_aia is only valid for EUV synthesis")
508 endif
509 case('white_light')
510 if (datatype /= 'image_whitelight') then
511 call mpistop("emission_model=white_light is only valid for white-light synthesis")
512 endif
513 case('radio_ff')
514 if (datatype /= 'image_euv') then
515 call mpistop("emission_model=radio_ff currently reuses EUV-image convert types")
516 endif
517 if (radio_frequency<=zero) then
518 call mpistop("emission_model=radio_ff needs radio_frequency > 0")
519 endif
520 case('pseudo_current')
521 if (datatype /= 'image_euv') then
522 call mpistop("emission_model=pseudo_current is only valid for EUV-image convert types")
523 endif
524 if (trim(radiation_transfer) /= 'thin') then
525 call mpistop("emission_model=pseudo_current currently supports only thin transfer")
526 endif
527 end select
528
529 if (trim(ray_method_active) == 'cart') then
530 if (datatype /= 'image_euv' .or. .not. slab) then
531 call mpistop("ray_method=cart needs Cartesian EUV slab images")
532 endif
533 endif
534 if (trim(ray_method_active) == 'spherical') then
535 {^ifoned
536 call mpistop("ray_method=spherical currently needs 3D spherical grids")
537 }
538 {^iftwod
539 call mpistop("ray_method=spherical currently needs 3D spherical grids")
540 }
541 {^ifthreed
542 if (datatype /= 'image_euv' .or. coordinate /= spherical .or. &
543 (trim(radiation_transfer) /= 'thin' .and. trim(radiation_transfer) /= 'thick')) then
544 call mpistop("bad ray_method=spherical mode")
545 endif
546 if (trim(emission_model) /= 'auto' .and. trim(emission_model) /= 'euv_aia') then
547 call mpistop("ray_method=spherical currently supports only EUV AIA emission")
548 endif
549 if (xprobmin2<=1.d-10 .or. xprobmax2>=dpi-1.d-10) then
550 call mpistop("ray_method=spherical does not support polar-axis crossing domains")
551 endif
552 if (xprobmax3<=xprobmin3 .or. xprobmax3-xprobmin3>=2.d0*dpi-1.d-10) then
553 call mpistop("ray_method=spherical does not support phi-wrapping domains")
554 endif
555 }
556 endif
557 if (trim(radiation_transfer) == 'thick') then
558 if (datatype /= 'image_euv') then
559 call mpistop("thick transfer is only defined for EUV images")
560 endif
561 if (trim(ray_method_active) == 'spherical') then
562 continue
563 else if (trim(ray_method_active) == 'cart') then
564 if (.not. slab) call mpistop("cartesian thick EUV currently needs slab output")
565 else if (.not. slab .or. .not. dat_resolution) then
566 call mpistop("thick EUV currently needs Cartesian dat_resolution output")
567 endif
568 if (trim(ray_method_active) /= 'cart' .and. &
569 trim(ray_method_active) /= 'spherical' .and. &
570 .not. ((los_phi==0 .and. los_theta==90) .or. &
571 (los_phi==90 .and. los_theta==90) .or. los_theta==0)) then
572 call mpistop("thick EUV currently needs x/y/z-aligned LOS")
573 endif
574 endif
576
577 subroutine integrate_transfer_step_first_order(emissivity,opacity,path_length,intensity,tau)
578 ! First-order formal-solution step used by the planned ordered LOS transfer.
579 double precision, intent(in) :: emissivity,opacity,path_length
580 double precision, intent(inout) :: intensity,tau
581
582 double precision :: dtau
583
584 if (path_length<=zero) return
585 intensity=intensity+transfer_attenuation(tau)*max(zero,emissivity)*path_length
586 dtau=max(zero,opacity)*path_length
587 tau=tau+dtau
589
591 radsyn_euv_has_doppler_output=trim(emission_model)/='pseudo_current' .and. &
592 trim(emission_model)/='radio_ff' .and. &
593 .not. (coordinate==spherical .and. trim(ray_method_active)=='spherical')
595
596 integer function radsyn_euv_num_outputs(has_doppler,has_thick) result(num_outputs)
597 logical, intent(in) :: has_doppler,has_thick
598
599 num_outputs=1
600 if (has_doppler) num_outputs=num_outputs+1
601 if (has_thick .and. output_tau) num_outputs=num_outputs+1
602 if (has_thick .and. output_absorption_fraction) num_outputs=num_outputs+1
603 end function radsyn_euv_num_outputs
604
605 subroutine normalize_euv_doppler(nI1,nI2,EUV,Dpl,unitv)
606 integer, intent(in) :: nI1,nI2
607 double precision, intent(in) :: EUV(nI1,nI2),unitv
608 double precision, intent(inout) :: Dpl(nI1,nI2)
609
610 integer :: ix1,ix2
611
612 do ix1=1,ni1
613 do ix2=1,ni2
614 if (euv(ix1,ix2)/=zero) then
615 dpl(ix1,ix2)=(dpl(ix1,ix2)/euv(ix1,ix2))*unitv
616 else
617 dpl(ix1,ix2)=zero
618 endif
619 if (abs(dpl(ix1,ix2))<smalldouble) dpl(ix1,ix2)=zero
620 enddo
621 enddo
622 end subroutine normalize_euv_doppler
623
624 subroutine fill_euv_absorption_fraction(nI1,nI2,EUV,EUVthin,smallflux,Absorption,cap_to_one)
625 integer, intent(in) :: nI1,nI2
626 double precision, intent(in) :: EUV(nI1,nI2),EUVthin(nI1,nI2),smallflux
627 double precision, intent(out) :: Absorption(nI1,nI2)
628 logical, intent(in), optional :: cap_to_one
629
630 integer :: ix1,ix2
631 logical :: cap_absorption
632
633 absorption=zero
634 cap_absorption=.false.
635 if (present(cap_to_one)) cap_absorption=cap_to_one
636 do ix1=1,ni1
637 do ix2=1,ni2
638 if (euvthin(ix1,ix2)>smallflux) then
639 absorption(ix1,ix2)=max(zero,(euvthin(ix1,ix2)-euv(ix1,ix2))/euvthin(ix1,ix2))
640 if (cap_absorption) absorption(ix1,ix2)=min(one,absorption(ix1,ix2))
641 endif
642 enddo
643 enddo
644 end subroutine fill_euv_absorption_fraction
645
646 subroutine pack_euv_image_outputs(nI1,nI2,EUV,wI,smallflux,has_doppler,has_thick,Dpl,Tau,EUVthin,&
647 cap_absorption)
648 integer, intent(in) :: nI1,nI2
649 double precision, intent(in) :: EUV(nI1,nI2),smallflux
650 double precision, intent(inout) :: wI(:,:,:)
651 logical, intent(in) :: has_doppler,has_thick
652 double precision, intent(in), optional :: Dpl(nI1,nI2),Tau(nI1,nI2),EUVthin(nI1,nI2)
653 logical, intent(in), optional :: cap_absorption
654
655 integer :: iw
656 double precision, allocatable :: Absorption(:,:)
657
658 wi=zero
659 wi(:,:,1)=euv(:,:)
660 iw=1
661 if (has_doppler) then
662 if (.not. present(dpl)) call mpistop("Doppler output requested without Doppler image")
663 iw=iw+1
664 wi(:,:,iw)=dpl(:,:)
665 endif
666 if (has_thick .and. output_tau) then
667 if (.not. present(tau)) call mpistop("tau output requested without tau image")
668 iw=iw+1
669 wi(:,:,iw)=tau(:,:)
670 endif
671 if (has_thick .and. output_absorption_fraction) then
672 if (.not. present(euvthin)) call mpistop("absorption output requested without thin image")
673 allocate(absorption(ni1,ni2))
674 call fill_euv_absorption_fraction(ni1,ni2,euv,euvthin,smallflux,absorption,cap_absorption)
675 iw=iw+1
676 wi(:,:,iw)=absorption(:,:)
677 deallocate(absorption)
678 endif
679 end subroutine pack_euv_image_outputs
680
681 subroutine radsyn_get_segment_batch_limits(pixel_batch_target,segment_batch_target,segment_comm_target)
682 integer, intent(out) :: pixel_batch_target,segment_batch_target,segment_comm_target
683
684 pixel_batch_target=max(1,radsyn_pixel_batch)
685 if (radsyn_segment_batch_factor>0) then
686 segment_batch_target=max(128,radsyn_segment_batch_factor*pixel_batch_target)
687 else
688 segment_batch_target=max(128,int(min(dble(huge(segment_batch_target)),&
689 max(128.d0,radsyn_segment_memory_mb*1048576.d0/256.d0))))
690 endif
691 segment_comm_target=max(128,radsyn_segment_comm_factor*pixel_batch_target)
693
694 double precision function transfer_attenuation(tau)
695 double precision, intent(in) :: tau
696
697 if (tau<=zero) then
699 else
701 endif
702 end function transfer_attenuation
703
704 double precision function exp_clamped(argument)
705 double precision, intent(in) :: argument
706
707 if (argument<-700.d0) then
708 exp_clamped=zero
709 else if (argument>700.d0) then
710 exp_clamped=huge(one)
711 else
712 exp_clamped=exp(argument)
713 endif
714 end function exp_clamped
715
716 double precision function pow10_clamped(exponent)
717 double precision, intent(in) :: exponent
718
719 if (exponent>300.d0) then
720 pow10_clamped=1.d300
721 else if (exponent<-300.d0) then
722 pow10_clamped=zero
723 else
724 pow10_clamped=10.d0**exponent
725 endif
726 end function pow10_clamped
727
728 double precision function interpolate_response_value(temperature,t_table,f_table,n_table,log_temperature,log_response)
729 double precision, intent(in) :: temperature
730 integer, intent(in) :: n_table
731 double precision, intent(in) :: t_table(n_table),f_table(n_table)
732 logical, intent(in) :: log_temperature,log_response
733
734 integer :: ilo,ihi,imid
735 double precision :: temp_lookup,response_lookup,flo,fhi
736
738 if (temperature<=zero) return
739 if (log_temperature) then
740 temp_lookup=log10(temperature)
741 else
742 temp_lookup=temperature
743 endif
744 if (temp_lookup<t_table(1) .or. temp_lookup>t_table(n_table)) return
745 if (temp_lookup==t_table(n_table)) then
746 if (log_response) then
747 response_lookup=log10(max(f_table(n_table),1.d-99))
748 else
749 response_lookup=f_table(n_table)
750 endif
751 else
752 ilo=1
753 ihi=n_table
754 do while (ihi-ilo>1)
755 imid=(ilo+ihi)/2
756 if (temp_lookup>=t_table(imid)) then
757 ilo=imid
758 else
759 ihi=imid
760 endif
761 enddo
762 if (log_response) then
763 flo=log10(max(f_table(ilo),1.d-99))
764 fhi=log10(max(f_table(ilo+1),1.d-99))
765 else
766 flo=f_table(ilo)
767 fhi=f_table(ilo+1)
768 endif
769 response_lookup=flo*(temp_lookup-t_table(ilo+1))/(t_table(ilo)-t_table(ilo+1))+&
770 fhi*(temp_lookup-t_table(ilo))/(t_table(ilo+1)-t_table(ilo))
771 endif
772
773 if (log_response) then
774 if (response_lookup>-99.d0) interpolate_response_value=10.d0**response_lookup
775 else
776 interpolate_response_value=response_lookup
777 endif
779 end function interpolate_response_value
780
781 subroutine apply_temperature_response(ixI^L,ixO^L,Te,flux,t_table,f_table,n_table,log_temperature,log_response)
782 integer, intent(in) :: ixI^L, ixO^L, n_table
783 double precision, intent(in) :: Te(ixI^S),t_table(n_table),f_table(n_table)
784 double precision, intent(inout) :: flux(ixI^S)
785 logical, intent(in) :: log_temperature,log_response
786
787 integer :: ix^D
788 double precision :: GT
789
790 {do ix^db=ixomin^db,ixomax^db\}
791 gt=interpolate_response_value(te(ix^d),t_table,f_table,n_table,log_temperature,log_response)
792 flux(ix^d)=flux(ix^d)*gt
793 if (flux(ix^d)<zero) flux(ix^d)=zero
794 {enddo\}
795 end subroutine apply_temperature_response
796
797 subroutine get_euv_saha_fractions(Te,Ne,x_HII,x_HeII,x_HeIII)
798 ! Ion fractions at fixed temperature and electron density. Ne is an
799 ! input here: this helper does not impose charge conservation or alter
800 ! the thermodynamic state of the simulation.
801 use mod_constants, only: kb_cgs
802
803 double precision, intent(in) :: Te,Ne
804 double precision, intent(out) :: x_HII,x_HeII,x_HeIII
805
806 double precision :: Pe,log_H21,log_He21,log_He32,log_He321
807 double precision :: logScaleHe,w_H21,term0,term1,term2,denHe
808 double precision, parameter :: Xe_H21=13.6d0
809 double precision, parameter :: Xe_He21=24.587d0
810 double precision, parameter :: Xe_He32=54.416d0
811
812 x_hii=zero
813 x_heii=zero
814 x_heiii=zero
815 if (te<=zero .or. ne<=zero) return
816
817 pe=ne*kb_cgs*te
818 if (pe<=zero) return
819
820 log_h21=2.5d0*log10(te)-5040.d0*xe_h21/te-log10(pe)-0.48d0
821 log_he21=log10(4.d0)+2.5d0*log10(te)-5040.d0*xe_he21/te-log10(pe)-0.48d0
822 log_he32=2.5d0*log10(te)-5040.d0*xe_he32/te-log10(pe)-0.48d0
823
824 w_h21=pow10_clamped(log_h21)
825 x_hii=w_h21/(1.d0+w_h21)
826
827 ! Normalize the three helium stages in logarithmic form to avoid
828 ! overflow in the product of the two Saha ratios.
829 log_he321=log_he21+log_he32
830 logscalehe=max(zero,log_he21,log_he321)
831 term0=pow10_clamped(-logscalehe)
832 term1=pow10_clamped(log_he21-logscalehe)
833 term2=pow10_clamped(log_he321-logscalehe)
834 denhe=term0+term1+term2
835 if (denhe>zero) then
836 x_heii=term1/denhe
837 x_heiii=term2/denhe
838 endif
839 end subroutine get_euv_saha_fractions
840
841 subroutine solve_euv_saha_charge_state(nH,Te,rHe,Ne_guess,x_HII,x_HeII,x_HeIII)
842 ! Radiation-only Saha closure at fixed total hydrogen density and
843 ! temperature. It is used for an FI simulation, whose fully-ionized
844 ! electron density cannot consistently determine cool neutral fractions.
845 ! rHe belongs to the synthetic absorber and is not fed back into the
846 ! simulation equation of state, pressure, or temperature.
847 double precision, intent(in) :: nH,Te,rHe,Ne_guess
848 double precision, intent(out) :: x_HII,x_HeII,x_HeIII
849
850 integer, parameter :: max_iter=32
851 integer :: iter
852 double precision :: Ne,Ne_lo,Ne_hi,Ne_new,residual,derivative
853 double precision :: e_He,de_HII_dNe,de_He_dNe
854
855 x_hii=zero
856 x_heii=zero
857 x_heiii=zero
858 if (nh<=zero .or. te<=zero) return
859
860 ne_lo=max(1.d-30*nh,1.d-100)
861 ne_hi=(1.d0+2.d0*rhe)*nh
862 ne=min(max(ne_guess,ne_lo),ne_hi)
863
864 do iter=1,max_iter
865 call get_euv_saha_fractions(te,ne,x_hii,x_heii,x_heiii)
866 e_he=x_heii+2.d0*x_heiii
867 residual=ne/nh-x_hii-rhe*e_he
868 if (abs(residual)<1.d-10) exit
869
870 if (residual>zero) then
871 ne_hi=ne
872 else
873 ne_lo=ne
874 endif
875
876 ! Analytic derivative of the charge-neutrality residual. The
877 ! Newton step is kept inside a bisection bracket for robustness.
878 de_hii_dne=-x_hii*(1.d0-x_hii)/ne
879 de_he_dne=(x_heii*(e_he-1.d0) &
880 +2.d0*x_heiii*(e_he-2.d0))/ne
881 derivative=1.d0/nh-de_hii_dne-rhe*de_he_dne
882 ne_new=ne-residual/derivative
883 if (.not.(ne_new>ne_lo .and. ne_new<ne_hi)) then
884 ne_new=0.5d0*(ne_lo+ne_hi)
885 endif
886 ne=ne_new
887 enddo
888
889 ! Ensure the returned fractions correspond to the final iterate.
890 call get_euv_saha_fractions(te,ne,x_hii,x_heii,x_heiii)
891 end subroutine solve_euv_saha_charge_state
892
893 subroutine get_euv_hhe_opacity(wl,ixI^L,ixO^L,w,x,fl,kappa)
894 ! H I + He I + He II photoionization opacity in cm^-1.
895 use mod_eos, only: eos
897
898 integer, intent(in) :: wl
899 integer, intent(in) :: ixI^L, ixO^L
900 double precision, intent(in) :: x(ixI^S,1:ndim)
901 double precision, intent(in) :: w(ixI^S,1:nw)
902 type(te_fluid), intent(in) :: fl
903 double precision, intent(out) :: kappa(ixI^S)
904
905 integer :: ix^D
906 double precision :: pth(ixI^S),rho(ixI^S),Rfactor(ixI^S),Te(ixI^S)
907 double precision :: Ne(ixI^S),nH(ixI^S)
908 double precision :: wave_ratio,s_H1,s_He1,s_He2
909 double precision :: x_HII,x_HeII,x_HeIII,iz_H,iz_He,Rdummy
910 double precision :: N_H1,N_He1,N_He2
911 double precision, parameter :: rHe_opacity=0.1d0
912 double precision, parameter :: sigma_H1=5.16d-20, sigma_he1=9.25d-19, sigma_he2=7.17d-19
913
914 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
915 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
916 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,rfactor)
917 te(ixo^s)=zero
918 {do ix^db=ixomin^db,ixomax^db\}
919 if (rho(ix^d)>zero .and. rfactor(ix^d)>zero) then
920 te(ix^d)=pth(ix^d)/(rho(ix^d)*rfactor(ix^d))*unit_temperature
921 endif
922 {enddo\}
923
924 ! nH always follows the mass density and composition of the simulated
925 ! gas. rHe_opacity is deliberately applied only when constructing the
926 ! synthetic absorber below; it never changes this EOS conversion.
927 call eos%get_ne_nH(ixi^l, ixo^l, w, ne, nh)
928 if (si_unit) then
929 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6
930 nh(ixo^s)=nh(ixo^s)*unit_numberdensity/1.d6
931 else
932 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
933 nh(ixo^s)=nh(ixo^s)*unit_numberdensity
934 endif
935
936 wave_ratio=dble(wl)/171.d0
937 s_h1=zero
938 s_he1=zero
939 s_he2=zero
940 if (wl<=912) s_h1=wave_ratio**3*sigma_h1
941 if (wl<=504) s_he1=wave_ratio**2*sigma_he1
942 if (wl<=228) s_he2=wave_ratio**2.75d0*sigma_he2
943 kappa(ixo^s)=zero
944
945 {do ix^db=ixomin^db,ixomax^db\}
946 if (te(ix^d)>zero .and. nh(ix^d)>zero) then
947 select case (trim(eos%eos_type))
948 case ('PI')
949 ! Reuse the ionisation state of the PI backend. In its helium
950 ! convention iz_He is the fraction ionised at least once and
951 ! iz_He**2 the fraction ionised twice.
952 call ionization_state_tp(te(ix^d)/unit_temperature,pth(ix^d), &
953 rdummy,iz_h,iz_he)
954 x_hii=iz_h
955 x_heii=iz_he*(1.d0-iz_he)
956 x_heiii=iz_he*iz_he
957 case ('LTE')
958 ! LTE stores the self-consistent total electron density rather
959 ! than separate H/He populations. Reconstruct the helium stages
960 ! at that EOS electron density and temperature, then retain the
961 ! simulated ne/nH exactly when obtaining the hydrogen fraction.
962 if (ne(ix^d)>zero) then
963 call get_euv_saha_fractions(te(ix^d),ne(ix^d), &
964 x_hii,x_heii,x_heiii)
965 if (trim(eos%method)=='analytic') then
966 ! The analytic LTE option is explicitly H-only below its FI
967 ! bypass, so its stored ne/nH is the hydrogen ion fraction.
968 x_hii=min(one,max(zero,ne(ix^d)/nh(ix^d)))
969 else
970 x_hii=min(one,max(zero,ne(ix^d)/nh(ix^d) &
971 -eos%He_abundance*(x_heii+2.d0*x_heiii)))
972 endif
973 else
974 call solve_euv_saha_charge_state(nh(ix^d),te(ix^d), &
975 rhe_opacity,ne(ix^d),x_hii,x_heii,x_heiii)
976 endif
977 case default
978 ! FI supplies a fully-ionized Ne even when its rho,T state is
979 ! cool. Discard that Ne constraint and solve charge neutrality
980 ! at fixed simulated nH and T for the radiation post-processing.
981 call solve_euv_saha_charge_state(nh(ix^d),te(ix^d), &
982 rhe_opacity,ne(ix^d),x_hii,x_heii,x_heiii)
983 end select
984
985 n_h1=nh(ix^d)*(1.d0-x_hii)
986 n_he1=rhe_opacity*nh(ix^d)*(1.d0-x_heii-x_heiii)
987 n_he2=rhe_opacity*nh(ix^d)*x_heii
988 kappa(ix^d)=max(zero,n_h1*s_h1+n_he1*s_he1+n_he2*s_he2)
989 endif
990 {enddo\}
991 end subroutine get_euv_hhe_opacity
992
993 subroutine get_pseudo_current(igrid,ixI^L,ixO^L,w,source)
994 integer, intent(in) :: igrid
995 integer, intent(in) :: ixI^L, ixO^L
996 double precision, intent(in) :: w(ixI^S,1:nw)
997 double precision, intent(out) :: source(ixI^S)
998
999 integer :: ix^D,idir,idirmin,idirmin0
1000 double precision :: current(ixI^S,7-2*ndir:3)
1001
1002 if (.not. allocated(iw_mag)) then
1003 call mpistop("emission_model=pseudo_current needs magnetic-field variables")
1004 endif
1005
1006 idirmin0=7-2*ndir
1007 current=zero
1008 call curlvector(w(ixi^s,iw_mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
1009 if (b0field) then
1010 current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+ps(igrid)%J0(ixo^s,idirmin0:3)
1011 endif
1012
1013 source(ixi^s)=zero
1014 {do ix^db=ixomin^db,ixomax^db\}
1015 do idir=idirmin0,3
1016 source(ix^d)=source(ix^d)+current(ix^d,idir)**2
1017 enddo
1018 {enddo\}
1019 end subroutine get_pseudo_current
1020
1021 subroutine get_radio_ff_source_opacity(ixI^L,ixO^L,w,x,fl,source,kappa)
1022 use mod_eos, only: eos
1023
1024 integer, intent(in) :: ixI^L, ixO^L
1025 double precision, intent(in) :: x(ixI^S,1:ndim)
1026 double precision, intent(in) :: w(ixI^S,1:nw)
1027 type(te_fluid), intent(in) :: fl
1028 double precision, intent(out) :: source(ixI^S),kappa(ixI^S)
1029
1030 integer :: ix^D
1031 double precision :: pth(ixI^S),Te(ixI^S),Ne(ixI^S)
1032 double precision :: nH_dummy(ixI^S),gff
1033
1034 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
1035 call fl%get_rho(w,x,ixi^l,ixo^l,ne)
1036 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,te)
1037 te(ixo^s)=pth(ixo^s)/(ne(ixo^s)*te(ixo^s))*unit_temperature
1038 call eos%get_ne_nH(ixi^l,ixo^l,w,ne,nh_dummy)
1039 if (si_unit) then
1040 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6
1041 else
1042 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
1043 endif
1044
1045 source(ixi^s)=zero
1046 kappa(ixi^s)=zero
1047 {do ix^db=ixomin^db,ixomax^db\}
1048 if (te(ix^d)>zero .and. ne(ix^d)>zero) then
1049 if (te(ix^d)<2.d5) then
1050 gff=18.2d0+1.5d0*log(te(ix^d))-log(radio_frequency)
1051 else
1052 gff=24.5d0+log(te(ix^d))-log(radio_frequency)
1053 endif
1054 gff=max(one,gff)
1055 kappa(ix^d)=9.78d-3*ne(ix^d)**2*gff/(radio_frequency**2*te(ix^d)**1.5d0)
1056 source(ix^d)=te(ix^d)*kappa(ix^d)
1057 endif
1058 {enddo\}
1059 end subroutine get_radio_ff_source_opacity
1060
1061 subroutine get_line_info(wl,ion,mass,logTe,line_center,spatial_px,spectral_px,sigma_PSF,width_slit)
1062 ! get information of the spectral line
1063 ! wl: wavelength
1064 ! mass: ion mass, unit -- proton mass
1065 ! logTe: peak temperature of emission line in logarithm
1066 ! line_center: center wavelength of emission line, unit -- Angstrom (0.1 nm)
1067 ! spatial_px: pixel size in space of instrument (for image), unit -- arcsec
1068 ! spectral_px: pixel size in wagelength of instrument (for spectrum), unit -- Angstrom
1069 ! sigma_PSF: width of point spread function core (for instrument), unit -- pixel
1070 ! width_slit: width of slit for spectrograph, unit -- arcsec
1072
1073 integer, intent(in) :: wl
1074 integer, intent(out) :: mass
1075 character(len=30), intent(out) :: ion
1076 double precision, intent(out) :: logTe,line_center,spatial_px,spectral_px
1077 double precision, intent(out) :: sigma_PSF,width_slit
1078
1079 select case(wl)
1080 case(304)
1081 ion='He II'
1082 mass=4
1083 logte=4.7d0
1084 line_center=303.8d0
1085 spatial_px=0.6d0
1086 spectral_px=0.02d0
1087 sigma_psf=0.895d0
1088 width_slit=0.6d0
1089 case(171)
1090 ion='Fe IX'
1091 mass=56
1092 logte=5.8d0
1093 line_center=171.1d0
1094 spatial_px=0.6d0
1095 spectral_px=0.02d0
1096 sigma_psf=1.019d0
1097 width_slit=0.6d0
1098 case(193)
1099 ion='Fe XXIV'
1100 mass=56
1101 logte=7.3d0
1102 line_center=193.5d0
1103 spatial_px=0.6d0
1104 spectral_px=0.02d0
1105 sigma_psf=0.813d0
1106 width_slit=0.6d0
1107 case(211)
1108 ion='Fe XIV'
1109 mass=56
1110 logte=6.3d0
1111 line_center=211.3d0
1112 spatial_px=0.6d0
1113 spectral_px=0.02d0
1114 sigma_psf=0.913d0
1115 width_slit=0.6d0
1116 case(335)
1117 ion='Fe XVI'
1118 mass=56
1119 logte=6.4d0
1120 line_center=335.4d0
1121 spatial_px=0.6d0
1122 spectral_px=0.02d0
1123 sigma_psf=1.019d0
1124 width_slit=0.6d0
1125 case(94)
1126 ion='Fe XVIII'
1127 mass=56
1128 logte=6.8d0
1129 line_center=93.9d0
1130 spatial_px=0.6d0
1131 spectral_px=0.02d0
1132 sigma_psf=1.025d0
1133 width_slit=0.6d0
1134 case(131)
1135 ion='Fe XXI'
1136 mass=56
1137 logte=7.0d0
1138 line_center=131.0d0
1139 spatial_px=0.6d0
1140 spectral_px=0.02d0
1141 sigma_psf=0.984d0
1142 width_slit=0.6d0
1143 case(1354)
1144 ion='Fe XXI'
1145 mass=56
1146 logte=7.0d0
1147 line_center=1354.1d0
1148 spatial_px=0.1663d0
1149 spectral_px=12.98d-3
1150 sigma_psf=1.d0
1151 width_slit=0.33d0
1152 case(263)
1153 ion='Fe XVI'
1154 mass=56
1155 logte=6.4d0
1156 line_center=262.976d0
1157 spatial_px=1.d0
1158 spectral_px=22.d-3
1159 sigma_psf=1.d0
1160 width_slit=2.d0
1161 case(264)
1162 ion='Fe XXIII'
1163 mass=56
1164 logte=7.1d0
1165 line_center=263.765d0
1166 spatial_px=1.d0
1167 spectral_px=22.d-3
1168 sigma_psf=1.d0
1169 width_slit=2.d0
1170 case(192)
1171 ion='Fe XXIV'
1172 mass=56
1173 logte=7.2d0
1174 line_center=192.028d0
1175 spatial_px=1.d0
1176 spectral_px=22.d-3
1177 sigma_psf=1.d0
1178 width_slit=2.d0
1179 case(255)
1180 ion='Fe XXIV'
1181 mass=56
1182 logte=7.2d0
1183 line_center=255.113d0
1184 spatial_px=1.d0
1185 spectral_px=22.d-3
1186 sigma_psf=1.d0
1187 width_slit=2.d0
1188 case default
1189 call mpistop("No information about this line")
1190 end select
1191
1192 spatial_px=spatial_px/instrument_resolution_factor
1193 end subroutine get_line_info
1194
1195 subroutine get_euv(wl,ixI^L,ixO^L,w,x,fl,flux)
1196 ! calculate the local emission intensity of given EUV line (optically thin)
1197 ! wavelength is the wave length of the emission line
1198 ! unit [DN cm^-1 s^-1 pixel^-1]
1199 ! ingrate flux along line of sight: DN s^-1 pixel^-1
1201 use mod_eos, only: eos
1202
1203 integer, intent(in) :: wl
1204 integer, intent(in) :: ixI^L, ixO^L
1205 double precision, intent(in) :: x(ixI^S,1:ndim)
1206 double precision, intent(in) :: w(ixI^S,1:nw)
1207 type(te_fluid), intent(in) :: fl
1208 double precision, intent(out) :: flux(ixI^S)
1209
1210 integer :: ix^D
1211 double precision :: pth(ixI^S),rho(ixI^S),Rfactor(ixI^S),Te(ixI^S)
1212 double precision :: Ne(ixI^S),nH(ixI^S)
1213
1214 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
1215 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
1216 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,rfactor)
1217 te(ixo^s)=pth(ixo^s)/(rho(ixo^s)*rfactor(ixo^s))*unit_temperature
1218
1219 ! The tabulated response is multiplied by the physical emission-measure
1220 ! factor ne*nH. Both densities come from the active EOS so the source
1221 ! remains consistent for FI, PI, and LTE simulations.
1222 call eos%get_ne_nH(ixi^l, ixo^l, w, ne, nh)
1223 if (si_unit) then
1224 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6 ! m^-3 -> cm-3
1225 nh(ixo^s)=nh(ixo^s)*unit_numberdensity/1.d6
1226 else
1227 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
1228 nh(ixo^s)=nh(ixo^s)*unit_numberdensity
1229 endif
1230 flux(ixo^s)=ne(ixo^s)*nh(ixo^s)
1231
1232 select case(wl)
1233 case(94)
1234 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_94,n_aia,.true.,.true.)
1235 case(131)
1236 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_131,n_aia,.true.,.true.)
1237 case(171)
1238 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_171,n_aia,.true.,.true.)
1239 case(193)
1240 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_193,n_aia,.true.,.true.)
1241 case(211)
1242 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_211,n_aia,.true.,.true.)
1243 case(304)
1244 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_304,n_aia,.true.,.true.)
1245 case(335)
1246 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_335,n_aia,.true.,.true.)
1247 case(1354)
1248 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_iris,f_1354,n_iris,.true.,.true.)
1249 case(263)
1250 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_eis1,f_263,n_eis,.false.,.false.)
1251 case(264)
1252 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_eis2,f_264,n_eis,.false.,.false.)
1253 case(192)
1254 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_eis2,f_192,n_eis,.false.,.false.)
1255 case(255)
1256 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_eis2,f_255,n_eis,.false.,.false.)
1257 case default
1258 call mpistop("Unknown wavelength")
1259 end select
1260 end subroutine get_euv
1261
1262 subroutine get_sxr(ixI^L,ixO^L,w,x,fl,flux,El,Eu)
1263 !synthesize thermal SXR from El keV to Eu keV released by cm^-3/m^-3
1264 ! volume of plasma in 1 s
1265 !flux (cgs): photons cm^-3 s^-1
1266 !flux (SI): photons m^-3 s^-1
1268 use mod_eos, only: eos
1269
1270 integer, intent(in) :: ixI^L,ixO^L
1271 integer, intent(in) :: El,Eu
1272 double precision, intent(in) :: x(ixI^S,1:ndim)
1273 double precision, intent(in) :: w(ixI^S,nw)
1274 type(te_fluid), intent(in) :: fl
1275 double precision, intent(out) :: flux(ixI^S)
1276
1277 integer :: ix^D,ixO^D
1278 integer :: iE,numE
1279 double precision :: I0,kb,keV,dE,Ei
1280 double precision :: pth(ixI^S),Te(ixI^S),kbT(ixI^S)
1281 double precision :: Ne(ixI^S),gff(ixI^S),fi(ixI^S)
1282 double precision :: EM(ixI^S)
1283
1284 i0=3.01d-15 ! I0*4*pi*AU**2, I0 from Pinto (2015)
1285 kb=const_kb
1286 kev=1.0d3*const_ev
1287 de=0.1
1288 nume=floor((eu-el)/de)
1289 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
1290 call fl%get_rho(w,x,ixi^l,ixo^l,ne)
1291 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,te)
1292 te(ixo^s)=pth(ixo^s)/(ne(ixo^s)*te(ixo^s))*unit_temperature
1293 ! get actual electron density from EoS (replaces rho with ne)
1294 block
1295 double precision :: nH_dummy(ixI^S)
1296 call eos%get_ne_nH(ixi^l, ixo^l, w, ne, nh_dummy)
1297 end block
1298 if (si_unit) then
1299 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6 ! m^-3 -> cm-3
1300 em(ixo^s)=(ne(ixo^s))**2*1.d6 ! cm^-3 m^-3
1301 else
1302 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
1303 em(ixo^s)=(ne(ixo^s))**2
1304 endif
1305 kbt(ixo^s)=kb*te(ixo^s)/kev
1306 flux(ixo^s)=0.0d0
1307 do ie=0,nume-1
1308 ei=de*ie+el*1.d0
1309 gff(ixo^s)=1.d0
1310 {do ix^db=ixomin^db,ixomax^db\}
1311 if (kbt(ix^d)>0.01*ei) then
1312 if(kbt(ix^d)<ei) gff(ix^d)=(kbt(ix^d)/ei)**0.4
1313 fi(ix^d)=(em(ix^d)*gff(ix^d))*exp_clamped(-ei/(kbt(ix^d)))/(ei*dsqrt(kbt(ix^d)))
1314 else
1315 fi(ix^d)=zero
1316 endif
1317 {enddo\}
1318 flux(ixo^s)=flux(ixo^s)+fi(ixo^s)*de
1319 enddo
1320 flux(ixo^s)=flux(ixo^s)*i0
1321 end subroutine get_sxr
1322
1323 subroutine get_goes_sxr_flux(xbox^L,fl,eflux)
1324 !get GOES SXR 1-8A flux observing at 1AU from given box [w/m^2]
1326
1327 double precision, intent(in) :: xbox^L
1328 type(te_fluid), intent(in) :: fl
1329 double precision, intent(out) :: eflux
1330
1331 double precision :: dxb^D,xb^L
1332 integer :: iigrid,igrid,j
1333 integer :: ixO^L,ixI^L,ix^D
1334 double precision :: eflux_grid,eflux_pe
1335
1336 ^d&iximin^d=ixglo^d;
1337 ^d&iximax^d=ixghi^d;
1338 ^d&ixomin^d=ixmlo^d;
1339 ^d&ixomax^d=ixmhi^d;
1340 eflux_pe=zero
1341 do iigrid=1,igridstail; igrid=igrids(iigrid);
1342 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1343 ^d&xbmin^d=rnode(rpxmin^d_,igrid);
1344 ^d&xbmax^d=rnode(rpxmax^d_,igrid);
1345 call get_goes_flux_grid(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,ps(igrid)%dvolume(ixi^s),xbox^l,xb^l,fl,eflux_grid)
1346 eflux_pe=eflux_pe+eflux_grid
1347 enddo
1348 call mpi_allreduce(eflux_pe,eflux,1,mpi_double_precision,mpi_sum,icomm,ierrmpi)
1349 end subroutine get_goes_sxr_flux
1350
1351 subroutine get_goes_flux_grid(ixI^L,ixO^L,w,x,dV,xbox^L,xb^L,fl,eflux_grid)
1353 use mod_eos, only: eos
1354
1355 integer, intent(in) :: ixI^L,ixO^L
1356 double precision, intent(in) :: x(ixI^S,1:ndim),dV(ixI^S)
1357 double precision, intent(in) :: w(ixI^S,nw)
1358 double precision, intent(in) :: xbox^L,xb^L
1359 type(te_fluid), intent(in) :: fl
1360 double precision, intent(out) :: eflux_grid
1361
1362 integer :: ix^D,ixO^D,ixb^L
1363 integer :: iE,numE,j,inbox
1364 double precision :: I0,kb,keV,dE,Ei,El,Eu,A_cgs
1365 double precision :: pth(ixI^S),Te(ixI^S),kbT(ixI^S)
1366 double precision :: Ne(ixI^S),EM(ixI^S)
1367 double precision :: gff,fi,erg_SI
1368
1369 ! check whether the grid is inside given box
1370 inbox=0
1371 {if (xbmin^d<xboxmax^d .and. xbmax^d>xboxmin^d) inbox=inbox+1\}
1372
1373 if (inbox==ndim) then
1374 ! indexes for cells inside given box
1375 ^d&ixbmin^d=ixomin^d;
1376 ^d&ixbmax^d=ixomax^d;
1377 {if (xbmax^d>xboxmax^d) ixbmax^d=ixomax^d-ceiling((xbmax^d-xboxmax^d)/dxlevel(^d))\}
1378 {if (xbmin^d<xboxmin^d) ixbmin^d=ceiling((xboxmin^d-xbmin^d)/dxlevel(^d))+ixomin^d\}
1379
1380 i0=1.07d-38 ! photon flux index for observed at 1AU [photon cm^3 m^-2 s^-1 keV^-1]
1381 kb=const_kb
1382 kev=1.0d3*const_ev
1383 erg_si=1.d-7
1384 a_cgs=1.d-8 ! Angstrom
1385 el=const_h*const_c/(8.d0*a_cgs)/kev ! 8 A
1386 eu=const_h*const_c/(1.d0*a_cgs)/kev ! 1 A
1387 de=0.1 ! keV
1388 nume=floor((eu-el)/de)
1389 call fl%get_pthermal(w,x,ixi^l,ixb^l,pth)
1390 call fl%get_rho(w,x,ixi^l,ixb^l,ne)
1391 call fl%get_var_Rfactor(w,x,ixi^l,ixb^l,te)
1392 te(ixb^s)=pth(ixb^s)/(ne(ixb^s)*te(ixb^s))*unit_temperature
1393 ! get actual electron density from EoS (replaces rho with ne)
1394 block
1395 double precision :: nH_dummy(ixI^S)
1396 call eos%get_ne_nH(ixi^l, ixb^l, w, ne, nh_dummy)
1397 end block
1398 if (si_unit) then
1399 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6 ! m^-3 -> cm-3
1400 em(ixb^s)=(i0*(ne(ixb^s))**2)*dv(ixb^s)*(unit_length*1.d2)**3 ! cm^-3
1401 else
1402 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
1403 em(ixb^s)=(i0*(ne(ixb^s))**2)*dv(ixb^s)*unit_length**3
1404 endif
1405 kbt(ixb^s)=kb*te(ixb^s)/kev
1406 eflux_grid=0.0d0
1407
1408 do ie=0,nume-1
1409 ei=de*ie+el
1410 {do ix^db=ixbmin^db,ixbmax^db\}
1411 if (kbt(ix^d)>1.d-2*ei) then
1412 if(kbt(ix^d)<ei) then
1413 gff=(kbt(ix^d)/ei)**0.4
1414 else
1415 gff=1.d0
1416 endif
1417 fi=(em(ix^d)*gff)*exp_clamped(-ei/(kbt(ix^d)))/(ei*dsqrt(kbt(ix^d)))
1418 eflux_grid=eflux_grid+fi*de*ei
1419 endif
1420 {enddo\}
1421 enddo
1422 eflux_grid=eflux_grid*kev*erg_si
1423 endif
1424
1425 end subroutine get_goes_flux_grid
1426
1427 {^ifthreed
1428 subroutine get_euv_spectrum(qunit,fl)
1430
1431 integer, intent(in) :: qunit
1432 type(te_fluid), intent(in) :: fl
1433 character(20) :: datatype
1434
1435 integer :: mass
1436 character (30) :: ion
1437 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
1438 double precision :: xslit,arcsec
1439
1440 datatype='spectrum_euv'
1442 arcsec=7.25d7/unit_length
1443 call get_line_info(spectrum_wl,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
1444
1445 if (mype==0) print *, '###################################################'
1446 select case(spectrum_wl)
1447 case (1354)
1448 if (mype==0) print *, 'Systhesizing EUV spectrum (observed by IRIS).'
1449 case (263,264,192,255)
1450 if (mype==0) print *, 'Systhesizing EUV spectrum (observed by Hinode/EIS).'
1451 case default
1452 call mpistop('Wrong wavelength!')
1453 end select
1454
1456 call mpistop('Wrong spectrum window!')
1457 endif
1458
1459 if (mype==0) write(*,'(a,f8.3,a)') ' Wavelength: ',linecent,' Angstrom'
1460 if (mype==0) print *, 'Unit of EUV flux: DN s^-1 pixel^-1'
1461
1462 if (dat_resolution) then
1463 if (mype==0) then
1464 write(*,'(a,f5.3,a,f5.1,a)') ' Supposed pixel: ',wlrsl,' Angstrom x ',spacersl*725.0, ' km'
1465 print *, 'Unit of wavelength: Angstrom (0.1 nm) '
1466 if (si_unit) then
1467 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
1468 else
1469 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
1470 endif
1471 write(*,'(a,f8.1,a)') ' Supposed width of slit: ',wslit*725.0,' km'
1472 endif
1473 call get_spectrum_datresol(qunit,datatype,fl)
1474 else
1475 if (mype==0) then
1476 print *, 'Unit of wavelength: Angstrom (0.1 nm) '
1477 if (activate_unit_arcsec) then
1478 write(*,'(a,f5.3,a,f5.1,a)') ' Pixel: ',wlrsl,' Angstrom x ',spacersl*725.0, ' km'
1479 print *, 'Unit of length: arcsec (~725 km)'
1480 write(*,'(a,f8.1,a)') ' Location of slit: xI1 = ',location_slit,' arcsec'
1481 write(*,'(a,f8.1,a)') ' Width of slit: ',wslit,' arcsec'
1482 else
1483 if (si_unit) then
1484 if (mype==0) write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
1485 else
1486 if (mype==0) write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
1487 endif
1488 write(*,'(a,f8.1,a)') ' Location of slit: xI1 = ',location_slit,' Unit_length'
1489 write(*,'(a,f8.1,a)') ' Width of slit: ',wslit*725.d0,' km'
1490 endif
1491 endif
1492 if (mype==0) print *, 'Direction of the slit: parallel to xI2 vector'
1493 if (coordinate==cartesian .or. coordinate==spherical) then
1494 call get_spectrum(qunit,datatype,fl)
1495 else
1496 call mpistop("EUV spectrum synthesis: support for sperical coordinates is to be added!")
1497 endif
1498 endif
1499
1500 if (mype==0) print *, '###################################################'
1501
1502 end subroutine get_euv_spectrum
1503
1504 subroutine get_spectrum_datresol(qunit,datatype,fl)
1505
1506 integer, intent(in) :: qunit
1507 character(20), intent(in) :: datatype
1508 type(te_fluid), intent(in) :: fl
1509
1510 integer :: numWL,numXS,iwL,ixS,numWI,numS
1511 double precision :: dwLg,xSmin,xSmax,wLmin,wLmax
1512 double precision, allocatable :: wL(:),xS(:),dwL(:),dxS(:)
1513 double precision, allocatable :: wI(:,:,:),spectra(:,:),spectra_rc(:,:)
1514 integer :: strtype,nstrb,nbb,nuni,nstr,bnx
1515 double precision :: qs,dxfirst,dxmid,lenstr
1516
1517 integer :: iigrid,igrid,j,dir_loc
1518 double precision :: xbmin(1:ndim),xbmax(1:ndim)
1519
1520 dwlg=1.d-3
1521 numwl=4*int((spectrum_window_max-spectrum_window_min)/(4.d0*dwlg))
1522 wlmin=(spectrum_window_max+spectrum_window_min)/2.d0-dwlg*numwl/2
1523 wlmax=(spectrum_window_max+spectrum_window_min)/2.d0+dwlg*numwl/2
1524 allocate(wl(numwl),dwl(numwl))
1525 dwl(:)=dwlg
1526 do iwl=1,numwl
1527 wl(iwl)=wlmin+iwl*dwlg-half*dwlg
1528 enddo
1529
1530 select case(direction_slit)
1531 case (1)
1532 numxs=domain_nx1*2**(refine_max_level-1)
1533 xsmin=xprobmin1
1534 xsmax=xprobmax1
1535 bnx=block_nx1
1536 nbb=domain_nx1
1537 strtype=stretch_type(1)
1538 nstrb=nstretchedblocks_baselevel(1)
1539 qs=qstretch_baselevel(1)
1540 if (mype==0) print *, 'Direction of the slit: x'
1541 case (2)
1542 numxs=domain_nx2*2**(refine_max_level-1)
1543 xsmin=xprobmin2
1544 xsmax=xprobmax2
1545 bnx=block_nx2
1546 nbb=domain_nx2
1547 strtype=stretch_type(2)
1548 nstrb=nstretchedblocks_baselevel(2)
1549 qs=qstretch_baselevel(2)
1550 if (mype==0) print *, 'Direction of the slit: y'
1551 case (3)
1552 numxs=domain_nx3*2**(refine_max_level-1)
1553 xsmin=xprobmin3
1554 xsmax=xprobmax3
1555 bnx=block_nx3
1556 nbb=domain_nx3
1557 strtype=stretch_type(3)
1558 nstrb=nstretchedblocks_baselevel(3)
1559 qs=qstretch_baselevel(3)
1560 if (mype==0) print *, 'Direction of the slit: z'
1561 case default
1562 call mpistop('Wrong direction_slit')
1563 end select
1564
1565 allocate(xs(numxs),dxs(numxs),spectra(numwl,numxs),spectra_rc(numwl,numxs))
1566 numwi=1
1567 allocate(wi(numwl,numxs,numwi))
1568
1569 select case(strtype)
1570 case(0) ! uniform
1571 dxs(:)=(xsmax-xsmin)/numxs
1572 do ixs=1,numxs
1573 xs(ixs)=xsmin+dxs(ixs)*(ixs-half)
1574 enddo
1575 case(1) ! uni stretch
1576 qs=qs**(one/2**(refine_max_level-1))
1577 dxfirst=(xsmax-xsmin)*(one-qs)/(one-qs**numxs)
1578 dxs(1)=dxfirst
1579 do ixs=2,numxs
1580 dxs(ixs)=dxfirst*qs**(ixs-1)
1581 xs(ixs)=dxs(1)/(one-qs)*(one-qs**(ixs-1))+half*dxs(ixs)
1582 enddo
1583 case(2) ! symm stretch
1584 ! base level, nbb = nstr + nuni + nstr
1585 nstr=nstrb*bnx/2
1586 nuni=nbb-nstrb*bnx
1587 lenstr=(xsmax-xsmin)/(2.d0+nuni*(one-qs)/(one-qs**nstr))
1588 dxfirst=(xsmax-xsmin)/(dble(nuni)+2.d0/(one-qs)*(one-qs**nstr))
1589 dxmid=dxfirst
1590 ! refine_max level, numXI = nstr + nuni + nstr
1591 nstr=nstr*2**(refine_max_level-1)
1592 nuni=nuni*2**(refine_max_level-1)
1593 qs=qs**(one/2**(refine_max_level-1))
1594 dxfirst=lenstr*(one-qs)/(one-qs**nstr)
1595 dxmid=dxmid/2**(refine_max_level-1)
1596 ! uniform center
1597 if(nuni .gt. 0) then
1598 do ixs=nstr+1,nstr+nuni
1599 dxs(ixs)=dxmid
1600 xs(ixs)=lenstr+(dble(ixs)-0.5d0-nstr)*dxs(ixs)+xsmin
1601 enddo
1602 endif
1603 ! left half
1604 do ixs=nstr,1,-1
1605 dxs(ixs)=dxfirst*qs**(nstr-ixs)
1606 xs(ixs)=xsmin+lenstr-dxs(ixs)*half-dxfirst*(one-qs**(nstr-ixs))/(one-qs)
1607 enddo
1608 ! right half
1609 do ixs=nstr+nuni+1,numxs
1610 dxs(ixs)=dxfirst*qs**(ixs-nstr-nuni-1)
1611 xs(ixs)=xsmax-lenstr+dxs(ixs)*half+dxfirst*(one-qs**(ixs-nstr-nuni-1))/(one-qs)
1612 enddo
1613 case default
1614 call mpistop("unknown stretch type")
1615 end select
1616
1617 if (los_phi==0 .and. los_theta==90 .and. direction_slit==2) then
1618 ! LOS->x slit->y
1619 dir_loc=3
1620 else if (los_phi==0 .and. los_theta==90 .and. direction_slit==3) then
1621 ! LOS->x slit->z
1622 dir_loc=2
1623 else if (los_phi==90 .and. los_theta==90 .and. direction_slit==1) then
1624 ! LOS->y slit->x
1625 dir_loc=3
1626 else if (los_phi==90 .and. los_theta==90 .and. direction_slit==3) then
1627 ! LOS->y slit->z
1628 dir_loc=1
1629 else if (los_theta==0 .and. direction_slit==1) then
1630 ! LOS->z slit->x
1631 dir_loc=2
1632 else if (los_theta==0 .and. direction_slit==2) then
1633 ! LOS->z slit->y
1634 dir_loc=1
1635 else
1636 call mpistop('Wrong combination of LOS and slit direction!')
1637 endif
1638
1639 if (dir_loc==1) then
1640 if (location_slit>xprobmax1 .or. location_slit<xprobmin1) then
1641 call mpistop('Wrong value for location_slit!')
1642 endif
1643 if(mype==0) write(*,'(a,f8.1,a)') ' Location of slit: x = ',location_slit,' Unit_length'
1644 else if (dir_loc==2) then
1645 if (location_slit>xprobmax2 .or. location_slit<xprobmin2) then
1646 call mpistop('Wrong value for location_slit!')
1647 endif
1648 if(mype==0) write(*,'(a,f8.1,a)') ' Location of slit: y = ',location_slit,' Unit_length'
1649 else
1650 if (location_slit>xprobmax3 .or. location_slit<xprobmin3) then
1651 call mpistop('Wrong value for location_slit!')
1652 endif
1653 if(mype==0) write(*,'(a,f8.1,a)') ' Location of slit: z = ',location_slit,' Unit_length'
1654 endif
1655
1656 ! find slit and do integration
1657 spectra=zero
1658 do iigrid=1,igridstail; igrid=igrids(iigrid);
1659 ^d&xbmin(^d)=rnode(rpxmin^d_,igrid);
1660 ^d&xbmax(^d)=rnode(rpxmax^d_,igrid);
1661 if (location_slit>=xbmin(dir_loc) .and. location_slit<xbmax(dir_loc)) then
1662 call integrate_spectra_datresol(igrid,wl,dwl,spectra,numwl,numxs,dir_loc,fl)
1663 endif
1664 enddo
1665
1666 nums=numwl*numxs
1667 call mpi_allreduce(spectra,spectra_rc,nums,mpi_double_precision, &
1668 mpi_sum,icomm,ierrmpi)
1669 do iwl=1,numwl
1670 do ixs=1,numxs
1671 if (spectra_rc(iwl,ixs)>smalldouble) then
1672 wi(iwl,ixs,1)=spectra_rc(iwl,ixs)
1673 else
1674 wi(iwl,ixs,1)=zero
1675 endif
1676 enddo
1677 enddo
1678
1679 call output_data(qunit,wl,xs,dwl,dxs,wi,numwl,numxs,numwi,datatype)
1680
1681 deallocate(wl,xs,dwl,dxs,spectra,spectra_rc,wi)
1682
1683 end subroutine get_spectrum_datresol
1684
1685 subroutine integrate_spectra_datresol(igrid,wL,dwL,spectra,numWL,numXS,dir_loc,fl)
1686 use mod_constants
1687
1688 integer, intent(in) :: igrid,numWL,numXS,dir_loc
1689 type(te_fluid), intent(in) :: fl
1690 double precision, intent(in) :: wL(numWL),dwL(numWL)
1691 double precision, intent(inout) :: spectra(numWL,numXS)
1692
1693 integer :: direction_LOS
1694 integer :: ixO^L,ixI^L,ix^D,ixOnew
1695 double precision, allocatable :: flux(:^D&),v(:^D&),pth(:^D&),Te(:^D&),rho(:^D&)
1696 double precision :: wlc,wlwd
1697
1698 integer :: mass
1699 double precision :: logTe,lineCent
1700 character (30) :: ion
1701 double precision :: spaceRsl,wlRsl,sigma_PSF,wslit
1702
1703 integer :: levelg,rft,ixSmin,ixSmax,iwL
1704 double precision :: flux_pix,dL
1705
1706 call get_line_info(spectrum_wl,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
1707
1708 if (los_phi==0 .and. los_theta==90) then
1709 direction_los=1
1710 else if (los_phi==90 .and. los_theta==90) then
1711 direction_los=2
1712 else
1713 direction_los=3
1714 endif
1715
1716 ^d&ixomin^d=ixmlo^d\
1717 ^d&ixomax^d=ixmhi^d\
1718 ^d&iximin^d=ixglo^d\
1719 ^d&iximax^d=ixghi^d\
1720 allocate(flux(ixi^s),v(ixi^s),pth(ixi^s),te(ixi^s),rho(ixi^s))
1721
1722 ^d&ix^d=ixomin^d;
1723 if (dir_loc==1) then
1724 do ix1=ixomin1,ixomax1
1725 if (location_slit>=(ps(igrid)%x(ix^d,1)-half*ps(igrid)%dx(ix^d,1)) .and. &
1726 location_slit<(ps(igrid)%x(ix^d,1)+half*ps(igrid)%dx(ix^d,1))) then
1727 ixonew=ix1
1728 endif
1729 enddo
1730 ixomin1=ixonew
1731 ixomax1=ixonew
1732 else if (dir_loc==2) then
1733 do ix2=ixomin2,ixomax2
1734 if (location_slit>=(ps(igrid)%x(ix^d,2)-half*ps(igrid)%dx(ix^d,2)) .and. &
1735 location_slit<(ps(igrid)%x(ix^d,2)+half*ps(igrid)%dx(ix^d,2))) then
1736 ixonew=ix2
1737 endif
1738 enddo
1739 ixomin2=ixonew
1740 ixomax2=ixonew
1741 else
1742 do ix3=ixomin3,ixomax3
1743 if (location_slit>=(ps(igrid)%x(ix^d,3)-half*ps(igrid)%dx(ix^d,3)) .and. &
1744 location_slit<(ps(igrid)%x(ix^d,3)+half*ps(igrid)%dx(ix^d,3))) then
1745 ixonew=ix3
1746 endif
1747 enddo
1748 ixomin3=ixonew
1749 ixomax3=ixonew
1750 endif
1751
1752 call get_euv(spectrum_wl,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
1753 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
1754 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
1755 v(ixo^s)=-ps(igrid)%w(ixo^s,iw_mom(direction_los))/rho(ixo^s)
1756 call fl%get_pthermal(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,pth)
1757 call fl%get_var_Rfactor(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,te)
1758 te(ixo^s)=pth(ixo^s)/(te(ixo^s)*rho(ixo^s))
1759
1760 ! grid parameters
1761 levelg=ps(igrid)%level
1762 rft=2**(refine_max_level-levelg)
1763
1764 {do ix^d=ixomin^d,ixomax^d\}
1765 if (flux(ix^d)>smalldouble) then
1766 if (si_unit) then
1767 wlc=linecent*(1.d0+v(ix^d)*unit_velocity*1.d2/const_c)
1768 else
1769 wlc=linecent*(1.d0+v(ix^d)*unit_velocity/const_c)
1770 endif
1771 wlwd=sqrt(kb_cgs*te(ix^d)*unit_temperature/(mass*mp_cgs))
1772 wlwd=wlwd*linecent/const_c
1773 ! involved pixel
1774 select case(direction_slit)
1775 case(1)
1776 ixsmin=(block_nx1*(node(pig1_,igrid)-1)+(ix1-ixomin1))*rft+1
1777 ixsmax=(block_nx1*(node(pig1_,igrid)-1)+(ix1-ixomin1+1))*rft
1778 case(2)
1779 ixsmin=(block_nx2*(node(pig2_,igrid)-1)+(ix2-ixomin2))*rft+1
1780 ixsmax=(block_nx2*(node(pig2_,igrid)-1)+(ix2-ixomin2+1))*rft
1781 case(3)
1782 ixsmin=(block_nx3*(node(pig3_,igrid)-1)+(ix3-ixomin3))*rft+1
1783 ixsmax=(block_nx3*(node(pig3_,igrid)-1)+(ix3-ixomin3+1))*rft
1784 end select
1785 ! LOS depth
1786 select case(direction_los)
1787 case(1)
1788 dl=ps(igrid)%dx(ix^d,1)*unit_length
1789 case(2)
1790 dl=ps(igrid)%dx(ix^d,2)*unit_length
1791 case default
1792 dl=ps(igrid)%dx(ix^d,3)*unit_length
1793 end select
1794 if (si_unit) dl=dl*1.d2
1795 ! integral pixel flux
1796 do iwl=1,numwl
1797 flux_pix=flux(ix^d)*wlrsl*dl*exp_clamped(-(wl(iwl)-wlc)**2/(2*wlwd**2))/(sqrt(2*dpi)*wlwd)
1798 if (flux_pix>smalldouble) then
1799 flux_pix=flux_pix*wslit/spacersl
1800 spectra(iwl,ixsmin:ixsmax)=spectra(iwl,ixsmin:ixsmax)+flux_pix
1801 endif
1802 enddo
1803 endif
1804 {enddo\}
1805
1806 deallocate(flux,v,pth,te,rho)
1807
1808 end subroutine integrate_spectra_datresol
1809
1810 subroutine get_spectrum(qunit,datatype,fl)
1811
1812 integer, intent(in) :: qunit
1813 character(20), intent(in) :: datatype
1814 type(te_fluid), intent(in) :: fl
1815
1816 integer :: numWL,numXS,iwL,ixS,numWI,ix^D
1817 double precision :: dwLg,dxSg,xSmin,xSmax,xScent,wLmin,wLmax
1818 double precision, allocatable :: wL(:),xS(:),dwL(:),dxS(:)
1819 double precision, allocatable :: wI(:,:,:),spectra(:,:),spectra_rc(:,:)
1820 double precision :: vec_cor(1:3),xI_cor(1:2)
1821 double precision :: res,r_loc,r_max
1822
1823 integer :: mass
1824 character (30) :: ion
1825 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
1826 double precision :: unitv,arcsec,RHESSI_rsl,pixel
1827 integer :: iigrid,igrid,i,j,numS
1828 double precision :: xLmin,xLmax,xslit
1829
1830 if (coordinate==spherical) then
1832 else
1833 ! cartesian
1835 endif
1836
1837 ! calculate domain in space
1838 if (coordinate==spherical) then
1839 xsmin=-abs(xprobmax1)
1840 xsmax=abs(xprobmax1)
1841 else
1842 do ix1=1,2
1843 if (ix1==1) vec_cor(1)=xprobmin1
1844 if (ix1==2) vec_cor(1)=xprobmax1
1845 do ix2=1,2
1846 if (ix2==1) vec_cor(2)=xprobmin2
1847 if (ix2==2) vec_cor(2)=xprobmax2
1848 do ix3=1,2
1849 if (ix3==1) vec_cor(3)=xprobmin3
1850 if (ix3==2) vec_cor(3)=xprobmax3
1851 if (big_image) then
1852 r_loc=(vec_cor(1)-x_origin(1))**2
1853 r_loc=r_loc+(vec_cor(2)-x_origin(2))**2
1854 r_loc=r_loc+(vec_cor(3)-x_origin(3))**2
1855 r_loc=sqrt(r_loc)
1856 if (ix1==1 .and. ix2==1 .and. ix3==1) then
1857 r_max=r_loc
1858 else
1859 r_max=max(r_max,r_loc)
1860 endif
1861 else
1862 call get_cor_image(vec_cor,xi_cor)
1863 if (ix1==1 .and. ix2==1 .and. ix3==1) then
1864 xsmin=xi_cor(2)
1865 xsmax=xi_cor(2)
1866 else
1867 xsmin=min(xsmin,xi_cor(2))
1868 xsmax=max(xsmax,xi_cor(2))
1869 endif
1870 endif
1871 enddo
1872 enddo
1873 enddo
1874 if (big_image) then
1875 xsmin=-r_max
1876 xsmax=r_max
1877 endif
1878 endif
1879 xscent=(xsmin+xsmax)/2.d0
1880
1881 ! tables for storing spectra data
1882 if (si_unit) then
1883 arcsec=7.25d5/unit_length
1884 else
1885 arcsec=7.25d7/unit_length
1886 endif
1887 call get_line_info(spectrum_wl,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
1888 dxsg=spacersl*arcsec
1889 numxs=ceiling((xsmax-xscent)/dxsg)
1890 xsmin=xscent-numxs*dxsg
1891 xsmax=xscent+numxs*dxsg
1892 numxs=numxs*2
1893 dwlg=wlrsl
1894 numwl=2*int((spectrum_window_max-spectrum_window_min)/(2.d0*dwlg))
1895 wlmin=(spectrum_window_max+spectrum_window_min)/2.d0-dwlg*numwl/2
1896 wlmax=(spectrum_window_max+spectrum_window_min)/2.d0+dwlg*numwl/2
1897 allocate(wl(numwl),dwl(numwl),xs(numxs),dxs(numxs))
1898 numwi=1
1899 allocate(wi(numwl,numxs,numwi),spectra(numwl,numxs),spectra_rc(numwl,numxs))
1900 do iwl=1,numwl
1901 wl(iwl)=wlmin+iwl*dwlg-half*dwlg
1902 dwl=dwlg
1903 enddo
1904 do ixs=1,numxs
1905 xs(ixs)=xsmin+dxsg*(ixs-half)
1906 dxs(ixs)=dxsg
1907 enddo
1908
1909 ! find slit and do integration
1910 spectra=zero
1911 do iigrid=1,igridstail; igrid=igrids(iigrid);
1912 do ix1=1,2
1913 if (ix1==1) vec_cor(1)=rnode(rpxmin1_,igrid)
1914 if (ix1==2) vec_cor(1)=rnode(rpxmax1_,igrid)
1915 do ix2=1,2
1916 if (ix2==1) vec_cor(2)=rnode(rpxmin2_,igrid)
1917 if (ix2==2) vec_cor(2)=rnode(rpxmax2_,igrid)
1918 do ix3=1,2
1919 if (ix3==1) vec_cor(3)=rnode(rpxmin3_,igrid)
1920 if (ix3==2) vec_cor(3)=rnode(rpxmax3_,igrid)
1921 call get_cor_image(vec_cor,xi_cor)
1922 if (ix1==1 .and. ix2==1 .and. ix3==1) then
1923 xlmin=xi_cor(1)
1924 xlmax=xi_cor(1)
1925 else
1926 xlmin=min(xlmin,xi_cor(1))
1927 xlmax=max(xlmax,xi_cor(1))
1928 endif
1929 enddo
1930 enddo
1931 enddo
1932
1933 if (activate_unit_arcsec) then
1934 xslit=location_slit*arcsec
1935 else
1936 xslit=location_slit
1937 endif
1938 if (xslit>=xlmin-wslit*arcsec .and. xslit<=xlmax+wslit*arcsec) then
1939 call integrate_spectra_cartesian(igrid,wl,dwlg,xs,dxsg,spectra,numwl,numxs,fl)
1940 endif
1941 enddo
1942
1943 nums=numwl*numxs
1944 call mpi_allreduce(spectra,spectra_rc,nums,mpi_double_precision, &
1945 mpi_sum,icomm,ierrmpi)
1946 do iwl=1,numwl
1947 do ixs=1,numxs
1948 if (spectra_rc(iwl,ixs)>smalldouble) then
1949 wi(iwl,ixs,1)=spectra_rc(iwl,ixs)
1950 else
1951 wi(iwl,ixs,1)=zero
1952 endif
1953 enddo
1954 enddo
1955
1956 if (activate_unit_arcsec) then
1957 xs=xs/arcsec
1958 dxs=dxs/arcsec
1959 endif
1960
1961 call output_data(qunit,wl,xs,dwl,dxs,wi,numwl,numxs,numwi,datatype)
1962
1963 deallocate(wl,xs,dwl,dxs,spectra,spectra_rc,wi)
1964
1965 end subroutine get_spectrum
1966
1967 subroutine integrate_spectra_cartesian(igrid,wL,dwLg,xS,dxSg,spectra,numWL,numXS,fl)
1968
1969 integer, intent(in) :: igrid,numWL,numXS
1970 double precision, intent(in) :: wL(numWL),xS(numXS)
1971 double precision, intent(in) :: dwLg,dxSg
1972 double precision, intent(inout) :: spectra(numWL,numXS)
1973 type(te_fluid), intent(in) :: fl
1974
1975 integer :: ixO^L,ixI^L,ix^D,ixOnew,j
1976 double precision, allocatable :: flux(:^D&),v(:^D&),pth(:^D&),Te(:^D&),rho(:^D&)
1977 double precision :: wlc,wlwd,res,dst_slit,xslit,arcsec
1978 double precision :: vloc(1:3),xloc(1:3),dxloc(1:3),xIloc(1:2),dxIloc(1:2)
1979 integer :: nSubC^D,iSubC^D,iwL,ixS,ixSmin,ixSmax,iwLmin,iwLmax,nwL
1980 double precision :: slit_width,dxSubC^D,xerf^L,fluxSubC
1981 double precision :: xSubC(1:3),xCent(1:2)
1982
1983 integer :: mass
1984 double precision :: logTe,lineCent
1985 character (30) :: ion
1986 double precision :: spaceRsl,wlRsl,sigma_PSF,wslit
1987 double precision :: sigma_wl,sigma_xs,factor
1988
1989 if (si_unit) then
1990 arcsec=7.25d5/unit_length
1991 else
1992 arcsec=7.25d7/unit_length
1993 endif
1994 if (activate_unit_arcsec) then
1995 xslit=location_slit*arcsec
1996 else
1997 xslit=location_slit
1998 endif
1999
2000 call get_line_info(spectrum_wl,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
2001
2002 ^d&ixomin^d=ixmlo^d\
2003 ^d&ixomax^d=ixmhi^d\
2004 ^d&iximin^d=ixglo^d\
2005 ^d&iximax^d=ixghi^d\
2006 allocate(flux(ixi^s),v(ixi^s),pth(ixi^s),te(ixi^s),rho(ixi^s))
2007 ! get local EUV flux and velocity
2008 call get_euv(spectrum_wl,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
2009 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
2010 call fl%get_pthermal(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,pth)
2011 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
2012 call fl%get_var_Rfactor(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,te)
2013 te(ixo^s)=pth(ixo^s)/(te(ixo^s)*rho(ixo^s))
2014 {do ix^d=ixomin^d,ixomax^d\}
2015 do j=1,3
2016 vloc(j)=ps(igrid)%w(ix^d,iw_mom(j))/rho(ix^d)
2017 enddo
2018 call dot_product_loc(vloc,vec_los,res)
2019 v(ix^d)=res
2020 {enddo\}
2021
2022 deallocate(rho)
2023
2024 slit_width=wslit*arcsec
2025 sigma_wl=sigma_psf*dwlg
2026 sigma_xs=sigma_psf*dxsg
2027 {do ix^d=ixomin^d,ixomax^d\}
2028 if (flux(ix^d)>smalldouble) then
2029 xloc(1:3)=ps(igrid)%x(ix^d,1:3)
2030 dxloc(1:3)=ps(igrid)%dx(ix^d,1:3)
2031 call get_cor_image(xloc,xiloc)
2032 call dot_product_loc(dxloc,vec_xi1,res)
2033 dxiloc(1)=abs(res)
2034 if (xiloc(1)>=xslit-half*(slit_width+dxiloc(1)) .and. &
2035 xiloc(1)<=xslit+half*(slit_width+dxiloc(1))) then
2036 ^d&nsubc^d=1;
2037 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi1(^d))/(slit_width/16.d0)));
2038 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi2(^d))/(dxsg/4.d0)));
2039 ^d&dxsubc^d=ps(igrid)%dx(ix^dd,^d)/nsubc^d;
2040 ! local line center and line width
2041 if (si_unit) then
2042 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length*1.d2/dxsg/dxsg ! DN s^-1
2043 wlc=linecent*(1.d0+v(ix^d)*unit_velocity*1.d2/const_c)
2044 else
2045 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length/dxsg/dxsg ! DN s^-1
2046 wlc=linecent*(1.d0+v(ix^d)*unit_velocity/const_c)
2047 endif
2048 wlwd=sqrt(kb_cgs*te(ix^d)*unit_temperature/(mass*mp_cgs))
2049 wlwd=wlwd*linecent/const_c
2050 ! dividing a cell to several parts to get more accurate integrating values
2051 {do isubc^d=1,nsubc^d\}
2052 ^d&xsubc(^d)=xloc(^d)-half*dxloc(^d)+(isubc^d-half)*dxsubc^d;
2053 call get_cor_image(xsubc,xcent)
2054 dst_slit=abs(xcent(1)-xslit) ! space distance to slit center
2055 if (dst_slit<=half*slit_width) then
2056 ixs=floor((xcent(2)-(xs(1)-half*dxsg))/dxsg)+1
2057 ixsmin=max(1,ixs-3)
2058 ixsmax=min(ixs+3,numxs)
2059 iwl=floor((wlc-(wl(1)-half*dwlg))/dwlg)+1
2060 nwl=3*ceiling(wlwd/dwlg+1)
2061 iwlmin=max(1,iwl-nwl)
2062 iwlmax=min(iwl+nwl,numwl)
2063 ! calculate the contribution to nearby pixels
2064 do iwl=iwlmin,iwlmax
2065 do ixs=ixsmin,ixsmax
2066 xerfmin1=(wl(iwl)-half*dwlg-wlc)/sqrt(2.d0*(sigma_wl**2+wlwd**2))
2067 xerfmax1=(wl(iwl)+half*dwlg-wlc)/sqrt(2.d0*(sigma_wl**2+wlwd**2))
2068 xerfmin2=(xs(ixs)-half*dxsg-xcent(2))/(sqrt(2.d0)*sigma_xs)
2069 xerfmax2=(xs(ixs)+half*dxsg-xcent(2))/(sqrt(2.d0)*sigma_xs)
2070 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
2071 spectra(iwl,ixs)=spectra(iwl,ixs)+fluxsubc*factor
2072 enddo
2073 enddo
2074 ! nearby pixels
2075 endif
2076 {enddo\}
2077 endif
2078 endif
2079 {enddo\}
2080
2081 deallocate(flux,v,pth,te)
2082 end subroutine integrate_spectra_cartesian
2083 }
2084
2085 {^ifthreed
2086 subroutine get_euv_image(qunit,fl)
2088
2089 integer, intent(in) :: qunit
2090 type(te_fluid), intent(in) :: fl
2091 character(20) :: datatype
2092
2093 integer :: mass
2094 character (30) :: ion
2095 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
2096 double precision :: t0,t1
2097
2098 t0=mpi_wtime()
2099 datatype='image_euv'
2101 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
2102
2103 if (mype==0) then
2104 print *, '###################################################'
2105 print *, 'Systhesizing EUV image'
2106 write(*,'(a,f8.3,a)') ' Wavelength: ',linecent,' Angstrom'
2107 print *, 'Unit of EUV flux: DN s^-1 pixel^-1'
2108 endif
2109
2110 if (dat_resolution) then
2111 if (.not. slab .and. .not. (coordinate==spherical .and. trim(ray_method_active)=='spherical')) &
2112 call mpistop('EUV dat-resolution needs Cartesian or spherical native rays')
2113 if (mype==0) then
2114 print *, 'Data-resolution image requested; native output pixel sizes are reported below.'
2115 if (si_unit) then
2116 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2117 else
2118 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2119 endif
2120 endif
2121 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') then
2122 call get_image_datresol(qunit,datatype,fl)
2123 else if (trim(ray_method_active)=='cart') then
2124 call get_image_datresol(qunit,datatype,fl)
2125 else if (los_phi==0 .and. los_theta==90) then
2126 call get_image_datresol(qunit,datatype,fl)
2127 else if (los_phi==90 .and. los_theta==90) then
2128 call get_image_datresol(qunit,datatype,fl)
2129 else if (los_theta==0) then
2130 call get_image_datresol(qunit,datatype,fl)
2131 else
2132 call mpistop('ERROR: Wrong LOS for synthesizing emission!')
2133 endif
2134 else
2135 if (mype==0) then
2136 write(*,'(a,f7.1,a,f7.1,a,f5.1,a,f5.1,a)') ' Pixel: ',spacersl*725.0,' km x ',spacersl*725.0, ' km (', &
2137 spacersl, ' arcsec x ', spacersl, ' arcsec)'
2138 if (activate_unit_arcsec) then
2139 print *, 'Unit of length: arcsec (~725 km)'
2140 else
2141 if (si_unit) then
2142 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2143 else
2144 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2145 endif
2146 endif
2147 endif
2148 if (slab) then
2149 if (mype==0) write(*,'(a,f8.3,f8.3,f8.3,a)') ' Mapping: [',x_origin(1),x_origin(2),x_origin(3), &
2150 '] of the simulation box is located at [X=0,Y=0] of the image'
2151 call get_image(qunit,datatype,fl)
2152 else if (coordinate==spherical) then
2153 if (mype==0) write(*,'(a,f6.3,f8.3,f8.3,a)') ' Mapping: R=0 of the simulation box is located at [X=0,Y=0] of the image'
2154 call get_image(qunit,datatype,fl)
2155 else
2156 call mpistop("EUV synthesis: this coordinate is not supported!")
2157 endif
2158 endif
2159
2160 t1=mpi_wtime()
2161 if (mype==0) print *, 'time comsuming: ',t1-t0,' s'
2162 if (mype==0) print *, '###################################################'
2163
2164 end subroutine get_euv_image
2165
2166 subroutine get_sxr_image(qunit,fl)
2168
2169 integer, intent(in) :: qunit
2170 type(te_fluid), intent(in) :: fl
2171 character(20) :: datatype
2172 double precision :: RHESSI_rsl
2173 double precision :: t0,t1
2174
2175 t0=mpi_wtime()
2176 datatype='image_sxr'
2178 rhessi_rsl=2.3/instrument_resolution_factor
2179
2180 if (mype==0) then
2181 print *, '###################################################'
2182 print *, 'Systhesizing SXR image (observed at 1 AU).'
2183 write(*,'(a,i2,a,i2,a)') ' Passband: ',emin_sxr,' - ',emax_sxr,' keV'
2184 endif
2185
2186 if (dat_resolution) then
2187 if (coordinate/=cartesian) call mpistop('SXR synthesis: only cartesian is supported for .dat resolution!')
2188 if (mype==0) then
2189 print *, 'Unit of SXR flux: photons cm^-2 s^-1 pixel^-1'
2190 write(*,'(a,f5.1,a,f5.1,a,f5.1,a,f5.1,a)') ' Supposed Pixel: ',rhessi_rsl*0.725, ' Mm x ',rhessi_rsl*0.725, &
2191 ' Mm (', rhessi_rsl, ' arcsec x ', rhessi_rsl, ' arcsec)'
2192 if (si_unit) then
2193 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2194 else
2195 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2196 endif
2197 endif
2198 if (los_phi==0 .and. los_theta==90) then
2199 call get_image_datresol(qunit,datatype,fl)
2200 else if (los_phi==90 .and. los_theta==90) then
2201 call get_image_datresol(qunit,datatype,fl)
2202 else if (los_theta==0) then
2203 call get_image_datresol(qunit,datatype,fl)
2204 else
2205 call mpistop('ERROR: Wrong LOS for synthesizing emission!')
2206 endif
2207 else
2208 if (mype==0) then
2209 print *, 'Unit of SXR flux: photons cm^-2 s^-1 pixel^-1'
2210 write(*,'(a,f5.1,a,f5.1,a,f5.1,a,f5.1,a)') ' Pixel: ',rhessi_rsl*0.725, ' Mm x ',rhessi_rsl*0.725, &
2211 ' Mm (', rhessi_rsl, ' arcsec x ', rhessi_rsl, ' arcsec)'
2212 if (activate_unit_arcsec) then
2213 print *, 'Unit of length: arcsec (~725 km)'
2214 else
2215 if (si_unit) then
2216 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2217 else
2218 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2219 endif
2220 endif
2221 endif
2222 if (coordinate==cartesian) then
2223 if (mype==0) write(*,'(a,f8.3,f8.3,f8.3,a)') ' Mapping: [',x_origin(1),x_origin(2),x_origin(3), &
2224 '] of the simulation box is located at [X=0,Y=0] of the image'
2225 call get_image(qunit,datatype,fl)
2226 else if (coordinate==spherical) then
2227 if (mype==0) write(*,'(a,f6.3,f8.3,f8.3,a)') ' Mapping: R=0 of the simulation box is located at [X=0,Y=0] of the image'
2228 call get_image(qunit,datatype,fl)
2229 else
2230 call mpistop("SXR synthesis: this coordinate is not supported!")
2231 endif
2232 endif
2233
2234 t1=mpi_wtime()
2235 if (mype==0) print *, 'time comsuming:',t1-t0
2236 if (mype==0) print *, '###################################################'
2237
2238 end subroutine get_sxr_image
2239
2240 subroutine get_whitelight_image(qunit,fl)
2242
2243 integer, intent(in) :: qunit
2244 type(te_fluid), intent(in) :: fl
2245 character(20) :: datatype
2246 double precision :: LASCO_rsl
2247
2248 if (mype==0) print *, '###################################################'
2249
2250 if (whitelight_instrument=='LASCO/C1') then
2251 lasco_rsl=5.6d0/instrument_resolution_factor
2252 if (mype==0) print *, 'Systhesizing white light image (observed by LASCO/C1).'
2253 else if (whitelight_instrument=='LASCO/C2') then
2254 lasco_rsl=11.4d0/instrument_resolution_factor
2255 if (mype==0) print *, 'Systhesizing white light image (observed by LASCO/C2).'
2256 else if (whitelight_instrument=='LASCO/C3') then
2257 lasco_rsl=56.d0/instrument_resolution_factor
2258 if (mype==0) print *, 'Systhesizing white light image (observed by LASCO/C3).'
2259 else
2260 call mpistop('Whitelight synthesis: instrument is not supported!')
2261 endif
2262
2263 if (mype==0) write(*,'(a,f5.1,a,f5.1,a,f5.1,a,f5.1,a)') ' Pixel: ',lasco_rsl*0.725,' Mm x ',lasco_rsl*0.725, ' Mm (', &
2264 lasco_rsl, ' arcsec x ', lasco_rsl, ' arcsec) '
2265 if (mype==0) print *, 'Unit of white light flux: average Sun brightness'
2266
2267 datatype='image_whitelight'
2269
2270 if (mype==0) then
2271 if (activate_unit_arcsec) then
2272 print *, 'Unit of length: arcsec (~725 km)'
2273 else
2274 if (si_unit) then
2275 if (mype==0) write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2276 else
2277 if (mype==0) write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2278 endif
2279 endif
2280 endif
2281
2282 if (coordinate==spherical) then
2283 if (mype==0) write(*,'(a,f6.3,f8.3,f8.3,a)') ' Mapping: R=0 of the simulation box is located at [X=0,Y=0] of the image'
2284 call get_image(qunit,datatype,fl)
2285 else
2286 call mpistop("Whitelight synthesis: this coordinate is not supported!")
2287 endif
2288
2289 if (mype==0) print *, '###################################################'
2290
2291 end subroutine get_whitelight_image
2292
2293 subroutine postprocess_euv_instrument_image(nSrc1,nSrc2,xSrc1,xSrc2,dxSrc1,dxSrc2,&
2294 EUV,Dpl,nOut1,nOut2,xOut1,xOut2,&
2295 dxOut1,dxOut2,wOut,numWOut,Tau,EUVthin)
2297 use mod_constants
2298
2299 integer, intent(in) :: nSrc1,nSrc2
2300 double precision, intent(in) :: xSrc1(nSrc1),xSrc2(nSrc2)
2301 double precision, intent(in) :: dxSrc1(nSrc1),dxSrc2(nSrc2)
2302 double precision, intent(in) :: EUV(nSrc1,nSrc2),Dpl(nSrc1,nSrc2)
2303 integer, intent(out) :: nOut1,nOut2,numWOut
2304 double precision, allocatable, intent(out) :: xOut1(:),xOut2(:),dxOut1(:),dxOut2(:)
2305 double precision, allocatable, intent(out) :: wOut(:,:,:)
2306 double precision, intent(in), optional :: Tau(nSrc1,nSrc2),EUVthin(nSrc1,nSrc2)
2307
2308 integer :: mass,ixS1,ixS2,ixP1,ixP2,ixC1,ixC2,iw
2309 integer :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
2310 character(30) :: ion
2311 double precision :: logTe,lineCent,spaceRsl,wlRsl,sigma_PSF,wslit
2312 double precision :: arcsec,dxInst,xMin1,xMax1,xMin2,xMax2,xCent1,xCent2
2313 double precision :: sigma0,xerfmin1,xerfmax1,xerfmin2,xerfmax2
2314 double precision :: factor,weightSum,weightNorm,thinVal,tauVal
2315 double precision, allocatable :: dplNum(:,:),thinOut(:,:),tauOut(:,:),tauWeight(:,:)
2316
2317 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
2318 if (si_unit) then
2319 arcsec=7.25d5/unit_length
2320 else
2321 arcsec=7.25d7/unit_length
2322 endif
2323 dxinst=spacersl*arcsec
2324 if (dxinst<=zero) call mpistop("instrument_postprocess has non-positive pixel size")
2325
2326 xmin1=minval(xsrc1-half*dxsrc1)
2327 xmax1=maxval(xsrc1+half*dxsrc1)
2328 xmin2=minval(xsrc2-half*dxsrc2)
2329 xmax2=maxval(xsrc2+half*dxsrc2)
2330 xcent1=half*(xmin1+xmax1)
2331 xcent2=half*(xmin2+xmax2)
2332 nout1=16*max(1,ceiling((xmax1-xmin1)/(16.d0*dxinst)))
2333 nout2=16*max(1,ceiling((xmax2-xmin2)/(16.d0*dxinst)))
2334 xmin1=xcent1-half*dble(nout1)*dxinst
2335 xmin2=xcent2-half*dble(nout2)*dxinst
2336
2337 allocate(xout1(nout1),xout2(nout2),dxout1(nout1),dxout2(nout2))
2338 do ixp1=1,nout1
2339 xout1(ixp1)=xmin1+dxinst*(dble(ixp1)-half)
2340 dxout1(ixp1)=dxinst
2341 enddo
2342 do ixp2=1,nout2
2343 xout2(ixp2)=xmin2+dxinst*(dble(ixp2)-half)
2344 dxout2(ixp2)=dxinst
2345 enddo
2346
2347 numwout=2
2348 if (present(tau) .and. output_tau) numwout=numwout+1
2349 if (present(euvthin) .and. output_absorption_fraction) numwout=numwout+1
2350 allocate(wout(nout1,nout2,numwout),dplnum(nout1,nout2))
2351 wout=zero
2352 dplnum=zero
2353 if (present(euvthin)) then
2354 allocate(thinout(nout1,nout2))
2355 thinout=zero
2356 endif
2357 if (present(tau) .and. output_tau) then
2358 allocate(tauout(nout1,nout2),tauweight(nout1,nout2))
2359 tauout=zero
2360 tauweight=zero
2361 endif
2362
2363 sigma0=sigma_psf*dxinst
2364 do ixs1=1,nsrc1
2365 do ixs2=1,nsrc2
2366 thinval=zero
2367 tauval=zero
2368 if (present(euvthin)) thinval=euvthin(ixs1,ixs2)
2369 if (present(tau)) tauval=tau(ixs1,ixs2)
2370 if (abs(euv(ixs1,ixs2))<=smalldouble .and. abs(thinval)<=smalldouble .and. &
2371 abs(tauval)<=smalldouble) cycle
2372
2373 ixc1=floor((xsrc1(ixs1)-(xout1(1)-half*dxinst))/dxinst)+1
2374 ixc2=floor((xsrc2(ixs2)-(xout2(1)-half*dxinst))/dxinst)+1
2375 ixpmin1=max(1,ixc1-3)
2376 ixpmax1=min(nout1,ixc1+3)
2377 ixpmin2=max(1,ixc2-3)
2378 ixpmax2=min(nout2,ixc2+3)
2379
2380 weightsum=zero
2381 do ixp1=ixpmin1,ixpmax1
2382 do ixp2=ixpmin2,ixpmax2
2383 xerfmin1=((xout1(ixp1)-half*dxinst)-xsrc1(ixs1))/(sqrt(2.d0)*sigma0)
2384 xerfmax1=((xout1(ixp1)+half*dxinst)-xsrc1(ixs1))/(sqrt(2.d0)*sigma0)
2385 xerfmin2=((xout2(ixp2)-half*dxinst)-xsrc2(ixs2))/(sqrt(2.d0)*sigma0)
2386 xerfmax2=((xout2(ixp2)+half*dxinst)-xsrc2(ixs2))/(sqrt(2.d0)*sigma0)
2387 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
2388 weightsum=weightsum+factor
2389 enddo
2390 enddo
2391 if (weightsum<=zero) cycle
2392
2393 do ixp1=ixpmin1,ixpmax1
2394 do ixp2=ixpmin2,ixpmax2
2395 xerfmin1=((xout1(ixp1)-half*dxinst)-xsrc1(ixs1))/(sqrt(2.d0)*sigma0)
2396 xerfmax1=((xout1(ixp1)+half*dxinst)-xsrc1(ixs1))/(sqrt(2.d0)*sigma0)
2397 xerfmin2=((xout2(ixp2)-half*dxinst)-xsrc2(ixs2))/(sqrt(2.d0)*sigma0)
2398 xerfmax2=((xout2(ixp2)+half*dxinst)-xsrc2(ixs2))/(sqrt(2.d0)*sigma0)
2399 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
2400 weightnorm=factor/weightsum
2401 wout(ixp1,ixp2,1)=wout(ixp1,ixp2,1)+euv(ixs1,ixs2)*weightnorm
2402 dplnum(ixp1,ixp2)=dplnum(ixp1,ixp2)+euv(ixs1,ixs2)*dpl(ixs1,ixs2)*weightnorm
2403 if (present(euvthin)) thinout(ixp1,ixp2)=thinout(ixp1,ixp2)+thinval*weightnorm
2404 if (present(tau) .and. output_tau) then
2405 tauout(ixp1,ixp2)=tauout(ixp1,ixp2)+tauval*weightnorm
2406 tauweight(ixp1,ixp2)=tauweight(ixp1,ixp2)+weightnorm
2407 endif
2408 enddo
2409 enddo
2410 enddo
2411 enddo
2412
2413 do ixp1=1,nout1
2414 do ixp2=1,nout2
2415 if (wout(ixp1,ixp2,1)>smalldouble) then
2416 wout(ixp1,ixp2,2)=dplnum(ixp1,ixp2)/wout(ixp1,ixp2,1)
2417 else
2418 wout(ixp1,ixp2,2)=zero
2419 endif
2420 enddo
2421 enddo
2422 iw=2
2423 if (present(tau) .and. output_tau) then
2424 iw=iw+1
2425 do ixp1=1,nout1
2426 do ixp2=1,nout2
2427 if (tauweight(ixp1,ixp2)>zero) then
2428 wout(ixp1,ixp2,iw)=tauout(ixp1,ixp2)/tauweight(ixp1,ixp2)
2429 else
2430 wout(ixp1,ixp2,iw)=zero
2431 endif
2432 enddo
2433 enddo
2434 endif
2435 if (present(euvthin) .and. output_absorption_fraction) then
2436 iw=iw+1
2437 do ixp1=1,nout1
2438 do ixp2=1,nout2
2439 if (thinout(ixp1,ixp2)>smalldouble) then
2440 wout(ixp1,ixp2,iw)=min(one,max(zero,(thinout(ixp1,ixp2)-wout(ixp1,ixp2,1))/thinout(ixp1,ixp2)))
2441 else
2442 wout(ixp1,ixp2,iw)=zero
2443 endif
2444 enddo
2445 enddo
2446 endif
2447
2448 if (mype==0) then
2449 write(*,'(a,2(i8,1x),a,2(i8,1x),a,1pe12.5)') &
2450 ' instrument_postprocess EUV grid src/out: ',nsrc1,nsrc2,' -> ',nout1,nout2,' dx=',dxinst
2451 endif
2452
2453 deallocate(dplnum)
2454 if (allocated(thinout)) deallocate(thinout)
2455 if (allocated(tauout)) deallocate(tauout,tauweight)
2457
2458 subroutine postprocess_radio_beam_image(nSrc1,nSrc2,xSrc1,xSrc2,dxSrc1,dxSrc2,&
2459 Bright,nOut1,nOut2,xOut1,xOut2,&
2460 dxOut1,dxOut2,wOut,numWOut,Tau,BrightThin)
2462
2463 integer, intent(in) :: nSrc1,nSrc2
2464 double precision, intent(in) :: xSrc1(nSrc1),xSrc2(nSrc2)
2465 double precision, intent(in) :: dxSrc1(nSrc1),dxSrc2(nSrc2)
2466 double precision, intent(in) :: Bright(nSrc1,nSrc2)
2467 integer, intent(out) :: nOut1,nOut2,numWOut
2468 double precision, allocatable, intent(out) :: xOut1(:),xOut2(:),dxOut1(:),dxOut2(:)
2469 double precision, allocatable, intent(out) :: wOut(:,:,:)
2470 double precision, intent(in), optional :: Tau(nSrc1,nSrc2),BrightThin(nSrc1,nSrc2)
2471
2472 integer :: ixS1,ixS2,ixP1,ixP2,ixC1,ixC2,iw,nStencil
2473 integer :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
2474 double precision :: arcsec,beamPixel,beamSigma,xMin1,xMax1,xMin2,xMax2,xCent1,xCent2
2475 double precision :: distance1,distance2,weight,cellArea,thinVal,tauVal
2476 double precision, allocatable :: norm(:,:),thinOut(:,:),tauOut(:,:),tauNorm(:,:)
2477
2478 if (si_unit) then
2479 arcsec=7.25d5/unit_length
2480 else
2481 arcsec=7.25d7/unit_length
2482 endif
2483 beamsigma=radio_beam_fwhm*arcsec/sqrt(8.d0*log(2.d0))
2484 if (radio_beam_pixel_size>zero) then
2485 beampixel=radio_beam_pixel_size*arcsec
2486 else
2487 beampixel=radio_beam_fwhm*arcsec/3.d0
2488 endif
2489 if (beamsigma<=zero .or. beampixel<=zero) then
2490 call mpistop("radio beam postprocess has non-positive beam or pixel size")
2491 endif
2492
2493 xmin1=minval(xsrc1-half*dxsrc1)
2494 xmax1=maxval(xsrc1+half*dxsrc1)
2495 xmin2=minval(xsrc2-half*dxsrc2)
2496 xmax2=maxval(xsrc2+half*dxsrc2)
2497 xcent1=half*(xmin1+xmax1)
2498 xcent2=half*(xmin2+xmax2)
2499 nout1=16*max(1,ceiling((xmax1-xmin1)/(16.d0*beampixel)))
2500 nout2=16*max(1,ceiling((xmax2-xmin2)/(16.d0*beampixel)))
2501 xmin1=xcent1-half*dble(nout1)*beampixel
2502 xmin2=xcent2-half*dble(nout2)*beampixel
2503
2504 allocate(xout1(nout1),xout2(nout2),dxout1(nout1),dxout2(nout2))
2505 do ixp1=1,nout1
2506 xout1(ixp1)=xmin1+beampixel*(dble(ixp1)-half)
2507 dxout1(ixp1)=beampixel
2508 enddo
2509 do ixp2=1,nout2
2510 xout2(ixp2)=xmin2+beampixel*(dble(ixp2)-half)
2511 dxout2(ixp2)=beampixel
2512 enddo
2513
2514 numwout=1
2515 if (present(tau) .and. output_tau) numwout=numwout+1
2516 if (present(brightthin) .and. output_absorption_fraction) numwout=numwout+1
2517 allocate(wout(nout1,nout2,numwout),norm(nout1,nout2))
2518 wout=zero
2519 norm=zero
2520 if (present(brightthin)) then
2521 allocate(thinout(nout1,nout2))
2522 thinout=zero
2523 endif
2524 if (present(tau) .and. output_tau) then
2525 allocate(tauout(nout1,nout2),taunorm(nout1,nout2))
2526 tauout=zero
2527 taunorm=zero
2528 endif
2529
2530 nstencil=max(3,ceiling(4.d0*beamsigma/beampixel)+1)
2531 do ixs1=1,nsrc1
2532 do ixs2=1,nsrc2
2533 thinval=zero
2534 tauval=zero
2535 if (present(brightthin)) thinval=brightthin(ixs1,ixs2)
2536 if (present(tau)) tauval=tau(ixs1,ixs2)
2537 if (abs(bright(ixs1,ixs2))<=smalldouble .and. abs(thinval)<=smalldouble .and. &
2538 abs(tauval)<=smalldouble) cycle
2539
2540 ixc1=floor((xsrc1(ixs1)-(xout1(1)-half*beampixel))/beampixel)+1
2541 ixc2=floor((xsrc2(ixs2)-(xout2(1)-half*beampixel))/beampixel)+1
2542 ixpmin1=max(1,ixc1-nstencil)
2543 ixpmax1=min(nout1,ixc1+nstencil)
2544 ixpmin2=max(1,ixc2-nstencil)
2545 ixpmax2=min(nout2,ixc2+nstencil)
2546 cellarea=max(smalldouble,dxsrc1(ixs1)*dxsrc2(ixs2))
2547
2548 do ixp1=ixpmin1,ixpmax1
2549 distance1=xout1(ixp1)-xsrc1(ixs1)
2550 do ixp2=ixpmin2,ixpmax2
2551 distance2=xout2(ixp2)-xsrc2(ixs2)
2552 weight=exp_clamped(-half*(distance1**2+distance2**2)/beamsigma**2)*cellarea
2553 wout(ixp1,ixp2,1)=wout(ixp1,ixp2,1)+bright(ixs1,ixs2)*weight
2554 norm(ixp1,ixp2)=norm(ixp1,ixp2)+weight
2555 if (present(brightthin)) thinout(ixp1,ixp2)=thinout(ixp1,ixp2)+thinval*weight
2556 if (present(tau) .and. output_tau) then
2557 tauout(ixp1,ixp2)=tauout(ixp1,ixp2)+tauval*weight
2558 taunorm(ixp1,ixp2)=taunorm(ixp1,ixp2)+weight
2559 endif
2560 enddo
2561 enddo
2562 enddo
2563 enddo
2564
2565 do ixp1=1,nout1
2566 do ixp2=1,nout2
2567 if (norm(ixp1,ixp2)>zero) then
2568 wout(ixp1,ixp2,1)=wout(ixp1,ixp2,1)/norm(ixp1,ixp2)
2569 if (present(brightthin)) thinout(ixp1,ixp2)=thinout(ixp1,ixp2)/norm(ixp1,ixp2)
2570 else
2571 wout(ixp1,ixp2,1)=zero
2572 if (present(brightthin)) thinout(ixp1,ixp2)=zero
2573 endif
2574 enddo
2575 enddo
2576
2577 iw=1
2578 if (present(tau) .and. output_tau) then
2579 iw=iw+1
2580 do ixp1=1,nout1
2581 do ixp2=1,nout2
2582 if (taunorm(ixp1,ixp2)>zero) then
2583 wout(ixp1,ixp2,iw)=tauout(ixp1,ixp2)/taunorm(ixp1,ixp2)
2584 else
2585 wout(ixp1,ixp2,iw)=zero
2586 endif
2587 enddo
2588 enddo
2589 endif
2590 if (present(brightthin) .and. output_absorption_fraction) then
2591 iw=iw+1
2592 do ixp1=1,nout1
2593 do ixp2=1,nout2
2594 if (thinout(ixp1,ixp2)>smalldouble) then
2595 wout(ixp1,ixp2,iw)=min(one,max(zero,(thinout(ixp1,ixp2)-wout(ixp1,ixp2,1))/thinout(ixp1,ixp2)))
2596 else
2597 wout(ixp1,ixp2,iw)=zero
2598 endif
2599 enddo
2600 enddo
2601 endif
2602
2603 if (mype==0) then
2604 write(*,'(a,2(i8,1x),a,2(i8,1x),a,2(1pe12.5,1x))') &
2605 ' radio_beam_postprocess grid src/out: ',nsrc1,nsrc2,' -> ',nout1,nout2,&
2606 ' fwhm/pixel=',radio_beam_fwhm,beampixel/arcsec
2607 endif
2608
2609 deallocate(norm)
2610 if (allocated(thinout)) deallocate(thinout)
2611 if (allocated(tauout)) deallocate(tauout,taunorm)
2612 end subroutine postprocess_radio_beam_image
2613
2614 subroutine get_image_datresol(qunit,datatype,fl)
2615 ! integrate emission flux along line of sight (LOS)
2616 ! in a 3D simulation box and get a 2D EUV image
2618 use mod_constants
2619
2620 integer, intent(in) :: qunit
2621 character(20), intent(in) :: datatype
2622 type(te_fluid), intent(in) :: fl
2623
2624 double precision :: dx^D
2625 integer :: numX^D,ix^D
2626 double precision, allocatable :: EUV(:,:),EUVs(:,:),Dpl(:,:),Dpls(:,:)
2627 double precision, allocatable :: EUVthin(:,:),Tau(:,:)
2628 double precision, allocatable :: SXR(:,:),SXRs(:,:),wI(:,:,:)
2629 double precision, allocatable :: xI1(:),xI2(:),dxI1(:),dxI2(:),dxIi
2630 integer :: numXI1,numXI2,numSI,numWI,iw
2631 double precision :: xI^L
2632 integer :: iigrid,igrid,i,j
2633 double precision, allocatable :: xIF1(:),xIF2(:),dxIF1(:),dxIF2(:)
2634 double precision, allocatable :: xIP1(:),xIP2(:),dxIP1(:),dxIP2(:),wIP(:,:,:)
2635 integer :: nXIF1,nXIF2
2636 integer :: nXIP1,nXIP2,numWIP
2637 double precision :: xIF^L
2638 double precision :: vec_cor(1:3),xI_cor(1:2),dxDDA,xIcent1,xIcent2
2639
2640 double precision :: unitv,arcsec,RHESSI_rsl,length_to_km
2641 integer :: strtype^D,nstrb^D,nbb^D,nuni^D,nstr^D,bnx^D
2642 double precision :: qs^D,dxfirst^D,dxmid^D,lenstr^D
2643 logical :: has_doppler_output,has_thick_output
2644
2645 numx1=domain_nx1*2**(refine_max_level-1)
2646 numx2=domain_nx2*2**(refine_max_level-1)
2647 numx3=domain_nx3*2**(refine_max_level-1)
2648
2649 if (trim(ray_method_active)=='cart') call init_vectors_cartesian()
2650 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') call init_vectors_spherical()
2651
2652 ! parameters for creating table
2653 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') then
2654 call get_sph_intersection_image_bounds(xifmin1,xifmax1,xifmin2,xifmax2)
2655 call get_native_datresol_spacing(dxdda)
2656 xicent1=half*(xifmin1+xifmax1)
2657 xicent2=half*(xifmin2+xifmax2)
2658 nxif1=max(1,ceiling((xifmax1-xifmin1)/dxdda))
2659 nxif2=max(1,ceiling((xifmax2-xifmin2)/dxdda))
2660 xifmin1=xicent1-half*dble(nxif1)*dxdda
2661 xifmax1=xicent1+half*dble(nxif1)*dxdda
2662 xifmin2=xicent2-half*dble(nxif2)*dxdda
2663 xifmax2=xicent2+half*dble(nxif2)*dxdda
2664 bnx1=1
2665 bnx2=1
2666 nbb1=nxif1
2667 nbb2=nxif2
2668 strtype1=0
2669 strtype2=0
2670 nstrb1=0
2671 nstrb2=0
2672 qs1=one
2673 qs2=one
2674 if (mype==0) write(*,'(a,a,a,1pe12.5,a,2(i8,1x))') &
2675 ' spherical dat-resolution mode=',trim(dat_resolution_mode),&
2676 ' image-plane dx=',dxdda,' n=',nxif1,nxif2
2677 else if (trim(ray_method_active)=='cart') then
2678 do ix1=1,2
2679 if (ix1==1) vec_cor(1)=xprobmin1
2680 if (ix1==2) vec_cor(1)=xprobmax1
2681 do ix2=1,2
2682 if (ix2==1) vec_cor(2)=xprobmin2
2683 if (ix2==2) vec_cor(2)=xprobmax2
2684 do ix3=1,2
2685 if (ix3==1) vec_cor(3)=xprobmin3
2686 if (ix3==2) vec_cor(3)=xprobmax3
2687 call get_cor_image(vec_cor,xi_cor)
2688 if (ix1==1 .and. ix2==1 .and. ix3==1) then
2689 xifmin1=xi_cor(1)
2690 xifmax1=xi_cor(1)
2691 xifmin2=xi_cor(2)
2692 xifmax2=xi_cor(2)
2693 else
2694 xifmin1=min(xifmin1,xi_cor(1))
2695 xifmax1=max(xifmax1,xi_cor(1))
2696 xifmin2=min(xifmin2,xi_cor(2))
2697 xifmax2=max(xifmax2,xi_cor(2))
2698 endif
2699 enddo
2700 enddo
2701 enddo
2702 call get_native_datresol_spacing(dxdda)
2703 xicent1=half*(xifmin1+xifmax1)
2704 xicent2=half*(xifmin2+xifmax2)
2705 nxif1=max(1,ceiling((xifmax1-xifmin1)/dxdda))
2706 nxif2=max(1,ceiling((xifmax2-xifmin2)/dxdda))
2707 xifmin1=xicent1-half*dble(nxif1)*dxdda
2708 xifmax1=xicent1+half*dble(nxif1)*dxdda
2709 xifmin2=xicent2-half*dble(nxif2)*dxdda
2710 xifmax2=xicent2+half*dble(nxif2)*dxdda
2711 bnx1=1
2712 bnx2=1
2713 nbb1=nxif1
2714 nbb2=nxif2
2715 strtype1=0
2716 strtype2=0
2717 nstrb1=0
2718 nstrb2=0
2719 qs1=one
2720 qs2=one
2721 if (mype==0) write(*,'(a,a,a,1pe12.5,a,2(i8,1x))') &
2722 ' Cartesian dat-resolution mode=',trim(dat_resolution_mode),&
2723 ' image-plane dx=',dxdda,' n=',nxif1,nxif2
2724 else if (los_phi==0 .and. los_theta==90) then
2725 nxif1=domain_nx2*2**(refine_max_level-1)
2726 nxif2=domain_nx3*2**(refine_max_level-1)
2727 xifmin1=xprobmin2
2728 xifmax1=xprobmax2
2729 xifmin2=xprobmin3
2730 xifmax2=xprobmax3
2731 bnx1=block_nx2
2732 bnx2=block_nx3
2733 nbb1=domain_nx2
2734 nbb2=domain_nx3
2735 strtype1=stretch_type(2)
2736 strtype2=stretch_type(3)
2739 qs1=qstretch_baselevel(2)
2740 qs2=qstretch_baselevel(3)
2741 if (mype==0) write(*,'(a)') ' LOS vector: [-1.00 0.00 0.00]'
2742 if (mype==0) write(*,'(a)') ' xI1 vector: [ 0.00 1.00 0.00]'
2743 if (mype==0) write(*,'(a)') ' xI2 vector: [ 0.00 0.00 1.00]'
2744 else if (los_phi==90 .and. los_theta==90) then
2745 nxif1=domain_nx3*2**(refine_max_level-1)
2746 nxif2=domain_nx1*2**(refine_max_level-1)
2747 xifmin1=xprobmin3
2748 xifmax1=xprobmax3
2749 xifmin2=xprobmin1
2750 xifmax2=xprobmax1
2751 bnx1=block_nx3
2752 bnx2=block_nx1
2753 nbb1=domain_nx3
2754 nbb2=domain_nx1
2755 strtype1=stretch_type(3)
2756 strtype2=stretch_type(1)
2759 qs1=qstretch_baselevel(3)
2760 qs2=qstretch_baselevel(1)
2761 if (mype==0) write(*,'(a)') ' LOS vector: [ 0.00 -1.00 0.00]'
2762 if (mype==0) write(*,'(a)') ' xI1 vector: [-1.00 0.00 0.00]'
2763 if (mype==0) write(*,'(a)') ' xI2 vector: [ 0.00 0.00 1.00]'
2764 else
2765 nxif1=domain_nx1*2**(refine_max_level-1)
2766 nxif2=domain_nx2*2**(refine_max_level-1)
2767 xifmin1=xprobmin1
2768 xifmax1=xprobmax1
2769 xifmin2=xprobmin2
2770 xifmax2=xprobmax2
2771 bnx1=block_nx1
2772 bnx2=block_nx2
2773 nbb1=domain_nx1
2774 nbb2=domain_nx2
2775 strtype1=stretch_type(1)
2776 strtype2=stretch_type(2)
2779 qs1=qstretch_baselevel(1)
2780 qs2=qstretch_baselevel(2)
2781 if (mype==0) write(*,'(a)') ' LOS vector: [ 0.00 0.00 -1.00]'
2782 if (mype==0) write(*,'(a)') ' xI1 vector: [ 1.00 0.00 0.00]'
2783 if (mype==0) write(*,'(a)') ' xI2 vector: [ 0.00 1.00 0.00]'
2784 endif
2785 allocate(xif1(nxif1),xif2(nxif2),dxif1(nxif1),dxif2(nxif2))
2786
2787 ! initialize image coordinate
2788 select case(strtype1)
2789 case(0) ! uniform
2790 dxif1(:)=(xifmax1-xifmin1)/nxif1
2791 do ix1=1,nxif1
2792 xif1(ix1)=xifmin1+dxif1(ix1)*(ix1-half)
2793 enddo
2794 case(1) ! uni stretch
2795 qs1=qs1**(one/2**(refine_max_level-1))
2796 dxfirst1=(xifmax1-xifmin1)*(one-qs1)/(one-qs1**nxif1)
2797 dxif1(1)=dxfirst1
2798 do ix1=2,nxif1
2799 dxif1(ix1)=dxfirst1*qs1**(ix1-1)
2800 xif1(ix1)=dxif1(1)/(one-qs1)*(one-qs1**(ix1-1))+half*dxif1(ix1)
2801 enddo
2802 case(2) ! symm stretch
2803 ! base level, nbb = nstr + nuni + nstr
2804 nstr1=nstrb1*bnx1/2
2805 nuni1=nbb1-nstrb1*bnx1
2806 lenstr1=(xifmax1-xifmin1)/(2.d0+nuni1*(one-qs1)/(one-qs1**nstr1))
2807 dxfirst1=(xifmax1-xifmin1)/(dble(nuni1)+2.d0/(one-qs1)*(one-qs1**nstr1))
2808 dxmid1=dxfirst1
2809 ! refine_max level, numXI = nstr + nuni + nstr
2810 nstr1=nstr1*2**(refine_max_level-1)
2811 nuni1=nuni1*2**(refine_max_level-1)
2812 qs1=qs1**(one/2**(refine_max_level-1))
2813 dxfirst1=lenstr1*(one-qs1)/(one-qs1**nstr1)
2814 dxmid1=dxmid1/2**(refine_max_level-1)
2815 ! uniform center
2816 if(nuni1 .gt. 0) then
2817 do ix1=nstr1+1,nstr1+nuni1
2818 dxif1(ix1)=dxmid1
2819 xif1(ix1)=lenstr1+(dble(ix1)-0.5d0-nstr1)*dxif1(ix1)+xifmin1
2820 enddo
2821 endif
2822 ! left half
2823 do ix1=nstr1,1,-1
2824 dxif1(ix1)=dxfirst1*qs1**(nstr1-ix1)
2825 xif1(ix1)=xifmin1+lenstr1-dxif1(ix1)*half-dxfirst1*(one-qs1**(nstr1-ix1))/(one-qs1)
2826 enddo
2827 ! right half
2828 do ix1=nstr1+nuni1+1,nxif1
2829 dxif1(ix1)=dxfirst1*qs1**(ix1-nstr1-nuni1-1)
2830 xif1(ix1)=xifmax1-lenstr1+dxif1(ix1)*half+dxfirst1*(one-qs1**(ix1-nstr1-nuni1-1))/(one-qs1)
2831 enddo
2832 case default
2833 call mpistop("unknown stretch type")
2834 end select
2835
2836 select case(strtype2)
2837 case(0) ! uniform
2838 dxif2(:)=(xifmax2-xifmin2)/nxif2
2839 do ix2=1,nxif2
2840 xif2(ix2)=xifmin2+dxif2(ix2)*(ix2-half)
2841 enddo
2842 case(1) ! uni stretch
2843 qs2=qs2**(one/2**(refine_max_level-1))
2844 dxfirst2=(xifmax2-xifmin2)*(one-qs2)/(one-qs2**nxif2)
2845 dxif2(1)=dxfirst2
2846 do ix2=2,nxif1
2847 dxif2(ix2)=dxfirst2*qs2**(ix2-1)
2848 xif2(ix2)=dxif2(1)/(one-qs2)*(one-qs2**(ix2-1))+half*dxif2(ix2)
2849 enddo
2850 case(2) ! symm stretch
2851 ! base level, nbb = nstr + nuni + nstr
2852 nstr2=nstrb2*bnx2/2
2853 nuni2=nbb2-nstrb2*bnx2
2854 lenstr2=(xifmax2-xifmin2)/(2.d0+nuni2*(one-qs2)/(one-qs2**nstr2))
2855 dxfirst2=(xifmax2-xifmin2)/(dble(nuni2)+2.d0/(one-qs2)*(one-qs2**nstr2))
2856 dxmid2=dxfirst2
2857 ! refine_max level, numXI = nstr + nuni + nstr
2858 nstr2=nstr2*2**(refine_max_level-1)
2859 nuni2=nuni2*2**(refine_max_level-1)
2860 qs2=qs2**(one/2**(refine_max_level-1))
2861 dxfirst2=lenstr2*(one-qs2)/(one-qs2**nstr2)
2862 dxmid2=dxmid2/2**(refine_max_level-1)
2863 ! uniform center
2864 if(nuni2 .gt. 0) then
2865 do ix2=nstr2+1,nstr2+nuni2
2866 dxif2(ix2)=dxmid2
2867 xif2(ix2)=lenstr2+(dble(ix2)-0.5d0-nstr2)*dxif2(ix2)+xifmin2
2868 enddo
2869 endif
2870 ! left half
2871 do ix2=nstr2,1,-1
2872 dxif2(ix2)=dxfirst2*qs2**(nstr2-ix2)
2873 xif2(ix2)=xifmin2+lenstr2-dxif2(ix2)*half-dxfirst2*(one-qs2**(nstr2-ix2))/(one-qs2)
2874 enddo
2875 ! right half
2876 do ix2=nstr2+nuni2+1,nxif2
2877 dxif2(ix2)=dxfirst2*qs2**(ix2-nstr2-nuni2-1)
2878 xif2(ix2)=xifmax2-lenstr2+dxif2(ix2)*half+dxfirst2*(one-qs2**(ix2-nstr2-nuni2-1))/(one-qs2)
2879 enddo
2880 case default
2881 call mpistop("unknown stretch type")
2882 end select
2883
2884 if (mype==0 .and. datatype=='image_euv') then
2885 if (si_unit) then
2886 length_to_km=unit_length/1.d3
2887 arcsec=7.25d5/unit_length
2888 else
2889 length_to_km=unit_length/1.d5
2890 arcsec=7.25d7/unit_length
2891 endif
2892 write(*,'(a,i8,a,i8)') ' Native data-resolution image grid: ',nxif1,' x ',nxif2
2893 write(*,'(a,f10.3,a,f10.3,a,f8.3,a,f8.3,a)') &
2894 ' Native xI1 pixel-size range: ',minval(dxif1)*length_to_km,'--', &
2895 maxval(dxif1)*length_to_km,' km (',minval(dxif1)/arcsec,'--',maxval(dxif1)/arcsec,' arcsec)'
2896 write(*,'(a,f10.3,a,f10.3,a,f8.3,a,f8.3,a)') &
2897 ' Native xI2 pixel-size range: ',minval(dxif2)*length_to_km,'--', &
2898 maxval(dxif2)*length_to_km,' km (',minval(dxif2)/arcsec,'--',maxval(dxif2)/arcsec,' arcsec)'
2899 endif
2900
2901 ! integrate EUV flux and get cell average flux for image
2902 if (datatype=='image_euv') then
2903 if (si_unit) then
2904 unitv=unit_velocity/1.0e3 ! km/s
2905 else
2906 unitv=unit_velocity/1.0e5 ! km/s
2907 endif
2908 has_thick_output=trim(radiation_transfer)=='thick'
2909 has_doppler_output=radsyn_euv_has_doppler_output()
2910 numwi=radsyn_euv_num_outputs(has_doppler_output,has_thick_output)
2911 allocate(wi(nxif1,nxif2,numwi))
2912 allocate(euv(nxif1,nxif2),dpl(nxif1,nxif2))
2913 if (trim(radiation_transfer)=='thick') then
2914 allocate(euvthin(nxif1,nxif2),tau(nxif1,nxif2))
2915 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') then
2916 call integrate_euv_sph_intersection_thick(nxif1,nxif2,xif1,xif2,dxif1(1),fl,euv,tau,euvthin)
2917 dpl=zero
2918 else if (trim(ray_method_active)=='cart') then
2919 call integrate_euv_cart_dda_thick_datresol(nxif1,nxif2,xif1,xif2,fl,euv,dpl,tau,euvthin)
2920 else
2921 call integrate_euv_thick_datresol(nxif1,nxif2,fl,euv,dpl,tau,euvthin)
2922 endif
2923 if (has_doppler_output) then
2924 where(euv<smalldouble) euv=zero
2925 call normalize_euv_doppler(nxif1,nxif2,euv,dpl,unitv)
2926 endif
2927 else
2928 allocate(euvs(nxif1,nxif2),dpls(nxif1,nxif2))
2929 euvs=0.0d0
2930 euv=0.0d0
2931 dpl=0.d0
2932 dpls=0.d0
2933 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') then
2934 call integrate_euv_sph_intersection_thin(nxif1,nxif2,xif1,xif2,dxif1(1),fl,euv)
2935 euvs=euv
2936 numsi=nxif1*nxif2
2937 call mpi_allreduce(euvs,euv,numsi,mpi_double_precision, &
2938 mpi_sum,icomm,ierrmpi)
2939 else if (trim(ray_method_active)=='cart') then
2940 call integrate_euv_cart_dda_datresol(nxif1,nxif2,xif1,xif2,fl,euv,dpl)
2941 else
2942 do iigrid=1,igridstail; igrid=igrids(iigrid);
2943 call integrate_euv_datresol(igrid,nxif1,nxif2,xif1,xif2,dxif1,dxif2,fl,euvs,dpls)
2944 enddo
2945 numsi=nxif1*nxif2
2946 call mpi_allreduce(euvs,euv,numsi,mpi_double_precision, &
2947 mpi_sum,icomm,ierrmpi)
2948 call mpi_allreduce(dpls,dpl,numsi,mpi_double_precision, &
2949 mpi_sum,icomm,ierrmpi)
2950 endif
2951 if (has_doppler_output) then
2952 where(euv<smalldouble) euv=zero
2953 call normalize_euv_doppler(nxif1,nxif2,euv,dpl,unitv)
2954 endif
2955 deallocate(euvs,dpls)
2956 endif
2957 if (has_thick_output) then
2958 if (has_doppler_output) then
2959 call pack_euv_image_outputs(nxif1,nxif2,euv,wi,smalldouble,has_doppler_output,&
2960 has_thick_output,dpl=dpl,tau=tau,euvthin=euvthin)
2961 else
2962 call pack_euv_image_outputs(nxif1,nxif2,euv,wi,smalldouble,has_doppler_output,&
2963 has_thick_output,tau=tau,euvthin=euvthin)
2964 endif
2965 else if (has_doppler_output) then
2966 call pack_euv_image_outputs(nxif1,nxif2,euv,wi,smalldouble,has_doppler_output,&
2967 has_thick_output,dpl=dpl)
2968 else
2969 call pack_euv_image_outputs(nxif1,nxif2,euv,wi,smalldouble,has_doppler_output,&
2970 has_thick_output)
2971 endif
2972
2973 if (instrument_postprocess) then
2974 if (trim(emission_model)=='radio_ff') then
2975 if (trim(radiation_transfer)=='thick') then
2976 call postprocess_radio_beam_image(nxif1,nxif2,xif1,xif2,dxif1,dxif2,&
2977 euv,nxip1,nxip2,xip1,xip2,&
2978 dxip1,dxip2,wip,numwip,tau=tau,brightthin=euvthin)
2979 else
2980 call postprocess_radio_beam_image(nxif1,nxif2,xif1,xif2,dxif1,dxif2,&
2981 euv,nxip1,nxip2,xip1,xip2,&
2982 dxip1,dxip2,wip,numwip)
2983 endif
2984 else if (trim(radiation_transfer)=='thick') then
2985 call postprocess_euv_instrument_image(nxif1,nxif2,xif1,xif2,dxif1,dxif2,&
2986 euv,dpl,nxip1,nxip2,xip1,xip2,&
2987 dxip1,dxip2,wip,numwip,tau=tau,euvthin=euvthin)
2988 else
2989 call postprocess_euv_instrument_image(nxif1,nxif2,xif1,xif2,dxif1,dxif2,&
2990 euv,dpl,nxip1,nxip2,xip1,xip2,&
2991 dxip1,dxip2,wip,numwip)
2992 endif
2993 call output_data(qunit,xip1,xip2,dxip1,dxip2,wip,nxip1,nxip2,numwip,datatype)
2994 deallocate(xip1,xip2,dxip1,dxip2,wip)
2995 else
2996 call output_data(qunit,xif1,xif2,dxif1,dxif2,wi,nxif1,nxif2,numwi,datatype)
2997 endif
2998 if (trim(radiation_transfer)=='thick') then
2999 deallocate(wi,euv,dpl,euvthin,tau)
3000 else
3001 deallocate(wi,euv,dpl)
3002 endif
3003 endif
3004
3005 ! integrate SXR flux and get cell average flux for image
3006 if (datatype=='image_sxr') then
3007 if (si_unit) then
3008 arcsec=7.25d5
3009 else
3010 arcsec=7.25d7
3011 endif
3012 rhessi_rsl=2.3d0/instrument_resolution_factor
3013 numwi=1
3014 allocate(wi(nxif1,nxif2,numwi))
3015 allocate(sxrs(nxif1,nxif2),sxr(nxif1,nxif2))
3016 sxrs=0.0d0
3017 sxr=0.0d0
3018 do iigrid=1,igridstail; igrid=igrids(iigrid);
3019 call integrate_sxr_datresol(igrid,nxif1,nxif2,xif1,xif2,dxif1,dxif2,fl,sxrs)
3020 enddo
3021 numsi=nxif1*nxif2
3022 call mpi_allreduce(sxrs,sxr,numsi,mpi_double_precision, &
3023 mpi_sum,icomm,ierrmpi)
3024
3025 sxr=sxr*(rhessi_rsl*arcsec)**2 ! photons cm^-2 s^-1 pixel^-1
3026 do ix1=1,nxif1
3027 do ix2=1,nxif2
3028 if (sxr(ix1,ix2)<smalldouble) sxr(ix1,ix2)=zero
3029 enddo
3030 enddo
3031 wi(:,:,1)=sxr(:,:)
3032
3033 call output_data(qunit,xif1,xif2,dxif1,dxif2,wi,nxif1,nxif2,numwi,datatype)
3034 deallocate(wi,sxr,sxrs)
3035 endif
3036
3037 deallocate(xif1,xif2,dxif1,dxif2)
3038
3039 end subroutine get_image_datresol
3040
3041 subroutine integrate_sxr_datresol(igrid,nXIF1,nXIF2,xIF1,xIF2,dxIF1,dxIF2,fl,SXR)
3043
3044 integer, intent(in) :: igrid,nXIF1,nXIF2
3045 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3046 double precision, intent(in) :: dxIF1(nXIF1),dxIF2(nXIF2)
3047 type(te_fluid), intent(in) :: fl
3048 double precision, intent(out) :: SXR(nXIF1,nXIF2)
3049
3050 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
3051 double precision :: xb^L,xd^D
3052 double precision, allocatable :: flux(:^D&),opacity(:^D&)
3053 double precision, allocatable :: dxb1(:^D&),dxb2(:^D&),dxb3(:^D&)
3054 double precision, allocatable :: SXRg(:,:),xg1(:),xg2(:),dxg1(:),dxg2(:)
3055 integer :: levelg,nXg1,nXg2,iXgmin1,iXgmax1,iXgmin2,iXgmax2,rft,iXg^D
3056 double precision :: SXRt,xc^L,xg^L,r2,area_1AU
3057 integer :: ixP^L,ixP^D
3058 integer :: direction_LOS
3059
3060 if (los_phi==0 .and. los_theta==90) then
3061 direction_los=1
3062 else if (los_phi==90 .and. los_theta==90) then
3063 direction_los=2
3064 else
3065 direction_los=3
3066 endif
3067
3068 ^d&ixomin^d=ixmlo^d\
3069 ^d&ixomax^d=ixmhi^d\
3070 ^d&iximin^d=ixglo^d\
3071 ^d&iximax^d=ixghi^d\
3072 ^d&xbmin^d=rnode(rpxmin^d_,igrid)\
3073 ^d&xbmax^d=rnode(rpxmax^d_,igrid)\
3074
3075 allocate(flux(ixi^s))
3076 allocate(dxb1(ixi^s),dxb2(ixi^s),dxb3(ixi^s))
3077 dxb1(ixo^s)=ps(igrid)%dx(ixo^s,1)
3078 dxb2(ixo^s)=ps(igrid)%dx(ixo^s,2)
3079 dxb3(ixo^s)=ps(igrid)%dx(ixo^s,3)
3080 ! get local SXR flux
3081 call get_sxr(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,emin_sxr,emax_sxr)
3082
3083 ! grid parameters
3084 levelg=ps(igrid)%level
3085 rft=2**(refine_max_level-levelg)
3086
3087 ! fine table for storing EUV flux of current grid
3088 select case(direction_los)
3089 case(1)
3090 nxg1=iximax2*rft
3091 nxg2=iximax3*rft
3092 case(2)
3093 nxg1=iximax3*rft
3094 nxg2=iximax1*rft
3095 case(3)
3096 nxg1=iximax1*rft
3097 nxg2=iximax2*rft
3098 end select
3099 allocate(sxrg(nxg1,nxg2),xg1(nxg1),xg2(nxg2),dxg1(nxg1),dxg2(nxg2))
3100 sxrg=zero
3101 xg1=zero
3102 xg2=zero
3103
3104 ! integrate for different direction
3105 select case(direction_los)
3106 case(1)
3107 do ix2=ixomin2,ixomax2
3108 ixgmin1=(ix2-1)*rft+1
3109 ixgmax1=ix2*rft
3110 do ix3=ixomin3,ixomax3
3111 ixgmin2=(ix3-1)*rft+1
3112 ixgmax2=ix3*rft
3113 sxrt=0.d0
3114 do ix1=ixomin1,ixomax1
3115 sxrt=sxrt+flux(ix^d)*dxb1(ix^d)*unit_length
3116 enddo
3117 sxrg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=sxrt
3118 enddo
3119 enddo
3120 case(2)
3121 do ix3=ixomin3,ixomax3
3122 ixgmin1=(ix3-1)*rft+1
3123 ixgmax1=ix3*rft
3124 do ix1=ixomin1,ixomax1
3125 ixgmin2=(ix1-1)*rft+1
3126 ixgmax2=ix1*rft
3127 sxrt=0.d0
3128 do ix2=ixomin2,ixomax2
3129 sxrt=sxrt+flux(ix^d)*dxb2(ix^d)*unit_length
3130 enddo
3131 sxrg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=sxrt
3132 enddo
3133 enddo
3134 case(3)
3135 do ix1=ixomin1,ixomax1
3136 ixgmin1=(ix1-1)*rft+1
3137 ixgmax1=ix1*rft
3138 do ix2=ixomin2,ixomax2
3139 ixgmin2=(ix2-1)*rft+1
3140 ixgmax2=ix2*rft
3141 sxrt=0.d0
3142 do ix3=ixomin3,ixomax3
3143 sxrt=sxrt+flux(ix^d)*dxb3(ix^d)*unit_length
3144 enddo
3145 sxrg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=sxrt
3146 enddo
3147 enddo
3148 end select
3149
3150 area_1au=2.81d27
3151 sxrg=sxrg/area_1au
3152
3153 ! mapping grid data to global table
3154 ! index ranges in local table
3155 select case(direction_los)
3156 case(1)
3157 ixgmin1=(ixomin2-1)*rft+1
3158 ixgmax1=ixomax2*rft
3159 ixgmin2=(ixomin3-1)*rft+1
3160 ixgmax2=ixomax3*rft
3161 case(2)
3162 ixgmin1=(ixomin3-1)*rft+1
3163 ixgmax1=ixomax3*rft
3164 ixgmin2=(ixomin1-1)*rft+1
3165 ixgmax2=ixomax1*rft
3166 case(3)
3167 ixgmin1=(ixomin1-1)*rft+1
3168 ixgmax1=ixomax1*rft
3169 ixgmin2=(ixomin2-1)*rft+1
3170 ixgmax2=ixomax2*rft
3171 end select
3172 ! index ranges in global table & mapping
3173 select case(direction_los)
3174 case(1)
3175 ixpmin1=(node(pig2_,igrid)-1)*rft*block_nx2+1
3176 ixpmax1=node(pig2_,igrid)*rft*block_nx2
3177 ixpmin2=(node(pig3_,igrid)-1)*rft*block_nx3+1
3178 ixpmax2=node(pig3_,igrid)*rft*block_nx3
3179 case(2)
3180 ixpmin1=(node(pig3_,igrid)-1)*rft*block_nx3+1
3181 ixpmax1=node(pig3_,igrid)*rft*block_nx3
3182 ixpmin2=(node(pig1_,igrid)-1)*rft*block_nx1+1
3183 ixpmax2=node(pig1_,igrid)*rft*block_nx1
3184 case(3)
3185 ixpmin1=(node(pig1_,igrid)-1)*rft*block_nx1+1
3186 ixpmax1=node(pig1_,igrid)*rft*block_nx1
3187 ixpmin2=(node(pig2_,igrid)-1)*rft*block_nx2+1
3188 ixpmax2=node(pig2_,igrid)*rft*block_nx2
3189 end select
3190 xg1(ixgmin1:ixgmax1)=xif1(ixpmin1:ixpmax1)
3191 xg2(ixgmin2:ixgmax2)=xif2(ixpmin2:ixpmax2)
3192 dxg1(ixgmin1:ixgmax1)=dxif1(ixpmin1:ixpmax1)
3193 dxg2(ixgmin2:ixgmax2)=dxif2(ixpmin2:ixpmax2)
3194 sxr(ixpmin1:ixpmax1,ixpmin2:ixpmax2)=sxr(ixpmin1:ixpmax1,ixpmin2:ixpmax2)+&
3195 sxrg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)
3196
3197 deallocate(flux,dxb1,dxb2,dxb3,sxrg,xg1,xg2,dxg1,dxg2)
3198
3199 end subroutine integrate_sxr_datresol
3200
3201 subroutine integrate_euv_datresol(igrid,nXIF1,nXIF2,xIF1,xIF2,dxIF1,dxIF2,fl,EUV,Dpl)
3203
3204 integer, intent(in) :: igrid,nXIF1,nXIF2
3205 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3206 double precision, intent(in) :: dxIF1(nXIF1),dxIF2(nXIF2)
3207 type(te_fluid), intent(in) :: fl
3208 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
3209
3210 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
3211 double precision :: xb^L,xd^D
3212 double precision, allocatable :: flux(:^D&),v(:^D&),rho(:^D&),opacity(:^D&)
3213 double precision, allocatable :: dxb1(:^D&),dxb2(:^D&),dxb3(:^D&)
3214 double precision, allocatable :: EUVg(:,:),Fvg(:,:),xg1(:),xg2(:),dxg1(:),dxg2(:)
3215 integer :: levelg,nXg1,nXg2,iXgmin1,iXgmax1,iXgmin2,iXgmax2,rft,iXg^D
3216 double precision :: EUVt,Fvt,xc^L,xg^L,r2
3217 integer :: ixP^L,ixP^D
3218 integer :: direction_LOS
3219
3220 if (los_phi==0 .and. los_theta==90) then
3221 direction_los=1
3222 else if (los_phi==90 .and. los_theta==90) then
3223 direction_los=2
3224 else
3225 direction_los=3
3226 endif
3227
3228 ^d&ixomin^d=ixmlo^d\
3229 ^d&ixomax^d=ixmhi^d\
3230 ^d&iximin^d=ixglo^d\
3231 ^d&iximax^d=ixghi^d\
3232 ^d&xbmin^d=rnode(rpxmin^d_,igrid)\
3233 ^d&xbmax^d=rnode(rpxmax^d_,igrid)\
3234
3235 allocate(flux(ixi^s),v(ixi^s),rho(ixi^s),opacity(ixi^s))
3236 allocate(dxb1(ixi^s),dxb2(ixi^s),dxb3(ixi^s))
3237 dxb1(ixo^s)=ps(igrid)%dx(ixo^s,1)
3238 dxb2(ixo^s)=ps(igrid)%dx(ixo^s,2)
3239 dxb3(ixo^s)=ps(igrid)%dx(ixo^s,3)
3240 if (trim(emission_model)=='pseudo_current') then
3241 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,flux)
3242 v(ixo^s)=zero
3243 deallocate(rho)
3244 else if (trim(emission_model)=='radio_ff') then
3245 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,opacity)
3246 v(ixo^s)=zero
3247 deallocate(rho)
3248 else
3249 ! get local EUV flux and velocity
3250 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
3251 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
3252 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
3253 v(ixo^s)=-ps(igrid)%w(ixo^s,iw_mom(direction_los))/rho(ixo^s)
3254 deallocate(rho)
3255 endif
3256
3257 ! grid parameters
3258 levelg=ps(igrid)%level
3259 rft=2**(refine_max_level-levelg)
3260
3261 ! fine table for storing EUV flux of current grid
3262 select case(direction_los)
3263 case(1)
3264 nxg1=iximax2*rft
3265 nxg2=iximax3*rft
3266 case(2)
3267 nxg1=iximax3*rft
3268 nxg2=iximax1*rft
3269 case(3)
3270 nxg1=iximax1*rft
3271 nxg2=iximax2*rft
3272 end select
3273 allocate(euvg(nxg1,nxg2),fvg(nxg1,nxg2),xg1(nxg1),xg2(nxg2),dxg1(nxg1),dxg2(nxg2))
3274 euvg=zero
3275 fvg=zero
3276 xg1=zero
3277 xg2=zero
3278
3279 ! integrate for different direction
3280 select case(direction_los)
3281 case(1)
3282 do ix2=ixomin2,ixomax2
3283 ixgmin1=(ix2-1)*rft+1
3284 ixgmax1=ix2*rft
3285 do ix3=ixomin3,ixomax3
3286 ixgmin2=(ix3-1)*rft+1
3287 ixgmax2=ix3*rft
3288 euvt=0.d0
3289 fvt=0.d0
3290 do ix1=ixomin1,ixomax1
3291 euvt=euvt+flux(ix^d)*dxb1(ix^d)*unit_length
3292 fvt=fvt+flux(ix^d)*dxb1(ix^d)*unit_length*v(ix^d)
3293 enddo
3294 euvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=euvt
3295 fvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=fvt
3296 enddo
3297 enddo
3298 case(2)
3299 do ix3=ixomin3,ixomax3
3300 ixgmin1=(ix3-1)*rft+1
3301 ixgmax1=ix3*rft
3302 do ix1=ixomin1,ixomax1
3303 ixgmin2=(ix1-1)*rft+1
3304 ixgmax2=ix1*rft
3305 euvt=0.d0
3306 fvt=0.d0
3307 do ix2=ixomin2,ixomax2
3308 euvt=euvt+flux(ix^d)*dxb2(ix^d)*unit_length
3309 fvt=fvt+flux(ix^d)*dxb2(ix^d)*unit_length*v(ix^d)
3310 enddo
3311 euvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=euvt
3312 fvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=fvt
3313 enddo
3314 enddo
3315 case(3)
3316 do ix1=ixomin1,ixomax1
3317 ixgmin1=(ix1-1)*rft+1
3318 ixgmax1=ix1*rft
3319 do ix2=ixomin2,ixomax2
3320 ixgmin2=(ix2-1)*rft+1
3321 ixgmax2=ix2*rft
3322 euvt=0.d0
3323 fvt=0.d0
3324 do ix3=ixomin3,ixomax3
3325 euvt=euvt+flux(ix^d)*dxb3(ix^d)*unit_length
3326 fvt=fvt+flux(ix^d)*dxb3(ix^d)*unit_length*v(ix^d)
3327 enddo
3328 euvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=euvt
3329 fvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=fvt
3330 enddo
3331 enddo
3332 end select
3333 if (si_unit) then
3334 euvg=euvg*1.d2
3335 fvg=fvg*1.d2
3336 endif
3337
3338 ! mapping grid data to global table
3339 ! index ranges in local table
3340 select case(direction_los)
3341 case(1)
3342 ixgmin1=(ixomin2-1)*rft+1
3343 ixgmax1=ixomax2*rft
3344 ixgmin2=(ixomin3-1)*rft+1
3345 ixgmax2=ixomax3*rft
3346 case(2)
3347 ixgmin1=(ixomin3-1)*rft+1
3348 ixgmax1=ixomax3*rft
3349 ixgmin2=(ixomin1-1)*rft+1
3350 ixgmax2=ixomax1*rft
3351 case(3)
3352 ixgmin1=(ixomin1-1)*rft+1
3353 ixgmax1=ixomax1*rft
3354 ixgmin2=(ixomin2-1)*rft+1
3355 ixgmax2=ixomax2*rft
3356 end select
3357 ! index ranges in global table & mapping
3358 select case(direction_los)
3359 case(1)
3360 ixpmin1=(node(pig2_,igrid)-1)*rft*block_nx2+1
3361 ixpmax1=node(pig2_,igrid)*rft*block_nx2
3362 ixpmin2=(node(pig3_,igrid)-1)*rft*block_nx3+1
3363 ixpmax2=node(pig3_,igrid)*rft*block_nx3
3364 case(2)
3365 ixpmin1=(node(pig3_,igrid)-1)*rft*block_nx3+1
3366 ixpmax1=node(pig3_,igrid)*rft*block_nx3
3367 ixpmin2=(node(pig1_,igrid)-1)*rft*block_nx1+1
3368 ixpmax2=node(pig1_,igrid)*rft*block_nx1
3369 case(3)
3370 ixpmin1=(node(pig1_,igrid)-1)*rft*block_nx1+1
3371 ixpmax1=node(pig1_,igrid)*rft*block_nx1
3372 ixpmin2=(node(pig2_,igrid)-1)*rft*block_nx2+1
3373 ixpmax2=node(pig2_,igrid)*rft*block_nx2
3374 end select
3375 xg1(ixgmin1:ixgmax1)=xif1(ixpmin1:ixpmax1)
3376 xg2(ixgmin2:ixgmax2)=xif2(ixpmin2:ixpmax2)
3377 dxg1(ixgmin1:ixgmax1)=dxif1(ixpmin1:ixpmax1)
3378 dxg2(ixgmin2:ixgmax2)=dxif2(ixpmin2:ixpmax2)
3379 euv(ixpmin1:ixpmax1,ixpmin2:ixpmax2)=euv(ixpmin1:ixpmax1,ixpmin2:ixpmax2)+&
3380 euvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)
3381 dpl(ixpmin1:ixpmax1,ixpmin2:ixpmax2)=dpl(ixpmin1:ixpmax1,ixpmin2:ixpmax2)+&
3382 fvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)
3383
3384 deallocate(flux,v,opacity,dxb1,dxb2,dxb3,euvg,fvg,xg1,xg2,dxg1,dxg2)
3385
3386 end subroutine integrate_euv_datresol
3387
3388 }
3389
3390 {^ifthreed
3391
3392 subroutine ray_box_intersection_cart(ray_origin,ray_dir,box_min,box_max,hit,t_enter,t_exit)
3393 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),box_min(1:3),box_max(1:3)
3394 logical, intent(out) :: hit
3395 double precision, intent(out) :: t_enter,t_exit
3396
3397 integer :: idir
3398 double precision :: t1,t2,td
3399
3400 hit=.true.
3401 t_enter=-huge(one)
3402 t_exit=huge(one)
3403 do idir=1,3
3404 if (abs(ray_dir(idir))<=smalldouble) then
3405 if (ray_origin(idir)<box_min(idir) .or. ray_origin(idir)>box_max(idir)) then
3406 hit=.false.
3407 return
3408 endif
3409 else
3410 t1=(box_min(idir)-ray_origin(idir))/ray_dir(idir)
3411 t2=(box_max(idir)-ray_origin(idir))/ray_dir(idir)
3412 if (t1>t2) then
3413 td=t1
3414 t1=t2
3415 t2=td
3416 endif
3417 t_enter=max(t_enter,t1)
3418 t_exit=min(t_exit,t2)
3419 if (t_enter>=t_exit) then
3420 hit=.false.
3421 return
3422 endif
3423 endif
3424 enddo
3425 end subroutine ray_box_intersection_cart
3426
3427 subroutine build_cart_dda_faces(ixI^L,ixO^L,x,dx,xface1,xface2,xface3)
3428 integer, intent(in) :: ixI^L, ixO^L
3429 double precision, intent(in) :: x(ixI^S,1:ndim),dx(ixI^S,1:ndim)
3430 double precision, allocatable, intent(out) :: xface1(:),xface2(:),xface3(:)
3431
3432 integer :: ix^D
3433
3434 allocate(xface1(ixomin1:ixomax1+1),xface2(ixomin2:ixomax2+1),xface3(ixomin3:ixomax3+1))
3435
3436 ix2=ixomin2
3437 ix3=ixomin3
3438 do ix1=ixomin1,ixomax1
3439 xface1(ix1)=x(ix^d,1)-half*dx(ix^d,1)
3440 enddo
3441 xface1(ixomax1+1)=x(ixomax1,ixomin2,ixomin3,1)+half*dx(ixomax1,ixomin2,ixomin3,1)
3442
3443 ix1=ixomin1
3444 ix3=ixomin3
3445 do ix2=ixomin2,ixomax2
3446 xface2(ix2)=x(ix^d,2)-half*dx(ix^d,2)
3447 enddo
3448 xface2(ixomax2+1)=x(ixomin1,ixomax2,ixomin3,2)+half*dx(ixomin1,ixomax2,ixomin3,2)
3449
3450 ix1=ixomin1
3451 ix2=ixomin2
3452 do ix3=ixomin3,ixomax3
3453 xface3(ix3)=x(ix^d,3)-half*dx(ix^d,3)
3454 enddo
3455 xface3(ixomax3+1)=x(ixomin1,ixomin2,ixomax3,3)+half*dx(ixomin1,ixomin2,ixomax3,3)
3456 end subroutine build_cart_dda_faces
3457
3458 integer function cart_dda_locate_index(pos,faces,imin,imax) result(idx)
3459 integer, intent(in) :: imin,imax
3460 double precision, intent(in) :: pos,faces(imin:imax+1)
3461
3462 integer :: ilo,ihi,imid
3463
3464 if (pos<=faces(imin)) then
3465 idx=imin
3466 return
3467 endif
3468 if (pos>=faces(imax+1)) then
3469 idx=imax
3470 return
3471 endif
3472
3473 ilo=imin
3474 ihi=imax+1
3475 do while (ihi-ilo>1)
3476 imid=(ilo+ihi)/2
3477 if (pos>=faces(imid)) then
3478 ilo=imid
3479 else
3480 ihi=imid
3481 endif
3482 enddo
3483 idx=min(imax,max(imin,ilo))
3484 end function cart_dda_locate_index
3485
3486 subroutine cart_dda_init_axis(ray_origin_axis,ray_dir_axis,faces,imin,imax,idx,step,tMax)
3487 integer, intent(in) :: imin,imax,idx
3488 double precision, intent(in) :: ray_origin_axis,ray_dir_axis,faces(imin:imax+1)
3489 integer, intent(out) :: step
3490 double precision, intent(out) :: tMax
3491
3492 if (ray_dir_axis>zero) then
3493 step=1
3494 tmax=(faces(idx+1)-ray_origin_axis)/ray_dir_axis
3495 else if (ray_dir_axis<zero) then
3496 step=-1
3497 tmax=(faces(idx)-ray_origin_axis)/ray_dir_axis
3498 else
3499 step=0
3500 tmax=huge(one)
3501 endif
3502 end subroutine cart_dda_init_axis
3503
3504 subroutine cart_dda_advance_axis(ray_origin_axis,ray_dir_axis,faces,imin,imax,idx,step,tMax,done)
3505 integer, intent(in) :: imin,imax,step
3506 double precision, intent(in) :: ray_origin_axis,ray_dir_axis,faces(imin:imax+1)
3507 integer, intent(inout) :: idx
3508 double precision, intent(inout) :: tMax
3509 logical, intent(out) :: done
3510
3511 done=.false.
3512 idx=idx+step
3513 if (idx<imin .or. idx>imax) then
3514 done=.true.
3515 return
3516 endif
3517 if (step>0) then
3518 tmax=(faces(idx+1)-ray_origin_axis)/ray_dir_axis
3519 else if (step<0) then
3520 tmax=(faces(idx)-ray_origin_axis)/ray_dir_axis
3521 else
3522 tmax=huge(one)
3523 endif
3524 end subroutine cart_dda_advance_axis
3525
3526 subroutine acc_euv_cart_dda(ixI^L,ixO^L,source,sourcev,&
3527 ray_origin,xface1,xface2,xface3,t_enter,t_exit,EUVp,Dplp)
3528 integer, intent(in) :: ixI^L, ixO^L
3529 double precision, intent(in) :: source(ixI^S),sourcev(ixI^S)
3530 double precision, intent(in) :: ray_origin(1:3)
3531 double precision, intent(in) :: xface1(ixOmin1:ixOmax1+1),xface2(ixOmin2:ixOmax2+1),&
3532 xface3(ixOmin3:ixOmax3+1)
3533 double precision, intent(in) :: t_enter,t_exit
3534 double precision, intent(inout) :: EUVp,Dplp
3535
3536 integer :: ix^D,step(1:3)
3537 double precision :: pos(1:3),tMax(1:3),tNow,tNext,ds_cm,epsRay
3538 logical :: done
3539
3540 if (t_exit<=t_enter) return
3541 epsray=max(1.d-12,1.d-10*abs(t_exit-t_enter))
3542 pos=ray_origin+(t_enter+epsray)*vec_los
3543 ix1=cart_dda_locate_index(pos(1),xface1,ixomin1,ixomax1)
3544 ix2=cart_dda_locate_index(pos(2),xface2,ixomin2,ixomax2)
3545 ix3=cart_dda_locate_index(pos(3),xface3,ixomin3,ixomax3)
3546
3547 call cart_dda_init_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1))
3548 call cart_dda_init_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2))
3549 call cart_dda_init_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3))
3550
3551 tnow=t_enter
3552 do
3553 tnext=min(t_exit,tmax(1),tmax(2),tmax(3))
3554 if (tnext>tnow) then
3555 ds_cm=(tnext-tnow)*unit_length
3556 if (si_unit) ds_cm=ds_cm*1.d2
3557 euvp=euvp+source(ix^d)*ds_cm
3558 dplp=dplp+sourcev(ix^d)*ds_cm
3559 endif
3560 tnow=tnext
3561 if (tnow>=t_exit-epsray) exit
3562
3563 if (tmax(1)<=tnow+epsray) then
3564 call cart_dda_advance_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1),done)
3565 if (done) exit
3566 endif
3567 if (tmax(2)<=tnow+epsray) then
3568 call cart_dda_advance_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2),done)
3569 if (done) exit
3570 endif
3571 if (tmax(3)<=tnow+epsray) then
3572 call cart_dda_advance_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3),done)
3573 if (done) exit
3574 endif
3575 enddo
3576 end subroutine acc_euv_cart_dda
3577
3578 subroutine append_cart_dda_segment(segments,nseg,capacity,pixel_id,tseg,jds,kds,jvds)
3579 double precision, allocatable, intent(inout) :: segments(:,:)
3580 integer, intent(inout) :: nseg,capacity
3581 integer, intent(in) :: pixel_id
3582 double precision, intent(in) :: tseg,jds,kds,jvds
3583
3584 double precision, allocatable :: tmp(:,:)
3585 integer :: new_capacity
3586
3587 if (capacity<=0) then
3588 capacity=1024
3589 allocate(segments(5,capacity))
3590 else if (nseg>=capacity) then
3591 new_capacity=2*capacity
3592 allocate(tmp(5,new_capacity))
3593 tmp(:,1:capacity)=segments(:,1:capacity)
3594 call move_alloc(tmp,segments)
3595 capacity=new_capacity
3596 endif
3597
3598 nseg=nseg+1
3599 segments(1,nseg)=dble(pixel_id)
3600 segments(2,nseg)=tseg
3601 segments(3,nseg)=jds
3602 segments(4,nseg)=kds
3603 segments(5,nseg)=jvds
3604 end subroutine append_cart_dda_segment
3605
3606 subroutine collect_euv_cart_dda_segments(ixI^L,ixO^L,source,opacity,sourcev,&
3607 pixel_id,ray_origin,xface1,xface2,xface3,t_enter,t_exit,&
3608 segments,nseg,capacity)
3609 integer, intent(in) :: ixI^L, ixO^L
3610 double precision, intent(in) :: source(ixI^S),opacity(ixI^S),sourcev(ixI^S)
3611 integer, intent(in) :: pixel_id
3612 double precision, intent(in) :: ray_origin(1:3)
3613 double precision, intent(in) :: xface1(ixOmin1:ixOmax1+1),xface2(ixOmin2:ixOmax2+1),&
3614 xface3(ixOmin3:ixOmax3+1)
3615 double precision, intent(in) :: t_enter,t_exit
3616 double precision, allocatable, intent(inout) :: segments(:,:)
3617 integer, intent(inout) :: nseg,capacity
3618
3619 integer :: ix^D,step(1:3)
3620 double precision :: pos(1:3),tMax(1:3),tNow,tNext,ds_cm,epsRay,tseg
3621 double precision :: jds,kds,jvds
3622 logical :: done
3623
3624 if (t_exit<=t_enter) return
3625 epsray=max(1.d-12,1.d-10*abs(t_exit-t_enter))
3626 pos=ray_origin+(t_enter+epsray)*vec_los
3627 ix1=cart_dda_locate_index(pos(1),xface1,ixomin1,ixomax1)
3628 ix2=cart_dda_locate_index(pos(2),xface2,ixomin2,ixomax2)
3629 ix3=cart_dda_locate_index(pos(3),xface3,ixomin3,ixomax3)
3630
3631 call cart_dda_init_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1))
3632 call cart_dda_init_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2))
3633 call cart_dda_init_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3))
3634
3635 tnow=t_enter
3636 do
3637 tnext=min(t_exit,tmax(1),tmax(2),tmax(3))
3638 if (tnext>tnow) then
3639 ds_cm=(tnext-tnow)*unit_length
3640 if (si_unit) ds_cm=ds_cm*1.d2
3641 jds=source(ix^d)*ds_cm
3642 kds=opacity(ix^d)*ds_cm
3643 jvds=sourcev(ix^d)*ds_cm
3644 if (jds/=zero .or. kds/=zero .or. jvds/=zero) then
3645 tseg=half*(tnow+tnext)
3646 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tseg,jds,kds,jvds)
3647 endif
3648 endif
3649 tnow=tnext
3650 if (tnow>=t_exit-epsray) exit
3651
3652 if (tmax(1)<=tnow+epsray) then
3653 call cart_dda_advance_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1),done)
3654 if (done) exit
3655 endif
3656 if (tmax(2)<=tnow+epsray) then
3657 call cart_dda_advance_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2),done)
3658 if (done) exit
3659 endif
3660 if (tmax(3)<=tnow+epsray) then
3661 call cart_dda_advance_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3),done)
3662 if (done) exit
3663 endif
3664 enddo
3665 end subroutine collect_euv_cart_dda_segments
3666
3667 subroutine sort_segment_indices_near_to_far(segments,idx,nidx)
3668 double precision, intent(in) :: segments(:,:)
3669 integer, intent(inout) :: idx(:)
3670 integer, intent(in) :: nidx
3671
3672 if (nidx<=1) return
3673 if (nidx<=32) then
3674 call insertion_sort_segment_indices(segments,idx,1,nidx)
3675 else
3676 call quicksort_segment_indices(segments,idx,1,nidx)
3677 endif
3679
3680 subroutine insertion_sort_segment_indices(segments,idx,ilo,ihi)
3681 double precision, intent(in) :: segments(:,:)
3682 integer, intent(inout) :: idx(:)
3683 integer, intent(in) :: ilo,ihi
3684
3685 integer :: i,j,key
3686
3687 do i=ilo+1,ihi
3688 key=idx(i)
3689 j=i-1
3690 do while (j>=ilo .and. segments(2,idx(j))>segments(2,key))
3691 idx(j+1)=idx(j)
3692 j=j-1
3693 enddo
3694 idx(j+1)=key
3695 enddo
3696 end subroutine insertion_sort_segment_indices
3697
3698 recursive subroutine quicksort_segment_indices(segments,idx,ilo,ihi)
3699 double precision, intent(in) :: segments(:,:)
3700 integer, intent(inout) :: idx(:)
3701 integer, intent(in) :: ilo,ihi
3702
3703 integer :: i,j,tmp
3704 double precision :: pivot
3705
3706 if (ihi-ilo<=32) then
3707 call insertion_sort_segment_indices(segments,idx,ilo,ihi)
3708 return
3709 endif
3710
3711 i=ilo
3712 j=ihi
3713 pivot=segments(2,idx((ilo+ihi)/2))
3714 do
3715 do while (segments(2,idx(i))<pivot)
3716 i=i+1
3717 enddo
3718 do while (segments(2,idx(j))>pivot)
3719 j=j-1
3720 enddo
3721 if (i<=j) then
3722 tmp=idx(i)
3723 idx(i)=idx(j)
3724 idx(j)=tmp
3725 i=i+1
3726 j=j-1
3727 endif
3728 if (i>j) exit
3729 enddo
3730
3731 if (ilo<j) call quicksort_segment_indices(segments,idx,ilo,j)
3732 if (i<ihi) call quicksort_segment_indices(segments,idx,i,ihi)
3733 end subroutine quicksort_segment_indices
3734
3735 integer function segment_pixel_owner(pixel_id) result(owner)
3736 integer, intent(in) :: pixel_id
3737
3738 owner=mod(pixel_id-1,npe)
3739 end function segment_pixel_owner
3740
3741 logical function segment_is_valid(segments,is,nvars) result(valid)
3742 double precision, intent(in) :: segments(:,:)
3743 integer, intent(in) :: is,nvars
3744
3745 integer :: iv
3746
3747 valid=.true.
3748 do iv=1,nvars
3749 if (segments(iv,is)/=segments(iv,is) .or. abs(segments(iv,is))>=1.d90) then
3750 valid=.false.
3751 return
3752 endif
3753 enddo
3754 end function segment_is_valid
3755
3756 subroutine cart_dda_block_pixel_range(box_min,box_max,nXIF1,nXIF2,xIF1,xIF2,ixPmin1,ixPmax1,ixPmin2,ixPmax2,has_pixels)
3757 double precision, intent(in) :: box_min(1:3),box_max(1:3)
3758 integer, intent(in) :: nXIF1,nXIF2
3759 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3760 integer, intent(out) :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
3761 logical, intent(out) :: has_pixels
3762
3763 integer :: i1,i2,i3
3764 double precision :: vec_cor(1:3),xI_cor(1:2)
3765 double precision :: xmin1,xmax1,xmin2,xmax2,dx1,dx2
3766
3767 do i1=1,2
3768 if (i1==1) vec_cor(1)=box_min(1)
3769 if (i1==2) vec_cor(1)=box_max(1)
3770 do i2=1,2
3771 if (i2==1) vec_cor(2)=box_min(2)
3772 if (i2==2) vec_cor(2)=box_max(2)
3773 do i3=1,2
3774 if (i3==1) vec_cor(3)=box_min(3)
3775 if (i3==2) vec_cor(3)=box_max(3)
3776 call get_cor_image(vec_cor,xi_cor)
3777 if (i1==1 .and. i2==1 .and. i3==1) then
3778 xmin1=xi_cor(1)
3779 xmax1=xi_cor(1)
3780 xmin2=xi_cor(2)
3781 xmax2=xi_cor(2)
3782 else
3783 xmin1=min(xmin1,xi_cor(1))
3784 xmax1=max(xmax1,xi_cor(1))
3785 xmin2=min(xmin2,xi_cor(2))
3786 xmax2=max(xmax2,xi_cor(2))
3787 endif
3788 enddo
3789 enddo
3790 enddo
3791
3792 if (nxif1>1) then
3793 dx1=abs(xif1(2)-xif1(1))
3794 else
3795 dx1=max(one,abs(xmax1-xmin1))
3796 endif
3797 if (nxif2>1) then
3798 dx2=abs(xif2(2)-xif2(1))
3799 else
3800 dx2=max(one,abs(xmax2-xmin2))
3801 endif
3802
3803 ixpmin1=max(1,floor((xmin1-xif1(1))/dx1)+1-1)
3804 ixpmax1=min(nxif1,ceiling((xmax1-xif1(1))/dx1)+1+1)
3805 ixpmin2=max(1,floor((xmin2-xif2(1))/dx2)+1-1)
3806 ixpmax2=min(nxif2,ceiling((xmax2-xif2(1))/dx2)+1+1)
3807 has_pixels=ixpmin1<=ixpmax1 .and. ixpmin2<=ixpmax2
3808 end subroutine cart_dda_block_pixel_range
3809
3810 subroutine integrate_euv_cart_dda_datresol(nXIF1,nXIF2,xIF1,xIF2,fl,EUV,Dpl)
3812
3813 integer, intent(in) :: nXIF1,nXIF2
3814 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3815 type(te_fluid), intent(in) :: fl
3816 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
3817
3818 integer :: ixO^L,ixO^D,ixI^L,ix^D
3819 integer :: iigrid,igrid,ixP1,ixP2,numSI,ixPmin1,ixPmax1,ixPmin2,ixPmax2
3820 double precision :: box_min(1:3),box_max(1:3),ray_origin(1:3)
3821 double precision :: t_enter,t_exit,vlos
3822 double precision :: profile_local(2),profile_global(2)
3823 logical :: hit,has_pixels
3824 double precision, allocatable :: source(:^D&),sourcev(:^D&),rho(:^D&),opacity(:^D&)
3825 double precision, allocatable :: xface1(:),xface2(:),xface3(:)
3826 double precision, allocatable :: EUVs(:,:),Dpls(:,:)
3827
3828 allocate(euvs(nxif1,nxif2),dpls(nxif1,nxif2))
3829 euvs=zero
3830 dpls=zero
3831 profile_local=zero
3832
3833 do iigrid=1,igridstail; igrid=igrids(iigrid);
3834 ^d&ixomin^d=ixmlo^d\
3835 ^d&ixomax^d=ixmhi^d\
3836 ^d&iximin^d=ixglo^d\
3837 ^d&iximax^d=ixghi^d\
3838
3839 box_min(1)=rnode(rpxmin1_,igrid)
3840 box_min(2)=rnode(rpxmin2_,igrid)
3841 box_min(3)=rnode(rpxmin3_,igrid)
3842 box_max(1)=rnode(rpxmax1_,igrid)
3843 box_max(2)=rnode(rpxmax2_,igrid)
3844 box_max(3)=rnode(rpxmax3_,igrid)
3845 call build_cart_dda_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,xface1,xface2,xface3)
3846 call cart_dda_block_pixel_range(box_min,box_max,nxif1,nxif2,xif1,xif2,&
3847 ixpmin1,ixpmax1,ixpmin2,ixpmax2,has_pixels)
3848 if (.not. has_pixels) then
3849 deallocate(xface1,xface2,xface3)
3850 cycle
3851 endif
3852
3853 allocate(source(ixi^s),sourcev(ixi^s),rho(ixi^s),opacity(ixi^s))
3854 source=zero
3855 sourcev=zero
3856 if (trim(emission_model)=='pseudo_current') then
3857 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,source)
3858 else if (trim(emission_model)=='radio_ff') then
3859 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,source,opacity)
3860 else
3861 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,source)
3862 source(ixo^s)=source(ixo^s)/instrument_resolution_factor**2
3863 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
3864 do ix1=ixomin1,ixomax1
3865 do ix2=ixomin2,ixomax2
3866 do ix3=ixomin3,ixomax3
3867 if (rho(ix^d)>smalldouble) then
3868 vlos=(ps(igrid)%w(ix^d,iw_mom(1))*vec_los(1)+&
3869 ps(igrid)%w(ix^d,iw_mom(2))*vec_los(2)+&
3870 ps(igrid)%w(ix^d,iw_mom(3))*vec_los(3))/rho(ix^d)
3871 sourcev(ix^d)=source(ix^d)*vlos
3872 endif
3873 enddo
3874 enddo
3875 enddo
3876 endif
3877 deallocate(rho,opacity)
3878
3879 do ixp1=ixpmin1,ixpmax1
3880 do ixp2=ixpmin2,ixpmax2
3881 ray_origin=x_origin+xif1(ixp1)*vec_xi1+xif2(ixp2)*vec_xi2
3882 profile_local(1)=profile_local(1)+one
3883 call ray_box_intersection_cart(ray_origin,vec_los,box_min,box_max,hit,t_enter,t_exit)
3884 if (hit) then
3885 profile_local(2)=profile_local(2)+one
3886 call acc_euv_cart_dda(ixi^l,ixo^l,source,sourcev,&
3887 ray_origin,xface1,xface2,xface3,t_enter,t_exit,euvs(ixp1,ixp2),dpls(ixp1,ixp2))
3888 endif
3889 enddo
3890 enddo
3891
3892 deallocate(source,sourcev,xface1,xface2,xface3)
3893 enddo
3894
3895 numsi=nxif1*nxif2
3896 call mpi_allreduce(euvs,euv,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
3897 call mpi_allreduce(dpls,dpl,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
3898 call mpi_allreduce(profile_local,profile_global,2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
3899 if (radsyn_verbose .and. mype==0) then
3900 write(*,'(a,2(es12.5,1x))') ' cart_dda thin profile ray_tests ray_hits: ',profile_global
3901 endif
3902 deallocate(euvs,dpls)
3903 end subroutine integrate_euv_cart_dda_datresol
3904
3905 subroutine integrate_euv_cart_dda_thick_datresol(nXIF1,nXIF2,xIF1,xIF2,fl,EUV,Dpl,Tau,EUVthin)
3907
3908 integer, intent(in) :: nXIF1,nXIF2
3909 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3910 type(te_fluid), intent(in) :: fl
3911 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
3912 double precision, intent(out) :: Tau(nXIF1,nXIF2),EUVthin(nXIF1,nXIF2)
3913
3914 integer, parameter :: nSegVars=5
3915 integer :: ixO^L,ixO^D,ixI^L,ix^D
3916 integer :: iigrid,igrid,ixP1,ixP2,ipix,ipixStart,ipixEnd,nPixBatch,pixel_id
3917 integer :: nseg,capacity,totalCount,totalSeg,ipe,is,iseg,nidx,owner,isegDest,nsegBefore
3918 integer :: ixGlobal,iyGlobal,ixPmin1,ixPmax1,ixPmin2,ixPmax2,iFirst,iLast,iLocal
3919 integer :: nPixBatchTarget
3920 integer :: maxSegBatchTarget,maxSegCommTarget,maxNsegBatch,nPixTotal
3921 integer :: maxOwnerSegCount,maxOwnerSegCountLocal,segOffset,recvFill,totalRoundCount,totalRoundSeg
3922 integer, allocatable :: sendCounts(:),recvCounts(:),sendDispls(:),recvDispls(:)
3923 integer, allocatable :: roundSendCounts(:),roundRecvCounts(:)
3924 integer, allocatable :: roundSendDispls(:),roundRecvDispls(:)
3925 integer, allocatable :: ownerSegCounts(:),ownerOffsets(:),idx(:)
3926 integer, allocatable :: bucketCounts(:),bucketOffsets(:),bucketFill(:)
3927 double precision :: ray_origin(1:3)
3928 double precision :: t_enter,t_exit,vlos,atten
3929 double precision :: profile_local(5),profile_global(5),profile_batch(5)
3930 logical :: hit,has_pixels,batchAccepted,batchReduced
3931 double precision, allocatable :: rho(:^D&)
3932 double precision, allocatable :: segments(:,:),segments_send(:,:),segments_recv(:,:)
3933 double precision, allocatable :: segments_recv_round(:,:)
3934 double precision, allocatable :: image_reduce(:,:)
3935 type(radsyn_euv_cache), allocatable :: cache(:)
3936
3937 euv=zero
3938 dpl=zero
3939 tau=zero
3940 euvthin=zero
3941 profile_local=zero
3942 allocate(sendcounts(0:npe-1),recvcounts(0:npe-1),senddispls(0:npe-1),recvdispls(0:npe-1))
3943 allocate(roundsendcounts(0:npe-1),roundrecvcounts(0:npe-1))
3944 allocate(roundsenddispls(0:npe-1),roundrecvdispls(0:npe-1))
3945 allocate(ownersegcounts(0:npe-1),owneroffsets(0:npe-1))
3946 allocate(cache(igridstail))
3947 call radsyn_get_segment_batch_limits(npixbatchtarget,maxsegbatchtarget,maxsegcommtarget)
3948 allocate(bucketcounts(npixbatchtarget),bucketoffsets(npixbatchtarget+1),&
3949 bucketfill(npixbatchtarget))
3950
3951 do iigrid=1,igridstail; igrid=igrids(iigrid);
3952 ^d&ixomin^d=ixmlo^d\
3953 ^d&ixomax^d=ixmhi^d\
3954 ^d&iximin^d=ixglo^d\
3955 ^d&iximax^d=ixghi^d\
3956
3957 cache(iigrid)%igrid=igrid
3958 allocate(cache(iigrid)%source(ixi^s),cache(iigrid)%opacity(ixi^s),&
3959 cache(iigrid)%sourcev(ixi^s),rho(ixi^s))
3960 cache(iigrid)%source=zero
3961 cache(iigrid)%opacity=zero
3962 cache(iigrid)%sourcev=zero
3963 if (trim(emission_model)=='radio_ff') then
3964 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,&
3965 cache(iigrid)%source,cache(iigrid)%opacity)
3966 else
3967 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%source)
3968 cache(iigrid)%source(ixo^s)=cache(iigrid)%source(ixo^s)/instrument_resolution_factor**2
3969 call get_euv_hhe_opacity(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%opacity)
3970 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
3971 do ix1=ixomin1,ixomax1
3972 do ix2=ixomin2,ixomax2
3973 do ix3=ixomin3,ixomax3
3974 if (rho(ix^d)>smalldouble) then
3975 vlos=(ps(igrid)%w(ix^d,iw_mom(1))*vec_los(1)+&
3976 ps(igrid)%w(ix^d,iw_mom(2))*vec_los(2)+&
3977 ps(igrid)%w(ix^d,iw_mom(3))*vec_los(3))/rho(ix^d)
3978 cache(iigrid)%sourcev(ix^d)=cache(iigrid)%source(ix^d)*vlos
3979 endif
3980 enddo
3981 enddo
3982 enddo
3983 endif
3984 deallocate(rho)
3985 cache(iigrid)%box_min(1)=rnode(rpxmin1_,igrid)
3986 cache(iigrid)%box_min(2)=rnode(rpxmin2_,igrid)
3987 cache(iigrid)%box_min(3)=rnode(rpxmin3_,igrid)
3988 cache(iigrid)%box_max(1)=rnode(rpxmax1_,igrid)
3989 cache(iigrid)%box_max(2)=rnode(rpxmax2_,igrid)
3990 cache(iigrid)%box_max(3)=rnode(rpxmax3_,igrid)
3991 call build_cart_dda_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,&
3992 cache(iigrid)%xface1,cache(iigrid)%xface2,&
3993 cache(iigrid)%xface3)
3994 call cart_dda_block_pixel_range(cache(iigrid)%box_min,cache(iigrid)%box_max,&
3995 nxif1,nxif2,xif1,xif2,cache(iigrid)%ixPmin1,cache(iigrid)%ixPmax1,&
3996 cache(iigrid)%ixPmin2,cache(iigrid)%ixPmax2,cache(iigrid)%has_pixels)
3997 enddo
3998
3999 npixtotal=nxif1*nxif2
4000 ipixstart=1
4001 do while (ipixstart<=npixtotal)
4002 ipixend=min(nxif1*nxif2,ipixstart+npixbatchtarget-1)
4003 npixbatch=ipixend-ipixstart+1
4004 batchaccepted=.false.
4005 batchreduced=.false.
4006
4007 do while (.not. batchaccepted)
4008 nseg=0
4009 capacity=0
4010 profile_batch=zero
4011
4012 do iigrid=1,igridstail; igrid=igrids(iigrid);
4013 ^d&ixomin^d=ixmlo^d\
4014 ^d&ixomax^d=ixmhi^d\
4015 ^d&iximin^d=ixglo^d\
4016 ^d&iximax^d=ixghi^d\
4017
4018 ixpmin1=cache(iigrid)%ixPmin1
4019 ixpmax1=cache(iigrid)%ixPmax1
4020 ixpmin2=cache(iigrid)%ixPmin2
4021 ixpmax2=cache(iigrid)%ixPmax2
4022 has_pixels=cache(iigrid)%has_pixels
4023 if (.not. has_pixels) cycle
4024
4025 do ixp2=ixpmin2,ixpmax2
4026 ifirst=max(ipixstart,(ixp2-1)*nxif1+ixpmin1)
4027 ilast=min(ipixend,(ixp2-1)*nxif1+ixpmax1)
4028 if (ifirst>ilast) cycle
4029 do ipix=ifirst,ilast
4030 ixp1=1+mod(ipix-1,nxif1)
4031 ray_origin=x_origin+xif1(ixp1)*vec_xi1+xif2(ixp2)*vec_xi2
4032 profile_batch(1)=profile_batch(1)+one
4033 call ray_box_intersection_cart(ray_origin,vec_los,cache(iigrid)%box_min,&
4034 cache(iigrid)%box_max,hit,t_enter,t_exit)
4035 if (hit) then
4036 profile_batch(2)=profile_batch(2)+one
4037 nsegbefore=nseg
4038 call collect_euv_cart_dda_segments(ixi^l,ixo^l,cache(iigrid)%source,&
4039 cache(iigrid)%opacity,cache(iigrid)%sourcev,&
4040 ipix,ray_origin,cache(iigrid)%xface1,&
4041 cache(iigrid)%xface2,cache(iigrid)%xface3,&
4042 t_enter,t_exit,&
4043 segments,nseg,capacity)
4044 profile_batch(3)=profile_batch(3)+dble(nseg-nsegbefore)
4045 endif
4046 enddo
4047 enddo
4048 enddo
4049
4050 call mpi_allreduce(nseg,maxnsegbatch,1,mpi_integer,mpi_max,icomm,ierrmpi)
4051 if (maxnsegbatch>maxsegbatchtarget .and. npixbatch>1) then
4052 npixbatch=max(1,npixbatch/2)
4053 ipixend=ipixstart+npixbatch-1
4054 if (allocated(segments)) deallocate(segments)
4055 batchreduced=.true.
4056 else
4057 batchaccepted=.true.
4058 endif
4059 enddo
4060
4061 profile_local=profile_local+profile_batch
4062 if (radsyn_verbose .and. mype==0 .and. batchreduced) then
4063 write(*,'(a,3(i0,1x))') ' cart_dda thick adaptive batch: ',&
4064 ipixstart,ipixend,maxnsegbatch
4065 endif
4066
4067 if (.not. allocated(segments)) then
4068 capacity=1
4069 allocate(segments(nsegvars,capacity))
4070 endif
4071 ownersegcounts=0
4072 do is=1,nseg
4073 owner=segment_pixel_owner(nint(segments(1,is)))
4074 ownersegcounts(owner)=ownersegcounts(owner)+1
4075 enddo
4076 sendcounts=nsegvars*ownersegcounts
4077 senddispls(0)=0
4078 do ipe=1,npe-1
4079 senddispls(ipe)=senddispls(ipe-1)+sendcounts(ipe-1)
4080 enddo
4081
4082 allocate(segments_send(nsegvars,max(1,nseg)))
4083 owneroffsets=0
4084 do is=1,nseg
4085 owner=segment_pixel_owner(nint(segments(1,is)))
4086 isegdest=senddispls(owner)/nsegvars+owneroffsets(owner)+1
4087 segments_send(:,isegdest)=segments(:,is)
4088 owneroffsets(owner)=owneroffsets(owner)+1
4089 enddo
4090
4091 call mpi_alltoall(sendcounts,1,mpi_integer,recvcounts,1,mpi_integer,icomm,ierrmpi)
4092 recvdispls(0)=0
4093 do ipe=1,npe-1
4094 recvdispls(ipe)=recvdispls(ipe-1)+recvcounts(ipe-1)
4095 enddo
4096 totalcount=sum(recvcounts)
4097 totalseg=totalcount/nsegvars
4098 profile_local(4)=profile_local(4)+dble(totalcount)
4099 allocate(segments_recv(nsegvars,max(1,totalseg)))
4100
4101 recvfill=0
4102 maxownersegcountlocal=maxval(ownersegcounts)
4103 call mpi_allreduce(maxownersegcountlocal,maxownersegcount,1,mpi_integer,mpi_max,icomm,ierrmpi)
4104 do segoffset=0,maxownersegcount-1,maxsegcommtarget
4105 roundsendcounts=0
4106 roundsenddispls=senddispls
4107 do ipe=0,npe-1
4108 if (ownersegcounts(ipe)>segoffset) then
4109 roundsendcounts(ipe)=nsegvars*min(maxsegcommtarget,ownersegcounts(ipe)-segoffset)
4110 roundsenddispls(ipe)=senddispls(ipe)+nsegvars*segoffset
4111 endif
4112 enddo
4113
4114 call mpi_alltoall(roundsendcounts,1,mpi_integer,roundrecvcounts,1,mpi_integer,icomm,ierrmpi)
4115 roundrecvdispls(0)=0
4116 do ipe=1,npe-1
4117 roundrecvdispls(ipe)=roundrecvdispls(ipe-1)+roundrecvcounts(ipe-1)
4118 enddo
4119 totalroundcount=sum(roundrecvcounts)
4120 totalroundseg=totalroundcount/nsegvars
4121 allocate(segments_recv_round(nsegvars,max(1,totalroundseg)))
4122
4123 call mpi_alltoallv(segments_send,roundsendcounts,roundsenddispls,mpi_double_precision,&
4124 segments_recv_round,roundrecvcounts,roundrecvdispls,&
4125 mpi_double_precision,icomm,ierrmpi)
4126
4127 if (totalroundseg>0) then
4128 segments_recv(:,recvfill+1:recvfill+totalroundseg)=segments_recv_round(:,1:totalroundseg)
4129 recvfill=recvfill+totalroundseg
4130 endif
4131 deallocate(segments_recv_round)
4132 enddo
4133
4134 if (recvfill/=totalseg) call mpistop("cart_dda thick segmented receive mismatch")
4135
4136 if (totalseg>0) then
4137 allocate(idx(totalseg))
4138 bucketcounts(1:npixbatch)=0
4139 do is=1,totalseg
4140 if (segment_is_valid(segments_recv,is,nsegvars)) then
4141 ipix=nint(segments_recv(1,is))
4142 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
4143 ilocal=ipix-ipixstart+1
4144 bucketcounts(ilocal)=bucketcounts(ilocal)+1
4145 endif
4146 endif
4147 enddo
4148
4149 bucketoffsets(1)=1
4150 do ilocal=1,npixbatch
4151 bucketoffsets(ilocal+1)=bucketoffsets(ilocal)+bucketcounts(ilocal)
4152 enddo
4153 bucketfill(1:npixbatch)=bucketoffsets(1:npixbatch)
4154 do is=1,totalseg
4155 if (segment_is_valid(segments_recv,is,nsegvars)) then
4156 ipix=nint(segments_recv(1,is))
4157 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
4158 ilocal=ipix-ipixstart+1
4159 idx(bucketfill(ilocal))=is
4160 bucketfill(ilocal)=bucketfill(ilocal)+1
4161 endif
4162 endif
4163 enddo
4164
4165 do ipix=ipixstart,ipixend
4166 if (segment_pixel_owner(ipix)/=mype) cycle
4167 ilocal=ipix-ipixstart+1
4168 nidx=bucketcounts(ilocal)
4169 if (nidx>0) then
4170 profile_local(5)=profile_local(5)+dble(nidx)*dble(nidx)
4171 call sort_segment_indices_near_to_far(segments_recv,idx(bucketoffsets(ilocal):bucketoffsets(ilocal+1)-1),nidx)
4172 ixglobal=1+mod(ipix-1,nxif1)
4173 iyglobal=1+(ipix-1)/nxif1
4174 do iseg=bucketoffsets(ilocal),bucketoffsets(ilocal+1)-1
4175 is=idx(iseg)
4176 euvthin(ixglobal,iyglobal)=euvthin(ixglobal,iyglobal)+segments_recv(3,is)
4177 atten=transfer_attenuation(tau(ixglobal,iyglobal))
4178 euv(ixglobal,iyglobal)=euv(ixglobal,iyglobal)+atten*segments_recv(3,is)
4179 dpl(ixglobal,iyglobal)=dpl(ixglobal,iyglobal)+atten*segments_recv(5,is)
4180 tau(ixglobal,iyglobal)=tau(ixglobal,iyglobal)+max(zero,segments_recv(4,is))
4181 enddo
4182 endif
4183 enddo
4184 deallocate(idx)
4185 endif
4186
4187 deallocate(segments_send,segments_recv)
4188 if (allocated(segments)) deallocate(segments)
4189 ipixstart=ipixend+1
4190 enddo
4191
4192 do iigrid=1,igridstail
4193 if (allocated(cache(iigrid)%source)) deallocate(cache(iigrid)%source)
4194 if (allocated(cache(iigrid)%opacity)) deallocate(cache(iigrid)%opacity)
4195 if (allocated(cache(iigrid)%sourcev)) deallocate(cache(iigrid)%sourcev)
4196 if (allocated(cache(iigrid)%xface1)) deallocate(cache(iigrid)%xface1)
4197 if (allocated(cache(iigrid)%xface2)) deallocate(cache(iigrid)%xface2)
4198 if (allocated(cache(iigrid)%xface3)) deallocate(cache(iigrid)%xface3)
4199 enddo
4200 deallocate(cache)
4201 deallocate(sendcounts,recvcounts,senddispls,recvdispls,roundsendcounts,roundrecvcounts,&
4202 roundsenddispls,roundrecvdispls,ownersegcounts,owneroffsets,bucketcounts,&
4203 bucketoffsets,bucketfill)
4204 allocate(image_reduce(nxif1,nxif2))
4205 call mpi_allreduce(euv,image_reduce,nxif1*nxif2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4206 euv=image_reduce
4207 call mpi_allreduce(dpl,image_reduce,nxif1*nxif2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4208 dpl=image_reduce
4209 call mpi_allreduce(tau,image_reduce,nxif1*nxif2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4210 tau=image_reduce
4211 call mpi_allreduce(euvthin,image_reduce,nxif1*nxif2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4212 euvthin=image_reduce
4213 deallocate(image_reduce)
4214 call mpi_allreduce(profile_local,profile_global,5,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4215 if (radsyn_verbose .and. mype==0) then
4216 write(*,'(a,5(es12.5,1x))') &
4217 ' cart_dda thick profile: ',profile_global
4218 endif
4220
4221 subroutine integrate_euv_thick_datresol(nXIF1,nXIF2,fl,EUV,Dpl,Tau,EUVthin)
4223
4224 integer, intent(in) :: nXIF1,nXIF2
4225 type(te_fluid), intent(in) :: fl
4226 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
4227 double precision, intent(out) :: Tau(nXIF1,nXIF2),EUVthin(nXIF1,nXIF2)
4228
4229 integer :: ixO^L,ixO^D,ixI^L,ix^D
4230 integer :: iigrid,igrid,levelg,rft,direction_LOS,nLOS,numSeg,nLayerVars,nLayerSeg
4231 integer :: ixP1,ixP2,ixL,iSub1,iSub2,relL
4232 integer :: nLosBatch,nBatch,iBatch,ixLstart,ixLend,ixLgridStart,ixLgridEnd
4233 integer :: ixPmin1,ixPmin2
4234 double precision :: ds_cm,jds,kds,jvds,atten,layerBytes,targetBytes
4235 double precision, allocatable :: rho(:^D&)
4236 double precision, allocatable :: layer_ds(:,:,:,:),layer_all(:,:,:,:)
4237 type(radsyn_euv_cache), allocatable :: cache(:)
4238
4239 if (los_phi==0 .and. los_theta==90) then
4240 direction_los=1
4241 nlos=domain_nx1*2**(refine_max_level-1)
4242 else if (los_phi==90 .and. los_theta==90) then
4243 direction_los=2
4244 nlos=domain_nx2*2**(refine_max_level-1)
4245 else
4246 direction_los=3
4247 nlos=domain_nx3*2**(refine_max_level-1)
4248 endif
4249
4250 nlayervars=3
4251 if (nxif1>huge(numseg)/max(1,nxif2) .or. nxif1*nxif2>huge(numseg)/nlayervars) then
4252 call mpistop("thick EUV layer buffer is too large for one MPI reduction")
4253 endif
4254 nlayerseg=nxif1*nxif2*nlayervars
4255 targetbytes=256.d0*1024.d0*1024.d0
4256 layerbytes=dble(nlayerseg)*8.d0*2.d0
4257 nlosbatch=max(1,min(16,int(targetbytes/max(one,layerbytes))))
4258 if (nlayerseg>huge(numseg)/nlosbatch) then
4259 call mpistop("thick EUV batched layer buffer is too large for one MPI reduction")
4260 endif
4261
4262 allocate(cache(igridstail))
4263 do iigrid=1,igridstail; igrid=igrids(iigrid);
4264 ^d&ixomin^d=ixmlo^d\
4265 ^d&ixomax^d=ixmhi^d\
4266 ^d&iximin^d=ixglo^d\
4267 ^d&iximax^d=ixghi^d\
4268
4269 cache(iigrid)%igrid=igrid
4270 levelg=ps(igrid)%level
4271 rft=2**(refine_max_level-levelg)
4272 cache(iigrid)%level=levelg
4273 cache(iigrid)%rft=rft
4274
4275 select case(direction_los)
4276 case(1)
4277 cache(iigrid)%los_min=(node(pig1_,igrid)-1)*rft*block_nx1+1
4278 cache(iigrid)%los_max=node(pig1_,igrid)*rft*block_nx1
4279 case(2)
4280 cache(iigrid)%los_min=(node(pig2_,igrid)-1)*rft*block_nx2+1
4281 cache(iigrid)%los_max=node(pig2_,igrid)*rft*block_nx2
4282 case(3)
4283 cache(iigrid)%los_min=(node(pig3_,igrid)-1)*rft*block_nx3+1
4284 cache(iigrid)%los_max=node(pig3_,igrid)*rft*block_nx3
4285 end select
4286
4287 allocate(cache(iigrid)%source(ixi^s),cache(iigrid)%opacity(ixi^s),&
4288 cache(iigrid)%sourcev(ixi^s),rho(ixi^s))
4289 cache(iigrid)%source=zero
4290 cache(iigrid)%opacity=zero
4291 cache(iigrid)%sourcev=zero
4292 if (trim(emission_model)=='radio_ff') then
4293 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,&
4294 cache(iigrid)%source,cache(iigrid)%opacity)
4295 else
4296 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%source)
4297 cache(iigrid)%source(ixo^s)=cache(iigrid)%source(ixo^s)/instrument_resolution_factor**2
4298 call get_euv_hhe_opacity(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%opacity)
4299 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
4300 cache(iigrid)%sourcev(ixo^s)=cache(iigrid)%source(ixo^s)*&
4301 (-ps(igrid)%w(ixo^s,iw_mom(direction_los))/rho(ixo^s))
4302 endif
4303 deallocate(rho)
4304 enddo
4305
4306 ! Stream a small batch of finest LOS layers; this avoids a full Npix*Nlos column buffer.
4307 allocate(layer_ds(nxif1,nxif2,nlayervars,nlosbatch),layer_all(nxif1,nxif2,nlayervars,nlosbatch))
4308 euv=zero
4309 dpl=zero
4310 tau=zero
4311 euvthin=zero
4312
4313 do ixlstart=1,nlos,nlosbatch
4314 ixlend=min(nlos,ixlstart+nlosbatch-1)
4315 nbatch=ixlend-ixlstart+1
4316 layer_ds(:,:,:,1:nbatch)=zero
4317
4318 do iigrid=1,igridstail
4319 ixlgridstart=max(ixlstart,cache(iigrid)%los_min)
4320 ixlgridend=min(ixlend,cache(iigrid)%los_max)
4321 if (ixlgridstart>ixlgridend) cycle
4322 igrid=cache(iigrid)%igrid
4323 rft=cache(iigrid)%rft
4324 ^d&ixomin^d=ixmlo^d\
4325 ^d&ixomax^d=ixmhi^d\
4326 ^d&iximin^d=ixglo^d\
4327 ^d&iximax^d=ixghi^d\
4328
4329 do ixl=ixlgridstart,ixlgridend
4330 ibatch=ixl-ixlstart+1
4331 rell=ixl-cache(iigrid)%los_min
4332
4333 select case(direction_los)
4334 case(1)
4335 ix1=ixomin1+rell/rft
4336 do ix2=ixomin2,ixomax2
4337 ixpmin1=(node(pig2_,igrid)-1)*rft*block_nx2+(ix2-ixomin2)*rft+1
4338 do ix3=ixomin3,ixomax3
4339 ixpmin2=(node(pig3_,igrid)-1)*rft*block_nx3+(ix3-ixomin3)*rft+1
4340 ds_cm=ps(igrid)%dx(ix^d,1)*unit_length/dble(rft)
4341 if (si_unit) ds_cm=ds_cm*1.d2
4342 jds=cache(iigrid)%source(ix^d)*ds_cm
4343 kds=cache(iigrid)%opacity(ix^d)*ds_cm
4344 jvds=cache(iigrid)%sourcev(ix^d)*ds_cm
4345 do isub1=0,rft-1
4346 ixp1=ixpmin1+isub1
4347 do isub2=0,rft-1
4348 ixp2=ixpmin2+isub2
4349 layer_ds(ixp1,ixp2,1,ibatch)=layer_ds(ixp1,ixp2,1,ibatch)+jds
4350 layer_ds(ixp1,ixp2,2,ibatch)=layer_ds(ixp1,ixp2,2,ibatch)+kds
4351 layer_ds(ixp1,ixp2,3,ibatch)=layer_ds(ixp1,ixp2,3,ibatch)+jvds
4352 enddo
4353 enddo
4354 enddo
4355 enddo
4356 case(2)
4357 ix2=ixomin2+rell/rft
4358 do ix3=ixomin3,ixomax3
4359 ixpmin1=(node(pig3_,igrid)-1)*rft*block_nx3+(ix3-ixomin3)*rft+1
4360 do ix1=ixomin1,ixomax1
4361 ixpmin2=(node(pig1_,igrid)-1)*rft*block_nx1+(ix1-ixomin1)*rft+1
4362 ds_cm=ps(igrid)%dx(ix^d,2)*unit_length/dble(rft)
4363 if (si_unit) ds_cm=ds_cm*1.d2
4364 jds=cache(iigrid)%source(ix^d)*ds_cm
4365 kds=cache(iigrid)%opacity(ix^d)*ds_cm
4366 jvds=cache(iigrid)%sourcev(ix^d)*ds_cm
4367 do isub1=0,rft-1
4368 ixp1=ixpmin1+isub1
4369 do isub2=0,rft-1
4370 ixp2=ixpmin2+isub2
4371 layer_ds(ixp1,ixp2,1,ibatch)=layer_ds(ixp1,ixp2,1,ibatch)+jds
4372 layer_ds(ixp1,ixp2,2,ibatch)=layer_ds(ixp1,ixp2,2,ibatch)+kds
4373 layer_ds(ixp1,ixp2,3,ibatch)=layer_ds(ixp1,ixp2,3,ibatch)+jvds
4374 enddo
4375 enddo
4376 enddo
4377 enddo
4378 case(3)
4379 ix3=ixomin3+rell/rft
4380 do ix1=ixomin1,ixomax1
4381 ixpmin1=(node(pig1_,igrid)-1)*rft*block_nx1+(ix1-ixomin1)*rft+1
4382 do ix2=ixomin2,ixomax2
4383 ixpmin2=(node(pig2_,igrid)-1)*rft*block_nx2+(ix2-ixomin2)*rft+1
4384 ds_cm=ps(igrid)%dx(ix^d,3)*unit_length/dble(rft)
4385 if (si_unit) ds_cm=ds_cm*1.d2
4386 jds=cache(iigrid)%source(ix^d)*ds_cm
4387 kds=cache(iigrid)%opacity(ix^d)*ds_cm
4388 jvds=cache(iigrid)%sourcev(ix^d)*ds_cm
4389 do isub1=0,rft-1
4390 ixp1=ixpmin1+isub1
4391 do isub2=0,rft-1
4392 ixp2=ixpmin2+isub2
4393 layer_ds(ixp1,ixp2,1,ibatch)=layer_ds(ixp1,ixp2,1,ibatch)+jds
4394 layer_ds(ixp1,ixp2,2,ibatch)=layer_ds(ixp1,ixp2,2,ibatch)+kds
4395 layer_ds(ixp1,ixp2,3,ibatch)=layer_ds(ixp1,ixp2,3,ibatch)+jvds
4396 enddo
4397 enddo
4398 enddo
4399 enddo
4400 end select
4401 enddo
4402 enddo
4403
4404 numseg=nlayerseg*nbatch
4405 call mpi_allreduce(layer_ds,layer_all,numseg,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4406
4407 do ibatch=1,nbatch
4408 !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(atten) SCHEDULE(static)
4409 do ixp1=1,nxif1
4410 do ixp2=1,nxif2
4411 euvthin(ixp1,ixp2)=euvthin(ixp1,ixp2)+layer_all(ixp1,ixp2,1,ibatch)
4412 atten=transfer_attenuation(tau(ixp1,ixp2))
4413 euv(ixp1,ixp2)=euv(ixp1,ixp2)+atten*layer_all(ixp1,ixp2,1,ibatch)
4414 dpl(ixp1,ixp2)=dpl(ixp1,ixp2)+atten*layer_all(ixp1,ixp2,3,ibatch)
4415 tau(ixp1,ixp2)=tau(ixp1,ixp2)+layer_all(ixp1,ixp2,2,ibatch)
4416 enddo
4417 enddo
4418 !$OMP END PARALLEL DO
4419 enddo
4420 enddo
4421
4422 do iigrid=1,igridstail
4423 if (allocated(cache(iigrid)%source)) deallocate(cache(iigrid)%source)
4424 if (allocated(cache(iigrid)%opacity)) deallocate(cache(iigrid)%opacity)
4425 if (allocated(cache(iigrid)%sourcev)) deallocate(cache(iigrid)%sourcev)
4426 enddo
4427 deallocate(cache,layer_ds,layer_all)
4428
4429 end subroutine integrate_euv_thick_datresol
4430
4431 }
4432
4433 {^ifthreed
4434
4435 subroutine build_sph_intersection_faces(ixI^L,ixO^L,x,dx,rface,thetaface,phiface)
4436 integer, intent(in) :: ixI^L, ixO^L
4437 double precision, intent(in) :: x(ixI^S,1:ndim),dx(ixI^S,1:ndim)
4438 double precision, allocatable, intent(out) :: rface(:),thetaface(:),phiface(:)
4439 integer :: ix1,ix2,ix3
4440
4441 allocate(rface(ixomin1:ixomax1+1),thetaface(ixomin2:ixomax2+1),phiface(ixomin3:ixomax3+1))
4442 do ix1=ixomin1,ixomax1
4443 rface(ix1)=x(ix1,ixomin2,ixomin3,1)-half*dx(ix1,ixomin2,ixomin3,1)
4444 enddo
4445 rface(ixomax1+1)=x(ixomax1,ixomin2,ixomin3,1)+half*dx(ixomax1,ixomin2,ixomin3,1)
4446 do ix2=ixomin2,ixomax2
4447 thetaface(ix2)=x(ixomin1,ix2,ixomin3,2)-half*dx(ixomin1,ix2,ixomin3,2)
4448 enddo
4449 thetaface(ixomax2+1)=x(ixomin1,ixomax2,ixomin3,2)+half*dx(ixomin1,ixomax2,ixomin3,2)
4450 do ix3=ixomin3,ixomax3
4451 phiface(ix3)=x(ixomin1,ixomin2,ix3,3)-half*dx(ixomin1,ixomin2,ix3,3)
4452 enddo
4453 phiface(ixomax3+1)=x(ixomin1,ixomin2,ixomax3,3)+half*dx(ixomin1,ixomin2,ixomax3,3)
4454 end subroutine build_sph_intersection_faces
4455
4456 subroutine sph_add_t(tvals,nt,capacity,t)
4457 double precision, allocatable, intent(inout) :: tvals(:)
4458 integer, intent(inout) :: nt,capacity
4459 double precision, intent(in) :: t
4460
4461 double precision, allocatable :: tmp(:)
4462
4463 if (t /= t .or. abs(t)>1.d90) return
4464 if (.not. allocated(tvals)) then
4465 capacity=64
4466 allocate(tvals(capacity))
4467 else if (nt>=capacity) then
4468 allocate(tmp(capacity))
4469 tmp=tvals
4470 deallocate(tvals)
4471 allocate(tvals(2*capacity))
4472 tvals(1:capacity)=tmp
4473 deallocate(tmp)
4474 capacity=2*capacity
4475 endif
4476 nt=nt+1
4477 tvals(nt)=t
4478 end subroutine sph_add_t
4479
4480 subroutine sph_add_t_fixed(tvals,nt,t)
4481 double precision, intent(inout) :: tvals(:)
4482 integer, intent(inout) :: nt
4483 double precision, intent(in) :: t
4484
4485 if (t /= t .or. abs(t)>1.d90) return
4486 if (nt>=size(tvals)) return
4487 nt=nt+1
4488 tvals(nt)=t
4489 end subroutine sph_add_t_fixed
4490
4491 subroutine sph_sort_unique_t(tvals,nt)
4492 double precision, intent(inout) :: tvals(:)
4493 integer, intent(inout) :: nt
4494
4495 integer :: i,j,nout
4496 double precision :: key,epsT
4497
4498 if (nt<=1) return
4499 do i=2,nt
4500 key=tvals(i)
4501 j=i-1
4502 do while (j>=1 .and. tvals(j)>key)
4503 tvals(j+1)=tvals(j)
4504 j=j-1
4505 enddo
4506 tvals(j+1)=key
4507 enddo
4508 epst=max(1.d-12,1.d-10*max(one,abs(tvals(nt)-tvals(1))))
4509 nout=1
4510 do i=2,nt
4511 if (abs(tvals(i)-tvals(nout))>epst) then
4512 nout=nout+1
4513 tvals(nout)=tvals(i)
4514 endif
4515 enddo
4516 nt=nout
4517 end subroutine sph_sort_unique_t
4518
4519 subroutine sph_add_sphere_intersections(ray_origin,ray_dir,rface,tvals,nt,capacity)
4520 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),rface
4521 double precision, allocatable, intent(inout) :: tvals(:)
4522 integer, intent(inout) :: nt,capacity
4523
4524 double precision :: aa,bb,cc,disc,root
4525
4526 aa=sum(ray_dir**2)
4527 bb=2.d0*sum(ray_origin*ray_dir)
4528 cc=sum(ray_origin**2)-rface**2
4529 disc=bb**2-4.d0*aa*cc
4530 if (disc<zero) return
4531 root=sqrt(max(zero,disc))
4532 call sph_add_t(tvals,nt,capacity,(-bb-root)/(2.d0*aa))
4533 call sph_add_t(tvals,nt,capacity,(-bb+root)/(2.d0*aa))
4534 end subroutine sph_add_sphere_intersections
4535
4536 subroutine sph_add_theta_intersections(ray_origin,ray_dir,thetaface,tvals,nt,capacity)
4537 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),thetaface
4538 double precision, allocatable, intent(inout) :: tvals(:)
4539 integer, intent(inout) :: nt,capacity
4540
4541 double precision :: cth,aa,bb,cc,disc,root
4542
4543 cth=cos(thetaface)
4544 ! At the equator the cone equation degenerates to z**2=0. Solve the
4545 ! corresponding plane intersection directly to avoid losing its double
4546 ! root through roundoff in the quadratic discriminant.
4547 if (abs(cth)<1.d-12) then
4548 if (abs(ray_dir(3))>1.d-14) &
4549 call sph_add_t(tvals,nt,capacity,-ray_origin(3)/ray_dir(3))
4550 return
4551 endif
4552 aa=ray_dir(3)**2-cth**2*sum(ray_dir**2)
4553 bb=2.d0*(ray_origin(3)*ray_dir(3)-cth**2*sum(ray_origin*ray_dir))
4554 cc=ray_origin(3)**2-cth**2*sum(ray_origin**2)
4555 if (abs(aa)<1.d-14) then
4556 if (abs(bb)>1.d-14) call sph_add_t(tvals,nt,capacity,-cc/bb)
4557 return
4558 endif
4559 disc=bb**2-4.d0*aa*cc
4560 if (disc<zero) return
4561 root=sqrt(max(zero,disc))
4562 call sph_add_t(tvals,nt,capacity,(-bb-root)/(2.d0*aa))
4563 call sph_add_t(tvals,nt,capacity,(-bb+root)/(2.d0*aa))
4564 end subroutine sph_add_theta_intersections
4565
4566 subroutine sph_add_phi_intersection(ray_origin,ray_dir,phiface,tvals,nt,capacity)
4567 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),phiface
4568 double precision, allocatable, intent(inout) :: tvals(:)
4569 integer, intent(inout) :: nt,capacity
4570
4571 double precision :: normal(1:3),denom,numer
4572
4573 normal(1)=-sin(phiface)
4574 normal(2)=cos(phiface)
4575 normal(3)=zero
4576 denom=sum(normal*ray_dir)
4577 if (abs(denom)<1.d-14) return
4578 numer=sum(normal*ray_origin)
4579 call sph_add_t(tvals,nt,capacity,-numer/denom)
4580 end subroutine sph_add_phi_intersection
4581
4582 subroutine sph_cart_to_coord(pos,sph)
4583 double precision, intent(in) :: pos(1:3)
4584 double precision, intent(out) :: sph(1:3)
4585
4586 sph(1)=sqrt(sum(pos**2))
4587 if (sph(1)>zero) then
4588 sph(2)=acos(max(-one,min(one,pos(3)/sph(1))))
4589 else
4590 sph(2)=zero
4591 endif
4592 sph(3)=atan2(pos(2),pos(1))
4593 end subroutine sph_cart_to_coord
4594
4595 integer function sph_locate_index(value,faces,imin,imax) result(idx)
4596 integer, intent(in) :: imin,imax
4597 double precision, intent(in) :: value,faces(imin:imax+1)
4598
4599 integer :: ilo,ihi,imid
4600
4601 idx=0
4602 if (value<faces(imin)-1.d-12 .or. value>faces(imax+1)+1.d-12) return
4603 if (value<=faces(imin)) then
4604 idx=imin
4605 return
4606 endif
4607 if (value>=faces(imax+1)) then
4608 idx=imax
4609 return
4610 endif
4611
4612 ilo=imin
4613 ihi=imax+1
4614 do while (ihi-ilo>1)
4615 imid=(ilo+ihi)/2
4616 if (value>=faces(imid)) then
4617 ilo=imid
4618 else
4619 ihi=imid
4620 endif
4621 enddo
4622 idx=min(imax,max(imin,ilo))
4623 end function sph_locate_index
4624
4625 integer function sph_locate_index_desc(value,faces,imin,imax) result(idx)
4626 integer, intent(in) :: imin,imax
4627 double precision, intent(in) :: value,faces(imin:imax+1)
4628
4629 integer :: ilo,ihi,imid
4630
4631 idx=0
4632 if (value>faces(imin)+1.d-12 .or. value<faces(imax+1)-1.d-12) return
4633 if (value>=faces(imin)) then
4634 idx=imin
4635 return
4636 endif
4637 if (value<=faces(imax+1)) then
4638 idx=imax
4639 return
4640 endif
4641
4642 ilo=imin
4643 ihi=imax+1
4644 do while (ihi-ilo>1)
4645 imid=(ilo+ihi)/2
4646 if (value<=faces(imid)) then
4647 ilo=imid
4648 else
4649 ihi=imid
4650 endif
4651 enddo
4652 idx=min(imax,max(imin,ilo))
4653 end function sph_locate_index_desc
4654
4655 subroutine sph_locate_cell(pos,rface,thetaface,phiface,ixO^L,ix1,ix2,ix3,inside)
4656 double precision, intent(in) :: pos(1:3)
4657 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4658 phiface(ixOmin3:ixOmax3+1)
4659 integer, intent(in) :: ixO^L
4660 integer, intent(out) :: ix1,ix2,ix3
4661 logical, intent(out) :: inside
4662
4663 double precision :: sph(1:3),phi
4664
4665 call sph_cart_to_coord(pos,sph)
4666 phi=sph(3)
4667 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4668 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4669 ix1=sph_locate_index(sph(1),rface,ixomin1,ixomax1)
4670 ix2=sph_locate_index(sph(2),thetaface,ixomin2,ixomax2)
4671 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4672 inside=ix1>0 .and. ix2>0 .and. ix3>0
4673 end subroutine sph_locate_cell
4674
4675 logical function sph_segment_visible(pos,ximg1,ximg2) result(visible)
4676 use mod_constants
4677 double precision, intent(in) :: pos(1:3),ximg1,ximg2
4678
4679 double precision :: dotp,rc,rthick,rloc
4680
4681 rthick=r_opt_thick*const_rsun/unit_length
4682 rc=sqrt(ximg1**2+ximg2**2)
4683 rloc=sqrt(sum(pos**2))
4684 call dot_product_loc(vec_los,pos,dotp)
4685 visible=.true.
4686 if (dotp>=zero) then
4687 if (rc<=rthick) visible=.false.
4688 else
4689 if (rloc<=rthick) visible=.false.
4690 endif
4691 end function sph_segment_visible
4692
4693 subroutine sph_block_pixel_range(rface,thetaface,phiface,ixO^L,nXI1,nXI2,xI1,xI2,dxI,&
4694 ixPmin1,ixPmax1,ixPmin2,ixPmax2,has_pixels)
4695 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4696 phiface(ixOmin3:ixOmax3+1)
4697 integer, intent(in) :: ixO^L,nXI1,nXI2
4698 double precision, intent(in) :: xI1(nXI1),xI2(nXI2),dxI
4699 integer, intent(out) :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
4700 logical, intent(out) :: has_pixels
4701
4702 integer, parameter :: nsample=5
4703 integer :: ir,it,ip
4704 double precision :: sph(1:3),xcent(1:2)
4705 double precision :: xmin1,xmax1,xmin2,xmax2
4706 double precision :: wr,wt,wp,pad
4707
4708 has_pixels=.false.
4709 xmin1=huge(one)
4710 xmax1=-huge(one)
4711 xmin2=huge(one)
4712 xmax2=-huge(one)
4713 do ir=0,nsample-1
4714 wr=dble(ir)/dble(nsample-1)
4715 sph(1)=(one-wr)*rface(ixomin1)+wr*rface(ixomax1+1)
4716 do it=0,nsample-1
4717 wt=dble(it)/dble(nsample-1)
4718 sph(2)=(one-wt)*thetaface(ixomin2)+wt*thetaface(ixomax2+1)
4719 do ip=0,nsample-1
4720 wp=dble(ip)/dble(nsample-1)
4721 if (ir/=0 .and. ir/=nsample-1 .and. it/=0 .and. it/=nsample-1 .and. &
4722 ip/=0 .and. ip/=nsample-1) cycle
4723 sph(3)=(one-wp)*phiface(ixomin3)+wp*phiface(ixomax3+1)
4724 call get_cor_image_spherical(sph,xcent)
4725 xmin1=min(xmin1,xcent(1))
4726 xmax1=max(xmax1,xcent(1))
4727 xmin2=min(xmin2,xcent(2))
4728 xmax2=max(xmax2,xcent(2))
4729 enddo
4730 enddo
4731 enddo
4732 pad=2.d0*dxi
4733 xmin1=xmin1-pad
4734 xmax1=xmax1+pad
4735 xmin2=xmin2-pad
4736 xmax2=xmax2+pad
4737 ixpmin1=max(1,floor((xmin1-(xi1(1)-half*dxi))/dxi)+1)
4738 ixpmax1=min(nxi1,ceiling((xmax1-(xi1(1)-half*dxi))/dxi))
4739 ixpmin2=max(1,floor((xmin2-(xi2(1)-half*dxi))/dxi)+1)
4740 ixpmax2=min(nxi2,ceiling((xmax2-(xi2(1)-half*dxi))/dxi))
4741 has_pixels=ixpmin1<=ixpmax1 .and. ixpmin2<=ixpmax2
4742 end subroutine sph_block_pixel_range
4743
4744 subroutine acc_euv_sph_intersection(ixI^L,ixO^L,source,ray_origin,ximg1,ximg2,&
4745 rface,thetaface,phiface,EUVp)
4746 integer, intent(in) :: ixI^L,ixO^L
4747 double precision, intent(in) :: source(ixI^S),ray_origin(1:3),ximg1,ximg2
4748 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4749 phiface(ixOmin3:ixOmax3+1)
4750 double precision, intent(inout) :: EUVp
4751
4752 integer :: nt,capacity,i,ix^D
4753 double precision, allocatable :: tvals(:)
4754 double precision :: posMid(1:3),ds_cm,tMid,t0,t1
4755 logical :: inside
4756
4757 nt=0
4758 capacity=0
4759 do ix1=ixomin1,ixomax1+1
4760 call sph_add_sphere_intersections(ray_origin,vec_los,rface(ix1),tvals,nt,capacity)
4761 enddo
4762 do ix2=ixomin2,ixomax2+1
4763 call sph_add_theta_intersections(ray_origin,vec_los,thetaface(ix2),tvals,nt,capacity)
4764 enddo
4765 do ix3=ixomin3,ixomax3+1
4766 call sph_add_phi_intersection(ray_origin,vec_los,phiface(ix3),tvals,nt,capacity)
4767 enddo
4768 if (nt<2) then
4769 if (allocated(tvals)) deallocate(tvals)
4770 return
4771 endif
4772 call sph_sort_unique_t(tvals,nt)
4773
4774 do i=1,nt-1
4775 t0=tvals(i)
4776 t1=tvals(i+1)
4777 if (t1<=t0) cycle
4778 tmid=half*(t0+t1)
4779 posmid=ray_origin+tmid*vec_los
4780 if (.not. sph_segment_visible(posmid,ximg1,ximg2)) cycle
4781 call sph_locate_cell(posmid,rface,thetaface,phiface,ixo^l,ix1,ix2,ix3,inside)
4782 if (.not. inside) cycle
4783 ds_cm=(t1-t0)*unit_length
4784 if (si_unit) ds_cm=ds_cm*1.d2
4785 euvp=euvp+source(ix^d)*ds_cm
4786 enddo
4787 deallocate(tvals)
4788 end subroutine acc_euv_sph_intersection
4789
4790 subroutine collect_euv_sph_intersection_segments(ixI^L,ixO^L,source,opacity,&
4791 pixel_id,ray_origin,ximg1,ximg2,&
4792 rface,thetaface,phiface,rface2,&
4793 theta_cos,phi_sin,phi_cos,&
4794 segments,nseg,capacity)
4795 use mod_constants, only: const_rsun
4796
4797 integer, intent(in) :: ixI^L,ixO^L,pixel_id
4798 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
4799 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
4800 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4801 phiface(ixOmin3:ixOmax3+1)
4802 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4803 phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
4804 double precision, allocatable, intent(inout) :: segments(:,:)
4805 integer, intent(inout) :: nseg,capacity
4806
4807 integer :: nt,i,ix^D
4808 double precision :: tvals(2*(ixOmax1-ixOmin1+2)+2*(ixOmax2-ixOmin2+2)+&
4809 (ixOmax3-ixOmin3+2))
4810 double precision :: posMid(1:3),ds_cm,tMid,t0,t1,jds,kds
4811 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2
4812 double precision :: denom,numer,r2,mu,phi,dotp,rthick2,rc2
4813 logical :: inside
4814
4815 nt=0
4816 dir2=sum(vec_los**2)
4817 origin2=sum(ray_origin**2)
4818 odotd=sum(ray_origin*vec_los)
4819 rthick2=(r_opt_thick*const_rsun/unit_length)**2
4820 rc2=ximg1**2+ximg2**2
4821
4822 do ix1=ixomin1,ixomax1+1
4823 aa=dir2
4824 bb=2.d0*odotd
4825 cc=origin2-rface2(ix1)
4826 disc=bb**2-4.d0*aa*cc
4827 if (disc>=zero) then
4828 root=sqrt(max(zero,disc))
4829 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
4830 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
4831 endif
4832 enddo
4833 do ix2=ixomin2,ixomax2+1
4834 if (abs(theta_cos(ix2))<1.d-12) then
4835 if (abs(vec_los(3))>1.d-14) &
4836 call sph_add_t_fixed(tvals,nt,-ray_origin(3)/vec_los(3))
4837 cycle
4838 endif
4839 cth2=theta_cos(ix2)**2
4840 aa=vec_los(3)**2-cth2*dir2
4841 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
4842 cc=ray_origin(3)**2-cth2*origin2
4843 if (abs(aa)<1.d-14) then
4844 if (abs(bb)>1.d-14) call sph_add_t_fixed(tvals,nt,-cc/bb)
4845 else
4846 disc=bb**2-4.d0*aa*cc
4847 if (disc>=zero) then
4848 root=sqrt(max(zero,disc))
4849 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
4850 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
4851 endif
4852 endif
4853 enddo
4854 do ix3=ixomin3,ixomax3+1
4855 denom=-phi_sin(ix3)*vec_los(1)+phi_cos(ix3)*vec_los(2)
4856 if (abs(denom)>=1.d-14) then
4857 numer=-phi_sin(ix3)*ray_origin(1)+phi_cos(ix3)*ray_origin(2)
4858 call sph_add_t_fixed(tvals,nt,-numer/denom)
4859 endif
4860 enddo
4861 if (nt<2) return
4862 call sph_sort_unique_t(tvals,nt)
4863
4864 do i=1,nt-1
4865 t0=tvals(i)
4866 t1=tvals(i+1)
4867 if (t1<=t0) cycle
4868 tmid=half*(t0+t1)
4869 posmid=ray_origin+tmid*vec_los
4870 r2=sum(posmid**2)
4871 dotp=sum(vec_los*posmid)
4872 if (dotp>=zero) then
4873 if (rc2<=rthick2) cycle
4874 else
4875 if (r2<=rthick2) cycle
4876 endif
4877
4878 ix1=sph_locate_index(r2,rface2,ixomin1,ixomax1)
4879 if (r2>zero) then
4880 mu=posmid(3)/sqrt(r2)
4881 else
4882 mu=one
4883 endif
4884 ix2=sph_locate_index_desc(mu,theta_cos,ixomin2,ixomax2)
4885 phi=atan2(posmid(2),posmid(1))
4886 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4887 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4888 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4889 inside=ix1>0 .and. ix2>0 .and. ix3>0
4890 if (.not. inside) cycle
4891 ds_cm=(t1-t0)*unit_length
4892 if (si_unit) ds_cm=ds_cm*1.d2
4893 jds=max(zero,source(ix^d))*ds_cm
4894 kds=max(zero,opacity(ix^d))*ds_cm
4895 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tmid,jds,kds,zero)
4896 enddo
4898
4899 subroutine sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixO^L,ix1,ix2,ix3,inside)
4900 double precision, intent(in) :: pos(1:3)
4901 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4902 phiface(ixOmin3:ixOmax3+1)
4903 integer, intent(in) :: ixO^L
4904 integer, intent(out) :: ix1,ix2,ix3
4905 logical, intent(out) :: inside
4906
4907 double precision :: r2,mu,phi
4908
4909 r2=sum(pos**2)
4910 ix1=sph_locate_index(r2,rface2,ixomin1,ixomax1)
4911 if (r2>zero) then
4912 mu=pos(3)/sqrt(r2)
4913 else
4914 mu=one
4915 endif
4916 ix2=sph_locate_index_desc(mu,theta_cos,ixomin2,ixomax2)
4917 phi=atan2(pos(2),pos(1))
4918 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4919 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4920 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4921 inside=ix1>0 .and. ix2>0 .and. ix3>0
4922 end subroutine sph_locate_cell_fast
4923
4924 subroutine sph_try_exit_candidate(t,tNow,tExit,epsRay,tNext,found)
4925 double precision, intent(in) :: t,tNow,tExit,epsRay
4926 double precision, intent(inout) :: tNext
4927 logical, intent(inout) :: found
4928
4929 if (t>tnow+epsray .and. t<=texit+epsray .and. t<tnext) then
4930 tnext=t
4931 found=.true.
4932 endif
4933 end subroutine sph_try_exit_candidate
4934
4935 subroutine sph_try_theta_exit_candidate(t,theta_face_cos,ray_origin,tNow,tExit,epsRay,tNext,found)
4936 double precision, intent(in) :: t,theta_face_cos,ray_origin(1:3),tNow,tExit,epsRay
4937 double precision, intent(inout) :: tNext
4938 logical, intent(inout) :: found
4939
4940 double precision :: pos(1:3),r2
4941
4942 if (t<=tnow+epsray .or. t>texit+epsray .or. t>=tnext) return
4943 pos=ray_origin+t*vec_los
4944 r2=sum(pos**2)
4945 if (r2<=zero) return
4946 if (theta_face_cos>1.d-12 .and. pos(3)<-1.d-10) return
4947 if (theta_face_cos<-1.d-12 .and. pos(3)>1.d-10) return
4948 if (abs(pos(3)**2-theta_face_cos**2*r2)>1.d-6*max(one,r2)) return
4949 tnext=t
4950 found=.true.
4951 end subroutine sph_try_theta_exit_candidate
4952
4953 subroutine sph_try_phi_exit_candidate(t,phi_face_sin,phi_face_cos,ray_origin,tNow,tExit,epsRay,tNext,found)
4954 double precision, intent(in) :: t,phi_face_sin,phi_face_cos,ray_origin(1:3),tNow,tExit,epsRay
4955 double precision, intent(inout) :: tNext
4956 logical, intent(inout) :: found
4957
4958 double precision :: pos(1:3),radialDot
4959
4960 if (t<=tnow+epsray .or. t>texit+epsray .or. t>=tnext) return
4961 pos=ray_origin+t*vec_los
4962 radialdot=phi_face_cos*pos(1)+phi_face_sin*pos(2)
4963 if (radialdot<-1.d-10) return
4964 tnext=t
4965 found=.true.
4966 end subroutine sph_try_phi_exit_candidate
4967
4968 subroutine sph_next_cell_exit(ray_origin,rface2,theta_cos,phiface,phi_sin,phi_cos,ixO^L,&
4969 ix1,ix2,ix3,tNow,tExit,epsRay,tNext,found)
4970 double precision, intent(in) :: ray_origin(1:3)
4971 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4972 phiface(ixOmin3:ixOmax3+1)
4973 double precision, intent(in) :: phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
4974 integer, intent(in) :: ixO^L,ix1,ix2,ix3
4975 double precision, intent(in) :: tNow,tExit,epsRay
4976 double precision, intent(out) :: tNext
4977 logical, intent(out) :: found
4978
4979 integer :: iface
4980 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2,denom,numer
4981
4982 found=.false.
4983 tnext=huge(one)
4984 dir2=sum(vec_los**2)
4985 origin2=sum(ray_origin**2)
4986 odotd=sum(ray_origin*vec_los)
4987
4988 do iface=ix1,ix1+1
4989 aa=dir2
4990 bb=2.d0*odotd
4991 cc=origin2-rface2(iface)
4992 disc=bb**2-4.d0*aa*cc
4993 if (disc>=zero) then
4994 root=sqrt(max(zero,disc))
4995 call sph_try_exit_candidate((-bb-root)/(2.d0*aa),tnow,texit,epsray,tnext,found)
4996 call sph_try_exit_candidate((-bb+root)/(2.d0*aa),tnow,texit,epsray,tnext,found)
4997 endif
4998 enddo
4999
5000 do iface=ix2,ix2+1
5001 if (abs(theta_cos(iface))<1.d-12) then
5002 if (abs(vec_los(3))>1.d-14) call sph_try_theta_exit_candidate(&
5003 -ray_origin(3)/vec_los(3),theta_cos(iface),ray_origin,tnow,texit,epsray,&
5004 tnext,found)
5005 cycle
5006 endif
5007 cth2=theta_cos(iface)**2
5008 aa=vec_los(3)**2-cth2*dir2
5009 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
5010 cc=ray_origin(3)**2-cth2*origin2
5011 if (abs(aa)<1.d-14) then
5012 if (abs(bb)>1.d-14) call sph_try_theta_exit_candidate(-cc/bb,theta_cos(iface),&
5013 ray_origin,tnow,texit,epsray,tnext,found)
5014 else
5015 disc=bb**2-4.d0*aa*cc
5016 if (disc>=zero) then
5017 root=sqrt(max(zero,disc))
5018 call sph_try_theta_exit_candidate((-bb-root)/(2.d0*aa),theta_cos(iface),&
5019 ray_origin,tnow,texit,epsray,tnext,found)
5020 call sph_try_theta_exit_candidate((-bb+root)/(2.d0*aa),theta_cos(iface),&
5021 ray_origin,tnow,texit,epsray,tnext,found)
5022 endif
5023 endif
5024 enddo
5025
5026 do iface=ix3,ix3+1
5027 denom=-phi_sin(iface)*vec_los(1)+phi_cos(iface)*vec_los(2)
5028 if (abs(denom)>=1.d-14) then
5029 numer=-phi_sin(iface)*ray_origin(1)+phi_cos(iface)*ray_origin(2)
5030 call sph_try_phi_exit_candidate(-numer/denom,phi_sin(iface),phi_cos(iface),ray_origin,&
5031 tnow,texit,epsray,tnext,found)
5032 endif
5033 enddo
5034 end subroutine sph_next_cell_exit
5035
5036 subroutine collect_euv_sph_dda_interval(ixI^L,ixO^L,source,opacity,pixel_id,&
5037 ray_origin,ximg1,ximg2,rface2,theta_cos,phiface,&
5038 phi_sin,phi_cos,&
5039 t_enter,t_exit,segments,nseg,capacity,ok)
5040 use mod_constants, only: const_rsun
5041
5042 integer, intent(in) :: ixI^L,ixO^L,pixel_id
5043 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
5044 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
5045 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
5046 phiface(ixOmin3:ixOmax3+1)
5047 double precision, intent(in) :: phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
5048 double precision, intent(in) :: t_enter,t_exit
5049 double precision, allocatable, intent(inout) :: segments(:,:)
5050 integer, intent(inout) :: nseg,capacity
5051 logical, intent(out) :: ok
5052
5053 integer :: ix^D,nstep,maxSteps
5054 double precision :: tNow,tNext,tEnd,tMid,epsRay,ds_cm,jds,kds
5055 double precision :: pos(1:3),r2,dotp,rthick2,rc2
5056 logical :: inside,found
5057
5058 ok=.true.
5059 if (t_exit<=t_enter) return
5060 epsray=max(1.d-12,1.d-10*max(one,abs(t_exit-t_enter)))
5061 pos=ray_origin+(t_enter+epsray)*vec_los
5062 call sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5063 if (.not. inside) then
5064 ok=.false.
5065 return
5066 endif
5067
5068 rthick2=(r_opt_thick*const_rsun/unit_length)**2
5069 rc2=ximg1**2+ximg2**2
5070 tnow=t_enter
5071 nstep=0
5072 maxsteps=8*((ixomax1-ixomin1+1)+(ixomax2-ixomin2+1)+(ixomax3-ixomin3+1)+3)
5073
5074 do while (tnow<t_exit-epsray)
5075 call sph_next_cell_exit(ray_origin,rface2,theta_cos,phiface,phi_sin,phi_cos,ixo^l,&
5076 ix1,ix2,ix3,tnow,t_exit,epsray,tnext,found)
5077 if (.not. found) then
5078 ok=.false.
5079 return
5080 endif
5081 tend=min(tnext,t_exit)
5082 if (tend>tnow) then
5083 tmid=half*(tnow+tend)
5084 pos=ray_origin+tmid*vec_los
5085 r2=sum(pos**2)
5086 dotp=sum(vec_los*pos)
5087 if (.not. ((dotp>=zero .and. rc2<=rthick2) .or. &
5088 (dotp<zero .and. r2<=rthick2))) then
5089 ds_cm=(tend-tnow)*unit_length
5090 if (si_unit) ds_cm=ds_cm*1.d2
5091 jds=max(zero,source(ix^d))*ds_cm
5092 kds=max(zero,opacity(ix^d))*ds_cm
5093 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tmid,jds,kds,zero)
5094 endif
5095 endif
5096 tnow=tend
5097 if (tnow>=t_exit-epsray) exit
5098 pos=ray_origin+(tnow+epsray)*vec_los
5099 call sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5100 if (.not. inside) then
5101 ok=.false.
5102 return
5103 endif
5104 nstep=nstep+1
5105 if (nstep>maxsteps) then
5106 ok=.false.
5107 return
5108 endif
5109 enddo
5110 end subroutine collect_euv_sph_dda_interval
5111
5112 subroutine collect_euv_sph_dda_segments(ixI^L,ixO^L,source,opacity,&
5113 pixel_id,ray_origin,ximg1,ximg2,&
5114 rface,thetaface,phiface,rface2,&
5115 theta_cos,phi_sin,phi_cos,&
5116 segments,nseg,capacity,fallback)
5117 integer, intent(in) :: ixI^L,ixO^L,pixel_id
5118 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
5119 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
5120 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
5121 phiface(ixOmin3:ixOmax3+1)
5122 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
5123 phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
5124 double precision, allocatable, intent(inout) :: segments(:,:)
5125 integer, intent(inout) :: nseg,capacity
5126 logical, intent(out) :: fallback
5127
5128 integer :: nt,i,nsegStart,ix^D
5129 double precision :: tvals(12),posMid(1:3),t0,t1,tMid
5130 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2,denom,numer
5131 logical :: inside,ok
5132
5133 fallback=.false.
5134 nsegstart=nseg
5135 nt=0
5136 dir2=sum(vec_los**2)
5137 origin2=sum(ray_origin**2)
5138 odotd=sum(ray_origin*vec_los)
5139
5140 do ix1=ixomin1,ixomax1+1,ixomax1-ixomin1+1
5141 aa=dir2
5142 bb=2.d0*odotd
5143 cc=origin2-rface2(ix1)
5144 disc=bb**2-4.d0*aa*cc
5145 if (disc>=zero) then
5146 root=sqrt(max(zero,disc))
5147 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
5148 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
5149 endif
5150 enddo
5151 do ix2=ixomin2,ixomax2+1,ixomax2-ixomin2+1
5152 if (abs(theta_cos(ix2))<1.d-12) then
5153 if (abs(vec_los(3))>1.d-14) &
5154 call sph_add_t_fixed(tvals,nt,-ray_origin(3)/vec_los(3))
5155 cycle
5156 endif
5157 cth2=theta_cos(ix2)**2
5158 aa=vec_los(3)**2-cth2*dir2
5159 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
5160 cc=ray_origin(3)**2-cth2*origin2
5161 if (abs(aa)<1.d-14) then
5162 if (abs(bb)>1.d-14) call sph_add_t_fixed(tvals,nt,-cc/bb)
5163 else
5164 disc=bb**2-4.d0*aa*cc
5165 if (disc>=zero) then
5166 root=sqrt(max(zero,disc))
5167 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
5168 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
5169 endif
5170 endif
5171 enddo
5172 do ix3=ixomin3,ixomax3+1,ixomax3-ixomin3+1
5173 denom=-phi_sin(ix3)*vec_los(1)+phi_cos(ix3)*vec_los(2)
5174 if (abs(denom)>=1.d-14) then
5175 numer=-phi_sin(ix3)*ray_origin(1)+phi_cos(ix3)*ray_origin(2)
5176 call sph_add_t_fixed(tvals,nt,-numer/denom)
5177 endif
5178 enddo
5179
5180 if (nt<2) return
5181 call sph_sort_unique_t(tvals,nt)
5182
5183 do i=1,nt-1
5184 t0=tvals(i)
5185 t1=tvals(i+1)
5186 if (t1<=t0) cycle
5187 tmid=half*(t0+t1)
5188 posmid=ray_origin+tmid*vec_los
5189 call sph_locate_cell_fast(posmid,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5190 if (.not. inside) cycle
5191 call collect_euv_sph_dda_interval(ixi^l,ixo^l,source,opacity,pixel_id,&
5192 ray_origin,ximg1,ximg2,rface2,theta_cos,phiface,phi_sin,phi_cos,&
5193 t0,t1,segments,nseg,capacity,ok)
5194 if (.not. ok) then
5195 nseg=nsegstart
5196 fallback=.true.
5197 call collect_euv_sph_intersection_segments(ixi^l,ixo^l,source,opacity,&
5198 pixel_id,ray_origin,ximg1,ximg2,rface,thetaface,phiface,rface2,&
5199 theta_cos,phi_sin,phi_cos,segments,nseg,capacity)
5200 return
5201 endif
5202 enddo
5203
5204 end subroutine collect_euv_sph_dda_segments
5205
5206 subroutine integrate_euv_sph_intersection_thin(numXI1,numXI2,xI1,xI2,dxI,fl,EM)
5208
5209 integer, intent(in) :: numXI1,numXI2
5210 double precision, intent(in) :: xI1(numXI1),xI2(numXI2),dxI
5211 type(te_fluid), intent(in) :: fl
5212 double precision, intent(inout) :: EM(numXI1,numXI2)
5213
5214 integer :: ixO^L,ixI^L,ix^D
5215 integer :: iigrid,igrid,ixP1,ixP2,ixPmin1,ixPmax1,ixPmin2,ixPmax2
5216 integer :: iseg,nseg,capacity,sphDdaFallbackLocal,sphDdaFallbackGlobal
5217 double precision :: ray_origin(1:3),profile_local(3),profile_global(3)
5218 double precision, allocatable :: source(:^D&)
5219 double precision, allocatable :: rface(:),thetaface(:),phiface(:)
5220 double precision, allocatable :: rface2(:),theta_cos(:),phi_sin(:),phi_cos(:)
5221 double precision, allocatable :: segments(:,:)
5222 logical :: has_pixels,ddaFallback
5223
5224 profile_local=zero
5225 sphddafallbacklocal=0
5226 do iigrid=1,igridstail; igrid=igrids(iigrid);
5227 ^d&ixomin^d=ixmlo^d\
5228 ^d&ixomax^d=ixmhi^d\
5229 ^d&iximin^d=ixglo^d\
5230 ^d&iximax^d=ixghi^d\
5231
5232 allocate(source(ixi^s))
5233 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,source)
5234 source(ixo^s)=source(ixo^s)/instrument_resolution_factor**2
5235 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,rface,thetaface,phiface)
5236 if (sph_use_dda) then
5237 allocate(rface2(ixomin1:ixomax1+1),theta_cos(ixomin2:ixomax2+1),&
5238 phi_sin(ixomin3:ixomax3+1),phi_cos(ixomin3:ixomax3+1))
5239 rface2=rface**2
5240 theta_cos=cos(thetaface)
5241 phi_sin=sin(phiface)
5242 phi_cos=cos(phiface)
5243 endif
5244 call sph_block_pixel_range(rface,thetaface,phiface,ixo^l,numxi1,numxi2,xi1,xi2,dxi,&
5245 ixpmin1,ixpmax1,ixpmin2,ixpmax2,has_pixels)
5246 if (has_pixels) then
5247 if (sph_use_dda) capacity=0
5248 do ixp1=ixpmin1,ixpmax1
5249 do ixp2=ixpmin2,ixpmax2
5250 ray_origin=xi1(ixp1)*vec_xi1+xi2(ixp2)*vec_xi2
5251 profile_local(1)=profile_local(1)+one
5252 if (sph_use_dda) then
5253 nseg=0
5254 call collect_euv_sph_dda_segments(ixi^l,ixo^l,source,source,&
5255 1,ray_origin,xi1(ixp1),xi2(ixp2),rface,thetaface,phiface,&
5256 rface2,theta_cos,phi_sin,phi_cos,segments,nseg,capacity,ddafallback)
5257 if (ddafallback) sphddafallbacklocal=sphddafallbacklocal+1
5258 do iseg=1,nseg
5259 em(ixp1,ixp2)=em(ixp1,ixp2)+segments(3,iseg)
5260 enddo
5261 else
5262 call acc_euv_sph_intersection(ixi^l,ixo^l,source,ray_origin,xi1(ixp1),xi2(ixp2),&
5263 rface,thetaface,phiface,em(ixp1,ixp2))
5264 endif
5265 enddo
5266 enddo
5267 profile_local(2)=profile_local(2)+dble((ixpmax1-ixpmin1+1)*(ixpmax2-ixpmin2+1))
5268 endif
5269 if (allocated(segments)) deallocate(segments)
5270 profile_local(3)=profile_local(3)+one
5271 if (allocated(rface2)) deallocate(rface2)
5272 if (allocated(theta_cos)) deallocate(theta_cos)
5273 if (allocated(phi_sin)) deallocate(phi_sin)
5274 if (allocated(phi_cos)) deallocate(phi_cos)
5275 deallocate(source,rface,thetaface,phiface)
5276 enddo
5277 call mpi_allreduce(profile_local,profile_global,3,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5278 call mpi_allreduce(sphddafallbacklocal,sphddafallbackglobal,1,mpi_integer,mpi_sum,icomm,ierrmpi)
5279 if (radsyn_verbose .and. mype==0) then
5280 if (sph_use_dda) then
5281 write(*,'(a,3(es12.5,1x))') ' sph_dda thin profile rays pixels blocks: ',profile_global
5282 write(*,'(a,i0)') ' sph_dda thin fallback rays: ',sphddafallbackglobal
5283 else
5284 write(*,'(a,3(es12.5,1x))') ' sph_intersection thin profile rays pixels blocks: ',profile_global
5285 endif
5286 endif
5288
5289 subroutine integrate_euv_sph_intersection_thick(numXI1,numXI2,xI1,xI2,dxI,fl,EUV,Tau,EUVthin)
5291
5292 integer, intent(in) :: numXI1,numXI2
5293 double precision, intent(in) :: xI1(numXI1),xI2(numXI2),dxI
5294 type(te_fluid), intent(in) :: fl
5295 double precision, intent(out) :: EUV(numXI1,numXI2),Tau(numXI1,numXI2),EUVthin(numXI1,numXI2)
5296
5297 integer, parameter :: nSegVars=5
5298 integer :: ixO^L,ixI^L,ix^D
5299 integer :: iigrid,igrid,ixP1,ixP2,ipix,ipixStart,ipixEnd,nPixBatch,pixel_id
5300 integer :: nseg,capacity,totalCount,totalSeg,ipe,is,iseg,nidx,owner,isegDest,nsegBefore
5301 integer :: ixGlobal,iyGlobal,ixPmin1,ixPmax1,ixPmin2,ixPmax2,iFirst,iLast,iLocal
5302 integer :: nPixBatchTarget
5303 integer :: maxSegBatchTarget,maxSegCommTarget,maxNsegBatch,nPixTotal
5304 integer :: maxOwnerSegCount,maxOwnerSegCountLocal,segOffset,recvFill,totalRoundCount,totalRoundSeg
5305 integer :: sphDdaFallbackLocal,sphDdaFallbackGlobal
5306 integer, allocatable :: sendCounts(:),recvCounts(:),sendDispls(:),recvDispls(:)
5307 integer, allocatable :: roundSendCounts(:),roundRecvCounts(:)
5308 integer, allocatable :: roundSendDispls(:),roundRecvDispls(:)
5309 integer, allocatable :: ownerSegCounts(:),ownerOffsets(:),idx(:)
5310 integer, allocatable :: bucketCounts(:),bucketOffsets(:),bucketFill(:)
5311 double precision :: ray_origin(1:3),atten
5312 double precision :: profile_local(5),profile_global(5),profile_batch(5)
5313 double precision :: phys_max_local(2),phys_max_global(2)
5314 double precision :: phys_sum_local(2),phys_sum_global(2),phys_sum_batch(2)
5315 double precision, allocatable :: segments(:,:),segments_send(:,:),segments_recv(:,:)
5316 double precision, allocatable :: segments_recv_round(:,:)
5317 double precision, allocatable :: image_reduce(:,:)
5318 logical :: has_pixels,batchAccepted,batchReduced,ddaFallback
5319 type(radsyn_euv_cache), allocatable :: cache(:)
5320
5321 euv=zero
5322 tau=zero
5323 euvthin=zero
5324 profile_local=zero
5325 phys_max_local=zero
5326 phys_sum_local=zero
5327 sphddafallbacklocal=0
5328 allocate(sendcounts(0:npe-1),recvcounts(0:npe-1),senddispls(0:npe-1),recvdispls(0:npe-1))
5329 allocate(roundsendcounts(0:npe-1),roundrecvcounts(0:npe-1))
5330 allocate(roundsenddispls(0:npe-1),roundrecvdispls(0:npe-1))
5331 allocate(ownersegcounts(0:npe-1),owneroffsets(0:npe-1))
5332 allocate(cache(igridstail))
5333 call radsyn_get_segment_batch_limits(npixbatchtarget,maxsegbatchtarget,maxsegcommtarget)
5334 allocate(bucketcounts(npixbatchtarget),bucketoffsets(npixbatchtarget+1),&
5335 bucketfill(npixbatchtarget))
5336
5337 do iigrid=1,igridstail; igrid=igrids(iigrid);
5338 ^d&ixomin^d=ixmlo^d\
5339 ^d&ixomax^d=ixmhi^d\
5340 ^d&iximin^d=ixglo^d\
5341 ^d&iximax^d=ixghi^d\
5342
5343 cache(iigrid)%igrid=igrid
5344 allocate(cache(iigrid)%source(ixi^s),cache(iigrid)%opacity(ixi^s))
5345 cache(iigrid)%source=zero
5346 cache(iigrid)%opacity=zero
5347 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%source)
5348 cache(iigrid)%source(ixo^s)=cache(iigrid)%source(ixo^s)/instrument_resolution_factor**2
5349 call get_euv_hhe_opacity(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%opacity)
5350 phys_max_local(1)=max(phys_max_local(1),maxval(cache(iigrid)%source(ixo^s)))
5351 phys_max_local(2)=max(phys_max_local(2),maxval(cache(iigrid)%opacity(ixo^s)))
5352 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,&
5353 cache(iigrid)%rface,cache(iigrid)%thetaface,&
5354 cache(iigrid)%phiface)
5355 allocate(cache(iigrid)%rface2(ixomin1:ixomax1+1),&
5356 cache(iigrid)%theta_cos(ixomin2:ixomax2+1),&
5357 cache(iigrid)%phi_sin(ixomin3:ixomax3+1),&
5358 cache(iigrid)%phi_cos(ixomin3:ixomax3+1))
5359 cache(iigrid)%rface2=cache(iigrid)%rface**2
5360 cache(iigrid)%theta_cos=cos(cache(iigrid)%thetaface)
5361 cache(iigrid)%phi_sin=sin(cache(iigrid)%phiface)
5362 cache(iigrid)%phi_cos=cos(cache(iigrid)%phiface)
5363 call sph_block_pixel_range(cache(iigrid)%rface,cache(iigrid)%thetaface,&
5364 cache(iigrid)%phiface,ixo^l,numxi1,numxi2,xi1,xi2,dxi,&
5365 cache(iigrid)%ixPmin1,cache(iigrid)%ixPmax1,&
5366 cache(iigrid)%ixPmin2,cache(iigrid)%ixPmax2,cache(iigrid)%has_pixels)
5367 enddo
5368
5369 npixtotal=numxi1*numxi2
5370 ipixstart=1
5371 do while (ipixstart<=npixtotal)
5372 ipixend=min(numxi1*numxi2,ipixstart+npixbatchtarget-1)
5373 npixbatch=ipixend-ipixstart+1
5374 batchaccepted=.false.
5375 batchreduced=.false.
5376
5377 do while (.not. batchaccepted)
5378 nseg=0
5379 capacity=0
5380 profile_batch=zero
5381 phys_sum_batch=zero
5382
5383 do iigrid=1,igridstail; igrid=igrids(iigrid);
5384 ^d&ixomin^d=ixmlo^d\
5385 ^d&ixomax^d=ixmhi^d\
5386 ^d&iximin^d=ixglo^d\
5387 ^d&iximax^d=ixghi^d\
5388
5389 ixpmin1=cache(iigrid)%ixPmin1
5390 ixpmax1=cache(iigrid)%ixPmax1
5391 ixpmin2=cache(iigrid)%ixPmin2
5392 ixpmax2=cache(iigrid)%ixPmax2
5393 has_pixels=cache(iigrid)%has_pixels
5394 if (.not. has_pixels) cycle
5395
5396 do ixp2=ixpmin2,ixpmax2
5397 ifirst=max(ipixstart,(ixp2-1)*numxi1+ixpmin1)
5398 ilast=min(ipixend,(ixp2-1)*numxi1+ixpmax1)
5399 if (ifirst>ilast) cycle
5400 do ipix=ifirst,ilast
5401 ixp1=1+mod(ipix-1,numxi1)
5402 pixel_id=ipix
5403 ray_origin=xi1(ixp1)*vec_xi1+xi2(ixp2)*vec_xi2
5404 profile_batch(1)=profile_batch(1)+one
5405 nsegbefore=nseg
5406 if (sph_use_dda) then
5407 call collect_euv_sph_dda_segments(ixi^l,ixo^l,cache(iigrid)%source,&
5408 cache(iigrid)%opacity,pixel_id,ray_origin,xi1(ixp1),xi2(ixp2),&
5409 cache(iigrid)%rface,cache(iigrid)%thetaface,cache(iigrid)%phiface,&
5410 cache(iigrid)%rface2,cache(iigrid)%theta_cos,&
5411 cache(iigrid)%phi_sin,cache(iigrid)%phi_cos,&
5412 segments,nseg,capacity,ddafallback)
5413 if (ddafallback) sphddafallbacklocal=sphddafallbacklocal+1
5414 else
5415 call collect_euv_sph_intersection_segments(ixi^l,ixo^l,cache(iigrid)%source,&
5416 cache(iigrid)%opacity,pixel_id,ray_origin,xi1(ixp1),xi2(ixp2),&
5417 cache(iigrid)%rface,cache(iigrid)%thetaface,cache(iigrid)%phiface,&
5418 cache(iigrid)%rface2,cache(iigrid)%theta_cos,&
5419 cache(iigrid)%phi_sin,cache(iigrid)%phi_cos,&
5420 segments,nseg,capacity)
5421 endif
5422 if (nseg>nsegbefore) profile_batch(2)=profile_batch(2)+one
5423 profile_batch(3)=profile_batch(3)+dble(nseg-nsegbefore)
5424 do iseg=nsegbefore+1,nseg
5425 phys_sum_batch(1)=phys_sum_batch(1)+segments(3,iseg)
5426 phys_sum_batch(2)=phys_sum_batch(2)+segments(4,iseg)
5427 enddo
5428 enddo
5429 enddo
5430 enddo
5431
5432 call mpi_allreduce(nseg,maxnsegbatch,1,mpi_integer,mpi_max,icomm,ierrmpi)
5433 if (maxnsegbatch>maxsegbatchtarget .and. npixbatch>1) then
5434 npixbatch=max(1,npixbatch/2)
5435 ipixend=ipixstart+npixbatch-1
5436 if (allocated(segments)) deallocate(segments)
5437 batchreduced=.true.
5438 else
5439 batchaccepted=.true.
5440 endif
5441 enddo
5442
5443 profile_local=profile_local+profile_batch
5444 phys_sum_local=phys_sum_local+phys_sum_batch
5445 if (radsyn_verbose .and. mype==0 .and. batchreduced) then
5446 if (sph_use_dda) then
5447 write(*,'(a,3(i0,1x))') ' sph_dda thick adaptive batch: ',&
5448 ipixstart,ipixend,maxnsegbatch
5449 else
5450 write(*,'(a,3(i0,1x))') ' sph_intersection thick adaptive batch: ',&
5451 ipixstart,ipixend,maxnsegbatch
5452 endif
5453 endif
5454
5455 if (.not. allocated(segments)) then
5456 capacity=1
5457 allocate(segments(nsegvars,capacity))
5458 endif
5459 ownersegcounts=0
5460 do is=1,nseg
5461 owner=segment_pixel_owner(nint(segments(1,is)))
5462 ownersegcounts(owner)=ownersegcounts(owner)+1
5463 enddo
5464 sendcounts=nsegvars*ownersegcounts
5465 senddispls(0)=0
5466 do ipe=1,npe-1
5467 senddispls(ipe)=senddispls(ipe-1)+sendcounts(ipe-1)
5468 enddo
5469
5470 allocate(segments_send(nsegvars,max(1,nseg)))
5471 owneroffsets=0
5472 do is=1,nseg
5473 owner=segment_pixel_owner(nint(segments(1,is)))
5474 isegdest=senddispls(owner)/nsegvars+owneroffsets(owner)+1
5475 segments_send(:,isegdest)=segments(:,is)
5476 owneroffsets(owner)=owneroffsets(owner)+1
5477 enddo
5478
5479 call mpi_alltoall(sendcounts,1,mpi_integer,recvcounts,1,mpi_integer,icomm,ierrmpi)
5480 recvdispls(0)=0
5481 do ipe=1,npe-1
5482 recvdispls(ipe)=recvdispls(ipe-1)+recvcounts(ipe-1)
5483 enddo
5484 totalcount=sum(recvcounts)
5485 totalseg=totalcount/nsegvars
5486 profile_local(4)=profile_local(4)+dble(totalcount)
5487 allocate(segments_recv(nsegvars,max(1,totalseg)))
5488
5489 recvfill=0
5490 maxownersegcountlocal=maxval(ownersegcounts)
5491 call mpi_allreduce(maxownersegcountlocal,maxownersegcount,1,mpi_integer,mpi_max,icomm,ierrmpi)
5492 do segoffset=0,maxownersegcount-1,maxsegcommtarget
5493 roundsendcounts=0
5494 roundsenddispls=senddispls
5495 do ipe=0,npe-1
5496 if (ownersegcounts(ipe)>segoffset) then
5497 roundsendcounts(ipe)=nsegvars*min(maxsegcommtarget,ownersegcounts(ipe)-segoffset)
5498 roundsenddispls(ipe)=senddispls(ipe)+nsegvars*segoffset
5499 endif
5500 enddo
5501
5502 call mpi_alltoall(roundsendcounts,1,mpi_integer,roundrecvcounts,1,mpi_integer,icomm,ierrmpi)
5503 roundrecvdispls(0)=0
5504 do ipe=1,npe-1
5505 roundrecvdispls(ipe)=roundrecvdispls(ipe-1)+roundrecvcounts(ipe-1)
5506 enddo
5507 totalroundcount=sum(roundrecvcounts)
5508 totalroundseg=totalroundcount/nsegvars
5509 allocate(segments_recv_round(nsegvars,max(1,totalroundseg)))
5510
5511 call mpi_alltoallv(segments_send,roundsendcounts,roundsenddispls,mpi_double_precision,&
5512 segments_recv_round,roundrecvcounts,roundrecvdispls,&
5513 mpi_double_precision,icomm,ierrmpi)
5514
5515 if (totalroundseg>0) then
5516 segments_recv(:,recvfill+1:recvfill+totalroundseg)=segments_recv_round(:,1:totalroundseg)
5517 recvfill=recvfill+totalroundseg
5518 endif
5519 deallocate(segments_recv_round)
5520 enddo
5521
5522 if (recvfill/=totalseg) call mpistop("ray-segment receive mismatch")
5523
5524 if (totalseg>0) then
5525 allocate(idx(totalseg))
5526 bucketcounts(1:npixbatch)=0
5527 do is=1,totalseg
5528 if (segment_is_valid(segments_recv,is,4)) then
5529 ipix=nint(segments_recv(1,is))
5530 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
5531 ilocal=ipix-ipixstart+1
5532 bucketcounts(ilocal)=bucketcounts(ilocal)+1
5533 endif
5534 endif
5535 enddo
5536
5537 bucketoffsets(1)=1
5538 do ilocal=1,npixbatch
5539 bucketoffsets(ilocal+1)=bucketoffsets(ilocal)+bucketcounts(ilocal)
5540 enddo
5541 bucketfill(1:npixbatch)=bucketoffsets(1:npixbatch)
5542 do is=1,totalseg
5543 if (segment_is_valid(segments_recv,is,4)) then
5544 ipix=nint(segments_recv(1,is))
5545 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
5546 ilocal=ipix-ipixstart+1
5547 idx(bucketfill(ilocal))=is
5548 bucketfill(ilocal)=bucketfill(ilocal)+1
5549 endif
5550 endif
5551 enddo
5552
5553 do ipix=ipixstart,ipixend
5554 if (segment_pixel_owner(ipix)/=mype) cycle
5555 ilocal=ipix-ipixstart+1
5556 nidx=bucketcounts(ilocal)
5557 if (nidx>0) then
5558 profile_local(5)=profile_local(5)+dble(nidx)*dble(nidx)
5559 call sort_segment_indices_near_to_far(segments_recv,&
5560 idx(bucketoffsets(ilocal):bucketoffsets(ilocal+1)-1),nidx)
5561 ixglobal=1+mod(ipix-1,numxi1)
5562 iyglobal=1+(ipix-1)/numxi1
5563 do iseg=bucketoffsets(ilocal),bucketoffsets(ilocal+1)-1
5564 is=idx(iseg)
5565 euvthin(ixglobal,iyglobal)=euvthin(ixglobal,iyglobal)+segments_recv(3,is)
5566 atten=transfer_attenuation(tau(ixglobal,iyglobal))
5567 euv(ixglobal,iyglobal)=euv(ixglobal,iyglobal)+atten*segments_recv(3,is)
5568 tau(ixglobal,iyglobal)=tau(ixglobal,iyglobal)+max(zero,segments_recv(4,is))
5569 enddo
5570 endif
5571 enddo
5572 deallocate(idx)
5573 endif
5574
5575 deallocate(segments_send,segments_recv)
5576 if (allocated(segments)) deallocate(segments)
5577 ipixstart=ipixend+1
5578 enddo
5579
5580 do iigrid=1,igridstail
5581 if (allocated(cache(iigrid)%source)) deallocate(cache(iigrid)%source)
5582 if (allocated(cache(iigrid)%opacity)) deallocate(cache(iigrid)%opacity)
5583 if (allocated(cache(iigrid)%rface)) deallocate(cache(iigrid)%rface)
5584 if (allocated(cache(iigrid)%thetaface)) deallocate(cache(iigrid)%thetaface)
5585 if (allocated(cache(iigrid)%phiface)) deallocate(cache(iigrid)%phiface)
5586 if (allocated(cache(iigrid)%rface2)) deallocate(cache(iigrid)%rface2)
5587 if (allocated(cache(iigrid)%theta_cos)) deallocate(cache(iigrid)%theta_cos)
5588 if (allocated(cache(iigrid)%phi_sin)) deallocate(cache(iigrid)%phi_sin)
5589 if (allocated(cache(iigrid)%phi_cos)) deallocate(cache(iigrid)%phi_cos)
5590 enddo
5591 deallocate(cache)
5592 deallocate(sendcounts,recvcounts,senddispls,recvdispls,roundsendcounts,roundrecvcounts,&
5593 roundsenddispls,roundrecvdispls,ownersegcounts,owneroffsets,bucketcounts,&
5594 bucketoffsets,bucketfill)
5595 allocate(image_reduce(numxi1,numxi2))
5596 call mpi_allreduce(euv,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5597 euv=image_reduce
5598 call mpi_allreduce(tau,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5599 tau=image_reduce
5600 call mpi_allreduce(euvthin,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5601 euvthin=image_reduce
5602 deallocate(image_reduce)
5603 call mpi_allreduce(profile_local,profile_global,5,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5604 call mpi_allreduce(phys_max_local,phys_max_global,2,mpi_double_precision,mpi_max,icomm,ierrmpi)
5605 call mpi_allreduce(phys_sum_local,phys_sum_global,2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5606 call mpi_allreduce(sphddafallbacklocal,sphddafallbackglobal,1,mpi_integer,mpi_sum,icomm,ierrmpi)
5607 if (radsyn_verbose .and. mype==0) then
5608 if (sph_use_dda) then
5609 write(*,'(a,5(es12.5,1x))') ' sph_dda thick profile: ',profile_global
5610 write(*,'(a,i0)') ' sph_dda thick fallback rays: ',sphddafallbackglobal
5611 write(*,'(a,4(es12.5,1x))') ' sph_dda thick physics maxj maxk sumjds sumkds: ',&
5612 phys_max_global(1),phys_max_global(2),phys_sum_global(1),phys_sum_global(2)
5613 else
5614 write(*,'(a,5(es12.5,1x))') ' sph_intersection thick profile: ',profile_global
5615 write(*,'(a,4(es12.5,1x))') ' sph_intersection thick physics maxj maxk sumjds sumkds: ',&
5616 phys_max_global(1),phys_max_global(2),phys_sum_global(1),phys_sum_global(2)
5617 endif
5618 endif
5620
5621 }
5622
5623 {^ifthreed
5624
5625 subroutine get_sph_intersection_image_bounds(xImin1,xImax1,xImin2,xImax2)
5626 double precision, intent(out) :: xImin1,xImax1,xImin2,xImax2
5627
5628 integer, parameter :: nsample=5
5629 integer :: iigrid,igrid,ir,it,ip
5630 integer :: ixI^L,ixO^L
5631 double precision, allocatable :: rface(:),thetaface(:),phiface(:)
5632 double precision :: local_min1,local_max1,local_min2,local_max2
5633 double precision :: sph(1:3),xcent(1:2),wr,wt,wp
5634
5635 local_min1=huge(one)
5636 local_max1=-huge(one)
5637 local_min2=huge(one)
5638 local_max2=-huge(one)
5639
5640 do iigrid=1,igridstail
5641 igrid=igrids(iigrid)
5642 ^d&ixomin^d=ixmlo^d\
5643 ^d&ixomax^d=ixmhi^d\
5644 ^d&iximin^d=ixglo^d\
5645 ^d&iximax^d=ixghi^d\
5646
5647 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,&
5648 rface,thetaface,phiface)
5649 do ir=0,nsample-1
5650 wr=dble(ir)/dble(nsample-1)
5651 sph(1)=(one-wr)*rface(ixomin1)+wr*rface(ixomax1+1)
5652 do it=0,nsample-1
5653 wt=dble(it)/dble(nsample-1)
5654 sph(2)=(one-wt)*thetaface(ixomin2)+wt*thetaface(ixomax2+1)
5655 do ip=0,nsample-1
5656 wp=dble(ip)/dble(nsample-1)
5657 if (ir/=0 .and. ir/=nsample-1 .and. it/=0 .and. it/=nsample-1 .and. &
5658 ip/=0 .and. ip/=nsample-1) cycle
5659 sph(3)=(one-wp)*phiface(ixomin3)+wp*phiface(ixomax3+1)
5660 call get_cor_image_spherical(sph,xcent)
5661 local_min1=min(local_min1,xcent(1))
5662 local_max1=max(local_max1,xcent(1))
5663 local_min2=min(local_min2,xcent(2))
5664 local_max2=max(local_max2,xcent(2))
5665 enddo
5666 enddo
5667 enddo
5668 deallocate(rface,thetaface,phiface)
5669 enddo
5670
5671 call mpi_allreduce(local_min1,ximin1,1,mpi_double_precision,mpi_min,icomm,ierrmpi)
5672 call mpi_allreduce(local_max1,ximax1,1,mpi_double_precision,mpi_max,icomm,ierrmpi)
5673 call mpi_allreduce(local_min2,ximin2,1,mpi_double_precision,mpi_min,icomm,ierrmpi)
5674 call mpi_allreduce(local_max2,ximax2,1,mpi_double_precision,mpi_max,icomm,ierrmpi)
5675 if (ximin1>0.5d0*huge(one) .or. ximax1<-0.5d0*huge(one) .or. &
5676 ximin2>0.5d0*huge(one) .or. ximax2<-0.5d0*huge(one)) then
5677 call mpistop("sph_intersection could not determine image bounds")
5678 endif
5680
5682 double precision, intent(out) :: dxI
5683
5684 select case(trim(dat_resolution_mode))
5685 case('nominal')
5687 case('minimum')
5689 case default
5690 call mpistop("unknown dat_resolution_mode")
5691 end select
5692 end subroutine get_native_datresol_spacing
5693
5695 double precision, intent(out) :: dxI
5696
5697 double precision :: refine_factor,dr,dtheta,dphi,rmin,sin_theta_min
5698
5699 refine_factor=dble(2**(refine_max_level-1))
5700 if (slab) then
5701 dxi=min(abs(xprobmax1-xprobmin1)/(dble(domain_nx1)*refine_factor),&
5702 abs(xprobmax2-xprobmin2)/(dble(domain_nx2)*refine_factor),&
5703 abs(xprobmax3-xprobmin3)/(dble(domain_nx3)*refine_factor))
5704 else if (coordinate==spherical) then
5705 rmin=max(smalldouble,min(xprobmin1,xprobmax1))
5706 sin_theta_min=max(smalldouble,min(abs(sin(xprobmin2)),&
5707 abs(sin(xprobmax2))))
5708 dr=abs(xprobmax1-xprobmin1)/(dble(domain_nx1)*refine_factor)
5709 dtheta=abs(xprobmax2-xprobmin2)/(dble(domain_nx2)*refine_factor)
5710 dphi=abs(xprobmax3-xprobmin3)/(dble(domain_nx3)*refine_factor)
5711 dxi=min(dr,rmin*dtheta,rmin*sin_theta_min*dphi)
5712 else
5713 call mpistop("nominal dat resolution needs Cartesian or spherical coordinates")
5714 endif
5715
5716 if (dxi<=zero .or. dxi>half*huge(one)) then
5717 call mpistop("could not determine nominal dat-resolution image spacing")
5718 endif
5719 end subroutine get_nominal_datresol_spacing
5720
5722 double precision, intent(out) :: dxI
5723
5724 integer :: iigrid,igrid,ixI^L,ixO^L,ix^D
5725 double precision :: local_min,global_min,dr,ds_theta,ds_phi,rval,theta
5726
5727 local_min=huge(one)
5728 do iigrid=1,igridstail
5729 igrid=igrids(iigrid)
5730 ^d&ixomin^d=ixmlo^d\
5731 ^d&ixomax^d=ixmhi^d\
5732 ^d&iximin^d=ixglo^d\
5733 ^d&iximax^d=ixghi^d\
5734
5735 do ix1=ixomin1,ixomax1
5736 do ix2=ixomin2,ixomax2
5737 do ix3=ixomin3,ixomax3
5738 if (slab) then
5739 local_min=min(local_min,ps(igrid)%dx(ix^d,1),&
5740 ps(igrid)%dx(ix^d,2),ps(igrid)%dx(ix^d,3))
5741 else if (coordinate==spherical) then
5742 rval=max(smalldouble,ps(igrid)%x(ix^d,1))
5743 theta=ps(igrid)%x(ix^d,2)
5744 dr=ps(igrid)%dx(ix^d,1)
5745 ds_theta=rval*ps(igrid)%dx(ix^d,2)
5746 ds_phi=rval*max(smalldouble,sin(theta))*ps(igrid)%dx(ix^d,3)
5747 local_min=min(local_min,dr,ds_theta,ds_phi)
5748 else
5749 call mpistop("minimum dat resolution needs Cartesian or spherical coordinates")
5750 endif
5751 enddo
5752 enddo
5753 enddo
5754 enddo
5755
5756 call mpi_allreduce(local_min,global_min,1,mpi_double_precision,mpi_min,&
5757 icomm,ierrmpi)
5758 if (global_min<=zero .or. global_min>half*huge(one)) then
5759 call mpistop("could not determine minimum dat-resolution image spacing")
5760 endif
5761 dxi=global_min
5762 end subroutine get_minimum_datresol_spacing
5763
5764 subroutine get_image(qunit,datatype,fl)
5765 ! integrate emission flux along line of sight (LOS)
5766 ! in a 3D simulation box and get a 2D EUV image
5768 use mod_constants
5769
5770 integer, intent(in) :: qunit
5771 type(te_fluid), intent(in) :: fl
5772 character(20), intent(in) :: datatype
5773
5774 integer :: ix^D,numXI1,numXI2,numWI
5775 double precision :: xImin1,xImax1,xImin2,xImax2,xIcent1,xIcent2,dxI
5776 double precision, allocatable :: xI1(:),xI2(:),dxI1(:),dxI2(:)
5777 double precision, allocatable :: wI(:,:,:),wIs(:,:,:),EM(:,:),Dpl(:,:),Tau(:,:),EMthin(:,:),WLB(:,:,:)
5778 double precision :: vec_temp1(1:3),vec_temp2(1:3)
5779 double precision :: vec_z(1:3),vec_cor(1:3),xI_cor(1:2)
5780 double precision :: res,LOS_psi,r_max,r_loc
5781
5782 integer :: mass
5783 character (30) :: ion
5784 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
5785 double precision :: arcsec,RHESSI_rsl,LASCO_rsl,pixel,R_occult,smallflux
5786 integer :: iigrid,igrid,i,j,numSI,iw
5787 logical :: emit,ray_image_global,has_thick_output
5788
5789 if (coordinate==spherical) then
5791 else
5792 ! cartesian
5794 endif
5795
5796 ! calculate domain of the image
5797 if (coordinate==spherical) then
5798 if (trim(ray_method_active)=='spherical' .and. datatype=='image_euv') then
5799 call get_sph_intersection_image_bounds(ximin1,ximax1,ximin2,ximax2)
5800 else
5801 ximin1=-abs(xprobmax1)
5802 ximin2=-abs(xprobmax1)
5803 ximax1=abs(xprobmax1)
5804 ximax2=abs(xprobmax1)
5805 endif
5806 else
5807 ! calculate domain of the image
5808 do ix1=1,2
5809 if (ix1==1) vec_cor(1)=xprobmin1
5810 if (ix1==2) vec_cor(1)=xprobmax1
5811 do ix2=1,2
5812 if (ix2==1) vec_cor(2)=xprobmin2
5813 if (ix2==2) vec_cor(2)=xprobmax2
5814 do ix3=1,2
5815 if (ix3==1) vec_cor(3)=xprobmin3
5816 if (ix3==2) vec_cor(3)=xprobmax3
5817 if (big_image) then
5818 r_loc=(vec_cor(1)-x_origin(1))**2
5819 r_loc=r_loc+(vec_cor(2)-x_origin(2))**2
5820 r_loc=r_loc+(vec_cor(3)-x_origin(3))**2
5821 r_loc=sqrt(r_loc)
5822 if (ix1==1 .and. ix2==1 .and. ix3==1) then
5823 r_max=r_loc
5824 else
5825 r_max=max(r_max,r_loc)
5826 endif
5827 else
5828 call get_cor_image(vec_cor,xi_cor)
5829 if (ix1==1 .and. ix2==1 .and. ix3==1) then
5830 ximin1=xi_cor(1)
5831 ximax1=xi_cor(1)
5832 ximin2=xi_cor(2)
5833 ximax2=xi_cor(2)
5834 else
5835 ximin1=min(ximin1,xi_cor(1))
5836 ximax1=max(ximax1,xi_cor(1))
5837 ximin2=min(ximin2,xi_cor(2))
5838 ximax2=max(ximax2,xi_cor(2))
5839 endif
5840 endif
5841 enddo
5842 enddo
5843 enddo
5844 if (big_image) then
5845 ximin1=-r_max
5846 ximin2=-r_max
5847 ximax1=r_max
5848 ximax2=r_max
5849 endif
5850 endif
5851 xicent1=(ximin1+ximax1)/2.d0
5852 xicent2=(ximin2+ximax2)/2.d0
5853
5854 ! tables for image
5855 if (si_unit) then
5856 arcsec=7.25d5/unit_length
5857 else
5858 arcsec=7.25d7/unit_length
5859 endif
5860 if (datatype=='image_euv') then
5861 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
5862 dxi=spacersl*arcsec ! intrument resolution of image
5863 smallflux=smalldouble
5864 else if (datatype=='image_sxr') then
5865 rhessi_rsl=2.3d0/instrument_resolution_factor
5866 dxi=rhessi_rsl*arcsec
5867 smallflux=1.d-40
5868 else if (datatype=='image_whitelight') then
5869 if (whitelight_instrument=='LASCO/C1') then
5870 lasco_rsl=5.6d0/instrument_resolution_factor
5871 r_occult=1.1d0
5872 else if (whitelight_instrument=='LASCO/C2') then
5873 lasco_rsl=11.4d0/instrument_resolution_factor
5874 r_occult=2.d0
5875 else if (whitelight_instrument=='LASCO/C3') then
5876 lasco_rsl=56.d0/instrument_resolution_factor
5877 r_occult=3.7d0
5878 else
5879 call mpistop('Whitelight synthesis: instrument is not supported!')
5880 endif
5881 dxi=lasco_rsl*arcsec
5882 if (r_occultor>1.d0) r_occult=r_occultor
5883 r_occult=r_occult*const_rsun/unit_length
5884 smallflux=1.d-20
5885 endif
5886 numxi1=8*ceiling((ximax1-xicent1)/dxi/8.d0)
5887 ximin1=xicent1-numxi1*dxi
5888 ximax1=xicent1+numxi1*dxi
5889 numxi1=numxi1*2
5890 numxi2=8*ceiling((ximax2-xicent2)/dxi/8.d0)
5891 ximin2=xicent2-numxi2*dxi
5892 ximax2=xicent2+numxi2*dxi
5893 numxi2=numxi2*2
5894 allocate(xi1(numxi1),xi2(numxi2),dxi1(numxi1),dxi2(numxi2))
5895 do ix1=1,numxi1
5896 xi1(ix1)=ximin1+dxi*(ix1-half)
5897 dxi1(ix1)=dxi
5898 enddo
5899 do ix2=1,numxi2
5900 xi2(ix2)=ximin2+dxi*(ix2-half)
5901 dxi2(ix2)=dxi
5902 enddo
5903
5904 ! calculate emission
5905 if (datatype=='image_euv' .or. datatype=='image_sxr') then
5906 has_thick_output=datatype=='image_euv' .and. trim(radiation_transfer)=='thick' .and. &
5907 ((coordinate==spherical .and. trim(ray_method_active)=='spherical') .or. &
5908 (slab .and. trim(ray_method_active)=='cart'))
5909 if (datatype=='image_euv') then
5910 numwi=radsyn_euv_num_outputs(.false.,has_thick_output)
5911 else
5912 numwi=1
5913 endif
5914 allocate(wi(numxi1,numxi2,numwi),wis(numxi1,numxi2,numwi),em(numxi1,numxi2))
5915 wi=zero
5916 wis=zero
5917 em=zero
5918 ray_image_global=.false.
5919 if (has_thick_output) then
5920 allocate(tau(numxi1,numxi2),emthin(numxi1,numxi2))
5921 tau=zero
5922 emthin=zero
5923 endif
5924 if (slab .and. datatype=='image_euv' .and. &
5925 trim(ray_method_active)=='cart') then
5926 ray_image_global=.true.
5927 allocate(dpl(numxi1,numxi2))
5928 dpl=zero
5929 if (trim(radiation_transfer)=='thick') then
5930 call integrate_euv_cart_dda_thick_datresol(numxi1,numxi2,xi1,xi2,fl,em,dpl,tau,emthin)
5931 else
5932 call integrate_euv_cart_dda_datresol(numxi1,numxi2,xi1,xi2,fl,em,dpl)
5933 endif
5934 deallocate(dpl)
5935 else if (slab) then
5936 do iigrid=1,igridstail; igrid=igrids(iigrid);
5937 call integrate_emission_cartesian(igrid,numxi1,numxi2,xi1,xi2,dxi,fl,datatype,em)
5938 enddo
5939 else if (trim(ray_method_active) == 'spherical' .and. datatype == 'image_euv') then
5940 if (trim(radiation_transfer) == 'thick') then
5941 ray_image_global=.true.
5942 call integrate_euv_sph_intersection_thick(numxi1,numxi2,xi1,xi2,dxi,fl,em,tau,emthin)
5943 else
5944 call integrate_euv_sph_intersection_thin(numxi1,numxi2,xi1,xi2,dxi,fl,em)
5945 endif
5946 else
5947 do iigrid=1,igridstail; igrid=igrids(iigrid);
5948 call integrate_emission_spherical(igrid,numxi1,numxi2,xi1,xi2,dxi,fl,datatype,em)
5949 enddo
5950 endif
5951 if (ray_image_global) then
5952 if (has_thick_output) then
5953 call pack_euv_image_outputs(numxi1,numxi2,em,wi,smallflux,.false.,&
5954 has_thick_output,tau=tau,euvthin=emthin,&
5955 cap_absorption=.true.)
5956 else
5957 call pack_euv_image_outputs(numxi1,numxi2,em,wi,smallflux,.false.,has_thick_output)
5958 endif
5959 else
5960 do ix1=1,numxi1
5961 do ix2=1,numxi2
5962 if (em(ix1,ix2)>smallflux) wis(ix1,ix2,1)=em(ix1,ix2)
5963 enddo
5964 enddo
5965 endif
5966 if (.not. ray_image_global) then
5967 numsi=numxi1*numxi2*numwi
5968 call mpi_allreduce(wis,wi,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5969 endif
5970 if (activate_unit_arcsec) then
5971 xi1=xi1/arcsec
5972 dxi1=dxi1/arcsec
5973 xi2=xi2/arcsec
5974 dxi2=dxi2/arcsec
5975 endif
5976 call output_data(qunit,xi1,xi2,dxi1,dxi2,wi,numxi1,numxi2,numwi,datatype)
5977 if (allocated(tau)) deallocate(tau)
5978 if (allocated(emthin)) deallocate(emthin)
5979 deallocate(wi,wis,em)
5980 else if (datatype=='image_whitelight') then
5981 numwi=2
5982 allocate(wi(numxi1,numxi2,numwi),wis(numxi1,numxi2,numwi),wlb(numxi1,numxi2,numwi))
5983 wi=zero
5984 wis=zero
5985 wlb=zero
5986 if (coordinate==spherical) then
5987 do iigrid=1,igridstail; igrid=igrids(iigrid);
5988 call integrate_whitelight_spherical(igrid,numxi1,numxi2,numwi,xi1,xi2,dxi,fl,datatype,wlb)
5989 enddo
5990 endif
5991 do ix1=1,numxi1
5992 do ix2=1,numxi2
5993 if (wlb(ix1,ix2,1)>smallflux) then
5994 wis(ix1,ix2,1)=wlb(ix1,ix2,1)
5995 wis(ix1,ix2,2)=wlb(ix1,ix2,2)
5996 endif
5997 enddo
5998 enddo
5999 numsi=numxi1*numxi2*numwi
6000 call mpi_allreduce(wis,wi,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
6001 if (activate_unit_arcsec) then
6002 xi1=xi1/arcsec
6003 dxi1=dxi1/arcsec
6004 xi2=xi2/arcsec
6005 dxi2=dxi2/arcsec
6006 endif
6007 call output_data(qunit,xi1,xi2,dxi1,dxi2,wi,numxi1,numxi2,numwi,datatype)
6008 deallocate(wi,wis,wlb)
6009 endif
6010
6011 deallocate(xi1,xi2,dxi1,dxi2)
6012
6013 end subroutine get_image
6014
6015 subroutine integrate_emission_cartesian(igrid,numXI1,numXI2,xI1,xI2,dxI,fl,datatype,EM)
6016 integer, intent(in) :: igrid,numXI1,numXI2
6017 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6018 double precision, intent(in) :: dxI
6019 type(te_fluid), intent(in) :: fl
6020 character(20), intent(in) :: datatype
6021 double precision, intent(inout) :: EM(numXI1,numXI2)
6022
6023 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6024 double precision :: xb^L,xd^D
6025 double precision, allocatable :: flux(:^D&),opacity(:^D&)
6026 double precision :: res
6027 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6028 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC
6029 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2)
6030
6031 integer :: mass
6032 double precision :: logTe
6033 character (30) :: ion
6034 double precision :: lineCent
6035 double precision :: sigma_PSF,spaceRsl,wlRsl,sigma0,factor,wslit
6036 double precision :: arcsec,pixel,RHESSI_rsl,area_1AU
6037 double precision :: aa,bb
6038
6039 ^d&ixomin^d=ixmlo^d\
6040 ^d&ixomax^d=ixmhi^d\
6041 ^d&iximin^d=ixglo^d\
6042 ^d&iximax^d=ixghi^d\
6043 ^d&xbmin^d=rnode(rpxmin^d_,igrid)\
6044 ^d&xbmax^d=rnode(rpxmax^d_,igrid)\
6045
6046 if (si_unit) then
6047 arcsec=7.25d5/unit_length
6048 else
6049 arcsec=7.25d7/unit_length
6050 endif
6051
6052 allocate(flux(ixi^s),opacity(ixi^s))
6053 if (datatype=='image_euv') then
6054 if (trim(emission_model)=='pseudo_current') then
6055 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,flux)
6056 else if (trim(emission_model)=='radio_ff') then
6057 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,opacity)
6058 else
6059 ! get local EUV flux and velocity
6060 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
6061 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
6062 endif
6063 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
6064 pixel=spacersl*arcsec
6065 sigma0=sigma_psf*pixel
6066 else if (datatype=='image_sxr') then
6067 ! get local SXR flux photons cm^-3 s^-1 (cgs) or photons m^-3 s^-1 (SI)
6068 call get_sxr(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,emin_sxr,emax_sxr)
6069 rhessi_rsl=2.3d0/instrument_resolution_factor
6070 sigma_psf=1.d0
6071 pixel=rhessi_rsl*arcsec
6072 sigma0=sigma_psf*pixel
6073 area_1au=2.81d27
6074 endif
6075
6076 ! integrate emission
6077 {do ix^d=ixomin^d,ixomax^d\}
6078 ^d&nsubc^d=1;
6079 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi1(^d))/(dxi/2.d0)));
6080 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi2(^d))/(dxi/2.d0)));
6081 ^d&dxsubc^d=ps(igrid)%dx(ix^dd,^d)/nsubc^d;
6082 if (datatype=='image_euv') then
6083 if (si_unit) then
6084 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length*1.d2/dxi/dxi ! DN s^-1
6085 else
6086 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length/dxi/dxi ! DN s^-1
6087 endif
6088 else if (datatype=='image_sxr') then
6089 ! sub-cell SXR flux at 1 AU [photons s^-1 cm^-2]
6090 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length**3/area_1au
6091 endif
6092 if (fluxsubc>smalldouble) then
6093 ! dividing a cell to several parts to get more accurate integrating values
6094 {do isubc^d=1,nsubc^d\}
6095 ^d&xsubc(^d)=ps(igrid)%x(ix^dd,^d)-half*ps(igrid)%dx(ix^dd,^d)+(isubc^d-half)*dxsubc^d;
6096 ! mapping the 3D coordinate to location at the image
6097 call get_cor_image(xsubc,xcent)
6098 ! distribution at nearby pixels
6099 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6100 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6101 ixpmin1=max(1,ixp1-3)
6102 ixpmax1=min(ixp1+3,numxi1)
6103 ixpmin2=max(1,ixp2-3)
6104 ixpmax2=min(ixp2+3,numxi2)
6105 do ixp1=ixpmin1,ixpmax1
6106 do ixp2=ixpmin2,ixpmax2
6107 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6108 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6109 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6110 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6111 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6112 em(ixp1,ixp2)=em(ixp1,ixp2)+fluxsubc*factor
6113 enddo !ixP2
6114 enddo !ixP1
6115 {enddo\} !iSubC
6116 endif
6117 {enddo\} !ix
6118
6119 deallocate(flux,opacity)
6120 end subroutine integrate_emission_cartesian
6121
6122 subroutine integrate_emission_spherical(igrid,numXI1,numXI2,xI1,xI2,dxI,fl,datatype,EM)
6123 integer, intent(in) :: igrid,numXI1,numXI2
6124 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6125 double precision, intent(in) :: dxI
6126 type(te_fluid), intent(in) :: fl
6127 character(20), intent(in) :: datatype
6128 double precision, intent(inout) :: EM(numXI1,numXI2)
6129
6130 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6131 double precision, allocatable :: flux(:^D&),Ne(:^D&),opacity(:^D&)
6132 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6133 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC,RsubC
6134 double precision :: TBsubC,PBsubC
6135 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2),xSubC_car(1:3)
6136 double precision :: R_thick,dotp,dvolume,R_occult,Rc
6137 double precision :: dxl(1:3),x_sph(1:3),dx_sph(1:3)
6138 double precision :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6139 logical :: sun_back_side,emit
6140
6141 integer :: mass
6142 double precision :: logTe
6143 character (30) :: ion
6144 double precision :: lineCent
6145 double precision :: sigma_PSF,spaceRsl,wlRsl,sigma0,factor,wslit
6146 double precision :: RHESSI_rsl,area_1AU,arcsec,pixel
6147
6148 ^d&ixomin^d=ixmlo^d;
6149 ^d&ixomax^d=ixmhi^d;
6150 ^d&iximin^d=ixglo^d;
6151 ^d&iximax^d=ixghi^d;
6152
6153 if (si_unit) then
6154 arcsec=7.25d5/unit_length
6155 else
6156 arcsec=7.25d7/unit_length
6157 endif
6158
6159 allocate(flux(ixi^s),opacity(ixi^s))
6160 if (datatype=='image_euv') then
6161 if (trim(emission_model)=='pseudo_current') then
6162 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,flux)
6163 else if (trim(emission_model)=='radio_ff') then
6164 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,opacity)
6165 else
6166 ! get local EUV flux and velocity
6167 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
6168 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
6169 endif
6170 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
6171 pixel=spacersl*arcsec
6172 sigma0=sigma_psf*pixel
6173 else if (datatype=='image_sxr') then
6174 ! get local SXR flux photons cm^-3 s^-1 (cgs) or photons m^-3 s^-1 (SI)
6175 call get_sxr(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,emin_sxr,emax_sxr)
6176 rhessi_rsl=2.3d0/instrument_resolution_factor
6177 sigma_psf=1.d0
6178 pixel=rhessi_rsl*arcsec
6179 sigma0=sigma_psf*pixel
6180 area_1au=2.81d27
6181 endif
6182
6183 ! integrate emission
6184 r_thick=r_opt_thick*const_rsun/unit_length
6185 {do ix^d=ixomin^d,ixomax^d\}
6186 x_sph(1:3)=ps(igrid)%x(ix^d,1:3)
6187 dx_sph(1:3)=ps(igrid)%dx(ix^d,1:3)
6188 dxl(1)=dx_sph(1) ! cell size in length
6189 dxl(2)=x_sph(1)*dx_sph(2) ! cell size in length
6190 dxl(3)=x_sph(1)*dsin(x_sph(2))*dx_sph(3) ! cell size in length
6191 ! dividing a cell to several sub-cells to get more accurate integrating values
6192 ^d&nsubc^d=1;
6193 call get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6194 call dot_product_loc(unitv_r,vec_xi1,dotp)
6195 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6196 call dot_product_loc(unitv_r,vec_xi2,dotp)
6197 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6198 call dot_product_loc(unitv_theta,vec_xi1,dotp)
6199 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6200 call dot_product_loc(unitv_theta,vec_xi2,dotp)
6201 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6202 call dot_product_loc(unitv_phi,vec_xi1,dotp)
6203 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6204 call dot_product_loc(unitv_phi,vec_xi2,dotp)
6205 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6206
6207 ! integrate sub-cells
6208 do isubc1=1,nsubc1
6209 ! sub-cell center coordinate in spherical
6210 xsubc(1)=x_sph(1)-half*dx_sph(1)+(isubc1-half)*dx_sph(1)/nsubc1
6211 rsubc=xsubc(1)
6212 dxsubc1=dx_sph(1)/nsubc1 ! sub-cell size in length
6213 do isubc2=1,nsubc2
6214 ! sub-cell center coordinate in spherical
6215 xsubc(2)=x_sph(2)-half*dx_sph(2)+(isubc2-half)*dx_sph(2)/nsubc2
6216 dxsubc2=xsubc(1)*dx_sph(2)/nsubc2 ! sub-cell size in length
6217 dxsubc3=xsubc(1)*dsin(xsubc(2))*dx_sph(3)/nsubc3 ! sub-cell size in length
6218 dvolume=dxsubc1*dxsubc2*dxsubc3
6219 if (datatype=='image_euv') then
6220 if (si_unit) then
6221 fluxsubc=flux(ix^d)*dvolume*unit_length*1.d2/dxi/dxi ! DN s^-1
6222 else
6223 fluxsubc=flux(ix^d)*dvolume*unit_length/dxi/dxi ! DN s^-1
6224 endif
6225 else if (datatype=='image_sxr') then
6226 ! sub-cell SXR flux at 1 AU [photons s^-1 cm^-2]
6227 fluxsubc=flux(ix^d)*dvolume*unit_length**3/area_1au
6228 endif
6229 ! enter integration if flux large enough
6230 if (fluxsubc>smalldouble) then
6231 do isubc3=1,nsubc3
6232 ! sub-cell center coordinate in spherical
6233 xsubc(3)=x_sph(3)-half*dx_sph(3)+(isubc3-half)*dx_sph(3)/nsubc3
6234 call get_cor_image_spherical(xsubc,xcent)
6235 rc=dsqrt(xcent(1)**2+xcent(2)**2) ! distance to sun center (on the image plane)
6236 !
6237 ! whether the local emitted photons can arrive the telescope
6238 call spherical_to_cartesian(xsubc,xsubc_car)
6239 call dot_product_loc(vec_los,xsubc_car,dotp)
6240 sun_back_side=.true.
6241 if (dotp<0.d0) sun_back_side=.false.
6242 ! whether the local emission can reach the telescope
6243 if (sun_back_side) then
6244 emit=.false.
6245 if (rc>r_thick) emit=.true.
6246 else
6247 emit=.true.
6248 if (xsubc(1)<=r_thick) emit=.false.
6249 endif
6250 !
6251 if (emit) then
6252 ! mapping the 3D coordinate to location at the image
6253 ! distribution at nearby pixels
6254 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6255 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6256 ixpmin1=max(1,ixp1-3)
6257 ixpmax1=min(ixp1+3,numxi1)
6258 ixpmin2=max(1,ixp2-3)
6259 ixpmax2=min(ixp2+3,numxi2)
6260 do ixp1=ixpmin1,ixpmax1
6261 do ixp2=ixpmin2,ixpmax2
6262 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6263 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6264 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6265 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6266 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6267 em(ixp1,ixp2)=em(ixp1,ixp2)+fluxsubc*factor
6268 enddo !ixP2
6269 enddo !ixP1
6270 endif !emit
6271 enddo !iSubC3
6272 endif !smallflux
6273 enddo !iSubC2
6274 enddo !iSubC1
6275 {enddo\} !ix
6276
6277 deallocate(flux,opacity)
6278
6279 end subroutine integrate_emission_spherical
6280
6281 subroutine integrate_whitelight_spherical(igrid,numXI1,numXI2,numWI,xI1,xI2,dxI,fl,datatype,WLB)
6282 use mod_eos, only: eos
6283
6284 integer, intent(in) :: igrid,numXI1,numXI2,numWI
6285 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6286 double precision, intent(in) :: dxI
6287 type(te_fluid), intent(in) :: fl
6288 character(20), intent(in) :: datatype
6289 double precision, intent(inout) :: WLB(numXI1,numXI2,numWI)
6290
6291 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6292 double precision, allocatable :: flux(:^D&),Ne(:^D&)
6293 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6294 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC,RsubC
6295 double precision :: sigma_PSF,sigma0,arcsec,pixel,LASCO_rsl
6296 double precision :: A,B,C,D,Rc,Ne0,TBsubC,PBsubC,factor
6297 double precision :: R_thick,dotp,dvolume,R_occult
6298 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2),xSubC_car(1:3)
6299 double precision :: dxl(1:3),x_sph(1:3),dx_sph(1:3)
6300 double precision :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6301 logical :: emit
6302
6303 ^d&ixomin^d=ixmlo^d;
6304 ^d&ixomax^d=ixmhi^d;
6305 ^d&iximin^d=ixglo^d;
6306 ^d&iximax^d=ixghi^d;
6307
6308 if (si_unit) then
6309 arcsec=7.25d5/unit_length
6310 else
6311 arcsec=7.25d7/unit_length
6312 endif
6313
6314 allocate(ne(ixi^s))
6315 if (whitelight_instrument=='LASCO/C1') then
6316 lasco_rsl=5.6d0/instrument_resolution_factor
6317 r_occult=1.1d0
6318 else if (whitelight_instrument=='LASCO/C2') then
6319 lasco_rsl=11.4d0/instrument_resolution_factor
6320 r_occult=2.d0
6321 else if (whitelight_instrument=='LASCO/C3') then
6322 lasco_rsl=56.d0/instrument_resolution_factor
6323 r_occult=3.7d0
6324 endif
6325 if (r_occultor>1.d0) r_occult=r_occultor
6326 r_occult=r_occult*const_rsun/unit_length
6327 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,ne)
6328 ! get actual electron density from EoS (replaces rho with ne)
6329 block
6330 double precision :: nH_dummy(ixI^S)
6331 call eos%get_ne_nH(ixi^l, ixo^l, ps(igrid)%w, ne, nh_dummy)
6332 end block
6333 sigma_psf=1.d0
6334 pixel=lasco_rsl*arcsec
6335 sigma0=sigma_psf*pixel
6336
6337 ! integrate emission
6338 r_thick=r_opt_thick*const_rsun/unit_length
6339 {do ix^d=ixomin^d,ixomax^d\}
6340 x_sph(1:3)=ps(igrid)%x(ix^d,1:3)
6341 dx_sph(1:3)=ps(igrid)%dx(ix^d,1:3)
6342 dxl(1)=dx_sph(1) ! cell size in length
6343 dxl(2)=x_sph(1)*dx_sph(2) ! cell size in length
6344 dxl(3)=x_sph(1)*dsin(x_sph(2))*dx_sph(3) ! cell size in length
6345 ne0=ne(ix^d)*unit_numberdensity
6346 ! dividing a cell to several sub-cells to get more accurate integrating values
6347 ^d&nsubc^d=1;
6348 call get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6349 call dot_product_loc(unitv_r,vec_xi1,dotp)
6350 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6351 call dot_product_loc(unitv_r,vec_xi2,dotp)
6352 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6353 call dot_product_loc(unitv_theta,vec_xi1,dotp)
6354 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6355 call dot_product_loc(unitv_theta,vec_xi2,dotp)
6356 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6357 call dot_product_loc(unitv_phi,vec_xi1,dotp)
6358 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6359 call dot_product_loc(unitv_phi,vec_xi2,dotp)
6360 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6361
6362 ! integrate sub-cells
6363 do isubc1=1,nsubc1
6364 ! sub-cell center coordinate in spherical
6365 xsubc(1)=x_sph(1)-half*dx_sph(1)+(isubc1-half)*dx_sph(1)/nsubc1
6366 rsubc=xsubc(1)
6367 dxsubc1=dx_sph(1)/nsubc1 ! sub-cell size in length
6368 call get_thomson_parameters(rsubc,a,b,c,d)
6369 do isubc2=1,nsubc2
6370 ! sub-cell center coordinate in spherical
6371 xsubc(2)=x_sph(2)-half*dx_sph(2)+(isubc2-half)*dx_sph(2)/nsubc2
6372 dxsubc2=xsubc(1)*dx_sph(2)/nsubc2 ! sub-cell size in length
6373 dxsubc3=xsubc(1)*dsin(xsubc(2))*dx_sph(3)/nsubc3 ! sub-cell size in length
6374 dvolume=dxsubc1*dxsubc2*dxsubc3
6375 do isubc3=1,nsubc3
6376 ! sub-cell center coordinate in spherical
6377 xsubc(3)=x_sph(3)-half*dx_sph(3)+(isubc3-half)*dx_sph(3)/nsubc3
6378 call get_cor_image_spherical(xsubc,xcent)
6379 rc=dsqrt(xcent(1)**2+xcent(2)**2) ! distance to sun center (on the image plane)
6380 ! whether the local emitted photons can arrive the telescope
6381 emit=.false.
6382 if (rc>r_occult) then
6383 emit=.true.
6384 ! scaterring flux from cm^-3 of plasma
6385 call get_whitelight_thomson(rsubc,rc,ne0,a,b,c,d,tbsubc,pbsubc)
6386 tbsubc=tbsubc*dvolume*unit_length/dxi/dxi
6387 pbsubc=pbsubc*dvolume*unit_length/dxi/dxi
6388 if (tbsubc<1.d-20) emit=.false.
6389 endif
6390 if (emit) then
6391 ! mapping the 3D coordinate to location at the image
6392 ! distribution at nearby pixels
6393 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6394 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6395 ixpmin1=max(1,ixp1-3)
6396 ixpmax1=min(ixp1+3,numxi1)
6397 ixpmin2=max(1,ixp2-3)
6398 ixpmax2=min(ixp2+3,numxi2)
6399 do ixp1=ixpmin1,ixpmax1
6400 do ixp2=ixpmin2,ixpmax2
6401 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6402 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6403 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6404 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6405 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6406 wlb(ixp1,ixp2,1)=wlb(ixp1,ixp2,1)+tbsubc*factor
6407 wlb(ixp1,ixp2,2)=wlb(ixp1,ixp2,2)+pbsubc*factor
6408 enddo !ixP2
6409 enddo !ixP1
6410 endif
6411 enddo !iSubC3
6412 enddo !iSubC2
6413 enddo !iSubC1
6414 {enddo\} !ix
6415
6416 deallocate(ne)
6417
6418 end subroutine integrate_whitelight_spherical
6419
6420 subroutine get_thomson_parameters(Rl,A,B,C,D)
6421 ! parameters given in Billings 1968
6422 use mod_constants
6423 double precision, intent(in) :: Rl
6424 double precision, intent(inout) :: A,B,C,D
6425
6426 double precision :: sinO,cosO,sinO2,cosO2,tmp
6427
6428 sino=const_rsun/(rl*unit_length)
6429 sino2=sino**2
6430 coso2=1.d0-sino2
6431 coso=abs(dsqrt(coso2))
6432 tmp=log((1.d0+sino)/coso)
6433 a=coso*sino2
6434 b=-(1.d0-3.d0*sino2-(coso2/sino)*(1.d0+3.d0*sino2)*tmp)/8.d0
6435 c=4.d0/3.d0-coso-coso*coso2/3.d0
6436 d=(5.d0+sino2-(coso2/sino)*(5.d0-sino2)*tmp)/8.d0
6437
6438 end subroutine get_thomson_parameters
6439
6440 subroutine get_whitelight_thomson(Rl,Rin,Ne,A,B,C,D,fluxTB,fluxPB)
6441 ! use the method in SSW/eltheory
6442 double precision, intent(in) :: Rl,Rin,Ne,A,B,C,D
6443 double precision, intent(inout) :: fluxTB,fluxPB
6444
6445 double precision :: const,u,Bt,Br,PB,TB,sinchi2
6446
6447 u=0.63d0
6448 const=1.24878d-25/(1.d0-u/3.d0)
6449 sinchi2=(rin/rl)**2
6450 bt=const*(c+u*(d-c))
6451 pb=const*sinchi2*((a+u*(b-a)))
6452 br=bt-pb
6453 tb=bt+br
6454 fluxtb=tb*ne
6455 fluxpb=pb*ne
6456
6457 end subroutine get_whitelight_thomson
6458
6459 subroutine get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6460 double precision, intent(in) :: x_sph(1:3)
6461 double precision, intent(inout) :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6462
6463 unitv_r(1)=dsin(x_sph(2))*dcos(x_sph(3))
6464 unitv_r(2)=dsin(x_sph(2))*dsin(x_sph(3))
6465 unitv_r(3)=dcos(x_sph(2))
6466 unitv_theta(1)=dcos(x_sph(2))*dcos(x_sph(3))
6467 unitv_theta(2)=dcos(x_sph(2))*dsin(x_sph(3))
6468 unitv_theta(3)=-dsin(x_sph(2))
6469 unitv_phi(1)=-dsin(x_sph(3))
6470 unitv_phi(2)=dcos(x_sph(3))
6471 unitv_phi(3)=zero
6472
6473 end subroutine get_unit_vector_spherical
6474
6475 subroutine output_data(qunit,xO1,xO2,dxO1,dxO2,wO,nXO1,nXO2,nWO,datatype)
6476 ! change the format of data and write data
6478
6479 integer, intent(in) :: qunit,nXO1,nXO2,nWO
6480 double precision, intent(in) :: dxO1(nxO1),dxO2(nxO2)
6481 double precision, intent(in) :: xO1(nXO1),xO2(nxO2)
6482 double precision, intent(inout) :: wO(nXO1,nXO2,nWO)
6483 character(20), intent(in) :: datatype
6484
6485 integer :: nPiece,nP1,nP2,nC1,nC2,nWC
6486 integer :: piece_nmax1,piece_nmax2,ix1,ix2,j,ipc,ixc1,ixc2
6487 double precision :: uniform_tol
6488 double precision, allocatable :: xC(:,:,:,:),wC(:,:,:,:),dxC(:,:,:,:)
6489
6490 ! clean small values
6491 uniform_tol=1.d-10
6492 do ix1=1,nxo1
6493 do ix2=1,nxo2
6494 do j=1,nwo
6495 if (abs(wo(ix1,ix2,j))<smalldouble) wo(ix1,ix2,j)=zero
6496 enddo
6497 enddo
6498 enddo
6499
6500 ! how many cells in each grid
6501 if (dat_resolution) then
6502 if (datatype=='image_euv' .or. datatype=='image_sxr') then
6503 if (los_phi==0 .and. los_theta==90) then
6504 piece_nmax1=block_nx2
6505 piece_nmax2=block_nx3
6506 else if (los_phi==90 .and. los_theta==90) then
6507 piece_nmax1=block_nx3
6508 piece_nmax2=block_nx1
6509 else
6510 piece_nmax1=block_nx1
6511 piece_nmax2=block_nx2
6512 endif
6513 else if (datatype=='spectrum_euv') then
6514 piece_nmax1=16
6515 if (direction_slit==1) then
6516 piece_nmax2=block_nx1
6517 else if (direction_slit==2) then
6518 piece_nmax2=block_nx2
6519 else
6520 piece_nmax2=block_nx3
6521 endif
6522 endif
6523 else
6524 piece_nmax1=20
6525 piece_nmax2=20
6526 endif
6527 loopn1: do j=piece_nmax1,1,-1
6528 if(mod(nxo1,j)==0) then
6529 nc1=j
6530 exit loopn1
6531 endif
6532 enddo loopn1
6533 loopn2: do j=piece_nmax2,1,-1
6534 if(mod(nxo2,j)==0) then
6535 nc2=j
6536 exit loopn2
6537 endif
6538 enddo loopn2
6539 ! how many grids
6540 np1=nxo1/nc1
6541 np2=nxo2/nc2
6542 npiece=np1*np2
6543 nwc=nwo
6544
6545 ! output images
6546 select case(convert_type)
6547 case('EIvtuCCmpi','ESvtuCCmpi','SIvtuCCmpi','WIvtuCCmpi')
6548 ! put data into grids
6549 allocate(xc(npiece,nc1,nc2,2))
6550 allocate(dxc(npiece,nc1,nc2,2))
6551 allocate(wc(npiece,nc1,nc2,nwo))
6552 do ipc=1,npiece
6553 do ixc1=1,nc1
6554 do ixc2=1,nc2
6555 ix1=mod(ipc-1,np1)*nc1+ixc1
6556 ix2=floor(1.0*(ipc-1)/np1)*nc2+ixc2
6557 xc(ipc,ixc1,ixc2,1)=xo1(ix1)
6558 xc(ipc,ixc1,ixc2,2)=xo2(ix2)
6559 dxc(ipc,ixc1,ixc2,1)=dxo1(ix1)
6560 dxc(ipc,ixc1,ixc2,2)=dxo2(ix2)
6561 do j=1,nwc
6562 wc(ipc,ixc1,ixc2,j)=wo(ix1,ix2,j)
6563 enddo
6564 enddo
6565 enddo
6566 enddo
6567 ! write data into vtu file
6568 call write_image_vtucc(qunit,xc,wc,dxc,npiece,nc1,nc2,nwc,datatype)
6569 deallocate(xc,dxc,wc)
6570 case('EIvtiCCmpi','ESvtiCCmpi','SIvtiCCmpi','WIvtiCCmpi')
6571 if (dat_resolution .and. &
6572 (maxval(abs(dxo1(:)-dxo1(1)))>uniform_tol*max(one,abs(dxo1(1))) .or. &
6573 maxval(abs(dxo2(:)-dxo2(1)))>uniform_tol*max(one,abs(dxo2(1))))) then
6574 call mpistop("vti needs uniform dat-resolution image grids")
6575 else
6576 call write_image_vticc(qunit,xo1,xo2,dxo1,dxo2,wo,nxo1,nxo2,nwo,nc1,nc2)
6577 endif
6578 case default
6579 call mpistop("Error in synthesize emission: Unknown convert_type")
6580 end select
6581
6582 end subroutine output_data
6583 }
6584
6585 subroutine write_image_vticc(qunit,xO1,xO2,dxO1,dxO2,wO,nXO1,nXO2,nWO,nC1,nC2)
6586 ! write image data to vti
6588
6589 integer, intent(in) :: qunit,nXO1,nXO2,nWO,nC1,nC2
6590 double precision, intent(in) :: xO1(nXO1),xO2(nxO2)
6591 double precision, intent(in) :: dxO1(nxO1),dxO2(nxO2)
6592 double precision, intent(in) :: wO(nXO1,nXO2,nWO)
6593
6594 double precision :: origin(1:3), spacing(1:3)
6595 integer :: wholeExtent(1:6)
6596 integer :: iw
6597 integer :: ixC1,ixC2
6598
6599 integer :: filenr
6600 logical :: fileopen
6601 character (70) :: subname,wname,vname,nameL,nameS
6602 character (len=std_len) :: filename
6603 logical :: sph_datres_no_doppler
6604
6605
6606 origin(1)=xo1(1)-0.5d0*dxo1(1)
6607 origin(2)=xo2(1)-0.5d0*dxo2(1)
6608 origin(3)=zero
6609 spacing(1)=dxo1(1)
6610 spacing(2)=dxo2(1)
6611 spacing(3)=one
6612 wholeextent=0
6613 wholeextent(2)=nxo1
6614 wholeextent(4)=nxo2
6615 sph_datres_no_doppler=dat_resolution .and. coordinate==spherical .and. trim(ray_method_active)=='spherical'
6616
6617 if (mype==0) then
6618 inquire(qunit,opened=fileopen)
6619 if(.not.fileopen)then
6620 ! generate filename
6621 filenr=snapshotini
6622 if (autoconvert) filenr=snapshotnext
6623 if (convert_type=='EIvtiCCmpi') then
6624 write(filename,'(a,i4.4,a)') trim(filename_euv),filenr,".vti"
6625 else if (convert_type=='SIvtiCCmpi') then
6626 write(filename,'(a,i4.4,a)') trim(filename_sxr),filenr,".vti"
6627 else if (convert_type=='WIvtiCCmpi') then
6628 write(filename,'(a,i4.4,a)') trim(filename_whitelight),filenr,".vti"
6629 else if (convert_type=='ESvtiCCmpi') then
6630 write(filename,'(a,i4.4,a)') trim(filename_spectrum),filenr,".vti"
6631 endif
6632 open(qunit,file=filename,status='unknown',form='formatted')
6633 endif
6634
6635 ! generate xml header
6636 write(qunit,'(a)')'<?xml version="1.0"?>'
6637 write(qunit,'(a)',advance='no') '<VTKFile type="ImageData"'
6638 write(qunit,'(a)')' version="0.1" byte_order="LittleEndian">'
6639 write(qunit,'(a,3(1pe14.6),a,6(i10),a,3(1pe14.6),a)')' <ImageData Origin="',&
6640 origin,'" WholeExtent="',wholeextent,'" Spacing="',spacing,'">'
6641 ! file info
6642 write(qunit,'(a)')'<FieldData>'
6643 write(qunit,'(2a)')'<DataArray type="Float32" Name="TIME" ',&
6644 'NumberOfTuples="1" format="ascii">'
6645 write(qunit,*) real(global_time*time_convert_factor)
6646 write(qunit,'(a)')'</DataArray>'
6647 write(qunit,'(a)')'</FieldData>'
6648 ! pixel/cell data
6649 write(qunit,'(a,6(i10),a)') '<Piece Extent="',wholeextent,'">'
6650 write(qunit,'(a)')'<CellData>'
6651 do iw=1,nwo
6652 ! variable name
6653 if (convert_type=='EIvtiCCmpi') then
6654 if (wavelength<100) then
6655 write(vname,'(a,i2)') "AIA",wavelength
6656 else if (wavelength<1000) then
6657 write(vname,'(a,i3)') "AIA",wavelength
6658 else
6659 write(vname,'(a,i4)') "IRIS",wavelength
6660 endif
6661 if (trim(emission_model)=='pseudo_current' .and. iw==1) vname='pseudo_current'
6662 if (trim(emission_model)=='radio_ff' .and. iw==1) vname='radio_brightness_temperature'
6663 if (trim(radiation_transfer)=='thick' .and. iw==1) vname=trim(vname)//'_thick'
6664 if (iw==2 .and. dat_resolution .and. (.not. sph_datres_no_doppler) .and. &
6665 trim(emission_model)/='radio_ff' .and. &
6666 trim(emission_model)/='pseudo_current') vname='Doppler_velocity'
6667 if (output_tau .and. trim(radiation_transfer)=='thick' .and. &
6668 ((trim(emission_model)=='radio_ff' .and. iw==2) .or. &
6669 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6670 ((dat_resolution .and. ((sph_datres_no_doppler .and. iw==2) .or. &
6671 ((.not. sph_datres_no_doppler) .and. iw==3))) .or. &
6672 ((.not. dat_resolution) .and. iw==2))))) then
6673 vname='tau'
6674 endif
6675 if (output_absorption_fraction .and. trim(radiation_transfer)=='thick' .and. &
6676 ((trim(emission_model)=='radio_ff' .and. ((output_tau .and. iw==3) .or. &
6677 ((.not. output_tau) .and. iw==2))) .or. &
6678 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6679 ((dat_resolution .and. sph_datres_no_doppler .and. output_tau .and. iw==3) .or. &
6680 (dat_resolution .and. sph_datres_no_doppler .and. (.not. output_tau) .and. iw==2) .or. &
6681 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. output_tau .and. iw==4) .or. &
6682 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. (.not. output_tau) .and. iw==3) .or. &
6683 ((.not. dat_resolution) .and. output_tau .and. iw==3) .or. &
6684 ((.not. dat_resolution) .and. (.not. output_tau) .and. iw==2))))) then
6685 vname='absorption_fraction'
6686 endif
6687 else if (convert_type=='SIvtiCCmpi') then
6688 if (emin_sxr<10 .and. emax_sxr<10) then
6689 write(vname,'(a,i1,a,i1,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6690 else if (emin_sxr<10 .and. emax_sxr>=10) then
6691 write(vname,'(a,i1,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6692 else
6693 write(vname,'(a,i2,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6694 endif
6695 else if (convert_type=='WIvtiCCmpi') then
6696 if (iw==1) write(vname,'(a)')'B'
6697 if (iw==2) write(vname,'(a)')'pB'
6698 else if (convert_type=='ESvtiCCmpi') then
6699 if (spectrum_wl==1354) then
6700 write(vname,'(a,i4)') "SG",spectrum_wl
6701 else
6702 write(vname,'(a,i3)') "EIS",spectrum_wl
6703 endif
6704 endif
6705 write(qunit,'(a,a,a)')&
6706 '<DataArray type="Float64" Name="',trim(vname),'" format="ascii">'
6707 write(qunit,'(200(1pe14.6))') ((wo(ixc1,ixc2,iw),ixc1=1,nxo1),ixc2=1,nxo2)
6708 write(qunit,'(a)')'</DataArray>'
6709 enddo
6710 write(qunit,'(a)')'</CellData>'
6711 write(qunit,'(a)')'</Piece>'
6712 ! end
6713 write(qunit,'(a)')'</ImageData>'
6714 write(qunit,'(a)')'</VTKFile>'
6715 close(qunit)
6716 endif
6717
6718 end subroutine write_image_vticc
6719
6720 subroutine write_image_vtucc(qunit,xC,wC,dxC,nPiece,nC1,nC2,nWC,datatype)
6721 ! write image data to vtu
6723
6724 integer, intent(in) :: qunit
6725 integer, intent(in) :: nPiece,nC1,nC2,nWC
6726 double precision, intent(in) :: xC(nPiece,nC1,nC2,2),dxC(nPiece,nc1,nc2,2)
6727 double precision, intent(in) :: wC(nPiece,nC1,nC2,nWC)
6728 character(20), intent(in) :: datatype
6729
6730 integer :: nP1,nP2
6731 double precision :: xP(nPiece,nC1+1,nC2+1,2)
6732 integer :: filenr
6733 logical :: fileopen
6734 character (70) :: subname,wname,vname,nameL,nameS
6735 character (len=std_len) :: filename
6736 integer :: ixC1,ixC2,ixP,ix1,ix2,j
6737 integer :: nc,np,icel,VTK_type
6738 logical :: sph_datres_no_doppler
6739
6740 np1=nc1+1
6741 np2=nc2+1
6742 np=np1*np2
6743 nc=nc1*nc2
6744 sph_datres_no_doppler=dat_resolution .and. coordinate==spherical .and. trim(ray_method_active)=='spherical'
6745 ! cell corner location
6746 do ixp=1,npiece
6747 do ix1=1,np1
6748 do ix2=1,np2
6749 if (ix1<np1) xp(ixp,ix1,ix2,1)=xc(ixp,ix1,1,1)-0.5d0*dxc(ixp,ix1,1,1)
6750 if (ix1==np1) xp(ixp,ix1,ix2,1)=xc(ixp,ix1-1,1,1)+0.5d0*dxc(ixp,ix1-1,1,1)
6751 if (ix2<np2) xp(ixp,ix1,ix2,2)=xc(ixp,1,ix2,2)-0.5d0*dxc(ixp,1,ix2,2)
6752 if (ix2==np2) xp(ixp,ix1,ix2,2)=xc(ixp,1,ix2-1,2)+0.5d0*dxc(ixp,1,ix2-1,2)
6753 enddo
6754 enddo
6755 enddo
6756 if (mype==0) then
6757 inquire(qunit,opened=fileopen)
6758 if(.not.fileopen)then
6759 ! generate filename
6760 filenr=snapshotini
6761 if (autoconvert) filenr=snapshotnext
6762 if (datatype=='image_euv') then
6763 write(filename,'(a,i4.4,a)') trim(filename_euv),filenr,".vtu"
6764 else if (datatype=='image_sxr') then
6765 write(filename,'(a,i4.4,a)') trim(filename_sxr),filenr,".vtu"
6766 else if (datatype=='image_whitelight') then
6767 write(filename,'(a,i4.4,a)') trim(filename_whitelight),filenr,".vtu"
6768 else if (datatype=='spectrum_euv') then
6769 write(filename,'(a,i4.4,a)') trim(filename_spectrum),filenr,".vtu"
6770 endif
6771 open(qunit,file=filename,status='unknown',form='formatted')
6772 endif
6773 ! generate xml header
6774 write(qunit,'(a)')'<?xml version="1.0"?>'
6775 write(qunit,'(a)',advance='no') '<VTKFile type="UnstructuredGrid"'
6776 write(qunit,'(a)')' version="0.1" byte_order="LittleEndian">'
6777 write(qunit,'(a)')'<UnstructuredGrid>'
6778 write(qunit,'(a)')'<FieldData>'
6779 write(qunit,'(2a)')'<DataArray type="Float32" Name="TIME" ',&
6780 'NumberOfTuples="1" format="ascii">'
6781 write(qunit,*) real(global_time*time_convert_factor)
6782 write(qunit,'(a)')'</DataArray>'
6783 write(qunit,'(a)')'</FieldData>'
6784 do ixp=1,npiece
6785 write(qunit,'(a,i7,a,i7,a)') &
6786 '<Piece NumberOfPoints="',np,'" NumberOfCells="',nc,'">'
6787 write(qunit,'(a)')'<CellData>'
6788 do j=1,nwc
6789 if (datatype=='image_euv') then
6790 if (j==1) then
6791 if (wavelength<100) then
6792 write(vname,'(a,i2)') "AIA",wavelength
6793 else if (wavelength<1000) then
6794 write(vname,'(a,i3)') "AIA",wavelength
6795 else
6796 write(vname,'(a,i4)') "IRIS",wavelength
6797 endif
6798 if (trim(emission_model)=='pseudo_current') vname='pseudo_current'
6799 if (trim(emission_model)=='radio_ff') vname='radio_brightness_temperature'
6800 if (trim(radiation_transfer)=='thick') vname=trim(vname)//'_thick'
6801 endif
6802 if (j==2 .and. dat_resolution .and. (.not. sph_datres_no_doppler) .and. &
6803 trim(emission_model)/='radio_ff' .and. &
6804 trim(emission_model)/='pseudo_current') vname='Doppler_velocity'
6805 if (output_tau .and. trim(radiation_transfer)=='thick' .and. &
6806 ((trim(emission_model)=='radio_ff' .and. j==2) .or. &
6807 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6808 ((dat_resolution .and. ((sph_datres_no_doppler .and. j==2) .or. &
6809 ((.not. sph_datres_no_doppler) .and. j==3))) .or. &
6810 ((.not. dat_resolution) .and. j==2))))) then
6811 vname='tau'
6812 endif
6813 if (output_absorption_fraction .and. trim(radiation_transfer)=='thick' .and. &
6814 ((trim(emission_model)=='radio_ff' .and. ((output_tau .and. j==3) .or. &
6815 ((.not. output_tau) .and. j==2))) .or. &
6816 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6817 ((dat_resolution .and. sph_datres_no_doppler .and. output_tau .and. j==3) .or. &
6818 (dat_resolution .and. sph_datres_no_doppler .and. (.not. output_tau) .and. j==2) .or. &
6819 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. output_tau .and. j==4) .or. &
6820 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. (.not. output_tau) .and. j==3) .or. &
6821 ((.not. dat_resolution) .and. output_tau .and. j==3) .or. &
6822 ((.not. dat_resolution) .and. (.not. output_tau) .and. j==2))))) then
6823 vname='absorption_fraction'
6824 endif
6825 else if (datatype=='image_sxr') then
6826 if (emin_sxr<10 .and. emax_sxr<10) then
6827 write(vname,'(a,i1,a,i1,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6828 else if (emin_sxr<10 .and. emax_sxr>=10) then
6829 write(vname,'(a,i1,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6830 else
6831 write(vname,'(a,i2,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6832 endif
6833 else if (datatype=='image_whitelight') then
6834 write(vname,'(a)')'whitelight'
6835 else if (datatype=='spectrum_euv') then
6836 if (spectrum_wl==1354) then
6837 write(vname,'(a,i4)') "SG",spectrum_wl
6838 else
6839 write(vname,'(a,i3)') "EIS",spectrum_wl
6840 endif
6841 endif
6842 write(qunit,'(a,a,a)')&
6843 '<DataArray type="Float64" Name="',trim(vname),'" format="ascii">'
6844 write(qunit,'(200(1pe14.6))') ((wc(ixp,ixc1,ixc2,j),ixc1=1,nc1),ixc2=1,nc2)
6845 write(qunit,'(a)')'</DataArray>'
6846 enddo
6847 write(qunit,'(a)')'</CellData>'
6848 write(qunit,'(a)')'<Points>'
6849 write(qunit,'(a)')'<DataArray type="Float32" NumberOfComponents="3" format="ascii">'
6850 do ix2=1,np2
6851 do ix1=1,np1
6852 if (datatype=='image_euv' .and. dat_resolution) then
6853 if (los_phi==0 .and. los_theta==90) then
6854 write(qunit,'(3(1pe14.6))') 0.d0,xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2)
6855 else if (los_phi==90 .and. los_theta==90) then
6856 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,2),0.d0,xp(ixp,ix1,ix2,1)
6857 else
6858 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6859 endif
6860 else if (datatype=='image_sxr' .and. dat_resolution) then
6861 if (los_phi==0 .and. los_theta==90) then
6862 write(qunit,'(3(1pe14.6))') 0.d0,xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2)
6863 else if (los_phi==90 .and. los_theta==90) then
6864 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,2),0.d0,xp(ixp,ix1,ix2,1)
6865 else
6866 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6867 endif
6868 else
6869 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6870 endif
6871 enddo
6872 enddo
6873 write(qunit,'(a)')'</DataArray>'
6874 write(qunit,'(a)')'</Points>'
6875 ! connetivity part
6876 write(qunit,'(a)')'<Cells>'
6877 write(qunit,'(a)')'<DataArray type="Int32" Name="connectivity" format="ascii">'
6878 do ix2=1,nc2
6879 do ix1=1,nc1
6880 write(qunit,'(4(i7))') ix1-1+(ix2-1)*np1,ix1+(ix2-1)*np1,&
6881 ix1-1+ix2*np1,ix1+ix2*np1
6882 enddo
6883 enddo
6884 write(qunit,'(a)')'</DataArray>'
6885 ! offsets data array
6886 write(qunit,'(a)')'<DataArray type="Int32" Name="offsets" format="ascii">'
6887 do icel=1,nc
6888 write(qunit,'(i7)') icel*(2**2)
6889 enddo
6890 write(qunit,'(a)')'</DataArray>'
6891 ! VTK cell type data array
6892 write(qunit,'(a)')'<DataArray type="Int32" Name="types" format="ascii">'
6893 ! VTK_LINE=3; VTK_PIXEL=8; VTK_VOXEL=11 -> vtk-syntax
6894 vtk_type=8
6895 do icel=1,nc
6896 write(qunit,'(i2)') vtk_type
6897 enddo
6898 write(qunit,'(a)')'</DataArray>'
6899 write(qunit,'(a)')'</Cells>'
6900 write(qunit,'(a)')'</Piece>'
6901 enddo
6902 write(qunit,'(a)')'</UnstructuredGrid>'
6903 write(qunit,'(a)')'</VTKFile>'
6904 close(qunit)
6905 endif
6906 end subroutine write_image_vtucc
6907
6908 subroutine dot_product_loc(vec1,vec2,res)
6909 double precision, intent(in) :: vec1(1:3),vec2(1:3)
6910 double precision, intent(out) :: res
6911
6912 res=vec1(1)*vec2(1)+vec1(2)*vec2(2)+vec1(3)*vec2(3)
6913
6914 end subroutine dot_product_loc
6915
6916 subroutine cross_product_loc(vec_in1,vec_in2,vec_out)
6917 double precision, intent(in) :: vec_in1(1:3),vec_in2(1:3)
6918 double precision, intent(out) :: vec_out(1:3)
6919
6920 vec_out(1)=vec_in1(2)*vec_in2(3)-vec_in1(3)*vec_in2(2)
6921 vec_out(2)=vec_in1(3)*vec_in2(1)-vec_in1(1)*vec_in2(3)
6922 vec_out(3)=vec_in1(1)*vec_in2(2)-vec_in1(2)*vec_in2(1)
6923
6924 end subroutine cross_product_loc
6925
6927 integer :: j
6928 double precision :: LOS_psi
6929 double precision :: vec_car(1:3),vec_z(1:3),vec_temp1(1:3),vec_temp2(1:3)
6930 double precision :: vec_LOS_sph(1:3),vec_xI1_sph(1:3),vec_xI2_sph(1:3)
6931
6932 ! antiparallel to LOS in spherical
6933 vec_los(1)=1.d0
6934 vec_los(2)=dpi*los_theta/180.d0
6935 vec_los(3)=dpi*los_phi/180.d0
6936 ! LOS in cartesian
6937 call spherical_to_cartesian(vec_los,vec_car)
6938 vec_los=-vec_car
6939
6940 ! theta=0 in cartesian
6941 vec_z(:)=zero
6942 vec_z(3)=1.d0
6943
6944 ! x direction for image
6945 if (los_theta==zero) then
6946 vec_temp1(1)=1.d0
6947 vec_temp1(2)=dpi/2.d0
6948 vec_temp1(3)=dpi*los_phi/180.d0
6949 call spherical_to_cartesian(vec_temp1,vec_car)
6950 vec_temp1=-vec_car
6951 call cross_product_loc(vec_temp1,vec_z,vec_xi1)
6952 else
6954 endif
6955
6956 ! y direction for image
6958
6959 ! rotate the image
6960 vec_temp1=vec_xi1/sqrt(vec_xi1(1)**2+vec_xi1(2)**2+vec_xi1(3)**2)
6961 vec_temp2=vec_xi2/sqrt(vec_xi2(1)**2+vec_xi2(2)**2+vec_xi2(3)**2)
6962 los_psi=dpi*image_rotate/180.d0
6963 vec_xi1=vec_temp1*cos(los_psi)-vec_temp2*sin(los_psi)
6964 vec_xi2=vec_temp2*cos(los_psi)+vec_temp1*sin(los_psi)
6965
6966 do j=1,3
6967 if (abs(vec_los(j))<smalldouble) vec_los(j)=zero
6968 if (abs(vec_xi1(j))<smalldouble) vec_xi1(j)=zero
6969 if (abs(vec_xi2(j))<smalldouble) vec_xi2(j)=zero
6970 enddo
6971
6972 call cartesian_to_spherical(vec_los,vec_los_sph)
6973 call cartesian_to_spherical(vec_xi1,vec_xi1_sph)
6974 call cartesian_to_spherical(vec_xi2,vec_xi2_sph)
6975 vec_los_sph(2:3)=vec_los_sph(2:3)*180.d0/dpi
6976 vec_xi1_sph(2:3)=vec_xi1_sph(2:3)*180.d0/dpi
6977 vec_xi2_sph(2:3)=vec_xi2_sph(2:3)*180.d0/dpi
6978
6979 if (mype==0) write(*,'(a,f3.1,f6.1,f6.1,a)') ' ray direction (spherical): [',vec_los_sph(1),vec_los_sph(2),vec_los_sph(3),']'
6980 if (mype==0) write(*,'(a,f3.1,f6.1,f6.1,a)') ' xI1 direction (spherical): [',vec_xi1_sph(1),vec_xi1_sph(2),vec_xi1_sph(3),']'
6981 if (mype==0) write(*,'(a,f3.1,f6.1,f6.1,a)') ' xI2 direction (spherical): [',vec_xi2_sph(1),vec_xi2_sph(2),vec_xi2_sph(3),']'
6982
6983 end subroutine init_vectors_spherical
6984
6985 subroutine spherical_to_cartesian(vec_sph,vec_car)
6986 ! angles in rad
6987 double precision, intent(in) :: vec_sph(1:3)
6988 double precision, intent(inout) :: vec_car(1:3)
6989
6990 vec_car(1)=vec_sph(1)*dsin(vec_sph(2))*dcos(vec_sph(3))
6991 vec_car(2)=vec_sph(1)*dsin(vec_sph(2))*dsin(vec_sph(3))
6992 vec_car(3)=vec_sph(1)*dcos(vec_sph(2))
6993
6994 end subroutine spherical_to_cartesian
6995
6996 subroutine cartesian_to_spherical(vec_car,vec_sph)
6997 ! angles in rad
6998 double precision, intent(in) :: vec_car(1:3)
6999 double precision, intent(inout) :: vec_sph(1:3)
7000
7001 vec_sph(1)=dsqrt(vec_car(1)**2+vec_car(2)**2+vec_car(3)**2)
7002 vec_sph(2)=dacos(vec_car(3)/vec_sph(1))
7003 vec_sph(3)=atan2(vec_car(2),vec_car(1))
7004
7005 end subroutine cartesian_to_spherical
7006
7008 integer :: j
7009 double precision :: LOS_psi
7010 double precision :: vec_z(1:3),vec_temp1(1:3),vec_temp2(1:3)
7011
7012 ! vectors for image coordinate
7013 vec_los(1)=-cos(dpi*los_phi/180.d0)*sin(dpi*los_theta/180.d0)
7014 vec_los(2)=-sin(dpi*los_phi/180.d0)*sin(dpi*los_theta/180.d0)
7015 vec_los(3)=-cos(dpi*los_theta/180.d0)
7016 do j=1,3
7017 if (abs(vec_los(j))<=smalldouble) vec_los(j)=zero
7018 enddo
7019 vec_z(:)=zero
7020 vec_z(3)=1.d0
7021 if (los_theta==zero) then
7022 vec_xi1(1)=cos(dpi*los_phi/180.d0)
7023 vec_xi1(2)=sin(dpi*los_phi/180.d0)
7024 vec_xi1(3)=zero
7025 else
7027 endif
7029 vec_temp1=vec_xi1/sqrt(vec_xi1(1)**2+vec_xi1(2)**2+vec_xi1(3)**2)
7030 vec_temp2=vec_xi2/sqrt(vec_xi2(1)**2+vec_xi2(2)**2+vec_xi2(3)**2)
7031 los_psi=dpi*image_rotate/180.d0
7032 vec_xi1=vec_temp1*cos(los_psi)-vec_temp2*sin(los_psi)
7033 vec_xi2=vec_temp2*cos(los_psi)+vec_temp1*sin(los_psi)
7034
7035 do j=1,3
7036 if (abs(vec_xi1(j))<smalldouble) vec_xi1(j)=zero
7037 if (abs(vec_xi2(j))<smalldouble) vec_xi2(j)=zero
7038 enddo
7039
7040 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' LOS vector: [',vec_los(1),vec_los(2),vec_los(3),']'
7041 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' xI1 vector: [',vec_xi1(1),vec_xi1(2),vec_xi1(3),']'
7042 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' xI2 vector: [',vec_xi2(1),vec_xi2(2),vec_xi2(3),']'
7043
7044 end subroutine init_vectors_cartesian
7045
7046 subroutine get_cor_image_spherical(x_3D_sph,x_image)
7047 double precision, intent(in) :: x_3D_sph(1:3)
7048 double precision, intent(inout) :: x_image(1:2)
7049 double precision :: res,res_origin
7050 double precision :: x_3D(1:3)
7051
7052 call spherical_to_cartesian(x_3d_sph,x_3d)
7053 call dot_product_loc(x_3d,vec_xi1,res)
7054 x_image(1)=res
7055 call dot_product_loc(x_3d,vec_xi2,res)
7056 x_image(2)=res
7057
7058 end subroutine get_cor_image_spherical
7059
7060 subroutine get_cor_image(x_3D,x_image)
7061 double precision, intent(in) :: x_3D(1:3)
7062 double precision, intent(inout) :: x_image(1:2)
7063 double precision :: res,res_origin
7064
7065 call dot_product_loc(x_3d,vec_xi1,res)
7066 call dot_product_loc(x_origin,vec_xi1,res_origin)
7067 x_image(1)=res-res_origin
7068 call dot_product_loc(x_3d,vec_xi2,res)
7069 call dot_product_loc(x_origin,vec_xi2,res_origin)
7070 x_image(2)=res-res_origin
7071
7072 end subroutine get_cor_image
7073
7074end module mod_thermal_emission
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
Module for physical and numeric constants.
double precision, parameter const_rsun
double precision, parameter kb_cgs
Boltzmann constant in cgs.
double precision, parameter half
double precision, parameter one
double precision, parameter dpi
Pi.
double precision, parameter zero
some frequently used numbers
double precision, parameter smalldouble
double precision, parameter mp_cgs
Proton mass in cgs.
double precision, parameter const_c
universal constants as specified in cgs units
PI (partial-ionisation) ionisation-degree backend for the eos% family.
subroutine, public ionization_state_tp(t, p, rfactor, iz_h, iz_he)
Equation of state for AMRVAC, handled through a single eos_container object.
Definition mod_eos.t:30
Module with geometry-related routines (e.g., divergence, curl)
Definition mod_geometry.t:2
integer coordinate
Definition mod_geometry.t:7
integer, parameter spherical
subroutine curlvector(qvec, ixil, ixol, curlvec, idirmin, idirmin0, ndir0, fourthorder)
Calculate curl of a vector qvec within ixL Options to employ standard second order CD evaluations use...
This module contains definitions of global parameters and variables and some generic functions/subrou...
type(state), pointer block
Block pointer for using one block and its previous state.
character(len=std_len) filename_sxr
Base file name for synthetic SXR emission output.
integer spectrum_wl
wave length for spectrum
integer ixghi
Upper index of grid block arrays.
logical activate_unit_arcsec
use arcsec as length unit of images/spectra
character(len=std_len) filename_spectrum
Base file name for synthetic EUV spectrum output.
double precision global_time
The global simulation time.
logical output_absorption_fraction
output absorption fraction for thick/thin EUV synthesis when available
double precision radio_beam_fwhm
Gaussian radio beam full width at half maximum in arcsec.
integer snapshotini
Resume from the snapshot with this index.
character(len=std_len) filename_euv
Base file name for synthetic EUV emission output.
logical instrument_postprocess
Post-process dat-resolution EUV images onto the instrument pixel grid.
double precision unit_numberdensity
Physical scaling factor for number density.
character(len=std_len) filename_whitelight
Base file name for synthetic white light.
character(len=std_len) convert_type
Which format to use when converting.
double precision unit_length
Physical scaling factor for length.
double precision location_slit
location of the slit
double precision time_convert_factor
Conversion factor for time unit.
integer icomm
The MPI communicator.
character(len=std_len) whitelight_instrument
white light observation instrument
integer mype
The rank of the current MPI task.
double precision radio_frequency
Observing frequency for radio free-free synthesis in Hz.
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
double precision, dimension(:), allocatable, parameter d
logical slab
Cartesian geometry or not.
double precision radio_beam_pixel_size
Output pixel size for radio beam post-processing in arcsec; <=0 uses FWHM/3.
integer snapshotnext
IO: snapshot and collapsed views output numbers/labels.
logical dat_resolution
resolution of the images
double precision r_occultor
the white light emission below it (unit=Rsun) is not visible
integer, dimension(ndim) nstretchedblocks_baselevel
(even) number of (symmetrically) stretched blocks at AMR level 1, per dimension
integer npe
The number of MPI tasks.
logical output_tau
output optical-depth map for synthetic emission when available
double precision, dimension(^nd) qstretch_baselevel
stretch factor between cells at AMR level 1, per dimension
double precision unit_velocity
Physical scaling factor for velocity.
integer radsyn_segment_batch_factor
Maximum ray segments per pixel batch, as a factor of radsyn_pixel_batch; <=0 uses memory budget....
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
double precision unit_temperature
Physical scaling factor for temperature.
logical si_unit
Use SI units (.true.) or use cgs units (.false.)
double precision los_theta
direction of the line of sight (LOS)
character(len=std_len) dat_resolution_mode
Data-resolution image spacing: nominal or minimum actual cell size.
character(len=std_len) radiation_transfer
Synthetic emission transfer mode: thin or thick.
double precision spectrum_window_max
integer wavelength
wavelength for output
integer, dimension(ndim) stretch_type
What kind of stretching is used per dimension.
double precision, dimension(^nd) dxlevel
store unstretched cell size of current level
integer radsyn_pixel_batch
Number of image pixels processed in one ray-segment MPI batch.
logical radsyn_verbose
Print synthetic-emission ray-tracing profiling counters.
double precision instrument_resolution_factor
times for enhancing spatial resolution for EUV image/spectra
double precision radsyn_segment_memory_mb
Approximate per-rank temporary memory budget, in MiB, for automatic ray-segment batch sizing.
double precision spectrum_window_min
spectral window
integer refine_max_level
Maximal number of AMR levels.
character(len=std_len) ray_method
Synthetic emission ray traversal method.
integer direction_slit
direction of the slit (for dat resolution only)
double precision, dimension(1:3) x_origin
where the is the origin (X=0,Y=0) of image
character(len=std_len) emission_model
Synthetic emission physical model selector.
integer, dimension(:,:), allocatable node
integer radsyn_segment_comm_factor
Maximum ray segments per segmented MPI all-to-all round, as a factor of radsyn_pixel_batch.
integer, parameter ixglo
Lower index of grid block arrays (always 1)
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
double precision, dimension(1:3) vec_los
subroutine get_goes_flux_grid(ixil, ixol, w, x, dv, xboxl, xbl, fl, eflux_grid)
subroutine get_minimum_datresol_spacing(dxi)
subroutine integrate_spectra_cartesian(igrid, wl, dwlg, xs, dxsg, spectra, numwl, numxs, fl)
subroutine sph_cart_to_coord(pos, sph)
subroutine get_spectrum_datresol(qunit, datatype, fl)
double precision, dimension(1:101) f_304
double precision, dimension(1:101) f_193
double precision, dimension(1:60) f_264
subroutine normalize_euv_doppler(ni1, ni2, euv, dpl, unitv)
subroutine get_sph_intersection_image_bounds(ximin1, ximax1, ximin2, ximax2)
double precision, dimension(1:60) f_263
integer function sph_locate_index(value, faces, imin, imax)
subroutine get_euv_image(qunit, fl)
double precision, dimension(1:60) t_eis1
subroutine postprocess_radio_beam_image(nsrc1, nsrc2, xsrc1, xsrc2, dxsrc1, dxsrc2, bright, nout1, nout2, xout1, xout2, dxout1, dxout2, wout, numwout, tau, brightthin)
subroutine solve_euv_saha_charge_state(nh, te, rhe, ne_guess, x_hii, x_heii, x_heiii)
subroutine get_sxr(ixil, ixol, w, x, fl, flux, el, eu)
integer function radsyn_euv_num_outputs(has_doppler, has_thick)
subroutine collect_euv_cart_dda_segments(ixil, ixol, source, opacity, sourcev, pixel_id, ray_origin, xface1, xface2, xface3, t_enter, t_exit, segments, nseg, capacity)
subroutine get_unit_vector_spherical(x_sph, unitv_r, unitv_theta, unitv_phi)
subroutine collect_euv_sph_intersection_segments(ixil, ixol, source, opacity, pixel_id, ray_origin, ximg1, ximg2, rface, thetaface, phiface, rface2, theta_cos, phi_sin, phi_cos, segments, nseg, capacity)
double precision, dimension(1:101) f_131
recursive subroutine quicksort_segment_indices(segments, idx, ilo, ihi)
subroutine get_line_info(wl, ion, mass, logte, line_center, spatial_px, spectral_px, sigma_psf, width_slit)
double precision, dimension(1:60) f_255
subroutine sph_block_pixel_range(rface, thetaface, phiface, ixol, nxi1, nxi2, xi1, xi2, dxi, ixpmin1, ixpmax1, ixpmin2, ixpmax2, has_pixels)
subroutine cart_dda_advance_axis(ray_origin_axis, ray_dir_axis, faces, imin, imax, idx, step, tmax, done)
subroutine get_pseudo_current(igrid, ixil, ixol, w, source)
logical function segment_is_valid(segments, is, nvars)
double precision function transfer_attenuation(tau)
double precision, dimension(1:101) t_aia
double precision function exp_clamped(argument)
subroutine write_image_vtucc(qunit, xc, wc, dxc, npiece, nc1, nc2, nwc, datatype)
logical function sph_segment_visible(pos, ximg1, ximg2)
subroutine get_cor_image(x_3d, x_image)
subroutine get_thomson_parameters(rl, a, b, c, d)
subroutine integrate_euv_datresol(igrid, nxif1, nxif2, xif1, xif2, dxif1, dxif2, fl, euv, dpl)
subroutine cart_dda_block_pixel_range(box_min, box_max, nxif1, nxif2, xif1, xif2, ixpmin1, ixpmax1, ixpmin2, ixpmax2, has_pixels)
subroutine sph_add_t_fixed(tvals, nt, t)
double precision, dimension(1:60) t_eis2
subroutine sph_add_theta_intersections(ray_origin, ray_dir, thetaface, tvals, nt, capacity)
subroutine integrate_euv_cart_dda_thick_datresol(nxif1, nxif2, xif1, xif2, fl, euv, dpl, tau, euvthin)
double precision, dimension(1:101) f_171
double precision, dimension(1:101) f_94
subroutine integrate_spectra_datresol(igrid, wl, dwl, spectra, numwl, numxs, dir_loc, fl)
subroutine acc_euv_cart_dda(ixil, ixol, source, sourcev, ray_origin, xface1, xface2, xface3, t_enter, t_exit, euvp, dplp)
subroutine sph_add_phi_intersection(ray_origin, ray_dir, phiface, tvals, nt, capacity)
double precision, dimension(1:3) vec_xi1
subroutine append_cart_dda_segment(segments, nseg, capacity, pixel_id, tseg, jds, kds, jvds)
subroutine radsyn_get_segment_batch_limits(pixel_batch_target, segment_batch_target, segment_comm_target)
subroutine get_spectrum(qunit, datatype, fl)
subroutine ray_box_intersection_cart(ray_origin, ray_dir, box_min, box_max, hit, t_enter, t_exit)
subroutine cartesian_to_spherical(vec_car, vec_sph)
subroutine get_cor_image_spherical(x_3d_sph, x_image)
subroutine dot_product_loc(vec1, vec2, res)
subroutine integrate_emission_spherical(igrid, numxi1, numxi2, xi1, xi2, dxi, fl, datatype, em)
subroutine get_image(qunit, datatype, fl)
subroutine integrate_emission_cartesian(igrid, numxi1, numxi2, xi1, xi2, dxi, fl, datatype, em)
logical function radsyn_euv_has_doppler_output()
integer function sph_locate_index_desc(value, faces, imin, imax)
subroutine insertion_sort_segment_indices(segments, idx, ilo, ihi)
subroutine get_nominal_datresol_spacing(dxi)
subroutine write_image_vticc(qunit, xo1, xo2, dxo1, dxo2, wo, nxo1, nxo2, nwo, nc1, nc2)
subroutine get_sxr_image(qunit, fl)
subroutine check_synthetic_emission_options(datatype)
subroutine fill_euv_absorption_fraction(ni1, ni2, euv, euvthin, smallflux, absorption, cap_to_one)
subroutine sph_sort_unique_t(tvals, nt)
double precision, dimension(1:60) f_192
subroutine sort_segment_indices_near_to_far(segments, idx, nidx)
integer function cart_dda_locate_index(pos, faces, imin, imax)
subroutine pack_euv_image_outputs(ni1, ni2, euv, wi, smallflux, has_doppler, has_thick, dpl, tau, euvthin, cap_absorption)
integer function segment_pixel_owner(pixel_id)
subroutine get_whitelight_thomson(rl, rin, ne, a, b, c, d, fluxtb, fluxpb)
subroutine get_image_datresol(qunit, datatype, fl)
subroutine collect_euv_sph_dda_interval(ixil, ixol, source, opacity, pixel_id, ray_origin, ximg1, ximg2, rface2, theta_cos, phiface, phi_sin, phi_cos, t_enter, t_exit, segments, nseg, capacity, ok)
subroutine get_goes_sxr_flux(xboxl, fl, eflux)
subroutine get_native_datresol_spacing(dxi)
double precision function interpolate_response_value(temperature, t_table, f_table, n_table, log_temperature, log_response)
subroutine integrate_whitelight_spherical(igrid, numxi1, numxi2, numwi, xi1, xi2, dxi, fl, datatype, wlb)
double precision, dimension(1:3) vec_xi2
double precision, dimension(1:41) f_1354
subroutine cross_product_loc(vec_in1, vec_in2, vec_out)
character(len=std_len) ray_method_active
subroutine integrate_sxr_datresol(igrid, nxif1, nxif2, xif1, xif2, dxif1, dxif2, fl, sxr)
subroutine apply_temperature_response(ixil, ixol, te, flux, t_table, f_table, n_table, log_temperature, log_response)
double precision, dimension(1:101) f_335
subroutine sph_try_theta_exit_candidate(t, theta_face_cos, ray_origin, tnow, texit, epsray, tnext, found)
subroutine get_radio_ff_source_opacity(ixil, ixol, w, x, fl, source, kappa)
subroutine sph_next_cell_exit(ray_origin, rface2, theta_cos, phiface, phi_sin, phi_cos, ixol, ix1, ix2, ix3, tnow, texit, epsray, tnext, found)
subroutine integrate_euv_thick_datresol(nxif1, nxif2, fl, euv, dpl, tau, euvthin)
subroutine output_data(qunit, xo1, xo2, dxo1, dxo2, wo, nxo1, nxo2, nwo, datatype)
subroutine integrate_euv_sph_intersection_thick(numxi1, numxi2, xi1, xi2, dxi, fl, euv, tau, euvthin)
subroutine sph_try_phi_exit_candidate(t, phi_face_sin, phi_face_cos, ray_origin, tnow, texit, epsray, tnext, found)
double precision, dimension(1:41) t_iris
subroutine sph_locate_cell_fast(pos, rface2, theta_cos, phiface, ixol, ix1, ix2, ix3, inside)
subroutine get_euv_spectrum(qunit, fl)
double precision, dimension(1:101) f_211
subroutine build_sph_intersection_faces(ixil, ixol, x, dx, rface, thetaface, phiface)
subroutine collect_euv_sph_dda_segments(ixil, ixol, source, opacity, pixel_id, ray_origin, ximg1, ximg2, rface, thetaface, phiface, rface2, theta_cos, phi_sin, phi_cos, segments, nseg, capacity, fallback)
subroutine cart_dda_init_axis(ray_origin_axis, ray_dir_axis, faces, imin, imax, idx, step, tmax)
subroutine get_euv_hhe_opacity(wl, ixil, ixol, w, x, fl, kappa)
subroutine integrate_euv_sph_intersection_thin(numxi1, numxi2, xi1, xi2, dxi, fl, em)
subroutine integrate_euv_cart_dda_datresol(nxif1, nxif2, xif1, xif2, fl, euv, dpl)
subroutine get_euv_saha_fractions(te, ne, x_hii, x_heii, x_heiii)
subroutine get_whitelight_image(qunit, fl)
subroutine get_euv(wl, ixil, ixol, w, x, fl, flux)
subroutine sph_add_sphere_intersections(ray_origin, ray_dir, rface, tvals, nt, capacity)
subroutine build_cart_dda_faces(ixil, ixol, x, dx, xface1, xface2, xface3)
subroutine integrate_transfer_step_first_order(emissivity, opacity, path_length, intensity, tau)
double precision function pow10_clamped(exponent)
subroutine acc_euv_sph_intersection(ixil, ixol, source, ray_origin, ximg1, ximg2, rface, thetaface, phiface, euvp)
subroutine sph_locate_cell(pos, rface, thetaface, phiface, ixol, ix1, ix2, ix3, inside)
subroutine sph_try_exit_candidate(t, tnow, texit, epsray, tnext, found)
subroutine spherical_to_cartesian(vec_sph, vec_car)
subroutine sph_add_t(tvals, nt, capacity, t)
subroutine postprocess_euv_instrument_image(nsrc1, nsrc2, xsrc1, xsrc2, dxsrc1, dxsrc2, euv, dpl, nout1, nout2, xout1, xout2, dxout1, dxout2, wout, numwout, tau, euvthin)