pyshbundle 1.0.0__py2.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.
- pyshbundle/GRACE_Data_Driven_Correction_Vishwakarma.py +346 -0
- pyshbundle/GRACEconstants.py +76 -0
- pyshbundle/GRACEpy.py +172 -0
- pyshbundle/Phase_calc.py +100 -0
- pyshbundle/__init__.py +42 -0
- pyshbundle/basin_avg.py +118 -0
- pyshbundle/clm2cs.py +91 -0
- pyshbundle/clm2sc.py +111 -0
- pyshbundle/conv_sh.py +230 -0
- pyshbundle/cs2sc.py +90 -0
- pyshbundle/eigengrav.py +119 -0
- pyshbundle/gaussian.py +114 -0
- pyshbundle/grule.py +134 -0
- pyshbundle/gsha.py +311 -0
- pyshbundle/gshs.py +253 -0
- pyshbundle/hydro.py +139 -0
- pyshbundle/io.py +1242 -0
- pyshbundle/iplm.py +214 -0
- pyshbundle/ispec.py +108 -0
- pyshbundle/klm2sc.py +103 -0
- pyshbundle/load_longterm_mean.py +93 -0
- pyshbundle/naninterp.py +71 -0
- pyshbundle/neumann.py +134 -0
- pyshbundle/new_io.py +846 -0
- pyshbundle/normalklm.py +121 -0
- pyshbundle/plm.py +304 -0
- pyshbundle/pysh_core.py +733 -0
- pyshbundle/pyshbundle.py +40 -0
- pyshbundle/read_GRACE_SH_paths.py +116 -0
- pyshbundle/reader_replacer.py +271 -0
- pyshbundle/reader_replacer_csr.py +304 -0
- pyshbundle/reader_replacer_itsg.py +301 -0
- pyshbundle/reader_replacer_jpl.py +310 -0
- pyshbundle/sc2cs.py +81 -0
- pyshbundle/shutils.py +827 -0
- pyshbundle/tws_cal.py +87 -0
- pyshbundle/viz_utils.py +313 -0
- pyshbundle-1.0.0.dist-info/LICENSE +33 -0
- pyshbundle-1.0.0.dist-info/METADATA +193 -0
- pyshbundle-1.0.0.dist-info/RECORD +43 -0
- pyshbundle-1.0.0.dist-info/WHEEL +6 -0
- pyshbundle-1.0.0.dist-info/dependency_links.txt +21 -0
- pyshbundle-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
#Created on Tue Jun 28 14:17:50 2022
|
|
5
|
+
#@author: Amin Shakya, Interdisciplinary Center for Water Research (ICWaR), Indian Institute of Science (IISc)
|
|
6
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
7
|
+
# Original Codes
|
|
8
|
+
|
|
9
|
+
#Data-driven approach for leakage and attenuation control
|
|
10
|
+
#based on Vishwakarma et. al., (2021)
|
|
11
|
+
|
|
12
|
+
# Detailed explanation goes here
|
|
13
|
+
|
|
14
|
+
# Input: F, a cell matrix with one column containing SH coefficients
|
|
15
|
+
# : cf, the column in F that contains SH coefficients from GRACE
|
|
16
|
+
# : GaussianR, radius of the Gaussian filter (recommened = 400)
|
|
17
|
+
# : basins, mask functions of basin, a cell data format with one
|
|
18
|
+
# column and each entry is a 360 x 720 matrix with 1 inside the
|
|
19
|
+
# catchment and 0 outside
|
|
20
|
+
|
|
21
|
+
# Output : every output has a size (number of months x basins)
|
|
22
|
+
# : RecoveredTWS, corrected data-driven time-series (Least Squares fit method)
|
|
23
|
+
# : RecoveredTWS2, corrected data-driven time-series (shift and amplify method)
|
|
24
|
+
# : FilteredTS, gaussian filtered GRACE TWS time-series for all the basins.
|
|
25
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
26
|
+
|
|
27
|
+
# License:
|
|
28
|
+
# This file is part of PySHbundle.
|
|
29
|
+
# PySHbundle is free software: you can redistribute it and/or modify
|
|
30
|
+
# it under the terms of the GNU General Public License as published by
|
|
31
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
32
|
+
# (at your option) any later version.
|
|
33
|
+
|
|
34
|
+
# This program is distributed in the hope that it will be useful,
|
|
35
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
36
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
37
|
+
# GNU General Public License for more details.
|
|
38
|
+
|
|
39
|
+
# You should have received a copy of the GNU General Public License
|
|
40
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
41
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
42
|
+
|
|
43
|
+
# Acknowledgement Statement:
|
|
44
|
+
# Please note that PySHbundle has adapted the following code packages,
|
|
45
|
+
# both licensed under GNU General Public License
|
|
46
|
+
# 1. SHbundle: https://www.gis.uni-stuttgart.de/en/research/downloads/shbundle/
|
|
47
|
+
|
|
48
|
+
# 2. Downscaling GRACE Total Water Storage Change using Partial Least Squares Regression
|
|
49
|
+
# https://springernature.figshare.com/collections/Downscaling_GRACE_Total_Water_Storage_Change_using_Partial_Least_Squares_Regression/5054564
|
|
50
|
+
|
|
51
|
+
# Key Papers Referred:
|
|
52
|
+
# 1. Vishwakarma, B. D., Horwath, M., Devaraju, B., Groh, A., & Sneeuw, N. (2017).
|
|
53
|
+
# A data‐driven approach for repairing the hydrological catchment signal damage
|
|
54
|
+
# due to filtering of GRACE products. Water Resources Research,
|
|
55
|
+
# 53(11), 9824-9844. https://doi.org/10.1002/2017WR021150
|
|
56
|
+
|
|
57
|
+
# 2. Vishwakarma, B. D., Zhang, J., & Sneeuw, N. (2021).
|
|
58
|
+
# Downscaling GRACE total water storage change using
|
|
59
|
+
# partial least squares regression. Scientific data, 8(1), 95.
|
|
60
|
+
# https://doi.org/10.1038/s41597-021-00862-6
|
|
61
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
62
|
+
|
|
63
|
+
import numpy as np
|
|
64
|
+
import numpy.matlib as npm
|
|
65
|
+
import scipy as sc
|
|
66
|
+
import scipy.io
|
|
67
|
+
#CS2SC, gsha, gshs, gaussian
|
|
68
|
+
|
|
69
|
+
from . import gaussian
|
|
70
|
+
from . import cs2sc
|
|
71
|
+
from . import gshs
|
|
72
|
+
from . import gsha
|
|
73
|
+
from . import naninterp
|
|
74
|
+
from . import Phase_calc
|
|
75
|
+
|
|
76
|
+
def deg_to_rad(deg: float):
|
|
77
|
+
"""Converts angle from degree to radian
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
deg (float): Angle in degree
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
float: Angle in Radian
|
|
84
|
+
|
|
85
|
+
Todo:
|
|
86
|
+
+ Inbuilt function available in numpy module
|
|
87
|
+
"""
|
|
88
|
+
return deg * np.pi/180
|
|
89
|
+
|
|
90
|
+
def GRACE_Data_Driven_Correction_Vishwakarma(F, cf, GaussianR, basins):
|
|
91
|
+
"""_summary_
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
F (_type_): a cell matrix with one column containing SH coefficients
|
|
95
|
+
cf (_type_): the column in F that contains SH coefficients from GRACE
|
|
96
|
+
GaussianR (_type_): radius of the Gaussian filter (recommened = 400)
|
|
97
|
+
basins (_type_): mask functions of basin, a cell data format with one
|
|
98
|
+
column and each entry is a 360 x 720 matrix with 1 inside the
|
|
99
|
+
catchment and 0 outside
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
Exception: corrected data-driven time-series (Least Squares fit method)
|
|
103
|
+
Exception: corrected data-driven time-series (shift and amplify method)
|
|
104
|
+
Exception: gaussian filtered GRACE TWS time-series for all the basins.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
_type_: _description_
|
|
108
|
+
|
|
109
|
+
Todo:
|
|
110
|
+
+ TypeError
|
|
111
|
+
"""
|
|
112
|
+
deg = 0.5
|
|
113
|
+
deg_rad = deg_to_rad(deg)
|
|
114
|
+
|
|
115
|
+
x = np.linspace(0, 360-deg, int(360/deg))
|
|
116
|
+
y = np.linspace(0, 180-deg, int(180/deg))
|
|
117
|
+
x1 = np.linspace(deg, 360, int(360/deg))
|
|
118
|
+
y1 = np.linspace(deg, 180, int(180/deg))
|
|
119
|
+
lambdd,theta = np.meshgrid(x,y)
|
|
120
|
+
lambdd1,theta1 = np.meshgrid(x1,y1)
|
|
121
|
+
|
|
122
|
+
theta_rad = deg_to_rad(theta)
|
|
123
|
+
theta1_rad = deg_to_rad(theta1)
|
|
124
|
+
|
|
125
|
+
#Areahalfdeg = (6378.137**2)*np.power(10,6)*np.pi/180*(np.multiply(a,b)) #Area matrix
|
|
126
|
+
Areahalfdeg = (6378.137**2)*(((np.pi/180)*lambdd1) - ((np.pi/180)*lambdd))*(np.sin((np.pi/2) - theta_rad) - np.sin((np.pi/2) - theta1_rad))
|
|
127
|
+
|
|
128
|
+
qty = 'water'
|
|
129
|
+
|
|
130
|
+
if type(F) != np.ndarray:
|
|
131
|
+
raise Exception("input GRACE field should be in Numpy Ndarray format, please check guidelines")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
if type(basins) != np.ndarray:
|
|
135
|
+
raise Exception("input basin field should be in Numpy NdArray format, please check guidelines")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
r = F.shape[0] #No of entries in F numpy ndarrray
|
|
139
|
+
|
|
140
|
+
cid = 1 #number of river catchments
|
|
141
|
+
|
|
142
|
+
f = F[:,cf-1:cf]
|
|
143
|
+
l = f[0][0].shape[0]
|
|
144
|
+
cfield = f[0][0].shape[1]
|
|
145
|
+
if cfield == l:
|
|
146
|
+
flag_cs = 0
|
|
147
|
+
else:
|
|
148
|
+
flag_cs = 1
|
|
149
|
+
|
|
150
|
+
Weights = gaussian.gaussian(l-1, GaussianR)
|
|
151
|
+
#gaussian returns weights as a list #gaussian is np.array()
|
|
152
|
+
|
|
153
|
+
try: #Broadcase Weights into dimensions
|
|
154
|
+
filter_ = np.ones([1,(2*(l-1))+1]) * Weights
|
|
155
|
+
except:
|
|
156
|
+
w0 = Weights.shape[0]
|
|
157
|
+
Weights = Weights.reshape(w0,1)
|
|
158
|
+
filter_ = np.ones([1,(2*(l-1))+1]) * Weights
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
#SH Synthesis
|
|
162
|
+
if l == cfield:
|
|
163
|
+
for m in range(r):
|
|
164
|
+
if flag_cs == 0:
|
|
165
|
+
Ft = cs2sc.cs2sc(f[m][0]).astype('longdouble')
|
|
166
|
+
else:
|
|
167
|
+
Ft = f[m][0].astype('longdouble')
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
fFld__, _, _ = gshs.gshs(Ft * filter_, qty, 'cell', int(180/deg), 0, 0)
|
|
171
|
+
ffFld__, _, _ = gshs.gshs((Ft * filter_ * filter_), qty, 'cell', int(180/deg), 0, 0)
|
|
172
|
+
|
|
173
|
+
if m == 0:
|
|
174
|
+
fFld = np.zeros((r,fFld__.shape[0],fFld__.shape[1]), dtype = 'longdouble')
|
|
175
|
+
ffFld = np.zeros((r, ffFld__.shape[0], ffFld__.shape[1]), dtype = 'longdouble')
|
|
176
|
+
|
|
177
|
+
fFld[m] = fFld__
|
|
178
|
+
ffFld[m] = ffFld__
|
|
179
|
+
|
|
180
|
+
long = 360/deg
|
|
181
|
+
Area = Areahalfdeg
|
|
182
|
+
else:
|
|
183
|
+
raise Exception("enter CS coefficients")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
#Declaration of size of the vectors:
|
|
188
|
+
cid = len(basins) #Here basins is a dictionary with each element storing nd array
|
|
189
|
+
tsleaktotalf = np.zeros([r, cid], dtype = 'longdouble')
|
|
190
|
+
tsleaktotalff = np.zeros([r, cid], dtype = 'longdouble')
|
|
191
|
+
|
|
192
|
+
ftsleaktotal = np.zeros([r, cid], dtype = 'longdouble')
|
|
193
|
+
fftsleaktotal = np.zeros([r, cid], dtype = 'longdouble')
|
|
194
|
+
|
|
195
|
+
lhat = np.zeros([r, cid], dtype = 'longdouble')
|
|
196
|
+
|
|
197
|
+
bfDevRegAv = np.zeros([r, cid], dtype = 'longdouble')
|
|
198
|
+
bbfDevRegAv = np.zeros([r, cid], dtype = 'longdouble')
|
|
199
|
+
|
|
200
|
+
FilteredTS = np.zeros([r, cid], dtype = 'longdouble')
|
|
201
|
+
filfilts = np.zeros([r, cid], dtype = 'longdouble')
|
|
202
|
+
|
|
203
|
+
leakage = np.zeros([r, cid], dtype = 'longdouble')
|
|
204
|
+
leakager = np.zeros([r, cid], dtype = 'longdouble')
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
for rbasin in range(0, cid):
|
|
209
|
+
#Get the basin functions ready
|
|
210
|
+
|
|
211
|
+
#Basin functions, filtered basin function and transfer function Kappa
|
|
212
|
+
Rb = basins[rbasin][0]
|
|
213
|
+
csRb = gsha.gsha(Rb, 'mean', 'block', long/2)
|
|
214
|
+
csF = cs2sc.cs2sc(csRb[0:l, 0:l])
|
|
215
|
+
filRb_ = gshs(csF * filter_, 'none', 'cell', int(long/2), 0, 0)
|
|
216
|
+
filRb = filRb_[0]
|
|
217
|
+
kappa = (1-Rb) * filRb
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
fF = np.zeros((fFld__.shape[0],fFld__.shape[1]), dtype = 'longdouble')
|
|
222
|
+
ffF = np.zeros((fFld__.shape[0],fFld__.shape[1]), dtype = 'longdouble')
|
|
223
|
+
for m in range(0,r):
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
fF = np.concatenate((fFld[m,:,int(fF.shape[1]/2):], fFld[m,:,:int(fF.shape[1]/2)]), axis=1)
|
|
227
|
+
ffF = np.concatenate((ffFld[m,:,int(ffF.shape[1]/2):], ffFld[m,:,:int(ffF.shape[1]/2)]), axis=1)
|
|
228
|
+
#if False:
|
|
229
|
+
if np.isnan(fF[:20,:20]).any(): #if there is a gap in time series, fill it with NaNs
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
tsleaktotalf[m][rbasin] = np.nan
|
|
233
|
+
tsleaktotalff[m][rbasin] = np.nan
|
|
234
|
+
FilteredTS[m][rbasin] = np.nan
|
|
235
|
+
filfilts[m][0:rbasin] = np.nan
|
|
236
|
+
bfDevRegAv[m][rbasin] = np.nan
|
|
237
|
+
bbfDevRegAv[m][0:rbasin] = np.nan
|
|
238
|
+
|
|
239
|
+
else:
|
|
240
|
+
#leakage time series from filtered and twice filtered fields
|
|
241
|
+
tsleaktotalf[m][rbasin] = np.sum(fF * kappa * Area) / np.sum(Rb * Area)
|
|
242
|
+
tsleaktotalff[m][rbasin] = np.sum(ffF * kappa * Area) / np.sum(Rb * Area)
|
|
243
|
+
|
|
244
|
+
#time series from filtered fields
|
|
245
|
+
FilteredTS[m][rbasin] = np.sum(fF * Rb * Area) / np.sum(Rb * Area)
|
|
246
|
+
filfilts[m][rbasin] = np.sum(ffF * Rb * Area) / np.sum(Rb * Area)
|
|
247
|
+
|
|
248
|
+
#Deviation integral timeseries
|
|
249
|
+
bfDevRegAv[m][rbasin] = np.sum((fF * Rb - FilteredTS[m][rbasin]) * filRb * Area) / np.sum(Rb * Area) #working 2022-10-20
|
|
250
|
+
bbfDevRegAv[m][rbasin] = np.sum((ffF * Rb - filfilts[m][rbasin]) * filRb * Area) / np.sum(Rb * Area)
|
|
251
|
+
print(m)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
b = list()
|
|
258
|
+
bl = list()
|
|
259
|
+
for i in range(0, cid):
|
|
260
|
+
|
|
261
|
+
A = np.ones([60,2])
|
|
262
|
+
A[:,1] = naninterp(bbfDevRegAv[:, i]) #Pchip interpolate should contain atleast two elements
|
|
263
|
+
|
|
264
|
+
lssol_ = sc.linalg.lstsq(A, naninterp(bfDevRegAv[:, i])) #returns a tuple of solution "x", residue and rank of matrix A; for A x = B
|
|
265
|
+
lssol = lssol_[0]
|
|
266
|
+
|
|
267
|
+
b.append(lssol[2-1])
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
A = np.ones([60,2])
|
|
271
|
+
A[:,1] = naninterp.naninterp(tsleaktotalff[:, i])
|
|
272
|
+
lssol_ = sc.linalg.lstsq(A, naninterp.naninterp(tsleaktotalf[:, i])) #returns a tuple of solution "x", residue and rank of matrix A; for A x = B
|
|
273
|
+
lssol = lssol_[0]
|
|
274
|
+
bl.append(lssol[2-1])
|
|
275
|
+
#Working till here 2022-10-21 1530pm
|
|
276
|
+
|
|
277
|
+
multp = npm.repmat(b, r, 1)
|
|
278
|
+
devint = bfDevRegAv * multp
|
|
279
|
+
multp = npm.repmat(bl, r, 1)
|
|
280
|
+
leakLS = tsleaktotalf * multp
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
ps = Phase_calc.Phase_calc(tsleaktotalf,tsleaktotalff)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
#Compute the near true leakage
|
|
288
|
+
|
|
289
|
+
for i in range(0, cid):
|
|
290
|
+
ftsleaktotal[:,i] = naninterp.naninterp(tsleaktotalf[:,i]) #Replaces gaps (NaN values) with an itnerpolated value in the leakage time series from once filtered fields
|
|
291
|
+
fftsleaktotal[:,i] = naninterp.naninterp(tsleaktotalff[:,i]) #replace the gaps (NaN values) with an interpolated value in leakage time series from twice filtered fields
|
|
292
|
+
|
|
293
|
+
X = sc.fft.fft(ftsleaktotal[:,i]) #take fast Fourier transform #check shape of X 2022-10-21
|
|
294
|
+
p = -ps[0,i] / r #compute the fraction of the time period by which the time series is to be shiftes
|
|
295
|
+
Y = np.exp(1j * np.pi * p * ((np.arange(r)) - r/2) / r) #compute the Conjugate-Symmetric shift
|
|
296
|
+
Z = X * Y #Apply the shift
|
|
297
|
+
|
|
298
|
+
a = sc.fft.ifft(Z) #apply inverse fft
|
|
299
|
+
|
|
300
|
+
con = np.conj(a)
|
|
301
|
+
|
|
302
|
+
s = a + con
|
|
303
|
+
|
|
304
|
+
z = s/2
|
|
305
|
+
|
|
306
|
+
leakage[:,i] = z #shifted timeseries
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
#Shift timeseriecs from once filtered fields in the direction of the time series from twice filtered fields, to later compute the amplitude ratio
|
|
310
|
+
p = ps[0,i] / r #Fraction of a time period to shift data
|
|
311
|
+
Y = np.exp(1j * np.pi * p * ((np.arange(r)) - r/2) / r) #compute the Conjugate-Symmetric shift
|
|
312
|
+
Z = X * Y
|
|
313
|
+
|
|
314
|
+
a = sc.fft.ifft(Z) #apply inverse fft
|
|
315
|
+
|
|
316
|
+
con = np.conj(a)
|
|
317
|
+
|
|
318
|
+
s = a + con
|
|
319
|
+
|
|
320
|
+
z = s/2
|
|
321
|
+
|
|
322
|
+
leakager[:,i] = z #shifted timeseries
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
#compute the ratio between the amplitude of the shifted leakage from once filtered fields and leakage from twice filtered fields
|
|
327
|
+
rfn = leakage/fftsleaktotal
|
|
328
|
+
rfn[(rfn) >= 2] = 1
|
|
329
|
+
rfn[(rfn) <= -2] = -1
|
|
330
|
+
rfn = np.sum(np.abs(rfn), axis = 0)
|
|
331
|
+
rfn=rfn/r # amplitude ratio
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
lhat = leakager * rfn #apply the amplitude ratio to the shifted leakage timeseries from the once filtered fields to get the near true leakage
|
|
335
|
+
lhat[np.isnan(FilteredTS)] = np.nan #reintroduce nan for data gaps
|
|
336
|
+
leakLS[np.isnan(FilteredTS)] = np.nan
|
|
337
|
+
RecoveredTWS = FilteredTS - leakLS - devint
|
|
338
|
+
RecoveredTWS2 = FilteredTS - lhat - devint
|
|
339
|
+
|
|
340
|
+
return RecoveredTWS, RecoveredTWS2, FilteredTS
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Created on Sat May 9 18:49:45 2022
|
|
5
|
+
# This file contains some basic constants:
|
|
6
|
+
# - physical
|
|
7
|
+
# - geodetic (GRS80)
|
|
8
|
+
# @author: Dr. Bramha Dutt Vishwakarma, Interdisciplinary Center for Water Research (ICWaR), Indian Institute of Science (IISc)
|
|
9
|
+
|
|
10
|
+
# License:
|
|
11
|
+
# This file is part of PySHbundle.
|
|
12
|
+
# PySHbundle is free software: you can redistribute it and/or modify
|
|
13
|
+
# it under the terms of the GNU General Public License as published by
|
|
14
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
15
|
+
# (at your option) any later version.
|
|
16
|
+
|
|
17
|
+
# This program is distributed in the hope that it will be useful,
|
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
20
|
+
# GNU General Public License for more details.
|
|
21
|
+
|
|
22
|
+
# You should have received a copy of the GNU General Public License
|
|
23
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Acknowledgement Statement:
|
|
27
|
+
# Please note that PySHbundle has adapted the following code packages,
|
|
28
|
+
# both licensed under GNU General Public License
|
|
29
|
+
# 1. SHbundle: https://www.gis.uni-stuttgart.de/en/research/downloads/shbundle/
|
|
30
|
+
|
|
31
|
+
# 2. Downscaling GRACE Total Water Storage Change using Partial Least Squares Regression
|
|
32
|
+
# https://springernature.figshare.com/collections/Downscaling_GRACE_Total_Water_Storage_Change_using_Partial_Least_Squares_Regression/5054564
|
|
33
|
+
|
|
34
|
+
# Key Papers Referred:
|
|
35
|
+
# 1. Vishwakarma, B. D., Horwath, M., Devaraju, B., Groh, A., & Sneeuw, N. (2017).
|
|
36
|
+
# A data‐driven approach for repairing the hydrological catchment signal damage
|
|
37
|
+
# due to filtering of GRACE products. Water Resources Research,
|
|
38
|
+
# 53(11), 9824-9844. https://doi.org/10.1002/2017WR021150
|
|
39
|
+
|
|
40
|
+
# 2. Vishwakarma, B. D., Zhang, J., & Sneeuw, N. (2021).
|
|
41
|
+
# Downscaling GRACE total water storage change using
|
|
42
|
+
# partial least squares regression. Scientific data, 8(1), 95.
|
|
43
|
+
# https://doi.org/10.1038/s41597-021-00862-6
|
|
44
|
+
|
|
45
|
+
""" This script contains some of the major relavant Physical and Geodetic(GRS80) constants:
|
|
46
|
+
|
|
47
|
+
+ `clight` speed of light - $2.99792458e+8$ $m/s$
|
|
48
|
+
+ `G` Gravitational constant- $6.67259e-11$ $\frac{m^3} {kg \cdot s^2}$
|
|
49
|
+
+ `au` astronomical unit - $149.597870691e+9$ $m$
|
|
50
|
+
|
|
51
|
+
+ `ae` semi-major axis of ellipsoid `GRS 80`- $6378137$ m
|
|
52
|
+
+ `GM` geocentric grav. constant `GRS 80`- $3.986005e+14$ $\frac{m^3}{s^2}$
|
|
53
|
+
+ `J2` earth's dynamic form factor `GRS 80` - $1.08263e-3$ [unitless C20 unnormalized coefficient]
|
|
54
|
+
+ `Omega` mean ang. velocity `GRS 80` - $7.292115e-5 $\frac{rad}{s}$
|
|
55
|
+
|
|
56
|
+
+ `flat` flattening - $\frac{1}{298.257222101}$
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
clight = 2.99792458e8 # speed of light [m/s]
|
|
62
|
+
G = 6.67259e-11 # gravitational constant [m^3 /(kg s^2)]
|
|
63
|
+
au = 149.597870691e9 # astronomical unit [m]
|
|
64
|
+
|
|
65
|
+
# GRS80 defining constants:
|
|
66
|
+
ae = 6378137 # semi-major axis of ellipsoid [m]
|
|
67
|
+
GM = 3.986005e14 # geocentric grav. constant [m^3 / s^2]
|
|
68
|
+
J2 = 1.08263e-3 # earth's dyn. form factor (= -C20 unnormalized)
|
|
69
|
+
Omega = 7.292115e-5 # mean ang. velocity [rad/s]
|
|
70
|
+
|
|
71
|
+
# GRS80 derived constants:
|
|
72
|
+
flat = 1/298.257222101 # flattening
|
|
73
|
+
J4 = -0.237091222e-5 # -C40 unnormalized
|
|
74
|
+
J6 = 0.608347e-8 # -C60 unnormalized
|
|
75
|
+
J8 = -0.1427e-10 # -C80 unnormalized
|
|
76
|
+
|
pyshbundle/GRACEpy.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# License:
|
|
5
|
+
# This file is part of PySHbundle.
|
|
6
|
+
# PySHbundle is free software: you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU General Public License for more details.
|
|
15
|
+
|
|
16
|
+
# You should have received a copy of the GNU General Public License
|
|
17
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
18
|
+
|
|
19
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
20
|
+
|
|
21
|
+
# Acknowledgement Statement:
|
|
22
|
+
# Please note that PySHbundle has adapted the following code packages,
|
|
23
|
+
# both licensed under GNU General Public License
|
|
24
|
+
# 1. SHbundle: https://www.gis.uni-stuttgart.de/en/research/downloads/shbundle/
|
|
25
|
+
|
|
26
|
+
# 2. Downscaling GRACE Total Water Storage Change using Partial Least Squares Regression
|
|
27
|
+
# https://springernature.figshare.com/collections/Downscaling_GRACE_Total_Water_Storage_Change_using_Partial_Least_Squares_Regression/5054564
|
|
28
|
+
|
|
29
|
+
# Key Papers Referred:
|
|
30
|
+
# 1. Vishwakarma, B. D., Horwath, M., Devaraju, B., Groh, A., & Sneeuw, N. (2017).
|
|
31
|
+
# A data‐driven approach for repairing the hydrological catchment signal damage
|
|
32
|
+
# due to filtering of GRACE products. Water Resources Research,
|
|
33
|
+
# 53(11), 9824-9844. https://doi.org/10.1002/2017WR021150
|
|
34
|
+
|
|
35
|
+
# 2. Vishwakarma, B. D., Zhang, J., & Sneeuw, N. (2021).
|
|
36
|
+
# Downscaling GRACE total water storage change using
|
|
37
|
+
# partial least squares regression. Scientific data, 8(1), 95.
|
|
38
|
+
# https://doi.org/10.1038/s41597-021-00862-6
|
|
39
|
+
|
|
40
|
+
import numpy
|
|
41
|
+
from . import GRACEconstants as GC
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def upwcon(degree: int, height):
|
|
45
|
+
"""returns the upward continuation $(R/r)^l$
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
degree (int): Spherical harmonic degree
|
|
49
|
+
height (int): Height above mean Earth radius [m] [scalar/vector]
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
uc (_type_): Upward continuation terms
|
|
53
|
+
|
|
54
|
+
Uses:
|
|
55
|
+
`GRACEconstants.GC`
|
|
56
|
+
|
|
57
|
+
Todo:
|
|
58
|
+
+ Add input checking functionality and raise exceptions
|
|
59
|
+
+ Add reference to formula
|
|
60
|
+
"""
|
|
61
|
+
# Created on Sat May 9 18:49:45 2022
|
|
62
|
+
rr = numpy.divide(GC.ae, numpy.add(GC.ae,height))
|
|
63
|
+
uc = numpy.power(rr, degree)
|
|
64
|
+
|
|
65
|
+
return(uc)
|
|
66
|
+
|
|
67
|
+
def lovenr(lmax: int):
|
|
68
|
+
"""
|
|
69
|
+
Created on Mon May 11 11:09:28 2022
|
|
70
|
+
|
|
71
|
+
Todo:
|
|
72
|
+
+ Add type and input checking functionality
|
|
73
|
+
|
|
74
|
+
_author_: Dr. Bramha Dutt Vishwakarma, Interdisciplinary Center for Water Research (ICWaR), Indian Institute of Science (IISc)
|
|
75
|
+
"""
|
|
76
|
+
l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 30, 40, 50, 70, 100, 150, 200]
|
|
77
|
+
kl = numpy.divide([0,270,-3030,-1940,-1320,-1040,-890,-810,-760,-720,-690,-640,-580,-510,-400,-330,-270,-200,-140,-100, -700],1e4)
|
|
78
|
+
n = range(0, lmax+1, 1)
|
|
79
|
+
kn = numpy.interp(n,l,kl)
|
|
80
|
+
return(kn)
|
|
81
|
+
|
|
82
|
+
def lovenrPREM(lmax:int, frame):
|
|
83
|
+
"""
|
|
84
|
+
Created on Mon May 11 11:51:29 2022
|
|
85
|
+
|
|
86
|
+
@author: Dr. Bramha Dutt Vishwakarma, Interdisciplinary Center for Water Research (ICWaR), Indian Institute of Science (IISc)
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
data = numpy.array([[ 1, -0.28476, 0.00000, 0.10462],
|
|
90
|
+
[2, -0.99297, -0.61274, 0.04661] ,
|
|
91
|
+
[3, -1.05142, -0.58897 , 0.21048] ,
|
|
92
|
+
[4, -1.05378, -0.53513 , 0.23564] ,
|
|
93
|
+
[5, -1.08658, -0.52382 , 0.23186] ,
|
|
94
|
+
[6, -1.14404, -0.54222 , 0.23263] ,
|
|
95
|
+
[7, -1.21254, -0.57464 , 0.24058] ,
|
|
96
|
+
[8, -1.28403, -0.61256 , 0.25308] ,
|
|
97
|
+
[9, -1.35479, -0.65203 , 0.26799] ,
|
|
98
|
+
[10, -1.42330, -0.69140, 0.28419] ,
|
|
99
|
+
[11, -1.48909, -0.72998, 0.30121] ,
|
|
100
|
+
[12, -1.55204, -0.76749, 0.31880] ,
|
|
101
|
+
[13, -1.61221, -0.80381, 0.33684] ,
|
|
102
|
+
[14, -1.66968, -0.83886, 0.35522] ,
|
|
103
|
+
[15, -1.72454, -0.87260, 0.37382] ,
|
|
104
|
+
[16, -1.77684, -0.90499, 0.39251] ,
|
|
105
|
+
[17, -1.82668, -0.93599, 0.41119] ,
|
|
106
|
+
[18, -1.87414, -0.96560, 0.42973] ,
|
|
107
|
+
[19, -1.91928, -0.99382, 0.44804] ,
|
|
108
|
+
[20, -1.96220, -1.02066, 0.46603] ,
|
|
109
|
+
[21, -2.00297, -1.04614, 0.48363] ,
|
|
110
|
+
[22, -2.04169, -1.07029, 0.50078] ,
|
|
111
|
+
[23, -2.07844, -1.09313, 0.51742] ,
|
|
112
|
+
[24, -2.11332, -1.11472, 0.53355] ,
|
|
113
|
+
[25, -2.14642, -1.13511, 0.54912] ,
|
|
114
|
+
[30, -2.28839, -1.22067, 0.61848] ,
|
|
115
|
+
[40, -2.48641, -1.33024, 0.71925] ,
|
|
116
|
+
[50, -2.61710, -1.39016, 0.78410] ,
|
|
117
|
+
[60, -2.71254, -1.42377, 0.82683] ,
|
|
118
|
+
[70, -2.78865, -1.44313, 0.85550] ,
|
|
119
|
+
[80, -2.85368, -1.45474, 0.87479] ,
|
|
120
|
+
[90, -2.91216, -1.46226, 0.88764] ,
|
|
121
|
+
[100, -2.96672, -1.46787, 0.89598] ,
|
|
122
|
+
[120, -3.06983, -1.47811, 0.90421] ,
|
|
123
|
+
[140, -3.16950, -1.49082, 0.90634] ,
|
|
124
|
+
[160, -3.26809, -1.50771, 0.90603] ,
|
|
125
|
+
[180, -3.36633, -1.52909, 0.90532] ,
|
|
126
|
+
[200, -3.48436, -1.55473, 0.90547] ,
|
|
127
|
+
[250, -3.70773, -1.63448, 0.91388] ,
|
|
128
|
+
[300, -3.94607, -1.73053, 0.93714] ,
|
|
129
|
+
[350, -4.17591, -1.83593, 0.97495] ,
|
|
130
|
+
[400, -4.39433, -1.94515, 1.02467] ,
|
|
131
|
+
[500, -4.78872, -2.15940, 1.14615] ,
|
|
132
|
+
[600, -5.12008, -2.35243, 1.27714] ,
|
|
133
|
+
[800, -5.59959, -2.64798, 1.50995] ,
|
|
134
|
+
[1000, -5.88447, -2.83157, 1.67325] ,
|
|
135
|
+
[1500, -6.15106, -3.00957, 1.84797] ,
|
|
136
|
+
[2000, -6.20058, -3.04408, 1.88423] ,
|
|
137
|
+
[3000, -6.21044, -3.05176, 1.89114] ,
|
|
138
|
+
[5000, -6.21155, -3.05324, 1.89118] ,
|
|
139
|
+
[10000, -6.21226, -3.05427, 1.89110]])
|
|
140
|
+
|
|
141
|
+
l = data[:,0]
|
|
142
|
+
hl = data[:,1]
|
|
143
|
+
kl = numpy.divide(data[:,2], l)
|
|
144
|
+
ll = numpy.divide(data[:,3], l)
|
|
145
|
+
|
|
146
|
+
if frame == 'CM':
|
|
147
|
+
hl[0] = hl[0] - 1
|
|
148
|
+
ll[0] = ll[0] - 1
|
|
149
|
+
kl[0] = kl[0] - 1
|
|
150
|
+
print('Love numbers are in center of mass frame')
|
|
151
|
+
elif frame == 'CF':
|
|
152
|
+
hlo = hl[0]
|
|
153
|
+
llo = ll[0]
|
|
154
|
+
hl[0] = (hlo - llo) * 2/3
|
|
155
|
+
ll[0] = (hlo - llo) * (-1/3)
|
|
156
|
+
kl[0] = ((-2/3)*llo) - ((-1/3)*hlo)
|
|
157
|
+
print('Love numbers are in center of figure frame')
|
|
158
|
+
elif frame == 'CE':
|
|
159
|
+
print('Love numbers are in center of solid Earth frame')
|
|
160
|
+
else:
|
|
161
|
+
lovenrPREM.exit('Please choose a compatible frame of reference: one of CM, CF, or CE')
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
n = range(0, lmax+1, 1)
|
|
165
|
+
kn = numpy.interp(n,l,kl)
|
|
166
|
+
hn = numpy.interp(n,l,hl)
|
|
167
|
+
ln = numpy.interp(n,l,ll)
|
|
168
|
+
kn[0] = 0
|
|
169
|
+
hn[0] = 0
|
|
170
|
+
ln[0] = 0
|
|
171
|
+
return(kn,hn,ln)
|
|
172
|
+
|
pyshbundle/Phase_calc.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Created on Thu Jul 14 09:10:27 2022
|
|
5
|
+
|
|
6
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
7
|
+
# Summary of this function goes here
|
|
8
|
+
# calculates the phase difference between two time series based on the
|
|
9
|
+
# Hilbert transform method explained by Phillip et al.
|
|
10
|
+
|
|
11
|
+
# Phillips, T., R. S. Nerem, B. Fox-Kemper, J. S. Famiglietti, and B. Rajagopalan (2012),
|
|
12
|
+
# The influence of ENSO on global terrestrial water storage using GRACE, Geophysical
|
|
13
|
+
# Research Letters, 39 (16), L16,705, doi:10.1029/2012GL052495.
|
|
14
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
15
|
+
|
|
16
|
+
# License:
|
|
17
|
+
# This file is part of PySHbundle.
|
|
18
|
+
# PySHbundle is free software: you can redistribute it and/or modify
|
|
19
|
+
# it under the terms of the GNU General Public License as published by
|
|
20
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
21
|
+
# (at your option) any later version.
|
|
22
|
+
|
|
23
|
+
# This program is distributed in the hope that it will be useful,
|
|
24
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
25
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
26
|
+
# GNU General Public License for more details.
|
|
27
|
+
|
|
28
|
+
# You should have received a copy of the GNU General Public License
|
|
29
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
30
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
31
|
+
|
|
32
|
+
# Acknowledgement Statement:
|
|
33
|
+
# Please note that PySHbundle has adapted the following code packages,
|
|
34
|
+
# both licensed under GNU General Public License
|
|
35
|
+
# 1. SHbundle: https://www.gis.uni-stuttgart.de/en/research/downloads/shbundle/
|
|
36
|
+
|
|
37
|
+
# 2. Downscaling GRACE Total Water Storage Change using Partial Least Squares Regression
|
|
38
|
+
# https://springernature.figshare.com/collections/Downscaling_GRACE_Total_Water_Storage_Change_using_Partial_Least_Squares_Regression/5054564
|
|
39
|
+
|
|
40
|
+
# Key Papers Referred:
|
|
41
|
+
# 1. Vishwakarma, B. D., Horwath, M., Devaraju, B., Groh, A., & Sneeuw, N. (2017).
|
|
42
|
+
# A data‐driven approach for repairing the hydrological catchment signal damage
|
|
43
|
+
# due to filtering of GRACE products. Water Resources Research,
|
|
44
|
+
# 53(11), 9824-9844. https://doi.org/10.1002/2017WR021150
|
|
45
|
+
|
|
46
|
+
# 2. Vishwakarma, B. D., Zhang, J., & Sneeuw, N. (2021).
|
|
47
|
+
# Downscaling GRACE total water storage change using
|
|
48
|
+
# partial least squares regression. Scientific data, 8(1), 95.
|
|
49
|
+
# https://doi.org/10.1038/s41597-021-00862-6
|
|
50
|
+
|
|
51
|
+
# @author: Amin Shakya, Interdisciplinary Center for Water Research (ICWaR), Indian Institute of Science (IISc)
|
|
52
|
+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
53
|
+
|
|
54
|
+
import scipy as sc
|
|
55
|
+
from scipy import signal as signal
|
|
56
|
+
import numpy as np
|
|
57
|
+
|
|
58
|
+
def Phase_calc(fts, ffts):
|
|
59
|
+
"""calculates the phase difference between two time series based on the
|
|
60
|
+
Hilbert transform method explained by Phillip et al.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
fts (np.ndarray): _description_
|
|
64
|
+
ffts (np.ndarray): _description_
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
_type_: _description_
|
|
68
|
+
|
|
69
|
+
References:
|
|
70
|
+
1. Phillips, T., R. S. Nerem, B. Fox-Kemper, J. S. Famiglietti, and B. Rajagopalan (2012),
|
|
71
|
+
The influence of ENSO on global terrestrial water storage using GRACE, Geophysical
|
|
72
|
+
Research Letters, 39 (16), L16,705, doi:10.1029/2012GL052495.
|
|
73
|
+
"""
|
|
74
|
+
c = fts.shape[1]
|
|
75
|
+
|
|
76
|
+
ps = np.zeros((1, c))
|
|
77
|
+
|
|
78
|
+
filter_ = ~np.isnan(fts)
|
|
79
|
+
filter__ = ~np.isnan(ffts)
|
|
80
|
+
|
|
81
|
+
fts_ = fts[filter_] #Extract values and leave Nan
|
|
82
|
+
ffts_ = ffts[filter__] #Extract values and leave Nan
|
|
83
|
+
|
|
84
|
+
fts = fts_.reshape(int(fts_.shape[0]/c),c)
|
|
85
|
+
ffts = ffts_.reshape(int(ffts_.shape[0]/c),c)
|
|
86
|
+
|
|
87
|
+
rn = fts.shape[0]
|
|
88
|
+
|
|
89
|
+
for i in range(c):
|
|
90
|
+
# A = np.concatenate(np.ones((rn,1)), np.real(signal.hilbert(ffts[:, i])), np.imag(signal.hilbert(ffts[:, i]))) #design matrix
|
|
91
|
+
|
|
92
|
+
A = np.array((np.ones((rn)), np.real(signal.hilbert(ffts[:, i])), np.imag(signal.hilbert(ffts[:, i])))).T
|
|
93
|
+
|
|
94
|
+
A = A.astype('double')
|
|
95
|
+
B = fts[:,i]
|
|
96
|
+
B = B.astype('double')
|
|
97
|
+
abc = np.linalg.lstsq(A.T @ A, A.T @ B)[0]
|
|
98
|
+
|
|
99
|
+
ps[0,i] = np.arctan2(abc[3-1],abc[2-1])*(180/np.pi) #check indices and degree/radian
|
|
100
|
+
return ps
|