1 |
|
|
2 |
######################################################## |
############################################################################## |
3 |
# |
# |
4 |
# Copyright (c) 2003-2012 by University of Queensland |
# Copyright (c) 2003-2013 by University of Queensland |
5 |
# Earth Systems Science Computational Center (ESSCC) |
# http://www.uq.edu.au |
|
# http://www.uq.edu.au/esscc |
|
6 |
# |
# |
7 |
# Primary Business: Queensland, Australia |
# Primary Business: Queensland, Australia |
8 |
# Licensed under the Open Software License version 3.0 |
# Licensed under the Open Software License version 3.0 |
9 |
# http://www.opensource.org/licenses/osl-3.0.php |
# http://www.opensource.org/licenses/osl-3.0.php |
10 |
# |
# |
11 |
######################################################## |
# Development until 2012 by Earth Systems Science Computational Center (ESSCC) |
12 |
|
# Development since 2012 by School of Earth Sciences |
13 |
|
# |
14 |
|
############################################################################## |
15 |
|
|
16 |
__copyright__="""Copyright (c) 2003-2012 by University of Queensland |
__copyright__="""Copyright (c) 2003-2013 by University of Queensland |
17 |
Earth Systems Science Computational Center (ESSCC) |
http://www.uq.edu.au |
|
http://www.uq.edu.au/esscc |
|
18 |
Primary Business: Queensland, Australia""" |
Primary Business: Queensland, Australia""" |
19 |
__license__="""Licensed under the Open Software License version 3.0 |
__license__="""Licensed under the Open Software License version 3.0 |
20 |
http://www.opensource.org/licenses/osl-3.0.php""" |
http://www.opensource.org/licenses/osl-3.0.php""" |
21 |
__url__="https://launchpad.net/escript-finley" |
__url__="https://launchpad.net/escript-finley" |
22 |
|
|
23 |
|
__all__ = ['Regularization'] |
24 |
|
|
25 |
|
from costfunctions import CostFunction |
26 |
|
|
27 |
import numpy as np |
import numpy as np |
28 |
from esys.escript.linearPDEs import LinearSinglePDE |
from esys.escript import ReducedFunction, outer, Data, Scalar, grad, inner, integrate, interpolate, kronecker, boundingBoxEdgeLengths, vol, sqrt, length |
29 |
from esys.escript import Data, grad, inner, integrate, kronecker, vol |
from esys.escript.linearPDEs import LinearPDE, IllegalCoefficientValue |
30 |
|
from esys.escript.pdetools import ArithmeticTuple |
31 |
|
|
32 |
class Regularization(object): |
class Regularization(CostFunction): |
33 |
""" |
""" |
34 |
|
The regularization term for the level set function ``m`` within the cost |
35 |
|
function J for an inversion: |
36 |
|
|
37 |
|
*J(m)=1/2 * sum_k imtegrate( mu[k] * ( w0[k] * m_k**2 * w1[k,i] * m_{k,i}**2) + sum_l<k mu_c[l,k] wc[l,k] * | curl(m_k) x curl(m_l) |^2* |
38 |
|
|
39 |
|
where w0[k], w1[k,i] and wc[k,l] are non-negative weighting factors and |
40 |
|
mu[k] and mu_c[l,k] are trade-off factors which may be altered |
41 |
|
during the inversion. The weighting factors are normalized such that their |
42 |
|
integrals over the domain are constant: |
43 |
|
|
44 |
|
*integrate(w0[k] + inner(w1[k,:],1/L[:]**2))=scale[k]* volume(domain)* |
45 |
|
*integrate(wc[l,k]*1/L**4)=scale_c[k]* volume(domain) * |
46 |
|
|
47 |
""" |
""" |
48 |
def __init__(self, domain, m_ref=0, w0=None, w=None, location_of_set_m=Data(), tol=1e-8): |
def __init__(self, domain, numLevelSets=1, |
49 |
|
w0=None, w1=None, wc=None, |
50 |
|
location_of_set_m=Data(), |
51 |
|
useDiagonalHessianApproximation=False, tol=1e-8, |
52 |
|
scale=None, scale_c=None): |
53 |
|
""" |
54 |
|
initialization. |
55 |
|
|
56 |
|
:param domain: domain |
57 |
|
:type domain: `Domain` |
58 |
|
:param numLevelSets: number of level sets |
59 |
|
:type numLevelSets: ``int`` |
60 |
|
:param w0: weighting factor for the m**2 term. If not set zero is assumed. |
61 |
|
:type w0: ``Scalar`` if ``numLevelSets`` == 1 or `Data` object of shape |
62 |
|
(``numLevelSets`` ,) if ``numLevelSets`` > 1 |
63 |
|
:param w1: weighting factor for the grad(m_i) terms. If not set zero is assumed |
64 |
|
:type w1: ``Vector`` if ``numLevelSets`` == 1 or `Data` object of shape |
65 |
|
(``numLevelSets`` , DIM) if ``numLevelSets`` > 1 |
66 |
|
:param wc: weighting factor for the cross gradient terms. If not set |
67 |
|
zero is assumed. Used for the case if ``numLevelSets`` > 1 |
68 |
|
only. Only values ``wc[l,k]`` in the lower triangle (l<k) |
69 |
|
are used. |
70 |
|
:type wc: `Data` object of shape (``numLevelSets`` , ``numLevelSets``) |
71 |
|
:param location_of_set_m: marks location of zero values of the level |
72 |
|
set function ``m`` by a positive entry. |
73 |
|
:type location_of_set_m: ``Scalar`` if ``numLevelSets`` == 1 or `Data` |
74 |
|
object of shape (``numLevelSets`` ,) if ``numLevelSets`` > 1 |
75 |
|
:param useDiagonalHessianApproximation: if True cross gradient terms |
76 |
|
between level set components are ignored when calculating |
77 |
|
approximations of the inverse of the Hessian Operator. |
78 |
|
This can speed-up the calculation of the inverse but may |
79 |
|
lead to an increase of the number of iteration steps in the |
80 |
|
inversion. |
81 |
|
:type useDiagonalHessianApproximation: ``bool`` |
82 |
|
:param tol: tolerance when solving the PDE for the inverse of the |
83 |
|
Hessian Operator |
84 |
|
:type tol: positive ``float`` |
85 |
|
|
86 |
|
:param scale: weighting factor for level set function variation terms. If not set one is used. |
87 |
|
:type scale: ``Scalar`` if ``numLevelSets`` == 1 or `Data` object of shape |
88 |
|
(``numLevelSets`` ,) if ``numLevelSets`` > 1 |
89 |
|
:param scale_c: scale for the cross gradient terms. If not set |
90 |
|
one is assumed. Used for the case if ``numLevelSets`` > 1 |
91 |
|
only. Only values ``scale_c[l,k]`` in the lower triangle (l<k) |
92 |
|
are used. |
93 |
|
:type scale_c: `Data` object of shape (``numLevelSets`` , ``numLevelSets``) |
94 |
|
|
95 |
|
|
96 |
|
""" |
97 |
|
if w0 == None and w1==None: |
98 |
|
raise ValueError("Values for w0 or for w1 must be given.") |
99 |
|
if wc == None and numLevelSets>1: |
100 |
|
raise ValueError("Values for wc must be given.") |
101 |
|
|
102 |
self.__domain=domain |
self.__domain=domain |
103 |
self.__m_ref=m_ref |
DIM=self.__domain.getDim() |
104 |
self.location_of_set_m=location_of_set_m |
self.__numLevelSets=numLevelSets |
105 |
if w0 is None: |
|
106 |
self._w0 = None |
self.__pde=LinearPDE(self.__domain, numEquations=self.__numLevelSets) |
107 |
else: |
self.__pde.getSolverOptions().setTolerance(tol) |
108 |
self._w0=np.asarray(w0) / vol(self.__domain) |
self.__pde.setSymmetryOn() |
109 |
if w is None: |
try: |
110 |
self._w = None |
self.__pde.setValue(q=location_of_set_m) |
111 |
|
except IllegalCoefficientValue: |
112 |
|
raise ValueError("Unable to set location of fixed level set function.") |
113 |
|
|
114 |
|
# =========== check the shape of the scales: ================================= |
115 |
|
if scale is None: |
116 |
|
if numLevelSets == 1 : |
117 |
|
scale = 1. |
118 |
|
else: |
119 |
|
scale = np.ones((numLevelSets,)) |
120 |
|
else: |
121 |
|
scale=np.asarray(scale) |
122 |
|
if numLevelSets == 1 : |
123 |
|
if scale.shape == (): |
124 |
|
if not scale > 0 : |
125 |
|
raise ValueError("Value for scale must be positive.") |
126 |
|
else: |
127 |
|
raise ValueError("Unexpected shape %s for scale."%scale.shape) |
128 |
|
else: |
129 |
|
if scale.shape is (numLevelSets,): |
130 |
|
if not min(scale) > 0: |
131 |
|
raise ValueError("All value for scale must be positive.") |
132 |
|
else: |
133 |
|
raise ValueError("Unexpected shape %s for scale."%scale.shape) |
134 |
|
|
135 |
|
if scale_c is None or numLevelSets < 2: |
136 |
|
scale_c = np.ones((numLevelSets,numLevelSets)) |
137 |
|
else: |
138 |
|
scale_c=np.asarray(scale_c) |
139 |
|
if scale_c.shape == (numLevelSets,numLevelSets): |
140 |
|
if not all( [ [ scale_c[l,k] > 0. for l in xrange(k) ] for k in xrange(1,numLevelSets) ]): |
141 |
|
raise ValueError("All values in the lower triangle of scale_c must be positive.") |
142 |
|
else: |
143 |
|
raise ValueError("Unexpected shape %s for scale."%scale_c.shape) |
144 |
|
# ===== check the shape of the weights: ============================================ |
145 |
|
if w0 is not None: |
146 |
|
w0 = interpolate(w0,self.__pde.getFunctionSpaceForCoefficient('D')) |
147 |
|
s0=w0.getShape() |
148 |
|
if numLevelSets == 1 : |
149 |
|
if not s0 == () : |
150 |
|
raise ValueError("Unexpected shape %s for weight w0."%s0) |
151 |
|
else: |
152 |
|
if not s0 == (numLevelSets,): |
153 |
|
raise ValueError("Unexpected shape %s for weight w0."%s0) |
154 |
|
if not w1 is None: |
155 |
|
w1 = interpolate(w1,self.__pde.getFunctionSpaceForCoefficient('A')) |
156 |
|
s1=w1.getShape() |
157 |
|
if numLevelSets is 1 : |
158 |
|
if not s1 == (DIM,) : |
159 |
|
raise ValueError("Unexpected shape %s for weight w1."%s1) |
160 |
|
else: |
161 |
|
if not s1 == (numLevelSets,DIM): |
162 |
|
raise ValueError("Unexpected shape %s for weight w1."%s1) |
163 |
|
if numLevelSets == 1 : |
164 |
|
wc=None |
165 |
|
else: |
166 |
|
wc = interpolate(wc,self.__pde.getFunctionSpaceForCoefficient('A')) |
167 |
|
sc=wc.getShape() |
168 |
|
if not sc == (numLevelSets, numLevelSets): |
169 |
|
raise ValueError("Unexpected shape %s for weight wc."%(sc,)) |
170 |
|
# ============= now we rescale weights: ====================================== |
171 |
|
L2s=np.asarray(boundingBoxEdgeLengths(domain))**2 |
172 |
|
L4=1/np.sum(1/L2s)**2 |
173 |
|
if numLevelSets == 1 : |
174 |
|
A=0 |
175 |
|
if w0 is not None: |
176 |
|
A = integrate(w0) |
177 |
|
if w1 is not None: |
178 |
|
A += integrate(inner(w1, 1/L2s)) |
179 |
|
if A > 0: |
180 |
|
f = scale/A |
181 |
|
if w0 is not None: |
182 |
|
w0*=f |
183 |
|
if w1 is not None: |
184 |
|
w1*=f |
185 |
|
else: |
186 |
|
raise ValueError("Non-positive weighting factor detected.") |
187 |
else: |
else: |
|
self._w=np.asarray(w) |
|
|
|
|
188 |
|
|
189 |
self.__projector=LinearSinglePDE(domain) |
for k in xrange(numLevelSets): |
190 |
self.__projector.getSolverOptions().setTolerance(tol) |
A=0 |
191 |
self.__projector.setValue(A=kronecker(domain), q=location_of_set_m, D=0.) |
if w0 is not None: |
192 |
|
A = integrate(w0[k]) |
193 |
|
if w1 is not None: |
194 |
|
A += integrate(inner(w1[k,:], 1/L2s)) |
195 |
|
if A > 0: |
196 |
|
f = scale[k]/A |
197 |
|
if w0 is not None: |
198 |
|
w0[k]*=f |
199 |
|
if w1 is not None: |
200 |
|
w1[k,:]*=f |
201 |
|
else: |
202 |
|
raise ValueError("Non-positive weighting factor for level set component %d detected."%k) |
203 |
|
|
204 |
|
# and now the cross-gradient: |
205 |
|
if wc is not None: |
206 |
|
for l in xrange(k): |
207 |
|
A = integrate(wc[l,k])/L4 |
208 |
|
if A > 0: |
209 |
|
f = scale_c[l,k]/A |
210 |
|
wc[l,k]*=f |
211 |
|
# else: |
212 |
|
# raise ValueError("Non-positive weighting factor for cross-gradient level set components %d and %d detected."%(l,k)) |
213 |
|
|
214 |
|
self.__w0=w0 |
215 |
|
self.__w1=w1 |
216 |
|
self.__wc=wc |
217 |
|
|
218 |
|
self.__pde_is_set=False |
219 |
|
if self.__numLevelSets > 1: |
220 |
|
self.__useDiagonalHessianApproximation=useDiagonalHessianApproximation |
221 |
|
else: |
222 |
|
self.__useDiagonalHessianApproximation=True |
223 |
|
self._update_Hessian=True |
224 |
|
|
225 |
def getInner(self, f0, f1): |
self.__num_tradeoff_factors=numLevelSets+((numLevelSets-1)*numLevelSets)/2 |
226 |
|
self.setTradeOffFactors() |
227 |
|
self.__vol_d=vol(self.__domain) |
228 |
|
|
229 |
|
def getDomain(self): |
230 |
""" |
""" |
231 |
returns the inner product of two gradients. |
returns the domain of the regularization term |
232 |
|
|
233 |
|
:rtype: ``Domain`` |
234 |
|
""" |
235 |
|
return self.__domain |
236 |
|
|
237 |
|
def getNumLevelSets(self): |
238 |
|
""" |
239 |
|
returns the number of level set functions |
240 |
|
|
241 |
|
:rtype: ``int`` |
242 |
|
""" |
243 |
|
return self.__numLevelSets |
244 |
|
|
245 |
|
def getPDE(self): |
246 |
|
""" |
247 |
|
returns the linear PDE to be solved for the Hessian Operator inverse |
248 |
|
|
249 |
|
:rtype: `LinearPDE` |
250 |
|
""" |
251 |
|
return self.__pde |
252 |
|
|
253 |
|
def getDualProduct(self, m, r): |
254 |
""" |
""" |
255 |
return integrate(inner(grad(f0),grad(f1))) |
returns the dual product of a gradient represented by X=r[1] and Y=r[0] |
256 |
|
with a level set function m: |
257 |
|
|
258 |
def project(self, Y=Data(), X=Data()): |
*Y_i*m_i + X_ij*m_{i,j}* |
|
self.__projector.setValue(Y=Y, X=X) |
|
|
return self.__projector.getSolution() |
|
259 |
|
|
260 |
def getValue(self, m): |
:type m: `Data` |
261 |
|
:type r: `ArithmeticTuple` |
262 |
|
:rtype: ``float`` |
263 |
|
""" |
264 |
A=0 |
A=0 |
265 |
if self._w0 is not None: |
if not r[0].isEmpty(): A+=integrate(inner(r[0], m)) |
266 |
A=(m-self.__m_ref)**2 * self._w0 |
if not r[1].isEmpty(): A+=integrate(inner(r[1], grad(m))) |
267 |
if self._w is not None: |
return A |
268 |
A=inner(self._w, grad(m-self.__m_ref)**2) + A |
def getNumTradeOffFactors(self): |
269 |
return integrate(A) |
""" |
270 |
|
returns the number of trade-off factors being used. |
271 |
def getGradient(self, m): |
|
272 |
if not self._w0 == None: |
:rtype: ``int`` |
273 |
Y=2. * (m-self.__m_ref) * self._w0 |
""" |
274 |
else: |
return self.__num_tradeoff_factors |
275 |
Y=0. |
|
276 |
if not self._w == None: |
def setTradeOffFactors(self, mu=None): |
277 |
X=2. * grad(m-self.__m_ref) * self._w |
""" |
278 |
|
sets the trade-off factors for the level-set variation and the cross-gradient |
279 |
|
|
280 |
|
:param mu: new values for the trade-off factors where values mu[:numLevelSets] are the |
281 |
|
trade-off factors for the level-set variation and the remaining values for |
282 |
|
the cross-gradient part with mu_c[l,k]=mu[numLevelSets+l+((k-1)*k)/2] (l<k). |
283 |
|
If no values for mu is given ones are used. Values must be positive. |
284 |
|
:type mu: ``list`` of ``float`` or ```numpy.array``` |
285 |
|
""" |
286 |
|
numLS=self.getNumLevelSets() |
287 |
|
numTF=self.getNumTradeOffFactors() |
288 |
|
if mu is None: |
289 |
|
mu = np.ones((numTF,)) |
290 |
else: |
else: |
291 |
X=np.zeros((self.__domain.getDim(),)) |
mu = np.asarray(mu) |
292 |
|
|
293 |
return Y, X |
if mu.shape == (numTF,): |
294 |
|
self.setTradeOffFactorsForVariation(mu[:numLS]) |
295 |
|
mu_c2=np.zeros((numLS,numLS)) |
296 |
|
for k in xrange(numLS): |
297 |
|
for l in xrange(k): |
298 |
|
mu_c2[l,k] = mu[numLS+l+((k-1)*k)/2] |
299 |
|
self.setTradeOffFactorsForCrossGradient(mu_c2) |
300 |
|
elif mu.shape == () and numLS ==1: |
301 |
|
self.setTradeOffFactorsForVariation(mu) |
302 |
|
else: |
303 |
|
raise ValueError("Unexpected shape %s for mu."%(mu.shape,)) |
304 |
|
|
305 |
|
def setTradeOffFactorsForVariation(self, mu=None): |
306 |
|
""" |
307 |
|
sets the trade-off factors for the level-set variation part |
308 |
|
|
309 |
|
:param mu: new values for the trade-off factors. Values must be positive. |
310 |
|
:type mu: ``float``, ``list`` of ``float`` or ```numpy.array``` |
311 |
|
""" |
312 |
|
numLS=self.getNumLevelSets() |
313 |
|
if mu is None: |
314 |
|
if numLS == 1: |
315 |
|
mu = 1. |
316 |
|
else: |
317 |
|
mu = np.ones((numLS,)) |
318 |
|
|
319 |
|
mu=np.asarray(mu) |
320 |
|
if numLS == 1: |
321 |
|
if mu.shape == (1,): mu=mu[0] |
322 |
|
if mu.shape == (): |
323 |
|
if mu > 0: |
324 |
|
self.__mu= mu |
325 |
|
self._new_mu=True |
326 |
|
else: |
327 |
|
raise ValueError("Value for trade-off factor must be positive.") |
328 |
|
else: |
329 |
|
raise ValueError("Unexpected shape %s for mu."%mu.shape) |
330 |
|
else: |
331 |
|
if mu.shape == (numLS,): |
332 |
|
if min(mu) > 0: |
333 |
|
self.__mu= mu |
334 |
|
self._new_mu=True |
335 |
|
else: |
336 |
|
raise ValueError("All value for mu must be positive.") |
337 |
|
else: |
338 |
|
raise ValueError("Unexpected shape %s for trade-off factor."%mu.shape) |
339 |
|
|
340 |
|
def setTradeOffFactorsForCrossGradient(self, mu_c=None): |
341 |
|
""" |
342 |
|
sets the trade-off factors for the cross-gradient terms |
343 |
|
|
344 |
|
:param mu_c: new values for the trade-off factors for the cross-gradient |
345 |
|
terms. Values must be positive. If no value is given ones |
346 |
|
are used. Onky value mu_c[l,k] for l<k are used. |
347 |
|
:type mu_c: ``float``, ``list`` of ``float`` or ``numpy.array`` |
348 |
|
|
349 |
|
""" |
350 |
|
numLS=self.getNumLevelSets() |
351 |
|
if mu_c is None or numLS < 2: |
352 |
|
self.__mu_c = np.ones((numLS,numLS)) |
353 |
|
if isinstance(mu_c, float) or isinstance(mu_c, int): |
354 |
|
self.__mu_c = np.zeros((numLS,numLS)) |
355 |
|
self.__mu_c[:,:]=mu_c |
356 |
|
else: |
357 |
|
mu_c=np.asarray(mu_c) |
358 |
|
if mu_c.shape == (numLS,numLS): |
359 |
|
if not all( [ [ mu_c[l,k] > 0. for l in xrange(k) ] for k in xrange(1,numLS) ]): |
360 |
|
raise ValueError("All trade-off factors in the lower triangle of mu_c must be positive.") |
361 |
|
else: |
362 |
|
self.__mu_c = mu_c |
363 |
|
self._new_mu=True |
364 |
|
else: |
365 |
|
raise ValueError("Unexpected shape %s for mu."%mu_c.shape) |
366 |
|
|
367 |
def getArguments(self, m): |
def getArguments(self, m): |
368 |
return () |
""" |
369 |
|
""" |
370 |
|
return ( grad(m),) |
371 |
|
|
372 |
|
|
373 |
|
def getValue(self, m, grad_m): |
374 |
|
""" |
375 |
|
returns the value of the cost function J with respect to m. |
376 |
|
|
377 |
|
:rtype: ``float`` |
378 |
|
""" |
379 |
|
mu=self.__mu |
380 |
|
mu_c=self.__mu_c |
381 |
|
DIM=self.getDomain().getDim() |
382 |
|
numLS=self.getNumLevelSets() |
383 |
|
|
384 |
|
A=0 |
385 |
|
if self.__w0 is not None: |
386 |
|
A+=inner(integrate(m**2 * self.__w0), mu) |
387 |
|
|
388 |
|
if self.__w1 is not None: |
389 |
|
if numLS == 1: |
390 |
|
A+=integrate(inner(grad_m**2, self.__w1))*mu |
391 |
|
else: |
392 |
|
for k in xrange(numLS): |
393 |
|
A+=mu[k]*integrate(inner(grad_m[k,:]**2,self.__w1[k,:])) |
394 |
|
|
395 |
|
if numLS > 1: |
396 |
|
for k in xrange(numLS): |
397 |
|
gk=grad_m[k,:] |
398 |
|
len_gk=length(gk) |
399 |
|
for l in xrange(k): |
400 |
|
gl=grad_m[l,:] |
401 |
|
A+= mu_c[l,k] * integrate( self.__wc[l,k] * ( len_gk * length(gl) )**2 - inner(gk, gl)**2 ) |
402 |
|
return A/2 |
403 |
|
|
404 |
|
def getGradient(self, m, grad_m): |
405 |
|
""" |
406 |
|
returns the gradient of the cost function J with respect to m. |
407 |
|
The function returns Y_k=dPsi/dm_k and X_kj=dPsi/dm_kj |
408 |
|
""" |
409 |
|
|
410 |
|
mu=self.__mu |
411 |
|
mu_c=self.__mu_c |
412 |
|
DIM=self.getDomain().getDim() |
413 |
|
numLS=self.getNumLevelSets() |
414 |
|
|
415 |
|
print "WARNING: WRONG FUNCTION SPACE" |
416 |
|
|
417 |
|
grad_m=grad(m, ReducedFunction(m.getDomain())) |
418 |
|
if self.__w0 is not None: |
419 |
|
Y = m * self.__w0 * mu |
420 |
|
else: |
421 |
|
if numLS == 1: |
422 |
|
Y = Scalar(0, grad_m.getFunctionSpace()) |
423 |
|
else: |
424 |
|
Y = Data(0, (numLS,) , grad_m.getFunctionSpace()) |
425 |
|
|
426 |
|
if self.__w1 is not None: |
427 |
|
X=grad_m*self.__w1 |
428 |
|
if numLS == 1: |
429 |
|
X=grad_m* self.__w1*mu |
430 |
|
else: |
431 |
|
for k in xrange(numLS): |
432 |
|
X[k,:]*=mu[k] |
433 |
|
else: |
434 |
|
X = Data(0, grad_m.getShape(), grad_m.getFunctionSpace()) |
435 |
|
|
436 |
|
# cross gradient terms: |
437 |
|
if numLS > 1: |
438 |
|
for k in xrange(numLS): |
439 |
|
grad_m_k=grad_m[k,:] |
440 |
|
l2_grad_m_k = length(grad_m_k)**2 |
441 |
|
for l in xrange(k): |
442 |
|
grad_m_l=grad_m[l,:] |
443 |
|
l2_grad_m_l = length(grad_m_l)**2 |
444 |
|
grad_m_lk = inner(grad_m_l, grad_m_k) |
445 |
|
f= mu_c[l,k]* self.__wc[l,k] |
446 |
|
X[l,:] += f * ( l2_grad_m_l * grad_m_l - grad_m_lk * grad_m_k ) |
447 |
|
X[k,:] += f * ( l2_grad_m_k * grad_m_k - grad_m_lk * grad_m_l ) |
448 |
|
|
449 |
|
return ArithmeticTuple(Y, X) |
450 |
|
|
451 |
|
|
452 |
|
|
453 |
|
def getInverseHessianApproximation(self, m, r, grad_m): |
454 |
|
""" |
455 |
|
""" |
456 |
|
if self._new_mu or self._update_Hessian: |
457 |
|
|
458 |
|
self._new_mu=False |
459 |
|
self._update_Hessian=False |
460 |
|
mu=self.__mu |
461 |
|
mu_c=self.__mu_c |
462 |
|
|
463 |
|
DIM=self.getDomain().getDim() |
464 |
|
numLS=self.getNumLevelSets() |
465 |
|
if self.__w0 is not None: |
466 |
|
if numLS == 1: |
467 |
|
D=self.__w0 * mu |
468 |
|
else: |
469 |
|
D=self.getPDE().createCoefficient("D") |
470 |
|
for k in xrange(numLS): D[k,k]=self.__w0[k] * mu[k] |
471 |
|
self.getPDE().setValue(D=D) |
472 |
|
|
473 |
|
A=self.getPDE().createCoefficient("A") |
474 |
|
if self.__w1 is not None: |
475 |
|
if numLS == 1: |
476 |
|
for i in xrange(DIM): A[i,i]=self.__w1[i] * mu |
477 |
|
else: |
478 |
|
for k in xrange(numLS): |
479 |
|
for i in xrange(DIM): A[k,i,k,i]=self.__w1[k,i] * mu[k] |
480 |
|
|
481 |
|
if numLS > 1: |
482 |
|
for k in xrange(numLS): |
483 |
|
grad_m_k=grad_m[k,:] |
484 |
|
l2_grad_m_k = length(grad_m_k)**2 |
485 |
|
o_kk=outer(grad_m_k, grad_m_k) |
486 |
|
for l in xrange(k): |
487 |
|
grad_m_l=grad_m[l,:] |
488 |
|
l2_grad_m_l = length(grad_m_l)**2 |
489 |
|
i_lk = inner(grad_m_l, grad_m_k) |
490 |
|
o_lk = outer(grad_m_l, grad_m_k) |
491 |
|
o_kl = outer(grad_m_k, grad_m_l) |
492 |
|
o_ll=outer(grad_m_l, grad_m_l) |
493 |
|
f= mu_c[l,k]* self.__wc[l,k] |
494 |
|
|
495 |
|
A[l,:,l,:] += f * ( l2_grad_m_k * kronecker(DIM) - o_kk ) |
496 |
|
A[l,:,k,:] += f * ( 2 * o_lk - o_kl - i_lk * kronecker(DIM) ) |
497 |
|
A[k,:,l,:] += f * ( 2 * o_kl - o_lk - i_lk * kronecker(DIM) ) |
498 |
|
A[k,:,k,:] += f * ( l2_grad_m_l * kronecker(DIM) - o_ll ) |
499 |
|
self.getPDE().setValue(A=A) |
500 |
|
#self.getPDE().resetRightHandSideCoefficients() |
501 |
|
#self.getPDE().setValue(X=r[1]) |
502 |
|
#print "X only: ",self.getPDE().getSolution() |
503 |
|
#self.getPDE().resetRightHandSideCoefficients() |
504 |
|
#self.getPDE().setValue(Y=r[0]) |
505 |
|
#print "Y only: ",self.getPDE().getSolution() |
506 |
|
|
507 |
|
self.getPDE().resetRightHandSideCoefficients() |
508 |
|
self.getPDE().setValue(X=r[1], Y=r[0]) |
509 |
|
return self.getPDE().getSolution() |
510 |
|
|
511 |
|
def updateHessian(self): |
512 |
|
""" |
513 |
|
notify the class to recalculate the Hessian operator |
514 |
|
""" |
515 |
|
if not self.__useDiagonalHessianApproximation: |
516 |
|
self._update_Hessian=True |
517 |
|
|
518 |
|
def getNorm(self, m): |
519 |
|
""" |
520 |
|
returns the norm of ``m`` |
521 |
|
|
522 |
|
:param m: level set function |
523 |
|
:type m: `Data` |
524 |
|
:rtype: ``float`` |
525 |
|
""" |
526 |
|
return sqrt(integrate(length(m)**2)/self.__vol_d) |