PyThea 1.2.0__tar.gz → 1.3.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-1.2.0 → pythea-1.3.0}/CHANGELOG.md +15 -1
- {pythea-1.2.0 → pythea-1.3.0}/PKG-INFO +4 -4
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/PyThea_app.py +112 -14
- pythea-1.3.0/PyThea/_version.py +24 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/config/selected_imagers.py +26 -20
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/geometrical_models.py +4 -5
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/modules.py +14 -4
- pythea-1.3.0/PyThea/sunpy_dev/net/dataretriever/__init__.py +0 -0
- pythea-1.3.0/PyThea/sunpy_dev/net/dataretriever/sources/__init__.py +0 -0
- pythea-1.3.0/PyThea/sunpy_dev/net/dataretriever/sources/lasco.py +87 -0
- pythea-1.3.0/PyThea/sunpy_dev/net/dataretriever/sources/stereo.py +100 -0
- pythea-1.3.0/PyThea/test/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/utils.py +30 -28
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/utils_database.py +3 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea.egg-info/PKG-INFO +4 -4
- {pythea-1.2.0 → pythea-1.3.0}/PyThea.egg-info/SOURCES.txt +5 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea.egg-info/requires.txt +1 -1
- {pythea-1.2.0 → pythea-1.3.0}/pyproject.toml +3 -3
- pythea-1.2.0/PyThea/_version.py +0 -34
- {pythea-1.2.0 → pythea-1.3.0}/.flake8 +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/.readthedocs.yaml +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/LICENSE.md +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/MANIFEST.in +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/callbacks.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/config/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/config/app_styles.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/config/config_sliders.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/config/selected_bodies.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/data/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/data/sample_data.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/extensions/LICENSE_gcs_python.md +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/extensions/Parker_spirals/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/extensions/Parker_spirals/utils.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/extensions/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/extensions/buttons.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/extensions/hek/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/extensions/hek/utils.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/pythea_cli.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/extern/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/extern/sunkit_instruments/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/extern/sunkit_instruments/aia/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/extern/sunkit_instruments/aia/utils.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/extern/sunkit_instruments/lasco/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/extern/sunkit_instruments/lasco/utils.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/extern/sunkit_instruments/stereo/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/extern/sunkit_instruments/stereo/utils.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/map/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/sunpy_dev/map/maputils.py +0 -0
- {pythea-1.2.0/PyThea/test → pythea-1.3.0/PyThea/sunpy_dev/net}/__init__.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/Pythea_test.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/conftest.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/figure_hashes.json +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/test_extension_utils.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/test_figures.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/test_geometrical_models.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/test_imports.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/test_remote_clients.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/test/test_utils.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea/version.py +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea.egg-info/.DS_Store +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea.egg-info/dependency_links.txt +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea.egg-info/entry_points.txt +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea.egg-info/not-zip-safe +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/PyThea.egg-info/top_level.txt +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/README.md +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/README_pypi.md +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/pytest.ini +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/setup.cfg +0 -0
- {pythea-1.2.0 → pythea-1.3.0}/setup.py +0 -0
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
# v1.
|
|
1
|
+
# v1.3.0 (12-Feb-2025)
|
|
2
|
+
|
|
3
|
+
## Features
|
|
4
|
+
- Extend net sources for selected imagers
|
|
5
|
+
- Adds a method to manually import fits files from folder
|
|
6
|
+
|
|
7
|
+
## Minor Changes
|
|
8
|
+
- Updates dependences with sunpy>=7.1.2
|
|
9
|
+
|
|
10
|
+
## Bug Fixes
|
|
11
|
+
- Fixes a bug with figure creation
|
|
12
|
+
- Fixes a bug with kinematic plots
|
|
13
|
+
- Guard against uninitialized variables
|
|
14
|
+
|
|
15
|
+
# v1.2.0 (12-Feb-2025)
|
|
2
16
|
|
|
3
17
|
## Minor Changes
|
|
4
18
|
- Change installation to pyproject.toml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyThea
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: PyThea: A software package to reconstruct the 3D structure of CMEs and shock waves
|
|
5
5
|
Author-email: Athanasios Kouloumvakos <athkouloumvakos@gmail.com>
|
|
6
6
|
License:
|
|
@@ -662,17 +662,17 @@ Keywords: science,solar physics,solar,coronal mass ejections,shock waves,EUV wav
|
|
|
662
662
|
Platform: any
|
|
663
663
|
Classifier: Programming Language :: Python
|
|
664
664
|
Classifier: Programming Language :: Python :: 3
|
|
665
|
-
Classifier: Programming Language :: Python :: 3.
|
|
665
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
666
666
|
Classifier: Development Status :: 5 - Production/Stable
|
|
667
667
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
668
668
|
Classifier: Operating System :: OS Independent
|
|
669
669
|
Classifier: Intended Audience :: Science/Research
|
|
670
670
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
671
671
|
Provides: PyThea
|
|
672
|
-
Requires-Python: >=3.
|
|
672
|
+
Requires-Python: >=3.12
|
|
673
673
|
Description-Content-Type: text/markdown
|
|
674
674
|
License-File: LICENSE.md
|
|
675
|
-
Requires-Dist: sunpy>=7.
|
|
675
|
+
Requires-Dist: sunpy>=7.1.2
|
|
676
676
|
Requires-Dist: pandas
|
|
677
677
|
Requires-Dist: scipy
|
|
678
678
|
Requires-Dist: matplotlib
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
import datetime
|
|
22
|
-
|
|
22
|
+
import glob
|
|
23
|
+
import os
|
|
24
|
+
from copy import deepcopy
|
|
23
25
|
|
|
24
26
|
import astropy.units as u
|
|
25
27
|
import numpy as np
|
|
@@ -49,11 +51,34 @@ def delete_from_state(vars):
|
|
|
49
51
|
del st.session_state[var]
|
|
50
52
|
|
|
51
53
|
|
|
54
|
+
def call_extend_sources(instrument):
|
|
55
|
+
for imager in selected_imagers.providers[instrument]['imagers']:
|
|
56
|
+
st.session_state.selected_imagers_[imager]['fido'][2] = a.Provider(st.session_state[f'provider_{instrument}'])
|
|
57
|
+
|
|
58
|
+
|
|
52
59
|
def highlight_row(row, row_index):
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
try:
|
|
61
|
+
if not len(row_index):
|
|
62
|
+
return ['']*len(row)
|
|
63
|
+
if row.name.strftime('%Y-%m-%dT%H:%M:%S.%f') == row_index.strftime('%Y-%m-%dT%H:%M:%S.%f').values[0]:
|
|
64
|
+
return ['background-color: lightpink']*len(row)
|
|
65
|
+
except (IndexError, AttributeError):
|
|
66
|
+
pass
|
|
67
|
+
return ['']*len(row)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def clear_text_input():
|
|
71
|
+
st.session_state['manual_dir'] = st.session_state['manual_dir_text']
|
|
72
|
+
st.session_state['manual_dir_text'] = ''
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def list_fits_files(directory):
|
|
76
|
+
"""Returns a list of .fits and .fts file paths from the selected directory."""
|
|
77
|
+
if directory:
|
|
78
|
+
fits_files = glob.glob(os.path.join(directory, '*.fits')) + \
|
|
79
|
+
glob.glob(os.path.join(directory, '*.fts'))
|
|
80
|
+
return fits_files
|
|
81
|
+
return []
|
|
57
82
|
|
|
58
83
|
|
|
59
84
|
def footer_text():
|
|
@@ -81,6 +106,10 @@ def footer_text():
|
|
|
81
106
|
st.markdown("""
|
|
82
107
|
**Citation**: Please cite the following paper [](https://www.frontiersin.org/articles/10.3389/fspas.2022.974137/) and [](https://doi.org/10.5281/zenodo.5713659)
|
|
83
108
|
""")
|
|
109
|
+
st.success('''
|
|
110
|
+
**Don't miss these new features:**
|
|
111
|
+
- Import .fits files from folder.
|
|
112
|
+
''', icon='ℹ️')
|
|
84
113
|
st.info('''
|
|
85
114
|
More imaging data have been added:
|
|
86
115
|
- SDO/AIA images from 211A channel.
|
|
@@ -118,6 +147,8 @@ def run():
|
|
|
118
147
|
#############################################################
|
|
119
148
|
# Startup Variables
|
|
120
149
|
if 'startup' not in st.session_state:
|
|
150
|
+
from PyThea.sunpy_dev.net.dataretriever.sources import lasco # noqa
|
|
151
|
+
from PyThea.sunpy_dev.net.dataretriever.sources import stereo # noqa
|
|
121
152
|
st.session_state.startup = {'fitting': True}
|
|
122
153
|
|
|
123
154
|
#############################################################
|
|
@@ -125,6 +156,29 @@ def run():
|
|
|
125
156
|
|
|
126
157
|
if 'date_process' not in st.session_state:
|
|
127
158
|
date_and_event_selection(st)
|
|
159
|
+
if 'selected_imagers_' not in st.session_state:
|
|
160
|
+
st.session_state.selected_imagers_ = deepcopy(selected_imagers.imager_dict)
|
|
161
|
+
|
|
162
|
+
st.sidebar.toggle('Change default data providers',
|
|
163
|
+
value=False,
|
|
164
|
+
help='Change data provider if you face issues or data are missing.',
|
|
165
|
+
key='extend_net_sources')
|
|
166
|
+
if st.session_state.extend_net_sources:
|
|
167
|
+
container = st.sidebar.container(border=True)
|
|
168
|
+
container.text('Select provider',
|
|
169
|
+
help='The default providers (left) use VSO to download data.')
|
|
170
|
+
for instrument in selected_imagers.providers.keys():
|
|
171
|
+
# container.text(f'{selected_imagers.imager_dict[prov]["source"]}')
|
|
172
|
+
col1, col2 = container.columns([0.3, 0.7], vertical_alignment='center')
|
|
173
|
+
col1.markdown(f'{instrument}:')
|
|
174
|
+
col2.segmented_control(f'{instrument}:',
|
|
175
|
+
options=selected_imagers.providers[instrument]['providers'],
|
|
176
|
+
selection_mode='single',
|
|
177
|
+
default=selected_imagers.providers[instrument]['providers'][0],
|
|
178
|
+
on_change=call_extend_sources,
|
|
179
|
+
args=[instrument],
|
|
180
|
+
key=f'provider_{instrument}',
|
|
181
|
+
label_visibility='collapsed')
|
|
128
182
|
else:
|
|
129
183
|
st.sidebar.markdown('## Processing Event|Date:')
|
|
130
184
|
st.sidebar.info(f'{st.session_state.event_selected}')
|
|
@@ -163,6 +217,8 @@ def run():
|
|
|
163
217
|
long_val = [0., 360.]
|
|
164
218
|
elif st.session_state.coord_system == 'HGS':
|
|
165
219
|
long_val = [-180., 180.]
|
|
220
|
+
else:
|
|
221
|
+
raise ValueError(f"Unsupported coordinate system: '{st.session_state.coord_system}'. Expected 'HGC' or 'HGS'.")
|
|
166
222
|
|
|
167
223
|
longit = st.sidebar.slider(f'{st.session_state.coord_system} \
|
|
168
224
|
Longitude [deg.]:',
|
|
@@ -180,7 +236,6 @@ def run():
|
|
|
180
236
|
|
|
181
237
|
fitting_sliders(st)
|
|
182
238
|
|
|
183
|
-
col1, col3, col2 = st.sidebar.columns(3)
|
|
184
239
|
store_fit_button_pressed = st.sidebar.button('Store Fit')
|
|
185
240
|
|
|
186
241
|
#############################################################
|
|
@@ -189,7 +244,7 @@ def run():
|
|
|
189
244
|
with st.sidebar.expander('Download Options'):
|
|
190
245
|
select_imagers_form = st.form(key='select_imagers_form', border=False)
|
|
191
246
|
imagers_list = select_imagers_form.multiselect('Select Imagers',
|
|
192
|
-
options=
|
|
247
|
+
options=st.session_state.selected_imagers_.keys(),
|
|
193
248
|
default=['LC2', 'LC3', 'COR2A'],
|
|
194
249
|
key='imagers_list')
|
|
195
250
|
select_imagers_form.form_submit_button(label='Submit', use_container_width=True)
|
|
@@ -203,6 +258,37 @@ def run():
|
|
|
203
258
|
kwargs={'vars': ['map', 'map_', 'imagers_list_', 'hek_responses']},
|
|
204
259
|
use_container_width=True)
|
|
205
260
|
|
|
261
|
+
# Import Imagers Manually
|
|
262
|
+
select_imager_manual_form = st.container()
|
|
263
|
+
if 'manual_dir' not in st.session_state:
|
|
264
|
+
st.session_state['manual_dir'] = ''
|
|
265
|
+
|
|
266
|
+
imager_manual = select_imager_manual_form.selectbox('Select an imager for manual import',
|
|
267
|
+
options={key for key in st.session_state.selected_imagers_.keys() if not key.endswith('m')})
|
|
268
|
+
select_imager_manual_form.text_input('Enter path containing the .fits files',
|
|
269
|
+
key='manual_dir_text', on_change=clear_text_input)
|
|
270
|
+
|
|
271
|
+
if st.session_state.manual_dir:
|
|
272
|
+
if os.path.isdir(st.session_state.manual_dir):
|
|
273
|
+
fits_files = list_fits_files(st.session_state.manual_dir)
|
|
274
|
+
if fits_files:
|
|
275
|
+
st.session_state.selected_imagers_[f'{imager_manual}m'] = deepcopy(st.session_state.selected_imagers_[imager_manual])
|
|
276
|
+
st.session_state.selected_imagers_[f'{imager_manual}m']['fido'] = {
|
|
277
|
+
'path': st.session_state.manual_dir,
|
|
278
|
+
'fits_files': fits_files}
|
|
279
|
+
st.session_state['manual_dir'] = ''
|
|
280
|
+
st.rerun()
|
|
281
|
+
else:
|
|
282
|
+
select_imager_manual_form.warning('No FITS files found in the selected directory.')
|
|
283
|
+
else:
|
|
284
|
+
select_imager_manual_form.error('Invalid directory. Please enter a valid folder path.')
|
|
285
|
+
st.session_state['manual_dir'] = ''
|
|
286
|
+
|
|
287
|
+
filtered_imager_dict = [key for key in st.session_state.selected_imagers_.keys() if key.endswith('m')]
|
|
288
|
+
if filtered_imager_dict:
|
|
289
|
+
formatted_list = ', '.join(filtered_imager_dict)
|
|
290
|
+
select_imager_manual_form.success(f'Imagers available for manual import: {formatted_list}')
|
|
291
|
+
|
|
206
292
|
with st.sidebar.expander('Processing Options'):
|
|
207
293
|
procoption_container = st.container()
|
|
208
294
|
if 'imagers_list_' not in st.session_state:
|
|
@@ -294,13 +380,17 @@ def run():
|
|
|
294
380
|
st.session_state['imagers_list_'] = imagers_list
|
|
295
381
|
progress_bar = st.progress(0, text='Preparing to Download data')
|
|
296
382
|
for i, imager in enumerate(imager_added):
|
|
297
|
-
progress_bar.progress(i/len(imager_added), text=f'Download {imager} images from VSO')
|
|
383
|
+
progress_bar.progress((i + 1)/len(imager_added), text=f'Download {imager} images from VSO')
|
|
298
384
|
if imager not in st.session_state.map_:
|
|
299
385
|
timerange = a.Time(st.session_state.date_process + datetime.timedelta(hours=imaging_time_range[0]),
|
|
300
386
|
st.session_state.date_process + datetime.timedelta(hours=imaging_time_range[1]))
|
|
301
387
|
|
|
302
388
|
if st.session_state.offline_mode is False:
|
|
303
|
-
|
|
389
|
+
if imager[-1] != 'm':
|
|
390
|
+
downloaded_files = download_fits(timerange, imager,
|
|
391
|
+
imager_dict=st.session_state.selected_imagers_)
|
|
392
|
+
else:
|
|
393
|
+
downloaded_files = st.session_state.selected_imagers_[imager]['fido']['fits_files']
|
|
304
394
|
elif st.session_state.offline_mode is True:
|
|
305
395
|
progress_bar.desc = f'Load {imager} images from local database.'
|
|
306
396
|
event_id = st.session_state.event_selected.replace('-', '').replace(':', '').replace('|', 'D').replace('.', 'p') \
|
|
@@ -309,7 +399,7 @@ def run():
|
|
|
309
399
|
|
|
310
400
|
st.session_state.map_[imager] = load_fits(downloaded_files)
|
|
311
401
|
st.session_state.map_[imager] = single_imager_maps_process(st.session_state.map_[imager],
|
|
312
|
-
**
|
|
402
|
+
**st.session_state.selected_imagers_[imager]['process'],
|
|
313
403
|
skip='sequence_processing')
|
|
314
404
|
processed_images = single_imager_maps_process(st.session_state.map_[imager],
|
|
315
405
|
skip=['filter', 'prepare'],
|
|
@@ -394,6 +484,8 @@ def run():
|
|
|
394
484
|
frame=frames.HeliographicStonyhurst,
|
|
395
485
|
observer='earth',
|
|
396
486
|
obstime=running_map_date)
|
|
487
|
+
else:
|
|
488
|
+
raise ValueError(f"Unsupported coordinate system: '{st.session_state.coord_system}'. Expected 'HGC' or 'HGS'.")
|
|
397
489
|
st.session_state.center = center
|
|
398
490
|
|
|
399
491
|
if st.session_state.geometrical_model == 'Spheroid':
|
|
@@ -402,6 +494,8 @@ def run():
|
|
|
402
494
|
model = ellipsoid(center, radaxis, orthoaxis1, orthoaxis2, tilt)
|
|
403
495
|
elif st.session_state.geometrical_model == 'GCS':
|
|
404
496
|
model = gcs(center, height, alpha, kappa, tilt)
|
|
497
|
+
else:
|
|
498
|
+
raise ValueError(f"Unsupported geometrical model: '{st.session_state.geometrical_model}'. Expected 'Spheroid', 'Ellipsoid', or 'GCS'.")
|
|
405
499
|
|
|
406
500
|
#############################################################
|
|
407
501
|
# Plot main and supplement figure images
|
|
@@ -418,12 +512,14 @@ def run():
|
|
|
418
512
|
st.markdown('*Active Regions without NOAA number have been removed from the table.')
|
|
419
513
|
|
|
420
514
|
if plt_supp_imagers:
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
515
|
+
other_elements = [element for element in st.session_state.imagers_list_ if element != imager_select]
|
|
516
|
+
if not other_elements:
|
|
517
|
+
st.warning('No supplementary imagers available.')
|
|
518
|
+
elif len(st.session_state.imagers_list_) < 3:
|
|
519
|
+
fig, axis = figure_streamlit(st, get_closest(st.session_state.map[other_elements[0]], running_map_date), image_mode, other_elements[0], model)
|
|
424
520
|
st.pyplot(fig)
|
|
425
521
|
else:
|
|
426
|
-
supl_imagers_list =
|
|
522
|
+
supl_imagers_list = deepcopy(st.session_state.imagers_list_)
|
|
427
523
|
supl_imagers_list.remove(imager_select)
|
|
428
524
|
supl_imagers = st.select_slider('Select supplement imagers',
|
|
429
525
|
options=supl_imagers_list,
|
|
@@ -502,6 +598,8 @@ def run():
|
|
|
502
598
|
fit_args_ = {'type': 'custom', 'expression': fitcustexpres_select,
|
|
503
599
|
'bounds': ([-np.inf, -np.inf, -np.inf], [np.inf, np.inf, np.inf]), 'order': 3}
|
|
504
600
|
st.info(f'A custom function {fit_args_["expression"]} was fitted when processing parameters.')
|
|
601
|
+
else:
|
|
602
|
+
raise ValueError(f"Unsupported fit mode: '{fit_mode}'. Expected 'polynomial', 'spline', or 'custom'.")
|
|
505
603
|
|
|
506
604
|
if plt_kinematics_select == 'All':
|
|
507
605
|
col1, col2 = st.columns(2)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '1.3.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 3, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = 'gf5bc63e11'
|
|
@@ -3,87 +3,93 @@
|
|
|
3
3
|
How to use this:
|
|
4
4
|
|
|
5
5
|
'''
|
|
6
|
+
|
|
6
7
|
import astropy.units as u
|
|
7
8
|
import sunpy_soar # noqa
|
|
8
9
|
from sunpy.net import attrs as a
|
|
9
10
|
|
|
10
11
|
imager_dict = {}
|
|
11
12
|
|
|
12
|
-
imager_dict['LC2'] = {'fido':
|
|
13
|
+
imager_dict['LC2'] = {'fido': [a.Instrument.lasco, a.Detector.c2, a.Provider('SDAC')],
|
|
13
14
|
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'polar': 'Clear', 'superpixel': 2},
|
|
14
15
|
'source': 'SOHO', 'instrument': 'LASCO', 'detector': 'C2'}
|
|
15
16
|
|
|
16
|
-
imager_dict['LC3'] = {'fido':
|
|
17
|
+
imager_dict['LC3'] = {'fido': [a.Instrument.lasco, a.Detector.c3, a.Provider('SDAC')],
|
|
17
18
|
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'polar': 'Clear', 'superpixel': 2},
|
|
18
19
|
'source': 'SOHO', 'instrument': 'LASCO', 'detector': 'C3'}
|
|
19
20
|
|
|
20
|
-
imager_dict['AIA-193'] = {'fido':
|
|
21
|
+
imager_dict['AIA-193'] = {'fido': [a.Instrument.aia, a.Wavelength(19.3 * u.nm), a.Sample(1*u.minute)],
|
|
21
22
|
'process': {'dimensions': (4096*u.pixel, 4096*u.pixel), 'superpixel': 8, 'exposure': 1.90},
|
|
22
23
|
'source': 'SDO', 'instrument': 'AIA', 'wavelength': '193'}
|
|
23
24
|
|
|
24
|
-
imager_dict['AIA-211'] = {'fido':
|
|
25
|
+
imager_dict['AIA-211'] = {'fido': [a.Instrument.aia, a.Wavelength(21.1 * u.nm), a.Sample(1*u.minute)],
|
|
25
26
|
'process': {'dimensions': (4096*u.pixel, 4096*u.pixel), 'superpixel': 8, 'exposure': 1.90},
|
|
26
27
|
'source': 'SDO', 'instrument': 'AIA', 'wavelength': '211'}
|
|
27
28
|
|
|
28
|
-
imager_dict['COR2A'] = {'fido':
|
|
29
|
+
imager_dict['COR2A'] = {'fido': [a.Source('STEREO_A'), a.Detector.cor2, a.Provider('SSC')],
|
|
29
30
|
'process': {'dimensions': (2048*u.pixel, 2048*u.pixel), 'polar': 1001, 'superpixel': 4},
|
|
30
31
|
'source': 'STEREO_A', 'instrument': 'SECCHI', 'detector': 'COR2'}
|
|
31
32
|
|
|
32
|
-
imager_dict['COR2B'] = {'fido':
|
|
33
|
+
imager_dict['COR2B'] = {'fido': [a.Source('STEREO_B'), a.Detector.cor2, a.Provider('SSC')],
|
|
33
34
|
'process': {'dimensions': (2048*u.pixel, 2048*u.pixel), 'polar': 1001, 'superpixel': 4},
|
|
34
35
|
'source': 'STEREO_B', 'instrument': 'SECCHI', 'detector': 'COR2'}
|
|
35
36
|
|
|
36
|
-
imager_dict['EUVIA'] = {'fido':
|
|
37
|
+
imager_dict['EUVIA'] = {'fido': [a.Source('STEREO_A'), a.Detector.euvi, a.Wavelength(19.5 * u.nm), a.Provider('SSC')],
|
|
37
38
|
'process': {'dimensions': (2048*u.pixel, 2048*u.pixel), 'superpixel': 4},
|
|
38
39
|
'source': 'STEREO_A', 'instrument': 'SECCHI', 'detector': 'EUVI'}
|
|
39
40
|
|
|
40
|
-
imager_dict['EUVIB'] = {'fido':
|
|
41
|
+
imager_dict['EUVIB'] = {'fido': [a.Source('STEREO_B'), a.Detector.euvi, a.Wavelength(19.5 * u.nm), a.Provider('SSC')],
|
|
41
42
|
'process': {'dimensions': (2048*u.pixel, 2048*u.pixel), 'superpixel': 4},
|
|
42
43
|
'source': 'STEREO_B', 'instrument': 'SECCHI', 'detector': 'EUVI'}
|
|
43
44
|
|
|
44
|
-
imager_dict['COR1A'] = {'fido':
|
|
45
|
+
imager_dict['COR1A'] = {'fido': [a.Source('STEREO_A'), a.Detector.cor1, a.Provider('SSC'), a.Provider('SSC')],
|
|
45
46
|
'process': {'dimensions': (512*u.pixel, 512*u.pixel)},
|
|
46
47
|
'source': 'STEREO_A', 'instrument': 'SECCHI', 'detector': 'COR1'}
|
|
47
48
|
|
|
48
|
-
imager_dict['COR1B'] = {'fido':
|
|
49
|
+
imager_dict['COR1B'] = {'fido': [a.Source('STEREO_B'), a.Detector.cor1, a.Provider('SSC'), a.Provider('SSC')],
|
|
49
50
|
'process': {'dimensions': (512*u.pixel, 512*u.pixel)},
|
|
50
51
|
'source': 'STEREO_B', 'instrument': 'SECCHI', 'detector': 'COR1'}
|
|
51
52
|
|
|
52
|
-
imager_dict['HI1A'] = {'fido':
|
|
53
|
+
imager_dict['HI1A'] = {'fido': [a.Source('STEREO_A'), a.Detector.hi1, a.Provider('SSC')],
|
|
53
54
|
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'superpixel': 2},
|
|
54
55
|
'source': 'STEREO_A', 'instrument': 'SECCHI', 'detector': 'HI1'}
|
|
55
56
|
|
|
56
|
-
imager_dict['HI1B'] = {'fido':
|
|
57
|
+
imager_dict['HI1B'] = {'fido': [a.Source('STEREO_B'), a.Detector.hi1, a.Provider('SSC')],
|
|
57
58
|
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'superpixel': 2},
|
|
58
59
|
'source': 'STEREO_B', 'instrument': 'SECCHI', 'detector': 'HI1'}
|
|
59
60
|
|
|
60
|
-
imager_dict['HI2A'] = {'fido':
|
|
61
|
+
imager_dict['HI2A'] = {'fido': [a.Source('STEREO_A'), a.Detector.hi2, a.Provider('SSC')],
|
|
61
62
|
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'superpixel': 2},
|
|
62
63
|
'source': 'STEREO_A', 'instrument': 'SECCHI', 'detector': 'HI2'}
|
|
63
64
|
|
|
64
|
-
imager_dict['HI2B'] = {'fido':
|
|
65
|
+
imager_dict['HI2B'] = {'fido': [a.Source('STEREO_B'), a.Detector.hi2, a.Provider('SSC')],
|
|
65
66
|
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'superpixel': 2},
|
|
66
67
|
'source': 'STEREO_B', 'instrument': 'SECCHI', 'detector': 'HI2'}
|
|
67
68
|
|
|
68
|
-
imager_dict['WISPR1'] = {'fido':
|
|
69
|
+
imager_dict['WISPR1'] = {'fido': [a.Instrument.wispr, a.Detector.inner],
|
|
69
70
|
'process': {'dimensions': (960*u.pixel, 1024*u.pixel), 'processing_level': 3, 'superpixel': 2},
|
|
70
71
|
'source': 'PSP', 'instrument': 'WISPR', 'detector': 'Inner'}
|
|
71
72
|
|
|
72
|
-
imager_dict['WISPR2'] = {'fido':
|
|
73
|
+
imager_dict['WISPR2'] = {'fido': [a.Instrument.wispr, a.Detector.outer],
|
|
73
74
|
'process': {'dimensions': (960*u.pixel, 1024*u.pixel), 'processing_level': 3, 'superpixel': 2},
|
|
74
75
|
'source': 'PSP', 'instrument': 'WISPR', 'detector': 'Outer'}
|
|
75
76
|
|
|
76
|
-
imager_dict['EUI-FSI'] = {'fido':
|
|
77
|
+
imager_dict['EUI-FSI'] = {'fido': [a.Instrument('EUI'), a.soar.Product('EUI-FSI174-IMAGE'), a.Level(2)],
|
|
77
78
|
'process': {'superpixel': 1},
|
|
78
79
|
'source': 'SOLO', 'instrument': 'EUI-FSI', 'wavelength': '174'}
|
|
79
80
|
|
|
80
|
-
imager_dict['METIS'] = {'fido':
|
|
81
|
+
imager_dict['METIS'] = {'fido': [a.Instrument('METIS'), a.soar.Product('METIS-VL-TB'), a.Level(2)],
|
|
81
82
|
'process': {'dimensions': (1024*u.pixel, 1024*u.pixel), 'superpixel': 2},
|
|
82
83
|
'source': 'SOLO', 'instrument': 'METIS', 'detector': 'VLD', 'wavelength': 'TB'}
|
|
83
84
|
|
|
84
85
|
for tile in range(1, 5):
|
|
85
86
|
z = 'T' if tile in [1, 2] else 'G'
|
|
86
|
-
imager_dict[f'SOLOHI-T{tile}'] = {'fido':
|
|
87
|
-
a.soar.Product(f'SOLOHI-{tile}F{z}'), a.Level(2)
|
|
87
|
+
imager_dict[f'SOLOHI-T{tile}'] = {'fido': [a.Instrument('SOLOHI'),
|
|
88
|
+
a.soar.Product(f'SOLOHI-{tile}F{z}'), a.Level(2)],
|
|
88
89
|
'process': {'superpixel': 2},
|
|
89
90
|
'source': 'SOLO', 'instrument': 'SOLOHI', 'detector': f'T{tile}'}
|
|
91
|
+
|
|
92
|
+
providers = {'LASCO': {'imagers': ['LC2', 'LC3'], 'providers': ['SDAC', 'NASCOM']},
|
|
93
|
+
'STEREO': {'imagers': ['COR2A', 'COR2B', 'COR1A', 'COR1B',
|
|
94
|
+
'EUVIA', 'EUVIB', 'HI1A', 'HI1B',
|
|
95
|
+
'HI2A', 'HI2B'], 'providers': ['SSC', 'NASCOM']}, }
|
|
@@ -406,7 +406,7 @@ class spheroid:
|
|
|
406
406
|
output += 'CRLT = %3.2f degrees \n'%center_.lat.to_value(u.degree)
|
|
407
407
|
output += 'rcenter = %3.2f Rsun \n'%self.rcenter.to_value(u.R_sun)
|
|
408
408
|
output += 'radaxis = %3.2f Rsun \n'%self.radaxis.to_value(u.R_sun)
|
|
409
|
-
output += 'height = %3.2f Rsun \n'%self.
|
|
409
|
+
output += 'height = %3.2f Rsun \n'%self.height.to_value(u.R_sun)
|
|
410
410
|
output += 'kappa = %3.2f \n'%self.kappa
|
|
411
411
|
output += 'epsilon = %3.2f '%self.epsilon
|
|
412
412
|
output += '>'
|
|
@@ -576,7 +576,7 @@ class ellipsoid(spheroid):
|
|
|
576
576
|
output += 'radaxis = %3.2f Rsun \n'%self.radaxis.to_value(u.R_sun)
|
|
577
577
|
output += 'orthoaxis1 = %3.2f Rsun \n'%self.orthoaxis1.to_value(u.R_sun)
|
|
578
578
|
output += 'orthoaxis2 = %3.2f Rsun \n'%self.orthoaxis2.to_value(u.R_sun)
|
|
579
|
-
output += 'height = %3.2f Rsun \n'%self.
|
|
579
|
+
output += 'height = %3.2f Rsun \n'%self.height.to_value(u.R_sun)
|
|
580
580
|
output += 'kappa = %3.2f \n'%self.kappa
|
|
581
581
|
output += 'alpha = %3.2f \n'%self.alpha
|
|
582
582
|
output += 'epsilon = %3.2f '%self.epsilon
|
|
@@ -653,7 +653,7 @@ class gcs():
|
|
|
653
653
|
"""
|
|
654
654
|
Returns the cross-section radius at the apex (see eq. 29 in T2011).
|
|
655
655
|
"""
|
|
656
|
-
rapex = self.kappa * (self.
|
|
656
|
+
rapex = self.kappa * (self.h / np.cos(self.alpha) + self.h * np.tan(self.alpha)) / (1 - self.kappa ** 2)
|
|
657
657
|
return rapex
|
|
658
658
|
|
|
659
659
|
@property
|
|
@@ -695,7 +695,6 @@ class gcs():
|
|
|
695
695
|
Converted and modified from the IDL script shellskeleton.pro
|
|
696
696
|
https://hesperia.gsfc.nasa.gov/ssw/stereo/secchi/idl/scraytrace/shellskeleton.pro
|
|
697
697
|
"""
|
|
698
|
-
self.height.to_value(u.R_sun)
|
|
699
698
|
alpha = self.alpha.to_value(u.rad)
|
|
700
699
|
kappa = self.kappa
|
|
701
700
|
h = self.h.to_value(u.R_sun)
|
|
@@ -795,7 +794,7 @@ class gcs():
|
|
|
795
794
|
output += 'CRLN = %3.2f degrees \n'%center_.lon.to_value(u.degree)
|
|
796
795
|
output += 'CRLT = %3.2f degrees \n'%center_.lat.to_value(u.degree)
|
|
797
796
|
output += 'rcenter = %3.2f Rsun \n'%self.rcenter.to_value(u.R_sun)
|
|
798
|
-
output += 'height = %3.2f Rsun \n'%self.
|
|
797
|
+
output += 'height = %3.2f Rsun \n'%self.height.to_value(u.R_sun)
|
|
799
798
|
output += 'alpha = %3.2f \n'%self.alpha
|
|
800
799
|
output += 'kappa = %3.2f \n'%self.kappa
|
|
801
800
|
output += 'tilt = %3.2f '%self.tilt
|
|
@@ -88,8 +88,8 @@ def date_and_event_selection(st):
|
|
|
88
88
|
|
|
89
89
|
elif initialisation == 'Manual':
|
|
90
90
|
# Manual form for event ID selection and time input
|
|
91
|
-
with st.sidebar.form('my_form'):
|
|
92
|
-
col1, col2 =
|
|
91
|
+
with st.sidebar.form('my_form') as form:
|
|
92
|
+
col1, col2 = form.columns(2)
|
|
93
93
|
ev_id = col1.selectbox('Event ID',
|
|
94
94
|
options=['Select', 'FL', 'CME', 'SHW'])
|
|
95
95
|
time = col2.time_input('Time', datetime.time(12, 0))
|
|
@@ -256,6 +256,8 @@ def final_parameters_gmodel(st):
|
|
|
256
256
|
rcenter, radaxis, orthoaxis1 = (st.session_state.rcenter * u.R_sun,
|
|
257
257
|
st.session_state.radaxis * u.R_sun,
|
|
258
258
|
st.session_state.orthoaxis1 * u.R_sun)
|
|
259
|
+
else:
|
|
260
|
+
raise ValueError(f"Unsupported representation mode for Spheroid: '{rmode}'. Expected 'h, e, k' or 'r, a, b'.")
|
|
259
261
|
return rcenter, radaxis, orthoaxis1
|
|
260
262
|
|
|
261
263
|
elif gmodel == 'Ellipsoid':
|
|
@@ -269,6 +271,8 @@ def final_parameters_gmodel(st):
|
|
|
269
271
|
st.session_state.radaxis * u.R_sun,
|
|
270
272
|
st.session_state.orthoaxis1 * u.R_sun,
|
|
271
273
|
st.session_state.orthoaxis2 * u.R_sun)
|
|
274
|
+
else:
|
|
275
|
+
raise ValueError(f"Unsupported representation mode for Ellipsoid: '{rmode}'. Expected 'h, e, k, a' or 'r, a, b, c'.")
|
|
272
276
|
tilt = st.session_state.tilt * u.degree
|
|
273
277
|
return rcenter, radaxis, orthoaxis1, orthoaxis2, tilt
|
|
274
278
|
|
|
@@ -278,6 +282,8 @@ def final_parameters_gmodel(st):
|
|
|
278
282
|
alpha = st.session_state.alpha * u.degree
|
|
279
283
|
kappa = st.session_state.kappa
|
|
280
284
|
rcenter = gcs.rcenter_(height, alpha, kappa)
|
|
285
|
+
else:
|
|
286
|
+
raise ValueError(f"Unsupported representation mode for GCS: '{rmode}'. Expected 'h, a, k, t'.")
|
|
281
287
|
tilt = st.session_state.tilt * u.degree
|
|
282
288
|
return rcenter, height, alpha, kappa, tilt
|
|
283
289
|
|
|
@@ -325,13 +331,17 @@ def figure_streamlit(st, running_map, image_mode, imager, model):
|
|
|
325
331
|
|
|
326
332
|
# Plot the model based on the selected mesh mode
|
|
327
333
|
plot_mode = st.session_state.plot_mesh_mode
|
|
328
|
-
if plot_mode == '
|
|
334
|
+
if plot_mode == 'No plot':
|
|
335
|
+
pass
|
|
336
|
+
elif plot_mode == 'Skeleton':
|
|
329
337
|
model.plot(axis, mode='Skeleton')
|
|
330
338
|
elif plot_mode == 'Full':
|
|
331
339
|
model.plot(axis, mode='Skeleton')
|
|
332
340
|
model.plot(axis, mode='Full')
|
|
333
341
|
elif plot_mode == 'Surface':
|
|
334
342
|
model.plot(axis, only_surface=True)
|
|
343
|
+
else:
|
|
344
|
+
raise ValueError(f"Unsupported plot mode: '{plot_mode}'. Expected 'No plot', 'Skeleton', 'Full', or 'Surface'.")
|
|
335
345
|
|
|
336
346
|
# Optionally plot star field, solar reference lines, and Parker spirals
|
|
337
347
|
if st.session_state.star_field:
|
|
@@ -352,7 +362,7 @@ def figure_streamlit(st, running_map, image_mode, imager, model):
|
|
|
352
362
|
if 'hek_responses' not in st.session_state:
|
|
353
363
|
st.session_state.hek_responses = {'Active Regions': [], 'Coronal Holes': [], 'Flares': []}
|
|
354
364
|
for mode in st.session_state.hek_list:
|
|
355
|
-
st.session_state.hek_responses[mode] = plot_hek(axis, running_map
|
|
365
|
+
st.session_state.hek_responses[mode] = plot_hek(axis, getattr(running_map, 'date_average', None) or running_map.date, mode,
|
|
356
366
|
st.session_state.imaging_time_range,
|
|
357
367
|
hek_responses=st.session_state.hek_responses)
|
|
358
368
|
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from collections import OrderedDict
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from sunpy.net.dataretriever import GenericClient, QueryResponse
|
|
5
|
+
from sunpy.time import TimeRange
|
|
6
|
+
|
|
7
|
+
__all__ = ['LASCOClient']
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LASCOClient(GenericClient):
|
|
11
|
+
"""
|
|
12
|
+
Provides access to data from NASA/NASCOM for LASCO instrument on board SOHO.
|
|
13
|
+
|
|
14
|
+
Examples
|
|
15
|
+
--------
|
|
16
|
+
>>> from sunpy.net import Fido, attrs as a
|
|
17
|
+
>>> res = Fido.search(a.Time('2015-06-21 00:00', '2015-06-23 23:59'),
|
|
18
|
+
... a.Detector('c2'),
|
|
19
|
+
a.Instrument('LASCO'),
|
|
20
|
+
a.Provider('NASCOM'))
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
baseurl = r'https://sohoftp.nascom.nasa.gov/qkl/lasco/quicklook/level_05/%y%m%d/'
|
|
25
|
+
# r'https://umbra.nascom.nasa.gov/pub/lasco_level05/%y%m%d/'
|
|
26
|
+
|
|
27
|
+
def post_search_hook(self, i, matchdict):
|
|
28
|
+
|
|
29
|
+
rowdict = OrderedDict()
|
|
30
|
+
rowdict['Start Time'] = i['start']
|
|
31
|
+
rowdict['End Time'] = i['start']
|
|
32
|
+
rowdict['Instrument'] = matchdict['Instrument'][0].upper()
|
|
33
|
+
rowdict['Source'] = matchdict['Source'][0]
|
|
34
|
+
rowdict['Provider'] = matchdict['Provider'][0]
|
|
35
|
+
rowdict['url'] = i['url']
|
|
36
|
+
|
|
37
|
+
return rowdict
|
|
38
|
+
|
|
39
|
+
def search(self, *args, **kwargs):
|
|
40
|
+
"""
|
|
41
|
+
Query this client for a list of results.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
\\*args: `tuple`
|
|
46
|
+
`sunpy.net.attrs` objects representing the query.
|
|
47
|
+
\\*\\*kwargs: `dict`
|
|
48
|
+
Any extra keywords to refine the search.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
A `QueryResponse` instance containing the query result.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
baseurl, _, matchdict = self.pre_search_hook(*args, **kwargs)
|
|
56
|
+
|
|
57
|
+
tr = TimeRange(matchdict['Start Time'], matchdict['End Time'])
|
|
58
|
+
|
|
59
|
+
metalist = []
|
|
60
|
+
|
|
61
|
+
for times in pd.date_range(tr.start.strftime('%Y-%m-%d %H:%M:%S'), tr.end.strftime('%Y-%m-%d %H:%M:%S')):
|
|
62
|
+
url = times.strftime(baseurl)
|
|
63
|
+
|
|
64
|
+
data = pd.read_fwf(url + matchdict['Detector'][0] + '/img_hdr.txt',
|
|
65
|
+
header=None, widths=(13, 13, 13),
|
|
66
|
+
names=['filename', 'date', 'time'])
|
|
67
|
+
data = data.set_index([pd.to_datetime(data.iloc[:, 1]+' '+data.iloc[:, 2], format='%Y/%m/%d %H:%M:%S')])
|
|
68
|
+
data = data[(data.index >= tr.start.strftime('%Y-%m-%d %H:%M:%S')) &
|
|
69
|
+
(data.index <= tr.end.strftime('%Y-%m-%d %H:%M:%S'))]
|
|
70
|
+
# files = 'https://sohoftp.nascom.nasa.gov/qkl/lasco/quicklook/level_05/210804/' + 'c2/' + files
|
|
71
|
+
|
|
72
|
+
for f in data.itertuples():
|
|
73
|
+
filemeta = {'start': f.Index,
|
|
74
|
+
'url': url+matchdict['Detector'][0]+'/' + f.filename}
|
|
75
|
+
rowdict = self.post_search_hook(filemeta, matchdict)
|
|
76
|
+
metalist.append(rowdict)
|
|
77
|
+
|
|
78
|
+
return QueryResponse(metalist, client=self)
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def register_values(cls):
|
|
82
|
+
from sunpy.net import attrs
|
|
83
|
+
adict = {attrs.Instrument: [('LASCO', '')],
|
|
84
|
+
attrs.Source: [('SOHO', '')],
|
|
85
|
+
attrs.Provider: [('NASCOM', '')],
|
|
86
|
+
attrs.Detector: [('c2', ''), ('c3', '')]}
|
|
87
|
+
return adict
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from collections import OrderedDict
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from sunpy.net.dataretriever import GenericClient, QueryResponse
|
|
5
|
+
from sunpy.time import TimeRange
|
|
6
|
+
|
|
7
|
+
__all__ = ['STEREOClient']
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class STEREOClient(GenericClient):
|
|
11
|
+
"""
|
|
12
|
+
Provides access to data from NASA/NASCOM for SECCHI instrument suite on board STEREO.
|
|
13
|
+
|
|
14
|
+
Examples
|
|
15
|
+
--------
|
|
16
|
+
>>> from sunpy.net import Fido, attrs as a
|
|
17
|
+
>>> res = Fido.search(a.Time('2015-06-21 00:00', '2015-06-23 23:59'),
|
|
18
|
+
... a.Detector('cor2'),
|
|
19
|
+
a.Instrument('STEREO'),
|
|
20
|
+
a.Provider('NASCOM'))
|
|
21
|
+
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
baseurl = r'https://stereo-ssc.nascom.nasa.gov/data/ins_data/secchi/L0/a/img/INSTRUMENT/%Y%m%d/'
|
|
25
|
+
|
|
26
|
+
def post_search_hook(self, i, matchdict):
|
|
27
|
+
|
|
28
|
+
rowdict = OrderedDict()
|
|
29
|
+
rowdict['Start Time'] = i['start']
|
|
30
|
+
rowdict['End Time'] = i['start']
|
|
31
|
+
rowdict['Instrument'] = matchdict['Instrument'][0].upper()
|
|
32
|
+
rowdict['Source'] = matchdict['Source'][0]
|
|
33
|
+
rowdict['Provider'] = matchdict['Provider'][0]
|
|
34
|
+
rowdict['url'] = i['url']
|
|
35
|
+
|
|
36
|
+
return rowdict
|
|
37
|
+
|
|
38
|
+
def search(self, *args, **kwargs):
|
|
39
|
+
"""
|
|
40
|
+
Query this client for a list of results.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
\\*args: `tuple`
|
|
45
|
+
`sunpy.net.attrs` objects representing the query.
|
|
46
|
+
\\*\\*kwargs: `dict`
|
|
47
|
+
Any extra keywords to refine the search.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
A `QueryResponse` instance containing the query result.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
baseurl, _, matchdict = self.pre_search_hook(*args, **kwargs)
|
|
55
|
+
summaryurl = r'https://stereo-ssc.nascom.nasa.gov/data/ins_data/secchi/L0/??/summary/SCC%Y%m.img.DETECTOR'
|
|
56
|
+
|
|
57
|
+
tr = TimeRange(matchdict['Start Time'], matchdict['End Time'])
|
|
58
|
+
|
|
59
|
+
metalist = []
|
|
60
|
+
print(matchdict['Source'][0])
|
|
61
|
+
if matchdict['Source'][0].upper() == 'STEREO_A':
|
|
62
|
+
scl, scc = 'a', 'sccA'
|
|
63
|
+
elif matchdict['Source'][0].upper() == 'STEREO_B':
|
|
64
|
+
scl, scc = 'b', 'sccB'
|
|
65
|
+
|
|
66
|
+
if matchdict['Detector'][0].upper() == 'COR2':
|
|
67
|
+
detect = 'c2'
|
|
68
|
+
|
|
69
|
+
for times in pd.date_range(tr.start.strftime('%Y-%m-%d %H:%M:%S'), tr.end.strftime('%Y-%m-%d %H:%M:%S')):
|
|
70
|
+
urlsum = summaryurl.replace('??', scl).replace('SCC', scc).replace('DETECTOR', detect)
|
|
71
|
+
urlsum = times.strftime(urlsum) # sccA201105.img.h1
|
|
72
|
+
|
|
73
|
+
data = pd.read_fwf(urlsum,
|
|
74
|
+
header=None, colspecs=([0, 25], [28, 47], [50, 54]), skiprows=2,
|
|
75
|
+
names=['filename', 'date', 'telescope'])
|
|
76
|
+
data = data.set_index([pd.to_datetime(data.iloc[:, 1], format='%Y/%m/%d %H:%M:%S')])
|
|
77
|
+
data = data[(data.index >= tr.start.strftime('%Y-%m-%d %H:%M:%S')) &
|
|
78
|
+
(data.index <= tr.end.strftime('%Y-%m-%d %H:%M:%S'))]
|
|
79
|
+
|
|
80
|
+
# URL for example: files = 'https://stereo-ssc.nascom.nasa.gov/data/ins_data/secchi/L0/a/img/cor2/20211028/' + files
|
|
81
|
+
urldata = times.strftime(baseurl).replace('INSTRUMENT', matchdict['Detector'][0])
|
|
82
|
+
|
|
83
|
+
for f in data.itertuples():
|
|
84
|
+
filemeta = {'start': f.Index,
|
|
85
|
+
'url': urldata + f.filename}
|
|
86
|
+
rowdict = self.post_search_hook(filemeta, matchdict)
|
|
87
|
+
metalist.append(rowdict)
|
|
88
|
+
|
|
89
|
+
return QueryResponse(metalist, client=self)
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def register_values(cls):
|
|
93
|
+
from sunpy.net import attrs
|
|
94
|
+
adict = {
|
|
95
|
+
attrs.Instrument: [('SECCHI', '')],
|
|
96
|
+
attrs.Source: [('STEREO_A', ''), ('STEREO_B', '')],
|
|
97
|
+
attrs.Provider: [('NASCOM', '')],
|
|
98
|
+
attrs.Detector: [('COR2', ''), ('COR1', '')]
|
|
99
|
+
}
|
|
100
|
+
return adict
|
|
File without changes
|
|
@@ -91,7 +91,7 @@ def get_hek_flare(timerange, thresshold='B1.0'):
|
|
|
91
91
|
return flare_list_
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
def make_figure(
|
|
94
|
+
def make_figure(smap, cmap='Greys_r', clim=[-20, 20], clip_model=True, **kwargs):
|
|
95
95
|
"""
|
|
96
96
|
Creates the main imager figure and returns the figure and axis handles.
|
|
97
97
|
|
|
@@ -121,49 +121,49 @@ def make_figure(map, cmap='Greys_r', clim=[-20, 20], clip_model=True, **kwargs):
|
|
|
121
121
|
This function customizes the plot by optionally applying a median filter,
|
|
122
122
|
setting color limits, drawing the solar limb, and adjusting axis properties.
|
|
123
123
|
"""
|
|
124
|
-
fig = kwargs
|
|
125
|
-
axis = kwargs
|
|
124
|
+
fig = kwargs['fig'] if 'fig' in kwargs else plt.figure()
|
|
125
|
+
axis = kwargs['axis'] if 'axis' in kwargs else plt.subplot(projection=smap)
|
|
126
126
|
|
|
127
127
|
median_filter_value = kwargs.get('median_filter', 1)
|
|
128
128
|
if median_filter_value != 1:
|
|
129
|
-
|
|
129
|
+
smap = sunpy.map.Map(median_filter(smap.data, size=int(median_filter_value)), smap.meta)
|
|
130
130
|
|
|
131
|
-
if
|
|
131
|
+
if smap.instrument in ['WISPR', 'Metis'] or smap.instrument.startswith('SoloHI'):
|
|
132
132
|
clim = [-10**-clim[0], 10**-clim[1]]
|
|
133
133
|
|
|
134
134
|
if cmap == 'default':
|
|
135
135
|
# TODO: For plain images or when EUVIA-B are used, this does not work very well.
|
|
136
|
-
|
|
136
|
+
smap.plot(norm=colors.Normalize(vmin=clim[0], vmax=clim[1]))
|
|
137
137
|
else:
|
|
138
|
-
|
|
138
|
+
smap.plot(cmap=cmap, norm=colors.Normalize(vmin=clim[0], vmax=clim[1]))
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
smap.draw_limb(resolution=90)
|
|
141
141
|
|
|
142
142
|
yax = axis.coords[1]
|
|
143
143
|
yax.set_ticklabel(rotation=90)
|
|
144
144
|
|
|
145
145
|
if clip_model:
|
|
146
|
-
axis.set_xlim([0,
|
|
147
|
-
axis.set_ylim([0,
|
|
146
|
+
axis.set_xlim([0, smap.data.shape[0]])
|
|
147
|
+
axis.set_ylim([0, smap.data.shape[1]])
|
|
148
148
|
|
|
149
|
-
cref =
|
|
150
|
-
if cref.Tx > 0 and (
|
|
149
|
+
cref = smap.pixel_to_world(0*u.pix, 0*u.pix)
|
|
150
|
+
if cref.Tx > 0 and (smap.instrument != 'WISPR'):
|
|
151
151
|
axis.invert_xaxis()
|
|
152
152
|
if cref.Ty > 0:
|
|
153
153
|
axis.invert_yaxis()
|
|
154
154
|
|
|
155
|
-
if
|
|
156
|
-
title = 'SoloHI' + f' Tile-{
|
|
157
|
-
elif
|
|
155
|
+
if smap.instrument == 'SoloHI':
|
|
156
|
+
title = 'SoloHI' + f' Tile-{smap.detector}' ' $T_{AGV}:$' + parse_time(smap.date_average).strftime('%Y-%m-%d %H:%M:%S')
|
|
157
|
+
elif smap.instrument == 'Metis':
|
|
158
158
|
title = re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}',
|
|
159
|
-
' $T_{AGV}:$' + parse_time(
|
|
160
|
-
|
|
159
|
+
' $T_{AGV}:$' + parse_time(smap.date_average).strftime('%Y-%m-%d %H:%M:%S'),
|
|
160
|
+
smap.latex_name.replace('VLD', 'METIS-VDL'))
|
|
161
161
|
else:
|
|
162
162
|
title = re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}',
|
|
163
|
-
' $T_{AGV}:$' + parse_time(
|
|
164
|
-
|
|
165
|
-
print(
|
|
166
|
-
print(
|
|
163
|
+
' $T_{AGV}:$' + parse_time(smap.date_average).strftime('%Y-%m-%d %H:%M:%S'),
|
|
164
|
+
smap.latex_name)
|
|
165
|
+
print(smap.instrument)
|
|
166
|
+
print(smap.latex_name)
|
|
167
167
|
axis.set_title(title,
|
|
168
168
|
fontsize=10, pad=8)
|
|
169
169
|
|
|
@@ -433,13 +433,15 @@ def single_imager_maps_process(map_list, skip=None, **kwargs):
|
|
|
433
433
|
-----
|
|
434
434
|
Operations can be skipped by specifying them in `skip`, e.g., 'filter', 'prepare', 'sequence_processing'.
|
|
435
435
|
"""
|
|
436
|
-
if
|
|
436
|
+
skip_set = set([skip] if isinstance(skip, str) else (skip or []))
|
|
437
|
+
|
|
438
|
+
if 'filter' not in skip_set:
|
|
437
439
|
map_list = filter_maps(map_list, **kwargs)
|
|
438
440
|
|
|
439
|
-
if 'prepare' not in
|
|
441
|
+
if 'prepare' not in skip_set:
|
|
440
442
|
map_list = prepare_maps(map_list, **kwargs)
|
|
441
443
|
|
|
442
|
-
if 'sequence_processing' not in
|
|
444
|
+
if 'sequence_processing' not in skip_set:
|
|
443
445
|
map_list = maps_sequence_processing(map_list, **kwargs)
|
|
444
446
|
|
|
445
447
|
return map_list
|
|
@@ -477,12 +479,12 @@ class model_fittings:
|
|
|
477
479
|
Converts the model fittings to JSON format.
|
|
478
480
|
"""
|
|
479
481
|
|
|
480
|
-
def __init__(self, event_selected, date_process, geometrical_model, model_parameters, kinematics=
|
|
482
|
+
def __init__(self, event_selected, date_process, geometrical_model, model_parameters, kinematics=None):
|
|
481
483
|
self.event_selected = event_selected
|
|
482
484
|
self.date_process = date_process
|
|
483
485
|
self.geometrical_model = geometrical_model
|
|
484
486
|
self.parameters = model_parameters
|
|
485
|
-
self.kinematics = kinematics
|
|
487
|
+
self.kinematics = kinematics if kinematics is not None else {'fit_method': None}
|
|
486
488
|
|
|
487
489
|
@staticmethod
|
|
488
490
|
def load_from_json(json_file):
|
|
@@ -920,8 +922,8 @@ def parameter_fit(x, y, fit_args):
|
|
|
920
922
|
sv_bound_low = np.minimum(sv_bound_low, spl(xxx))
|
|
921
923
|
sv_bound_dup = np.maximum(sv_bound_dup, np.gradient(spl(xxx), xxx))
|
|
922
924
|
sv_bound_dlow = np.minimum(sv_bound_dlow, np.gradient(spl(xxx), xxx))
|
|
923
|
-
sv_bound_ddup = np.maximum(sv_bound_ddup, np.gradient(np.gradient(spl(xxx), xxx)))
|
|
924
|
-
sv_bound_ddlow = np.minimum(sv_bound_ddlow, np.gradient(np.gradient(spl(xxx), xxx)))
|
|
925
|
+
sv_bound_ddup = np.maximum(sv_bound_ddup, np.gradient(np.gradient(spl(xxx), xxx), xxx))
|
|
926
|
+
sv_bound_ddlow = np.minimum(sv_bound_ddlow, np.gradient(np.gradient(spl(xxx), xxx), xxx))
|
|
925
927
|
|
|
926
928
|
fitting = {
|
|
927
929
|
'spl': spl,
|
|
@@ -55,6 +55,9 @@ def update_nested_dict(d, u):
|
|
|
55
55
|
|
|
56
56
|
def get_fits_filenames_from_database(event_id, timerange, imager):
|
|
57
57
|
|
|
58
|
+
if imager not in imager_dict:
|
|
59
|
+
raise KeyError(f"Unknown imager '{imager}'. Available imagers: {list(imager_dict.keys())}")
|
|
60
|
+
|
|
58
61
|
db_args = [imager_dict[imager]['source'],
|
|
59
62
|
imager_dict[imager]['instrument'],
|
|
60
63
|
imager_dict[imager].get('detector', imager_dict[imager].get('wavelength'))]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyThea
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: PyThea: A software package to reconstruct the 3D structure of CMEs and shock waves
|
|
5
5
|
Author-email: Athanasios Kouloumvakos <athkouloumvakos@gmail.com>
|
|
6
6
|
License:
|
|
@@ -662,17 +662,17 @@ Keywords: science,solar physics,solar,coronal mass ejections,shock waves,EUV wav
|
|
|
662
662
|
Platform: any
|
|
663
663
|
Classifier: Programming Language :: Python
|
|
664
664
|
Classifier: Programming Language :: Python :: 3
|
|
665
|
-
Classifier: Programming Language :: Python :: 3.
|
|
665
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
666
666
|
Classifier: Development Status :: 5 - Production/Stable
|
|
667
667
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
668
668
|
Classifier: Operating System :: OS Independent
|
|
669
669
|
Classifier: Intended Audience :: Science/Research
|
|
670
670
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
671
671
|
Provides: PyThea
|
|
672
|
-
Requires-Python: >=3.
|
|
672
|
+
Requires-Python: >=3.12
|
|
673
673
|
Description-Content-Type: text/markdown
|
|
674
674
|
License-File: LICENSE.md
|
|
675
|
-
Requires-Dist: sunpy>=7.
|
|
675
|
+
Requires-Dist: sunpy>=7.1.2
|
|
676
676
|
Requires-Dist: pandas
|
|
677
677
|
Requires-Dist: scipy
|
|
678
678
|
Requires-Dist: matplotlib
|
|
@@ -51,6 +51,11 @@ PyThea/sunpy_dev/extern/sunkit_instruments/stereo/__init__.py
|
|
|
51
51
|
PyThea/sunpy_dev/extern/sunkit_instruments/stereo/utils.py
|
|
52
52
|
PyThea/sunpy_dev/map/__init__.py
|
|
53
53
|
PyThea/sunpy_dev/map/maputils.py
|
|
54
|
+
PyThea/sunpy_dev/net/__init__.py
|
|
55
|
+
PyThea/sunpy_dev/net/dataretriever/__init__.py
|
|
56
|
+
PyThea/sunpy_dev/net/dataretriever/sources/__init__.py
|
|
57
|
+
PyThea/sunpy_dev/net/dataretriever/sources/lasco.py
|
|
58
|
+
PyThea/sunpy_dev/net/dataretriever/sources/stereo.py
|
|
54
59
|
PyThea/test/Pythea_test.py
|
|
55
60
|
PyThea/test/__init__.py
|
|
56
61
|
PyThea/test/conftest.py
|
|
@@ -9,13 +9,13 @@ build-backend = "setuptools.build_meta"
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "PyThea"
|
|
11
11
|
description = "PyThea: A software package to reconstruct the 3D structure of CMEs and shock waves"
|
|
12
|
-
requires-python = ">=3.
|
|
12
|
+
requires-python = ">=3.12"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
license = { file = "LICENSE.md" }
|
|
15
15
|
classifiers=[
|
|
16
16
|
'Programming Language :: Python',
|
|
17
17
|
'Programming Language :: Python :: 3',
|
|
18
|
-
'Programming Language :: Python :: 3.
|
|
18
|
+
'Programming Language :: Python :: 3.12',
|
|
19
19
|
'Development Status :: 5 - Production/Stable',
|
|
20
20
|
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
|
|
21
21
|
'Operating System :: OS Independent',
|
|
@@ -28,7 +28,7 @@ authors = [
|
|
|
28
28
|
]
|
|
29
29
|
|
|
30
30
|
dependencies = [
|
|
31
|
-
"sunpy>=7.
|
|
31
|
+
"sunpy>=7.1.2",
|
|
32
32
|
"pandas",
|
|
33
33
|
"scipy",
|
|
34
34
|
"matplotlib",
|
pythea-1.2.0/PyThea/_version.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools-scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
|
|
4
|
-
__all__ = [
|
|
5
|
-
"__version__",
|
|
6
|
-
"__version_tuple__",
|
|
7
|
-
"version",
|
|
8
|
-
"version_tuple",
|
|
9
|
-
"__commit_id__",
|
|
10
|
-
"commit_id",
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
TYPE_CHECKING = False
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from typing import Tuple
|
|
16
|
-
from typing import Union
|
|
17
|
-
|
|
18
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
-
COMMIT_ID = Union[str, None]
|
|
20
|
-
else:
|
|
21
|
-
VERSION_TUPLE = object
|
|
22
|
-
COMMIT_ID = object
|
|
23
|
-
|
|
24
|
-
version: str
|
|
25
|
-
__version__: str
|
|
26
|
-
__version_tuple__: VERSION_TUPLE
|
|
27
|
-
version_tuple: VERSION_TUPLE
|
|
28
|
-
commit_id: COMMIT_ID
|
|
29
|
-
__commit_id__: COMMIT_ID
|
|
30
|
-
|
|
31
|
-
__version__ = version = '1.2.0'
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 2, 0)
|
|
33
|
-
|
|
34
|
-
__commit_id__ = commit_id = 'g0f05ae06e'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|