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 integer, intent(in) :: ixI^L, ixO^L
3426 double precision, intent(in) :: x(ixI^S,1:ndim),dx(ixI^S,1:ndim)
3427 double precision, allocatable, intent(out) :: xface1(:),xface2(:),xface3(:)
3428
3429 integer :: ix^D
3430
3431 allocate(xface1(ixomin1:ixomax1+1),xface2(ixomin2:ixomax2+1),xface3(ixomin3:ixomax3+1))
3432
3433 ix2=ixomin2
3434 ix3=ixomin3
3435 do ix1=ixomin1,ixomax1
3436 xface1(ix1)=x(ix^d,1)-half*dx(ix^d,1)
3437 enddo
3438 xface1(ixomax1+1)=x(ixomax1,ixomin2,ixomin3,1)+half*dx(ixomax1,ixomin2,ixomin3,1)
3439
3440 ix1=ixomin1
3441 ix3=ixomin3
3442 do ix2=ixomin2,ixomax2
3443 xface2(ix2)=x(ix^d,2)-half*dx(ix^d,2)
3444 enddo
3445 xface2(ixomax2+1)=x(ixomin1,ixomax2,ixomin3,2)+half*dx(ixomin1,ixomax2,ixomin3,2)
3446
3447 ix1=ixomin1
3448 ix2=ixomin2
3449 do ix3=ixomin3,ixomax3
3450 xface3(ix3)=x(ix^d,3)-half*dx(ix^d,3)
3451 enddo
3452 xface3(ixomax3+1)=x(ixomin1,ixomin2,ixomax3,3)+half*dx(ixomin1,ixomin2,ixomax3,3)
3453 end subroutine build_cart_dda_faces
3454
3455 integer function cart_dda_locate_index(pos,faces,imin,imax) result(idx)
3456 integer, intent(in) :: imin,imax
3457 double precision, intent(in) :: pos,faces(imin:imax+1)
3458
3459 integer :: ilo,ihi,imid
3460
3461 if (pos<=faces(imin)) then
3462 idx=imin
3463 return
3464 endif
3465 if (pos>=faces(imax+1)) then
3466 idx=imax
3467 return
3468 endif
3469
3470 ilo=imin
3471 ihi=imax+1
3472 do while (ihi-ilo>1)
3473 imid=(ilo+ihi)/2
3474 if (pos>=faces(imid)) then
3475 ilo=imid
3476 else
3477 ihi=imid
3478 endif
3479 enddo
3480 idx=min(imax,max(imin,ilo))
3481 end function cart_dda_locate_index
3482
3483 subroutine cart_dda_init_axis(ray_origin_axis,ray_dir_axis,faces,imin,imax,idx,step,tMax)
3484 integer, intent(in) :: imin,imax,idx
3485 double precision, intent(in) :: ray_origin_axis,ray_dir_axis,faces(imin:imax+1)
3486 integer, intent(out) :: step
3487 double precision, intent(out) :: tMax
3488
3489 if (ray_dir_axis>zero) then
3490 step=1
3491 tmax=(faces(idx+1)-ray_origin_axis)/ray_dir_axis
3492 else if (ray_dir_axis<zero) then
3493 step=-1
3494 tmax=(faces(idx)-ray_origin_axis)/ray_dir_axis
3495 else
3496 step=0
3497 tmax=huge(one)
3498 endif
3499 end subroutine cart_dda_init_axis
3500
3501 subroutine cart_dda_advance_axis(ray_origin_axis,ray_dir_axis,faces,imin,imax,idx,step,tMax,done)
3502 integer, intent(in) :: imin,imax,step
3503 double precision, intent(in) :: ray_origin_axis,ray_dir_axis,faces(imin:imax+1)
3504 integer, intent(inout) :: idx
3505 double precision, intent(inout) :: tMax
3506 logical, intent(out) :: done
3507
3508 done=.false.
3509 idx=idx+step
3510 if (idx<imin .or. idx>imax) then
3511 done=.true.
3512 return
3513 endif
3514 if (step>0) then
3515 tmax=(faces(idx+1)-ray_origin_axis)/ray_dir_axis
3516 else if (step<0) then
3517 tmax=(faces(idx)-ray_origin_axis)/ray_dir_axis
3518 else
3519 tmax=huge(one)
3520 endif
3521 end subroutine cart_dda_advance_axis
3522
3523 subroutine acc_euv_cart_dda(ixI^L,ixO^L,source,sourcev,&
3524 ray_origin,xface1,xface2,xface3,t_enter,t_exit,EUVp,Dplp)
3525 integer, intent(in) :: ixI^L, ixO^L
3526 double precision, intent(in) :: source(ixI^S),sourcev(ixI^S)
3527 double precision, intent(in) :: ray_origin(1:3)
3528 double precision, intent(in) :: xface1(ixOmin1:ixOmax1+1),xface2(ixOmin2:ixOmax2+1),&
3529 xface3(ixOmin3:ixOmax3+1)
3530 double precision, intent(in) :: t_enter,t_exit
3531 double precision, intent(inout) :: EUVp,Dplp
3532
3533 integer :: ix^D,step(1:3)
3534 double precision :: pos(1:3),tMax(1:3),tNow,tNext,ds_cm,epsRay
3535 logical :: done
3536
3537 if (t_exit<=t_enter) return
3538 epsray=max(1.d-12,1.d-10*abs(t_exit-t_enter))
3539 pos=ray_origin+(t_enter+epsray)*vec_los
3540 ix1=cart_dda_locate_index(pos(1),xface1,ixomin1,ixomax1)
3541 ix2=cart_dda_locate_index(pos(2),xface2,ixomin2,ixomax2)
3542 ix3=cart_dda_locate_index(pos(3),xface3,ixomin3,ixomax3)
3543
3544 call cart_dda_init_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1))
3545 call cart_dda_init_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2))
3546 call cart_dda_init_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3))
3547
3548 tnow=t_enter
3549 do
3550 tnext=min(t_exit,tmax(1),tmax(2),tmax(3))
3551 if (tnext>tnow) then
3552 ds_cm=(tnext-tnow)*unit_length
3553 if (si_unit) ds_cm=ds_cm*1.d2
3554 euvp=euvp+source(ix^d)*ds_cm
3555 dplp=dplp+sourcev(ix^d)*ds_cm
3556 endif
3557 tnow=tnext
3558 if (tnow>=t_exit-epsray) exit
3559
3560 if (tmax(1)<=tnow+epsray) then
3561 call cart_dda_advance_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1),done)
3562 if (done) exit
3563 endif
3564 if (tmax(2)<=tnow+epsray) then
3565 call cart_dda_advance_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2),done)
3566 if (done) exit
3567 endif
3568 if (tmax(3)<=tnow+epsray) then
3569 call cart_dda_advance_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3),done)
3570 if (done) exit
3571 endif
3572 enddo
3573 end subroutine acc_euv_cart_dda
3574
3575 subroutine append_cart_dda_segment(segments,nseg,capacity,pixel_id,tseg,jds,kds,jvds)
3576 double precision, allocatable, intent(inout) :: segments(:,:)
3577 integer, intent(inout) :: nseg,capacity
3578 integer, intent(in) :: pixel_id
3579 double precision, intent(in) :: tseg,jds,kds,jvds
3580
3581 double precision, allocatable :: tmp(:,:)
3582 integer :: new_capacity
3583
3584 if (capacity<=0) then
3585 capacity=1024
3586 allocate(segments(5,capacity))
3587 else if (nseg>=capacity) then
3588 new_capacity=2*capacity
3589 allocate(tmp(5,new_capacity))
3590 tmp(:,1:capacity)=segments(:,1:capacity)
3591 call move_alloc(tmp,segments)
3592 capacity=new_capacity
3593 endif
3594
3595 nseg=nseg+1
3596 segments(1,nseg)=dble(pixel_id)
3597 segments(2,nseg)=tseg
3598 segments(3,nseg)=jds
3599 segments(4,nseg)=kds
3600 segments(5,nseg)=jvds
3601 end subroutine append_cart_dda_segment
3602
3603 subroutine collect_euv_cart_dda_segments(ixI^L,ixO^L,source,opacity,sourcev,&
3604 pixel_id,ray_origin,xface1,xface2,xface3,t_enter,t_exit,&
3605 segments,nseg,capacity)
3606 integer, intent(in) :: ixI^L, ixO^L
3607 double precision, intent(in) :: source(ixI^S),opacity(ixI^S),sourcev(ixI^S)
3608 integer, intent(in) :: pixel_id
3609 double precision, intent(in) :: ray_origin(1:3)
3610 double precision, intent(in) :: xface1(ixOmin1:ixOmax1+1),xface2(ixOmin2:ixOmax2+1),&
3611 xface3(ixOmin3:ixOmax3+1)
3612 double precision, intent(in) :: t_enter,t_exit
3613 double precision, allocatable, intent(inout) :: segments(:,:)
3614 integer, intent(inout) :: nseg,capacity
3615
3616 integer :: ix^D,step(1:3)
3617 double precision :: pos(1:3),tMax(1:3),tNow,tNext,ds_cm,epsRay,tseg
3618 double precision :: jds,kds,jvds
3619 logical :: done
3620
3621 if (t_exit<=t_enter) return
3622 epsray=max(1.d-12,1.d-10*abs(t_exit-t_enter))
3623 pos=ray_origin+(t_enter+epsray)*vec_los
3624 ix1=cart_dda_locate_index(pos(1),xface1,ixomin1,ixomax1)
3625 ix2=cart_dda_locate_index(pos(2),xface2,ixomin2,ixomax2)
3626 ix3=cart_dda_locate_index(pos(3),xface3,ixomin3,ixomax3)
3627
3628 call cart_dda_init_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1))
3629 call cart_dda_init_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2))
3630 call cart_dda_init_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3))
3631
3632 tnow=t_enter
3633 do
3634 tnext=min(t_exit,tmax(1),tmax(2),tmax(3))
3635 if (tnext>tnow) then
3636 ds_cm=(tnext-tnow)*unit_length
3637 if (si_unit) ds_cm=ds_cm*1.d2
3638 jds=source(ix^d)*ds_cm
3639 kds=opacity(ix^d)*ds_cm
3640 jvds=sourcev(ix^d)*ds_cm
3641 if (jds/=zero .or. kds/=zero .or. jvds/=zero) then
3642 tseg=half*(tnow+tnext)
3643 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tseg,jds,kds,jvds)
3644 endif
3645 endif
3646 tnow=tnext
3647 if (tnow>=t_exit-epsray) exit
3648
3649 if (tmax(1)<=tnow+epsray) then
3650 call cart_dda_advance_axis(ray_origin(1),vec_los(1),xface1,ixomin1,ixomax1,ix1,step(1),tmax(1),done)
3651 if (done) exit
3652 endif
3653 if (tmax(2)<=tnow+epsray) then
3654 call cart_dda_advance_axis(ray_origin(2),vec_los(2),xface2,ixomin2,ixomax2,ix2,step(2),tmax(2),done)
3655 if (done) exit
3656 endif
3657 if (tmax(3)<=tnow+epsray) then
3658 call cart_dda_advance_axis(ray_origin(3),vec_los(3),xface3,ixomin3,ixomax3,ix3,step(3),tmax(3),done)
3659 if (done) exit
3660 endif
3661 enddo
3662 end subroutine collect_euv_cart_dda_segments
3663
3664 subroutine sort_segment_indices_near_to_far(segments,idx,nidx)
3665 double precision, intent(in) :: segments(:,:)
3666 integer, intent(inout) :: idx(:)
3667 integer, intent(in) :: nidx
3668
3669 if (nidx<=1) return
3670 if (nidx<=32) then
3671 call insertion_sort_segment_indices(segments,idx,1,nidx)
3672 else
3673 call quicksort_segment_indices(segments,idx,1,nidx)
3674 endif
3676
3677 subroutine insertion_sort_segment_indices(segments,idx,ilo,ihi)
3678 double precision, intent(in) :: segments(:,:)
3679 integer, intent(inout) :: idx(:)
3680 integer, intent(in) :: ilo,ihi
3681
3682 integer :: i,j,key
3683
3684 do i=ilo+1,ihi
3685 key=idx(i)
3686 j=i-1
3687 do while (j>=ilo .and. segments(2,idx(j))>segments(2,key))
3688 idx(j+1)=idx(j)
3689 j=j-1
3690 enddo
3691 idx(j+1)=key
3692 enddo
3693 end subroutine insertion_sort_segment_indices
3694
3695 recursive subroutine quicksort_segment_indices(segments,idx,ilo,ihi)
3696 double precision, intent(in) :: segments(:,:)
3697 integer, intent(inout) :: idx(:)
3698 integer, intent(in) :: ilo,ihi
3699
3700 integer :: i,j,tmp
3701 double precision :: pivot
3702
3703 if (ihi-ilo<=32) then
3704 call insertion_sort_segment_indices(segments,idx,ilo,ihi)
3705 return
3706 endif
3707
3708 i=ilo
3709 j=ihi
3710 pivot=segments(2,idx((ilo+ihi)/2))
3711 do
3712 do while (segments(2,idx(i))<pivot)
3713 i=i+1
3714 enddo
3715 do while (segments(2,idx(j))>pivot)
3716 j=j-1
3717 enddo
3718 if (i<=j) then
3719 tmp=idx(i)
3720 idx(i)=idx(j)
3721 idx(j)=tmp
3722 i=i+1
3723 j=j-1
3724 endif
3725 if (i>j) exit
3726 enddo
3727
3728 if (ilo<j) call quicksort_segment_indices(segments,idx,ilo,j)
3729 if (i<ihi) call quicksort_segment_indices(segments,idx,i,ihi)
3730 end subroutine quicksort_segment_indices
3731
3732 integer function segment_pixel_owner(pixel_id) result(owner)
3733 integer, intent(in) :: pixel_id
3734
3735 owner=mod(pixel_id-1,npe)
3736 end function segment_pixel_owner
3737
3738 logical function segment_is_valid(segments,is,nvars) result(valid)
3739 double precision, intent(in) :: segments(:,:)
3740 integer, intent(in) :: is,nvars
3741
3742 integer :: iv
3743
3744 valid=.true.
3745 do iv=1,nvars
3746 if (segments(iv,is)/=segments(iv,is) .or. abs(segments(iv,is))>=1.d90) then
3747 valid=.false.
3748 return
3749 endif
3750 enddo
3751 end function segment_is_valid
3752
3753 subroutine cart_dda_block_pixel_range(box_min,box_max,nXIF1,nXIF2,xIF1,xIF2,ixPmin1,ixPmax1,ixPmin2,ixPmax2,has_pixels)
3754 double precision, intent(in) :: box_min(1:3),box_max(1:3)
3755 integer, intent(in) :: nXIF1,nXIF2
3756 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3757 integer, intent(out) :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
3758 logical, intent(out) :: has_pixels
3759
3760 integer :: i1,i2,i3
3761 double precision :: vec_cor(1:3),xI_cor(1:2)
3762 double precision :: xmin1,xmax1,xmin2,xmax2,dx1,dx2
3763
3764 do i1=1,2
3765 if (i1==1) vec_cor(1)=box_min(1)
3766 if (i1==2) vec_cor(1)=box_max(1)
3767 do i2=1,2
3768 if (i2==1) vec_cor(2)=box_min(2)
3769 if (i2==2) vec_cor(2)=box_max(2)
3770 do i3=1,2
3771 if (i3==1) vec_cor(3)=box_min(3)
3772 if (i3==2) vec_cor(3)=box_max(3)
3773 call get_cor_image(vec_cor,xi_cor)
3774 if (i1==1 .and. i2==1 .and. i3==1) then
3775 xmin1=xi_cor(1)
3776 xmax1=xi_cor(1)
3777 xmin2=xi_cor(2)
3778 xmax2=xi_cor(2)
3779 else
3780 xmin1=min(xmin1,xi_cor(1))
3781 xmax1=max(xmax1,xi_cor(1))
3782 xmin2=min(xmin2,xi_cor(2))
3783 xmax2=max(xmax2,xi_cor(2))
3784 endif
3785 enddo
3786 enddo
3787 enddo
3788
3789 if (nxif1>1) then
3790 dx1=abs(xif1(2)-xif1(1))
3791 else
3792 dx1=max(one,abs(xmax1-xmin1))
3793 endif
3794 if (nxif2>1) then
3795 dx2=abs(xif2(2)-xif2(1))
3796 else
3797 dx2=max(one,abs(xmax2-xmin2))
3798 endif
3799
3800 ixpmin1=max(1,floor((xmin1-xif1(1))/dx1)+1-1)
3801 ixpmax1=min(nxif1,ceiling((xmax1-xif1(1))/dx1)+1+1)
3802 ixpmin2=max(1,floor((xmin2-xif2(1))/dx2)+1-1)
3803 ixpmax2=min(nxif2,ceiling((xmax2-xif2(1))/dx2)+1+1)
3804 has_pixels=ixpmin1<=ixpmax1 .and. ixpmin2<=ixpmax2
3805 end subroutine cart_dda_block_pixel_range
3806
3807 subroutine integrate_euv_cart_dda_datresol(nXIF1,nXIF2,xIF1,xIF2,fl,EUV,Dpl)
3809
3810 integer, intent(in) :: nXIF1,nXIF2
3811 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3812 type(te_fluid), intent(in) :: fl
3813 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
3814
3815 integer :: ixO^L,ixO^D,ixI^L,ix^D
3816 integer :: iigrid,igrid,ixP1,ixP2,numSI,ixPmin1,ixPmax1,ixPmin2,ixPmax2
3817 double precision :: box_min(1:3),box_max(1:3),ray_origin(1:3)
3818 double precision :: t_enter,t_exit,vlos
3819 double precision :: profile_local(2),profile_global(2)
3820 logical :: hit,has_pixels
3821 double precision, allocatable :: source(:^D&),sourcev(:^D&),rho(:^D&),opacity(:^D&)
3822 double precision, allocatable :: xface1(:),xface2(:),xface3(:)
3823 double precision, allocatable :: EUVs(:,:),Dpls(:,:)
3824
3825 allocate(euvs(nxif1,nxif2),dpls(nxif1,nxif2))
3826 euvs=zero
3827 dpls=zero
3828 profile_local=zero
3829
3830 do iigrid=1,igridstail; igrid=igrids(iigrid);
3831 ^d&ixomin^d=ixmlo^d\
3832 ^d&ixomax^d=ixmhi^d\
3833 ^d&iximin^d=ixglo^d\
3834 ^d&iximax^d=ixghi^d\
3835
3836 box_min(1)=rnode(rpxmin1_,igrid)
3837 box_min(2)=rnode(rpxmin2_,igrid)
3838 box_min(3)=rnode(rpxmin3_,igrid)
3839 box_max(1)=rnode(rpxmax1_,igrid)
3840 box_max(2)=rnode(rpxmax2_,igrid)
3841 box_max(3)=rnode(rpxmax3_,igrid)
3842 call build_cart_dda_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,xface1,xface2,xface3)
3843 call cart_dda_block_pixel_range(box_min,box_max,nxif1,nxif2,xif1,xif2,&
3844 ixpmin1,ixpmax1,ixpmin2,ixpmax2,has_pixels)
3845 if (.not. has_pixels) then
3846 deallocate(xface1,xface2,xface3)
3847 cycle
3848 endif
3849
3850 allocate(source(ixi^s),sourcev(ixi^s),rho(ixi^s),opacity(ixi^s))
3851 source=zero
3852 sourcev=zero
3853 if (trim(emission_model)=='pseudo_current') then
3854 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,source)
3855 else if (trim(emission_model)=='radio_ff') then
3856 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,source,opacity)
3857 else
3858 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,source)
3859 source(ixo^s)=source(ixo^s)/instrument_resolution_factor**2
3860 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
3861 do ix1=ixomin1,ixomax1
3862 do ix2=ixomin2,ixomax2
3863 do ix3=ixomin3,ixomax3
3864 if (rho(ix^d)>smalldouble) then
3865 vlos=(ps(igrid)%w(ix^d,iw_mom(1))*vec_los(1)+&
3866 ps(igrid)%w(ix^d,iw_mom(2))*vec_los(2)+&
3867 ps(igrid)%w(ix^d,iw_mom(3))*vec_los(3))/rho(ix^d)
3868 sourcev(ix^d)=source(ix^d)*vlos
3869 endif
3870 enddo
3871 enddo
3872 enddo
3873 endif
3874 deallocate(rho,opacity)
3875
3876 do ixp1=ixpmin1,ixpmax1
3877 do ixp2=ixpmin2,ixpmax2
3878 ray_origin=x_origin+xif1(ixp1)*vec_xi1+xif2(ixp2)*vec_xi2
3879 profile_local(1)=profile_local(1)+one
3880 call ray_box_intersection_cart(ray_origin,vec_los,box_min,box_max,hit,t_enter,t_exit)
3881 if (hit) then
3882 profile_local(2)=profile_local(2)+one
3883 call acc_euv_cart_dda(ixi^l,ixo^l,source,sourcev,&
3884 ray_origin,xface1,xface2,xface3,t_enter,t_exit,euvs(ixp1,ixp2),dpls(ixp1,ixp2))
3885 endif
3886 enddo
3887 enddo
3888
3889 deallocate(source,sourcev,xface1,xface2,xface3)
3890 enddo
3891
3892 numsi=nxif1*nxif2
3893 call mpi_allreduce(euvs,euv,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
3894 call mpi_allreduce(dpls,dpl,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
3895 call mpi_allreduce(profile_local,profile_global,2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
3896 if (radsyn_verbose .and. mype==0) then
3897 write(*,'(a,2(es12.5,1x))') ' cart_dda thin profile ray_tests ray_hits: ',profile_global
3898 endif
3899 deallocate(euvs,dpls)
3900 end subroutine integrate_euv_cart_dda_datresol
3901
3902 subroutine integrate_euv_cart_dda_thick_datresol(nXIF1,nXIF2,xIF1,xIF2,fl,EUV,Dpl,Tau,EUVthin)
3904
3905 integer, intent(in) :: nXIF1,nXIF2
3906 double precision, intent(in) :: xIF1(nXIF1),xIF2(nXIF2)
3907 type(te_fluid), intent(in) :: fl
3908 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
3909 double precision, intent(out) :: Tau(nXIF1,nXIF2),EUVthin(nXIF1,nXIF2)
3910
3911 integer, parameter :: nSegVars=5
3912 integer :: ixO^L,ixO^D,ixI^L,ix^D
3913 integer :: iigrid,igrid,ixP1,ixP2,ipix,ipixStart,ipixEnd,nPixBatch,pixel_id
3914 integer :: nseg,capacity,totalCount,totalSeg,ipe,is,iseg,nidx,owner,isegDest,nsegBefore
3915 integer :: ixGlobal,iyGlobal,ixPmin1,ixPmax1,ixPmin2,ixPmax2,iFirst,iLast,iLocal
3916 integer :: nPixBatchTarget
3917 integer :: maxSegBatchTarget,maxSegCommTarget,maxNsegBatch,nPixTotal
3918 integer :: maxOwnerSegCount,maxOwnerSegCountLocal,segOffset,recvFill,totalRoundCount,totalRoundSeg
3919 integer, allocatable :: sendCounts(:),recvCounts(:),sendDispls(:),recvDispls(:)
3920 integer, allocatable :: roundSendCounts(:),roundRecvCounts(:)
3921 integer, allocatable :: roundSendDispls(:),roundRecvDispls(:)
3922 integer, allocatable :: ownerSegCounts(:),ownerOffsets(:),idx(:)
3923 integer, allocatable :: bucketCounts(:),bucketOffsets(:),bucketFill(:)
3924 double precision :: ray_origin(1:3)
3925 double precision :: t_enter,t_exit,vlos,atten
3926 double precision :: profile_local(5),profile_global(5),profile_batch(5)
3927 logical :: hit,has_pixels,batchAccepted,batchReduced
3928 double precision, allocatable :: rho(:^D&)
3929 double precision, allocatable :: segments(:,:),segments_send(:,:),segments_recv(:,:)
3930 double precision, allocatable :: segments_recv_round(:,:)
3931 double precision, allocatable :: image_reduce(:,:)
3932 type(radsyn_euv_cache), allocatable :: cache(:)
3933
3934 euv=zero
3935 dpl=zero
3936 tau=zero
3937 euvthin=zero
3938 profile_local=zero
3939 allocate(sendcounts(0:npe-1),recvcounts(0:npe-1),senddispls(0:npe-1),recvdispls(0:npe-1))
3940 allocate(roundsendcounts(0:npe-1),roundrecvcounts(0:npe-1))
3941 allocate(roundsenddispls(0:npe-1),roundrecvdispls(0:npe-1))
3942 allocate(ownersegcounts(0:npe-1),owneroffsets(0:npe-1))
3943 allocate(cache(igridstail))
3944 call radsyn_get_segment_batch_limits(npixbatchtarget,maxsegbatchtarget,maxsegcommtarget)
3945 allocate(bucketcounts(npixbatchtarget),bucketoffsets(npixbatchtarget+1),&
3946 bucketfill(npixbatchtarget))
3947
3948 do iigrid=1,igridstail; igrid=igrids(iigrid);
3949 ^d&ixomin^d=ixmlo^d\
3950 ^d&ixomax^d=ixmhi^d\
3951 ^d&iximin^d=ixglo^d\
3952 ^d&iximax^d=ixghi^d\
3953
3954 cache(iigrid)%igrid=igrid
3955 allocate(cache(iigrid)%source(ixi^s),cache(iigrid)%opacity(ixi^s),&
3956 cache(iigrid)%sourcev(ixi^s),rho(ixi^s))
3957 cache(iigrid)%source=zero
3958 cache(iigrid)%opacity=zero
3959 cache(iigrid)%sourcev=zero
3960 if (trim(emission_model)=='radio_ff') then
3961 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,&
3962 cache(iigrid)%source,cache(iigrid)%opacity)
3963 else
3964 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%source)
3965 cache(iigrid)%source(ixo^s)=cache(iigrid)%source(ixo^s)/instrument_resolution_factor**2
3966 call get_euv_hhe_opacity(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%opacity)
3967 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
3968 do ix1=ixomin1,ixomax1
3969 do ix2=ixomin2,ixomax2
3970 do ix3=ixomin3,ixomax3
3971 if (rho(ix^d)>smalldouble) then
3972 vlos=(ps(igrid)%w(ix^d,iw_mom(1))*vec_los(1)+&
3973 ps(igrid)%w(ix^d,iw_mom(2))*vec_los(2)+&
3974 ps(igrid)%w(ix^d,iw_mom(3))*vec_los(3))/rho(ix^d)
3975 cache(iigrid)%sourcev(ix^d)=cache(iigrid)%source(ix^d)*vlos
3976 endif
3977 enddo
3978 enddo
3979 enddo
3980 endif
3981 deallocate(rho)
3982 cache(iigrid)%box_min(1)=rnode(rpxmin1_,igrid)
3983 cache(iigrid)%box_min(2)=rnode(rpxmin2_,igrid)
3984 cache(iigrid)%box_min(3)=rnode(rpxmin3_,igrid)
3985 cache(iigrid)%box_max(1)=rnode(rpxmax1_,igrid)
3986 cache(iigrid)%box_max(2)=rnode(rpxmax2_,igrid)
3987 cache(iigrid)%box_max(3)=rnode(rpxmax3_,igrid)
3988 call build_cart_dda_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,&
3989 cache(iigrid)%xface1,cache(iigrid)%xface2,&
3990 cache(iigrid)%xface3)
3991 call cart_dda_block_pixel_range(cache(iigrid)%box_min,cache(iigrid)%box_max,&
3992 nxif1,nxif2,xif1,xif2,cache(iigrid)%ixPmin1,cache(iigrid)%ixPmax1,&
3993 cache(iigrid)%ixPmin2,cache(iigrid)%ixPmax2,cache(iigrid)%has_pixels)
3994 enddo
3995
3996 npixtotal=nxif1*nxif2
3997 ipixstart=1
3998 do while (ipixstart<=npixtotal)
3999 ipixend=min(nxif1*nxif2,ipixstart+npixbatchtarget-1)
4000 npixbatch=ipixend-ipixstart+1
4001 batchaccepted=.false.
4002 batchreduced=.false.
4003
4004 do while (.not. batchaccepted)
4005 nseg=0
4006 capacity=0
4007 profile_batch=zero
4008
4009 do iigrid=1,igridstail; igrid=igrids(iigrid);
4010 ^d&ixomin^d=ixmlo^d\
4011 ^d&ixomax^d=ixmhi^d\
4012 ^d&iximin^d=ixglo^d\
4013 ^d&iximax^d=ixghi^d\
4014
4015 ixpmin1=cache(iigrid)%ixPmin1
4016 ixpmax1=cache(iigrid)%ixPmax1
4017 ixpmin2=cache(iigrid)%ixPmin2
4018 ixpmax2=cache(iigrid)%ixPmax2
4019 has_pixels=cache(iigrid)%has_pixels
4020 if (.not. has_pixels) cycle
4021
4022 do ixp2=ixpmin2,ixpmax2
4023 ifirst=max(ipixstart,(ixp2-1)*nxif1+ixpmin1)
4024 ilast=min(ipixend,(ixp2-1)*nxif1+ixpmax1)
4025 if (ifirst>ilast) cycle
4026 do ipix=ifirst,ilast
4027 ixp1=1+mod(ipix-1,nxif1)
4028 ray_origin=x_origin+xif1(ixp1)*vec_xi1+xif2(ixp2)*vec_xi2
4029 profile_batch(1)=profile_batch(1)+one
4030 call ray_box_intersection_cart(ray_origin,vec_los,cache(iigrid)%box_min,&
4031 cache(iigrid)%box_max,hit,t_enter,t_exit)
4032 if (hit) then
4033 profile_batch(2)=profile_batch(2)+one
4034 nsegbefore=nseg
4035 call collect_euv_cart_dda_segments(ixi^l,ixo^l,cache(iigrid)%source,&
4036 cache(iigrid)%opacity,cache(iigrid)%sourcev,&
4037 ipix,ray_origin,cache(iigrid)%xface1,&
4038 cache(iigrid)%xface2,cache(iigrid)%xface3,&
4039 t_enter,t_exit,&
4040 segments,nseg,capacity)
4041 profile_batch(3)=profile_batch(3)+dble(nseg-nsegbefore)
4042 endif
4043 enddo
4044 enddo
4045 enddo
4046
4047 call mpi_allreduce(nseg,maxnsegbatch,1,mpi_integer,mpi_max,icomm,ierrmpi)
4048 if (maxnsegbatch>maxsegbatchtarget .and. npixbatch>1) then
4049 npixbatch=max(1,npixbatch/2)
4050 ipixend=ipixstart+npixbatch-1
4051 if (allocated(segments)) deallocate(segments)
4052 batchreduced=.true.
4053 else
4054 batchaccepted=.true.
4055 endif
4056 enddo
4057
4058 profile_local=profile_local+profile_batch
4059 if (radsyn_verbose .and. mype==0 .and. batchreduced) then
4060 write(*,'(a,3(i0,1x))') ' cart_dda thick adaptive batch: ',&
4061 ipixstart,ipixend,maxnsegbatch
4062 endif
4063
4064 if (.not. allocated(segments)) then
4065 capacity=1
4066 allocate(segments(nsegvars,capacity))
4067 endif
4068 ownersegcounts=0
4069 do is=1,nseg
4070 owner=segment_pixel_owner(nint(segments(1,is)))
4071 ownersegcounts(owner)=ownersegcounts(owner)+1
4072 enddo
4073 sendcounts=nsegvars*ownersegcounts
4074 senddispls(0)=0
4075 do ipe=1,npe-1
4076 senddispls(ipe)=senddispls(ipe-1)+sendcounts(ipe-1)
4077 enddo
4078
4079 allocate(segments_send(nsegvars,max(1,nseg)))
4080 owneroffsets=0
4081 do is=1,nseg
4082 owner=segment_pixel_owner(nint(segments(1,is)))
4083 isegdest=senddispls(owner)/nsegvars+owneroffsets(owner)+1
4084 segments_send(:,isegdest)=segments(:,is)
4085 owneroffsets(owner)=owneroffsets(owner)+1
4086 enddo
4087
4088 call mpi_alltoall(sendcounts,1,mpi_integer,recvcounts,1,mpi_integer,icomm,ierrmpi)
4089 recvdispls(0)=0
4090 do ipe=1,npe-1
4091 recvdispls(ipe)=recvdispls(ipe-1)+recvcounts(ipe-1)
4092 enddo
4093 totalcount=sum(recvcounts)
4094 totalseg=totalcount/nsegvars
4095 profile_local(4)=profile_local(4)+dble(totalcount)
4096 allocate(segments_recv(nsegvars,max(1,totalseg)))
4097
4098 recvfill=0
4099 maxownersegcountlocal=maxval(ownersegcounts)
4100 call mpi_allreduce(maxownersegcountlocal,maxownersegcount,1,mpi_integer,mpi_max,icomm,ierrmpi)
4101 do segoffset=0,maxownersegcount-1,maxsegcommtarget
4102 roundsendcounts=0
4103 roundsenddispls=senddispls
4104 do ipe=0,npe-1
4105 if (ownersegcounts(ipe)>segoffset) then
4106 roundsendcounts(ipe)=nsegvars*min(maxsegcommtarget,ownersegcounts(ipe)-segoffset)
4107 roundsenddispls(ipe)=senddispls(ipe)+nsegvars*segoffset
4108 endif
4109 enddo
4110
4111 call mpi_alltoall(roundsendcounts,1,mpi_integer,roundrecvcounts,1,mpi_integer,icomm,ierrmpi)
4112 roundrecvdispls(0)=0
4113 do ipe=1,npe-1
4114 roundrecvdispls(ipe)=roundrecvdispls(ipe-1)+roundrecvcounts(ipe-1)
4115 enddo
4116 totalroundcount=sum(roundrecvcounts)
4117 totalroundseg=totalroundcount/nsegvars
4118 allocate(segments_recv_round(nsegvars,max(1,totalroundseg)))
4119
4120 call mpi_alltoallv(segments_send,roundsendcounts,roundsenddispls,mpi_double_precision,&
4121 segments_recv_round,roundrecvcounts,roundrecvdispls,&
4122 mpi_double_precision,icomm,ierrmpi)
4123
4124 if (totalroundseg>0) then
4125 segments_recv(:,recvfill+1:recvfill+totalroundseg)=segments_recv_round(:,1:totalroundseg)
4126 recvfill=recvfill+totalroundseg
4127 endif
4128 deallocate(segments_recv_round)
4129 enddo
4130
4131 if (recvfill/=totalseg) call mpistop("cart_dda thick segmented receive mismatch")
4132
4133 if (totalseg>0) then
4134 allocate(idx(totalseg))
4135 bucketcounts(1:npixbatch)=0
4136 do is=1,totalseg
4137 if (segment_is_valid(segments_recv,is,nsegvars)) then
4138 ipix=nint(segments_recv(1,is))
4139 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
4140 ilocal=ipix-ipixstart+1
4141 bucketcounts(ilocal)=bucketcounts(ilocal)+1
4142 endif
4143 endif
4144 enddo
4145
4146 bucketoffsets(1)=1
4147 do ilocal=1,npixbatch
4148 bucketoffsets(ilocal+1)=bucketoffsets(ilocal)+bucketcounts(ilocal)
4149 enddo
4150 bucketfill(1:npixbatch)=bucketoffsets(1:npixbatch)
4151 do is=1,totalseg
4152 if (segment_is_valid(segments_recv,is,nsegvars)) then
4153 ipix=nint(segments_recv(1,is))
4154 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
4155 ilocal=ipix-ipixstart+1
4156 idx(bucketfill(ilocal))=is
4157 bucketfill(ilocal)=bucketfill(ilocal)+1
4158 endif
4159 endif
4160 enddo
4161
4162 do ipix=ipixstart,ipixend
4163 if (segment_pixel_owner(ipix)/=mype) cycle
4164 ilocal=ipix-ipixstart+1
4165 nidx=bucketcounts(ilocal)
4166 if (nidx>0) then
4167 profile_local(5)=profile_local(5)+dble(nidx)*dble(nidx)
4168 call sort_segment_indices_near_to_far(segments_recv,idx(bucketoffsets(ilocal):bucketoffsets(ilocal+1)-1),nidx)
4169 ixglobal=1+mod(ipix-1,nxif1)
4170 iyglobal=1+(ipix-1)/nxif1
4171 do iseg=bucketoffsets(ilocal),bucketoffsets(ilocal+1)-1
4172 is=idx(iseg)
4173 euvthin(ixglobal,iyglobal)=euvthin(ixglobal,iyglobal)+segments_recv(3,is)
4174 atten=transfer_attenuation(tau(ixglobal,iyglobal))
4175 euv(ixglobal,iyglobal)=euv(ixglobal,iyglobal)+atten*segments_recv(3,is)
4176 dpl(ixglobal,iyglobal)=dpl(ixglobal,iyglobal)+atten*segments_recv(5,is)
4177 tau(ixglobal,iyglobal)=tau(ixglobal,iyglobal)+max(zero,segments_recv(4,is))
4178 enddo
4179 endif
4180 enddo
4181 deallocate(idx)
4182 endif
4183
4184 deallocate(segments_send,segments_recv)
4185 if (allocated(segments)) deallocate(segments)
4186 ipixstart=ipixend+1
4187 enddo
4188
4189 do iigrid=1,igridstail
4190 if (allocated(cache(iigrid)%source)) deallocate(cache(iigrid)%source)
4191 if (allocated(cache(iigrid)%opacity)) deallocate(cache(iigrid)%opacity)
4192 if (allocated(cache(iigrid)%sourcev)) deallocate(cache(iigrid)%sourcev)
4193 if (allocated(cache(iigrid)%xface1)) deallocate(cache(iigrid)%xface1)
4194 if (allocated(cache(iigrid)%xface2)) deallocate(cache(iigrid)%xface2)
4195 if (allocated(cache(iigrid)%xface3)) deallocate(cache(iigrid)%xface3)
4196 enddo
4197 deallocate(cache)
4198 deallocate(sendcounts,recvcounts,senddispls,recvdispls,roundsendcounts,roundrecvcounts,&
4199 roundsenddispls,roundrecvdispls,ownersegcounts,owneroffsets,bucketcounts,&
4200 bucketoffsets,bucketfill)
4201 allocate(image_reduce(nxif1,nxif2))
4202 call mpi_allreduce(euv,image_reduce,nxif1*nxif2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4203 euv=image_reduce
4204 call mpi_allreduce(dpl,image_reduce,nxif1*nxif2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4205 dpl=image_reduce
4206 call mpi_allreduce(tau,image_reduce,nxif1*nxif2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4207 tau=image_reduce
4208 call mpi_allreduce(euvthin,image_reduce,nxif1*nxif2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4209 euvthin=image_reduce
4210 deallocate(image_reduce)
4211 call mpi_allreduce(profile_local,profile_global,5,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4212 if (radsyn_verbose .and. mype==0) then
4213 write(*,'(a,5(es12.5,1x))') &
4214 ' cart_dda thick profile: ',profile_global
4215 endif
4217
4218 subroutine integrate_euv_thick_datresol(nXIF1,nXIF2,fl,EUV,Dpl,Tau,EUVthin)
4220
4221 integer, intent(in) :: nXIF1,nXIF2
4222 type(te_fluid), intent(in) :: fl
4223 double precision, intent(out) :: EUV(nXIF1,nXIF2),Dpl(nXIF1,nXIF2)
4224 double precision, intent(out) :: Tau(nXIF1,nXIF2),EUVthin(nXIF1,nXIF2)
4225
4226 integer :: ixO^L,ixO^D,ixI^L,ix^D
4227 integer :: iigrid,igrid,levelg,rft,direction_LOS,nLOS,numSeg,nLayerVars,nLayerSeg
4228 integer :: ixP1,ixP2,ixL,iSub1,iSub2,relL
4229 integer :: nLosBatch,nBatch,iBatch,ixLstart,ixLend,ixLgridStart,ixLgridEnd
4230 integer :: ixPmin1,ixPmin2
4231 double precision :: ds_cm,jds,kds,jvds,atten,layerBytes,targetBytes
4232 double precision, allocatable :: rho(:^D&)
4233 double precision, allocatable :: layer_ds(:,:,:,:),layer_all(:,:,:,:)
4234 type(radsyn_euv_cache), allocatable :: cache(:)
4235
4236 if (los_phi==0 .and. los_theta==90) then
4237 direction_los=1
4238 nlos=domain_nx1*2**(refine_max_level-1)
4239 else if (los_phi==90 .and. los_theta==90) then
4240 direction_los=2
4241 nlos=domain_nx2*2**(refine_max_level-1)
4242 else
4243 direction_los=3
4244 nlos=domain_nx3*2**(refine_max_level-1)
4245 endif
4246
4247 nlayervars=3
4248 if (nxif1>huge(numseg)/max(1,nxif2) .or. nxif1*nxif2>huge(numseg)/nlayervars) then
4249 call mpistop("thick EUV layer buffer is too large for one MPI reduction")
4250 endif
4251 nlayerseg=nxif1*nxif2*nlayervars
4252 targetbytes=256.d0*1024.d0*1024.d0
4253 layerbytes=dble(nlayerseg)*8.d0*2.d0
4254 nlosbatch=max(1,min(16,int(targetbytes/max(one,layerbytes))))
4255 if (nlayerseg>huge(numseg)/nlosbatch) then
4256 call mpistop("thick EUV batched layer buffer is too large for one MPI reduction")
4257 endif
4258
4259 allocate(cache(igridstail))
4260 do iigrid=1,igridstail; igrid=igrids(iigrid);
4261 ^d&ixomin^d=ixmlo^d\
4262 ^d&ixomax^d=ixmhi^d\
4263 ^d&iximin^d=ixglo^d\
4264 ^d&iximax^d=ixghi^d\
4265
4266 cache(iigrid)%igrid=igrid
4267 levelg=ps(igrid)%level
4268 rft=2**(refine_max_level-levelg)
4269 cache(iigrid)%level=levelg
4270 cache(iigrid)%rft=rft
4271
4272 select case(direction_los)
4273 case(1)
4274 cache(iigrid)%los_min=(node(pig1_,igrid)-1)*rft*block_nx1+1
4275 cache(iigrid)%los_max=node(pig1_,igrid)*rft*block_nx1
4276 case(2)
4277 cache(iigrid)%los_min=(node(pig2_,igrid)-1)*rft*block_nx2+1
4278 cache(iigrid)%los_max=node(pig2_,igrid)*rft*block_nx2
4279 case(3)
4280 cache(iigrid)%los_min=(node(pig3_,igrid)-1)*rft*block_nx3+1
4281 cache(iigrid)%los_max=node(pig3_,igrid)*rft*block_nx3
4282 end select
4283
4284 allocate(cache(iigrid)%source(ixi^s),cache(iigrid)%opacity(ixi^s),&
4285 cache(iigrid)%sourcev(ixi^s),rho(ixi^s))
4286 cache(iigrid)%source=zero
4287 cache(iigrid)%opacity=zero
4288 cache(iigrid)%sourcev=zero
4289 if (trim(emission_model)=='radio_ff') then
4290 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,&
4291 cache(iigrid)%source,cache(iigrid)%opacity)
4292 else
4293 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%source)
4294 cache(iigrid)%source(ixo^s)=cache(iigrid)%source(ixo^s)/instrument_resolution_factor**2
4295 call get_euv_hhe_opacity(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%opacity)
4296 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,rho)
4297 cache(iigrid)%sourcev(ixo^s)=cache(iigrid)%source(ixo^s)*&
4298 (-ps(igrid)%w(ixo^s,iw_mom(direction_los))/rho(ixo^s))
4299 endif
4300 deallocate(rho)
4301 enddo
4302
4303 ! Stream a small batch of finest LOS layers; this avoids a full Npix*Nlos column buffer.
4304 allocate(layer_ds(nxif1,nxif2,nlayervars,nlosbatch),layer_all(nxif1,nxif2,nlayervars,nlosbatch))
4305 euv=zero
4306 dpl=zero
4307 tau=zero
4308 euvthin=zero
4309
4310 do ixlstart=1,nlos,nlosbatch
4311 ixlend=min(nlos,ixlstart+nlosbatch-1)
4312 nbatch=ixlend-ixlstart+1
4313 layer_ds(:,:,:,1:nbatch)=zero
4314
4315 do iigrid=1,igridstail
4316 ixlgridstart=max(ixlstart,cache(iigrid)%los_min)
4317 ixlgridend=min(ixlend,cache(iigrid)%los_max)
4318 if (ixlgridstart>ixlgridend) cycle
4319 igrid=cache(iigrid)%igrid
4320 rft=cache(iigrid)%rft
4321 ^d&ixomin^d=ixmlo^d\
4322 ^d&ixomax^d=ixmhi^d\
4323 ^d&iximin^d=ixglo^d\
4324 ^d&iximax^d=ixghi^d\
4325
4326 do ixl=ixlgridstart,ixlgridend
4327 ibatch=ixl-ixlstart+1
4328 rell=ixl-cache(iigrid)%los_min
4329
4330 select case(direction_los)
4331 case(1)
4332 ix1=ixomin1+rell/rft
4333 do ix2=ixomin2,ixomax2
4334 ixpmin1=(node(pig2_,igrid)-1)*rft*block_nx2+(ix2-ixomin2)*rft+1
4335 do ix3=ixomin3,ixomax3
4336 ixpmin2=(node(pig3_,igrid)-1)*rft*block_nx3+(ix3-ixomin3)*rft+1
4337 ds_cm=ps(igrid)%dx(ix^d,1)*unit_length/dble(rft)
4338 if (si_unit) ds_cm=ds_cm*1.d2
4339 jds=cache(iigrid)%source(ix^d)*ds_cm
4340 kds=cache(iigrid)%opacity(ix^d)*ds_cm
4341 jvds=cache(iigrid)%sourcev(ix^d)*ds_cm
4342 do isub1=0,rft-1
4343 ixp1=ixpmin1+isub1
4344 do isub2=0,rft-1
4345 ixp2=ixpmin2+isub2
4346 layer_ds(ixp1,ixp2,1,ibatch)=layer_ds(ixp1,ixp2,1,ibatch)+jds
4347 layer_ds(ixp1,ixp2,2,ibatch)=layer_ds(ixp1,ixp2,2,ibatch)+kds
4348 layer_ds(ixp1,ixp2,3,ibatch)=layer_ds(ixp1,ixp2,3,ibatch)+jvds
4349 enddo
4350 enddo
4351 enddo
4352 enddo
4353 case(2)
4354 ix2=ixomin2+rell/rft
4355 do ix3=ixomin3,ixomax3
4356 ixpmin1=(node(pig3_,igrid)-1)*rft*block_nx3+(ix3-ixomin3)*rft+1
4357 do ix1=ixomin1,ixomax1
4358 ixpmin2=(node(pig1_,igrid)-1)*rft*block_nx1+(ix1-ixomin1)*rft+1
4359 ds_cm=ps(igrid)%dx(ix^d,2)*unit_length/dble(rft)
4360 if (si_unit) ds_cm=ds_cm*1.d2
4361 jds=cache(iigrid)%source(ix^d)*ds_cm
4362 kds=cache(iigrid)%opacity(ix^d)*ds_cm
4363 jvds=cache(iigrid)%sourcev(ix^d)*ds_cm
4364 do isub1=0,rft-1
4365 ixp1=ixpmin1+isub1
4366 do isub2=0,rft-1
4367 ixp2=ixpmin2+isub2
4368 layer_ds(ixp1,ixp2,1,ibatch)=layer_ds(ixp1,ixp2,1,ibatch)+jds
4369 layer_ds(ixp1,ixp2,2,ibatch)=layer_ds(ixp1,ixp2,2,ibatch)+kds
4370 layer_ds(ixp1,ixp2,3,ibatch)=layer_ds(ixp1,ixp2,3,ibatch)+jvds
4371 enddo
4372 enddo
4373 enddo
4374 enddo
4375 case(3)
4376 ix3=ixomin3+rell/rft
4377 do ix1=ixomin1,ixomax1
4378 ixpmin1=(node(pig1_,igrid)-1)*rft*block_nx1+(ix1-ixomin1)*rft+1
4379 do ix2=ixomin2,ixomax2
4380 ixpmin2=(node(pig2_,igrid)-1)*rft*block_nx2+(ix2-ixomin2)*rft+1
4381 ds_cm=ps(igrid)%dx(ix^d,3)*unit_length/dble(rft)
4382 if (si_unit) ds_cm=ds_cm*1.d2
4383 jds=cache(iigrid)%source(ix^d)*ds_cm
4384 kds=cache(iigrid)%opacity(ix^d)*ds_cm
4385 jvds=cache(iigrid)%sourcev(ix^d)*ds_cm
4386 do isub1=0,rft-1
4387 ixp1=ixpmin1+isub1
4388 do isub2=0,rft-1
4389 ixp2=ixpmin2+isub2
4390 layer_ds(ixp1,ixp2,1,ibatch)=layer_ds(ixp1,ixp2,1,ibatch)+jds
4391 layer_ds(ixp1,ixp2,2,ibatch)=layer_ds(ixp1,ixp2,2,ibatch)+kds
4392 layer_ds(ixp1,ixp2,3,ibatch)=layer_ds(ixp1,ixp2,3,ibatch)+jvds
4393 enddo
4394 enddo
4395 enddo
4396 enddo
4397 end select
4398 enddo
4399 enddo
4400
4401 numseg=nlayerseg*nbatch
4402 call mpi_allreduce(layer_ds,layer_all,numseg,mpi_double_precision,mpi_sum,icomm,ierrmpi)
4403
4404 do ibatch=1,nbatch
4405 !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(atten) SCHEDULE(static)
4406 do ixp1=1,nxif1
4407 do ixp2=1,nxif2
4408 euvthin(ixp1,ixp2)=euvthin(ixp1,ixp2)+layer_all(ixp1,ixp2,1,ibatch)
4409 atten=transfer_attenuation(tau(ixp1,ixp2))
4410 euv(ixp1,ixp2)=euv(ixp1,ixp2)+atten*layer_all(ixp1,ixp2,1,ibatch)
4411 dpl(ixp1,ixp2)=dpl(ixp1,ixp2)+atten*layer_all(ixp1,ixp2,3,ibatch)
4412 tau(ixp1,ixp2)=tau(ixp1,ixp2)+layer_all(ixp1,ixp2,2,ibatch)
4413 enddo
4414 enddo
4415 !$OMP END PARALLEL DO
4416 enddo
4417 enddo
4418
4419 do iigrid=1,igridstail
4420 if (allocated(cache(iigrid)%source)) deallocate(cache(iigrid)%source)
4421 if (allocated(cache(iigrid)%opacity)) deallocate(cache(iigrid)%opacity)
4422 if (allocated(cache(iigrid)%sourcev)) deallocate(cache(iigrid)%sourcev)
4423 enddo
4424 deallocate(cache,layer_ds,layer_all)
4425
4426 end subroutine integrate_euv_thick_datresol
4427
4428 }
4429
4430 {^ifthreed
4431
4432 subroutine build_sph_intersection_faces(ixI^L,ixO^L,x,dx,rface,thetaface,phiface)
4433 integer, intent(in) :: ixI^L, ixO^L
4434 double precision, intent(in) :: x(ixI^S,1:ndim),dx(ixI^S,1:ndim)
4435 double precision, allocatable, intent(out) :: rface(:),thetaface(:),phiface(:)
4436 integer :: ix1,ix2,ix3
4437
4438 allocate(rface(ixomin1:ixomax1+1),thetaface(ixomin2:ixomax2+1),phiface(ixomin3:ixomax3+1))
4439 do ix1=ixomin1,ixomax1
4440 rface(ix1)=x(ix1,ixomin2,ixomin3,1)-half*dx(ix1,ixomin2,ixomin3,1)
4441 enddo
4442 rface(ixomax1+1)=x(ixomax1,ixomin2,ixomin3,1)+half*dx(ixomax1,ixomin2,ixomin3,1)
4443 do ix2=ixomin2,ixomax2
4444 thetaface(ix2)=x(ixomin1,ix2,ixomin3,2)-half*dx(ixomin1,ix2,ixomin3,2)
4445 enddo
4446 thetaface(ixomax2+1)=x(ixomin1,ixomax2,ixomin3,2)+half*dx(ixomin1,ixomax2,ixomin3,2)
4447 do ix3=ixomin3,ixomax3
4448 phiface(ix3)=x(ixomin1,ixomin2,ix3,3)-half*dx(ixomin1,ixomin2,ix3,3)
4449 enddo
4450 phiface(ixomax3+1)=x(ixomin1,ixomin2,ixomax3,3)+half*dx(ixomin1,ixomin2,ixomax3,3)
4451 end subroutine build_sph_intersection_faces
4452
4453 subroutine sph_add_t(tvals,nt,capacity,t)
4454 double precision, allocatable, intent(inout) :: tvals(:)
4455 integer, intent(inout) :: nt,capacity
4456 double precision, intent(in) :: t
4457
4458 double precision, allocatable :: tmp(:)
4459
4460 if (t /= t .or. abs(t)>1.d90) return
4461 if (.not. allocated(tvals)) then
4462 capacity=64
4463 allocate(tvals(capacity))
4464 else if (nt>=capacity) then
4465 allocate(tmp(capacity))
4466 tmp=tvals
4467 deallocate(tvals)
4468 allocate(tvals(2*capacity))
4469 tvals(1:capacity)=tmp
4470 deallocate(tmp)
4471 capacity=2*capacity
4472 endif
4473 nt=nt+1
4474 tvals(nt)=t
4475 end subroutine sph_add_t
4476
4477 subroutine sph_add_t_fixed(tvals,nt,t)
4478 double precision, intent(inout) :: tvals(:)
4479 integer, intent(inout) :: nt
4480 double precision, intent(in) :: t
4481
4482 if (t /= t .or. abs(t)>1.d90) return
4483 if (nt>=size(tvals)) return
4484 nt=nt+1
4485 tvals(nt)=t
4486 end subroutine sph_add_t_fixed
4487
4488 subroutine sph_sort_unique_t(tvals,nt)
4489 double precision, intent(inout) :: tvals(:)
4490 integer, intent(inout) :: nt
4491
4492 integer :: i,j,nout
4493 double precision :: key,epsT
4494
4495 if (nt<=1) return
4496 do i=2,nt
4497 key=tvals(i)
4498 j=i-1
4499 do while (j>=1 .and. tvals(j)>key)
4500 tvals(j+1)=tvals(j)
4501 j=j-1
4502 enddo
4503 tvals(j+1)=key
4504 enddo
4505 epst=max(1.d-12,1.d-10*max(one,abs(tvals(nt)-tvals(1))))
4506 nout=1
4507 do i=2,nt
4508 if (abs(tvals(i)-tvals(nout))>epst) then
4509 nout=nout+1
4510 tvals(nout)=tvals(i)
4511 endif
4512 enddo
4513 nt=nout
4514 end subroutine sph_sort_unique_t
4515
4516 subroutine sph_add_sphere_intersections(ray_origin,ray_dir,rface,tvals,nt,capacity)
4517 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),rface
4518 double precision, allocatable, intent(inout) :: tvals(:)
4519 integer, intent(inout) :: nt,capacity
4520
4521 double precision :: aa,bb,cc,disc,root
4522
4523 aa=sum(ray_dir**2)
4524 bb=2.d0*sum(ray_origin*ray_dir)
4525 cc=sum(ray_origin**2)-rface**2
4526 disc=bb**2-4.d0*aa*cc
4527 if (disc<zero) return
4528 root=sqrt(max(zero,disc))
4529 call sph_add_t(tvals,nt,capacity,(-bb-root)/(2.d0*aa))
4530 call sph_add_t(tvals,nt,capacity,(-bb+root)/(2.d0*aa))
4531 end subroutine sph_add_sphere_intersections
4532
4533 subroutine sph_add_theta_intersections(ray_origin,ray_dir,thetaface,tvals,nt,capacity)
4534 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),thetaface
4535 double precision, allocatable, intent(inout) :: tvals(:)
4536 integer, intent(inout) :: nt,capacity
4537
4538 double precision :: cth,aa,bb,cc,disc,root
4539
4540 cth=cos(thetaface)
4541 ! At the equator the cone equation degenerates to z**2=0. Solve the
4542 ! corresponding plane intersection directly to avoid losing its double
4543 ! root through roundoff in the quadratic discriminant.
4544 if (abs(cth)<1.d-12) then
4545 if (abs(ray_dir(3))>1.d-14) &
4546 call sph_add_t(tvals,nt,capacity,-ray_origin(3)/ray_dir(3))
4547 return
4548 endif
4549 aa=ray_dir(3)**2-cth**2*sum(ray_dir**2)
4550 bb=2.d0*(ray_origin(3)*ray_dir(3)-cth**2*sum(ray_origin*ray_dir))
4551 cc=ray_origin(3)**2-cth**2*sum(ray_origin**2)
4552 if (abs(aa)<1.d-14) then
4553 if (abs(bb)>1.d-14) call sph_add_t(tvals,nt,capacity,-cc/bb)
4554 return
4555 endif
4556 disc=bb**2-4.d0*aa*cc
4557 if (disc<zero) return
4558 root=sqrt(max(zero,disc))
4559 call sph_add_t(tvals,nt,capacity,(-bb-root)/(2.d0*aa))
4560 call sph_add_t(tvals,nt,capacity,(-bb+root)/(2.d0*aa))
4561 end subroutine sph_add_theta_intersections
4562
4563 subroutine sph_add_phi_intersection(ray_origin,ray_dir,phiface,tvals,nt,capacity)
4564 double precision, intent(in) :: ray_origin(1:3),ray_dir(1:3),phiface
4565 double precision, allocatable, intent(inout) :: tvals(:)
4566 integer, intent(inout) :: nt,capacity
4567
4568 double precision :: normal(1:3),denom,numer
4569
4570 normal(1)=-sin(phiface)
4571 normal(2)=cos(phiface)
4572 normal(3)=zero
4573 denom=sum(normal*ray_dir)
4574 if (abs(denom)<1.d-14) return
4575 numer=sum(normal*ray_origin)
4576 call sph_add_t(tvals,nt,capacity,-numer/denom)
4577 end subroutine sph_add_phi_intersection
4578
4579 subroutine sph_cart_to_coord(pos,sph)
4580 double precision, intent(in) :: pos(1:3)
4581 double precision, intent(out) :: sph(1:3)
4582
4583 sph(1)=sqrt(sum(pos**2))
4584 if (sph(1)>zero) then
4585 sph(2)=acos(max(-one,min(one,pos(3)/sph(1))))
4586 else
4587 sph(2)=zero
4588 endif
4589 sph(3)=atan2(pos(2),pos(1))
4590 end subroutine sph_cart_to_coord
4591
4592 integer function sph_locate_index(value,faces,imin,imax) result(idx)
4593 integer, intent(in) :: imin,imax
4594 double precision, intent(in) :: value,faces(imin:imax+1)
4595
4596 integer :: ilo,ihi,imid
4597
4598 idx=0
4599 if (value<faces(imin)-1.d-12 .or. value>faces(imax+1)+1.d-12) return
4600 if (value<=faces(imin)) then
4601 idx=imin
4602 return
4603 endif
4604 if (value>=faces(imax+1)) then
4605 idx=imax
4606 return
4607 endif
4608
4609 ilo=imin
4610 ihi=imax+1
4611 do while (ihi-ilo>1)
4612 imid=(ilo+ihi)/2
4613 if (value>=faces(imid)) then
4614 ilo=imid
4615 else
4616 ihi=imid
4617 endif
4618 enddo
4619 idx=min(imax,max(imin,ilo))
4620 end function sph_locate_index
4621
4622 integer function sph_locate_index_desc(value,faces,imin,imax) result(idx)
4623 integer, intent(in) :: imin,imax
4624 double precision, intent(in) :: value,faces(imin:imax+1)
4625
4626 integer :: ilo,ihi,imid
4627
4628 idx=0
4629 if (value>faces(imin)+1.d-12 .or. value<faces(imax+1)-1.d-12) return
4630 if (value>=faces(imin)) then
4631 idx=imin
4632 return
4633 endif
4634 if (value<=faces(imax+1)) then
4635 idx=imax
4636 return
4637 endif
4638
4639 ilo=imin
4640 ihi=imax+1
4641 do while (ihi-ilo>1)
4642 imid=(ilo+ihi)/2
4643 if (value<=faces(imid)) then
4644 ilo=imid
4645 else
4646 ihi=imid
4647 endif
4648 enddo
4649 idx=min(imax,max(imin,ilo))
4650 end function sph_locate_index_desc
4651
4652 subroutine sph_locate_cell(pos,rface,thetaface,phiface,ixO^L,ix1,ix2,ix3,inside)
4653 double precision, intent(in) :: pos(1:3)
4654 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4655 phiface(ixOmin3:ixOmax3+1)
4656 integer, intent(in) :: ixO^L
4657 integer, intent(out) :: ix1,ix2,ix3
4658 logical, intent(out) :: inside
4659
4660 double precision :: sph(1:3),phi
4661
4662 call sph_cart_to_coord(pos,sph)
4663 phi=sph(3)
4664 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4665 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4666 ix1=sph_locate_index(sph(1),rface,ixomin1,ixomax1)
4667 ix2=sph_locate_index(sph(2),thetaface,ixomin2,ixomax2)
4668 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4669 inside=ix1>0 .and. ix2>0 .and. ix3>0
4670 end subroutine sph_locate_cell
4671
4672 logical function sph_segment_visible(pos,ximg1,ximg2) result(visible)
4673 use mod_constants
4674 double precision, intent(in) :: pos(1:3),ximg1,ximg2
4675
4676 double precision :: dotp,rc,rthick,rloc
4677
4678 rthick=r_opt_thick*const_rsun/unit_length
4679 rc=sqrt(ximg1**2+ximg2**2)
4680 rloc=sqrt(sum(pos**2))
4681 call dot_product_loc(vec_los,pos,dotp)
4682 visible=.true.
4683 if (dotp>=zero) then
4684 if (rc<=rthick) visible=.false.
4685 else
4686 if (rloc<=rthick) visible=.false.
4687 endif
4688 end function sph_segment_visible
4689
4690 subroutine sph_block_pixel_range(rface,thetaface,phiface,ixO^L,nXI1,nXI2,xI1,xI2,dxI,&
4691 ixPmin1,ixPmax1,ixPmin2,ixPmax2,has_pixels)
4692 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4693 phiface(ixOmin3:ixOmax3+1)
4694 integer, intent(in) :: ixO^L,nXI1,nXI2
4695 double precision, intent(in) :: xI1(nXI1),xI2(nXI2),dxI
4696 integer, intent(out) :: ixPmin1,ixPmax1,ixPmin2,ixPmax2
4697 logical, intent(out) :: has_pixels
4698
4699 integer, parameter :: nsample=5
4700 integer :: ir,it,ip
4701 double precision :: sph(1:3),xcent(1:2)
4702 double precision :: xmin1,xmax1,xmin2,xmax2
4703 double precision :: wr,wt,wp,pad
4704
4705 has_pixels=.false.
4706 xmin1=huge(one)
4707 xmax1=-huge(one)
4708 xmin2=huge(one)
4709 xmax2=-huge(one)
4710 do ir=0,nsample-1
4711 wr=dble(ir)/dble(nsample-1)
4712 sph(1)=(one-wr)*rface(ixomin1)+wr*rface(ixomax1+1)
4713 do it=0,nsample-1
4714 wt=dble(it)/dble(nsample-1)
4715 sph(2)=(one-wt)*thetaface(ixomin2)+wt*thetaface(ixomax2+1)
4716 do ip=0,nsample-1
4717 wp=dble(ip)/dble(nsample-1)
4718 if (ir/=0 .and. ir/=nsample-1 .and. it/=0 .and. it/=nsample-1 .and. &
4719 ip/=0 .and. ip/=nsample-1) cycle
4720 sph(3)=(one-wp)*phiface(ixomin3)+wp*phiface(ixomax3+1)
4721 call get_cor_image_spherical(sph,xcent)
4722 xmin1=min(xmin1,xcent(1))
4723 xmax1=max(xmax1,xcent(1))
4724 xmin2=min(xmin2,xcent(2))
4725 xmax2=max(xmax2,xcent(2))
4726 enddo
4727 enddo
4728 enddo
4729 pad=2.d0*dxi
4730 xmin1=xmin1-pad
4731 xmax1=xmax1+pad
4732 xmin2=xmin2-pad
4733 xmax2=xmax2+pad
4734 ixpmin1=max(1,floor((xmin1-(xi1(1)-half*dxi))/dxi)+1)
4735 ixpmax1=min(nxi1,ceiling((xmax1-(xi1(1)-half*dxi))/dxi))
4736 ixpmin2=max(1,floor((xmin2-(xi2(1)-half*dxi))/dxi)+1)
4737 ixpmax2=min(nxi2,ceiling((xmax2-(xi2(1)-half*dxi))/dxi))
4738 has_pixels=ixpmin1<=ixpmax1 .and. ixpmin2<=ixpmax2
4739 end subroutine sph_block_pixel_range
4740
4741 subroutine acc_euv_sph_intersection(ixI^L,ixO^L,source,ray_origin,ximg1,ximg2,&
4742 rface,thetaface,phiface,EUVp)
4743 integer, intent(in) :: ixI^L,ixO^L
4744 double precision, intent(in) :: source(ixI^S),ray_origin(1:3),ximg1,ximg2
4745 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4746 phiface(ixOmin3:ixOmax3+1)
4747 double precision, intent(inout) :: EUVp
4748
4749 integer :: nt,capacity,i,ix^D
4750 double precision, allocatable :: tvals(:)
4751 double precision :: posMid(1:3),ds_cm,tMid,t0,t1
4752 logical :: inside
4753
4754 nt=0
4755 capacity=0
4756 do ix1=ixomin1,ixomax1+1
4757 call sph_add_sphere_intersections(ray_origin,vec_los,rface(ix1),tvals,nt,capacity)
4758 enddo
4759 do ix2=ixomin2,ixomax2+1
4760 call sph_add_theta_intersections(ray_origin,vec_los,thetaface(ix2),tvals,nt,capacity)
4761 enddo
4762 do ix3=ixomin3,ixomax3+1
4763 call sph_add_phi_intersection(ray_origin,vec_los,phiface(ix3),tvals,nt,capacity)
4764 enddo
4765 if (nt<2) then
4766 if (allocated(tvals)) deallocate(tvals)
4767 return
4768 endif
4769 call sph_sort_unique_t(tvals,nt)
4770
4771 do i=1,nt-1
4772 t0=tvals(i)
4773 t1=tvals(i+1)
4774 if (t1<=t0) cycle
4775 tmid=half*(t0+t1)
4776 posmid=ray_origin+tmid*vec_los
4777 if (.not. sph_segment_visible(posmid,ximg1,ximg2)) cycle
4778 call sph_locate_cell(posmid,rface,thetaface,phiface,ixo^l,ix1,ix2,ix3,inside)
4779 if (.not. inside) cycle
4780 ds_cm=(t1-t0)*unit_length
4781 if (si_unit) ds_cm=ds_cm*1.d2
4782 euvp=euvp+source(ix^d)*ds_cm
4783 enddo
4784 deallocate(tvals)
4785 end subroutine acc_euv_sph_intersection
4786
4787 subroutine collect_euv_sph_intersection_segments(ixI^L,ixO^L,source,opacity,&
4788 pixel_id,ray_origin,ximg1,ximg2,&
4789 rface,thetaface,phiface,rface2,&
4790 theta_cos,phi_sin,phi_cos,&
4791 segments,nseg,capacity)
4792 use mod_constants, only: const_rsun
4793
4794 integer, intent(in) :: ixI^L,ixO^L,pixel_id
4795 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
4796 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
4797 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
4798 phiface(ixOmin3:ixOmax3+1)
4799 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4800 phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
4801 double precision, allocatable, intent(inout) :: segments(:,:)
4802 integer, intent(inout) :: nseg,capacity
4803
4804 integer :: nt,i,ix^D
4805 double precision :: tvals(2*(ixOmax1-ixOmin1+2)+2*(ixOmax2-ixOmin2+2)+&
4806 (ixOmax3-ixOmin3+2))
4807 double precision :: posMid(1:3),ds_cm,tMid,t0,t1,jds,kds
4808 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2
4809 double precision :: denom,numer,r2,mu,phi,dotp,rthick2,rc2
4810 logical :: inside
4811
4812 nt=0
4813 dir2=sum(vec_los**2)
4814 origin2=sum(ray_origin**2)
4815 odotd=sum(ray_origin*vec_los)
4816 rthick2=(r_opt_thick*const_rsun/unit_length)**2
4817 rc2=ximg1**2+ximg2**2
4818
4819 do ix1=ixomin1,ixomax1+1
4820 aa=dir2
4821 bb=2.d0*odotd
4822 cc=origin2-rface2(ix1)
4823 disc=bb**2-4.d0*aa*cc
4824 if (disc>=zero) then
4825 root=sqrt(max(zero,disc))
4826 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
4827 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
4828 endif
4829 enddo
4830 do ix2=ixomin2,ixomax2+1
4831 if (abs(theta_cos(ix2))<1.d-12) then
4832 if (abs(vec_los(3))>1.d-14) &
4833 call sph_add_t_fixed(tvals,nt,-ray_origin(3)/vec_los(3))
4834 cycle
4835 endif
4836 cth2=theta_cos(ix2)**2
4837 aa=vec_los(3)**2-cth2*dir2
4838 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
4839 cc=ray_origin(3)**2-cth2*origin2
4840 if (abs(aa)<1.d-14) then
4841 if (abs(bb)>1.d-14) call sph_add_t_fixed(tvals,nt,-cc/bb)
4842 else
4843 disc=bb**2-4.d0*aa*cc
4844 if (disc>=zero) then
4845 root=sqrt(max(zero,disc))
4846 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
4847 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
4848 endif
4849 endif
4850 enddo
4851 do ix3=ixomin3,ixomax3+1
4852 denom=-phi_sin(ix3)*vec_los(1)+phi_cos(ix3)*vec_los(2)
4853 if (abs(denom)>=1.d-14) then
4854 numer=-phi_sin(ix3)*ray_origin(1)+phi_cos(ix3)*ray_origin(2)
4855 call sph_add_t_fixed(tvals,nt,-numer/denom)
4856 endif
4857 enddo
4858 if (nt<2) return
4859 call sph_sort_unique_t(tvals,nt)
4860
4861 do i=1,nt-1
4862 t0=tvals(i)
4863 t1=tvals(i+1)
4864 if (t1<=t0) cycle
4865 tmid=half*(t0+t1)
4866 posmid=ray_origin+tmid*vec_los
4867 r2=sum(posmid**2)
4868 dotp=sum(vec_los*posmid)
4869 if (dotp>=zero) then
4870 if (rc2<=rthick2) cycle
4871 else
4872 if (r2<=rthick2) cycle
4873 endif
4874
4875 ix1=sph_locate_index(r2,rface2,ixomin1,ixomax1)
4876 if (r2>zero) then
4877 mu=posmid(3)/sqrt(r2)
4878 else
4879 mu=one
4880 endif
4881 ix2=sph_locate_index_desc(mu,theta_cos,ixomin2,ixomax2)
4882 phi=atan2(posmid(2),posmid(1))
4883 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4884 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4885 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4886 inside=ix1>0 .and. ix2>0 .and. ix3>0
4887 if (.not. inside) cycle
4888 ds_cm=(t1-t0)*unit_length
4889 if (si_unit) ds_cm=ds_cm*1.d2
4890 jds=max(zero,source(ix^d))*ds_cm
4891 kds=max(zero,opacity(ix^d))*ds_cm
4892 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tmid,jds,kds,zero)
4893 enddo
4895
4896 subroutine sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixO^L,ix1,ix2,ix3,inside)
4897 double precision, intent(in) :: pos(1:3)
4898 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4899 phiface(ixOmin3:ixOmax3+1)
4900 integer, intent(in) :: ixO^L
4901 integer, intent(out) :: ix1,ix2,ix3
4902 logical, intent(out) :: inside
4903
4904 double precision :: r2,mu,phi
4905
4906 r2=sum(pos**2)
4907 ix1=sph_locate_index(r2,rface2,ixomin1,ixomax1)
4908 if (r2>zero) then
4909 mu=pos(3)/sqrt(r2)
4910 else
4911 mu=one
4912 endif
4913 ix2=sph_locate_index_desc(mu,theta_cos,ixomin2,ixomax2)
4914 phi=atan2(pos(2),pos(1))
4915 if (phi<phiface(ixomin3)-1.d-12) phi=phi+2.d0*dpi
4916 if (phi>phiface(ixomax3+1)+1.d-12) phi=phi-2.d0*dpi
4917 ix3=sph_locate_index(phi,phiface,ixomin3,ixomax3)
4918 inside=ix1>0 .and. ix2>0 .and. ix3>0
4919 end subroutine sph_locate_cell_fast
4920
4921 subroutine sph_try_exit_candidate(t,tNow,tExit,epsRay,tNext,found)
4922 double precision, intent(in) :: t,tNow,tExit,epsRay
4923 double precision, intent(inout) :: tNext
4924 logical, intent(inout) :: found
4925
4926 if (t>tnow+epsray .and. t<=texit+epsray .and. t<tnext) then
4927 tnext=t
4928 found=.true.
4929 endif
4930 end subroutine sph_try_exit_candidate
4931
4932 subroutine sph_try_theta_exit_candidate(t,theta_face_cos,ray_origin,tNow,tExit,epsRay,tNext,found)
4933 double precision, intent(in) :: t,theta_face_cos,ray_origin(1:3),tNow,tExit,epsRay
4934 double precision, intent(inout) :: tNext
4935 logical, intent(inout) :: found
4936
4937 double precision :: pos(1:3),r2
4938
4939 if (t<=tnow+epsray .or. t>texit+epsray .or. t>=tnext) return
4940 pos=ray_origin+t*vec_los
4941 r2=sum(pos**2)
4942 if (r2<=zero) return
4943 if (theta_face_cos>1.d-12 .and. pos(3)<-1.d-10) return
4944 if (theta_face_cos<-1.d-12 .and. pos(3)>1.d-10) return
4945 if (abs(pos(3)**2-theta_face_cos**2*r2)>1.d-6*max(one,r2)) return
4946 tnext=t
4947 found=.true.
4948 end subroutine sph_try_theta_exit_candidate
4949
4950 subroutine sph_try_phi_exit_candidate(t,phi_face_sin,phi_face_cos,ray_origin,tNow,tExit,epsRay,tNext,found)
4951 double precision, intent(in) :: t,phi_face_sin,phi_face_cos,ray_origin(1:3),tNow,tExit,epsRay
4952 double precision, intent(inout) :: tNext
4953 logical, intent(inout) :: found
4954
4955 double precision :: pos(1:3),radialDot
4956
4957 if (t<=tnow+epsray .or. t>texit+epsray .or. t>=tnext) return
4958 pos=ray_origin+t*vec_los
4959 radialdot=phi_face_cos*pos(1)+phi_face_sin*pos(2)
4960 if (radialdot<-1.d-10) return
4961 tnext=t
4962 found=.true.
4963 end subroutine sph_try_phi_exit_candidate
4964
4965 subroutine sph_next_cell_exit(ray_origin,rface2,theta_cos,phiface,phi_sin,phi_cos,ixO^L,&
4966 ix1,ix2,ix3,tNow,tExit,epsRay,tNext,found)
4967 double precision, intent(in) :: ray_origin(1:3)
4968 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
4969 phiface(ixOmin3:ixOmax3+1)
4970 double precision, intent(in) :: phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
4971 integer, intent(in) :: ixO^L,ix1,ix2,ix3
4972 double precision, intent(in) :: tNow,tExit,epsRay
4973 double precision, intent(out) :: tNext
4974 logical, intent(out) :: found
4975
4976 integer :: iface
4977 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2,denom,numer
4978
4979 found=.false.
4980 tnext=huge(one)
4981 dir2=sum(vec_los**2)
4982 origin2=sum(ray_origin**2)
4983 odotd=sum(ray_origin*vec_los)
4984
4985 do iface=ix1,ix1+1
4986 aa=dir2
4987 bb=2.d0*odotd
4988 cc=origin2-rface2(iface)
4989 disc=bb**2-4.d0*aa*cc
4990 if (disc>=zero) then
4991 root=sqrt(max(zero,disc))
4992 call sph_try_exit_candidate((-bb-root)/(2.d0*aa),tnow,texit,epsray,tnext,found)
4993 call sph_try_exit_candidate((-bb+root)/(2.d0*aa),tnow,texit,epsray,tnext,found)
4994 endif
4995 enddo
4996
4997 do iface=ix2,ix2+1
4998 if (abs(theta_cos(iface))<1.d-12) then
4999 if (abs(vec_los(3))>1.d-14) call sph_try_theta_exit_candidate(&
5000 -ray_origin(3)/vec_los(3),theta_cos(iface),ray_origin,tnow,texit,epsray,&
5001 tnext,found)
5002 cycle
5003 endif
5004 cth2=theta_cos(iface)**2
5005 aa=vec_los(3)**2-cth2*dir2
5006 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
5007 cc=ray_origin(3)**2-cth2*origin2
5008 if (abs(aa)<1.d-14) then
5009 if (abs(bb)>1.d-14) call sph_try_theta_exit_candidate(-cc/bb,theta_cos(iface),&
5010 ray_origin,tnow,texit,epsray,tnext,found)
5011 else
5012 disc=bb**2-4.d0*aa*cc
5013 if (disc>=zero) then
5014 root=sqrt(max(zero,disc))
5015 call sph_try_theta_exit_candidate((-bb-root)/(2.d0*aa),theta_cos(iface),&
5016 ray_origin,tnow,texit,epsray,tnext,found)
5017 call sph_try_theta_exit_candidate((-bb+root)/(2.d0*aa),theta_cos(iface),&
5018 ray_origin,tnow,texit,epsray,tnext,found)
5019 endif
5020 endif
5021 enddo
5022
5023 do iface=ix3,ix3+1
5024 denom=-phi_sin(iface)*vec_los(1)+phi_cos(iface)*vec_los(2)
5025 if (abs(denom)>=1.d-14) then
5026 numer=-phi_sin(iface)*ray_origin(1)+phi_cos(iface)*ray_origin(2)
5027 call sph_try_phi_exit_candidate(-numer/denom,phi_sin(iface),phi_cos(iface),ray_origin,&
5028 tnow,texit,epsray,tnext,found)
5029 endif
5030 enddo
5031 end subroutine sph_next_cell_exit
5032
5033 subroutine collect_euv_sph_dda_interval(ixI^L,ixO^L,source,opacity,pixel_id,&
5034 ray_origin,ximg1,ximg2,rface2,theta_cos,phiface,&
5035 phi_sin,phi_cos,&
5036 t_enter,t_exit,segments,nseg,capacity,ok)
5037 use mod_constants, only: const_rsun
5038
5039 integer, intent(in) :: ixI^L,ixO^L,pixel_id
5040 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
5041 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
5042 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
5043 phiface(ixOmin3:ixOmax3+1)
5044 double precision, intent(in) :: phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
5045 double precision, intent(in) :: t_enter,t_exit
5046 double precision, allocatable, intent(inout) :: segments(:,:)
5047 integer, intent(inout) :: nseg,capacity
5048 logical, intent(out) :: ok
5049
5050 integer :: ix^D,nstep,maxSteps
5051 double precision :: tNow,tNext,tEnd,tMid,epsRay,ds_cm,jds,kds
5052 double precision :: pos(1:3),r2,dotp,rthick2,rc2
5053 logical :: inside,found
5054
5055 ok=.true.
5056 if (t_exit<=t_enter) return
5057 epsray=max(1.d-12,1.d-10*max(one,abs(t_exit-t_enter)))
5058 pos=ray_origin+(t_enter+epsray)*vec_los
5059 call sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5060 if (.not. inside) then
5061 ok=.false.
5062 return
5063 endif
5064
5065 rthick2=(r_opt_thick*const_rsun/unit_length)**2
5066 rc2=ximg1**2+ximg2**2
5067 tnow=t_enter
5068 nstep=0
5069 maxsteps=8*((ixomax1-ixomin1+1)+(ixomax2-ixomin2+1)+(ixomax3-ixomin3+1)+3)
5070
5071 do while (tnow<t_exit-epsray)
5072 call sph_next_cell_exit(ray_origin,rface2,theta_cos,phiface,phi_sin,phi_cos,ixo^l,&
5073 ix1,ix2,ix3,tnow,t_exit,epsray,tnext,found)
5074 if (.not. found) then
5075 ok=.false.
5076 return
5077 endif
5078 tend=min(tnext,t_exit)
5079 if (tend>tnow) then
5080 tmid=half*(tnow+tend)
5081 pos=ray_origin+tmid*vec_los
5082 r2=sum(pos**2)
5083 dotp=sum(vec_los*pos)
5084 if (.not. ((dotp>=zero .and. rc2<=rthick2) .or. &
5085 (dotp<zero .and. r2<=rthick2))) then
5086 ds_cm=(tend-tnow)*unit_length
5087 if (si_unit) ds_cm=ds_cm*1.d2
5088 jds=max(zero,source(ix^d))*ds_cm
5089 kds=max(zero,opacity(ix^d))*ds_cm
5090 call append_cart_dda_segment(segments,nseg,capacity,pixel_id,tmid,jds,kds,zero)
5091 endif
5092 endif
5093 tnow=tend
5094 if (tnow>=t_exit-epsray) exit
5095 pos=ray_origin+(tnow+epsray)*vec_los
5096 call sph_locate_cell_fast(pos,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5097 if (.not. inside) then
5098 ok=.false.
5099 return
5100 endif
5101 nstep=nstep+1
5102 if (nstep>maxsteps) then
5103 ok=.false.
5104 return
5105 endif
5106 enddo
5107 end subroutine collect_euv_sph_dda_interval
5108
5109 subroutine collect_euv_sph_dda_segments(ixI^L,ixO^L,source,opacity,&
5110 pixel_id,ray_origin,ximg1,ximg2,&
5111 rface,thetaface,phiface,rface2,&
5112 theta_cos,phi_sin,phi_cos,&
5113 segments,nseg,capacity,fallback)
5114 integer, intent(in) :: ixI^L,ixO^L,pixel_id
5115 double precision, intent(in) :: source(ixI^S),opacity(ixI^S)
5116 double precision, intent(in) :: ray_origin(1:3),ximg1,ximg2
5117 double precision, intent(in) :: rface(ixOmin1:ixOmax1+1),thetaface(ixOmin2:ixOmax2+1),&
5118 phiface(ixOmin3:ixOmax3+1)
5119 double precision, intent(in) :: rface2(ixOmin1:ixOmax1+1),theta_cos(ixOmin2:ixOmax2+1),&
5120 phi_sin(ixOmin3:ixOmax3+1),phi_cos(ixOmin3:ixOmax3+1)
5121 double precision, allocatable, intent(inout) :: segments(:,:)
5122 integer, intent(inout) :: nseg,capacity
5123 logical, intent(out) :: fallback
5124
5125 integer :: nt,i,nsegStart,ix^D
5126 double precision :: tvals(12),posMid(1:3),t0,t1,tMid
5127 double precision :: dir2,origin2,odotd,aa,bb,cc,disc,root,cth2,denom,numer
5128 logical :: inside,ok
5129
5130 fallback=.false.
5131 nsegstart=nseg
5132 nt=0
5133 dir2=sum(vec_los**2)
5134 origin2=sum(ray_origin**2)
5135 odotd=sum(ray_origin*vec_los)
5136
5137 do ix1=ixomin1,ixomax1+1,ixomax1-ixomin1+1
5138 aa=dir2
5139 bb=2.d0*odotd
5140 cc=origin2-rface2(ix1)
5141 disc=bb**2-4.d0*aa*cc
5142 if (disc>=zero) then
5143 root=sqrt(max(zero,disc))
5144 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
5145 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
5146 endif
5147 enddo
5148 do ix2=ixomin2,ixomax2+1,ixomax2-ixomin2+1
5149 if (abs(theta_cos(ix2))<1.d-12) then
5150 if (abs(vec_los(3))>1.d-14) &
5151 call sph_add_t_fixed(tvals,nt,-ray_origin(3)/vec_los(3))
5152 cycle
5153 endif
5154 cth2=theta_cos(ix2)**2
5155 aa=vec_los(3)**2-cth2*dir2
5156 bb=2.d0*(ray_origin(3)*vec_los(3)-cth2*odotd)
5157 cc=ray_origin(3)**2-cth2*origin2
5158 if (abs(aa)<1.d-14) then
5159 if (abs(bb)>1.d-14) call sph_add_t_fixed(tvals,nt,-cc/bb)
5160 else
5161 disc=bb**2-4.d0*aa*cc
5162 if (disc>=zero) then
5163 root=sqrt(max(zero,disc))
5164 call sph_add_t_fixed(tvals,nt,(-bb-root)/(2.d0*aa))
5165 call sph_add_t_fixed(tvals,nt,(-bb+root)/(2.d0*aa))
5166 endif
5167 endif
5168 enddo
5169 do ix3=ixomin3,ixomax3+1,ixomax3-ixomin3+1
5170 denom=-phi_sin(ix3)*vec_los(1)+phi_cos(ix3)*vec_los(2)
5171 if (abs(denom)>=1.d-14) then
5172 numer=-phi_sin(ix3)*ray_origin(1)+phi_cos(ix3)*ray_origin(2)
5173 call sph_add_t_fixed(tvals,nt,-numer/denom)
5174 endif
5175 enddo
5176
5177 if (nt<2) return
5178 call sph_sort_unique_t(tvals,nt)
5179
5180 do i=1,nt-1
5181 t0=tvals(i)
5182 t1=tvals(i+1)
5183 if (t1<=t0) cycle
5184 tmid=half*(t0+t1)
5185 posmid=ray_origin+tmid*vec_los
5186 call sph_locate_cell_fast(posmid,rface2,theta_cos,phiface,ixo^l,ix1,ix2,ix3,inside)
5187 if (.not. inside) cycle
5188 call collect_euv_sph_dda_interval(ixi^l,ixo^l,source,opacity,pixel_id,&
5189 ray_origin,ximg1,ximg2,rface2,theta_cos,phiface,phi_sin,phi_cos,&
5190 t0,t1,segments,nseg,capacity,ok)
5191 if (.not. ok) then
5192 nseg=nsegstart
5193 fallback=.true.
5194 call collect_euv_sph_intersection_segments(ixi^l,ixo^l,source,opacity,&
5195 pixel_id,ray_origin,ximg1,ximg2,rface,thetaface,phiface,rface2,&
5196 theta_cos,phi_sin,phi_cos,segments,nseg,capacity)
5197 return
5198 endif
5199 enddo
5200
5201 end subroutine collect_euv_sph_dda_segments
5202
5203 subroutine integrate_euv_sph_intersection_thin(numXI1,numXI2,xI1,xI2,dxI,fl,EM)
5205
5206 integer, intent(in) :: numXI1,numXI2
5207 double precision, intent(in) :: xI1(numXI1),xI2(numXI2),dxI
5208 type(te_fluid), intent(in) :: fl
5209 double precision, intent(inout) :: EM(numXI1,numXI2)
5210
5211 integer :: ixO^L,ixI^L,ix^D
5212 integer :: iigrid,igrid,ixP1,ixP2,ixPmin1,ixPmax1,ixPmin2,ixPmax2
5213 integer :: iseg,nseg,capacity,sphDdaFallbackLocal,sphDdaFallbackGlobal
5214 double precision :: ray_origin(1:3),profile_local(3),profile_global(3)
5215 double precision, allocatable :: source(:^D&)
5216 double precision, allocatable :: rface(:),thetaface(:),phiface(:)
5217 double precision, allocatable :: rface2(:),theta_cos(:),phi_sin(:),phi_cos(:)
5218 double precision, allocatable :: segments(:,:)
5219 logical :: has_pixels,ddaFallback
5220
5221 profile_local=zero
5222 sphddafallbacklocal=0
5223 do iigrid=1,igridstail; igrid=igrids(iigrid);
5224 ^d&ixomin^d=ixmlo^d\
5225 ^d&ixomax^d=ixmhi^d\
5226 ^d&iximin^d=ixglo^d\
5227 ^d&iximax^d=ixghi^d\
5228
5229 allocate(source(ixi^s))
5230 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,source)
5231 source(ixo^s)=source(ixo^s)/instrument_resolution_factor**2
5232 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,rface,thetaface,phiface)
5233 if (sph_use_dda) then
5234 allocate(rface2(ixomin1:ixomax1+1),theta_cos(ixomin2:ixomax2+1),&
5235 phi_sin(ixomin3:ixomax3+1),phi_cos(ixomin3:ixomax3+1))
5236 rface2=rface**2
5237 theta_cos=cos(thetaface)
5238 phi_sin=sin(phiface)
5239 phi_cos=cos(phiface)
5240 endif
5241 call sph_block_pixel_range(rface,thetaface,phiface,ixo^l,numxi1,numxi2,xi1,xi2,dxi,&
5242 ixpmin1,ixpmax1,ixpmin2,ixpmax2,has_pixels)
5243 if (has_pixels) then
5244 if (sph_use_dda) capacity=0
5245 do ixp1=ixpmin1,ixpmax1
5246 do ixp2=ixpmin2,ixpmax2
5247 ray_origin=xi1(ixp1)*vec_xi1+xi2(ixp2)*vec_xi2
5248 profile_local(1)=profile_local(1)+one
5249 if (sph_use_dda) then
5250 nseg=0
5251 call collect_euv_sph_dda_segments(ixi^l,ixo^l,source,source,&
5252 1,ray_origin,xi1(ixp1),xi2(ixp2),rface,thetaface,phiface,&
5253 rface2,theta_cos,phi_sin,phi_cos,segments,nseg,capacity,ddafallback)
5254 if (ddafallback) sphddafallbacklocal=sphddafallbacklocal+1
5255 do iseg=1,nseg
5256 em(ixp1,ixp2)=em(ixp1,ixp2)+segments(3,iseg)
5257 enddo
5258 else
5259 call acc_euv_sph_intersection(ixi^l,ixo^l,source,ray_origin,xi1(ixp1),xi2(ixp2),&
5260 rface,thetaface,phiface,em(ixp1,ixp2))
5261 endif
5262 enddo
5263 enddo
5264 profile_local(2)=profile_local(2)+dble((ixpmax1-ixpmin1+1)*(ixpmax2-ixpmin2+1))
5265 endif
5266 if (allocated(segments)) deallocate(segments)
5267 profile_local(3)=profile_local(3)+one
5268 if (allocated(rface2)) deallocate(rface2)
5269 if (allocated(theta_cos)) deallocate(theta_cos)
5270 if (allocated(phi_sin)) deallocate(phi_sin)
5271 if (allocated(phi_cos)) deallocate(phi_cos)
5272 deallocate(source,rface,thetaface,phiface)
5273 enddo
5274 call mpi_allreduce(profile_local,profile_global,3,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5275 call mpi_allreduce(sphddafallbacklocal,sphddafallbackglobal,1,mpi_integer,mpi_sum,icomm,ierrmpi)
5276 if (radsyn_verbose .and. mype==0) then
5277 if (sph_use_dda) then
5278 write(*,'(a,3(es12.5,1x))') ' sph_dda thin profile rays pixels blocks: ',profile_global
5279 write(*,'(a,i0)') ' sph_dda thin fallback rays: ',sphddafallbackglobal
5280 else
5281 write(*,'(a,3(es12.5,1x))') ' sph_intersection thin profile rays pixels blocks: ',profile_global
5282 endif
5283 endif
5285
5286 subroutine integrate_euv_sph_intersection_thick(numXI1,numXI2,xI1,xI2,dxI,fl,EUV,Tau,EUVthin)
5288
5289 integer, intent(in) :: numXI1,numXI2
5290 double precision, intent(in) :: xI1(numXI1),xI2(numXI2),dxI
5291 type(te_fluid), intent(in) :: fl
5292 double precision, intent(out) :: EUV(numXI1,numXI2),Tau(numXI1,numXI2),EUVthin(numXI1,numXI2)
5293
5294 integer, parameter :: nSegVars=5
5295 integer :: ixO^L,ixI^L,ix^D
5296 integer :: iigrid,igrid,ixP1,ixP2,ipix,ipixStart,ipixEnd,nPixBatch,pixel_id
5297 integer :: nseg,capacity,totalCount,totalSeg,ipe,is,iseg,nidx,owner,isegDest,nsegBefore
5298 integer :: ixGlobal,iyGlobal,ixPmin1,ixPmax1,ixPmin2,ixPmax2,iFirst,iLast,iLocal
5299 integer :: nPixBatchTarget
5300 integer :: maxSegBatchTarget,maxSegCommTarget,maxNsegBatch,nPixTotal
5301 integer :: maxOwnerSegCount,maxOwnerSegCountLocal,segOffset,recvFill,totalRoundCount,totalRoundSeg
5302 integer :: sphDdaFallbackLocal,sphDdaFallbackGlobal
5303 integer, allocatable :: sendCounts(:),recvCounts(:),sendDispls(:),recvDispls(:)
5304 integer, allocatable :: roundSendCounts(:),roundRecvCounts(:)
5305 integer, allocatable :: roundSendDispls(:),roundRecvDispls(:)
5306 integer, allocatable :: ownerSegCounts(:),ownerOffsets(:),idx(:)
5307 integer, allocatable :: bucketCounts(:),bucketOffsets(:),bucketFill(:)
5308 double precision :: ray_origin(1:3),atten
5309 double precision :: profile_local(5),profile_global(5),profile_batch(5)
5310 double precision :: phys_max_local(2),phys_max_global(2)
5311 double precision :: phys_sum_local(2),phys_sum_global(2),phys_sum_batch(2)
5312 double precision, allocatable :: segments(:,:),segments_send(:,:),segments_recv(:,:)
5313 double precision, allocatable :: segments_recv_round(:,:)
5314 double precision, allocatable :: image_reduce(:,:)
5315 logical :: has_pixels,batchAccepted,batchReduced,ddaFallback
5316 type(radsyn_euv_cache), allocatable :: cache(:)
5317
5318 euv=zero
5319 tau=zero
5320 euvthin=zero
5321 profile_local=zero
5322 phys_max_local=zero
5323 phys_sum_local=zero
5324 sphddafallbacklocal=0
5325 allocate(sendcounts(0:npe-1),recvcounts(0:npe-1),senddispls(0:npe-1),recvdispls(0:npe-1))
5326 allocate(roundsendcounts(0:npe-1),roundrecvcounts(0:npe-1))
5327 allocate(roundsenddispls(0:npe-1),roundrecvdispls(0:npe-1))
5328 allocate(ownersegcounts(0:npe-1),owneroffsets(0:npe-1))
5329 allocate(cache(igridstail))
5330 call radsyn_get_segment_batch_limits(npixbatchtarget,maxsegbatchtarget,maxsegcommtarget)
5331 allocate(bucketcounts(npixbatchtarget),bucketoffsets(npixbatchtarget+1),&
5332 bucketfill(npixbatchtarget))
5333
5334 do iigrid=1,igridstail; igrid=igrids(iigrid);
5335 ^d&ixomin^d=ixmlo^d\
5336 ^d&ixomax^d=ixmhi^d\
5337 ^d&iximin^d=ixglo^d\
5338 ^d&iximax^d=ixghi^d\
5339
5340 cache(iigrid)%igrid=igrid
5341 allocate(cache(iigrid)%source(ixi^s),cache(iigrid)%opacity(ixi^s))
5342 cache(iigrid)%source=zero
5343 cache(iigrid)%opacity=zero
5344 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%source)
5345 cache(iigrid)%source(ixo^s)=cache(iigrid)%source(ixo^s)/instrument_resolution_factor**2
5346 call get_euv_hhe_opacity(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,cache(iigrid)%opacity)
5347 phys_max_local(1)=max(phys_max_local(1),maxval(cache(iigrid)%source(ixo^s)))
5348 phys_max_local(2)=max(phys_max_local(2),maxval(cache(iigrid)%opacity(ixo^s)))
5349 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,&
5350 cache(iigrid)%rface,cache(iigrid)%thetaface,&
5351 cache(iigrid)%phiface)
5352 allocate(cache(iigrid)%rface2(ixomin1:ixomax1+1),&
5353 cache(iigrid)%theta_cos(ixomin2:ixomax2+1),&
5354 cache(iigrid)%phi_sin(ixomin3:ixomax3+1),&
5355 cache(iigrid)%phi_cos(ixomin3:ixomax3+1))
5356 cache(iigrid)%rface2=cache(iigrid)%rface**2
5357 cache(iigrid)%theta_cos=cos(cache(iigrid)%thetaface)
5358 cache(iigrid)%phi_sin=sin(cache(iigrid)%phiface)
5359 cache(iigrid)%phi_cos=cos(cache(iigrid)%phiface)
5360 call sph_block_pixel_range(cache(iigrid)%rface,cache(iigrid)%thetaface,&
5361 cache(iigrid)%phiface,ixo^l,numxi1,numxi2,xi1,xi2,dxi,&
5362 cache(iigrid)%ixPmin1,cache(iigrid)%ixPmax1,&
5363 cache(iigrid)%ixPmin2,cache(iigrid)%ixPmax2,cache(iigrid)%has_pixels)
5364 enddo
5365
5366 npixtotal=numxi1*numxi2
5367 ipixstart=1
5368 do while (ipixstart<=npixtotal)
5369 ipixend=min(numxi1*numxi2,ipixstart+npixbatchtarget-1)
5370 npixbatch=ipixend-ipixstart+1
5371 batchaccepted=.false.
5372 batchreduced=.false.
5373
5374 do while (.not. batchaccepted)
5375 nseg=0
5376 capacity=0
5377 profile_batch=zero
5378 phys_sum_batch=zero
5379
5380 do iigrid=1,igridstail; igrid=igrids(iigrid);
5381 ^d&ixomin^d=ixmlo^d\
5382 ^d&ixomax^d=ixmhi^d\
5383 ^d&iximin^d=ixglo^d\
5384 ^d&iximax^d=ixghi^d\
5385
5386 ixpmin1=cache(iigrid)%ixPmin1
5387 ixpmax1=cache(iigrid)%ixPmax1
5388 ixpmin2=cache(iigrid)%ixPmin2
5389 ixpmax2=cache(iigrid)%ixPmax2
5390 has_pixels=cache(iigrid)%has_pixels
5391 if (.not. has_pixels) cycle
5392
5393 do ixp2=ixpmin2,ixpmax2
5394 ifirst=max(ipixstart,(ixp2-1)*numxi1+ixpmin1)
5395 ilast=min(ipixend,(ixp2-1)*numxi1+ixpmax1)
5396 if (ifirst>ilast) cycle
5397 do ipix=ifirst,ilast
5398 ixp1=1+mod(ipix-1,numxi1)
5399 pixel_id=ipix
5400 ray_origin=xi1(ixp1)*vec_xi1+xi2(ixp2)*vec_xi2
5401 profile_batch(1)=profile_batch(1)+one
5402 nsegbefore=nseg
5403 if (sph_use_dda) then
5404 call collect_euv_sph_dda_segments(ixi^l,ixo^l,cache(iigrid)%source,&
5405 cache(iigrid)%opacity,pixel_id,ray_origin,xi1(ixp1),xi2(ixp2),&
5406 cache(iigrid)%rface,cache(iigrid)%thetaface,cache(iigrid)%phiface,&
5407 cache(iigrid)%rface2,cache(iigrid)%theta_cos,&
5408 cache(iigrid)%phi_sin,cache(iigrid)%phi_cos,&
5409 segments,nseg,capacity,ddafallback)
5410 if (ddafallback) sphddafallbacklocal=sphddafallbacklocal+1
5411 else
5412 call collect_euv_sph_intersection_segments(ixi^l,ixo^l,cache(iigrid)%source,&
5413 cache(iigrid)%opacity,pixel_id,ray_origin,xi1(ixp1),xi2(ixp2),&
5414 cache(iigrid)%rface,cache(iigrid)%thetaface,cache(iigrid)%phiface,&
5415 cache(iigrid)%rface2,cache(iigrid)%theta_cos,&
5416 cache(iigrid)%phi_sin,cache(iigrid)%phi_cos,&
5417 segments,nseg,capacity)
5418 endif
5419 if (nseg>nsegbefore) profile_batch(2)=profile_batch(2)+one
5420 profile_batch(3)=profile_batch(3)+dble(nseg-nsegbefore)
5421 do iseg=nsegbefore+1,nseg
5422 phys_sum_batch(1)=phys_sum_batch(1)+segments(3,iseg)
5423 phys_sum_batch(2)=phys_sum_batch(2)+segments(4,iseg)
5424 enddo
5425 enddo
5426 enddo
5427 enddo
5428
5429 call mpi_allreduce(nseg,maxnsegbatch,1,mpi_integer,mpi_max,icomm,ierrmpi)
5430 if (maxnsegbatch>maxsegbatchtarget .and. npixbatch>1) then
5431 npixbatch=max(1,npixbatch/2)
5432 ipixend=ipixstart+npixbatch-1
5433 if (allocated(segments)) deallocate(segments)
5434 batchreduced=.true.
5435 else
5436 batchaccepted=.true.
5437 endif
5438 enddo
5439
5440 profile_local=profile_local+profile_batch
5441 phys_sum_local=phys_sum_local+phys_sum_batch
5442 if (radsyn_verbose .and. mype==0 .and. batchreduced) then
5443 if (sph_use_dda) then
5444 write(*,'(a,3(i0,1x))') ' sph_dda thick adaptive batch: ',&
5445 ipixstart,ipixend,maxnsegbatch
5446 else
5447 write(*,'(a,3(i0,1x))') ' sph_intersection thick adaptive batch: ',&
5448 ipixstart,ipixend,maxnsegbatch
5449 endif
5450 endif
5451
5452 if (.not. allocated(segments)) then
5453 capacity=1
5454 allocate(segments(nsegvars,capacity))
5455 endif
5456 ownersegcounts=0
5457 do is=1,nseg
5458 owner=segment_pixel_owner(nint(segments(1,is)))
5459 ownersegcounts(owner)=ownersegcounts(owner)+1
5460 enddo
5461 sendcounts=nsegvars*ownersegcounts
5462 senddispls(0)=0
5463 do ipe=1,npe-1
5464 senddispls(ipe)=senddispls(ipe-1)+sendcounts(ipe-1)
5465 enddo
5466
5467 allocate(segments_send(nsegvars,max(1,nseg)))
5468 owneroffsets=0
5469 do is=1,nseg
5470 owner=segment_pixel_owner(nint(segments(1,is)))
5471 isegdest=senddispls(owner)/nsegvars+owneroffsets(owner)+1
5472 segments_send(:,isegdest)=segments(:,is)
5473 owneroffsets(owner)=owneroffsets(owner)+1
5474 enddo
5475
5476 call mpi_alltoall(sendcounts,1,mpi_integer,recvcounts,1,mpi_integer,icomm,ierrmpi)
5477 recvdispls(0)=0
5478 do ipe=1,npe-1
5479 recvdispls(ipe)=recvdispls(ipe-1)+recvcounts(ipe-1)
5480 enddo
5481 totalcount=sum(recvcounts)
5482 totalseg=totalcount/nsegvars
5483 profile_local(4)=profile_local(4)+dble(totalcount)
5484 allocate(segments_recv(nsegvars,max(1,totalseg)))
5485
5486 recvfill=0
5487 maxownersegcountlocal=maxval(ownersegcounts)
5488 call mpi_allreduce(maxownersegcountlocal,maxownersegcount,1,mpi_integer,mpi_max,icomm,ierrmpi)
5489 do segoffset=0,maxownersegcount-1,maxsegcommtarget
5490 roundsendcounts=0
5491 roundsenddispls=senddispls
5492 do ipe=0,npe-1
5493 if (ownersegcounts(ipe)>segoffset) then
5494 roundsendcounts(ipe)=nsegvars*min(maxsegcommtarget,ownersegcounts(ipe)-segoffset)
5495 roundsenddispls(ipe)=senddispls(ipe)+nsegvars*segoffset
5496 endif
5497 enddo
5498
5499 call mpi_alltoall(roundsendcounts,1,mpi_integer,roundrecvcounts,1,mpi_integer,icomm,ierrmpi)
5500 roundrecvdispls(0)=0
5501 do ipe=1,npe-1
5502 roundrecvdispls(ipe)=roundrecvdispls(ipe-1)+roundrecvcounts(ipe-1)
5503 enddo
5504 totalroundcount=sum(roundrecvcounts)
5505 totalroundseg=totalroundcount/nsegvars
5506 allocate(segments_recv_round(nsegvars,max(1,totalroundseg)))
5507
5508 call mpi_alltoallv(segments_send,roundsendcounts,roundsenddispls,mpi_double_precision,&
5509 segments_recv_round,roundrecvcounts,roundrecvdispls,&
5510 mpi_double_precision,icomm,ierrmpi)
5511
5512 if (totalroundseg>0) then
5513 segments_recv(:,recvfill+1:recvfill+totalroundseg)=segments_recv_round(:,1:totalroundseg)
5514 recvfill=recvfill+totalroundseg
5515 endif
5516 deallocate(segments_recv_round)
5517 enddo
5518
5519 if (recvfill/=totalseg) call mpistop("ray-segment receive mismatch")
5520
5521 if (totalseg>0) then
5522 allocate(idx(totalseg))
5523 bucketcounts(1:npixbatch)=0
5524 do is=1,totalseg
5525 if (segment_is_valid(segments_recv,is,4)) then
5526 ipix=nint(segments_recv(1,is))
5527 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
5528 ilocal=ipix-ipixstart+1
5529 bucketcounts(ilocal)=bucketcounts(ilocal)+1
5530 endif
5531 endif
5532 enddo
5533
5534 bucketoffsets(1)=1
5535 do ilocal=1,npixbatch
5536 bucketoffsets(ilocal+1)=bucketoffsets(ilocal)+bucketcounts(ilocal)
5537 enddo
5538 bucketfill(1:npixbatch)=bucketoffsets(1:npixbatch)
5539 do is=1,totalseg
5540 if (segment_is_valid(segments_recv,is,4)) then
5541 ipix=nint(segments_recv(1,is))
5542 if (ipix>=ipixstart .and. ipix<=ipixend .and. segment_pixel_owner(ipix)==mype) then
5543 ilocal=ipix-ipixstart+1
5544 idx(bucketfill(ilocal))=is
5545 bucketfill(ilocal)=bucketfill(ilocal)+1
5546 endif
5547 endif
5548 enddo
5549
5550 do ipix=ipixstart,ipixend
5551 if (segment_pixel_owner(ipix)/=mype) cycle
5552 ilocal=ipix-ipixstart+1
5553 nidx=bucketcounts(ilocal)
5554 if (nidx>0) then
5555 profile_local(5)=profile_local(5)+dble(nidx)*dble(nidx)
5556 call sort_segment_indices_near_to_far(segments_recv,&
5557 idx(bucketoffsets(ilocal):bucketoffsets(ilocal+1)-1),nidx)
5558 ixglobal=1+mod(ipix-1,numxi1)
5559 iyglobal=1+(ipix-1)/numxi1
5560 do iseg=bucketoffsets(ilocal),bucketoffsets(ilocal+1)-1
5561 is=idx(iseg)
5562 euvthin(ixglobal,iyglobal)=euvthin(ixglobal,iyglobal)+segments_recv(3,is)
5563 atten=transfer_attenuation(tau(ixglobal,iyglobal))
5564 euv(ixglobal,iyglobal)=euv(ixglobal,iyglobal)+atten*segments_recv(3,is)
5565 tau(ixglobal,iyglobal)=tau(ixglobal,iyglobal)+max(zero,segments_recv(4,is))
5566 enddo
5567 endif
5568 enddo
5569 deallocate(idx)
5570 endif
5571
5572 deallocate(segments_send,segments_recv)
5573 if (allocated(segments)) deallocate(segments)
5574 ipixstart=ipixend+1
5575 enddo
5576
5577 do iigrid=1,igridstail
5578 if (allocated(cache(iigrid)%source)) deallocate(cache(iigrid)%source)
5579 if (allocated(cache(iigrid)%opacity)) deallocate(cache(iigrid)%opacity)
5580 if (allocated(cache(iigrid)%rface)) deallocate(cache(iigrid)%rface)
5581 if (allocated(cache(iigrid)%thetaface)) deallocate(cache(iigrid)%thetaface)
5582 if (allocated(cache(iigrid)%phiface)) deallocate(cache(iigrid)%phiface)
5583 if (allocated(cache(iigrid)%rface2)) deallocate(cache(iigrid)%rface2)
5584 if (allocated(cache(iigrid)%theta_cos)) deallocate(cache(iigrid)%theta_cos)
5585 if (allocated(cache(iigrid)%phi_sin)) deallocate(cache(iigrid)%phi_sin)
5586 if (allocated(cache(iigrid)%phi_cos)) deallocate(cache(iigrid)%phi_cos)
5587 enddo
5588 deallocate(cache)
5589 deallocate(sendcounts,recvcounts,senddispls,recvdispls,roundsendcounts,roundrecvcounts,&
5590 roundsenddispls,roundrecvdispls,ownersegcounts,owneroffsets,bucketcounts,&
5591 bucketoffsets,bucketfill)
5592 allocate(image_reduce(numxi1,numxi2))
5593 call mpi_allreduce(euv,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5594 euv=image_reduce
5595 call mpi_allreduce(tau,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5596 tau=image_reduce
5597 call mpi_allreduce(euvthin,image_reduce,numxi1*numxi2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5598 euvthin=image_reduce
5599 deallocate(image_reduce)
5600 call mpi_allreduce(profile_local,profile_global,5,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5601 call mpi_allreduce(phys_max_local,phys_max_global,2,mpi_double_precision,mpi_max,icomm,ierrmpi)
5602 call mpi_allreduce(phys_sum_local,phys_sum_global,2,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5603 call mpi_allreduce(sphddafallbacklocal,sphddafallbackglobal,1,mpi_integer,mpi_sum,icomm,ierrmpi)
5604 if (radsyn_verbose .and. mype==0) then
5605 if (sph_use_dda) then
5606 write(*,'(a,5(es12.5,1x))') ' sph_dda thick profile: ',profile_global
5607 write(*,'(a,i0)') ' sph_dda thick fallback rays: ',sphddafallbackglobal
5608 write(*,'(a,4(es12.5,1x))') ' sph_dda thick physics maxj maxk sumjds sumkds: ',&
5609 phys_max_global(1),phys_max_global(2),phys_sum_global(1),phys_sum_global(2)
5610 else
5611 write(*,'(a,5(es12.5,1x))') ' sph_intersection thick profile: ',profile_global
5612 write(*,'(a,4(es12.5,1x))') ' sph_intersection thick physics maxj maxk sumjds sumkds: ',&
5613 phys_max_global(1),phys_max_global(2),phys_sum_global(1),phys_sum_global(2)
5614 endif
5615 endif
5617
5618 }
5619
5620 {^ifthreed
5621
5622 subroutine get_sph_intersection_image_bounds(xImin1,xImax1,xImin2,xImax2)
5623 double precision, intent(out) :: xImin1,xImax1,xImin2,xImax2
5624
5625 integer, parameter :: nsample=5
5626 integer :: iigrid,igrid,ir,it,ip
5627 integer :: ixI^L,ixO^L
5628 double precision, allocatable :: rface(:),thetaface(:),phiface(:)
5629 double precision :: local_min1,local_max1,local_min2,local_max2
5630 double precision :: sph(1:3),xcent(1:2),wr,wt,wp
5631
5632 local_min1=huge(one)
5633 local_max1=-huge(one)
5634 local_min2=huge(one)
5635 local_max2=-huge(one)
5636
5637 do iigrid=1,igridstail
5638 igrid=igrids(iigrid)
5639 ^d&ixomin^d=ixmlo^d\
5640 ^d&ixomax^d=ixmhi^d\
5641 ^d&iximin^d=ixglo^d\
5642 ^d&iximax^d=ixghi^d\
5643
5644 call build_sph_intersection_faces(ixi^l,ixo^l,ps(igrid)%x,ps(igrid)%dx,&
5645 rface,thetaface,phiface)
5646 do ir=0,nsample-1
5647 wr=dble(ir)/dble(nsample-1)
5648 sph(1)=(one-wr)*rface(ixomin1)+wr*rface(ixomax1+1)
5649 do it=0,nsample-1
5650 wt=dble(it)/dble(nsample-1)
5651 sph(2)=(one-wt)*thetaface(ixomin2)+wt*thetaface(ixomax2+1)
5652 do ip=0,nsample-1
5653 wp=dble(ip)/dble(nsample-1)
5654 if (ir/=0 .and. ir/=nsample-1 .and. it/=0 .and. it/=nsample-1 .and. &
5655 ip/=0 .and. ip/=nsample-1) cycle
5656 sph(3)=(one-wp)*phiface(ixomin3)+wp*phiface(ixomax3+1)
5657 call get_cor_image_spherical(sph,xcent)
5658 local_min1=min(local_min1,xcent(1))
5659 local_max1=max(local_max1,xcent(1))
5660 local_min2=min(local_min2,xcent(2))
5661 local_max2=max(local_max2,xcent(2))
5662 enddo
5663 enddo
5664 enddo
5665 deallocate(rface,thetaface,phiface)
5666 enddo
5667
5668 call mpi_allreduce(local_min1,ximin1,1,mpi_double_precision,mpi_min,icomm,ierrmpi)
5669 call mpi_allreduce(local_max1,ximax1,1,mpi_double_precision,mpi_max,icomm,ierrmpi)
5670 call mpi_allreduce(local_min2,ximin2,1,mpi_double_precision,mpi_min,icomm,ierrmpi)
5671 call mpi_allreduce(local_max2,ximax2,1,mpi_double_precision,mpi_max,icomm,ierrmpi)
5672 if (ximin1>0.5d0*huge(one) .or. ximax1<-0.5d0*huge(one) .or. &
5673 ximin2>0.5d0*huge(one) .or. ximax2<-0.5d0*huge(one)) then
5674 call mpistop("sph_intersection could not determine image bounds")
5675 endif
5677
5679 double precision, intent(out) :: dxI
5680
5681 select case(trim(dat_resolution_mode))
5682 case('nominal')
5684 case('minimum')
5686 case default
5687 call mpistop("unknown dat_resolution_mode")
5688 end select
5689 end subroutine get_native_datresol_spacing
5690
5692 double precision, intent(out) :: dxI
5693
5694 double precision :: refine_factor,dr,dtheta,dphi,rmin,sin_theta_min
5695
5696 refine_factor=dble(2**(refine_max_level-1))
5697 if (slab) then
5698 dxi=min(abs(xprobmax1-xprobmin1)/(dble(domain_nx1)*refine_factor),&
5699 abs(xprobmax2-xprobmin2)/(dble(domain_nx2)*refine_factor),&
5700 abs(xprobmax3-xprobmin3)/(dble(domain_nx3)*refine_factor))
5701 else if (coordinate==spherical) then
5702 rmin=max(smalldouble,min(xprobmin1,xprobmax1))
5703 sin_theta_min=max(smalldouble,min(abs(sin(xprobmin2)),&
5704 abs(sin(xprobmax2))))
5705 dr=abs(xprobmax1-xprobmin1)/(dble(domain_nx1)*refine_factor)
5706 dtheta=abs(xprobmax2-xprobmin2)/(dble(domain_nx2)*refine_factor)
5707 dphi=abs(xprobmax3-xprobmin3)/(dble(domain_nx3)*refine_factor)
5708 dxi=min(dr,rmin*dtheta,rmin*sin_theta_min*dphi)
5709 else
5710 call mpistop("nominal dat resolution needs Cartesian or spherical coordinates")
5711 endif
5712
5713 if (dxi<=zero .or. dxi>half*huge(one)) then
5714 call mpistop("could not determine nominal dat-resolution image spacing")
5715 endif
5716 end subroutine get_nominal_datresol_spacing
5717
5719 double precision, intent(out) :: dxI
5720
5721 integer :: iigrid,igrid,ixI^L,ixO^L,ix^D
5722 double precision :: local_min,global_min,dr,ds_theta,ds_phi,rval,theta
5723
5724 local_min=huge(one)
5725 do iigrid=1,igridstail
5726 igrid=igrids(iigrid)
5727 ^d&ixomin^d=ixmlo^d\
5728 ^d&ixomax^d=ixmhi^d\
5729 ^d&iximin^d=ixglo^d\
5730 ^d&iximax^d=ixghi^d\
5731
5732 do ix1=ixomin1,ixomax1
5733 do ix2=ixomin2,ixomax2
5734 do ix3=ixomin3,ixomax3
5735 if (slab) then
5736 local_min=min(local_min,ps(igrid)%dx(ix^d,1),&
5737 ps(igrid)%dx(ix^d,2),ps(igrid)%dx(ix^d,3))
5738 else if (coordinate==spherical) then
5739 rval=max(smalldouble,ps(igrid)%x(ix^d,1))
5740 theta=ps(igrid)%x(ix^d,2)
5741 dr=ps(igrid)%dx(ix^d,1)
5742 ds_theta=rval*ps(igrid)%dx(ix^d,2)
5743 ds_phi=rval*max(smalldouble,sin(theta))*ps(igrid)%dx(ix^d,3)
5744 local_min=min(local_min,dr,ds_theta,ds_phi)
5745 else
5746 call mpistop("minimum dat resolution needs Cartesian or spherical coordinates")
5747 endif
5748 enddo
5749 enddo
5750 enddo
5751 enddo
5752
5753 call mpi_allreduce(local_min,global_min,1,mpi_double_precision,mpi_min,&
5754 icomm,ierrmpi)
5755 if (global_min<=zero .or. global_min>half*huge(one)) then
5756 call mpistop("could not determine minimum dat-resolution image spacing")
5757 endif
5758 dxi=global_min
5759 end subroutine get_minimum_datresol_spacing
5760
5761 subroutine get_image(qunit,datatype,fl)
5762 ! integrate emission flux along line of sight (LOS)
5763 ! in a 3D simulation box and get a 2D EUV image
5765 use mod_constants
5766
5767 integer, intent(in) :: qunit
5768 type(te_fluid), intent(in) :: fl
5769 character(20), intent(in) :: datatype
5770
5771 integer :: ix^D,numXI1,numXI2,numWI
5772 double precision :: xImin1,xImax1,xImin2,xImax2,xIcent1,xIcent2,dxI
5773 double precision, allocatable :: xI1(:),xI2(:),dxI1(:),dxI2(:)
5774 double precision, allocatable :: wI(:,:,:),wIs(:,:,:),EM(:,:),Dpl(:,:),Tau(:,:),EMthin(:,:),WLB(:,:,:)
5775 double precision :: vec_temp1(1:3),vec_temp2(1:3)
5776 double precision :: vec_z(1:3),vec_cor(1:3),xI_cor(1:2)
5777 double precision :: res,LOS_psi,r_max,r_loc
5778
5779 integer :: mass
5780 character (30) :: ion
5781 double precision :: logTe,lineCent,sigma_PSF,spaceRsl,wlRsl,wslit
5782 double precision :: arcsec,RHESSI_rsl,LASCO_rsl,pixel,R_occult,smallflux
5783 integer :: iigrid,igrid,i,j,numSI,iw
5784 logical :: emit,ray_image_global,has_thick_output
5785
5786 if (coordinate==spherical) then
5788 else
5789 ! cartesian
5791 endif
5792
5793 ! calculate domain of the image
5794 if (coordinate==spherical) then
5795 if (trim(ray_method_active)=='spherical' .and. datatype=='image_euv') then
5796 call get_sph_intersection_image_bounds(ximin1,ximax1,ximin2,ximax2)
5797 else
5798 ximin1=-abs(xprobmax1)
5799 ximin2=-abs(xprobmax1)
5800 ximax1=abs(xprobmax1)
5801 ximax2=abs(xprobmax1)
5802 endif
5803 else
5804 ! calculate domain of the image
5805 do ix1=1,2
5806 if (ix1==1) vec_cor(1)=xprobmin1
5807 if (ix1==2) vec_cor(1)=xprobmax1
5808 do ix2=1,2
5809 if (ix2==1) vec_cor(2)=xprobmin2
5810 if (ix2==2) vec_cor(2)=xprobmax2
5811 do ix3=1,2
5812 if (ix3==1) vec_cor(3)=xprobmin3
5813 if (ix3==2) vec_cor(3)=xprobmax3
5814 if (big_image) then
5815 r_loc=(vec_cor(1)-x_origin(1))**2
5816 r_loc=r_loc+(vec_cor(2)-x_origin(2))**2
5817 r_loc=r_loc+(vec_cor(3)-x_origin(3))**2
5818 r_loc=sqrt(r_loc)
5819 if (ix1==1 .and. ix2==1 .and. ix3==1) then
5820 r_max=r_loc
5821 else
5822 r_max=max(r_max,r_loc)
5823 endif
5824 else
5825 call get_cor_image(vec_cor,xi_cor)
5826 if (ix1==1 .and. ix2==1 .and. ix3==1) then
5827 ximin1=xi_cor(1)
5828 ximax1=xi_cor(1)
5829 ximin2=xi_cor(2)
5830 ximax2=xi_cor(2)
5831 else
5832 ximin1=min(ximin1,xi_cor(1))
5833 ximax1=max(ximax1,xi_cor(1))
5834 ximin2=min(ximin2,xi_cor(2))
5835 ximax2=max(ximax2,xi_cor(2))
5836 endif
5837 endif
5838 enddo
5839 enddo
5840 enddo
5841 if (big_image) then
5842 ximin1=-r_max
5843 ximin2=-r_max
5844 ximax1=r_max
5845 ximax2=r_max
5846 endif
5847 endif
5848 xicent1=(ximin1+ximax1)/2.d0
5849 xicent2=(ximin2+ximax2)/2.d0
5850
5851 ! tables for image
5852 if (si_unit) then
5853 arcsec=7.25d5/unit_length
5854 else
5855 arcsec=7.25d7/unit_length
5856 endif
5857 if (datatype=='image_euv') then
5858 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
5859 dxi=spacersl*arcsec ! intrument resolution of image
5860 smallflux=smalldouble
5861 else if (datatype=='image_sxr') then
5862 rhessi_rsl=2.3d0/instrument_resolution_factor
5863 dxi=rhessi_rsl*arcsec
5864 smallflux=1.d-40
5865 else if (datatype=='image_whitelight') then
5866 if (whitelight_instrument=='LASCO/C1') then
5867 lasco_rsl=5.6d0/instrument_resolution_factor
5868 r_occult=1.1d0
5869 else if (whitelight_instrument=='LASCO/C2') then
5870 lasco_rsl=11.4d0/instrument_resolution_factor
5871 r_occult=2.d0
5872 else if (whitelight_instrument=='LASCO/C3') then
5873 lasco_rsl=56.d0/instrument_resolution_factor
5874 r_occult=3.7d0
5875 else
5876 call mpistop('Whitelight synthesis: instrument is not supported!')
5877 endif
5878 dxi=lasco_rsl*arcsec
5879 if (r_occultor>1.d0) r_occult=r_occultor
5880 r_occult=r_occult*const_rsun/unit_length
5881 smallflux=1.d-20
5882 endif
5883 numxi1=8*ceiling((ximax1-xicent1)/dxi/8.d0)
5884 ximin1=xicent1-numxi1*dxi
5885 ximax1=xicent1+numxi1*dxi
5886 numxi1=numxi1*2
5887 numxi2=8*ceiling((ximax2-xicent2)/dxi/8.d0)
5888 ximin2=xicent2-numxi2*dxi
5889 ximax2=xicent2+numxi2*dxi
5890 numxi2=numxi2*2
5891 allocate(xi1(numxi1),xi2(numxi2),dxi1(numxi1),dxi2(numxi2))
5892 do ix1=1,numxi1
5893 xi1(ix1)=ximin1+dxi*(ix1-half)
5894 dxi1(ix1)=dxi
5895 enddo
5896 do ix2=1,numxi2
5897 xi2(ix2)=ximin2+dxi*(ix2-half)
5898 dxi2(ix2)=dxi
5899 enddo
5900
5901 ! calculate emission
5902 if (datatype=='image_euv' .or. datatype=='image_sxr') then
5903 has_thick_output=datatype=='image_euv' .and. trim(radiation_transfer)=='thick' .and. &
5904 ((coordinate==spherical .and. trim(ray_method_active)=='spherical') .or. &
5905 (slab .and. trim(ray_method_active)=='cart'))
5906 if (datatype=='image_euv') then
5907 numwi=radsyn_euv_num_outputs(.false.,has_thick_output)
5908 else
5909 numwi=1
5910 endif
5911 allocate(wi(numxi1,numxi2,numwi),wis(numxi1,numxi2,numwi),em(numxi1,numxi2))
5912 wi=zero
5913 wis=zero
5914 em=zero
5915 ray_image_global=.false.
5916 if (has_thick_output) then
5917 allocate(tau(numxi1,numxi2),emthin(numxi1,numxi2))
5918 tau=zero
5919 emthin=zero
5920 endif
5921 if (slab .and. datatype=='image_euv' .and. &
5922 trim(ray_method_active)=='cart') then
5923 ray_image_global=.true.
5924 allocate(dpl(numxi1,numxi2))
5925 dpl=zero
5926 if (trim(radiation_transfer)=='thick') then
5927 call integrate_euv_cart_dda_thick_datresol(numxi1,numxi2,xi1,xi2,fl,em,dpl,tau,emthin)
5928 else
5929 call integrate_euv_cart_dda_datresol(numxi1,numxi2,xi1,xi2,fl,em,dpl)
5930 endif
5931 deallocate(dpl)
5932 else if (slab) then
5933 do iigrid=1,igridstail; igrid=igrids(iigrid);
5934 call integrate_emission_cartesian(igrid,numxi1,numxi2,xi1,xi2,dxi,fl,datatype,em)
5935 enddo
5936 else if (trim(ray_method_active) == 'spherical' .and. datatype == 'image_euv') then
5937 if (trim(radiation_transfer) == 'thick') then
5938 ray_image_global=.true.
5939 call integrate_euv_sph_intersection_thick(numxi1,numxi2,xi1,xi2,dxi,fl,em,tau,emthin)
5940 else
5941 call integrate_euv_sph_intersection_thin(numxi1,numxi2,xi1,xi2,dxi,fl,em)
5942 endif
5943 else
5944 do iigrid=1,igridstail; igrid=igrids(iigrid);
5945 call integrate_emission_spherical(igrid,numxi1,numxi2,xi1,xi2,dxi,fl,datatype,em)
5946 enddo
5947 endif
5948 if (ray_image_global) then
5949 if (has_thick_output) then
5950 call pack_euv_image_outputs(numxi1,numxi2,em,wi,smallflux,.false.,&
5951 has_thick_output,tau=tau,euvthin=emthin,&
5952 cap_absorption=.true.)
5953 else
5954 call pack_euv_image_outputs(numxi1,numxi2,em,wi,smallflux,.false.,has_thick_output)
5955 endif
5956 else
5957 do ix1=1,numxi1
5958 do ix2=1,numxi2
5959 if (em(ix1,ix2)>smallflux) wis(ix1,ix2,1)=em(ix1,ix2)
5960 enddo
5961 enddo
5962 endif
5963 if (.not. ray_image_global) then
5964 numsi=numxi1*numxi2*numwi
5965 call mpi_allreduce(wis,wi,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5966 endif
5967 if (activate_unit_arcsec) then
5968 xi1=xi1/arcsec
5969 dxi1=dxi1/arcsec
5970 xi2=xi2/arcsec
5971 dxi2=dxi2/arcsec
5972 endif
5973 call output_data(qunit,xi1,xi2,dxi1,dxi2,wi,numxi1,numxi2,numwi,datatype)
5974 if (allocated(tau)) deallocate(tau)
5975 if (allocated(emthin)) deallocate(emthin)
5976 deallocate(wi,wis,em)
5977 else if (datatype=='image_whitelight') then
5978 numwi=2
5979 allocate(wi(numxi1,numxi2,numwi),wis(numxi1,numxi2,numwi),wlb(numxi1,numxi2,numwi))
5980 wi=zero
5981 wis=zero
5982 wlb=zero
5983 if (coordinate==spherical) then
5984 do iigrid=1,igridstail; igrid=igrids(iigrid);
5985 call integrate_whitelight_spherical(igrid,numxi1,numxi2,numwi,xi1,xi2,dxi,fl,datatype,wlb)
5986 enddo
5987 endif
5988 do ix1=1,numxi1
5989 do ix2=1,numxi2
5990 if (wlb(ix1,ix2,1)>smallflux) then
5991 wis(ix1,ix2,1)=wlb(ix1,ix2,1)
5992 wis(ix1,ix2,2)=wlb(ix1,ix2,2)
5993 endif
5994 enddo
5995 enddo
5996 numsi=numxi1*numxi2*numwi
5997 call mpi_allreduce(wis,wi,numsi,mpi_double_precision,mpi_sum,icomm,ierrmpi)
5998 if (activate_unit_arcsec) then
5999 xi1=xi1/arcsec
6000 dxi1=dxi1/arcsec
6001 xi2=xi2/arcsec
6002 dxi2=dxi2/arcsec
6003 endif
6004 call output_data(qunit,xi1,xi2,dxi1,dxi2,wi,numxi1,numxi2,numwi,datatype)
6005 deallocate(wi,wis,wlb)
6006 endif
6007
6008 deallocate(xi1,xi2,dxi1,dxi2)
6009
6010 end subroutine get_image
6011
6012 subroutine integrate_emission_cartesian(igrid,numXI1,numXI2,xI1,xI2,dxI,fl,datatype,EM)
6013 integer, intent(in) :: igrid,numXI1,numXI2
6014 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6015 double precision, intent(in) :: dxI
6016 type(te_fluid), intent(in) :: fl
6017 character(20), intent(in) :: datatype
6018 double precision, intent(inout) :: EM(numXI1,numXI2)
6019
6020 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6021 double precision :: xb^L,xd^D
6022 double precision, allocatable :: flux(:^D&),opacity(:^D&)
6023 double precision :: res
6024 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6025 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC
6026 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2)
6027
6028 integer :: mass
6029 double precision :: logTe
6030 character (30) :: ion
6031 double precision :: lineCent
6032 double precision :: sigma_PSF,spaceRsl,wlRsl,sigma0,factor,wslit
6033 double precision :: arcsec,pixel,RHESSI_rsl,area_1AU
6034 double precision :: aa,bb
6035
6036 ^d&ixomin^d=ixmlo^d\
6037 ^d&ixomax^d=ixmhi^d\
6038 ^d&iximin^d=ixglo^d\
6039 ^d&iximax^d=ixghi^d\
6040 ^d&xbmin^d=rnode(rpxmin^d_,igrid)\
6041 ^d&xbmax^d=rnode(rpxmax^d_,igrid)\
6042
6043 if (si_unit) then
6044 arcsec=7.25d5/unit_length
6045 else
6046 arcsec=7.25d7/unit_length
6047 endif
6048
6049 allocate(flux(ixi^s),opacity(ixi^s))
6050 if (datatype=='image_euv') then
6051 if (trim(emission_model)=='pseudo_current') then
6052 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,flux)
6053 else if (trim(emission_model)=='radio_ff') then
6054 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,opacity)
6055 else
6056 ! get local EUV flux and velocity
6057 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
6058 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
6059 endif
6060 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
6061 pixel=spacersl*arcsec
6062 sigma0=sigma_psf*pixel
6063 else if (datatype=='image_sxr') then
6064 ! get local SXR flux photons cm^-3 s^-1 (cgs) or photons m^-3 s^-1 (SI)
6065 call get_sxr(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,emin_sxr,emax_sxr)
6066 rhessi_rsl=2.3d0/instrument_resolution_factor
6067 sigma_psf=1.d0
6068 pixel=rhessi_rsl*arcsec
6069 sigma0=sigma_psf*pixel
6070 area_1au=2.81d27
6071 endif
6072
6073 ! integrate emission
6074 {do ix^d=ixomin^d,ixomax^d\}
6075 ^d&nsubc^d=1;
6076 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi1(^d))/(dxi/2.d0)));
6077 ^d&nsubc^d=max(nsubc^d,ceiling(ps(igrid)%dx(ix^dd,^d)*abs(vec_xi2(^d))/(dxi/2.d0)));
6078 ^d&dxsubc^d=ps(igrid)%dx(ix^dd,^d)/nsubc^d;
6079 if (datatype=='image_euv') then
6080 if (si_unit) then
6081 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length*1.d2/dxi/dxi ! DN s^-1
6082 else
6083 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length/dxi/dxi ! DN s^-1
6084 endif
6085 else if (datatype=='image_sxr') then
6086 ! sub-cell SXR flux at 1 AU [photons s^-1 cm^-2]
6087 fluxsubc=flux(ix^d)*dxsubc1*dxsubc2*dxsubc3*unit_length**3/area_1au
6088 endif
6089 if (fluxsubc>smalldouble) then
6090 ! dividing a cell to several parts to get more accurate integrating values
6091 {do isubc^d=1,nsubc^d\}
6092 ^d&xsubc(^d)=ps(igrid)%x(ix^dd,^d)-half*ps(igrid)%dx(ix^dd,^d)+(isubc^d-half)*dxsubc^d;
6093 ! mapping the 3D coordinate to location at the image
6094 call get_cor_image(xsubc,xcent)
6095 ! distribution at nearby pixels
6096 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6097 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6098 ixpmin1=max(1,ixp1-3)
6099 ixpmax1=min(ixp1+3,numxi1)
6100 ixpmin2=max(1,ixp2-3)
6101 ixpmax2=min(ixp2+3,numxi2)
6102 do ixp1=ixpmin1,ixpmax1
6103 do ixp2=ixpmin2,ixpmax2
6104 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6105 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6106 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6107 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6108 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6109 em(ixp1,ixp2)=em(ixp1,ixp2)+fluxsubc*factor
6110 enddo !ixP2
6111 enddo !ixP1
6112 {enddo\} !iSubC
6113 endif
6114 {enddo\} !ix
6115
6116 deallocate(flux,opacity)
6117 end subroutine integrate_emission_cartesian
6118
6119 subroutine integrate_emission_spherical(igrid,numXI1,numXI2,xI1,xI2,dxI,fl,datatype,EM)
6120 integer, intent(in) :: igrid,numXI1,numXI2
6121 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6122 double precision, intent(in) :: dxI
6123 type(te_fluid), intent(in) :: fl
6124 character(20), intent(in) :: datatype
6125 double precision, intent(inout) :: EM(numXI1,numXI2)
6126
6127 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6128 double precision, allocatable :: flux(:^D&),Ne(:^D&),opacity(:^D&)
6129 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6130 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC,RsubC
6131 double precision :: TBsubC,PBsubC
6132 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2),xSubC_car(1:3)
6133 double precision :: R_thick,dotp,dvolume,R_occult,Rc
6134 double precision :: dxl(1:3),x_sph(1:3),dx_sph(1:3)
6135 double precision :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6136 logical :: sun_back_side,emit
6137
6138 integer :: mass
6139 double precision :: logTe
6140 character (30) :: ion
6141 double precision :: lineCent
6142 double precision :: sigma_PSF,spaceRsl,wlRsl,sigma0,factor,wslit
6143 double precision :: RHESSI_rsl,area_1AU,arcsec,pixel
6144
6145 ^d&ixomin^d=ixmlo^d;
6146 ^d&ixomax^d=ixmhi^d;
6147 ^d&iximin^d=ixglo^d;
6148 ^d&iximax^d=ixghi^d;
6149
6150 if (si_unit) then
6151 arcsec=7.25d5/unit_length
6152 else
6153 arcsec=7.25d7/unit_length
6154 endif
6155
6156 allocate(flux(ixi^s),opacity(ixi^s))
6157 if (datatype=='image_euv') then
6158 if (trim(emission_model)=='pseudo_current') then
6159 call get_pseudo_current(igrid,ixi^l,ixo^l,ps(igrid)%w,flux)
6160 else if (trim(emission_model)=='radio_ff') then
6161 call get_radio_ff_source_opacity(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,opacity)
6162 else
6163 ! get local EUV flux and velocity
6164 call get_euv(wavelength,ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux)
6165 flux(ixo^s)=flux(ixo^s)/instrument_resolution_factor**2 ! adjust flux due to artifical change of resolution
6166 endif
6167 call get_line_info(wavelength,ion,mass,logte,linecent,spacersl,wlrsl,sigma_psf,wslit)
6168 pixel=spacersl*arcsec
6169 sigma0=sigma_psf*pixel
6170 else if (datatype=='image_sxr') then
6171 ! get local SXR flux photons cm^-3 s^-1 (cgs) or photons m^-3 s^-1 (SI)
6172 call get_sxr(ixi^l,ixo^l,ps(igrid)%w,ps(igrid)%x,fl,flux,emin_sxr,emax_sxr)
6173 rhessi_rsl=2.3d0/instrument_resolution_factor
6174 sigma_psf=1.d0
6175 pixel=rhessi_rsl*arcsec
6176 sigma0=sigma_psf*pixel
6177 area_1au=2.81d27
6178 endif
6179
6180 ! integrate emission
6181 r_thick=r_opt_thick*const_rsun/unit_length
6182 {do ix^d=ixomin^d,ixomax^d\}
6183 x_sph(1:3)=ps(igrid)%x(ix^d,1:3)
6184 dx_sph(1:3)=ps(igrid)%dx(ix^d,1:3)
6185 dxl(1)=dx_sph(1) ! cell size in length
6186 dxl(2)=x_sph(1)*dx_sph(2) ! cell size in length
6187 dxl(3)=x_sph(1)*dsin(x_sph(2))*dx_sph(3) ! cell size in length
6188 ! dividing a cell to several sub-cells to get more accurate integrating values
6189 ^d&nsubc^d=1;
6190 call get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6191 call dot_product_loc(unitv_r,vec_xi1,dotp)
6192 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6193 call dot_product_loc(unitv_r,vec_xi2,dotp)
6194 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6195 call dot_product_loc(unitv_theta,vec_xi1,dotp)
6196 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6197 call dot_product_loc(unitv_theta,vec_xi2,dotp)
6198 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6199 call dot_product_loc(unitv_phi,vec_xi1,dotp)
6200 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6201 call dot_product_loc(unitv_phi,vec_xi2,dotp)
6202 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6203
6204 ! integrate sub-cells
6205 do isubc1=1,nsubc1
6206 ! sub-cell center coordinate in spherical
6207 xsubc(1)=x_sph(1)-half*dx_sph(1)+(isubc1-half)*dx_sph(1)/nsubc1
6208 rsubc=xsubc(1)
6209 dxsubc1=dx_sph(1)/nsubc1 ! sub-cell size in length
6210 do isubc2=1,nsubc2
6211 ! sub-cell center coordinate in spherical
6212 xsubc(2)=x_sph(2)-half*dx_sph(2)+(isubc2-half)*dx_sph(2)/nsubc2
6213 dxsubc2=xsubc(1)*dx_sph(2)/nsubc2 ! sub-cell size in length
6214 dxsubc3=xsubc(1)*dsin(xsubc(2))*dx_sph(3)/nsubc3 ! sub-cell size in length
6215 dvolume=dxsubc1*dxsubc2*dxsubc3
6216 if (datatype=='image_euv') then
6217 if (si_unit) then
6218 fluxsubc=flux(ix^d)*dvolume*unit_length*1.d2/dxi/dxi ! DN s^-1
6219 else
6220 fluxsubc=flux(ix^d)*dvolume*unit_length/dxi/dxi ! DN s^-1
6221 endif
6222 else if (datatype=='image_sxr') then
6223 ! sub-cell SXR flux at 1 AU [photons s^-1 cm^-2]
6224 fluxsubc=flux(ix^d)*dvolume*unit_length**3/area_1au
6225 endif
6226 ! enter integration if flux large enough
6227 if (fluxsubc>smalldouble) then
6228 do isubc3=1,nsubc3
6229 ! sub-cell center coordinate in spherical
6230 xsubc(3)=x_sph(3)-half*dx_sph(3)+(isubc3-half)*dx_sph(3)/nsubc3
6231 call get_cor_image_spherical(xsubc,xcent)
6232 rc=dsqrt(xcent(1)**2+xcent(2)**2) ! distance to sun center (on the image plane)
6233 !
6234 ! whether the local emitted photons can arrive the telescope
6235 call spherical_to_cartesian(xsubc,xsubc_car)
6236 call dot_product_loc(vec_los,xsubc_car,dotp)
6237 sun_back_side=.true.
6238 if (dotp<0.d0) sun_back_side=.false.
6239 ! whether the local emission can reach the telescope
6240 if (sun_back_side) then
6241 emit=.false.
6242 if (rc>r_thick) emit=.true.
6243 else
6244 emit=.true.
6245 if (xsubc(1)<=r_thick) emit=.false.
6246 endif
6247 !
6248 if (emit) then
6249 ! mapping the 3D coordinate to location at the image
6250 ! distribution at nearby pixels
6251 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6252 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6253 ixpmin1=max(1,ixp1-3)
6254 ixpmax1=min(ixp1+3,numxi1)
6255 ixpmin2=max(1,ixp2-3)
6256 ixpmax2=min(ixp2+3,numxi2)
6257 do ixp1=ixpmin1,ixpmax1
6258 do ixp2=ixpmin2,ixpmax2
6259 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6260 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6261 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6262 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6263 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6264 em(ixp1,ixp2)=em(ixp1,ixp2)+fluxsubc*factor
6265 enddo !ixP2
6266 enddo !ixP1
6267 endif !emit
6268 enddo !iSubC3
6269 endif !smallflux
6270 enddo !iSubC2
6271 enddo !iSubC1
6272 {enddo\} !ix
6273
6274 deallocate(flux,opacity)
6275
6276 end subroutine integrate_emission_spherical
6277
6278 subroutine integrate_whitelight_spherical(igrid,numXI1,numXI2,numWI,xI1,xI2,dxI,fl,datatype,WLB)
6279 use mod_eos, only: eos
6280
6281 integer, intent(in) :: igrid,numXI1,numXI2,numWI
6282 double precision, intent(in) :: xI1(numXI1),xI2(numXI2)
6283 double precision, intent(in) :: dxI
6284 type(te_fluid), intent(in) :: fl
6285 character(20), intent(in) :: datatype
6286 double precision, intent(inout) :: WLB(numXI1,numXI2,numWI)
6287
6288 integer :: ixO^L,ixO^D,ixI^L,ix^D,i,j
6289 double precision, allocatable :: flux(:^D&),Ne(:^D&),nH_dummy(:^D&)
6290 integer :: ixP^L,ixP^D,nSubC^D,iSubC^D
6291 double precision :: xSubP1,xSubP2,dxSubP,xerf^L,fluxsubC,RsubC
6292 double precision :: sigma_PSF,sigma0,arcsec,pixel,LASCO_rsl
6293 double precision :: A,B,C,D,Rc,Ne0,TBsubC,PBsubC,factor
6294 double precision :: R_thick,dotp,dvolume,R_occult
6295 double precision :: xSubC(1:3),dxSubC^D,xCent(1:2),xSubC_car(1:3)
6296 double precision :: dxl(1:3),x_sph(1:3),dx_sph(1:3)
6297 double precision :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6298 logical :: emit
6299
6300 ^d&ixomin^d=ixmlo^d;
6301 ^d&ixomax^d=ixmhi^d;
6302 ^d&iximin^d=ixglo^d;
6303 ^d&iximax^d=ixghi^d;
6304
6305 if (si_unit) then
6306 arcsec=7.25d5/unit_length
6307 else
6308 arcsec=7.25d7/unit_length
6309 endif
6310
6311 allocate(ne(ixi^s))
6312 allocate(nh_dummy(ixi^s))
6313 if (whitelight_instrument=='LASCO/C1') then
6314 lasco_rsl=5.6d0/instrument_resolution_factor
6315 r_occult=1.1d0
6316 else if (whitelight_instrument=='LASCO/C2') then
6317 lasco_rsl=11.4d0/instrument_resolution_factor
6318 r_occult=2.d0
6319 else if (whitelight_instrument=='LASCO/C3') then
6320 lasco_rsl=56.d0/instrument_resolution_factor
6321 r_occult=3.7d0
6322 endif
6323 if (r_occultor>1.d0) r_occult=r_occultor
6324 r_occult=r_occult*const_rsun/unit_length
6325 call fl%get_rho(ps(igrid)%w,ps(igrid)%x,ixi^l,ixo^l,ne)
6326 ! get actual electron density from EoS (replaces rho with ne)
6327 call eos%get_ne_nH(ixi^l, ixo^l, ps(igrid)%w, ps(igrid)%x, ne, nh_dummy)
6328 sigma_psf=1.d0
6329 pixel=lasco_rsl*arcsec
6330 sigma0=sigma_psf*pixel
6331
6332 ! integrate emission
6333 r_thick=r_opt_thick*const_rsun/unit_length
6334 {do ix^d=ixomin^d,ixomax^d\}
6335 x_sph(1:3)=ps(igrid)%x(ix^d,1:3)
6336 dx_sph(1:3)=ps(igrid)%dx(ix^d,1:3)
6337 dxl(1)=dx_sph(1) ! cell size in length
6338 dxl(2)=x_sph(1)*dx_sph(2) ! cell size in length
6339 dxl(3)=x_sph(1)*dsin(x_sph(2))*dx_sph(3) ! cell size in length
6340 ne0=ne(ix^d)*unit_numberdensity
6341 ! dividing a cell to several sub-cells to get more accurate integrating values
6342 ^d&nsubc^d=1;
6343 call get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6344 call dot_product_loc(unitv_r,vec_xi1,dotp)
6345 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6346 call dot_product_loc(unitv_r,vec_xi2,dotp)
6347 nsubc1=max(nsubc1,ceiling(dxl(1)*abs(dotp)/(dxi/2.d0)))
6348 call dot_product_loc(unitv_theta,vec_xi1,dotp)
6349 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6350 call dot_product_loc(unitv_theta,vec_xi2,dotp)
6351 nsubc2=max(nsubc2,ceiling(dxl(2)*abs(dotp)/(dxi/2.d0)))
6352 call dot_product_loc(unitv_phi,vec_xi1,dotp)
6353 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6354 call dot_product_loc(unitv_phi,vec_xi2,dotp)
6355 nsubc3=max(nsubc3,ceiling(dxl(3)*abs(dotp)/(dxi/2.d0)))
6356
6357 ! integrate sub-cells
6358 do isubc1=1,nsubc1
6359 ! sub-cell center coordinate in spherical
6360 xsubc(1)=x_sph(1)-half*dx_sph(1)+(isubc1-half)*dx_sph(1)/nsubc1
6361 rsubc=xsubc(1)
6362 dxsubc1=dx_sph(1)/nsubc1 ! sub-cell size in length
6363 call get_thomson_parameters(rsubc,a,b,c,d)
6364 do isubc2=1,nsubc2
6365 ! sub-cell center coordinate in spherical
6366 xsubc(2)=x_sph(2)-half*dx_sph(2)+(isubc2-half)*dx_sph(2)/nsubc2
6367 dxsubc2=xsubc(1)*dx_sph(2)/nsubc2 ! sub-cell size in length
6368 dxsubc3=xsubc(1)*dsin(xsubc(2))*dx_sph(3)/nsubc3 ! sub-cell size in length
6369 dvolume=dxsubc1*dxsubc2*dxsubc3
6370 do isubc3=1,nsubc3
6371 ! sub-cell center coordinate in spherical
6372 xsubc(3)=x_sph(3)-half*dx_sph(3)+(isubc3-half)*dx_sph(3)/nsubc3
6373 call get_cor_image_spherical(xsubc,xcent)
6374 rc=dsqrt(xcent(1)**2+xcent(2)**2) ! distance to sun center (on the image plane)
6375 ! whether the local emitted photons can arrive the telescope
6376 emit=.false.
6377 if (rc>r_occult) then
6378 emit=.true.
6379 ! scaterring flux from cm^-3 of plasma
6380 call get_whitelight_thomson(rsubc,rc,ne0,a,b,c,d,tbsubc,pbsubc)
6381 tbsubc=tbsubc*dvolume*unit_length/dxi/dxi
6382 pbsubc=pbsubc*dvolume*unit_length/dxi/dxi
6383 if (tbsubc<1.d-20) emit=.false.
6384 endif
6385 if (emit) then
6386 ! mapping the 3D coordinate to location at the image
6387 ! distribution at nearby pixels
6388 ixp1=floor((xcent(1)-(xi1(1)-half*dxi))/dxi)+1
6389 ixp2=floor((xcent(2)-(xi2(1)-half*dxi))/dxi)+1
6390 ixpmin1=max(1,ixp1-3)
6391 ixpmax1=min(ixp1+3,numxi1)
6392 ixpmin2=max(1,ixp2-3)
6393 ixpmax2=min(ixp2+3,numxi2)
6394 do ixp1=ixpmin1,ixpmax1
6395 do ixp2=ixpmin2,ixpmax2
6396 xerfmin1=((xi1(ixp1)-half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6397 xerfmax1=((xi1(ixp1)+half*dxi)-xcent(1))/(sqrt(2.d0)*sigma0)
6398 xerfmin2=((xi2(ixp2)-half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6399 xerfmax2=((xi2(ixp2)+half*dxi)-xcent(2))/(sqrt(2.d0)*sigma0)
6400 factor=(erfc(xerfmin1)-erfc(xerfmax1))*(erfc(xerfmin2)-erfc(xerfmax2))/4.d0
6401 wlb(ixp1,ixp2,1)=wlb(ixp1,ixp2,1)+tbsubc*factor
6402 wlb(ixp1,ixp2,2)=wlb(ixp1,ixp2,2)+pbsubc*factor
6403 enddo !ixP2
6404 enddo !ixP1
6405 endif
6406 enddo !iSubC3
6407 enddo !iSubC2
6408 enddo !iSubC1
6409 {enddo\} !ix
6410
6411 deallocate(ne)
6412 deallocate(nh_dummy)
6413
6414 end subroutine integrate_whitelight_spherical
6415
6416 subroutine get_thomson_parameters(Rl,A,B,C,D)
6417 ! parameters given in Billings 1968
6418 use mod_constants
6419 double precision, intent(in) :: Rl
6420 double precision, intent(inout) :: A,B,C,D
6421
6422 double precision :: sinO,cosO,sinO2,cosO2,tmp
6423
6424 sino=const_rsun/(rl*unit_length)
6425 sino2=sino**2
6426 coso2=1.d0-sino2
6427 coso=abs(dsqrt(coso2))
6428 tmp=log((1.d0+sino)/coso)
6429 a=coso*sino2
6430 b=-(1.d0-3.d0*sino2-(coso2/sino)*(1.d0+3.d0*sino2)*tmp)/8.d0
6431 c=4.d0/3.d0-coso-coso*coso2/3.d0
6432 d=(5.d0+sino2-(coso2/sino)*(5.d0-sino2)*tmp)/8.d0
6433
6434 end subroutine get_thomson_parameters
6435
6436 subroutine get_whitelight_thomson(Rl,Rin,Ne,A,B,C,D,fluxTB,fluxPB)
6437 ! use the method in SSW/eltheory
6438 double precision, intent(in) :: Rl,Rin,Ne,A,B,C,D
6439 double precision, intent(inout) :: fluxTB,fluxPB
6440
6441 double precision :: const,u,Bt,Br,PB,TB,sinchi2
6442
6443 u=0.63d0
6444 const=1.24878d-25/(1.d0-u/3.d0)
6445 sinchi2=(rin/rl)**2
6446 bt=const*(c+u*(d-c))
6447 pb=const*sinchi2*((a+u*(b-a)))
6448 br=bt-pb
6449 tb=bt+br
6450 fluxtb=tb*ne
6451 fluxpb=pb*ne
6452
6453 end subroutine get_whitelight_thomson
6454
6455 subroutine get_unit_vector_spherical(x_sph,unitv_r,unitv_theta,unitv_phi)
6456 double precision, intent(in) :: x_sph(1:3)
6457 double precision, intent(inout) :: unitv_r(1:3),unitv_theta(1:3),unitv_phi(1:3)
6458
6459 unitv_r(1)=dsin(x_sph(2))*dcos(x_sph(3))
6460 unitv_r(2)=dsin(x_sph(2))*dsin(x_sph(3))
6461 unitv_r(3)=dcos(x_sph(2))
6462 unitv_theta(1)=dcos(x_sph(2))*dcos(x_sph(3))
6463 unitv_theta(2)=dcos(x_sph(2))*dsin(x_sph(3))
6464 unitv_theta(3)=-dsin(x_sph(2))
6465 unitv_phi(1)=-dsin(x_sph(3))
6466 unitv_phi(2)=dcos(x_sph(3))
6467 unitv_phi(3)=zero
6468
6469 end subroutine get_unit_vector_spherical
6470
6471 subroutine output_data(qunit,xO1,xO2,dxO1,dxO2,wO,nXO1,nXO2,nWO,datatype)
6472 ! change the format of data and write data
6474
6475 integer, intent(in) :: qunit,nXO1,nXO2,nWO
6476 double precision, intent(in) :: dxO1(nxO1),dxO2(nxO2)
6477 double precision, intent(in) :: xO1(nXO1),xO2(nxO2)
6478 double precision, intent(inout) :: wO(nXO1,nXO2,nWO)
6479 character(20), intent(in) :: datatype
6480
6481 integer :: nPiece,nP1,nP2,nC1,nC2,nWC
6482 integer :: piece_nmax1,piece_nmax2,ix1,ix2,j,ipc,ixc1,ixc2
6483 double precision :: uniform_tol
6484 double precision, allocatable :: xC(:,:,:,:),wC(:,:,:,:),dxC(:,:,:,:)
6485
6486 ! clean small values
6487 uniform_tol=1.d-10
6488 do ix1=1,nxo1
6489 do ix2=1,nxo2
6490 do j=1,nwo
6491 if (abs(wo(ix1,ix2,j))<smalldouble) wo(ix1,ix2,j)=zero
6492 enddo
6493 enddo
6494 enddo
6495
6496 ! how many cells in each grid
6497 if (dat_resolution) then
6498 if (datatype=='image_euv' .or. datatype=='image_sxr') then
6499 if (los_phi==0 .and. los_theta==90) then
6500 piece_nmax1=block_nx2
6501 piece_nmax2=block_nx3
6502 else if (los_phi==90 .and. los_theta==90) then
6503 piece_nmax1=block_nx3
6504 piece_nmax2=block_nx1
6505 else
6506 piece_nmax1=block_nx1
6507 piece_nmax2=block_nx2
6508 endif
6509 else if (datatype=='spectrum_euv') then
6510 piece_nmax1=16
6511 if (direction_slit==1) then
6512 piece_nmax2=block_nx1
6513 else if (direction_slit==2) then
6514 piece_nmax2=block_nx2
6515 else
6516 piece_nmax2=block_nx3
6517 endif
6518 endif
6519 else
6520 piece_nmax1=20
6521 piece_nmax2=20
6522 endif
6523 loopn1: do j=piece_nmax1,1,-1
6524 if(mod(nxo1,j)==0) then
6525 nc1=j
6526 exit loopn1
6527 endif
6528 enddo loopn1
6529 loopn2: do j=piece_nmax2,1,-1
6530 if(mod(nxo2,j)==0) then
6531 nc2=j
6532 exit loopn2
6533 endif
6534 enddo loopn2
6535 ! how many grids
6536 np1=nxo1/nc1
6537 np2=nxo2/nc2
6538 npiece=np1*np2
6539 nwc=nwo
6540
6541 ! output images
6542 select case(convert_type)
6543 case('EIvtuCCmpi','ESvtuCCmpi','SIvtuCCmpi','WIvtuCCmpi')
6544 ! put data into grids
6545 allocate(xc(npiece,nc1,nc2,2))
6546 allocate(dxc(npiece,nc1,nc2,2))
6547 allocate(wc(npiece,nc1,nc2,nwo))
6548 do ipc=1,npiece
6549 do ixc1=1,nc1
6550 do ixc2=1,nc2
6551 ix1=mod(ipc-1,np1)*nc1+ixc1
6552 ix2=floor(1.0*(ipc-1)/np1)*nc2+ixc2
6553 xc(ipc,ixc1,ixc2,1)=xo1(ix1)
6554 xc(ipc,ixc1,ixc2,2)=xo2(ix2)
6555 dxc(ipc,ixc1,ixc2,1)=dxo1(ix1)
6556 dxc(ipc,ixc1,ixc2,2)=dxo2(ix2)
6557 do j=1,nwc
6558 wc(ipc,ixc1,ixc2,j)=wo(ix1,ix2,j)
6559 enddo
6560 enddo
6561 enddo
6562 enddo
6563 ! write data into vtu file
6564 call write_image_vtucc(qunit,xc,wc,dxc,npiece,nc1,nc2,nwc,datatype)
6565 deallocate(xc,dxc,wc)
6566 case('EIvtiCCmpi','ESvtiCCmpi','SIvtiCCmpi','WIvtiCCmpi')
6567 if (dat_resolution .and. &
6568 (maxval(abs(dxo1(:)-dxo1(1)))>uniform_tol*max(one,abs(dxo1(1))) .or. &
6569 maxval(abs(dxo2(:)-dxo2(1)))>uniform_tol*max(one,abs(dxo2(1))))) then
6570 call mpistop("vti needs uniform dat-resolution image grids")
6571 else
6572 call write_image_vticc(qunit,xo1,xo2,dxo1,dxo2,wo,nxo1,nxo2,nwo,nc1,nc2)
6573 endif
6574 case default
6575 call mpistop("Error in synthesize emission: Unknown convert_type")
6576 end select
6577
6578 end subroutine output_data
6579 }
6580
6581 subroutine write_image_vticc(qunit,xO1,xO2,dxO1,dxO2,wO,nXO1,nXO2,nWO,nC1,nC2)
6582 ! write image data to vti
6584
6585 integer, intent(in) :: qunit,nXO1,nXO2,nWO,nC1,nC2
6586 double precision, intent(in) :: xO1(nXO1),xO2(nxO2)
6587 double precision, intent(in) :: dxO1(nxO1),dxO2(nxO2)
6588 double precision, intent(in) :: wO(nXO1,nXO2,nWO)
6589
6590 double precision :: origin(1:3), spacing(1:3)
6591 integer :: wholeExtent(1:6)
6592 integer :: iw
6593 integer :: ixC1,ixC2
6594
6595 integer :: filenr
6596 logical :: fileopen
6597 character (70) :: subname,wname,vname,nameL,nameS
6598 character (len=std_len) :: filename
6599 logical :: sph_datres_no_doppler
6600
6601
6602 origin(1)=xo1(1)-0.5d0*dxo1(1)
6603 origin(2)=xo2(1)-0.5d0*dxo2(1)
6604 origin(3)=zero
6605 spacing(1)=dxo1(1)
6606 spacing(2)=dxo2(1)
6607 spacing(3)=one
6608 wholeextent=0
6609 wholeextent(2)=nxo1
6610 wholeextent(4)=nxo2
6611 sph_datres_no_doppler=dat_resolution .and. coordinate==spherical .and. trim(ray_method_active)=='spherical'
6612
6613 if (mype==0) then
6614 inquire(qunit,opened=fileopen)
6615 if(.not.fileopen)then
6616 ! generate filename
6617 filenr=snapshotini
6618 if (autoconvert) filenr=snapshotnext
6619 if (convert_type=='EIvtiCCmpi') then
6620 write(filename,'(a,i4.4,a)') trim(filename_euv),filenr,".vti"
6621 else if (convert_type=='SIvtiCCmpi') then
6622 write(filename,'(a,i4.4,a)') trim(filename_sxr),filenr,".vti"
6623 else if (convert_type=='WIvtiCCmpi') then
6624 write(filename,'(a,i4.4,a)') trim(filename_whitelight),filenr,".vti"
6625 else if (convert_type=='ESvtiCCmpi') then
6626 write(filename,'(a,i4.4,a)') trim(filename_spectrum),filenr,".vti"
6627 endif
6628 open(qunit,file=filename,status='unknown',form='formatted')
6629 endif
6630
6631 ! generate xml header
6632 write(qunit,'(a)')'<?xml version="1.0"?>'
6633 write(qunit,'(a)',advance='no') '<VTKFile type="ImageData"'
6634 write(qunit,'(a)')' version="0.1" byte_order="LittleEndian">'
6635 write(qunit,'(a,3(1pe14.6),a,6(i10),a,3(1pe14.6),a)')' <ImageData Origin="',&
6636 origin,'" WholeExtent="',wholeextent,'" Spacing="',spacing,'">'
6637 ! file info
6638 write(qunit,'(a)')'<FieldData>'
6639 write(qunit,'(2a)')'<DataArray type="Float32" Name="TIME" ',&
6640 'NumberOfTuples="1" format="ascii">'
6641 write(qunit,*) real(global_time*time_convert_factor)
6642 write(qunit,'(a)')'</DataArray>'
6643 write(qunit,'(a)')'</FieldData>'
6644 ! pixel/cell data
6645 write(qunit,'(a,6(i10),a)') '<Piece Extent="',wholeextent,'">'
6646 write(qunit,'(a)')'<CellData>'
6647 do iw=1,nwo
6648 ! variable name
6649 if (convert_type=='EIvtiCCmpi') then
6650 if (wavelength<100) then
6651 write(vname,'(a,i2)') "AIA",wavelength
6652 else if (wavelength<1000) then
6653 write(vname,'(a,i3)') "AIA",wavelength
6654 else
6655 write(vname,'(a,i4)') "IRIS",wavelength
6656 endif
6657 if (trim(emission_model)=='pseudo_current' .and. iw==1) vname='pseudo_current'
6658 if (trim(emission_model)=='radio_ff' .and. iw==1) vname='radio_brightness_temperature'
6659 if (trim(radiation_transfer)=='thick' .and. iw==1) vname=trim(vname)//'_thick'
6660 if (iw==2 .and. dat_resolution .and. (.not. sph_datres_no_doppler) .and. &
6661 trim(emission_model)/='radio_ff' .and. &
6662 trim(emission_model)/='pseudo_current') vname='Doppler_velocity'
6663 if (output_tau .and. trim(radiation_transfer)=='thick' .and. &
6664 ((trim(emission_model)=='radio_ff' .and. iw==2) .or. &
6665 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6666 ((dat_resolution .and. ((sph_datres_no_doppler .and. iw==2) .or. &
6667 ((.not. sph_datres_no_doppler) .and. iw==3))) .or. &
6668 ((.not. dat_resolution) .and. iw==2))))) then
6669 vname='tau'
6670 endif
6671 if (output_absorption_fraction .and. trim(radiation_transfer)=='thick' .and. &
6672 ((trim(emission_model)=='radio_ff' .and. ((output_tau .and. iw==3) .or. &
6673 ((.not. output_tau) .and. iw==2))) .or. &
6674 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6675 ((dat_resolution .and. sph_datres_no_doppler .and. output_tau .and. iw==3) .or. &
6676 (dat_resolution .and. sph_datres_no_doppler .and. (.not. output_tau) .and. iw==2) .or. &
6677 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. output_tau .and. iw==4) .or. &
6678 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. (.not. output_tau) .and. iw==3) .or. &
6679 ((.not. dat_resolution) .and. output_tau .and. iw==3) .or. &
6680 ((.not. dat_resolution) .and. (.not. output_tau) .and. iw==2))))) then
6681 vname='absorption_fraction'
6682 endif
6683 else if (convert_type=='SIvtiCCmpi') then
6684 if (emin_sxr<10 .and. emax_sxr<10) then
6685 write(vname,'(a,i1,a,i1,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6686 else if (emin_sxr<10 .and. emax_sxr>=10) then
6687 write(vname,'(a,i1,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6688 else
6689 write(vname,'(a,i2,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6690 endif
6691 else if (convert_type=='WIvtiCCmpi') then
6692 if (iw==1) write(vname,'(a)')'B'
6693 if (iw==2) write(vname,'(a)')'pB'
6694 else if (convert_type=='ESvtiCCmpi') then
6695 if (spectrum_wl==1354) then
6696 write(vname,'(a,i4)') "SG",spectrum_wl
6697 else
6698 write(vname,'(a,i3)') "EIS",spectrum_wl
6699 endif
6700 endif
6701 write(qunit,'(a,a,a)')&
6702 '<DataArray type="Float64" Name="',trim(vname),'" format="ascii">'
6703 write(qunit,'(200(1pe14.6))') ((wo(ixc1,ixc2,iw),ixc1=1,nxo1),ixc2=1,nxo2)
6704 write(qunit,'(a)')'</DataArray>'
6705 enddo
6706 write(qunit,'(a)')'</CellData>'
6707 write(qunit,'(a)')'</Piece>'
6708 ! end
6709 write(qunit,'(a)')'</ImageData>'
6710 write(qunit,'(a)')'</VTKFile>'
6711 close(qunit)
6712 endif
6713
6714 end subroutine write_image_vticc
6715
6716 subroutine write_image_vtucc(qunit,xC,wC,dxC,nPiece,nC1,nC2,nWC,datatype)
6717 ! write image data to vtu
6719
6720 integer, intent(in) :: qunit
6721 integer, intent(in) :: nPiece,nC1,nC2,nWC
6722 double precision, intent(in) :: xC(nPiece,nC1,nC2,2),dxC(nPiece,nc1,nc2,2)
6723 double precision, intent(in) :: wC(nPiece,nC1,nC2,nWC)
6724 character(20), intent(in) :: datatype
6725
6726 integer :: nP1,nP2
6727 double precision :: xP(nPiece,nC1+1,nC2+1,2)
6728 integer :: filenr
6729 logical :: fileopen
6730 character (70) :: subname,wname,vname,nameL,nameS
6731 character (len=std_len) :: filename
6732 integer :: ixC1,ixC2,ixP,ix1,ix2,j
6733 integer :: nc,np,icel,VTK_type
6734 logical :: sph_datres_no_doppler
6735
6736 np1=nc1+1
6737 np2=nc2+1
6738 np=np1*np2
6739 nc=nc1*nc2
6740 sph_datres_no_doppler=dat_resolution .and. coordinate==spherical .and. trim(ray_method_active)=='spherical'
6741 ! cell corner location
6742 do ixp=1,npiece
6743 do ix1=1,np1
6744 do ix2=1,np2
6745 if (ix1<np1) xp(ixp,ix1,ix2,1)=xc(ixp,ix1,1,1)-0.5d0*dxc(ixp,ix1,1,1)
6746 if (ix1==np1) xp(ixp,ix1,ix2,1)=xc(ixp,ix1-1,1,1)+0.5d0*dxc(ixp,ix1-1,1,1)
6747 if (ix2<np2) xp(ixp,ix1,ix2,2)=xc(ixp,1,ix2,2)-0.5d0*dxc(ixp,1,ix2,2)
6748 if (ix2==np2) xp(ixp,ix1,ix2,2)=xc(ixp,1,ix2-1,2)+0.5d0*dxc(ixp,1,ix2-1,2)
6749 enddo
6750 enddo
6751 enddo
6752 if (mype==0) then
6753 inquire(qunit,opened=fileopen)
6754 if(.not.fileopen)then
6755 ! generate filename
6756 filenr=snapshotini
6757 if (autoconvert) filenr=snapshotnext
6758 if (datatype=='image_euv') then
6759 write(filename,'(a,i4.4,a)') trim(filename_euv),filenr,".vtu"
6760 else if (datatype=='image_sxr') then
6761 write(filename,'(a,i4.4,a)') trim(filename_sxr),filenr,".vtu"
6762 else if (datatype=='image_whitelight') then
6763 write(filename,'(a,i4.4,a)') trim(filename_whitelight),filenr,".vtu"
6764 else if (datatype=='spectrum_euv') then
6765 write(filename,'(a,i4.4,a)') trim(filename_spectrum),filenr,".vtu"
6766 endif
6767 open(qunit,file=filename,status='unknown',form='formatted')
6768 endif
6769 ! generate xml header
6770 write(qunit,'(a)')'<?xml version="1.0"?>'
6771 write(qunit,'(a)',advance='no') '<VTKFile type="UnstructuredGrid"'
6772 write(qunit,'(a)')' version="0.1" byte_order="LittleEndian">'
6773 write(qunit,'(a)')'<UnstructuredGrid>'
6774 write(qunit,'(a)')'<FieldData>'
6775 write(qunit,'(2a)')'<DataArray type="Float32" Name="TIME" ',&
6776 'NumberOfTuples="1" format="ascii">'
6777 write(qunit,*) real(global_time*time_convert_factor)
6778 write(qunit,'(a)')'</DataArray>'
6779 write(qunit,'(a)')'</FieldData>'
6780 do ixp=1,npiece
6781 write(qunit,'(a,i7,a,i7,a)') &
6782 '<Piece NumberOfPoints="',np,'" NumberOfCells="',nc,'">'
6783 write(qunit,'(a)')'<CellData>'
6784 do j=1,nwc
6785 if (datatype=='image_euv') then
6786 if (j==1) then
6787 if (wavelength<100) then
6788 write(vname,'(a,i2)') "AIA",wavelength
6789 else if (wavelength<1000) then
6790 write(vname,'(a,i3)') "AIA",wavelength
6791 else
6792 write(vname,'(a,i4)') "IRIS",wavelength
6793 endif
6794 if (trim(emission_model)=='pseudo_current') vname='pseudo_current'
6795 if (trim(emission_model)=='radio_ff') vname='radio_brightness_temperature'
6796 if (trim(radiation_transfer)=='thick') vname=trim(vname)//'_thick'
6797 endif
6798 if (j==2 .and. dat_resolution .and. (.not. sph_datres_no_doppler) .and. &
6799 trim(emission_model)/='radio_ff' .and. &
6800 trim(emission_model)/='pseudo_current') vname='Doppler_velocity'
6801 if (output_tau .and. trim(radiation_transfer)=='thick' .and. &
6802 ((trim(emission_model)=='radio_ff' .and. j==2) .or. &
6803 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6804 ((dat_resolution .and. ((sph_datres_no_doppler .and. j==2) .or. &
6805 ((.not. sph_datres_no_doppler) .and. j==3))) .or. &
6806 ((.not. dat_resolution) .and. j==2))))) then
6807 vname='tau'
6808 endif
6809 if (output_absorption_fraction .and. trim(radiation_transfer)=='thick' .and. &
6810 ((trim(emission_model)=='radio_ff' .and. ((output_tau .and. j==3) .or. &
6811 ((.not. output_tau) .and. j==2))) .or. &
6812 (trim(emission_model)/='radio_ff' .and. trim(emission_model)/='pseudo_current' .and. &
6813 ((dat_resolution .and. sph_datres_no_doppler .and. output_tau .and. j==3) .or. &
6814 (dat_resolution .and. sph_datres_no_doppler .and. (.not. output_tau) .and. j==2) .or. &
6815 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. output_tau .and. j==4) .or. &
6816 (dat_resolution .and. (.not. sph_datres_no_doppler) .and. (.not. output_tau) .and. j==3) .or. &
6817 ((.not. dat_resolution) .and. output_tau .and. j==3) .or. &
6818 ((.not. dat_resolution) .and. (.not. output_tau) .and. j==2))))) then
6819 vname='absorption_fraction'
6820 endif
6821 else if (datatype=='image_sxr') then
6822 if (emin_sxr<10 .and. emax_sxr<10) then
6823 write(vname,'(a,i1,a,i1,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6824 else if (emin_sxr<10 .and. emax_sxr>=10) then
6825 write(vname,'(a,i1,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6826 else
6827 write(vname,'(a,i2,a,i2,a)') "SXR",emin_sxr,"-",emax_sxr,"keV"
6828 endif
6829 else if (datatype=='image_whitelight') then
6830 write(vname,'(a)')'whitelight'
6831 else if (datatype=='spectrum_euv') then
6832 if (spectrum_wl==1354) then
6833 write(vname,'(a,i4)') "SG",spectrum_wl
6834 else
6835 write(vname,'(a,i3)') "EIS",spectrum_wl
6836 endif
6837 endif
6838 write(qunit,'(a,a,a)')&
6839 '<DataArray type="Float64" Name="',trim(vname),'" format="ascii">'
6840 write(qunit,'(200(1pe14.6))') ((wc(ixp,ixc1,ixc2,j),ixc1=1,nc1),ixc2=1,nc2)
6841 write(qunit,'(a)')'</DataArray>'
6842 enddo
6843 write(qunit,'(a)')'</CellData>'
6844 write(qunit,'(a)')'<Points>'
6845 write(qunit,'(a)')'<DataArray type="Float32" NumberOfComponents="3" format="ascii">'
6846 do ix2=1,np2
6847 do ix1=1,np1
6848 if (datatype=='image_euv' .and. dat_resolution) then
6849 if (los_phi==0 .and. los_theta==90) then
6850 write(qunit,'(3(1pe14.6))') 0.d0,xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2)
6851 else if (los_phi==90 .and. los_theta==90) then
6852 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,2),0.d0,xp(ixp,ix1,ix2,1)
6853 else
6854 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6855 endif
6856 else if (datatype=='image_sxr' .and. dat_resolution) then
6857 if (los_phi==0 .and. los_theta==90) then
6858 write(qunit,'(3(1pe14.6))') 0.d0,xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2)
6859 else if (los_phi==90 .and. los_theta==90) then
6860 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,2),0.d0,xp(ixp,ix1,ix2,1)
6861 else
6862 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6863 endif
6864 else
6865 write(qunit,'(3(1pe14.6))') xp(ixp,ix1,ix2,1),xp(ixp,ix1,ix2,2),0.d0
6866 endif
6867 enddo
6868 enddo
6869 write(qunit,'(a)')'</DataArray>'
6870 write(qunit,'(a)')'</Points>'
6871 ! connetivity part
6872 write(qunit,'(a)')'<Cells>'
6873 write(qunit,'(a)')'<DataArray type="Int32" Name="connectivity" format="ascii">'
6874 do ix2=1,nc2
6875 do ix1=1,nc1
6876 write(qunit,'(4(i7))') ix1-1+(ix2-1)*np1,ix1+(ix2-1)*np1,&
6877 ix1-1+ix2*np1,ix1+ix2*np1
6878 enddo
6879 enddo
6880 write(qunit,'(a)')'</DataArray>'
6881 ! offsets data array
6882 write(qunit,'(a)')'<DataArray type="Int32" Name="offsets" format="ascii">'
6883 do icel=1,nc
6884 write(qunit,'(i7)') icel*(2**2)
6885 enddo
6886 write(qunit,'(a)')'</DataArray>'
6887 ! VTK cell type data array
6888 write(qunit,'(a)')'<DataArray type="Int32" Name="types" format="ascii">'
6889 ! VTK_LINE=3; VTK_PIXEL=8; VTK_VOXEL=11 -> vtk-syntax
6890 vtk_type=8
6891 do icel=1,nc
6892 write(qunit,'(i2)') vtk_type
6893 enddo
6894 write(qunit,'(a)')'</DataArray>'
6895 write(qunit,'(a)')'</Cells>'
6896 write(qunit,'(a)')'</Piece>'
6897 enddo
6898 write(qunit,'(a)')'</UnstructuredGrid>'
6899 write(qunit,'(a)')'</VTKFile>'
6900 close(qunit)
6901 endif
6902 end subroutine write_image_vtucc
6903
6904 subroutine dot_product_loc(vec1,vec2,res)
6905 double precision, intent(in) :: vec1(1:3),vec2(1:3)
6906 double precision, intent(out) :: res
6907
6908 res=vec1(1)*vec2(1)+vec1(2)*vec2(2)+vec1(3)*vec2(3)
6909
6910 end subroutine dot_product_loc
6911
6912 subroutine cross_product_loc(vec_in1,vec_in2,vec_out)
6913 double precision, intent(in) :: vec_in1(1:3),vec_in2(1:3)
6914 double precision, intent(out) :: vec_out(1:3)
6915
6916 vec_out(1)=vec_in1(2)*vec_in2(3)-vec_in1(3)*vec_in2(2)
6917 vec_out(2)=vec_in1(3)*vec_in2(1)-vec_in1(1)*vec_in2(3)
6918 vec_out(3)=vec_in1(1)*vec_in2(2)-vec_in1(2)*vec_in2(1)
6919
6920 end subroutine cross_product_loc
6921
6923 integer :: j
6924 double precision :: LOS_psi
6925 double precision :: vec_car(1:3),vec_z(1:3),vec_temp1(1:3),vec_temp2(1:3)
6926 double precision :: vec_LOS_sph(1:3),vec_xI1_sph(1:3),vec_xI2_sph(1:3)
6927
6928 ! antiparallel to LOS in spherical
6929 vec_los(1)=1.d0
6930 vec_los(2)=dpi*los_theta/180.d0
6931 vec_los(3)=dpi*los_phi/180.d0
6932 ! LOS in cartesian
6933 call spherical_to_cartesian(vec_los,vec_car)
6934 vec_los=-vec_car
6935
6936 ! theta=0 in cartesian
6937 vec_z(:)=zero
6938 vec_z(3)=1.d0
6939
6940 ! x direction for image
6941 if (los_theta==zero) then
6942 vec_temp1(1)=1.d0
6943 vec_temp1(2)=dpi/2.d0
6944 vec_temp1(3)=dpi*los_phi/180.d0
6945 call spherical_to_cartesian(vec_temp1,vec_car)
6946 vec_temp1=-vec_car
6947 call cross_product_loc(vec_temp1,vec_z,vec_xi1)
6948 else
6950 endif
6951
6952 ! y direction for image
6954
6955 ! rotate the image
6956 vec_temp1=vec_xi1/sqrt(vec_xi1(1)**2+vec_xi1(2)**2+vec_xi1(3)**2)
6957 vec_temp2=vec_xi2/sqrt(vec_xi2(1)**2+vec_xi2(2)**2+vec_xi2(3)**2)
6958 los_psi=dpi*image_rotate/180.d0
6959 vec_xi1=vec_temp1*cos(los_psi)-vec_temp2*sin(los_psi)
6960 vec_xi2=vec_temp2*cos(los_psi)+vec_temp1*sin(los_psi)
6961
6962 do j=1,3
6963 if (abs(vec_los(j))<smalldouble) vec_los(j)=zero
6964 if (abs(vec_xi1(j))<smalldouble) vec_xi1(j)=zero
6965 if (abs(vec_xi2(j))<smalldouble) vec_xi2(j)=zero
6966 enddo
6967
6968 call cartesian_to_spherical(vec_los,vec_los_sph)
6969 call cartesian_to_spherical(vec_xi1,vec_xi1_sph)
6970 call cartesian_to_spherical(vec_xi2,vec_xi2_sph)
6971 vec_los_sph(2:3)=vec_los_sph(2:3)*180.d0/dpi
6972 vec_xi1_sph(2:3)=vec_xi1_sph(2:3)*180.d0/dpi
6973 vec_xi2_sph(2:3)=vec_xi2_sph(2:3)*180.d0/dpi
6974
6975 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),']'
6976 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),']'
6977 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),']'
6978
6979 end subroutine init_vectors_spherical
6980
6981 subroutine spherical_to_cartesian(vec_sph,vec_car)
6982 ! angles in rad
6983 double precision, intent(in) :: vec_sph(1:3)
6984 double precision, intent(inout) :: vec_car(1:3)
6985
6986 vec_car(1)=vec_sph(1)*dsin(vec_sph(2))*dcos(vec_sph(3))
6987 vec_car(2)=vec_sph(1)*dsin(vec_sph(2))*dsin(vec_sph(3))
6988 vec_car(3)=vec_sph(1)*dcos(vec_sph(2))
6989
6990 end subroutine spherical_to_cartesian
6991
6992 subroutine cartesian_to_spherical(vec_car,vec_sph)
6993 ! angles in rad
6994 double precision, intent(in) :: vec_car(1:3)
6995 double precision, intent(inout) :: vec_sph(1:3)
6996
6997 vec_sph(1)=dsqrt(vec_car(1)**2+vec_car(2)**2+vec_car(3)**2)
6998 vec_sph(2)=dacos(vec_car(3)/vec_sph(1))
6999 vec_sph(3)=atan2(vec_car(2),vec_car(1))
7000
7001 end subroutine cartesian_to_spherical
7002
7004 integer :: j
7005 double precision :: LOS_psi
7006 double precision :: vec_z(1:3),vec_temp1(1:3),vec_temp2(1:3)
7007
7008 ! vectors for image coordinate
7009 vec_los(1)=-cos(dpi*los_phi/180.d0)*sin(dpi*los_theta/180.d0)
7010 vec_los(2)=-sin(dpi*los_phi/180.d0)*sin(dpi*los_theta/180.d0)
7011 vec_los(3)=-cos(dpi*los_theta/180.d0)
7012 do j=1,3
7013 if (abs(vec_los(j))<=smalldouble) vec_los(j)=zero
7014 enddo
7015 vec_z(:)=zero
7016 vec_z(3)=1.d0
7017 if (los_theta==zero) then
7018 vec_xi1(1)=cos(dpi*los_phi/180.d0)
7019 vec_xi1(2)=sin(dpi*los_phi/180.d0)
7020 vec_xi1(3)=zero
7021 else
7023 endif
7025 vec_temp1=vec_xi1/sqrt(vec_xi1(1)**2+vec_xi1(2)**2+vec_xi1(3)**2)
7026 vec_temp2=vec_xi2/sqrt(vec_xi2(1)**2+vec_xi2(2)**2+vec_xi2(3)**2)
7027 los_psi=dpi*image_rotate/180.d0
7028 vec_xi1=vec_temp1*cos(los_psi)-vec_temp2*sin(los_psi)
7029 vec_xi2=vec_temp2*cos(los_psi)+vec_temp1*sin(los_psi)
7030
7031 do j=1,3
7032 if (abs(vec_xi1(j))<smalldouble) vec_xi1(j)=zero
7033 if (abs(vec_xi2(j))<smalldouble) vec_xi2(j)=zero
7034 enddo
7035
7036 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' LOS vector: [',vec_los(1),vec_los(2),vec_los(3),']'
7037 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' xI1 vector: [',vec_xi1(1),vec_xi1(2),vec_xi1(3),']'
7038 if (mype==0) write(*,'(a,f5.2,f6.2,f6.2,a)') ' xI2 vector: [',vec_xi2(1),vec_xi2(2),vec_xi2(3),']'
7039
7040 end subroutine init_vectors_cartesian
7041
7042 subroutine get_cor_image_spherical(x_3D_sph,x_image)
7043 double precision, intent(in) :: x_3D_sph(1:3)
7044 double precision, intent(inout) :: x_image(1:2)
7045 double precision :: res,res_origin
7046 double precision :: x_3D(1:3)
7047
7048 call spherical_to_cartesian(x_3d_sph,x_3d)
7049 call dot_product_loc(x_3d,vec_xi1,res)
7050 x_image(1)=res
7051 call dot_product_loc(x_3d,vec_xi2,res)
7052 x_image(2)=res
7053
7054 end subroutine get_cor_image_spherical
7055
7056 subroutine get_cor_image(x_3D,x_image)
7057 double precision, intent(in) :: x_3D(1:3)
7058 double precision, intent(inout) :: x_image(1:2)
7059 double precision :: res,res_origin
7060
7061 call dot_product_loc(x_3d,vec_xi1,res)
7062 call dot_product_loc(x_origin,vec_xi1,res_origin)
7063 x_image(1)=res-res_origin
7064 call dot_product_loc(x_3d,vec_xi2,res)
7065 call dot_product_loc(x_origin,vec_xi2,res_origin)
7066 x_image(2)=res-res_origin
7067
7068 end subroutine get_cor_image
7069
7070end 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.
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)