Skip to content

Commit 2e191b6

Browse files
authored
Merge pull request #67 from SCIInstitute/uncertainty
Uncertainty
2 parents 606614e + 609d90a commit 2e191b6

19 files changed

+26261
-51
lines changed

FwdInvToolkit.toolkit

Lines changed: 12306 additions & 1 deletion
Large diffs are not rendered by default.

Networks/uncertainty-forward/uncertainty_forward.srn5

Lines changed: 3207 additions & 0 deletions
Large diffs are not rendered by default.

Networks/uncertainty-forward/uncertainty_forward_II.srn5

Lines changed: 3423 additions & 0 deletions
Large diffs are not rendered by default.

Networks/uncertainty-forward/uncertainty_forward_visualization.srn5

Lines changed: 5681 additions & 0 deletions
Large diffs are not rendered by default.

PythonLibrary/ICP/icp.py

Lines changed: 63 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
@author: andrewcorbato
66
"""
7-
def icp(model,data,*args):
7+
def icp(model,data,*arg):
88
# ICP Iterative Closest Point Algorithm. Takes use of
99
# Delaunay tesselation of points in model.
1010
#
@@ -110,66 +110,83 @@ def icp(model,data,*args):
110110
# To clear old global tesselation variables run: "clear global Tes ir jc" (tes_flag=1)
111111
# or run: "clear global Tes Tesind Tesver" (tes_flag=2) in Command Window.
112112
#
113-
# m-file can be downloaded for free at
113+
# based on an m-file can be downloaded for free at
114114
# http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=12627&objectType=FILE
115115
#
116-
# icp version 1.4
117116
#
118-
# written by Per Bergstrm 2007-03-07
119117

120118
import numpy as np
121119
import scipy as sp
122120
from numpy import matlib as ml
123121
from numpy import matrix as mx
122+
import sys
124123

125-
if model == False and data == False:
126-
import sys
127-
sys.exit('ERROR: Only one input. There must be at least two inputs.')
128-
elif model == False:
129-
import sys
130-
sys.exit('ERROR: Model cannot be an empty matrix.')
124+
if model.any() == False and data.any() == False:
125+
raise ValueError('ERROR: Only one input. There must be at least two inputs.')
126+
elif model.any() == False:
127+
raise ValueError('ERROR: Model cannot be an empty matrix.')
131128
global MODEL, DATA, TR, TT, TS
132129

133130
dims_model = np.shape(model)
134131
if dims_model[1]<dims_model[0]:
135-
global MODEL
136132
MODEL = np.transpose(model)
137133
else:
138-
global MODEL
139134
MODEL = model
140135

141136
dims_data = np.shape(data)
142137
if dims_data[1]<dims_data[0]:
143138
data = np.transpose(data)
144139
dims_data = np.shape(data)
145-
global DATA
146140
DATA = data
147141
else:
148-
global DATA
149142
DATA = data
150143

151144
if dims_data[0] is not dims_model[0]:
152-
import sys
153-
sys.exit('ERROR: DATA and MODEL cannot have different dimensions.')
154-
# default options
155-
if len(args) == 0:
156-
options = {'max_iter': 104, 'min_iter': 4,'fitting': 2,'thres': 1e-05, \
145+
raise ValueError('ERROR: DATA and MODEL cannot have different dimensions.')
146+
# default options
147+
if not len(arg)==0:
148+
opt = arg[0]
149+
else:
150+
opt = {'max_iter': 104, 'min_iter': 4,'fitting': [2],'thres': 1e-05, \
157151
'init_flag': 1,'tes_flag': 1, 'delta': 10,'mode': 'rigid', \
158152
'refpnt': np.array([]),}
159-
elif len(args) != 9:
160-
import sys
161-
sys.exit('ERROR: Options dictionary must have 9 entries.')
153+
154+
print(opt)
155+
156+
if not isinstance(opt, dict):
157+
raise ValueError("opt must be dictionary of options")
158+
if not 'max_iter' in opt:
159+
opt['max_iter'] = 104;
160+
if not 'min_iter' in opt:
161+
opt['min_iter'] = 4;
162+
if not 'fitting' in opt:
163+
opt['fitting'] = [2];
164+
if not 'thres' in opt:
165+
opt['thres'] = 1e-5;
166+
if not 'delta' in opt:
167+
opt['delta'] = 10;
168+
if not 'mode' in opt:
169+
opt['mode'] = 'rigid';
170+
if not 'refpnt' in opt:
171+
opt['refpnt'] = np.array([]);
172+
if not 'init_flag' in opt:
173+
opt['init_flag'] = 1;
174+
if not 'tes_flag' in opt:
175+
opt['tes_flag'] = 1;
176+
177+
178+
162179

163180
# move options out of dictionary for ease of use
164-
max_iter = args['max_iter']
165-
min_iter = args['min_iter']
166-
fitting = args['fitting']
167-
thres = args['thres']
168-
init_flag = args['init_flag']
169-
tes_flag = args['tes_flag']
170-
delta = args['delta']
171-
mode = args['mode']
172-
refpnt = args['refpnt']
181+
max_iter = opt['max_iter']
182+
min_iter = opt['min_iter']
183+
fitting = opt['fitting']
184+
thres = opt['thres']
185+
init_flag = opt['init_flag']
186+
tes_flag = opt['tes_flag']
187+
delta = opt['delta']
188+
mode = opt['mode']
189+
refpnt = opt['refpnt']
173190

174191
# input error checks
175192
if (tes_flag != 0 and tes_flag != 1 and tes_flag != 2 and tes_flag != 3):
@@ -178,7 +195,7 @@ def icp(model,data,*args):
178195
must be 0-3.')
179196
if dims_model[1] == dims_model[0] and tes_flag is not 0:
180197
import sys
181-
sys.exit('ERROR: This icp method requires the number of model points \
198+
raise ValueError('ERROR: This icp method requires the number of model points \
182199
to be greater than the dimension')
183200
if max_iter < min_iter:
184201
max_iter = min_iter
@@ -309,9 +326,10 @@ def icp_init(init_flag,fitting):
309326
DATA = DATA + ml.repmat(TT,1,N) # apply transformation
310327
else:
311328
import sys
312-
sys.exit('ERROR: Wrong init_flag')
329+
raise ValueError('ERROR: Wrong init_flag')
313330
###############################################################################
314331
def icp_struct(tes_flag):
332+
global Tes, ir, jc, Tesind, Tesver
315333
if tes_flag != 3:
316334
if tes_flag == 0:
317335
global ir
@@ -321,15 +339,15 @@ def icp_struct(tes_flag):
321339
dims_Tesind = np.shape(Tesind)
322340
if dims_Tesind[0] == 0:
323341
import sys
324-
sys.exit('ERROR: No tesselation system exists')
342+
raise ValueError('ERROR: No tesselation system exists')
325343
else:
326344
tes_flag = 2
327345
else:
328346
tes_flag = 1
329347
elif tes_flag == 3:
330348
return tes_flag
331349
else:
332-
global MODEL, Tes
350+
333351
[m,n] = np.shape(MODEL)
334352
if m == 1:
335353
ind1 = np.argsort(MODEL)
@@ -364,7 +382,6 @@ def icp_struct(tes_flag):
364382
Tes = np.sort(np.sort(Tes,axis=1),axis=1)
365383
[mT,nT] = np.shape(Tes)
366384
if tes_flag == 1:
367-
global ir, jc
368385
num = np.zeros((1,n))
369386
for jj in range(0,mT,1):
370387
for kk in range(0,nT,1):
@@ -381,7 +398,6 @@ def icp_struct(tes_flag):
381398
ir[ind[Tes[i,j]]] = i
382399
ind[Tes[i,j]] = ind[Tes[i,j]]+1
383400
else: # tes_flag ==2
384-
global Tesind, Tesver
385401
Tesind = np.zeros(mT,nT)
386402
Tesver = np.zeros(mT,nT)
387403
couvec = np.zeros(mT,1)
@@ -458,8 +474,8 @@ def icp_closest_start(tes_flag,fitting):
458474
# ICP_CLOSEST_START finds indexes of closest MODEL points for each point in DATA.
459475
# The _start version allocates memory for iclosest and finds the closest MODEL points
460476
# to the DATA points
477+
global MODEL, DATA, Tes, ir, jc, iclosest
461478
if tes_flag == 3:
462-
global MODEL, DATA, iclosest
463479
dims_MODEL = np.shape(MODEL)
464480
dims_DATA = np.shape(DATA)
465481
mm = dims_MODEL[1]
@@ -477,25 +493,24 @@ def icp_closest_start(tes_flag,fitting):
477493
ERROR += err(dist,fitting,ID)
478494

479495
elif tes_flag == 1:
480-
global MODEL, DATA, Tes, ir, jc, iclosest
481496
dims_DATA = np.shape(DATA)
482497
md = dims_DATA[1]
483498
dims_MODEL = np.shape(MODEL)
484499
iclosest = np.zeros((1,md))
485500
mid = np.round(md/2)
486-
iclosest(mid) = np.round((dims_MODEL[1]/2))
501+
iclosest[mid] = np.round((dims_MODEL[1]/2))
487502
bol = 1
488503
while bol:
489504
bol = np.logical_not(bol)
490-
distc = np.linalg.norm((DATA[:,mid]-MODEL[:,iclosest(mid)]))
505+
distc = np.linalg.norm((DATA[:,mid]-MODEL[:,iclosest[mid]]))
491506
distcc = 2*distc
492507
for i in range(ir[jc[iclosest[mid]]],ir[jc[iclosest[mid]+1]-1],1):
493508
for ind in Tes[i,:]:
494509
distcc = np.linalg.norm((DATA[:,mid]-MODEL[:,ind]))
495510
if distcc<distc:
496511
distc = distcc
497512
bol = np.logical_not(bol)
498-
iclosest(mid) = ind
513+
iclosest[mid] = ind
499514
break
500515
if bol:
501516
break
@@ -514,7 +529,7 @@ def icp_closest_start(tes_flag,fitting):
514529
if distcc<distc:
515530
distc = distcc
516531
bol = np.logical_not(bol)
517-
iclosest(mid) = ind
532+
iclosest[mid] = ind
518533
break
519534
if bol:
520535
break
@@ -533,10 +548,9 @@ def icp_closest_start(tes_flag,fitting):
533548
if distcc<distc:
534549
distc = distcc
535550
bol = np.logical_not(bol)
536-
iclosest(mid) = ind
551+
iclosest[mid] = ind
537552
break
538553
else: # tes_flag == 2
539-
global MODEL, DATA, Tes, Tesind, Tesver, icTesind, iclosest
540554
dims_DATA = np.shape(DATA)
541555
md = dims_DATA[1]
542556
iclosest = np.zeros((1,md))
@@ -691,8 +705,8 @@ def icp_transformation(fitting,refpnt,delta,optmode):
691705
b = np.concatenate(0,DATA[0,n],0,0,DATA[1,n],0,0,DATA[2,n],0,0,1,0, axis=1)
692706
c = np.concatenate(0,0,DATA[0,n],0,0,DATA[1,n],0,0,DATA[2,n],0,0,1, axis=1)
693707
P[ind,:] = np.concatenate(a,b,c, axis=0)
694-
q[ind] = MODEL[0:2,iclosest[p_ind[n]]
695-
ind += 3
708+
q[ind] = MODEL[0:2,iclosest[p_ind[n]]]
709+
ind = 3
696710
if mode == 'affine':
697711
theta = q/P
698712
a_r = np.concatenate(theta[0],theta[3],theta[6],axis=0)
@@ -734,7 +748,7 @@ def err(dist,fitting,ind):
734748
ERR = dist**2
735749
else:
736750
ERR = 0
737-
print(WARNING: Unknown fitting value.)
751+
print('WARNING: Unknown fitting value.')
738752
return ERR
739753
###############################################################################
740754
def weightfcn(distances):
@@ -745,4 +759,4 @@ def weightfcn(distances):
745759
else:
746760
weights = max_distances+min_distances-distances
747761
weights = weights/np.sum(weights)
748-
return weights
762+
return weights

PythonLibrary/uncertainty/demo.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Shows some PCE analysis from samples:
2+
# - generation of samples
3+
# - construction of PCE coefficients
4+
# - sensitivity analysis of PCE coefficients
5+
# - comparison of PCE predictor versus truth
6+
7+
import itertools
8+
import numpy as np
9+
from matplotlib import pyplot as plt
10+
11+
import indexing, wafp, sensitivity
12+
from test_functions import genz_oscillatory
13+
from opolynd import opolynd_eval
14+
from recurrence import jacobi_recurrence
15+
16+
# construction of our "expensive model". Here just a collection of
17+
# not-so-complicated test functions.
18+
Nx = 100 # Number of "spatial" grid points (here, space is 1D)
19+
x = np.linspace(0, 1, Nx) # spatial grid
20+
print(x)
21+
22+
def expensive_model(zz,xx):
23+
"""
24+
Evaluates a toy function as if it were an expensive model.
25+
26+
x is a "spatial" grid (numpy array)
27+
z is a single d-variate parameter/random variable instance.
28+
29+
Returns an array shaped like xx.
30+
"""
31+
32+
r = 2. # Fixed input into genz oscillatory function
33+
34+
d = zz.size
35+
36+
f = np.zeros(xx.shape)
37+
for ind,xval in np.ndenumerate(xx):
38+
f[ind] = genz_oscillatory(xval*np.ones(d), r)(zz)
39+
40+
return f
41+
42+
######## Step 1: generate samples
43+
44+
d = 2 # dimension of random/parameter space
45+
k = 7 # polynomial degree (parameter space)
46+
poly_space = indexing.total_degree_indices
47+
48+
lambdas = poly_space(d, k)
49+
N = lambdas.shape[0]
50+
51+
M = N + 10 # Number of samples (expensive model runs) to perform. Must
52+
# be at least N, but the +10 is arbitrary.
53+
# Of course, large M ===> better.
54+
55+
candidate_mesh_size = int(2e2)
56+
57+
print("Generating parameter mesh...")
58+
z = wafp.legendre_wafp(lambdas, M=candidate_mesh_size)
59+
z = wafp.legendre_wafp_enrichment(z, lambdas, M-N)
60+
61+
# The samples are the array z, each row is a d-dimensional sample on the
62+
# hypercube [-1,1]^d. The particular way these points are generated is
63+
# random, so you'll get a different set of z each time this is fun, but
64+
# the "quality" of the grid has relatively low variance from run to run.
65+
# This takes a while, but these points may be stored for future use.
66+
67+
######## Step 2: run "expensive" model
68+
69+
u = np.zeros([Nx, M])
70+
71+
print("Evaluating model on mesh...")
72+
for ind,zval in enumerate(z):
73+
u[:,ind] = expensive_model(zval, x)
74+
75+
print(u)
76+
77+
# Each column of u is a model run for a fixed parameter value
78+
79+
######## Step 3: compute PCE coefficients
80+
print("Assembling PCE coefficients...")
81+
ab = jacobi_recurrence(lambdas.max()+1, alpha=0., beta=0., probability=True)
82+
V = opolynd_eval(z, lambdas, ab)
83+
weights = np.sqrt(float(N)/float(M)) / np.sqrt(np.sum(V**2,axis=1))
84+
85+
# The PCE coefficients are computed as a weighted discrete least-squares
86+
# estimator with the weights above.
87+
coeffs = np.linalg.lstsq( (V.T*weights).T, (u*weights).T)[0].T
88+
89+
# Each row of coeffs contains PCE coefficients for a single x gridpoint.
90+
# Each column of coeffs contains a particular PCE coefficient for all
91+
# values of x.
92+
93+
######## Step 4: whatever postprocessing you want
94+
print("Processing PCE coefficients...")
95+
# Compute total sensitivities
96+
total_sensitivities = sensitivity.pce_total_sensitivity(coeffs.T, lambdas, list(range(d)))
97+
98+
# Compute global sensitivities
99+
# Compute main-effect and main-interaction sensitivities
100+
Js = [[j] for j in range(d)]
101+
[Js.append(comb) for comb in itertools.combinations(list(range(d)), 2)]
102+
103+
global_sensitivities = sensitivity.pce_global_sensitivity(coeffs.T, lambdas, Js)
104+
105+
# Compare surrogate discrepancy at validation points
106+
M_validation = 100
107+
z_validation = np.random.uniform(0, 1, [100, d])
108+
109+
u_truth = np.zeros([Nx, M_validation])
110+
for ind, zval in enumerate(z_validation):
111+
u_truth[:,ind] = expensive_model(zval, x)
112+
113+
u_pce = np.zeros([Nx, M_validation])
114+
V = opolynd_eval(z_validation, lambdas, ab)
115+
u_pce = np.dot(V, coeffs.T).T
116+
117+
# Compute l2- and max-errors for each grid point:
118+
l2_error = np.sqrt(np.sum((u_truth - u_pce)**2, axis=1))/np.sqrt(N)
119+
linf_error = np.max(np.abs(u_truth - u_pce), axis=1)
120+
121+
print("L2 error on validation mesh: {0:1.3e}\nMaximum error on validation mesh: {1:1.3e}".format(np.linalg.norm(l2_error)/np.sqrt(Nx), np.max(linf_error.flatten())))
122+
123+
if d == 2:
124+
plt.plot(z[:,0], z[:,1], 'r.')
125+
plt.show()

0 commit comments

Comments
 (0)