ticoi 0.0.1__py3-none-any.whl
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.
Potentially problematic release.
This version of ticoi might be problematic. Click here for more details.
- ticoi/__about__.py +1 -0
- ticoi/__init__.py +0 -0
- ticoi/core.py +1500 -0
- ticoi/cube_data_classxr.py +2204 -0
- ticoi/cube_writer.py +741 -0
- ticoi/example.py +81 -0
- ticoi/filtering_functions.py +676 -0
- ticoi/interpolation_functions.py +236 -0
- ticoi/inversion_functions.py +1015 -0
- ticoi/mjd2date.py +31 -0
- ticoi/optimize_coefficient_functions.py +264 -0
- ticoi/pixel_class.py +1830 -0
- ticoi/seasonality_functions.py +209 -0
- ticoi/utils.py +725 -0
- ticoi-0.0.1.dist-info/METADATA +152 -0
- ticoi-0.0.1.dist-info/RECORD +18 -0
- ticoi-0.0.1.dist-info/WHEEL +4 -0
- ticoi-0.0.1.dist-info/licenses/LICENSE +165 -0
ticoi/mjd2date.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# From Jeremie Mouginot
|
|
2
|
+
|
|
3
|
+
import jdcal
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
# make jdcal external library data-type friendly (-datatime- and -integer- instead tuples)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def mjd2date(date):
|
|
10
|
+
"""
|
|
11
|
+
Convert the dates from Modified Julian Date to Gregorian Date
|
|
12
|
+
Modified Julian Date MJD = JD-2400001.5 , 17 November 1858=0.
|
|
13
|
+
:param date: Modified Julian Date, integer
|
|
14
|
+
:return: Gregoryan date, datatime type
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
t = jdcal.jd2gcal(2400000.5, date)
|
|
18
|
+
return np.datetime64(f"{t[0]}-{f'{t[1]:02}'}-{f'{t[2]:02}'}")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def date2mjd(date):
|
|
22
|
+
"""Convert from Gregorian Date to Modified Julian Date.
|
|
23
|
+
:param date: Gregorian Date, datatime type
|
|
24
|
+
:return: Modified Julian Date, integer"""
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
JD = jdcal.gcal2jd(date.year, date.month, date.day)
|
|
28
|
+
except:
|
|
29
|
+
date = date.astype("M8[D]").astype("O")
|
|
30
|
+
JD = jdcal.gcal2jd(date.year, date.month, date.day)
|
|
31
|
+
return int(JD[1])
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import itertools
|
|
3
|
+
|
|
4
|
+
import matplotlib.pyplot as plt
|
|
5
|
+
import numpy as np
|
|
6
|
+
from joblib import Parallel, delayed
|
|
7
|
+
from tqdm import tqdm
|
|
8
|
+
|
|
9
|
+
from ticoi.core import chunk_to_block, load_block
|
|
10
|
+
from ticoi.utils import optimize_coef
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def process_block(
|
|
14
|
+
cube,
|
|
15
|
+
block,
|
|
16
|
+
cube_gt,
|
|
17
|
+
load_pixel_kwargs,
|
|
18
|
+
inversion_kwargs,
|
|
19
|
+
interpolation_kwargs,
|
|
20
|
+
optimization_method="stable_ground",
|
|
21
|
+
regu=None,
|
|
22
|
+
flag=None,
|
|
23
|
+
cmin=10,
|
|
24
|
+
cmax=1000,
|
|
25
|
+
step=10,
|
|
26
|
+
coefs=None,
|
|
27
|
+
nb_cpu=8,
|
|
28
|
+
preData_kwargs=None,
|
|
29
|
+
):
|
|
30
|
+
"""Optimize the coef on a given block"""
|
|
31
|
+
|
|
32
|
+
if optimization_method == "stable_ground": # We only compute stable ground pixels
|
|
33
|
+
xy_values = list(
|
|
34
|
+
filter(
|
|
35
|
+
bool,
|
|
36
|
+
[
|
|
37
|
+
(x, y) if flag.sel(x=x, y=y)["flag"].values == 0 else False
|
|
38
|
+
for x in flag["x"].values
|
|
39
|
+
for y in flag["y"].values
|
|
40
|
+
],
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
else:
|
|
44
|
+
xy_values = list(itertools.product(cube.ds["x"].values, cube.ds["y"].values))
|
|
45
|
+
|
|
46
|
+
# Progression bar
|
|
47
|
+
xy_values_tqdm = tqdm(xy_values, total=len(xy_values))
|
|
48
|
+
|
|
49
|
+
# Filter cube
|
|
50
|
+
obs_filt, flag_block = block.filter_cube_before_inversion(**preData_kwargs, flag=flag)
|
|
51
|
+
|
|
52
|
+
# Optimization of the coefficient for every pixels of the block
|
|
53
|
+
# (faster using parallelization here and sequential processing in optimize_coef)
|
|
54
|
+
result_block = Parallel(n_jobs=nb_cpu, verbose=0)(
|
|
55
|
+
delayed(optimize_coef)(
|
|
56
|
+
block,
|
|
57
|
+
cube_gt,
|
|
58
|
+
i,
|
|
59
|
+
j,
|
|
60
|
+
obs_filt,
|
|
61
|
+
load_pixel_kwargs,
|
|
62
|
+
inversion_kwargs,
|
|
63
|
+
interpolation_kwargs,
|
|
64
|
+
method=optimization_method,
|
|
65
|
+
regu=regu,
|
|
66
|
+
flag=flag_block,
|
|
67
|
+
cmin=cmin,
|
|
68
|
+
cmax=cmax,
|
|
69
|
+
step=step,
|
|
70
|
+
coefs=coefs,
|
|
71
|
+
stats=True,
|
|
72
|
+
parallel=False,
|
|
73
|
+
visual=False,
|
|
74
|
+
)
|
|
75
|
+
for i, j in xy_values_tqdm
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return result_block
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
async def process_blocks_main(
|
|
82
|
+
cube,
|
|
83
|
+
cube_gt,
|
|
84
|
+
load_pixel_kwargs,
|
|
85
|
+
inversion_kwargs,
|
|
86
|
+
preData_kwargs,
|
|
87
|
+
interpolation_kwargs,
|
|
88
|
+
optimization_method="stable_ground",
|
|
89
|
+
regu=None,
|
|
90
|
+
flag=None,
|
|
91
|
+
cmin=10,
|
|
92
|
+
cmax=1000,
|
|
93
|
+
step=10,
|
|
94
|
+
coefs=None,
|
|
95
|
+
nb_cpu=8,
|
|
96
|
+
block_size=0.5,
|
|
97
|
+
verbose=False,
|
|
98
|
+
):
|
|
99
|
+
"""Main function for the optimization of the coef using a block processing approach"""
|
|
100
|
+
|
|
101
|
+
blocks = chunk_to_block(cube, block_size=block_size, verbose=True)
|
|
102
|
+
|
|
103
|
+
dataf_list = [None] * (cube.nx * cube.ny)
|
|
104
|
+
|
|
105
|
+
loop = asyncio.get_event_loop()
|
|
106
|
+
|
|
107
|
+
for n in range(len(blocks)):
|
|
108
|
+
print(f"Processing block {n + 1}/{len(blocks)}")
|
|
109
|
+
|
|
110
|
+
# Load the first block and start the loop
|
|
111
|
+
if n == 0:
|
|
112
|
+
x_start, x_end, y_start, y_end = blocks[0]
|
|
113
|
+
future = loop.run_in_executor(None, load_block, cube, x_start, x_end, y_start, y_end)
|
|
114
|
+
|
|
115
|
+
block, block_flag, duration = await future
|
|
116
|
+
if verbose:
|
|
117
|
+
print(f"Block {n + 1} loaded in {duration:.2f} s")
|
|
118
|
+
|
|
119
|
+
if n < len(blocks) - 1:
|
|
120
|
+
# Load the next block while processing the current block
|
|
121
|
+
x_start, x_end, y_start, y_end = blocks[n + 1]
|
|
122
|
+
future = loop.run_in_executor(None, load_block, cube, x_start, x_end, y_start, y_end)
|
|
123
|
+
|
|
124
|
+
block_result = await process_block(
|
|
125
|
+
cube,
|
|
126
|
+
block,
|
|
127
|
+
cube_gt,
|
|
128
|
+
load_pixel_kwargs,
|
|
129
|
+
inversion_kwargs,
|
|
130
|
+
interpolation_kwargs,
|
|
131
|
+
optimization_method=optimization_method,
|
|
132
|
+
regu=regu,
|
|
133
|
+
flag=flag,
|
|
134
|
+
cmin=cmin,
|
|
135
|
+
cmax=cmax,
|
|
136
|
+
step=step,
|
|
137
|
+
coefs=coefs,
|
|
138
|
+
nb_cpu=nb_cpu,
|
|
139
|
+
preData_kwargs=preData_kwargs,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
for i in range(len(block_result)):
|
|
143
|
+
row = i % block.ny + blocks[n][2]
|
|
144
|
+
col = np.floor(i / block.ny) + blocks[n][0]
|
|
145
|
+
idx = int(col * cube.ny + row)
|
|
146
|
+
|
|
147
|
+
dataf_list[idx] = block_result[i]
|
|
148
|
+
|
|
149
|
+
del block_result, block
|
|
150
|
+
|
|
151
|
+
return dataf_list
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def find_good_coefs(
|
|
155
|
+
coefs,
|
|
156
|
+
measures,
|
|
157
|
+
method="stable_ground",
|
|
158
|
+
select_method="min-max relative",
|
|
159
|
+
thresh=None,
|
|
160
|
+
mean_disp=None,
|
|
161
|
+
mean_angle=None,
|
|
162
|
+
visual=False,
|
|
163
|
+
):
|
|
164
|
+
if select_method == "curvature":
|
|
165
|
+
smooth_measures = [
|
|
166
|
+
measures[i - 1] / 4 + measures[i] / 2 + measures[i - 1] / 4 for i in range(1, len(measures) - 1)
|
|
167
|
+
]
|
|
168
|
+
accel = np.array(
|
|
169
|
+
[
|
|
170
|
+
(smooth_measures[i + 1] - 2 * smooth_measures[i] + smooth_measures[i - 1])
|
|
171
|
+
/ ((coefs[i + 2] - coefs[i]) / 2) ** 2
|
|
172
|
+
for i in range(1, len(coefs) - 3)
|
|
173
|
+
]
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
if visual:
|
|
177
|
+
plt.plot(coefs[2:-2], accel)
|
|
178
|
+
plt.ylim([-2 * 10**-6, 0.5 * 10**-6])
|
|
179
|
+
plt.show()
|
|
180
|
+
|
|
181
|
+
if method in ["ground_truth", "stable_ground"]:
|
|
182
|
+
best_coef = coefs[np.argmin(measures)]
|
|
183
|
+
best_measure = np.min(measures)
|
|
184
|
+
good_measure = measures[np.argmin(accel) + 2]
|
|
185
|
+
good_coefs = coefs[measures < good_measure]
|
|
186
|
+
elif method == "vvc":
|
|
187
|
+
best_coef = coefs[np.argmax(measures)]
|
|
188
|
+
best_measure = np.max(measures)
|
|
189
|
+
good_measure = measures[np.argmax(accel) + 2]
|
|
190
|
+
good_coefs = coefs[measures > good_measure]
|
|
191
|
+
|
|
192
|
+
elif select_method == "min-max relative":
|
|
193
|
+
if method in ["ground_truth", "stable_ground"]:
|
|
194
|
+
best_measure = np.min(measures)
|
|
195
|
+
good_measure = best_measure + (1 - thresh / 100) * (np.max(measures) - best_measure)
|
|
196
|
+
best_coef = coefs[np.argmin(measures)]
|
|
197
|
+
good_coefs = coefs[measures < good_measure]
|
|
198
|
+
elif method == "vvc":
|
|
199
|
+
best_measure = np.max(measures)
|
|
200
|
+
good_measure = best_measure - (1 - thresh / 100) * (best_measure - np.min(measures))
|
|
201
|
+
best_coef = coefs[np.argmax(measures)]
|
|
202
|
+
good_coefs = coefs[measures > good_measure]
|
|
203
|
+
|
|
204
|
+
elif select_method == "max relative":
|
|
205
|
+
if method in ["ground_truth", "stable_ground"]:
|
|
206
|
+
best_measure = np.min(measures)
|
|
207
|
+
good_measure = (1 + thresh / 100) * best_measure
|
|
208
|
+
best_coef = coefs[np.argmin(measures)]
|
|
209
|
+
good_coefs = coefs[measures < good_measure]
|
|
210
|
+
elif method == "vvc":
|
|
211
|
+
best_measure = np.max(measures)
|
|
212
|
+
good_measure = (1 - thresh / 100) * best_measure
|
|
213
|
+
best_coef = coefs[np.argmax(measures)]
|
|
214
|
+
good_coefs = coefs[measures > good_measure]
|
|
215
|
+
|
|
216
|
+
elif select_method == "absolute":
|
|
217
|
+
if method in ["ground_truth", "stable_ground"]:
|
|
218
|
+
best_measure = np.min(measures)
|
|
219
|
+
good_measure = best_measure + thresh
|
|
220
|
+
best_coef = coefs[np.argmin(measures)]
|
|
221
|
+
good_coefs = coefs[measures < good_measure]
|
|
222
|
+
elif method == "vvc":
|
|
223
|
+
best_measure = np.max(measures)
|
|
224
|
+
good_measure = best_measure - thresh
|
|
225
|
+
best_coef = coefs[np.argmax(measures)]
|
|
226
|
+
good_coefs = coefs[measures > good_measure]
|
|
227
|
+
|
|
228
|
+
elif select_method == "vvc_angle_thresh":
|
|
229
|
+
assert mean_angle is not None, (
|
|
230
|
+
"Mean angle to median direction over the area must be given for 'vvc_angle_thresh' selection method"
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
dVVC = abs(-np.sin(mean_angle) / (2 * np.sqrt(2 * (1 + np.cos(mean_angle)))) * thresh)
|
|
234
|
+
if visual:
|
|
235
|
+
print(mean_angle * 360 / (2 * np.pi))
|
|
236
|
+
print(dVVC)
|
|
237
|
+
|
|
238
|
+
return find_good_coefs(coefs, measures, method="vvc", select_method="absolute", thresh=dVVC)
|
|
239
|
+
|
|
240
|
+
elif select_method == "vvc_disp_thresh":
|
|
241
|
+
assert mean_disp is not None, (
|
|
242
|
+
"Mean displacements over the area must be given for 'vvc_disp_thresh' selection method"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
vx, vy = mean_disp
|
|
246
|
+
v0 = np.array([vx - thresh, vy + thresh])
|
|
247
|
+
v1 = np.array([vx + thresh, vy - thresh])
|
|
248
|
+
d_angle = np.arccos((v0[0] * v1[0] + v0[1] * v1[1]) / (np.linalg.norm(v0) * np.linalg.norm(v1)))
|
|
249
|
+
|
|
250
|
+
if visual:
|
|
251
|
+
print(mean_disp)
|
|
252
|
+
print(d_angle * 360 / (2 * np.pi))
|
|
253
|
+
|
|
254
|
+
return find_good_coefs(
|
|
255
|
+
coefs,
|
|
256
|
+
measures,
|
|
257
|
+
method == "vvc",
|
|
258
|
+
select_method="vvc_angle_thresh",
|
|
259
|
+
thresh=d_angle,
|
|
260
|
+
mean_angle=mean_angle,
|
|
261
|
+
visual=visual,
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
return good_measure, good_coefs, best_measure, best_coef
|