anta-database 0.3.4__tar.gz → 0.3.6__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.
- {anta_database-0.3.4 → anta_database-0.3.6}/PKG-INFO +1 -1
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/compiling/compile.py +22 -9
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/database/database.py +81 -37
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/indexing/index_database.py +28 -9
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/plotting/plotting.py +25 -29
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database.egg-info/PKG-INFO +1 -1
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database.egg-info/SOURCES.txt +1 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/_toc.yml +1 -0
- anta_database-0.3.6/book/advanced.md +154 -0
- anta_database-0.3.6/book/pism_example.ipynb +302 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/quick_start.ipynb +130 -76
- anta_database-0.3.4/book/advanced.md +0 -90
- {anta_database-0.3.4 → anta_database-0.3.6}/.github/workflows/deploy.yml +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/.github/workflows/release.yml +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/.gitignore +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/LICENSE +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/README.md +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/ROADMAP.md +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/__init__.py +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/anta_database.py +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/compiling/__init__.py +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/compiling/reconnect.py +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/ANT_Basins_IMBIE2_v1.6.cpg +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/ANT_Basins_IMBIE2_v1.6.dbf +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/ANT_Basins_IMBIE2_v1.6.prj +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/ANT_Basins_IMBIE2_v1.6.shp +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/ANT_Basins_IMBIE2_v1.6.shx +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/GL.pkl +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/centeroid_coords_basins.cpg +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/centeroid_coords_basins.dbf +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/centeroid_coords_basins.prj +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/centeroid_coords_basins.shp +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/centeroid_coords_basins.shx +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/data/site-coords.pkl +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/database/__init__.py +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/figures/AntA_38ka.png +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/indexing/__init__.py +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database/plotting/__init__.py +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database.egg-info/dependency_links.txt +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database.egg-info/requires.txt +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/anta_database.egg-info/top_level.txt +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/_config.yml +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/contact.md +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/contribute.md +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/figures/Overview_all.png +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/intro.md +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/logo.png +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/references.bib +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/book/requirements.txt +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/pyproject.toml +0 -0
- {anta_database-0.3.4 → anta_database-0.3.6}/setup.cfg +0 -0
|
@@ -24,6 +24,7 @@ class CompileDatabase:
|
|
|
24
24
|
firn_correction: Optional[float] = None,
|
|
25
25
|
extract_data: bool = True,
|
|
26
26
|
hdf5: bool = True,
|
|
27
|
+
netcdf: bool = False,
|
|
27
28
|
compute_distance: bool = True,
|
|
28
29
|
compute_IMBIE_basins: bool = True,
|
|
29
30
|
compute_IRH_density: bool = True,
|
|
@@ -42,6 +43,7 @@ class CompileDatabase:
|
|
|
42
43
|
self._compute_IMBIE_basins = compute_IMBIE_basins
|
|
43
44
|
self._set_attributes = set_attributes
|
|
44
45
|
self._hdf5 = hdf5
|
|
46
|
+
self._netcdf = netcdf
|
|
45
47
|
self._shapefiles = shapefiles
|
|
46
48
|
self._geopackages = geopackages
|
|
47
49
|
self._break_transects = break_transects
|
|
@@ -94,7 +96,7 @@ class CompileDatabase:
|
|
|
94
96
|
for file_dict in tqdm(all_files_list, desc="Processing", unit="file"):
|
|
95
97
|
self.extract(file_dict=file_dict)
|
|
96
98
|
|
|
97
|
-
if self._hdf5 is True:
|
|
99
|
+
if self._hdf5 is True or self._netcdf is True:
|
|
98
100
|
all_dirs = []
|
|
99
101
|
for dir_ in self._dir_list:
|
|
100
102
|
dirs = [d for d in glob.glob(f"{dir_}/pkl/*") if os.path.isdir(d)]
|
|
@@ -104,7 +106,7 @@ class CompileDatabase:
|
|
|
104
106
|
num_workers = min(num_tasks, cpus)
|
|
105
107
|
|
|
106
108
|
print('\n',
|
|
107
|
-
'Will start creating the hdf5 for', len(all_dirs), 'traces\n'
|
|
109
|
+
'Will start creating the hdf5/netcdf for', len(all_dirs), 'traces\n'
|
|
108
110
|
'\n ', num_workers, 'worker(s) allocated out of', cpu_count(), 'available cpus\n')
|
|
109
111
|
|
|
110
112
|
if num_workers > 1:
|
|
@@ -680,14 +682,25 @@ class CompileDatabase:
|
|
|
680
682
|
ds[var] = ds[var].chunk({'point': chunk_size_point})
|
|
681
683
|
encoding[var] = {'zlib': True, 'complevel': 1, 'chunksizes': (chunk_size_point)}
|
|
682
684
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
685
|
+
if self._hdf5:
|
|
686
|
+
h5_dir = os.path.join(dataset_dir, 'h5')
|
|
687
|
+
os.makedirs(h5_dir, exist_ok=True)
|
|
688
|
+
if not isinstance(institute, (list, tuple, set)) and institute != 'nan':
|
|
689
|
+
h5_file = f'{h5_dir}/{institute}_{flight_id}.h5'
|
|
690
|
+
else:
|
|
691
|
+
h5_file = f'{h5_dir}/{flight_id}.h5'
|
|
692
|
+
|
|
693
|
+
ds.to_netcdf(h5_file, engine='h5netcdf', encoding=encoding, mode='w')
|
|
694
|
+
|
|
695
|
+
if self._netcdf:
|
|
696
|
+
nc_dir = os.path.join(dataset_dir, 'nc')
|
|
697
|
+
os.makedirs(nc_dir, exist_ok=True)
|
|
698
|
+
if not isinstance(institute, (list, tuple, set)) and institute != 'nan':
|
|
699
|
+
nc_file = f'{nc_dir}/{institute}_{flight_id}.nc'
|
|
700
|
+
else:
|
|
701
|
+
nc_file = f'{nc_dir}/{flight_id}.nc'
|
|
689
702
|
|
|
690
|
-
|
|
703
|
+
ds.to_netcdf(nc_file, engine='netcdf4', encoding=encoding, mode='w')
|
|
691
704
|
|
|
692
705
|
def do_break_transects(self, h5_file: str) -> None:
|
|
693
706
|
h5_dir, name = os.path.split(h5_file)
|
|
@@ -8,9 +8,10 @@ from typing import Union, List, Dict, Tuple, Optional, Generator
|
|
|
8
8
|
from tqdm import tqdm
|
|
9
9
|
|
|
10
10
|
from anta_database.plotting.plotting import Plotting
|
|
11
|
+
from anta_database.indexing.index_database import IndexDatabase
|
|
11
12
|
|
|
12
13
|
class Database:
|
|
13
|
-
def __init__(self, database_dir: str, file_db: str = 'AntADatabase.db', include_BEDMAP: bool = False, max_displayed_flight_ids: Optional[int] = 50) -> None:
|
|
14
|
+
def __init__(self, database_dir: str, file_db: str = 'AntADatabase.db', index_database: bool = False, include_BEDMAP: bool = False, max_displayed_flight_ids: Optional[int] = 50) -> None:
|
|
14
15
|
self._db_dir = database_dir
|
|
15
16
|
self._file_db = file_db
|
|
16
17
|
self._file_db_path = os.path.join(self._db_dir, file_db)
|
|
@@ -18,6 +19,7 @@ class Database:
|
|
|
18
19
|
self._plotting = None
|
|
19
20
|
self._max_displayed_flight_ids = max_displayed_flight_ids
|
|
20
21
|
self._include_BM = include_BEDMAP
|
|
22
|
+
self._include_BM = index_database
|
|
21
23
|
self._disable_tqdm = os.getenv("JUPYTER_BOOK_BUILD", False)
|
|
22
24
|
self._excluded = {
|
|
23
25
|
'dataset': [],
|
|
@@ -32,6 +34,10 @@ class Database:
|
|
|
32
34
|
'radar_instrument': [],
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
if index_database:
|
|
38
|
+
indexing = IndexDatabase(self._db_dir)
|
|
39
|
+
indexing.index_database()
|
|
40
|
+
|
|
35
41
|
def _build_query_and_params(self,
|
|
36
42
|
age: Optional[Union[str, List[str]]] = None,
|
|
37
43
|
var: Optional[Union[str, List[str]]] = None,
|
|
@@ -177,38 +183,40 @@ class Database:
|
|
|
177
183
|
op, val = self._parse_range_query(field)
|
|
178
184
|
if op == '>':
|
|
179
185
|
conditions.append(f"("
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
186
|
+
f"CAST({column} AS INTEGER) > ? OR "
|
|
187
|
+
f"{column} LIKE '%-%' AND CAST(SUBSTR({column}, INSTR({column}, '-') + 1) AS INTEGER) > ?"
|
|
188
|
+
f")")
|
|
183
189
|
params.extend([val, val])
|
|
184
190
|
elif op == '<':
|
|
185
191
|
conditions.append(f"("
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
f"CAST({column} AS INTEGER) < ? OR "
|
|
193
|
+
f"{column} LIKE '%-%' AND CAST(SUBSTR({column}, 1, INSTR({column}, '-') - 1) AS INTEGER) < ?"
|
|
194
|
+
f")")
|
|
189
195
|
params.extend([val, val])
|
|
190
196
|
elif op == '>=':
|
|
191
197
|
conditions.append(f"("
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
198
|
+
f"CAST({column} AS INTEGER) >= ? OR "
|
|
199
|
+
f"{column} LIKE '%-%' AND CAST(SUBSTR({column}, INSTR({column}, '-') + 1) AS INTEGER) >= ?"
|
|
200
|
+
f")")
|
|
195
201
|
params.extend([val, val])
|
|
196
202
|
elif op == '<=':
|
|
197
203
|
conditions.append(f"("
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
f"CAST({column} AS INTEGER) <= ? OR "
|
|
205
|
+
f"{column} LIKE '%-%' AND CAST(SUBSTR({column}, 1, INSTR({column}, '-') - 1) AS INTEGER) <= ?"
|
|
206
|
+
f")")
|
|
201
207
|
params.extend([val, val])
|
|
202
208
|
elif op == '=':
|
|
203
209
|
conditions.append(f"("
|
|
204
|
-
f"({column} = ?
|
|
210
|
+
f"CAST({column} AS INTEGER) = ? OR "
|
|
205
211
|
f"({column} LIKE '%-%' AND CAST(SUBSTR({column}, 1, INSTR({column}, '-')-1) AS INTEGER) <= ? AND CAST(SUBSTR({column}, INSTR({column}, '-')+1) AS INTEGER) >= ?)"
|
|
206
212
|
f")")
|
|
207
213
|
params.extend([val, val, val])
|
|
208
214
|
elif self._is_range_value(field):
|
|
209
215
|
start, end = self._parse_range_value(field)
|
|
216
|
+
start = int(start)
|
|
217
|
+
end = int(end)
|
|
210
218
|
conditions.append(f"("
|
|
211
|
-
f"({column}
|
|
219
|
+
f"CAST({column} AS INTEGER) >= ? AND CAST({column} AS INTEGER) <= ? OR "
|
|
212
220
|
f"({column} LIKE '%-%' AND "
|
|
213
221
|
f"CAST(SUBSTR({column}, 1, INSTR({column}, '-')-1) AS INTEGER) <= ? AND "
|
|
214
222
|
f"CAST(SUBSTR({column}, INSTR({column}, '-')+1) AS INTEGER) >= ?)"
|
|
@@ -240,31 +248,31 @@ class Database:
|
|
|
240
248
|
inverted_op = self._invert_range_operator(op)
|
|
241
249
|
if inverted_op == '>':
|
|
242
250
|
conditions.append(f"("
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
251
|
+
f"CAST({column} AS INTEGER) > ? OR "
|
|
252
|
+
f"{column} LIKE '%-%' AND CAST(SUBSTR({column}, INSTR({column}, '-') + 1) AS INTEGER) > ?"
|
|
253
|
+
f")")
|
|
246
254
|
params.extend([val, val])
|
|
247
255
|
elif inverted_op == '<':
|
|
248
256
|
conditions.append(f"("
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
257
|
+
f"CAST({column} AS INTEGER) < ? OR "
|
|
258
|
+
f"{column} LIKE '%-%' AND CAST(SUBSTR({column}, 1, INSTR({column}, '-') - 1) AS INTEGER) < ?"
|
|
259
|
+
f")")
|
|
252
260
|
params.extend([val, val])
|
|
253
261
|
elif inverted_op == '>=':
|
|
254
262
|
conditions.append(f"("
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
263
|
+
f"CAST({column} AS INTEGER) >= ? OR "
|
|
264
|
+
f"{column} LIKE '%-%' AND CAST(SUBSTR({column}, INSTR({column}, '-') + 1) AS INTEGER) >= ?"
|
|
265
|
+
f")")
|
|
258
266
|
params.extend([val, val])
|
|
259
267
|
elif inverted_op == '<=':
|
|
260
268
|
conditions.append(f"("
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
269
|
+
f"CAST({column} AS INTEGER) <= ? OR "
|
|
270
|
+
f"{column} LIKE '%-%' AND CAST(SUBSTR({column}, 1, INSTR({column}, '-') - 1) AS INTEGER) <= ?"
|
|
271
|
+
f")")
|
|
264
272
|
params.extend([val, val])
|
|
265
273
|
elif inverted_op == '=':
|
|
266
274
|
conditions.append(f"("
|
|
267
|
-
f"({column} = ?
|
|
275
|
+
f"CAST({column} AS INTEGER) = ? OR "
|
|
268
276
|
f"({column} LIKE '%-%' AND CAST(SUBSTR({column}, 1, INSTR({column}, '-')-1) AS INTEGER) <= ? AND CAST(SUBSTR({column}, INSTR({column}, '-')+1) AS INTEGER) >= ?)"
|
|
269
277
|
f")")
|
|
270
278
|
params.extend([val, val, val])
|
|
@@ -642,21 +650,48 @@ class Database:
|
|
|
642
650
|
seen.add(age)
|
|
643
651
|
unique_pairs.append((age, unc))
|
|
644
652
|
|
|
653
|
+
unique_institutes = set()
|
|
654
|
+
for institutes in institutes_list:
|
|
655
|
+
for institute in institutes.split(', '):
|
|
656
|
+
unique_institutes.add(institute.strip())
|
|
657
|
+
|
|
658
|
+
unique_projects = set()
|
|
659
|
+
for projects in projects_list:
|
|
660
|
+
for project in projects.split(', '):
|
|
661
|
+
unique_projects.add(project.strip())
|
|
662
|
+
|
|
663
|
+
unique_radar_instruments = set()
|
|
664
|
+
for radar_instruments in radar_instruments_list:
|
|
665
|
+
for radar_instrument in radar_instruments.split(', '):
|
|
666
|
+
unique_radar_instruments.add(radar_instrument.strip())
|
|
667
|
+
|
|
668
|
+
unique_basins = set()
|
|
669
|
+
for basins in basin_list:
|
|
670
|
+
for basin in basins.split(', '):
|
|
671
|
+
unique_basins.add(basin.strip())
|
|
672
|
+
|
|
673
|
+
df_dataset_sorted = pd.DataFrame({
|
|
674
|
+
'dataset': metadata['dataset'],
|
|
675
|
+
'reference': metadata['reference'],
|
|
676
|
+
'DOI_dataset': metadata['DOI_dataset'],
|
|
677
|
+
'DOI_publication': metadata['DOI_publication']
|
|
678
|
+
}).sort_values('dataset')
|
|
679
|
+
|
|
645
680
|
sorted_ages, sorted_age_unc = zip(*unique_pairs) if unique_pairs else ([], [])
|
|
646
681
|
metadata['age'] = [str(age) for age in sorted_ages]
|
|
647
682
|
metadata['age_unc'] = [str(age_unc) for age_unc in sorted_age_unc]
|
|
648
683
|
metadata['var'] = sorted(set(vars_list))
|
|
649
|
-
metadata['institute'] = sorted(set(
|
|
650
|
-
metadata['project'] = sorted(set(
|
|
684
|
+
metadata['institute'] = sorted(set(unique_institutes))
|
|
685
|
+
metadata['project'] = sorted(set(unique_projects))
|
|
651
686
|
metadata['acquisition_year'] = sorted(set(acq_years_list))
|
|
652
|
-
metadata['dataset'] = list(dict.fromkeys(
|
|
653
|
-
metadata['reference'] = list(dict.fromkeys(
|
|
654
|
-
metadata['DOI_dataset'] = list(dict.fromkeys(
|
|
655
|
-
metadata['DOI_publication'] = list(dict.fromkeys(
|
|
687
|
+
metadata['dataset'] = list(dict.fromkeys(df_dataset_sorted['dataset']))
|
|
688
|
+
metadata['reference'] = list(dict.fromkeys(df_dataset_sorted['reference']))
|
|
689
|
+
metadata['DOI_dataset'] = list(dict.fromkeys(df_dataset_sorted['DOI_dataset']))
|
|
690
|
+
metadata['DOI_publication'] = list(dict.fromkeys(df_dataset_sorted['DOI_publication']))
|
|
656
691
|
metadata['flight_id'] = list(set(metadata['flight_id']))
|
|
657
|
-
metadata['radar_instrument'] = sorted(set(
|
|
692
|
+
metadata['radar_instrument'] = sorted(set(unique_radar_instruments))
|
|
658
693
|
metadata['region'] = sorted(set(region_list))
|
|
659
|
-
metadata['IMBIE_basin'] = sorted(set(
|
|
694
|
+
metadata['IMBIE_basin'] = sorted(set(unique_basins))
|
|
660
695
|
|
|
661
696
|
if retain_query:
|
|
662
697
|
self._md = metadata
|
|
@@ -717,6 +752,7 @@ class Database:
|
|
|
717
752
|
data_dir: Optional[str] = None,
|
|
718
753
|
downsampling_factor: Optional[str] = None,
|
|
719
754
|
disable_tqdm: bool = False,
|
|
755
|
+
fraction_depth: Optional[bool] = False,
|
|
720
756
|
) -> Generator[Tuple[pd.DataFrame, Dict]]:
|
|
721
757
|
"""
|
|
722
758
|
Generates xarray Datasets from HDF5 files, one at a time, with lazy loading.
|
|
@@ -770,13 +806,21 @@ class Database:
|
|
|
770
806
|
irh_index = irh_index[0]
|
|
771
807
|
age_impl.append(age)
|
|
772
808
|
|
|
773
|
-
df[
|
|
809
|
+
df[age] = ds[var][::downsampling_factor, irh_index]
|
|
810
|
+
if fraction_depth:
|
|
811
|
+
if 'ICE_THK' in ds.keys():
|
|
812
|
+
df[age] *= 100/ds['ICE_THK'][::downsampling_factor]
|
|
813
|
+
else:
|
|
814
|
+
df[age] = np.nan
|
|
815
|
+
# print(f'WARNING: flight line {file_md['flight_id']} in {file_md['dataset']} does not have ICE_THK, cannot compute fraction depth, will return NaN')
|
|
774
816
|
|
|
775
817
|
else:
|
|
776
818
|
if var in ds.keys():
|
|
777
819
|
var_impl.append(var)
|
|
778
820
|
df[var] = ds[var][::downsampling_factor]
|
|
779
821
|
|
|
822
|
+
if 0 < len(age_impl) <= 1:
|
|
823
|
+
age_impl = list(age_impl)[0]
|
|
780
824
|
metadata = {
|
|
781
825
|
'dataset': file_md['dataset'],
|
|
782
826
|
'var': var_impl,
|
|
@@ -3,23 +3,42 @@ from tqdm import tqdm
|
|
|
3
3
|
import glob
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import numpy as np
|
|
6
|
-
import xarray as xr
|
|
7
6
|
import sqlite3
|
|
8
7
|
import h5py
|
|
9
8
|
import json
|
|
10
9
|
import ast
|
|
11
10
|
|
|
12
11
|
class IndexDatabase:
|
|
13
|
-
def __init__(self, database_dir: str, file_db: str = 'AntADatabase.db'
|
|
12
|
+
def __init__(self, database_dir: str, file_db: str = 'AntADatabase.db') -> None:
|
|
14
13
|
self._db_dir = database_dir
|
|
15
14
|
self._file_db = os.path.join(self._db_dir, file_db)
|
|
16
|
-
self.
|
|
17
|
-
with open(os.path.join(self._db_dir, self._file_index), 'r', encoding='utf-8') as f:
|
|
18
|
-
self._index = json.load(f)
|
|
15
|
+
self._disable_tqdm = os.getenv("JUPYTER_BOOK_BUILD", False)
|
|
19
16
|
|
|
20
17
|
def index_database(self):
|
|
21
18
|
h5_files = []
|
|
22
|
-
|
|
19
|
+
|
|
20
|
+
dirs = glob.glob(f'{self._db_dir}/*/')
|
|
21
|
+
self._dataset_list = []
|
|
22
|
+
|
|
23
|
+
for d in dirs:
|
|
24
|
+
with open(f'{d}/raw_md.json', 'r', encoding='utf-8') as f:
|
|
25
|
+
unique_data = []
|
|
26
|
+
seen = set()
|
|
27
|
+
index = json.load(f)
|
|
28
|
+
for item in index:
|
|
29
|
+
combo = (item['dataset'], item['DOI publication'], item['DOI dataset'])
|
|
30
|
+
if combo not in seen:
|
|
31
|
+
seen.add(combo)
|
|
32
|
+
unique_data.append({
|
|
33
|
+
"dataset": item['dataset'],
|
|
34
|
+
"citation": item['citation'],
|
|
35
|
+
"DOI publication": item['DOI publication'],
|
|
36
|
+
"DOI dataset": item['DOI dataset']
|
|
37
|
+
})
|
|
38
|
+
for unique in unique_data:
|
|
39
|
+
self._dataset_list.append(unique)
|
|
40
|
+
|
|
41
|
+
for ref in self._dataset_list:
|
|
23
42
|
found_files = glob.glob(f'{self._db_dir}/{ref['dataset']}/h5/*.h5', recursive=False)
|
|
24
43
|
if found_files:
|
|
25
44
|
h5_files.extend(found_files)
|
|
@@ -44,11 +63,11 @@ class IndexDatabase:
|
|
|
44
63
|
)
|
|
45
64
|
''')
|
|
46
65
|
|
|
47
|
-
for row in self.
|
|
66
|
+
for row in self._dataset_list:
|
|
48
67
|
try:
|
|
49
68
|
cursor.execute(
|
|
50
69
|
'INSERT INTO sources (name, citation, DOI_dataset, DOI_publication) VALUES (?, ?, ?, ?)',
|
|
51
|
-
(row['dataset'], row['citation'], row['
|
|
70
|
+
(row['dataset'], row['citation'], row['DOI dataset'], row['DOI publication'])
|
|
52
71
|
)
|
|
53
72
|
except sqlite3.IntegrityError:
|
|
54
73
|
# dataset already exists, skip
|
|
@@ -172,7 +191,7 @@ class IndexDatabase:
|
|
|
172
191
|
)
|
|
173
192
|
''')
|
|
174
193
|
|
|
175
|
-
for f in tqdm(h5_files, desc="Indexing files"):
|
|
194
|
+
for f in tqdm(h5_files, desc="Indexing files", disable=self._disable_tqdm):
|
|
176
195
|
_, file_name = os.path.split(f)
|
|
177
196
|
|
|
178
197
|
with h5py.File(f, 'r') as f:
|
|
@@ -177,6 +177,7 @@ class Plotting:
|
|
|
177
177
|
self,
|
|
178
178
|
metadata: Union[None, Dict, 'MetadataResult'] = None,
|
|
179
179
|
downsampling_factor: Optional[int] = None,
|
|
180
|
+
fraction_depth: Optional[bool] = False,
|
|
180
181
|
title: Optional[str] = None,
|
|
181
182
|
xlim: Optional[tuple] = (None, None),
|
|
182
183
|
ylim: Optional[tuple] = (None, None),
|
|
@@ -197,6 +198,7 @@ class Plotting:
|
|
|
197
198
|
color_by='var',
|
|
198
199
|
metadata=metadata,
|
|
199
200
|
downsampling_factor=downsampling_factor,
|
|
201
|
+
fraction_depth=fraction_depth,
|
|
200
202
|
title=title,
|
|
201
203
|
xlim=xlim,
|
|
202
204
|
ylim=ylim,
|
|
@@ -261,6 +263,7 @@ class Plotting:
|
|
|
261
263
|
self,
|
|
262
264
|
metadata: Union[None, Dict, 'MetadataResult'] = None,
|
|
263
265
|
elevation: Optional[bool] = False,
|
|
266
|
+
fraction_depth: Optional[bool] = False,
|
|
264
267
|
downsampling_factor: Optional[int] = None,
|
|
265
268
|
title: Optional[str] = None,
|
|
266
269
|
xlim: Optional[tuple] = (None, None),
|
|
@@ -402,9 +405,8 @@ class Plotting:
|
|
|
402
405
|
else:
|
|
403
406
|
var = var[0]
|
|
404
407
|
|
|
405
|
-
|
|
406
408
|
all_dfs = []
|
|
407
|
-
for ds, _ in tqdm(self._db.data_generator(metadata, downsampling_factor=downsampling_factor, disable_tqdm=True), desc="Plotting", total=total_traces, unit='trace', disable=self._disable_tqdm):
|
|
409
|
+
for ds, _ in tqdm(self._db.data_generator(metadata, downsampling_factor=downsampling_factor, disable_tqdm=True, fraction_depth=fraction_depth), desc="Plotting", total=total_traces, unit='trace', disable=self._disable_tqdm):
|
|
408
410
|
all_dfs.append(ds)
|
|
409
411
|
df = pd.concat(all_dfs)
|
|
410
412
|
|
|
@@ -478,37 +480,31 @@ class Plotting:
|
|
|
478
480
|
title = f'AntADatabase Basal Unit'
|
|
479
481
|
scatter = plt.scatter(df['PSX']/1000, df['PSY']/1000, c=df[var], cmap=cmap, s=marker_size, vmin=vmin, vmax=vmax, linewidths=0, rasterized=True)
|
|
480
482
|
|
|
481
|
-
elif var in ['IRH_DEPTH'
|
|
482
|
-
if
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
483
|
+
elif var in ['IRH_DEPTH']:
|
|
484
|
+
if cmap == None:
|
|
485
|
+
cmap = cmaps.torch_r
|
|
486
|
+
extend = 'both'
|
|
487
|
+
age = list(metadata['age'])
|
|
488
|
+
if not title:
|
|
489
|
+
if fraction_depth:
|
|
490
|
+
title = f'AntADatabase IRH Fraction Depth'
|
|
491
|
+
else:
|
|
489
492
|
title = f'AntADatabase IRH Depth'
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if cmap == None:
|
|
498
|
-
cmap = cmaps.torch_r
|
|
499
|
-
extend = 'both'
|
|
500
|
-
age = list(metadata['age'])
|
|
501
|
-
if len(age) > 1:
|
|
502
|
-
print('WARNING: Multiple layers provided: ', age,
|
|
503
|
-
'\nSelect a unique age for better results')
|
|
504
|
-
elif len(age) == 0:
|
|
505
|
-
print('No layer provided, please provide a valid age.')
|
|
506
|
-
return
|
|
507
|
-
age = age[0]
|
|
493
|
+
if len(age) > 1:
|
|
494
|
+
print('WARNING: Multiple layers provided: ', age,
|
|
495
|
+
'\nSelect a unique age for better results')
|
|
496
|
+
elif len(age) == 0:
|
|
497
|
+
print('No layer provided, please provide a valid age.')
|
|
498
|
+
return
|
|
499
|
+
if fraction_depth:
|
|
508
500
|
label = r'IRH Fractional Depth [\%]'
|
|
501
|
+
if vmin is None: vmin = 0
|
|
502
|
+
if vmax is None: vmax = 100
|
|
503
|
+
else:
|
|
504
|
+
label = f'IRH Depth [m]'
|
|
509
505
|
|
|
510
506
|
for age in metadata['age']:
|
|
511
|
-
scatter = plt.scatter(df['PSX']/1000, df['PSY']/1000, c=df[
|
|
507
|
+
scatter = plt.scatter(df['PSX']/1000, df['PSY']/1000, c=df[age], cmap=cmap, s=marker_size, vmin=vmin, vmax=vmax, linewidths=0, rasterized=True)
|
|
512
508
|
|
|
513
509
|
if color_by == 'transect_1D':
|
|
514
510
|
flight_id = list(metadata['flight_id'])
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
jupytext:
|
|
3
|
+
formats: md:myst
|
|
4
|
+
text_representation:
|
|
5
|
+
extension: .md
|
|
6
|
+
format_name: myst
|
|
7
|
+
format_version: 0.13
|
|
8
|
+
jupytext_version: 1.11.5
|
|
9
|
+
kernelspec:
|
|
10
|
+
display_name: Python 3
|
|
11
|
+
language: python
|
|
12
|
+
name: python3
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Advanced: Managing the database
|
|
16
|
+
|
|
17
|
+
## Reindexing
|
|
18
|
+
|
|
19
|
+
You may want for example to update the age of the layers in a particular dataset. For this, you just need to modify the ages in the file called `raw_md.json` located under a dataset directory. Then, reindex with the `IndexDatabase` class:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
from anta_database import IndexDatabase
|
|
23
|
+
|
|
24
|
+
db_path = '/home/anthe/documents/data/isochrones/AntADatabase/'
|
|
25
|
+
indexing = IndexDatabase(db_path)
|
|
26
|
+
indexing.index_database()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or simply use the `index_database=True` argument when initializing the `Database`, which runs the IndexDatabase class itself:
|
|
30
|
+
```
|
|
31
|
+
from anta_database import Database
|
|
32
|
+
|
|
33
|
+
db_path = '/home/anthe/documents/data/isochrones/AntADatabase/'
|
|
34
|
+
db = Database(db_path, index_database=True)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## (Re)compile the database
|
|
38
|
+
|
|
39
|
+
You can (re)compile the database, if for example you modify some data in the raw directories or if you add a dataset. For this, make sure to follow the structure:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
AntADatabase/
|
|
43
|
+
├── AntADatabase.db
|
|
44
|
+
├── FirstAuthor_YYYY
|
|
45
|
+
├── raw_md.json # file containing information about the dataset, take example on an existing dataset and see the section below
|
|
46
|
+
├── original_new_column_names.csv # first row: names of columns to keep from raw files, second row: how the columns should be renamed (see section below)
|
|
47
|
+
├── raw/ #Directory with the original files to process
|
|
48
|
+
└── h5/ # Directory were the processed files will be written (it will be created in the process)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Note that the header information in the raw files should be commented out with '#'. The column names of the dataframe should be kept.
|
|
52
|
+
Then use the `CompileDatabase class to compile the database:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
from anta_database import CompileDatabase
|
|
56
|
+
|
|
57
|
+
dir_path_list = [ # list of the dataset subdirectories to compile
|
|
58
|
+
'./Winter_2018',
|
|
59
|
+
'./Sanderson_2024',
|
|
60
|
+
'./Franke_2025',
|
|
61
|
+
'./Cavitte_2020',
|
|
62
|
+
'./Beem_2021',
|
|
63
|
+
'./Bodart_2021/',
|
|
64
|
+
'./Muldoon_2023/',
|
|
65
|
+
'./Ashmore_2020/',
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
compiler = CompileDatabase(dir_path_list)
|
|
69
|
+
compiler.compile()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then reindex (see above). Furthermore, if the depth is not given in meters but TWT, you should set the wave\_speed (units should match values in the file) for conversion and firn\_correction (meters):
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
dir_path = './Wang_2023'
|
|
76
|
+
compiler = CompileDatabase(dir_path, wave_speed=0.1685, firn_correction=15.5)
|
|
77
|
+
compiler.compile()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## The JSON file
|
|
81
|
+
|
|
82
|
+
The `raw_md.json` defines all the metadata of a raw file which we be associated to the corresponding data in the database. This will allow to query the database with all the implemented filters. One should provide all the information that exists if possible:
|
|
83
|
+
One important field is the `data type`, which specifies if the raw files are organised per layers or per flight lines. There are then two possibilities:
|
|
84
|
+
|
|
85
|
+
`data type`: "layer"
|
|
86
|
+
| field | Description | Example Values |
|
|
87
|
+
|-------------------|-------------------------------------------------------------------------------------------------|-------------------------------------|
|
|
88
|
+
| `data type` | `layer` | `'layer'` |
|
|
89
|
+
| `raw file` | Name of the raw file in the raw folder with the correct extension (csv, txt, tab). | `'OIA_EDC_IRH1.csv'` |
|
|
90
|
+
| `dataset` | Name of the dataset corresponding dataset (usually same as the folder name) | `'Cavitte_2020'` |
|
|
91
|
+
| `institute` | Institute(s) that produced the data. | `'BAS'`, `['AWI', 'NASA']` |
|
|
92
|
+
| `project` | Project(s) under which the data were collected. | `'OIB'` |
|
|
93
|
+
| `acquisition year`| Year(s) in which the radar data were acquired. Can be a range. | `'2000-2010'`, `'2005'` |
|
|
94
|
+
| `age` | Age in years before present of the layer. | `'10000'` |
|
|
95
|
+
| `age uncertainty` | Uncertainty on the age of the layer | `'800'` |
|
|
96
|
+
| `citation` | How the dataset should be cited | `'Cavitte et al. 2020'` |
|
|
97
|
+
| `DOI dataset` | DOI that directly links to the original dataset (e.g zenodo, USAP-DC...) | `'https://doi.org/10.15784/601411'` |
|
|
98
|
+
| `DOI publication` | DOI of the associated publication that published the data | `'https://doi.org/10.5194/essd-13-4759-2021'` |
|
|
99
|
+
Example of such a dataset is Cavitte_2020
|
|
100
|
+
|
|
101
|
+
`data type`: "flight line"
|
|
102
|
+
Replace the `raw file` entry by `IRH name` as they are named in the raw files. Then the compilation will use the file name for flight ID.
|
|
103
|
+
| field | Description | Example Values |
|
|
104
|
+
|-------------------|-------------------------------------------------------------------------------------------------|-------------------------------------|
|
|
105
|
+
| `data type` | `flight line` | `'flight line'` |
|
|
106
|
+
| `IRH name` | Name of the IRH layer as is it named in the raw file (e.g. column name) | `'IRH1'` |
|
|
107
|
+
| `age` | Age in years before present of the layer. | `'10000'` |
|
|
108
|
+
Example of such a dataset is Wang_2023
|
|
109
|
+
|
|
110
|
+
## The CSV column file
|
|
111
|
+
|
|
112
|
+
The original_new_column_names.csv pairs the columns in the raw file with associated variables in the database. The minimal information in the file should be:
|
|
113
|
+
- Polar Stereographic coordinates PSX and PSY or lon, lat (will be converted to PSX, PSY)
|
|
114
|
+
- The IRH depth
|
|
115
|
+
|
|
116
|
+
More information can be provided such as flight ID, Ice thickness, acquisition year etc. But the columns should be renamed following the database convention:
|
|
117
|
+
| variable | variable name convention in the Database |
|
|
118
|
+
|-------------------|-------------------------------------------------------------------------------------------------|
|
|
119
|
+
| IRH depth | `IRH_DEPTH` |
|
|
120
|
+
| Ice thickness | `ICE_THK` |
|
|
121
|
+
| Surface elevation | `SURF_ELEV` |
|
|
122
|
+
| Bed elevation | `BED_ELEV` |
|
|
123
|
+
| Distance along transect | `DIST` |
|
|
124
|
+
| `acquisition year`| `acq_year` |
|
|
125
|
+
| `Flight ID` | `Flight_ID` |
|
|
126
|
+
|
|
127
|
+
Note if the acquisition year column is not directly a year YYYY but a string that contains the year, add a third row to provide the pattern to extract the acquisition year from the string.
|
|
128
|
+
|
|
129
|
+
Example of original_new_column_names.csv file:
|
|
130
|
+
```
|
|
131
|
+
timestamp,x,y,thk_m,bedelv_mABSL,IRHdepth_m,line
|
|
132
|
+
acq_year,PSX,PSY,ICE_THK,BED_ELEV,IRH_DEPTH,Flight_ID
|
|
133
|
+
YYYYxxxxxxxxxxxxxxxxxxxxxx
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
For a dataset organized by flight lines, so many IRH depth in the raw files, the original_new_column_names.csv should look like:
|
|
137
|
+
```
|
|
138
|
+
Longitude,Latitude,TWT [ns] (of bed),TWT [ns] (of H1),TWT [ns] (of H2),TWT [ns] (of H3),TWT [ns] (of H4),TWT [ns] (of H5),TWT [ns] (of H6),TWT [ns] (of H7)
|
|
139
|
+
lon,lat,ICE_THK,IRH1,IRH2,IRH3,IRH4,IRH5,IRH6,IRH7
|
|
140
|
+
```
|
|
141
|
+
Where the new column names for the layers correspond to the names you provided in the JSON file.
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
## Notes
|
|
145
|
+
### Multiprocessing
|
|
146
|
+
The compilation uses multiprocessing tools for parallel processing. It first finds all the raw files to process and then distribute the processes on multiple processors. By default, it uses all available cpus on the machine minus 1 (to not completely freeze the machine). However, if there are fewer tasks than cpus (fewer files to process), it will use only as many cpus as there are tasks.
|
|
147
|
+
To manually fix the number of cpus used during the compilation:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
compiler.compile(cpus=2) # Or any integer of choice
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Compilation process
|
|
154
|
+
Needs to be updated.
|