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, x, val1, val2)
384 integer, intent(in) :: ixI^L, ixO^L
385 double precision, intent(in) :: w(ixI^S, nw)
386 double precision, intent(in) :: x(ixI^S, 1:ndim)
387 double precision, intent(out):: val1(ixI^S), val2(ixI^S)
388 end subroutine get_2var_subr_te
389 end interface
390
392
393 procedure(get_subr1), pointer, nopass :: get_rho => null()
394 procedure(get_subr1), pointer, nopass :: get_pthermal => null()
395 procedure(get_subr1), pointer, nopass :: get_var_rfactor => null()
396 procedure(get_2var_subr_te), pointer, nopass :: get_ne_nh => null()
397
398 end type te_fluid
399
401 integer :: igrid=0
402 integer :: level=0
403 integer :: rft=1
404 integer :: los_min=0
405 integer :: los_max=0
406 double precision, allocatable :: source(:^d&)
407 double precision, allocatable :: opacity(:^d&)
408 double precision, allocatable :: sourcev(:^d&)
409 double precision, allocatable :: xface1(:),xface2(:),xface3(:)
410 double precision, allocatable :: rface(:),thetaface(:),phiface(:)
411 double precision, allocatable :: rface2(:),theta_cos(:),phi_sin(:),phi_cos(:)
412 double precision :: box_min(1:3)=0.d0
413 double precision :: box_max(1:3)=0.d0
414 integer :: ixpmin1=1
415 integer :: ixpmax1=0
416 integer :: ixpmin2=1
417 integer :: ixpmax2=0
418 logical :: has_pixels=.false.
419 end type radsyn_euv_cache
420
421 character(len=std_len) :: ray_method_active='legacy'
422 logical :: sph_use_dda=.false.
423
424
425 contains
426
429
430 character(len=*), intent(in) :: datatype
431
432 if (trim(radiation_transfer) /= 'thin' .and. trim(radiation_transfer) /= 'thick') then
433 call mpistop("bad radiation_transfer")
434 endif
435
436 if (trim(dat_resolution_mode) /= 'nominal' .and. &
437 trim(dat_resolution_mode) /= 'minimum') then
438 call mpistop("dat_resolution_mode must be nominal or minimum")
439 endif
440
441 sph_use_dda=.false.
442 select case(trim(ray_method))
443 case('auto','')
444 if (datatype=='image_euv' .and. coordinate==spherical) then
445 ray_method_active='spherical'
446 sph_use_dda=.true.
447 else if (datatype=='image_euv' .and. dat_resolution .and. slab) then
448 ray_method_active='cart'
449 else
450 ray_method_active='legacy'
451 endif
452 case('legacy')
453 ray_method_active='legacy'
454 case('cart','cart_dda')
455 ray_method_active='cart'
456 case('spherical','sph_intersection')
457 ray_method_active='spherical'
458 case('sph_dda','spherical_dda')
459 ray_method_active='spherical'
460 sph_use_dda=.true.
461 case default
462 call mpistop("bad ray_method")
463 end select
464
465 if (trim(emission_model) /= 'auto' .and. trim(emission_model) /= 'euv_aia' .and. &
466 trim(emission_model) /= 'white_light' .and. trim(emission_model) /= 'radio_ff' .and. &
467 trim(emission_model) /= 'pseudo_current') then
468 call mpistop("bad emission_model")
469 endif
470
471 if ((output_tau .or. output_absorption_fraction) .and. trim(radiation_transfer) /= 'thick') then
472 call mpistop("tau and absorption-fraction output need thick transfer")
473 endif
474
475 if (radsyn_pixel_batch<1) then
476 call mpistop("radsyn_pixel_batch must be positive")
477 endif
479 call mpistop("radsyn_segment_batch_factor must be non-negative")
480 endif
481 if (radsyn_segment_memory_mb<=zero) then
482 call mpistop("radsyn_segment_memory_mb must be positive")
483 endif
485 call mpistop("radsyn_segment_comm_factor must be positive")
486 endif
487
488 if (instrument_postprocess) then
489 if (datatype /= 'image_euv' .or. .not. dat_resolution) then
490 call mpistop("instrument_postprocess currently needs dat-resolution EUV images")
491 endif
492 if (trim(ray_method_active) == 'spherical') then
493 call mpistop("instrument_postprocess is not yet supported for spherical rays")
494 endif
495 if (trim(emission_model) == 'pseudo_current') then
496 call mpistop("instrument_postprocess currently supports only EUV AIA or radio_ff images")
497 endif
498 if (trim(emission_model) == 'radio_ff' .and. radio_beam_fwhm<=zero) then
499 call mpistop("radio_ff instrument_postprocess needs radio_beam_fwhm > 0 arcsec")
500 endif
501 endif
502
503 select case(trim(emission_model))
504 case('auto')
505 continue
506 case('euv_aia')
507 if (datatype /= 'image_euv' .and. datatype /= 'spectrum_euv') then
508 call mpistop("emission_model=euv_aia is only valid for EUV synthesis")
509 endif
510 case('white_light')
511 if (datatype /= 'image_whitelight') then
512 call mpistop("emission_model=white_light is only valid for white-light synthesis")
513 endif
514 case('radio_ff')
515 if (datatype /= 'image_euv') then
516 call mpistop("emission_model=radio_ff currently reuses EUV-image convert types")
517 endif
518 if (radio_frequency<=zero) then
519 call mpistop("emission_model=radio_ff needs radio_frequency > 0")
520 endif
521 case('pseudo_current')
522 if (datatype /= 'image_euv') then
523 call mpistop("emission_model=pseudo_current is only valid for EUV-image convert types")
524 endif
525 if (trim(radiation_transfer) /= 'thin') then
526 call mpistop("emission_model=pseudo_current currently supports only thin transfer")
527 endif
528 end select
529
530 if (trim(ray_method_active) == 'cart') then
531 if (datatype /= 'image_euv' .or. .not. slab) then
532 call mpistop("ray_method=cart needs Cartesian EUV slab images")
533 endif
534 endif
535 if (trim(ray_method_active) == 'spherical') then
536 {^ifoned
537 call mpistop("ray_method=spherical currently needs 3D spherical grids")
538 }
539 {^iftwod
540 call mpistop("ray_method=spherical currently needs 3D spherical grids")
541 }
542 {^ifthreed
543 if (datatype /= 'image_euv' .or. coordinate /= spherical .or. &
544 (trim(radiation_transfer) /= 'thin' .and. trim(radiation_transfer) /= 'thick')) then
545 call mpistop("bad ray_method=spherical mode")
546 endif
547 if (trim(emission_model) /= 'auto' .and. trim(emission_model) /= 'euv_aia') then
548 call mpistop("ray_method=spherical currently supports only EUV AIA emission")
549 endif
550 if (xprobmin2<=1.d-10 .or. xprobmax2>=dpi-1.d-10) then
551 call mpistop("ray_method=spherical does not support polar-axis crossing domains")
552 endif
553 if (xprobmax3<=xprobmin3 .or. xprobmax3-xprobmin3>=2.d0*dpi-1.d-10) then
554 call mpistop("ray_method=spherical does not support phi-wrapping domains")
555 endif
556 }
557 endif
558 if (trim(radiation_transfer) == 'thick') then
559 if (datatype /= 'image_euv') then
560 call mpistop("thick transfer is only defined for EUV images")
561 endif
562 if (trim(ray_method_active) == 'spherical') then
563 continue
564 else if (trim(ray_method_active) == 'cart') then
565 if (.not. slab) call mpistop("cartesian thick EUV currently needs slab output")
566 else if (.not. slab .or. .not. dat_resolution) then
567 call mpistop("thick EUV currently needs Cartesian dat_resolution output")
568 endif
569 if (trim(ray_method_active) /= 'cart' .and. &
570 trim(ray_method_active) /= 'spherical' .and. &
571 .not. ((los_phi==0 .and. los_theta==90) .or. &
572 (los_phi==90 .and. los_theta==90) .or. los_theta==0)) then
573 call mpistop("thick EUV currently needs x/y/z-aligned LOS")
574 endif
575 endif
577
578 subroutine integrate_transfer_step_first_order(emissivity,opacity,path_length,intensity,tau)
579 ! First-order formal-solution step used by the planned ordered LOS transfer.
580 double precision, intent(in) :: emissivity,opacity,path_length
581 double precision, intent(inout) :: intensity,tau
582
583 double precision :: dtau
584
585 if (path_length<=zero) return
586 intensity=intensity+transfer_attenuation(tau)*max(zero,emissivity)*path_length
587 dtau=max(zero,opacity)*path_length
588 tau=tau+dtau
590
592 radsyn_euv_has_doppler_output=trim(emission_model)/='pseudo_current' .and. &
593 trim(emission_model)/='radio_ff' .and. &
594 .not. (coordinate==spherical .and. trim(ray_method_active)=='spherical')
596
597 integer function radsyn_euv_num_outputs(has_doppler,has_thick) result(num_outputs)
598 logical, intent(in) :: has_doppler,has_thick
599
600 num_outputs=1
601 if (has_doppler) num_outputs=num_outputs+1
602 if (has_thick .and. output_tau) num_outputs=num_outputs+1
603 if (has_thick .and. output_absorption_fraction) num_outputs=num_outputs+1
604 end function radsyn_euv_num_outputs
605
606 subroutine normalize_euv_doppler(nI1,nI2,EUV,Dpl,unitv)
607 integer, intent(in) :: nI1,nI2
608 double precision, intent(in) :: EUV(nI1,nI2),unitv
609 double precision, intent(inout) :: Dpl(nI1,nI2)
610
611 integer :: ix1,ix2
612
613 do ix1=1,ni1
614 do ix2=1,ni2
615 if (euv(ix1,ix2)/=zero) then
616 dpl(ix1,ix2)=(dpl(ix1,ix2)/euv(ix1,ix2))*unitv
617 else
618 dpl(ix1,ix2)=zero
619 endif
620 if (abs(dpl(ix1,ix2))<smalldouble) dpl(ix1,ix2)=zero
621 enddo
622 enddo
623 end subroutine normalize_euv_doppler
624
625 subroutine fill_euv_absorption_fraction(nI1,nI2,EUV,EUVthin,smallflux,Absorption,cap_to_one)
626 integer, intent(in) :: nI1,nI2
627 double precision, intent(in) :: EUV(nI1,nI2),EUVthin(nI1,nI2),smallflux
628 double precision, intent(out) :: Absorption(nI1,nI2)
629 logical, intent(in), optional :: cap_to_one
630
631 integer :: ix1,ix2
632 logical :: cap_absorption
633
634 absorption=zero
635 cap_absorption=.false.
636 if (present(cap_to_one)) cap_absorption=cap_to_one
637 do ix1=1,ni1
638 do ix2=1,ni2
639 if (euvthin(ix1,ix2)>smallflux) then
640 absorption(ix1,ix2)=max(zero,(euvthin(ix1,ix2)-euv(ix1,ix2))/euvthin(ix1,ix2))
641 if (cap_absorption) absorption(ix1,ix2)=min(one,absorption(ix1,ix2))
642 endif
643 enddo
644 enddo
645 end subroutine fill_euv_absorption_fraction
646
647 subroutine pack_euv_image_outputs(nI1,nI2,EUV,wI,smallflux,has_doppler,has_thick,Dpl,Tau,EUVthin,&
648 cap_absorption)
649 integer, intent(in) :: nI1,nI2
650 double precision, intent(in) :: EUV(nI1,nI2),smallflux
651 double precision, intent(inout) :: wI(:,:,:)
652 logical, intent(in) :: has_doppler,has_thick
653 double precision, intent(in), optional :: Dpl(nI1,nI2),Tau(nI1,nI2),EUVthin(nI1,nI2)
654 logical, intent(in), optional :: cap_absorption
655
656 integer :: iw
657 double precision, allocatable :: Absorption(:,:)
658
659 wi=zero
660 wi(:,:,1)=euv(:,:)
661 iw=1
662 if (has_doppler) then
663 if (.not. present(dpl)) call mpistop("Doppler output requested without Doppler image")
664 iw=iw+1
665 wi(:,:,iw)=dpl(:,:)
666 endif
667 if (has_thick .and. output_tau) then
668 if (.not. present(tau)) call mpistop("tau output requested without tau image")
669 iw=iw+1
670 wi(:,:,iw)=tau(:,:)
671 endif
672 if (has_thick .and. output_absorption_fraction) then
673 if (.not. present(euvthin)) call mpistop("absorption output requested without thin image")
674 allocate(absorption(ni1,ni2))
675 call fill_euv_absorption_fraction(ni1,ni2,euv,euvthin,smallflux,absorption,cap_absorption)
676 iw=iw+1
677 wi(:,:,iw)=absorption(:,:)
678 deallocate(absorption)
679 endif
680 end subroutine pack_euv_image_outputs
681
682 subroutine radsyn_get_segment_batch_limits(pixel_batch_target,segment_batch_target,segment_comm_target)
683 integer, intent(out) :: pixel_batch_target,segment_batch_target,segment_comm_target
684
685 pixel_batch_target=max(1,radsyn_pixel_batch)
686 if (radsyn_segment_batch_factor>0) then
687 segment_batch_target=max(128,radsyn_segment_batch_factor*pixel_batch_target)
688 else
689 segment_batch_target=max(128,int(min(dble(huge(segment_batch_target)),&
690 max(128.d0,radsyn_segment_memory_mb*1048576.d0/256.d0))))
691 endif
692 segment_comm_target=max(128,radsyn_segment_comm_factor*pixel_batch_target)
694
695 double precision function transfer_attenuation(tau)
696 double precision, intent(in) :: tau
697
698 if (tau<=zero) then
700 else
702 endif
703 end function transfer_attenuation
704
705 double precision function exp_clamped(argument)
706 double precision, intent(in) :: argument
707
708 if (argument<-700.d0) then
709 exp_clamped=zero
710 else if (argument>700.d0) then
711 exp_clamped=huge(one)
712 else
713 exp_clamped=exp(argument)
714 endif
715 end function exp_clamped
716
717 double precision function pow10_clamped(exponent)
718 double precision, intent(in) :: exponent
719
720 if (exponent>300.d0) then
721 pow10_clamped=1.d300
722 else if (exponent<-300.d0) then
723 pow10_clamped=zero
724 else
725 pow10_clamped=10.d0**exponent
726 endif
727 end function pow10_clamped
728
729 double precision function interpolate_response_value(temperature,t_table,f_table,n_table,log_temperature,log_response)
730 double precision, intent(in) :: temperature
731 integer, intent(in) :: n_table
732 double precision, intent(in) :: t_table(n_table),f_table(n_table)
733 logical, intent(in) :: log_temperature,log_response
734
735 integer :: ilo,ihi,imid
736 double precision :: temp_lookup,response_lookup,flo,fhi
737
739 if (temperature<=zero) return
740 if (log_temperature) then
741 temp_lookup=log10(temperature)
742 else
743 temp_lookup=temperature
744 endif
745 if (temp_lookup<t_table(1) .or. temp_lookup>t_table(n_table)) return
746 if (temp_lookup==t_table(n_table)) then
747 if (log_response) then
748 response_lookup=log10(max(f_table(n_table),1.d-99))
749 else
750 response_lookup=f_table(n_table)
751 endif
752 else
753 ilo=1
754 ihi=n_table
755 do while (ihi-ilo>1)
756 imid=(ilo+ihi)/2
757 if (temp_lookup>=t_table(imid)) then
758 ilo=imid
759 else
760 ihi=imid
761 endif
762 enddo
763 if (log_response) then
764 flo=log10(max(f_table(ilo),1.d-99))
765 fhi=log10(max(f_table(ilo+1),1.d-99))
766 else
767 flo=f_table(ilo)
768 fhi=f_table(ilo+1)
769 endif
770 response_lookup=flo*(temp_lookup-t_table(ilo+1))/(t_table(ilo)-t_table(ilo+1))+&
771 fhi*(temp_lookup-t_table(ilo))/(t_table(ilo+1)-t_table(ilo))
772 endif
773
774 if (log_response) then
775 if (response_lookup>-99.d0) interpolate_response_value=10.d0**response_lookup
776 else
777 interpolate_response_value=response_lookup
778 endif
780 end function interpolate_response_value
781
782 subroutine apply_temperature_response(ixI^L,ixO^L,Te,flux,t_table,f_table,n_table,log_temperature,log_response)
783 integer, intent(in) :: ixI^L, ixO^L, n_table
784 double precision, intent(in) :: Te(ixI^S),t_table(n_table),f_table(n_table)
785 double precision, intent(inout) :: flux(ixI^S)
786 logical, intent(in) :: log_temperature,log_response
787
788 integer :: ix^D
789 double precision :: GT
790
791 {do ix^db=ixomin^db,ixomax^db\}
792 gt=interpolate_response_value(te(ix^d),t_table,f_table,n_table,log_temperature,log_response)
793 flux(ix^d)=flux(ix^d)*gt
794 if (flux(ix^d)<zero) flux(ix^d)=zero
795 {enddo\}
796 end subroutine apply_temperature_response
797
798 subroutine get_euv_saha_fractions(Te,Ne,x_HII,x_HeII,x_HeIII)
799 ! Ion fractions at fixed temperature and electron density. Ne is an
800 ! input here: this helper does not impose charge conservation or alter
801 ! the thermodynamic state of the simulation.
802 use mod_constants, only: kb_cgs
803
804 double precision, intent(in) :: Te,Ne
805 double precision, intent(out) :: x_HII,x_HeII,x_HeIII
806
807 double precision :: Pe,log_H21,log_He21,log_He32,log_He321
808 double precision :: logScaleHe,w_H21,term0,term1,term2,denHe
809 double precision, parameter :: Xe_H21=13.6d0
810 double precision, parameter :: Xe_He21=24.587d0
811 double precision, parameter :: Xe_He32=54.416d0
812
813 x_hii=zero
814 x_heii=zero
815 x_heiii=zero
816 if (te<=zero .or. ne<=zero) return
817
818 pe=ne*kb_cgs*te
819 if (pe<=zero) return
820
821 log_h21=2.5d0*log10(te)-5040.d0*xe_h21/te-log10(pe)-0.48d0
822 log_he21=log10(4.d0)+2.5d0*log10(te)-5040.d0*xe_he21/te-log10(pe)-0.48d0
823 log_he32=2.5d0*log10(te)-5040.d0*xe_he32/te-log10(pe)-0.48d0
824
825 w_h21=pow10_clamped(log_h21)
826 x_hii=w_h21/(1.d0+w_h21)
827
828 ! Normalize the three helium stages in logarithmic form to avoid
829 ! overflow in the product of the two Saha ratios.
830 log_he321=log_he21+log_he32
831 logscalehe=max(zero,log_he21,log_he321)
832 term0=pow10_clamped(-logscalehe)
833 term1=pow10_clamped(log_he21-logscalehe)
834 term2=pow10_clamped(log_he321-logscalehe)
835 denhe=term0+term1+term2
836 if (denhe>zero) then
837 x_heii=term1/denhe
838 x_heiii=term2/denhe
839 endif
840 end subroutine get_euv_saha_fractions
841
842 subroutine solve_euv_saha_charge_state(nH,Te,rHe,Ne_guess,x_HII,x_HeII,x_HeIII)
843 ! Radiation-only Saha closure at fixed total hydrogen density and
844 ! temperature. It is used for an FI simulation, whose fully-ionized
845 ! electron density cannot consistently determine cool neutral fractions.
846 ! rHe belongs to the synthetic absorber and is not fed back into the
847 ! simulation equation of state, pressure, or temperature.
848 double precision, intent(in) :: nH,Te,rHe,Ne_guess
849 double precision, intent(out) :: x_HII,x_HeII,x_HeIII
850
851 integer, parameter :: max_iter=32
852 integer :: iter
853 double precision :: Ne,Ne_lo,Ne_hi,Ne_new,residual,derivative
854 double precision :: e_He,de_HII_dNe,de_He_dNe
855
856 x_hii=zero
857 x_heii=zero
858 x_heiii=zero
859 if (nh<=zero .or. te<=zero) return
860
861 ne_lo=max(1.d-30*nh,1.d-100)
862 ne_hi=(1.d0+2.d0*rhe)*nh
863 ne=min(max(ne_guess,ne_lo),ne_hi)
864
865 do iter=1,max_iter
866 call get_euv_saha_fractions(te,ne,x_hii,x_heii,x_heiii)
867 e_he=x_heii+2.d0*x_heiii
868 residual=ne/nh-x_hii-rhe*e_he
869 if (abs(residual)<1.d-10) exit
870
871 if (residual>zero) then
872 ne_hi=ne
873 else
874 ne_lo=ne
875 endif
876
877 ! Analytic derivative of the charge-neutrality residual. The
878 ! Newton step is kept inside a bisection bracket for robustness.
879 de_hii_dne=-x_hii*(1.d0-x_hii)/ne
880 de_he_dne=(x_heii*(e_he-1.d0) &
881 +2.d0*x_heiii*(e_he-2.d0))/ne
882 derivative=1.d0/nh-de_hii_dne-rhe*de_he_dne
883 ne_new=ne-residual/derivative
884 if (.not.(ne_new>ne_lo .and. ne_new<ne_hi)) then
885 ne_new=0.5d0*(ne_lo+ne_hi)
886 endif
887 ne=ne_new
888 enddo
889
890 ! Ensure the returned fractions correspond to the final iterate.
891 call get_euv_saha_fractions(te,ne,x_hii,x_heii,x_heiii)
892 end subroutine solve_euv_saha_charge_state
893
894 subroutine get_euv_hhe_opacity(wl,ixI^L,ixO^L,w,x,fl,kappa)
895 ! H I + He I + He II photoionization opacity in cm^-1.
896 use mod_eos, only: eos
898
899 integer, intent(in) :: wl
900 integer, intent(in) :: ixI^L, ixO^L
901 double precision, intent(in) :: x(ixI^S,1:ndim)
902 double precision, intent(in) :: w(ixI^S,1:nw)
903 type(te_fluid), intent(in) :: fl
904 double precision, intent(out) :: kappa(ixI^S)
905
906 integer :: ix^D
907 double precision :: pth(ixI^S),rho(ixI^S),Rfactor(ixI^S),Te(ixI^S)
908 double precision :: Ne(ixI^S),nH(ixI^S)
909 double precision :: wave_ratio,s_H1,s_He1,s_He2
910 double precision :: x_HII,x_HeII,x_HeIII,iz_H,iz_He,Rdummy
911 double precision :: N_H1,N_He1,N_He2
912 double precision, parameter :: rHe_opacity=0.1d0
913 double precision, parameter :: sigma_H1=5.16d-20, sigma_he1=9.25d-19, sigma_he2=7.17d-19
914
915 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
916 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
917 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,rfactor)
918 te(ixo^s)=zero
919 {do ix^db=ixomin^db,ixomax^db\}
920 if (rho(ix^d)>zero .and. rfactor(ix^d)>zero) then
921 te(ix^d)=pth(ix^d)/(rho(ix^d)*rfactor(ix^d))*unit_temperature
922 endif
923 {enddo\}
924
925 ! nH always follows the mass density and composition of the simulated
926 ! gas. rHe_opacity is deliberately applied only when constructing the
927 ! synthetic absorber below; it never changes this EOS conversion.
928 call eos%get_ne_nH(ixi^l, ixo^l, w, x, ne, nh)
929 if (si_unit) then
930 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6
931 nh(ixo^s)=nh(ixo^s)*unit_numberdensity/1.d6
932 else
933 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
934 nh(ixo^s)=nh(ixo^s)*unit_numberdensity
935 endif
936
937 wave_ratio=dble(wl)/171.d0
938 s_h1=zero
939 s_he1=zero
940 s_he2=zero
941 if (wl<=912) s_h1=wave_ratio**3*sigma_h1
942 if (wl<=504) s_he1=wave_ratio**2*sigma_he1
943 if (wl<=228) s_he2=wave_ratio**2.75d0*sigma_he2
944 kappa(ixo^s)=zero
945
946 {do ix^db=ixomin^db,ixomax^db\}
947 if (te(ix^d)>zero .and. nh(ix^d)>zero) then
948 select case (trim(eos%eos_type))
949 case ('PI')
950 ! Reuse the ionisation state of the PI backend. In its helium
951 ! convention iz_He is the fraction ionised at least once and
952 ! iz_He**2 the fraction ionised twice.
953 call ionization_state_tp(te(ix^d)/unit_temperature,pth(ix^d), &
954 rdummy,iz_h,iz_he)
955 x_hii=iz_h
956 x_heii=iz_he*(1.d0-iz_he)
957 x_heiii=iz_he*iz_he
958 case ('LTE')
959 ! LTE stores the self-consistent total electron density rather
960 ! than separate H/He populations. Reconstruct the helium stages
961 ! at that EOS electron density and temperature, then retain the
962 ! simulated ne/nH exactly when obtaining the hydrogen fraction.
963 if (ne(ix^d)>zero) then
964 call get_euv_saha_fractions(te(ix^d),ne(ix^d), &
965 x_hii,x_heii,x_heiii)
966 if (trim(eos%method)=='analytic') then
967 ! The analytic LTE option is explicitly H-only below its FI
968 ! bypass, so its stored ne/nH is the hydrogen ion fraction.
969 x_hii=min(one,max(zero,ne(ix^d)/nh(ix^d)))
970 else
971 x_hii=min(one,max(zero,ne(ix^d)/nh(ix^d) &
972 -eos%He_abundance*(x_heii+2.d0*x_heiii)))
973 endif
974 else
975 call solve_euv_saha_charge_state(nh(ix^d),te(ix^d), &
976 rhe_opacity,ne(ix^d),x_hii,x_heii,x_heiii)
977 endif
978 case default
979 ! FI supplies a fully-ionized Ne even when its rho,T state is
980 ! cool. Discard that Ne constraint and solve charge neutrality
981 ! at fixed simulated nH and T for the radiation post-processing.
982 call solve_euv_saha_charge_state(nh(ix^d),te(ix^d), &
983 rhe_opacity,ne(ix^d),x_hii,x_heii,x_heiii)
984 end select
985
986 n_h1=nh(ix^d)*(1.d0-x_hii)
987 n_he1=rhe_opacity*nh(ix^d)*(1.d0-x_heii-x_heiii)
988 n_he2=rhe_opacity*nh(ix^d)*x_heii
989 kappa(ix^d)=max(zero,n_h1*s_h1+n_he1*s_he1+n_he2*s_he2)
990 endif
991 {enddo\}
992 end subroutine get_euv_hhe_opacity
993
994 subroutine get_pseudo_current(igrid,ixI^L,ixO^L,w,source)
995 integer, intent(in) :: igrid
996 integer, intent(in) :: ixI^L, ixO^L
997 double precision, intent(in) :: w(ixI^S,1:nw)
998 double precision, intent(out) :: source(ixI^S)
999
1000 integer :: ix^D,idir,idirmin,idirmin0
1001 double precision :: current(ixI^S,7-2*ndir:3)
1002
1003 if (.not. allocated(iw_mag)) then
1004 call mpistop("emission_model=pseudo_current needs magnetic-field variables")
1005 endif
1006
1007 idirmin0=7-2*ndir
1008 current=zero
1009 call curlvector(w(ixi^s,iw_mag(1:ndir)),ixi^l,ixo^l,current,idirmin,idirmin0,ndir)
1010 if (b0field) then
1011 current(ixo^s,idirmin0:3)=current(ixo^s,idirmin0:3)+ps(igrid)%J0(ixo^s,idirmin0:3)
1012 endif
1013
1014 source(ixi^s)=zero
1015 {do ix^db=ixomin^db,ixomax^db\}
1016 do idir=idirmin0,3
1017 source(ix^d)=source(ix^d)+current(ix^d,idir)**2
1018 enddo
1019 {enddo\}
1020 end subroutine get_pseudo_current
1021
1022 subroutine get_radio_ff_source_opacity(ixI^L,ixO^L,w,x,fl,source,kappa)
1023 use mod_eos, only: eos
1024
1025 integer, intent(in) :: ixI^L, ixO^L
1026 double precision, intent(in) :: x(ixI^S,1:ndim)
1027 double precision, intent(in) :: w(ixI^S,1:nw)
1028 type(te_fluid), intent(in) :: fl
1029 double precision, intent(out) :: source(ixI^S),kappa(ixI^S)
1030
1031 integer :: ix^D
1032 double precision :: pth(ixI^S),Te(ixI^S),Ne(ixI^S)
1033 double precision :: nH_dummy(ixI^S),gff
1034
1035 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
1036 call fl%get_rho(w,x,ixi^l,ixo^l,ne)
1037 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,te)
1038 te(ixo^s)=pth(ixo^s)/(ne(ixo^s)*te(ixo^s))*unit_temperature
1039 call eos%get_ne_nH(ixi^l,ixo^l,w, x,ne,nh_dummy)
1040 if (si_unit) then
1041 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6
1042 else
1043 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
1044 endif
1045
1046 source(ixi^s)=zero
1047 kappa(ixi^s)=zero
1048 {do ix^db=ixomin^db,ixomax^db\}
1049 if (te(ix^d)>zero .and. ne(ix^d)>zero) then
1050 if (te(ix^d)<2.d5) then
1051 gff=18.2d0+1.5d0*log(te(ix^d))-log(radio_frequency)
1052 else
1053 gff=24.5d0+log(te(ix^d))-log(radio_frequency)
1054 endif
1055 gff=max(one,gff)
1056 kappa(ix^d)=9.78d-3*ne(ix^d)**2*gff/(radio_frequency**2*te(ix^d)**1.5d0)
1057 source(ix^d)=te(ix^d)*kappa(ix^d)
1058 endif
1059 {enddo\}
1060 end subroutine get_radio_ff_source_opacity
1061
1062 subroutine get_line_info(wl,ion,mass,logTe,line_center,spatial_px,spectral_px,sigma_PSF,width_slit)
1063 ! get information of the spectral line
1064 ! wl: wavelength
1065 ! mass: ion mass, unit -- proton mass
1066 ! logTe: peak temperature of emission line in logarithm
1067 ! line_center: center wavelength of emission line, unit -- Angstrom (0.1 nm)
1068 ! spatial_px: pixel size in space of instrument (for image), unit -- arcsec
1069 ! spectral_px: pixel size in wagelength of instrument (for spectrum), unit -- Angstrom
1070 ! sigma_PSF: width of point spread function core (for instrument), unit -- pixel
1071 ! width_slit: width of slit for spectrograph, unit -- arcsec
1073
1074 integer, intent(in) :: wl
1075 integer, intent(out) :: mass
1076 character(len=30), intent(out) :: ion
1077 double precision, intent(out) :: logTe,line_center,spatial_px,spectral_px
1078 double precision, intent(out) :: sigma_PSF,width_slit
1079
1080 select case(wl)
1081 case(304)
1082 ion='He II'
1083 mass=4
1084 logte=4.7d0
1085 line_center=303.8d0
1086 spatial_px=0.6d0
1087 spectral_px=0.02d0
1088 sigma_psf=0.895d0
1089 width_slit=0.6d0
1090 case(171)
1091 ion='Fe IX'
1092 mass=56
1093 logte=5.8d0
1094 line_center=171.1d0
1095 spatial_px=0.6d0
1096 spectral_px=0.02d0
1097 sigma_psf=1.019d0
1098 width_slit=0.6d0
1099 case(193)
1100 ion='Fe XXIV'
1101 mass=56
1102 logte=7.3d0
1103 line_center=193.5d0
1104 spatial_px=0.6d0
1105 spectral_px=0.02d0
1106 sigma_psf=0.813d0
1107 width_slit=0.6d0
1108 case(211)
1109 ion='Fe XIV'
1110 mass=56
1111 logte=6.3d0
1112 line_center=211.3d0
1113 spatial_px=0.6d0
1114 spectral_px=0.02d0
1115 sigma_psf=0.913d0
1116 width_slit=0.6d0
1117 case(335)
1118 ion='Fe XVI'
1119 mass=56
1120 logte=6.4d0
1121 line_center=335.4d0
1122 spatial_px=0.6d0
1123 spectral_px=0.02d0
1124 sigma_psf=1.019d0
1125 width_slit=0.6d0
1126 case(94)
1127 ion='Fe XVIII'
1128 mass=56
1129 logte=6.8d0
1130 line_center=93.9d0
1131 spatial_px=0.6d0
1132 spectral_px=0.02d0
1133 sigma_psf=1.025d0
1134 width_slit=0.6d0
1135 case(131)
1136 ion='Fe XXI'
1137 mass=56
1138 logte=7.0d0
1139 line_center=131.0d0
1140 spatial_px=0.6d0
1141 spectral_px=0.02d0
1142 sigma_psf=0.984d0
1143 width_slit=0.6d0
1144 case(1354)
1145 ion='Fe XXI'
1146 mass=56
1147 logte=7.0d0
1148 line_center=1354.1d0
1149 spatial_px=0.1663d0
1150 spectral_px=12.98d-3
1151 sigma_psf=1.d0
1152 width_slit=0.33d0
1153 case(263)
1154 ion='Fe XVI'
1155 mass=56
1156 logte=6.4d0
1157 line_center=262.976d0
1158 spatial_px=1.d0
1159 spectral_px=22.d-3
1160 sigma_psf=1.d0
1161 width_slit=2.d0
1162 case(264)
1163 ion='Fe XXIII'
1164 mass=56
1165 logte=7.1d0
1166 line_center=263.765d0
1167 spatial_px=1.d0
1168 spectral_px=22.d-3
1169 sigma_psf=1.d0
1170 width_slit=2.d0
1171 case(192)
1172 ion='Fe XXIV'
1173 mass=56
1174 logte=7.2d0
1175 line_center=192.028d0
1176 spatial_px=1.d0
1177 spectral_px=22.d-3
1178 sigma_psf=1.d0
1179 width_slit=2.d0
1180 case(255)
1181 ion='Fe XXIV'
1182 mass=56
1183 logte=7.2d0
1184 line_center=255.113d0
1185 spatial_px=1.d0
1186 spectral_px=22.d-3
1187 sigma_psf=1.d0
1188 width_slit=2.d0
1189 case default
1190 call mpistop("No information about this line")
1191 end select
1192
1193 spatial_px=spatial_px/instrument_resolution_factor
1194 end subroutine get_line_info
1195
1196 subroutine get_euv(wl,ixI^L,ixO^L,w,x,fl,flux)
1197 ! calculate the local emission intensity of given EUV line (optically thin)
1198 ! wavelength is the wave length of the emission line
1199 ! unit [DN cm^-1 s^-1 pixel^-1]
1200 ! ingrate flux along line of sight: DN s^-1 pixel^-1
1202 use mod_eos, only: eos
1203
1204 integer, intent(in) :: wl
1205 integer, intent(in) :: ixI^L, ixO^L
1206 double precision, intent(in) :: x(ixI^S,1:ndim)
1207 double precision, intent(in) :: w(ixI^S,1:nw)
1208 type(te_fluid), intent(in) :: fl
1209 double precision, intent(out) :: flux(ixI^S)
1210
1211 integer :: ix^D
1212 double precision :: pth(ixI^S),rho(ixI^S),Rfactor(ixI^S),Te(ixI^S)
1213 double precision :: Ne(ixI^S),nH(ixI^S)
1214
1215 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
1216 call fl%get_rho(w,x,ixi^l,ixo^l,rho)
1217 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,rfactor)
1218 te(ixo^s)=pth(ixo^s)/(rho(ixo^s)*rfactor(ixo^s))*unit_temperature
1219
1220 ! The tabulated response is multiplied by the physical emission-measure
1221 ! factor ne*nH. Both densities come from the active EOS so the source
1222 ! remains consistent for FI, PI, and LTE simulations.
1223 call eos%get_ne_nH(ixi^l, ixo^l, w, x, ne, nh)
1224 if (si_unit) then
1225 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6 ! m^-3 -> cm-3
1226 nh(ixo^s)=nh(ixo^s)*unit_numberdensity/1.d6
1227 else
1228 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
1229 nh(ixo^s)=nh(ixo^s)*unit_numberdensity
1230 endif
1231 flux(ixo^s)=ne(ixo^s)*nh(ixo^s)
1232
1233 select case(wl)
1234 case(94)
1235 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_94,n_aia,.true.,.true.)
1236 case(131)
1237 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_131,n_aia,.true.,.true.)
1238 case(171)
1239 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_171,n_aia,.true.,.true.)
1240 case(193)
1241 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_193,n_aia,.true.,.true.)
1242 case(211)
1243 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_211,n_aia,.true.,.true.)
1244 case(304)
1245 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_304,n_aia,.true.,.true.)
1246 case(335)
1247 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_aia,f_335,n_aia,.true.,.true.)
1248 case(1354)
1249 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_iris,f_1354,n_iris,.true.,.true.)
1250 case(263)
1251 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_eis1,f_263,n_eis,.false.,.false.)
1252 case(264)
1253 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_eis2,f_264,n_eis,.false.,.false.)
1254 case(192)
1255 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_eis2,f_192,n_eis,.false.,.false.)
1256 case(255)
1257 call apply_temperature_response(ixi^l,ixo^l,te,flux,t_eis2,f_255,n_eis,.false.,.false.)
1258 case default
1259 call mpistop("Unknown wavelength")
1260 end select
1261 end subroutine get_euv
1262
1263 subroutine get_sxr(ixI^L,ixO^L,w,x,fl,flux,El,Eu)
1264 !synthesize thermal SXR from El keV to Eu keV released by cm^-3/m^-3
1265 ! volume of plasma in 1 s
1266 !flux (cgs): photons cm^-3 s^-1
1267 !flux (SI): photons m^-3 s^-1
1269 use mod_eos, only: eos
1270
1271 integer, intent(in) :: ixI^L,ixO^L
1272 integer, intent(in) :: El,Eu
1273 double precision, intent(in) :: x(ixI^S,1:ndim)
1274 double precision, intent(in) :: w(ixI^S,nw)
1275 type(te_fluid), intent(in) :: fl
1276 double precision, intent(out) :: flux(ixI^S)
1277
1278 integer :: ix^D,ixO^D
1279 integer :: iE,numE
1280 double precision :: I0,kb,keV,dE,Ei
1281 double precision :: pth(ixI^S),Te(ixI^S),kbT(ixI^S)
1282 double precision :: Ne(ixI^S),gff(ixI^S),fi(ixI^S)
1283 double precision :: EM(ixI^S)
1284 double precision :: nH_dummy(ixI^S)
1285
1286 i0=3.01d-15 ! I0*4*pi*AU**2, I0 from Pinto (2015)
1287 kb=const_kb
1288 kev=1.0d3*const_ev
1289 de=0.1
1290 nume=floor((eu-el)/de)
1291 call fl%get_pthermal(w,x,ixi^l,ixo^l,pth)
1292 call fl%get_rho(w,x,ixi^l,ixo^l,ne)
1293 call fl%get_var_Rfactor(w,x,ixi^l,ixo^l,te)
1294 te(ixo^s)=pth(ixo^s)/(ne(ixo^s)*te(ixo^s))*unit_temperature
1295 ! get actual electron density from EoS (replaces rho with ne)
1296 call eos%get_ne_nH(ixi^l, ixo^l, w, x, ne, nh_dummy)
1297 if (si_unit) then
1298 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6 ! m^-3 -> cm-3
1299 em(ixo^s)=(ne(ixo^s))**2*1.d6 ! cm^-3 m^-3
1300 else
1301 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
1302 em(ixo^s)=(ne(ixo^s))**2
1303 endif
1304 kbt(ixo^s)=kb*te(ixo^s)/kev
1305 flux(ixo^s)=0.0d0
1306 do ie=0,nume-1
1307 ei=de*ie+el*1.d0
1308 gff(ixo^s)=1.d0
1309 {do ix^db=ixomin^db,ixomax^db\}
1310 if (kbt(ix^d)>0.01*ei) then
1311 if(kbt(ix^d)<ei) gff(ix^d)=(kbt(ix^d)/ei)**0.4
1312 fi(ix^d)=(em(ix^d)*gff(ix^d))*exp_clamped(-ei/(kbt(ix^d)))/(ei*dsqrt(kbt(ix^d)))
1313 else
1314 fi(ix^d)=zero
1315 endif
1316 {enddo\}
1317 flux(ixo^s)=flux(ixo^s)+fi(ixo^s)*de
1318 enddo
1319 flux(ixo^s)=flux(ixo^s)*i0
1320 end subroutine get_sxr
1321
1322 subroutine get_goes_sxr_flux(xbox^L,fl,eflux)
1323 !get GOES SXR 1-8A flux observing at 1AU from given box [w/m^2]
1325
1326 double precision, intent(in) :: xbox^L
1327 type(te_fluid), intent(in) :: fl
1328 double precision, intent(out) :: eflux
1329
1330 double precision :: dxb^D,xb^L
1331 integer :: iigrid,igrid,j
1332 integer :: ixO^L,ixI^L,ix^D
1333 double precision :: eflux_grid,eflux_pe
1334
1335 ^d&iximin^d=ixglo^d;
1336 ^d&iximax^d=ixghi^d;
1337 ^d&ixomin^d=ixmlo^d;
1338 ^d&ixomax^d=ixmhi^d;
1339 eflux_pe=zero
1340 do iigrid=1,igridstail; igrid=igrids(iigrid);
1341 ^d&dxlevel(^d)=rnode(rpdx^d_,igrid);
1342 ^d&xbmin^d=rnode(rpxmin^d_,igrid);
1343 ^d&xbmax^d=rnode(rpxmax^d_,igrid);
1344 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)
1345 eflux_pe=eflux_pe+eflux_grid
1346 enddo
1347 call mpi_allreduce(eflux_pe,eflux,1,mpi_double_precision,mpi_sum,icomm,ierrmpi)
1348 end subroutine get_goes_sxr_flux
1349
1350 subroutine get_goes_flux_grid(ixI^L,ixO^L,w,x,dV,xbox^L,xb^L,fl,eflux_grid)
1352 use mod_eos, only: eos
1353
1354 integer, intent(in) :: ixI^L,ixO^L
1355 double precision, intent(in) :: x(ixI^S,1:ndim),dV(ixI^S)
1356 double precision, intent(in) :: w(ixI^S,nw)
1357 double precision, intent(in) :: xbox^L,xb^L
1358 type(te_fluid), intent(in) :: fl
1359 double precision, intent(out) :: eflux_grid
1360
1361 integer :: ix^D,ixO^D,ixb^L
1362 integer :: iE,numE,j,inbox
1363 double precision :: I0,kb,keV,dE,Ei,El,Eu,A_cgs
1364 double precision :: pth(ixI^S),Te(ixI^S),kbT(ixI^S)
1365 double precision :: Ne(ixI^S),EM(ixI^S)
1366 double precision :: nH_dummy(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 call eos%get_ne_nH(ixi^l, ixb^l, w, x, ne, nh_dummy)
1395 if (si_unit) then
1396 ne(ixo^s)=ne(ixo^s)*unit_numberdensity/1.d6 ! m^-3 -> cm-3
1397 em(ixb^s)=(i0*(ne(ixb^s))**2)*dv(ixb^s)*(unit_length*1.d2)**3 ! cm^-3
1398 else
1399 ne(ixo^s)=ne(ixo^s)*unit_numberdensity
1400 em(ixb^s)=(i0*(ne(ixb^s))**2)*dv(ixb^s)*unit_length**3
1401 endif
1402 kbt(ixb^s)=kb*te(ixb^s)/kev
1403 eflux_grid=0.0d0
1404
1405 do ie=0,nume-1
1406 ei=de*ie+el
1407 {do ix^db=ixbmin^db,ixbmax^db\}
1408 if (kbt(ix^d)>1.d-2*ei) then
1409 if(kbt(ix^d)<ei) then
1410 gff=(kbt(ix^d)/ei)**0.4
1411 else
1412 gff=1.d0
1413 endif
1414 fi=(em(ix^d)*gff)*exp_clamped(-ei/(kbt(ix^d)))/(ei*dsqrt(kbt(ix^d)))
1415 eflux_grid=eflux_grid+fi*de*ei
1416 endif
1417 {enddo\}
1418 enddo
1419 eflux_grid=eflux_grid*kev*erg_si
1420 endif
1421
1422 end subroutine get_goes_flux_grid
1423
1424 {^ifthreed
1425 subroutine get_euv_spectrum(qunit,fl)
1427
1428 integer, intent(in) :: qunit
1429 type(te_fluid), intent(in) :: fl
1430 character(20) :: datatype
1431
1432 integer :: mass
1433 character (30) :: ion
1434 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
1435 double precision :: xslit,arcsec
1436
1437 datatype='spectrum_euv'
1439 arcsec=7.25d7/unit_length
1440 call get_line_info(spectrum_wl,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
1441
1442 if (mype==0) print *, '###################################################'
1443 select case(spectrum_wl)
1444 case (1354)
1445 if (mype==0) print *, 'Systhesizing EUV spectrum (observed by IRIS).'
1446 case (263,264,192,255)
1447 if (mype==0) print *, 'Systhesizing EUV spectrum (observed by Hinode/EIS).'
1448 case default
1449 call mpistop('Wrong wavelength!')
1450 end select
1451
1453 call mpistop('Wrong spectrum window!')
1454 endif
1455
1456 if (mype==0) write(*,'(a,f8.3,a)') ' Wavelength: ',linecent,' Angstrom'
1457 if (mype==0) print *, 'Unit of EUV flux: DN s^-1 pixel^-1'
1458
1459 if (dat_resolution) then
1460 if (mype==0) then
1461 write(*,'(a,f5.3,a,f5.1,a)') ' Supposed pixel: ',wlrsl,' Angstrom x ',spacersl*725.0, ' km'
1462 print *, 'Unit of wavelength: Angstrom (0.1 nm) '
1463 if (si_unit) then
1464 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
1465 else
1466 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
1467 endif
1468 write(*,'(a,f8.1,a)') ' Supposed width of slit: ',wslit*725.0,' km'
1469 endif
1470 call get_spectrum_datresol(qunit,datatype,fl)
1471 else
1472 if (mype==0) then
1473 print *, 'Unit of wavelength: Angstrom (0.1 nm) '
1474 if (activate_unit_arcsec) then
1475 write(*,'(a,f5.3,a,f5.1,a)') ' Pixel: ',wlrsl,' Angstrom x ',spacersl*725.0, ' km'
1476 print *, 'Unit of length: arcsec (~725 km)'
1477 write(*,'(a,f8.1,a)') ' Location of slit: xI1 = ',location_slit,' arcsec'
1478 write(*,'(a,f8.1,a)') ' Width of slit: ',wslit,' arcsec'
1479 else
1480 if (si_unit) then
1481 if (mype==0) write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
1482 else
1483 if (mype==0) write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
1484 endif
1485 write(*,'(a,f8.1,a)') ' Location of slit: xI1 = ',location_slit,' Unit_length'
1486 write(*,'(a,f8.1,a)') ' Width of slit: ',wslit*725.d0,' km'
1487 endif
1488 endif
1489 if (mype==0) print *, 'Direction of the slit: parallel to xI2 vector'
1490 if (coordinate==cartesian .or. coordinate==spherical) then
1491 call get_spectrum(qunit,datatype,fl)
1492 else
1493 call mpistop("EUV spectrum synthesis: support for sperical coordinates is to be added!")
1494 endif
1495 endif
1496
1497 if (mype==0) print *, '###################################################'
1498
1499 end subroutine get_euv_spectrum
1500
1501 subroutine get_spectrum_datresol(qunit,datatype,fl)
1502
1503 integer, intent(in) :: qunit
1504 character(20), intent(in) :: datatype
1505 type(te_fluid), intent(in) :: fl
1506
1507 integer :: numWL,numXS,iwL,ixS,numWI,numS
1508 double precision :: dwLg,xSmin,xSmax,wLmin,wLmax
1509 double precision, allocatable :: wL(:),xS(:),dwL(:),dxS(:)
1510 double precision, allocatable :: wI(:,:,:),spectra(:,:),spectra_rc(:,:)
1511 integer :: strtype,nstrb,nbb,nuni,nstr,bnx
1512 double precision :: qs,dxfirst,dxmid,lenstr
1513
1514 integer :: iigrid,igrid,j,dir_loc
1515 double precision :: xbmin(1:ndim),xbmax(1:ndim)
1516
1517 dwlg=1.d-3
1518 numwl=4*int((spectrum_window_max-spectrum_window_min)/(4.d0*dwlg))
1519 wlmin=(spectrum_window_max+spectrum_window_min)/2.d0-dwlg*numwl/2
1520 wlmax=(spectrum_window_max+spectrum_window_min)/2.d0+dwlg*numwl/2
1521 allocate(wl(numwl),dwl(numwl))
1522 dwl(:)=dwlg
1523 do iwl=1,numwl
1524 wl(iwl)=wlmin+iwl*dwlg-half*dwlg
1525 enddo
1526
1527 select case(direction_slit)
1528 case (1)
1529 numxs=domain_nx1*2**(refine_max_level-1)
1530 xsmin=xprobmin1
1531 xsmax=xprobmax1
1532 bnx=block_nx1
1533 nbb=domain_nx1
1534 strtype=stretch_type(1)
1535 nstrb=nstretchedblocks_baselevel(1)
1536 qs=qstretch_baselevel(1)
1537 if (mype==0) print *, 'Direction of the slit: x'
1538 case (2)
1539 numxs=domain_nx2*2**(refine_max_level-1)
1540 xsmin=xprobmin2
1541 xsmax=xprobmax2
1542 bnx=block_nx2
1543 nbb=domain_nx2
1544 strtype=stretch_type(2)
1545 nstrb=nstretchedblocks_baselevel(2)
1546 qs=qstretch_baselevel(2)
1547 if (mype==0) print *, 'Direction of the slit: y'
1548 case (3)
1549 numxs=domain_nx3*2**(refine_max_level-1)
1550 xsmin=xprobmin3
1551 xsmax=xprobmax3
1552 bnx=block_nx3
1553 nbb=domain_nx3
1554 strtype=stretch_type(3)
1555 nstrb=nstretchedblocks_baselevel(3)
1556 qs=qstretch_baselevel(3)
1557 if (mype==0) print *, 'Direction of the slit: z'
1558 case default
1559 call mpistop('Wrong direction_slit')
1560 end select
1561
1562 allocate(xs(numxs),dxs(numxs),spectra(numwl,numxs),spectra_rc(numwl,numxs))
1563 numwi=1
1564 allocate(wi(numwl,numxs,numwi))
1565
1566 select case(strtype)
1567 case(0) ! uniform
1568 dxs(:)=(xsmax-xsmin)/numxs
1569 do ixs=1,numxs
1570 xs(ixs)=xsmin+dxs(ixs)*(ixs-half)
1571 enddo
1572 case(1) ! uni stretch
1573 qs=qs**(one/2**(refine_max_level-1))
1574 dxfirst=(xsmax-xsmin)*(one-qs)/(one-qs**numxs)
1575 dxs(1)=dxfirst
1576 do ixs=2,numxs
1577 dxs(ixs)=dxfirst*qs**(ixs-1)
1578 xs(ixs)=dxs(1)/(one-qs)*(one-qs**(ixs-1))+half*dxs(ixs)
1579 enddo
1580 case(2) ! symm stretch
1581 ! base level, nbb = nstr + nuni + nstr
1582 nstr=nstrb*bnx/2
1583 nuni=nbb-nstrb*bnx
1584 lenstr=(xsmax-xsmin)/(2.d0+nuni*(one-qs)/(one-qs**nstr))
1585 dxfirst=(xsmax-xsmin)/(dble(nuni)+2.d0/(one-qs)*(one-qs**nstr))
1586 dxmid=dxfirst
1587 ! refine_max level, numXI = nstr + nuni + nstr
1588 nstr=nstr*2**(refine_max_level-1)
1589 nuni=nuni*2**(refine_max_level-1)
1590 qs=qs**(one/2**(refine_max_level-1))
1591 dxfirst=lenstr*(one-qs)/(one-qs**nstr)
1592 dxmid=dxmid/2**(refine_max_level-1)
1593 ! uniform center
1594 if(nuni .gt. 0) then
1595 do ixs=nstr+1,nstr+nuni
1596 dxs(ixs)=dxmid
1597 xs(ixs)=lenstr+(dble(ixs)-0.5d0-nstr)*dxs(ixs)+xsmin
1598 enddo
1599 endif
1600 ! left half
1601 do ixs=nstr,1,-1
1602 dxs(ixs)=dxfirst*qs**(nstr-ixs)
1603 xs(ixs)=xsmin+lenstr-dxs(ixs)*half-dxfirst*(one-qs**(nstr-ixs))/(one-qs)
1604 enddo
1605 ! right half
1606 do ixs=nstr+nuni+1,numxs
1607 dxs(ixs)=dxfirst*qs**(ixs-nstr-nuni-1)
1608 xs(ixs)=xsmax-lenstr+dxs(ixs)*half+dxfirst*(one-qs**(ixs-nstr-nuni-1))/(one-qs)
1609 enddo
1610 case default
1611 call mpistop("unknown stretch type")
1612 end select
1613
1614 if (los_phi==0 .and. los_theta==90 .and. direction_slit==2) then
1615 ! LOS->x slit->y
1616 dir_loc=3
1617 else if (los_phi==0 .and. los_theta==90 .and. direction_slit==3) then
1618 ! LOS->x slit->z
1619 dir_loc=2
1620 else if (los_phi==90 .and. los_theta==90 .and. direction_slit==1) then
1621 ! LOS->y slit->x
1622 dir_loc=3
1623 else if (los_phi==90 .and. los_theta==90 .and. direction_slit==3) then
1624 ! LOS->y slit->z
1625 dir_loc=1
1626 else if (los_theta==0 .and. direction_slit==1) then
1627 ! LOS->z slit->x
1628 dir_loc=2
1629 else if (los_theta==0 .and. direction_slit==2) then
1630 ! LOS->z slit->y
1631 dir_loc=1
1632 else
1633 call mpistop('Wrong combination of LOS and slit direction!')
1634 endif
1635
1636 if (dir_loc==1) then
1637 if (location_slit>xprobmax1 .or. location_slit<xprobmin1) then
1638 call mpistop('Wrong value for location_slit!')
1639 endif
1640 if(mype==0) write(*,'(a,f8.1,a)') ' Location of slit: x = ',location_slit,' Unit_length'
1641 else if (dir_loc==2) then
1642 if (location_slit>xprobmax2 .or. location_slit<xprobmin2) then
1643 call mpistop('Wrong value for location_slit!')
1644 endif
1645 if(mype==0) write(*,'(a,f8.1,a)') ' Location of slit: y = ',location_slit,' Unit_length'
1646 else
1647 if (location_slit>xprobmax3 .or. location_slit<xprobmin3) then
1648 call mpistop('Wrong value for location_slit!')
1649 endif
1650 if(mype==0) write(*,'(a,f8.1,a)') ' Location of slit: z = ',location_slit,' Unit_length'
1651 endif
1652
1653 ! find slit and do integration
1654 spectra=zero
1655 do iigrid=1,igridstail; igrid=igrids(iigrid);
1656 ^d&xbmin(^d)=rnode(rpxmin^d_,igrid);
1657 ^d&xbmax(^d)=rnode(rpxmax^d_,igrid);
1658 if (location_slit>=xbmin(dir_loc) .and. location_slit<xbmax(dir_loc)) then
1659 call integrate_spectra_datresol(igrid,wl,dwl,spectra,numwl,numxs,dir_loc,fl)
1660 endif
1661 enddo
1662
1663 nums=numwl*numxs
1664 call mpi_allreduce(spectra,spectra_rc,nums,mpi_double_precision, &
1665 mpi_sum,icomm,ierrmpi)
1666 do iwl=1,numwl
1667 do ixs=1,numxs
1668 if (spectra_rc(iwl,ixs)>smalldouble) then
1669 wi(iwl,ixs,1)=spectra_rc(iwl,ixs)
1670 else
1671 wi(iwl,ixs,1)=zero
1672 endif
1673 enddo
1674 enddo
1675
1676 call output_data(qunit,wl,xs,dwl,dxs,wi,numwl,numxs,numwi,datatype)
1677
1678 deallocate(wl,xs,dwl,dxs,spectra,spectra_rc,wi)
1679
1680 end subroutine get_spectrum_datresol
1681
1682 subroutine integrate_spectra_datresol(igrid,wL,dwL,spectra,numWL,numXS,dir_loc,fl)
1683 use mod_constants
1684
1685 integer, intent(in) :: igrid,numWL,numXS,dir_loc
1686 type(te_fluid), intent(in) :: fl
1687 double precision, intent(in) :: wL(numWL),dwL(numWL)
1688 double precision, intent(inout) :: spectra(numWL,numXS)
1689
1690 integer :: direction_LOS
1691 integer :: ixO^L,ixI^L,ix^D,ixOnew
1692 double precision, allocatable :: flux(:^D&),v(:^D&),pth(:^D&),Te(:^D&),rho(:^D&)
1693 double precision :: wlc,wlwd
1694
1695 integer :: mass
1696 double precision :: logTe,lineCent
1697 character (30) :: ion
1698 double precision :: spaceRsl,wlRsl,sigma_PSF,wslit
1699
1700 integer :: levelg,rft,ixSmin,ixSmax,iwL
1701 double precision :: flux_pix,dL
1702
1703 call get_line_info(spectrum_wl,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
1704
1705 if (los_phi==0 .and. los_theta==90) then
1706 direction_los=1
1707 else if (los_phi==90 .and. los_theta==90) then
1708 direction_los=2
1709 else
1710 direction_los=3
1711 endif
1712
1713 ^d&ixomin^d=ixmlo^d\
1714 ^d&ixomax^d=ixmhi^d\
1715 ^d&iximin^d=ixglo^d\
1716 ^d&iximax^d=ixghi^d\
1717 allocate(flux(ixi^s),v(ixi^s),pth(ixi^s),te(ixi^s),rho(ixi^s))
1718
1719 ^d&ix^d=ixomin^d;
1720 if (dir_loc==1) then
1721 do ix1=ixomin1,ixomax1
1722 if (location_slit>=(ps(igrid)%x(ix^d,1)-half*ps(igrid)%dx(ix^d,1)) .and. &
1723 location_slit<(ps(igrid)%x(ix^d,1)+half*ps(igrid)%dx(ix^d,1))) then
1724 ixonew=ix1
1725 endif
1726 enddo
1727 ixomin1=ixonew
1728 ixomax1=ixonew
1729 else if (dir_loc==2) then
1730 do ix2=ixomin2,ixomax2
1731 if (location_slit>=(ps(igrid)%x(ix^d,2)-half*ps(igrid)%dx(ix^d,2)) .and. &
1732 location_slit<(ps(igrid)%x(ix^d,2)+half*ps(igrid)%dx(ix^d,2))) then
1733 ixonew=ix2
1734 endif
1735 enddo
1736 ixomin2=ixonew
1737 ixomax2=ixonew
1738 else
1739 do ix3=ixomin3,ixomax3
1740 if (location_slit>=(ps(igrid)%x(ix^d,3)-half*ps(igrid)%dx(ix^d,3)) .and. &
1741 location_slit<(ps(igrid)%x(ix^d,3)+half*ps(igrid)%dx(ix^d,3))) then
1742 ixonew=ix3
1743 endif
1744 enddo
1745 ixomin3=ixonew
1746 ixomax3=ixonew
1747 endif
1748
1749 call get_euv(spectrum_wl,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
1750 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
1751 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
1752 v(ixo^s)=-ps(igrid)%w(ixo^s,iw_mom(direction_los))/rho(ixo^s)
1753 call fl%get_pthermal(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,pth)
1754 call fl%get_var_Rfactor(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,te)
1755 te(ixo^s)=pth(ixo^s)/(te(ixo^s)*rho(ixo^s))
1756
1757 ! grid parameters
1758 levelg=ps(igrid)%level
1759 rft=2**(refine_max_level-levelg)
1760
1761 {do ix^d=ixomin^d,ixomax^d\}
1762 if (flux(ix^d)>smalldouble) then
1763 if (si_unit) then
1764 wlc=linecent*(1.d0+v(ix^d)*unit_velocity*1.d2/const_c)
1765 else
1766 wlc=linecent*(1.d0+v(ix^d)*unit_velocity/const_c)
1767 endif
1768 wlwd=sqrt(kb_cgs*te(ix^d)*unit_temperature/(mass*mp_cgs))
1769 wlwd=wlwd*linecent/const_c
1770 ! involved pixel
1771 select case(direction_slit)
1772 case(1)
1773 ixsmin=(block_nx1*(node(pig1_,igrid)-1)+(ix1-ixomin1))*rft+1
1774 ixsmax=(block_nx1*(node(pig1_,igrid)-1)+(ix1-ixomin1+1))*rft
1775 case(2)
1776 ixsmin=(block_nx2*(node(pig2_,igrid)-1)+(ix2-ixomin2))*rft+1
1777 ixsmax=(block_nx2*(node(pig2_,igrid)-1)+(ix2-ixomin2+1))*rft
1778 case(3)
1779 ixsmin=(block_nx3*(node(pig3_,igrid)-1)+(ix3-ixomin3))*rft+1
1780 ixsmax=(block_nx3*(node(pig3_,igrid)-1)+(ix3-ixomin3+1))*rft
1781 end select
1782 ! LOS depth
1783 select case(direction_los)
1784 case(1)
1785 dl=ps(igrid)%dx(ix^d,1)*unit_length
1786 case(2)
1787 dl=ps(igrid)%dx(ix^d,2)*unit_length
1788 case default
1789 dl=ps(igrid)%dx(ix^d,3)*unit_length
1790 end select
1791 if (si_unit) dl=dl*1.d2
1792 ! integral pixel flux
1793 do iwl=1,numwl
1794 flux_pix=flux(ix^d)*wlrsl*dl*exp_clamped(-(wl(iwl)-wlc)**2/(2*wlwd**2))/(sqrt(2*dpi)*wlwd)
1795 if (flux_pix>smalldouble) then
1796 flux_pix=flux_pix*wslit/spacersl
1797 spectra(iwl,ixsmin:ixsmax)=spectra(iwl,ixsmin:ixsmax)+flux_pix
1798 endif
1799 enddo
1800 endif
1801 {enddo\}
1802
1803 deallocate(flux,v,pth,te,rho)
1804
1805 end subroutine integrate_spectra_datresol
1806
1807 subroutine get_spectrum(qunit,datatype,fl)
1808
1809 integer, intent(in) :: qunit
1810 character(20), intent(in) :: datatype
1811 type(te_fluid), intent(in) :: fl
1812
1813 integer :: numWL,numXS,iwL,ixS,numWI,ix^D
1814 double precision :: dwLg,dxSg,xSmin,xSmax,xScent,wLmin,wLmax
1815 double precision, allocatable :: wL(:),xS(:),dwL(:),dxS(:)
1816 double precision, allocatable :: wI(:,:,:),spectra(:,:),spectra_rc(:,:)
1817 double precision :: vec_cor(1:3),xI_cor(1:2)
1818 double precision :: res,r_loc,r_max
1819
1820 integer :: mass
1821 character (30) :: ion
1822 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
1823 double precision :: unitv,arcsec,RHESSI_rsl,pixel
1824 integer :: iigrid,igrid,i,j,numS
1825 double precision :: xLmin,xLmax,xslit
1826
1827 if (coordinate==spherical) then
1829 else
1830 ! cartesian
1832 endif
1833
1834 ! calculate domain in space
1835 if (coordinate==spherical) then
1836 xsmin=-abs(xprobmax1)
1837 xsmax=abs(xprobmax1)
1838 else
1839 do ix1=1,2
1840 if (ix1==1) vec_cor(1)=xprobmin1
1841 if (ix1==2) vec_cor(1)=xprobmax1
1842 do ix2=1,2
1843 if (ix2==1) vec_cor(2)=xprobmin2
1844 if (ix2==2) vec_cor(2)=xprobmax2
1845 do ix3=1,2
1846 if (ix3==1) vec_cor(3)=xprobmin3
1847 if (ix3==2) vec_cor(3)=xprobmax3
1848 if (big_image) then
1849 r_loc=(vec_cor(1)-x_origin(1))**2
1850 r_loc=r_loc+(vec_cor(2)-x_origin(2))**2
1851 r_loc=r_loc+(vec_cor(3)-x_origin(3))**2
1852 r_loc=sqrt(r_loc)
1853 if (ix1==1 .and. ix2==1 .and. ix3==1) then
1854 r_max=r_loc
1855 else
1856 r_max=max(r_max,r_loc)
1857 endif
1858 else
1859 call get_cor_image(vec_cor,xi_cor)
1860 if (ix1==1 .and. ix2==1 .and. ix3==1) then
1861 xsmin=xi_cor(2)
1862 xsmax=xi_cor(2)
1863 else
1864 xsmin=min(xsmin,xi_cor(2))
1865 xsmax=max(xsmax,xi_cor(2))
1866 endif
1867 endif
1868 enddo
1869 enddo
1870 enddo
1871 if (big_image) then
1872 xsmin=-r_max
1873 xsmax=r_max
1874 endif
1875 endif
1876 xscent=(xsmin+xsmax)/2.d0
1877
1878 ! tables for storing spectra data
1879 if (si_unit) then
1880 arcsec=7.25d5/unit_length
1881 else
1882 arcsec=7.25d7/unit_length
1883 endif
1884 call get_line_info(spectrum_wl,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
1885 dxsg=spacersl*arcsec
1886 numxs=ceiling((xsmax-xscent)/dxsg)
1887 xsmin=xscent-numxs*dxsg
1888 xsmax=xscent+numxs*dxsg
1889 numxs=numxs*2
1890 dwlg=wlrsl
1891 numwl=2*int((spectrum_window_max-spectrum_window_min)/(2.d0*dwlg))
1892 wlmin=(spectrum_window_max+spectrum_window_min)/2.d0-dwlg*numwl/2
1893 wlmax=(spectrum_window_max+spectrum_window_min)/2.d0+dwlg*numwl/2
1894 allocate(wl(numwl),dwl(numwl),xs(numxs),dxs(numxs))
1895 numwi=1
1896 allocate(wi(numwl,numxs,numwi),spectra(numwl,numxs),spectra_rc(numwl,numxs))
1897 do iwl=1,numwl
1898 wl(iwl)=wlmin+iwl*dwlg-half*dwlg
1899 dwl=dwlg
1900 enddo
1901 do ixs=1,numxs
1902 xs(ixs)=xsmin+dxsg*(ixs-half)
1903 dxs(ixs)=dxsg
1904 enddo
1905
1906 ! find slit and do integration
1907 spectra=zero
1908 do iigrid=1,igridstail; igrid=igrids(iigrid);
1909 do ix1=1,2
1910 if (ix1==1) vec_cor(1)=rnode(rpxmin1_,igrid)
1911 if (ix1==2) vec_cor(1)=rnode(rpxmax1_,igrid)
1912 do ix2=1,2
1913 if (ix2==1) vec_cor(2)=rnode(rpxmin2_,igrid)
1914 if (ix2==2) vec_cor(2)=rnode(rpxmax2_,igrid)
1915 do ix3=1,2
1916 if (ix3==1) vec_cor(3)=rnode(rpxmin3_,igrid)
1917 if (ix3==2) vec_cor(3)=rnode(rpxmax3_,igrid)
1918 call get_cor_image(vec_cor,xi_cor)
1919 if (ix1==1 .and. ix2==1 .and. ix3==1) then
1920 xlmin=xi_cor(1)
1921 xlmax=xi_cor(1)
1922 else
1923 xlmin=min(xlmin,xi_cor(1))
1924 xlmax=max(xlmax,xi_cor(1))
1925 endif
1926 enddo
1927 enddo
1928 enddo
1929
1930 if (activate_unit_arcsec) then
1931 xslit=location_slit*arcsec
1932 else
1933 xslit=location_slit
1934 endif
1935 if (xslit>=xlmin-wslit*arcsec .and. xslit<=xlmax+wslit*arcsec) then
1936 call integrate_spectra_cartesian(igrid,wl,dwlg,xs,dxsg,spectra,numwl,numxs,fl)
1937 endif
1938 enddo
1939
1940 nums=numwl*numxs
1941 call mpi_allreduce(spectra,spectra_rc,nums,mpi_double_precision, &
1942 mpi_sum,icomm,ierrmpi)
1943 do iwl=1,numwl
1944 do ixs=1,numxs
1945 if (spectra_rc(iwl,ixs)>smalldouble) then
1946 wi(iwl,ixs,1)=spectra_rc(iwl,ixs)
1947 else
1948 wi(iwl,ixs,1)=zero
1949 endif
1950 enddo
1951 enddo
1952
1953 if (activate_unit_arcsec) then
1954 xs=xs/arcsec
1955 dxs=dxs/arcsec
1956 endif
1957
1958 call output_data(qunit,wl,xs,dwl,dxs,wi,numwl,numxs,numwi,datatype)
1959
1960 deallocate(wl,xs,dwl,dxs,spectra,spectra_rc,wi)
1961
1962 end subroutine get_spectrum
1963
1964 subroutine integrate_spectra_cartesian(igrid,wL,dwLg,xS,dxSg,spectra,numWL,numXS,fl)
1965
1966 integer, intent(in) :: igrid,numWL,numXS
1967 double precision, intent(in) :: wL(numWL),xS(numXS)
1968 double precision, intent(in) :: dwLg,dxSg
1969 double precision, intent(inout) :: spectra(numWL,numXS)
1970 type(te_fluid), intent(in) :: fl
1971
1972 integer :: ixO^L,ixI^L,ix^D,ixOnew,j
1973 double precision, allocatable :: flux(:^D&),v(:^D&),pth(:^D&),Te(:^D&),rho(:^D&)
1974 double precision :: wlc,wlwd,res,dst_slit,xslit,arcsec
1975 double precision :: vloc(1:3),xloc(1:3),dxloc(1:3),xIloc(1:2),dxIloc(1:2)
1976 integer :: nSubC^D,iSubC^D,iwL,ixS,ixSmin,ixSmax,iwLmin,iwLmax,nwL
1977 double precision :: slit_width,dxSubC^D,xerf^L,fluxSubC
1978 double precision :: xSubC(1:3),xCent(1:2)
1979
1980 integer :: mass
1981 double precision :: logTe,lineCent
1982 character (30) :: ion
1983 double precision :: spaceRsl,wlRsl,sigma_PSF,wslit
1984 double precision :: sigma_wl,sigma_xs,factor
1985
1986 if (si_unit) then
1987 arcsec=7.25d5/unit_length
1988 else
1989 arcsec=7.25d7/unit_length
1990 endif
1991 if (activate_unit_arcsec) then
1992 xslit=location_slit*arcsec
1993 else
1994 xslit=location_slit
1995 endif
1996
1997 call get_line_info(spectrum_wl,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
1998
1999 ^d&ixomin^d=ixmlo^d\
2000 ^d&ixomax^d=ixmhi^d\
2001 ^d&iximin^d=ixglo^d\
2002 ^d&iximax^d=ixghi^d\
2003 allocate(flux(ixi^s),v(ixi^s),pth(ixi^s),te(ixi^s),rho(ixi^s))
2004 ! get local EUV flux and velocity
2005 call get_euv(spectrum_wl,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
2006 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
2007 call fl%get_pthermal(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,pth)
2008 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
2009 call fl%get_var_Rfactor(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,te)
2010 te(ixo^s)=pth(ixo^s)/(te(ixo^s)*rho(ixo^s))
2011 {do ix^d=ixomin^d,ixomax^d\}
2012 do j=1,3
2013 vloc(j)=ps(igrid)%w(ix^d,iw_mom(j))/rho(ix^d)
2014 enddo
2015 call dot_product_loc(vloc,vec_los,res)
2016 v(ix^d)=res
2017 {enddo\}
2018
2019 deallocate(rho)
2020
2021 slit_width=wslit*arcsec
2022 sigma_wl=sigma_psf*dwlg
2023 sigma_xs=sigma_psf*dxsg
2024 {do ix^d=ixomin^d,ixomax^d\}
2025 if (flux(ix^d)>smalldouble) then
2026 xloc(1:3)=ps(igrid)%x(ix^d,1:3)
2027 dxloc(1:3)=ps(igrid)%dx(ix^d,1:3)
2028 call get_cor_image(xloc,xiloc)
2029 call dot_product_loc(dxloc,vec_xi1,res)
2030 dxiloc(1)=abs(res)
2031 if (xiloc(1)>=xslit-half*(slit_width+dxiloc(1)) .and. &
2032 xiloc(1)<=xslit+half*(slit_width+dxiloc(1))) then
2033 ^d&nsubc^d=1;
2034 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi1(^d))/(slit_width/16.d0)));
2035 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi2(^d))/(dxsg/4.d0)));
2036 ^d&dxsubc^d=ps(igrid)%dx(ix^dd,^d)/nsubc^d;
2037 ! local line center and line width
2038 if (si_unit) then
2039 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length*1.d2/dxsg/dxsg ! DN s^-1
2040 wlc=linecent*(1.d0+v(ix^d)*unit_velocity*1.d2/const_c)
2041 else
2042 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length/dxsg/dxsg ! DN s^-1
2043 wlc=linecent*(1.d0+v(ix^d)*unit_velocity/const_c)
2044 endif
2045 wlwd=sqrt(kb_cgs*te(ix^d)*unit_temperature/(mass*mp_cgs))
2046 wlwd=wlwd*linecent/const_c
2047 ! dividing a cell to several parts to get more accurate integrating values
2048 {do isubc^d=1,nsubc^d\}
2049 ^d&xsubc(^d)=xloc(^d)-half*dxloc(^d)+(isubc^d-half)*dxsubc^d;
2050 call get_cor_image(xsubc,xcent)
2051 dst_slit=abs(xcent(1)-xslit) ! space distance to slit center
2052 if (dst_slit<=half*slit_width) then
2053 ixs=floor((xcent(2)-(xs(1)-half*dxsg))/dxsg)+1
2054 ixsmin=max(1,ixs-3)
2055 ixsmax=min(ixs+3,numxs)
2056 iwl=floor((wlc-(wl(1)-half*dwlg))/dwlg)+1
2057 nwl=3*ceiling(wlwd/dwlg+1)
2058 iwlmin=max(1,iwl-nwl)
2059 iwlmax=min(iwl+nwl,numwl)
2060 ! calculate the contribution to nearby pixels
2061 do iwl=iwlmin,iwlmax
2062 do ixs=ixsmin,ixsmax
2063 xerfmin1=(wl(iwl)-half*dwlg-wlc)/sqrt(2.d0*(sigma_wl**2+wlwd**2))
2064 xerfmax1=(wl(iwl)+half*dwlg-wlc)/sqrt(2.d0*(sigma_wl**2+wlwd**2))
2065 xerfmin2=(xs(ixs)-half*dxsg-xcent(2))/(sqrt(2.d0)*sigma_xs)
2066 xerfmax2=(xs(ixs)+half*dxsg-xcent(2))/(sqrt(2.d0)*sigma_xs)
2067 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
2068 spectra(iwl,ixs)=spectra(iwl,ixs)+fluxsubc*factor
2069 enddo
2070 enddo
2071 ! nearby pixels
2072 endif
2073 {enddo\}
2074 endif
2075 endif
2076 {enddo\}
2077
2078 deallocate(flux,v,pth,te)
2079 end subroutine integrate_spectra_cartesian
2080 }
2081
2082 {^ifthreed
2083 subroutine get_euv_image(qunit,fl)
2085
2086 integer, intent(in) :: qunit
2087 type(te_fluid), intent(in) :: fl
2088 character(20) :: datatype
2089
2090 integer :: mass
2091 character (30) :: ion
2092 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
2093 double precision :: t0,t1
2094
2095 t0=mpi_wtime()
2096 datatype='image_euv'
2098 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
2099
2100 if (mype==0) then
2101 print *, '###################################################'
2102 print *, 'Systhesizing EUV image'
2103 write(*,'(a,f8.3,a)') ' Wavelength: ',linecent,' Angstrom'
2104 print *, 'Unit of EUV flux: DN s^-1 pixel^-1'
2105 endif
2106
2107 if (dat_resolution) then
2108 if (.not. slab .and. .not. (coordinate==spherical .and. trim(ray_method_active)=='spherical')) &
2109 call mpistop('EUV dat-resolution needs Cartesian or spherical native rays')
2110 if (mype==0) then
2111 print *, 'Data-resolution image requested; native output pixel sizes are reported below.'
2112 if (si_unit) then
2113 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2114 else
2115 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2116 endif
2117 endif
2118 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') then
2119 call get_image_datresol(qunit,datatype,fl)
2120 else if (trim(ray_method_active)=='cart') then
2121 call get_image_datresol(qunit,datatype,fl)
2122 else if (los_phi==0 .and. los_theta==90) then
2123 call get_image_datresol(qunit,datatype,fl)
2124 else if (los_phi==90 .and. los_theta==90) then
2125 call get_image_datresol(qunit,datatype,fl)
2126 else if (los_theta==0) then
2127 call get_image_datresol(qunit,datatype,fl)
2128 else
2129 call mpistop('ERROR: Wrong LOS for synthesizing emission!')
2130 endif
2131 else
2132 if (mype==0) then
2133 write(*,'(a,f7.1,a,f7.1,a,f5.1,a,f5.1,a)') ' Pixel: ',spacersl*725.0,' km x ',spacersl*725.0, ' km (', &
2134 spacersl, ' arcsec x ', spacersl, ' arcsec)'
2135 if (activate_unit_arcsec) then
2136 print *, 'Unit of length: arcsec (~725 km)'
2137 else
2138 if (si_unit) then
2139 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2140 else
2141 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2142 endif
2143 endif
2144 endif
2145 if (slab) then
2146 if (mype==0) write(*,'(a,f8.3,f8.3,f8.3,a)') ' Mapping: [',x_origin(1),x_origin(2),x_origin(3), &
2147 '] of the simulation box is located at [X=0,Y=0] of the image'
2148 call get_image(qunit,datatype,fl)
2149 else if (coordinate==spherical) then
2150 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'
2151 call get_image(qunit,datatype,fl)
2152 else
2153 call mpistop("EUV synthesis: this coordinate is not supported!")
2154 endif
2155 endif
2156
2157 t1=mpi_wtime()
2158 if (mype==0) print *, 'time comsuming: ',t1-t0,' s'
2159 if (mype==0) print *, '###################################################'
2160
2161 end subroutine get_euv_image
2162
2163 subroutine get_sxr_image(qunit,fl)
2165
2166 integer, intent(in) :: qunit
2167 type(te_fluid), intent(in) :: fl
2168 character(20) :: datatype
2169 double precision :: RHESSI_rsl
2170 double precision :: t0,t1
2171
2172 t0=mpi_wtime()
2173 datatype='image_sxr'
2175 rhessi_rsl=2.3/instrument_resolution_factor
2176
2177 if (mype==0) then
2178 print *, '###################################################'
2179 print *, 'Systhesizing SXR image (observed at 1 AU).'
2180 write(*,'(a,i2,a,i2,a)') ' Passband: ',emin_sxr,' - ',emax_sxr,' keV'
2181 endif
2182
2183 if (dat_resolution) then
2184 if (coordinate/=cartesian) call mpistop('SXR synthesis: only cartesian is supported for .dat resolution!')
2185 if (mype==0) then
2186 print *, 'Unit of SXR flux: photons cm^-2 s^-1 pixel^-1'
2187 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, &
2188 ' Mm (', rhessi_rsl, ' arcsec x ', rhessi_rsl, ' arcsec)'
2189 if (si_unit) then
2190 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2191 else
2192 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2193 endif
2194 endif
2195 if (los_phi==0 .and. los_theta==90) then
2196 call get_image_datresol(qunit,datatype,fl)
2197 else if (los_phi==90 .and. los_theta==90) then
2198 call get_image_datresol(qunit,datatype,fl)
2199 else if (los_theta==0) then
2200 call get_image_datresol(qunit,datatype,fl)
2201 else
2202 call mpistop('ERROR: Wrong LOS for synthesizing emission!')
2203 endif
2204 else
2205 if (mype==0) then
2206 print *, 'Unit of SXR flux: photons cm^-2 s^-1 pixel^-1'
2207 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, &
2208 ' Mm (', rhessi_rsl, ' arcsec x ', rhessi_rsl, ' arcsec)'
2209 if (activate_unit_arcsec) then
2210 print *, 'Unit of length: arcsec (~725 km)'
2211 else
2212 if (si_unit) then
2213 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2214 else
2215 write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2216 endif
2217 endif
2218 endif
2219 if (coordinate==cartesian) then
2220 if (mype==0) write(*,'(a,f8.3,f8.3,f8.3,a)') ' Mapping: [',x_origin(1),x_origin(2),x_origin(3), &
2221 '] of the simulation box is located at [X=0,Y=0] of the image'
2222 call get_image(qunit,datatype,fl)
2223 else if (coordinate==spherical) then
2224 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'
2225 call get_image(qunit,datatype,fl)
2226 else
2227 call mpistop("SXR synthesis: this coordinate is not supported!")
2228 endif
2229 endif
2230
2231 t1=mpi_wtime()
2232 if (mype==0) print *, 'time comsuming:',t1-t0
2233 if (mype==0) print *, '###################################################'
2234
2235 end subroutine get_sxr_image
2236
2237 subroutine get_whitelight_image(qunit,fl)
2239
2240 integer, intent(in) :: qunit
2241 type(te_fluid), intent(in) :: fl
2242 character(20) :: datatype
2243 double precision :: LASCO_rsl
2244
2245 if (mype==0) print *, '###################################################'
2246
2247 if (whitelight_instrument=='LASCO/C1') then
2248 lasco_rsl=5.6d0/instrument_resolution_factor
2249 if (mype==0) print *, 'Systhesizing white light image (observed by LASCO/C1).'
2250 else if (whitelight_instrument=='LASCO/C2') then
2251 lasco_rsl=11.4d0/instrument_resolution_factor
2252 if (mype==0) print *, 'Systhesizing white light image (observed by LASCO/C2).'
2253 else if (whitelight_instrument=='LASCO/C3') then
2254 lasco_rsl=56.d0/instrument_resolution_factor
2255 if (mype==0) print *, 'Systhesizing white light image (observed by LASCO/C3).'
2256 else
2257 call mpistop('Whitelight synthesis: instrument is not supported!')
2258 endif
2259
2260 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 (', &
2261 lasco_rsl, ' arcsec x ', lasco_rsl, ' arcsec) '
2262 if (mype==0) print *, 'Unit of white light flux: average Sun brightness'
2263
2264 datatype='image_whitelight'
2266
2267 if (mype==0) then
2268 if (activate_unit_arcsec) then
2269 print *, 'Unit of length: arcsec (~725 km)'
2270 else
2271 if (si_unit) then
2272 if (mype==0) write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d6,' Mm'
2273 else
2274 if (mype==0) write(*,'(a,f8.1,a)') ' Unit of length: ',unit_length/1.d8,' Mm'
2275 endif
2276 endif
2277 endif
2278
2279 if (coordinate==spherical) then
2280 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'
2281 call get_image(qunit,datatype,fl)
2282 else
2283 call mpistop("Whitelight synthesis: this coordinate is not supported!")
2284 endif
2285
2286 if (mype==0) print *, '###################################################'
2287
2288 end subroutine get_whitelight_image
2289
2290 subroutine postprocess_euv_instrument_image(nSrc1,nSrc2,xSrc1,xSrc2,dxSrc1,dxSrc2,&
2291 EUV,Dpl,nOut1,nOut2,xOut1,xOut2,&
2292 dxOut1,dxOut2,wOut,numWOut,Tau,EUVthin)
2294 use mod_constants
2295
2296 integer, intent(in) :: nSrc1,nSrc2
2297 double precision, intent(in) :: xSrc1(nSrc1),xSrc2(nSrc2)
2298 double precision, intent(in) :: dxSrc1(nSrc1),dxSrc2(nSrc2)
2299 double precision, intent(in) :: EUV(nSrc1,nSrc2),Dpl(nSrc1,nSrc2)
2300 integer, intent(out) :: nOut1,nOut2,numWOut
2301 double precision, allocatable, intent(out) :: xOut1(:),xOut2(:),dxOut1(:),dxOut2(:)
2302 double precision, allocatable, intent(out) :: wOut(:,:,:)
2303 double precision, intent(in), optional :: Tau(nSrc1,nSrc2),EUVthin(nSrc1,nSrc2)
2304
2305 integer :: mass,ixS1,ixS2,ixP1,ixP2,ixC1,ixC2,iw
2306 integer :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
2307 character(30) :: ion
2308 double precision :: logTe,lineCent,spaceRsl,wlRsl,sigma_PSF,wslit
2309 double precision :: arcsec,dxInst,xMin1,xMax1,xMin2,xMax2,xCent1,xCent2
2310 double precision :: sigma0,xerfmin1,xerfmax1,xerfmin2,xerfmax2
2311 double precision :: factor,weightSum,weightNorm,thinVal,tauVal
2312 double precision, allocatable :: dplNum(:,:),thinOut(:,:),tauOut(:,:),tauWeight(:,:)
2313
2314 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
2315 if (si_unit) then
2316 arcsec=7.25d5/unit_length
2317 else
2318 arcsec=7.25d7/unit_length
2319 endif
2320 dxinst=spacersl*arcsec
2321 if (dxinst<=zero) call mpistop("instrument_postprocess has non-positive pixel size")
2322
2323 xmin1=minval(xsrc1-half*dxsrc1)
2324 xmax1=maxval(xsrc1+half*dxsrc1)
2325 xmin2=minval(xsrc2-half*dxsrc2)
2326 xmax2=maxval(xsrc2+half*dxsrc2)
2327 xcent1=half*(xmin1+xmax1)
2328 xcent2=half*(xmin2+xmax2)
2329 nout1=16*max(1,ceiling((xmax1-xmin1)/(16.d0*dxinst)))
2330 nout2=16*max(1,ceiling((xmax2-xmin2)/(16.d0*dxinst)))
2331 xmin1=xcent1-half*dble(nout1)*dxinst
2332 xmin2=xcent2-half*dble(nout2)*dxinst
2333
2334 allocate(xout1(nout1),xout2(nout2),dxout1(nout1),dxout2(nout2))
2335 do ixp1=1,nout1
2336 xout1(ixp1)=xmin1+dxinst*(dble(ixp1)-half)
2337 dxout1(ixp1)=dxinst
2338 enddo
2339 do ixp2=1,nout2
2340 xout2(ixp2)=xmin2+dxinst*(dble(ixp2)-half)
2341 dxout2(ixp2)=dxinst
2342 enddo
2343
2344 numwout=2
2345 if (present(tau) .and. output_tau) numwout=numwout+1
2346 if (present(euvthin) .and. output_absorption_fraction) numwout=numwout+1
2347 allocate(wout(nout1,nout2,numwout),dplnum(nout1,nout2))
2348 wout=zero
2349 dplnum=zero
2350 if (present(euvthin)) then
2351 allocate(thinout(nout1,nout2))
2352 thinout=zero
2353 endif
2354 if (present(tau) .and. output_tau) then
2355 allocate(tauout(nout1,nout2),tauweight(nout1,nout2))
2356 tauout=zero
2357 tauweight=zero
2358 endif
2359
2360 sigma0=sigma_psf*dxinst
2361 do ixs1=1,nsrc1
2362 do ixs2=1,nsrc2
2363 thinval=zero
2364 tauval=zero
2365 if (present(euvthin)) thinval=euvthin(ixs1,ixs2)
2366 if (present(tau)) tauval=tau(ixs1,ixs2)
2367 if (abs(euv(ixs1,ixs2))<=smalldouble .and. abs(thinval)<=smalldouble .and. &
2368 abs(tauval)<=smalldouble) cycle
2369
2370 ixc1=floor((xsrc1(ixs1)-(xout1(1)-half*dxinst))/dxinst)+1
2371 ixc2=floor((xsrc2(ixs2)-(xout2(1)-half*dxinst))/dxinst)+1
2372 ixpmin1=max(1,ixc1-3)
2373 ixpmax1=min(nout1,ixc1+3)
2374 ixpmin2=max(1,ixc2-3)
2375 ixpmax2=min(nout2,ixc2+3)
2376
2377 weightsum=zero
2378 do ixp1=ixpmin1,ixpmax1
2379 do ixp2=ixpmin2,ixpmax2
2380 xerfmin1=((xout1(ixp1)-half*dxinst)-xsrc1(ixs1))/(sqrt(2.d0)*sigma0)
2381 xerfmax1=((xout1(ixp1)+half*dxinst)-xsrc1(ixs1))/(sqrt(2.d0)*sigma0)
2382 xerfmin2=((xout2(ixp2)-half*dxinst)-xsrc2(ixs2))/(sqrt(2.d0)*sigma0)
2383 xerfmax2=((xout2(ixp2)+half*dxinst)-xsrc2(ixs2))/(sqrt(2.d0)*sigma0)
2384 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
2385 weightsum=weightsum+factor
2386 enddo
2387 enddo
2388 if (weightsum<=zero) cycle
2389
2390 do ixp1=ixpmin1,ixpmax1
2391 do ixp2=ixpmin2,ixpmax2
2392 xerfmin1=((xout1(ixp1)-half*dxinst)-xsrc1(ixs1))/(sqrt(2.d0)*sigma0)
2393 xerfmax1=((xout1(ixp1)+half*dxinst)-xsrc1(ixs1))/(sqrt(2.d0)*sigma0)
2394 xerfmin2=((xout2(ixp2)-half*dxinst)-xsrc2(ixs2))/(sqrt(2.d0)*sigma0)
2395 xerfmax2=((xout2(ixp2)+half*dxinst)-xsrc2(ixs2))/(sqrt(2.d0)*sigma0)
2396 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
2397 weightnorm=factor/weightsum
2398 wout(ixp1,ixp2,1)=wout(ixp1,ixp2,1)+euv(ixs1,ixs2)*weightnorm
2399 dplnum(ixp1,ixp2)=dplnum(ixp1,ixp2)+euv(ixs1,ixs2)*dpl(ixs1,ixs2)*weightnorm
2400 if (present(euvthin)) thinout(ixp1,ixp2)=thinout(ixp1,ixp2)+thinval*weightnorm
2401 if (present(tau) .and. output_tau) then
2402 tauout(ixp1,ixp2)=tauout(ixp1,ixp2)+tauval*weightnorm
2403 tauweight(ixp1,ixp2)=tauweight(ixp1,ixp2)+weightnorm
2404 endif
2405 enddo
2406 enddo
2407 enddo
2408 enddo
2409
2410 do ixp1=1,nout1
2411 do ixp2=1,nout2
2412 if (wout(ixp1,ixp2,1)>smalldouble) then
2413 wout(ixp1,ixp2,2)=dplnum(ixp1,ixp2)/wout(ixp1,ixp2,1)
2414 else
2415 wout(ixp1,ixp2,2)=zero
2416 endif
2417 enddo
2418 enddo
2419 iw=2
2420 if (present(tau) .and. output_tau) then
2421 iw=iw+1
2422 do ixp1=1,nout1
2423 do ixp2=1,nout2
2424 if (tauweight(ixp1,ixp2)>zero) then
2425 wout(ixp1,ixp2,iw)=tauout(ixp1,ixp2)/tauweight(ixp1,ixp2)
2426 else
2427 wout(ixp1,ixp2,iw)=zero
2428 endif
2429 enddo
2430 enddo
2431 endif
2432 if (present(euvthin) .and. output_absorption_fraction) then
2433 iw=iw+1
2434 do ixp1=1,nout1
2435 do ixp2=1,nout2
2436 if (thinout(ixp1,ixp2)>smalldouble) then
2437 wout(ixp1,ixp2,iw)=min(one,max(zero,(thinout(ixp1,ixp2)-wout(ixp1,ixp2,1))/thinout(ixp1,ixp2)))
2438 else
2439 wout(ixp1,ixp2,iw)=zero
2440 endif
2441 enddo
2442 enddo
2443 endif
2444
2445 if (mype==0) then
2446 write(*,'(a,2(i8,1x),a,2(i8,1x),a,1pe12.5)') &
2447 ' instrument_postprocess EUV grid src/out: ',nsrc1,nsrc2,' -> ',nout1,nout2,' dx=',dxinst
2448 endif
2449
2450 deallocate(dplnum)
2451 if (allocated(thinout)) deallocate(thinout)
2452 if (allocated(tauout)) deallocate(tauout,tauweight)
2454
2455 subroutine postprocess_radio_beam_image(nSrc1,nSrc2,xSrc1,xSrc2,dxSrc1,dxSrc2,&
2456 Bright,nOut1,nOut2,xOut1,xOut2,&
2457 dxOut1,dxOut2,wOut,numWOut,Tau,BrightThin)
2459
2460 integer, intent(in) :: nSrc1,nSrc2
2461 double precision, intent(in) :: xSrc1(nSrc1),xSrc2(nSrc2)
2462 double precision, intent(in) :: dxSrc1(nSrc1),dxSrc2(nSrc2)
2463 double precision, intent(in) :: Bright(nSrc1,nSrc2)
2464 integer, intent(out) :: nOut1,nOut2,numWOut
2465 double precision, allocatable, intent(out) :: xOut1(:),xOut2(:),dxOut1(:),dxOut2(:)
2466 double precision, allocatable, intent(out) :: wOut(:,:,:)
2467 double precision, intent(in), optional :: Tau(nSrc1,nSrc2),BrightThin(nSrc1,nSrc2)
2468
2469 integer :: ixS1,ixS2,ixP1,ixP2,ixC1,ixC2,iw,nStencil
2470 integer :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
2471 double precision :: arcsec,beamPixel,beamSigma,xMin1,xMax1,xMin2,xMax2,xCent1,xCent2
2472 double precision :: distance1,distance2,weight,cellArea,thinVal,tauVal
2473 double precision, allocatable :: norm(:,:),thinOut(:,:),tauOut(:,:),tauNorm(:,:)
2474
2475 if (si_unit) then
2476 arcsec=7.25d5/unit_length
2477 else
2478 arcsec=7.25d7/unit_length
2479 endif
2480 beamsigma=radio_beam_fwhm*arcsec/sqrt(8.d0*log(2.d0))
2481 if (radio_beam_pixel_size>zero) then
2482 beampixel=radio_beam_pixel_size*arcsec
2483 else
2484 beampixel=radio_beam_fwhm*arcsec/3.d0
2485 endif
2486 if (beamsigma<=zero .or. beampixel<=zero) then
2487 call mpistop("radio beam postprocess has non-positive beam or pixel size")
2488 endif
2489
2490 xmin1=minval(xsrc1-half*dxsrc1)
2491 xmax1=maxval(xsrc1+half*dxsrc1)
2492 xmin2=minval(xsrc2-half*dxsrc2)
2493 xmax2=maxval(xsrc2+half*dxsrc2)
2494 xcent1=half*(xmin1+xmax1)
2495 xcent2=half*(xmin2+xmax2)
2496 nout1=16*max(1,ceiling((xmax1-xmin1)/(16.d0*beampixel)))
2497 nout2=16*max(1,ceiling((xmax2-xmin2)/(16.d0*beampixel)))
2498 xmin1=xcent1-half*dble(nout1)*beampixel
2499 xmin2=xcent2-half*dble(nout2)*beampixel
2500
2501 allocate(xout1(nout1),xout2(nout2),dxout1(nout1),dxout2(nout2))
2502 do ixp1=1,nout1
2503 xout1(ixp1)=xmin1+beampixel*(dble(ixp1)-half)
2504 dxout1(ixp1)=beampixel
2505 enddo
2506 do ixp2=1,nout2
2507 xout2(ixp2)=xmin2+beampixel*(dble(ixp2)-half)
2508 dxout2(ixp2)=beampixel
2509 enddo
2510
2511 numwout=1
2512 if (present(tau) .and. output_tau) numwout=numwout+1
2513 if (present(brightthin) .and. output_absorption_fraction) numwout=numwout+1
2514 allocate(wout(nout1,nout2,numwout),norm(nout1,nout2))
2515 wout=zero
2516 norm=zero
2517 if (present(brightthin)) then
2518 allocate(thinout(nout1,nout2))
2519 thinout=zero
2520 endif
2521 if (present(tau) .and. output_tau) then
2522 allocate(tauout(nout1,nout2),taunorm(nout1,nout2))
2523 tauout=zero
2524 taunorm=zero
2525 endif
2526
2527 nstencil=max(3,ceiling(4.d0*beamsigma/beampixel)+1)
2528 do ixs1=1,nsrc1
2529 do ixs2=1,nsrc2
2530 thinval=zero
2531 tauval=zero
2532 if (present(brightthin)) thinval=brightthin(ixs1,ixs2)
2533 if (present(tau)) tauval=tau(ixs1,ixs2)
2534 if (abs(bright(ixs1,ixs2))<=smalldouble .and. abs(thinval)<=smalldouble .and. &
2535 abs(tauval)<=smalldouble) cycle
2536
2537 ixc1=floor((xsrc1(ixs1)-(xout1(1)-half*beampixel))/beampixel)+1
2538 ixc2=floor((xsrc2(ixs2)-(xout2(1)-half*beampixel))/beampixel)+1
2539 ixpmin1=max(1,ixc1-nstencil)
2540 ixpmax1=min(nout1,ixc1+nstencil)
2541 ixpmin2=max(1,ixc2-nstencil)
2542 ixpmax2=min(nout2,ixc2+nstencil)
2543 cellarea=max(smalldouble,dxsrc1(ixs1)*dxsrc2(ixs2))
2544
2545 do ixp1=ixpmin1,ixpmax1
2546 distance1=xout1(ixp1)-xsrc1(ixs1)
2547 do ixp2=ixpmin2,ixpmax2
2548 distance2=xout2(ixp2)-xsrc2(ixs2)
2549 weight=exp_clamped(-half*(distance1**2+distance2**2)/beamsigma**2)*cellarea
2550 wout(ixp1,ixp2,1)=wout(ixp1,ixp2,1)+bright(ixs1,ixs2)*weight
2551 norm(ixp1,ixp2)=norm(ixp1,ixp2)+weight
2552 if (present(brightthin)) thinout(ixp1,ixp2)=thinout(ixp1,ixp2)+thinval*weight
2553 if (present(tau) .and. output_tau) then
2554 tauout(ixp1,ixp2)=tauout(ixp1,ixp2)+tauval*weight
2555 taunorm(ixp1,ixp2)=taunorm(ixp1,ixp2)+weight
2556 endif
2557 enddo
2558 enddo
2559 enddo
2560 enddo
2561
2562 do ixp1=1,nout1
2563 do ixp2=1,nout2
2564 if (norm(ixp1,ixp2)>zero) then
2565 wout(ixp1,ixp2,1)=wout(ixp1,ixp2,1)/norm(ixp1,ixp2)
2566 if (present(brightthin)) thinout(ixp1,ixp2)=thinout(ixp1,ixp2)/norm(ixp1,ixp2)
2567 else
2568 wout(ixp1,ixp2,1)=zero
2569 if (present(brightthin)) thinout(ixp1,ixp2)=zero
2570 endif
2571 enddo
2572 enddo
2573
2574 iw=1
2575 if (present(tau) .and. output_tau) then
2576 iw=iw+1
2577 do ixp1=1,nout1
2578 do ixp2=1,nout2
2579 if (taunorm(ixp1,ixp2)>zero) then
2580 wout(ixp1,ixp2,iw)=tauout(ixp1,ixp2)/taunorm(ixp1,ixp2)
2581 else
2582 wout(ixp1,ixp2,iw)=zero
2583 endif
2584 enddo
2585 enddo
2586 endif
2587 if (present(brightthin) .and. output_absorption_fraction) then
2588 iw=iw+1
2589 do ixp1=1,nout1
2590 do ixp2=1,nout2
2591 if (thinout(ixp1,ixp2)>smalldouble) then
2592 wout(ixp1,ixp2,iw)=min(one,max(zero,(thinout(ixp1,ixp2)-wout(ixp1,ixp2,1))/thinout(ixp1,ixp2)))
2593 else
2594 wout(ixp1,ixp2,iw)=zero
2595 endif
2596 enddo
2597 enddo
2598 endif
2599
2600 if (mype==0) then
2601 write(*,'(a,2(i8,1x),a,2(i8,1x),a,2(1pe12.5,1x))') &
2602 ' radio_beam_postprocess grid src/out: ',nsrc1,nsrc2,' -> ',nout1,nout2,&
2603 ' fwhm/pixel=',radio_beam_fwhm,beampixel/arcsec
2604 endif
2605
2606 deallocate(norm)
2607 if (allocated(thinout)) deallocate(thinout)
2608 if (allocated(tauout)) deallocate(tauout,taunorm)
2609 end subroutine postprocess_radio_beam_image
2610
2611 subroutine get_image_datresol(qunit,datatype,fl)
2612 ! integrate emission flux along line of sight (LOS)
2613 ! in a 3D simulation box and get a 2D EUV image
2615 use mod_constants
2616
2617 integer, intent(in) :: qunit
2618 character(20), intent(in) :: datatype
2619 type(te_fluid), intent(in) :: fl
2620
2621 double precision :: dx^D
2622 integer :: numX^D,ix^D
2623 double precision, allocatable :: EUV(:,:),EUVs(:,:),Dpl(:,:),Dpls(:,:)
2624 double precision, allocatable :: EUVthin(:,:),Tau(:,:)
2625 double precision, allocatable :: SXR(:,:),SXRs(:,:),wI(:,:,:)
2626 double precision, allocatable :: xI1(:),xI2(:),dxI1(:),dxI2(:),dxIi
2627 integer :: numXI1,numXI2,numSI,numWI,iw
2628 double precision :: xI^L
2629 integer :: iigrid,igrid,i,j
2630 double precision, allocatable :: xIF1(:),xIF2(:),dxIF1(:),dxIF2(:)
2631 double precision, allocatable :: xIP1(:),xIP2(:),dxIP1(:),dxIP2(:),wIP(:,:,:)
2632 integer :: nXIF1,nXIF2
2633 integer :: nXIP1,nXIP2,numWIP
2634 double precision :: xIF^L
2635 double precision :: vec_cor(1:3),xI_cor(1:2),dxDDA,xIcent1,xIcent2
2636
2637 double precision :: unitv,arcsec,RHESSI_rsl,length_to_km
2638 integer :: strtype^D,nstrb^D,nbb^D,nuni^D,nstr^D,bnx^D
2639 double precision :: qs^D,dxfirst^D,dxmid^D,lenstr^D
2640 logical :: has_doppler_output,has_thick_output
2641
2642 numx1=domain_nx1*2**(refine_max_level-1)
2643 numx2=domain_nx2*2**(refine_max_level-1)
2644 numx3=domain_nx3*2**(refine_max_level-1)
2645
2646 if (trim(ray_method_active)=='cart') call init_vectors_cartesian()
2647 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') call init_vectors_spherical()
2648
2649 ! parameters for creating table
2650 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') then
2651 call get_sph_intersection_image_bounds(xifmin1,xifmax1,xifmin2,xifmax2)
2652 call get_native_datresol_spacing(dxdda)
2653 xicent1=half*(xifmin1+xifmax1)
2654 xicent2=half*(xifmin2+xifmax2)
2655 nxif1=max(1,ceiling((xifmax1-xifmin1)/dxdda))
2656 nxif2=max(1,ceiling((xifmax2-xifmin2)/dxdda))
2657 xifmin1=xicent1-half*dble(nxif1)*dxdda
2658 xifmax1=xicent1+half*dble(nxif1)*dxdda
2659 xifmin2=xicent2-half*dble(nxif2)*dxdda
2660 xifmax2=xicent2+half*dble(nxif2)*dxdda
2661 bnx1=1
2662 bnx2=1
2663 nbb1=nxif1
2664 nbb2=nxif2
2665 strtype1=0
2666 strtype2=0
2667 nstrb1=0
2668 nstrb2=0
2669 qs1=one
2670 qs2=one
2671 if (mype==0) write(*,'(a,a,a,1pe12.5,a,2(i8,1x))') &
2672 ' spherical dat-resolution mode=',trim(dat_resolution_mode),&
2673 ' image-plane dx=',dxdda,' n=',nxif1,nxif2
2674 else if (trim(ray_method_active)=='cart') then
2675 do ix1=1,2
2676 if (ix1==1) vec_cor(1)=xprobmin1
2677 if (ix1==2) vec_cor(1)=xprobmax1
2678 do ix2=1,2
2679 if (ix2==1) vec_cor(2)=xprobmin2
2680 if (ix2==2) vec_cor(2)=xprobmax2
2681 do ix3=1,2
2682 if (ix3==1) vec_cor(3)=xprobmin3
2683 if (ix3==2) vec_cor(3)=xprobmax3
2684 call get_cor_image(vec_cor,xi_cor)
2685 if (ix1==1 .and. ix2==1 .and. ix3==1) then
2686 xifmin1=xi_cor(1)
2687 xifmax1=xi_cor(1)
2688 xifmin2=xi_cor(2)
2689 xifmax2=xi_cor(2)
2690 else
2691 xifmin1=min(xifmin1,xi_cor(1))
2692 xifmax1=max(xifmax1,xi_cor(1))
2693 xifmin2=min(xifmin2,xi_cor(2))
2694 xifmax2=max(xifmax2,xi_cor(2))
2695 endif
2696 enddo
2697 enddo
2698 enddo
2699 call get_native_datresol_spacing(dxdda)
2700 xicent1=half*(xifmin1+xifmax1)
2701 xicent2=half*(xifmin2+xifmax2)
2702 nxif1=max(1,ceiling((xifmax1-xifmin1)/dxdda))
2703 nxif2=max(1,ceiling((xifmax2-xifmin2)/dxdda))
2704 xifmin1=xicent1-half*dble(nxif1)*dxdda
2705 xifmax1=xicent1+half*dble(nxif1)*dxdda
2706 xifmin2=xicent2-half*dble(nxif2)*dxdda
2707 xifmax2=xicent2+half*dble(nxif2)*dxdda
2708 bnx1=1
2709 bnx2=1
2710 nbb1=nxif1
2711 nbb2=nxif2
2712 strtype1=0
2713 strtype2=0
2714 nstrb1=0
2715 nstrb2=0
2716 qs1=one
2717 qs2=one
2718 if (mype==0) write(*,'(a,a,a,1pe12.5,a,2(i8,1x))') &
2719 ' Cartesian dat-resolution mode=',trim(dat_resolution_mode),&
2720 ' image-plane dx=',dxdda,' n=',nxif1,nxif2
2721 else if (los_phi==0 .and. los_theta==90) then
2722 nxif1=domain_nx2*2**(refine_max_level-1)
2723 nxif2=domain_nx3*2**(refine_max_level-1)
2724 xifmin1=xprobmin2
2725 xifmax1=xprobmax2
2726 xifmin2=xprobmin3
2727 xifmax2=xprobmax3
2728 bnx1=block_nx2
2729 bnx2=block_nx3
2730 nbb1=domain_nx2
2731 nbb2=domain_nx3
2732 strtype1=stretch_type(2)
2733 strtype2=stretch_type(3)
2736 qs1=qstretch_baselevel(2)
2737 qs2=qstretch_baselevel(3)
2738 if (mype==0) write(*,'(a)') ' LOS vector: [-1.00 0.00 0.00]'
2739 if (mype==0) write(*,'(a)') ' xI1 vector: [ 0.00 1.00 0.00]'
2740 if (mype==0) write(*,'(a)') ' xI2 vector: [ 0.00 0.00 1.00]'
2741 else if (los_phi==90 .and. los_theta==90) then
2742 nxif1=domain_nx3*2**(refine_max_level-1)
2743 nxif2=domain_nx1*2**(refine_max_level-1)
2744 xifmin1=xprobmin3
2745 xifmax1=xprobmax3
2746 xifmin2=xprobmin1
2747 xifmax2=xprobmax1
2748 bnx1=block_nx3
2749 bnx2=block_nx1
2750 nbb1=domain_nx3
2751 nbb2=domain_nx1
2752 strtype1=stretch_type(3)
2753 strtype2=stretch_type(1)
2756 qs1=qstretch_baselevel(3)
2757 qs2=qstretch_baselevel(1)
2758 if (mype==0) write(*,'(a)') ' LOS vector: [ 0.00 -1.00 0.00]'
2759 if (mype==0) write(*,'(a)') ' xI1 vector: [-1.00 0.00 0.00]'
2760 if (mype==0) write(*,'(a)') ' xI2 vector: [ 0.00 0.00 1.00]'
2761 else
2762 nxif1=domain_nx1*2**(refine_max_level-1)
2763 nxif2=domain_nx2*2**(refine_max_level-1)
2764 xifmin1=xprobmin1
2765 xifmax1=xprobmax1
2766 xifmin2=xprobmin2
2767 xifmax2=xprobmax2
2768 bnx1=block_nx1
2769 bnx2=block_nx2
2770 nbb1=domain_nx1
2771 nbb2=domain_nx2
2772 strtype1=stretch_type(1)
2773 strtype2=stretch_type(2)
2776 qs1=qstretch_baselevel(1)
2777 qs2=qstretch_baselevel(2)
2778 if (mype==0) write(*,'(a)') ' LOS vector: [ 0.00 0.00 -1.00]'
2779 if (mype==0) write(*,'(a)') ' xI1 vector: [ 1.00 0.00 0.00]'
2780 if (mype==0) write(*,'(a)') ' xI2 vector: [ 0.00 1.00 0.00]'
2781 endif
2782 allocate(xif1(nxif1),xif2(nxif2),dxif1(nxif1),dxif2(nxif2))
2783
2784 ! initialize image coordinate
2785 select case(strtype1)
2786 case(0) ! uniform
2787 dxif1(:)=(xifmax1-xifmin1)/nxif1
2788 do ix1=1,nxif1
2789 xif1(ix1)=xifmin1+dxif1(ix1)*(ix1-half)
2790 enddo
2791 case(1) ! uni stretch
2792 qs1=qs1**(one/2**(refine_max_level-1))
2793 dxfirst1=(xifmax1-xifmin1)*(one-qs1)/(one-qs1**nxif1)
2794 dxif1(1)=dxfirst1
2795 do ix1=2,nxif1
2796 dxif1(ix1)=dxfirst1*qs1**(ix1-1)
2797 xif1(ix1)=dxif1(1)/(one-qs1)*(one-qs1**(ix1-1))+half*dxif1(ix1)
2798 enddo
2799 case(2) ! symm stretch
2800 ! base level, nbb = nstr + nuni + nstr
2801 nstr1=nstrb1*bnx1/2
2802 nuni1=nbb1-nstrb1*bnx1
2803 lenstr1=(xifmax1-xifmin1)/(2.d0+nuni1*(one-qs1)/(one-qs1**nstr1))
2804 dxfirst1=(xifmax1-xifmin1)/(dble(nuni1)+2.d0/(one-qs1)*(one-qs1**nstr1))
2805 dxmid1=dxfirst1
2806 ! refine_max level, numXI = nstr + nuni + nstr
2807 nstr1=nstr1*2**(refine_max_level-1)
2808 nuni1=nuni1*2**(refine_max_level-1)
2809 qs1=qs1**(one/2**(refine_max_level-1))
2810 dxfirst1=lenstr1*(one-qs1)/(one-qs1**nstr1)
2811 dxmid1=dxmid1/2**(refine_max_level-1)
2812 ! uniform center
2813 if(nuni1 .gt. 0) then
2814 do ix1=nstr1+1,nstr1+nuni1
2815 dxif1(ix1)=dxmid1
2816 xif1(ix1)=lenstr1+(dble(ix1)-0.5d0-nstr1)*dxif1(ix1)+xifmin1
2817 enddo
2818 endif
2819 ! left half
2820 do ix1=nstr1,1,-1
2821 dxif1(ix1)=dxfirst1*qs1**(nstr1-ix1)
2822 xif1(ix1)=xifmin1+lenstr1-dxif1(ix1)*half-dxfirst1*(one-qs1**(nstr1-ix1))/(one-qs1)
2823 enddo
2824 ! right half
2825 do ix1=nstr1+nuni1+1,nxif1
2826 dxif1(ix1)=dxfirst1*qs1**(ix1-nstr1-nuni1-1)
2827 xif1(ix1)=xifmax1-lenstr1+dxif1(ix1)*half+dxfirst1*(one-qs1**(ix1-nstr1-nuni1-1))/(one-qs1)
2828 enddo
2829 case default
2830 call mpistop("unknown stretch type")
2831 end select
2832
2833 select case(strtype2)
2834 case(0) ! uniform
2835 dxif2(:)=(xifmax2-xifmin2)/nxif2
2836 do ix2=1,nxif2
2837 xif2(ix2)=xifmin2+dxif2(ix2)*(ix2-half)
2838 enddo
2839 case(1) ! uni stretch
2840 qs2=qs2**(one/2**(refine_max_level-1))
2841 dxfirst2=(xifmax2-xifmin2)*(one-qs2)/(one-qs2**nxif2)
2842 dxif2(1)=dxfirst2
2843 do ix2=2,nxif1
2844 dxif2(ix2)=dxfirst2*qs2**(ix2-1)
2845 xif2(ix2)=dxif2(1)/(one-qs2)*(one-qs2**(ix2-1))+half*dxif2(ix2)
2846 enddo
2847 case(2) ! symm stretch
2848 ! base level, nbb = nstr + nuni + nstr
2849 nstr2=nstrb2*bnx2/2
2850 nuni2=nbb2-nstrb2*bnx2
2851 lenstr2=(xifmax2-xifmin2)/(2.d0+nuni2*(one-qs2)/(one-qs2**nstr2))
2852 dxfirst2=(xifmax2-xifmin2)/(dble(nuni2)+2.d0/(one-qs2)*(one-qs2**nstr2))
2853 dxmid2=dxfirst2
2854 ! refine_max level, numXI = nstr + nuni + nstr
2855 nstr2=nstr2*2**(refine_max_level-1)
2856 nuni2=nuni2*2**(refine_max_level-1)
2857 qs2=qs2**(one/2**(refine_max_level-1))
2858 dxfirst2=lenstr2*(one-qs2)/(one-qs2**nstr2)
2859 dxmid2=dxmid2/2**(refine_max_level-1)
2860 ! uniform center
2861 if(nuni2 .gt. 0) then
2862 do ix2=nstr2+1,nstr2+nuni2
2863 dxif2(ix2)=dxmid2
2864 xif2(ix2)=lenstr2+(dble(ix2)-0.5d0-nstr2)*dxif2(ix2)+xifmin2
2865 enddo
2866 endif
2867 ! left half
2868 do ix2=nstr2,1,-1
2869 dxif2(ix2)=dxfirst2*qs2**(nstr2-ix2)
2870 xif2(ix2)=xifmin2+lenstr2-dxif2(ix2)*half-dxfirst2*(one-qs2**(nstr2-ix2))/(one-qs2)
2871 enddo
2872 ! right half
2873 do ix2=nstr2+nuni2+1,nxif2
2874 dxif2(ix2)=dxfirst2*qs2**(ix2-nstr2-nuni2-1)
2875 xif2(ix2)=xifmax2-lenstr2+dxif2(ix2)*half+dxfirst2*(one-qs2**(ix2-nstr2-nuni2-1))/(one-qs2)
2876 enddo
2877 case default
2878 call mpistop("unknown stretch type")
2879 end select
2880
2881 if (mype==0 .and. datatype=='image_euv') then
2882 if (si_unit) then
2883 length_to_km=unit_length/1.d3
2884 arcsec=7.25d5/unit_length
2885 else
2886 length_to_km=unit_length/1.d5
2887 arcsec=7.25d7/unit_length
2888 endif
2889 write(*,'(a,i8,a,i8)') ' Native data-resolution image grid: ',nxif1,' x ',nxif2
2890 write(*,'(a,f10.3,a,f10.3,a,f8.3,a,f8.3,a)') &
2891 ' Native xI1 pixel-size range: ',minval(dxif1)*length_to_km,'--', &
2892 maxval(dxif1)*length_to_km,' km (',minval(dxif1)/arcsec,'--',maxval(dxif1)/arcsec,' arcsec)'
2893 write(*,'(a,f10.3,a,f10.3,a,f8.3,a,f8.3,a)') &
2894 ' Native xI2 pixel-size range: ',minval(dxif2)*length_to_km,'--', &
2895 maxval(dxif2)*length_to_km,' km (',minval(dxif2)/arcsec,'--',maxval(dxif2)/arcsec,' arcsec)'
2896 endif
2897
2898 ! integrate EUV flux and get cell average flux for image
2899 if (datatype=='image_euv') then
2900 if (si_unit) then
2901 unitv=unit_velocity/1.0e3 ! km/s
2902 else
2903 unitv=unit_velocity/1.0e5 ! km/s
2904 endif
2905 has_thick_output=trim(radiation_transfer)=='thick'
2906 has_doppler_output=radsyn_euv_has_doppler_output()
2907 numwi=radsyn_euv_num_outputs(has_doppler_output,has_thick_output)
2908 allocate(wi(nxif1,nxif2,numwi))
2909 allocate(euv(nxif1,nxif2),dpl(nxif1,nxif2))
2910 if (trim(radiation_transfer)=='thick') then
2911 allocate(euvthin(nxif1,nxif2),tau(nxif1,nxif2))
2912 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') then
2913 call integrate_euv_sph_intersection_thick(nxif1,nxif2,xif1,xif2,dxif1(1),fl,euv,tau,euvthin)
2914 dpl=zero
2915 else if (trim(ray_method_active)=='cart') then
2916 call integrate_euv_cart_dda_thick_datresol(nxif1,nxif2,xif1,xif2,fl,euv,dpl,tau,euvthin)
2917 else
2918 call integrate_euv_thick_datresol(nxif1,nxif2,fl,euv,dpl,tau,euvthin)
2919 endif
2920 if (has_doppler_output) then
2921 where(euv<smalldouble) euv=zero
2922 call normalize_euv_doppler(nxif1,nxif2,euv,dpl,unitv)
2923 endif
2924 else
2925 allocate(euvs(nxif1,nxif2),dpls(nxif1,nxif2))
2926 euvs=0.0d0
2927 euv=0.0d0
2928 dpl=0.d0
2929 dpls=0.d0
2930 if (coordinate==spherical .and. trim(ray_method_active)=='spherical') then
2931 call integrate_euv_sph_intersection_thin(nxif1,nxif2,xif1,xif2,dxif1(1),fl,euv)
2932 euvs=euv
2933 numsi=nxif1*nxif2
2934 call mpi_allreduce(euvs,euv,numsi,mpi_double_precision, &
2935 mpi_sum,icomm,ierrmpi)
2936 else if (trim(ray_method_active)=='cart') then
2937 call integrate_euv_cart_dda_datresol(nxif1,nxif2,xif1,xif2,fl,euv,dpl)
2938 else
2939 do iigrid=1,igridstail; igrid=igrids(iigrid);
2940 call integrate_euv_datresol(igrid,nxif1,nxif2,xif1,xif2,dxif1,dxif2,fl,euvs,dpls)
2941 enddo
2942 numsi=nxif1*nxif2
2943 call mpi_allreduce(euvs,euv,numsi,mpi_double_precision, &
2944 mpi_sum,icomm,ierrmpi)
2945 call mpi_allreduce(dpls,dpl,numsi,mpi_double_precision, &
2946 mpi_sum,icomm,ierrmpi)
2947 endif
2948 if (has_doppler_output) then
2949 where(euv<smalldouble) euv=zero
2950 call normalize_euv_doppler(nxif1,nxif2,euv,dpl,unitv)
2951 endif
2952 deallocate(euvs,dpls)
2953 endif
2954 if (has_thick_output) then
2955 if (has_doppler_output) then
2956 call pack_euv_image_outputs(nxif1,nxif2,euv,wi,smalldouble,has_doppler_output,&
2957 has_thick_output,dpl=dpl,tau=tau,euvthin=euvthin)
2958 else
2959 call pack_euv_image_outputs(nxif1,nxif2,euv,wi,smalldouble,has_doppler_output,&
2960 has_thick_output,tau=tau,euvthin=euvthin)
2961 endif
2962 else if (has_doppler_output) then
2963 call pack_euv_image_outputs(nxif1,nxif2,euv,wi,smalldouble,has_doppler_output,&
2964 has_thick_output,dpl=dpl)
2965 else
2966 call pack_euv_image_outputs(nxif1,nxif2,euv,wi,smalldouble,has_doppler_output,&
2967 has_thick_output)
2968 endif
2969
2970 if (instrument_postprocess) then
2971 if (trim(emission_model)=='radio_ff') then
2972 if (trim(radiation_transfer)=='thick') then
2973 call postprocess_radio_beam_image(nxif1,nxif2,xif1,xif2,dxif1,dxif2,&
2974 euv,nxip1,nxip2,xip1,xip2,&
2975 dxip1,dxip2,wip,numwip,tau=tau,brightthin=euvthin)
2976 else
2977 call postprocess_radio_beam_image(nxif1,nxif2,xif1,xif2,dxif1,dxif2,&
2978 euv,nxip1,nxip2,xip1,xip2,&
2979 dxip1,dxip2,wip,numwip)
2980 endif
2981 else if (trim(radiation_transfer)=='thick') then
2982 call postprocess_euv_instrument_image(nxif1,nxif2,xif1,xif2,dxif1,dxif2,&
2983 euv,dpl,nxip1,nxip2,xip1,xip2,&
2984 dxip1,dxip2,wip,numwip,tau=tau,euvthin=euvthin)
2985 else
2986 call postprocess_euv_instrument_image(nxif1,nxif2,xif1,xif2,dxif1,dxif2,&
2987 euv,dpl,nxip1,nxip2,xip1,xip2,&
2988 dxip1,dxip2,wip,numwip)
2989 endif
2990 call output_data(qunit,xip1,xip2,dxip1,dxip2,wip,nxip1,nxip2,numwip,datatype)
2991 deallocate(xip1,xip2,dxip1,dxip2,wip)
2992 else
2993 call output_data(qunit,xif1,xif2,dxif1,dxif2,wi,nxif1,nxif2,numwi,datatype)
2994 endif
2995 if (trim(radiation_transfer)=='thick') then
2996 deallocate(wi,euv,dpl,euvthin,tau)
2997 else
2998 deallocate(wi,euv,dpl)
2999 endif
3000 endif
3001
3002 ! integrate SXR flux and get cell average flux for image
3003 if (datatype=='image_sxr') then
3004 if (si_unit) then
3005 arcsec=7.25d5
3006 else
3007 arcsec=7.25d7
3008 endif
3009 rhessi_rsl=2.3d0/instrument_resolution_factor
3010 numwi=1
3011 allocate(wi(nxif1,nxif2,numwi))
3012 allocate(sxrs(nxif1,nxif2),sxr(nxif1,nxif2))
3013 sxrs=0.0d0
3014 sxr=0.0d0
3015 do iigrid=1,igridstail; igrid=igrids(iigrid);
3016 call integrate_sxr_datresol(igrid,nxif1,nxif2,xif1,xif2,dxif1,dxif2,fl,sxrs)
3017 enddo
3018 numsi=nxif1*nxif2
3019 call mpi_allreduce(sxrs,sxr,numsi,mpi_double_precision, &
3020 mpi_sum,icomm,ierrmpi)
3021
3022 sxr=sxr*(rhessi_rsl*arcsec)**2 ! photons cm^-2 s^-1 pixel^-1
3023 do ix1=1,nxif1
3024 do ix2=1,nxif2
3025 if (sxr(ix1,ix2)<smalldouble) sxr(ix1,ix2)=zero
3026 enddo
3027 enddo
3028 wi(:,:,1)=sxr(:,:)
3029
3030 call output_data(qunit,xif1,xif2,dxif1,dxif2,wi,nxif1,nxif2,numwi,datatype)
3031 deallocate(wi,sxr,sxrs)
3032 endif
3033
3034 deallocate(xif1,xif2,dxif1,dxif2)
3035
3036 end subroutine get_image_datresol
3037
3038 subroutine integrate_sxr_datresol(igrid,nXIF1,nXIF2,xIF1,xIF2,dxIF1,dxIF2,fl,SXR)
3040
3041 integer, intent(in) :: igrid,nXIF1,nXIF2
3042 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3043 double precision, intent(in) :: dxIF1(nXIF1),dxIF2(nXIF2)
3044 type(te_fluid), intent(in) :: fl
3045 double precision, intent(out) :: SXR(nXIF1,nXIF2)
3046
3047 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
3048 double precision :: xb^L,xd^D
3049 double precision, allocatable :: flux(:^D&),opacity(:^D&)
3050 double precision, allocatable :: dxb1(:^D&),dxb2(:^D&),dxb3(:^D&)
3051 double precision, allocatable :: SXRg(:,:),xg1(:),xg2(:),dxg1(:),dxg2(:)
3052 integer :: levelg,nXg1,nXg2,iXgmin1,iXgmax1,iXgmin2,iXgmax2,rft,iXg^D
3053 double precision :: SXRt,xc^L,xg^L,r2,area_1AU
3054 integer :: ixP^L,ixP^D
3055 integer :: direction_LOS
3056
3057 if (los_phi==0 .and. los_theta==90) then
3058 direction_los=1
3059 else if (los_phi==90 .and. los_theta==90) then
3060 direction_los=2
3061 else
3062 direction_los=3
3063 endif
3064
3065 ^d&ixomin^d=ixmlo^d\
3066 ^d&ixomax^d=ixmhi^d\
3067 ^d&iximin^d=ixglo^d\
3068 ^d&iximax^d=ixghi^d\
3069 ^d&xbmin^d=rnode(rpxmin^d_,igrid)\
3070 ^d&xbmax^d=rnode(rpxmax^d_,igrid)\
3071
3072 allocate(flux(ixi^s))
3073 allocate(dxb1(ixi^s),dxb2(ixi^s),dxb3(ixi^s))
3074 dxb1(ixo^s)=ps(igrid)%dx(ixo^s,1)
3075 dxb2(ixo^s)=ps(igrid)%dx(ixo^s,2)
3076 dxb3(ixo^s)=ps(igrid)%dx(ixo^s,3)
3077 ! get local SXR flux
3078 call get_sxr(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,emin_sxr,emax_sxr)
3079
3080 ! grid parameters
3081 levelg=ps(igrid)%level
3082 rft=2**(refine_max_level-levelg)
3083
3084 ! fine table for storing EUV flux of current grid
3085 select case(direction_los)
3086 case(1)
3087 nxg1=iximax2*rft
3088 nxg2=iximax3*rft
3089 case(2)
3090 nxg1=iximax3*rft
3091 nxg2=iximax1*rft
3092 case(3)
3093 nxg1=iximax1*rft
3094 nxg2=iximax2*rft
3095 end select
3096 allocate(sxrg(nxg1,nxg2),xg1(nxg1),xg2(nxg2),dxg1(nxg1),dxg2(nxg2))
3097 sxrg=zero
3098 xg1=zero
3099 xg2=zero
3100
3101 ! integrate for different direction
3102 select case(direction_los)
3103 case(1)
3104 do ix2=ixomin2,ixomax2
3105 ixgmin1=(ix2-1)*rft+1
3106 ixgmax1=ix2*rft
3107 do ix3=ixomin3,ixomax3
3108 ixgmin2=(ix3-1)*rft+1
3109 ixgmax2=ix3*rft
3110 sxrt=0.d0
3111 do ix1=ixomin1,ixomax1
3112 sxrt=sxrt+flux(ix^d)*dxb1(ix^d)*unit_length
3113 enddo
3114 sxrg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=sxrt
3115 enddo
3116 enddo
3117 case(2)
3118 do ix3=ixomin3,ixomax3
3119 ixgmin1=(ix3-1)*rft+1
3120 ixgmax1=ix3*rft
3121 do ix1=ixomin1,ixomax1
3122 ixgmin2=(ix1-1)*rft+1
3123 ixgmax2=ix1*rft
3124 sxrt=0.d0
3125 do ix2=ixomin2,ixomax2
3126 sxrt=sxrt+flux(ix^d)*dxb2(ix^d)*unit_length
3127 enddo
3128 sxrg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=sxrt
3129 enddo
3130 enddo
3131 case(3)
3132 do ix1=ixomin1,ixomax1
3133 ixgmin1=(ix1-1)*rft+1
3134 ixgmax1=ix1*rft
3135 do ix2=ixomin2,ixomax2
3136 ixgmin2=(ix2-1)*rft+1
3137 ixgmax2=ix2*rft
3138 sxrt=0.d0
3139 do ix3=ixomin3,ixomax3
3140 sxrt=sxrt+flux(ix^d)*dxb3(ix^d)*unit_length
3141 enddo
3142 sxrg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=sxrt
3143 enddo
3144 enddo
3145 end select
3146
3147 area_1au=2.81d27
3148 sxrg=sxrg/area_1au
3149
3150 ! mapping grid data to global table
3151 ! index ranges in local table
3152 select case(direction_los)
3153 case(1)
3154 ixgmin1=(ixomin2-1)*rft+1
3155 ixgmax1=ixomax2*rft
3156 ixgmin2=(ixomin3-1)*rft+1
3157 ixgmax2=ixomax3*rft
3158 case(2)
3159 ixgmin1=(ixomin3-1)*rft+1
3160 ixgmax1=ixomax3*rft
3161 ixgmin2=(ixomin1-1)*rft+1
3162 ixgmax2=ixomax1*rft
3163 case(3)
3164 ixgmin1=(ixomin1-1)*rft+1
3165 ixgmax1=ixomax1*rft
3166 ixgmin2=(ixomin2-1)*rft+1
3167 ixgmax2=ixomax2*rft
3168 end select
3169 ! index ranges in global table & mapping
3170 select case(direction_los)
3171 case(1)
3172 ixpmin1=(node(pig2_,igrid)-1)*rft*block_nx2+1
3173 ixpmax1=node(pig2_,igrid)*rft*block_nx2
3174 ixpmin2=(node(pig3_,igrid)-1)*rft*block_nx3+1
3175 ixpmax2=node(pig3_,igrid)*rft*block_nx3
3176 case(2)
3177 ixpmin1=(node(pig3_,igrid)-1)*rft*block_nx3+1
3178 ixpmax1=node(pig3_,igrid)*rft*block_nx3
3179 ixpmin2=(node(pig1_,igrid)-1)*rft*block_nx1+1
3180 ixpmax2=node(pig1_,igrid)*rft*block_nx1
3181 case(3)
3182 ixpmin1=(node(pig1_,igrid)-1)*rft*block_nx1+1
3183 ixpmax1=node(pig1_,igrid)*rft*block_nx1
3184 ixpmin2=(node(pig2_,igrid)-1)*rft*block_nx2+1
3185 ixpmax2=node(pig2_,igrid)*rft*block_nx2
3186 end select
3187 xg1(ixgmin1:ixgmax1)=xif1(ixpmin1:ixpmax1)
3188 xg2(ixgmin2:ixgmax2)=xif2(ixpmin2:ixpmax2)
3189 dxg1(ixgmin1:ixgmax1)=dxif1(ixpmin1:ixpmax1)
3190 dxg2(ixgmin2:ixgmax2)=dxif2(ixpmin2:ixpmax2)
3191 sxr(ixpmin1:ixpmax1,ixpmin2:ixpmax2)=sxr(ixpmin1:ixpmax1,ixpmin2:ixpmax2)+&
3192 sxrg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)
3193
3194 deallocate(flux,dxb1,dxb2,dxb3,sxrg,xg1,xg2,dxg1,dxg2)
3195
3196 end subroutine integrate_sxr_datresol
3197
3198 subroutine integrate_euv_datresol(igrid,nXIF1,nXIF2,xIF1,xIF2,dxIF1,dxIF2,fl,EUV,Dpl)
3200
3201 integer, intent(in) :: igrid,nXIF1,nXIF2
3202 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3203 double precision, intent(in) :: dxIF1(nXIF1),dxIF2(nXIF2)
3204 type(te_fluid), intent(in) :: fl
3205 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
3206
3207 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
3208 double precision :: xb^L,xd^D
3209 double precision, allocatable :: flux(:^D&),v(:^D&),rho(:^D&),opacity(:^D&)
3210 double precision, allocatable :: dxb1(:^D&),dxb2(:^D&),dxb3(:^D&)
3211 double precision, allocatable :: EUVg(:,:),Fvg(:,:),xg1(:),xg2(:),dxg1(:),dxg2(:)
3212 integer :: levelg,nXg1,nXg2,iXgmin1,iXgmax1,iXgmin2,iXgmax2,rft,iXg^D
3213 double precision :: EUVt,Fvt,xc^L,xg^L,r2
3214 integer :: ixP^L,ixP^D
3215 integer :: direction_LOS
3216
3217 if (los_phi==0 .and. los_theta==90) then
3218 direction_los=1
3219 else if (los_phi==90 .and. los_theta==90) then
3220 direction_los=2
3221 else
3222 direction_los=3
3223 endif
3224
3225 ^d&ixomin^d=ixmlo^d\
3226 ^d&ixomax^d=ixmhi^d\
3227 ^d&iximin^d=ixglo^d\
3228 ^d&iximax^d=ixghi^d\
3229 ^d&xbmin^d=rnode(rpxmin^d_,igrid)\
3230 ^d&xbmax^d=rnode(rpxmax^d_,igrid)\
3231
3232 allocate(flux(ixi^s),v(ixi^s),rho(ixi^s),opacity(ixi^s))
3233 allocate(dxb1(ixi^s),dxb2(ixi^s),dxb3(ixi^s))
3234 dxb1(ixo^s)=ps(igrid)%dx(ixo^s,1)
3235 dxb2(ixo^s)=ps(igrid)%dx(ixo^s,2)
3236 dxb3(ixo^s)=ps(igrid)%dx(ixo^s,3)
3237 if (trim(emission_model)=='pseudo_current') then
3238 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,flux)
3239 v(ixo^s)=zero
3240 deallocate(rho)
3241 else if (trim(emission_model)=='radio_ff') then
3242 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,opacity)
3243 v(ixo^s)=zero
3244 deallocate(rho)
3245 else
3246 ! get local EUV flux and velocity
3247 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
3248 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
3249 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
3250 v(ixo^s)=-ps(igrid)%w(ixo^s,iw_mom(direction_los))/rho(ixo^s)
3251 deallocate(rho)
3252 endif
3253
3254 ! grid parameters
3255 levelg=ps(igrid)%level
3256 rft=2**(refine_max_level-levelg)
3257
3258 ! fine table for storing EUV flux of current grid
3259 select case(direction_los)
3260 case(1)
3261 nxg1=iximax2*rft
3262 nxg2=iximax3*rft
3263 case(2)
3264 nxg1=iximax3*rft
3265 nxg2=iximax1*rft
3266 case(3)
3267 nxg1=iximax1*rft
3268 nxg2=iximax2*rft
3269 end select
3270 allocate(euvg(nxg1,nxg2),fvg(nxg1,nxg2),xg1(nxg1),xg2(nxg2),dxg1(nxg1),dxg2(nxg2))
3271 euvg=zero
3272 fvg=zero
3273 xg1=zero
3274 xg2=zero
3275
3276 ! integrate for different direction
3277 select case(direction_los)
3278 case(1)
3279 do ix2=ixomin2,ixomax2
3280 ixgmin1=(ix2-1)*rft+1
3281 ixgmax1=ix2*rft
3282 do ix3=ixomin3,ixomax3
3283 ixgmin2=(ix3-1)*rft+1
3284 ixgmax2=ix3*rft
3285 euvt=0.d0
3286 fvt=0.d0
3287 do ix1=ixomin1,ixomax1
3288 euvt=euvt+flux(ix^d)*dxb1(ix^d)*unit_length
3289 fvt=fvt+flux(ix^d)*dxb1(ix^d)*unit_length*v(ix^d)
3290 enddo
3291 euvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=euvt
3292 fvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=fvt
3293 enddo
3294 enddo
3295 case(2)
3296 do ix3=ixomin3,ixomax3
3297 ixgmin1=(ix3-1)*rft+1
3298 ixgmax1=ix3*rft
3299 do ix1=ixomin1,ixomax1
3300 ixgmin2=(ix1-1)*rft+1
3301 ixgmax2=ix1*rft
3302 euvt=0.d0
3303 fvt=0.d0
3304 do ix2=ixomin2,ixomax2
3305 euvt=euvt+flux(ix^d)*dxb2(ix^d)*unit_length
3306 fvt=fvt+flux(ix^d)*dxb2(ix^d)*unit_length*v(ix^d)
3307 enddo
3308 euvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=euvt
3309 fvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=fvt
3310 enddo
3311 enddo
3312 case(3)
3313 do ix1=ixomin1,ixomax1
3314 ixgmin1=(ix1-1)*rft+1
3315 ixgmax1=ix1*rft
3316 do ix2=ixomin2,ixomax2
3317 ixgmin2=(ix2-1)*rft+1
3318 ixgmax2=ix2*rft
3319 euvt=0.d0
3320 fvt=0.d0
3321 do ix3=ixomin3,ixomax3
3322 euvt=euvt+flux(ix^d)*dxb3(ix^d)*unit_length
3323 fvt=fvt+flux(ix^d)*dxb3(ix^d)*unit_length*v(ix^d)
3324 enddo
3325 euvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=euvt
3326 fvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)=fvt
3327 enddo
3328 enddo
3329 end select
3330 if (si_unit) then
3331 euvg=euvg*1.d2
3332 fvg=fvg*1.d2
3333 endif
3334
3335 ! mapping grid data to global table
3336 ! index ranges in local table
3337 select case(direction_los)
3338 case(1)
3339 ixgmin1=(ixomin2-1)*rft+1
3340 ixgmax1=ixomax2*rft
3341 ixgmin2=(ixomin3-1)*rft+1
3342 ixgmax2=ixomax3*rft
3343 case(2)
3344 ixgmin1=(ixomin3-1)*rft+1
3345 ixgmax1=ixomax3*rft
3346 ixgmin2=(ixomin1-1)*rft+1
3347 ixgmax2=ixomax1*rft
3348 case(3)
3349 ixgmin1=(ixomin1-1)*rft+1
3350 ixgmax1=ixomax1*rft
3351 ixgmin2=(ixomin2-1)*rft+1
3352 ixgmax2=ixomax2*rft
3353 end select
3354 ! index ranges in global table & mapping
3355 select case(direction_los)
3356 case(1)
3357 ixpmin1=(node(pig2_,igrid)-1)*rft*block_nx2+1
3358 ixpmax1=node(pig2_,igrid)*rft*block_nx2
3359 ixpmin2=(node(pig3_,igrid)-1)*rft*block_nx3+1
3360 ixpmax2=node(pig3_,igrid)*rft*block_nx3
3361 case(2)
3362 ixpmin1=(node(pig3_,igrid)-1)*rft*block_nx3+1
3363 ixpmax1=node(pig3_,igrid)*rft*block_nx3
3364 ixpmin2=(node(pig1_,igrid)-1)*rft*block_nx1+1
3365 ixpmax2=node(pig1_,igrid)*rft*block_nx1
3366 case(3)
3367 ixpmin1=(node(pig1_,igrid)-1)*rft*block_nx1+1
3368 ixpmax1=node(pig1_,igrid)*rft*block_nx1
3369 ixpmin2=(node(pig2_,igrid)-1)*rft*block_nx2+1
3370 ixpmax2=node(pig2_,igrid)*rft*block_nx2
3371 end select
3372 xg1(ixgmin1:ixgmax1)=xif1(ixpmin1:ixpmax1)
3373 xg2(ixgmin2:ixgmax2)=xif2(ixpmin2:ixpmax2)
3374 dxg1(ixgmin1:ixgmax1)=dxif1(ixpmin1:ixpmax1)
3375 dxg2(ixgmin2:ixgmax2)=dxif2(ixpmin2:ixpmax2)
3376 euv(ixpmin1:ixpmax1,ixpmin2:ixpmax2)=euv(ixpmin1:ixpmax1,ixpmin2:ixpmax2)+&
3377 euvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)
3378 dpl(ixpmin1:ixpmax1,ixpmin2:ixpmax2)=dpl(ixpmin1:ixpmax1,ixpmin2:ixpmax2)+&
3379 fvg(ixgmin1:ixgmax1,ixgmin2:ixgmax2)
3380
3381 deallocate(flux,v,opacity,dxb1,dxb2,dxb3,euvg,fvg,xg1,xg2,dxg1,dxg2)
3382
3383 end subroutine integrate_euv_datresol
3384
3385 }
3386
3387 {^ifthreed
3388
3389 subroutine ray_box_intersection_cart(ray_origin,ray_dir,box_min,box_max,hit,t_enter,t_exit)
3390 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),box_min(1:3),box_max(1:3)
3391 logical, intent(out) :: hit
3392 double precision, intent(out) :: t_enter,t_exit
3393
3394 integer :: idir
3395 double precision :: t1,t2,td
3396
3397 hit=.true.
3398 t_enter=-huge(one)
3399 t_exit=huge(one)
3400 do idir=1,3
3401 if (abs(ray_dir(idir))<=smalldouble) then
3402 if (ray_origin(idir)<box_min(idir) .or. ray_origin(idir)>box_max(idir)) then
3403 hit=.false.
3404 return
3405 endif
3406 else
3407 t1=(box_min(idir)-ray_origin(idir))/ray_dir(idir)
3408 t2=(box_max(idir)-ray_origin(idir))/ray_dir(idir)
3409 if (t1>t2) then
3410 td=t1
3411 t1=t2
3412 t2=td
3413 endif
3414 t_enter=max(t_enter,t1)
3415 t_exit=min(t_exit,t2)
3416 if (t_enter>=t_exit) then
3417 hit=.false.
3418 return
3419 endif
3420 endif
3421 enddo
3422 end subroutine ray_box_intersection_cart
3423
3424 subroutine build_cart_dda_faces(ixI^L,ixO^L,x,dx,xface1,xface2,xface3)
3425 ! Slice state%dx to ixI at call sites: CT/odd ghost cells extend its
3426 ! allocation beyond state%x; the explicit-shape dummy uses ixI strides.
3427 integer, intent(in) :: ixI^L, ixO^L
3428 double precision, intent(in) :: x(ixI^S,1:ndim),dx(ixI^S,1:ndim)
3429 double precision, allocatable, intent(out) :: xface1(:),xface2(:),xface3(:)
3430
3431 integer :: ix^D
3432
3433 allocate(xface1(ixomin1:ixomax1+1),xface2(ixomin2:ixomax2+1),xface3(ixomin3:ixomax3+1))
3434
3435 ix2=ixomin2
3436 ix3=ixomin3
3437 do ix1=ixomin1,ixomax1
3438 xface1(ix1)=x(ix^d,1)-half*dx(ix^d,1)
3439 enddo
3440 xface1(ixomax1+1)=x(ixomax1,ixomin2,ixomin3,1)+half*dx(ixomax1,ixomin2,ixomin3,1)
3441
3442 ix1=ixomin1
3443 ix3=ixomin3
3444 do ix2=ixomin2,ixomax2
3445 xface2(ix2)=x(ix^d,2)-half*dx(ix^d,2)
3446 enddo
3447 xface2(ixomax2+1)=x(ixomin1,ixomax2,ixomin3,2)+half*dx(ixomin1,ixomax2,ixomin3,2)
3448
3449 ix1=ixomin1
3450 ix2=ixomin2
3451 do ix3=ixomin3,ixomax3
3452 xface3(ix3)=x(ix^d,3)-half*dx(ix^d,3)
3453 enddo
3454 xface3(ixomax3+1)=x(ixomin1,ixomin2,ixomax3,3)+half*dx(ixomin1,ixomin2,ixomax3,3)
3455 end subroutine build_cart_dda_faces
3456
3457 integer function cart_dda_locate_index(pos,faces,imin,imax) result(idx)
3458 integer, intent(in) :: imin,imax
3459 double precision, intent(in) :: pos,faces(imin:imax+1)
3460
3461 integer :: ilo,ihi,imid
3462
3463 if (pos<=faces(imin)) then
3464 idx=imin
3465 return
3466 endif
3467 if (pos>=faces(imax+1)) then
3468 idx=imax
3469 return
3470 endif
3471
3472 ilo=imin
3473 ihi=imax+1
3474 do while (ihi-ilo>1)
3475 imid=(ilo+ihi)/2
3476 if (pos>=faces(imid)) then
3477 ilo=imid
3478 else
3479 ihi=imid
3480 endif
3481 enddo
3482 idx=min(imax,max(imin,ilo))
3483 end function cart_dda_locate_index
3484
3485 subroutine cart_dda_init_axis(ray_origin_axis,ray_dir_axis,faces,imin,imax,idx,step,tMax)
3486 integer, intent(in) :: imin,imax,idx
3487 double precision, intent(in) :: ray_origin_axis,ray_dir_axis,faces(imin:imax+1)
3488 integer, intent(out) :: step
3489 double precision, intent(out) :: tMax
3490
3491 if (ray_dir_axis>zero) then
3492 step=1
3493 tmax=(faces(idx+1)-ray_origin_axis)/ray_dir_axis
3494 else if (ray_dir_axis<zero) then
3495 step=-1
3496 tmax=(faces(idx)-ray_origin_axis)/ray_dir_axis
3497 else
3498 step=0
3499 tmax=huge(one)
3500 endif
3501 end subroutine cart_dda_init_axis
3502
3503 subroutine cart_dda_advance_axis(ray_origin_axis,ray_dir_axis,faces,imin,imax,idx,step,tMax,done)
3504 integer, intent(in) :: imin,imax,step
3505 double precision, intent(in) :: ray_origin_axis,ray_dir_axis,faces(imin:imax+1)
3506 integer, intent(inout) :: idx
3507 double precision, intent(inout) :: tMax
3508 logical, intent(out) :: done
3509
3510 done=.false.
3511 idx=idx+step
3512 if (idx<imin .or. idx>imax) then
3513 done=.true.
3514 return
3515 endif
3516 if (step>0) then
3517 tmax=(faces(idx+1)-ray_origin_axis)/ray_dir_axis
3518 else if (step<0) then
3519 tmax=(faces(idx)-ray_origin_axis)/ray_dir_axis
3520 else
3521 tmax=huge(one)
3522 endif
3523 end subroutine cart_dda_advance_axis
3524
3525 subroutine acc_euv_cart_dda(ixI^L,ixO^L,source,sourcev,&
3526 ray_origin,xface1,xface2,xface3,t_enter,t_exit,EUVp,Dplp)
3527 integer, intent(in) :: ixI^L, ixO^L
3528 double precision, intent(in) :: source(ixI^S),sourcev(ixI^S)
3529 double precision, intent(in) :: ray_origin(1:3)
3530 double precision, intent(in) :: xface1(ixOmin1:ixOmax1+1),xface2(ixOmin2:ixOmax2+1),&
3531 xface3(ixOmin3:ixOmax3+1)
3532 double precision, intent(in) :: t_enter,t_exit
3533 double precision, intent(inout) :: EUVp,Dplp
3534
3535 integer :: ix^D,step(1:3)
3536 double precision :: pos(1:3),tMax(1:3),tNow,tNext,ds_cm,epsRay
3537 logical :: done
3538
3539 if (t_exit<=t_enter) return
3540 epsray=max(1.d-12,1.d-10*abs(t_exit-t_enter))
3541 pos=ray_origin+(t_enter+epsray)*vec_los
3542 ix1=cart_dda_locate_index(pos(1),xface1,ixomin1,ixomax1)
3543 ix2=cart_dda_locate_index(pos(2),xface2,ixomin2,ixomax2)
3544 ix3=cart_dda_locate_index(pos(3),xface3,ixomin3,ixomax3)
3545
3546 call cart_dda_init_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1))
3547 call cart_dda_init_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2))
3548 call cart_dda_init_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3))
3549
3550 tnow=t_enter
3551 do
3552 tnext=min(t_exit,tmax(1),tmax(2),tmax(3))
3553 if (tnext>tnow) then
3554 ds_cm=(tnext-tnow)*unit_length
3555 if (si_unit) ds_cm=ds_cm*1.d2
3556 euvp=euvp+source(ix^d)*ds_cm
3557 dplp=dplp+sourcev(ix^d)*ds_cm
3558 endif
3559 tnow=tnext
3560 if (tnow>=t_exit-epsray) exit
3561
3562 if (tmax(1)<=tnow+epsray) then
3563 call cart_dda_advance_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1),done)
3564 if (done) exit
3565 endif
3566 if (tmax(2)<=tnow+epsray) then
3567 call cart_dda_advance_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2),done)
3568 if (done) exit
3569 endif
3570 if (tmax(3)<=tnow+epsray) then
3571 call cart_dda_advance_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3),done)
3572 if (done) exit
3573 endif
3574 enddo
3575 end subroutine acc_euv_cart_dda
3576
3577 subroutine append_cart_dda_segment(segments,nseg,capacity,pixel_id,tseg,jds,kds,jvds)
3578 double precision, allocatable, intent(inout) :: segments(:,:)
3579 integer, intent(inout) :: nseg,capacity
3580 integer, intent(in) :: pixel_id
3581 double precision, intent(in) :: tseg,jds,kds,jvds
3582
3583 double precision, allocatable :: tmp(:,:)
3584 integer :: new_capacity
3585
3586 if (capacity<=0) then
3587 capacity=1024
3588 allocate(segments(5,capacity))
3589 else if (nseg>=capacity) then
3590 new_capacity=2*capacity
3591 allocate(tmp(5,new_capacity))
3592 tmp(:,1:capacity)=segments(:,1:capacity)
3593 call move_alloc(tmp,segments)
3594 capacity=new_capacity
3595 endif
3596
3597 nseg=nseg+1
3598 segments(1,nseg)=dble(pixel_id)
3599 segments(2,nseg)=tseg
3600 segments(3,nseg)=jds
3601 segments(4,nseg)=kds
3602 segments(5,nseg)=jvds
3603 end subroutine append_cart_dda_segment
3604
3605 subroutine collect_euv_cart_dda_segments(ixI^L,ixO^L,source,opacity,sourcev,&
3606 pixel_id,ray_origin,xface1,xface2,xface3,t_enter,t_exit,&
3607 segments,nseg,capacity)
3608 integer, intent(in) :: ixI^L, ixO^L
3609 double precision, intent(in) :: source(ixI^S),opacity(ixI^S),sourcev(ixI^S)
3610 integer, intent(in) :: pixel_id
3611 double precision, intent(in) :: ray_origin(1:3)
3612 double precision, intent(in) :: xface1(ixOmin1:ixOmax1+1),xface2(ixOmin2:ixOmax2+1),&
3613 xface3(ixOmin3:ixOmax3+1)
3614 double precision, intent(in) :: t_enter,t_exit
3615 double precision, allocatable, intent(inout) :: segments(:,:)
3616 integer, intent(inout) :: nseg,capacity
3617
3618 integer :: ix^D,step(1:3)
3619 double precision :: pos(1:3),tMax(1:3),tNow,tNext,ds_cm,epsRay,tseg
3620 double precision :: jds,kds,jvds
3621 logical :: done
3622
3623 if (t_exit<=t_enter) return
3624 epsray=max(1.d-12,1.d-10*abs(t_exit-t_enter))
3625 pos=ray_origin+(t_enter+epsray)*vec_los
3626 ix1=cart_dda_locate_index(pos(1),xface1,ixomin1,ixomax1)
3627 ix2=cart_dda_locate_index(pos(2),xface2,ixomin2,ixomax2)
3628 ix3=cart_dda_locate_index(pos(3),xface3,ixomin3,ixomax3)
3629
3630 call cart_dda_init_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1))
3631 call cart_dda_init_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2))
3632 call cart_dda_init_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3))
3633
3634 tnow=t_enter
3635 do
3636 tnext=min(t_exit,tmax(1),tmax(2),tmax(3))
3637 if (tnext>tnow) then
3638 ds_cm=(tnext-tnow)*unit_length
3639 if (si_unit) ds_cm=ds_cm*1.d2
3640 jds=source(ix^d)*ds_cm
3641 kds=opacity(ix^d)*ds_cm
3642 jvds=sourcev(ix^d)*ds_cm
3643 if (jds/=zero .or. kds/=zero .or. jvds/=zero) then
3644 tseg=half*(tnow+tnext)
3645 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tseg,jds,kds,jvds)
3646 endif
3647 endif
3648 tnow=tnext
3649 if (tnow>=t_exit-epsray) exit
3650
3651 if (tmax(1)<=tnow+epsray) then
3652 call cart_dda_advance_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1),done)
3653 if (done) exit
3654 endif
3655 if (tmax(2)<=tnow+epsray) then
3656 call cart_dda_advance_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2),done)
3657 if (done) exit
3658 endif
3659 if (tmax(3)<=tnow+epsray) then
3660 call cart_dda_advance_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3),done)
3661 if (done) exit
3662 endif
3663 enddo
3664 end subroutine collect_euv_cart_dda_segments
3665
3666 subroutine sort_segment_indices_near_to_far(segments,idx,nidx)
3667 double precision, intent(in) :: segments(:,:)
3668 integer, intent(inout) :: idx(:)
3669 integer, intent(in) :: nidx
3670
3671 if (nidx<=1) return
3672 if (nidx<=32) then
3673 call insertion_sort_segment_indices(segments,idx,1,nidx)
3674 else
3675 call quicksort_segment_indices(segments,idx,1,nidx)
3676 endif
3678
3679 subroutine insertion_sort_segment_indices(segments,idx,ilo,ihi)
3680 double precision, intent(in) :: segments(:,:)
3681 integer, intent(inout) :: idx(:)
3682 integer, intent(in) :: ilo,ihi
3683
3684 integer :: i,j,key
3685
3686 do i=ilo+1,ihi
3687 key=idx(i)
3688 j=i-1
3689 do while (j>=ilo .and. segments(2,idx(j))>segments(2,key))
3690 idx(j+1)=idx(j)
3691 j=j-1
3692 enddo
3693 idx(j+1)=key
3694 enddo
3695 end subroutine insertion_sort_segment_indices
3696
3697 recursive subroutine quicksort_segment_indices(segments,idx,ilo,ihi)
3698 double precision, intent(in) :: segments(:,:)
3699 integer, intent(inout) :: idx(:)
3700 integer, intent(in) :: ilo,ihi
3701
3702 integer :: i,j,tmp
3703 double precision :: pivot
3704
3705 if (ihi-ilo<=32) then
3706 call insertion_sort_segment_indices(segments,idx,ilo,ihi)
3707 return
3708 endif
3709
3710 i=ilo
3711 j=ihi
3712 pivot=segments(2,idx((ilo+ihi)/2))
3713 do
3714 do while (segments(2,idx(i))<pivot)
3715 i=i+1
3716 enddo
3717 do while (segments(2,idx(j))>pivot)
3718 j=j-1
3719 enddo
3720 if (i<=j) then
3721 tmp=idx(i)
3722 idx(i)=idx(j)
3723 idx(j)=tmp
3724 i=i+1
3725 j=j-1
3726 endif
3727 if (i>j) exit
3728 enddo
3729
3730 if (ilo<j) call quicksort_segment_indices(segments,idx,ilo,j)
3731 if (i<ihi) call quicksort_segment_indices(segments,idx,i,ihi)
3732 end subroutine quicksort_segment_indices
3733
3734 integer function segment_pixel_owner(pixel_id) result(owner)
3735 integer, intent(in) :: pixel_id
3736
3737 owner=mod(pixel_id-1,npe)
3738 end function segment_pixel_owner
3739
3740 logical function segment_is_valid(segments,is,nvars) result(valid)
3741 double precision, intent(in) :: segments(:,:)
3742 integer, intent(in) :: is,nvars
3743
3744 integer :: iv
3745
3746 valid=.true.
3747 do iv=1,nvars
3748 if (segments(iv,is)/=segments(iv,is) .or. abs(segments(iv,is))>=1.d90) then
3749 valid=.false.
3750 return
3751 endif
3752 enddo
3753 end function segment_is_valid
3754
3755 subroutine cart_dda_block_pixel_range(box_min,box_max,nXIF1,nXIF2,xIF1,xIF2,ixPmin1,ixPmax1,ixPmin2,ixPmax2,has_pixels)
3756 double precision, intent(in) :: box_min(1:3),box_max(1:3)
3757 integer, intent(in) :: nXIF1,nXIF2
3758 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3759 integer, intent(out) :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
3760 logical, intent(out) :: has_pixels
3761
3762 integer :: i1,i2,i3
3763 double precision :: vec_cor(1:3),xI_cor(1:2)
3764 double precision :: xmin1,xmax1,xmin2,xmax2,dx1,dx2
3765
3766 do i1=1,2
3767 if (i1==1) vec_cor(1)=box_min(1)
3768 if (i1==2) vec_cor(1)=box_max(1)
3769 do i2=1,2
3770 if (i2==1) vec_cor(2)=box_min(2)
3771 if (i2==2) vec_cor(2)=box_max(2)
3772 do i3=1,2
3773 if (i3==1) vec_cor(3)=box_min(3)
3774 if (i3==2) vec_cor(3)=box_max(3)
3775 call get_cor_image(vec_cor,xi_cor)
3776 if (i1==1 .and. i2==1 .and. i3==1) then
3777 xmin1=xi_cor(1)
3778 xmax1=xi_cor(1)
3779 xmin2=xi_cor(2)
3780 xmax2=xi_cor(2)
3781 else
3782 xmin1=min(xmin1,xi_cor(1))
3783 xmax1=max(xmax1,xi_cor(1))
3784 xmin2=min(xmin2,xi_cor(2))
3785 xmax2=max(xmax2,xi_cor(2))
3786 endif
3787 enddo
3788 enddo
3789 enddo
3790
3791 if (nxif1>1) then
3792 dx1=abs(xif1(2)-xif1(1))
3793 else
3794 dx1=max(one,abs(xmax1-xmin1))
3795 endif
3796 if (nxif2>1) then
3797 dx2=abs(xif2(2)-xif2(1))
3798 else
3799 dx2=max(one,abs(xmax2-xmin2))
3800 endif
3801
3802 ixpmin1=max(1,floor((xmin1-xif1(1))/dx1)+1-1)
3803 ixpmax1=min(nxif1,ceiling((xmax1-xif1(1))/dx1)+1+1)
3804 ixpmin2=max(1,floor((xmin2-xif2(1))/dx2)+1-1)
3805 ixpmax2=min(nxif2,ceiling((xmax2-xif2(1))/dx2)+1+1)
3806 has_pixels=ixpmin1<=ixpmax1 .and. ixpmin2<=ixpmax2
3807 end subroutine cart_dda_block_pixel_range
3808
3809 subroutine integrate_euv_cart_dda_datresol(nXIF1,nXIF2,xIF1,xIF2,fl,EUV,Dpl)
3811
3812 integer, intent(in) :: nXIF1,nXIF2
3813 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3814 type(te_fluid), intent(in) :: fl
3815 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
3816
3817 integer :: ixO^L,ixO^D,ixI^L,ix^D
3818 integer :: iigrid,igrid,ixP1,ixP2,numSI,ixPmin1,ixPmax1,ixPmin2,ixPmax2
3819 double precision :: box_min(1:3),box_max(1:3),ray_origin(1:3)
3820 double precision :: t_enter,t_exit,vlos
3821 double precision :: profile_local(2),profile_global(2)
3822 logical :: hit,has_pixels
3823 double precision, allocatable :: source(:^D&),sourcev(:^D&),rho(:^D&),opacity(:^D&)
3824 double precision, allocatable :: xface1(:),xface2(:),xface3(:)
3825 double precision, allocatable :: EUVs(:,:),Dpls(:,:)
3826
3827 allocate(euvs(nxif1,nxif2),dpls(nxif1,nxif2))
3828 euvs=zero
3829 dpls=zero
3830 profile_local=zero
3831
3832 do iigrid=1,igridstail; igrid=igrids(iigrid);
3833 ^d&ixomin^d=ixmlo^d\
3834 ^d&ixomax^d=ixmhi^d\
3835 ^d&iximin^d=ixglo^d\
3836 ^d&iximax^d=ixghi^d\
3837
3838 box_min(1)=rnode(rpxmin1_,igrid)
3839 box_min(2)=rnode(rpxmin2_,igrid)
3840 box_min(3)=rnode(rpxmin3_,igrid)
3841 box_max(1)=rnode(rpxmax1_,igrid)
3842 box_max(2)=rnode(rpxmax2_,igrid)
3843 box_max(3)=rnode(rpxmax3_,igrid)
3844 call build_cart_dda_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx(ixi^s,1:ndim),&
3845 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(ixi^s,1:ndim),&
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 ! Slice state%dx to ixI at call sites: CT/odd ghost cells extend its
4437 ! allocation beyond state%x; the explicit-shape dummy uses ixI strides.
4438 integer, intent(in) :: ixI^L, ixO^L
4439 double precision, intent(in) :: x(ixI^S,1:ndim),dx(ixI^S,1:ndim)
4440 double precision, allocatable, intent(out) :: rface(:),thetaface(:),phiface(:)
4441 integer :: ix1,ix2,ix3
4442
4443 allocate(rface(ixomin1:ixomax1+1),thetaface(ixomin2:ixomax2+1),phiface(ixomin3:ixomax3+1))
4444 do ix1=ixomin1,ixomax1
4445 rface(ix1)=x(ix1,ixomin2,ixomin3,1)-half*dx(ix1,ixomin2,ixomin3,1)
4446 enddo
4447 rface(ixomax1+1)=x(ixomax1,ixomin2,ixomin3,1)+half*dx(ixomax1,ixomin2,ixomin3,1)
4448 do ix2=ixomin2,ixomax2
4449 thetaface(ix2)=x(ixomin1,ix2,ixomin3,2)-half*dx(ixomin1,ix2,ixomin3,2)
4450 enddo
4451 thetaface(ixomax2+1)=x(ixomin1,ixomax2,ixomin3,2)+half*dx(ixomin1,ixomax2,ixomin3,2)
4452 do ix3=ixomin3,ixomax3
4453 phiface(ix3)=x(ixomin1,ixomin2,ix3,3)-half*dx(ixomin1,ixomin2,ix3,3)
4454 enddo
4455 phiface(ixomax3+1)=x(ixomin1,ixomin2,ixomax3,3)+half*dx(ixomin1,ixomin2,ixomax3,3)
4456 end subroutine build_sph_intersection_faces
4457
4458 subroutine sph_add_t(tvals,nt,capacity,t)
4459 double precision, allocatable, intent(inout) :: tvals(:)
4460 integer, intent(inout) :: nt,capacity
4461 double precision, intent(in) :: t
4462
4463 double precision, allocatable :: tmp(:)
4464
4465 if (t /= t .or. abs(t)>1.d90) return
4466 if (.not. allocated(tvals)) then
4467 capacity=64
4468 allocate(tvals(capacity))
4469 else if (nt>=capacity) then
4470 allocate(tmp(capacity))
4471 tmp=tvals
4472 deallocate(tvals)
4473 allocate(tvals(2*capacity))
4474 tvals(1:capacity)=tmp
4475 deallocate(tmp)
4476 capacity=2*capacity
4477 endif
4478 nt=nt+1
4479 tvals(nt)=t
4480 end subroutine sph_add_t
4481
4482 subroutine sph_add_t_fixed(tvals,nt,t)
4483 double precision, intent(inout) :: tvals(:)
4484 integer, intent(inout) :: nt
4485 double precision, intent(in) :: t
4486
4487 if (t /= t .or. abs(t)>1.d90) return
4488 if (nt>=size(tvals)) return
4489 nt=nt+1
4490 tvals(nt)=t
4491 end subroutine sph_add_t_fixed
4492
4493 subroutine sph_sort_unique_t(tvals,nt)
4494 double precision, intent(inout) :: tvals(:)
4495 integer, intent(inout) :: nt
4496
4497 integer :: i,j,nout
4498 double precision :: key,epsT
4499
4500 if (nt<=1) return
4501 do i=2,nt
4502 key=tvals(i)
4503 j=i-1
4504 do while (j>=1 .and. tvals(j)>key)
4505 tvals(j+1)=tvals(j)
4506 j=j-1
4507 enddo
4508 tvals(j+1)=key
4509 enddo
4510 epst=max(1.d-12,1.d-10*max(one,abs(tvals(nt)-tvals(1))))
4511 nout=1
4512 do i=2,nt
4513 if (abs(tvals(i)-tvals(nout))>epst) then
4514 nout=nout+1
4515 tvals(nout)=tvals(i)
4516 endif
4517 enddo
4518 nt=nout
4519 end subroutine sph_sort_unique_t
4520
4521 subroutine sph_add_sphere_intersections(ray_origin,ray_dir,rface,tvals,nt,capacity)
4522 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),rface
4523 double precision, allocatable, intent(inout) :: tvals(:)
4524 integer, intent(inout) :: nt,capacity
4525
4526 double precision :: aa,bb,cc,disc,root
4527
4528 aa=sum(ray_dir**2)
4529 bb=2.d0*sum(ray_origin*ray_dir)
4530 cc=sum(ray_origin**2)-rface**2
4531 disc=bb**2-4.d0*aa*cc
4532 if (disc<zero) return
4533 root=sqrt(max(zero,disc))
4534 call sph_add_t(tvals,nt,capacity,(-bb-root)/(2.d0*aa))
4535 call sph_add_t(tvals,nt,capacity,(-bb+root)/(2.d0*aa))
4536 end subroutine sph_add_sphere_intersections
4537
4538 subroutine sph_add_theta_intersections(ray_origin,ray_dir,thetaface,tvals,nt,capacity)
4539 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),thetaface
4540 double precision, allocatable, intent(inout) :: tvals(:)
4541 integer, intent(inout) :: nt,capacity
4542
4543 double precision :: cth,aa,bb,cc,disc,root
4544
4545 cth=cos(thetaface)
4546 ! At the equator the cone equation degenerates to z**2=0. Solve the
4547 ! corresponding plane intersection directly to avoid losing its double
4548 ! root through roundoff in the quadratic discriminant.
4549 if (abs(cth)<1.d-12) then
4550 if (abs(ray_dir(3))>1.d-14) &
4551 call sph_add_t(tvals,nt,capacity,-ray_origin(3)/ray_dir(3))
4552 return
4553 endif
4554 aa=ray_dir(3)**2-cth**2*sum(ray_dir**2)
4555 bb=2.d0*(ray_origin(3)*ray_dir(3)-cth**2*sum(ray_origin*ray_dir))
4556 cc=ray_origin(3)**2-cth**2*sum(ray_origin**2)
4557 if (abs(aa)<1.d-14) then
4558 if (abs(bb)>1.d-14) call sph_add_t(tvals,nt,capacity,-cc/bb)
4559 return
4560 endif
4561 disc=bb**2-4.d0*aa*cc
4562 if (disc<zero) return
4563 root=sqrt(max(zero,disc))
4564 call sph_add_t(tvals,nt,capacity,(-bb-root)/(2.d0*aa))
4565 call sph_add_t(tvals,nt,capacity,(-bb+root)/(2.d0*aa))
4566 end subroutine sph_add_theta_intersections
4567
4568 subroutine sph_add_phi_intersection(ray_origin,ray_dir,phiface,tvals,nt,capacity)
4569 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),phiface
4570 double precision, allocatable, intent(inout) :: tvals(:)
4571 integer, intent(inout) :: nt,capacity
4572
4573 double precision :: normal(1:3),denom,numer
4574
4575 normal(1)=-sin(phiface)
4576 normal(2)=cos(phiface)
4577 normal(3)=zero
4578 denom=sum(normal*ray_dir)
4579 if (abs(denom)<1.d-14) return
4580 numer=sum(normal*ray_origin)
4581 call sph_add_t(tvals,nt,capacity,-numer/denom)
4582 end subroutine sph_add_phi_intersection
4583
4584 subroutine sph_cart_to_coord(pos,sph)
4585 double precision, intent(in) :: pos(1:3)
4586 double precision, intent(out) :: sph(1:3)
4587
4588 sph(1)=sqrt(sum(pos**2))
4589 if (sph(1)>zero) then
4590 sph(2)=acos(max(-one,min(one,pos(3)/sph(1))))
4591 else
4592 sph(2)=zero
4593 endif
4594 sph(3)=atan2(pos(2),pos(1))
4595 end subroutine sph_cart_to_coord
4596
4597 integer function sph_locate_index(value,faces,imin,imax) result(idx)
4598 integer, intent(in) :: imin,imax
4599 double precision, intent(in) :: value,faces(imin:imax+1)
4600
4601 integer :: ilo,ihi,imid
4602
4603 idx=0
4604 if (value<faces(imin)-1.d-12 .or. value>faces(imax+1)+1.d-12) return
4605 if (value<=faces(imin)) then
4606 idx=imin
4607 return
4608 endif
4609 if (value>=faces(imax+1)) then
4610 idx=imax
4611 return
4612 endif
4613
4614 ilo=imin
4615 ihi=imax+1
4616 do while (ihi-ilo>1)
4617 imid=(ilo+ihi)/2
4618 if (value>=faces(imid)) then
4619 ilo=imid
4620 else
4621 ihi=imid
4622 endif
4623 enddo
4624 idx=min(imax,max(imin,ilo))
4625 end function sph_locate_index
4626
4627 integer function sph_locate_index_desc(value,faces,imin,imax) result(idx)
4628 integer, intent(in) :: imin,imax
4629 double precision, intent(in) :: value,faces(imin:imax+1)
4630
4631 integer :: ilo,ihi,imid
4632
4633 idx=0
4634 if (value>faces(imin)+1.d-12 .or. value<faces(imax+1)-1.d-12) return
4635 if (value>=faces(imin)) then
4636 idx=imin
4637 return
4638 endif
4639 if (value<=faces(imax+1)) then
4640 idx=imax
4641 return
4642 endif
4643
4644 ilo=imin
4645 ihi=imax+1
4646 do while (ihi-ilo>1)
4647 imid=(ilo+ihi)/2
4648 if (value<=faces(imid)) then
4649 ilo=imid
4650 else
4651 ihi=imid
4652 endif
4653 enddo
4654 idx=min(imax,max(imin,ilo))
4655 end function sph_locate_index_desc
4656
4657 subroutine sph_locate_cell(pos,rface,thetaface,phiface,ixO^L,ix1,ix2,ix3,inside)
4658 double precision, intent(in) :: pos(1:3)
4659 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4660 phiface(ixOmin3:ixOmax3+1)
4661 integer, intent(in) :: ixO^L
4662 integer, intent(out) :: ix1,ix2,ix3
4663 logical, intent(out) :: inside
4664
4665 double precision :: sph(1:3),phi
4666
4667 call sph_cart_to_coord(pos,sph)
4668 phi=sph(3)
4669 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4670 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4671 ix1=sph_locate_index(sph(1),rface,ixomin1,ixomax1)
4672 ix2=sph_locate_index(sph(2),thetaface,ixomin2,ixomax2)
4673 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4674 inside=ix1>0 .and. ix2>0 .and. ix3>0
4675 end subroutine sph_locate_cell
4676
4677 logical function sph_segment_visible(pos,ximg1,ximg2) result(visible)
4678 use mod_constants
4679 double precision, intent(in) :: pos(1:3),ximg1,ximg2
4680
4681 double precision :: dotp,rc,rthick,rloc
4682
4683 rthick=r_opt_thick*const_rsun/unit_length
4684 rc=sqrt(ximg1**2+ximg2**2)
4685 rloc=sqrt(sum(pos**2))
4686 call dot_product_loc(vec_los,pos,dotp)
4687 visible=.true.
4688 if (dotp>=zero) then
4689 if (rc<=rthick) visible=.false.
4690 else
4691 if (rloc<=rthick) visible=.false.
4692 endif
4693 end function sph_segment_visible
4694
4695 subroutine sph_block_pixel_range(rface,thetaface,phiface,ixO^L,nXI1,nXI2,xI1,xI2,dxI,&
4696 ixPmin1,ixPmax1,ixPmin2,ixPmax2,has_pixels)
4697 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4698 phiface(ixOmin3:ixOmax3+1)
4699 integer, intent(in) :: ixO^L,nXI1,nXI2
4700 double precision, intent(in) :: xI1(nXI1),xI2(nXI2),dxI
4701 integer, intent(out) :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
4702 logical, intent(out) :: has_pixels
4703
4704 integer, parameter :: nsample=5
4705 integer :: ir,it,ip
4706 double precision :: sph(1:3),xcent(1:2)
4707 double precision :: xmin1,xmax1,xmin2,xmax2
4708 double precision :: wr,wt,wp,pad
4709
4710 has_pixels=.false.
4711 xmin1=huge(one)
4712 xmax1=-huge(one)
4713 xmin2=huge(one)
4714 xmax2=-huge(one)
4715 do ir=0,nsample-1
4716 wr=dble(ir)/dble(nsample-1)
4717 sph(1)=(one-wr)*rface(ixomin1)+wr*rface(ixomax1+1)
4718 do it=0,nsample-1
4719 wt=dble(it)/dble(nsample-1)
4720 sph(2)=(one-wt)*thetaface(ixomin2)+wt*thetaface(ixomax2+1)
4721 do ip=0,nsample-1
4722 wp=dble(ip)/dble(nsample-1)
4723 if (ir/=0 .and. ir/=nsample-1 .and. it/=0 .and. it/=nsample-1 .and. &
4724 ip/=0 .and. ip/=nsample-1) cycle
4725 sph(3)=(one-wp)*phiface(ixomin3)+wp*phiface(ixomax3+1)
4726 call get_cor_image_spherical(sph,xcent)
4727 xmin1=min(xmin1,xcent(1))
4728 xmax1=max(xmax1,xcent(1))
4729 xmin2=min(xmin2,xcent(2))
4730 xmax2=max(xmax2,xcent(2))
4731 enddo
4732 enddo
4733 enddo
4734 pad=2.d0*dxi
4735 xmin1=xmin1-pad
4736 xmax1=xmax1+pad
4737 xmin2=xmin2-pad
4738 xmax2=xmax2+pad
4739 ixpmin1=max(1,floor((xmin1-(xi1(1)-half*dxi))/dxi)+1)
4740 ixpmax1=min(nxi1,ceiling((xmax1-(xi1(1)-half*dxi))/dxi))
4741 ixpmin2=max(1,floor((xmin2-(xi2(1)-half*dxi))/dxi)+1)
4742 ixpmax2=min(nxi2,ceiling((xmax2-(xi2(1)-half*dxi))/dxi))
4743 has_pixels=ixpmin1<=ixpmax1 .and. ixpmin2<=ixpmax2
4744 end subroutine sph_block_pixel_range
4745
4746 subroutine acc_euv_sph_intersection(ixI^L,ixO^L,source,ray_origin,ximg1,ximg2,&
4747 rface,thetaface,phiface,EUVp)
4748 integer, intent(in) :: ixI^L,ixO^L
4749 double precision, intent(in) :: source(ixI^S),ray_origin(1:3),ximg1,ximg2
4750 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4751 phiface(ixOmin3:ixOmax3+1)
4752 double precision, intent(inout) :: EUVp
4753
4754 integer :: nt,capacity,i,ix^D
4755 double precision, allocatable :: tvals(:)
4756 double precision :: posMid(1:3),ds_cm,tMid,t0,t1
4757 logical :: inside
4758
4759 nt=0
4760 capacity=0
4761 do ix1=ixomin1,ixomax1+1
4762 call sph_add_sphere_intersections(ray_origin,vec_los,rface(ix1),tvals,nt,capacity)
4763 enddo
4764 do ix2=ixomin2,ixomax2+1
4765 call sph_add_theta_intersections(ray_origin,vec_los,thetaface(ix2),tvals,nt,capacity)
4766 enddo
4767 do ix3=ixomin3,ixomax3+1
4768 call sph_add_phi_intersection(ray_origin,vec_los,phiface(ix3),tvals,nt,capacity)
4769 enddo
4770 if (nt<2) then
4771 if (allocated(tvals)) deallocate(tvals)
4772 return
4773 endif
4774 call sph_sort_unique_t(tvals,nt)
4775
4776 do i=1,nt-1
4777 t0=tvals(i)
4778 t1=tvals(i+1)
4779 if (t1<=t0) cycle
4780 tmid=half*(t0+t1)
4781 posmid=ray_origin+tmid*vec_los
4782 if (.not. sph_segment_visible(posmid,ximg1,ximg2)) cycle
4783 call sph_locate_cell(posmid,rface,thetaface,phiface,ixo^l,ix1,ix2,ix3,inside)
4784 if (.not. inside) cycle
4785 ds_cm=(t1-t0)*unit_length
4786 if (si_unit) ds_cm=ds_cm*1.d2
4787 euvp=euvp+source(ix^d)*ds_cm
4788 enddo
4789 deallocate(tvals)
4790 end subroutine acc_euv_sph_intersection
4791
4792 subroutine collect_euv_sph_intersection_segments(ixI^L,ixO^L,source,opacity,&
4793 pixel_id,ray_origin,ximg1,ximg2,&
4794 rface,thetaface,phiface,rface2,&
4795 theta_cos,phi_sin,phi_cos,&
4796 segments,nseg,capacity)
4797 use mod_constants, only: const_rsun
4798
4799 integer, intent(in) :: ixI^L,ixO^L,pixel_id
4800 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
4801 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
4802 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4803 phiface(ixOmin3:ixOmax3+1)
4804 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4805 phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
4806 double precision, allocatable, intent(inout) :: segments(:,:)
4807 integer, intent(inout) :: nseg,capacity
4808
4809 integer :: nt,i,ix^D
4810 double precision :: tvals(2*(ixOmax1-ixOmin1+2)+2*(ixOmax2-ixOmin2+2)+&
4811 (ixOmax3-ixOmin3+2))
4812 double precision :: posMid(1:3),ds_cm,tMid,t0,t1,jds,kds
4813 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2
4814 double precision :: denom,numer,r2,mu,phi,dotp,rthick2,rc2
4815 logical :: inside
4816
4817 nt=0
4818 dir2=sum(vec_los**2)
4819 origin2=sum(ray_origin**2)
4820 odotd=sum(ray_origin*vec_los)
4821 rthick2=(r_opt_thick*const_rsun/unit_length)**2
4822 rc2=ximg1**2+ximg2**2
4823
4824 do ix1=ixomin1,ixomax1+1
4825 aa=dir2
4826 bb=2.d0*odotd
4827 cc=origin2-rface2(ix1)
4828 disc=bb**2-4.d0*aa*cc
4829 if (disc>=zero) then
4830 root=sqrt(max(zero,disc))
4831 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
4832 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
4833 endif
4834 enddo
4835 do ix2=ixomin2,ixomax2+1
4836 if (abs(theta_cos(ix2))<1.d-12) then
4837 if (abs(vec_los(3))>1.d-14) &
4838 call sph_add_t_fixed(tvals,nt,-ray_origin(3)/vec_los(3))
4839 cycle
4840 endif
4841 cth2=theta_cos(ix2)**2
4842 aa=vec_los(3)**2-cth2*dir2
4843 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
4844 cc=ray_origin(3)**2-cth2*origin2
4845 if (abs(aa)<1.d-14) then
4846 if (abs(bb)>1.d-14) call sph_add_t_fixed(tvals,nt,-cc/bb)
4847 else
4848 disc=bb**2-4.d0*aa*cc
4849 if (disc>=zero) then
4850 root=sqrt(max(zero,disc))
4851 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
4852 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
4853 endif
4854 endif
4855 enddo
4856 do ix3=ixomin3,ixomax3+1
4857 denom=-phi_sin(ix3)*vec_los(1)+phi_cos(ix3)*vec_los(2)
4858 if (abs(denom)>=1.d-14) then
4859 numer=-phi_sin(ix3)*ray_origin(1)+phi_cos(ix3)*ray_origin(2)
4860 call sph_add_t_fixed(tvals,nt,-numer/denom)
4861 endif
4862 enddo
4863 if (nt<2) return
4864 call sph_sort_unique_t(tvals,nt)
4865
4866 do i=1,nt-1
4867 t0=tvals(i)
4868 t1=tvals(i+1)
4869 if (t1<=t0) cycle
4870 tmid=half*(t0+t1)
4871 posmid=ray_origin+tmid*vec_los
4872 r2=sum(posmid**2)
4873 dotp=sum(vec_los*posmid)
4874 if (dotp>=zero) then
4875 if (rc2<=rthick2) cycle
4876 else
4877 if (r2<=rthick2) cycle
4878 endif
4879
4880 ix1=sph_locate_index(r2,rface2,ixomin1,ixomax1)
4881 if (r2>zero) then
4882 mu=posmid(3)/sqrt(r2)
4883 else
4884 mu=one
4885 endif
4886 ix2=sph_locate_index_desc(mu,theta_cos,ixomin2,ixomax2)
4887 phi=atan2(posmid(2),posmid(1))
4888 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4889 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4890 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4891 inside=ix1>0 .and. ix2>0 .and. ix3>0
4892 if (.not. inside) cycle
4893 ds_cm=(t1-t0)*unit_length
4894 if (si_unit) ds_cm=ds_cm*1.d2
4895 jds=max(zero,source(ix^d))*ds_cm
4896 kds=max(zero,opacity(ix^d))*ds_cm
4897 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tmid,jds,kds,zero)
4898 enddo
4900
4901 subroutine sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixO^L,ix1,ix2,ix3,inside)
4902 double precision, intent(in) :: pos(1:3)
4903 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4904 phiface(ixOmin3:ixOmax3+1)
4905 integer, intent(in) :: ixO^L
4906 integer, intent(out) :: ix1,ix2,ix3
4907 logical, intent(out) :: inside
4908
4909 double precision :: r2,mu,phi
4910
4911 r2=sum(pos**2)
4912 ix1=sph_locate_index(r2,rface2,ixomin1,ixomax1)
4913 if (r2>zero) then
4914 mu=pos(3)/sqrt(r2)
4915 else
4916 mu=one
4917 endif
4918 ix2=sph_locate_index_desc(mu,theta_cos,ixomin2,ixomax2)
4919 phi=atan2(pos(2),pos(1))
4920 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4921 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4922 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4923 inside=ix1>0 .and. ix2>0 .and. ix3>0
4924 end subroutine sph_locate_cell_fast
4925
4926 subroutine sph_try_exit_candidate(t,tNow,tExit,epsRay,tNext,found)
4927 double precision, intent(in) :: t,tNow,tExit,epsRay
4928 double precision, intent(inout) :: tNext
4929 logical, intent(inout) :: found
4930
4931 if (t>tnow+epsray .and. t<=texit+epsray .and. t<tnext) then
4932 tnext=t
4933 found=.true.
4934 endif
4935 end subroutine sph_try_exit_candidate
4936
4937 subroutine sph_try_theta_exit_candidate(t,theta_face_cos,ray_origin,tNow,tExit,epsRay,tNext,found)
4938 double precision, intent(in) :: t,theta_face_cos,ray_origin(1:3),tNow,tExit,epsRay
4939 double precision, intent(inout) :: tNext
4940 logical, intent(inout) :: found
4941
4942 double precision :: pos(1:3),r2
4943
4944 if (t<=tnow+epsray .or. t>texit+epsray .or. t>=tnext) return
4945 pos=ray_origin+t*vec_los
4946 r2=sum(pos**2)
4947 if (r2<=zero) return
4948 if (theta_face_cos>1.d-12 .and. pos(3)<-1.d-10) return
4949 if (theta_face_cos<-1.d-12 .and. pos(3)>1.d-10) return
4950 if (abs(pos(3)**2-theta_face_cos**2*r2)>1.d-6*max(one,r2)) return
4951 tnext=t
4952 found=.true.
4953 end subroutine sph_try_theta_exit_candidate
4954
4955 subroutine sph_try_phi_exit_candidate(t,phi_face_sin,phi_face_cos,ray_origin,tNow,tExit,epsRay,tNext,found)
4956 double precision, intent(in) :: t,phi_face_sin,phi_face_cos,ray_origin(1:3),tNow,tExit,epsRay
4957 double precision, intent(inout) :: tNext
4958 logical, intent(inout) :: found
4959
4960 double precision :: pos(1:3),radialDot
4961
4962 if (t<=tnow+epsray .or. t>texit+epsray .or. t>=tnext) return
4963 pos=ray_origin+t*vec_los
4964 radialdot=phi_face_cos*pos(1)+phi_face_sin*pos(2)
4965 if (radialdot<-1.d-10) return
4966 tnext=t
4967 found=.true.
4968 end subroutine sph_try_phi_exit_candidate
4969
4970 subroutine sph_next_cell_exit(ray_origin,rface2,theta_cos,phiface,phi_sin,phi_cos,ixO^L,&
4971 ix1,ix2,ix3,tNow,tExit,epsRay,tNext,found)
4972 double precision, intent(in) :: ray_origin(1:3)
4973 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4974 phiface(ixOmin3:ixOmax3+1)
4975 double precision, intent(in) :: phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
4976 integer, intent(in) :: ixO^L,ix1,ix2,ix3
4977 double precision, intent(in) :: tNow,tExit,epsRay
4978 double precision, intent(out) :: tNext
4979 logical, intent(out) :: found
4980
4981 integer :: iface
4982 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2,denom,numer
4983
4984 found=.false.
4985 tnext=huge(one)
4986 dir2=sum(vec_los**2)
4987 origin2=sum(ray_origin**2)
4988 odotd=sum(ray_origin*vec_los)
4989
4990 do iface=ix1,ix1+1
4991 aa=dir2
4992 bb=2.d0*odotd
4993 cc=origin2-rface2(iface)
4994 disc=bb**2-4.d0*aa*cc
4995 if (disc>=zero) then
4996 root=sqrt(max(zero,disc))
4997 call sph_try_exit_candidate((-bb-root)/(2.d0*aa),tnow,texit,epsray,tnext,found)
4998 call sph_try_exit_candidate((-bb+root)/(2.d0*aa),tnow,texit,epsray,tnext,found)
4999 endif
5000 enddo
5001
5002 do iface=ix2,ix2+1
5003 if (abs(theta_cos(iface))<1.d-12) then
5004 if (abs(vec_los(3))>1.d-14) call sph_try_theta_exit_candidate(&
5005 -ray_origin(3)/vec_los(3),theta_cos(iface),ray_origin,tnow,texit,epsray,&
5006 tnext,found)
5007 cycle
5008 endif
5009 cth2=theta_cos(iface)**2
5010 aa=vec_los(3)**2-cth2*dir2
5011 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
5012 cc=ray_origin(3)**2-cth2*origin2
5013 if (abs(aa)<1.d-14) then
5014 if (abs(bb)>1.d-14) call sph_try_theta_exit_candidate(-cc/bb,theta_cos(iface),&
5015 ray_origin,tnow,texit,epsray,tnext,found)
5016 else
5017 disc=bb**2-4.d0*aa*cc
5018 if (disc>=zero) then
5019 root=sqrt(max(zero,disc))
5020 call sph_try_theta_exit_candidate((-bb-root)/(2.d0*aa),theta_cos(iface),&
5021 ray_origin,tnow,texit,epsray,tnext,found)
5022 call sph_try_theta_exit_candidate((-bb+root)/(2.d0*aa),theta_cos(iface),&
5023 ray_origin,tnow,texit,epsray,tnext,found)
5024 endif
5025 endif
5026 enddo
5027
5028 do iface=ix3,ix3+1
5029 denom=-phi_sin(iface)*vec_los(1)+phi_cos(iface)*vec_los(2)
5030 if (abs(denom)>=1.d-14) then
5031 numer=-phi_sin(iface)*ray_origin(1)+phi_cos(iface)*ray_origin(2)
5032 call sph_try_phi_exit_candidate(-numer/denom,phi_sin(iface),phi_cos(iface),ray_origin,&
5033 tnow,texit,epsray,tnext,found)
5034 endif
5035 enddo
5036 end subroutine sph_next_cell_exit
5037
5038 subroutine collect_euv_sph_dda_interval(ixI^L,ixO^L,source,opacity,pixel_id,&
5039 ray_origin,ximg1,ximg2,rface2,theta_cos,phiface,&
5040 phi_sin,phi_cos,&
5041 t_enter,t_exit,segments,nseg,capacity,ok)
5042 use mod_constants, only: const_rsun
5043
5044 integer, intent(in) :: ixI^L,ixO^L,pixel_id
5045 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
5046 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
5047 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
5048 phiface(ixOmin3:ixOmax3+1)
5049 double precision, intent(in) :: phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
5050 double precision, intent(in) :: t_enter,t_exit
5051 double precision, allocatable, intent(inout) :: segments(:,:)
5052 integer, intent(inout) :: nseg,capacity
5053 logical, intent(out) :: ok
5054
5055 integer :: ix^D,nstep,maxSteps
5056 double precision :: tNow,tNext,tEnd,tMid,epsRay,ds_cm,jds,kds
5057 double precision :: pos(1:3),r2,dotp,rthick2,rc2
5058 logical :: inside,found
5059
5060 ok=.true.
5061 if (t_exit<=t_enter) return
5062 epsray=max(1.d-12,1.d-10*max(one,abs(t_exit-t_enter)))
5063 pos=ray_origin+(t_enter+epsray)*vec_los
5064 call sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5065 if (.not. inside) then
5066 ok=.false.
5067 return
5068 endif
5069
5070 rthick2=(r_opt_thick*const_rsun/unit_length)**2
5071 rc2=ximg1**2+ximg2**2
5072 tnow=t_enter
5073 nstep=0
5074 maxsteps=8*((ixomax1-ixomin1+1)+(ixomax2-ixomin2+1)+(ixomax3-ixomin3+1)+3)
5075
5076 do while (tnow<t_exit-epsray)
5077 call sph_next_cell_exit(ray_origin,rface2,theta_cos,phiface,phi_sin,phi_cos,ixo^l,&
5078 ix1,ix2,ix3,tnow,t_exit,epsray,tnext,found)
5079 if (.not. found) then
5080 ok=.false.
5081 return
5082 endif
5083 tend=min(tnext,t_exit)
5084 if (tend>tnow) then
5085 tmid=half*(tnow+tend)
5086 pos=ray_origin+tmid*vec_los
5087 r2=sum(pos**2)
5088 dotp=sum(vec_los*pos)
5089 if (.not. ((dotp>=zero .and. rc2<=rthick2) .or. &
5090 (dotp<zero .and. r2<=rthick2))) then
5091 ds_cm=(tend-tnow)*unit_length
5092 if (si_unit) ds_cm=ds_cm*1.d2
5093 jds=max(zero,source(ix^d))*ds_cm
5094 kds=max(zero,opacity(ix^d))*ds_cm
5095 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tmid,jds,kds,zero)
5096 endif
5097 endif
5098 tnow=tend
5099 if (tnow>=t_exit-epsray) exit
5100 pos=ray_origin+(tnow+epsray)*vec_los
5101 call sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5102 if (.not. inside) then
5103 ok=.false.
5104 return
5105 endif
5106 nstep=nstep+1
5107 if (nstep>maxsteps) then
5108 ok=.false.
5109 return
5110 endif
5111 enddo
5112 end subroutine collect_euv_sph_dda_interval
5113
5114 subroutine collect_euv_sph_dda_segments(ixI^L,ixO^L,source,opacity,&
5115 pixel_id,ray_origin,ximg1,ximg2,&
5116 rface,thetaface,phiface,rface2,&
5117 theta_cos,phi_sin,phi_cos,&
5118 segments,nseg,capacity,fallback)
5119 integer, intent(in) :: ixI^L,ixO^L,pixel_id
5120 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
5121 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
5122 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
5123 phiface(ixOmin3:ixOmax3+1)
5124 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
5125 phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
5126 double precision, allocatable, intent(inout) :: segments(:,:)
5127 integer, intent(inout) :: nseg,capacity
5128 logical, intent(out) :: fallback
5129
5130 integer :: nt,i,nsegStart,ix^D
5131 double precision :: tvals(12),posMid(1:3),t0,t1,tMid
5132 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2,denom,numer
5133 logical :: inside,ok
5134
5135 fallback=.false.
5136 nsegstart=nseg
5137 nt=0
5138 dir2=sum(vec_los**2)
5139 origin2=sum(ray_origin**2)
5140 odotd=sum(ray_origin*vec_los)
5141
5142 do ix1=ixomin1,ixomax1+1,ixomax1-ixomin1+1
5143 aa=dir2
5144 bb=2.d0*odotd
5145 cc=origin2-rface2(ix1)
5146 disc=bb**2-4.d0*aa*cc
5147 if (disc>=zero) then
5148 root=sqrt(max(zero,disc))
5149 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
5150 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
5151 endif
5152 enddo
5153 do ix2=ixomin2,ixomax2+1,ixomax2-ixomin2+1
5154 if (abs(theta_cos(ix2))<1.d-12) then
5155 if (abs(vec_los(3))>1.d-14) &
5156 call sph_add_t_fixed(tvals,nt,-ray_origin(3)/vec_los(3))
5157 cycle
5158 endif
5159 cth2=theta_cos(ix2)**2
5160 aa=vec_los(3)**2-cth2*dir2
5161 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
5162 cc=ray_origin(3)**2-cth2*origin2
5163 if (abs(aa)<1.d-14) then
5164 if (abs(bb)>1.d-14) call sph_add_t_fixed(tvals,nt,-cc/bb)
5165 else
5166 disc=bb**2-4.d0*aa*cc
5167 if (disc>=zero) then
5168 root=sqrt(max(zero,disc))
5169 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
5170 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
5171 endif
5172 endif
5173 enddo
5174 do ix3=ixomin3,ixomax3+1,ixomax3-ixomin3+1
5175 denom=-phi_sin(ix3)*vec_los(1)+phi_cos(ix3)*vec_los(2)
5176 if (abs(denom)>=1.d-14) then
5177 numer=-phi_sin(ix3)*ray_origin(1)+phi_cos(ix3)*ray_origin(2)
5178 call sph_add_t_fixed(tvals,nt,-numer/denom)
5179 endif
5180 enddo
5181
5182 if (nt<2) return
5183 call sph_sort_unique_t(tvals,nt)
5184
5185 do i=1,nt-1
5186 t0=tvals(i)
5187 t1=tvals(i+1)
5188 if (t1<=t0) cycle
5189 tmid=half*(t0+t1)
5190 posmid=ray_origin+tmid*vec_los
5191 call sph_locate_cell_fast(posmid,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5192 if (.not. inside) cycle
5193 call collect_euv_sph_dda_interval(ixi^l,ixo^l,source,opacity,pixel_id,&
5194 ray_origin,ximg1,ximg2,rface2,theta_cos,phiface,phi_sin,phi_cos,&
5195 t0,t1,segments,nseg,capacity,ok)
5196 if (.not. ok) then
5197 nseg=nsegstart
5198 fallback=.true.
5199 call collect_euv_sph_intersection_segments(ixi^l,ixo^l,source,opacity,&
5200 pixel_id,ray_origin,ximg1,ximg2,rface,thetaface,phiface,rface2,&
5201 theta_cos,phi_sin,phi_cos,segments,nseg,capacity)
5202 return
5203 endif
5204 enddo
5205
5206 end subroutine collect_euv_sph_dda_segments
5207
5208 subroutine integrate_euv_sph_intersection_thin(numXI1,numXI2,xI1,xI2,dxI,fl,EM)
5210
5211 integer, intent(in) :: numXI1,numXI2
5212 double precision, intent(in) :: xI1(numXI1),xI2(numXI2),dxI
5213 type(te_fluid), intent(in) :: fl
5214 double precision, intent(inout) :: EM(numXI1,numXI2)
5215
5216 integer :: ixO^L,ixI^L,ix^D
5217 integer :: iigrid,igrid,ixP1,ixP2,ixPmin1,ixPmax1,ixPmin2,ixPmax2
5218 integer :: iseg,nseg,capacity,sphDdaFallbackLocal,sphDdaFallbackGlobal
5219 double precision :: ray_origin(1:3),profile_local(3),profile_global(3)
5220 double precision, allocatable :: source(:^D&)
5221 double precision, allocatable :: rface(:),thetaface(:),phiface(:)
5222 double precision, allocatable :: rface2(:),theta_cos(:),phi_sin(:),phi_cos(:)
5223 double precision, allocatable :: segments(:,:)
5224 logical :: has_pixels,ddaFallback
5225
5226 profile_local=zero
5227 sphddafallbacklocal=0
5228 do iigrid=1,igridstail; igrid=igrids(iigrid);
5229 ^d&ixomin^d=ixmlo^d\
5230 ^d&ixomax^d=ixmhi^d\
5231 ^d&iximin^d=ixglo^d\
5232 ^d&iximax^d=ixghi^d\
5233
5234 allocate(source(ixi^s))
5235 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,source)
5236 source(ixo^s)=source(ixo^s)/instrument_resolution_factor**2
5237 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx(ixi^s,1:ndim),&
5238 rface,thetaface,phiface)
5239 if (sph_use_dda) then
5240 allocate(rface2(ixomin1:ixomax1+1),theta_cos(ixomin2:ixomax2+1),&
5241 phi_sin(ixomin3:ixomax3+1),phi_cos(ixomin3:ixomax3+1))
5242 rface2=rface**2
5243 theta_cos=cos(thetaface)
5244 phi_sin=sin(phiface)
5245 phi_cos=cos(phiface)
5246 endif
5247 call sph_block_pixel_range(rface,thetaface,phiface,ixo^l,numxi1,numxi2,xi1,xi2,dxi,&
5248 ixpmin1,ixpmax1,ixpmin2,ixpmax2,has_pixels)
5249 if (has_pixels) then
5250 if (sph_use_dda) capacity=0
5251 do ixp1=ixpmin1,ixpmax1
5252 do ixp2=ixpmin2,ixpmax2
5253 ray_origin=xi1(ixp1)*vec_xi1+xi2(ixp2)*vec_xi2
5254 profile_local(1)=profile_local(1)+one
5255 if (sph_use_dda) then
5256 nseg=0
5257 call collect_euv_sph_dda_segments(ixi^l,ixo^l,source,source,&
5258 1,ray_origin,xi1(ixp1),xi2(ixp2),rface,thetaface,phiface,&
5259 rface2,theta_cos,phi_sin,phi_cos,segments,nseg,capacity,ddafallback)
5260 if (ddafallback) sphddafallbacklocal=sphddafallbacklocal+1
5261 do iseg=1,nseg
5262 em(ixp1,ixp2)=em(ixp1,ixp2)+segments(3,iseg)
5263 enddo
5264 else
5265 call acc_euv_sph_intersection(ixi^l,ixo^l,source,ray_origin,xi1(ixp1),xi2(ixp2),&
5266 rface,thetaface,phiface,em(ixp1,ixp2))
5267 endif
5268 enddo
5269 enddo
5270 profile_local(2)=profile_local(2)+dble((ixpmax1-ixpmin1+1)*(ixpmax2-ixpmin2+1))
5271 endif
5272 if (allocated(segments)) deallocate(segments)
5273 profile_local(3)=profile_local(3)+one
5274 if (allocated(rface2)) deallocate(rface2)
5275 if (allocated(theta_cos)) deallocate(theta_cos)
5276 if (allocated(phi_sin)) deallocate(phi_sin)
5277 if (allocated(phi_cos)) deallocate(phi_cos)
5278 deallocate(source,rface,thetaface,phiface)
5279 enddo
5280 call mpi_allreduce(profile_local,profile_global,3,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5281 call mpi_allreduce(sphddafallbacklocal,sphddafallbackglobal,1,mpi_integer,mpi_sum,icomm,ierrmpi)
5282 if (radsyn_verbose .and. mype==0) then
5283 if (sph_use_dda) then
5284 write(*,'(a,3(es12.5,1x))') ' sph_dda thin profile rays pixels blocks: ',profile_global
5285 write(*,'(a,i0)') ' sph_dda thin fallback rays: ',sphddafallbackglobal
5286 else
5287 write(*,'(a,3(es12.5,1x))') ' sph_intersection thin profile rays pixels blocks: ',profile_global
5288 endif
5289 endif
5291
5292 subroutine integrate_euv_sph_intersection_thick(numXI1,numXI2,xI1,xI2,dxI,fl,EUV,Tau,EUVthin)
5294
5295 integer, intent(in) :: numXI1,numXI2
5296 double precision, intent(in) :: xI1(numXI1),xI2(numXI2),dxI
5297 type(te_fluid), intent(in) :: fl
5298 double precision, intent(out) :: EUV(numXI1,numXI2),Tau(numXI1,numXI2),EUVthin(numXI1,numXI2)
5299
5300 integer, parameter :: nSegVars=5
5301 integer :: ixO^L,ixI^L,ix^D
5302 integer :: iigrid,igrid,ixP1,ixP2,ipix,ipixStart,ipixEnd,nPixBatch,pixel_id
5303 integer :: nseg,capacity,totalCount,totalSeg,ipe,is,iseg,nidx,owner,isegDest,nsegBefore
5304 integer :: ixGlobal,iyGlobal,ixPmin1,ixPmax1,ixPmin2,ixPmax2,iFirst,iLast,iLocal
5305 integer :: nPixBatchTarget
5306 integer :: maxSegBatchTarget,maxSegCommTarget,maxNsegBatch,nPixTotal
5307 integer :: maxOwnerSegCount,maxOwnerSegCountLocal,segOffset,recvFill,totalRoundCount,totalRoundSeg
5308 integer :: sphDdaFallbackLocal,sphDdaFallbackGlobal
5309 integer, allocatable :: sendCounts(:),recvCounts(:),sendDispls(:),recvDispls(:)
5310 integer, allocatable :: roundSendCounts(:),roundRecvCounts(:)
5311 integer, allocatable :: roundSendDispls(:),roundRecvDispls(:)
5312 integer, allocatable :: ownerSegCounts(:),ownerOffsets(:),idx(:)
5313 integer, allocatable :: bucketCounts(:),bucketOffsets(:),bucketFill(:)
5314 double precision :: ray_origin(1:3),atten
5315 double precision :: profile_local(5),profile_global(5),profile_batch(5)
5316 double precision :: phys_max_local(2),phys_max_global(2)
5317 double precision :: phys_sum_local(2),phys_sum_global(2),phys_sum_batch(2)
5318 double precision, allocatable :: segments(:,:),segments_send(:,:),segments_recv(:,:)
5319 double precision, allocatable :: segments_recv_round(:,:)
5320 double precision, allocatable :: image_reduce(:,:)
5321 logical :: has_pixels,batchAccepted,batchReduced,ddaFallback
5322 type(radsyn_euv_cache), allocatable :: cache(:)
5323
5324 euv=zero
5325 tau=zero
5326 euvthin=zero
5327 profile_local=zero
5328 phys_max_local=zero
5329 phys_sum_local=zero
5330 sphddafallbacklocal=0
5331 allocate(sendcounts(0:npe-1),recvcounts(0:npe-1),senddispls(0:npe-1),recvdispls(0:npe-1))
5332 allocate(roundsendcounts(0:npe-1),roundrecvcounts(0:npe-1))
5333 allocate(roundsenddispls(0:npe-1),roundrecvdispls(0:npe-1))
5334 allocate(ownersegcounts(0:npe-1),owneroffsets(0:npe-1))
5335 allocate(cache(igridstail))
5336 call radsyn_get_segment_batch_limits(npixbatchtarget,maxsegbatchtarget,maxsegcommtarget)
5337 allocate(bucketcounts(npixbatchtarget),bucketoffsets(npixbatchtarget+1),&
5338 bucketfill(npixbatchtarget))
5339
5340 do iigrid=1,igridstail; igrid=igrids(iigrid);
5341 ^d&ixomin^d=ixmlo^d\
5342 ^d&ixomax^d=ixmhi^d\
5343 ^d&iximin^d=ixglo^d\
5344 ^d&iximax^d=ixghi^d\
5345
5346 cache(iigrid)%igrid=igrid
5347 allocate(cache(iigrid)%source(ixi^s),cache(iigrid)%opacity(ixi^s))
5348 cache(iigrid)%source=zero
5349 cache(iigrid)%opacity=zero
5350 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%source)
5351 cache(iigrid)%source(ixo^s)=cache(iigrid)%source(ixo^s)/instrument_resolution_factor**2
5352 call get_euv_hhe_opacity(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%opacity)
5353 phys_max_local(1)=max(phys_max_local(1),maxval(cache(iigrid)%source(ixo^s)))
5354 phys_max_local(2)=max(phys_max_local(2),maxval(cache(iigrid)%opacity(ixo^s)))
5355 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx(ixi^s,1:ndim),&
5356 cache(iigrid)%rface,cache(iigrid)%thetaface,&
5357 cache(iigrid)%phiface)
5358 allocate(cache(iigrid)%rface2(ixomin1:ixomax1+1),&
5359 cache(iigrid)%theta_cos(ixomin2:ixomax2+1),&
5360 cache(iigrid)%phi_sin(ixomin3:ixomax3+1),&
5361 cache(iigrid)%phi_cos(ixomin3:ixomax3+1))
5362 cache(iigrid)%rface2=cache(iigrid)%rface**2
5363 cache(iigrid)%theta_cos=cos(cache(iigrid)%thetaface)
5364 cache(iigrid)%phi_sin=sin(cache(iigrid)%phiface)
5365 cache(iigrid)%phi_cos=cos(cache(iigrid)%phiface)
5366 call sph_block_pixel_range(cache(iigrid)%rface,cache(iigrid)%thetaface,&
5367 cache(iigrid)%phiface,ixo^l,numxi1,numxi2,xi1,xi2,dxi,&
5368 cache(iigrid)%ixPmin1,cache(iigrid)%ixPmax1,&
5369 cache(iigrid)%ixPmin2,cache(iigrid)%ixPmax2,cache(iigrid)%has_pixels)
5370 enddo
5371
5372 npixtotal=numxi1*numxi2
5373 ipixstart=1
5374 do while (ipixstart<=npixtotal)
5375 ipixend=min(numxi1*numxi2,ipixstart+npixbatchtarget-1)
5376 npixbatch=ipixend-ipixstart+1
5377 batchaccepted=.false.
5378 batchreduced=.false.
5379
5380 do while (.not. batchaccepted)
5381 nseg=0
5382 capacity=0
5383 profile_batch=zero
5384 phys_sum_batch=zero
5385
5386 do iigrid=1,igridstail; igrid=igrids(iigrid);
5387 ^d&ixomin^d=ixmlo^d\
5388 ^d&ixomax^d=ixmhi^d\
5389 ^d&iximin^d=ixglo^d\
5390 ^d&iximax^d=ixghi^d\
5391
5392 ixpmin1=cache(iigrid)%ixPmin1
5393 ixpmax1=cache(iigrid)%ixPmax1
5394 ixpmin2=cache(iigrid)%ixPmin2
5395 ixpmax2=cache(iigrid)%ixPmax2
5396 has_pixels=cache(iigrid)%has_pixels
5397 if (.not. has_pixels) cycle
5398
5399 do ixp2=ixpmin2,ixpmax2
5400 ifirst=max(ipixstart,(ixp2-1)*numxi1+ixpmin1)
5401 ilast=min(ipixend,(ixp2-1)*numxi1+ixpmax1)
5402 if (ifirst>ilast) cycle
5403 do ipix=ifirst,ilast
5404 ixp1=1+mod(ipix-1,numxi1)
5405 pixel_id=ipix
5406 ray_origin=xi1(ixp1)*vec_xi1+xi2(ixp2)*vec_xi2
5407 profile_batch(1)=profile_batch(1)+one
5408 nsegbefore=nseg
5409 if (sph_use_dda) then
5410 call collect_euv_sph_dda_segments(ixi^l,ixo^l,cache(iigrid)%source,&
5411 cache(iigrid)%opacity,pixel_id,ray_origin,xi1(ixp1),xi2(ixp2),&
5412 cache(iigrid)%rface,cache(iigrid)%thetaface,cache(iigrid)%phiface,&
5413 cache(iigrid)%rface2,cache(iigrid)%theta_cos,&
5414 cache(iigrid)%phi_sin,cache(iigrid)%phi_cos,&
5415 segments,nseg,capacity,ddafallback)
5416 if (ddafallback) sphddafallbacklocal=sphddafallbacklocal+1
5417 else
5418 call collect_euv_sph_intersection_segments(ixi^l,ixo^l,cache(iigrid)%source,&
5419 cache(iigrid)%opacity,pixel_id,ray_origin,xi1(ixp1),xi2(ixp2),&
5420 cache(iigrid)%rface,cache(iigrid)%thetaface,cache(iigrid)%phiface,&
5421 cache(iigrid)%rface2,cache(iigrid)%theta_cos,&
5422 cache(iigrid)%phi_sin,cache(iigrid)%phi_cos,&
5423 segments,nseg,capacity)
5424 endif
5425 if (nseg>nsegbefore) profile_batch(2)=profile_batch(2)+one
5426 profile_batch(3)=profile_batch(3)+dble(nseg-nsegbefore)
5427 do iseg=nsegbefore+1,nseg
5428 phys_sum_batch(1)=phys_sum_batch(1)+segments(3,iseg)
5429 phys_sum_batch(2)=phys_sum_batch(2)+segments(4,iseg)
5430 enddo
5431 enddo
5432 enddo
5433 enddo
5434
5435 call mpi_allreduce(nseg,maxnsegbatch,1,mpi_integer,mpi_max,icomm,ierrmpi)
5436 if (maxnsegbatch>maxsegbatchtarget .and. npixbatch>1) then
5437 npixbatch=max(1,npixbatch/2)
5438 ipixend=ipixstart+npixbatch-1
5439 if (allocated(segments)) deallocate(segments)
5440 batchreduced=.true.
5441 else
5442 batchaccepted=.true.
5443 endif
5444 enddo
5445
5446 profile_local=profile_local+profile_batch
5447 phys_sum_local=phys_sum_local+phys_sum_batch
5448 if (radsyn_verbose .and. mype==0 .and. batchreduced) then
5449 if (sph_use_dda) then
5450 write(*,'(a,3(i0,1x))') ' sph_dda thick adaptive batch: ',&
5451 ipixstart,ipixend,maxnsegbatch
5452 else
5453 write(*,'(a,3(i0,1x))') ' sph_intersection thick adaptive batch: ',&
5454 ipixstart,ipixend,maxnsegbatch
5455 endif
5456 endif
5457
5458 if (.not. allocated(segments)) then
5459 capacity=1
5460 allocate(segments(nsegvars,capacity))
5461 endif
5462 ownersegcounts=0
5463 do is=1,nseg
5464 owner=segment_pixel_owner(nint(segments(1,is)))
5465 ownersegcounts(owner)=ownersegcounts(owner)+1
5466 enddo
5467 sendcounts=nsegvars*ownersegcounts
5468 senddispls(0)=0
5469 do ipe=1,npe-1
5470 senddispls(ipe)=senddispls(ipe-1)+sendcounts(ipe-1)
5471 enddo
5472
5473 allocate(segments_send(nsegvars,max(1,nseg)))
5474 owneroffsets=0
5475 do is=1,nseg
5476 owner=segment_pixel_owner(nint(segments(1,is)))
5477 isegdest=senddispls(owner)/nsegvars+owneroffsets(owner)+1
5478 segments_send(:,isegdest)=segments(:,is)
5479 owneroffsets(owner)=owneroffsets(owner)+1
5480 enddo
5481
5482 call mpi_alltoall(sendcounts,1,mpi_integer,recvcounts,1,mpi_integer,icomm,ierrmpi)
5483 recvdispls(0)=0
5484 do ipe=1,npe-1
5485 recvdispls(ipe)=recvdispls(ipe-1)+recvcounts(ipe-1)
5486 enddo
5487 totalcount=sum(recvcounts)
5488 totalseg=totalcount/nsegvars
5489 profile_local(4)=profile_local(4)+dble(totalcount)
5490 allocate(segments_recv(nsegvars,max(1,totalseg)))
5491
5492 recvfill=0
5493 maxownersegcountlocal=maxval(ownersegcounts)
5494 call mpi_allreduce(maxownersegcountlocal,maxownersegcount,1,mpi_integer,mpi_max,icomm,ierrmpi)
5495 do segoffset=0,maxownersegcount-1,maxsegcommtarget
5496 roundsendcounts=0
5497 roundsenddispls=senddispls
5498 do ipe=0,npe-1
5499 if (ownersegcounts(ipe)>segoffset) then
5500 roundsendcounts(ipe)=nsegvars*min(maxsegcommtarget,ownersegcounts(ipe)-segoffset)
5501 roundsenddispls(ipe)=senddispls(ipe)+nsegvars*segoffset
5502 endif
5503 enddo
5504
5505 call mpi_alltoall(roundsendcounts,1,mpi_integer,roundrecvcounts,1,mpi_integer,icomm,ierrmpi)
5506 roundrecvdispls(0)=0
5507 do ipe=1,npe-1
5508 roundrecvdispls(ipe)=roundrecvdispls(ipe-1)+roundrecvcounts(ipe-1)
5509 enddo
5510 totalroundcount=sum(roundrecvcounts)
5511 totalroundseg=totalroundcount/nsegvars
5512 allocate(segments_recv_round(nsegvars,max(1,totalroundseg)))
5513
5514 call mpi_alltoallv(segments_send,roundsendcounts,roundsenddispls,mpi_double_precision,&
5515 segments_recv_round,roundrecvcounts,roundrecvdispls,&
5516 mpi_double_precision,icomm,ierrmpi)
5517
5518 if (totalroundseg>0) then
5519 segments_recv(:,recvfill+1:recvfill+totalroundseg)=segments_recv_round(:,1:totalroundseg)
5520 recvfill=recvfill+totalroundseg
5521 endif
5522 deallocate(segments_recv_round)
5523 enddo
5524
5525 if (recvfill/=totalseg) call mpistop("ray-segment receive mismatch")
5526
5527 if (totalseg>0) then
5528 allocate(idx(totalseg))
5529 bucketcounts(1:npixbatch)=0
5530 do is=1,totalseg
5531 if (segment_is_valid(segments_recv,is,4)) then
5532 ipix=nint(segments_recv(1,is))
5533 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
5534 ilocal=ipix-ipixstart+1
5535 bucketcounts(ilocal)=bucketcounts(ilocal)+1
5536 endif
5537 endif
5538 enddo
5539
5540 bucketoffsets(1)=1
5541 do ilocal=1,npixbatch
5542 bucketoffsets(ilocal+1)=bucketoffsets(ilocal)+bucketcounts(ilocal)
5543 enddo
5544 bucketfill(1:npixbatch)=bucketoffsets(1:npixbatch)
5545 do is=1,totalseg
5546 if (segment_is_valid(segments_recv,is,4)) then
5547 ipix=nint(segments_recv(1,is))
5548 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
5549 ilocal=ipix-ipixstart+1
5550 idx(bucketfill(ilocal))=is
5551 bucketfill(ilocal)=bucketfill(ilocal)+1
5552 endif
5553 endif
5554 enddo
5555
5556 do ipix=ipixstart,ipixend
5557 if (segment_pixel_owner(ipix)/=mype) cycle
5558 ilocal=ipix-ipixstart+1
5559 nidx=bucketcounts(ilocal)
5560 if (nidx>0) then
5561 profile_local(5)=profile_local(5)+dble(nidx)*dble(nidx)
5562 call sort_segment_indices_near_to_far(segments_recv,&
5563 idx(bucketoffsets(ilocal):bucketoffsets(ilocal+1)-1),nidx)
5564 ixglobal=1+mod(ipix-1,numxi1)
5565 iyglobal=1+(ipix-1)/numxi1
5566 do iseg=bucketoffsets(ilocal),bucketoffsets(ilocal+1)-1
5567 is=idx(iseg)
5568 euvthin(ixglobal,iyglobal)=euvthin(ixglobal,iyglobal)+segments_recv(3,is)
5569 atten=transfer_attenuation(tau(ixglobal,iyglobal))
5570 euv(ixglobal,iyglobal)=euv(ixglobal,iyglobal)+atten*segments_recv(3,is)
5571 tau(ixglobal,iyglobal)=tau(ixglobal,iyglobal)+max(zero,segments_recv(4,is))
5572 enddo
5573 endif
5574 enddo
5575 deallocate(idx)
5576 endif
5577
5578 deallocate(segments_send,segments_recv)
5579 if (allocated(segments)) deallocate(segments)
5580 ipixstart=ipixend+1
5581 enddo
5582
5583 do iigrid=1,igridstail
5584 if (allocated(cache(iigrid)%source)) deallocate(cache(iigrid)%source)
5585 if (allocated(cache(iigrid)%opacity)) deallocate(cache(iigrid)%opacity)
5586 if (allocated(cache(iigrid)%rface)) deallocate(cache(iigrid)%rface)
5587 if (allocated(cache(iigrid)%thetaface)) deallocate(cache(iigrid)%thetaface)
5588 if (allocated(cache(iigrid)%phiface)) deallocate(cache(iigrid)%phiface)
5589 if (allocated(cache(iigrid)%rface2)) deallocate(cache(iigrid)%rface2)
5590 if (allocated(cache(iigrid)%theta_cos)) deallocate(cache(iigrid)%theta_cos)
5591 if (allocated(cache(iigrid)%phi_sin)) deallocate(cache(iigrid)%phi_sin)
5592 if (allocated(cache(iigrid)%phi_cos)) deallocate(cache(iigrid)%phi_cos)
5593 enddo
5594 deallocate(cache)
5595 deallocate(sendcounts,recvcounts,senddispls,recvdispls,roundsendcounts,roundrecvcounts,&
5596 roundsenddispls,roundrecvdispls,ownersegcounts,owneroffsets,bucketcounts,&
5597 bucketoffsets,bucketfill)
5598 allocate(image_reduce(numxi1,numxi2))
5599 call mpi_allreduce(euv,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5600 euv=image_reduce
5601 call mpi_allreduce(tau,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5602 tau=image_reduce
5603 call mpi_allreduce(euvthin,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5604 euvthin=image_reduce
5605 deallocate(image_reduce)
5606 call mpi_allreduce(profile_local,profile_global,5,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5607 call mpi_allreduce(phys_max_local,phys_max_global,2,mpi_double_precision,mpi_max,icomm,ierrmpi)
5608 call mpi_allreduce(phys_sum_local,phys_sum_global,2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5609 call mpi_allreduce(sphddafallbacklocal,sphddafallbackglobal,1,mpi_integer,mpi_sum,icomm,ierrmpi)
5610 if (radsyn_verbose .and. mype==0) then
5611 if (sph_use_dda) then
5612 write(*,'(a,5(es12.5,1x))') ' sph_dda thick profile: ',profile_global
5613 write(*,'(a,i0)') ' sph_dda thick fallback rays: ',sphddafallbackglobal
5614 write(*,'(a,4(es12.5,1x))') ' sph_dda thick physics maxj maxk sumjds sumkds: ',&
5615 phys_max_global(1),phys_max_global(2),phys_sum_global(1),phys_sum_global(2)
5616 else
5617 write(*,'(a,5(es12.5,1x))') ' sph_intersection thick profile: ',profile_global
5618 write(*,'(a,4(es12.5,1x))') ' sph_intersection thick physics maxj maxk sumjds sumkds: ',&
5619 phys_max_global(1),phys_max_global(2),phys_sum_global(1),phys_sum_global(2)
5620 endif
5621 endif
5623
5624 }
5625
5626 {^ifthreed
5627
5628 subroutine get_sph_intersection_image_bounds(xImin1,xImax1,xImin2,xImax2)
5629 double precision, intent(out) :: xImin1,xImax1,xImin2,xImax2
5630
5631 integer, parameter :: nsample=5
5632 integer :: iigrid,igrid,ir,it,ip
5633 integer :: ixI^L,ixO^L
5634 double precision, allocatable :: rface(:),thetaface(:),phiface(:)
5635 double precision :: local_min1,local_max1,local_min2,local_max2
5636 double precision :: sph(1:3),xcent(1:2),wr,wt,wp
5637
5638 local_min1=huge(one)
5639 local_max1=-huge(one)
5640 local_min2=huge(one)
5641 local_max2=-huge(one)
5642
5643 do iigrid=1,igridstail
5644 igrid=igrids(iigrid)
5645 ^d&ixomin^d=ixmlo^d\
5646 ^d&ixomax^d=ixmhi^d\
5647 ^d&iximin^d=ixglo^d\
5648 ^d&iximax^d=ixghi^d\
5649
5650 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx(ixi^s,1:ndim),&
5651 rface,thetaface,phiface)
5652 do ir=0,nsample-1
5653 wr=dble(ir)/dble(nsample-1)
5654 sph(1)=(one-wr)*rface(ixomin1)+wr*rface(ixomax1+1)
5655 do it=0,nsample-1
5656 wt=dble(it)/dble(nsample-1)
5657 sph(2)=(one-wt)*thetaface(ixomin2)+wt*thetaface(ixomax2+1)
5658 do ip=0,nsample-1
5659 wp=dble(ip)/dble(nsample-1)
5660 if (ir/=0 .and. ir/=nsample-1 .and. it/=0 .and. it/=nsample-1 .and. &
5661 ip/=0 .and. ip/=nsample-1) cycle
5662 sph(3)=(one-wp)*phiface(ixomin3)+wp*phiface(ixomax3+1)
5663 call get_cor_image_spherical(sph,xcent)
5664 local_min1=min(local_min1,xcent(1))
5665 local_max1=max(local_max1,xcent(1))
5666 local_min2=min(local_min2,xcent(2))
5667 local_max2=max(local_max2,xcent(2))
5668 enddo
5669 enddo
5670 enddo
5671 deallocate(rface,thetaface,phiface)
5672 enddo
5673
5674 call mpi_allreduce(local_min1,ximin1,1,mpi_double_precision,mpi_min,icomm,ierrmpi)
5675 call mpi_allreduce(local_max1,ximax1,1,mpi_double_precision,mpi_max,icomm,ierrmpi)
5676 call mpi_allreduce(local_min2,ximin2,1,mpi_double_precision,mpi_min,icomm,ierrmpi)
5677 call mpi_allreduce(local_max2,ximax2,1,mpi_double_precision,mpi_max,icomm,ierrmpi)
5678 if (ximin1>0.5d0*huge(one) .or. ximax1<-0.5d0*huge(one) .or. &
5679 ximin2>0.5d0*huge(one) .or. ximax2<-0.5d0*huge(one)) then
5680 call mpistop("sph_intersection could not determine image bounds")
5681 endif
5683
5685 double precision, intent(out) :: dxI
5686
5687 select case(trim(dat_resolution_mode))
5688 case('nominal')
5690 case('minimum')
5692 case default
5693 call mpistop("unknown dat_resolution_mode")
5694 end select
5695 end subroutine get_native_datresol_spacing
5696
5698 double precision, intent(out) :: dxI
5699
5700 double precision :: refine_factor,dr,dtheta,dphi,rmin,sin_theta_min
5701
5702 refine_factor=dble(2**(refine_max_level-1))
5703 if (slab) then
5704 dxi=min(abs(xprobmax1-xprobmin1)/(dble(domain_nx1)*refine_factor),&
5705 abs(xprobmax2-xprobmin2)/(dble(domain_nx2)*refine_factor),&
5706 abs(xprobmax3-xprobmin3)/(dble(domain_nx3)*refine_factor))
5707 else if (coordinate==spherical) then
5708 rmin=max(smalldouble,min(xprobmin1,xprobmax1))
5709 sin_theta_min=max(smalldouble,min(abs(sin(xprobmin2)),&
5710 abs(sin(xprobmax2))))
5711 dr=abs(xprobmax1-xprobmin1)/(dble(domain_nx1)*refine_factor)
5712 dtheta=abs(xprobmax2-xprobmin2)/(dble(domain_nx2)*refine_factor)
5713 dphi=abs(xprobmax3-xprobmin3)/(dble(domain_nx3)*refine_factor)
5714 dxi=min(dr,rmin*dtheta,rmin*sin_theta_min*dphi)
5715 else
5716 call mpistop("nominal dat resolution needs Cartesian or spherical coordinates")
5717 endif
5718
5719 if (dxi<=zero .or. dxi>half*huge(one)) then
5720 call mpistop("could not determine nominal dat-resolution image spacing")
5721 endif
5722 end subroutine get_nominal_datresol_spacing
5723
5725 double precision, intent(out) :: dxI
5726
5727 integer :: iigrid,igrid,ixI^L,ixO^L,ix^D
5728 double precision :: local_min,global_min,dr,ds_theta,ds_phi,rval,theta
5729
5730 local_min=huge(one)
5731 do iigrid=1,igridstail
5732 igrid=igrids(iigrid)
5733 ^d&ixomin^d=ixmlo^d\
5734 ^d&ixomax^d=ixmhi^d\
5735 ^d&iximin^d=ixglo^d\
5736 ^d&iximax^d=ixghi^d\
5737
5738 do ix1=ixomin1,ixomax1
5739 do ix2=ixomin2,ixomax2
5740 do ix3=ixomin3,ixomax3
5741 if (slab) then
5742 local_min=min(local_min,ps(igrid)%dx(ix^d,1),&
5743 ps(igrid)%dx(ix^d,2),ps(igrid)%dx(ix^d,3))
5744 else if (coordinate==spherical) then
5745 rval=max(smalldouble,ps(igrid)%x(ix^d,1))
5746 theta=ps(igrid)%x(ix^d,2)
5747 dr=ps(igrid)%dx(ix^d,1)
5748 ds_theta=rval*ps(igrid)%dx(ix^d,2)
5749 ds_phi=rval*max(smalldouble,sin(theta))*ps(igrid)%dx(ix^d,3)
5750 local_min=min(local_min,dr,ds_theta,ds_phi)
5751 else
5752 call mpistop("minimum dat resolution needs Cartesian or spherical coordinates")
5753 endif
5754 enddo
5755 enddo
5756 enddo
5757 enddo
5758
5759 call mpi_allreduce(local_min,global_min,1,mpi_double_precision,mpi_min,&
5760 icomm,ierrmpi)
5761 if (global_min<=zero .or. global_min>half*huge(one)) then
5762 call mpistop("could not determine minimum dat-resolution image spacing")
5763 endif
5764 dxi=global_min
5765 end subroutine get_minimum_datresol_spacing
5766
5767 subroutine get_image(qunit,datatype,fl)
5768 ! integrate emission flux along line of sight (LOS)
5769 ! in a 3D simulation box and get a 2D EUV image
5771 use mod_constants
5772
5773 integer, intent(in) :: qunit
5774 type(te_fluid), intent(in) :: fl
5775 character(20), intent(in) :: datatype
5776
5777 integer :: ix^D,numXI1,numXI2,numWI
5778 double precision :: xImin1,xImax1,xImin2,xImax2,xIcent1,xIcent2,dxI
5779 double precision, allocatable :: xI1(:),xI2(:),dxI1(:),dxI2(:)
5780 double precision, allocatable :: wI(:,:,:),wIs(:,:,:),EM(:,:),Dpl(:,:),Tau(:,:),EMthin(:,:),WLB(:,:,:)
5781 double precision :: vec_temp1(1:3),vec_temp2(1:3)
5782 double precision :: vec_z(1:3),vec_cor(1:3),xI_cor(1:2)
5783 double precision :: res,LOS_psi,r_max,r_loc
5784
5785 integer :: mass
5786 character (30) :: ion
5787 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
5788 double precision :: arcsec,RHESSI_rsl,LASCO_rsl,pixel,R_occult,smallflux
5789 integer :: iigrid,igrid,i,j,numSI,iw
5790 logical :: emit,ray_image_global,has_thick_output
5791
5792 if (coordinate==spherical) then
5794 else
5795 ! cartesian
5797 endif
5798
5799 ! calculate domain of the image
5800 if (coordinate==spherical) then
5801 if (trim(ray_method_active)=='spherical' .and. datatype=='image_euv') then
5802 call get_sph_intersection_image_bounds(ximin1,ximax1,ximin2,ximax2)
5803 else
5804 ximin1=-abs(xprobmax1)
5805 ximin2=-abs(xprobmax1)
5806 ximax1=abs(xprobmax1)
5807 ximax2=abs(xprobmax1)
5808 endif
5809 else
5810 ! calculate domain of the image
5811 do ix1=1,2
5812 if (ix1==1) vec_cor(1)=xprobmin1
5813 if (ix1==2) vec_cor(1)=xprobmax1
5814 do ix2=1,2
5815 if (ix2==1) vec_cor(2)=xprobmin2
5816 if (ix2==2) vec_cor(2)=xprobmax2
5817 do ix3=1,2
5818 if (ix3==1) vec_cor(3)=xprobmin3
5819 if (ix3==2) vec_cor(3)=xprobmax3
5820 if (big_image) then
5821 r_loc=(vec_cor(1)-x_origin(1))**2
5822 r_loc=r_loc+(vec_cor(2)-x_origin(2))**2
5823 r_loc=r_loc+(vec_cor(3)-x_origin(3))**2
5824 r_loc=sqrt(r_loc)
5825 if (ix1==1 .and. ix2==1 .and. ix3==1) then
5826 r_max=r_loc
5827 else
5828 r_max=max(r_max,r_loc)
5829 endif
5830 else
5831 call get_cor_image(vec_cor,xi_cor)
5832 if (ix1==1 .and. ix2==1 .and. ix3==1) then
5833 ximin1=xi_cor(1)
5834 ximax1=xi_cor(1)
5835 ximin2=xi_cor(2)
5836 ximax2=xi_cor(2)
5837 else
5838 ximin1=min(ximin1,xi_cor(1))
5839 ximax1=max(ximax1,xi_cor(1))
5840 ximin2=min(ximin2,xi_cor(2))
5841 ximax2=max(ximax2,xi_cor(2))
5842 endif
5843 endif
5844 enddo
5845 enddo
5846 enddo
5847 if (big_image) then
5848 ximin1=-r_max
5849 ximin2=-r_max
5850 ximax1=r_max
5851 ximax2=r_max
5852 endif
5853 endif
5854 xicent1=(ximin1+ximax1)/2.d0
5855 xicent2=(ximin2+ximax2)/2.d0
5856
5857 ! tables for image
5858 if (si_unit) then
5859 arcsec=7.25d5/unit_length
5860 else
5861 arcsec=7.25d7/unit_length
5862 endif
5863 if (datatype=='image_euv') then
5864 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
5865 dxi=spacersl*arcsec ! intrument resolution of image
5866 smallflux=smalldouble
5867 else if (datatype=='image_sxr') then
5868 rhessi_rsl=2.3d0/instrument_resolution_factor
5869 dxi=rhessi_rsl*arcsec
5870 smallflux=1.d-40
5871 else if (datatype=='image_whitelight') then
5872 if (whitelight_instrument=='LASCO/C1') then
5873 lasco_rsl=5.6d0/instrument_resolution_factor
5874 r_occult=1.1d0
5875 else if (whitelight_instrument=='LASCO/C2') then
5876 lasco_rsl=11.4d0/instrument_resolution_factor
5877 r_occult=2.d0
5878 else if (whitelight_instrument=='LASCO/C3') then
5879 lasco_rsl=56.d0/instrument_resolution_factor
5880 r_occult=3.7d0
5881 else
5882 call mpistop('Whitelight synthesis: instrument is not supported!')
5883 endif
5884 dxi=lasco_rsl*arcsec
5885 if (r_occultor>1.d0) r_occult=r_occultor
5886 r_occult=r_occult*const_rsun/unit_length
5887 smallflux=1.d-20
5888 endif
5889 numxi1=8*ceiling((ximax1-xicent1)/dxi/8.d0)
5890 ximin1=xicent1-numxi1*dxi
5891 ximax1=xicent1+numxi1*dxi
5892 numxi1=numxi1*2
5893 numxi2=8*ceiling((ximax2-xicent2)/dxi/8.d0)
5894 ximin2=xicent2-numxi2*dxi
5895 ximax2=xicent2+numxi2*dxi
5896 numxi2=numxi2*2
5897 allocate(xi1(numxi1),xi2(numxi2),dxi1(numxi1),dxi2(numxi2))
5898 do ix1=1,numxi1
5899 xi1(ix1)=ximin1+dxi*(ix1-half)
5900 dxi1(ix1)=dxi
5901 enddo
5902 do ix2=1,numxi2
5903 xi2(ix2)=ximin2+dxi*(ix2-half)
5904 dxi2(ix2)=dxi
5905 enddo
5906
5907 ! calculate emission
5908 if (datatype=='image_euv' .or. datatype=='image_sxr') then
5909 has_thick_output=datatype=='image_euv' .and. trim(radiation_transfer)=='thick' .and. &
5910 ((coordinate==spherical .and. trim(ray_method_active)=='spherical') .or. &
5911 (slab .and. trim(ray_method_active)=='cart'))
5912 if (datatype=='image_euv') then
5913 numwi=radsyn_euv_num_outputs(.false.,has_thick_output)
5914 else
5915 numwi=1
5916 endif
5917 allocate(wi(numxi1,numxi2,numwi),wis(numxi1,numxi2,numwi),em(numxi1,numxi2))
5918 wi=zero
5919 wis=zero
5920 em=zero
5921 ray_image_global=.false.
5922 if (has_thick_output) then
5923 allocate(tau(numxi1,numxi2),emthin(numxi1,numxi2))
5924 tau=zero
5925 emthin=zero
5926 endif
5927 if (slab .and. datatype=='image_euv' .and. &
5928 trim(ray_method_active)=='cart') then
5929 ray_image_global=.true.
5930 allocate(dpl(numxi1,numxi2))
5931 dpl=zero
5932 if (trim(radiation_transfer)=='thick') then
5933 call integrate_euv_cart_dda_thick_datresol(numxi1,numxi2,xi1,xi2,fl,em,dpl,tau,emthin)
5934 else
5935 call integrate_euv_cart_dda_datresol(numxi1,numxi2,xi1,xi2,fl,em,dpl)
5936 endif
5937 deallocate(dpl)
5938 else if (slab) then
5939 do iigrid=1,igridstail; igrid=igrids(iigrid);
5940 call integrate_emission_cartesian(igrid,numxi1,numxi2,xi1,xi2,dxi,fl,datatype,em)
5941 enddo
5942 else if (trim(ray_method_active) == 'spherical' .and. datatype == 'image_euv') then
5943 if (trim(radiation_transfer) == 'thick') then
5944 ray_image_global=.true.
5945 call integrate_euv_sph_intersection_thick(numxi1,numxi2,xi1,xi2,dxi,fl,em,tau,emthin)
5946 else
5947 call integrate_euv_sph_intersection_thin(numxi1,numxi2,xi1,xi2,dxi,fl,em)
5948 endif
5949 else
5950 do iigrid=1,igridstail; igrid=igrids(iigrid);
5951 call integrate_emission_spherical(igrid,numxi1,numxi2,xi1,xi2,dxi,fl,datatype,em)
5952 enddo
5953 endif
5954 if (ray_image_global) then
5955 if (has_thick_output) then
5956 call pack_euv_image_outputs(numxi1,numxi2,em,wi,smallflux,.false.,&
5957 has_thick_output,tau=tau,euvthin=emthin,&
5958 cap_absorption=.true.)
5959 else
5960 call pack_euv_image_outputs(numxi1,numxi2,em,wi,smallflux,.false.,has_thick_output)
5961 endif
5962 else
5963 do ix1=1,numxi1
5964 do ix2=1,numxi2
5965 if (em(ix1,ix2)>smallflux) wis(ix1,ix2,1)=em(ix1,ix2)
5966 enddo
5967 enddo
5968 endif
5969 if (.not. ray_image_global) then
5970 numsi=numxi1*numxi2*numwi
5971 call mpi_allreduce(wis,wi,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5972 endif
5973 if (activate_unit_arcsec) then
5974 xi1=xi1/arcsec
5975 dxi1=dxi1/arcsec
5976 xi2=xi2/arcsec
5977 dxi2=dxi2/arcsec
5978 endif
5979 call output_data(qunit,xi1,xi2,dxi1,dxi2,wi,numxi1,numxi2,numwi,datatype)
5980 if (allocated(tau)) deallocate(tau)
5981 if (allocated(emthin)) deallocate(emthin)
5982 deallocate(wi,wis,em)
5983 else if (datatype=='image_whitelight') then
5984 numwi=2
5985 allocate(wi(numxi1,numxi2,numwi),wis(numxi1,numxi2,numwi),wlb(numxi1,numxi2,numwi))
5986 wi=zero
5987 wis=zero
5988 wlb=zero
5989 if (coordinate==spherical) then
5990 do iigrid=1,igridstail; igrid=igrids(iigrid);
5991 call integrate_whitelight_spherical(igrid,numxi1,numxi2,numwi,xi1,xi2,dxi,fl,datatype,wlb)
5992 enddo
5993 endif
5994 do ix1=1,numxi1
5995 do ix2=1,numxi2
5996 if (wlb(ix1,ix2,1)>smallflux) then
5997 wis(ix1,ix2,1)=wlb(ix1,ix2,1)
5998 wis(ix1,ix2,2)=wlb(ix1,ix2,2)
5999 endif
6000 enddo
6001 enddo
6002 numsi=numxi1*numxi2*numwi
6003 call mpi_allreduce(wis,wi,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
6004 if (activate_unit_arcsec) then
6005 xi1=xi1/arcsec
6006 dxi1=dxi1/arcsec
6007 xi2=xi2/arcsec
6008 dxi2=dxi2/arcsec
6009 endif
6010 call output_data(qunit,xi1,xi2,dxi1,dxi2,wi,numxi1,numxi2,numwi,datatype)
6011 deallocate(wi,wis,wlb)
6012 endif
6013
6014 deallocate(xi1,xi2,dxi1,dxi2)
6015
6016 end subroutine get_image
6017
6018 subroutine integrate_emission_cartesian(igrid,numXI1,numXI2,xI1,xI2,dxI,fl,datatype,EM)
6019 integer, intent(in) :: igrid,numXI1,numXI2
6020 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6021 double precision, intent(in) :: dxI
6022 type(te_fluid), intent(in) :: fl
6023 character(20), intent(in) :: datatype
6024 double precision, intent(inout) :: EM(numXI1,numXI2)
6025
6026 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6027 double precision :: xb^L,xd^D
6028 double precision, allocatable :: flux(:^D&),opacity(:^D&)
6029 double precision :: res
6030 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6031 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC
6032 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2)
6033
6034 integer :: mass
6035 double precision :: logTe
6036 character (30) :: ion
6037 double precision :: lineCent
6038 double precision :: sigma_PSF,spaceRsl,wlRsl,sigma0,factor,wslit
6039 double precision :: arcsec,pixel,RHESSI_rsl,area_1AU
6040 double precision :: aa,bb
6041
6042 ^d&ixomin^d=ixmlo^d\
6043 ^d&ixomax^d=ixmhi^d\
6044 ^d&iximin^d=ixglo^d\
6045 ^d&iximax^d=ixghi^d\
6046 ^d&xbmin^d=rnode(rpxmin^d_,igrid)\
6047 ^d&xbmax^d=rnode(rpxmax^d_,igrid)\
6048
6049 if (si_unit) then
6050 arcsec=7.25d5/unit_length
6051 else
6052 arcsec=7.25d7/unit_length
6053 endif
6054
6055 allocate(flux(ixi^s),opacity(ixi^s))
6056 if (datatype=='image_euv') then
6057 if (trim(emission_model)=='pseudo_current') then
6058 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,flux)
6059 else if (trim(emission_model)=='radio_ff') then
6060 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,opacity)
6061 else
6062 ! get local EUV flux and velocity
6063 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
6064 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
6065 endif
6066 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
6067 pixel=spacersl*arcsec
6068 sigma0=sigma_psf*pixel
6069 else if (datatype=='image_sxr') then
6070 ! get local SXR flux photons cm^-3 s^-1 (cgs) or photons m^-3 s^-1 (SI)
6071 call get_sxr(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,emin_sxr,emax_sxr)
6072 rhessi_rsl=2.3d0/instrument_resolution_factor
6073 sigma_psf=1.d0
6074 pixel=rhessi_rsl*arcsec
6075 sigma0=sigma_psf*pixel
6076 area_1au=2.81d27
6077 endif
6078
6079 ! integrate emission
6080 {do ix^d=ixomin^d,ixomax^d\}
6081 ^d&nsubc^d=1;
6082 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi1(^d))/(dxi/2.d0)));
6083 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi2(^d))/(dxi/2.d0)));
6084 ^d&dxsubc^d=ps(igrid)%dx(ix^dd,^d)/nsubc^d;
6085 if (datatype=='image_euv') then
6086 if (si_unit) then
6087 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length*1.d2/dxi/dxi ! DN s^-1
6088 else
6089 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length/dxi/dxi ! DN s^-1
6090 endif
6091 else if (datatype=='image_sxr') then
6092 ! sub-cell SXR flux at 1 AU [photons s^-1 cm^-2]
6093 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length**3/area_1au
6094 endif
6095 if (fluxsubc>smalldouble) then
6096 ! dividing a cell to several parts to get more accurate integrating values
6097 {do isubc^d=1,nsubc^d\}
6098 ^d&xsubc(^d)=ps(igrid)%x(ix^dd,^d)-half*ps(igrid)%dx(ix^dd,^d)+(isubc^d-half)*dxsubc^d;
6099 ! mapping the 3D coordinate to location at the image
6100 call get_cor_image(xsubc,xcent)
6101 ! distribution at nearby pixels
6102 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6103 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6104 ixpmin1=max(1,ixp1-3)
6105 ixpmax1=min(ixp1+3,numxi1)
6106 ixpmin2=max(1,ixp2-3)
6107 ixpmax2=min(ixp2+3,numxi2)
6108 do ixp1=ixpmin1,ixpmax1
6109 do ixp2=ixpmin2,ixpmax2
6110 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6111 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6112 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6113 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6114 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6115 em(ixp1,ixp2)=em(ixp1,ixp2)+fluxsubc*factor
6116 enddo !ixP2
6117 enddo !ixP1
6118 {enddo\} !iSubC
6119 endif
6120 {enddo\} !ix
6121
6122 deallocate(flux,opacity)
6123 end subroutine integrate_emission_cartesian
6124
6125 subroutine integrate_emission_spherical(igrid,numXI1,numXI2,xI1,xI2,dxI,fl,datatype,EM)
6126 integer, intent(in) :: igrid,numXI1,numXI2
6127 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6128 double precision, intent(in) :: dxI
6129 type(te_fluid), intent(in) :: fl
6130 character(20), intent(in) :: datatype
6131 double precision, intent(inout) :: EM(numXI1,numXI2)
6132
6133 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6134 double precision, allocatable :: flux(:^D&),Ne(:^D&),opacity(:^D&)
6135 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6136 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC,RsubC
6137 double precision :: TBsubC,PBsubC
6138 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2),xSubC_car(1:3)
6139 double precision :: R_thick,dotp,dvolume,R_occult,Rc
6140 double precision :: dxl(1:3),x_sph(1:3),dx_sph(1:3)
6141 double precision :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6142 logical :: sun_back_side,emit
6143
6144 integer :: mass
6145 double precision :: logTe
6146 character (30) :: ion
6147 double precision :: lineCent
6148 double precision :: sigma_PSF,spaceRsl,wlRsl,sigma0,factor,wslit
6149 double precision :: RHESSI_rsl,area_1AU,arcsec,pixel
6150
6151 ^d&ixomin^d=ixmlo^d;
6152 ^d&ixomax^d=ixmhi^d;
6153 ^d&iximin^d=ixglo^d;
6154 ^d&iximax^d=ixghi^d;
6155
6156 if (si_unit) then
6157 arcsec=7.25d5/unit_length
6158 else
6159 arcsec=7.25d7/unit_length
6160 endif
6161
6162 allocate(flux(ixi^s),opacity(ixi^s))
6163 if (datatype=='image_euv') then
6164 if (trim(emission_model)=='pseudo_current') then
6165 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,flux)
6166 else if (trim(emission_model)=='radio_ff') then
6167 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,opacity)
6168 else
6169 ! get local EUV flux and velocity
6170 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
6171 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
6172 endif
6173 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
6174 pixel=spacersl*arcsec
6175 sigma0=sigma_psf*pixel
6176 else if (datatype=='image_sxr') then
6177 ! get local SXR flux photons cm^-3 s^-1 (cgs) or photons m^-3 s^-1 (SI)
6178 call get_sxr(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,emin_sxr,emax_sxr)
6179 rhessi_rsl=2.3d0/instrument_resolution_factor
6180 sigma_psf=1.d0
6181 pixel=rhessi_rsl*arcsec
6182 sigma0=sigma_psf*pixel
6183 area_1au=2.81d27
6184 endif
6185
6186 ! integrate emission
6187 r_thick=r_opt_thick*const_rsun/unit_length
6188 {do ix^d=ixomin^d,ixomax^d\}
6189 x_sph(1:3)=ps(igrid)%x(ix^d,1:3)
6190 dx_sph(1:3)=ps(igrid)%dx(ix^d,1:3)
6191 dxl(1)=dx_sph(1) ! cell size in length
6192 dxl(2)=x_sph(1)*dx_sph(2) ! cell size in length
6193 dxl(3)=x_sph(1)*dsin(x_sph(2))*dx_sph(3) ! cell size in length
6194 ! dividing a cell to several sub-cells to get more accurate integrating values
6195 ^d&nsubc^d=1;
6196 call get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6197 call dot_product_loc(unitv_r,vec_xi1,dotp)
6198 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6199 call dot_product_loc(unitv_r,vec_xi2,dotp)
6200 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6201 call dot_product_loc(unitv_theta,vec_xi1,dotp)
6202 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6203 call dot_product_loc(unitv_theta,vec_xi2,dotp)
6204 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6205 call dot_product_loc(unitv_phi,vec_xi1,dotp)
6206 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6207 call dot_product_loc(unitv_phi,vec_xi2,dotp)
6208 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6209
6210 ! integrate sub-cells
6211 do isubc1=1,nsubc1
6212 ! sub-cell center coordinate in spherical
6213 xsubc(1)=x_sph(1)-half*dx_sph(1)+(isubc1-half)*dx_sph(1)/nsubc1
6214 rsubc=xsubc(1)
6215 dxsubc1=dx_sph(1)/nsubc1 ! sub-cell size in length
6216 do isubc2=1,nsubc2
6217 ! sub-cell center coordinate in spherical
6218 xsubc(2)=x_sph(2)-half*dx_sph(2)+(isubc2-half)*dx_sph(2)/nsubc2
6219 dxsubc2=xsubc(1)*dx_sph(2)/nsubc2 ! sub-cell size in length
6220 dxsubc3=xsubc(1)*dsin(xsubc(2))*dx_sph(3)/nsubc3 ! sub-cell size in length
6221 dvolume=dxsubc1*dxsubc2*dxsubc3
6222 if (datatype=='image_euv') then
6223 if (si_unit) then
6224 fluxsubc=flux(ix^d)*dvolume*unit_length*1.d2/dxi/dxi ! DN s^-1
6225 else
6226 fluxsubc=flux(ix^d)*dvolume*unit_length/dxi/dxi ! DN s^-1
6227 endif
6228 else if (datatype=='image_sxr') then
6229 ! sub-cell SXR flux at 1 AU [photons s^-1 cm^-2]
6230 fluxsubc=flux(ix^d)*dvolume*unit_length**3/area_1au
6231 endif
6232 ! enter integration if flux large enough
6233 if (fluxsubc>smalldouble) then
6234 do isubc3=1,nsubc3
6235 ! sub-cell center coordinate in spherical
6236 xsubc(3)=x_sph(3)-half*dx_sph(3)+(isubc3-half)*dx_sph(3)/nsubc3
6237 call get_cor_image_spherical(xsubc,xcent)
6238 rc=dsqrt(xcent(1)**2+xcent(2)**2) ! distance to sun center (on the image plane)
6239 !
6240 ! whether the local emitted photons can arrive the telescope
6241 call spherical_to_cartesian(xsubc,xsubc_car)
6242 call dot_product_loc(vec_los,xsubc_car,dotp)
6243 sun_back_side=.true.
6244 if (dotp<0.d0) sun_back_side=.false.
6245 ! whether the local emission can reach the telescope
6246 if (sun_back_side) then
6247 emit=.false.
6248 if (rc>r_thick) emit=.true.
6249 else
6250 emit=.true.
6251 if (xsubc(1)<=r_thick) emit=.false.
6252 endif
6253 !
6254 if (emit) then
6255 ! mapping the 3D coordinate to location at the image
6256 ! distribution at nearby pixels
6257 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6258 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6259 ixpmin1=max(1,ixp1-3)
6260 ixpmax1=min(ixp1+3,numxi1)
6261 ixpmin2=max(1,ixp2-3)
6262 ixpmax2=min(ixp2+3,numxi2)
6263 do ixp1=ixpmin1,ixpmax1
6264 do ixp2=ixpmin2,ixpmax2
6265 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6266 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6267 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6268 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6269 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6270 em(ixp1,ixp2)=em(ixp1,ixp2)+fluxsubc*factor
6271 enddo !ixP2
6272 enddo !ixP1
6273 endif !emit
6274 enddo !iSubC3
6275 endif !smallflux
6276 enddo !iSubC2
6277 enddo !iSubC1
6278 {enddo\} !ix
6279
6280 deallocate(flux,opacity)
6281
6282 end subroutine integrate_emission_spherical
6283
6284 subroutine integrate_whitelight_spherical(igrid,numXI1,numXI2,numWI,xI1,xI2,dxI,fl,datatype,WLB)
6285 use mod_eos, only: eos
6286
6287 integer, intent(in) :: igrid,numXI1,numXI2,numWI
6288 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6289 double precision, intent(in) :: dxI
6290 type(te_fluid), intent(in) :: fl
6291 character(20), intent(in) :: datatype
6292 double precision, intent(inout) :: WLB(numXI1,numXI2,numWI)
6293
6294 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6295 double precision, allocatable :: flux(:^D&),Ne(:^D&),nH_dummy(:^D&)
6296 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6297 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC,RsubC
6298 double precision :: sigma_PSF,sigma0,arcsec,pixel,LASCO_rsl
6299 double precision :: A,B,C,D,Rc,Ne0,TBsubC,PBsubC,factor
6300 double precision :: R_thick,dotp,dvolume,R_occult
6301 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2),xSubC_car(1:3)
6302 double precision :: dxl(1:3),x_sph(1:3),dx_sph(1:3)
6303 double precision :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6304 logical :: emit
6305
6306 ^d&ixomin^d=ixmlo^d;
6307 ^d&ixomax^d=ixmhi^d;
6308 ^d&iximin^d=ixglo^d;
6309 ^d&iximax^d=ixghi^d;
6310
6311 if (si_unit) then
6312 arcsec=7.25d5/unit_length
6313 else
6314 arcsec=7.25d7/unit_length
6315 endif
6316
6317 allocate(ne(ixi^s))
6318 allocate(nh_dummy(ixi^s))
6319 if (whitelight_instrument=='LASCO/C1') then
6320 lasco_rsl=5.6d0/instrument_resolution_factor
6321 r_occult=1.1d0
6322 else if (whitelight_instrument=='LASCO/C2') then
6323 lasco_rsl=11.4d0/instrument_resolution_factor
6324 r_occult=2.d0
6325 else if (whitelight_instrument=='LASCO/C3') then
6326 lasco_rsl=56.d0/instrument_resolution_factor
6327 r_occult=3.7d0
6328 endif
6329 if (r_occultor>1.d0) r_occult=r_occultor
6330 r_occult=r_occult*const_rsun/unit_length
6331 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,ne)
6332 ! get actual electron density from EoS (replaces rho with ne)
6333 call eos%get_ne_nH(ixi^l, ixo^l, ps(igrid)%w, ps(igrid)%x, ne, nh_dummy)
6334 sigma_psf=1.d0
6335 pixel=lasco_rsl*arcsec
6336 sigma0=sigma_psf*pixel
6337
6338 ! integrate emission
6339 r_thick=r_opt_thick*const_rsun/unit_length
6340 {do ix^d=ixomin^d,ixomax^d\}
6341 x_sph(1:3)=ps(igrid)%x(ix^d,1:3)
6342 dx_sph(1:3)=ps(igrid)%dx(ix^d,1:3)
6343 dxl(1)=dx_sph(1) ! cell size in length
6344 dxl(2)=x_sph(1)*dx_sph(2) ! cell size in length
6345 dxl(3)=x_sph(1)*dsin(x_sph(2))*dx_sph(3) ! cell size in length
6346 ne0=ne(ix^d)*unit_numberdensity
6347 ! dividing a cell to several sub-cells to get more accurate integrating values
6348 ^d&nsubc^d=1;
6349 call get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6350 call dot_product_loc(unitv_r,vec_xi1,dotp)
6351 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6352 call dot_product_loc(unitv_r,vec_xi2,dotp)
6353 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6354 call dot_product_loc(unitv_theta,vec_xi1,dotp)
6355 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6356 call dot_product_loc(unitv_theta,vec_xi2,dotp)
6357 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6358 call dot_product_loc(unitv_phi,vec_xi1,dotp)
6359 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6360 call dot_product_loc(unitv_phi,vec_xi2,dotp)
6361 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6362
6363 ! integrate sub-cells
6364 do isubc1=1,nsubc1
6365 ! sub-cell center coordinate in spherical
6366 xsubc(1)=x_sph(1)-half*dx_sph(1)+(isubc1-half)*dx_sph(1)/nsubc1
6367 rsubc=xsubc(1)
6368 dxsubc1=dx_sph(1)/nsubc1 ! sub-cell size in length
6369 call get_thomson_parameters(rsubc,a,b,c,d)
6370 do isubc2=1,nsubc2
6371 ! sub-cell center coordinate in spherical
6372 xsubc(2)=x_sph(2)-half*dx_sph(2)+(isubc2-half)*dx_sph(2)/nsubc2
6373 dxsubc2=xsubc(1)*dx_sph(2)/nsubc2 ! sub-cell size in length
6374 dxsubc3=xsubc(1)*dsin(xsubc(2))*dx_sph(3)/nsubc3 ! sub-cell size in length
6375 dvolume=dxsubc1*dxsubc2*dxsubc3
6376 do isubc3=1,nsubc3
6377 ! sub-cell center coordinate in spherical
6378 xsubc(3)=x_sph(3)-half*dx_sph(3)+(isubc3-half)*dx_sph(3)/nsubc3
6379 call get_cor_image_spherical(xsubc,xcent)
6380 rc=dsqrt(xcent(1)**2+xcent(2)**2) ! distance to sun center (on the image plane)
6381 ! whether the local emitted photons can arrive the telescope
6382 emit=.false.
6383 if (rc>r_occult) then
6384 emit=.true.
6385 ! scaterring flux from cm^-3 of plasma
6386 call get_whitelight_thomson(rsubc,rc,ne0,a,b,c,d,tbsubc,pbsubc)
6387 tbsubc=tbsubc*dvolume*unit_length/dxi/dxi
6388 pbsubc=pbsubc*dvolume*unit_length/dxi/dxi
6389 if (tbsubc<1.d-20) emit=.false.
6390 endif
6391 if (emit) then
6392 ! mapping the 3D coordinate to location at the image
6393 ! distribution at nearby pixels
6394 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6395 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6396 ixpmin1=max(1,ixp1-3)
6397 ixpmax1=min(ixp1+3,numxi1)
6398 ixpmin2=max(1,ixp2-3)
6399 ixpmax2=min(ixp2+3,numxi2)
6400 do ixp1=ixpmin1,ixpmax1
6401 do ixp2=ixpmin2,ixpmax2
6402 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6403 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6404 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6405 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6406 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6407 wlb(ixp1,ixp2,1)=wlb(ixp1,ixp2,1)+tbsubc*factor
6408 wlb(ixp1,ixp2,2)=wlb(ixp1,ixp2,2)+pbsubc*factor
6409 enddo !ixP2
6410 enddo !ixP1
6411 endif
6412 enddo !iSubC3
6413 enddo !iSubC2
6414 enddo !iSubC1
6415 {enddo\} !ix
6416
6417 deallocate(ne)
6418 deallocate(nh_dummy)
6419
6420 end subroutine integrate_whitelight_spherical
6421
6422 subroutine get_thomson_parameters(Rl,A,B,C,D)
6423 ! parameters given in Billings 1968
6424 use mod_constants
6425 double precision, intent(in) :: Rl
6426 double precision, intent(inout) :: A,B,C,D
6427
6428 double precision :: sinO,cosO,sinO2,cosO2,tmp
6429
6430 sino=const_rsun/(rl*unit_length)
6431 sino2=sino**2
6432 coso2=1.d0-sino2
6433 coso=abs(dsqrt(coso2))
6434 tmp=log((1.d0+sino)/coso)
6435 a=coso*sino2
6436 b=-(1.d0-3.d0*sino2-(coso2/sino)*(1.d0+3.d0*sino2)*tmp)/8.d0
6437 c=4.d0/3.d0-coso-coso*coso2/3.d0
6438 d=(5.d0+sino2-(coso2/sino)*(5.d0-sino2)*tmp)/8.d0
6439
6440 end subroutine get_thomson_parameters
6441
6442 subroutine get_whitelight_thomson(Rl,Rin,Ne,A,B,C,D,fluxTB,fluxPB)
6443 ! use the method in SSW/eltheory
6444 double precision, intent(in) :: Rl,Rin,Ne,A,B,C,D
6445 double precision, intent(inout) :: fluxTB,fluxPB
6446
6447 double precision :: const,u,Bt,Br,PB,TB,sinchi2
6448
6449 u=0.63d0
6450 const=1.24878d-25/(1.d0-u/3.d0)
6451 sinchi2=(rin/rl)**2
6452 bt=const*(c+u*(d-c))
6453 pb=const*sinchi2*((a+u*(b-a)))
6454 br=bt-pb
6455 tb=bt+br
6456 fluxtb=tb*ne
6457 fluxpb=pb*ne
6458
6459 end subroutine get_whitelight_thomson
6460
6461 subroutine get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6462 double precision, intent(in) :: x_sph(1:3)
6463 double precision, intent(inout) :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6464
6465 unitv_r(1)=dsin(x_sph(2))*dcos(x_sph(3))
6466 unitv_r(2)=dsin(x_sph(2))*dsin(x_sph(3))
6467 unitv_r(3)=dcos(x_sph(2))
6468 unitv_theta(1)=dcos(x_sph(2))*dcos(x_sph(3))
6469 unitv_theta(2)=dcos(x_sph(2))*dsin(x_sph(3))
6470 unitv_theta(3)=-dsin(x_sph(2))
6471 unitv_phi(1)=-dsin(x_sph(3))
6472 unitv_phi(2)=dcos(x_sph(3))
6473 unitv_phi(3)=zero
6474
6475 end subroutine get_unit_vector_spherical
6476
6477 subroutine output_data(qunit,xO1,xO2,dxO1,dxO2,wO,nXO1,nXO2,nWO,datatype)
6478 ! change the format of data and write data
6480
6481 integer, intent(in) :: qunit,nXO1,nXO2,nWO
6482 double precision, intent(in) :: dxO1(nxO1),dxO2(nxO2)
6483 double precision, intent(in) :: xO1(nXO1),xO2(nxO2)
6484 double precision, intent(inout) :: wO(nXO1,nXO2,nWO)
6485 character(20), intent(in) :: datatype
6486
6487 integer :: nPiece,nP1,nP2,nC1,nC2,nWC
6488 integer :: piece_nmax1,piece_nmax2,ix1,ix2,j,ipc,ixc1,ixc2
6489 double precision :: uniform_tol
6490 double precision, allocatable :: xC(:,:,:,:),wC(:,:,:,:),dxC(:,:,:,:)
6491
6492 ! clean small values
6493 uniform_tol=1.d-10
6494 do ix1=1,nxo1
6495 do ix2=1,nxo2
6496 do j=1,nwo
6497 if (abs(wo(ix1,ix2,j))<smalldouble) wo(ix1,ix2,j)=zero
6498 enddo
6499 enddo
6500 enddo
6501
6502 ! how many cells in each grid
6503 if (dat_resolution) then
6504 if (datatype=='image_euv' .or. datatype=='image_sxr') then
6505 if (los_phi==0 .and. los_theta==90) then
6506 piece_nmax1=block_nx2
6507 piece_nmax2=block_nx3
6508 else if (los_phi==90 .and. los_theta==90) then
6509 piece_nmax1=block_nx3
6510 piece_nmax2=block_nx1
6511 else
6512 piece_nmax1=block_nx1
6513 piece_nmax2=block_nx2
6514 endif
6515 else if (datatype=='spectrum_euv') then
6516 piece_nmax1=16
6517 if (direction_slit==1) then
6518 piece_nmax2=block_nx1
6519 else if (direction_slit==2) then
6520 piece_nmax2=block_nx2
6521 else
6522 piece_nmax2=block_nx3
6523 endif
6524 endif
6525 else
6526 piece_nmax1=20
6527 piece_nmax2=20
6528 endif
6529 loopn1: do j=piece_nmax1,1,-1
6530 if(mod(nxo1,j)==0) then
6531 nc1=j
6532 exit loopn1
6533 endif
6534 enddo loopn1
6535 loopn2: do j=piece_nmax2,1,-1
6536 if(mod(nxo2,j)==0) then
6537 nc2=j
6538 exit loopn2
6539 endif
6540 enddo loopn2
6541 ! how many grids
6542 np1=nxo1/nc1
6543 np2=nxo2/nc2
6544 npiece=np1*np2
6545 nwc=nwo
6546
6547 ! output images
6548 select case(convert_type)
6549 case('EIvtuCCmpi','ESvtuCCmpi','SIvtuCCmpi','WIvtuCCmpi')
6550 ! put data into grids
6551 allocate(xc(npiece,nc1,nc2,2))
6552 allocate(dxc(npiece,nc1,nc2,2))
6553 allocate(wc(npiece,nc1,nc2,nwo))
6554 do ipc=1,npiece
6555 do ixc1=1,nc1
6556 do ixc2=1,nc2
6557 ix1=mod(ipc-1,np1)*nc1+ixc1
6558 ix2=floor(1.0*(ipc-1)/np1)*nc2+ixc2
6559 xc(ipc,ixc1,ixc2,1)=xo1(ix1)
6560 xc(ipc,ixc1,ixc2,2)=xo2(ix2)
6561 dxc(ipc,ixc1,ixc2,1)=dxo1(ix1)
6562 dxc(ipc,ixc1,ixc2,2)=dxo2(ix2)
6563 do j=1,nwc
6564 wc(ipc,ixc1,ixc2,j)=wo(ix1,ix2,j)
6565 enddo
6566 enddo
6567 enddo
6568 enddo
6569 ! write data into vtu file
6570 call write_image_vtucc(qunit,xc,wc,dxc,npiece,nc1,nc2,nwc,datatype)
6571 deallocate(xc,dxc,wc)
6572 case('EIvtiCCmpi','ESvtiCCmpi','SIvtiCCmpi','WIvtiCCmpi')
6573 if (dat_resolution .and. &
6574 (maxval(abs(dxo1(:)-dxo1(1)))>uniform_tol*max(one,abs(dxo1(1))) .or. &
6575 maxval(abs(dxo2(:)-dxo2(1)))>uniform_tol*max(one,abs(dxo2(1))))) then
6576 call mpistop("vti needs uniform dat-resolution image grids")
6577 else
6578 call write_image_vticc(qunit,xo1,xo2,dxo1,dxo2,wo,nxo1,nxo2,nwo,nc1,nc2)
6579 endif
6580 case default
6581 call mpistop("Error in synthesize emission: Unknown convert_type")
6582 end select
6583
6584 end subroutine output_data
6585 }
6586
6587 subroutine write_image_vticc(qunit,xO1,xO2,dxO1,dxO2,wO,nXO1,nXO2,nWO,nC1,nC2)
6588 ! write image data to vti
6590
6591 integer, intent(in) :: qunit,nXO1,nXO2,nWO,nC1,nC2
6592 double precision, intent(in) :: xO1(nXO1),xO2(nxO2)
6593 double precision, intent(in) :: dxO1(nxO1),dxO2(nxO2)
6594 double precision, intent(in) :: wO(nXO1,nXO2,nWO)
6595
6596 double precision :: origin(1:3), spacing(1:3)
6597 integer :: wholeExtent(1:6)
6598 integer :: iw
6599 integer :: ixC1,ixC2
6600
6601 integer :: filenr
6602 logical :: fileopen
6603 character (70) :: subname,wname,vname,nameL,nameS
6604 character (len=std_len) :: filename
6605 logical :: sph_datres_no_doppler
6606
6607
6608 origin(1)=xo1(1)-0.5d0*dxo1(1)
6609 origin(2)=xo2(1)-0.5d0*dxo2(1)
6610 origin(3)=zero
6611 spacing(1)=dxo1(1)
6612 spacing(2)=dxo2(1)
6613 spacing(3)=one
6614 wholeextent=0
6615 wholeextent(2)=nxo1
6616 wholeextent(4)=nxo2
6617 sph_datres_no_doppler=dat_resolution .and. coordinate==spherical .and. trim(ray_method_active)=='spherical'
6618
6619 if (mype==0) then
6620 inquire(qunit,opened=fileopen)
6621 if(.not.fileopen)then
6622 ! generate filename
6623 filenr=snapshotini
6624 if (autoconvert) filenr=snapshotnext
6625 if (convert_type=='EIvtiCCmpi') then
6626 write(filename,'(a,i4.4,a)') trim(filename_euv),filenr,".vti"
6627 else if (convert_type=='SIvtiCCmpi') then
6628 write(filename,'(a,i4.4,a)') trim(filename_sxr),filenr,".vti"
6629 else if (convert_type=='WIvtiCCmpi') then
6630 write(filename,'(a,i4.4,a)') trim(filename_whitelight),filenr,".vti"
6631 else if (convert_type=='ESvtiCCmpi') then
6632 write(filename,'(a,i4.4,a)') trim(filename_spectrum),filenr,".vti"
6633 endif
6634 open(qunit,file=filename,status='unknown',form='formatted')
6635 endif
6636
6637 ! generate xml header
6638 write(qunit,'(a)')'<?xml version="1.0"?>'
6639 write(qunit,'(a)',advance='no') '<VTKFile type="ImageData"'
6640 write(qunit,'(a)')' version="0.1" byte_order="LittleEndian">'
6641 write(qunit,'(a,3(1pe14.6),a,6(i10),a,3(1pe14.6),a)')' <ImageData Origin="',&
6642 origin,'" WholeExtent="',wholeextent,'" Spacing="',spacing,'">'
6643 ! file info
6644 write(qunit,'(a)')'<FieldData>'
6645 write(qunit,'(2a)')'<DataArray type="Float32" Name="TIME" ',&
6646 'NumberOfTuples="1" format="ascii">'
6647 write(qunit,*) real(global_time*time_convert_factor)
6648 write(qunit,'(a)')'</DataArray>'
6649 write(qunit,'(a)')'</FieldData>'
6650 ! pixel/cell data
6651 write(qunit,'(a,6(i10),a)') '<Piece Extent="',wholeextent,'">'
6652 write(qunit,'(a)')'<CellData>'
6653 do iw=1,nwo
6654 ! variable name
6655 if (convert_type=='EIvtiCCmpi') then
6656 if (wavelength<100) then
6657 write(vname,'(a,i2)') "AIA",wavelength
6658 else if (wavelength<1000) then
6659 write(vname,'(a,i3)') "AIA",wavelength
6660 else
6661 write(vname,'(a,i4)') "IRIS",wavelength
6662 endif
6663 if (trim(emission_model)=='pseudo_current' .and. iw==1) vname='pseudo_current'
6664 if (trim(emission_model)=='radio_ff' .and. iw==1) vname='radio_brightness_temperature'
6665 if (trim(radiation_transfer)=='thick' .and. iw==1) vname=trim(vname)//'_thick'
6666 if (iw==2 .and. dat_resolution .and. (.not. sph_datres_no_doppler) .and. &
6667 trim(emission_model)/='radio_ff' .and. &
6668 trim(emission_model)/='pseudo_current') vname='Doppler_velocity'
6669 if (output_tau .and. trim(radiation_transfer)=='thick' .and. &
6670 ((trim(emission_model)=='radio_ff' .and. iw==2) .or. &
6671 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6672 ((dat_resolution .and. ((sph_datres_no_doppler .and. iw==2) .or. &
6673 ((.not. sph_datres_no_doppler) .and. iw==3))) .or. &
6674 ((.not. dat_resolution) .and. iw==2))))) then
6675 vname='tau'
6676 endif
6677 if (output_absorption_fraction .and. trim(radiation_transfer)=='thick' .and. &
6678 ((trim(emission_model)=='radio_ff' .and. ((output_tau .and. iw==3) .or. &
6679 ((.not. output_tau) .and. iw==2))) .or. &
6680 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6681 ((dat_resolution .and. sph_datres_no_doppler .and. output_tau .and. iw==3) .or. &
6682 (dat_resolution .and. sph_datres_no_doppler .and. (.not. output_tau) .and. iw==2) .or. &
6683 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. output_tau .and. iw==4) .or. &
6684 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. (.not. output_tau) .and. iw==3) .or. &
6685 ((.not. dat_resolution) .and. output_tau .and. iw==3) .or. &
6686 ((.not. dat_resolution) .and. (.not. output_tau) .and. iw==2))))) then
6687 vname='absorption_fraction'
6688 endif
6689 else if (convert_type=='SIvtiCCmpi') then
6690 if (emin_sxr<10 .and. emax_sxr<10) then
6691 write(vname,'(a,i1,a,i1,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6692 else if (emin_sxr<10 .and. emax_sxr>=10) then
6693 write(vname,'(a,i1,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6694 else
6695 write(vname,'(a,i2,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6696 endif
6697 else if (convert_type=='WIvtiCCmpi') then
6698 if (iw==1) write(vname,'(a)')'B'
6699 if (iw==2) write(vname,'(a)')'pB'
6700 else if (convert_type=='ESvtiCCmpi') then
6701 if (spectrum_wl==1354) then
6702 write(vname,'(a,i4)') "SG",spectrum_wl
6703 else
6704 write(vname,'(a,i3)') "EIS",spectrum_wl
6705 endif
6706 endif
6707 write(qunit,'(a,a,a)')&
6708 '<DataArray type="Float64" Name="',trim(vname),'" format="ascii">'
6709 write(qunit,'(200(1pe14.6))') ((wo(ixc1,ixc2,iw),ixc1=1,nxo1),ixc2=1,nxo2)
6710 write(qunit,'(a)')'</DataArray>'
6711 enddo
6712 write(qunit,'(a)')'</CellData>'
6713 write(qunit,'(a)')'</Piece>'
6714 ! end
6715 write(qunit,'(a)')'</ImageData>'
6716 write(qunit,'(a)')'</VTKFile>'
6717 close(qunit)
6718 endif
6719
6720 end subroutine write_image_vticc
6721
6722 subroutine write_image_vtucc(qunit,xC,wC,dxC,nPiece,nC1,nC2,nWC,datatype)
6723 ! write image data to vtu
6725
6726 integer, intent(in) :: qunit
6727 integer, intent(in) :: nPiece,nC1,nC2,nWC
6728 double precision, intent(in) :: xC(nPiece,nC1,nC2,2),dxC(nPiece,nc1,nc2,2)
6729 double precision, intent(in) :: wC(nPiece,nC1,nC2,nWC)
6730 character(20), intent(in) :: datatype
6731
6732 integer :: nP1,nP2
6733 double precision :: xP(nPiece,nC1+1,nC2+1,2)
6734 integer :: filenr
6735 logical :: fileopen
6736 character (70) :: subname,wname,vname,nameL,nameS
6737 character (len=std_len) :: filename
6738 integer :: ixC1,ixC2,ixP,ix1,ix2,j
6739 integer :: nc,np,icel,VTK_type
6740 logical :: sph_datres_no_doppler
6741
6742 np1=nc1+1
6743 np2=nc2+1
6744 np=np1*np2
6745 nc=nc1*nc2
6746 sph_datres_no_doppler=dat_resolution .and. coordinate==spherical .and. trim(ray_method_active)=='spherical'
6747 ! cell corner location
6748 do ixp=1,npiece
6749 do ix1=1,np1
6750 do ix2=1,np2
6751 if (ix1<np1) xp(ixp,ix1,ix2,1)=xc(ixp,ix1,1,1)-0.5d0*dxc(ixp,ix1,1,1)
6752 if (ix1==np1) xp(ixp,ix1,ix2,1)=xc(ixp,ix1-1,1,1)+0.5d0*dxc(ixp,ix1-1,1,1)
6753 if (ix2<np2) xp(ixp,ix1,ix2,2)=xc(ixp,1,ix2,2)-0.5d0*dxc(ixp,1,ix2,2)
6754 if (ix2==np2) xp(ixp,ix1,ix2,2)=xc(ixp,1,ix2-1,2)+0.5d0*dxc(ixp,1,ix2-1,2)
6755 enddo
6756 enddo
6757 enddo
6758 if (mype==0) then
6759 inquire(qunit,opened=fileopen)
6760 if(.not.fileopen)then
6761 ! generate filename
6762 filenr=snapshotini
6763 if (autoconvert) filenr=snapshotnext
6764 if (datatype=='image_euv') then
6765 write(filename,'(a,i4.4,a)') trim(filename_euv),filenr,".vtu"
6766 else if (datatype=='image_sxr') then
6767 write(filename,'(a,i4.4,a)') trim(filename_sxr),filenr,".vtu"
6768 else if (datatype=='image_whitelight') then
6769 write(filename,'(a,i4.4,a)') trim(filename_whitelight),filenr,".vtu"
6770 else if (datatype=='spectrum_euv') then
6771 write(filename,'(a,i4.4,a)') trim(filename_spectrum),filenr,".vtu"
6772 endif
6773 open(qunit,file=filename,status='unknown',form='formatted')
6774 endif
6775 ! generate xml header
6776 write(qunit,'(a)')'<?xml version="1.0"?>'
6777 write(qunit,'(a)',advance='no') '<VTKFile type="UnstructuredGrid"'
6778 write(qunit,'(a)')' version="0.1" byte_order="LittleEndian">'
6779 write(qunit,'(a)')'<UnstructuredGrid>'
6780 write(qunit,'(a)')'<FieldData>'
6781 write(qunit,'(2a)')'<DataArray type="Float32" Name="TIME" ',&
6782 'NumberOfTuples="1" format="ascii">'
6783 write(qunit,*) real(global_time*time_convert_factor)
6784 write(qunit,'(a)')'</DataArray>'
6785 write(qunit,'(a)')'</FieldData>'
6786 do ixp=1,npiece
6787 write(qunit,'(a,i7,a,i7,a)') &
6788 '<Piece NumberOfPoints="',np,'" NumberOfCells="',nc,'">'
6789 write(qunit,'(a)')'<CellData>'
6790 do j=1,nwc
6791 if (datatype=='image_euv') then
6792 if (j==1) then
6793 if (wavelength<100) then
6794 write(vname,'(a,i2)') "AIA",wavelength
6795 else if (wavelength<1000) then
6796 write(vname,'(a,i3)') "AIA",wavelength
6797 else
6798 write(vname,'(a,i4)') "IRIS",wavelength
6799 endif
6800 if (trim(emission_model)=='pseudo_current') vname='pseudo_current'
6801 if (trim(emission_model)=='radio_ff') vname='radio_brightness_temperature'
6802 if (trim(radiation_transfer)=='thick') vname=trim(vname)//'_thick'
6803 endif
6804 if (j==2 .and. dat_resolution .and. (.not. sph_datres_no_doppler) .and. &
6805 trim(emission_model)/='radio_ff' .and. &
6806 trim(emission_model)/='pseudo_current') vname='Doppler_velocity'
6807 if (output_tau .and. trim(radiation_transfer)=='thick' .and. &
6808 ((trim(emission_model)=='radio_ff' .and. j==2) .or. &
6809 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6810 ((dat_resolution .and. ((sph_datres_no_doppler .and. j==2) .or. &
6811 ((.not. sph_datres_no_doppler) .and. j==3))) .or. &
6812 ((.not. dat_resolution) .and. j==2))))) then
6813 vname='tau'
6814 endif
6815 if (output_absorption_fraction .and. trim(radiation_transfer)=='thick' .and. &
6816 ((trim(emission_model)=='radio_ff' .and. ((output_tau .and. j==3) .or. &
6817 ((.not. output_tau) .and. j==2))) .or. &
6818 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6819 ((dat_resolution .and. sph_datres_no_doppler .and. output_tau .and. j==3) .or. &
6820 (dat_resolution .and. sph_datres_no_doppler .and. (.not. output_tau) .and. j==2) .or. &
6821 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. output_tau .and. j==4) .or. &
6822 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. (.not. output_tau) .and. j==3) .or. &
6823 ((.not. dat_resolution) .and. output_tau .and. j==3) .or. &
6824 ((.not. dat_resolution) .and. (.not. output_tau) .and. j==2))))) then
6825 vname='absorption_fraction'
6826 endif
6827 else if (datatype=='image_sxr') then
6828 if (emin_sxr<10 .and. emax_sxr<10) then
6829 write(vname,'(a,i1,a,i1,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6830 else if (emin_sxr<10 .and. emax_sxr>=10) then
6831 write(vname,'(a,i1,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6832 else
6833 write(vname,'(a,i2,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6834 endif
6835 else if (datatype=='image_whitelight') then
6836 write(vname,'(a)')'whitelight'
6837 else if (datatype=='spectrum_euv') then
6838 if (spectrum_wl==1354) then
6839 write(vname,'(a,i4)') "SG",spectrum_wl
6840 else
6841 write(vname,'(a,i3)') "EIS",spectrum_wl
6842 endif
6843 endif
6844 write(qunit,'(a,a,a)')&
6845 '<DataArray type="Float64" Name="',trim(vname),'" format="ascii">'
6846 write(qunit,'(200(1pe14.6))') ((wc(ixp,ixc1,ixc2,j),ixc1=1,nc1),ixc2=1,nc2)
6847 write(qunit,'(a)')'</DataArray>'
6848 enddo
6849 write(qunit,'(a)')'</CellData>'
6850 write(qunit,'(a)')'<Points>'
6851 write(qunit,'(a)')'<DataArray type="Float32" NumberOfComponents="3" format="ascii">'
6852 do ix2=1,np2
6853 do ix1=1,np1
6854 if (datatype=='image_euv' .and. dat_resolution) then
6855 if (los_phi==0 .and. los_theta==90) then
6856 write(qunit,'(3(1pe14.6))') 0.d0,xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2)
6857 else if (los_phi==90 .and. los_theta==90) then
6858 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,2),0.d0,xp(ixp,ix1,ix2,1)
6859 else
6860 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6861 endif
6862 else if (datatype=='image_sxr' .and. dat_resolution) then
6863 if (los_phi==0 .and. los_theta==90) then
6864 write(qunit,'(3(1pe14.6))') 0.d0,xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2)
6865 else if (los_phi==90 .and. los_theta==90) then
6866 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,2),0.d0,xp(ixp,ix1,ix2,1)
6867 else
6868 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6869 endif
6870 else
6871 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6872 endif
6873 enddo
6874 enddo
6875 write(qunit,'(a)')'</DataArray>'
6876 write(qunit,'(a)')'</Points>'
6877 ! connetivity part
6878 write(qunit,'(a)')'<Cells>'
6879 write(qunit,'(a)')'<DataArray type="Int32" Name="connectivity" format="ascii">'
6880 do ix2=1,nc2
6881 do ix1=1,nc1
6882 write(qunit,'(4(i7))') ix1-1+(ix2-1)*np1,ix1+(ix2-1)*np1,&
6883 ix1-1+ix2*np1,ix1+ix2*np1
6884 enddo
6885 enddo
6886 write(qunit,'(a)')'</DataArray>'
6887 ! offsets data array
6888 write(qunit,'(a)')'<DataArray type="Int32" Name="offsets" format="ascii">'
6889 do icel=1,nc
6890 write(qunit,'(i7)') icel*(2**2)
6891 enddo
6892 write(qunit,'(a)')'</DataArray>'
6893 ! VTK cell type data array
6894 write(qunit,'(a)')'<DataArray type="Int32" Name="types" format="ascii">'
6895 ! VTK_LINE=3; VTK_PIXEL=8; VTK_VOXEL=11 -> vtk-syntax
6896 vtk_type=8
6897 do icel=1,nc
6898 write(qunit,'(i2)') vtk_type
6899 enddo
6900 write(qunit,'(a)')'</DataArray>'
6901 write(qunit,'(a)')'</Cells>'
6902 write(qunit,'(a)')'</Piece>'
6903 enddo
6904 write(qunit,'(a)')'</UnstructuredGrid>'
6905 write(qunit,'(a)')'</VTKFile>'
6906 close(qunit)
6907 endif
6908 end subroutine write_image_vtucc
6909
6910 subroutine dot_product_loc(vec1,vec2,res)
6911 double precision, intent(in) :: vec1(1:3),vec2(1:3)
6912 double precision, intent(out) :: res
6913
6914 res=vec1(1)*vec2(1)+vec1(2)*vec2(2)+vec1(3)*vec2(3)
6915
6916 end subroutine dot_product_loc
6917
6918 subroutine cross_product_loc(vec_in1,vec_in2,vec_out)
6919 double precision, intent(in) :: vec_in1(1:3),vec_in2(1:3)
6920 double precision, intent(out) :: vec_out(1:3)
6921
6922 vec_out(1)=vec_in1(2)*vec_in2(3)-vec_in1(3)*vec_in2(2)
6923 vec_out(2)=vec_in1(3)*vec_in2(1)-vec_in1(1)*vec_in2(3)
6924 vec_out(3)=vec_in1(1)*vec_in2(2)-vec_in1(2)*vec_in2(1)
6925
6926 end subroutine cross_product_loc
6927
6929 integer :: j
6930 double precision :: LOS_psi
6931 double precision :: vec_car(1:3),vec_z(1:3),vec_temp1(1:3),vec_temp2(1:3)
6932 double precision :: vec_LOS_sph(1:3),vec_xI1_sph(1:3),vec_xI2_sph(1:3)
6933
6934 ! antiparallel to LOS in spherical
6935 vec_los(1)=1.d0
6936 vec_los(2)=dpi*los_theta/180.d0
6937 vec_los(3)=dpi*los_phi/180.d0
6938 ! LOS in cartesian
6939 call spherical_to_cartesian(vec_los,vec_car)
6940 vec_los=-vec_car
6941
6942 ! theta=0 in cartesian
6943 vec_z(:)=zero
6944 vec_z(3)=1.d0
6945
6946 ! x direction for image
6947 if (los_theta==zero) then
6948 vec_temp1(1)=1.d0
6949 vec_temp1(2)=dpi/2.d0
6950 vec_temp1(3)=dpi*los_phi/180.d0
6951 call spherical_to_cartesian(vec_temp1,vec_car)
6952 vec_temp1=-vec_car
6953 call cross_product_loc(vec_temp1,vec_z,vec_xi1)
6954 else
6956 endif
6957
6958 ! y direction for image
6960
6961 ! rotate the image
6962 vec_temp1=vec_xi1/sqrt(vec_xi1(1)**2+vec_xi1(2)**2+vec_xi1(3)**2)
6963 vec_temp2=vec_xi2/sqrt(vec_xi2(1)**2+vec_xi2(2)**2+vec_xi2(3)**2)
6964 los_psi=dpi*image_rotate/180.d0
6965 vec_xi1=vec_temp1*cos(los_psi)-vec_temp2*sin(los_psi)
6966 vec_xi2=vec_temp2*cos(los_psi)+vec_temp1*sin(los_psi)
6967
6968 do j=1,3
6969 if (abs(vec_los(j))<smalldouble) vec_los(j)=zero
6970 if (abs(vec_xi1(j))<smalldouble) vec_xi1(j)=zero
6971 if (abs(vec_xi2(j))<smalldouble) vec_xi2(j)=zero
6972 enddo
6973
6974 call cartesian_to_spherical(vec_los,vec_los_sph)
6975 call cartesian_to_spherical(vec_xi1,vec_xi1_sph)
6976 call cartesian_to_spherical(vec_xi2,vec_xi2_sph)
6977 vec_los_sph(2:3)=vec_los_sph(2:3)*180.d0/dpi
6978 vec_xi1_sph(2:3)=vec_xi1_sph(2:3)*180.d0/dpi
6979 vec_xi2_sph(2:3)=vec_xi2_sph(2:3)*180.d0/dpi
6980
6981 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),']'
6982 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),']'
6983 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),']'
6984
6985 end subroutine init_vectors_spherical
6986
6987 subroutine spherical_to_cartesian(vec_sph,vec_car)
6988 ! angles in rad
6989 double precision, intent(in) :: vec_sph(1:3)
6990 double precision, intent(inout) :: vec_car(1:3)
6991
6992 vec_car(1)=vec_sph(1)*dsin(vec_sph(2))*dcos(vec_sph(3))
6993 vec_car(2)=vec_sph(1)*dsin(vec_sph(2))*dsin(vec_sph(3))
6994 vec_car(3)=vec_sph(1)*dcos(vec_sph(2))
6995
6996 end subroutine spherical_to_cartesian
6997
6998 subroutine cartesian_to_spherical(vec_car,vec_sph)
6999 ! angles in rad
7000 double precision, intent(in) :: vec_car(1:3)
7001 double precision, intent(inout) :: vec_sph(1:3)
7002
7003 vec_sph(1)=dsqrt(vec_car(1)**2+vec_car(2)**2+vec_car(3)**2)
7004 vec_sph(2)=dacos(vec_car(3)/vec_sph(1))
7005 vec_sph(3)=atan2(vec_car(2),vec_car(1))
7006
7007 end subroutine cartesian_to_spherical
7008
7010 integer :: j
7011 double precision :: LOS_psi
7012 double precision :: vec_z(1:3),vec_temp1(1:3),vec_temp2(1:3)
7013
7014 ! vectors for image coordinate
7015 vec_los(1)=-cos(dpi*los_phi/180.d0)*sin(dpi*los_theta/180.d0)
7016 vec_los(2)=-sin(dpi*los_phi/180.d0)*sin(dpi*los_theta/180.d0)
7017 vec_los(3)=-cos(dpi*los_theta/180.d0)
7018 do j=1,3
7019 if (abs(vec_los(j))<=smalldouble) vec_los(j)=zero
7020 enddo
7021 vec_z(:)=zero
7022 vec_z(3)=1.d0
7023 if (los_theta==zero) then
7024 vec_xi1(1)=cos(dpi*los_phi/180.d0)
7025 vec_xi1(2)=sin(dpi*los_phi/180.d0)
7026 vec_xi1(3)=zero
7027 else
7029 endif
7031 vec_temp1=vec_xi1/sqrt(vec_xi1(1)**2+vec_xi1(2)**2+vec_xi1(3)**2)
7032 vec_temp2=vec_xi2/sqrt(vec_xi2(1)**2+vec_xi2(2)**2+vec_xi2(3)**2)
7033 los_psi=dpi*image_rotate/180.d0
7034 vec_xi1=vec_temp1*cos(los_psi)-vec_temp2*sin(los_psi)
7035 vec_xi2=vec_temp2*cos(los_psi)+vec_temp1*sin(los_psi)
7036
7037 do j=1,3
7038 if (abs(vec_xi1(j))<smalldouble) vec_xi1(j)=zero
7039 if (abs(vec_xi2(j))<smalldouble) vec_xi2(j)=zero
7040 enddo
7041
7042 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' LOS vector: [',vec_los(1),vec_los(2),vec_los(3),']'
7043 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' xI1 vector: [',vec_xi1(1),vec_xi1(2),vec_xi1(3),']'
7044 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' xI2 vector: [',vec_xi2(1),vec_xi2(2),vec_xi2(3),']'
7045
7046 end subroutine init_vectors_cartesian
7047
7048 subroutine get_cor_image_spherical(x_3D_sph,x_image)
7049 double precision, intent(in) :: x_3D_sph(1:3)
7050 double precision, intent(inout) :: x_image(1:2)
7051 double precision :: res,res_origin
7052 double precision :: x_3D(1:3)
7053
7054 call spherical_to_cartesian(x_3d_sph,x_3d)
7055 call dot_product_loc(x_3d,vec_xi1,res)
7056 x_image(1)=res
7057 call dot_product_loc(x_3d,vec_xi2,res)
7058 x_image(2)=res
7059
7060 end subroutine get_cor_image_spherical
7061
7062 subroutine get_cor_image(x_3D,x_image)
7063 double precision, intent(in) :: x_3D(1:3)
7064 double precision, intent(inout) :: x_image(1:2)
7065 double precision :: res,res_origin
7066
7067 call dot_product_loc(x_3d,vec_xi1,res)
7068 call dot_product_loc(x_origin,vec_xi1,res_origin)
7069 x_image(1)=res-res_origin
7070 call dot_product_loc(x_3d,vec_xi2,res)
7071 call dot_product_loc(x_origin,vec_xi2,res_origin)
7072 x_image(2)=res-res_origin
7073
7074 end subroutine get_cor_image
7075
7076end 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
integer, parameter cartesian
Definition mod_geometry.t:8
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...
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.
integer, parameter ndim
Number of spatial dimensions for grid variables.
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)