-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtest_1line.py
475 lines (331 loc) · 17.5 KB
/
test_1line.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
#!/usr/bin/env python
# coding: utf-8
# # Test the one-line CLEDB inversion on synthetic CLE data.
# In[1]:
## the script version "test_1line.py" is generated by exporting this notebook via file -> export as -> executable script.
## Do not directly edit that version!
# In[2]:
## Needed modules
import pickle ## CLE synthetic observation data cube is saved in the pickle format.
import importlib ## reloads imports (python default settings will not reload small changes).
from numba.typed import List ## Most numba functions are loaded by the CLEDB modules; non-reflected lists are needed to create a list of 2 bservation arrays
## Inversion Constants and control parameter imports.
## symbolic links pointing to the root directory containing the files are used. Pythondoes not allow relative upstream references anymore
import constants as consts
import ctrlparams
params=ctrlparams.ctrlparams() ## just a shorter label
# ### 1. LOAD the input data
# #### 1.a CLE 3dipole along LOS simulation example
# In[3]:
## observations of a 3 dipole coronal structure of a Fe XIII combined observation
## sobs1-3 are the independent dipoles
## sobsa is the combined 3 dipole output
## waveA and waveB are the wavelength arrays for the two Fe XIII lines
with open('obsstokes_3dipole_hires_fullspectra.pkl','rb') as f:
sobs1,sobs2,sobs3,sobsa,waveA,waveB = pickle.load(f)
### reversing of the wavelength range. THIS IS NEEDED! CLE writes frequency-wise, so wavelengths are reversed in the original datacubes!!!!!!
sobsa=sobsa[:,:,::-1,:]
## A fake minimal header for CLE
## This assumes the reference pixel is in the left bottom of the array; the values are in solar coordinates at crpixn in r_sun. The wavelength raferences (vacuum), ranges and spectral resolutions are unique. See CLE outfiles and grid.dat.
head_in = [np.array((0, 0, np.int32(sobsa.shape[2]/2)-1,\
-0.75, 0.8, 1074.62686-0.0124,\
(0.75-(-0.75))/sobsa.shape[0], (1.5-0.8)/sobsa.shape[1], 0.0247,"CLE-SIM" ),\
dtype = [('crpix1', np.float32), ('crpix2', np.float32), ('crpix3', np.float32),\
('crval1', np.float32), ('crval2', np.float32),('crval3', np.float32),\
('cdelt1', np.float32), ('cdelt2', np.float32),('cdelt3', np.float32), ('instrume','U7')]).view(np.recarray),\
np.array((0, 0, np.int32(sobsa.shape[2]/2)-1,\
-0.75, 0.8, 1079.78047-0.0124,\
(0.75-(-0.75))/sobsa.shape[0], (1.5-0.8)/sobsa.shape[1], 0.0249,"CLE-SIM" ),\
dtype = [('crpix1', np.float32), ('crpix2', np.float32), ('crpix3', np.float32),\
('crval1', np.float32), ('crval2', np.float32),('crval3', np.float32),\
('cdelt1', np.float32), ('cdelt2', np.float32),('cdelt3', np.float32), ('instrume', 'U7')]).view(np.recarray) ]
#waveA=waveA[::-1] ##the wave arrays are not needed by the inversion. the information is reconstructed from keywords
#waveB=waveB[::-1]
# #### 1.b CLE sheets along LOS example loading
# In[4]:
## observations of sheetlos coronal structure of a Fe XIII combined observation
## sobsa is the combined 5 dipole output
## waveA and waveB are the wavelength arrays for the two Fe XIII lines
# with open('obsstokes_sheetslos_hires_fullspectra.pkl','rb') as f:
# sobsa,waveA,waveB = pickle.load(f)
### reversing of the wavelength range. THIS IS NEEDED! CLE writes frequency-wise, so wavelengths are reversed in the original datacubes!!!!!!
# sobsa=sobsa[:,:,::-1,:]
# ## A fake minimal header for CLE
# ## This assumes the reference pixel is in the left bottom of the array; the values are in solar coordinates at crpixn in r_sun. The wavelength raferences (vacuum), ranges and spectral resolutions are unique. See CLE outfiles and grid.dat.
# head_in = TBD
# waveA=waveA[::-1] ##the wave arrays are not needed by the inversion. the information is reconstructed from keywords
# waveB=waveB[::-1]
## not yet included as test data. Coming soon!
# #### 1.c MURAM data example loading
# In[4]:
## load the fake observation muram data.
## FE XIII 1074+1079
# with open('obsstokes_avg_muram3.pkl','rb') as f:
# sobsa = pickle.load(f)
# sobsa=sobsa[0] ##needed because sobsa was saved as a 1 element list instead of pure np.array;
## A fake minimal header for MURAM
## This assumes the reference pixel is in the left bottom of the array; the values are in solar coordinates at crpixn in r_sun (from muram xvec and yvec arrays). The wavelength raferences (vacuum), ranges and spectral resolutions are unique (muram wvvec1 and wvvce2 arrays).
# head_in = [np.array((0, 0, 0,\
# -0.071, 0.989, 1074.257137,\
# 0.0001379, 0.0000689, 0.0071641,"MUR-SIM" ),\
# dtype = [('crpix1', np.float32), ('crpix2', np.float32), ('crpix3', np.float32),\
# ('crval1', np.float32), ('crval2', np.float32),('crval3', np.float32),\
# ('cdelt1', np.float32), ('cdelt2', np.float32),('cdelt3', np.float32), ('instrume','U7')]).view(np.recarray),\
# np.array((0, 0, 0,\
# -0.071, 0.989, 1079.420513,\
# 0.0001379, 0.0000689, 0.0071985,"MUR-SIM" ),\
# dtype = [('crpix1', np.float32), ('crpix2', np.float32), ('crpix3', np.float32),\
# ('crval1', np.float32), ('crval2', np.float32),('crval3', np.float32),\
# ('cdelt1', np.float32), ('cdelt2', np.float32),('cdelt3', np.float32), ('instrume','U7')]).view(np.recarray) ]
## muram data too big to include as test data!!!!
# #### 1.d ~~CoMP data example loading (IQUD required. No stokes V!)~~
# ### 2. Test the CLEDB_PREPINV module with synthetic data.
# ##### Remember to set your personal options and database paths in the ctrlparams class (in the parent directory) before continuing.
# In[5]:
import CLEDB_PREPINV.CLEDB_PREPINV as prepinv ##imports from the CLEDB_PREPINV subdirectory
# In[6]:
## take in just one line from the observation; e.g. one set of IQUV
## arrange the two observation "files" in a simple list;
## un-necesary step given the shape of sobs array, but it mimicks a file/header structure.
## set a proper numba typed list
sobs_lst=[sobsa[:,:,:,0:4]] ## standard python lists will be deprecated by numba
sobs_in = List() ## this is the List object implemented by numba; It utilizes memory in a column-like fashion.
[sobs_in.append(x) for x in sobs_lst] ## Numba developers claim that it is a significantly faster performing object
# ##### preprocess the observation "files"
# In[7]:
importlib.reload(prepinv) ## If module is modified, reload the contents
sobs_tot,yobs,rms,background,keyvals,sobs_totrot,aobs=prepinv.sobs_preprocess(sobs_in,head_in,params)
# ##### At this point all necesary data is loaded into memory;
# ##### An analythical LOS B field solution is used and the database is not required in this case
# ### 3. Test the CLEDB_PROC module with the same synthetic data.
# In[8]:
import CLEDB_PROC.CLEDB_PROC as procinv
# ##### Process the spectroscopy outputs
# In[48]:
#importlib.reload(procinv) ## If module is modified, reload the contents
specout=procinv.spectro_proc(sobs_in,sobs_tot,rms,background,keyvals,consts,params) ## when storing to disk do an if to reduce dimensions for 1 line cases
# ##### Process the LOS vector magnetic field inversion products (Analythical solution)
# In[55]:
importlib.reload(procinv) ## If module is modified, reload the contents
blosout=procinv.blos_proc(sobs_tot,rms,keyvals,consts,params)
# ## All should be good if we reached this point; all the outputs should be computed and saved in memory.
# ## 4. OPTIONAL tidbits
# In[50]:
##optionally needed libraries and functions
from datetime import datetime
import os
import glob
import numpy as np
from matplotlib import pyplot as plt
## interactive plotting; use only on local machines if widget is installed
get_ipython().run_line_magic('matplotlib', 'widget')
# colorbar function to have nice colorbars in figures with title
def colorbar(mappable,*args,**kwargs):
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.pyplot as plt
last_axes = plt.gca()
ax = mappable.axes
fig = ax.figure
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cbar = fig.colorbar(mappable, cax=cax,format='%.2f')
#cbar.formatter.set_powerlimits((0, 0))
title= kwargs.get('title', None)
cbar.set_label(title)
plt.sca(last_axes)
return cbar
# ### 4.a DUMP results (optional)
# In[51]:
## Remove old file saves and keep just the last run
lst=glob.glob('./outparams_1line*.pkl')
if len(lst) >0:
for i in range(len(lst)):
os.remove(lst[i])
## save the last run
datestamp = datetime.now().strftime("%Y%m%d-%H:%M:%S")
if not os.path.exists('./testrun_outputs'): ## make an output directory to keep things clean
os.makedirs('./testrun_outputs')
with open(f'./testrun_outputs/outparams_1line_{datestamp}.pkl', 'wb') as f:
pickle.dump([specout,blosout], f)
# ### 4.b PLOT the outputs (optional)
# In[52]:
## Plot utils
import numpy as np
linen=0 ## choose which line to plot; range is [0:1] for 2 line input
## plot subranges for soome in snapshots
# ## 3dipole
srx1=230
srx2=400
sry1=65
sry2=195
rnge=[0.8,1.5,-1.1,1.1]
##muram ## muram data not offered as part of the test scripts due to large sizes.
# srx1=0
# srx2=1023
# sry1=0
# sry2=1023
# rnge=[0.989,1.060,-0.071,0.071]
# In[53]:
##Plot spectroscopy
fig, plots = plt.subplots(nrows=3, ncols=4, figsize=(12,12))
## remove the 0 values and unreasonable/outlier values.
mx = np.ma.masked_array(specout[srx1:srx2,sry1:sry2,linen,0], mask=specout[srx1:srx2,sry1:sry2,linen,0]==0)
mx = np.ma.masked_array(mx, mask=specout[srx1:srx2,sry1:sry2,linen,0]>= 3950)
mx = np.ma.masked_array(mx, mask=specout[srx1:srx2,sry1:sry2,linen,0]<= 1070)
vvmin=np.min(mx)
vvmax=np.max(mx)
ab=plots[0,0].imshow(specout[srx1:srx2,sry1:sry2,linen,0],extent=rnge,vmin=vvmin,vmax=vvmax,cmap='bone')
plots[0,0].set_title('Wavelength')
colorbar(ab,title="[nm]")
plots[0,0].set_ylabel('Z [R$_\odot$]')
#plots[0,0].set_xlabel('Y [R$_\odot$]')
############################################################
## for correctly scaling in doppler scales
## remove unreasonable/outlier values.
mx = np.ma.masked_array(specout[srx1:srx2,sry1:sry2,linen,1], mask=specout[srx1:srx2,sry1:sry2,linen,1]>= 2 )
mx = np.ma.masked_array(mx, mask=specout[srx1:srx2,sry1:sry2,linen,1]<= -2 )
vvmax=np.max(mx)
vvmin=np.min(mx)
if np.abs(vvmin) > np.abs(vvmax):
vr=np.abs(vvmin)
else:
vr=np.abs(vvmax)
ab=plots[0,1].imshow(specout[srx1:srx2,sry1:sry2,linen,1],extent=rnge,vmin=-vr,vmax=vr,cmap='seismic')
plots[0,1].set_title('Doppler shift')
colorbar(ab,title="[nm]")
#plots[0,1].set_ylabel('Z [R$_\odot$]')
#plots[0,1].set_xlabel('Y [R$_\odot$]')
############################################################
## for correctly scaling in doppler scales
mx = np.ma.masked_array(specout[srx1:srx2,sry1:sry2,linen,2], mask=specout[srx1:srx2,sry1:sry2,linen,2]>= 1000 )
mx = np.ma.masked_array(mx, mask=specout[srx1:srx2,sry1:sry2,linen,2]<= -1000 )
vvmax=np.max(mx)
vvmin=np.min(mx)
if np.abs(vvmin) > np.abs(vvmax):
vr=np.abs(vvmin)
else:
vr=np.abs(vvmax)
## back to plotting
ab=plots[0,2].imshow(specout[srx1:srx2,sry1:sry2,linen,2],extent=rnge,vmin=-vr,vmax=vr,cmap='seismic')
plots[0,2].set_title('Doppler shift')
colorbar(ab,title="[km s$^{-1}$]")
#plots[0,2].set_ylabel('Z [R$_\odot$]')
#plots[0,2].set_xlabel('Y [R$_\odot$]')
############################################################
ab=plots[0,3].imshow(specout[srx1:srx2,sry1:sry2,linen,7],extent=rnge,vmin=0,vmax=np.max(specout[srx1:srx2,sry1:sry2,linen,7]),cmap='Reds')
plots[0,3].set_title('Stokes I bkg.')
colorbar(ab,title="Signal [erg cm${-2}$ s$^{-1}$]")
#plots[0,3].set_ylabel('Z [R$_\odot$]')
#plots[0,3].set_xlabel('Y [R$_\odot$]')
############################################################
ab=plots[1,0].imshow(specout[srx1:srx2,sry1:sry2,linen,3],extent=rnge,vmin=0,vmax=np.max(specout[srx1:srx2,sry1:sry2,linen,3]),cmap='Reds')
plots[1,0].set_title('Stokes I int. (linecore)')
colorbar(ab,title="Signal [erg cm${-2}$ s$^{-1}$]")
plots[1,0].set_ylabel('Z [R$_\odot$]')
#plots[1,0].set_xlabel('Y [R$_\odot$]')
############################################################
vvmin=np.min(specout[srx1:srx2,sry1:sry2,linen,4])
vvmax=np.max(specout[srx1:srx2,sry1:sry2,linen,4])
if np.abs(vvmin) > np.abs(vvmax):
vr=np.abs(vvmin)
else:
vr=np.abs(vvmax)
ab=plots[1,1].imshow(specout[srx1:srx2,sry1:sry2,linen,4],extent=rnge,vmin=-vr,vmax=vr,cmap='seismic')
plots[1,1].set_title('Stokes Q int. (linecore)')
colorbar(ab,title="Signal [erg cm${-2}$ s$^{-1}$]")
#plots[1,1].set_ylabel('Z [R$_\odot$]')
#plots[1,1].set_xlabel('Y [R$_\odot$]')
############################################################
vvmin=np.min(specout[srx1:srx2,sry1:sry2,linen,5])
vvmax=np.max(specout[srx1:srx2,sry1:sry2,linen,5])
if np.abs(vvmin) > np.abs(vvmax):
vr=np.abs(vvmin)
else:
vr=np.abs(vvmax)
ab=plots[1,2].imshow(specout[srx1:srx2,sry1:sry2,linen,5],extent=rnge,vmin=-vr,vmax=vr,cmap='seismic')
plots[1,2].set_title('Stokes U int. (linecore)')
colorbar(ab,title="Signal [erg cm${-2}$ s$^{-1}$]")
#plots[1,2].set_ylabel('Z [R$_\odot$]')
#plots[1,2].set_xlabel('Y [R$_\odot$]')
############################################################
vvmin=np.min(specout[srx1:srx2,sry1:sry2,linen,6])
vvmax=np.max(specout[srx1:srx2,sry1:sry2,linen,6])
if np.abs(vvmin) > np.abs(vvmax):
vr=np.abs(vvmin)
else:
vr=np.abs(vvmax)
ab=plots[1,3].imshow(specout[srx1:srx2,sry1:sry2,linen,6],extent=rnge,vmin=-vr,vmax=vr,cmap='seismic')
plots[1,3].set_title('Stokes V int. (linecore)')
colorbar(ab,title="Signal [erg cm${-2}$ s$^{-1}$]")
#plots[1,3].set_ylabel('Z [R$_\odot$]')
#plots[1,3].set_xlabel('Y [R$_\odot$]')
############################################################
## remove unreasonable/outlier values.
mx = np.ma.masked_array(specout[srx1:srx2,sry1:sry2,linen,8], mask=specout[srx1:srx2,sry1:sry2,linen,8]>= 0.45 )
mx = np.ma.masked_array(mx, mask=specout[srx1:srx2,sry1:sry2,linen,8]<= 0.01 )
vvmax=np.max(mx)
vvmin=np.min(mx)
ab=plots[2,0].imshow(specout[srx1:srx2,sry1:sry2,linen,8],extent=rnge,vmin=vvmin,vmax=vvmax,cmap='YlGnBu')
plots[2,0].set_title('Line full width half max.')
colorbar(ab,title="[nm]")
plots[2,0].set_ylabel('Z [R$_\odot$]')
plots[2,0].set_xlabel('Y [R$_\odot$]')
############################################################
## remove unreasonable/outlier values.
## PLOT INSIDE THE SAME SUBRANGES AS FULL WIDTHS TO SHOW THAT THEY ARE FRACTIONS.
mx = np.ma.masked_array(specout[srx1:srx2,sry1:sry2,linen,9], mask=specout[srx1:srx2,sry1:sry2,linen,9]>= 0.35 )
vvmax=np.nanmax(mx)
mx = np.ma.masked_array(mx, mask=specout[srx1:srx2,sry1:sry2,linen,9]<= 0.01 )
vvmin=np.nanmin(mx)
ab=plots[2,1].imshow(specout[srx1:srx2,sry1:sry2,linen,9],extent=rnge,vmin=0.1,vmax=vvmax,cmap='YlGnBu')
plots[2,1].set_title('Line non-thermal width')
colorbar(ab,title="[nm]")
#plots[2,1].set_ylabel('Z [R$_\odot$]')
plots[2,1].set_xlabel('Y [R$_\odot$]')
############################################################
ab=plots[2,2].imshow(specout[srx1:srx2,sry1:sry2,linen,10],extent=rnge,vmin=0.01,vmax=0.5*np.max(specout[srx1:srx2,sry1:sry2,linen,10]),cmap='YlOrRd')
plots[2,2].set_title('Linear polarization fraction')
colorbar(ab,title="L / I ratio")
#plots[0,0].set_ylabel('Z [R$_\odot$]')
plots[2,2].set_xlabel('Y [R$_\odot$]')
############################################################
ab=plots[2,3].imshow(specout[srx1:srx2,sry1:sry2,linen,11],extent=rnge,vmin=0.01,vmax=np.max(specout[srx1:srx2,sry1:sry2,linen,11]),cmap='YlOrRd')
plots[2,3].set_title('Total polarization fraction')
colorbar(ab,title="P / I ratio")
#plots[2,3].set_ylabel('Z [R$_\odot$]')
plots[2,3].set_xlabel('Y [R$_\odot$]')
############################################################
plt.tight_layout()
### Save the putput plots
if not os.path.exists('./testrun_outputs'): ## make an output directory to keep things clean
os.makedirs('./testrun_outputs')
plt.savefig(f"./testrun_outputs/specout_1line_sol{linen}_{datestamp}.pdf")
# In[57]:
## plot 1-line BLOS
fig, plots = plt.subplots(nrows=2, ncols=2, figsize=(8,10))
ab=plots[0,0].imshow(blosout[srx1:srx2,sry1:sry2,0],extent=rnge)
plots[0,0].set_title('1$^{st}$ degenerate magnetograph solution')
colorbar(ab,title="B$_{LOS}$ [G]")
plots[0,0].set_ylabel('Z [R$_\odot$]')
#plots[0,0].set_xlabel('Y [R$_\odot$]')
ab=plots[0,1].imshow(blosout[srx1:srx2,sry1:sry2,1],extent=rnge)
plots[0,1].set_title('2$^{nd}$ degenerate magnetograph solution')
colorbar(ab,title="B$_{LOS}$ [G]")
#plots[0,1].set_ylabel('Z [R$_\odot$]')
#plots[0,1].set_xlabel('Y [R$_\odot$]')
ab=plots[1,0].imshow(blosout[srx1:srx2,sry1:sry2,2],extent=rnge)
plots[1,0].set_title('Classic magnetograph solution')
colorbar(ab,title="B$_{LOS}$ [G]")
plots[1,0].set_ylabel('Z [R$_\odot$]')
plots[1,0].set_xlabel('Y [R$_\odot$]')
ab=plots[1,1].imshow(blosout[srx1:srx2,sry1:sry2,3],extent=rnge)
plots[1,1].set_title('Magnetic Azimuth')
colorbar(ab,title="B$_{LOS}$ [G]")
plots[1,1].set_xlabel('Y [R$_\odot$]')
plt.tight_layout()
### Save the putput plots
if not os.path.exists('./testrun_outputs'): ## make an output directory to keep things clean
os.makedirs('./testrun_outputs')
plt.savefig(f"./testrun_outputs/blosout_1line_{datestamp}.pdf")
# In[ ]:
# In[ ]: