PyThea 0.12.0__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pythea-0.12.0 → pythea-0.14.0}/CHANGELOG.md +24 -0
- {pythea-0.12.0 → pythea-0.14.0}/PKG-INFO +4 -3
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/PyThea_app.py +79 -31
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/_version.py +2 -2
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/callbacks.py +40 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/config/__init__.py +5 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/config/selected_imagers.py +17 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/data/sample_data.py +14 -5
- pythea-0.14.0/PyThea/extensions/Parker_spirals/__init__.py +62 -0
- pythea-0.14.0/PyThea/extensions/Parker_spirals/utils.py +45 -0
- pythea-0.14.0/PyThea/extensions/hek/utils.py +118 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/geometrical_models.py +123 -30
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/modules.py +174 -25
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/sunpy_dev/map/maputils.py +10 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/test/Pythea_test.py +3 -3
- pythea-0.14.0/PyThea/test/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/test/figure_hashes.json +2 -0
- pythea-0.14.0/PyThea/test/test_extension_utils.py +56 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/test/test_figures.py +71 -1
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/test/test_utils.py +37 -5
- pythea-0.14.0/PyThea/utils.py +961 -0
- pythea-0.14.0/PyThea/utils_database.py +93 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea.egg-info/PKG-INFO +4 -3
- {pythea-0.12.0 → pythea-0.14.0}/PyThea.egg-info/SOURCES.txt +6 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea.egg-info/requires.txt +3 -2
- {pythea-0.12.0 → pythea-0.14.0}/environment.yml +4 -3
- {pythea-0.12.0 → pythea-0.14.0}/requirements.txt +3 -2
- {pythea-0.12.0 → pythea-0.14.0}/setup.py +1 -0
- pythea-0.12.0/PyThea/utils.py +0 -562
- {pythea-0.12.0 → pythea-0.14.0}/.readthedocs.yaml +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/LICENSE.md +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/MANIFEST.in +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/config/app_styles.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/config/config_sliders.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/config/selected_bodies.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/data/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/extensions/LICENSE_gcs_python.md +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/extensions/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/extensions/buttons.py +0 -0
- {pythea-0.12.0/PyThea/sunpy_dev → pythea-0.14.0/PyThea/extensions/hek}/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/pythea_cli.py +0 -0
- {pythea-0.12.0/PyThea/sunpy_dev/extern → pythea-0.14.0/PyThea/sunpy_dev}/__init__.py +0 -0
- {pythea-0.12.0/PyThea/sunpy_dev/extern/sunkit_instruments → pythea-0.14.0/PyThea/sunpy_dev/extern}/__init__.py +0 -0
- {pythea-0.12.0/PyThea/sunpy_dev/extern/sunkit_instruments/aia → pythea-0.14.0/PyThea/sunpy_dev/extern/sunkit_instruments}/__init__.py +0 -0
- {pythea-0.12.0/PyThea/sunpy_dev/extern/sunkit_instruments/lasco → pythea-0.14.0/PyThea/sunpy_dev/extern/sunkit_instruments/aia}/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/sunpy_dev/extern/sunkit_instruments/aia/utils.py +0 -0
- {pythea-0.12.0/PyThea/sunpy_dev/extern/sunkit_instruments/stereo → pythea-0.14.0/PyThea/sunpy_dev/extern/sunkit_instruments/lasco}/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/sunpy_dev/extern/sunkit_instruments/lasco/utils.py +0 -0
- {pythea-0.12.0/PyThea/sunpy_dev/map → pythea-0.14.0/PyThea/sunpy_dev/extern/sunkit_instruments/stereo}/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/sunpy_dev/extern/sunkit_instruments/stereo/utils.py +0 -0
- {pythea-0.12.0/PyThea/test → pythea-0.14.0/PyThea/sunpy_dev/map}/__init__.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/test/conftest.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/test/test_geometrical_models.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/test/test_imports.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/test/test_remote_clients.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea/version.py +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea.egg-info/.DS_Store +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea.egg-info/dependency_links.txt +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea.egg-info/entry_points.txt +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea.egg-info/not-zip-safe +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/PyThea.egg-info/top_level.txt +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/README.md +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/README_pypi.md +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/pyproject.toml +0 -0
- {pythea-0.12.0 → pythea-0.14.0}/setup.cfg +0 -0
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
# v0.14.0 (03-Oct-2024)
|
|
2
|
+
|
|
3
|
+
## Features
|
|
4
|
+
- Adds imaging data from Solar Orbiter EUI and METIS.
|
|
5
|
+
- Implements offline fits file loading from local database.
|
|
6
|
+
|
|
7
|
+
## Minor Changes
|
|
8
|
+
- Simplifies the configuration of the database directory.
|
|
9
|
+
- Improves Parker Spiral visualization.
|
|
10
|
+
|
|
11
|
+
# v0.13.0 (14-Jul-2024)
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
- Adds imaging data from PSP/WISPR.
|
|
15
|
+
- Implements new feature of Parker spiral and HEK events visualization on the images.
|
|
16
|
+
- Adds a method to get directly the geometrical model from model_fittings.
|
|
17
|
+
- Adds tests for extensions, WISPR imaging.
|
|
18
|
+
- Adds and improves docstrings in utilities, modules, and geometrical models.
|
|
19
|
+
- Adds GCS and kinematic plots in documentation
|
|
20
|
+
- Adds function reference in the documentation
|
|
21
|
+
|
|
22
|
+
## Minor Changes
|
|
23
|
+
- Changes some optional inputs for get_hek_flare, make_figure, plot_bodies, and plot_solar_reference_lines to be better utilised.
|
|
24
|
+
|
|
1
25
|
# v0.12.0 (09-Jun-2024)
|
|
2
26
|
|
|
3
27
|
## Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PyThea
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: PyThea: A software package to reconstruct the 3D structure of CMEs and shock waves
|
|
5
5
|
Home-page: https://github.com/AthKouloumvakos/PyThea
|
|
6
6
|
Author: Athanasios Kouloumvakos
|
|
@@ -20,15 +20,16 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
|
20
20
|
Requires-Python: >=3.8, <3.11
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE.md
|
|
23
|
-
Requires-Dist: numpy
|
|
23
|
+
Requires-Dist: numpy==1.26.4
|
|
24
24
|
Requires-Dist: pandas
|
|
25
25
|
Requires-Dist: scipy
|
|
26
26
|
Requires-Dist: aiapy
|
|
27
|
-
Requires-Dist: astropy
|
|
27
|
+
Requires-Dist: astropy==6.0.0
|
|
28
28
|
Requires-Dist: astroquery
|
|
29
29
|
Requires-Dist: jplephem
|
|
30
30
|
Requires-Dist: numexpr
|
|
31
31
|
Requires-Dist: sunpy==5.1.2
|
|
32
|
+
Requires-Dist: sunpy_soar
|
|
32
33
|
Requires-Dist: parfive==2.1.0
|
|
33
34
|
Requires-Dist: pooch
|
|
34
35
|
Requires-Dist: matplotlib
|
|
@@ -39,6 +39,7 @@ from PyThea.modules import (date_and_event_selection, figure_streamlit,
|
|
|
39
39
|
from PyThea.sunpy_dev.map.maputils import get_closest, maps_clims
|
|
40
40
|
from PyThea.utils import (download_fits, load_fits, model_fittings,
|
|
41
41
|
plot_fitting_model, single_imager_maps_process)
|
|
42
|
+
from PyThea.utils_database import get_fits_filenames_from_database
|
|
42
43
|
from PyThea.version import version
|
|
43
44
|
|
|
44
45
|
|
|
@@ -82,7 +83,9 @@ def footer_text():
|
|
|
82
83
|
""")
|
|
83
84
|
st.info('''
|
|
84
85
|
More imaging data have been added:
|
|
85
|
-
- SDO/AIA images from 211A channel
|
|
86
|
+
- SDO/AIA images from 211A channel.
|
|
87
|
+
- PSP/WISPR inner and outer telescope images.
|
|
88
|
+
- SolO/EUI and METIS images.
|
|
86
89
|
''', icon='ℹ️')
|
|
87
90
|
st.warning('''
|
|
88
91
|
**NOTE: From PyThea >0.8.1 the JSON fitting files will be slightly different from the old ones.**
|
|
@@ -197,7 +200,7 @@ def run():
|
|
|
197
200
|
key='imaging_time_range')
|
|
198
201
|
select_timerange_form.form_submit_button(label='Submit',
|
|
199
202
|
on_click=delete_from_state,
|
|
200
|
-
kwargs={'vars': ['map', 'map_', 'imagers_list_']})
|
|
203
|
+
kwargs={'vars': ['map', 'map_', 'imagers_list_', 'hek_responses']})
|
|
201
204
|
|
|
202
205
|
with st.sidebar.expander('Processing Options'):
|
|
203
206
|
procoption_container = st.container()
|
|
@@ -222,32 +225,59 @@ def run():
|
|
|
222
225
|
plotviewopt_container = st.container()
|
|
223
226
|
plotviewopt_container.checkbox('Clip plot on image limits', value=True, key='clip_model')
|
|
224
227
|
plt_supp_imagers = plotviewopt_container.checkbox('Supplementary Imaging', value=False)
|
|
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
|
-
|
|
228
|
+
|
|
229
|
+
#############################################################
|
|
230
|
+
# Magnetic Connectivity
|
|
231
|
+
st.sidebar.markdown('## Overlays')
|
|
232
|
+
with st.sidebar.expander('Bodies or s/c Location'):
|
|
233
|
+
bodies_container = st.container()
|
|
234
|
+
bodies_container.checkbox('View Bodies or s/c', key='star_field')
|
|
235
|
+
bodies_container.multiselect('Select Bodies', options=selected_bodies.bodies_dict.keys(),
|
|
236
|
+
default=['Mercury', 'Venus', 'Jupiter'],
|
|
237
|
+
key='bodies_list',
|
|
238
|
+
disabled=not st.session_state.star_field)
|
|
239
|
+
with st.sidebar.expander('Limb and Meridians'):
|
|
240
|
+
limb_meridians_container = st.container()
|
|
241
|
+
limb_meridians_container.checkbox('View Limb and Meridians', key='plot_solar_reference_lines_')
|
|
242
|
+
markdown = '''
|
|
243
|
+
**Limb**: plots the solar limb as observed
|
|
244
|
+
for the selected observers.
|
|
245
|
+
**Central Meridian**: plots the central meridian
|
|
246
|
+
observed for the selected observers.
|
|
247
|
+
**CR Meridan+Equator**: plots the primary meridian
|
|
248
|
+
and equator of Carrington coordinate system.
|
|
249
|
+
'''.strip()
|
|
250
|
+
limb_meridians_container.selectbox('Select plot option',
|
|
251
|
+
options=['Limb from Obs.', 'Central Meridian from Obs.', 'Carr. Prime Meridian+Solar Equator',
|
|
252
|
+
'Stonyhurst Grid', 'Carrington Grid'],
|
|
253
|
+
help=markdown,
|
|
254
|
+
key='plot_solar_reference_lines_mode',
|
|
255
|
+
disabled=not st.session_state.plot_solar_reference_lines_)
|
|
256
|
+
disabled = False if (st.session_state.plot_solar_reference_lines_) and \
|
|
257
|
+
(st.session_state.plot_solar_reference_lines_mode in ['Limb from Obs.', 'Central Meridian from Obs.']) else True
|
|
258
|
+
limb_meridians_container.multiselect('Select Bodies',
|
|
259
|
+
label_visibility='collapsed',
|
|
260
|
+
options=selected_bodies.bodies_dict.keys(),
|
|
261
|
+
default=['Earth'], disabled=disabled,
|
|
262
|
+
key='plot_solar_reference_lines_bodies_list')
|
|
263
|
+
with st.sidebar.expander('Magnetic Connectivity'):
|
|
264
|
+
connectivity_container = st.container()
|
|
265
|
+
connectivity_container.checkbox('Plot Parker spirals', key='plot_parker_spirals')
|
|
266
|
+
connectivity_container.multiselect('Select bodies/spacecraft', options=selected_bodies.bodies_dict.keys(),
|
|
267
|
+
default=['Earth'], key='mag_bodies_list',
|
|
268
|
+
disabled=not st.session_state.plot_parker_spirals)
|
|
269
|
+
st.session_state.sw_speed_select = {}
|
|
270
|
+
for body in st.session_state.mag_bodies_list:
|
|
271
|
+
connectivity_container.number_input(f'{body} solar wind speed', min_value=200, max_value=800, value=350, step=50,
|
|
272
|
+
key=f'sw_speed_select_{body}',
|
|
273
|
+
disabled=not st.session_state.plot_parker_spirals)
|
|
274
|
+
st.session_state.sw_speed_select[body] = st.session_state[f'sw_speed_select_{body}'] * (u.km/u.second)
|
|
275
|
+
with st.sidebar.expander('HEK feature/events'):
|
|
276
|
+
hek_container = st.container()
|
|
277
|
+
hek_container.checkbox('Plot HEK feature/events', key='plot_hek', on_change=delete_from_state,
|
|
278
|
+
kwargs={'vars': ['hek_responses', ]})
|
|
279
|
+
hek_container.multiselect('Select HEK feature/events', options=['Active Regions', 'Coronal Holes', 'Flares'],
|
|
280
|
+
default=['Flares'], key='hek_list', disabled=not st.session_state.plot_hek)
|
|
251
281
|
|
|
252
282
|
#############################################################
|
|
253
283
|
# Download and Process the Images
|
|
@@ -267,7 +297,15 @@ def run():
|
|
|
267
297
|
if imager not in st.session_state.map_:
|
|
268
298
|
timerange = a.Time(st.session_state.date_process + datetime.timedelta(hours=imaging_time_range[0]),
|
|
269
299
|
st.session_state.date_process + datetime.timedelta(hours=imaging_time_range[1]))
|
|
270
|
-
|
|
300
|
+
|
|
301
|
+
if st.session_state.offline_mode is False:
|
|
302
|
+
downloaded_files = download_fits(timerange, imager)
|
|
303
|
+
elif st.session_state.offline_mode is True:
|
|
304
|
+
progress_bar.desc = f'Load {imager} images from local database.'
|
|
305
|
+
event_id = st.session_state.event_selected.replace('-', '').replace(':', '').replace('|', 'D').replace('.', 'p') \
|
|
306
|
+
+ 'M' + st.session_state.geometrical_model
|
|
307
|
+
downloaded_files = get_fits_filenames_from_database(event_id, timerange, imager)
|
|
308
|
+
|
|
271
309
|
st.session_state.map_[imager] = load_fits(downloaded_files)
|
|
272
310
|
st.session_state.map_[imager] = single_imager_maps_process(st.session_state.map_[imager],
|
|
273
311
|
**selected_imagers.imager_dict[imager]['process'],
|
|
@@ -299,13 +337,14 @@ def run():
|
|
|
299
337
|
col1, col2 = st.columns((1, 3))
|
|
300
338
|
imager_select = col1.selectbox('Select an imager',
|
|
301
339
|
options=st.session_state.imagers_list_,
|
|
302
|
-
on_change=delete_from_state, kwargs={'vars': ['clim', 'clim_manual_low', 'clim_manual_high']})
|
|
340
|
+
on_change=delete_from_state, kwargs={'vars': ['clim', 'clim_manual_low', 'clim_manual_high', 'hek_responses']})
|
|
303
341
|
|
|
304
342
|
maps_date = [getattr(maps, 'date_average', None) or getattr(maps, 'date', None) for maps in st.session_state.map[imager_select]]
|
|
305
343
|
if len(maps_date) > 1:
|
|
306
344
|
running_map_date = col2.select_slider('Slide to the image time',
|
|
307
345
|
options=maps_date, value=maps_date[0],
|
|
308
|
-
key='running_map_date'
|
|
346
|
+
key='running_map_date',
|
|
347
|
+
on_change=delete_from_state, kwargs={'vars': ['hek_responses']})
|
|
309
348
|
else:
|
|
310
349
|
running_map_date = maps_date[0]
|
|
311
350
|
|
|
@@ -368,6 +407,15 @@ def run():
|
|
|
368
407
|
fig, axis = figure_streamlit(st, running_map, image_mode, imager_select, model)
|
|
369
408
|
st.pyplot(fig)
|
|
370
409
|
|
|
410
|
+
if st.session_state.plot_hek and st.session_state.hek_responses['Flares']:
|
|
411
|
+
st.markdown('**HEK Flare List:**')
|
|
412
|
+
st.write(st.session_state.hek_responses['Flares'].to_pandas())
|
|
413
|
+
st.markdown('*Flares with no location have been removed from the table.')
|
|
414
|
+
if st.session_state.plot_hek and st.session_state.hek_responses['Active Regions']:
|
|
415
|
+
st.markdown('**HEK Active Regions List:**')
|
|
416
|
+
st.write(st.session_state.hek_responses['Active Regions'].to_pandas())
|
|
417
|
+
st.markdown('*Active Regions without NOAA number have been removed from the table.')
|
|
418
|
+
|
|
371
419
|
if plt_supp_imagers:
|
|
372
420
|
if len(st.session_state.imagers_list_) < 3:
|
|
373
421
|
other_element = [element for element in st.session_state.imagers_list_ if element != imager_select][0]
|
|
@@ -3,10 +3,24 @@ from sunpy.coordinates import frames
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def load_or_delete_fittings(st):
|
|
6
|
+
"""
|
|
7
|
+
Load or delete fitting parameters from the model fittings based on user selection.
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
st : Streamlit session state object
|
|
12
|
+
Streamlit session state object for managing UI components.
|
|
13
|
+
|
|
14
|
+
Returns
|
|
15
|
+
-------
|
|
16
|
+
None
|
|
17
|
+
"""
|
|
6
18
|
selected_row = str(st.session_state.fitting_select)
|
|
7
19
|
dataframe = st.session_state.model_fittings.parameters
|
|
20
|
+
|
|
8
21
|
if st.session_state.fit_action == 'Select':
|
|
9
22
|
pass
|
|
23
|
+
|
|
10
24
|
elif st.session_state.fit_action == 'Load':
|
|
11
25
|
if st.session_state.coord_system == 'HGS':
|
|
12
26
|
st.session_state.longit = float(dataframe.loc[selected_row, 'hgln'])
|
|
@@ -27,6 +41,7 @@ def load_or_delete_fittings(st):
|
|
|
27
41
|
# del st.session_state[key]
|
|
28
42
|
st.session_state[key] = float(dataframe.loc[selected_row, key])
|
|
29
43
|
del st.session_state.fit_action
|
|
44
|
+
|
|
30
45
|
elif st.session_state.fit_action == 'Delete':
|
|
31
46
|
st.session_state.model_fittings.parameters = dataframe.drop(st.session_state.fitting_select)
|
|
32
47
|
del st.session_state.fitting_select
|
|
@@ -36,6 +51,18 @@ def load_or_delete_fittings(st):
|
|
|
36
51
|
|
|
37
52
|
|
|
38
53
|
def change_long_lat_sliders(st):
|
|
54
|
+
"""
|
|
55
|
+
Update longitude and latitude sliders based on the selected coordinate system.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
st : Streamlit session state object
|
|
60
|
+
Streamlit session state object for managing UI components.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
None
|
|
65
|
+
"""
|
|
39
66
|
if st.session_state.coord_system == 'HGS':
|
|
40
67
|
center_ = st.session_state.center.transform_to(frames.HeliographicStonyhurst)
|
|
41
68
|
elif st.session_state.coord_system == 'HGC':
|
|
@@ -46,9 +73,22 @@ def change_long_lat_sliders(st):
|
|
|
46
73
|
|
|
47
74
|
|
|
48
75
|
def change_fitting_sliders(st):
|
|
76
|
+
"""
|
|
77
|
+
Update fitting sliders based on the selected fitting method.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
st : Streamlit session state object
|
|
82
|
+
Streamlit session state object for managing UI components.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
None
|
|
87
|
+
"""
|
|
49
88
|
st.session_state.startup['fitting'] = False
|
|
50
89
|
fit_opt = st.session_state.fit_args_prime
|
|
51
90
|
st.session_state.fit_mode = fit_opt['type']
|
|
91
|
+
|
|
52
92
|
if fit_opt['type'] == 'polynomial':
|
|
53
93
|
st.session_state.polyfit_order = fit_opt['order']
|
|
54
94
|
elif fit_opt['type'] == 'spline':
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
'''
|
|
6
6
|
import astropy.units as u
|
|
7
|
+
import sunpy_soar # noqa
|
|
7
8
|
from sunpy.net import attrs as a
|
|
8
9
|
|
|
9
10
|
imager_dict = {}
|
|
@@ -63,3 +64,19 @@ imager_dict['HI2A'] = {'fido': (a.Source('STEREO_A'), a.Detector.hi2),
|
|
|
63
64
|
imager_dict['HI2B'] = {'fido': (a.Source('STEREO_B'), a.Detector.hi2),
|
|
64
65
|
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'superpixel': 2},
|
|
65
66
|
'source': 'STEREO_B', 'instrument': 'SECCHI', 'detector': 'HI2'}
|
|
67
|
+
|
|
68
|
+
imager_dict['WISPR1'] = {'fido': (a.Instrument.wispr, a.Detector.inner),
|
|
69
|
+
'process': {'dimensions': (960*u.pixel, 1024*u.pixel), 'processing_level': 3, 'superpixel': 2},
|
|
70
|
+
'source': 'PSP', 'instrument': 'WISPR', 'detector': 'Inner'}
|
|
71
|
+
|
|
72
|
+
imager_dict['WISPR2'] = {'fido': (a.Instrument.wispr, a.Detector.outer),
|
|
73
|
+
'process': {'dimensions': (960*u.pixel, 1024*u.pixel), 'processing_level': 3, 'superpixel': 2},
|
|
74
|
+
'source': 'PSP', 'instrument': 'WISPR', 'detector': 'Outer'}
|
|
75
|
+
|
|
76
|
+
imager_dict['EUI-FSI'] = {'fido': (a.Instrument('EUI'), a.soar.Product('EUI-FSI174-IMAGE'), a.Level(2)),
|
|
77
|
+
'process': {'superpixel': 1},
|
|
78
|
+
'source': 'SOLO', 'instrument': 'EUI-FSI', 'wavelength': '174'}
|
|
79
|
+
|
|
80
|
+
imager_dict['METIS'] = {'fido': (a.Instrument('METIS'), a.soar.Product('METIS-VL-TB'), a.Level(2)),
|
|
81
|
+
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'superpixel': 2},
|
|
82
|
+
'source': 'SOLO', 'instrument': 'METIS', 'detector': 'VLD', 'wavelength': 'TB'}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from pathlib import Path
|
|
3
2
|
|
|
4
3
|
import pooch
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
from PyThea.config import database_dir_default
|
|
6
|
+
|
|
7
7
|
github_main_url = 'https://github.com/AthKouloumvakos/PyThea-sample-data'
|
|
8
8
|
|
|
9
9
|
aia_sample_data = pooch.create(
|
|
10
|
-
path=os.path.join(
|
|
10
|
+
path=os.path.join(database_dir_default, 'sample_data'), # The cache folder
|
|
11
11
|
base_url=f'{github_main_url}/raw/main/data/', # The remote data url on Github
|
|
12
12
|
registry={
|
|
13
13
|
'aia_lev1_1600a_2012_06_06t04_07_29_12z_image_lev1.fits': 'sha256:7e88d8a277ad3dd111c1bcff3c3936d6d5ef5186e05b4bfa7749ee43c05577d5',
|
|
@@ -16,7 +16,7 @@ aia_sample_data = pooch.create(
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
stereo_sample_data = pooch.create(
|
|
19
|
-
path=os.path.join(
|
|
19
|
+
path=os.path.join(database_dir_default, 'sample_data'), # The cache folder
|
|
20
20
|
base_url=f'{github_main_url}/raw/main/data/', # The remote data url on Github
|
|
21
21
|
registry={
|
|
22
22
|
'20120622_235400_d4c2a.fts': 'sha256:940680fe8bea754c9859170585d8299b9b049b631155435a31ecacf5b702d9cf',
|
|
@@ -26,8 +26,17 @@ stereo_sample_data = pooch.create(
|
|
|
26
26
|
},
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
+
wispr_sample_data = pooch.create(
|
|
30
|
+
path=os.path.join(database_dir_default, 'sample_data'), # The cache folder
|
|
31
|
+
base_url=f'{github_main_url}/raw/main/data/', # The remote data url on Github
|
|
32
|
+
registry={
|
|
33
|
+
'psp_l3_wispr_20210808t103707_v1_1211.fits': 'sha256:85035693c4677e8fa8a3e61b8051d6f0a46e96806b5b0cbdb3efa77652308bda',
|
|
34
|
+
'psp_l3_wispr_20210808t104010_v1_2222.fits': 'sha256:5e55e17f1aed7dc96f88b79f092947c58e6ee0def1b72822dbf1a696d8df7e6f'
|
|
35
|
+
},
|
|
36
|
+
)
|
|
37
|
+
|
|
29
38
|
json_fitting_file_sample_data = pooch.create(
|
|
30
|
-
path=os.path.join(
|
|
39
|
+
path=os.path.join(database_dir_default, 'sample_data'), # The cache folder
|
|
31
40
|
base_url=f'{github_main_url}/raw/main/data/', # The remote data url on Github
|
|
32
41
|
registry={
|
|
33
42
|
'FLX1p0D20211028T153500MEllipsoid.json': 'sha256:34fced8530875110117ba27a73541d3acd0c90bc8fca99367c1ec4cdfc05ce86',
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import astropy.units as u
|
|
2
|
+
import numpy as np
|
|
3
|
+
from astropy.coordinates import SkyCoord
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def spiral(pos, sw_speed, date, omega=360. * u.degree / (25.38 * 24 * 60 * 60 * u.second)):
|
|
7
|
+
"""
|
|
8
|
+
Calculates the Parker spiral coordinates based on the input position, solar wind speed, and date.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
pos : astropy.coordinates.SkyCoord
|
|
13
|
+
The initial position in heliographic Carrington coordinates.
|
|
14
|
+
sw_speed : astropy.units.Quantity
|
|
15
|
+
The solar wind speed (should be in velocity units, e.g., km/s).
|
|
16
|
+
date : astropy.time.Time
|
|
17
|
+
The observation time.
|
|
18
|
+
omega : astropy.units.Quantity, optional
|
|
19
|
+
The solar rotation rate in radians per second (default is sidereal period).
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
astropy.coordinates.SkyCoord
|
|
24
|
+
The calculated spiral coordinates in heliographic Carrington coordinates.
|
|
25
|
+
"""
|
|
26
|
+
r = np.arange(1, pos.radius.to_value(u.R_sun), 0.1)
|
|
27
|
+
r = np.append(r, pos.radius.to_value(u.R_sun)) * u.R_sun
|
|
28
|
+
alpha = omega * ((pos.radius - r) / sw_speed)
|
|
29
|
+
hg_coord = SkyCoord(pos.lon + alpha, pos.lat, r,
|
|
30
|
+
frame='heliographic_carrington',
|
|
31
|
+
observer='earth',
|
|
32
|
+
obstime=date)
|
|
33
|
+
return hg_coord
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def footpoint(pos, sw_speed, date, r=1*u.R_sun, omega=360. * u.degree / (25.38 * 24 * 60 * 60 * u.second)):
|
|
37
|
+
"""
|
|
38
|
+
Calculates the footpoint location based on the input position, solar wind speed, and date.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
pos : astropy.coordinates.SkyCoord
|
|
43
|
+
The initial position in heliographic Carrington coordinates.
|
|
44
|
+
sw_speed : astropy.units.Quantity
|
|
45
|
+
The solar wind speed (should be in velocity units, e.g., km/s).
|
|
46
|
+
date : astropy.time.Time
|
|
47
|
+
The observation time.
|
|
48
|
+
r : astropy.units.Quantity, optional
|
|
49
|
+
The radial distance for the footpoint (default is 1 solar radius).
|
|
50
|
+
omega : astropy.units.Quantity, optional
|
|
51
|
+
The solar rotation rate in radians per second (default is 2.7e-6 rad/s).
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
astropy.coordinates.SkyCoord
|
|
56
|
+
The calculated footpoint coordinates in heliographic Carrington coordinates.
|
|
57
|
+
"""
|
|
58
|
+
alpha = omega * ((pos.radius - r) / sw_speed)
|
|
59
|
+
hg_coord = SkyCoord(pos.lon + alpha, pos.lat, r,
|
|
60
|
+
frame='heliographic_carrington',
|
|
61
|
+
observer='earth', obstime=date)
|
|
62
|
+
return hg_coord
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import astropy.units as u
|
|
2
|
+
from sunpy.coordinates import frames, get_horizons_coord
|
|
3
|
+
|
|
4
|
+
from PyThea.config.selected_bodies import bodies_dict
|
|
5
|
+
from PyThea.extensions import Parker_spirals
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def plot_parker_spiral(axis, map, bodies, sw_speed=350 * (u.km / u.second)):
|
|
9
|
+
"""
|
|
10
|
+
Plot Parker spiral for specified bodies on the given map axis.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
axis : matplotlib.axes.Axes
|
|
15
|
+
The axis on which to plot the Parker spiral.
|
|
16
|
+
map : sunpy.map.Map
|
|
17
|
+
The solar map on which the Parker spiral will be plotted.
|
|
18
|
+
bodies : list of str
|
|
19
|
+
List of bodies for which to plot the Parker spiral.
|
|
20
|
+
sw_speed : Quantity, optional
|
|
21
|
+
Solar wind speed for the Parker spiral (default: 350 km/s).
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
None
|
|
26
|
+
"""
|
|
27
|
+
for body in bodies:
|
|
28
|
+
pos = get_horizons_coord(bodies_dict[body][0], map.date_average, 'id')
|
|
29
|
+
pos = pos.transform_to(frames.HeliographicCarrington(observer='Earth', obstime=map.date_average))
|
|
30
|
+
|
|
31
|
+
spiral_coord = Parker_spirals.spiral(pos, sw_speed[body], map.date_average)
|
|
32
|
+
|
|
33
|
+
hpc_frame = frames.Helioprojective(observer=map.observer_coordinate, obstime=map.date_average)
|
|
34
|
+
|
|
35
|
+
spiral_coord_visible_index = spiral_coord.transform_to(hpc_frame).is_visible()
|
|
36
|
+
|
|
37
|
+
axis.plot_coord(spiral_coord[spiral_coord_visible_index], markersize=0, linewidth=1, color=bodies_dict[body][1])
|
|
38
|
+
if spiral_coord_visible_index[1]:
|
|
39
|
+
axis.plot_coord(spiral_coord[0], markersize=16, linewidth=10, marker='+', color=bodies_dict[body][1])
|
|
40
|
+
else:
|
|
41
|
+
axis.plot_coord(spiral_coord[0], markersize=16, linewidth=10, marker='+', color='white')
|
|
42
|
+
|
|
43
|
+
axis.plot_coord(spiral_coord[0], markersize=3, linewidth=4, marker='s', color=bodies_dict[body][1])
|
|
44
|
+
|
|
45
|
+
axis.plot_coord(spiral_coord[-1], markersize=8, linewidth=6, marker='x', color=bodies_dict[body][1])
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import astropy.units as u
|
|
2
|
+
import numpy as np
|
|
3
|
+
from astropy.coordinates import SkyCoord
|
|
4
|
+
from astropy.time import Time, TimeDelta
|
|
5
|
+
from sunpy.coordinates import frames
|
|
6
|
+
from sunpy.net import attrs as a
|
|
7
|
+
from sunpy.net import hek
|
|
8
|
+
from sunpy.physics.differential_rotation import solar_rotate_coordinate
|
|
9
|
+
from sunpy.time import parse_time
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def plot_hek(axis, map, mode, time_range=[-2, 2], hek_responses=None):
|
|
13
|
+
"""
|
|
14
|
+
Plots HEK (Heliophysics Event Knowledgebase) events on a given axis.
|
|
15
|
+
|
|
16
|
+
This function fetches and plots HEK events, such as Active Regions, Coronal Holes, or Flares, on a provided
|
|
17
|
+
matplotlib axis using data from a SunPy map object.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
axis : matplotlib.axes._subplots.AxesSubplot
|
|
22
|
+
The matplotlib axis to plot on.
|
|
23
|
+
map : sunpy.map.Map
|
|
24
|
+
The SunPy map object containing the data.
|
|
25
|
+
mode : str
|
|
26
|
+
The type of HEK events to plot ('Active Regions', 'Coronal Holes', or 'Flares').
|
|
27
|
+
time_range : list, optional
|
|
28
|
+
Time range in hours around the map date to search for events (default is [-2, 2]).
|
|
29
|
+
hek_responses : dict, optional
|
|
30
|
+
Pre-fetched HEK responses (default is None).
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
responses: list
|
|
35
|
+
The list of HEK event responses.
|
|
36
|
+
"""
|
|
37
|
+
hek_client = hek.HEKClient()
|
|
38
|
+
start_time = map.date_average + TimeDelta(time_range[0] * u.hour)
|
|
39
|
+
end_time = map.date_average + TimeDelta(time_range[1] * u.hour)
|
|
40
|
+
|
|
41
|
+
if mode == 'Active Regions':
|
|
42
|
+
if hek_responses is None or not hek_responses['Active Regions']:
|
|
43
|
+
responses = hek_client.search(a.Time(start_time, end_time),
|
|
44
|
+
a.hek.AR, a.hek.FRM.Name == 'HMI SHARP')
|
|
45
|
+
|
|
46
|
+
responses.keep_columns(['ar_noaanum', 'ar_mcintoshcls', 'ar_mtwilsoncls', 'hgs_x', 'hgs_y', 'event_starttime'])
|
|
47
|
+
indx = [i for i, x in enumerate(responses['ar_noaanum']) if x is None]
|
|
48
|
+
responses.remove_rows(indx)
|
|
49
|
+
responses = responses[['ar_noaanum', 'ar_mcintoshcls', 'ar_mtwilsoncls', 'hgs_x', 'hgs_y', 'event_starttime']]
|
|
50
|
+
dates = Time(responses['event_starttime'])
|
|
51
|
+
time_diff = np.abs(dates - map.date_average)
|
|
52
|
+
time_diff_seconds = np.array([td.sec for td in time_diff])
|
|
53
|
+
if len(np.unique(time_diff_seconds)) > 1:
|
|
54
|
+
responses.remove_rows(np.where(time_diff_seconds == np.max(time_diff_seconds)))
|
|
55
|
+
|
|
56
|
+
responses_ = hek_client.search(a.Time(start_time, end_time),
|
|
57
|
+
a.hek.AR, a.hek.FRM.Name == 'NOAA SWPC Observer')
|
|
58
|
+
responses_.keep_columns(['ar_noaanum', 'ar_mcintoshcls', 'ar_mtwilsoncls', 'hgs_x', 'hgs_y'])
|
|
59
|
+
|
|
60
|
+
responses['ar_mcintoshcls'] = np.full(responses['ar_noaanum'].shape[0], None)
|
|
61
|
+
responses['ar_mtwilsoncls'] = np.full(responses['ar_noaanum'].shape[0], None)
|
|
62
|
+
|
|
63
|
+
for rn, clm, clw in zip(responses_['ar_noaanum'], responses_['ar_mcintoshcls'], responses_['ar_mtwilsoncls']):
|
|
64
|
+
i = np.argwhere(responses['ar_noaanum'] == rn)
|
|
65
|
+
responses['ar_mcintoshcls'][i] = clm
|
|
66
|
+
responses['ar_mtwilsoncls'][i] = clw
|
|
67
|
+
print(responses)
|
|
68
|
+
else:
|
|
69
|
+
responses = hek_responses['Active Regions']
|
|
70
|
+
|
|
71
|
+
for i, response in enumerate(responses):
|
|
72
|
+
axis.annotate(i, (float(response['hgs_x']), float(response['hgs_y'])),
|
|
73
|
+
xytext=(float(response['hgs_x']), float(response['hgs_y'])),
|
|
74
|
+
xycoords=axis.get_transform('heliographic_stonyhurst'),
|
|
75
|
+
backgroundcolor='none',
|
|
76
|
+
color='tab:blue',
|
|
77
|
+
fontsize=8,
|
|
78
|
+
horizontalalignment='center', verticalalignment='center')
|
|
79
|
+
elif mode == 'Coronal Holes':
|
|
80
|
+
if hek_responses is None or not hek_responses['Coronal Holes']:
|
|
81
|
+
responses = hek_client.search(a.Time(start_time, end_time),
|
|
82
|
+
a.hek.CH, a.hek.FRM.Name == 'SPoCA')
|
|
83
|
+
else:
|
|
84
|
+
responses = hek_responses['Coronal Holes']
|
|
85
|
+
|
|
86
|
+
for response in responses:
|
|
87
|
+
p1 = response['hpc_boundcc'][9:-2]
|
|
88
|
+
p2 = p1.split(',')
|
|
89
|
+
p3 = [v.split(' ') for v in p2]
|
|
90
|
+
ch_date = parse_time(response['event_starttime'])
|
|
91
|
+
ch_boundary = SkyCoord(
|
|
92
|
+
[(float(v[0]), float(v[1])) * u.arcsec for v in p3],
|
|
93
|
+
obstime=ch_date, observer='earth',
|
|
94
|
+
frame=frames.Helioprojective)
|
|
95
|
+
rotated_ch_boundary = solar_rotate_coordinate(ch_boundary, time=map.date_average)
|
|
96
|
+
axis.plot_coord(rotated_ch_boundary, color='c')
|
|
97
|
+
elif mode == 'Flares':
|
|
98
|
+
if hek_responses is None or not hek_responses['Flares']:
|
|
99
|
+
responses = hek_client.search(a.Time(start_time, end_time),
|
|
100
|
+
a.hek.FL, a.hek.FRM.Name == 'SWPC')
|
|
101
|
+
responses.keep_columns(['event_starttime', 'event_peaktime', 'fl_goescls', 'hgs_x', 'hgs_y', 'ar_noaanum'])
|
|
102
|
+
responses.remove_rows(np.where((responses['hgs_x'] == 0) & (responses['hgs_y'] == 0)))
|
|
103
|
+
responses = responses[['event_starttime', 'event_peaktime', 'fl_goescls', 'hgs_x', 'hgs_y', 'ar_noaanum']]
|
|
104
|
+
else:
|
|
105
|
+
responses = hek_responses['Flares']
|
|
106
|
+
|
|
107
|
+
for i, response in enumerate(responses):
|
|
108
|
+
axis.annotate(i, (float(response['hgs_x']), float(response['hgs_y'])),
|
|
109
|
+
xytext=(float(response['hgs_x']), float(response['hgs_y'])),
|
|
110
|
+
xycoords=axis.get_transform('heliographic_stonyhurst'),
|
|
111
|
+
backgroundcolor='none',
|
|
112
|
+
color='tab:red',
|
|
113
|
+
fontsize=8,
|
|
114
|
+
horizontalalignment='center', verticalalignment='center')
|
|
115
|
+
else:
|
|
116
|
+
raise ValueError(f"Unsupported mode: {mode}. Use 'Coronal Holes' or 'Flares'.")
|
|
117
|
+
|
|
118
|
+
return responses
|