-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprobdata.py
More file actions
executable file
·183 lines (159 loc) · 6.34 KB
/
Copy pathprobdata.py
File metadata and controls
executable file
·183 lines (159 loc) · 6.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import numpy as np
import scipy.stats as stats
from scipy.integrate import dblquad, fixed_quad
import scipy.optimize as op
def _dblquad0(rvi,rvj,rho0,ns):
""" Computes z1, z2 and x1, x2 values for Gauss integration - Vectorized version"""
stnorm = stats.norm()
mi, vi = rvi.stats(); si = np.sqrt(vi)
mj, vj = rvj.stats(); sj = np.sqrt(vj)
res = np.zeros(np.asarray(rho0).shape)
for i,rhoij in enumerate(rho0):
mulnorm = stats.multivariate_normal([0.,0.], [[1.,rhoij], [rhoij,1.]])
# integration function
def fij(yi,yj):
zi = (rvi.ppf(stnorm.cdf(yi))-mi)/si
zj = (rvj.ppf(stnorm.cdf(yj))-mj)/sj
return zi*zj*mulnorm.pdf([yi,yj])
quadres = dblquad(fij, -ns, ns, lambda x: -ns, lambda x: ns)
res[i] = quadres[0]
return res
def _dblquad(rvi,rvj,rho0,ns,nip):
""" Computes z1, z2 and x1, x2 values for Gauss integration - Vectorized version"""
stnorm = stats.norm()
mi, vi = rvi.stats(); si = np.sqrt(vi)
mj, vj = rvj.stats(); sj = np.sqrt(vj)
res = np.zeros(np.asarray(rho0).shape)
for i,rhoij in enumerate(rho0):
mulnorm = stats.multivariate_normal([0.,0.], [[1.,rhoij], [rhoij,1.]])
# integration function
def fij(yi,yj):
zi = (rvi.ppf(stnorm.cdf(yi))-mi)/si
zj = (rvj.ppf(stnorm.cdf(yj))-mj)/sj
y = np.zeros(np.asarray(yi).shape+(2,))
y[:,0] = yi
y[:,1] = yj
return zi*zj*mulnorm.pdf(y)
def fj(yj):
return fixed_quad(fij, -ns, ns, args=(yj,), n=nip)[0]
quadres = fixed_quad(fj, -ns, ns, n=nip)
res[i] = quadres[0]
return res
class ProbData(object):
""" probdata class, equivalent to probdata struct in FERUM
Attributes:
name: rv name
rvs: list of random variable objects
corr: correlation of random variables
startpoint: start point of FORM
"""
def __init__(self, names, rvs, corr=None, startpoint=None, nataf=False):
self.names = names
self.rvs = rvs
if corr is None:
self.corr = np.eye(np.size(rvs))
else:
self.corr = corr
if startpoint is None:
self.startpoint = np.asarray([rv.mean() for rv in rvs])
else:
self.startpoint = startpoint
self.lo = None
self.ilo = None
self.nataf = nataf
def setcorr(self, corr):
self.corr = corr
def _mod_corr_solve(self, flagsens, verbose, tol=1e-5, ns=5, nip=32):
nrv = np.size(self.rvs)
if flagsens:
dRodrho = np.eye((nrv,nrv))
dRodthetafi.mu = np.zeros((nrv,nrv))
dRodthetafi.sigma = np.zeros((nrv,nrv))
dRodthetafi.p1 = np.zeros((nrv,nrv))
dRodthetafi.p2 = np.zeros((nrv,nrv))
dRodthetafi.p3 = np.zeros((nrv,nrv))
dRodthetafi.p4 = np.zeros((nrv,nrv))
dRodthetafj.mu = np.zeros((nrv,nrv))
dRodthetafj.sigma = np.zeros((nrv,nrv))
dRodthetafj.p1 = np.zeros((nrv,nrv))
dRodthetafj.p2 = np.zeros((nrv,nrv))
dRodthetafj.p3 = np.zeros((nrv,nrv))
dRodthetafj.p4 = np.zeros((nrv,nrv))
else:
dRodrho = None
dRodthetafi = None
dRodthetafj = None
# loop over all off diagonal element of correlation matrix
corrnew = np.ones((nrv,nrv))
for i in range(nrv):
for j in range(i+1, nrv):
rvi = self.rvs[i]
rvj = self.rvs[j]
rho = self.corr[i,j]
mi, vi = rvi.stats(); si = np.sqrt(vi)
mj, vj = rvj.stats(); sj = np.sqrt(vj)
ibound = np.array([mi-ns*si, mi+ns*si])
jbound = np.array([mj-ns*sj, mj+ns*sj])
def objfunc(x):
return abs(_dblquad(rvi, rvj, x, ns)-rho)
#opres = op.minimize_scalar(objfunc, bounds=[-1.0+tol, 1.0-tol], method='Bounded')
test = _dblquad(rvi, rvj, np.array([0.9]), ns, nip=nip)
opres = op.minimize(objfunc, rho, bounds=((-1.0+tol, 1.0-tol),))
rho0 = opres.x
corrnew[i,j] = rho0
for i in range(nrv):
for j in range(i+1, nrv):
corrnew[j,i] = corrnew[i,j]
return corrnew, dRodrho, dRodthetafi, dRodthetafj
def cholesky(self, flagsens, verbose):
# Nataf transformation of correlation matrix
if self.nataf:
if verbose:
print '\n'
print 'Computation of modified correlation matrix R0'
print 'Takes some time if sensitivities are to be computed with gamma (3), beta (7) or chi-square (8) distributions.'
print 'Please wait... (Ctrl+C breaks)'
[corrnew, dRodrho, dRodthetafi, dRodthetafj] = self._mod_corr_solve(flagsens, verbose)
self.corr = corrnew
# Cholesky decomposition
try:
lo = np.linalg.cholesky(self.corr)
except LinAlgError:
print "error in probdata.py cholesky(): self.corr must be positive definitive"
sys.exit(1)
self.lo = lo
self.ilo = np.linalg.inv(lo)
def x_to_u(self, x):
if self.ilo is None:
print "conduct cholesky depcomposition first"
sys.exit(1)
else:
z = np.copy(x)
for i, rv in enumerate(self.rvs):
z[i] = stats.norm.ppf(rv.cdf(x[i]))
u = self.ilo.dot(z)
return u
def u_to_x(self, u):
if self.lo is None:
print "conduct cholesky depcomposition first"
sys.exit(1)
else:
z = np.dot(self.lo, u)
x = np.copy(z)
for i, rv in enumerate(self.rvs):
x[i] = rv.ppf(stats.norm.cdf(z[i]))
return x
def jacobian(self, x, u):
if self.lo is None or self.ilo is None:
print "conduct cholesky depcomposition first"
sys.exit(1)
else:
nrv = np.size(self.rvs)
z = np.dot(self.lo, u)
J_z_x = np.zeros((nrv,nrv))
for i,rv in enumerate(self.rvs):
pdf1 = rv.pdf(x[i])
pdf2 = stats.norm.pdf(z[i])
J_z_x[i,i] = pdf1/pdf2
J_u_x = np.dot(self.ilo, J_z_x)
return J_u_x