Skip to content

Commit 9c252b5

Browse files
authored
Additions to Seed et al. weights function to prevent numeric instability (#278)
* Additions to weights function to prevent numerical instability by: Preventing the use of a determinant of singular matrix and making sure the correlation of coefficient (np.corrcoef) of the model with itself is always 1.0
1 parent 464525f commit 9c252b5

File tree

1 file changed

+19
-2
lines changed

1 file changed

+19
-2
lines changed

pysteps/blending/steps.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,24 +1435,38 @@ def calculate_weights_spn(correlations, cov):
14351435
# Check if the correlations are positive, otherwise rho = 10e-5
14361436
correlations = np.where(correlations < 10e-5, 10e-5, correlations)
14371437

1438-
if correlations.shape[0] > 1:
1438+
if correlations.shape[0] > 1 and len(cov) > 1:
14391439
if isinstance(cov, type(None)):
14401440
raise ValueError("cov must contain a covariance matrix")
14411441
else:
1442+
print(cov)
14421443
# Make a numpy matrix out of cov and get the inverse
1444+
cov = np.where(cov == 0.0, 10e-5, cov)
1445+
# Make sure the determinant of the matrix is not zero, otherwise
1446+
# subtract 10e-5 from the cross-correlations between the models
1447+
if np.linalg.det(cov) == 0.0:
1448+
cov = cov - 10e-5
1449+
# Ensure the correlation of the model with itself is always 1.0
1450+
for i, _ in enumerate(cov):
1451+
cov[i][i] = 1.0
1452+
# Make a numpy matrix out of the array
14431453
cov_matrix = np.asmatrix(cov)
1454+
# Get the inverse of the matrix
14441455
cov_matrix_inv = cov_matrix.getI()
14451456
# The component weights are the dot product between cov_matrix_inv
14461457
# and cor_vec
14471458
weights = cov_matrix_inv.dot(correlations)
1459+
weights = np.nan_to_num(
1460+
weights, copy=True, nan=10e-5, posinf=10e-5, neginf=10e-5
1461+
)
14481462
# If the dot product of the weights with the correlations is
14491463
# larger than 1.0, we assign a weight of 0.0 to the noise (to make
14501464
# it numerically stable)
14511465
if weights.dot(correlations) > 1.0:
14521466
noise_weight = np.array([0])
14531467
# Calculate the noise weight
14541468
else:
1455-
noise_weight = np.asarray(np.sqrt(1 - weights.dot(correlations)))[0]
1469+
noise_weight = np.asarray(np.sqrt(1.0 - weights.dot(correlations)))[0]
14561470
# Make sure the weights are positive, otherwise weight = 0.0
14571471
weights = np.where(weights < 0.0, 0.0, weights)[0]
14581472
# Finally, add the noise_weights to the weights variable.
@@ -1467,6 +1481,9 @@ def calculate_weights_spn(correlations, cov):
14671481
noise_weight = 1.0 - correlations
14681482
weights = np.concatenate((correlations, noise_weight), axis=0)
14691483

1484+
# Make sure weights are always a real number
1485+
weights = np.nan_to_num(weights, copy=True, nan=10e-5, posinf=10e-5, neginf=10e-5)
1486+
14701487
return weights
14711488

14721489

0 commit comments

Comments
 (0)