From 19f79b3275bd0169d8e5b98ac25356d7fa2ab763 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Thu, 7 Nov 2013 17:42:24 -0800 Subject: [PATCH] updates to Inversion. Bug Fixes. --- SimPEG/inverse/BetaSchedule.py | 4 +- SimPEG/inverse/Inversion.py | 98 ++++++++++++++++++++++++++++------ SimPEG/inverse/Optimize.py | 8 +-- SimPEG/utils/__init__.py | 6 ++- 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/SimPEG/inverse/BetaSchedule.py b/SimPEG/inverse/BetaSchedule.py index fe197340..af4d883d 100644 --- a/SimPEG/inverse/BetaSchedule.py +++ b/SimPEG/inverse/BetaSchedule.py @@ -8,5 +8,5 @@ class Cooling(object): def getBeta(self): if self._beta is None: - return beta0 - return self._beta / beta_coolingFactor + return self.beta0 + return self._beta / self.beta_coolingFactor diff --git a/SimPEG/inverse/Inversion.py b/SimPEG/inverse/Inversion.py index 32663213..e3d500b1 100644 --- a/SimPEG/inverse/Inversion.py +++ b/SimPEG/inverse/Inversion.py @@ -1,13 +1,17 @@ import numpy as np import scipy.sparse as sp import SimPEG -from SimPEG.utils import sdiag, mkvc, setKwargs, checkStoppers +from SimPEG.utils import sdiag, mkvc, setKwargs, checkStoppers, printStoppers +from Optimize import Remember +from BetaSchedule import Cooling -class Inversion(object): - """docstring for Inversion""" +class BaseInversion(object): + """docstring for BaseInversion""" - maxIter = 10 - name = 'SimPEG Inversion' + maxIter = 1 + name = 'BaseInversion' + debug = False + beta0 = 1e4 def __init__(self, prob, reg, opt, **kwargs): setKwargs(self, **kwargs) @@ -47,32 +51,87 @@ class Inversion(object): if getattr(self, '_phi_d_target', None) is None: return self.prob.dobs.size # return self._phi_d_target + @phi_d_target.setter def phi_d_target(self, value): self._phi_d_target = value def run(self, m0): - m = m0 - self._iter = 0 - self._beta = None + self.startup(m0) while True: self._beta = self.getBeta() - m = self.opt.minimize(self.evalFunction,m) - self._iter += 1 + self.m = self.opt.minimize(self.evalFunction, self.m) + self.doEndIteration() if self.stoppingCriteria(): break - return m - beta0 = 1.e2 - beta_coolingFactor = 5. + self.printDone() + return self.m + + def startup(self, m0): + """ + **startup** is called at the start of any new run call. + + If you have things that also need to run on startup, you can create a method:: + + def _startup*(self, x0): + pass + + Where the * can be any string. If present, _startup* will be called at the start of the default startup call. + You may also completely overwrite this function. + + :param numpy.ndarray x0: initial x + :rtype: None + :return: None + """ + for method in [posible for posible in dir(self) if '_startup' in posible]: + if self.debug: print 'startup is calling self.'+method + getattr(self,method)(m0) + + self.m = m0 + self._iter = 0 + self._beta = None + + def doEndIteration(self): + """ + **doEndIteration** is called at the end of each run iteration. + + If you have things that also need to run at the end of every iteration, you can create a method:: + + def _doEndIteration*(self, xt): + pass + + Where the * can be any string. If present, _doEndIteration* will be called at the start of the default doEndIteration call. + You may also completely overwrite this function. + + :param numpy.ndarray xt: tested new iterate that ensures a descent direction. + :rtype: None + :return: None + """ + for method in [posible for posible in dir(self) if '_doEndIteration' in posible]: + if self.debug: print 'doEndIteration is calling self.'+method + getattr(self,method)() + + # store old values + self.phi_d_last = self.phi_d + self.phi_m_last = self.phi_m + self._iter += 1 def getBeta(self): - if self._beta is None: - return self.beta0 - return self._beta / self.beta_coolingFactor + return self.beta0 def stoppingCriteria(self): + if self.debug: print 'checking stoppingCriteria' return checkStoppers(self, self.stoppers) + + def printDone(self): + """ + **printDone** is called at the end of the inversion routine. + + """ + printStoppers(self, self.stoppers) + + def evalFunction(self, m, return_g=True, return_H=True): u = self.prob.field(m) @@ -209,3 +268,10 @@ class Inversion(object): return dmisfit +class Inversion(Cooling, Remember, BaseInversion): + + maxIter = 10 + name = "SimPEG Inversion" + + def __init__(self, prob, reg, opt, **kwargs): + BaseInversion.__init__(self, prob, reg, opt, **kwargs) diff --git a/SimPEG/inverse/Optimize.py b/SimPEG/inverse/Optimize.py index 4bc8bd0a..bd26ea79 100644 --- a/SimPEG/inverse/Optimize.py +++ b/SimPEG/inverse/Optimize.py @@ -468,7 +468,7 @@ class Remember(object): self._rememberThese = args def recall(self, param): - assert param in self._rememberThese, "You didn't tell me to remember "+param+", you gotta tell me what to remember!" + assert param in self._rememberList, "You didn't tell me to remember "+param+", you gotta tell me what to remember!" return self._rememberList[param] def _startupRemember(self, x0): @@ -479,15 +479,17 @@ class Remember(object): elif type(param) is tuple: self._rememberList[param[0]] = [] - def _doEndIterationRemember(self, xt): + def _doEndIterationRemember(self, *args): for param in self._rememberThese: if type(param) is str: + if self.debug: print 'Remember is remembering: ' + param val = getattr(self, param, None) - if val is None and self.parent is not None: + if val is None and getattr(self, 'parent', None) is not None: # Look to the parent for the param if not found here. val = getattr(self.parent, param, None) self._rememberList[param].append( val ) elif type(param) is tuple: + if self.debug: print 'Remember is remembering: ' + param[0] self._rememberList[param[0]].append( param[1](self) ) diff --git a/SimPEG/utils/__init__.py b/SimPEG/utils/__init__.py index 5adbaa9f..c54949ad 100644 --- a/SimPEG/utils/__init__.py +++ b/SimPEG/utils/__init__.py @@ -47,7 +47,11 @@ def checkStoppers(obj, stoppers): optimal.append(l <= r) if stopper['stopType'] == 'critical': critical.append(l <= r) - return all(optimal) | any(critical) + + if obj.debug: print 'checkStoppers.optimal: ', optimal + if obj.debug: print 'checkStoppers.critical: ', critical + + return (len(optimal)>0 and all(optimal)) | (len(critical)>0 and any(critical)) def printStoppers(obj, stoppers, pad='', stop='STOP!', done='DONE!'): print pad + "%s%s%s" % ('-'*25,stop,'-'*25)