From 5797fa41101fc3693340dd9176e518812790e755 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 14 Jan 2014 12:22:58 -0800 Subject: [PATCH 01/28] Get DC inversion working with the changes in the data class. --- SimPEG/examples/DC.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SimPEG/examples/DC.py b/SimPEG/examples/DC.py index ad98d6c2..4fcb68f6 100644 --- a/SimPEG/examples/DC.py +++ b/SimPEG/examples/DC.py @@ -203,7 +203,7 @@ if __name__ == '__main__': problem = DCProblem(mesh) problem.P = P problem.RHS = q - dobs, Wd = problem.createSyntheticData(mSynth, std=0.05) + data = problem.createSyntheticData(mSynth, std=0.05) u = problem.field(mSynth) u = problem.reshapeFields(u) @@ -211,13 +211,13 @@ if __name__ == '__main__': # plt.show() # Now set up the problem to do some minimization - problem.dobs = dobs - problem.std = dobs*0 + 0.05 + # problem.dobs = dobs + # problem.std = dobs*0 + 0.05 m0 = mesh.gridCC[:,0]*0+sig2 opt = inverse.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) reg = inverse.Regularization(mesh) - inv = inverse.Inversion(problem, reg, opt, beta0=1e4) + inv = inverse.Inversion(problem, reg, opt, data, beta0=1e4) # Check Derivative derChk = lambda m: [inv.dataObj(m), inv.dataObjDeriv(m)] From 9b5d19ad8e1c0269e862290147ddbac287d0b7ff Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 15 Jan 2014 10:53:45 -0800 Subject: [PATCH 02/28] Clean up imports in DC, move data to forward folder. clean up init statements. --- SimPEG/__init__.py | 2 +- SimPEG/examples/DC.py | 48 ++++++++------------ SimPEG/{data/__init__.py => forward/Data.py} | 0 SimPEG/forward/Problem.py | 5 +- SimPEG/forward/__init__.py | 1 + SimPEG/tests/__init__.py | 13 ++++++ 6 files changed, 37 insertions(+), 32 deletions(-) rename SimPEG/{data/__init__.py => forward/Data.py} (100%) diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index f421bc82..c7c3638b 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -3,11 +3,11 @@ import scipy.sparse as sp import utils from utils import Solver import mesh -import data import forward import inverse import visualize import examples +import tests import scipy.version as _v if _v.version < '0.13.0': diff --git a/SimPEG/examples/DC.py b/SimPEG/examples/DC.py index 4fcb68f6..f975b108 100644 --- a/SimPEG/examples/DC.py +++ b/SimPEG/examples/DC.py @@ -1,13 +1,6 @@ -from SimPEG.mesh import TensorMesh -from SimPEG.forward import Problem, ModelTransforms -from SimPEG.tests import checkDerivative -from SimPEG.utils import ModelBuilder, sdiag, mkvc -from SimPEG import Solver -import numpy as np -import scipy.sparse as sp +from SimPEG import * - -class DCProblem(ModelTransforms.LogModel, Problem): +class DCProblem(forward.ModelTransforms.LogModel, forward.Problem): """ **DCProblem** @@ -15,7 +8,7 @@ class DCProblem(ModelTransforms.LogModel, Problem): """ def __init__(self, mesh): - Problem.__init__(self, mesh) + forward.Problem.__init__(self, mesh) self.mesh.setCellGradBC('neumann') def reshapeFields(self, u): @@ -55,13 +48,13 @@ class DCProblem(ModelTransforms.LogModel, Problem): u = self.reshapeFields(u) - return mkvc(self.P*u) + return utils.mkvc(self.P*u) def field(self, m): A = self.createMatrix(m) solve = Solver(A) phi = solve.solve(self.RHS) - return mkvc(phi) + return utils.mkvc(phi) def J(self, m, v, u=None): """ @@ -101,11 +94,11 @@ class DCProblem(ModelTransforms.LogModel, Problem): dCdm = np.empty_like(u) for i, ui in enumerate(u.T): # loop over each column - dCdm[:, i] = D * ( sdiag( G * ui ) * ( Av_dm * ( mT_dm * v ) ) ) + dCdm[:, i] = D * ( utils.sdiag( G * ui ) * ( Av_dm * ( mT_dm * v ) ) ) solve = Solver(dCdu) Jv = - P * solve.solve(dCdm) - return mkvc(Jv) + return utils.mkvc(Jv) def Jt(self, m, v, u=None): """Takes data, turns it into a model..ish""" @@ -130,7 +123,7 @@ class DCProblem(ModelTransforms.LogModel, Problem): Jtv = 0 for i, ui in enumerate(u.T): # loop over each column - Jtv += sdiag( G * ui ) * ( D.T * w[:,i] ) + Jtv += utils.sdiag( G * ui ) * ( D.T * w[:,i] ) Jtv = - mT_dm.T * ( Av_dm.T * Jtv ) return Jtv @@ -165,16 +158,13 @@ def genTxRxmat(nelec, spacelec, surfloc, elecini, mesh): return q, Q, rxmidLoc - if __name__ == '__main__': - - from SimPEG import inverse import matplotlib.pyplot as plt # Create the mesh h1 = np.ones(20) h2 = np.ones(100) - mesh = TensorMesh([h1,h2]) + M = mesh.TensorMesh([h1,h2]) # Create some parameters for the model sig1 = np.log(1) @@ -184,8 +174,8 @@ if __name__ == '__main__': p0 = [5, 10] p1 = [15, 50] condVals = [sig1, sig2] - mSynth = ModelBuilder.defineBlockConductivity(p0,p1,mesh.gridCC,condVals) - plt.colorbar(mesh.plotImage(mSynth)) + mSynth = utils.ModelBuilder.defineBlockConductivity(p0,p1,M.gridCC,condVals) + plt.colorbar(M.plotImage(mSynth)) plt.show() # Set up the projection @@ -196,32 +186,32 @@ if __name__ == '__main__': elecend = 0.5+spacelec*(nelec-1) elecLocR = np.linspace(elecini, elecend, nelec) rxmidLoc = (elecLocR[0:nelec-1]+elecLocR[1:nelec])*0.5 - q, Q, rxmidloc = genTxRxmat(nelec, spacelec, surfloc, elecini, mesh) + q, Q, rxmidloc = genTxRxmat(nelec, spacelec, surfloc, elecini, M) P = Q.T # Create some data - problem = DCProblem(mesh) + problem = DCProblem(M) problem.P = P problem.RHS = q data = problem.createSyntheticData(mSynth, std=0.05) u = problem.field(mSynth) u = problem.reshapeFields(u) - mesh.plotImage(u[:,10]) + M.plotImage(u[:,10]) # plt.show() # Now set up the problem to do some minimization # problem.dobs = dobs # problem.std = dobs*0 + 0.05 - m0 = mesh.gridCC[:,0]*0+sig2 + m0 = M.gridCC[:,0]*0+sig2 - opt = inverse.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) - reg = inverse.Regularization(mesh) + opt = inverse.InexactGaussNewton(maxIterLS=20, maxIter=3, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + reg = inverse.Regularization(M) inv = inverse.Inversion(problem, reg, opt, data, beta0=1e4) # Check Derivative derChk = lambda m: [inv.dataObj(m), inv.dataObjDeriv(m)] - checkDerivative(derChk, mSynth) + tests.checkDerivative(derChk, mSynth) @@ -230,7 +220,7 @@ if __name__ == '__main__': m = inv.run(m0) - plt.colorbar(mesh.plotImage(m)) + plt.colorbar(M.plotImage(m)) print m plt.show() diff --git a/SimPEG/data/__init__.py b/SimPEG/forward/Data.py similarity index 100% rename from SimPEG/data/__init__.py rename to SimPEG/forward/Data.py diff --git a/SimPEG/forward/Problem.py b/SimPEG/forward/Problem.py index 1412ff5b..adc825cc 100644 --- a/SimPEG/forward/Problem.py +++ b/SimPEG/forward/Problem.py @@ -1,4 +1,5 @@ -from SimPEG import utils, data, np, sp +from SimPEG import utils, np, sp +import Data norm = np.linalg.norm @@ -224,7 +225,7 @@ class Problem(object): noise = std*abs(dtrue)*np.random.randn(*dtrue.shape) dobs = dtrue+noise stdev = dobs*0 + std - return data.SimPEGData(self, dobs=dobs, std=stdev, dtrue=dtrue, mtrue=m) + return Data.SimPEGData(self, dobs=dobs, std=stdev, dtrue=dtrue, mtrue=m) diff --git a/SimPEG/forward/__init__.py b/SimPEG/forward/__init__.py index ce6f7e52..6eb4042d 100644 --- a/SimPEG/forward/__init__.py +++ b/SimPEG/forward/__init__.py @@ -1,2 +1,3 @@ from Problem import * import ModelTransforms +from Data import * diff --git a/SimPEG/tests/__init__.py b/SimPEG/tests/__init__.py index d082562d..feede8f7 100644 --- a/SimPEG/tests/__init__.py +++ b/SimPEG/tests/__init__.py @@ -1,2 +1,15 @@ import TestUtils from TestUtils import checkDerivative, Rosenbrock, OrderTest, getQuadratic + + +if __name__ == '__main__': + import os + import glob + import unittest + test_file_strings = glob.glob('test_*.py') + module_strings = [str[0:len(str)-3] for str in test_file_strings] + suites = [unittest.defaultTestLoader.loadTestsFromName(str) for str + in module_strings] + testSuite = unittest.TestSuite(suites) + + unittest.TextTestRunner(verbosity=2).run(testSuite) From 124337024c1186443074d06e217c2582d2596d77 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 15 Jan 2014 17:58:42 -0800 Subject: [PATCH 03/28] Utils fixing. --- SimPEG/tests/TestUtils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/tests/TestUtils.py b/SimPEG/tests/TestUtils.py index 2723b0b7..fa4ee89a 100644 --- a/SimPEG/tests/TestUtils.py +++ b/SimPEG/tests/TestUtils.py @@ -1,6 +1,6 @@ import numpy as np import matplotlib.pyplot as plt -from pylab import norm +from numpy.linalg import norm from SimPEG.utils import mkvc, sdiag from SimPEG import utils from SimPEG.mesh import TensorMesh, LogicallyOrthogonalMesh From 2f5b7ae8f7d98e30a7db668dc1569b69f92b7df4 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 10:06:00 -0800 Subject: [PATCH 04/28] Moving functions around into the new framework. Added requiresProblem annotation. --- SimPEG/forward/Data.py | 81 +++++++++++++++++++++++++++++++++++-- SimPEG/forward/Problem.py | 13 ------ SimPEG/inverse/Inversion.py | 13 ------ SimPEG/utils/__init__.py | 8 ++-- 4 files changed, 81 insertions(+), 34 deletions(-) diff --git a/SimPEG/forward/Data.py b/SimPEG/forward/Data.py index 86123003..bc18e2a5 100644 --- a/SimPEG/forward/Data.py +++ b/SimPEG/forward/Data.py @@ -1,6 +1,37 @@ from SimPEG import utils +def requiresProblem(f): + """ + Use this to wrap a funciton:: + + @requiresProblem + def dpred(self): + pass + + This wrapper will ensure that a problem has been bound to the data. + If a problem is not bound an Exception will be raised, and an nice error message printed. + """ + extra = """ + This function requires that a problem be bound to the data. + If a problem has not been bound, an Exception will be raised. + To bind a problem to the Data object:: + + data.setProblem(myProblem) + """ + from functools import wraps + @wraps(f) + def requiresProblemWrapper(self,*args,**kwargs): + if getattr(self, 'prob', None) is None: + raise Exception(extra) + return f(self,*args,**kwargs) + + doc = requiresProblemWrapper.__doc__ + requiresProblemWrapper.__doc__ = ('' if doc is None else doc) + extra + + return requiresProblemWrapper + + class SimPEGData(object): """Data holds the observed data, and the standard deviations.""" @@ -10,11 +41,55 @@ class SimPEGData(object): dobs = None #: Observed data dtrue = None #: True data, if data is synthetic mtrue = None #: True model, if data is synthetic + prob = None #: The geophysical problem that explains this data - def __init__(self, prob, **kwargs): + + def __init__(self, **kwargs): utils.setKwargs(self, **kwargs) - self.prob = prob def isSynthetic(self): "Check if the data is synthetic." - return self.mtrue is not None + return (self.mtrue is not None) + + def setProblem(self, prob): + self.prob = prob + + @property + def Wd(self): + """ + Standard deviation weighting matrix. + + By default, this is based on the norm of the data plus a noise floor. + + """ + if getattr(self,'_Wd',None) is None: + eps = np.linalg.norm(utils.mkvc(self.dobs),2)*1e-5 + self._Wd = 1/(abs(self.dobs)*self.std+eps) + return self._Wd + @Wd.setter + def Wd(self, value): + self._Wd = value + + @requiresProblem + def dpred(self, m, u=None): + pass + + def residual(self, m, u=None): + pass + + def residualWeighted(self, m, u=None): + pass + + def projectField(self, m, u=None): + """ + Projection matrix. + + .. math:: + d_\\text{pred} = Pu(m) + """ + return self.P*u + + +if __name__ == '__main__': + d = SimPEGData() + d.dpred() diff --git a/SimPEG/forward/Problem.py b/SimPEG/forward/Problem.py index adc825cc..2b2af6d1 100644 --- a/SimPEG/forward/Problem.py +++ b/SimPEG/forward/Problem.py @@ -55,19 +55,6 @@ class Problem(object): def RHS(self, value): self._RHS = value - @property - def P(self): - """ - Projection matrix. - - .. math:: - d_\\text{pred} = Pu(m) - """ - return self._P - @P.setter - def P(self, value): - self._P = value - @utils.count def dpred(self, m, u=None): """ diff --git a/SimPEG/inverse/Inversion.py b/SimPEG/inverse/Inversion.py index 926f719a..44b3e57b 100644 --- a/SimPEG/inverse/Inversion.py +++ b/SimPEG/inverse/Inversion.py @@ -42,19 +42,6 @@ class BaseInversion(object): opt.bfgsH0 = SimPEG.Solver(reg.modelObj2Deriv()) - @property - def Wd(self): - """ - Standard deviation weighting matrix. - """ - if getattr(self,'_Wd',None) is None: - eps = np.linalg.norm(utils.mkvc(self.data.dobs),2)*1e-5 - self._Wd = 1/(abs(self.data.dobs)*self.data.std+eps) - return self._Wd - @Wd.setter - def Wd(self, value): - self._Wd = value - @property def phi_d_target(self): """ diff --git a/SimPEG/utils/__init__.py b/SimPEG/utils/__init__.py index d20c2cec..ab67b25d 100644 --- a/SimPEG/utils/__init__.py +++ b/SimPEG/utils/__init__.py @@ -98,7 +98,7 @@ def callHooks(match, mainFirst=False): def doEndIteration(self): pass - This will call everything named _doEndIteration* at the beginning of the function call. + This will call everything named _doEndIteration* at the beginning of the function call. By default the master method (doEndIteration) is run after all of the sub methods (_doEndIteration*). This can be reversed by adding the mainFirst=True kwarg. """ @@ -131,10 +131,8 @@ def callHooks(match, mainFirst=False): Where the * can be any string. If present, _%s* will be called at the start of the default %s call. You may also completely overwrite this function. """ % (match, match, match, match) - try: - wrapper.__doc__ += extra - except Exception, e: - pass + doc = wrapper.__doc__ + wrapper.__doc__ = ('' if doc is None else doc) + extra return wrapper return callHooksWrap From c49ae77fbd99ef0dd7b36d3e5d3459633bda59b3 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 11:02:35 -0800 Subject: [PATCH 05/28] Cleaning up imports. --- SimPEG/__init__.py | 5 +++-- SimPEG/forward/Problem.py | 4 ++-- SimPEG/forward/{Data.py => SimPEGData.py} | 12 ++++++++---- SimPEG/forward/__init__.py | 2 +- SimPEG/tests/__init__.py | 1 - SimPEG/utils/Solver.py | 3 ++- SimPEG/utils/__init__.py | 7 ------- 7 files changed, 16 insertions(+), 18 deletions(-) rename SimPEG/forward/{Data.py => SimPEGData.py} (90%) diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index c7c3638b..07397233 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -1,14 +1,15 @@ import numpy as np import scipy.sparse as sp import utils -from utils import Solver +Solver = utils.Solver import mesh import forward import inverse -import visualize import examples import tests +Data = forward.Data + import scipy.version as _v if _v.version < '0.13.0': print 'Warning: upgrade your scipy to 0.13.0' diff --git a/SimPEG/forward/Problem.py b/SimPEG/forward/Problem.py index 2b2af6d1..1fb5de1f 100644 --- a/SimPEG/forward/Problem.py +++ b/SimPEG/forward/Problem.py @@ -1,5 +1,5 @@ from SimPEG import utils, np, sp -import Data +import SimPEGData norm = np.linalg.norm @@ -212,7 +212,7 @@ class Problem(object): noise = std*abs(dtrue)*np.random.randn(*dtrue.shape) dobs = dtrue+noise stdev = dobs*0 + std - return Data.SimPEGData(self, dobs=dobs, std=stdev, dtrue=dtrue, mtrue=m) + return SimPEGData.Data(dobs=dobs, std=stdev, dtrue=dtrue, mtrue=m) diff --git a/SimPEG/forward/Data.py b/SimPEG/forward/SimPEGData.py similarity index 90% rename from SimPEG/forward/Data.py rename to SimPEG/forward/SimPEGData.py index bc18e2a5..934fd47a 100644 --- a/SimPEG/forward/Data.py +++ b/SimPEG/forward/SimPEGData.py @@ -32,7 +32,7 @@ def requiresProblem(f): return requiresProblemWrapper -class SimPEGData(object): +class Data(object): """Data holds the observed data, and the standard deviations.""" __metaclass__ = utils.Save.Savable @@ -72,14 +72,17 @@ class SimPEGData(object): @requiresProblem def dpred(self, m, u=None): - pass + if u is None: u = self.prob.field(m) + @requiresProblem def residual(self, m, u=None): - pass + if u is None: u = self.prob.field(m) + @requiresProblem def residualWeighted(self, m, u=None): - pass + if u is None: u = self.prob.field(m) + @requiresProblem def projectField(self, m, u=None): """ Projection matrix. @@ -87,6 +90,7 @@ class SimPEGData(object): .. math:: d_\\text{pred} = Pu(m) """ + if u is None: u = self.prob.field(m) return self.P*u diff --git a/SimPEG/forward/__init__.py b/SimPEG/forward/__init__.py index 6eb4042d..47153f5c 100644 --- a/SimPEG/forward/__init__.py +++ b/SimPEG/forward/__init__.py @@ -1,3 +1,3 @@ from Problem import * import ModelTransforms -from Data import * +from SimPEGData import * diff --git a/SimPEG/tests/__init__.py b/SimPEG/tests/__init__.py index feede8f7..32112042 100644 --- a/SimPEG/tests/__init__.py +++ b/SimPEG/tests/__init__.py @@ -1,4 +1,3 @@ -import TestUtils from TestUtils import checkDerivative, Rosenbrock, OrderTest, getQuadratic diff --git a/SimPEG/utils/Solver.py b/SimPEG/utils/Solver.py index e0f1e017..0b6e0d95 100644 --- a/SimPEG/utils/Solver.py +++ b/SimPEG/utils/Solver.py @@ -1,7 +1,8 @@ import numpy as np import scipy.sparse as sp import scipy.sparse.linalg as linalg -from SimPEG.utils import mkvc, sdiag +from matutils import mkvc +from sputils import sdiag import warnings DEFAULTS = {'direct':'scipy', 'iter':'scipy', 'triangular':'fortran', 'diagonal':'python'} diff --git a/SimPEG/utils/__init__.py b/SimPEG/utils/__init__.py index ab67b25d..2def4332 100644 --- a/SimPEG/utils/__init__.py +++ b/SimPEG/utils/__init__.py @@ -1,16 +1,9 @@ -import matutils -import sputils -import lomutils -import interputils -import ModelBuilder -import meshutils from matutils import getSubArray, mkvc, ndgrid, ind2sub, sub2ind from sputils import spzeros, kron3, speye, sdiag, ddx, av, avExtrap from meshutils import exampleLomGird, meshTensors from lomutils import volTetra, faceInfo, inv2X2BlockDiagonal, inv3X3BlockDiagonal, indexCube from interputils import interpmat from ipythonUtils import easyAnimate as animate -import Solver from Solver import Solver import Save import Geophysics From ca4932fd19d3f26b300e28392d05a8028de27d88 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 13:19:29 -0800 Subject: [PATCH 06/28] Moved things around! Packages should now all be capitalized. may need to to tweak git to ensure this... --- SimPEG/{forward/SimPEGData.py => Data.py} | 121 +++++++++------ SimPEG/Model.py | 94 ++++++++++++ SimPEG/{forward => }/Problem.py | 94 ++---------- SimPEG/__init__.py | 17 ++- SimPEG/examples/DC.py | 82 +++++++---- SimPEG/examples/Linear.py | 10 +- SimPEG/forward/ModelTransforms.py | 49 ------- SimPEG/forward/__init__.py | 3 - SimPEG/inverse/Inversion.py | 34 ++--- SimPEG/inverse/Optimize.py | 66 ++++----- SimPEG/inverse/Regularization.py | 40 ++--- SimPEG/mesh/BaseMesh.py | 8 +- SimPEG/mesh/Cyl1DMesh.py | 4 +- SimPEG/mesh/DiffOperators.py | 2 +- SimPEG/mesh/InnerProducts.py | 2 +- SimPEG/mesh/LogicallyOrthogonalMesh.py | 94 ++++++------ SimPEG/mesh/LomView.py | 2 +- SimPEG/mesh/TensorMesh.py | 60 ++++---- SimPEG/mesh/TensorView.py | 2 +- SimPEG/setup.py | 4 +- SimPEG/tests/TestUtils.py | 12 +- SimPEG/tests/test_LogicallyOrthogonalMesh.py | 4 +- SimPEG/tests/test_Solver.py | 4 +- SimPEG/tests/test_basemesh.py | 2 +- SimPEG/tests/test_forward_DCproblem.py | 138 +++++++++--------- SimPEG/tests/test_interpolation.py | 2 +- SimPEG/tests/test_model.py | 27 ++++ SimPEG/tests/test_optimizers.py | 18 +-- ...est_forward_problem.py => test_problem.py} | 16 +- SimPEG/tests/test_tensorMesh.py | 2 +- SimPEG/tests/test_utils.py | 4 +- SimPEG/utils/ModelBuilder.py | 2 +- SimPEG/utils/Save.py | 4 +- SimPEG/utils/__init__.py | 2 +- SimPEG/utils/interputils.py | 4 +- SimPEG/utils/meshutils.py | 4 +- SimPEG/visualize/vtk/vtkTools.py | 2 +- 37 files changed, 546 insertions(+), 489 deletions(-) rename SimPEG/{forward/SimPEGData.py => Data.py} (51%) create mode 100644 SimPEG/Model.py rename SimPEG/{forward => }/Problem.py (63%) delete mode 100644 SimPEG/forward/ModelTransforms.py delete mode 100644 SimPEG/forward/__init__.py create mode 100644 SimPEG/tests/test_model.py rename SimPEG/tests/{test_forward_problem.py => test_problem.py} (51%) diff --git a/SimPEG/forward/SimPEGData.py b/SimPEG/Data.py similarity index 51% rename from SimPEG/forward/SimPEGData.py rename to SimPEG/Data.py index 934fd47a..bc874de2 100644 --- a/SimPEG/forward/SimPEGData.py +++ b/SimPEG/Data.py @@ -1,4 +1,4 @@ -from SimPEG import utils +import Utils def requiresProblem(f): @@ -32,58 +32,28 @@ def requiresProblem(f): return requiresProblemWrapper -class Data(object): +class BaseData(object): """Data holds the observed data, and the standard deviations.""" - __metaclass__ = utils.Save.Savable + __metaclass__ = Utils.Save.Savable - std = None #: Estimated Standard Deviations - dobs = None #: Observed data - dtrue = None #: True data, if data is synthetic - mtrue = None #: True model, if data is synthetic - prob = None #: The geophysical problem that explains this data + std = None #: Estimated Standard Deviations + dobs = None #: Observed data + dtrue = None #: True data, if data is synthetic + mtrue = None #: True model, if data is synthetic + prob = None #: The geophysical problem that explains this data + counter = None #: A SimPEG.Utils.Counter object def __init__(self, **kwargs): - utils.setKwargs(self, **kwargs) - - def isSynthetic(self): - "Check if the data is synthetic." - return (self.mtrue is not None) + Utils.setKwargs(self, **kwargs) def setProblem(self, prob): self.prob = prob - @property - def Wd(self): - """ - Standard deviation weighting matrix. - - By default, this is based on the norm of the data plus a noise floor. - - """ - if getattr(self,'_Wd',None) is None: - eps = np.linalg.norm(utils.mkvc(self.dobs),2)*1e-5 - self._Wd = 1/(abs(self.dobs)*self.std+eps) - return self._Wd - @Wd.setter - def Wd(self, value): - self._Wd = value - + @Utils.count @requiresProblem def dpred(self, m, u=None): - if u is None: u = self.prob.field(m) - - @requiresProblem - def residual(self, m, u=None): - if u is None: u = self.prob.field(m) - - @requiresProblem - def residualWeighted(self, m, u=None): - if u is None: u = self.prob.field(m) - - @requiresProblem - def projectField(self, m, u=None): """ Projection matrix. @@ -93,7 +63,74 @@ class Data(object): if u is None: u = self.prob.field(m) return self.P*u + @Utils.count + def residual(self, m, u=None): + """ + :param numpy.array m: geophysical model + :param numpy.array u: fields + :rtype: float + :return: data residual + + The data residual: + + .. math:: + + \mu_\\text{data} = \mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs} + + """ + return self.dpred(m, u=u) - self.dobs + + + @property + def Wd(self): + """ + Data weighting matrix. This is a covariance matrix used in:: + + def data.residualWeighted(m,u=None): + return self.Wd*self.residual(m, u=u) + + By default, this is based on the norm of the data plus a noise floor. + + """ + if getattr(self,'_Wd',None) is None: + eps = np.linalg.norm(Utils.mkvc(self.dobs),2)*1e-5 + self._Wd = 1/(abs(self.dobs)*self.std+eps) + return self._Wd + @Wd.setter + def Wd(self, value): + self._Wd = value + + def residualWeighted(self, m, u=None): + """ + :param numpy.array m: geophysical model + :param numpy.array u: fields + :rtype: float + :return: data residual + + The weighted data residual: + + .. math:: + + \mu_\\text{data}^{\\text{weighted}} = \mathbf{W}_d(\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) + + Where W_d is a covariance matrix that weights the data residual. + """ + return self.Wd*self.residual(m, u=u) + + @property + def RHS(self): + """ + Source matrix. + """ + return self._RHS + @RHS.setter + def RHS(self, value): + self._RHS = value + + def isSynthetic(self): + "Check if the data is synthetic." + return (self.mtrue is not None) if __name__ == '__main__': - d = SimPEGData() + d = BaseData() d.dpred() diff --git a/SimPEG/Model.py b/SimPEG/Model.py new file mode 100644 index 00000000..75912deb --- /dev/null +++ b/SimPEG/Model.py @@ -0,0 +1,94 @@ +from SimPEG import Utils, np, sp + + +class BaseModel(object): + """SimPEG Model""" + + __metaclass__ = Utils.Save.Savable + + counter = None #: A SimPEG.Utils.Counter object + + def __init__(self): + pass + + def transform(self, m): + """ + :param numpy.array m: model + :rtype: numpy.array + :return: transformed model + + The *transform* changes the model into the physical property. + + A common example of this is to invert for electrical conductivity + in log space. In this case, your model will be log(sigma) and to + get back to sigma, you can take the exponential: + + """ + return m + + def transformDeriv(self, m): + """ + :param numpy.array m: model + :rtype: scipy.csr_matrix + :return: derivative of transformed model + + The *transform* changes the model into the physical property. + The *transformDeriv* provides the derivative of the *transform*. + """ + return sp.identity(m.size) + + def example(self, mesh, type=None): + return np.random.rand(mesh.nC) + + + +class LogModel(BaseModel): + """SimPEG LogModel""" + + def __init__(self, **kwargs): + BaseModel.__init__(self, **kwargs) + + def transform(self, m): + """ + :param numpy.array m: model + :rtype: numpy.array + :return: transformed model + + The *transform* changes the model into the physical property. + + A common example of this is to invert for electrical conductivity + in log space. In this case, your model will be log(sigma) and to + get back to sigma, you can take the exponential: + + .. math:: + + m = \log{\sigma} + + \exp{m} = \exp{\log{\sigma}} = \sigma + """ + return np.exp(Utils.mkvc(m)) + + def transformDeriv(self, m): + """ + :param numpy.array m: model + :rtype: scipy.csr_matrix + :return: derivative of transformed model + + The *transform* changes the model into the physical property. + The *transformDeriv* provides the derivative of the *transform*. + + If the model *transform* is: + + .. math:: + + m = \log{\sigma} + + \exp{m} = \exp{\log{\sigma}} = \sigma + + Then the derivative is: + + .. math:: + + \\frac{\partial \exp{m}}{\partial m} = \\text{sdiag}(\exp{m}) + """ + return Utils.sdiag(np.exp(Utils.mkvc(m))) diff --git a/SimPEG/forward/Problem.py b/SimPEG/Problem.py similarity index 63% rename from SimPEG/forward/Problem.py rename to SimPEG/Problem.py index 1fb5de1f..e3e5fed7 100644 --- a/SimPEG/forward/Problem.py +++ b/SimPEG/Problem.py @@ -1,9 +1,8 @@ -from SimPEG import utils, np, sp -import SimPEGData +from SimPEG import Utils, np, sp, Data norm = np.linalg.norm -class Problem(object): +class BaseProblem(object): """ Problem is the base class for all geophysical forward problems in SimPEG. @@ -36,58 +35,19 @@ class Problem(object): to (locally) find how model parameters change the data, and optimize! """ - __metaclass__ = utils.Save.Savable + __metaclass__ = Utils.Save.Savable - counter = None #: A SimPEG.utils.Counter object + counter = None #: A SimPEG.Utils.Counter object + + dataPair = Data.BaseData - def __init__(self, mesh, *args, **kwargs): - utils.setKwargs(self, **kwargs) + def __init__(self, mesh, model, *args, **kwargs): + Utils.setKwargs(self, **kwargs) self.mesh = mesh + self.model = model - @property - def RHS(self): - """ - Source matrix. - """ - return self._RHS - @RHS.setter - def RHS(self, value): - self._RHS = value - - @utils.count - def dpred(self, m, u=None): - """ - Predicted data. - - .. math:: - d_\\text{pred} = Pu(m) - """ - if u is None: - u = self.field(m) - return self.P*u - - @utils.count - def dataResidual(self, m, data, u=None): - """ - :param numpy.array m: geophysical model - :param numpy.array u: fields - :rtype: float - :return: data misfit - - The data misfit: - - .. math:: - - \mu_\\text{data} = \mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs} - - Where P is a projection matrix that brings the field on the full domain to the data measurement locations; - u is the field of interest; d_obs is the observed data. - """ - - return self.dpred(m, u=u) - data.dobs - - @utils.timeIt + @Utils.timeIt def J(self, m, v, u=None): """ :param numpy.array m: model @@ -117,7 +77,7 @@ class Problem(object): """ raise NotImplementedError('J is not yet implemented.') - @utils.timeIt + @Utils.timeIt def Jt(self, m, v, u=None): """ :param numpy.array m: model @@ -131,7 +91,7 @@ class Problem(object): raise NotImplementedError('Jt is not yet implemented.') - @utils.timeIt + @Utils.timeIt def J_approx(self, m, v, u=None): """ @@ -146,7 +106,7 @@ class Problem(object): """ return self.J(m, v, u) - @utils.timeIt + @Utils.timeIt def Jt_approx(self, m, v, u=None): """ :param numpy.array m: model @@ -170,32 +130,6 @@ class Problem(object): """ pass - def modelTransform(self, m): - """ - :param numpy.array m: model - :rtype: numpy.array - :return: transformed model - - The modelTransform changes the model into the physical property. - - A common example of this is to invert for electrical conductivity - in log space. In this case, your model will be log(sigma) and to - get back to sigma, you can take the exponential: - - """ - return m - - def modelTransformDeriv(self, m): - """ - :param numpy.array m: model - :rtype: scipy.csr_matrix - :return: derivative of transformed model - - The modelTransform changes the model into the physical property. - The modelTransformDeriv provides the derivative of the modelTransform. - """ - return sp.identity(m.size) - def createSyntheticData(self, m, std=0.05, u=None): """ Create synthetic data given a model, and a standard deviation. @@ -212,7 +146,7 @@ class Problem(object): noise = std*abs(dtrue)*np.random.randn(*dtrue.shape) dobs = dtrue+noise stdev = dobs*0 + std - return SimPEGData.Data(dobs=dobs, std=stdev, dtrue=dtrue, mtrue=m) + return self.dataPair(dobs=dobs, std=stdev, dtrue=dtrue, mtrue=m) diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index 07397233..904766d2 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -1,14 +1,15 @@ import numpy as np import scipy.sparse as sp -import utils -Solver = utils.Solver -import mesh -import forward -import inverse -import examples -import tests +import Utils +Solver = Utils.Solver +import Mesh +import Model +import Problem +import Data +import Inverse +import Examples +import Tests -Data = forward.Data import scipy.version as _v if _v.version < '0.13.0': diff --git a/SimPEG/examples/DC.py b/SimPEG/examples/DC.py index f975b108..fa50cd1c 100644 --- a/SimPEG/examples/DC.py +++ b/SimPEG/examples/DC.py @@ -1,20 +1,56 @@ from SimPEG import * -class DCProblem(forward.ModelTransforms.LogModel, forward.Problem): + + +class DCData(Data.BaseData): + """ + **DCData** + + Geophysical DC resistivity data. + + """ + + def __init__(self, mesh, model, **kwargs): + problem.BaseProblem.__init__(self, mesh, model) + self.mesh.setCellGradBC('neumann') + Utils.setKwargs(self, **kwargs) + + def reshapeFields(self, u): + if len(u.shape) == 1: + u = u.reshape([-1, self.RHS.shape[1]], order='F') + return u + + def dpred(self, m, u=None): + """ + Predicted data. + + .. math:: + d_\\text{pred} = Pu(m) + """ + if u is None: + u = self.field(m) + + u = self.reshapeFields(u) + + return Utils.mkvc(self.P*u) + + + +class DCProblem(Problem.BaseProblem): """ **DCProblem** Geophysical DC resistivity problem. """ - def __init__(self, mesh): - forward.Problem.__init__(self, mesh) - self.mesh.setCellGradBC('neumann') - def reshapeFields(self, u): - if len(u.shape) == 1: - u = u.reshape([-1, self.RHS.shape[1]], order='F') - return u + dataPair = DCData + + def __init__(self, mesh, model, **kwargs): + problem.BaseProblem.__init__(self, mesh, model) + self.mesh.setCellGradBC('neumann') + Utils.setKwargs(self, **kwargs) + def createMatrix(self, m): """ @@ -31,30 +67,16 @@ class DCProblem(forward.ModelTransforms.LogModel, forward.Problem): """ D = self.mesh.faceDiv G = self.mesh.cellGrad - sigma = self.modelTransform(m) + sigma = self.model.transform(m) Msig = self.mesh.getFaceMass(sigma) A = D*Msig*G return A.tocsc() - def dpred(self, m, u=None): - """ - Predicted data. - - .. math:: - d_\\text{pred} = Pu(m) - """ - if u is None: - u = self.field(m) - - u = self.reshapeFields(u) - - return utils.mkvc(self.P*u) - def field(self, m): A = self.createMatrix(m) solve = Solver(A) phi = solve.solve(self.RHS) - return utils.mkvc(phi) + return Utils.mkvc(phi) def J(self, m, v, u=None): """ @@ -88,17 +110,17 @@ class DCProblem(forward.ModelTransforms.LogModel, forward.Problem): G = self.mesh.cellGrad A = self.createMatrix(m) Av_dm = self.mesh.getFaceMassDeriv() - mT_dm = self.modelTransformDeriv(m) + mT_dm = self.model.transformDeriv(m) dCdu = A dCdm = np.empty_like(u) for i, ui in enumerate(u.T): # loop over each column - dCdm[:, i] = D * ( utils.sdiag( G * ui ) * ( Av_dm * ( mT_dm * v ) ) ) + dCdm[:, i] = D * ( Utils.sdiag( G * ui ) * ( Av_dm * ( mT_dm * v ) ) ) solve = Solver(dCdu) Jv = - P * solve.solve(dCdm) - return utils.mkvc(Jv) + return Utils.mkvc(Jv) def Jt(self, m, v, u=None): """Takes data, turns it into a model..ish""" @@ -114,7 +136,7 @@ class DCProblem(forward.ModelTransforms.LogModel, forward.Problem): G = self.mesh.cellGrad A = self.createMatrix(m) Av_dm = self.mesh.getFaceMassDeriv() - mT_dm = self.modelTransformDeriv(m) + mT_dm = self.model.transformDeriv(m) dCdu = A.T solve = Solver(dCdu) @@ -123,7 +145,7 @@ class DCProblem(forward.ModelTransforms.LogModel, forward.Problem): Jtv = 0 for i, ui in enumerate(u.T): # loop over each column - Jtv += utils.sdiag( G * ui ) * ( D.T * w[:,i] ) + Jtv += Utils.sdiag( G * ui ) * ( D.T * w[:,i] ) Jtv = - mT_dm.T * ( Av_dm.T * Jtv ) return Jtv @@ -174,7 +196,7 @@ if __name__ == '__main__': p0 = [5, 10] p1 = [15, 50] condVals = [sig1, sig2] - mSynth = utils.ModelBuilder.defineBlockConductivity(p0,p1,M.gridCC,condVals) + mSynth = Utils.ModelBuilder.defineBlockConductivity(p0,p1,M.gridCC,condVals) plt.colorbar(M.plotImage(mSynth)) plt.show() diff --git a/SimPEG/examples/Linear.py b/SimPEG/examples/Linear.py index dbee7dff..618ff260 100644 --- a/SimPEG/examples/Linear.py +++ b/SimPEG/examples/Linear.py @@ -1,12 +1,12 @@ -from SimPEG import mesh, forward, inverse, np +from SimPEG import Mesh, Model, Problem, Data, Inverse, np import matplotlib.pyplot as plt -class LinearProblem(forward.Problem): +class LinearProblem(Problem.BaseProblem): """docstring for LinearProblem""" def __init__(self, *args, **kwargs): - forward.Problem.__init__(self, *args, **kwargs) + problem.BaseProblem.__init__(self, *args, **kwargs) def dpred(self, m, u=None): return self.G.dot(m) @@ -39,7 +39,9 @@ def example(N): mtrue[M.vectorCCx > 0.45] = -0.5 mtrue[M.vectorCCx > 0.6] = 0 - prob = LinearProblem(M) + + + prob = LinearProblem(M, None) prob.G = G data = prob.createSyntheticData(mtrue, std=0.01) diff --git a/SimPEG/forward/ModelTransforms.py b/SimPEG/forward/ModelTransforms.py deleted file mode 100644 index ea89b974..00000000 --- a/SimPEG/forward/ModelTransforms.py +++ /dev/null @@ -1,49 +0,0 @@ -import numpy as np -from SimPEG.utils import mkvc, sdiag - -class LogModel(object): - """docstring for LogModel""" - def modelTransform(self, m): - """ - :param numpy.array m: model - :rtype: numpy.array - :return: transformed model - - The modelTransform changes the model into the physical property. - - A common example of this is to invert for electrical conductivity - in log space. In this case, your model will be log(sigma) and to - get back to sigma, you can take the exponential: - - .. math:: - - m = \log{\sigma} - - \exp{m} = \exp{\log{\sigma}} = \sigma - """ - return np.exp(mkvc(m)) - - def modelTransformDeriv(self, m): - """ - :param numpy.array m: model - :rtype: scipy.csr_matrix - :return: derivative of transformed model - - The modelTransform changes the model into the physical property. - The modelTransformDeriv provides the derivative of the modelTransform. - - If the model transform is: - - .. math:: - - m = \log{\sigma} - - \exp{m} = \exp{\log{\sigma}} = \sigma - - Then the derivative is: - - .. math:: - - \\frac{\partial \exp{m}}{\partial m} = \\text{sdiag}(\exp{m}) - """ - return sdiag(np.exp(mkvc(m))) diff --git a/SimPEG/forward/__init__.py b/SimPEG/forward/__init__.py deleted file mode 100644 index 47153f5c..00000000 --- a/SimPEG/forward/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from Problem import * -import ModelTransforms -from SimPEGData import * diff --git a/SimPEG/inverse/Inversion.py b/SimPEG/inverse/Inversion.py index 44b3e57b..1679c789 100644 --- a/SimPEG/inverse/Inversion.py +++ b/SimPEG/inverse/Inversion.py @@ -1,14 +1,14 @@ import SimPEG -from SimPEG import utils, sp, np +from SimPEG import Utils, sp, np from Optimize import Remember from BetaSchedule import Cooling -from SimPEG.inverse import IterationPrinters, StoppingCriteria +from SimPEG.Inverse import IterationPrinters, StoppingCriteria class BaseInversion(object): """BaseInversion(prob, reg, opt, data, **kwargs) """ - __metaclass__ = utils.Save.Savable + __metaclass__ = Utils.Save.Savable maxIter = 1 #: Maximum number of iterations name = 'BaseInversion' @@ -16,13 +16,13 @@ class BaseInversion(object): debug = False #: Print debugging information comment = '' #: Used by some functions to indicate what is going on in the algorithm - counter = None #: Set this to a SimPEG.utils.Counter() if you want to count things + counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things beta0 = None #: The initial Beta (regularization parameter) beta0_ratio = 0.1 #: When beta0 is set to None, estimateBeta0 is used with this ratio def __init__(self, prob, reg, opt, data, **kwargs): - utils.setKwargs(self, **kwargs) + Utils.setKwargs(self, **kwargs) self.prob = prob self.reg = reg self.opt = opt @@ -59,7 +59,7 @@ class BaseInversion(object): def phi_d_target(self, value): self._phi_d_target = value - @utils.timeIt + @Utils.timeIt def run(self, m0): """run(m0) @@ -78,7 +78,7 @@ class BaseInversion(object): return self.m - @utils.callHooks('startup') + @Utils.callHooks('startup') def startup(self, m0): """ **startup** is called at the start of any new run call. @@ -98,7 +98,7 @@ class BaseInversion(object): self.phi_d_last = np.nan self.phi_m_last = np.nan - @utils.callHooks('doStartIteration') + @Utils.callHooks('doStartIteration') def doStartIteration(self): """ **doStartIteration** is called at the end of each run iteration. @@ -109,7 +109,7 @@ class BaseInversion(object): self._beta = self.getBeta() - @utils.callHooks('doEndIteration') + @Utils.callHooks('doEndIteration') def doEndIteration(self): """ **doEndIteration** is called at the end of each run iteration. @@ -168,7 +168,7 @@ class BaseInversion(object): def stoppingCriteria(self): if self.debug: print 'checking stoppingCriteria' - return utils.checkStoppers(self, self.stoppers) + return Utils.checkStoppers(self, self.stoppers) def printDone(self): @@ -176,9 +176,9 @@ class BaseInversion(object): **printDone** is called at the end of the inversion routine. """ - utils.printStoppers(self, self.stoppers) + Utils.printStoppers(self, self.stoppers) - @utils.callHooks('finish') + @Utils.callHooks('finish') def finish(self): """finish() @@ -186,7 +186,7 @@ class BaseInversion(object): """ pass - @utils.timeIt + @Utils.timeIt def evalFunction(self, m, return_g=True, return_H=True): """evalFunction(m, return_g=True, return_H=True) @@ -226,7 +226,7 @@ class BaseInversion(object): out += (operator,) return out if len(out) > 1 else out[0] - @utils.timeIt + @Utils.timeIt def dataObj(self, m, u=None): """dataObj(m, u=None) @@ -246,10 +246,10 @@ class BaseInversion(object): """ # TODO: ensure that this is a data is vector and Wd is a matrix. R = self.Wd*self.prob.dataResidual(m, self.data, u=u) - R = utils.mkvc(R) + R = Utils.mkvc(R) return 0.5*np.vdot(R, R) - @utils.timeIt + @Utils.timeIt def dataObjDeriv(self, m, u=None): """dataObjDeriv(m, u=None) @@ -291,7 +291,7 @@ class BaseInversion(object): return dmisfit - @utils.timeIt + @Utils.timeIt def dataObj2Deriv(self, m, v, u=None): """dataObj2Deriv(m, v, u=None) diff --git a/SimPEG/inverse/Optimize.py b/SimPEG/inverse/Optimize.py index 9d5edcc2..f11cd7b1 100644 --- a/SimPEG/inverse/Optimize.py +++ b/SimPEG/inverse/Optimize.py @@ -1,4 +1,4 @@ -from SimPEG import Solver, utils, sp, np +from SimPEG import Solver, Utils, sp, np import matplotlib.pyplot as plt norm = np.linalg.norm @@ -82,7 +82,7 @@ class Minimize(object): Minimize is a general class for derivative based optimization. """ - __metaclass__ = utils.Save.Savable + __metaclass__ = Utils.Save.Savable name = "General Optimization Algorithm" #: The name of the optimization algorithm @@ -100,7 +100,7 @@ class Minimize(object): debugLS = False #: Print debugging information for the line-search comment = '' #: Used by some functions to indicate what is going on in the algorithm - counter = None #: Set this to a SimPEG.utils.Counter() if you want to count things + counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things def __init__(self, **kwargs): self.stoppers = [StoppingCriteria.tolerance_f, StoppingCriteria.moving_x, StoppingCriteria.tolerance_g, StoppingCriteria.norm_g, StoppingCriteria.iteration] @@ -109,9 +109,9 @@ class Minimize(object): self.printers = [IterationPrinters.iteration, IterationPrinters.f, IterationPrinters.norm_g, IterationPrinters.totalLS] self.printersLS = [IterationPrinters.iterationLS, IterationPrinters.LS_ft, IterationPrinters.LS_t, IterationPrinters.LS_armijoGoldstein] - utils.setKwargs(self, **kwargs) + Utils.setKwargs(self, **kwargs) - @utils.timeIt + @Utils.timeIt def minimize(self, evalFunction, x0): """minimize(evalFunction, x0) @@ -189,7 +189,7 @@ class Minimize(object): def parent(self, value): self._parent = value - @utils.callHooks('startup') + @Utils.callHooks('startup') def startup(self, x0): """ **startup** is called at the start of any new minimize call. @@ -214,8 +214,8 @@ class Minimize(object): self.f_last = np.nan self.x_last = x0 - @utils.count - @utils.callHooks('doStartIteration') + @Utils.count + @Utils.callHooks('doStartIteration') def doStartIteration(self): """doStartIteration() @@ -237,9 +237,9 @@ class Minimize(object): """ pad = ' '*10 if inLS else '' name = self.name if not inLS else self.nameLS - utils.printTitles(self, self.printers if not inLS else self.printersLS, name, pad) + Utils.printTitles(self, self.printers if not inLS else self.printersLS, name, pad) - @utils.callHooks('printIter') + @Utils.callHooks('printIter') def printIter(self, inLS=False): """ **printIter** is called directly after function evaluations. @@ -249,7 +249,7 @@ class Minimize(object): """ pad = ' '*10 if inLS else '' - utils.printLine(self, self.printers if not inLS else self.printersLS, pad=pad) + Utils.printLine(self, self.printers if not inLS else self.printersLS, pad=pad) def printDone(self, inLS=False): """ @@ -262,10 +262,10 @@ class Minimize(object): pad = ' '*10 if inLS else '' stop, done = (' STOP! ', ' DONE! ') if not inLS else ('----------------', ' End Linesearch ') stoppers = self.stoppers if not inLS else self.stoppersLS - utils.printStoppers(self, stoppers, pad='', stop=stop, done=done) + Utils.printStoppers(self, stoppers, pad='', stop=stop, done=done) - @utils.callHooks('finish') + @Utils.callHooks('finish') def finish(self): """finish() @@ -281,10 +281,10 @@ class Minimize(object): if self._iter == 0: self.f0 = self.f self.g0 = self.g - return utils.checkStoppers(self, self.stoppers if not inLS else self.stoppersLS) + return Utils.checkStoppers(self, self.stoppers if not inLS else self.stoppersLS) - @utils.timeIt - @utils.callHooks('projection') + @Utils.timeIt + @Utils.callHooks('projection') def projection(self, p): """projection(p) @@ -298,7 +298,7 @@ class Minimize(object): """ return p - @utils.timeIt + @Utils.timeIt def findSearchDirection(self): """findSearchDirection() @@ -329,7 +329,7 @@ class Minimize(object): """ return -self.g - @utils.count + @Utils.count def scaleSearchDirection(self, p): """scaleSearchDirection(p) @@ -348,7 +348,7 @@ class Minimize(object): nameLS = "Armijo linesearch" #: The line-search name - @utils.timeIt + @Utils.timeIt def modifySearchDirection(self, p): """modifySearchDirection(p) @@ -386,7 +386,7 @@ class Minimize(object): return self._LS_xt, self._iterLS < self.maxIterLS - @utils.count + @Utils.count def modifySearchDirectionBreak(self, p): """modifySearchDirectionBreak(p) @@ -408,8 +408,8 @@ class Minimize(object): print 'The linesearch got broken. Boo.' return p, False - @utils.count - @utils.callHooks('doEndIteration') + @Utils.count + @Utils.callHooks('doEndIteration') def doEndIteration(self, xt): """doEndIteration(xt) @@ -527,7 +527,7 @@ class ProjectedGradient(Minimize, Remember): self.aSet_prev = self.activeSet(x0) - @utils.count + @Utils.count def projection(self, x): """projection(x) @@ -536,7 +536,7 @@ class ProjectedGradient(Minimize, Remember): """ return np.median(np.c_[self.lower,x,self.upper],axis=1) - @utils.count + @Utils.count def activeSet(self, x): """activeSet(x) @@ -545,7 +545,7 @@ class ProjectedGradient(Minimize, Remember): """ return np.logical_or(x == self.lower, x == self.upper) - @utils.count + @Utils.count def inactiveSet(self, x): """inactiveSet(x) @@ -554,7 +554,7 @@ class ProjectedGradient(Minimize, Remember): """ return np.logical_not(self.activeSet(x)) - @utils.count + @Utils.count def bindingSet(self, x): """bindingSet(x) @@ -567,7 +567,7 @@ class ProjectedGradient(Minimize, Remember): bind_low = np.logical_and(x == self.upper, self.g <= 0) return np.logical_or(bind_up, bind_low) - @utils.timeIt + @Utils.timeIt def findSearchDirection(self): """findSearchDirection() @@ -612,7 +612,7 @@ class ProjectedGradient(Minimize, Remember): # aSet_after = self.activeSet(self.xc+p) return p - @utils.timeIt + @Utils.timeIt def _doEndIteration_ProjectedGradient(self, xt): """_doEndIteration_ProjectedGradient(xt)""" aSet = self.activeSet(xt) @@ -718,7 +718,7 @@ class GaussNewton(Minimize, Remember): def __init__(self, **kwargs): Minimize.__init__(self, **kwargs) - @utils.timeIt + @Utils.timeIt def findSearchDirection(self): return Solver(self.H).solve(-self.g) @@ -765,7 +765,7 @@ class InexactGaussNewton(BFGS, Minimize, Remember): def approxHinv(self, value): self._approxHinv = value - @utils.timeIt + @Utils.timeIt def findSearchDirection(self): Hinv = Solver(self.H, doDirect=False, options={'iterSolver': 'CG', 'M': self.approxHinv, 'tol': self.tolCG, 'maxIter': self.maxIterCG}) p = Hinv.solve(-self.g) @@ -778,7 +778,7 @@ class SteepestDescent(Minimize, Remember): def __init__(self, **kwargs): Minimize.__init__(self, **kwargs) - @utils.timeIt + @Utils.timeIt def findSearchDirection(self): return -self.g @@ -811,7 +811,7 @@ class NewtonRoot(object): doLS = True def __init__(self, **kwargs): - utils.setKwargs(self, **kwargs) + Utils.setKwargs(self, **kwargs) def root(self, fun, x): """root(fun, x) @@ -885,7 +885,7 @@ if __name__ == '__main__': print 'test the newtonRoot finding.' - fun = lambda x, return_g=True: np.sin(x) if not return_g else ( np.sin(x), utils.sdiag( np.cos(x) ) ) + fun = lambda x, return_g=True: np.sin(x) if not return_g else ( np.sin(x), Utils.sdiag( np.cos(x) ) ) x = np.array([np.pi-0.3, np.pi+0.1, 0]) pnt = NewtonRoot(comments=True).root(fun,x) print pnt diff --git a/SimPEG/inverse/Regularization.py b/SimPEG/inverse/Regularization.py index 8c6f19ef..1569d767 100644 --- a/SimPEG/inverse/Regularization.py +++ b/SimPEG/inverse/Regularization.py @@ -1,4 +1,4 @@ -from SimPEG import utils, np, sp +from SimPEG import Utils, np, sp class Regularization(object): """**Regularization** @@ -83,20 +83,20 @@ class Regularization(object): """ - __metaclass__ = utils.Save.Savable + __metaclass__ = Utils.Save.Savable - alpha_s = utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Ws'], "Smallness weight") - alpha_x = utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") - alpha_y = utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") - alpha_z = utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") - alpha_xx = utils.dependentProperty('_alpha_xx', 0.0, ['_W', '_Wxx'], "Weight for the second derivative in the x direction") - alpha_yy = utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") - alpha_zz = utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") + alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Ws'], "Smallness weight") + alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") + alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") + alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") + alpha_xx = Utils.dependentProperty('_alpha_xx', 0.0, ['_W', '_Wxx'], "Weight for the second derivative in the x direction") + alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") + alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") counter = None def __init__(self, mesh, **kwargs): - utils.setKwargs(self, **kwargs) + Utils.setKwargs(self, **kwargs) self.mesh = mesh @property @@ -112,7 +112,7 @@ class Regularization(object): def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - self._Ws = utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) + self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) return self._Ws @property @@ -120,7 +120,7 @@ class Regularization(object): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: Ave_x_vol = self.mesh.aveF2CC[:,:self.mesh.nFv[0]].T*self.mesh.vol - self._Wx = utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.mesh.cellGradx + self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.mesh.cellGradx return self._Wx @property @@ -128,7 +128,7 @@ class Regularization(object): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: Ave_y_vol = self.mesh.aveF2CC[:,self.mesh.nFv[0]:np.sum(self.mesh.nFv[:2])].T*self.mesh.vol - self._Wy = utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.mesh.cellGrady + self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.mesh.cellGrady return self._Wy @property @@ -136,28 +136,28 @@ class Regularization(object): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: Ave_z_vol = self.mesh.aveF2CC[:,np.sum(self.mesh.nFv[:2]):].T*self.mesh.vol - self._Wz = utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.mesh.cellGradz + self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.mesh.cellGradz return self._Wz @property def Wxx(self): """Regularization matrix Wxx""" if getattr(self, '_Wxx', None) is None: - self._Wxx = utils.sdiag((self.mesh.vol*self.alpha_xx)**0.5)*self.mesh.faceDivx*self.mesh.cellGradx + self._Wxx = Utils.sdiag((self.mesh.vol*self.alpha_xx)**0.5)*self.mesh.faceDivx*self.mesh.cellGradx return self._Wxx @property def Wyy(self): """Regularization matrix Wyy""" if getattr(self, '_Wyy', None) is None: - self._Wyy = utils.sdiag((self.mesh.vol*self.alpha_yy)**0.5)*self.mesh.faceDivy*self.mesh.cellGrady + self._Wyy = Utils.sdiag((self.mesh.vol*self.alpha_yy)**0.5)*self.mesh.faceDivy*self.mesh.cellGrady return self._Wyy @property def Wzz(self): """Regularization matrix Wzz""" if getattr(self, '_Wzz', None) is None: - self._Wzz = utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz + self._Wzz = Utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz return self._Wzz @@ -174,12 +174,12 @@ class Regularization(object): return self._W - @utils.timeIt + @Utils.timeIt def modelObj(self, m): r = self.W * (m - self.mref) return 0.5*r.dot(r) - @utils.timeIt + @Utils.timeIt def modelObjDeriv(self, m): """ @@ -198,7 +198,7 @@ class Regularization(object): """ return self.W.T * ( self.W * (m - self.mref) ) - @utils.timeIt + @Utils.timeIt def modelObj2Deriv(self): """ diff --git a/SimPEG/mesh/BaseMesh.py b/SimPEG/mesh/BaseMesh.py index 6151d20b..f034aa5f 100644 --- a/SimPEG/mesh/BaseMesh.py +++ b/SimPEG/mesh/BaseMesh.py @@ -1,5 +1,5 @@ import numpy as np -from SimPEG import utils +from SimPEG import Utils class BaseMesh(object): @@ -78,7 +78,7 @@ class BaseMesh(object): x_array = np.ones((x.size, len(x))) # Unwrap it and put it in a np array for i, xi in enumerate(x): - x_array[:, i] = utils.mkvc(xi) + x_array[:, i] = Utils.mkvc(xi) x = x_array assert type(x) == np.ndarray, "x must be a numpy array" @@ -91,7 +91,7 @@ class BaseMesh(object): if format == 'M': return xx.reshape(nn, order='F') elif format == 'V': - return utils.mkvc(xx) + return Utils.mkvc(xx) def switchKernal(xx): """Switches over the different options.""" @@ -101,7 +101,7 @@ class BaseMesh(object): return outKernal(xx, nn) elif xType in ['F', 'E']: # This will only deal with components of fields, not full 'F' or 'E' - xx = utils.mkvc(xx) # unwrap it in case it is a matrix + xx = Utils.mkvc(xx) # unwrap it in case it is a matrix nn = self.nFv if xType == 'F' else self.nEv nn = np.r_[0, nn] diff --git a/SimPEG/mesh/Cyl1DMesh.py b/SimPEG/mesh/Cyl1DMesh.py index e22e12b9..2b291c54 100644 --- a/SimPEG/mesh/Cyl1DMesh.py +++ b/SimPEG/mesh/Cyl1DMesh.py @@ -1,7 +1,7 @@ import numpy as np import scipy.sparse as sp from scipy.constants import pi -from SimPEG.utils import mkvc, ndgrid, sdiag +from SimPEG.Utils import mkvc, ndgrid, sdiag class Cyl1DMesh(object): """ @@ -84,7 +84,7 @@ class Cyl1DMesh(object): doc = "Total number of cells in each direction" fget = lambda self: np.array([self.nCx, self.nCz]) return locals() - nCv = property(**nCv()) + nCv = property(**nCv()) def nNr(): doc = "Number of nodes in the radial direction" diff --git a/SimPEG/mesh/DiffOperators.py b/SimPEG/mesh/DiffOperators.py index d384ca17..1e8c1ccb 100644 --- a/SimPEG/mesh/DiffOperators.py +++ b/SimPEG/mesh/DiffOperators.py @@ -1,6 +1,6 @@ import numpy as np from scipy import sparse as sp -from SimPEG.utils import mkvc, sdiag, speye, kron3, spzeros, ddx, av, avExtrap +from SimPEG.Utils import mkvc, sdiag, speye, kron3, spzeros, ddx, av, avExtrap def checkBC(bc): diff --git a/SimPEG/mesh/InnerProducts.py b/SimPEG/mesh/InnerProducts.py index 45853071..9e7c1d93 100644 --- a/SimPEG/mesh/InnerProducts.py +++ b/SimPEG/mesh/InnerProducts.py @@ -1,5 +1,5 @@ from scipy import sparse as sp -from SimPEG.utils import sub2ind, ndgrid, mkvc, getSubArray, sdiag, inv3X3BlockDiagonal, inv2X2BlockDiagonal +from SimPEG.Utils import sub2ind, ndgrid, mkvc, getSubArray, sdiag, inv3X3BlockDiagonal, inv2X2BlockDiagonal import numpy as np diff --git a/SimPEG/mesh/LogicallyOrthogonalMesh.py b/SimPEG/mesh/LogicallyOrthogonalMesh.py index b3dcd095..a0495630 100644 --- a/SimPEG/mesh/LogicallyOrthogonalMesh.py +++ b/SimPEG/mesh/LogicallyOrthogonalMesh.py @@ -1,4 +1,4 @@ -from SimPEG import utils, np +from SimPEG import Utils, np from BaseMesh import BaseMesh from DiffOperators import DiffOperators from InnerProducts import InnerProducts @@ -7,8 +7,8 @@ from LomView import LomView # Some helper functions. length2D = lambda x: (x[:, 0]**2 + x[:, 1]**2)**0.5 length3D = lambda x: (x[:, 0]**2 + x[:, 1]**2 + x[:, 2]**2)**0.5 -normalize2D = lambda x: x/np.kron(np.ones((1, 2)), utils.mkvc(length2D(x), 2)) -normalize3D = lambda x: x/np.kron(np.ones((1, 3)), utils.mkvc(length3D(x), 2)) +normalize2D = lambda x: x/np.kron(np.ones((1, 2)), Utils.mkvc(length2D(x), 2)) +normalize3D = lambda x: x/np.kron(np.ones((1, 3)), Utils.mkvc(length3D(x), 2)) class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): @@ -21,7 +21,7 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): """ - __metaclass__ = utils.Save.Savable + __metaclass__ = Utils.Save.Savable _meshType = 'LOM' @@ -40,7 +40,7 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): # Save nodes to private variable _gridN as vectors self._gridN = np.ones((nodes[0].size, self.dim)) for i, node_i in enumerate(nodes): - self._gridN[:, i] = utils.mkvc(node_i.astype(float)) + self._gridN[:, i] = Utils.mkvc(node_i.astype(float)) def gridCC(): doc = "Cell-centered grid." @@ -71,10 +71,10 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): if self._gridFx is None: N = self.r(self.gridN, 'N', 'N', 'M') if self.dim == 2: - XY = [utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N] + XY = [Utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N] self._gridFx = np.c_[XY[0], XY[1]] elif self.dim == 3: - XYZ = [utils.mkvc(0.25 * (n[:, :-1, :-1] + n[:, :-1, 1:] + n[:, 1:, :-1] + n[:, 1:, 1:])) for n in N] + XYZ = [Utils.mkvc(0.25 * (n[:, :-1, :-1] + n[:, :-1, 1:] + n[:, 1:, :-1] + n[:, 1:, 1:])) for n in N] self._gridFx = np.c_[XYZ[0], XYZ[1], XYZ[2]] return self._gridFx return locals() @@ -88,10 +88,10 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): if self._gridFy is None: N = self.r(self.gridN, 'N', 'N', 'M') if self.dim == 2: - XY = [utils.mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N] + XY = [Utils.mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N] self._gridFy = np.c_[XY[0], XY[1]] elif self.dim == 3: - XYZ = [utils.mkvc(0.25 * (n[:-1, :, :-1] + n[:-1, :, 1:] + n[1:, :, :-1] + n[1:, :, 1:])) for n in N] + XYZ = [Utils.mkvc(0.25 * (n[:-1, :, :-1] + n[:-1, :, 1:] + n[1:, :, :-1] + n[1:, :, 1:])) for n in N] self._gridFy = np.c_[XYZ[0], XYZ[1], XYZ[2]] return self._gridFy return locals() @@ -104,7 +104,7 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): def fget(self): if self._gridFz is None and self.dim == 3: N = self.r(self.gridN, 'N', 'N', 'M') - XYZ = [utils.mkvc(0.25 * (n[:-1, :-1, :] + n[:-1, 1:, :] + n[1:, :-1, :] + n[1:, 1:, :])) for n in N] + XYZ = [Utils.mkvc(0.25 * (n[:-1, :-1, :] + n[:-1, 1:, :] + n[1:, :-1, :] + n[1:, 1:, :])) for n in N] self._gridFz = np.c_[XYZ[0], XYZ[1], XYZ[2]] return self._gridFz return locals() @@ -118,10 +118,10 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): if self._gridEx is None: N = self.r(self.gridN, 'N', 'N', 'M') if self.dim == 2: - XY = [utils.mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N] + XY = [Utils.mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N] self._gridEx = np.c_[XY[0], XY[1]] elif self.dim == 3: - XYZ = [utils.mkvc(0.5 * (n[:-1, :, :] + n[1:, :, :])) for n in N] + XYZ = [Utils.mkvc(0.5 * (n[:-1, :, :] + n[1:, :, :])) for n in N] self._gridEx = np.c_[XYZ[0], XYZ[1], XYZ[2]] return self._gridEx return locals() @@ -135,10 +135,10 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): if self._gridEy is None: N = self.r(self.gridN, 'N', 'N', 'M') if self.dim == 2: - XY = [utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N] + XY = [Utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N] self._gridEy = np.c_[XY[0], XY[1]] elif self.dim == 3: - XYZ = [utils.mkvc(0.5 * (n[:, :-1, :] + n[:, 1:, :])) for n in N] + XYZ = [Utils.mkvc(0.5 * (n[:, :-1, :] + n[:, 1:, :])) for n in N] self._gridEy = np.c_[XYZ[0], XYZ[1], XYZ[2]] return self._gridEy return locals() @@ -151,7 +151,7 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): def fget(self): if self._gridEz is None and self.dim == 3: N = self.r(self.gridN, 'N', 'N', 'M') - XYZ = [utils.mkvc(0.5 * (n[:, :, :-1] + n[:, :, 1:])) for n in N] + XYZ = [Utils.mkvc(0.5 * (n[:, :, :-1] + n[:, :, 1:])) for n in N] self._gridEz = np.c_[XYZ[0], XYZ[1], XYZ[2]] return self._gridEz return locals() @@ -194,25 +194,25 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): def fget(self): if(self._vol is None): if self.dim == 2: - A, B, C, D = utils.indexCube('ABCD', self.n+1) - normal, area = utils.faceInfo(np.c_[self.gridN, np.zeros((self.nN, 1))], A, B, C, D) + A, B, C, D = Utils.indexCube('ABCD', self.n+1) + normal, area = Utils.faceInfo(np.c_[self.gridN, np.zeros((self.nN, 1))], A, B, C, D) self._vol = area elif self.dim == 3: # Each polyhedron can be decomposed into 5 tetrahedrons # However, this presents a choice so we may as well divide in two ways and average. - A, B, C, D, E, F, G, H = utils.indexCube('ABCDEFGH', self.n+1) + A, B, C, D, E, F, G, H = Utils.indexCube('ABCDEFGH', self.n+1) - vol1 = (utils.volTetra(self.gridN, A, B, D, E) + # cutted edge top - utils.volTetra(self.gridN, B, E, F, G) + # cutted edge top - utils.volTetra(self.gridN, B, D, E, G) + # middle - utils.volTetra(self.gridN, B, C, D, G) + # cutted edge bottom - utils.volTetra(self.gridN, D, E, G, H)) # cutted edge bottom + vol1 = (Utils.volTetra(self.gridN, A, B, D, E) + # cutted edge top + Utils.volTetra(self.gridN, B, E, F, G) + # cutted edge top + Utils.volTetra(self.gridN, B, D, E, G) + # middle + Utils.volTetra(self.gridN, B, C, D, G) + # cutted edge bottom + Utils.volTetra(self.gridN, D, E, G, H)) # cutted edge bottom - vol2 = (utils.volTetra(self.gridN, A, F, B, C) + # cutted edge top - utils.volTetra(self.gridN, A, E, F, H) + # cutted edge top - utils.volTetra(self.gridN, A, H, F, C) + # middle - utils.volTetra(self.gridN, C, H, D, A) + # cutted edge bottom - utils.volTetra(self.gridN, C, G, H, F)) # cutted edge bottom + vol2 = (Utils.volTetra(self.gridN, A, F, B, C) + # cutted edge top + Utils.volTetra(self.gridN, A, E, F, H) + # cutted edge top + Utils.volTetra(self.gridN, A, H, F, C) + # middle + Utils.volTetra(self.gridN, C, H, D, A) + # cutted edge bottom + Utils.volTetra(self.gridN, C, G, H, F)) # cutted edge bottom self._vol = (vol1 + vol2)/2 return self._vol @@ -228,30 +228,30 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): # Compute areas of cell faces if(self.dim == 2): xy = self.gridN - A, B = utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy])) + A, B = Utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy])) edge1 = xy[B, :] - xy[A, :] normal1 = np.c_[edge1[:, 1], -edge1[:, 0]] area1 = length2D(edge1) - A, D = utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy])) + A, D = Utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy])) # Note that we are doing A-D to make sure the normal points the right way. # Think about it. Look at the picture. Normal points towards C iff you do this. edge2 = xy[A, :] - xy[D, :] normal2 = np.c_[edge2[:, 1], -edge2[:, 0]] area2 = length2D(edge2) - self._area = np.r_[utils.mkvc(area1), utils.mkvc(area2)] + self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2)] self._normals = [normalize2D(normal1), normalize2D(normal2)] elif(self.dim == 3): - A, E, F, B = utils.indexCube('AEFB', self.n+1, np.array([self.nNx, self.nCy, self.nCz])) - normal1, area1 = utils.faceInfo(self.gridN, A, E, F, B, average=False, normalizeNormals=False) + A, E, F, B = Utils.indexCube('AEFB', self.n+1, np.array([self.nNx, self.nCy, self.nCz])) + normal1, area1 = Utils.faceInfo(self.gridN, A, E, F, B, average=False, normalizeNormals=False) - A, D, H, E = utils.indexCube('ADHE', self.n+1, np.array([self.nCx, self.nNy, self.nCz])) - normal2, area2 = utils.faceInfo(self.gridN, A, D, H, E, average=False, normalizeNormals=False) + A, D, H, E = Utils.indexCube('ADHE', self.n+1, np.array([self.nCx, self.nNy, self.nCz])) + normal2, area2 = Utils.faceInfo(self.gridN, A, D, H, E, average=False, normalizeNormals=False) - A, B, C, D = utils.indexCube('ABCD', self.n+1, np.array([self.nCx, self.nCy, self.nNz])) - normal3, area3 = utils.faceInfo(self.gridN, A, B, C, D, average=False, normalizeNormals=False) + A, B, C, D = Utils.indexCube('ABCD', self.n+1, np.array([self.nCx, self.nCy, self.nNz])) + normal3, area3 = Utils.faceInfo(self.gridN, A, B, C, D, average=False, normalizeNormals=False) - self._area = np.r_[utils.mkvc(area1), utils.mkvc(area2), utils.mkvc(area3)] + self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2), Utils.mkvc(area3)] self._normals = [normal1, normal2, normal3] return self._area return locals() @@ -291,21 +291,21 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): if(self._edge is None or self._tangents is None): if(self.dim == 2): xy = self.gridN - A, D = utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy])) + A, D = Utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy])) edge1 = xy[D, :] - xy[A, :] - A, B = utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy])) + A, B = Utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy])) edge2 = xy[B, :] - xy[A, :] - self._edge = np.r_[utils.mkvc(length2D(edge1)), utils.mkvc(length2D(edge2))] + self._edge = np.r_[Utils.mkvc(length2D(edge1)), Utils.mkvc(length2D(edge2))] self._tangents = np.r_[edge1, edge2]/np.c_[self._edge, self._edge] elif(self.dim == 3): xyz = self.gridN - A, D = utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy, self.nNz])) + A, D = Utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy, self.nNz])) edge1 = xyz[D, :] - xyz[A, :] - A, B = utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy, self.nNz])) + A, B = Utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy, self.nNz])) edge2 = xyz[B, :] - xyz[A, :] - A, E = utils.indexCube('AE', self.n+1, np.array([self.nNx, self.nNy, self.nCz])) + A, E = Utils.indexCube('AE', self.n+1, np.array([self.nNx, self.nNy, self.nCz])) edge3 = xyz[E, :] - xyz[A, :] - self._edge = np.r_[utils.mkvc(length3D(edge1)), utils.mkvc(length3D(edge2)), utils.mkvc(length3D(edge3))] + self._edge = np.r_[Utils.mkvc(length3D(edge1)), Utils.mkvc(length3D(edge2)), Utils.mkvc(length3D(edge3))] self._tangents = np.r_[edge1, edge2, edge3]/np.c_[self._edge, self._edge, self._edge] return self._edge return locals() @@ -331,10 +331,10 @@ if __name__ == '__main__': h3 = np.cumsum(np.r_[0, np.ones(nc)/(nc)]) dee3 = True if dee3: - X, Y, Z = utils.ndgrid(h1, h2, h3, vector=False) + X, Y, Z = Utils.ndgrid(h1, h2, h3, vector=False) M = LogicallyOrthogonalMesh([X, Y, Z]) else: - X, Y = utils.ndgrid(h1, h2, vector=False) + X, Y = Utils.ndgrid(h1, h2, vector=False) M = LogicallyOrthogonalMesh([X, Y]) print M.r(M.normals, 'F', 'Fx', 'V') diff --git a/SimPEG/mesh/LomView.py b/SimPEG/mesh/LomView.py index 2a9b242b..8243a248 100644 --- a/SimPEG/mesh/LomView.py +++ b/SimPEG/mesh/LomView.py @@ -2,7 +2,7 @@ import numpy as np import matplotlib.pyplot as plt import matplotlib from mpl_toolkits.mplot3d import Axes3D -from SimPEG.utils import mkvc +from SimPEG.Utils import mkvc class LomView(object): diff --git a/SimPEG/mesh/TensorMesh.py b/SimPEG/mesh/TensorMesh.py index d4ab86b0..544ec716 100644 --- a/SimPEG/mesh/TensorMesh.py +++ b/SimPEG/mesh/TensorMesh.py @@ -1,4 +1,4 @@ -from SimPEG import utils, np, sp +from SimPEG import Utils, np, sp from BaseMesh import BaseMesh from TensorView import TensorView from DiffOperators import DiffOperators @@ -23,8 +23,8 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): .. plot:: - from SimPEG import mesh, utils - M = mesh.TensorMesh(utils.meshTensors(((10,10),(40,10),(10,10)), ((10,10),(20,10),(0,0)))) + from SimPEG import mesh, Utils + M = mesh.TensorMesh(Utils.meshTensors(((10,10),(40,10),(10,10)), ((10,10),(20,10),(0,0)))) M.plotGrid() For a quick tensor mesh on a (10x12x15) unit cube:: @@ -33,7 +33,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): """ - __metaclass__ = utils.Save.Savable + __metaclass__ = Utils.Save.Savable _meshType = 'TENSOR' @@ -52,7 +52,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): assert len(h) == len(self.x0), "Dimension mismatch. x0 != len(h)" # Ensure h contains 1D vectors - self._h = [utils.mkvc(x.astype(float)) for x in h] + self._h = [Utils.mkvc(x.astype(float)) for x in h] def __str__(self): outStr = ' ---- {0:d}-D TensorMesh ---- '.format(self.dim) @@ -170,7 +170,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): def fget(self): if self._gridCC is None: - self._gridCC = utils.ndgrid(self.getTensor('CC')) + self._gridCC = Utils.ndgrid(self.getTensor('CC')) return self._gridCC return locals() _gridCC = None # Store grid by default @@ -181,7 +181,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): def fget(self): if self._gridN is None: - self._gridN = utils.ndgrid(self.getTensor('N')) + self._gridN = Utils.ndgrid(self.getTensor('N')) return self._gridN return locals() _gridN = None # Store grid by default @@ -192,7 +192,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): def fget(self): if self._gridFx is None: - self._gridFx = utils.ndgrid(self.getTensor('Fx')) + self._gridFx = Utils.ndgrid(self.getTensor('Fx')) return self._gridFx return locals() _gridFx = None # Store grid by default @@ -203,7 +203,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): def fget(self): if self._gridFy is None and self.dim > 1: - self._gridFy = utils.ndgrid(self.getTensor('Fy')) + self._gridFy = Utils.ndgrid(self.getTensor('Fy')) return self._gridFy return locals() _gridFy = None # Store grid by default @@ -214,7 +214,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): def fget(self): if self._gridFz is None and self.dim > 2: - self._gridFz = utils.ndgrid(self.getTensor('Fz')) + self._gridFz = Utils.ndgrid(self.getTensor('Fz')) return self._gridFz return locals() _gridFz = None # Store grid by default @@ -225,7 +225,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): def fget(self): if self._gridEx is None: - self._gridEx = utils.ndgrid(self.getTensor('Ex')) + self._gridEx = Utils.ndgrid(self.getTensor('Ex')) return self._gridEx return locals() _gridEx = None # Store grid by default @@ -236,7 +236,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): def fget(self): if self._gridEy is None and self.dim > 1: - self._gridEy = utils.ndgrid(self.getTensor('Ey')) + self._gridEy = Utils.ndgrid(self.getTensor('Ey')) return self._gridEy return locals() _gridEy = None # Store grid by default @@ -247,7 +247,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): def fget(self): if self._gridEz is None and self.dim > 2: - self._gridEz = utils.ndgrid(self.getTensor('Ez')) + self._gridEz = Utils.ndgrid(self.getTensor('Ez')) return self._gridEz return locals() _gridEz = None # Store grid by default @@ -262,13 +262,13 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): vh = self.h # Compute cell volumes if(self.dim == 1): - self._vol = utils.mkvc(vh[0]) + self._vol = Utils.mkvc(vh[0]) elif(self.dim == 2): # Cell sizes in each direction - self._vol = utils.mkvc(np.outer(vh[0], vh[1])) + self._vol = Utils.mkvc(np.outer(vh[0], vh[1])) elif(self.dim == 3): # Cell sizes in each direction - self._vol = utils.mkvc(np.outer(utils.mkvc(np.outer(vh[0], vh[1])), vh[2])) + self._vol = Utils.mkvc(np.outer(Utils.mkvc(np.outer(vh[0], vh[1])), vh[2])) return self._vol return locals() _vol = None @@ -289,12 +289,12 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): elif(self.dim == 2): area1 = np.outer(np.ones(n[0]+1), vh[1]) area2 = np.outer(vh[0], np.ones(n[1]+1)) - self._area = np.r_[utils.mkvc(area1), utils.mkvc(area2)] + self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2)] elif(self.dim == 3): - area1 = np.outer(np.ones(n[0]+1), utils.mkvc(np.outer(vh[1], vh[2]))) - area2 = np.outer(vh[0], utils.mkvc(np.outer(np.ones(n[1]+1), vh[2]))) - area3 = np.outer(vh[0], utils.mkvc(np.outer(vh[1], np.ones(n[2]+1)))) - self._area = np.r_[utils.mkvc(area1), utils.mkvc(area2), utils.mkvc(area3)] + area1 = np.outer(np.ones(n[0]+1), Utils.mkvc(np.outer(vh[1], vh[2]))) + area2 = np.outer(vh[0], Utils.mkvc(np.outer(np.ones(n[1]+1), vh[2]))) + area3 = np.outer(vh[0], Utils.mkvc(np.outer(vh[1], np.ones(n[2]+1)))) + self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2), Utils.mkvc(area3)] return self._area return locals() _area = None @@ -311,16 +311,16 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): n = self.n # Compute edge lengths if(self.dim == 1): - self._edge = utils.mkvc(vh[0]) + self._edge = Utils.mkvc(vh[0]) elif(self.dim == 2): l1 = np.outer(vh[0], np.ones(n[1]+1)) l2 = np.outer(np.ones(n[0]+1), vh[1]) - self._edge = np.r_[utils.mkvc(l1), utils.mkvc(l2)] + self._edge = np.r_[Utils.mkvc(l1), Utils.mkvc(l2)] elif(self.dim == 3): - l1 = np.outer(vh[0], utils.mkvc(np.outer(np.ones(n[1]+1), np.ones(n[2]+1)))) - l2 = np.outer(np.ones(n[0]+1), utils.mkvc(np.outer(vh[1], np.ones(n[2]+1)))) - l3 = np.outer(np.ones(n[0]+1), utils.mkvc(np.outer(np.ones(n[1]+1), vh[2]))) - self._edge = np.r_[utils.mkvc(l1), utils.mkvc(l2), utils.mkvc(l3)] + l1 = np.outer(vh[0], Utils.mkvc(np.outer(np.ones(n[1]+1), np.ones(n[2]+1)))) + l2 = np.outer(np.ones(n[0]+1), Utils.mkvc(np.outer(vh[1], np.ones(n[2]+1)))) + l3 = np.outer(np.ones(n[0]+1), Utils.mkvc(np.outer(np.ones(n[1]+1), vh[2]))) + self._edge = np.r_[Utils.mkvc(l1), Utils.mkvc(l2), Utils.mkvc(l3)] return self._edge return locals() _edge = None @@ -410,11 +410,11 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): ind = 0 if 'x' in locType else 1 if 'y' in locType else 2 if 'z' in locType else -1 if locType in ['Fx','Fy','Fz','Ex','Ey','Ez'] and self.dim >= ind: nF_nE = self.nFv if 'F' in locType else self.nEv - components = [utils.spzeros(loc.shape[0], n) for n in nF_nE] - components[ind] = utils.interpmat(loc, *self.getTensor(locType)) + components = [Utils.spzeros(loc.shape[0], n) for n in nF_nE] + components[ind] = Utils.interpmat(loc, *self.getTensor(locType)) Q = sp.hstack(components) elif locType in ['CC', 'N']: - Q = utils.interpmat(loc, *self.getTensor(locType)) + Q = Utils.interpmat(loc, *self.getTensor(locType)) else: raise NotImplementedError('getInterpolationMat: locType=='+locType+' and mesh.dim=='+str(self.dim)) return Q diff --git a/SimPEG/mesh/TensorView.py b/SimPEG/mesh/TensorView.py index a745c1cd..cbecde0a 100644 --- a/SimPEG/mesh/TensorView.py +++ b/SimPEG/mesh/TensorView.py @@ -2,7 +2,7 @@ import numpy as np import matplotlib.pyplot as plt import matplotlib from mpl_toolkits.mplot3d import Axes3D -from SimPEG.utils import mkvc, animate +from SimPEG.Utils import mkvc, animate class TensorView(object): diff --git a/SimPEG/setup.py b/SimPEG/setup.py index c421cb4b..5afc57a4 100644 --- a/SimPEG/setup.py +++ b/SimPEG/setup.py @@ -1,8 +1,8 @@ import os print 'Compiling TriSolve.' -os.system('f2py -c utils/TriSolve.f -m TriSolve') +os.system('f2py -c Utils/TriSolve.f -m TriSolve') print 'TriSolve Compiled! yay.' print 'Moving TriSolve into Utils.' -os.system('mv TriSolve.so utils/TriSolve.so') +os.system('mv TriSolve.so Utils/TriSolve.so') print 'Thats it. Well Done Computer.' diff --git a/SimPEG/tests/TestUtils.py b/SimPEG/tests/TestUtils.py index fa4ee89a..c5490f90 100644 --- a/SimPEG/tests/TestUtils.py +++ b/SimPEG/tests/TestUtils.py @@ -1,9 +1,9 @@ import numpy as np import matplotlib.pyplot as plt from numpy.linalg import norm -from SimPEG.utils import mkvc, sdiag -from SimPEG import utils -from SimPEG.mesh import TensorMesh, LogicallyOrthogonalMesh +from SimPEG.Utils import mkvc, sdiag +from SimPEG import Utils +from SimPEG.Mesh import TensorMesh, LogicallyOrthogonalMesh import numpy as np import scipy.sparse as sp import unittest @@ -112,10 +112,10 @@ class OrderTest(unittest.TestCase): else: raise Exception('Unexpected meshType') if self.meshDimension == 2: - X, Y = utils.exampleLomGird([nc, nc], kwrd) + X, Y = Utils.exampleLomGird([nc, nc], kwrd) self.M = LogicallyOrthogonalMesh([X, Y]) if self.meshDimension == 3: - X, Y, Z = utils.exampleLomGird([nc, nc, nc], kwrd) + X, Y, Z = Utils.exampleLomGird([nc, nc, nc], kwrd) self.M = LogicallyOrthogonalMesh([X, Y, Z]) return 1./nc @@ -212,7 +212,7 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole :include-source: from SimPEG.tests import checkDerivative - from SimPEG.utils import sdiag + from SimPEG.Utils import sdiag import numpy as np def simplePass(x): return np.sin(x), sdiag(np.cos(x)) diff --git a/SimPEG/tests/test_LogicallyOrthogonalMesh.py b/SimPEG/tests/test_LogicallyOrthogonalMesh.py index d760e230..241b2da8 100644 --- a/SimPEG/tests/test_LogicallyOrthogonalMesh.py +++ b/SimPEG/tests/test_LogicallyOrthogonalMesh.py @@ -1,7 +1,7 @@ import numpy as np import unittest -from SimPEG.mesh import TensorMesh, LogicallyOrthogonalMesh -from SimPEG.utils import ndgrid +from SimPEG.Mesh import TensorMesh, LogicallyOrthogonalMesh +from SimPEG.Utils import ndgrid class BasicLOMTests(unittest.TestCase): diff --git a/SimPEG/tests/test_Solver.py b/SimPEG/tests/test_Solver.py index f8c2964d..f8a8983f 100644 --- a/SimPEG/tests/test_Solver.py +++ b/SimPEG/tests/test_Solver.py @@ -1,7 +1,7 @@ import unittest from SimPEG import Solver -from SimPEG.mesh import TensorMesh -from SimPEG.utils import sdiag +from SimPEG.Mesh import TensorMesh +from SimPEG.Utils import sdiag import numpy as np import scipy.sparse as sparse diff --git a/SimPEG/tests/test_basemesh.py b/SimPEG/tests/test_basemesh.py index d81a8553..835bd29e 100644 --- a/SimPEG/tests/test_basemesh.py +++ b/SimPEG/tests/test_basemesh.py @@ -1,6 +1,6 @@ import unittest import sys -from SimPEG.mesh import BaseMesh +from SimPEG.Mesh import BaseMesh import numpy as np diff --git a/SimPEG/tests/test_forward_DCproblem.py b/SimPEG/tests/test_forward_DCproblem.py index 90312fdf..1a44b350 100644 --- a/SimPEG/tests/test_forward_DCproblem.py +++ b/SimPEG/tests/test_forward_DCproblem.py @@ -1,85 +1,85 @@ -import numpy as np -import unittest -from SimPEG.mesh import TensorMesh -from SimPEG.utils import ModelBuilder, sdiag -from SimPEG.forward import Problem -from SimPEG.examples.DC import * -from TestUtils import checkDerivative -from scipy.sparse.linalg import dsolve -from SimPEG import inverse +# import numpy as np +# import unittest +# from SimPEG.mesh import TensorMesh +# from SimPEG.Utils import ModelBuilder, sdiag +# from SimPEG.forward import Problem +# from SimPEG.examples.DC import * +# from TestUtils import checkDerivative +# from scipy.sparse.linalg import dsolve +# from SimPEG import inverse -class DCProblemTests(unittest.TestCase): +# class DCProblemTests(unittest.TestCase): - def setUp(self): - # Create the mesh - h1 = np.ones(20) - h2 = np.ones(20) - mesh = TensorMesh([h1,h2]) +# def setUp(self): +# # Create the mesh +# h1 = np.ones(20) +# h2 = np.ones(20) +# mesh = TensorMesh([h1,h2]) - # Create some parameters for the model - sig1 = 1 - sig2 = 0.01 +# # Create some parameters for the model +# sig1 = 1 +# sig2 = 0.01 - # Create a synthetic model from a block in a half-space - p0 = [2, 2] - p1 = [5, 5] - condVals = [sig1, sig2] - mSynth = ModelBuilder.defineBlockConductivity(p0,p1,mesh.gridCC,condVals) +# # Create a synthetic model from a block in a half-space +# p0 = [2, 2] +# p1 = [5, 5] +# condVals = [sig1, sig2] +# mSynth = ModelBuilder.defineBlockConductivity(p0,p1,mesh.gridCC,condVals) - # Set up the projection - nelec = 10 - spacelec = 2 - surfloc = 0.5 - elecini = 0.5 - elecend = 0.5+spacelec*(nelec-1) - elecLocR = np.linspace(elecini, elecend, nelec) - rxmidLoc = (elecLocR[0:nelec-1]+elecLocR[1:nelec])*0.5 - q, Q, rxmidloc = genTxRxmat(nelec, spacelec, surfloc, elecini, mesh) - P = Q.T +# # Set up the projection +# nelec = 10 +# spacelec = 2 +# surfloc = 0.5 +# elecini = 0.5 +# elecend = 0.5+spacelec*(nelec-1) +# elecLocR = np.linspace(elecini, elecend, nelec) +# rxmidLoc = (elecLocR[0:nelec-1]+elecLocR[1:nelec])*0.5 +# q, Q, rxmidloc = genTxRxmat(nelec, spacelec, surfloc, elecini, mesh) +# P = Q.T - # Create some data +# # Create some data - problem = DCProblem(mesh) - problem.P = P - problem.RHS = q - data = problem.createSyntheticData(mSynth, std=0.05) +# problem = DCProblem(mesh) +# problem.P = P +# problem.RHS = q +# data = problem.createSyntheticData(mSynth, std=0.05) - # Now set up the problem to do some minimization - opt = inverse.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) - reg = inverse.Regularization(mesh) - inv = inverse.Inversion(problem, reg, opt, data, beta0=1e4) +# # Now set up the problem to do some minimization +# opt = inverse.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) +# reg = inverse.Regularization(mesh) +# inv = inverse.Inversion(problem, reg, opt, data, beta0=1e4) - self.inv = inv - self.reg = reg - self.p = problem - self.mesh = mesh - self.m0 = mSynth - self.data = data +# self.inv = inv +# self.reg = reg +# self.p = problem +# self.mesh = mesh +# self.m0 = mSynth +# self.data = data - def test_misfit(self): - derChk = lambda m: [self.p.dpred(m), lambda mx: self.p.J(self.m0, mx)] - passed = checkDerivative(derChk, self.m0, plotIt=False) - self.assertTrue(passed) +# def test_misfit(self): +# derChk = lambda m: [self.p.dpred(m), lambda mx: self.p.J(self.m0, mx)] +# passed = checkDerivative(derChk, self.m0, plotIt=False) +# self.assertTrue(passed) - def test_adjoint(self): - # Adjoint Test - u = np.random.rand(self.mesh.nC*self.p.RHS.shape[1]) - v = np.random.rand(self.mesh.nC) - w = np.random.rand(self.data.dobs.shape[0]) - wtJv = w.dot(self.p.J(self.m0, v, u=u)) - vtJtw = v.dot(self.p.Jt(self.m0, w, u=u)) - passed = (wtJv - vtJtw) < 1e-10 - self.assertTrue(passed) +# def test_adjoint(self): +# # Adjoint Test +# u = np.random.rand(self.mesh.nC*self.p.RHS.shape[1]) +# v = np.random.rand(self.mesh.nC) +# w = np.random.rand(self.data.dobs.shape[0]) +# wtJv = w.dot(self.p.J(self.m0, v, u=u)) +# vtJtw = v.dot(self.p.Jt(self.m0, w, u=u)) +# passed = (wtJv - vtJtw) < 1e-10 +# self.assertTrue(passed) - def test_dataObj(self): - derChk = lambda m: [self.inv.dataObj(m), self.inv.dataObjDeriv(m)] - checkDerivative(derChk, self.m0, plotIt=False) +# def test_dataObj(self): +# derChk = lambda m: [self.inv.dataObj(m), self.inv.dataObjDeriv(m)] +# checkDerivative(derChk, self.m0, plotIt=False) - def test_modelObj(self): - derChk = lambda m: [self.reg.modelObj(m), self.reg.modelObjDeriv(m)] - checkDerivative(derChk, self.m0, plotIt=False) +# def test_modelObj(self): +# derChk = lambda m: [self.reg.modelObj(m), self.reg.modelObjDeriv(m)] +# checkDerivative(derChk, self.m0, plotIt=False) -if __name__ == '__main__': - unittest.main() +# if __name__ == '__main__': +# unittest.main() diff --git a/SimPEG/tests/test_interpolation.py b/SimPEG/tests/test_interpolation.py index 3d751dde..d01dcbc3 100644 --- a/SimPEG/tests/test_interpolation.py +++ b/SimPEG/tests/test_interpolation.py @@ -1,7 +1,7 @@ import numpy as np import unittest from TestUtils import OrderTest -from SimPEG.utils import mkvc +from SimPEG.Utils import mkvc MESHTYPES = ['uniformTensorMesh', 'randomTensorMesh'] TOLERANCES = [0.9, 0.55] diff --git a/SimPEG/tests/test_model.py b/SimPEG/tests/test_model.py new file mode 100644 index 00000000..946224f1 --- /dev/null +++ b/SimPEG/tests/test_model.py @@ -0,0 +1,27 @@ +import numpy as np +import unittest +from SimPEG import * +from TestUtils import checkDerivative +from scipy.sparse.linalg import dsolve + + +class ModelTests(unittest.TestCase): + + def setUp(self): + + a = np.array([1, 1, 1]) + b = np.array([1, 2]) + c = np.array([1, 4]) + self.mesh2 = Mesh.TensorMesh([a, b], np.array([3, 5])) + + def test_modelTransforms(self): + print 'SimPEG.Model.BaseModel: Testing Model Transform' + for M in dir(Model): + if 'Model' not in M: continue + model = getattr(Model, M)() + m = model.example(self.mesh2) + passed = checkDerivative(lambda m : [model.transform(m), model.transformDeriv(m)], m, plotIt=False) + self.assertTrue(passed) + +if __name__ == '__main__': + unittest.main() diff --git a/SimPEG/tests/test_optimizers.py b/SimPEG/tests/test_optimizers.py index 0253852c..12c8c9b5 100644 --- a/SimPEG/tests/test_optimizers.py +++ b/SimPEG/tests/test_optimizers.py @@ -1,11 +1,11 @@ import unittest from SimPEG import Solver -from SimPEG.mesh import TensorMesh -from SimPEG.utils import sdiag +from SimPEG.Mesh import TensorMesh +from SimPEG.Utils import sdiag import numpy as np import scipy.sparse as sp -from SimPEG import inverse -from SimPEG.tests import getQuadratic, Rosenbrock +from SimPEG import Inverse +from SimPEG.Tests import getQuadratic, Rosenbrock TOL = 1e-2 @@ -16,7 +16,7 @@ class TestOptimizers(unittest.TestCase): self.b = np.array([-5,-5]) def test_GN_Rosenbrock(self): - GN = inverse.GaussNewton() + GN = Inverse.GaussNewton() xopt = GN.minimize(Rosenbrock,np.array([0,0])) x_true = np.array([1.,1.]) print 'xopt: ', xopt @@ -24,7 +24,7 @@ class TestOptimizers(unittest.TestCase): self.assertTrue(np.linalg.norm(xopt-x_true,2) < TOL, True) def test_GN_quadratic(self): - GN = inverse.GaussNewton() + GN = Inverse.GaussNewton() xopt = GN.minimize(getQuadratic(self.A,self.b),np.array([0,0])) x_true = np.array([5.,5.]) print 'xopt: ', xopt @@ -32,7 +32,7 @@ class TestOptimizers(unittest.TestCase): self.assertTrue(np.linalg.norm(xopt-x_true,2) < TOL, True) def test_ProjGradient_quadraticBounded(self): - PG = inverse.ProjectedGradient(debug=True) + PG = Inverse.ProjectedGradient(debug=True) PG.lower, PG.upper = -2, 2 xopt = PG.minimize(getQuadratic(self.A,self.b),np.array([0,0])) x_true = np.array([2.,2.]) @@ -42,7 +42,7 @@ class TestOptimizers(unittest.TestCase): def test_ProjGradient_quadratic1Bound(self): myB = np.array([-5,1]) - PG = inverse.ProjectedGradient() + PG = Inverse.ProjectedGradient() PG.lower, PG.upper = -2, 2 xopt = PG.minimize(getQuadratic(self.A,myB),np.array([0,0])) x_true = np.array([2.,-1.]) @@ -53,7 +53,7 @@ class TestOptimizers(unittest.TestCase): def test_NewtonRoot(self): fun = lambda x, return_g=True: np.sin(x) if not return_g else ( np.sin(x), sdiag( np.cos(x) ) ) x = np.array([np.pi-0.3, np.pi+0.1, 0]) - xopt = inverse.NewtonRoot(comments=False).root(fun,x) + xopt = Inverse.NewtonRoot(comments=False).root(fun,x) x_true = np.array([np.pi,np.pi,0]) print 'Newton Root Finding' print 'xopt: ', xopt diff --git a/SimPEG/tests/test_forward_problem.py b/SimPEG/tests/test_problem.py similarity index 51% rename from SimPEG/tests/test_forward_problem.py rename to SimPEG/tests/test_problem.py index 1d4de045..fa94e6b8 100644 --- a/SimPEG/tests/test_forward_problem.py +++ b/SimPEG/tests/test_problem.py @@ -1,6 +1,6 @@ import numpy as np import unittest -from SimPEG import mesh, forward, inverse +from SimPEG import * from TestUtils import checkDerivative from scipy.sparse.linalg import dsolve @@ -12,15 +12,9 @@ class ProblemTests(unittest.TestCase): a = np.array([1, 1, 1]) b = np.array([1, 2]) c = np.array([1, 4]) - self.mesh2 = mesh.TensorMesh([a, b], np.array([3, 5])) - self.p2 = forward.Problem(self.mesh2) - self.reg = inverse.Regularization(self.mesh2) - - def test_modelTransform(self): - print 'SimPEG.forward.Problem: Testing Model Transform' - m = np.random.rand(self.mesh2.nC) - passed = checkDerivative(lambda m : [self.p2.modelTransform(m), self.p2.modelTransformDeriv(m)], m, plotIt=False) - self.assertTrue(passed) + self.mesh2 = Mesh.TensorMesh([a, b], np.array([3, 5])) + self.p2 = Problem.BaseProblem(self.mesh2, None) + self.reg = Inverse.Regularization(self.mesh2) def test_regularization(self): derChk = lambda m: [self.reg.modelObj(m), self.reg.modelObjDeriv(m)] @@ -28,7 +22,5 @@ class ProblemTests(unittest.TestCase): checkDerivative(derChk, mSynth, plotIt=False) - - if __name__ == '__main__': unittest.main() diff --git a/SimPEG/tests/test_tensorMesh.py b/SimPEG/tests/test_tensorMesh.py index 9544dab6..3e01181b 100644 --- a/SimPEG/tests/test_tensorMesh.py +++ b/SimPEG/tests/test_tensorMesh.py @@ -1,6 +1,6 @@ import numpy as np import unittest -from SimPEG.mesh import TensorMesh +from SimPEG.Mesh import TensorMesh from TestUtils import OrderTest from scipy.sparse.linalg import dsolve diff --git a/SimPEG/tests/test_utils.py b/SimPEG/tests/test_utils.py index 058dba56..fea231f2 100644 --- a/SimPEG/tests/test_utils.py +++ b/SimPEG/tests/test_utils.py @@ -1,7 +1,7 @@ import numpy as np import unittest -from SimPEG.utils import mkvc, ndgrid, indexCube, sdiag, inv3X3BlockDiagonal, inv2X2BlockDiagonal -from SimPEG.tests import checkDerivative +from SimPEG.Utils import mkvc, ndgrid, indexCube, sdiag, inv3X3BlockDiagonal, inv2X2BlockDiagonal +from SimPEG.Tests import checkDerivative class TestCheckDerivative(unittest.TestCase): diff --git a/SimPEG/utils/ModelBuilder.py b/SimPEG/utils/ModelBuilder.py index 969551ed..be172b6b 100644 --- a/SimPEG/utils/ModelBuilder.py +++ b/SimPEG/utils/ModelBuilder.py @@ -151,7 +151,7 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]): .. plot:: import matplotlib.pyplot as plt - import SimPEG.utils.ModelBuilder as MB + import SimPEG.Utils.ModelBuilder as MB plt.colorbar(plt.imshow(MB.randomModel((50,50),bounds=[-4,0]))) plt.title('A very cool, yet completely random model.') plt.show() diff --git a/SimPEG/utils/Save.py b/SimPEG/utils/Save.py index 25fd9b9e..55de4b4b 100644 --- a/SimPEG/utils/Save.py +++ b/SimPEG/utils/Save.py @@ -5,7 +5,7 @@ import re try: import h5py except Exception, e: - print 'Warning: SimPEG.utils.Save needs h5py to be installed.' + print 'Warning: SimPEG.Utils.Save needs h5py to be installed.' SAVEABLES = {} @@ -347,6 +347,6 @@ def loadSavable(node, pointers=None): print 'KWARGS: ', KWARGS return (cls, ARGS, KWARGS, node) else: - print 'Warning: %s Class not found in SimPEG.utils.Save.SAVABLES' % cls + print 'Warning: %s Class not found in SimPEG.Utils.Save.SAVABLES' % cls return (cls, ARGS, KWARGS, node) diff --git a/SimPEG/utils/__init__.py b/SimPEG/utils/__init__.py index 2def4332..fc1c1d0f 100644 --- a/SimPEG/utils/__init__.py +++ b/SimPEG/utils/__init__.py @@ -3,7 +3,7 @@ from sputils import spzeros, kron3, speye, sdiag, ddx, av, avExtrap from meshutils import exampleLomGird, meshTensors from lomutils import volTetra, faceInfo, inv2X2BlockDiagonal, inv3X3BlockDiagonal, indexCube from interputils import interpmat -from ipythonUtils import easyAnimate as animate +from ipythonutils import easyAnimate as animate from Solver import Solver import Save import Geophysics diff --git a/SimPEG/utils/interputils.py b/SimPEG/utils/interputils.py index c8bcb4ec..43cbff6b 100644 --- a/SimPEG/utils/interputils.py +++ b/SimPEG/utils/interputils.py @@ -45,7 +45,7 @@ def interpmat(locs, x, y=None, z=None): x = np.linspace(0,1,7) dense = np.linspace(0,1,200) fun = lambda x: np.cos(2*np.pi*x) - Q = SimPEG.utils.interpmat(locs, x) + Q = SimPEG.Utils.interpmat(locs, x) plt.plot(x, fun(x), 'bs-') plt.plot(dense, fun(dense), 'y:') plt.plot(locs, Q*fun(x), 'mo') @@ -173,7 +173,7 @@ if __name__ == '__main__': x = np.linspace(0,1,7) dense = np.linspace(0,1,200) fun = lambda x: np.cos(2*np.pi*x) - Q = SimPEG.utils.interpmat(locs, x) + Q = SimPEG.Utils.interpmat(locs, x) plt.plot(x, fun(x), 'bs-') plt.plot(dense, fun(dense), 'y:') plt.plot(locs, Q*fun(x), 'mo') diff --git a/SimPEG/utils/meshutils.py b/SimPEG/utils/meshutils.py index 429db04b..0e016fb5 100644 --- a/SimPEG/utils/meshutils.py +++ b/SimPEG/utils/meshutils.py @@ -34,8 +34,8 @@ def meshTensors(*args): .. plot:: - from SimPEG import mesh, utils - M = mesh.TensorMesh(utils.meshTensors(((10,10),(40,10),(10,10)), ((10,10),(20,10),(0,0)))) + from SimPEG import mesh, Utils + M = mesh.TensorMesh(Utils.meshTensors(((10,10),(40,10),(10,10)), ((10,10),(20,10),(0,0)))) M.plotGrid() """ diff --git a/SimPEG/visualize/vtk/vtkTools.py b/SimPEG/visualize/vtk/vtkTools.py index c3d9f4a7..68326662 100644 --- a/SimPEG/visualize/vtk/vtkTools.py +++ b/SimPEG/visualize/vtk/vtkTools.py @@ -3,7 +3,7 @@ try: import vtk, vtk.util.numpy_support as npsup, pdb except Exception, e: print 'VTK import error. Please ensure you have VTK installed to use this visualization package.' -from SimPEG.utils import mkvc +from SimPEG.Utils import mkvc class vtkTools(object): From 743259145054b5b85e63ee09a6c6c59bdf90a8dc Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 13:22:06 -0800 Subject: [PATCH 07/28] renaming to ensure capitals --- {SimPEG/GCEtools => GCEtools}/gceStartup.txt | 0 {SimPEG/GCEtools => GCEtools}/startup.sh | 0 SimPEG/{examples => Examples1}/DC.py | 0 SimPEG/{examples => Examples1}/Linear.py | 0 SimPEG/{examples => Examples1}/__init__.py | 0 SimPEG/{inverse => Inverse1}/BetaSchedule.py | 0 SimPEG/{inverse => Inverse1}/Inversion.py | 0 SimPEG/{inverse => Inverse1}/Optimize.py | 0 SimPEG/{inverse => Inverse1}/Regularization.py | 0 SimPEG/{inverse => Inverse1}/__init__.py | 0 SimPEG/{mesh => Mesh1}/BaseMesh.py | 0 SimPEG/{mesh => Mesh1}/Cyl1DMesh.py | 0 SimPEG/{mesh => Mesh1}/DiffOperators.py | 0 SimPEG/{mesh => Mesh1}/InnerProducts.py | 0 SimPEG/{mesh => Mesh1}/LogicallyOrthogonalMesh.py | 0 SimPEG/{mesh => Mesh1}/LomView.py | 0 SimPEG/{mesh => Mesh1}/TensorMesh.py | 0 SimPEG/{mesh => Mesh1}/TensorView.py | 0 SimPEG/{mesh => Mesh1}/__init__.py | 0 SimPEG/{tests => Tests1}/HTMLTestRunner.py | 0 SimPEG/{tests => Tests1}/TestUtils.py | 0 SimPEG/{tests => Tests1}/__init__.py | 0 SimPEG/{tests => Tests1}/runTests.py | 0 SimPEG/{tests => Tests1}/runTests.sh | 0 SimPEG/{tests => Tests1}/test_LogicallyOrthogonalMesh.py | 0 SimPEG/{tests => Tests1}/test_Solver.py | 0 SimPEG/{tests => Tests1}/test_basemesh.py | 0 SimPEG/{tests => Tests1}/test_forward_DCproblem.py | 0 SimPEG/{tests => Tests1}/test_interpolation.py | 0 SimPEG/{tests => Tests1}/test_massMatrices.py | 0 SimPEG/{tests => Tests1}/test_model.py | 0 SimPEG/{tests => Tests1}/test_operators.py | 0 SimPEG/{tests => Tests1}/test_optimizers.py | 0 SimPEG/{tests => Tests1}/test_problem.py | 0 SimPEG/{tests => Tests1}/test_tensorMesh.py | 0 SimPEG/{tests => Tests1}/test_utils.py | 0 SimPEG/{utils => Utils1}/Geophysics/__init__.py | 0 SimPEG/{utils => Utils1}/Geophysics/emSources/__init__.py | 0 SimPEG/{utils => Utils1}/Geophysics/emSources/emSources.py | 0 SimPEG/{utils => Utils1}/ModelBuilder.py | 0 SimPEG/{utils => Utils1}/Save.py | 0 SimPEG/{utils => Utils1}/Solver.py | 0 SimPEG/{utils => Utils1}/TriSolve.f | 0 SimPEG/{utils => Utils1}/__init__.py | 0 SimPEG/{utils => Utils1}/interputils.py | 0 SimPEG/{utils/ipythonUtils.py => Utils1/ipythonutils.py} | 0 SimPEG/{utils => Utils1}/lomutils.py | 0 SimPEG/{utils => Utils1}/matutils.py | 0 SimPEG/{utils => Utils1}/meshutils.py | 0 SimPEG/{utils => Utils1}/sputils.py | 0 50 files changed, 0 insertions(+), 0 deletions(-) rename {SimPEG/GCEtools => GCEtools}/gceStartup.txt (100%) rename {SimPEG/GCEtools => GCEtools}/startup.sh (100%) rename SimPEG/{examples => Examples1}/DC.py (100%) rename SimPEG/{examples => Examples1}/Linear.py (100%) rename SimPEG/{examples => Examples1}/__init__.py (100%) rename SimPEG/{inverse => Inverse1}/BetaSchedule.py (100%) rename SimPEG/{inverse => Inverse1}/Inversion.py (100%) rename SimPEG/{inverse => Inverse1}/Optimize.py (100%) rename SimPEG/{inverse => Inverse1}/Regularization.py (100%) rename SimPEG/{inverse => Inverse1}/__init__.py (100%) rename SimPEG/{mesh => Mesh1}/BaseMesh.py (100%) rename SimPEG/{mesh => Mesh1}/Cyl1DMesh.py (100%) rename SimPEG/{mesh => Mesh1}/DiffOperators.py (100%) rename SimPEG/{mesh => Mesh1}/InnerProducts.py (100%) rename SimPEG/{mesh => Mesh1}/LogicallyOrthogonalMesh.py (100%) rename SimPEG/{mesh => Mesh1}/LomView.py (100%) rename SimPEG/{mesh => Mesh1}/TensorMesh.py (100%) rename SimPEG/{mesh => Mesh1}/TensorView.py (100%) rename SimPEG/{mesh => Mesh1}/__init__.py (100%) rename SimPEG/{tests => Tests1}/HTMLTestRunner.py (100%) rename SimPEG/{tests => Tests1}/TestUtils.py (100%) rename SimPEG/{tests => Tests1}/__init__.py (100%) rename SimPEG/{tests => Tests1}/runTests.py (100%) rename SimPEG/{tests => Tests1}/runTests.sh (100%) rename SimPEG/{tests => Tests1}/test_LogicallyOrthogonalMesh.py (100%) rename SimPEG/{tests => Tests1}/test_Solver.py (100%) rename SimPEG/{tests => Tests1}/test_basemesh.py (100%) rename SimPEG/{tests => Tests1}/test_forward_DCproblem.py (100%) rename SimPEG/{tests => Tests1}/test_interpolation.py (100%) rename SimPEG/{tests => Tests1}/test_massMatrices.py (100%) rename SimPEG/{tests => Tests1}/test_model.py (100%) rename SimPEG/{tests => Tests1}/test_operators.py (100%) rename SimPEG/{tests => Tests1}/test_optimizers.py (100%) rename SimPEG/{tests => Tests1}/test_problem.py (100%) rename SimPEG/{tests => Tests1}/test_tensorMesh.py (100%) rename SimPEG/{tests => Tests1}/test_utils.py (100%) rename SimPEG/{utils => Utils1}/Geophysics/__init__.py (100%) rename SimPEG/{utils => Utils1}/Geophysics/emSources/__init__.py (100%) rename SimPEG/{utils => Utils1}/Geophysics/emSources/emSources.py (100%) rename SimPEG/{utils => Utils1}/ModelBuilder.py (100%) rename SimPEG/{utils => Utils1}/Save.py (100%) rename SimPEG/{utils => Utils1}/Solver.py (100%) rename SimPEG/{utils => Utils1}/TriSolve.f (100%) rename SimPEG/{utils => Utils1}/__init__.py (100%) rename SimPEG/{utils => Utils1}/interputils.py (100%) rename SimPEG/{utils/ipythonUtils.py => Utils1/ipythonutils.py} (100%) rename SimPEG/{utils => Utils1}/lomutils.py (100%) rename SimPEG/{utils => Utils1}/matutils.py (100%) rename SimPEG/{utils => Utils1}/meshutils.py (100%) rename SimPEG/{utils => Utils1}/sputils.py (100%) diff --git a/SimPEG/GCEtools/gceStartup.txt b/GCEtools/gceStartup.txt similarity index 100% rename from SimPEG/GCEtools/gceStartup.txt rename to GCEtools/gceStartup.txt diff --git a/SimPEG/GCEtools/startup.sh b/GCEtools/startup.sh similarity index 100% rename from SimPEG/GCEtools/startup.sh rename to GCEtools/startup.sh diff --git a/SimPEG/examples/DC.py b/SimPEG/Examples1/DC.py similarity index 100% rename from SimPEG/examples/DC.py rename to SimPEG/Examples1/DC.py diff --git a/SimPEG/examples/Linear.py b/SimPEG/Examples1/Linear.py similarity index 100% rename from SimPEG/examples/Linear.py rename to SimPEG/Examples1/Linear.py diff --git a/SimPEG/examples/__init__.py b/SimPEG/Examples1/__init__.py similarity index 100% rename from SimPEG/examples/__init__.py rename to SimPEG/Examples1/__init__.py diff --git a/SimPEG/inverse/BetaSchedule.py b/SimPEG/Inverse1/BetaSchedule.py similarity index 100% rename from SimPEG/inverse/BetaSchedule.py rename to SimPEG/Inverse1/BetaSchedule.py diff --git a/SimPEG/inverse/Inversion.py b/SimPEG/Inverse1/Inversion.py similarity index 100% rename from SimPEG/inverse/Inversion.py rename to SimPEG/Inverse1/Inversion.py diff --git a/SimPEG/inverse/Optimize.py b/SimPEG/Inverse1/Optimize.py similarity index 100% rename from SimPEG/inverse/Optimize.py rename to SimPEG/Inverse1/Optimize.py diff --git a/SimPEG/inverse/Regularization.py b/SimPEG/Inverse1/Regularization.py similarity index 100% rename from SimPEG/inverse/Regularization.py rename to SimPEG/Inverse1/Regularization.py diff --git a/SimPEG/inverse/__init__.py b/SimPEG/Inverse1/__init__.py similarity index 100% rename from SimPEG/inverse/__init__.py rename to SimPEG/Inverse1/__init__.py diff --git a/SimPEG/mesh/BaseMesh.py b/SimPEG/Mesh1/BaseMesh.py similarity index 100% rename from SimPEG/mesh/BaseMesh.py rename to SimPEG/Mesh1/BaseMesh.py diff --git a/SimPEG/mesh/Cyl1DMesh.py b/SimPEG/Mesh1/Cyl1DMesh.py similarity index 100% rename from SimPEG/mesh/Cyl1DMesh.py rename to SimPEG/Mesh1/Cyl1DMesh.py diff --git a/SimPEG/mesh/DiffOperators.py b/SimPEG/Mesh1/DiffOperators.py similarity index 100% rename from SimPEG/mesh/DiffOperators.py rename to SimPEG/Mesh1/DiffOperators.py diff --git a/SimPEG/mesh/InnerProducts.py b/SimPEG/Mesh1/InnerProducts.py similarity index 100% rename from SimPEG/mesh/InnerProducts.py rename to SimPEG/Mesh1/InnerProducts.py diff --git a/SimPEG/mesh/LogicallyOrthogonalMesh.py b/SimPEG/Mesh1/LogicallyOrthogonalMesh.py similarity index 100% rename from SimPEG/mesh/LogicallyOrthogonalMesh.py rename to SimPEG/Mesh1/LogicallyOrthogonalMesh.py diff --git a/SimPEG/mesh/LomView.py b/SimPEG/Mesh1/LomView.py similarity index 100% rename from SimPEG/mesh/LomView.py rename to SimPEG/Mesh1/LomView.py diff --git a/SimPEG/mesh/TensorMesh.py b/SimPEG/Mesh1/TensorMesh.py similarity index 100% rename from SimPEG/mesh/TensorMesh.py rename to SimPEG/Mesh1/TensorMesh.py diff --git a/SimPEG/mesh/TensorView.py b/SimPEG/Mesh1/TensorView.py similarity index 100% rename from SimPEG/mesh/TensorView.py rename to SimPEG/Mesh1/TensorView.py diff --git a/SimPEG/mesh/__init__.py b/SimPEG/Mesh1/__init__.py similarity index 100% rename from SimPEG/mesh/__init__.py rename to SimPEG/Mesh1/__init__.py diff --git a/SimPEG/tests/HTMLTestRunner.py b/SimPEG/Tests1/HTMLTestRunner.py similarity index 100% rename from SimPEG/tests/HTMLTestRunner.py rename to SimPEG/Tests1/HTMLTestRunner.py diff --git a/SimPEG/tests/TestUtils.py b/SimPEG/Tests1/TestUtils.py similarity index 100% rename from SimPEG/tests/TestUtils.py rename to SimPEG/Tests1/TestUtils.py diff --git a/SimPEG/tests/__init__.py b/SimPEG/Tests1/__init__.py similarity index 100% rename from SimPEG/tests/__init__.py rename to SimPEG/Tests1/__init__.py diff --git a/SimPEG/tests/runTests.py b/SimPEG/Tests1/runTests.py similarity index 100% rename from SimPEG/tests/runTests.py rename to SimPEG/Tests1/runTests.py diff --git a/SimPEG/tests/runTests.sh b/SimPEG/Tests1/runTests.sh similarity index 100% rename from SimPEG/tests/runTests.sh rename to SimPEG/Tests1/runTests.sh diff --git a/SimPEG/tests/test_LogicallyOrthogonalMesh.py b/SimPEG/Tests1/test_LogicallyOrthogonalMesh.py similarity index 100% rename from SimPEG/tests/test_LogicallyOrthogonalMesh.py rename to SimPEG/Tests1/test_LogicallyOrthogonalMesh.py diff --git a/SimPEG/tests/test_Solver.py b/SimPEG/Tests1/test_Solver.py similarity index 100% rename from SimPEG/tests/test_Solver.py rename to SimPEG/Tests1/test_Solver.py diff --git a/SimPEG/tests/test_basemesh.py b/SimPEG/Tests1/test_basemesh.py similarity index 100% rename from SimPEG/tests/test_basemesh.py rename to SimPEG/Tests1/test_basemesh.py diff --git a/SimPEG/tests/test_forward_DCproblem.py b/SimPEG/Tests1/test_forward_DCproblem.py similarity index 100% rename from SimPEG/tests/test_forward_DCproblem.py rename to SimPEG/Tests1/test_forward_DCproblem.py diff --git a/SimPEG/tests/test_interpolation.py b/SimPEG/Tests1/test_interpolation.py similarity index 100% rename from SimPEG/tests/test_interpolation.py rename to SimPEG/Tests1/test_interpolation.py diff --git a/SimPEG/tests/test_massMatrices.py b/SimPEG/Tests1/test_massMatrices.py similarity index 100% rename from SimPEG/tests/test_massMatrices.py rename to SimPEG/Tests1/test_massMatrices.py diff --git a/SimPEG/tests/test_model.py b/SimPEG/Tests1/test_model.py similarity index 100% rename from SimPEG/tests/test_model.py rename to SimPEG/Tests1/test_model.py diff --git a/SimPEG/tests/test_operators.py b/SimPEG/Tests1/test_operators.py similarity index 100% rename from SimPEG/tests/test_operators.py rename to SimPEG/Tests1/test_operators.py diff --git a/SimPEG/tests/test_optimizers.py b/SimPEG/Tests1/test_optimizers.py similarity index 100% rename from SimPEG/tests/test_optimizers.py rename to SimPEG/Tests1/test_optimizers.py diff --git a/SimPEG/tests/test_problem.py b/SimPEG/Tests1/test_problem.py similarity index 100% rename from SimPEG/tests/test_problem.py rename to SimPEG/Tests1/test_problem.py diff --git a/SimPEG/tests/test_tensorMesh.py b/SimPEG/Tests1/test_tensorMesh.py similarity index 100% rename from SimPEG/tests/test_tensorMesh.py rename to SimPEG/Tests1/test_tensorMesh.py diff --git a/SimPEG/tests/test_utils.py b/SimPEG/Tests1/test_utils.py similarity index 100% rename from SimPEG/tests/test_utils.py rename to SimPEG/Tests1/test_utils.py diff --git a/SimPEG/utils/Geophysics/__init__.py b/SimPEG/Utils1/Geophysics/__init__.py similarity index 100% rename from SimPEG/utils/Geophysics/__init__.py rename to SimPEG/Utils1/Geophysics/__init__.py diff --git a/SimPEG/utils/Geophysics/emSources/__init__.py b/SimPEG/Utils1/Geophysics/emSources/__init__.py similarity index 100% rename from SimPEG/utils/Geophysics/emSources/__init__.py rename to SimPEG/Utils1/Geophysics/emSources/__init__.py diff --git a/SimPEG/utils/Geophysics/emSources/emSources.py b/SimPEG/Utils1/Geophysics/emSources/emSources.py similarity index 100% rename from SimPEG/utils/Geophysics/emSources/emSources.py rename to SimPEG/Utils1/Geophysics/emSources/emSources.py diff --git a/SimPEG/utils/ModelBuilder.py b/SimPEG/Utils1/ModelBuilder.py similarity index 100% rename from SimPEG/utils/ModelBuilder.py rename to SimPEG/Utils1/ModelBuilder.py diff --git a/SimPEG/utils/Save.py b/SimPEG/Utils1/Save.py similarity index 100% rename from SimPEG/utils/Save.py rename to SimPEG/Utils1/Save.py diff --git a/SimPEG/utils/Solver.py b/SimPEG/Utils1/Solver.py similarity index 100% rename from SimPEG/utils/Solver.py rename to SimPEG/Utils1/Solver.py diff --git a/SimPEG/utils/TriSolve.f b/SimPEG/Utils1/TriSolve.f similarity index 100% rename from SimPEG/utils/TriSolve.f rename to SimPEG/Utils1/TriSolve.f diff --git a/SimPEG/utils/__init__.py b/SimPEG/Utils1/__init__.py similarity index 100% rename from SimPEG/utils/__init__.py rename to SimPEG/Utils1/__init__.py diff --git a/SimPEG/utils/interputils.py b/SimPEG/Utils1/interputils.py similarity index 100% rename from SimPEG/utils/interputils.py rename to SimPEG/Utils1/interputils.py diff --git a/SimPEG/utils/ipythonUtils.py b/SimPEG/Utils1/ipythonutils.py similarity index 100% rename from SimPEG/utils/ipythonUtils.py rename to SimPEG/Utils1/ipythonutils.py diff --git a/SimPEG/utils/lomutils.py b/SimPEG/Utils1/lomutils.py similarity index 100% rename from SimPEG/utils/lomutils.py rename to SimPEG/Utils1/lomutils.py diff --git a/SimPEG/utils/matutils.py b/SimPEG/Utils1/matutils.py similarity index 100% rename from SimPEG/utils/matutils.py rename to SimPEG/Utils1/matutils.py diff --git a/SimPEG/utils/meshutils.py b/SimPEG/Utils1/meshutils.py similarity index 100% rename from SimPEG/utils/meshutils.py rename to SimPEG/Utils1/meshutils.py diff --git a/SimPEG/utils/sputils.py b/SimPEG/Utils1/sputils.py similarity index 100% rename from SimPEG/utils/sputils.py rename to SimPEG/Utils1/sputils.py From fa8a5cd7cbe2324dd8129695d530400a5bc0b712 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 13:22:46 -0800 Subject: [PATCH 08/28] renaming to ensure capitals --- SimPEG/{Examples1 => Examples}/DC.py | 0 SimPEG/{Examples1 => Examples}/Linear.py | 0 SimPEG/{Examples1 => Examples}/__init__.py | 0 SimPEG/{Inverse1 => Inverse}/BetaSchedule.py | 0 SimPEG/{Inverse1 => Inverse}/Inversion.py | 0 SimPEG/{Inverse1 => Inverse}/Optimize.py | 0 SimPEG/{Inverse1 => Inverse}/Regularization.py | 0 SimPEG/{Inverse1 => Inverse}/__init__.py | 0 SimPEG/{Mesh1 => Mesh}/BaseMesh.py | 0 SimPEG/{Mesh1 => Mesh}/Cyl1DMesh.py | 0 SimPEG/{Mesh1 => Mesh}/DiffOperators.py | 0 SimPEG/{Mesh1 => Mesh}/InnerProducts.py | 0 SimPEG/{Mesh1 => Mesh}/LogicallyOrthogonalMesh.py | 0 SimPEG/{Mesh1 => Mesh}/LomView.py | 0 SimPEG/{Mesh1 => Mesh}/TensorMesh.py | 0 SimPEG/{Mesh1 => Mesh}/TensorView.py | 0 SimPEG/{Mesh1 => Mesh}/__init__.py | 0 SimPEG/{Tests1 => Tests}/HTMLTestRunner.py | 0 SimPEG/{Tests1 => Tests}/TestUtils.py | 0 SimPEG/{Tests1 => Tests}/__init__.py | 0 SimPEG/{Tests1 => Tests}/runTests.py | 0 SimPEG/{Tests1 => Tests}/runTests.sh | 0 SimPEG/{Tests1 => Tests}/test_LogicallyOrthogonalMesh.py | 0 SimPEG/{Tests1 => Tests}/test_Solver.py | 0 SimPEG/{Tests1 => Tests}/test_basemesh.py | 0 SimPEG/{Tests1 => Tests}/test_forward_DCproblem.py | 0 SimPEG/{Tests1 => Tests}/test_interpolation.py | 0 SimPEG/{Tests1 => Tests}/test_massMatrices.py | 0 SimPEG/{Tests1 => Tests}/test_model.py | 0 SimPEG/{Tests1 => Tests}/test_operators.py | 0 SimPEG/{Tests1 => Tests}/test_optimizers.py | 0 SimPEG/{Tests1 => Tests}/test_problem.py | 0 SimPEG/{Tests1 => Tests}/test_tensorMesh.py | 0 SimPEG/{Tests1 => Tests}/test_utils.py | 0 SimPEG/{Utils1 => Utils}/Geophysics/__init__.py | 0 SimPEG/{Utils1 => Utils}/Geophysics/emSources/__init__.py | 0 SimPEG/{Utils1 => Utils}/Geophysics/emSources/emSources.py | 0 SimPEG/{Utils1 => Utils}/ModelBuilder.py | 0 SimPEG/{Utils1 => Utils}/Save.py | 0 SimPEG/{Utils1 => Utils}/Solver.py | 0 SimPEG/{Utils1 => Utils}/TriSolve.f | 0 SimPEG/{Utils1 => Utils}/__init__.py | 0 SimPEG/{Utils1 => Utils}/interputils.py | 0 SimPEG/{Utils1 => Utils}/ipythonutils.py | 0 SimPEG/{Utils1 => Utils}/lomutils.py | 0 SimPEG/{Utils1 => Utils}/matutils.py | 0 SimPEG/{Utils1 => Utils}/meshutils.py | 0 SimPEG/{Utils1 => Utils}/sputils.py | 0 48 files changed, 0 insertions(+), 0 deletions(-) rename SimPEG/{Examples1 => Examples}/DC.py (100%) rename SimPEG/{Examples1 => Examples}/Linear.py (100%) rename SimPEG/{Examples1 => Examples}/__init__.py (100%) rename SimPEG/{Inverse1 => Inverse}/BetaSchedule.py (100%) rename SimPEG/{Inverse1 => Inverse}/Inversion.py (100%) rename SimPEG/{Inverse1 => Inverse}/Optimize.py (100%) rename SimPEG/{Inverse1 => Inverse}/Regularization.py (100%) rename SimPEG/{Inverse1 => Inverse}/__init__.py (100%) rename SimPEG/{Mesh1 => Mesh}/BaseMesh.py (100%) rename SimPEG/{Mesh1 => Mesh}/Cyl1DMesh.py (100%) rename SimPEG/{Mesh1 => Mesh}/DiffOperators.py (100%) rename SimPEG/{Mesh1 => Mesh}/InnerProducts.py (100%) rename SimPEG/{Mesh1 => Mesh}/LogicallyOrthogonalMesh.py (100%) rename SimPEG/{Mesh1 => Mesh}/LomView.py (100%) rename SimPEG/{Mesh1 => Mesh}/TensorMesh.py (100%) rename SimPEG/{Mesh1 => Mesh}/TensorView.py (100%) rename SimPEG/{Mesh1 => Mesh}/__init__.py (100%) rename SimPEG/{Tests1 => Tests}/HTMLTestRunner.py (100%) rename SimPEG/{Tests1 => Tests}/TestUtils.py (100%) rename SimPEG/{Tests1 => Tests}/__init__.py (100%) rename SimPEG/{Tests1 => Tests}/runTests.py (100%) rename SimPEG/{Tests1 => Tests}/runTests.sh (100%) rename SimPEG/{Tests1 => Tests}/test_LogicallyOrthogonalMesh.py (100%) rename SimPEG/{Tests1 => Tests}/test_Solver.py (100%) rename SimPEG/{Tests1 => Tests}/test_basemesh.py (100%) rename SimPEG/{Tests1 => Tests}/test_forward_DCproblem.py (100%) rename SimPEG/{Tests1 => Tests}/test_interpolation.py (100%) rename SimPEG/{Tests1 => Tests}/test_massMatrices.py (100%) rename SimPEG/{Tests1 => Tests}/test_model.py (100%) rename SimPEG/{Tests1 => Tests}/test_operators.py (100%) rename SimPEG/{Tests1 => Tests}/test_optimizers.py (100%) rename SimPEG/{Tests1 => Tests}/test_problem.py (100%) rename SimPEG/{Tests1 => Tests}/test_tensorMesh.py (100%) rename SimPEG/{Tests1 => Tests}/test_utils.py (100%) rename SimPEG/{Utils1 => Utils}/Geophysics/__init__.py (100%) rename SimPEG/{Utils1 => Utils}/Geophysics/emSources/__init__.py (100%) rename SimPEG/{Utils1 => Utils}/Geophysics/emSources/emSources.py (100%) rename SimPEG/{Utils1 => Utils}/ModelBuilder.py (100%) rename SimPEG/{Utils1 => Utils}/Save.py (100%) rename SimPEG/{Utils1 => Utils}/Solver.py (100%) rename SimPEG/{Utils1 => Utils}/TriSolve.f (100%) rename SimPEG/{Utils1 => Utils}/__init__.py (100%) rename SimPEG/{Utils1 => Utils}/interputils.py (100%) rename SimPEG/{Utils1 => Utils}/ipythonutils.py (100%) rename SimPEG/{Utils1 => Utils}/lomutils.py (100%) rename SimPEG/{Utils1 => Utils}/matutils.py (100%) rename SimPEG/{Utils1 => Utils}/meshutils.py (100%) rename SimPEG/{Utils1 => Utils}/sputils.py (100%) diff --git a/SimPEG/Examples1/DC.py b/SimPEG/Examples/DC.py similarity index 100% rename from SimPEG/Examples1/DC.py rename to SimPEG/Examples/DC.py diff --git a/SimPEG/Examples1/Linear.py b/SimPEG/Examples/Linear.py similarity index 100% rename from SimPEG/Examples1/Linear.py rename to SimPEG/Examples/Linear.py diff --git a/SimPEG/Examples1/__init__.py b/SimPEG/Examples/__init__.py similarity index 100% rename from SimPEG/Examples1/__init__.py rename to SimPEG/Examples/__init__.py diff --git a/SimPEG/Inverse1/BetaSchedule.py b/SimPEG/Inverse/BetaSchedule.py similarity index 100% rename from SimPEG/Inverse1/BetaSchedule.py rename to SimPEG/Inverse/BetaSchedule.py diff --git a/SimPEG/Inverse1/Inversion.py b/SimPEG/Inverse/Inversion.py similarity index 100% rename from SimPEG/Inverse1/Inversion.py rename to SimPEG/Inverse/Inversion.py diff --git a/SimPEG/Inverse1/Optimize.py b/SimPEG/Inverse/Optimize.py similarity index 100% rename from SimPEG/Inverse1/Optimize.py rename to SimPEG/Inverse/Optimize.py diff --git a/SimPEG/Inverse1/Regularization.py b/SimPEG/Inverse/Regularization.py similarity index 100% rename from SimPEG/Inverse1/Regularization.py rename to SimPEG/Inverse/Regularization.py diff --git a/SimPEG/Inverse1/__init__.py b/SimPEG/Inverse/__init__.py similarity index 100% rename from SimPEG/Inverse1/__init__.py rename to SimPEG/Inverse/__init__.py diff --git a/SimPEG/Mesh1/BaseMesh.py b/SimPEG/Mesh/BaseMesh.py similarity index 100% rename from SimPEG/Mesh1/BaseMesh.py rename to SimPEG/Mesh/BaseMesh.py diff --git a/SimPEG/Mesh1/Cyl1DMesh.py b/SimPEG/Mesh/Cyl1DMesh.py similarity index 100% rename from SimPEG/Mesh1/Cyl1DMesh.py rename to SimPEG/Mesh/Cyl1DMesh.py diff --git a/SimPEG/Mesh1/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py similarity index 100% rename from SimPEG/Mesh1/DiffOperators.py rename to SimPEG/Mesh/DiffOperators.py diff --git a/SimPEG/Mesh1/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py similarity index 100% rename from SimPEG/Mesh1/InnerProducts.py rename to SimPEG/Mesh/InnerProducts.py diff --git a/SimPEG/Mesh1/LogicallyOrthogonalMesh.py b/SimPEG/Mesh/LogicallyOrthogonalMesh.py similarity index 100% rename from SimPEG/Mesh1/LogicallyOrthogonalMesh.py rename to SimPEG/Mesh/LogicallyOrthogonalMesh.py diff --git a/SimPEG/Mesh1/LomView.py b/SimPEG/Mesh/LomView.py similarity index 100% rename from SimPEG/Mesh1/LomView.py rename to SimPEG/Mesh/LomView.py diff --git a/SimPEG/Mesh1/TensorMesh.py b/SimPEG/Mesh/TensorMesh.py similarity index 100% rename from SimPEG/Mesh1/TensorMesh.py rename to SimPEG/Mesh/TensorMesh.py diff --git a/SimPEG/Mesh1/TensorView.py b/SimPEG/Mesh/TensorView.py similarity index 100% rename from SimPEG/Mesh1/TensorView.py rename to SimPEG/Mesh/TensorView.py diff --git a/SimPEG/Mesh1/__init__.py b/SimPEG/Mesh/__init__.py similarity index 100% rename from SimPEG/Mesh1/__init__.py rename to SimPEG/Mesh/__init__.py diff --git a/SimPEG/Tests1/HTMLTestRunner.py b/SimPEG/Tests/HTMLTestRunner.py similarity index 100% rename from SimPEG/Tests1/HTMLTestRunner.py rename to SimPEG/Tests/HTMLTestRunner.py diff --git a/SimPEG/Tests1/TestUtils.py b/SimPEG/Tests/TestUtils.py similarity index 100% rename from SimPEG/Tests1/TestUtils.py rename to SimPEG/Tests/TestUtils.py diff --git a/SimPEG/Tests1/__init__.py b/SimPEG/Tests/__init__.py similarity index 100% rename from SimPEG/Tests1/__init__.py rename to SimPEG/Tests/__init__.py diff --git a/SimPEG/Tests1/runTests.py b/SimPEG/Tests/runTests.py similarity index 100% rename from SimPEG/Tests1/runTests.py rename to SimPEG/Tests/runTests.py diff --git a/SimPEG/Tests1/runTests.sh b/SimPEG/Tests/runTests.sh similarity index 100% rename from SimPEG/Tests1/runTests.sh rename to SimPEG/Tests/runTests.sh diff --git a/SimPEG/Tests1/test_LogicallyOrthogonalMesh.py b/SimPEG/Tests/test_LogicallyOrthogonalMesh.py similarity index 100% rename from SimPEG/Tests1/test_LogicallyOrthogonalMesh.py rename to SimPEG/Tests/test_LogicallyOrthogonalMesh.py diff --git a/SimPEG/Tests1/test_Solver.py b/SimPEG/Tests/test_Solver.py similarity index 100% rename from SimPEG/Tests1/test_Solver.py rename to SimPEG/Tests/test_Solver.py diff --git a/SimPEG/Tests1/test_basemesh.py b/SimPEG/Tests/test_basemesh.py similarity index 100% rename from SimPEG/Tests1/test_basemesh.py rename to SimPEG/Tests/test_basemesh.py diff --git a/SimPEG/Tests1/test_forward_DCproblem.py b/SimPEG/Tests/test_forward_DCproblem.py similarity index 100% rename from SimPEG/Tests1/test_forward_DCproblem.py rename to SimPEG/Tests/test_forward_DCproblem.py diff --git a/SimPEG/Tests1/test_interpolation.py b/SimPEG/Tests/test_interpolation.py similarity index 100% rename from SimPEG/Tests1/test_interpolation.py rename to SimPEG/Tests/test_interpolation.py diff --git a/SimPEG/Tests1/test_massMatrices.py b/SimPEG/Tests/test_massMatrices.py similarity index 100% rename from SimPEG/Tests1/test_massMatrices.py rename to SimPEG/Tests/test_massMatrices.py diff --git a/SimPEG/Tests1/test_model.py b/SimPEG/Tests/test_model.py similarity index 100% rename from SimPEG/Tests1/test_model.py rename to SimPEG/Tests/test_model.py diff --git a/SimPEG/Tests1/test_operators.py b/SimPEG/Tests/test_operators.py similarity index 100% rename from SimPEG/Tests1/test_operators.py rename to SimPEG/Tests/test_operators.py diff --git a/SimPEG/Tests1/test_optimizers.py b/SimPEG/Tests/test_optimizers.py similarity index 100% rename from SimPEG/Tests1/test_optimizers.py rename to SimPEG/Tests/test_optimizers.py diff --git a/SimPEG/Tests1/test_problem.py b/SimPEG/Tests/test_problem.py similarity index 100% rename from SimPEG/Tests1/test_problem.py rename to SimPEG/Tests/test_problem.py diff --git a/SimPEG/Tests1/test_tensorMesh.py b/SimPEG/Tests/test_tensorMesh.py similarity index 100% rename from SimPEG/Tests1/test_tensorMesh.py rename to SimPEG/Tests/test_tensorMesh.py diff --git a/SimPEG/Tests1/test_utils.py b/SimPEG/Tests/test_utils.py similarity index 100% rename from SimPEG/Tests1/test_utils.py rename to SimPEG/Tests/test_utils.py diff --git a/SimPEG/Utils1/Geophysics/__init__.py b/SimPEG/Utils/Geophysics/__init__.py similarity index 100% rename from SimPEG/Utils1/Geophysics/__init__.py rename to SimPEG/Utils/Geophysics/__init__.py diff --git a/SimPEG/Utils1/Geophysics/emSources/__init__.py b/SimPEG/Utils/Geophysics/emSources/__init__.py similarity index 100% rename from SimPEG/Utils1/Geophysics/emSources/__init__.py rename to SimPEG/Utils/Geophysics/emSources/__init__.py diff --git a/SimPEG/Utils1/Geophysics/emSources/emSources.py b/SimPEG/Utils/Geophysics/emSources/emSources.py similarity index 100% rename from SimPEG/Utils1/Geophysics/emSources/emSources.py rename to SimPEG/Utils/Geophysics/emSources/emSources.py diff --git a/SimPEG/Utils1/ModelBuilder.py b/SimPEG/Utils/ModelBuilder.py similarity index 100% rename from SimPEG/Utils1/ModelBuilder.py rename to SimPEG/Utils/ModelBuilder.py diff --git a/SimPEG/Utils1/Save.py b/SimPEG/Utils/Save.py similarity index 100% rename from SimPEG/Utils1/Save.py rename to SimPEG/Utils/Save.py diff --git a/SimPEG/Utils1/Solver.py b/SimPEG/Utils/Solver.py similarity index 100% rename from SimPEG/Utils1/Solver.py rename to SimPEG/Utils/Solver.py diff --git a/SimPEG/Utils1/TriSolve.f b/SimPEG/Utils/TriSolve.f similarity index 100% rename from SimPEG/Utils1/TriSolve.f rename to SimPEG/Utils/TriSolve.f diff --git a/SimPEG/Utils1/__init__.py b/SimPEG/Utils/__init__.py similarity index 100% rename from SimPEG/Utils1/__init__.py rename to SimPEG/Utils/__init__.py diff --git a/SimPEG/Utils1/interputils.py b/SimPEG/Utils/interputils.py similarity index 100% rename from SimPEG/Utils1/interputils.py rename to SimPEG/Utils/interputils.py diff --git a/SimPEG/Utils1/ipythonutils.py b/SimPEG/Utils/ipythonutils.py similarity index 100% rename from SimPEG/Utils1/ipythonutils.py rename to SimPEG/Utils/ipythonutils.py diff --git a/SimPEG/Utils1/lomutils.py b/SimPEG/Utils/lomutils.py similarity index 100% rename from SimPEG/Utils1/lomutils.py rename to SimPEG/Utils/lomutils.py diff --git a/SimPEG/Utils1/matutils.py b/SimPEG/Utils/matutils.py similarity index 100% rename from SimPEG/Utils1/matutils.py rename to SimPEG/Utils/matutils.py diff --git a/SimPEG/Utils1/meshutils.py b/SimPEG/Utils/meshutils.py similarity index 100% rename from SimPEG/Utils1/meshutils.py rename to SimPEG/Utils/meshutils.py diff --git a/SimPEG/Utils1/sputils.py b/SimPEG/Utils/sputils.py similarity index 100% rename from SimPEG/Utils1/sputils.py rename to SimPEG/Utils/sputils.py From 687ef0c20ae5ff83362837fb6cba3a3830a7156e Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 14:29:08 -0800 Subject: [PATCH 09/28] DC inversion working again. Almost in the new framework..! --- SimPEG/Data.py | 37 +++++++++++++++++----- SimPEG/Examples/DC.py | 59 +++++++++++++++++------------------- SimPEG/Inverse/Inversion.py | 12 ++++---- SimPEG/Problem.py | 14 +++++---- SimPEG/Utils/ModelBuilder.py | 2 +- SimPEG/Utils/__init__.py | 1 + 6 files changed, 73 insertions(+), 52 deletions(-) diff --git a/SimPEG/Data.py b/SimPEG/Data.py index bc874de2..dc9239e1 100644 --- a/SimPEG/Data.py +++ b/SimPEG/Data.py @@ -1,5 +1,5 @@ import Utils - +import numpy as np def requiresProblem(f): """ @@ -13,12 +13,13 @@ def requiresProblem(f): If a problem is not bound an Exception will be raised, and an nice error message printed. """ extra = """ - This function requires that a problem be bound to the data. + To use data.%s(), SimPEG requires that a problem be bound to the data. If a problem has not been bound, an Exception will be raised. To bind a problem to the Data object:: data.setProblem(myProblem) - """ + + """ % f.__name__ from functools import wraps @wraps(f) def requiresProblemWrapper(self,*args,**kwargs): @@ -37,11 +38,11 @@ class BaseData(object): __metaclass__ = Utils.Save.Savable + prob = None #: The geophysical problem that explains this data, use data.setProblem(prob) std = None #: Estimated Standard Deviations dobs = None #: Observed data dtrue = None #: True data, if data is synthetic mtrue = None #: True model, if data is synthetic - prob = None #: The geophysical problem that explains this data counter = None #: A SimPEG.Utils.Counter object @@ -49,19 +50,39 @@ class BaseData(object): Utils.setKwargs(self, **kwargs) def setProblem(self, prob): + # Bind these two instances together using pointers self.prob = prob + prob.data = self @Utils.count @requiresProblem def dpred(self, m, u=None): """ - Projection matrix. + Create the projected data from a model. + The field, u, (if provided) will be used for the predicted data + instead of recalculating the fields (which may be expensive!). + + .. math:: + d_\\text{pred} = P(u(m)) + + Where P is a projection of the fields onto the data space. + """ + if u is None: u = self.prob.field(m) + return self.projectField(u) + + + @Utils.count + def projectField(self, u): + """ + This function projects the fields onto the data space. + .. math:: d_\\text{pred} = Pu(m) """ - if u is None: u = self.prob.field(m) - return self.P*u + return u + + #TODO: def projectFieldDeriv(self, u): Does this need to be made??! @Utils.count def residual(self, m, u=None): @@ -122,7 +143,7 @@ class BaseData(object): """ Source matrix. """ - return self._RHS + return getattr(self, '_RHS', None) @RHS.setter def RHS(self, value): self._RHS = value diff --git a/SimPEG/Examples/DC.py b/SimPEG/Examples/DC.py index fa50cd1c..a05e3e3c 100644 --- a/SimPEG/Examples/DC.py +++ b/SimPEG/Examples/DC.py @@ -10,9 +10,10 @@ class DCData(Data.BaseData): """ - def __init__(self, mesh, model, **kwargs): - problem.BaseProblem.__init__(self, mesh, model) - self.mesh.setCellGradBC('neumann') + P = None #: projection + + def __init__(self, **kwargs): + Data.BaseData.__init__(self, **kwargs) Utils.setKwargs(self, **kwargs) def reshapeFields(self, u): @@ -20,18 +21,14 @@ class DCData(Data.BaseData): u = u.reshape([-1, self.RHS.shape[1]], order='F') return u - def dpred(self, m, u=None): + def projectField(self, u): """ Predicted data. .. math:: d_\\text{pred} = Pu(m) """ - if u is None: - u = self.field(m) - u = self.reshapeFields(u) - return Utils.mkvc(self.P*u) @@ -47,7 +44,7 @@ class DCProblem(Problem.BaseProblem): dataPair = DCData def __init__(self, mesh, model, **kwargs): - problem.BaseProblem.__init__(self, mesh, model) + Problem.BaseProblem.__init__(self, mesh, model) self.mesh.setCellGradBC('neumann') Utils.setKwargs(self, **kwargs) @@ -75,7 +72,7 @@ class DCProblem(Problem.BaseProblem): def field(self, m): A = self.createMatrix(m) solve = Solver(A) - phi = solve.solve(self.RHS) + phi = solve.solve(self.data.RHS) return Utils.mkvc(phi) def J(self, m, v, u=None): @@ -103,9 +100,9 @@ class DCProblem(Problem.BaseProblem): if u is None: u = self.field(m) - u = self.reshapeFields(u) + u = self.data.reshapeFields(u) - P = self.P + P = self.data.P D = self.mesh.faceDiv G = self.mesh.cellGrad A = self.createMatrix(m) @@ -128,10 +125,10 @@ class DCProblem(Problem.BaseProblem): if u is None: u = self.field(m) - u = self.reshapeFields(u) - v = self.reshapeFields(v) + u = self.data.reshapeFields(u) + v = self.data.reshapeFields(v) - P = self.P + P = self.data.P D = self.mesh.faceDiv G = self.mesh.cellGrad A = self.createMatrix(m) @@ -186,7 +183,7 @@ if __name__ == '__main__': # Create the mesh h1 = np.ones(20) h2 = np.ones(100) - M = mesh.TensorMesh([h1,h2]) + M = Mesh.TensorMesh([h1,h2]) # Create some parameters for the model sig1 = np.log(1) @@ -198,7 +195,7 @@ if __name__ == '__main__': condVals = [sig1, sig2] mSynth = Utils.ModelBuilder.defineBlockConductivity(p0,p1,M.gridCC,condVals) plt.colorbar(M.plotImage(mSynth)) - plt.show() + # plt.show() # Set up the projection nelec = 50 @@ -211,29 +208,29 @@ if __name__ == '__main__': q, Q, rxmidloc = genTxRxmat(nelec, spacelec, surfloc, elecini, M) P = Q.T - # Create some data - problem = DCProblem(M) - problem.P = P - problem.RHS = q - data = problem.createSyntheticData(mSynth, std=0.05) + model = Model.LogModel() + prob = DCProblem(M, model) - u = problem.field(mSynth) - u = problem.reshapeFields(u) + # Create some data + data = prob.createSyntheticData(mSynth, std=0.05, P=P, RHS=q) + + u = prob.field(mSynth) + u = data.reshapeFields(u) M.plotImage(u[:,10]) # plt.show() - # Now set up the problem to do some minimization - # problem.dobs = dobs - # problem.std = dobs*0 + 0.05 + # Now set up the prob to do some minimization + # prob.dobs = dobs + # prob.std = dobs*0 + 0.05 m0 = M.gridCC[:,0]*0+sig2 - opt = inverse.InexactGaussNewton(maxIterLS=20, maxIter=3, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) - reg = inverse.Regularization(M) - inv = inverse.Inversion(problem, reg, opt, data, beta0=1e4) + opt = Inverse.InexactGaussNewton(maxIterLS=20, maxIter=3, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + reg = Inverse.Regularization(M) + inv = Inverse.Inversion(prob, reg, opt, data, beta0=1e4) # Check Derivative derChk = lambda m: [inv.dataObj(m), inv.dataObjDeriv(m)] - tests.checkDerivative(derChk, mSynth) + # Tests.checkDerivative(derChk, mSynth) diff --git a/SimPEG/Inverse/Inversion.py b/SimPEG/Inverse/Inversion.py index 1679c789..2e7d7f50 100644 --- a/SimPEG/Inverse/Inversion.py +++ b/SimPEG/Inverse/Inversion.py @@ -201,7 +201,7 @@ class BaseInversion(object): phi_d = self.dataObj(m, u) phi_m = self.reg.modelObj(m) - self.dpred = self.prob.dpred(m, u=u) # This is a cheap matrix vector calculation. + self.dpred = self.data.dpred(m, u=u) # This is a cheap matrix vector calculation. self.phi_d = phi_d self.phi_m = phi_m @@ -245,7 +245,7 @@ class BaseInversion(object): u is the field of interest; d_obs is the observed data; and W is the weighting matrix. """ # TODO: ensure that this is a data is vector and Wd is a matrix. - R = self.Wd*self.prob.dataResidual(m, self.data, u=u) + R = self.data.residualWeighted(m, u=u) R = Utils.mkvc(R) return 0.5*np.vdot(R, R) @@ -285,9 +285,9 @@ class BaseInversion(object): if u is None: u = self.prob.field(m) - R = self.Wd*self.prob.dataResidual(m, self.data, u=u) + R = self.data.residualWeighted(m, u=u) - dmisfit = self.prob.Jt(m, self.Wd * R, u=u) + dmisfit = self.prob.Jt(m, self.data.Wd * R, u=u) return dmisfit @@ -330,11 +330,11 @@ class BaseInversion(object): if u is None: u = self.prob.field(m) - R = self.Wd*self.prob.dataResidual(m, self.data, u=u) + R = self.data.residualWeighted(m, u=u) # TODO: abstract to different norms a little cleaner. # \/ it goes here. in l2 it is the identity. - dmisfit = self.prob.Jt_approx(m, self.Wd * self.Wd * self.prob.J_approx(m, v, u=u), u=u) + dmisfit = self.prob.Jt_approx(m, self.data.Wd * self.data.Wd * self.prob.J_approx(m, v, u=u), u=u) return dmisfit diff --git a/SimPEG/Problem.py b/SimPEG/Problem.py index e3e5fed7..18f7aba4 100644 --- a/SimPEG/Problem.py +++ b/SimPEG/Problem.py @@ -130,7 +130,7 @@ class BaseProblem(object): """ pass - def createSyntheticData(self, m, std=0.05, u=None): + def createSyntheticData(self, m, std=0.05, u=None, **geometry_kwargs): """ Create synthetic data given a model, and a standard deviation. @@ -142,11 +142,13 @@ class BaseProblem(object): Returns the observed data with random Gaussian noise and Wd which is the same size as data, and can be used to weight the inversion. """ - dtrue = self.dpred(m,u=u) - noise = std*abs(dtrue)*np.random.randn(*dtrue.shape) - dobs = dtrue+noise - stdev = dobs*0 + std - return self.dataPair(dobs=dobs, std=stdev, dtrue=dtrue, mtrue=m) + data = self.dataPair(mtrue=m, **geometry_kwargs) + data.setProblem(self) + data.dtrue = self.data.dpred(m,u=u) + noise = std*abs(data.dtrue)*np.random.randn(*data.dtrue.shape) + data.dobs = data.dtrue+noise + data.std = data.dobs*0 + std + return data diff --git a/SimPEG/Utils/ModelBuilder.py b/SimPEG/Utils/ModelBuilder.py index be172b6b..ec9b61e8 100644 --- a/SimPEG/Utils/ModelBuilder.py +++ b/SimPEG/Utils/ModelBuilder.py @@ -196,7 +196,7 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]): if __name__ == '__main__': - from SimPEG.mesh import TensorMesh + from SimPEG.Mesh import TensorMesh from matplotlib import pyplot as plt # Define the mesh diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index fc1c1d0f..b48a856e 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -7,6 +7,7 @@ from ipythonutils import easyAnimate as animate from Solver import Solver import Save import Geophysics +import ModelBuilder import types import time From be90cc48d2dcdaf98ac2d5f1cdaa692d0e06820a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 15:46:17 -0800 Subject: [PATCH 10/28] Removed mesh.n as it is the same as mesh.nCv --- SimPEG/Mesh/BaseMesh.py | 34 +++++++++++++------------- SimPEG/Mesh/DiffOperators.py | 32 ++++++++++++------------ SimPEG/Mesh/LogicallyOrthogonalMesh.py | 24 +++++++++--------- SimPEG/Mesh/TensorMesh.py | 4 +-- SimPEG/Tests/test_basemesh.py | 14 +++++------ 5 files changed, 54 insertions(+), 54 deletions(-) diff --git a/SimPEG/Mesh/BaseMesh.py b/SimPEG/Mesh/BaseMesh.py index f034aa5f..7b656697 100644 --- a/SimPEG/Mesh/BaseMesh.py +++ b/SimPEG/Mesh/BaseMesh.py @@ -96,7 +96,7 @@ class BaseMesh(object): def switchKernal(xx): """Switches over the different options.""" if xType in ['CC', 'N']: - nn = (self.n) if xType == 'CC' else (self.n+1) + nn = (self._n) if xType == 'CC' else (self._n+1) assert xx.size == np.prod(nn), "Number of elements must not change." return outKernal(xx, nn) elif xType in ['F', 'E']: @@ -147,16 +147,16 @@ class BaseMesh(object): else: return switchKernal(x) - def n(): - doc = """ - Number of Cells in each dimension (array of integers) + # def n(): + # doc = """ + # Number of Cells in each dimension (array of integers) - :rtype: numpy.array - :return: n - """ - fget = lambda self: self._n - return locals() - n = property(**n()) + # :rtype: numpy.array + # :return: n + # """ + # fget = lambda self: self._n + # return locals() + # n = property(**n()) def dim(): doc = """ @@ -176,7 +176,7 @@ class BaseMesh(object): :rtype: int :return: nCx """ - fget = lambda self: self.n[0] + fget = lambda self: self._n[0] return locals() nCx = property(**nCx()) @@ -190,7 +190,7 @@ class BaseMesh(object): def fget(self): if self.dim > 1: - return self.n[1] + return self._n[1] else: return None return locals() @@ -205,7 +205,7 @@ class BaseMesh(object): def fget(self): if self.dim > 2: - return self.n[2] + return self._n[2] else: return None return locals() @@ -224,7 +224,7 @@ class BaseMesh(object): import numpy as np TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(centers=True,showIt=True) """ - fget = lambda self: np.prod(self.n) + fget = lambda self: np.prod(self._n) return locals() nC = property(**nC()) @@ -260,7 +260,7 @@ class BaseMesh(object): def fget(self): if self.dim > 1: - return self.n[1] + 1 + return self._n[1] + 1 else: return None return locals() @@ -276,7 +276,7 @@ class BaseMesh(object): def fget(self): if self.dim > 2: - return self.n[2] + 1 + return self._n[2] + 1 else: return None return locals() @@ -295,7 +295,7 @@ class BaseMesh(object): import numpy as np TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(nodes=True,showIt=True) """ - fget = lambda self: np.prod(self.n + 1) + fget = lambda self: np.prod(self.nCv + 1) return locals() nN = property(**nN()) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index 1e8c1ccb..978f964b 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -129,7 +129,7 @@ class DiffOperators(object): def fget(self): if(self._faceDiv is None): # The number of cell centers in each direction - n = self.n + n = self.nCv # Compute faceDivergence operator on faces if(self.dim == 1): D = ddx(n[0]) @@ -158,7 +158,7 @@ class DiffOperators(object): def fget(self): if(self._faceDivx is None): # The number of cell centers in each direction - n = self.n + n = self.nCv # Compute faceDivergence operator on faces if(self.dim == 1): D1 = ddx(n[0]) @@ -183,7 +183,7 @@ class DiffOperators(object): if(self.dim < 2): return None if(self._faceDivy is None): # The number of cell centers in each direction - n = self.n + n = self.nCv # Compute faceDivergence operator on faces if(self.dim == 2): D2 = sp.kron(ddx(n[1]), speye(n[0])) @@ -225,7 +225,7 @@ class DiffOperators(object): def fget(self): if(self._nodalGrad is None): # The number of cell centers in each direction - n = self.n + n = self.nCv # Compute divergence operator on faces if(self.dim == 1): G = ddx(n[0]) @@ -253,7 +253,7 @@ class DiffOperators(object): if(self._nodalLaplacian is None): print 'Warning: Laplacian has not been tested rigorously.' # The number of cell centers in each direction - n = self.n + n = self.nCv # Compute divergence operator on faces if(self.dim == 1): D1 = sdiag(1./self.hx) * ddx(mesh.nCx) @@ -291,7 +291,7 @@ class DiffOperators(object): """ if(type(BC) is str): - BC = [BC for _ in self.n] # Repeat the str self.dim times + BC = [BC for _ in self.nCv] # Repeat the str self.dim times elif(type(BC) is list): assert len(BC) == self.dim, 'BC list must be the size of your mesh' else: @@ -313,7 +313,7 @@ class DiffOperators(object): def fget(self): if(self._cellGrad is None): BC = self.setCellGradBC(self._cellGradBC_list) - n = self.n + n = self.nCv if(self.dim == 1): G = ddxCellGrad(n[0], BC[0]) elif(self.dim == 2): @@ -340,7 +340,7 @@ class DiffOperators(object): def fget(self): if(self._cellGradBC is None): BC = self.setCellGradBC(self._cellGradBC_list) - n = self.n + n = self.nCv if(self.dim == 1): G = ddxCellGradBC(n[0], BC[0]) elif(self.dim == 2): @@ -367,7 +367,7 @@ class DiffOperators(object): def fget(self): if getattr(self, '_cellGradx', None) is None: BC = ['neumann', 'neumann'] - n = self.n + n = self.nCv if(self.dim == 1): G1 = ddxCellGrad(n[0], BC) elif(self.dim == 2): @@ -388,7 +388,7 @@ class DiffOperators(object): if self.dim < 2: return None if getattr(self, '_cellGrady', None) is None: BC = ['neumann', 'neumann'] - n = self.n + n = self.nCv if(self.dim == 2): G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0])) elif(self.dim == 3): @@ -466,7 +466,7 @@ class DiffOperators(object): def fget(self): if(self._aveF2CC is None): - n = self.n + n = self.nCv if(self.dim == 1): self._aveF2CC = av(n[0]) elif(self.dim == 2): @@ -486,7 +486,7 @@ class DiffOperators(object): def fget(self): if(self._aveCC2F is None): - n = self.n + n = self.nCv if(self.dim == 1): self._aveCC2F = avExtrap(n[0]) elif(self.dim == 2): @@ -507,7 +507,7 @@ class DiffOperators(object): def fget(self): if(self._aveE2CC is None): # The number of cell centers in each direction - n = self.n + n = self.nCv if(self.dim == 1): raise Exception('Edge Averaging does not make sense in 1D: Use Identity?') elif(self.dim == 2): @@ -528,7 +528,7 @@ class DiffOperators(object): def fget(self): if(self._aveN2CC is None): # The number of cell centers in each direction - n = self.n + n = self.nCv if(self.dim == 1): self._aveN2CC = av(n[0]) elif(self.dim == 2): @@ -546,7 +546,7 @@ class DiffOperators(object): def fget(self): if(self._aveN2E is None): # The number of cell centers in each direction - n = self.n + n = self.nCv if(self.dim == 1): self._aveN2E = av(n[0]) elif(self.dim == 2): @@ -567,7 +567,7 @@ class DiffOperators(object): def fget(self): if(self._aveN2F is None): # The number of cell centers in each direction - n = self.n + n = self.nCv if(self.dim == 1): self._aveN2F = av(n[0]) elif(self.dim == 2): diff --git a/SimPEG/Mesh/LogicallyOrthogonalMesh.py b/SimPEG/Mesh/LogicallyOrthogonalMesh.py index a0495630..dca59026 100644 --- a/SimPEG/Mesh/LogicallyOrthogonalMesh.py +++ b/SimPEG/Mesh/LogicallyOrthogonalMesh.py @@ -194,13 +194,13 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): def fget(self): if(self._vol is None): if self.dim == 2: - A, B, C, D = Utils.indexCube('ABCD', self.n+1) + A, B, C, D = Utils.indexCube('ABCD', self.nCv+1) normal, area = Utils.faceInfo(np.c_[self.gridN, np.zeros((self.nN, 1))], A, B, C, D) self._vol = area elif self.dim == 3: # Each polyhedron can be decomposed into 5 tetrahedrons # However, this presents a choice so we may as well divide in two ways and average. - A, B, C, D, E, F, G, H = Utils.indexCube('ABCDEFGH', self.n+1) + A, B, C, D, E, F, G, H = Utils.indexCube('ABCDEFGH', self.nCv+1) vol1 = (Utils.volTetra(self.gridN, A, B, D, E) + # cutted edge top Utils.volTetra(self.gridN, B, E, F, G) + # cutted edge top @@ -228,11 +228,11 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): # Compute areas of cell faces if(self.dim == 2): xy = self.gridN - A, B = Utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy])) + A, B = Utils.indexCube('AB', self.nCv+1, np.array([self.nNx, self.nCy])) edge1 = xy[B, :] - xy[A, :] normal1 = np.c_[edge1[:, 1], -edge1[:, 0]] area1 = length2D(edge1) - A, D = Utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy])) + A, D = Utils.indexCube('AD', self.nCv+1, np.array([self.nCx, self.nNy])) # Note that we are doing A-D to make sure the normal points the right way. # Think about it. Look at the picture. Normal points towards C iff you do this. edge2 = xy[A, :] - xy[D, :] @@ -242,13 +242,13 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): self._normals = [normalize2D(normal1), normalize2D(normal2)] elif(self.dim == 3): - A, E, F, B = Utils.indexCube('AEFB', self.n+1, np.array([self.nNx, self.nCy, self.nCz])) + A, E, F, B = Utils.indexCube('AEFB', self.nCv+1, np.array([self.nNx, self.nCy, self.nCz])) normal1, area1 = Utils.faceInfo(self.gridN, A, E, F, B, average=False, normalizeNormals=False) - A, D, H, E = Utils.indexCube('ADHE', self.n+1, np.array([self.nCx, self.nNy, self.nCz])) + A, D, H, E = Utils.indexCube('ADHE', self.nCv+1, np.array([self.nCx, self.nNy, self.nCz])) normal2, area2 = Utils.faceInfo(self.gridN, A, D, H, E, average=False, normalizeNormals=False) - A, B, C, D = Utils.indexCube('ABCD', self.n+1, np.array([self.nCx, self.nCy, self.nNz])) + A, B, C, D = Utils.indexCube('ABCD', self.nCv+1, np.array([self.nCx, self.nCy, self.nNz])) normal3, area3 = Utils.faceInfo(self.gridN, A, B, C, D, average=False, normalizeNormals=False) self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2), Utils.mkvc(area3)] @@ -291,19 +291,19 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): if(self._edge is None or self._tangents is None): if(self.dim == 2): xy = self.gridN - A, D = Utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy])) + A, D = Utils.indexCube('AD', self.nCv+1, np.array([self.nCx, self.nNy])) edge1 = xy[D, :] - xy[A, :] - A, B = Utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy])) + A, B = Utils.indexCube('AB', self.nCv+1, np.array([self.nNx, self.nCy])) edge2 = xy[B, :] - xy[A, :] self._edge = np.r_[Utils.mkvc(length2D(edge1)), Utils.mkvc(length2D(edge2))] self._tangents = np.r_[edge1, edge2]/np.c_[self._edge, self._edge] elif(self.dim == 3): xyz = self.gridN - A, D = Utils.indexCube('AD', self.n+1, np.array([self.nCx, self.nNy, self.nNz])) + A, D = Utils.indexCube('AD', self.nCv+1, np.array([self.nCx, self.nNy, self.nNz])) edge1 = xyz[D, :] - xyz[A, :] - A, B = Utils.indexCube('AB', self.n+1, np.array([self.nNx, self.nCy, self.nNz])) + A, B = Utils.indexCube('AB', self.nCv+1, np.array([self.nNx, self.nCy, self.nNz])) edge2 = xyz[B, :] - xyz[A, :] - A, E = Utils.indexCube('AE', self.n+1, np.array([self.nNx, self.nNy, self.nCz])) + A, E = Utils.indexCube('AE', self.nCv+1, np.array([self.nNx, self.nNy, self.nCz])) edge3 = xyz[E, :] - xyz[A, :] self._edge = np.r_[Utils.mkvc(length3D(edge1)), Utils.mkvc(length3D(edge2)), Utils.mkvc(length3D(edge3))] self._tangents = np.r_[edge1, edge2, edge3]/np.c_[self._edge, self._edge, self._edge] diff --git a/SimPEG/Mesh/TensorMesh.py b/SimPEG/Mesh/TensorMesh.py index 544ec716..441cb234 100644 --- a/SimPEG/Mesh/TensorMesh.py +++ b/SimPEG/Mesh/TensorMesh.py @@ -282,7 +282,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): # Ensure that we are working with column vectors vh = self.h # The number of cell centers in each direction - n = self.n + n = self.nCv # Compute areas of cell faces if(self.dim == 1): self._area = np.ones(n[0]+1) @@ -308,7 +308,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): # Ensure that we are working with column vectors vh = self.h # The number of cell centers in each direction - n = self.n + n = self.nCv # Compute edge lengths if(self.dim == 1): self._edge = Utils.mkvc(vh[0]) diff --git a/SimPEG/Tests/test_basemesh.py b/SimPEG/Tests/test_basemesh.py index 835bd29e..75b67347 100644 --- a/SimPEG/Tests/test_basemesh.py +++ b/SimPEG/Tests/test_basemesh.py @@ -13,7 +13,7 @@ class TestBaseMesh(unittest.TestCase): self.assertTrue(self.mesh.dim, 3) def test_mesh_nc(self): - self.assertTrue(np.all(self.mesh.n == [6, 2, 3])) + self.assertTrue(np.all(self.mesh.nCv == [6, 2, 3])) def test_mesh_nc_xyz(self): x = np.all(self.mesh.nCx == 6) @@ -106,9 +106,9 @@ class TestBaseMesh(unittest.TestCase): g[:, 1] = 2 g[:, 2] = 3 Xc, Yc, Zc = self.mesh.r(g, 'CC', 'CC', 'M') - self.assertTrue(np.all(Xc.shape == self.mesh.n)) - self.assertTrue(np.all(Yc.shape == self.mesh.n)) - self.assertTrue(np.all(Zc.shape == self.mesh.n)) + self.assertTrue(np.all(Xc.shape == self.mesh.nCv)) + self.assertTrue(np.all(Yc.shape == self.mesh.nCv)) + self.assertTrue(np.all(Zc.shape == self.mesh.nCv)) self.assertTrue(np.all(Xc == 1)) self.assertTrue(np.all(Yc == 2)) self.assertTrue(np.all(Zc == 3)) @@ -123,7 +123,7 @@ class TestMeshNumbers2D(unittest.TestCase): self.assertTrue(self.mesh.dim, 2) def test_mesh_nc(self): - self.assertTrue(np.all(self.mesh.n == [6, 2])) + self.assertTrue(np.all(self.mesh.nCv == [6, 2])) def test_mesh_nc_xyz(self): x = np.all(self.mesh.nCx == 6) @@ -203,8 +203,8 @@ class TestMeshNumbers2D(unittest.TestCase): g = np.ones((self.mesh.nC, 2)) g[:, 1] = 2 Xc, Yc = self.mesh.r(g, 'CC', 'CC', 'M') - self.assertTrue(np.all(Xc.shape == self.mesh.n)) - self.assertTrue(np.all(Yc.shape == self.mesh.n)) + self.assertTrue(np.all(Xc.shape == self.mesh.nCv)) + self.assertTrue(np.all(Yc.shape == self.mesh.nCv)) self.assertTrue(np.all(Xc == 1)) self.assertTrue(np.all(Yc == 2)) From 882b88934461a8bb64ec2ea2efd77af84370ea56 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 15:48:20 -0800 Subject: [PATCH 11/28] ModelBuilder changes for consistency. --- SimPEG/Utils/ModelBuilder.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SimPEG/Utils/ModelBuilder.py b/SimPEG/Utils/ModelBuilder.py index ec9b61e8..c70c7019 100644 --- a/SimPEG/Utils/ModelBuilder.py +++ b/SimPEG/Utils/ModelBuilder.py @@ -27,6 +27,9 @@ def getIndecesBlock(p0,p1,ccMesh): dimMesh = np.size(ccMesh[0,:]) assert len(p0) == dimMesh, "Dimension mismatch. len(p0) != dimMesh" + for ii in range(len(p0)): + p0[ii], p1[ii] = np.min([p0[ii], p1[ii]]), np.max([p0[ii], p1[ii]]) + if dimMesh == 1: # Define the reference points x1 = p0[0] @@ -67,7 +70,7 @@ def getIndecesBlock(p0,p1,ccMesh): # Return a tuple return ind -def defineBlockConductivity(p0,p1,ccMesh,condVals): +def defineBlockConductivity(ccMesh,p0,p1,condVals): """ Build a block with the conductivity specified by condVal. Returns an array. condVals[0] conductivity of the block @@ -80,7 +83,7 @@ def defineBlockConductivity(p0,p1,ccMesh,condVals): return sigma -def defineTwoLayeredConductivity(depth,ccMesh,condVals): +def defineTwoLayeredConductivity(ccMesh,depth,condVals): """ Define a two layered model. Depth of the first layer must be specified. CondVals vector with the conductivity values of the layers. Eg: @@ -229,7 +232,7 @@ if __name__ == '__main__': p1 = np.array([1.0,1.0,1.0])[:testDim] condVals = np.array([100,1e-6]) - sigma = defineBlockConductivity(p0,p1,ccMesh,condVals) + sigma = defineBlockConductivity(ccMesh,p0,p1,condVals) # Plot sigma model print sigma.shape @@ -242,7 +245,7 @@ if __name__ == '__main__': condVals = np.array([100,1e-5]); depth = 1.0; - sigma = defineTwoLayeredConductivity(depth,ccMesh,condVals) + sigma = defineTwoLayeredConductivity(ccMesh,depth,condVals) M.plotImage(sigma) print sigma From ac898846d1195b959d29064bbccd7c6a7fd0373c Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 16 Jan 2014 15:51:16 -0800 Subject: [PATCH 12/28] =?UTF-8?q?bug=20Fix=20to=20do=20with=20n=20?= =?UTF-8?q?=E2=80=94>=20nCv?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SimPEG/Mesh/TensorView.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SimPEG/Mesh/TensorView.py b/SimPEG/Mesh/TensorView.py index cbecde0a..7f1cb5e5 100644 --- a/SimPEG/Mesh/TensorView.py +++ b/SimPEG/Mesh/TensorView.py @@ -124,9 +124,9 @@ class TensorView(object): ax.axis('tight') elif self.dim == 2: if imageType == 'CC': - C = I[:].reshape(self.n, order='F') + C = I[:].reshape(self.nCv, order='F') elif imageType == 'N': - C = I[:].reshape(self.n+1, order='F') + C = I[:].reshape(self.nNv, order='F') C = 0.25*(C[:-1, :-1] + C[1:, :-1] + C[:-1, 1:] + C[1:, 1:]) elif imageType == 'Fx': C = I[:].reshape(self.nFx, order='F') @@ -153,9 +153,9 @@ class TensorView(object): # get copy of image and average to cell-centres is necessary if imageType == 'CC': - Ic = I[:].reshape(self.n, order='F') + Ic = I[:].reshape(self.nCv, order='F') elif imageType == 'N': - Ic = I[:].reshape(self.n+1, order='F') + Ic = I[:].reshape(self.nNv, order='F') Ic = .125*(Ic[:-1,:-1,:-1]+Ic[1:,:-1,:-1] + Ic[:-1,1:,:-1]+ Ic[1:,1:,:-1]+ Ic[:-1,:-1,1:]+Ic[1:,:-1,1:] + Ic[:-1,1:,1:]+ Ic[1:,1:,1:] ) elif imageType == 'Fx': Ic = I[:].reshape(self.nFx, order='F') From 67b067d93897620b47a329e483424eb07d0fa69a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 17 Jan 2014 14:03:08 -0800 Subject: [PATCH 13/28] Major Reorganization (Things are likely still broken...) Added Parameter to Utils, which hints at where we are going with functions as parameters. --- SimPEG/Data.py | 39 +- SimPEG/Examples/DC.py | 4 +- SimPEG/Examples/Linear.py | 2 +- SimPEG/Inverse/BetaSchedule.py | 12 - SimPEG/Inverse/Inversion.py | 383 ------------------ SimPEG/Inverse/__init__.py | 4 - SimPEG/Inversion.py | 188 +++++++++ SimPEG/Model.py | 52 ++- SimPEG/ObjFunction.py | 260 ++++++++++++ .../{Inverse/Optimize.py => Optimization.py} | 14 +- SimPEG/{Inverse => }/Regularization.py | 2 +- SimPEG/Tests/test_model.py | 4 +- SimPEG/Tests/test_optimizers.py | 12 +- SimPEG/Tests/test_problem.py | 2 +- SimPEG/Utils/__init__.py | 62 +++ SimPEG/Utils/interputils.py | 4 +- SimPEG/__init__.py | 4 +- 17 files changed, 575 insertions(+), 473 deletions(-) delete mode 100644 SimPEG/Inverse/BetaSchedule.py delete mode 100644 SimPEG/Inverse/Inversion.py delete mode 100644 SimPEG/Inverse/__init__.py create mode 100644 SimPEG/Inversion.py create mode 100644 SimPEG/ObjFunction.py rename SimPEG/{Inverse/Optimize.py => Optimization.py} (98%) rename SimPEG/{Inverse => }/Regularization.py (99%) diff --git a/SimPEG/Data.py b/SimPEG/Data.py index dc9239e1..17eebaeb 100644 --- a/SimPEG/Data.py +++ b/SimPEG/Data.py @@ -1,37 +1,6 @@ import Utils import numpy as np -def requiresProblem(f): - """ - Use this to wrap a funciton:: - - @requiresProblem - def dpred(self): - pass - - This wrapper will ensure that a problem has been bound to the data. - If a problem is not bound an Exception will be raised, and an nice error message printed. - """ - extra = """ - To use data.%s(), SimPEG requires that a problem be bound to the data. - If a problem has not been bound, an Exception will be raised. - To bind a problem to the Data object:: - - data.setProblem(myProblem) - - """ % f.__name__ - from functools import wraps - @wraps(f) - def requiresProblemWrapper(self,*args,**kwargs): - if getattr(self, 'prob', None) is None: - raise Exception(extra) - return f(self,*args,**kwargs) - - doc = requiresProblemWrapper.__doc__ - requiresProblemWrapper.__doc__ = ('' if doc is None else doc) + extra - - return requiresProblemWrapper - class BaseData(object): """Data holds the observed data, and the standard deviations.""" @@ -55,7 +24,7 @@ class BaseData(object): prob.data = self @Utils.count - @requiresProblem + @Utils.requires('prob') def dpred(self, m, u=None): """ Create the projected data from a model. @@ -68,7 +37,7 @@ class BaseData(object): Where P is a projection of the fields onto the data space. """ if u is None: u = self.prob.field(m) - return self.projectField(u) + return Utils.mkvc(self.projectField(u)) @Utils.count @@ -99,7 +68,7 @@ class BaseData(object): \mu_\\text{data} = \mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs} """ - return self.dpred(m, u=u) - self.dobs + return Utils.mkvc(self.dpred(m, u=u) - self.dobs) @property @@ -136,7 +105,7 @@ class BaseData(object): Where W_d is a covariance matrix that weights the data residual. """ - return self.Wd*self.residual(m, u=u) + return Utils.mkvc(self.Wd*self.residual(m, u=u)) @property def RHS(self): diff --git a/SimPEG/Examples/DC.py b/SimPEG/Examples/DC.py index a05e3e3c..28b1466f 100644 --- a/SimPEG/Examples/DC.py +++ b/SimPEG/Examples/DC.py @@ -193,7 +193,7 @@ if __name__ == '__main__': p0 = [5, 10] p1 = [15, 50] condVals = [sig1, sig2] - mSynth = Utils.ModelBuilder.defineBlockConductivity(p0,p1,M.gridCC,condVals) + mSynth = Utils.ModelBuilder.defineBlockConductivity(M.gridCC,p0,p1,condVals) plt.colorbar(M.plotImage(mSynth)) # plt.show() @@ -217,7 +217,7 @@ if __name__ == '__main__': u = prob.field(mSynth) u = data.reshapeFields(u) M.plotImage(u[:,10]) - # plt.show() + plt.show() # Now set up the prob to do some minimization # prob.dobs = dobs diff --git a/SimPEG/Examples/Linear.py b/SimPEG/Examples/Linear.py index 618ff260..acaaf38b 100644 --- a/SimPEG/Examples/Linear.py +++ b/SimPEG/Examples/Linear.py @@ -1,4 +1,4 @@ -from SimPEG import Mesh, Model, Problem, Data, Inverse, np +from SimPEG import Mesh, Model, Problem, Data, Inversion, np import matplotlib.pyplot as plt diff --git a/SimPEG/Inverse/BetaSchedule.py b/SimPEG/Inverse/BetaSchedule.py deleted file mode 100644 index c225c0c0..00000000 --- a/SimPEG/Inverse/BetaSchedule.py +++ /dev/null @@ -1,12 +0,0 @@ - - -class Cooling(object): - """Simple Beta Schedule""" - - beta0 = None #: The initial beta value, set to none means that it will be approximated in the first iteration. - beta_coolingFactor = 2. - - def getBeta(self): - if self._beta is None: - return self.beta0 - return self._beta / self.beta_coolingFactor diff --git a/SimPEG/Inverse/Inversion.py b/SimPEG/Inverse/Inversion.py deleted file mode 100644 index 2e7d7f50..00000000 --- a/SimPEG/Inverse/Inversion.py +++ /dev/null @@ -1,383 +0,0 @@ -import SimPEG -from SimPEG import Utils, sp, np -from Optimize import Remember -from BetaSchedule import Cooling -from SimPEG.Inverse import IterationPrinters, StoppingCriteria - -class BaseInversion(object): - """BaseInversion(prob, reg, opt, data, **kwargs) - """ - - __metaclass__ = Utils.Save.Savable - - maxIter = 1 #: Maximum number of iterations - name = 'BaseInversion' - - debug = False #: Print debugging information - - comment = '' #: Used by some functions to indicate what is going on in the algorithm - counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things - - beta0 = None #: The initial Beta (regularization parameter) - beta0_ratio = 0.1 #: When beta0 is set to None, estimateBeta0 is used with this ratio - - def __init__(self, prob, reg, opt, data, **kwargs): - Utils.setKwargs(self, **kwargs) - self.prob = prob - self.reg = reg - self.opt = opt - self.data = data - self.opt.parent = self - - self.stoppers = [StoppingCriteria.iteration] - - # Check if we have inserted printers into the optimization - if IterationPrinters.phi_d not in self.opt.printers: - self.opt.printers.insert(1,IterationPrinters.beta) - self.opt.printers.insert(2,IterationPrinters.phi_d) - self.opt.printers.insert(3,IterationPrinters.phi_m) - - if not hasattr(opt, '_bfgsH0') and hasattr(opt, 'bfgsH0'): # Check if it has been set by the user and the default is not being used. - print 'Setting bfgsH0 to the inverse of the modelObj2Deriv. Done using direct methods.' - opt.bfgsH0 = SimPEG.Solver(reg.modelObj2Deriv()) - - - @property - def phi_d_target(self): - """ - target for phi_d - - By default this is the number of data. - - Note that we do not set the target if it is None, but we return the default value. - """ - if getattr(self, '_phi_d_target', None) is None: - return self.data.dobs.size # - return self._phi_d_target - - @phi_d_target.setter - def phi_d_target(self, value): - self._phi_d_target = value - - @Utils.timeIt - def run(self, m0): - """run(m0) - - Runs the inversion! - - """ - self.startup(m0) - while True: - self.doStartIteration() - self.m = self.opt.minimize(self.evalFunction, self.m) - self.doEndIteration() - if self.stoppingCriteria(): break - - self.printDone() - self.finish() - - return self.m - - @Utils.callHooks('startup') - def startup(self, m0): - """ - **startup** is called at the start of any new run call. - - :param numpy.ndarray x0: initial x - :rtype: None - :return: None - """ - - if not hasattr(self.reg, '_mref'): - print 'Regularization has not set mref. SimPEG will set it to m0.' - self.reg.mref = m0 - - self.m = m0 - self._iter = 0 - self._beta = None - self.phi_d_last = np.nan - self.phi_m_last = np.nan - - @Utils.callHooks('doStartIteration') - def doStartIteration(self): - """ - **doStartIteration** is called at the end of each run iteration. - - :rtype: None - :return: None - """ - self._beta = self.getBeta() - - - @Utils.callHooks('doEndIteration') - def doEndIteration(self): - """ - **doEndIteration** is called at the end of each run iteration. - - :rtype: None - :return: None - """ - # store old values - self.phi_d_last = self.phi_d - self.phi_m_last = self.phi_m - self._iter += 1 - - def getBeta(self): - return self.beta0 - - def estimateBeta0(self, u=None, ratio=0.1): - """estimateBeta0(u=None, ratio=0.1) - - The initial beta is calculated by comparing the estimated - eigenvalues of JtJ and WtW. - - To estimate the eigenvector of **A**, we will use one iteration - of the *Power Method*: - - .. math:: - - \mathbf{x_1 = A x_0} - - Given this (very course) approximation of the eigenvector, - we can use the *Rayleigh quotient* to approximate the largest eigenvalue. - - .. math:: - - \lambda_0 = \\frac{\mathbf{x^\\top A x}}{\mathbf{x^\\top x}} - - We will approximate the largest eigenvalue for both JtJ and WtW, and - use some ratio of the quotient to estimate beta0. - - .. math:: - - \\beta_0 = \gamma \\frac{\mathbf{x^\\top J^\\top J x}}{\mathbf{x^\\top W^\\top W x}} - - - :param numpy.array u: fields - :param float ratio: desired ratio of the eigenvalues, default is 0.1 - :rtype: float - :return: beta0 - """ - if u is None: - u = self.prob.field(self.m) - - x0 = np.random.rand(*self.m.shape) - t = x0.dot(self.dataObj2Deriv(self.m,x0,u=u)) - b = x0.dot(self.reg.modelObj2Deriv()*x0) - return ratio*(t/b) - - def stoppingCriteria(self): - if self.debug: print 'checking stoppingCriteria' - return Utils.checkStoppers(self, self.stoppers) - - - def printDone(self): - """ - **printDone** is called at the end of the inversion routine. - - """ - Utils.printStoppers(self, self.stoppers) - - @Utils.callHooks('finish') - def finish(self): - """finish() - - **finish** is called at the end of the optimization. - """ - pass - - @Utils.timeIt - def evalFunction(self, m, return_g=True, return_H=True): - """evalFunction(m, return_g=True, return_H=True) - - - """ - - u = self.prob.field(m) - - if self._iter is 0 and self._beta is None: - self._beta = self.beta0 = self.estimateBeta0(u=u,ratio=self.beta0_ratio) - - phi_d = self.dataObj(m, u) - phi_m = self.reg.modelObj(m) - - self.dpred = self.data.dpred(m, u=u) # This is a cheap matrix vector calculation. - self.phi_d = phi_d - self.phi_m = phi_m - - f = phi_d + self._beta * phi_m - - out = (f,) - if return_g: - phi_dDeriv = self.dataObjDeriv(m, u=u) - phi_mDeriv = self.reg.modelObjDeriv(m) - - g = phi_dDeriv + self._beta * phi_mDeriv - out += (g,) - - if return_H: - def H_fun(v): - phi_d2Deriv = self.dataObj2Deriv(m, v, u=u) - phi_m2Deriv = self.reg.modelObj2Deriv()*v - - return phi_d2Deriv + self._beta * phi_m2Deriv - - operator = sp.linalg.LinearOperator( (m.size, m.size), H_fun, dtype=m.dtype ) - out += (operator,) - return out if len(out) > 1 else out[0] - - @Utils.timeIt - def dataObj(self, m, u=None): - """dataObj(m, u=None) - - :param numpy.array m: geophysical model - :param numpy.array u: fields - :rtype: float - :return: data misfit - - The data misfit using an l_2 norm is: - - .. math:: - - \mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2 - - Where P is a projection matrix that brings the field on the full domain to the data measurement locations; - u is the field of interest; d_obs is the observed data; and W is the weighting matrix. - """ - # TODO: ensure that this is a data is vector and Wd is a matrix. - R = self.data.residualWeighted(m, u=u) - R = Utils.mkvc(R) - return 0.5*np.vdot(R, R) - - @Utils.timeIt - def dataObjDeriv(self, m, u=None): - """dataObjDeriv(m, u=None) - - :param numpy.array m: geophysical model - :param numpy.array u: fields - :rtype: numpy.array - :return: data misfit derivative - - The data misfit using an l_2 norm is: - - .. math:: - - \mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2 - - If the field, u, is provided, the calculation of the data is fast: - - .. math:: - - \mathbf{d}_\\text{pred} = \mathbf{Pu(m)} - - \mathbf{R} = \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) - - Where P is a projection matrix that brings the field on the full domain to the data measurement locations; - u is the field of interest; d_obs is the observed data; and W is the weighting matrix. - - The derivative of this, with respect to the model, is: - - .. math:: - - \\frac{\partial \mu_\\text{data}}{\partial \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ R} - - """ - if u is None: - u = self.prob.field(m) - - R = self.data.residualWeighted(m, u=u) - - dmisfit = self.prob.Jt(m, self.data.Wd * R, u=u) - - return dmisfit - - @Utils.timeIt - def dataObj2Deriv(self, m, v, u=None): - """dataObj2Deriv(m, v, u=None) - - :param numpy.array m: geophysical model - :param numpy.array v: vector to multiply - :param numpy.array u: fields - :rtype: numpy.array - :return: data misfit derivative - - The data misfit using an l_2 norm is: - - .. math:: - - \mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2 - - If the field, u, is provided, the calculation of the data is fast: - - .. math:: - - \mathbf{d}_\\text{pred} = \mathbf{Pu(m)} - - \mathbf{R} = \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) - - Where P is a projection matrix that brings the field on the full domain to the data measurement locations; - u is the field of interest; d_obs is the observed data; and W is the weighting matrix. - - The derivative of this, with respect to the model, is: - - .. math:: - - \\frac{\partial \mu_\\text{data}}{\partial \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ R} - - \\frac{\partial^2 \mu_\\text{data}}{\partial^2 \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ W J} - - """ - if u is None: - u = self.prob.field(m) - - R = self.data.residualWeighted(m, u=u) - - # TODO: abstract to different norms a little cleaner. - # \/ it goes here. in l2 it is the identity. - dmisfit = self.prob.Jt_approx(m, self.data.Wd * self.data.Wd * self.prob.J_approx(m, v, u=u), u=u) - - return dmisfit - - def save(self, group): - group.attrs['phi_d'] = self.phi_d - group.attrs['phi_m'] = self.phi_m - group.setArray('m', self.m) - group.setArray('dpred', self.dpred) - -class Inversion(Cooling, Remember, BaseInversion): - - maxIter = 10 - name = "SimPEG Inversion" - - def __init__(self, prob, reg, opt, data, **kwargs): - BaseInversion.__init__(self, prob, reg, opt, data, **kwargs) - - self.stoppers.append(StoppingCriteria.phi_d_target_Inversion) - - if StoppingCriteria.phi_d_target_Minimize not in self.opt.stoppers: - self.opt.stoppers.append(StoppingCriteria.phi_d_target_Minimize) - -class TimeSteppingInversion(Remember, BaseInversion): - """ - A slightly different view on regularization parameters, - let Beta be viewed as 1/dt, and timestep by updating the - reference model every optimization iteration. - """ - maxIter = 1 - name = "Time-Stepping SimPEG Inversion" - - def __init__(self, prob, reg, opt, data, **kwargs): - BaseInversion.__init__(self, prob, reg, opt, data, **kwargs) - - self.stoppers.append(StoppingCriteria.phi_d_target_Inversion) - - if StoppingCriteria.phi_d_target_Minimize not in self.opt.stoppers: - self.opt.stoppers.append(StoppingCriteria.phi_d_target_Minimize) - - def _startup_TimeSteppingInversion(self, m0): - - def _doEndIteration_updateMref(self, xt): - if self.debug: 'Updating the reference model.' - self.parent.reg.mref = self.xc - - self.opt.hook(_doEndIteration_updateMref, overwrite=True) diff --git a/SimPEG/Inverse/__init__.py b/SimPEG/Inverse/__init__.py deleted file mode 100644 index d83a8269..00000000 --- a/SimPEG/Inverse/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from Optimize import * -from Inversion import * -from Regularization import Regularization -import BetaSchedule diff --git a/SimPEG/Inversion.py b/SimPEG/Inversion.py new file mode 100644 index 00000000..63a42bb3 --- /dev/null +++ b/SimPEG/Inversion.py @@ -0,0 +1,188 @@ +import SimPEG +from SimPEG import Utils, sp, np +from Optimization import Remember, IterationPrinters, StoppingCriteria + +class BaseInversion(object): + """BaseInversion(prob, reg, opt, data, **kwargs) + """ + + __metaclass__ = Utils.Save.Savable + + maxIter = 1 #: Maximum number of iterations + name = 'BaseInversion' + + debug = False #: Print debugging information + + comment = '' #: Used by some functions to indicate what is going on in the algorithm + counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things + + def __init__(self, dataObj, opt, **kwargs): + Utils.setKwargs(self, **kwargs) + + self.dataObj = dataObj + self.dataObj.parent = self + + self.opt = opt + self.opt.parent = self + + self.stoppers = [StoppingCriteria.iteration] + + # Check if we have inserted printers into the optimization + if IterationPrinters.phi_d not in self.opt.printers: + self.opt.printers.insert(1,IterationPrinters.beta) + self.opt.printers.insert(2,IterationPrinters.phi_d) + self.opt.printers.insert(3,IterationPrinters.phi_m) + + if not hasattr(opt, '_bfgsH0') and hasattr(opt, 'bfgsH0'): # Check if it has been set by the user and the default is not being used. + #TODO: I don't think that this if statement is working... + print 'Setting bfgsH0 to the inverse of the modelObj2Deriv. Done using direct methods.' + opt.bfgsH0 = SimPEG.Solver(reg.modelObj2Deriv()) + + + @property + def phi_d_target(self): + """ + target for phi_d + + By default this is the number of data. + + Note that we do not set the target if it is None, but we return the default value. + """ + if getattr(self, '_phi_d_target', None) is None: + return self.data.dobs.size # + return self._phi_d_target + + @phi_d_target.setter + def phi_d_target(self, value): + self._phi_d_target = value + + @Utils.timeIt + def run(self, m0): + """run(m0) + + Runs the inversion! + + """ + self.startup(m0) + while True: + self.doStartIteration() + self.m = self.opt.minimize(self.evalFunction, self.m) + self.doEndIteration() + if self.stoppingCriteria(): break + + self.printDone() + self.finish() + + return self.m + + @Utils.callHooks('startup') + def startup(self, m0): + """ + **startup** is called at the start of any new run call. + + :param numpy.ndarray x0: initial x + :rtype: None + :return: None + """ + + if not hasattr(self.reg, '_mref'): + print 'Regularization has not set mref. SimPEG will set it to m0.' + self.reg.mref = m0 + + self.m = m0 + self._iter = 0 + self._beta = None + self.phi_d_last = np.nan + self.phi_m_last = np.nan + + @Utils.callHooks('doStartIteration') + def doStartIteration(self): + """ + **doStartIteration** is called at the end of each run iteration. + + :rtype: None + :return: None + """ + self._beta = self.getBeta() + + + @Utils.callHooks('doEndIteration') + def doEndIteration(self): + """ + **doEndIteration** is called at the end of each run iteration. + + :rtype: None + :return: None + """ + # store old values + self.phi_d_last = self.phi_d + self.phi_m_last = self.phi_m + self._iter += 1 + + + def stoppingCriteria(self): + if self.debug: print 'checking stoppingCriteria' + return Utils.checkStoppers(self, self.stoppers) + + + def printDone(self): + """ + **printDone** is called at the end of the inversion routine. + + """ + Utils.printStoppers(self, self.stoppers) + + @Utils.callHooks('finish') + def finish(self): + """finish() + + **finish** is called at the end of the optimization. + """ + pass + + + def save(self, group): + group.attrs['phi_d'] = self.phi_d + group.attrs['phi_m'] = self.phi_m + group.setArray('m', self.m) + group.setArray('dpred', self.dpred) + + + +# class Inversion(Cooling, Remember, BaseInversion): + +# maxIter = 10 +# name = "SimPEG Inversion" + +# def __init__(self, prob, reg, opt, data, **kwargs): +# BaseInversion.__init__(self, prob, reg, opt, data, **kwargs) + +# self.stoppers.append(StoppingCriteria.phi_d_target_Inversion) + +# if StoppingCriteria.phi_d_target_Minimize not in self.opt.stoppers: +# self.opt.stoppers.append(StoppingCriteria.phi_d_target_Minimize) + +# class TimeSteppingInversion(Remember, BaseInversion): +# """ +# A slightly different view on regularization parameters, +# let Beta be viewed as 1/dt, and timestep by updating the +# reference model every optimization iteration. +# """ +# maxIter = 1 +# name = "Time-Stepping SimPEG Inversion" + +# def __init__(self, prob, reg, opt, data, **kwargs): +# BaseInversion.__init__(self, prob, reg, opt, data, **kwargs) + +# self.stoppers.append(StoppingCriteria.phi_d_target_Inversion) + +# if StoppingCriteria.phi_d_target_Minimize not in self.opt.stoppers: +# self.opt.stoppers.append(StoppingCriteria.phi_d_target_Minimize) + +# def _startup_TimeSteppingInversion(self, m0): + +# def _doEndIteration_updateMref(self, xt): +# if self.debug: 'Updating the reference model.' +# self.parent.reg.mref = self.xc + +# self.opt.hook(_doEndIteration_updateMref, overwrite=True) diff --git a/SimPEG/Model.py b/SimPEG/Model.py index 75912deb..6eb3c297 100644 --- a/SimPEG/Model.py +++ b/SimPEG/Model.py @@ -2,14 +2,18 @@ from SimPEG import Utils, np, sp class BaseModel(object): - """SimPEG Model""" + """ + SimPEG Model + + """ __metaclass__ = Utils.Save.Savable counter = None #: A SimPEG.Utils.Counter object + mesh = None #: A SimPEG Mesh - def __init__(self): - pass + def __init__(self, mesh): + self.mesh = mesh def transform(self, m): """ @@ -19,13 +23,22 @@ class BaseModel(object): The *transform* changes the model into the physical property. - A common example of this is to invert for electrical conductivity - in log space. In this case, your model will be log(sigma) and to - get back to sigma, you can take the exponential: - """ return m + def transformInverse(self, D): + """ + :param numpy.array D: physical property + :rtype: numpy.array + :return: model + + The *transformInverse* changes the physical property into the model. + + .. note:: The *transformInverse* may not be easy to create in general. + + """ + raise NotImplementedError('The transformInverse is not implemented.') + def transformDeriv(self, m): """ :param numpy.array m: model @@ -37,16 +50,16 @@ class BaseModel(object): """ return sp.identity(m.size) - def example(self, mesh, type=None): - return np.random.rand(mesh.nC) + def example(self, modelType=None): + return np.random.rand(self.mesh.nC) class LogModel(BaseModel): """SimPEG LogModel""" - def __init__(self, **kwargs): - BaseModel.__init__(self, **kwargs) + def __init__(self, mesh, **kwargs): + BaseModel.__init__(self, mesh, **kwargs) def transform(self, m): """ @@ -68,6 +81,23 @@ class LogModel(BaseModel): """ return np.exp(Utils.mkvc(m)) + + def transformInverse(self, D): + """ + :param numpy.array D: physical property + :rtype: numpy.array + :return: model + + The *transformInverse* changes the physical property into the model. + + .. math:: + + m = \log{\sigma} + + """ + return np.log(Utils.mkvc(D)) + + def transformDeriv(self, m): """ :param numpy.array m: model diff --git a/SimPEG/ObjFunction.py b/SimPEG/ObjFunction.py new file mode 100644 index 00000000..38323cd3 --- /dev/null +++ b/SimPEG/ObjFunction.py @@ -0,0 +1,260 @@ +from SimPEG import Utils + +class BaseObjFunction(object): + """docstring for BaseObjFunction""" + + __metaclass__ = Utils.Save.Savable + + beta = None #: Regularization trade-off parameter + + name = 'BaseObjFunction' #: Name of the objective function + + counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things + + u_current = None #: The most current evaluated field + m_current = None #: The most current model + + @property + def parent(self): + """This is the parent of the objective function.""" + return getattr(self,'_parent',None) + @parent.setter + def parent(self, p): + if getattr(self,'_parent',None) is not None: + print 'Objective function has switched to a new parent!' + self._parent = p + + + def __init__(self, data, reg, **kwargs): + Utils.setKwargs(self, **kwargs) + + self.data = data + self.reg = reg + + @Utils.timeIt + def evalFunction(self, m, return_g=True, return_H=True): + """evalFunction(m, return_g=True, return_H=True) + """ + + self.u_current = None + self.m_current = m + + u = self.data.prob.field(m) + self.u_current = u + + if self._iter is 0 and self._beta is None: + self._beta = self.beta0 = self.estimateBeta0(u=u,ratio=self.beta0_ratio) + + phi_d = self.dataObj(m, u=u) + phi_m = self.reg.modelObj(m) + + self.dpred = self.data.dpred(m, u=u) # This is a cheap matrix vector calculation. + self.phi_d = phi_d + self.phi_m = phi_m + + f = phi_d + self._beta * phi_m + + out = (f,) + if return_g: + phi_dDeriv = self.dataObjDeriv(m, u=u) + phi_mDeriv = self.reg.modelObjDeriv(m) + + g = phi_dDeriv + self._beta * phi_mDeriv + out += (g,) + + if return_H: + def H_fun(v): + phi_d2Deriv = self.dataObj2Deriv(m, v, u=u) + phi_m2Deriv = self.reg.modelObj2Deriv()*v + + return phi_d2Deriv + self._beta * phi_m2Deriv + + operator = sp.linalg.LinearOperator( (m.size, m.size), H_fun, dtype=m.dtype ) + out += (operator,) + return out if len(out) > 1 else out[0] + + @Utils.timeIt + def dataObj(self, m, u=None): + """dataObj(m, u=None) + + :param numpy.array m: geophysical model + :param numpy.array u: fields + :rtype: float + :return: data misfit + + The data misfit using an l_2 norm is: + + .. math:: + + \mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2 + + Where P is a projection matrix that brings the field on the full domain to the data measurement locations; + u is the field of interest; d_obs is the observed data; and W is the weighting matrix. + """ + # TODO: ensure that this is a data is vector and Wd is a matrix. + R = self.data.residualWeighted(m, u=u) + return 0.5*np.vdot(R, R) + + @Utils.timeIt + def dataObjDeriv(self, m, u=None): + """dataObjDeriv(m, u=None) + + :param numpy.array m: geophysical model + :param numpy.array u: fields + :rtype: numpy.array + :return: data misfit derivative + + The data misfit using an l_2 norm is: + + .. math:: + + \mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2 + + If the field, u, is provided, the calculation of the data is fast: + + .. math:: + + \mathbf{d}_\\text{pred} = \mathbf{Pu(m)} + + \mathbf{R} = \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) + + Where P is a projection matrix that brings the field on the full domain to the data measurement locations; + u is the field of interest; d_obs is the observed data; and W is the weighting matrix. + + The derivative of this, with respect to the model, is: + + .. math:: + + \\frac{\partial \mu_\\text{data}}{\partial \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ R} + + """ + if u is None: u = self.data.prob.field(m) + + R = self.data.residualWeighted(m, u=u) + + dmisfit = self.data.prob.Jt(m, self.data.Wd * R, u=u) + + return dmisfit + + @Utils.timeIt + def dataObj2Deriv(self, m, v, u=None): + """dataObj2Deriv(m, v, u=None) + + :param numpy.array m: geophysical model + :param numpy.array v: vector to multiply + :param numpy.array u: fields + :rtype: numpy.array + :return: data misfit derivative + + The data misfit using an l_2 norm is: + + .. math:: + + \mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2 + + If the field, u, is provided, the calculation of the data is fast: + + .. math:: + + \mathbf{d}_\\text{pred} = \mathbf{Pu(m)} + + \mathbf{R} = \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) + + Where P is a projection matrix that brings the field on the full domain to the data measurement locations; + u is the field of interest; d_obs is the observed data; and W is the weighting matrix. + + The derivative of this, with respect to the model, is: + + .. math:: + + \\frac{\partial \mu_\\text{data}}{\partial \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ R} + + \\frac{\partial^2 \mu_\\text{data}}{\partial^2 \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ W J} + + """ + if u is None: u = self.data.prob.field(m) + + R = self.data.residualWeighted(m, u=u) + + # TODO: abstract to different norms a little cleaner. + # \/ it goes here. in l2 it is the identity. + dmisfit = self.data.prob.Jt_approx(m, self.data.Wd * self.data.Wd * self.data.prob.J_approx(m, v, u=u), u=u) + + return dmisfit + + + +class BetaSchedule(Utils.Parameter): + """BetaSchedule""" + + beta0 = 'guess' #: The initial Beta (regularization parameter) + beta0_ratio = 0.1 #: When beta0 is set to 'guess', estimateBeta0 is used with this ratio + + coolingFactor = 2. + coolingRate = 3 + + beta = None #: Beta parameter + + def __init__(self, **kwargs): + Utils.setKwargs(self, **kwargs) + + def initialize(self): + self.beta = self.beta0 + + @Utils.requires('parent') + def get(self): + if self.beta is 'guess': + self.beta = self.estimateBeta0() + + invesion = self.parent.parent + if inversion._iter > 0 and inversion._iter % self.coolingRate == 0: + self.beta /= self.coolingFactor + + return self.beta + + @Utils.requires('parent') + def estimateBeta0(self, u=None): + """estimateBeta0(u=None) + + The initial beta is calculated by comparing the estimated + eigenvalues of JtJ and WtW. + + To estimate the eigenvector of **A**, we will use one iteration + of the *Power Method*: + + .. math:: + + \mathbf{x_1 = A x_0} + + Given this (very course) approximation of the eigenvector, + we can use the *Rayleigh quotient* to approximate the largest eigenvalue. + + .. math:: + + \lambda_0 = \\frac{\mathbf{x^\\top A x}}{\mathbf{x^\\top x}} + + We will approximate the largest eigenvalue for both JtJ and WtW, and + use some ratio of the quotient to estimate beta0. + + .. math:: + + \\beta_0 = \gamma \\frac{\mathbf{x^\\top J^\\top J x}}{\mathbf{x^\\top W^\\top W x}} + + + :param numpy.array u: fields + :param float ratio: desired ratio of the eigenvalues, default is 0.1 + :rtype: float + :return: beta0 + """ + objFunc = + data = objFunc.data + + m = invesion.m + + if u is None: + u = data.prob.field(m) + + x0 = np.random.rand(*m.shape) + t = x0.dot(objFunc.dataObj2Deriv(m,x0,u=u)) + b = x0.dot(objFunc.reg.modelObj2Deriv()*x0) + return self.beta0_ratio*(t/b) diff --git a/SimPEG/Inverse/Optimize.py b/SimPEG/Optimization.py similarity index 98% rename from SimPEG/Inverse/Optimize.py rename to SimPEG/Optimization.py index f11cd7b1..3157b5c1 100644 --- a/SimPEG/Inverse/Optimize.py +++ b/SimPEG/Optimization.py @@ -1,5 +1,4 @@ from SimPEG import Solver, Utils, sp, np -import matplotlib.pyplot as plt norm = np.linalg.norm @@ -101,6 +100,7 @@ class Minimize(object): comment = '' #: Used by some functions to indicate what is going on in the algorithm counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things + parent = None #: This is the parent of the optimization routine. def __init__(self, **kwargs): self.stoppers = [StoppingCriteria.tolerance_f, StoppingCriteria.moving_x, StoppingCriteria.tolerance_g, StoppingCriteria.norm_g, StoppingCriteria.iteration] @@ -179,16 +179,6 @@ class Minimize(object): return self.xc - @property - def parent(self): - """ - This is the parent of the optimization routine. - """ - return getattr(self, '_parent', None) - @parent.setter - def parent(self, value): - self._parent = value - @Utils.callHooks('startup') def startup(self, x0): """ @@ -873,7 +863,7 @@ class NewtonRoot(object): if __name__ == '__main__': - from SimPEG.tests import Rosenbrock, checkDerivative + from SimPEG.Tests import Rosenbrock, checkDerivative import matplotlib.pyplot as plt x0 = np.array([2.6, 3.7]) checkDerivative(Rosenbrock, x0, plotIt=False) diff --git a/SimPEG/Inverse/Regularization.py b/SimPEG/Regularization.py similarity index 99% rename from SimPEG/Inverse/Regularization.py rename to SimPEG/Regularization.py index 1569d767..e592d643 100644 --- a/SimPEG/Inverse/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,6 +1,6 @@ from SimPEG import Utils, np, sp -class Regularization(object): +class BaseRegularization(object): """**Regularization** Here we will define regularization of a model, m, in general however, this should be thought of as (m-m_ref) but otherwise it is exactly the same: diff --git a/SimPEG/Tests/test_model.py b/SimPEG/Tests/test_model.py index 946224f1..0c3b2c54 100644 --- a/SimPEG/Tests/test_model.py +++ b/SimPEG/Tests/test_model.py @@ -18,8 +18,8 @@ class ModelTests(unittest.TestCase): print 'SimPEG.Model.BaseModel: Testing Model Transform' for M in dir(Model): if 'Model' not in M: continue - model = getattr(Model, M)() - m = model.example(self.mesh2) + model = getattr(Model, M)(self.mesh2) + m = model.example() passed = checkDerivative(lambda m : [model.transform(m), model.transformDeriv(m)], m, plotIt=False) self.assertTrue(passed) diff --git a/SimPEG/Tests/test_optimizers.py b/SimPEG/Tests/test_optimizers.py index 12c8c9b5..3132beb9 100644 --- a/SimPEG/Tests/test_optimizers.py +++ b/SimPEG/Tests/test_optimizers.py @@ -4,7 +4,7 @@ from SimPEG.Mesh import TensorMesh from SimPEG.Utils import sdiag import numpy as np import scipy.sparse as sp -from SimPEG import Inverse +from SimPEG import Optimization from SimPEG.Tests import getQuadratic, Rosenbrock TOL = 1e-2 @@ -16,7 +16,7 @@ class TestOptimizers(unittest.TestCase): self.b = np.array([-5,-5]) def test_GN_Rosenbrock(self): - GN = Inverse.GaussNewton() + GN = Optimization.GaussNewton() xopt = GN.minimize(Rosenbrock,np.array([0,0])) x_true = np.array([1.,1.]) print 'xopt: ', xopt @@ -24,7 +24,7 @@ class TestOptimizers(unittest.TestCase): self.assertTrue(np.linalg.norm(xopt-x_true,2) < TOL, True) def test_GN_quadratic(self): - GN = Inverse.GaussNewton() + GN = Optimization.GaussNewton() xopt = GN.minimize(getQuadratic(self.A,self.b),np.array([0,0])) x_true = np.array([5.,5.]) print 'xopt: ', xopt @@ -32,7 +32,7 @@ class TestOptimizers(unittest.TestCase): self.assertTrue(np.linalg.norm(xopt-x_true,2) < TOL, True) def test_ProjGradient_quadraticBounded(self): - PG = Inverse.ProjectedGradient(debug=True) + PG = Optimization.ProjectedGradient(debug=True) PG.lower, PG.upper = -2, 2 xopt = PG.minimize(getQuadratic(self.A,self.b),np.array([0,0])) x_true = np.array([2.,2.]) @@ -42,7 +42,7 @@ class TestOptimizers(unittest.TestCase): def test_ProjGradient_quadratic1Bound(self): myB = np.array([-5,1]) - PG = Inverse.ProjectedGradient() + PG = Optimization.ProjectedGradient() PG.lower, PG.upper = -2, 2 xopt = PG.minimize(getQuadratic(self.A,myB),np.array([0,0])) x_true = np.array([2.,-1.]) @@ -53,7 +53,7 @@ class TestOptimizers(unittest.TestCase): def test_NewtonRoot(self): fun = lambda x, return_g=True: np.sin(x) if not return_g else ( np.sin(x), sdiag( np.cos(x) ) ) x = np.array([np.pi-0.3, np.pi+0.1, 0]) - xopt = Inverse.NewtonRoot(comments=False).root(fun,x) + xopt = Optimization.NewtonRoot(comments=False).root(fun,x) x_true = np.array([np.pi,np.pi,0]) print 'Newton Root Finding' print 'xopt: ', xopt diff --git a/SimPEG/Tests/test_problem.py b/SimPEG/Tests/test_problem.py index fa94e6b8..e1d30337 100644 --- a/SimPEG/Tests/test_problem.py +++ b/SimPEG/Tests/test_problem.py @@ -14,7 +14,7 @@ class ProblemTests(unittest.TestCase): c = np.array([1, 4]) self.mesh2 = Mesh.TensorMesh([a, b], np.array([3, 5])) self.p2 = Problem.BaseProblem(self.mesh2, None) - self.reg = Inverse.Regularization(self.mesh2) + self.reg = Regularization.BaseRegularization(self.mesh2) def test_regularization(self): derChk = lambda m: [self.reg.modelObj(m), self.reg.modelObjDeriv(m)] diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index b48a856e..b9094a42 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -139,6 +139,42 @@ def dependentProperty(name, value, children, doc): setattr(self, name, val) return property(fget=fget, fset=fset, doc=doc) +def requires(var): + """ + Use this to wrap a funciton:: + + @requires('prob') + def dpred(self): + pass + + This wrapper will ensure that a problem has been bound to the data. + If a problem is not bound an Exception will be raised, and an nice error message printed. + """ + def requiresVar(f): + if var is 'prob': + extra = """ + To use data.%s(), SimPEG requires that a problem be bound to the data. + If a problem has not been bound, an Exception will be raised. + To bind a problem to the Data object:: + + data.setProblem(myProblem) + + """ % f.__name__ + else: + extra = """ + To use *%s* method, SimPEG requires that the %s be specified. + """ % (f.__name__, var) + @wraps(f) + def requiresVarWrapper(self,*args,**kwargs): + if getattr(self, var, None) is None: + raise Exception(extra) + return f(self,*args,**kwargs) + + doc = requiresVarWrapper.__doc__ + requiresVarWrapper.__doc__ = ('' if doc is None else doc) + extra + + return requiresVarWrapper + return requiresVar class Counter(object): """ @@ -232,6 +268,32 @@ def timeIt(f): return wrapper +class Parameter(object): + """Parameter""" + + debug = False #: Print debugging information + + def __init__(self, *args, **kwargs): + pass + + @property + def parent(self): + """This is the parent of the Parameter instance.""" + return getattr(self,'_parent',None) + @parent.setter + def parent(self, p): + if getattr(self,'_parent',None) is not None: + print 'Parameter has switched to a new parent!' + self._parent = p + + def initialize(self): + pass + + def get(self): + raise NotImplementedError('Getting the Parameter is not yet implemented.') + + + if __name__ == '__main__': class MyClass(object): def __init__(self, url): diff --git a/SimPEG/Utils/interputils.py b/SimPEG/Utils/interputils.py index 43cbff6b..38308492 100644 --- a/SimPEG/Utils/interputils.py +++ b/SimPEG/Utils/interputils.py @@ -14,10 +14,10 @@ def _interp_point_1D(x, xr_i): """ # TODO: This fails if the point is on the outside of the mesh. We may want to replace this by extrapolation? im = np.argmin(abs(x-xr_i)) - if xr_i - x[im] >= 0: # Point on the left + if xr_i - x[im] >= 0: # Point on the left ind_x1 = im ind_x2 = im+1 - elif xr_i - x[im] < 0: # Point on the right + elif xr_i - x[im] < 0: # Point on the right ind_x1 = im-1 ind_x2 = im dx1 = xr_i - x[ind_x1] diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index 904766d2..01607c80 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -6,7 +6,9 @@ import Mesh import Model import Problem import Data -import Inverse +import Inversion +import Optimization +import Regularization import Examples import Tests From 2eb074ba5471f6c7b036ec461e6c3dc36bd3f5e0 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 17 Jan 2014 14:40:42 -0800 Subject: [PATCH 14/28] Moved Solver to main Package --- SimPEG/{Utils => }/Solver.py | 8 ++++---- SimPEG/Utils/__init__.py | 1 - SimPEG/__init__.py | 7 ++++--- 3 files changed, 8 insertions(+), 8 deletions(-) rename SimPEG/{Utils => }/Solver.py (98%) diff --git a/SimPEG/Utils/Solver.py b/SimPEG/Solver.py similarity index 98% rename from SimPEG/Utils/Solver.py rename to SimPEG/Solver.py index 0b6e0d95..3e9c2d02 100644 --- a/SimPEG/Utils/Solver.py +++ b/SimPEG/Solver.py @@ -1,15 +1,15 @@ import numpy as np import scipy.sparse as sp import scipy.sparse.linalg as linalg -from matutils import mkvc -from sputils import sdiag +from Utils.matutils import mkvc +from Utils.sputils import sdiag import warnings DEFAULTS = {'direct':'scipy', 'iter':'scipy', 'triangular':'fortran', 'diagonal':'python'} OPTIONS = {'direct':['scipy'], 'iter':['scipy'], 'triangular':['python'], 'diagonal':['python']} try: - import TriSolve + import Utils.TriSolve as TriSolve OPTIONS['triangular'].append('fortran') except Exception, e: print 'Warning: Python backend is being used for solver. Run setup.py from the command line.' @@ -320,7 +320,7 @@ class Solver(object): if __name__ == '__main__': - from SimPEG.mesh import TensorMesh + from SimPEG.Mesh import TensorMesh from time import time h1 = np.ones(20)*100. h2 = np.ones(20)*100. diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index b9094a42..ab520ab4 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -4,7 +4,6 @@ from meshutils import exampleLomGird, meshTensors from lomutils import volTetra, faceInfo, inv2X2BlockDiagonal, inv3X3BlockDiagonal, indexCube from interputils import interpmat from ipythonutils import easyAnimate as animate -from Solver import Solver import Save import Geophysics import ModelBuilder diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index 01607c80..10d6d4e8 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -1,14 +1,15 @@ import numpy as np import scipy.sparse as sp import Utils -Solver = Utils.Solver +from Solver import Solver import Mesh import Model import Problem import Data -import Inversion -import Optimization import Regularization +import ObjFunction +import Optimization +import Inversion import Examples import Tests From 18f0e67619926bc19b412ed9800cd0a9e263f03d Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 17 Jan 2014 15:53:37 -0800 Subject: [PATCH 15/28] Parameter function for Beta instead of a scalar. Bug Fixes. --- SimPEG/Inversion.py | 71 ++++------------------------------------ SimPEG/ObjFunction.py | 54 +++++++++++++++++++++--------- SimPEG/Optimization.py | 6 ++-- SimPEG/Utils/__init__.py | 16 ++++++++- 4 files changed, 62 insertions(+), 85 deletions(-) diff --git a/SimPEG/Inversion.py b/SimPEG/Inversion.py index 63a42bb3..65abb6eb 100644 --- a/SimPEG/Inversion.py +++ b/SimPEG/Inversion.py @@ -8,7 +8,6 @@ class BaseInversion(object): __metaclass__ = Utils.Save.Savable - maxIter = 1 #: Maximum number of iterations name = 'BaseInversion' debug = False #: Print debugging information @@ -16,11 +15,11 @@ class BaseInversion(object): comment = '' #: Used by some functions to indicate what is going on in the algorithm counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things - def __init__(self, dataObj, opt, **kwargs): + def __init__(self, objFunc, opt, **kwargs): Utils.setKwargs(self, **kwargs) - self.dataObj = dataObj - self.dataObj.parent = self + self.objFunc = objFunc + self.objFunc.parent = self self.opt = opt self.opt.parent = self @@ -36,7 +35,7 @@ class BaseInversion(object): if not hasattr(opt, '_bfgsH0') and hasattr(opt, 'bfgsH0'): # Check if it has been set by the user and the default is not being used. #TODO: I don't think that this if statement is working... print 'Setting bfgsH0 to the inverse of the modelObj2Deriv. Done using direct methods.' - opt.bfgsH0 = SimPEG.Solver(reg.modelObj2Deriv()) + opt.bfgsH0 = SimPEG.Solver(objFunc.reg.modelObj2Deriv()) @property @@ -63,75 +62,17 @@ class BaseInversion(object): Runs the inversion! """ - self.startup(m0) - while True: - self.doStartIteration() - self.m = self.opt.minimize(self.evalFunction, self.m) - self.doEndIteration() - if self.stoppingCriteria(): break - - self.printDone() + self.objFunc.startup(m0) + self.m = self.opt.minimize(self.objFunc.evalFunction, m0) self.finish() return self.m - @Utils.callHooks('startup') - def startup(self, m0): - """ - **startup** is called at the start of any new run call. - - :param numpy.ndarray x0: initial x - :rtype: None - :return: None - """ - - if not hasattr(self.reg, '_mref'): - print 'Regularization has not set mref. SimPEG will set it to m0.' - self.reg.mref = m0 - - self.m = m0 - self._iter = 0 - self._beta = None - self.phi_d_last = np.nan - self.phi_m_last = np.nan - - @Utils.callHooks('doStartIteration') - def doStartIteration(self): - """ - **doStartIteration** is called at the end of each run iteration. - - :rtype: None - :return: None - """ - self._beta = self.getBeta() - - - @Utils.callHooks('doEndIteration') - def doEndIteration(self): - """ - **doEndIteration** is called at the end of each run iteration. - - :rtype: None - :return: None - """ - # store old values - self.phi_d_last = self.phi_d - self.phi_m_last = self.phi_m - self._iter += 1 - - def stoppingCriteria(self): if self.debug: print 'checking stoppingCriteria' return Utils.checkStoppers(self, self.stoppers) - def printDone(self): - """ - **printDone** is called at the end of the inversion routine. - - """ - Utils.printStoppers(self, self.stoppers) - @Utils.callHooks('finish') def finish(self): """finish() diff --git a/SimPEG/ObjFunction.py b/SimPEG/ObjFunction.py index 38323cd3..c9578c54 100644 --- a/SimPEG/ObjFunction.py +++ b/SimPEG/ObjFunction.py @@ -1,16 +1,16 @@ -from SimPEG import Utils +from SimPEG import Utils, np, sp class BaseObjFunction(object): """docstring for BaseObjFunction""" __metaclass__ = Utils.Save.Savable - beta = None #: Regularization trade-off parameter + beta = None #: Regularization trade-off parameter + debug = False #: Print debugging information + counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things name = 'BaseObjFunction' #: Name of the objective function - counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things - u_current = None #: The most current evaluated field m_current = None #: The most current model @@ -31,6 +31,24 @@ class BaseObjFunction(object): self.data = data self.reg = reg + + @Utils.callHooks('startup') + def startup(self, m0): + """startup(m0) + + Called when inversion is first starting. + """ + if self.debug: print 'Calling ObjFunction.startup' + + if not hasattr(self.reg, '_mref'): + print 'Regularization has not set mref. SimPEG will set it to m0.' + self.reg.mref = m0 + + self.phi_d = np.nan + self.phi_m = np.nan + + self.m_current = m0 + @Utils.timeIt def evalFunction(self, m, return_g=True, return_H=True): """evalFunction(m, return_g=True, return_H=True) @@ -42,15 +60,15 @@ class BaseObjFunction(object): u = self.data.prob.field(m) self.u_current = u - if self._iter is 0 and self._beta is None: - self._beta = self.beta0 = self.estimateBeta0(u=u,ratio=self.beta0_ratio) - phi_d = self.dataObj(m, u=u) phi_m = self.reg.modelObj(m) self.dpred = self.data.dpred(m, u=u) # This is a cheap matrix vector calculation. - self.phi_d = phi_d - self.phi_m = phi_m + + self.phi_d, self.phi_d_last = phi_d, self.phi_d + self.phi_m, self.phi_m_last = phi_m, self.phi_m + + self._beta = self.beta.get() #TODO: This needs to be fixed. f = phi_d + self._beta * phi_m @@ -195,25 +213,28 @@ class BetaSchedule(Utils.Parameter): beta = None #: Beta parameter - def __init__(self, **kwargs): + def __init__(self, *args, **kwargs): + Utils.Parameter.__init__(self, *args, **kwargs) Utils.setKwargs(self, **kwargs) def initialize(self): self.beta = self.beta0 @Utils.requires('parent') - def get(self): + def nextIter(self): if self.beta is 'guess': + if self.debug: print 'BetaSchedule is estimating Beta0.' self.beta = self.estimateBeta0() - invesion = self.parent.parent - if inversion._iter > 0 and inversion._iter % self.coolingRate == 0: + opt = self.parent.parent.opt + if opt._iter > 0 and opt._iter % self.coolingRate == 0: + if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % opt._iter self.beta /= self.coolingFactor return self.beta @Utils.requires('parent') - def estimateBeta0(self, u=None): + def estimateBeta0(self): """estimateBeta0(u=None) The initial beta is calculated by comparing the estimated @@ -246,10 +267,11 @@ class BetaSchedule(Utils.Parameter): :rtype: float :return: beta0 """ - objFunc = + objFunc = self.parent data = objFunc.data - m = invesion.m + m = objFunc.m_current + u = objFunc.u_current if u is None: u = data.prob.field(m) diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 3157b5c1..afb2b2a2 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -71,9 +71,9 @@ class IterationPrinters(object): bSet = {"title": "bSet", "value": lambda M: np.sum(M.bindingSet(M.xc)), "width": 8, "format": "%d"} comment = {"title": "Comment", "value": lambda M: M.comment, "width": 12, "format": "%s"} - beta = {"title": "beta", "value": lambda M: M.parent._beta, "width": 10, "format": "%1.2e"} - phi_d = {"title": "phi_d", "value": lambda M: M.parent.phi_d, "width": 10, "format": "%1.2e"} - phi_m = {"title": "phi_m", "value": lambda M: M.parent.phi_m, "width": 10, "format": "%1.2e"} + beta = {"title": "beta", "value": lambda M: M.parent.objFunc.beta.get(), "width": 10, "format": "%1.2e"} + phi_d = {"title": "phi_d", "value": lambda M: M.parent.objFunc.phi_d, "width": 10, "format": "%1.2e"} + phi_m = {"title": "phi_m", "value": lambda M: M.parent.objFunc.phi_m, "width": 10, "format": "%1.2e"} class Minimize(object): diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index ab520ab4..f35ee5a0 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -270,7 +270,10 @@ def timeIt(f): class Parameter(object): """Parameter""" - debug = False #: Print debugging information + debug = False #: Print debugging information + + current = None #: This hold + currentIter = 0 def __init__(self, *args, **kwargs): pass @@ -285,10 +288,21 @@ class Parameter(object): print 'Parameter has switched to a new parent!' self._parent = p + @property + def opt(self): + return self.parent.parent.opt + def initialize(self): pass def get(self): + if (self.current is None or + not self.opt._iter == self.currentIter): + self.current = self.nextIter() + self.currentIter = self.opt._iter + return self.current + + def nextIter(self): raise NotImplementedError('Getting the Parameter is not yet implemented.') From 583f3ed8d0bc709b353e2b7c65df5ae762afbf2b Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 19 Jan 2014 11:51:15 -0700 Subject: [PATCH 16/28] Added ParameterProperty, which handles the logic for calling the parameter each iteration of the optimization. --- SimPEG/ObjFunction.py | 11 +++++------ SimPEG/Optimization.py | 2 +- SimPEG/Utils/__init__.py | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/SimPEG/ObjFunction.py b/SimPEG/ObjFunction.py index c9578c54..d88d5740 100644 --- a/SimPEG/ObjFunction.py +++ b/SimPEG/ObjFunction.py @@ -5,7 +5,8 @@ class BaseObjFunction(object): __metaclass__ = Utils.Save.Savable - beta = None #: Regularization trade-off parameter + beta = Utils.ParameterProperty('beta', default=None, doc='Regularization trade-off parameter') + debug = False #: Print debugging information counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things @@ -68,16 +69,14 @@ class BaseObjFunction(object): self.phi_d, self.phi_d_last = phi_d, self.phi_d self.phi_m, self.phi_m_last = phi_m, self.phi_m - self._beta = self.beta.get() #TODO: This needs to be fixed. - - f = phi_d + self._beta * phi_m + f = phi_d + self.beta * phi_m out = (f,) if return_g: phi_dDeriv = self.dataObjDeriv(m, u=u) phi_mDeriv = self.reg.modelObjDeriv(m) - g = phi_dDeriv + self._beta * phi_mDeriv + g = phi_dDeriv + self.beta * phi_mDeriv out += (g,) if return_H: @@ -85,7 +84,7 @@ class BaseObjFunction(object): phi_d2Deriv = self.dataObj2Deriv(m, v, u=u) phi_m2Deriv = self.reg.modelObj2Deriv()*v - return phi_d2Deriv + self._beta * phi_m2Deriv + return phi_d2Deriv + self.beta * phi_m2Deriv operator = sp.linalg.LinearOperator( (m.size, m.size), H_fun, dtype=m.dtype ) out += (operator,) diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index afb2b2a2..35b71160 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -71,7 +71,7 @@ class IterationPrinters(object): bSet = {"title": "bSet", "value": lambda M: np.sum(M.bindingSet(M.xc)), "width": 8, "format": "%d"} comment = {"title": "Comment", "value": lambda M: M.comment, "width": 12, "format": "%s"} - beta = {"title": "beta", "value": lambda M: M.parent.objFunc.beta.get(), "width": 10, "format": "%1.2e"} + beta = {"title": "beta", "value": lambda M: M.parent.objFunc.beta, "width": 10, "format": "%1.2e"} phi_d = {"title": "phi_d", "value": lambda M: M.parent.objFunc.phi_d, "width": 10, "format": "%1.2e"} phi_m = {"title": "phi_m", "value": lambda M: M.parent.objFunc.phi_m, "width": 10, "format": "%1.2e"} diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index f35ee5a0..8c0f899b 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -284,14 +284,32 @@ class Parameter(object): return getattr(self,'_parent',None) @parent.setter def parent(self, p): + startupName = '_startup_paramProperty_'+self._propertyName if getattr(self,'_parent',None) is not None: - print 'Parameter has switched to a new parent!' + delattr(self._parent,startupName) + print 'Warning: Parameter %s has switched to a new parent.' % self._propertyName + if self.debug: print '%s function has been deleted' % startupName self._parent = p + prop = self + def _startup_paramProperty(self, *args): + if prop.debug: print 'initializing %s' % prop._propertyName + prop.initialize() + + hook(self._parent, _startup_paramProperty, name=startupName, overwrite=True) + @property def opt(self): return self.parent.parent.opt + @property + def objFunc(self): + return self.parent + + @property + def reg(self): + return self.parent.reg + def initialize(self): pass @@ -306,6 +324,20 @@ class Parameter(object): raise NotImplementedError('Getting the Parameter is not yet implemented.') +def ParameterProperty(name, default=None, doc=""): + def getter(self): + out = getattr(self,'_'+name,default) + if isinstance(out, Parameter): + out = out.get() + return out + def setter(self, value): + if isinstance(value, Parameter): + value._propertyName = name + value.parent = self + setattr(self, '_'+name, value) + + return property(fget=getter, fset=setter, doc=doc) + if __name__ == '__main__': class MyClass(object): From 25d79d36367479ab3223a93197d396e0563b8026 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 19 Jan 2014 13:39:50 -0700 Subject: [PATCH 17/28] Clean Up Documentation --- SimPEG/Mesh/BaseMesh.py | 34 +- SimPEG/Mesh/LogicallyOrthogonalMesh.py | 7 +- SimPEG/Mesh/LomView.py | 15 +- SimPEG/Mesh/TensorMesh.py | 8 +- SimPEG/Mesh/TensorView.py | 37 +- SimPEG/Tests/TestUtils.py | 8 +- SimPEG/Tests/runTests.py | 57 - SimPEG/Tests/runTests.sh | 3 - SimPEG/Utils/meshutils.py | 4 +- docs/api_BaseMesh.rst | 2 +- docs/api_Cyl1DMesh.rst | 4 +- docs/api_DiffOperators.rst | 2 +- docs/api_InnerProducts.rst | 2 +- docs/api_LogicallyOrthogonalMesh.rst | 10 +- docs/api_Optimize.rst | 23 +- docs/api_Problem.rst | 6 +- docs/api_TensorMesh.rst | 9 +- docs/api_TestResults.rst | 3994 ----------------- docs/api_Tests.rst | 2 +- docs/api_Utils.rst | 16 +- .../mesh/plot_LogicallyOrthogonalMesh.py | 7 - docs/examples/mesh/plot_grid_2D.py | 11 - docs/examples/mesh/plot_grid_3D.py | 12 - docs/examples/mesh/plot_image_2D.py | 11 - docs/examples/mesh/plot_image_3D.py | 12 - docs/examples/mesh/plot_nodes.py | 13 - docs/index.rst | 16 +- 27 files changed, 109 insertions(+), 4216 deletions(-) delete mode 100644 SimPEG/Tests/runTests.py delete mode 100644 SimPEG/Tests/runTests.sh delete mode 100644 docs/api_TestResults.rst delete mode 100644 docs/examples/mesh/plot_LogicallyOrthogonalMesh.py delete mode 100644 docs/examples/mesh/plot_grid_2D.py delete mode 100644 docs/examples/mesh/plot_grid_3D.py delete mode 100644 docs/examples/mesh/plot_image_2D.py delete mode 100644 docs/examples/mesh/plot_image_3D.py delete mode 100644 docs/examples/mesh/plot_nodes.py diff --git a/SimPEG/Mesh/BaseMesh.py b/SimPEG/Mesh/BaseMesh.py index 7b656697..672b5c02 100644 --- a/SimPEG/Mesh/BaseMesh.py +++ b/SimPEG/Mesh/BaseMesh.py @@ -147,16 +147,6 @@ class BaseMesh(object): else: return switchKernal(x) - # def n(): - # doc = """ - # Number of Cells in each dimension (array of integers) - - # :rtype: numpy.array - # :return: n - # """ - # fget = lambda self: self._n - # return locals() - # n = property(**n()) def dim(): doc = """ @@ -219,10 +209,10 @@ class BaseMesh(object): :return: nC .. plot:: + :include-source: - from SimPEG.mesh import TensorMesh - import numpy as np - TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(centers=True,showIt=True) + from SimPEG import Mesh, np + Mesh.TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(centers=True,showIt=True) """ fget = lambda self: np.prod(self._n) return locals() @@ -290,10 +280,10 @@ class BaseMesh(object): :return: nN .. plot:: + :include-source: - from SimPEG.mesh import TensorMesh - import numpy as np - TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(nodes=True,showIt=True) + from SimPEG import Mesh, np + Mesh.TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(nodes=True,showIt=True) """ fget = lambda self: np.prod(self.nCv + 1) return locals() @@ -361,10 +351,10 @@ class BaseMesh(object): :return: [prod(nEx), prod(nEy), prod(nEz)] .. plot:: + :include-source: - from SimPEG.mesh import TensorMesh - import numpy as np - TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(edges=True,showIt=True) + from SimPEG import Mesh, np + Mesh.TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(edges=True,showIt=True) """ fget = lambda self: np.array([np.prod(x) for x in [self.nEx, self.nEy, self.nEz] if not x is None]) return locals() @@ -433,10 +423,10 @@ class BaseMesh(object): :return: [prod(nFx), prod(nFy), prod(nFz)] .. plot:: + :include-source: - from SimPEG.mesh import TensorMesh - import numpy as np - TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(faces=True,showIt=True) + from SimPEG import Mesh, np + Mesh.TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(faces=True,showIt=True) """ fget = lambda self: np.array([np.prod(x) for x in [self.nFx, self.nFy, self.nFz] if not x is None]) return locals() diff --git a/SimPEG/Mesh/LogicallyOrthogonalMesh.py b/SimPEG/Mesh/LogicallyOrthogonalMesh.py index dca59026..e39c0f54 100644 --- a/SimPEG/Mesh/LogicallyOrthogonalMesh.py +++ b/SimPEG/Mesh/LogicallyOrthogonalMesh.py @@ -17,8 +17,13 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): Example of a logically orthogonal mesh: - .. plot:: examples/mesh/plot_LogicallyOrthogonalMesh.py + .. plot:: + :include-source: + from SimPEG import Mesh, Utils + X, Y = Utils.exampleLomGird([3,3],'rotate') + M = Mesh.LogicallyOrthogonalMesh([X, Y]) + M.plotGrid(showIt=True) """ __metaclass__ = Utils.Save.Savable diff --git a/SimPEG/Mesh/LomView.py b/SimPEG/Mesh/LomView.py index 8243a248..4eceb918 100644 --- a/SimPEG/Mesh/LomView.py +++ b/SimPEG/Mesh/LomView.py @@ -15,10 +15,18 @@ class LomView(object): def __init__(self): pass - def plotGrid(self, length=0.05): + def plotGrid(self, length=0.05, showIt=False): """Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions. - .. plot:: examples/mesh/plot_LogicallyOrthogonalMesh.py + + .. plot:: + :include-source: + + from SimPEG import Mesh, Utils + X, Y = Utils.exampleLomGird([3,3],'rotate') + M = Mesh.LogicallyOrthogonalMesh([X, Y]) + M.plotGrid(showIt=True) + """ NN = self.r(self.gridN, 'N', 'N', 'M') if self.dim == 2: @@ -92,4 +100,5 @@ class LomView(object): ax.hold(False) ax.set_xlabel('x1') ax.set_ylabel('x2') - fig.show() + + if showIt: plt.show() diff --git a/SimPEG/Mesh/TensorMesh.py b/SimPEG/Mesh/TensorMesh.py index 441cb234..341cfba7 100644 --- a/SimPEG/Mesh/TensorMesh.py +++ b/SimPEG/Mesh/TensorMesh.py @@ -17,19 +17,19 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): hy = np.array([1,2]) hz = np.array([1,1,1,1]) - mesh = TensorMesh([hx, hy, hz]) + mesh = Mesh.TensorMesh([hx, hy, hz]) Example of a padded tensor mesh: .. plot:: - from SimPEG import mesh, Utils - M = mesh.TensorMesh(Utils.meshTensors(((10,10),(40,10),(10,10)), ((10,10),(20,10),(0,0)))) + from SimPEG import Mesh, Utils + M = Mesh.TensorMesh(Utils.meshTensors(((10,10),(40,10),(10,10)), ((10,10),(20,10),(0,0)))) M.plotGrid() For a quick tensor mesh on a (10x12x15) unit cube:: - mesh = TensorMesh([10, 12, 15]) + mesh = Mesh.TensorMesh([10, 12, 15]) """ diff --git a/SimPEG/Mesh/TensorView.py b/SimPEG/Mesh/TensorView.py index 7f1cb5e5..7446aecd 100644 --- a/SimPEG/Mesh/TensorView.py +++ b/SimPEG/Mesh/TensorView.py @@ -34,11 +34,22 @@ class TensorView(object): :param str annotationColor: color of annotation, e.g. 'w', 'k', 'b' :param bool showIt: call plt.show() - .. plot:: examples/mesh/plot_image_2D.py - :include-source: + .. plot:: + :include-source: + + from SimPEG import Mesh, np + M = Mesh.TensorMesh([20, 20]) + I = np.sin(M.gridCC[:,0]*2*np.pi)*np.sin(M.gridCC[:,1]*2*np.pi) + M.plotImage(I, showIt=True) + + .. plot:: + :include-source: + + from SimPEG import Mesh, np + M = Mesh.TensorMesh([20,20,20]) + I = np.sin(M.gridCC[:,0]*2*np.pi)*np.sin(M.gridCC[:,1]*2*np.pi)*np.sin(M.gridCC[:,2]*2*np.pi) + M.plotImage(I, annotationColor='k', showIt=True) - .. plot:: examples/mesh/plot_image_3D.py - :include-source: """ assert type(I) == np.ndarray, "I must be a numpy array" assert type(numbering) == bool, "numbering must be a bool" @@ -237,11 +248,25 @@ class TensorView(object): :param bool lines: plot lines connecting nodes :param bool showIt: call plt.show() - .. plot:: examples/mesh/plot_grid_2D.py + .. plot:: :include-source: - .. plot:: examples/mesh/plot_grid_3D.py + from SimPEG import Mesh, np + h1 = np.linspace(.1,.5,3) + h2 = np.linspace(.1,.5,5) + mesh = Mesh.TensorMesh([h1, h2]) + mesh.plotGrid(nodes=True, faces=True, centers=True, lines=True, showIt=True) + + .. plot:: :include-source: + + from SimPEG import Mesh, np + h1 = np.linspace(.1,.5,3) + h2 = np.linspace(.1,.5,5) + h3 = np.linspace(.1,.5,3) + mesh = Mesh.TensorMesh([h1,h2,h3]) + mesh.plotGrid(nodes=True, faces=True, centers=True, lines=True, showIt=True) + """ if self.dim == 1: fig = plt.figure(1) diff --git a/SimPEG/Tests/TestUtils.py b/SimPEG/Tests/TestUtils.py index c5490f90..d84408d4 100644 --- a/SimPEG/Tests/TestUtils.py +++ b/SimPEG/Tests/TestUtils.py @@ -211,12 +211,10 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole .. plot:: :include-source: - from SimPEG.tests import checkDerivative - from SimPEG.Utils import sdiag - import numpy as np + from SimPEG import Tests, Utils, np def simplePass(x): - return np.sin(x), sdiag(np.cos(x)) - checkDerivative(simplePass, np.random.randn(5)) + return np.sin(x), Utils.sdiag(np.cos(x)) + Tests.checkDerivative(simplePass, np.random.randn(5)) """ print "%s checkDerivative %s" % ('='*20, '='*20) diff --git a/SimPEG/Tests/runTests.py b/SimPEG/Tests/runTests.py deleted file mode 100644 index 58d94303..00000000 --- a/SimPEG/Tests/runTests.py +++ /dev/null @@ -1,57 +0,0 @@ -import os -import glob -import unittest -import HTMLTestRunner - -# This code will run all tests in directory named test_*.py -def main(html=False): - TITLE = 'Test Results' - test_file_strings = glob.glob('test_*.py') - module_strings = [str[0:len(str)-3] for str in test_file_strings] - suites = [unittest.defaultTestLoader.loadTestsFromName(str) for str - in module_strings] - testSuite = unittest.TestSuite(suites) - - if not html: - unittest.TextTestRunner(verbosity=2).run(testSuite) - return - - - outfile = open("report.html", "w") - runner = HTMLTestRunner.HTMLTestRunner( - stream=outfile, - title=TITLE, - description='SimPEG Test Report was automatically generated.', - verbosity=2 - ) - - runner.run(testSuite) - outfile.close() - - reader = open("report.html", "r") - writer = open("../../docs/api_TestResults.rst", "w") - - writer.write('.. _api_TestResults:\n\nTest Results\n============\n\n.. raw:: html\n\n') - - go = False - for line in reader: - skip = False - if line == ' - - - -
-

Start Time: 2013-11-26 20:46:38

-

Duration: 0:00:31.569170

-

Status: Pass 124

- -

SimPEG Test Report was automatically generated.

-
- - - -

Show - Summary - Failed - All -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Test Group/Test caseCountPassFailErrorView
test_basemesh.TestBaseMesh111100Detail
test_meshDimensions
pass
test_mesh_nc
pass
test_mesh_nc_xyz
pass
test_mesh_ne
pass
test_mesh_nf
pass
test_mesh_numbers
pass
test_mesh_r_CC_M
pass
test_mesh_r_E_M
pass
test_mesh_r_E_V
pass
test_mesh_r_F_M
pass
test_mesh_r_F_V
pass
test_basemesh.TestMeshNumbers2D111100Detail
test_meshDimensions
pass
test_mesh_nc
pass
test_mesh_nc_xyz
pass
test_mesh_ne
pass
test_mesh_nf
pass
test_mesh_numbers
pass
test_mesh_r_CC_M
pass
test_mesh_r_E_M
pass
test_mesh_r_E_V
pass
test_mesh_r_F_M
pass
test_mesh_r_F_V
pass
test_forward_DCproblem.DCProblemTests4400Detail
test_adjoint
pass
test_dataObj
- - - - pass - - - - -
test_misfit
- - - - pass - - - - -
test_modelObj
- - - - pass - - - - -
test_forward_problem.ProblemTests2200Detail
test_modelTransform
- - - - pass - - - - -
test_regularization
- - - - pass - - - - -
test_interpolation.TestInterpolation1D2200Detail
test_orderCC
- - - - pass - - - - -
test_orderN
- - - - pass - - - - -
test_interpolation.TestInterpolation2d6600Detail
test_orderCC
- - - - pass - - - - -
test_orderEx
- - - - pass - - - - -
test_orderEy
- - - - pass - - - - -
test_orderFx
- - - - pass - - - - -
test_orderFy
- - - - pass - - - - -
test_orderN
- - - - pass - - - - -
test_interpolation.TestInterpolation3D8800Detail
test_orderCC
- - - - pass - - - - -
test_orderEx
- - - - pass - - - - -
test_orderEy
- - - - pass - - - - -
test_orderEz
- - - - pass - - - - -
test_orderFx
- - - - pass - - - - -
test_orderFy
- - - - pass - - - - -
test_orderFz
- - - - pass - - - - -
test_orderN
- - - - pass - - - - -
test_LogicallyOrthogonalMesh.BasicLOMTests8800Detail
test_area_3D
pass
test_edge_2D
pass
test_edge_3D
pass
test_grid
pass
test_normals
pass
test_tangents
pass
test_vol_2D
pass
test_vol_3D
pass
test_massMatrices.TestInnerProducts: Integrate an function over a unit cube domain using edgeInnerProducts and faceInnerProducts.6600Detail
test_order1_edges
- - - - pass - - - - -
test_order1_faces
- - - - pass - - - - -
test_order3_edges
- - - - pass - - - - -
test_order3_faces
- - - - pass - - - - -
test_order6_edges
- - - - pass - - - - -
test_order6_faces
- - - - pass - - - - -
test_massMatrices.TestInnerProducts2D: Integrate an function over a unit cube domain using edgeInnerProducts and faceInnerProducts.6600Detail
test_order1_edges
- - - - pass - - - - -
test_order1_faces
- - - - pass - - - - -
test_order2_faces
- - - - pass - - - - -
test_order3_edges
- - - - pass - - - - -
test_order3_faces
- - - - pass - - - - -
test_order6_edges
- - - - pass - - - - -
test_operators.TestAveraging2D6600Detail
test_orderCC2F
- - - - pass - - - - -
test_orderE2CC
- - - - pass - - - - -
test_orderF2CC
- - - - pass - - - - -
test_orderN2CC
- - - - pass - - - - -
test_orderN2E
- - - - pass - - - - -
test_orderN2F
- - - - pass - - - - -
test_operators.TestAveraging3D6600Detail
test_orderCC2F
- - - - pass - - - - -
test_orderE2CC
- - - - pass - - - - -
test_orderF2CC
- - - - pass - - - - -
test_orderN2CC
- - - - pass - - - - -
test_orderN2E
- - - - pass - - - - -
test_orderN2F
- - - - pass - - - - -
test_operators.TestCellGrad1D_InhomogeneousDirichlet1100Detail
test_order
- - - - pass - - - - -
test_operators.TestCellGrad2D_Dirichlet1100Detail
test_order
- - - - pass - - - - -
test_operators.TestCellGrad2D_Neumann1100Detail
test_order
- - - - pass - - - - -
test_operators.TestCellGrad3D_Dirichlet1100Detail
test_order
- - - - pass - - - - -
test_operators.TestCellGrad3D_Neumann1100Detail
test_order
- - - - pass - - - - -
test_operators.TestCurl1100Detail
test_order
- - - - pass - - - - -
test_operators.TestFaceDiv2D1100Detail
test_order
- - - - pass - - - - -
test_operators.TestFaceDiv3D1100Detail
test_order
- - - - pass - - - - -
test_operators.TestNodalGrad1100Detail
test_order
- - - - pass - - - - -
test_operators.TestNodalGrad2D1100Detail
test_order
- - - - pass - - - - -
test_optimizers.TestOptimizers4400Detail
test_GN_Rosenbrock
- - - - pass - - - - -
test_GN_quadratic
- - - - pass - - - - -
test_ProjGradient_quadratic1Bound
- - - - pass - - - - -
test_ProjGradient_quadraticBounded
- - - - pass - - - - -
test_Solver.TestSolver141400Detail
test_directDiagonal_1
pass
test_directDiagonal_M
pass
test_directFactored_1
pass
test_directFactored_M
pass
test_directLower_1_fortran
pass
test_directLower_1_python
pass
test_directLower_M_fortran
pass
test_directLower_M_python
pass
test_directSpsolve_1
pass
test_directSpsolve_M
pass
test_directUpper_1_fortran
pass
test_directUpper_1_python
pass
test_directUpper_M_fortran
pass
test_directUpper_M_python
pass
test_tensorMesh.BasicTensorMeshTests7700Detail
test_area_3D
pass
test_edge_2D
pass
test_edge_3D
pass
test_vectorCC_2D
pass
test_vectorN_2D
pass
test_vol_2D
pass
test_vol_3D
pass
test_tensorMesh.TestPoissonEqn2200Detail
test_orderBackward
- - - - pass - - - - -
test_orderForward
- - - - pass - - - - -
test_utils.TestCheckDerivative3300Detail
test_simpleFail
- - - - pass - - - - -
test_simpleFunction
- - - - pass - - - - -
test_simplePass
- - - - pass - - - - -
test_utils.TestSequenceFunctions8800Detail
test_indexCube_2D
pass
test_indexCube_3D
pass
test_invXXXBlockDiagonal
pass
test_mkvc1
pass
test_mkvc2
pass
test_mkvc3
pass
test_ndgrid_2D
pass
test_ndgrid_3D
pass
Total12412400 
- diff --git a/docs/api_Tests.rst b/docs/api_Tests.rst index 164f5b5d..0ab45c51 100644 --- a/docs/api_Tests.rst +++ b/docs/api_Tests.rst @@ -3,6 +3,6 @@ Testing SimPEG ************** -.. automodule:: SimPEG.tests.TestUtils +.. automodule:: SimPEG.Tests.TestUtils :members: :undoc-members: diff --git a/docs/api_Utils.rst b/docs/api_Utils.rst index 7960b3e1..9c40cabe 100644 --- a/docs/api_Utils.rst +++ b/docs/api_Utils.rst @@ -4,7 +4,7 @@ Solver ****** -.. automodule:: SimPEG.utils.Solver +.. automodule:: SimPEG.Solver :members: :undoc-members: @@ -12,49 +12,49 @@ Solver Utilities ********* -.. automodule:: SimPEG.utils +.. automodule:: SimPEG.Utils :members: :undoc-members: Matrix Utilities **************** -.. automodule:: SimPEG.utils.matutils +.. automodule:: SimPEG.Utils.matutils :members: :undoc-members: Sparse Utilities **************** -.. automodule:: SimPEG.utils.sputils +.. automodule:: SimPEG.Utils.sputils :members: :undoc-members: LOM Utilities ************* -.. automodule:: SimPEG.utils.lomutils +.. automodule:: SimPEG.Utils.lomutils :members: :undoc-members: Mesh Utilities ************** -.. automodule:: SimPEG.utils.meshutils +.. automodule:: SimPEG.Utils.meshutils :members: :undoc-members: Model Builder Utilities *********************** -.. automodule:: SimPEG.utils.ModelBuilder +.. automodule:: SimPEG.Utils.ModelBuilder :members: :undoc-members: Interpolation Utilities *********************** -.. automodule:: SimPEG.utils.interputils +.. automodule:: SimPEG.Utils.interputils :members: :undoc-members: diff --git a/docs/examples/mesh/plot_LogicallyOrthogonalMesh.py b/docs/examples/mesh/plot_LogicallyOrthogonalMesh.py deleted file mode 100644 index bb49ae9a..00000000 --- a/docs/examples/mesh/plot_LogicallyOrthogonalMesh.py +++ /dev/null @@ -1,7 +0,0 @@ -from SimPEG.mesh import LogicallyOrthogonalMesh -from SimPEG import utils -import matplotlib.pyplot as plt -X, Y = utils.exampleLomGird([3,3],'rotate') -M = LogicallyOrthogonalMesh([X, Y]) -M.plotGrid() -plt.show() diff --git a/docs/examples/mesh/plot_grid_2D.py b/docs/examples/mesh/plot_grid_2D.py deleted file mode 100644 index 4c6d5da5..00000000 --- a/docs/examples/mesh/plot_grid_2D.py +++ /dev/null @@ -1,11 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from SimPEG.mesh import TensorMesh - -h1 = np.linspace(.1,.5,3) -h2 = np.linspace(.1,.5,5) -mesh = TensorMesh([h1, h2]) -mesh.plotGrid(nodes=True, faces=True, centers=True, lines=True) - -plt.show() - diff --git a/docs/examples/mesh/plot_grid_3D.py b/docs/examples/mesh/plot_grid_3D.py deleted file mode 100644 index 6278802c..00000000 --- a/docs/examples/mesh/plot_grid_3D.py +++ /dev/null @@ -1,12 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from SimPEG.mesh import TensorMesh - -h1 = np.linspace(.1,.5,3) -h2 = np.linspace(.1,.5,5) -h3 = np.linspace(.1,.5,3) -mesh = TensorMesh([h1,h2,h3]) -mesh.plotGrid(nodes=True, faces=True, centers=True, lines=True) - -plt.show() - diff --git a/docs/examples/mesh/plot_image_2D.py b/docs/examples/mesh/plot_image_2D.py deleted file mode 100644 index 9fef3f1b..00000000 --- a/docs/examples/mesh/plot_image_2D.py +++ /dev/null @@ -1,11 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from SimPEG.mesh import TensorMesh - -n = 20 -h = np.ones(n)/n -M = TensorMesh([h, h]) -I = np.sin(M.gridCC[:,0]*2*np.pi)*np.sin(M.gridCC[:,1]*2*np.pi) -M.plotImage(I) - -plt.show() diff --git a/docs/examples/mesh/plot_image_3D.py b/docs/examples/mesh/plot_image_3D.py deleted file mode 100644 index c67b0d84..00000000 --- a/docs/examples/mesh/plot_image_3D.py +++ /dev/null @@ -1,12 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from SimPEG.mesh import TensorMesh - -n = 20 -h = np.ones(n)/n -M = TensorMesh([h,h,h]) - -I = np.sin(M.gridCC[:,0]*2*np.pi)*np.sin(M.gridCC[:,1]*2*np.pi)*np.sin(M.gridCC[:,2]*2*np.pi) -M.plotImage(I, annotationColor='k') - -plt.show() diff --git a/docs/examples/mesh/plot_nodes.py b/docs/examples/mesh/plot_nodes.py deleted file mode 100644 index ef11b351..00000000 --- a/docs/examples/mesh/plot_nodes.py +++ /dev/null @@ -1,13 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from SimPEG.mesh import TensorMesh - -x0 = np.zeros(2) -h1 = np.linspace(.1,.5,3) -h2 = np.linspace(.1,.5,5) -M = TensorMesh([h1,h2],x0) -M.plotGrid() -plt.hold() -plt.plot(M.gridN[:,0], M.gridN[:,1], 'ks', markersize=10) -plt.show() - diff --git a/docs/index.rst b/docs/index.rst index b2b9806f..62fd3239 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -64,16 +64,16 @@ Build Results ============= * Master Branch -.. image:: https://travis-ci.org/simpeg/simpeg.png?branch=master - :target: https://travis-ci.org/simpeg/simpeg - :alt: Master Branch - :align: center + .. image:: https://travis-ci.org/simpeg/simpeg.png?branch=master + :target: https://travis-ci.org/simpeg/simpeg + :alt: Master Branch + :align: center * Develop Branch -.. image:: https://travis-ci.org/simpeg/simpeg.png?branch=develop - :target: https://travis-ci.org/simpeg/simpeg - :alt: Develop Branch - :align: center + .. image:: https://travis-ci.org/simpeg/simpeg.png?branch=develop + :target: https://travis-ci.org/simpeg/simpeg + :alt: Develop Branch + :align: center Utility Codes From 1055b613ce581bdd16a1d4cea840e54e60a2be99 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 19 Jan 2014 13:46:42 -0700 Subject: [PATCH 18/28] Removed runTestsHTML, combined build results into testing section. --- SimPEG/Tests/HTMLTestRunner.py | 825 --------------------------------- docs/index.rst | 4 - 2 files changed, 829 deletions(-) delete mode 100644 SimPEG/Tests/HTMLTestRunner.py diff --git a/SimPEG/Tests/HTMLTestRunner.py b/SimPEG/Tests/HTMLTestRunner.py deleted file mode 100644 index 05ae09df..00000000 --- a/SimPEG/Tests/HTMLTestRunner.py +++ /dev/null @@ -1,825 +0,0 @@ -""" -A TestRunner for use with the Python unit testing framework. It -generates a HTML report to show the result at a glance. - -The simplest way to use this is to invoke its main method. E.g. - - import unittest - import HTMLTestRunner - - ... define your tests ... - - if __name__ == '__main__': - HTMLTestRunner.main() - - -For more customization options, instantiates a HTMLTestRunner object. -HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g. - - # output to a file - fp = file('my_report.html', 'wb') - runner = HTMLTestRunner.HTMLTestRunner( - stream=fp, - title='My unit test', - description='This demonstrates the report output by HTMLTestRunner.' - ) - - # Use an external stylesheet. - # See the Template_mixin class for more customizable options - runner.STYLESHEET_TMPL = '' - - # run the test - runner.run(my_test_suite) - - ------------------------------------------------------------------------- -Copyright (c) 2004-2007, Wai Yip Tung -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -* Neither the name Wai Yip Tung nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" - -# URL: http://tungwaiyip.info/software/HTMLTestRunner.html - -__author__ = "Wai Yip Tung" -__version__ = "0.8.2" - - -""" -Change History - -Version 0.8.2 -* Show output inline instead of popup window (Viorel Lupu). - -Version in 0.8.1 -* Validated XHTML (Wolfgang Borgert). -* Added description of test classes and test cases. - -Version in 0.8.0 -* Define Template_mixin class for customization. -* Workaround a IE 6 bug that it does not treat - -%(heading)s -%(report)s -%(ending)s - - - -""" - # variables: (title, generator, stylesheet, heading, report, ending) - - - # ------------------------------------------------------------------------ - # Stylesheet - # - # alternatively use a for external style sheet, e.g. - # - - STYLESHEET_TMPL = """ - -""" - - - - # ------------------------------------------------------------------------ - # Heading - # - - HEADING_TMPL = """
-

%(title)s

-%(parameters)s -

%(description)s

-
- -""" # variables: (title, parameters, description) - - HEADING_ATTRIBUTE_TMPL = """

%(name)s: %(value)s

-""" # variables: (name, value) - - - - # ------------------------------------------------------------------------ - # Report - # - - REPORT_TMPL = """ -

Show -Summary -Failed -All -

- -------- - - - - - - - - -%(test_list)s - - - - - - - - -
Test Group/Test caseCountPassFailErrorView
Total%(count)s%(Pass)s%(fail)s%(error)s 
-""" # variables: (test_list, count, Pass, fail, error) - - REPORT_CLASS_TMPL = r""" - - %(desc)s - %(count)s - %(Pass)s - %(fail)s - %(error)s - Detail - -""" # variables: (style, desc, count, Pass, fail, error, cid) - - - REPORT_TEST_WITH_OUTPUT_TMPL = r""" - -
%(desc)s
- - - - - %(status)s - - - - - - -""" # variables: (tid, Class, style, desc, status) - - - REPORT_TEST_NO_OUTPUT_TMPL = r""" - -
%(desc)s
- %(status)s - -""" # variables: (tid, Class, style, desc, status) - - - REPORT_TEST_OUTPUT_TMPL = r""" -%(id)s: %(output)s -""" # variables: (id, output) - - - - # ------------------------------------------------------------------------ - # ENDING - # - - ENDING_TMPL = """
 
""" - -# -------------------- The end of the Template class ------------------- - - -TestResult = unittest.TestResult - -class _TestResult(TestResult): - # note: _TestResult is a pure representation of results. - # It lacks the output and reporting ability compares to unittest._TextTestResult. - - def __init__(self, verbosity=1): - TestResult.__init__(self) - self.stdout0 = None - self.stderr0 = None - self.success_count = 0 - self.failure_count = 0 - self.error_count = 0 - self.verbosity = verbosity - - # result is a list of result in 4 tuple - # ( - # result code (0: success; 1: fail; 2: error), - # TestCase object, - # Test output (byte string), - # stack trace, - # ) - self.result = [] - - - def startTest(self, test): - TestResult.startTest(self, test) - # just one buffer for both stdout and stderr - self.outputBuffer = StringIO.StringIO() - stdout_redirector.fp = self.outputBuffer - stderr_redirector.fp = self.outputBuffer - self.stdout0 = sys.stdout - self.stderr0 = sys.stderr - sys.stdout = stdout_redirector - sys.stderr = stderr_redirector - - - def complete_output(self): - """ - Disconnect output redirection and return buffer. - Safe to call multiple times. - """ - if self.stdout0: - sys.stdout = self.stdout0 - sys.stderr = self.stderr0 - self.stdout0 = None - self.stderr0 = None - return self.outputBuffer.getvalue() - - - def stopTest(self, test): - # Usually one of addSuccess, addError or addFailure would have been called. - # But there are some path in unittest that would bypass this. - # We must disconnect stdout in stopTest(), which is guaranteed to be called. - self.complete_output() - - - def addSuccess(self, test): - self.success_count += 1 - TestResult.addSuccess(self, test) - output = self.complete_output() - self.result.append((0, test, output, '')) - if self.verbosity > 1: - sys.stderr.write('ok ') - sys.stderr.write(str(test)) - sys.stderr.write('\n') - else: - sys.stderr.write('.') - - def addError(self, test, err): - self.error_count += 1 - TestResult.addError(self, test, err) - _, _exc_str = self.errors[-1] - output = self.complete_output() - self.result.append((2, test, output, _exc_str)) - if self.verbosity > 1: - sys.stderr.write('E ') - sys.stderr.write(str(test)) - sys.stderr.write('\n') - else: - sys.stderr.write('E') - - def addFailure(self, test, err): - self.failure_count += 1 - TestResult.addFailure(self, test, err) - _, _exc_str = self.failures[-1] - output = self.complete_output() - self.result.append((1, test, output, _exc_str)) - if self.verbosity > 1: - sys.stderr.write('F ') - sys.stderr.write(str(test)) - sys.stderr.write('\n') - else: - sys.stderr.write('F') - - -class HTMLTestRunner(Template_mixin): - """ - """ - def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None): - self.stream = stream - self.verbosity = verbosity - if title is None: - self.title = self.DEFAULT_TITLE - else: - self.title = title - if description is None: - self.description = self.DEFAULT_DESCRIPTION - else: - self.description = description - - self.startTime = datetime.datetime.now() - - - def run(self, test): - "Run the given test case or test suite." - result = _TestResult(self.verbosity) - test(result) - self.stopTime = datetime.datetime.now() - self.generateReport(test, result) - print >>sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime) - return result - - - def sortResult(self, result_list): - # unittest does not seems to run in any particular order. - # Here at least we want to group them together by class. - rmap = {} - classes = [] - for n,t,o,e in result_list: - cls = t.__class__ - if not rmap.has_key(cls): - rmap[cls] = [] - classes.append(cls) - rmap[cls].append((n,t,o,e)) - r = [(cls, rmap[cls]) for cls in classes] - return r - - - def getReportAttributes(self, result): - """ - Return report attributes as a list of (name, value). - Override this to add custom attributes. - """ - startTime = str(self.startTime)[:19] - duration = str(self.stopTime - self.startTime) - status = [] - if result.success_count: status.append('Pass %s' % result.success_count) - if result.failure_count: status.append('Failure %s' % result.failure_count) - if result.error_count: status.append('Error %s' % result.error_count ) - if status: - status = ' '.join(status) - else: - status = 'none' - return [ - ('Start Time', startTime), - ('Duration', duration), - ('Status', status), - ] - - - def generateReport(self, test, result): - report_attrs = self.getReportAttributes(result) - generator = 'HTMLTestRunner %s' % __version__ - stylesheet = self._generate_stylesheet() - heading = self._generate_heading(report_attrs) - report = self._generate_report(result) - ending = self._generate_ending() - output = self.HTML_TMPL % dict( - title = saxutils.escape(self.title), - generator = generator, - stylesheet = stylesheet, - heading = heading, - report = report, - ending = ending, - ) - self.stream.write(output.encode('utf8')) - - - def _generate_stylesheet(self): - return self.STYLESHEET_TMPL - - - def _generate_heading(self, report_attrs): - a_lines = [] - for name, value in report_attrs: - line = self.HEADING_ATTRIBUTE_TMPL % dict( - name = saxutils.escape(name), - value = saxutils.escape(value), - ) - a_lines.append(line) - heading = self.HEADING_TMPL % dict( - title = saxutils.escape(self.title), - parameters = ''.join(a_lines), - description = saxutils.escape(self.description), - ) - return heading - - - def _generate_report(self, result): - rows = [] - sortedResult = self.sortResult(result.result) - for cid, (cls, cls_results) in enumerate(sortedResult): - # subtotal for a class - np = nf = ne = 0 - for n,t,o,e in cls_results: - if n == 0: np += 1 - elif n == 1: nf += 1 - else: ne += 1 - - # format class description - if cls.__module__ == "__main__": - name = cls.__name__ - else: - name = "%s.%s" % (cls.__module__, cls.__name__) - doc = cls.__doc__ and cls.__doc__.split("\n")[0] or "" - desc = doc and '%s: %s' % (name, doc) or name - - row = self.REPORT_CLASS_TMPL % dict( - style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass', - desc = desc, - count = np+nf+ne, - Pass = np, - fail = nf, - error = ne, - cid = 'c%s' % (cid+1), - ) - rows.append(row) - - for tid, (n,t,o,e) in enumerate(cls_results): - self._generate_report_test(rows, cid, tid, n, t, o, e) - - report = self.REPORT_TMPL % dict( - test_list = ''.join(rows), - count = str(result.success_count+result.failure_count+result.error_count), - Pass = str(result.success_count), - fail = str(result.failure_count), - error = str(result.error_count), - ) - return report - - - def _generate_report_test(self, rows, cid, tid, n, t, o, e): - # e.g. 'pt1.1', 'ft1.1', etc - has_output = bool(o or e) - tid = (n == 0 and 'p' or 'f') + 't%s.%s' % (cid+1,tid+1) - name = t.id().split('.')[-1] - doc = t.shortDescription() or "" - desc = doc and ('%s: %s' % (name, doc)) or name - tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL - - # o and e should be byte string because they are collected from stdout and stderr? - if isinstance(o,str): - # TODO: some problem with 'string_escape': it escape \n and mess up formating - # uo = unicode(o.encode('string_escape')) - uo = o.decode('latin-1') - else: - uo = o - if isinstance(e,str): - # TODO: some problem with 'string_escape': it escape \n and mess up formating - # ue = unicode(e.encode('string_escape')) - ue = e.decode('latin-1') - else: - ue = e - - script = self.REPORT_TEST_OUTPUT_TMPL % dict( - id = tid, - output = saxutils.escape(uo+ue), - ) - - row = tmpl % dict( - tid = tid, - Class = (n == 0 and 'hiddenRow' or 'none'), - style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'), - desc = desc, - script = script, - status = self.STATUS[n], - ) - rows.append(row) - if not has_output: - return - - def _generate_ending(self): - return self.ENDING_TMPL - - -############################################################################## -# Facilities for running tests from the command line -############################################################################## - -# Note: Reuse unittest.TestProgram to launch test. In the future we may -# build our own launcher to support more specific command line -# parameters like test title, CSS, etc. -class TestProgram(unittest.TestProgram): - """ - A variation of the unittest.TestProgram. Please refer to the base - class for command line parameters. - """ - def runTests(self): - # Pick HTMLTestRunner as the default test runner. - # base class's testRunner parameter is not useful because it means - # we have to instantiate HTMLTestRunner before we know self.verbosity. - if self.testRunner is None: - self.testRunner = HTMLTestRunner(verbosity=self.verbosity) - unittest.TestProgram.runTests(self) - -main = TestProgram - -############################################################################## -# Executing this module from the command line -############################################################################## - -if __name__ == "__main__": - main(module=None) diff --git a/docs/index.rst b/docs/index.rst index 62fd3239..b2882cf0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -58,10 +58,6 @@ Testing SimPEG :maxdepth: 2 api_Tests - api_TestResults - -Build Results -============= * Master Branch .. image:: https://travis-ci.org/simpeg/simpeg.png?branch=master From 5452f2be4bfb448e76b9efa5925c734db1c940da Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 22 Jan 2014 19:17:15 -0700 Subject: [PATCH 19/28] Regularization is on the Model, so it needs to take that as input. Testing is completed on every SimPEG regularization object by default. --- SimPEG/Model.py | 5 + SimPEG/Regularization.py | 153 ++++++++++++++++------------ SimPEG/Tests/test_problem.py | 26 ----- SimPEG/Tests/test_regularization.py | 30 ++++++ 4 files changed, 125 insertions(+), 89 deletions(-) delete mode 100644 SimPEG/Tests/test_problem.py create mode 100644 SimPEG/Tests/test_regularization.py diff --git a/SimPEG/Model.py b/SimPEG/Model.py index 6eb3c297..8482edde 100644 --- a/SimPEG/Model.py +++ b/SimPEG/Model.py @@ -50,6 +50,11 @@ class BaseModel(object): """ return sp.identity(m.size) + @property + def nP(self): + """Number of parameters in the model.""" + return self.mesh.nC + def example(self, modelType=None): return np.random.rand(self.mesh.nC) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index e592d643..ea6cd753 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,7 +1,93 @@ -from SimPEG import Utils, np, sp +from SimPEG import Utils, Model, np, sp class BaseRegularization(object): - """**Regularization** + """ + **Base Regularization Class** + + This is used to regularize the model space:: + + reg = Regularization(mesh, model) + + """ + + __metaclass__ = Utils.Save.Savable + + modelPair = Model.BaseModel #: Some regularizations only work on specific models + + mesh = None #: A SimPEG.Mesh instance. + model = None #: A SimPEG.Model instance. + + counter = None + + def __init__(self, mesh, model, **kwargs): + Utils.setKwargs(self, **kwargs) + assert isinstance(model, self.modelPair), "Incorrect model for this regularization" + self.mesh = mesh + self.model = model + + @property + def mref(self): + if getattr(self, '_mref', None) is None: + return np.zeros(self.model.nP); + return self._mref + @mref.setter + def mref(self, value): + self._mref = value + + + @property + def W(self): + """Full regularization weighting matrix W.""" + return sp.identity(self.model.nP) + + + @Utils.timeIt + def modelObj(self, m): + r = self.W * (m - self.mref) + return 0.5*r.dot(r) + + @Utils.timeIt + def modelObjDeriv(self, m): + """ + + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} + + So the derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} + + """ + return self.W.T * ( self.W * (m - self.mref) ) + + @Utils.timeIt + def modelObj2Deriv(self): + """ + + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} + + So the second derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top W} + + """ + return self.W.T * self.W + + + +class Tikhonov(BaseRegularization): + """**Tikhonov Regularization** Here we will define regularization of a model, m, in general however, this should be thought of as (m-m_ref) but otherwise it is exactly the same: @@ -83,8 +169,6 @@ class BaseRegularization(object): """ - __metaclass__ = Utils.Save.Savable - alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Ws'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") @@ -93,20 +177,8 @@ class BaseRegularization(object): alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") - counter = None - - def __init__(self, mesh, **kwargs): - Utils.setKwargs(self, **kwargs) - self.mesh = mesh - - @property - def mref(self): - if getattr(self, '_mref', None) is None: - return np.zeros(self.mesh.nC); - return self._mref - @mref.setter - def mref(self, value): - self._mref = value + def __init__(self, mesh, model, **kwargs): + BaseRegularization.__init__(self, mesh, model, **kwargs) @property def Ws(self): @@ -160,7 +232,6 @@ class BaseRegularization(object): self._Wzz = Utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz return self._Wzz - @property def W(self): """Full regularization matrix W""" @@ -173,47 +244,3 @@ class BaseRegularization(object): self._W = sp.vstack(wlist) return self._W - - @Utils.timeIt - def modelObj(self, m): - r = self.W * (m - self.mref) - return 0.5*r.dot(r) - - @Utils.timeIt - def modelObjDeriv(self, m): - """ - - The regularization is: - - .. math:: - - R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} - - So the derivative is straight forward: - - .. math:: - - R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} - - """ - return self.W.T * ( self.W * (m - self.mref) ) - - @Utils.timeIt - def modelObj2Deriv(self): - """ - - The regularization is: - - .. math:: - - R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} - - So the second derivative is straight forward: - - .. math:: - - R(m) = \mathbf{W^\\top W} - - """ - return self.W.T * self.W - diff --git a/SimPEG/Tests/test_problem.py b/SimPEG/Tests/test_problem.py deleted file mode 100644 index e1d30337..00000000 --- a/SimPEG/Tests/test_problem.py +++ /dev/null @@ -1,26 +0,0 @@ -import numpy as np -import unittest -from SimPEG import * -from TestUtils import checkDerivative -from scipy.sparse.linalg import dsolve - - -class ProblemTests(unittest.TestCase): - - def setUp(self): - - a = np.array([1, 1, 1]) - b = np.array([1, 2]) - c = np.array([1, 4]) - self.mesh2 = Mesh.TensorMesh([a, b], np.array([3, 5])) - self.p2 = Problem.BaseProblem(self.mesh2, None) - self.reg = Regularization.BaseRegularization(self.mesh2) - - def test_regularization(self): - derChk = lambda m: [self.reg.modelObj(m), self.reg.modelObjDeriv(m)] - mSynth = np.random.randn(self.mesh2.nC) - checkDerivative(derChk, mSynth, plotIt=False) - - -if __name__ == '__main__': - unittest.main() diff --git a/SimPEG/Tests/test_regularization.py b/SimPEG/Tests/test_regularization.py new file mode 100644 index 00000000..129948e1 --- /dev/null +++ b/SimPEG/Tests/test_regularization.py @@ -0,0 +1,30 @@ +import numpy as np +import unittest +from SimPEG import * +from TestUtils import checkDerivative +from scipy.sparse.linalg import dsolve +import inspect + + +class RegularizationTests(unittest.TestCase): + + def setUp(self): + self.mesh2 = Mesh.TensorMesh([3, 2]) + + def test_regularization(self): + for R in dir(Regularization): + r = getattr(Regularization, R) + if not inspect.isclass(r): continue + if not issubclass(r, Regularization.BaseRegularization): + continue + # if 'Regularization' not in R: continue + print 'Check:', R + model = r.modelPair(self.mesh2) + reg = r(self.mesh2, model) + m = model.example() + passed = checkDerivative(lambda m : [reg.modelObj(m), reg.modelObjDeriv(m)], m, plotIt=False) + self.assertTrue(passed) + + +if __name__ == '__main__': + unittest.main() From 4d9f87807ecd77a083cf874dd8d0a72495b8ac07 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 24 Jan 2014 07:44:52 -0700 Subject: [PATCH 20/28] pair data-problem --- SimPEG/Data.py | 32 +++++++++++++++++++++++++++----- SimPEG/Inversion.py | 1 + SimPEG/Problem.py | 34 +++++++++++++++++++++++++++++----- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/SimPEG/Data.py b/SimPEG/Data.py index 17eebaeb..6c94811a 100644 --- a/SimPEG/Data.py +++ b/SimPEG/Data.py @@ -7,7 +7,6 @@ class BaseData(object): __metaclass__ = Utils.Save.Savable - prob = None #: The geophysical problem that explains this data, use data.setProblem(prob) std = None #: Estimated Standard Deviations dobs = None #: Observed data dtrue = None #: True data, if data is synthetic @@ -18,10 +17,32 @@ class BaseData(object): def __init__(self, **kwargs): Utils.setKwargs(self, **kwargs) - def setProblem(self, prob): - # Bind these two instances together using pointers - self.prob = prob - prob.data = self + @property + def prob(self): + """ + The geophysical problem that explains this data, use:: + + data.setProblem(prob) + """ + return getattr(self, '_prob', None) + + def pair(self, p): + """Bind a problem to this data instance using pointers""" + assert hasattr(p, 'dataPair'), "Problem must have an attribute 'dataPair'." + assert isinstance(self, p.dataPair), "Problem requires data object must be an instance of a %s class."%(p.dataPair.__name__) + if p.ispaired: + raise Exception("The problem object is already paired to a data. Use prob.unpair()") + self._prob = p + p._data = self + + def unpair(self): + """Unbind a problem from this data instance""" + if not self.ispaired: return + self.prob._data = None + self._prob = None + + @property + def ispaired(self): return self.prob is not None @Utils.count @Utils.requires('prob') @@ -117,6 +138,7 @@ class BaseData(object): def RHS(self, value): self._RHS = value + @property def isSynthetic(self): "Check if the data is synthetic." return (self.mtrue is not None) diff --git a/SimPEG/Inversion.py b/SimPEG/Inversion.py index 65abb6eb..0bef2d92 100644 --- a/SimPEG/Inversion.py +++ b/SimPEG/Inversion.py @@ -2,6 +2,7 @@ import SimPEG from SimPEG import Utils, sp, np from Optimization import Remember, IterationPrinters, StoppingCriteria + class BaseInversion(object): """BaseInversion(prob, reg, opt, data, **kwargs) """ diff --git a/SimPEG/Problem.py b/SimPEG/Problem.py index 18f7aba4..501b1c45 100644 --- a/SimPEG/Problem.py +++ b/SimPEG/Problem.py @@ -1,5 +1,6 @@ -from SimPEG import Utils, np, sp, Data -norm = np.linalg.norm +import Utils, Data +import scipy.sparse as sp +import numpy as np class BaseProblem(object): @@ -41,12 +42,35 @@ class BaseProblem(object): dataPair = Data.BaseData - def __init__(self, mesh, model, *args, **kwargs): Utils.setKwargs(self, **kwargs) self.mesh = mesh self.model = model + @property + def data(self): + """ + The data object for this problem. Data + """ + return getattr(self, '_data', None) + + def pair(self, d): + """Bind a data to this problem instance using pointers.""" + assert isinstance(d, self.dataPair), "Data object must be an instance of a %s class."%(self.dataPair.__name__) + if d.ispaired: + raise Exception("The data object is already paired to a problem. Use data.unpair()") + self._data = d + d._prob = self + + def unpair(self): + """Unbind a data from this problem instance.""" + if not self.ispaired: return + self.data._prob = None + self._data = None + + @property + def ispaired(self): return self.data is not None + @Utils.timeIt def J(self, m, v, u=None): """ @@ -143,8 +167,8 @@ class BaseProblem(object): and Wd which is the same size as data, and can be used to weight the inversion. """ data = self.dataPair(mtrue=m, **geometry_kwargs) - data.setProblem(self) - data.dtrue = self.data.dpred(m,u=u) + data.pair(self) + data.dtrue = data.dpred(m, u=u) noise = std*abs(data.dtrue)*np.random.randn(*data.dtrue.shape) data.dobs = data.dtrue+noise data.std = data.dobs*0 + std From 56dc9a55914e9ab25591b32040ed824ebc6fa59a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 24 Jan 2014 08:20:29 -0700 Subject: [PATCH 21/28] pointers to parent. rename _iter to iter --- SimPEG/Inversion.py | 2 +- SimPEG/ObjFunction.py | 27 +++++++++++++++++------ SimPEG/Optimization.py | 46 ++++++++++++++++++++-------------------- SimPEG/Regularization.py | 30 ++++++++++++++++++++------ SimPEG/Utils/Save.py | 4 ++-- SimPEG/Utils/__init__.py | 25 +++++++++++++--------- 6 files changed, 85 insertions(+), 49 deletions(-) diff --git a/SimPEG/Inversion.py b/SimPEG/Inversion.py index 0bef2d92..5b2dfa4d 100644 --- a/SimPEG/Inversion.py +++ b/SimPEG/Inversion.py @@ -4,7 +4,7 @@ from Optimization import Remember, IterationPrinters, StoppingCriteria class BaseInversion(object): - """BaseInversion(prob, reg, opt, data, **kwargs) + """BaseInversion(objFunc, opt, **kwargs) """ __metaclass__ = Utils.Save.Savable diff --git a/SimPEG/ObjFunction.py b/SimPEG/ObjFunction.py index d88d5740..fb2fe2f4 100644 --- a/SimPEG/ObjFunction.py +++ b/SimPEG/ObjFunction.py @@ -1,16 +1,16 @@ from SimPEG import Utils, np, sp class BaseObjFunction(object): - """docstring for BaseObjFunction""" + """BaseObjFunction(data, reg, **kwargs)""" __metaclass__ = Utils.Save.Savable - beta = Utils.ParameterProperty('beta', default=None, doc='Regularization trade-off parameter') + beta = Utils.ParameterProperty('beta', default=1, doc='Regularization trade-off parameter') debug = False #: Print debugging information counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things - name = 'BaseObjFunction' #: Name of the objective function + name = 'Base Objective Function' #: Name of the objective function u_current = None #: The most current evaluated field m_current = None #: The most current model @@ -25,12 +25,27 @@ class BaseObjFunction(object): print 'Objective function has switched to a new parent!' self._parent = p + @property + def inv(self): return self.parent + @property + def objFunc(self): return self + @property + def opt(self): return getattr(self.parent,'opt',None) + @property + def prob(self): return self.data.prob + @property + def mesh(self): return self.data.prob.mesh + @property + def model(self): return self.data.prob.model + def __init__(self, data, reg, **kwargs): Utils.setKwargs(self, **kwargs) self.data = data + self.reg = reg + self.reg.parent = self @Utils.callHooks('startup') @@ -41,7 +56,7 @@ class BaseObjFunction(object): """ if self.debug: print 'Calling ObjFunction.startup' - if not hasattr(self.reg, '_mref'): + if self.reg.mref is None: print 'Regularization has not set mref. SimPEG will set it to m0.' self.reg.mref = m0 @@ -226,8 +241,8 @@ class BetaSchedule(Utils.Parameter): self.beta = self.estimateBeta0() opt = self.parent.parent.opt - if opt._iter > 0 and opt._iter % self.coolingRate == 0: - if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % opt._iter + if opt.iter > 0 and opt.iter % self.coolingRate == 0: + if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % opt.iter self.beta /= self.coolingFactor return self.beta diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 35b71160..2362dd20 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -9,11 +9,11 @@ class StoppingCriteria(object): """docstring for StoppingCriteria""" iteration = { "str": "%d : maxIter = %3d <= iter = %3d", - "left": lambda M: M.maxIter, "right": lambda M: M._iter, + "left": lambda M: M.maxIter, "right": lambda M: M.iter, "stopType": "critical"} iterationLS = { "str": "%d : maxIterLS = %3d <= iterLS = %3d", - "left": lambda M: M.maxIterLS, "right": lambda M: M._iterLS, + "left": lambda M: M.maxIterLS, "right": lambda M: M.iterLS, "stopType": "critical"} armijoGoldstein = { "str": "%d : ft = %1.4e <= alp*descent = %1.4e", @@ -21,11 +21,11 @@ class StoppingCriteria(object): "stopType": "optimal"} tolerance_f = { "str": "%d : |fc-fOld| = %1.4e <= tolF*(1+|f0|) = %1.4e", - "left": lambda M: 1 if M._iter==0 else abs(M.f-M.f_last), "right": lambda M: 0 if M._iter==0 else M.tolF*(1+abs(M.f0)), + "left": lambda M: 1 if M.iter==0 else abs(M.f-M.f_last), "right": lambda M: 0 if M.iter==0 else M.tolF*(1+abs(M.f0)), "stopType": "optimal"} moving_x = { "str": "%d : |xc-x_last| = %1.4e <= tolX*(1+|x0|) = %1.4e", - "left": lambda M: 1 if M._iter==0 else norm(M.xc-M.x_last), "right": lambda M: 0 if M._iter==0 else M.tolX*(1+norm(M.x0)), + "left": lambda M: 1 if M.iter==0 else norm(M.xc-M.x_last), "right": lambda M: 0 if M.iter==0 else M.tolX*(1+norm(M.x0)), "stopType": "optimal"} tolerance_g = { "str": "%d : |proj(x-g)-x| = %1.4e <= tolG = %1.4e", @@ -56,12 +56,12 @@ class StoppingCriteria(object): class IterationPrinters(object): """docstring for IterationPrinters""" - iteration = {"title": "#", "value": lambda M: M._iter, "width": 5, "format": "%3d"} + iteration = {"title": "#", "value": lambda M: M.iter, "width": 5, "format": "%3d"} f = {"title": "f", "value": lambda M: M.f, "width": 10, "format": "%1.2e"} norm_g = {"title": "|proj(x-g)-x|", "value": lambda M: norm(M.projection(M.xc - M.g) - M.xc), "width": 15, "format": "%1.2e"} - totalLS = {"title": "LS", "value": lambda M: M._iterLS, "width": 5, "format": "%d"} + totalLS = {"title": "LS", "value": lambda M: M.iterLS, "width": 5, "format": "%d"} - iterationLS = {"title": "#", "value": lambda M: (M._iter, M._iterLS), "width": 5, "format": "%3d.%d"} + iterationLS = {"title": "#", "value": lambda M: (M.iter, M.iterLS), "width": 5, "format": "%3d.%d"} LS_ft = {"title": "ft", "value": lambda M: M._LS_ft, "width": 10, "format": "%1.2e"} LS_t = {"title": "t", "value": lambda M: M._LS_t, "width": 10, "format": "%0.5f"} LS_armijoGoldstein = {"title": "f + alp*g.T*p", "value": lambda M: M.f + M.LSreduction*M._LS_descent, "width": 16, "format": "%1.2e"} @@ -188,15 +188,15 @@ class Minimize(object): x0 = x0 xc = x0 - _iter = _iterLS = 0 + iter = iterLS = 0 :param numpy.ndarray x0: initial x :rtype: None :return: None """ - self._iter = 0 - self._iterLS = 0 + self.iter = 0 + self.iterLS = 0 x0 = self.projection(x0) # ensure that we start of feasible. self.x0 = x0 @@ -268,7 +268,7 @@ class Minimize(object): pass def stoppingCriteria(self, inLS=False): - if self._iter == 0: + if self.iter == 0: self.f0 = self.f self.g0 = self.g return Utils.checkStoppers(self, self.stoppers if not inLS else self.stoppersLS) @@ -360,21 +360,21 @@ class Minimize(object): """ # Projected Armijo linesearch self._LS_t = 1 - self._iterLS = 0 - while self._iterLS < self.maxIterLS: + self.iterLS = 0 + while self.iterLS < self.maxIterLS: self._LS_xt = self.projection(self.xc + self._LS_t*p) self._LS_ft = self.evalFunction(self._LS_xt, return_g=False, return_H=False) self._LS_descent = np.inner(self.g, self._LS_xt - self.xc) # this takes into account multiplying by t, but is important for projection. if self.stoppingCriteria(inLS=True): break - self._iterLS += 1 + self.iterLS += 1 self._LS_t = self.LSshorten*self._LS_t if self.debugLS: - if self._iterLS == 1: self.printInit(inLS=True) + if self.iterLS == 1: self.printInit(inLS=True) self.printIter(inLS=True) - if self.debugLS and self._iterLS > 0: self.printDone(inLS=True) + if self.debugLS and self.iterLS > 0: self.printDone(inLS=True) - return self._LS_xt, self._iterLS < self.maxIterLS + return self._LS_xt, self.iterLS < self.maxIterLS @Utils.count def modifySearchDirectionBreak(self, p): @@ -416,7 +416,7 @@ class Minimize(object): # store old values self.f_last = self.f self.x_last, self.xc = self.xc, xt - self._iter += 1 + self.iter += 1 if self.debug: self.printDone() @@ -613,7 +613,7 @@ class ProjectedGradient(Minimize, Remember): f_current_decrease = self.f_last - self.f self.comment = '' - if self._iter < 1: + if self.iter < 1: # Note that this is reset on every CG iteration. self.f_decrease_max = -np.inf else: @@ -684,7 +684,7 @@ class BFGS(Minimize, Remember): return self.bfgs(-self.g) def _doEndIteration_BFGS(self, xt): - if self._iter is 0: + if self.iter is 0: self.g_last = self.g return @@ -817,7 +817,7 @@ class NewtonRoot(object): """ if self.comments: print 'Newton Method:\n' - self._iter = 0 + self.iter = 0 while True: r, J = fun(x, return_g=True) @@ -851,10 +851,10 @@ class NewtonRoot(object): rt = fun(xt, return_g=False) x = xt - self._iter += 1 + self.iter += 1 if norm(rt) < self.tol: break - if self._iter > self.maxIter: + if self.iter > self.maxIter: print 'NewtonRoot stopped by maxIters. norm: %4.4e' % norm(rt) break diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index ea6cd753..d483c2e5 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -25,14 +25,30 @@ class BaseRegularization(object): self.mesh = mesh self.model = model + mref = Utils.ParameterProperty('mref', default=None, doc='Reference model.') + @property - def mref(self): - if getattr(self, '_mref', None) is None: - return np.zeros(self.model.nP); - return self._mref - @mref.setter - def mref(self, value): - self._mref = value + def parent(self): + """This is the parent of the regularization.""" + return getattr(self,'_parent',None) + @parent.setter + def parent(self, p): + if getattr(self,'_parent',None) is not None: + print 'Regularization has switched to a new parent!' + self._parent = p + + @property + def inv(self): return self.parent.inv + @property + def objFunc(self): return self.parent + @property + def reg(self): return self + @property + def opt(self): return self.parent.opt + @property + def prob(self): return self.parent.prob + @property + def data(self): return self.parent.data @property diff --git a/SimPEG/Utils/Save.py b/SimPEG/Utils/Save.py index 55de4b4b..a9c77191 100644 --- a/SimPEG/Utils/Save.py +++ b/SimPEG/Utils/Save.py @@ -57,7 +57,7 @@ class SimPEGTable: # At the start of every iteration we will create a inversion iteration node. def _doStartIteration_hdf5_inv(invObj): - invObj._invNodeIt = invObj._invNode.addGroup('%d'%(invObj._iter+1)) + invObj._invNodeIt = invObj._invNode.addGroup('%d'%(invObj.iter+1)) preIteration(invObj._invNodeIt) invObj.hook(_doStartIteration_hdf5_inv, overwrite=True) @@ -78,7 +78,7 @@ class SimPEGTable: invObj.hook(_finish_hdf5_inv, overwrite=True) def _doStartIteration_hdf5_opt(optObj): - optObj._optNodeIt = optObj.parent._invNode.addGroup('%d.%d'%(optObj.parent._iter, optObj._iter)) + optObj._optNodeIt = optObj.parent._invNode.addGroup('%d.%d'%(optObj.parent.iter, optObj.iter)) preIteration(optObj._optNodeIt) invObj.opt.hook(_doStartIteration_hdf5_opt, overwrite=True) diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 8c0f899b..8853500e 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -299,25 +299,30 @@ class Parameter(object): hook(self._parent, _startup_paramProperty, name=startupName, overwrite=True) @property - def opt(self): - return self.parent.parent.opt - + def inv(self): return self.parent.inv @property - def objFunc(self): - return self.parent - + def objFunc(self): return self.parent.objFunc @property - def reg(self): - return self.parent.reg + def opt(self): return self.parent.opt + @property + def reg(self): return self.parent.reg + @property + def data(self): return self.parent.data + @property + def prob(self): return self.parent.prob + @property + def model(self): return self.parent.model + @property + def mesh(self): return self.parent.mesh def initialize(self): pass def get(self): if (self.current is None or - not self.opt._iter == self.currentIter): + not self.opt.iter == self.currentIter): self.current = self.nextIter() - self.currentIter = self.opt._iter + self.currentIter = self.opt.iter return self.current def nextIter(self): From 18476e53c2c949c5a71cf5c2410ca02a3c820837 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 24 Jan 2014 08:37:47 -0700 Subject: [PATCH 22/28] Regularization now just takes a model. (The mesh can be attached to the model.) --- SimPEG/Regularization.py | 10 +++++----- SimPEG/Tests/test_regularization.py | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index d483c2e5..bc754592 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -14,15 +14,13 @@ class BaseRegularization(object): modelPair = Model.BaseModel #: Some regularizations only work on specific models - mesh = None #: A SimPEG.Mesh instance. model = None #: A SimPEG.Model instance. counter = None - def __init__(self, mesh, model, **kwargs): + def __init__(self, model, **kwargs): Utils.setKwargs(self, **kwargs) assert isinstance(model, self.modelPair), "Incorrect model for this regularization" - self.mesh = mesh self.model = model mref = Utils.ParameterProperty('mref', default=None, doc='Reference model.') @@ -49,6 +47,8 @@ class BaseRegularization(object): def prob(self): return self.parent.prob @property def data(self): return self.parent.data + @property + def mesh(self): return self.model.mesh @property @@ -193,8 +193,8 @@ class Tikhonov(BaseRegularization): alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") - def __init__(self, mesh, model, **kwargs): - BaseRegularization.__init__(self, mesh, model, **kwargs) + def __init__(self, model, **kwargs): + BaseRegularization.__init__(self, model, **kwargs) @property def Ws(self): diff --git a/SimPEG/Tests/test_regularization.py b/SimPEG/Tests/test_regularization.py index 129948e1..3df9180c 100644 --- a/SimPEG/Tests/test_regularization.py +++ b/SimPEG/Tests/test_regularization.py @@ -20,8 +20,9 @@ class RegularizationTests(unittest.TestCase): # if 'Regularization' not in R: continue print 'Check:', R model = r.modelPair(self.mesh2) - reg = r(self.mesh2, model) + reg = r(model) m = model.example() + reg.mref = model.example()*0 passed = checkDerivative(lambda m : [reg.modelObj(m), reg.modelObjDeriv(m)], m, plotIt=False) self.assertTrue(passed) From cae723eb0e82ea97a1adc232d60e0ab66ab7a52b Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 24 Jan 2014 09:36:01 -0700 Subject: [PATCH 23/28] Moved parameters to separate file. Documentation updates. --- README.md | 18 ++- SimPEG/Data.py | 3 +- SimPEG/Model.py | 2 +- SimPEG/ObjFunction.py | 85 +---------- SimPEG/Optimization.py | 3 +- SimPEG/Parameters.py | 164 +++++++++++++++++++++ SimPEG/Problem.py | 4 +- SimPEG/Regularization.py | 4 +- SimPEG/Utils/__init__.py | 77 ---------- SimPEG/__init__.py | 1 + docs/{api_Optimize.rst => api_Inverse.rst} | 16 +- docs/api_Parameters.rst | 11 ++ docs/index.rst | 14 +- docs/simpeg-framework.png | Bin 0 -> 16020 bytes 14 files changed, 218 insertions(+), 184 deletions(-) create mode 100644 SimPEG/Parameters.py rename docs/{api_Optimize.rst => api_Inverse.rst} (99%) create mode 100644 docs/api_Parameters.rst create mode 100644 docs/simpeg-framework.png diff --git a/README.md b/README.md index c2eafa26..37e0a743 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![SimPEG](https://raw.github.com/simpeg/simpeg/master/docs/simpeg-logo.png) -Simulation and Parameter Estimation in Geoscience - A python package for simulation and gradient based parameter estimation in the context of geophysical applications. +Simulation and Parameter Estimation in Geophysics - A python package for simulation and gradient based parameter estimation in the context of geophysical applications. The vision is to create a package for finite volume simulation with applications to geophysical imaging and subsurface flow. To enable the understanding of the many different components, this package has the following features: @@ -10,4 +10,20 @@ The vision is to create a package for finite volume simulation with applications * supports 1D, 2D and 3D problems * designed for large-scale inversions +Documentation: +[http://simpeg.readthedocs.org/en/latest/](http://simpeg.readthedocs.org/en/latest/) + +Code: +[https://github.com/simpeg/simpeg](https://github.com/simpeg/simpeg) + +Tests: +[https://travis-ci.org/simpeg/simpeg](https://travis-ci.org/simpeg/simpeg) + +Build Status: [![Build Status](https://travis-ci.org/simpeg/simpeg.png)](https://travis-ci.org/simpeg/simpeg) + +Bugs & Issues: +[https://github.com/simpeg/simpeg/issues](https://github.com/simpeg/simpeg/issues) + +Code Snippets & Tutorials: +[http://www.row1.ca/simpeg](http://www.row1.ca/simpeg) diff --git a/SimPEG/Data.py b/SimPEG/Data.py index 6c94811a..948b1c83 100644 --- a/SimPEG/Data.py +++ b/SimPEG/Data.py @@ -1,5 +1,4 @@ -import Utils -import numpy as np +import Utils, numpy as np class BaseData(object): diff --git a/SimPEG/Model.py b/SimPEG/Model.py index 8482edde..33cfeef8 100644 --- a/SimPEG/Model.py +++ b/SimPEG/Model.py @@ -1,4 +1,4 @@ -from SimPEG import Utils, np, sp +import Utils, Parameters, numpy as np, scipy.sparse as sp class BaseModel(object): diff --git a/SimPEG/ObjFunction.py b/SimPEG/ObjFunction.py index fb2fe2f4..ea2fe831 100644 --- a/SimPEG/ObjFunction.py +++ b/SimPEG/ObjFunction.py @@ -1,11 +1,11 @@ -from SimPEG import Utils, np, sp +import Utils, Parameters, numpy as np, scipy.sparse as sp class BaseObjFunction(object): """BaseObjFunction(data, reg, **kwargs)""" __metaclass__ = Utils.Save.Savable - beta = Utils.ParameterProperty('beta', default=1, doc='Regularization trade-off parameter') + beta = Parameters.ParameterProperty('beta', default=1, doc='Regularization trade-off parameter') debug = False #: Print debugging information counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things @@ -213,84 +213,3 @@ class BaseObjFunction(object): dmisfit = self.data.prob.Jt_approx(m, self.data.Wd * self.data.Wd * self.data.prob.J_approx(m, v, u=u), u=u) return dmisfit - - - -class BetaSchedule(Utils.Parameter): - """BetaSchedule""" - - beta0 = 'guess' #: The initial Beta (regularization parameter) - beta0_ratio = 0.1 #: When beta0 is set to 'guess', estimateBeta0 is used with this ratio - - coolingFactor = 2. - coolingRate = 3 - - beta = None #: Beta parameter - - def __init__(self, *args, **kwargs): - Utils.Parameter.__init__(self, *args, **kwargs) - Utils.setKwargs(self, **kwargs) - - def initialize(self): - self.beta = self.beta0 - - @Utils.requires('parent') - def nextIter(self): - if self.beta is 'guess': - if self.debug: print 'BetaSchedule is estimating Beta0.' - self.beta = self.estimateBeta0() - - opt = self.parent.parent.opt - if opt.iter > 0 and opt.iter % self.coolingRate == 0: - if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % opt.iter - self.beta /= self.coolingFactor - - return self.beta - - @Utils.requires('parent') - def estimateBeta0(self): - """estimateBeta0(u=None) - - The initial beta is calculated by comparing the estimated - eigenvalues of JtJ and WtW. - - To estimate the eigenvector of **A**, we will use one iteration - of the *Power Method*: - - .. math:: - - \mathbf{x_1 = A x_0} - - Given this (very course) approximation of the eigenvector, - we can use the *Rayleigh quotient* to approximate the largest eigenvalue. - - .. math:: - - \lambda_0 = \\frac{\mathbf{x^\\top A x}}{\mathbf{x^\\top x}} - - We will approximate the largest eigenvalue for both JtJ and WtW, and - use some ratio of the quotient to estimate beta0. - - .. math:: - - \\beta_0 = \gamma \\frac{\mathbf{x^\\top J^\\top J x}}{\mathbf{x^\\top W^\\top W x}} - - - :param numpy.array u: fields - :param float ratio: desired ratio of the eigenvalues, default is 0.1 - :rtype: float - :return: beta0 - """ - objFunc = self.parent - data = objFunc.data - - m = objFunc.m_current - u = objFunc.u_current - - if u is None: - u = data.prob.field(m) - - x0 = np.random.rand(*m.shape) - t = x0.dot(objFunc.dataObj2Deriv(m,x0,u=u)) - b = x0.dot(objFunc.reg.modelObj2Deriv()*x0) - return self.beta0_ratio*(t/b) diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 2362dd20..4e5963f6 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -1,4 +1,5 @@ -from SimPEG import Solver, Utils, sp, np +import Utils, numpy as np, scipy.sparse as sp +from Solver import Solver norm = np.linalg.norm diff --git a/SimPEG/Parameters.py b/SimPEG/Parameters.py new file mode 100644 index 00000000..2a07aa69 --- /dev/null +++ b/SimPEG/Parameters.py @@ -0,0 +1,164 @@ +import Utils, numpy as np + + +class Parameter(object): + """Parameter""" + + debug = False #: Print debugging information + + current = None #: This hold + currentIter = 0 + + def __init__(self, **kwargs): + Utils.setKwargs(self, **kwargs) + + @property + def parent(self): + """This is the parent of the Parameter instance.""" + return getattr(self,'_parent',None) + @parent.setter + def parent(self, p): + startupName = '_startup_paramProperty_'+self._propertyName + if getattr(self,'_parent',None) is not None: + delattr(self._parent,startupName) + print 'Warning: Parameter %s has switched to a new parent.' % self._propertyName + if self.debug: print '%s function has been deleted' % startupName + self._parent = p + + prop = self + def _startup_paramProperty(self, *args): + if prop.debug: print 'initializing %s' % prop._propertyName + prop.initialize() + + Utils.hook(self._parent, _startup_paramProperty, name=startupName, overwrite=True) + + @property + def inv(self): return self.parent.inv + @property + def objFunc(self): return self.parent.objFunc + @property + def opt(self): return self.parent.opt + @property + def reg(self): return self.parent.reg + @property + def data(self): return self.parent.data + @property + def prob(self): return self.parent.prob + @property + def model(self): return self.parent.model + @property + def mesh(self): return self.parent.mesh + + def initialize(self): + pass + + def get(self): + if (self.current is None or + not self.opt.iter == self.currentIter): + self.current = self.nextIter() + self.currentIter = self.opt.iter + return self.current + + def nextIter(self): + raise NotImplementedError('Getting the Parameter is not yet implemented.') + + +def ParameterProperty(name, default=None, doc=""): + def getter(self): + out = getattr(self,'_'+name,default) + if isinstance(out, Parameter): + out = out.get() + return out + def setter(self, value): + if isinstance(value, Parameter): + value._propertyName = name + value.parent = self + setattr(self, '_'+name, value) + + return property(fget=getter, fset=setter, doc=doc) + + +class BetaEstimate(Parameter): + """BetaEstimate""" + + beta0 = 'guess' #: The initial Beta (regularization parameter) + beta0_ratio = 0.1 #: When beta0 is set to 'guess', estimateBeta0 is used with this ratio + + beta = None #: Beta parameter + + def __init__(self, **kwargs): + Parameter.__init__(self, **kwargs) + + def initialize(self): + self.beta = self.beta0 + + @Utils.requires('parent') + def nextIter(self): + if self.beta is 'guess': + if self.debug: print 'BetaSchedule is estimating Beta0.' + self.beta = self.estimateBeta0() + return self.beta + + @Utils.requires('parent') + def estimateBeta0(self): + """estimateBeta0(u=None) + + The initial beta is calculated by comparing the estimated + eigenvalues of JtJ and WtW. + + To estimate the eigenvector of **A**, we will use one iteration + of the *Power Method*: + + .. math:: + + \mathbf{x_1 = A x_0} + + Given this (very course) approximation of the eigenvector, + we can use the *Rayleigh quotient* to approximate the largest eigenvalue. + + .. math:: + + \lambda_0 = \\frac{\mathbf{x^\\top A x}}{\mathbf{x^\\top x}} + + We will approximate the largest eigenvalue for both JtJ and WtW, and + use some ratio of the quotient to estimate beta0. + + .. math:: + + \\beta_0 = \gamma \\frac{\mathbf{x^\\top J^\\top J x}}{\mathbf{x^\\top W^\\top W x}} + + :rtype: float + :return: beta0 + """ + objFunc = self.parent + data = objFunc.data + + m = objFunc.m_current + u = objFunc.u_current + + if u is None: + u = data.prob.field(m) + + x0 = np.random.rand(*m.shape) + t = x0.dot(objFunc.dataObj2Deriv(m,x0,u=u)) + b = x0.dot(objFunc.reg.modelObj2Deriv()*x0) + return self.beta0_ratio*(t/b) + + +class BetaSchedule(BetaEstimate): + """BetaSchedule""" + + coolingFactor = 2. + coolingRate = 3 + + @Utils.requires('parent') + def nextIter(self): + if self.beta is 'guess': + if self.debug: print 'BetaSchedule is estimating Beta0.' + self.beta = self.estimateBeta0() + + if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0: + if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter + self.beta /= self.coolingFactor + + return self.beta diff --git a/SimPEG/Problem.py b/SimPEG/Problem.py index 501b1c45..e53c4675 100644 --- a/SimPEG/Problem.py +++ b/SimPEG/Problem.py @@ -1,6 +1,4 @@ -import Utils, Data -import scipy.sparse as sp -import numpy as np +import Utils, Data, numpy as np, scipy.sparse as sp class BaseProblem(object): diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index bc754592..aa62449a 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,4 +1,4 @@ -from SimPEG import Utils, Model, np, sp +import Utils, Model, Parameters, numpy as np, scipy.sparse as sp class BaseRegularization(object): """ @@ -23,7 +23,7 @@ class BaseRegularization(object): assert isinstance(model, self.modelPair), "Incorrect model for this regularization" self.model = model - mref = Utils.ParameterProperty('mref', default=None, doc='Reference model.') + mref = Parameters.ParameterProperty('mref', default=None, doc='Reference model.') @property def parent(self): diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 8853500e..437f1387 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -267,83 +267,6 @@ def timeIt(f): return wrapper -class Parameter(object): - """Parameter""" - - debug = False #: Print debugging information - - current = None #: This hold - currentIter = 0 - - def __init__(self, *args, **kwargs): - pass - - @property - def parent(self): - """This is the parent of the Parameter instance.""" - return getattr(self,'_parent',None) - @parent.setter - def parent(self, p): - startupName = '_startup_paramProperty_'+self._propertyName - if getattr(self,'_parent',None) is not None: - delattr(self._parent,startupName) - print 'Warning: Parameter %s has switched to a new parent.' % self._propertyName - if self.debug: print '%s function has been deleted' % startupName - self._parent = p - - prop = self - def _startup_paramProperty(self, *args): - if prop.debug: print 'initializing %s' % prop._propertyName - prop.initialize() - - hook(self._parent, _startup_paramProperty, name=startupName, overwrite=True) - - @property - def inv(self): return self.parent.inv - @property - def objFunc(self): return self.parent.objFunc - @property - def opt(self): return self.parent.opt - @property - def reg(self): return self.parent.reg - @property - def data(self): return self.parent.data - @property - def prob(self): return self.parent.prob - @property - def model(self): return self.parent.model - @property - def mesh(self): return self.parent.mesh - - def initialize(self): - pass - - def get(self): - if (self.current is None or - not self.opt.iter == self.currentIter): - self.current = self.nextIter() - self.currentIter = self.opt.iter - return self.current - - def nextIter(self): - raise NotImplementedError('Getting the Parameter is not yet implemented.') - - -def ParameterProperty(name, default=None, doc=""): - def getter(self): - out = getattr(self,'_'+name,default) - if isinstance(out, Parameter): - out = out.get() - return out - def setter(self, value): - if isinstance(value, Parameter): - value._propertyName = name - value.parent = self - setattr(self, '_'+name, value) - - return property(fget=getter, fset=setter, doc=doc) - - if __name__ == '__main__': class MyClass(object): def __init__(self, url): diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index 10d6d4e8..4967608e 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -10,6 +10,7 @@ import Regularization import ObjFunction import Optimization import Inversion +import Parameters import Examples import Tests diff --git a/docs/api_Optimize.rst b/docs/api_Inverse.rst similarity index 99% rename from docs/api_Optimize.rst rename to docs/api_Inverse.rst index 462ae0be..21f4386e 100644 --- a/docs/api_Optimize.rst +++ b/docs/api_Inverse.rst @@ -1,6 +1,15 @@ .. _api_Inverse: +Regularization +************** + +.. automodule:: SimPEG.Regularization + :show-inheritance: + :members: + :undoc-members: + + Objective Function ****************** @@ -27,10 +36,3 @@ Inversion :undoc-members: -Regularization -************** - -.. automodule:: SimPEG.Regularization - :show-inheritance: - :members: - :undoc-members: diff --git a/docs/api_Parameters.rst b/docs/api_Parameters.rst new file mode 100644 index 00000000..e90b58a5 --- /dev/null +++ b/docs/api_Parameters.rst @@ -0,0 +1,11 @@ +.. _api_Parameters: + + +Parameters +********** + +.. automodule:: SimPEG.Parameters + :show-inheritance: + :members: + :undoc-members: + :inherited-members: diff --git a/docs/index.rst b/docs/index.rst index b2882cf0..5ba56947 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,7 +3,7 @@ :alt: SimPEG :align: center -SimPEG (Simulation and Parameter Estimation in Geoscience) is a python +SimPEG (Simulation and Parameter Estimation in Geophysics) is a python package for simulation and gradient based parameter estimation in the context of geoscience applications. @@ -16,11 +16,10 @@ these goals, this package has the following features: * provides a framework for geophysical and hydrogeologic problems * supports 1D, 2D and 3D problems - -.. raw:: html - - - +.. image:: simpeg-framework.png + :width: 400 px + :alt: Framework + :align: center Meshing & Operators =================== @@ -49,7 +48,8 @@ Inversion .. toctree:: :maxdepth: 2 - api_Optimize + api_Inverse + api_Parameters Testing SimPEG ============== diff --git a/docs/simpeg-framework.png b/docs/simpeg-framework.png new file mode 100644 index 0000000000000000000000000000000000000000..ad8e5c1c0d848cd29af422bc8e316944b0264359 GIT binary patch literal 16020 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 Date: Fri, 24 Jan 2014 09:46:42 -0700 Subject: [PATCH 24/28] Deleted Notebooks. Use GISTS in github. --- .gitignore | 1 - notebooks/BFGS.ipynb | 158 - notebooks/Bound Constraint Problem.ipynb | 620 ---- notebooks/SliceThroughModel.ipynb | 3048 ------------------ notebooks/VisualizeWithvtkView-updated.ipynb | 142 - notebooks/exLomPlots.ipynb | 122 - notebooks/exPlotImage2D.ipynb | 235 -- 7 files changed, 4326 deletions(-) delete mode 100644 notebooks/BFGS.ipynb delete mode 100644 notebooks/Bound Constraint Problem.ipynb delete mode 100644 notebooks/SliceThroughModel.ipynb delete mode 100644 notebooks/VisualizeWithvtkView-updated.ipynb delete mode 100644 notebooks/exLomPlots.ipynb delete mode 100644 notebooks/exPlotImage2D.ipynb diff --git a/.gitignore b/.gitignore index 5c39733b..7678b15c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ *.sublime-project *.sublime-workspace docs/_build/ -myNotebooks/* diff --git a/notebooks/BFGS.ipynb b/notebooks/BFGS.ipynb deleted file mode 100644 index c2f68c99..00000000 --- a/notebooks/BFGS.ipynb +++ /dev/null @@ -1,158 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import SimPEG\n", - "from SimPEG import Solver\n", - "from SimPEG.mesh import TensorMesh\n", - "from SimPEG.regularization import Regularization\n", - "import SimPEG.inverse as inverse\n", - "from SimPEG.inverse import Minimize, Remember, IterationPrinters\n", - "import numpy as np\n", - "import scipy.sparse as sp" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "FUN = SimPEG.tests.Rosenbrock\n", - "FUN = SimPEG.tests.getQuadratic(sp.csr_matrix(([100,1],([0,1],[0,1])),shape=(2,2)),np.array([-5,-5]),100)\n", - "\n", - "x0 = np.array([1,0])\n", - "opt = inverse.BFGS()\n", - "xopt = opt.minimize(FUN,x0)\n", - "print xopt\n", - "opt = inverse.GaussNewton()\n", - "xopt = opt.minimize(FUN,x0)\n", - "print xopt\n", - "opt = inverse.SteepestDescent()\n", - "xopt = opt.minimize(FUN,x0)\n", - "print xopt" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "===================== BFGS =====================\n", - " # f |proj(x-g)-x| LS Comment \n", - "-----------------------------------------------\n", - " 0 1.45e+02 9.51e+01 0 \n", - " 1 1.14e+02 5.37e+01 6 \n", - " 2 1.04e+02 3.04e+01 6 \n", - " 3 8.83e+01 1.37e+01 0 \n", - " 4 8.76e+01 5.97e+00 0 Skip BFGS \n", - " 5 8.74e+01 2.61e+00 0 Skip BFGS \n", - " 6 8.74e+01 1.14e+00 0 Skip BFGS \n", - " 7 8.74e+01 5.01e-01 0 Skip BFGS \n", - " 8 8.74e+01 2.19e-01 0 Skip BFGS \n", - " 9 8.74e+01 9.60e-02 0 Skip BFGS \n", - "------------------------- STOP! -------------------------\n", - "1 : |fc-fOld| = 1.9437e-04 <= tolF*(1+|f0|) = 1.4600e+01\n", - "1 : |xc-x_last| = 1.2663e-03 <= tolX*(1+|x0|) = 2.0000e-01\n", - "1 : |proj(x-g)-x| = 9.5952e-02 <= tolG = 1.0000e-01\n", - "0 : |proj(x-g)-x| = 9.5952e-02 <= 1e3*eps = 1.0000e-02\n", - "0 : maxIter = 20 <= iter = 9\n", - "------------------------- DONE! -------------------------\n", - "[ 0.05095952 4.99977449]\n", - "=========== Gauss Newton ===========\n", - " # f |proj(x-g)-x| LS \n", - "-----------------------------------\n", - " 0 1.45e+02 9.51e+01 0 \n", - " 1 8.74e+01 4.44e-15 0 \n", - "------------------------- STOP! -------------------------\n", - "0 : |fc-fOld| = 5.7625e+01 <= tolF*(1+|f0|) = 1.4600e+01\n", - "0 : |xc-x_last| = 5.0894e+00 <= tolX*(1+|x0|) = 2.0000e-01\n", - "1 : |proj(x-g)-x| = 4.4409e-15 <= tolG = 1.0000e-01\n", - "1 : |proj(x-g)-x| = 4.4409e-15 <= 1e3*eps = 1.0000e-02\n", - "0 : maxIter = 20 <= iter = 1\n", - "------------------------- DONE! -------------------------\n", - "[ 0.05 5. ]\n", - "========= Steepest Descent =========\n", - " # f |proj(x-g)-x| LS \n", - "-----------------------------------\n", - " 0 1.45e+02 9.51e+01 0 \n", - " 1 1.14e+02 5.37e+01 6 \n", - " 2 1.04e+02 3.04e+01 6 \n", - " 3 1.00e+02 1.76e+01 6 \n", - " 4 9.88e+01 1.06e+01 6 \n", - " 5 9.82e+01 7.07e+00 6 \n", - " 6 9.80e+01 1.22e+01 5 \n", - " 7 9.73e+01 7.77e+00 6 \n", - " 8 9.68e+01 5.64e+00 6 \n", - " 9 9.65e+01 8.72e+00 5 \n", - " 10 9.60e+01 5.97e+00 6 \n", - " 11 9.58e+01 9.98e+00 5 \n", - " 12 9.53e+01 6.48e+00 6 \n", - " 13 9.53e+01 1.16e+01 5 \n", - " 14 9.46e+01 7.20e+00 6 \n", - " 15 9.43e+01 5.07e+00 6 \n", - " 16 9.41e+01 8.17e+00 5 \n", - " 17 9.37e+01 5.43e+00 6 \n", - " 18 9.36e+01 9.42e+00 5 \n", - " 19 9.32e+01 5.98e+00 6 \n", - " 20 9.29e+01 4.32e+00 6 \n", - "------------------------- STOP! -------------------------\n", - "1 : |fc-fOld| = 2.5913e-01 <= tolF*(1+|f0|) = 1.4600e+01\n", - "1 : |xc-x_last| = 9.3379e-02 <= tolX*(1+|x0|) = 2.0000e-01\n", - "0 : |proj(x-g)-x| = 4.3246e+00 <= tolG = 1.0000e-01\n", - "0 : |proj(x-g)-x| = 4.3246e+00 <= 1e3*eps = 1.0000e-02\n", - "1 : maxIter = 20 <= iter = 20\n", - "------------------------- DONE! -------------------------\n", - "[ 0.07777107 1.6849632 ]\n" - ] - }, - { - "output_type": "stream", - "stream": "stderr", - "text": [ - "/Users/rowan/git/simpeg/SimPEG/inverse/Optimize.py:664: RuntimeWarning: divide by zero encountered in remainder\n", - " khat = np.mod(n-nn+k,nn)\n" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "A = sp.identity(2)\n", - "S = Solver(A)\n", - "\n", - "assert type(S) is Solver" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/notebooks/Bound Constraint Problem.ipynb b/notebooks/Bound Constraint Problem.ipynb deleted file mode 100644 index efaa487c..00000000 --- a/notebooks/Bound Constraint Problem.ipynb +++ /dev/null @@ -1,620 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import SimPEG\n", - "from SimPEG.mesh import TensorMesh\n", - "from SimPEG.regularization import Regularization\n", - "import SimPEG.inverse as inverse\n", - "from SimPEG.inverse import Minimize\n", - "import numpy as np\n", - "import scipy.sparse as sp" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from SimPEG.forward.LinearProblem import example as LinExample\n", - "\n", - "prob, m_true = LinExample(1000)\n", - "M = prob.mesh\n", - "\n", - "reg = Regularization(M)\n", - "opt = inverse.InexactGaussNewton(maxIter=100,maxStep=0.2,debug=False,LSreduction=0.3,maxIterLS=50)\n", - "opt.remember('f', ('norm_g', lambda M:np.linalg.norm(M.g)))\n", - "inv = inverse.Inversion(prob,reg,opt,beta0=1e-4,maxIter=2,debug=False)\n", - "m0 = np.zeros_like(m_true)\n", - "\n", - "mrec = inv.run(m0)\n", - "\n", - "plt.plot(M.vectorCCx, m_true, 'b-')\n", - "plt.plot(M.vectorCCx, mrec, 'r-')\n", - "\n", - "figure()\n", - "plot(opt.recall('f'))\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "====================== Inexact Gauss Newton ======================\n", - " # beta phi_d phi_m f |proj(x-g)-x| LS \n", - "-----------------------------------------------------------------\n", - " 0 1.00e-04 9.62e+02 0.00e+00 9.62e+02 1.02e+04 0 \n", - " 1 1.00e-04 6.63e+02 7.73e+02 6.63e+02 8.47e+03 0 \n", - " 2 1.00e-04 4.15e+02 4.39e+03 4.15e+02 6.63e+03 0 \n", - " 3 1.00e-04 2.26e+02 6.85e+03 2.27e+02 4.80e+03 0 " - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " 4 1.00e-04 9.74e+01 1.07e+04 9.84e+01 3.02e+03 0 \n", - " 5 1.00e-04 2.42e+01 1.64e+04 2.58e+01 1.35e+03 0 \n", - " 6 1.00e-04 1.06e+00 2.34e+04 3.39e+00 9.21e+00 0 \n", - "------------------------- STOP! -------------------------\n", - "1 : |fc-fOld| = 2.2421e+01 <= tolF*(1+|f0|) = 9.6325e+01\n", - "0 : |xc-x_last| = 2.1351e+00 <= tolX*(1+|x0|) = 1.0000e-01\n", - "0 : |proj(x-g)-x| = 9.2073e+00 <= tolG = 1.0000e-01\n", - "0 : |proj(x-g)-x| = 9.2073e+00 <= 1e3*eps = 1.0000e-02\n", - "0 : maxIter = 100 <= iter = 6\n", - "1 : phi_d = 1.0595e+00 <= phi_d_target = 2.0000e+01 \n", - "------------------------- DONE! -------------------------\n", - "-------------------------STOP!-------------------------\n", - "0 : maxIter = 2 <= iter = 1\n", - "1 : phi_d = 1.0595e+00 <= phi_d_target = 2.0000e+01 \n", - "-------------------------DONE!-------------------------\n" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 3, - "text": [ - "[]" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAEACAYAAAC08h1NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XlcVPX+P/DXYcncwgVzSUXBBVAQBEGvgriAGmndopLW\nq9VXLZUyy6/lfRhere79ZWXWVatrt+916RZa7imYgEkC7hum4oJaLkjiigLz+f3xkVGcGWZfz+v5\neMxDmDlzzpvjzGs+8zmf8zmKEEKAiIhUw8vZBRARkWMx+ImIVIbBT0SkMgx+IiKVYfATEakMg5+I\nSGWsDv7Ro0ejZcuWCAsL0/t4dnY2/Pz8EBkZicjISMycOdPaTRIRkRV8rF3BqFGjMGHCBDz33HMG\nl+nfvz9Wrlxp7aaIiMgGrG7xx8XFoWnTpnUuw3PEiIhch937+BVFQV5eHiIiIjBp0iQUFxfbe5NE\nRFQHuwd/z549cfLkSRQWFiI0NBRpaWn23iQREdVF2MCxY8dE9+7djS6n0WjE/fffLyoqKnQeCwoK\nEgB444033ngz4xYUFGR2Ztu9xX/27FltH/+qVasQHh6OevXq6SxXXFwMIQRvQmD69OlOr8FVbtwX\n3BfcF3XfLOk+t3pUT2pqKnJyclBaWop27dohPT0dlZWVAIAxY8YgIyMD8+bNg4+PD8LDwzF79mxr\nN0lERFawOviXLl1a5+OvvPIKXnnlFWs3Q0RENsIzd11QQkKCs0twGdwXt3Ff3MZ9YR1FCCGcXQQg\nh326SClERG7Dkuxki5+ISGUY/EREKsPgJyJSGQY/EZHKMPiJiFSGwU9EpDIMfiIilWHwExGpDIOf\niEhlGPxERCrD4CciUhkGPxGRyjD4iYhUhsFPRKQyDH4iIpVh8BMRqQyDn4hIZRj8REQqw+AnIlIZ\nBj8Rkcow+ImIVMbH2QWQyly5AmRmAhcuAD17ApGRgKI4uyoiVWGLnxxn0SIgKAiYPx/YsgV4/HEg\nKQk4dcrZlRGpClv85BjvvQf861/A+vVARIS8r6pK3t+vH7BpE9Cxo3NrJFIJBj/Z37ffAp9/Dvzy\nC9Cq1e37fXyAv/4VaNwYGDFCPt6okfPqJFIJRQghnF0EACiKAhcphWzpyBGgTx9gwwbZn6+PEMDz\nzwP33Qd8+qlj6yNyc5ZkJ4Of7EcIYMgQ2Y8/eXLdy/7xB9C9O5CRIT8oiMgklmQnD+6S/Xz3HXD2\nLJCWZnzZpk2BWbOAKVPkBwYR2Q2Dn+yjqgqYNg2YPRvw9TXtOc8+C5SWAj/+aN/aiFSOwU/2sXgx\n0KYNMGiQ6c/x9gZmzJA3IrIb9vGT7Wk0QHAw8MUXQP/+5j23uhro1An45hsgNtY+9RF5EPbxk2tY\nt06O0ImPN/+53t7AxInAnDm2r4uIALDFT/YwZAjw9NPAc89Z9vzyciAgAPj1V6BlS9vWRuRh2OIn\n5ysqAnbvBp580vJ1+PkBDz8MLFliu7qISMvq4B89ejRatmyJsLAwg8tMnToVgYGBiIqKwsGDB63d\nJLmyBQuAF18E6tWzbj2jRgFffcWhnUR2YHXwjxo1Cj/WMfyuoKAAmzdvxrZt2zB58mRMNnYiD7mv\nmzdlK33UKOvXFR8vZ/LcudP6dRFRLVYHf1xcHJo2bWrw8fz8fKSkpKBZs2ZITU1FUVGRtZskV7Vu\nnRzNExRk/bq8vIDUVDnPDxHZlN0naSsoKMCzzz6r/b1FixYoLi5GkC3CgexCowF+/hmorDTveWEf\nfI3S2Ofx+0bb1NGoXQrC/vY4fhn8nsVz9gcFAR062KYeIk9h9+AXQugccVYMvInfeecd7c8JCQlI\nSEiwY2VkSFER8OCD5g2jv6/yAv6z9SdM8fo3rtmqd0ZE4D9lAv99azeKG0eY/fTSUjk4aOVKG9VD\n5AKys7ORnZ1t1TpsMpzz+PHjGD58OPbu3avz2Ny5c1FVVYXXXnsNABAUFITi4mLdQjic02Xs3i1H\nYu7ebcaTvvxSzsBp666ZKVPklA8zZ5r91LVr5WSfa9fatiQiV+KSwzljY2OxbNkyXLhwAUuWLEFI\nSIi9N0lWEsKCnpWMDHlFLVtLSZHrJiKbsbqrJzU1FTk5OSgtLUW7du2Qnp6Oyludw2PGjEFMTAz6\n9euH6OhoNGvWDIsWLbK6aLIvs4O/rExeRGXZMtsXEx0NXL4MHD4MdO5s1lMVhaNBifSxOviXLl1q\ndJn3338f77//vrWbIgcxO/h/+AFITAQaNrR9MYoiDzisXWva9M53PZXBT6SLZ+6SDrODPyNDdsnY\ny7BhcqgoEdkEg590mBX8Fy8CW7YAycn2K2jwYLmNq1fNehpb/ET6MfhJh1lhuW6dPMu2cWO71YP7\n7gN69QI2bTL7qQx+Il0MftJhVot/9Wpg+HC71gNAdveYOS7TwnO+iDweg590mBz8VVXyMon27Oap\nkZQEZGWZ9RR29RDpx+AnHSYH/y+/yFNjH3jA7jUhLEwOGz150v7bIvJwDH7SYXLwO6qbB5CTtg0Y\nYFY/P1v8RPox+EmHycG/ahXw0EN2r0dr0CDgp59MXpzBT6Qfg590mBT8xcWy6yUqyiE1AQAGDpTB\nzzQnsgqDn3SYFPxr1sgzar0c+BLq3FnOGa1nkj992OIn0o/BTzpMCv7MTGDoUIfUo6Uot1v9Ji7O\n4CfSxeAnHUaDv7ISyM2VIexoZgQ/EenH4CcdRoM/Px/o1Anw93dYTVpxccDmzSY15dniJ9KPwU86\njAZ/VpacjdMZAgNlP/+JEyYtzuAn0sXgJx1Ggz8zU06c5gyKAvTrJy8KbMKiRKSLwU866gz+S5eA\nPXuAvn0dWlMtZgQ/W/xEuhj8pKPO4M/OBnr3BurXd2RJtZkY/ACDn0gfBj/pqDP4s7Kc181To0cP\noKQE+OOPOhdjVw+Rfgx+0mE0+J11YLeGjw8QEwPk5dW5GLt6iPRj8JNeeoP/1Cng3DkgIsLh9egw\no7uHiGpj8JMOgy3+jRvlCVSOnKbBEBOCny1+Iv1c4B1MrsZg8GdmOr+bp0bv3sCOHcCNGwYXYfAT\n6cfgJx16g18I1ziwW6NRI3n28O7dzq6EyO0w+EmH3uDfv1+GbceOTqlJr9hYOX2EAWzxE+nH4Ccd\neoPfmWfrGsLgJ7IIg5906A1+V+rmqWEk+IlIPwY/6dBpJd+8KWfEdMY0zHUJCQHOngUuXND7MFv8\nRPox+EmHTot/61aga1egWTOn1aSXtzcQHQ0UFBhchMFPpIvBTzp0gt+VhnHerY7uHk7ZQKQfg590\n6AS/K/bv1zAS/GzxE+li8JOOWsFfXg7s2wf86U9Orcmg2FjZ1WMg4Rn8RLoY/KSjVvBv2iRD/957\nnVqTQa1bAw0bAkeO6DzErh4i/Rj8pKNW8LtyN08NA9097Ooh0o/BTzpqBb8rH9itwfH8RGZh8JMO\nbfCXlABlZUB4uLNLqltMDFv8RGawOvhzc3MREhKCzp07Y+7cuTqPZ2dnw8/PD5GRkYiMjMTMmTOt\n3STZmTb4N24EBg1yjWmY6xIVJQ9A3zVTJ4OfSD8fa1eQlpaGBQsWICAgAEOGDEFqair8/f1rLdO/\nf3+sXLnS2k2Rg2iD3x26eQB5cLdTJ2DvXnlCFxHVyaqmXHl5OQAgPj4eAQEBSEpKQr6er9yCzS63\nIgTgBY1s8bv6gd0a0dHAtm217mKLn0g/q4K/sLAQwcHB2t9DQ0OxdevWWssoioK8vDxERERg0qRJ\nKC4utmaT5ABCAAGX9gL33QcEBDi7HNNERwPbt+vczeAn0mX3ztuePXvi5MmTKCwsRGhoKNLS0uy9\nSbKSEED4WTfp5qkRFaW3xU9Euqzq4+/VqxfeeOMN7e/79+/H0KFDay3TuHFj7c8vvPAC3n77bdy4\ncQP16tXTWd8777yj/TkhIQEJCQnWlEcWEgIIO5sJJI1zdimmCw8Hfv0VqKjQnmzGrh7yRNnZ2cjO\nzrZqHVYFv5+fHwA5sqd9+/bIzMzE9OnTay1z9uxZ3H///VAUBatWrUJ4eLje0AdqBz85j3KjAl1K\n84AB3zq7FNPVry9nEN2zRw7vvIXBT57m7kZxenq62euwelTPxx9/jDFjxqCyshITJ06Ev78/FixY\nAAAYM2YMMjIyMG/ePPj4+CA8PByzZ8+2dpNkZy1+/Rknm4Shy60PdrdR091zK/jZ1UOknyJcZMiN\noigc/eMi9j00BYdK7sWje8xvSTjV/PlywraFCwHIof0jR8p/iTyVJdnp4mfmkDO03peJ/a3d6MBu\nDT0je9iWINLF4Kfazp1D43NHcbRFrLMrMV9YGHD4MHDtGgB29RAZwuCn2jZuxJmu/aHx9nV2Jear\nV09eh3f3bgAc1UNkCIOfasvMxG/dEt23tXzXGbwMfiJdDH66TQhgwwacCnXz4L/Vz++2fwORnTH4\n6baDBwEvL5Tf38XZlVjurjN42eIn0sXgp9tuzcYpoLhva7l7d+DoUeDqVff9G4jsjMFPt61bB9ya\ncsNtQ/Oee2T479rFg7tEBjD4Sbp2Dfj5ZyApqfalF93RHd09DH4iXQx+kn76SQamn5/7B/+tkT1u\n/TcQ2RGDn6S1a4HkZADwjODfvp1dPUQGMPhJpuOaNcCDD2p/devgDw0FTpyAcuUyg59IDwY/AQcO\nyKQPDQXgAcHv6wuEheHeop3OroTIJTH46XY3z620d/vgB4DoaNy7fztb/ER6MPipVjcP4DnBX29v\nIYOfSA8Gv9qVlwM7dgADBmjv8pjg36d78XUiYvDT2rVAfDzQoIH2Lo8I/uBg+Jw9jUbV5c6uhMjl\nMPjVbvly4NFHa93lEcHv44ObIRHoVsFWP9HdGPxqdv06sGEDMGJErbs9IvgB3AyPRvjNbcYXJFIZ\nBr+abdggT3by9691t6cE/42waIQx+Il0MPjVTE83D+A5wX+zRy+E32DwE92Nwa9WlZXA6tXAI4/o\nPOQpwV8d2BlNNBeACxecXQqRS2Hwq9WmTUCXLsADD+g85CnBDy8v7LunZ60LsxARg1+9vvtObzcP\n4DnBryjAHt9oBj/RXXycXQA5QUWF7N/ftUvvw54U/Lt8ewHbljq7FCKXwha/Gq1dC/ToAbRrp/dh\nTwl+ANjNFj+RDga/Gi1aBDzzjMGHPSX4FQUo8e4IXL0KnDnj7HKIXAaDX23KyoCNG4HHHjO4iKcE\nPwAIKNorchGRxOBXm4wMYMgQwM/P4CKeEvzaK3D16sXgJ7oDg19tvvwSeP75OhfxlKmMtR9ebPET\n1cLgV5MdO4CzZ4GhQ+tczFNa/MCtD7Ga4PeUTzQiKzH41WTBAuCllwBv7zoX85Tg13b1tG0rfzh1\nytklEbkEjuNXi8uXgW+/BfbvN7qoJwW/9oeaVr+BIaxEasIWv1osXAgMHgy0aWN0UU8JfuCO3h0e\n4CXSYovfWjduyDNgT5wASksBX1+geXOga1cgONhot4pDVFYCH34oR/SYwFOCv9bfEB0NzJ3rtFqI\nXIlrBf+mTUCnTq7/dfzcOTnXzbffylZk587y1rw5UFUlHy8qAv74Qw6dfPFFICHBeWn67bdAYKBs\n9ZrAk4Jf2+KPirp9gNcT/jgiK1jd1ZObm4uQkBB07twZcw20qKZOnYrAwEBERUXh4MGDhlc2cCDQ\nvr18Y374IXD0qLXl2daePcBf/iJb81u3Am+8IUfJ7NolPwjmz5fDJVeuBA4flvf36QNMmAB06yZb\n3I4eWaLRAH//O/DmmyY/xZOyUbu7W7cG6tcHjh1zaj1ErsDqFn9aWhoWLFiAgIAADBkyBKmpqfC/\n44pOBQUF2Lx5M7Zt24b169dj8uTJWL16tf6VFRUB27cD33wDfPIJ8PrrQEQE8K9/AT17Wluq5Y4c\nAd56C9i8WYZ4cTHQrJnx57VtC4wfD7zyirza1f/+LzB7NvD550BYmP3rBuS+rF/f6BDOOwkBeHnA\n0R+dD6+afv7AQKfU43Rnz8prMGzeDBw6dHsai0aNgA4dZIOmXz95a97cqaXaxbVr8m++elVOVHjz\nJnDPPfL90aAB0KqV/FcFrAr+8vJyAEB8fDwAICkpCfn5+UhOTtYuk5+fj5SUFDRr1gypqamYNm2a\n4RUGB8vb00/L9Hn5ZdmKjoqSb9Yff5RdKo5y7hwwY4YMz0mTgK++Aho2NH89iiK7fBIT5YfYwIHy\nw+Ctt+QLz15u3gSmTZMHds1owntkix+4PbLniSecVo9T7NkDpKfLqTqGDQP695fdj61ayU/4S5eA\n48eBffuAf/4TeO45OYnf448DKSny25I7OX9efiPfu1f+7UVFwMmTMvhbtZLv4fr1gXr15DG669dv\nz+dUv74cANGpk/yW3q2bbKSFhgI+rtUzbg2r2nWFhYUIDg7W/h4aGoqtW7fWWqagoAChoaHa31u0\naIHi4mLjK1cUYN48ObfM11/L1kqXLrKr5fp1a8o27to1YObM2//ZBw/KkLYk9O/k5SXH0e/cCRQW\nAnFx9u16mD9ftuISEsx+qicEf60+fkAGf0GB0+pxuCtXgDFjgKQkID4eKCkBli4Fxo6VrfpOnWSD\nKiJCXolt2jRg/XrZ4HnzTfkh2a2bfGztWqC62tl/kX7V1TLop08HYmLk3/Xpp8DFi0BysmywHTok\nc+P4cTmkeds2YMsW+e/+/fL+69flt/ulS4Fnn5UfDCtWAE8+Kb/hDxwo99GaNcCtRq+7svtHmBAC\n4q5+bcVAqvj66ru3KYDn4CWexkten2P216+i3tdfY5LXx5jrlWbTWr1ENZ4R/0G6ZhrylL6Y5lWA\nY58FAp/ZdDMA2gJiNdLEx3gzMBYvey3ACq8/23QLbcRpbKv+GwZ7Z+OA3v1qWHU1MGeOTctxCp2X\nWUyM7EqsqnK71ltqqsmDsgAAPcQuLK1+HD8r8Zjs9SsuTfYDJpv67HoAHgLwEBqKK3hi1X/x4op0\ntMJYLPR6EV8ro3BKce4AjBbiHJLEegwR65AoNuAMWuNHZRh+VP6OPKUvKn+6B/jJ3LUqAJrfuoUD\nSNE+0lSUISYnH32y8/AnzEa0GIl9CEOWkoiNXonIRyyqFDPfaDbQpYtlz1PE3alshvLyciQkJGDn\nzp0AgAkTJmDo0KG1unrmzp2LqqoqvPbaawCAoKAgvS1+RVEwbdp07e/9+yegf/8E3Y1WVMDr4w/h\n9fFsiPAe0Lw5FWLQYOuaqBoNlBU/wHtmOkTjxtD8/QOI2N6Wr88MSkE+vJ8ZCU3ycGje/3+ylWEt\nIeD9+KMQ3cOgeWeGRavw8XH/Vn9ZGRAUJAdXaYWGAkuWyFauGxkwQH7pNOXLm7L+R3iPfg7VH34C\n8eRI2xWxaxe8/vU5vL77L0Rsb2hGvQiR/JChFpttVVdDKciH8uM6KOvXQSk+ApEwEJqhwyCShjp+\nJOD161DytkDJyoTXxkzgaDFEv3iIxCRoEofILmk7vYFycrKRk5Ot/X3mzHSdxrVRwkoREREiJydH\nHDt2THTt2lWcP3++1uP5+fmib9++orS0VCxevFgkJyfrXY/Zpdy8KcTXXwsRGipEz55CLFkixLVr\n5q3jyhUhFi4UIiREiF69hPjhByE0GvPWYQtlZUI88oj8Ow4ftn59//ynEOHhQly/bv263FhZmRB+\nfnfdOWqU3D9uJj5eiOxsExb84Qch7r9fiJ9/tl8xV6/K915cnBAtWwrxxhtCFBba/r1z8qQQX30l\nxJNPCtGsmXxNT5kid8SNG7bdlrXOnRPim2+EGD1aiAceECIgQIiXXhIiI0O+EO3Ikhi3Ovizs7NF\ncHCwCAoKEnPmzBFCCDF//nwxf/587TJTpkwRHTp0ED179hQHDhzQX4iln0HV1UKsWCHE4MFCNG0q\nd/x//yvE77/rLqvRyBfTokVCPPusEE2aCJGcLERWlnMC/+7aPvlECH9/Wb+l8vLkOn791Xa1uak/\n/tAT/J9/LsRzzzmlHmv06ydEbq6RhTIzhWjRQoawoxQVyTDu3FmIdu2EmDBBiOXLhTh71rz1aDRC\nFBfL1/748UIEB8uwT0kR4ssvhTh1yj7124NGI8T+/UJ89JEQQ4cK0aiREL17CzF9uhBbtghRWWnT\nzVmSnVZ19diSoijmf1252+nT8mSln36SB26qq+WQSl9fOcKlpEQO1+rbV46wefRReZTflWzfLg8m\nDRoEfPAB0Lix6c/du1dOy/DVV8CDD9qvRjdx8SIQEHDXcbi9e+VFaA4dclpdlujbF/jHP+S/eh08\nKA/gLlsmBw04mhDAgQPyHJbNm4G8PHlAtEsX2e3RurV8LTdsKN+L167JPrgTJ+QAh/375XszOlqe\n+5KYKLvjPGFccUWFzKP16+Ww7hMn5IHipCR569jRqtVbkp2eFfx3EkK+80+dkh8APj7yQ6BJE9tt\nw14uXQLS0oCsLHmU9c9/Nt5fmJkpL6f4ySfyg4NQXi67fi9duuPO6mqgaVMZNm40Vr1PH3lOY58+\neh68eBGIjQWmTAFGj3Z4bXpVV8sRMocPy9u5c3KiwKtX5RDmhg3lxYACAuQ5BMHBrtcIs5czZ+T7\ndcMGefPzkw22gQPlQZw7zoMyBYPf0+TkyBPA6teXb+rkZODee2svc/IkMGuWbGktXSrHaBMAGfht\n294V/IB8k732mtyfbiI2Vn6mx8be9YAQcrhl+/aci8gdaTTA7t2yl2LTJvltqWlTOQItLk5+A+rW\nDbjvPoOrsCQ73WtMm9r07y9fFMuXy3HJL74o3/kdOsgW1YED8iv+88/Ln93h24yD6X0/9O4tx327\nUfBrNAZ6Pb74Qn6r/e47h9dENuDlBURGytvrr8uhxjt2yHMFMjPl+RQVFfKD/dFH5Yl10dHyJDM/\nP9ltZgG2+N3J2bPyxK+SEjnrZ5cu8oNAJaeZm+vyZdm1fOXKXQ+sWQN89JHsSnMTUVFypo+oqDvu\nPHwY+NOfgNxcICTEabWRnWVny5M+T52SXUP79t1+rEcPKLt3s6uHqIbB4C8tlQP8y8pcY9psE0RG\nypk3IiNv3aHRyIO5TzwBTJzo1NrIwS5flo0/Hx+gUSMobduyq4eohs6UDTX8/YGWLWX3mKMmy7OS\nRnPX8f2FC2V33/jxTquJnKRxY9nvbwUPGCtFpF+dA6Fq+vndRK0ZU0tLgbfflnNZecJwR3I4vmrI\noxn8Bty7N/DLLw6txRq1Du6++Sbw1FNuN+0EuQ529ZDHMtjVA8gzodxoJjpt8BcUyBOBioqcXRK5\nMbb4yWPV2dXTvbs8qajmYiQuTqMBvBQhW/vp6XWO6yYyhsFPHs1gi9/bW85Jv3mzQ+uxlEYDNM5d\nIy8y8pe/OLsccnMMfvJYdXb1AHI4ZG6uw+qxhlJdBf8PpsjrJ7vZtQTI9TD4yWMZnQ7djYL/z5f+\nDU3zFm51tjG5Lp7ARR7rxg055NngWe2VlXIGyRMn5L+u6sYN/NawE/BdBtr8+e7JekjtLMlOtvjJ\nYxnt6vH1lcM6t2xxWE0W+b//wyHfbqiKYuiTbTD4Sd1cvbunqgp47z3MaTSN52qRzfClRB7LaIsf\ncP3gX7oUaN8eBff0c/trIJPrYPCTxzIp+GNi5NWfLl92SE1mqa4G3n0XmDbN8LTMRBbgS4nUrX59\noFcv12z1L18u51wfNIjBTzbFlxJ5LJNa/IC8vmtmpt3rMYsQwMyZwLRpgKIw+Mmm+FIij2Vyn3hi\noutdlGX1avkH3Bq3z+AnW+JLiTyaSS3+nj2B336TN1dwV2sfYPCTbfGlRB7L5Ba/tzcwcKDrtPqz\nsuTB5kcf1d7F4Cdb4kuJPJZZwx9dqbtn5kx5oZU7kp7BT7bElxJ5PJMP8GZlmbiwHeXmAqdPA08+\nWetuBj/ZEl9K5PFMyvLAQKBBA2D3brvXU6dZs4CpU3Vm4GTwky3xpURUY/hwYNUq522/oEBeWevZ\nZ3Ue0rnYOpEVGPzk0Uweyw8AI0Y4N/hnzQKmTAHuuUfnoVoXWyeyEqdlJo/m7S2nZzbp2iWVlUDL\nlsC+fUCbNnavrZbdu4Fhw4DiYnk28V18fICKCl6DhXRxWmYia/j6AkOHAmvWOH7b774LvP663tAH\n2MdPtsWXEnk0s7p6ANnPv3Kl3erRq6gI2LQJGDNG78NCyBv7+MlW2NVDHs3XF7h6VW+3uX5//AEE\nBAC//w40bGjX2rSefhro1g146y29D2s0sotHo3FMOeRe2NVDZK2mTYE+feRcOY7w66/Ahg3A+PEG\nF2E3D9kaX07k0czu6gGA1FTgm2/sUo+OWbOAiROB++4zuAiDn2yNXT3k0erVAy5dkv+arLwcaN9e\nXoS9SRO71YYjR+Q1f4uL5bz7BlRUyDIqKuxXCrkvdvUQ6WF2e8LPT07a9v33dqlHa9Ys2cVTR+gD\nbPGT7Vn8crp8+TIefvhhtG/fHo888giuXLmid7kOHTogPDwckZGRiImJsbhQIktY1NUDyO6exYtt\nXo/WkSNy9FBamtFFedYu2ZrFwT9v3jy0b98ehw8fRtu2bTF//ny9yymKguzsbOzcuRMFBQUWF0rk\nUCNGyJOqjh61z/rffhuYNEkeTDaCZ+2SrVn8ciooKMALL7yAevXqYfTo0cjPzze4LPvuyVksbvHf\ne6+cM+eLL2xeEwoLgZ9/Bl591aTF2dVDtmbxCeCFhYUIDg4GAAQHBxtszSuKgoEDB6Jjx44YPXo0\nRowYYekmicymKEBGhpkHd29p3PZ/MGBGAlZ3T4fGx9QTAYwQAgkzp6Dkwek4utq08wSuXmXwk23V\nGfyJiYk4c+aMzv2zZs0yuRW/ZcsWtG7dGkVFRRg+fDhiYmLQqlUrvcu+88472p8TEhKQkJBg0jaI\nDPmf/7FmBoZgBNwTjFOf/YCt7Z6wST09fl+PuJLT+DBkNDTLTX/eiy/aZPPkAbKzs5GdnW3VOiwe\nzvnYY49h2rRpiIyMxPbt2/Hee+8hIyOjzudMmjQJISEheOmll3QL4XBOckXffy/n0SkosP4I640b\nQHg48MEHcmoIIhtw6HDO2NhYLFy4ENevX8fChQvRu3dvnWWuXbuGy5cvAwDOnz+P9evXY+jQoZZu\nksjxHn5wKB3JAAAHuElEQVRY9rX89JP16/rgAyA4mKFPTmdx8I8bNw4lJSXo2rUrTp8+jbFjxwIA\nfvvtNyQnJwMAzpw5g7i4OERERGDkyJF4/fXX0a5dO9tUTuQIXl5yjvy//c26yzIeOwZ89BEwZ47t\naiOyEM/cJTKmqkp20fzjH8BDD5n/fI0GGDwYGDJEfogQ2RDP3CWyBx8f2U0zebK8WIu5Zs+Wz5s8\n2fa1EVmALX4iUwgh++ajooD0dNOft3WrfF5hIdChg93KI/WyJDsZ/ESm+v13ICICWLFCTq5mTEmJ\nnOJ5wQLLuoiITMCuHiJ7at0a+PJL4LHHjE/lcPIkMGgQ8MYbDH1yOQx+InMMHw789a8y1Pft079M\nXh7Qrx8wbpzJ0zIQOZLFUzYQqdbYsfKyjP37y+vkPvWU/DZw6BDw1VeyK+iLL+REb0QuiH38RJYq\nKZGjfdatA0pL5bV6H3kEmDABaN7c2dWRSvDgLhGRyvDgLhERGcXgJyJSGQY/EZHKMPiJiFSGwU9E\npDIMfiIilWHwExGpDIOfiEhlGPxERCrD4CciUhkGPxGRyjD4iYhUhsFPRKQyDH4iIpVh8BMRqQyD\nn4hIZRj8REQqw+AnIlIZBj8Rkcow+ImIVIbBT0SkMgx+IiKVYfATEakMg5+ISGUY/EREKsPgJyJS\nGQY/EZHKWBz83333Hbp16wZvb2/s2LHD4HK5ubkICQlB586dMXfuXEs3R0RENmJx8IeFheH7779H\nfHx8nculpaVhwYIFyMrKwmeffYbS0lJLN6ka2dnZzi7BZXBf3MZ9cRv3hXUsDv7g4GB06dKlzmXK\ny8sBAPHx8QgICEBSUhLy8/Mt3aRq8EV9G/fFbdwXt3FfWMeuffyFhYUIDg7W/h4aGoqtW7fac5NE\nRGSET10PJiYm4syZMzr3v/vuuxg+fLjdiiIiIjsSVkpISBDbt2/X+9jFixdFRESE9vfx48eL1atX\n6102KChIAOCNN954482MW1BQkNm5XWeL31RCCL33+/n5AZAje9q3b4/MzExMnz5d77JHjhyxRSlE\nRGSExX3833//Pdq1a4etW7ciOTkZw4YNAwD89ttvSE5O1i738ccfY8yYMRg8eDBefvll+Pv7W181\nERFZTBGGmutEROSRHHrmriknc02dOhWBgYGIiorCwYMHHVmeQxnbF4sXL0aPHj3Qo0cPPPXUUzh0\n6JATqnQMU0/yKywshI+PD5YvX+7A6hzLlH1RWFiIXr16ISQkBAkJCY4t0IGM7Yvr16/j+eefR2Rk\nJPr3748VK1Y4oUr7Gz16NFq2bImwsDCDy5idm2YfFbBCRESEyMnJEcePHxddu3YV58+fr/V4fn6+\n6Nu3r7hw4YJYsmSJSE5OdmR5DmVsX+Tl5YmLFy8KIYT497//LZ555hlnlOkQxvaFEEJUVVWJAQMG\niOTkZJGRkeGEKh3D2L7QaDSie/fuIjMzUwgh9O4rT2FsX8ybN0+MGzdOCCHE8ePHRWBgoNBoNM4o\n1a5yc3PFjh07RPfu3fU+bkluOqzFb8rJXPn5+UhJSUGzZs2QmpqKoqIiR5XnUKbsiz59+mgPjicn\nJyMnJ8fhdTqCqSf5zZ07FykpKWjRooWjS3QYU/bFtm3bEB4ejsGDBwOAxx4zM2Vf+Pn54fLly6is\nrERZWRkaNGgARVGcUa5dxcXFoWnTpgYftyQ3HRb8ppzMVVBQgNDQUO3vLVq0QHFxsaNKdBhzT2z7\n/PPPPfa8CVP2xenTp7FixQqMGzcOADzyzQ2Yti/Wr18PRVEQFxeH4cOHY/369Y4u0yFM2Repqamo\nrq6Gv78/+vXrh8WLFzu6TJdgSW7aZDinrQghdIaGeuqb3FRZWVlYtGgR8vLynF2K07z66qt4//33\noSiK3teImlRUVGDXrl3IysrCtWvXkJiYiH379qF+/frOLs3hPv30U/j4+OD333/H3r17kZycjBMn\nTsDLS12TDluSmw7bQ7169ap10GH//v3o3bt3rWViY2Nx4MAB7e/nz59HYGCgo0p0GFP2BQDs2bMH\nY8eOxcqVK9GkSRNHlugwpuyL7du3Y+TIkejYsSOWLVuGl19+GStXrnR0qXZnyr7o06cPhg0bhlat\nWiEwMBDR0dHIzc11dKl2Z8q+yM3NxdNPP40GDRogNjYWbdq08ehBEIZYkpsOC/47T+Y6fvw4MjMz\nERsbW2uZ2NhYLFu2DBcuXMCSJUsQEhLiqPIcypR9UVJSgsceewyLFy9Gp06dnFGmQ5iyL44ePYpj\nx47h2LFjSElJwbx58zBixAhnlGtXpuyL3r17IycnB9euXUNZWRl27tyJvn37OqNcuzJlXwwaNAir\nVq2CRqPB0aNHUVZWVqt7SC0syU2HdvXUnMxVWVmJiRMnwt/fHwsWLAAAjBkzBjExMejXrx+io6PR\nrFkzLFq0yJHlOZSxfTFjxgyUlZVh7NixAABfX18UFBQ4s2S7MbYv1MTYvmjevDlGjRqF6OhotGjR\nAjNmzECjRo2cXLV9GNsXI0eOxIEDB7T7Ys6cOU6u2D5SU1ORk5OD0tJStGvXDunp6aisrARgeW7y\nBC4iIpVR11EQIiJi8BMRqQ2Dn4hIZRj8REQqw+AnIlIZBj8Rkcow+ImIVIbBT0SkMv8fsrmNQhBd\nxXsAAAAASUVORK5CYII=\n", - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "iVBORw0KGgoAAAANSUhEUgAAAXsAAAEACAYAAABS29YJAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAHo1JREFUeJzt3Xt01OWdx/H3BCQUuRRFgrswgpDmAkoC5oIYElAhoiEB\nRMoKWBOtRm1A4NSzqy3Y3SMFbSGgCdjdWC3HWo/dKiIKJDZAUJJwKSiEkggt4HIRRJ0IKMLsH49M\nQLkkk8k8c/m8zpkzYTK/zHfmcD558v09v+dxuN1uNyIiEtIibBcgIiItT2EvIhIGFPYiImFAYS8i\nEgYU9iIiYUBhLyISBi4a9rm5uURFRXHdddd5HnO5XGRnZ+N0OsnJyaG+vt7zvQULFhAdHU18fDwV\nFRWex2tqahgwYADXXnstjz/+eAu8DRERuZiLhv29997LO++8c85jxcXFOJ1Oamtr6d69O4sWLQLg\n0KFDFBUVUVZWRnFxMQUFBZ5jpk+fzmOPPUZ1dTWrV69mw4YNLfBWRETkQi4a9mlpaXTu3Pmcx6qq\nqsjLyyMyMpLc3FwqKysBqKysJDMzE6fTSXp6Om632zPq//vf/8748eO58sorGTNmjOcYERHxjyb3\n7Kurq4mNjQUgNjaWqqoqwIR9XFyc53kxMTFUVlZSV1dH165dPY/Hx8ezfv365tYtIiJN0OSwb8rq\nCg6Ho1nHi4iIb7Ru6gFJSUnU1NSQmJhITU0NSUlJAKSkpFBaWup53o4dO0hKSqJDhw4cPHjQ8/j2\n7dtJTU0978/u06cPH330UVNLEhEJa71796auru6iz2nyyD4lJYWSkhKOHz9OSUmJJ7iTk5NZsWIF\ne/bsoby8nIiICDp06ACYds8rr7zC4cOH+ctf/kJKSsp5f/ZHH32E2+3Wze1m5syZ1msIlJs+C30W\n+iwufmvMIPmiYT9hwgRuvPFGdu7cSY8ePXjhhRfIz89nz549xMTE8PHHH/Pggw8CEBUVRX5+PsOG\nDeOhhx6isLDQ83OeeeYZ5s6dS1JSEmlpadxwww2N+80iIiI+cdE2zh//+MfzPv7GG2+c9/EpU6Yw\nZcqU7z0eHx/Ppk2bvChPRER8QVfQBqiMjAzbJQQMfRYN9Fk00GfRNA632x0w02McDgcBVI6ISFBo\nTHZqZC8iEgYU9iIiYSDgwn7XLtsViIiEnoAL+2HDFPgiIr4WcGH/2GMwdKgCX0TEl5q8XEJLy88H\nh8ME/rvvQu/etisSEQl+ARf2AN9elMuwYQp8ERFfCMiwBxP4DocCX0TEFwI27AEeeODclk6fPrYr\nEhEJTgEd9gA//am5PzPCV+CLiDRdwIc9KPBFRJorKMIeTOCf6eGXlUF0tO2KRESCR9CEPcD99597\n0laBLyLSOEEV9gD33WfuFfgiIo0XdGEPJvDPbun86Ee2KxIRCWxBGfYAeXkm8G++WYEvInIpQRv2\nALm55l6BLyJycUEd9mAC/+yWTkyM7YpERAJP0Ic9wL33mvszI3wFvojIuUIi7MEE/tk9fAW+iEiD\nkAl7gJ/8pCHwS0shNtZ2RSIigSGkwh7gnnvM/ZkRvgJfRCQEwx4U+CIi3xWSYQ8m8M9u6cTF2a5I\nRMSekA17gMmTTeDfcgusWgXx8bYrEhGxI6TDHmDSJBP4t96qwBeR8BXyYQ8wcaK5v+UW09JR4ItI\nuAmLsAcT+Ge3dPr2tV2RiIj/hE3YA9x9t7k/09JR4ItIuAirsAcT+Gf38BX4IhIOwi7sAf7t38z9\nrbfCypXQr5/dekREWlpYhj2YwD97hK/AF5FQFrZhDzBhgrlX4ItIqAvrsAcT+GdG+CtXwnXX2a5I\nRMT3Irw98He/+x033ngjAwcOZOrUqQC4XC6ys7NxOp3k5ORQX1/vef6CBQuIjo4mPj6eioqK5lfu\nQz/+McyfD8OHw9attqsREfE9r8L+008/5amnnmLVqlVUV1ezc+dOVqxYQXFxMU6nk9raWrp3786i\nRYsAOHToEEVFRZSVlVFcXExBQYFP34QvjB9vAn/ECAW+iIQer8L+Bz/4AW63m88//5zjx49z7Ngx\nfvjDH1JVVUVeXh6RkZHk5uZSWVkJQGVlJZmZmTidTtLT03G73bhcLp++EV8YPx4KCxX4IhJ6vA77\n4uJievbsSbdu3Rg8eDApKSlUV1cT++16wrGxsVRVVQEm7OPOWnYyJibG871Ac9ddJvCHD4ctW2xX\nIyLiG16doP3kk0/Iz89n+/btdO7cmXHjxrFs2TLcbnejf4bD4Tjv47NmzfJ8nZGRQUZGhjclNstd\nd5mTtiNGwIoV0L+/30sQEbmg8vJyysvLm3SMV2FfVVVFamoqffr0AWDcuHGsXbuWpKQkampqSExM\npKamhqSkJABSUlIoLS31HL9jxw7P977r7LC3adw4c6/AF5FA892B8JNPPnnJY7xq46SlpbFhwwY+\n/fRTvvrqK95++22GDx9OSkoKJSUlHD9+nJKSElJTUwFITk5mxYoV7Nmzh/LyciIiIujQoYM3L+1X\n48bBs8+awP/b32xXIyLiPa9G9h07duSJJ55g9OjRHDt2jMzMTIYOHUpycjITJ04kJiaGAQMGMGfO\nHACioqLIz89n2LBhtGnThsWLF/v0TbSkO+8095mZ8M47kJBgtx4REW843E1ptLcwh8PRpL6/P/35\nz/Dww/D225CYaLsaEZEGjcnOsL+CtrHGjjX3t92mwBeR4KOwb4KxY80sHQW+iAQbhX0TjRnTEPjL\nl8OAAbYrEhG5NIW9F0aPNvdnRvgKfBEJdAp7LynwRSSYKOybYfToc1s6AwfarkhE5PwU9s2Uk2MC\nf+RIeOstuOEG2xWJiHyfwt4HsrPN/e23K/BFJDAp7H0kO9uM8BX4IhKIFPY+NGpUQ+AvWwYXWOtN\nRMTvvN6WUM4vKwv++79N4Afokv0iEoYU9i0gKwv+53/gjjsU+CISGBT2LSQrC0pKzL0CX0RsU9i3\noDvuaBjhf7sdr4iIFQr7FnbHHfDCC2aEr8AXEVsU9n5w++3w+9+bwF+/3nY1IhKOFPZ+MnKkCfxR\noxT4IuJ/Cns/UuCLiC0Kez8bORJefNEE/vvv265GRMKFwt6C226Dl14ySyy8957takQkHCjsLcnM\nNIGfk6PAF5GWp7C3KDMT/vAHBb6ItDyFvWUjRjQE/rp1tqsRkVClsA8AZwJ/9GioqLBdjYiEIoV9\ngBgxApYsgTFjFPgi4nsK+wAyfHhD4K9aZbsaEQklCvsAM3w4vPYaTJoECxeC2227IhEJBQ63O3Di\nxOFwEEDlWLVrl7nwavBgE/pt2tiuSEQCVWOyUyP7AHXttWY65v/9nxntHz5suyIRCWYK+wDWsSO8\n/jqkpkJyMnz4oe2KRCRYqY0TJJYsgUcfNZuhjBpluxoRCSSNyc7WfqpFmmniRIiONjN1amrg5z8H\nh8N2VSISLDSyDzL79pkF1OLj4Xe/g7ZtbVckIrbpBG0I6t4d1q6Fr7+GjAzYv992RSISDBT2Qahd\nO3jlFbPdYXIybNxouyIRCXReh/2XX37JPffcw49+9CPi4+OprKzE5XKRnZ2N0+kkJyeH+vp6z/MX\nLFhAdHQ08fHxVGg9gGZzOOAXv4D5883qmX/6k+2KRCSQeR32M2fOxOl0snXrVrZu3UpsbCzFxcU4\nnU5qa2vp3r07ixYtAuDQoUMUFRVRVlZGcXExBQUFPnsD4W7sWLO0ws9/Dr/8JZw+bbsiEQlEXod9\naWkp//Ef/0Hbtm1p3bo1nTp1oqqqiry8PCIjI8nNzaWyshKAyspKMjMzcTqdpKen43a7cblcPnsT\n4S4hAaqqoKwMxo2DL7+0XZGIBBqvwn7fvn2cOHGC/Px8UlJSmDNnDsePH6e6uprY2FgAYmNjqaqq\nAkzYx8XFeY6PiYnxfE98IyoK3n3XXIg1eDD885+2KxKRQOJV2J84cYKdO3cyduxYysvL2bZtG6++\n+mqTpk06NEnc5yIjoaTELKI2aJA2QxGRBl5dVNWnTx9iYmLIysoCYMKECbz00kskJSVRU1NDYmIi\nNTU1JCUlAZCSkkJpaann+B07dni+912zZs3yfJ2RkUFGRoY3JYYthwOmTzfz8EePhrlz4Sc/sV2V\niPhSeXk55eXlTTrG64uqRo0axeOPP05SUhIFBQUkJiZy5MgR9u7dy9y5c5kxYwa9evVixowZHDx4\nkPT0dFauXMmuXbuYNm0amzZt+n4xuqjKp2pqICvLbHk4Zw60amW7IhFpCY3JTq/DfufOnUyePJkT\nJ05wyy238OSTT3L69GkmTpzI5s2bGTBgAEuWLKF9+/YAFBYWsnDhQtq0acPixYtJS0vzqmBpmiNH\n4K67TIvnj3+ETp1sVyQivtaiYd8SFPYt4+RJs4haWRksXWrW2BGR0KHlEgSAyy6DZ5+FKVPgpptM\n6ItIeFHYh5EHHzTLLNx9Nzz3nO1qRMSf1MYJQx99ZNbEHzIEFiwwI38RCV5q48h59e4N778Pe/ea\nLQ+PHLFdkYi0NIV9mOrYEd54A5KSzMqZ27bZrkhEWpLCPoy1amUuupo506yNv2yZ7YpEpKWoZy+A\naevceSdMnQozZmjLQ5Fgonn20iR795otD/v1g+ef15aHIsFCJ2ilSXr0MFseHj8OQ4fCgQO2KxIR\nX1HYyzkuv9zsepWZaU7cnmcJIxEJQmrjyAW99hrk50NRkdkURUQCk3r20mybN5s+fm6u2fYwQn8L\nigQchb34xIEDZm38f/1XePFF0+oRkcChE7TiE926wV//akL+pptgzx7bFYlIUynspVHatoXf/94s\nopaaaubli0jwUBtHmuytt+Dee+Hpp+Gee2xXIyLq2UuL2b7dbHk4Zgz8+tfa8lDEJoW9tKgjR8wS\nC+3amS0PO3a0XZFIeNIJWmlRV14JK1fCNdeYPn5dne2KRORCFPbSLJddZi66euQRGDzYzNoRkcCj\nsBefeOgh08r58Y+huNh2NSLyXerZi0/V1ZkTt8OGwfz52vJQxB/Usxe/69MH1q+H3bthxAhteSgS\nKBT24nOdOsGbb8LAgZCSAjU1tisSEYW9tIhWrcxFV7/4BaSnw/LltisSCW/q2UuLe+89Mx9/2jSY\nPl1bHor4mi6qkoCxZw+MGgUJCbB4MURG2q5IJHToBK0EDKcT1q2D+npteShig8Je/Obyy+HVV+HW\nW82J282bbVckEj7UxhErXn0VHn4YFi2CsWNtVyMS3NSzl4C2cSPk5MD995tZOzpxK+Idhb0EvP37\nzZaHTqfZHKVdO9sViQQfnaCVgHf11VBebnbCSkuDfftsVyQSmhT2Yl3btmYj8/HjzYnb9ettVyQS\netTGkYCybJnZ8vC3v4VJk2xXIxIc1LOXoPThh+YCrHHj4KmntOWhyKW0eM/+1KlTJCYmkpWVBYDL\n5SI7Oxun00lOTg719fWe5y5YsIDo6Gji4+OpqKhozstKiOvXD6qqoLISsrPh6FHbFYkEv2aFfWFh\nIfHx8Ti+nTNXXFyM0+mktraW7t27s2jRIgAOHTpEUVERZWVlFBcXU1BQ0PzKJaR16WK2POzTB/r2\nNRuj6I8+Ee95Hfb79u1j+fLl3HfffZ4/H6qqqsjLyyMyMpLc3FwqKysBqKysJDMzE6fTSXp6Om63\nG5fL5Zt3ICGrTRuzAcqf/wyzZ8Ntt8GuXbarEglOXof9o48+ytNPP01ERMOPqK6uJjY2FoDY2Fiq\nqqoAE/ZxcXGe58XExHi+J3IpgwaZC7CGDoXkZJgzB06etF2VSHDxKuyXLVtG165dSUxMPOekQFNO\nrjp0uaQ0wWWXwWOPmV7+X/9qNkbRFE2RxmvtzUHvvfceS5cuZfny5Zw4cYIvvviCSZMmkZSURE1N\nDYmJidTU1JCUlARASkoKpaWlnuN37Njh+d53zZo1y/N1RkYGGRkZ3pQoIeraa+Htt+FPf4IxY8xy\nC7Nnm92xRMJFeXk55eXlTTqm2VMvV69ezTPPPMObb77J3Llz2bt3L3PnzmXGjBn06tWLGTNmcPDg\nQdLT01m5ciW7du1i2rRpbNq06fvFaOqlNMHRo2a0/9Zbprd/551aX0fCk9+WSzjTksnPz2fPnj3E\nxMTw8ccf8+CDDwIQFRVFfn4+w4YN46GHHqKwsNAXLythrnNneP55M8qfNQuysuCf/7RdlUhg0kVV\nEhK+/trseTtvHvz7v8OUKdDaqyalSPDRFbQSdurq4MEH4cgRM+q/wKkhkZCiVS8l7PTpA6tWmc3N\ns7KgoAC++MJ2VSL2Kewl5DgcZhG1bdvgyy/NFbivv267KhG71MaRkLd6NTzwAMTGwsKF0KOH7YpE\nfEttHBEgPR22bIHERHMrLIRTp2xXJeJfGtlLWNmxw5zAra83J3AHDLBdkUjzaWQv8h2xsWa5hYcf\nNgurTZ9ugl8k1CnsJew4HGY3rA8/hE8+MSdwly2zXZVIy1IbR8JeWZlp7SQkmH7+v/yL7YpEmkZt\nHJFGuPlm2LrVtHj694fnntMJXAk9GtmLnGX7dvjpT+Gbb8wJ3Ouvt12RyKVpZC/SRPHxsGYN5OXB\nLbeYVTWPHbNdlUjzKexFviMiAu6/Hz74APbuNRugv/OO7apEmkdtHJFLWLECHnrILKo2fz5062a7\nIpFzqY0j4gMjRphRfq9epof//PNw+rTtqkSaRiN7kSb44ANzArdVK1i82MzRF7FNI3sRH7vuOli3\nDu6+GzIy4PHH4fhx21WJXJrCXqSJIiIgP98srlZba34BlJbarkrk4tTGEWmmt94ya+2kpcFvfgNd\nu9quSMKN2jgifnD77WajlKgoM8ovKQGNWSTQaGQv4kObN5uNUn7wA3MCNzbWdkUSDjSyF/GzxER4\n/32480646SaYORNOnLBdlYjCXsTnWrWCn/0M/vY3M1Wzf3+zhr6ITWrjiLSwN94w4X/zzfD009Cl\ni+2KJNSojSMSALKzzQncTp3MOjsvvaQTuOJ/GtmL+NGGDeYK3M6dYdEiiI62XZGEAo3sRQLMDTdA\nVRXccQcMGgT/9V/w9de2q5JwoLAX8bPWreHRR2HjRqisNNshrl1ruyoJdWrjiFjkdsP//i9MmQK3\n3QZz5sAVV9iuSoKN2jgiAc7hgLFjzQncyEiziubLL+sErvieRvYiAWT9enMFbrduUFQEvXvbrkiC\ngUb2IkEmNdXM2Ln5ZkhJgV//Gk6etF2VhAKN7EUC1O7dZjvEffvM7liDBtmuSAJVY7JTYS8SwNxu\nePVVM3snOxt++Uu4+mrbVUmgURtHJMg5HDB+PGzfDm3aQHy82SWrstJ2ZRJsNLIXCSKffWbWy3/u\nObPGzs9+BuPGmZk8Er5abGS/d+9ehg4dSt++fcnIyODll18GwOVykZ2djdPpJCcnh/r6es8xCxYs\nIDo6mvj4eCoqKrx5WZGw98MfwrRpsHMnPPEEvPgi9OwJs2bB/v22q5NA5lXYX3bZZcybN49t27bx\n2muv8cQTT+ByuSguLsbpdFJbW0v37t1ZtGgRAIcOHaKoqIiysjKKi4spKCjw6ZsQCTetWkFWFqxa\nBWVlcOiQWjxycV6Ffbdu3UhISACgS5cu9O3bl+rqaqqqqsjLyyMyMpLc3Fwqv/1fV1lZSWZmJk6n\nk/T0dNxuNy6Xy3fvQiSMxcebOfm7d8PAgTBhgpm2uWQJfPWV7eokUDT7BG1dXR3btm0jOTmZ6upq\nYr/dhy02NpaqqirAhH1cXJznmJiYGM/3RMQ3zrR4amvV4pHva92cg10uF+PHj2fevHm0b9++SSdX\nHQ7HeR+fNWuW5+uMjAwyMjKaU6JI2DnT4snKMrN4nn3WjP5HjoSCAjPql+BWXl5OeXl50w5ye+nr\nr79233rrre558+Z5HhszZox706ZNbrfb7d6wYYN77Nixbrfb7V66dKm7oKDA87z+/fu7v/jii+/9\nzGaUIyIXcfSo2/2b37jdvXq53cnJbvcf/uB2nzhhuyrxlcZkp1dtHLfbTV5eHv369WPq1Kmex1NS\nUigpKeH48eOUlJSQmpoKQHJyMitWrGDPnj2Ul5cTERFBhw4dvHlpEfGCWjzi1Tz7iooKhgwZwvXX\nX+9px8yePZvBgwczceJENm/ezIABA1iyZAnt27cHoLCwkIULF9KmTRsWL15MWlra94vRPHsRv9m+\nHRYuhFdeUYsn2Gm5BBG5pKNH4YUXTG//qqt0oVYwUtiLSKOdOgXLl8OCBfDhh2ap5Qce0Fo8wUBr\n44hIo333Qq2DB3WhVijRyF5ELkgtnuCgNo6I+MSpU/DWW+aErlo8gUdtHBHxiVatYNQo0+IpLVWL\nJxhpZC8iXlGLJ3CojSMiLU4tHvvUxhGRFqcWT3DQyF5EfE4tHv9SG0dErFKLxz/UxhERqy7U4pk4\nUS0ef9PIXkT86ujRhk3Tr7rKLMA2bhy0aWO7suClNo6IBKwzLZ4FC2DbNrV4mkNtHBEJWGdaPKWl\navH4g0b2IhIw1OLxjto4IhKU1OJpGrVxRCQoqcXjexrZi0hQOLvF06WL+WUwZAgkJ0Pbtrars0tt\nHBEJOadOwcqVZsS/Zg3U1MCAASb4hwyBQYOgQwfbVfqXwl5EQp7LBe+/b4J/zRrYuBH69m0I/5tu\ngiuusF1ly1LYi0jYOXECqqoawv/996FXr4bwT0sLvRO9CnsRCXsnT8LmzQ3hX1Fhev5nwn/IELjm\nGnA4bFfqPYW9iMh3nD5tFmU7E/5r1ph5/GeHf0xMcIW/wl5E5BLcbqitPTf8jx0z7Z4z4X/99WY6\naKBS2IuIeGHPHli7tiH89++HwYMbwn/gwMC6qldhLyLiAwcPml7/mfCvqzPz+8+Ef0oKtGtnrz6F\nvYhIC/jsM1i3riH8t26FhISG8L/xRujUyX/1KOxFRPzgyy9h/fqG8K+uNid5z57rf9VVLff6CnsR\nEQu++go2bDDBv3at+Suge/dzT/p27+6711PYi4gEgG++Ma2es2f8dOx47nTP3r29n+6psBcRCUCn\nT8OOHQ3Bv3q1mQJ6dvjHx0NEI9clVtiLiAQBtxt27z535H/06Lltn4QEaN36/Mcr7EVEgtTHHzfM\n9V+71sz9HzSoIfyTkiAy0jxXYS8iEiKOHDl3rn9NDdxwgwn+//xPhb2ISEj64guzoufq1TB7doBt\nS7hmzRri4uKIjo5m4cKF/nxpEZGQ0rEjjBgBTz3VuOf7NeynTJnC4sWLKS0t5bnnnuPw4cP+fPmg\nUl5ebruEgKHPooE+iwb6LJrGb2H/+eefAzBkyBCuueYahg8fTqV2Dr4g/UduoM+igT6LBvosmsZv\nYV9dXU1sbKzn3/Hx8axfv95fLy8iEtb82sYRERFL3H7y2WefuRMSEjz/fuSRR9zLli075zm9e/d2\nA7rppptuujXh1rt370tm8AWux/K9Tt+u97lmzRqcTierVq1i5syZ5zynrq7OX+WIiIQVv4U9wPz5\n83nggQc4efIkBQUFdOnSxZ8vLyIStgLqoioREWkZAXGCVhdbNcjNzSUqKorrrrvOdilW7d27l6FD\nh9K3b18yMjJ4+eWXbZdkzYkTJ0hJSSEhIYHU1FTmzZtnuyTrTp06RWJiIllZWbZLsapnz55cf/31\nJCYmkpycfNHnBsTIPjExkcLCQq655hpGjBhBRUVF2LZ41q5dS/v27Zk8eTIffPCB7XKsOXDgAAcO\nHCAhIYHDhw+TnJzMli1b6NChg+3SrDh27Bjt2rXjq6++YuDAgbz++uv06dPHdlnW/Pa3v2Xjxo24\nXC6WLl1quxxrevXqxcaNG7niiisu+VzrI3tdbHWutLQ0OnfubLsM67p160ZCQgIAXbp0oW/fvmzY\nsMFyVfa0+3Y36/r6er755hsizyx3GIb27dvH8uXLue+++7SWFjT6M7Ae9rrYSi6lrq6Obdu2XfLP\n1FB2+vRp+vfvT1RUFI888gg9evSwXZI1jz76KE8//TQRjd3ZI4Q5HA6GDRtGTk7OJf/C0aclAc3l\ncjF+/HjmzZvH5ZdfbrscayIiItiyZQt1dXUUFRWxefNm2yVZsWzZMrp27UpiYqJG9cC6devYsmUL\ns2fPZtq0aRw4cOCCz7Ue9klJSezYscPz723btpGammqxIgkUJ0+eZOzYsUyaNIns7Gzb5QSEnj17\nMnLkyLBtdb733nssXbqUXr16MWHCBN59910mT55suyxrrr76agDi4uIYNWoUb7755gWfaz3sz77Y\n6h//+AerVq0iJSXFclVim9vtJi8vj379+jF16lTb5Vh1+PBhPvvsMwCOHDnCypUrw/aX31NPPcXe\nvXvZvXs3r7zyCsOGDeOll16yXZYVx44dw+VyAfDJJ5+wYsUKMjMzL/h8v15UdSG62KrBhAkTWL16\nNUeOHKFHjx786le/4t5777Vdlt+tW7eOJUuWeKaVAcyePfui/5lD1f79+7nnnns4deoU3bp1Y8aM\nGZ4RXbhzOBy2S7Dm4MGDjB49GoArr7yS6dOnX/RcTkBMvRQRkZZlvY0jIiItT2EvIhIGFPYiImFA\nYS8iEgYU9iIiYUBhLyISBhT2IiJhQGEvIhIG/h+tMGlORAtokQAAAABJRU5ErkJggg==\n", - "text": [ - "" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "FUN = SimPEG.tests.getQuadratic(sp.identity(2),np.array([-5,-5]))\n", - "# FUN = SimPEG.tests.Rosenbrock\n", - "\n", - "f = FUN(np.array([1,2]))\n", - "print f\n", - "n,l,u = 50,-10,10\n", - "I = np.zeros((n,n))\n", - "X = np.linspace(l,u,n)\n", - "for i, x in enumerate(X):\n", - " for j, y in enumerate(X):\n", - " f, g, H = FUN(np.array([x,y]))\n", - " I[i,j] = f\n", - "\n", - "colorbar(contourf(X,X, I.T))\n", - "\n", - "GN = inverse.GaussNewton()\n", - "xopt = GN.minimize(FUN,np.array([0,0]))\n", - "print xopt" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "(-12.5, array([-4., -3.]), <2x2 sparse matrix of type ''\n", - "\twith 2 stored elements (1 diagonals) in DIAgonal format>)\n", - "=========== Gauss Newton ===========" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " # f |proj(x-g)-x| LS \n", - "-----------------------------------\n", - " 0 0.00e+00 7.07e+00 0 \n", - " 1 -2.50e+01 0.00e+00 0 \n", - "------------------------- STOP! -------------------------\n", - "0 : |fc-fOld| = 2.5000e+01 <= tolF*(1+|f0|) = 1.0000e-01\n", - "0 : |xc-x_last| = 7.0711e+00 <= tolX*(1+|x0|) = 1.0000e-01\n", - "1 : |proj(x-g)-x| = 0.0000e+00 <= tolG = 1.0000e-01\n", - "1 : |proj(x-g)-x| = 0.0000e+00 <= 1e3*eps = 1.0000e-02\n", - "0 : maxIter = 20 <= iter = 1\n", - "------------------------- DONE! -------------------------\n", - "[ 5. 5.]\n" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "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\nBFYAAAAASUVORK5CYII=\n", - "text": [ - "" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "opt = inverse.ProjectedGradient(maxIter=50,maxStep=np.inf, maxIterLS=20, debug=False)\n", - "opt.remember('f')\n", - "opt.lower = -2\n", - "opt.upper = 2\n", - "opt.minimize(FUN,np.array([0,0]))" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "======================= Projected Gradient =======================\n", - " # f |proj(x-g)-x| LS itType aSet bSet Comment\n", - "------------------------------------------------------------------\n", - " 0 0.00e+00 2.83e+00 0 SD 0 0 \n", - " 1 -1.60e+01 0.00e+00 0 SD 2 2 \n", - "------------------------- STOP! -------------------------\n", - "0 : |fc-fOld| = 1.6000e+01 <= tolF*(1+|f0|) = 1.0000e-01\n", - "0 : |xc-x_last| = 2.8284e+00 <= tolX*(1+|x0|) = 1.0000e-01\n", - "1 : |proj(x-g)-x| = 0.0000e+00 <= tolG = 1.0000e-01\n", - "1 : |proj(x-g)-x| = 0.0000e+00 <= 1e3*eps = 1.0000e-02\n", - "0 : maxIter = 50 <= iter = 1\n", - "1 : probSize = 2 <= bindingSet = 2\n", - "------------------------- DONE! -------------------------\n" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 7, - "text": [ - "array([ 2., 2.])" - ] - } - ], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "opt = inverse.ProjectedGradient(maxIter=50, maxStep=0.3,debug=False, maxIterLS=20, tolCG=1e-5, maxIterCG=1000)\n", - "opt.lower, opt.upper = -0.4, 0.9\n", - "opt.remember('f', 'xc', ('norm_g', lambda M: np.linalg.norm(M.g)), 'phi_d', 'phi_m')\n", - "inv = inverse.Inversion(prob,reg,opt,beta0=1e-3,debug=False)\n", - "inv.remember(('phi_d',lambda I:I.opt.recall('phi_d')),('phi_m',lambda I:I.opt.recall('phi_m')))\n", - "m0 = np.zeros_like(m_true)\n", - "mrecB = inv.run(m0)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "====================================== Projected Gradient ======================================\n", - " # beta phi_d phi_m f |proj(x-g)-x| LS itType aSet bSet Comment\n", - "------------------------------------------------------------------------------------------------\n", - " 0 1.00e-03 9.62e+02 0.00e+00 9.62e+02 2.14e+01 0 SD 0 0 \n", - " 1 1.00e-03 9.53e+02 8.49e-03 9.53e+02 2.18e+01 9 SD 0 0 \n", - " 2 1.00e-03 5.32e+02 1.42e+03 5.33e+02 2.20e+01 0 .CG. 0 0 " - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " 3 1.00e-03 2.32e+02 5.66e+03 2.38e+02 2.26e+01 0 .CG. 0 0 " - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " 4 1.00e-03 1.29e+02 8.85e+03 1.38e+02 2.30e+01 1 .CG. 0 0 " - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " 5 1.00e-03 1.10e+02 9.74e+03 1.20e+02 2.15e+01 3 .CG. 22 22 " - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " 6 1.00e-03 1.09e+02 9.74e+03 1.19e+02 2.36e+01 10 SD 22 0 Stop SD\n", - " 7 1.00e-03 7.65e+01 1.33e+04 8.98e+01 2.21e+01 1 .CG. 85 75 " - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " 8 1.00e-03 5.11e+01 1.33e+04 6.44e+01 2.38e+01 9 SD 75 3 \n", - " 9 1.00e-03 5.07e+01 1.33e+04 6.41e+01 2.11e+01 12 SD 4 4 \n", - " 10 1.00e-03 5.06e+01 1.33e+04 6.40e+01 2.20e+01 12 SD 17 9 Stop SD\n", - " 11 1.00e-03 5.04e+01 1.34e+04 6.37e+01 2.05e+01 8 .CG. 85 81 " - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " 12 1.00e-03 5.03e+01 1.34e+04 6.37e+01 1.65e+01 13 SD 81 26 \n", - " 13 1.00e-03 5.03e+01 1.34e+04 6.37e+01 1.67e+01 15 SD 30 30 \n", - " 14 1.00e-03 5.03e+01 1.34e+04 6.36e+01 1.42e+01 15 SD 84 84 Stop SD\n", - " 15 1.00e-03 2.65e+01 2.26e+04 4.91e+01 2.52e+01 0 .CG. 190 50 " - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - " 16 1.00e-03 1.51e+01 2.26e+04 3.77e+01 2.24e+01 10 SD 50 1 \n", - "------------------------- STOP! -------------------------\n", - "1 : |fc-fOld| = 1.1392e+01 <= tolF*(1+|f0|) = 9.6325e+01\n", - "1 : |xc-x_last| = 3.4809e-03 <= tolX*(1+|x0|) = 1.0000e-01\n", - "0 : |proj(x-g)-x| = 2.2369e+01 <= tolG = 1.0000e-01\n", - "0 : |proj(x-g)-x| = 2.2369e+01 <= 1e3*eps = 1.0000e-02\n", - "0 : maxIter = 50 <= iter = 16\n", - "0 : probSize = 1000 <= bindingSet = 1\n", - "1 : phi_d = 1.5077e+01 <= phi_d_target = 2.0000e+01 \n", - "------------------------- DONE! -------------------------\n", - "-------------------------STOP!-------------------------\n", - "0 : maxIter = 10 <= iter = 1\n", - "1 : phi_d = 1.5077e+01 <= phi_d_target = 2.0000e+01 \n", - "-------------------------DONE!-------------------------\n" - ] - } - ], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# First set up the figure, the axis, and the plot element we want to animate\n", - "fig = plt.figure()\n", - "ax = plt.axes()\n", - "ax.plot(M.vectorCCx, m_true, 'b-')\n", - "txt = plt.text(0.8,0.9,'')\n", - "line, = ax.plot([], [], 'r-', lw=1)\n", - "\n", - "def animate(i):\n", - " txt.set_text('iteration %d'%i)\n", - " line.set_data(M.vectorCCx, np.array(opt.recall('xc')[i]))\n", - "\n", - "SimPEG.utils.animate(fig, animate, frames=len(opt.recall('xc')))" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 9, - "text": [ - "" - ] - } - ], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "plot(opt.recall('phi_d'))" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 10, - "text": [ - "[]" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ] - } - ], - "prompt_number": 10 - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/notebooks/SliceThroughModel.ipynb b/notebooks/SliceThroughModel.ipynb deleted file mode 100644 index 1259ebf6..00000000 --- a/notebooks/SliceThroughModel.ipynb +++ /dev/null @@ -1,3048 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from SimPEG import mesh, utils\n", - "sz = [10,20,30]\n", - "M = mesh.TensorMesh(sz)\n", - "mtrue = utils.ModelBuilder.randomModel(sz,seed=786,its=20)\n", - "M.videoSlicer(utils.mkvc(mtrue), normal='x')" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 2, - "text": [ - "" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "models = [utils.ModelBuilder.randomModel(sz,seed=786,its=i) for i in range(40)]" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def function(var, ax, clim, tlt, i):\n", - " p = M.slicer(var, normal='y', index=5, imageType='CC', ax=ax, clim=clim)\n", - " tlt.set_text('%d smoothing iterations'%(i))\n", - " return p\n", - " \n", - "M.video(models,function)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 5, - "text": [ - "" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/notebooks/VisualizeWithvtkView-updated.ipynb b/notebooks/VisualizeWithvtkView-updated.ipynb deleted file mode 100644 index f4e8a3a7..00000000 --- a/notebooks/VisualizeWithvtkView-updated.ipynb +++ /dev/null @@ -1,142 +0,0 @@ -{ - "metadata": { - "name": "VisualizeWithvtkView-updated" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import SimPEG as simpeg, matplotlib as mpl" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "The history saving thread hit an unexpected error (OperationalError('disk I/O error',)).History will not be written to the database.\n", - "Warning: mumps solver not available." - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Simple notebook of how to use vtkView to visualize SimPEG models. It will pop-up external vtk windows." - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Make a mesh and model\n", - "x0 = np.zeros(3)\n", - "h1 = np.ones(60)*50\n", - "h2 = np.ones(60)*100\n", - "h3 = np.ones(50)*200\n", - "\n", - "mesh = simpeg.mesh.TensorMesh([h1,h2,h3],x0)\n", - "\n", - "# Make a models that correspond to the cells, faces and edges.\n", - "t = np.ones(mesh.nC)\n", - "t[10000:50000] = 100\n", - "t[100000:120000] = 100\n", - "t[100000:120000] = 50\n", - "# Make models called 'Test' for all with a range. \n", - "models = {'C':{'Test':np.arange(0,mesh.nC),'Model':t},'F':{'Test':np.arange(0,mesh.nF)},'E':{'Test':np.arange(0,mesh.nE)}}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Make the vtk viewer object.\n", - "vtkViewer = simpeg.visualize.vtk.vtkView(mesh,models)\n", - "# Set the .viewprop for which model to view\n", - "vtkViewer.viewprop = {'F':'Test'}\n", - "# Show the image\n", - "vtkViewer.Show()\n", - "\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Set subset of the mesh to view (remove padding)\n", - "vtkViewer.extent = [4,14,0,7,0,3]\n", - "vtkViewer.Show()\n", - "\n", - "# Change viewing property \n", - "vtkViewer.viewprop = {'C':'Model'}\n", - "# Set the color range\n", - "# Reset extent. Error check will reset the limits correctly.\n", - "vtkViewer.extent = [-1,1000,-1,1000,-1,1000]\n", - "# Set the range\n", - "vtkViewer.range = [0.,100.]\n", - "# Show\n", - "vtkViewer.Show()\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stderr", - "text": [ - "/home/Gudni/Codes/python/simpeg/SimPEG/visualize/vtk/vtkView.py:116: UserWarning: Lower bounds smaller then 0\n", - " warnings.warn('Lower bounds smaller then 0')\n", - "/home/Gudni/Codes/python/simpeg/SimPEG/visualize/vtk/vtkView.py:128: UserWarning: Upper bounds greater then number of cells\n", - " warnings.warn('Upper bounds greater then number of cells')\n", - "/home/Gudni/Codes/python/simpeg/SimPEG/visualize/vtk/vtkView.py:137: UserWarning: Changed given extent from [-1, 1000, -1, 1000, -1, 1000] to [0, 59, 0, 59, 0, 49]\n", - " warnings.warn('Changed given extent from {:s} to {:s}'.format(value,valnp.tolist()))\n" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Change color scale, has to be set to bytes=True.\n", - "vtkViewer.cmap = mpl.cm.copper(np.arange(0.,1.,0.01),bytes=True)\n", - "vtkViewer.Show()\n", - "# Set limits of values to view \n", - "vtkViewer.limits = [5.0,100.0]\n", - "vtkViewer.Show()" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 5 - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/notebooks/exLomPlots.ipynb b/notebooks/exLomPlots.ipynb deleted file mode 100644 index 3170f831..00000000 --- a/notebooks/exLomPlots.ipynb +++ /dev/null @@ -1,122 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import sys\n", - "sys.path.append('../')\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from SimPEG import LogicallyOrthogonalMesh, utils\n", - "mkvc = utils.mkvc" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test 2D Plots\n", - "\n", - "For 2D nodal or cell-centered plots are supported.\n" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "X, Y = utils.exampleLomGird([3,3],'rotate')\n", - "M = LogicallyOrthogonalMesh([X, Y])" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "M.plotGrid()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test 3D Plots\n", - "\n", - "Plot x, y, and z coordinates of cell-centred points" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "X, Y, Z = utils.exampleLomGird([3,3,3],'rotate')\n", - "M = LogicallyOrthogonalMesh([X, Y, Z])" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "M.plotGrid()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ] - } - ], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 42 - } - ], - "metadata": {} - } - ] -} \ No newline at end of file diff --git a/notebooks/exPlotImage2D.ipynb b/notebooks/exPlotImage2D.ipynb deleted file mode 100644 index 6dce54c1..00000000 --- a/notebooks/exPlotImage2D.ipynb +++ /dev/null @@ -1,235 +0,0 @@ -{ - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import sys\n", - "sys.path.append('../')\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from SimPEG import TensorMesh\n", - "%pylab inline" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Populating the interactive namespace from numpy and matplotlib\n" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test 1D Plots\n", - "\n", - "For 1D nodal or cell-centered plots are supported.\n" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x0 = np.zeros(1)\n", - "h = np.random.rand(32)\n", - "mesh = TensorMesh([h],x0)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "ax1 = plt.subplot()\n", - "ax1.set_title('sin(x) on CC grid')\n", - "ph1 = mesh.plotImage(np.sin(mesh.gridCC),ax=ax1)\n", - "ax2 = plt.subplot()\n", - "ax2.set_title('sin(x) on N grid')\n", - "ph2 = mesh.plotImage(np.sin(mesh.gridN), ax=ax2,imageType='N')" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\nYII=\n", - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test 2D Plots\n", - "\n", - "Plot x and y coordinates of cell-centred points" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x0 = np.zeros(2)\n", - "h1 = np.linspace(.1,.5,3)\n", - "h2 = np.linspace(.1,.5,5)\n", - "mesh = TensorMesh([h1,h2],x0)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "fig = plt.figure(1)\n", - "ax1 = plt.subplot()\n", - "ax1.set_title('mesh.gridCC[:,0]')\n", - "mesh.plotImage(mesh.gridCC[:,0],ax = ax1)\n", - "ax2 = plt.subplot()\n", - "ax2.set_title('mesh.gridFx[:,1]')\n", - "mesh.plotImage(mesh.gridFx[:,1],ax = ax2,imageType='Fx')" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\nkyZNrPENGzZ0PZMkZWVlaciQIWrVqpWjea40l7mGK7z+ZNq0aZO6du2qu+++W5IUHBzseqaLLVq0\nSOnp6a5nCgoK0okTJ1ReXq6ysjI1btzY0VPw/cm0Zs0apaamSrrw3uDPyTx1phjq4gVx/mS61q40\n05tvvqm0tLQ6ken9999Xhw4dNHLkSL311luuZzp48KCWLVumMWPGSLo219D4k8vj8Wj9+vWKiYnR\nxIkTHb/o059Mq1atksfjUUJCgtLS0rRq1SrXM/3k9OnTWrVqlQYPHux6pvT0dFVUVCg4OFh9+/ZV\nTk6O65lSUlL07rvv6syZM1q+fLm2bdum/fv3X3ZeR89KutoMF8RdkdzcXC1cuFDr1693O4ok6b77\n7tN9992nf//737r33nu1efNmV/NMmDBBs2bNksfjqfK/Lbfccccd+vrrrxUYGKh33nlH48eP1wcf\nfOBqprNnz2rLli3Kzc3V6dOnNWDAAG3fvl2NGjVyNZckrVixQn379lWzZs3cjqLXXntNAQEBOnTo\nkLZt26bU1FR99dVXqlfPvc/gDz74oL755hv169dPt912m8LDw9WgQYPLPqbOfGOIi4uzDiYXFxer\nZ8+e1pj4+Hjt2LHDt3348GGFhYW5mula8zdTUVGRRo8ereXLlzv+P8yVvk4PPvigvv32W505c8bV\nTJ9//rmGDh2qjh07avHixfrLX/6i5cuXO5bJ31xNmzZV48aNFRgYqFGjRsnr9ercuXOuZurVq5d+\n97vfqU2bNgoLC1NsbKzy8/NdzfSTf/3rX44vI/mbKT8/Xw899JAaN26s+Ph4tW3b1tGTP/zJ1Lhx\nY02fPl2FhYWaO3euGjVqpLZt21523jpTDBdfEFdSUqLVq1crPj7eGhMfH6/FixfryJEjWrRoUbUX\nxF3LTD+5Vp82/cl04MABDR48WDk5OerUqVOdyLR3717fa/TRRx+pe/fujn7a9CfTvn37tH//fu3f\nv19DhgzR3LlzNWjQIMcy+Zvru+++871WK1asUNeuXWv8hOd0pp49eyovL0+nT59WWVmZNm/erD59\n+riaSbqwxp6fn68//OEPjmW5kkx33XWXVqxYocrKSu3bt09lZWXWUo8bmY4fP67z58/r9OnT+tvf\n/qYBAwbUPPFVPTz+P1q3bp2JiIgwt956q3nllVeMMca88cYb5o033vCNmTJliunQoYO54447zI4d\nO1zPdOjQIdOuXTtz0003mWbNmpmQkBBz4sQJVzONGjXKtGjRwsTExJiYmBgTFxfnaB5/Mv397383\nnTt3NjExMWbEiBFm27Ztrme62KOPPmoWL17seCZ/cr322mumc+fOJjo62gwfPtxs3brV9UzGGPP6\n66+byMhIk5iYaN599906kWn+/PkmPT3d8Sz+Zjp27JgZN26c6datm0lOTjYffvih65nWr19vfvvb\n35pOnTqZ4cOHm1OnTtU4Jxe4AQAsdWYpCQBQN1AMAAALxQAAsFAMAAALxQAAsFAMAAALxQAAsFAM\nAAALxQDUgtfrVXR0tM6dO6dTp07p9ttvt36PF3A948pnoJamT5+us2fP6syZMwoJCdGUKVPcjgRc\nFRQDUEvl5eWKjY1Vo0aNtGHDBn4FPH4xWEoCaqm0tFSnTp3SyZMnHf0V4sC1xjcGoJYGDRqkYcOG\nad++fTp06FCVf4gduB5dV3/BDagrFixYoAYNGmjo0KGqrKxU7969tW7dOiUlJbkdDfif8Y0BAGDh\nGAMAwEIxAAAsFAMAwEIxAAAsFAMAwEIxAAAsFAMAwEIxAAAs/wdUR6yWo70KQwAAAABJRU5ErkJg\ngg==\n", - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "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\niFFs+w+jIAAAAABJRU5ErkJggg==\n", - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 5, - "text": [ - "" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Test 3D Plots\n" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "x0 = np.zeros(3)\n", - "h1 = np.linspace(.1,.5,3)\n", - "h1 = np.r_[1,2,1]\n", - "h2 = np.r_[1,3]\n", - "h3 = np.linspace(.1,.5,10)\n", - "\n", - "mesh = TensorMesh([h1,h2,h3],x0)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "ax1 = plt.subplot()\n", - "ax1.set_title('mesh.gridCC[:,0]')\n", - "a1 = mesh.plotImage(mesh.gridCC[:,0],ax=ax1,annotationColor='w')\n", - "ax2 = plt.subplot()\n", - "ax2.set_title('mesh.gridFx[:,1]')\n", - "a2 = mesh.plotImage(mesh.gridFx[:,1],ax=ax2,imageType='Fx')\n", - "ax3 = plt.subplot()\n", - "ax3.set_title('mesh.gridEz[:,2]')\n", - "mesh.plotImage(mesh.gridEz[:,2],ax=ax3,imageType='Ez')" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\nAABJRU5ErkJggg==\n", - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "iVBORw0KGgoAAAANSUhEUgAAAXEAAAEKCAYAAADkYmWmAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XtcVHXeB/DPGe4oGonilTAwQURA5SJEgnkhN8QeMuXZ\n9QpmtOYlzdzCwLZcL5Xl5prrhq6aEWu5pAZeQ8wEdLVUvCAGCTyaAnITQRx+zx/mJMttZhg4c/Tz\nfr3m9YLhnDOf+QIfDmfmzEhCCAEiIlIkldwBiIhIfyxxIiIFY4kTESkYS5yISMFY4kRECsYSJyJS\nMJY4GZ1NmzYhMDCwzbb/2WefYcyYMU1+PSgoCJ9++mmrbmPatGkwNzfH448/3qrt3LN//37Y2NjA\nxMQEBw4cMMg26cHAEqeHzu9//3vs2bOnya9LkgRJkgDc/YNiYmICGxsbzWXOnDkt3oYkSVi8eDF+\n+uknrXMtWbIE7u7uMDMzw9KlS+t9beTIkaioqICDg4MmGxEAmModgKg9qdVqmJiY6LROQEAA0tLS\ndL4tXc+j69evH1atWoVPPvmERU1a45446czR0RHr1q3DsGHDYG9vj0WLFuHmzZt44YUX0KNHD8yb\nNw8VFRUAgEuXLmHRokV47LHHMHPmTJw9e1aznaSkJAQHB+ORRx7B448/jm3bttW7nbfffhu9evVC\nSEgIjh492mSerKwsvPDCC+jZsyfeeOONeodDNm3ahCeffBJvvfUWHnvsMcTFxTU4XHP/+m+++WaD\n7TdWxrdv34aXlxc+/vhjAHf/OAQEBOCdd97RYZL1TZkyBSEhIbCxsdH5DwA9vFjipDNJkrBhwwas\nW7cO+/btw/r16xEcHIzJkyfjxIkTSE9Px7///W+o1Wr4+/tjwIABOHPmDAIDAzXHomtrazF37lws\nX74cpaWlOHr0KDw9PTW3kZmZCQA4c+YM/Pz8sGjRokazCCEwYsQI+Pv749SpU6itrcXRo0fr7clm\nZmbizp07OHXqVIOSvre+r68vTp06herqanz//fctzsDc3Bxbt27FW2+9hfPnz2P58uUQQjT6R+Ce\n5cuXIzQ0tMVtE+mCJU56mTx5Mjw9PTFo0CD4+vqiT58+CA0NRY8ePTBu3DgcOHAABw8ehIeHB6ZN\nmwYbGxtMmTIFdnZ2OHbsGCRJwu3bt5GTk4OqqirY29tjwIABmu136NABMTExsLW1xaxZs5CRkYGb\nN282yHHs2DFYWFhg3rx5sLOzw5///OcGhyJMTU0RFxeHzp07w9LSstH1FyxYADs7O7zzzjsN1k9P\nT4etra3mcu8PjJubG2JiYhAWFoYPPvgAW7ZsafYwyOLFi7Fz506dZ03UHJY46cXDw0Pzsb29fYPP\nCwsLceDAARw+fLheAebk5CAtLQ2mpqb48ssvsX37dvTu3RuRkZHIzc3VbMPNzQ0q1d0fzx49euDO\nnTv45ZdfGuTIyMiotwdvaWkJV1fXBlnNzc0bvR8ZGRn1sltZWcHFxaXeMn5+frhx44bm4uPjo/na\nlClTcPnyZYwdOxZOTk7NzoyoLbDEySDuP4Z77+Pg4GAEBQXVK8CKigosWLAAADBs2DDs2LEDeXl5\nMDMza/KQSXN8fX3x448/aj6/desWzp8/X28ZU9OmH7/38fFpcf3mvPzyy3j22WeRkpKCI0eO6JC8\neXxgk7TFEqc2M2rUKJw+fRqbN2/GjRs3UF1djdTUVBQWFuLatWtISkrCzZs3YWJiAktLS9jY2Oh8\nG0OHDkV1dTXWrFmD69evIy4uDnV1dVqv7+3tjZqaGqxevRrXr1/HkiVLtH5QccuWLTh58iT++c9/\nYs2aNZg6dWq9Qz4tFXFcXByCg4M1n9+5cwfV1dVQq9Wora1FdXW1TveFHk4scTKI+wvr3vOsVSoV\nUlNTceHCBQwZMgQODg54//33IYRAXV0dVq9ejV69esHFxQUlJSWa50bf/zztxrYfHR2N6OhoAIBK\npcL+/fuRlpYGDw8PmJiYwMPDA507d252W/euu7f+kSNH4OHhAQsLCwQEBDS67P0uX76M+fPnY/Pm\nzbC2tkZERASGDh2KV199FcDd/0b++4/BsmXLMHbsWM3n+fn5ePLJJzWfR0VFwdraGgkJCXj33Xdh\nbW2NrVu3tjR6etiJZkyfPl1069ZNDBw4UHPdwoULhYuLi/Dy8hJz584VVVVVzW2CqF2VlpYKc3Nz\nUVRUJGuOmTNnio4dOwpnZ+cml/H09BQlJSVabW///v3ikUceEdbW1iI1NdVQMekBIAnR9P+Ohw8f\nRseOHTFlyhScPn0aALBv3z48/fTTAIBZs2bBz88PkZGR7fMXh6gRe/fuhY+PDyorK/Huu+/i2LFj\nOH78uNyxiNpFs4dTAgMDYWtrW++6UaNGQaVSQaVSYcyYMTh06FCbBiRqydGjR+Hs7Axvb2906NAB\nn3/+udyRiNpNs3viAJCXl4fQ0FDNnvj9xowZg6ioKEyYMKHNAhIRUdP0fmDz7bffho2NDQuciEhG\ner0A1qZNm7Bnz55mXxLT2dkZly5d0jsYEdHDyMnJCTk5OVovr3OJp6SkYNWqVUhLS2twCvP9Ll26\nhDhdNy6DbwEEt7iUvGKFQFxcHKT/enlSY2Ts87w3y7i4OLmjtIg5DUspOXU90avZwykRERHw9/fH\nhQsX0KdPH8THx+OVV15BZWUlRo4cCS8vL7z88sutCkxERPprdk+8sUf5Z8yY0WZhiIhINw/9GZuO\ncgfQUlBQkNwRtOIodwAtKGWWzGlYSsmpqxafYqj3hiVJEcfElSD212/RUr4oUqvF8s0WyMhJkqTT\nm4I89HviRERKxhInIlIwljgRkYKxxImIFIwlTkSkYCxxIiIFY4kTESkYS5yISMFY4kRECsYSJyJS\nMJY4EZGCscSJiBSMJU5EpGAscSIiBWOJExEpGEuciEjBWOJERArGEiciUjCWOBGRgrHEiYgUjCVO\nRKRgLHEiIgVjiRMRKRhLnIhIwVjiREQKxhInIlKwZkt8xowZsLe3h7u7u+a6iooKhIWFwcHBAePH\nj0dlZWWbhyQiosY1W+LTp09HSkpKvevWrVsHBwcHXLx4Eb1798Ynn3zSpgGJiKhpzZZ4YGAgbG1t\n612XmZmJyMhIWFhYYMaMGcjIyGjTgERE1DSdj4kfO3YMLi4uAAAXFxdkZmYaPBQREWlH5xIXQrRF\nDiIi0oOprit4e3vj3Llz8PLywrlz5+Dt7d3kst/e97EjgL665yMieqClpqYiNTVV7/V1LnFfX1/E\nx8dj5cqViI+Ph5+fX5PLBusdi4jo4RAUFISgoCDN50uXLtVp/WYPp0RERMDf3x/Z2dno06cPNm7c\niOjoaFy+fBn9+/dHYWEhXnrpJb2CExFR6zW7J/755583en1SUlKbhCEiIt3wjE0iIgVjiRMRKRhL\nnIhIwVjiREQKxhInIlIwljgRkYKxxImIFIwlTkSkYCxxIiIFY4kTESkYS5yISMFY4kRECsYSJyJS\nMJY4EZGCscSJiBRMEm30ppmSJAGIa4tNP3SEiAUASJJu7/hBDd2bJZGxkiRJp/cy5p44EZGCscSJ\niBSMJd6Grl5dgMGDewAADh2ahkmTBtb7ekTEQGzfPgHXri3EkSMzEBs7HJ07W8gRVRGam6ckAc8/\nPwBffPE8iopeQ2ZmFCIiBja1KaIHBku8jTg52cLa2gwnT16BmZkKQ4f2xHffXdZ83cXFDps3P4fM\nzP/DU09twsqVRzB1qgdeey1AxtTGq6V5hocPwIYNoTh06GcMH74JX3yRhY0bwxr84SR60DT7Rsmk\nv4AAB2RkFEIIwNu7F4qLq1BQUK75+qRJA5GXV4qVK48AAM6fL4KHR3dMn+6JmJiDcsU2Wi3Nc84c\nH2ze/CP+9rdjAICsrOvw8+uNmJhAJCSckSs2UZtjiRvYjRuvQwgBCwtTqFQSSkoWwczMBBYWJigp\nWQQhgC5dVmL37mwsXhyA8HBX7N59Ec7OjyI83BVffnlO7rtgVLSdZ6dOFqisvF1v3YqKGri6doWt\nrSVu3KiW6R4QtS2WuIENGrQOkiQhPT0SL720Gz/8cBUJCeHYtu0MkpLOa5Y7duz/MGLEZuzbNxnm\n5iZQqSSsXp2OhQv3ypje+Gg7zw0bTuDNNwNx6NDP+O67yxg16nE8//wACCHQp09nljg9sFjiBpaf\nXw53924wMzPBzp0X0LGjOTw9u2PcuAQUFVVplgsOdsT27S9g5cojSEnJgbu7PV57zR+SBCxYwCK/\nR9t5btr0A3r0sMFf//oMnJxscfFiCT74IB1LljyFO3fqZLwHRG2LJ/sY0Jkz0XBw6AxTUxXMzExw\n61YtVCoJVlZmuHnz7r/6rq5rUVhYgR07JkKlkhAWlqBZf+JEN2zaNB729u+hvLxGc/3DerKPLvO8\nX+fOFigrq8GcOb744IPRsLZehtu31QB4sg8ZP11P9uGeuAGFhHwGc3MTxMePQ3JyDhITsxAbOxw1\nNWosX/4dAODKlUoAgFpdB7W6/vpqtUBdnYAktXdy46TLPO9XVnb3D+DUqR7YtStbU+BEDyKWuAEV\nFJRDpZIwaJA9XnxxF3JzS+Hubo+4uFTk5pbWW3bt2mPYs+cPWLjQH3v25MDNrRtiYgKxbdtpTQk9\n7HSZ55AhPdC3ry1OnryC4OC+WLBgGOzsrDFx4naZ0hO1D5a4gXl5dUdNjRrZ2cXo1MkCbm5dkZb2\nc4Plvv02D9OnJ+F3v+uHhQuH4fz5ImzefAqbNv0gQ2rjpe08LSxM8dZbT8HJ6VFcv34TR48WYOHC\nvQ0OtRA9aHhMXAEe1mPibYHHxMnYtdsLYG3YsAH+/v4YMmQI5s2bp+9miIioFfQq8ZKSEixbtgz7\n9u3DsWPHkJ2djT179hg6GxERtUCvY+JWVlYQQqCsrAwAUFVVBVtbW4MGIyKilul9TDw5ORlhYWGw\nsLDAnDlz8O6779bfsI7HdYiIqJ2eJ379+nVER0fj7NmzsLW1xYQJE7B792787ne/q7dcXFyc5uOg\noCAEBQXpc3NERA+s1NRUpKam6r2+Xnviu3fvxpYtW5CQcPdsw3Xr1iEvLw8rVqz4bcOSxOemGEjs\nr9+ipTwLqNU4S8PiPA0rVoj2eXZKYGAgjh8/jpKSEtTU1CA5ORmjR4/WZ1NERNQKeh1O6dSpE2Ji\nYvDcc8+hqqoKISEhCA4ONnQ2IiJqgd5nbE6bNg3Tpk0zYBQiItIV356NiEjBWOJERArGEiciUjCW\nOBGRgrHEiYgUjCVORKRgLHEiIgVjiRMRKRhLnIhIwVjiREQKxhInIlIwljgRkYKxxImIFIwlTkSk\nYCxxIiIFY4kTESkYS5yISMFY4kRECsYSJyJSMJY4EZGCscSJiBSMJU5EpGAscSIiBWOJExEpGEuc\niEjBWOJERArGEiciUjCWOBGRguld4jdv3sTUqVPxxBNPYMCAAUhPTzdkLiIi0oKpvivGxsbCwcEB\n69evh6mpKW7evGnIXEREpAW9S3z//v04evQoLC0tAQCdO3c2WCgiItKOXodTCgoKUF1djejoaPj6\n+mLFihWorq42dDYiImqBXiVeXV2N7OxshIeHIzU1FVlZWUhMTGyw3Lf3XXJbl5OI6IGUi996Mi4u\nTuf19SpxZ2dn9O/fH6GhobCyskJERASSk5MbLBd836WvPjdERPSA64vferLdShwA+vXrh4yMDNTV\n1WH37t0YOXKkvpsiIiI96V3i7733HubOnYvBgwfD0tISkyZNMmQuIiLSgt7PTnniiSf43HAiIpnx\njE0iIgVjiRMRKRhLnIhIwVjiREQKxhInIlIwljgRkYKxxImIFIwlTkSkYCxxIiIFY4kTESkYS5yI\nSMFY4kRECsYSJyJSMJY4EZGCSUII0SYbliQAcW2x6YeOELEAAElaKnMS5eMsDYvzNCwhYiFJEnSp\nZe6JExEpGEuciEjBWOJt6OrVBRg8uAcA4NChaZg0aWCjy7m62qGy8k+4fTumPeMpTnPznDrVA2r1\nWw0uwcGO8oRVgJZ+PlUqCW++GYgTJ17EzZtvID9/PmJjh8sRVRGam+e3305t9OezouJPrb5dvd+e\njZrn5GQLa2sznDx5BWZmKgwd2hPffXe5wXJWVqZITJyAAwdyERLiLENSZdBmnmp1HXr2/ACS9Nt1\nN25Ut3NSZdBmnjt3RsDZ+VHEx5/EV1+dQ4cO5uja1VqmxMatpXk+99wXMDP7bZ9ZpZJw7NhMpKRc\navVts8TbSECAAzIyCiEE4O3dC8XFVSgoKG+w3Nq1Y5GW9jMyMgrxzDMs8aZoO8+ioioZ0ilPS/P8\nn/9xRUiIMwYNWoesrOsyJlWGluZZWlp/Z2LkyMfRq1cnfPLJ8VbfNkvcwG7ceB1CCFhYmEKlklBS\nsghmZiawsDBBSckiCAF06bISADB58iAMGdIT3t4bEBHR+KGWh50u8zQxUSEn5xXcvq3G9u3n8MUX\nZ1hA/0XbeU6YMAC5uTfw7LNPIDFxAoqKqhAffxKJiVm4deuO3HfDaOjy83m/l14aghMnruDEiSut\nzsASN7BBg9ZBkiSkp0fipZd244cfriIhIRzbtp1BUtJ5zXIuLnZ4773RCArahNu31TImNm7azvP8\n+SJMmbIDp079gn79umDiRDecOhWNiRO3Y/v2szLeA+Oi7Tz79XsUPXrYYNy4/vjTnw6gSxcrvPFG\nIEaM6IupU/8t4z0wLtrO837du3dEaGh//PGP3xgkA0vcwPLzy+Hu3g1mZibYufMCOnY0h6dnd4wb\nl6D5V9/c3AT/+tcExMQcxLlzRTInNm7azBMAMjIKkZFRCAA4ffoavvrqHDIyovDmm4Es8ftoO897\ne5PTpychO7sYAFBWVoONG8NgaWmK6mrujQPaz/N+M2Z44datWmzbdtogGVjiBnTmTDQcHDrD1FQF\nMzMTlJUthkolwcLCFD/9NAcA4Oq6FqamKgwY0BVr147F2rVjAdw9OUqlknD7dgyWLPkWK1YckfOu\nGAVt51lYWNHo+l9+eQ4xMYHtGdmo6TLPgoJy2Nt30BQ4ABw6lIeOHc0xbFhvfPttnkz3wnjo8/Mp\nScDMmYPx2WenUVVVa5AcLHEDCgn5DObmJoiPH4fk5BwkJmYhNnY4amrUWL78OwDAlSuVkCRg4MC/\n1Vt3/HgXLF0aBA+PT3Dt2k054hsdbefZlNDQJ3Dp0o32imv0dJlnWtrPCAlxhpOTrWaGgYGPoaKi\nBt9/ny/bfTAm+vx8hoQ4w8GhM9av/4/BcrDEDaigoBwqlYRBg+zx4ou7kJtbCnd3e8TFpSI3t7Te\nsv99GMXHp6LR6x9muswzNnY4MjIKcfFiMRwdH8ELL7jB378PJk/eIVN646PLPD/55DgWLBiGv/89\nFMuWHcajj1phyZKn8MUXWaip4WM4gG7zvGfWrCHIzCzEqVO/GCwHS9zAvLy6o6ZGjezsYnTqZAE3\nt65IS/tZq3Xb5lVslE3bedrYWGDt2rHo3r0jcnNvICnpAoYN+xSZmYUypDZe2s6zrKwGPj7/wJo1\nIfj883CcO1eE1avT8cUXWTKkNl66/L737GmDsWP74cUXdxk0A18ASwH4IkOGw1kaFudpWO3+Alhq\ntRpeXl4IDQ1tzWaIiEhPrSrxjz76CAMGDPh1r5uIiNqb3iVeUFCAb775BlFRUTrt+hMRkeHo/cDm\n/PnzsWrVKpSXN3z9invuHS8jw+A8DYezNCzOUz56lfiuXbvQrVs3eHl5ITU1tcnl4uLiNB8HBQUh\nKChIn5sjInpgpaamNtujLdHr2SlvvPEGtmzZAlNTU1RXV6O8vBzh4eHYvHnzbxuWJD43xUBif/0W\nLeVjD63GWRoW52lYsUK0z7NTli1bhvz8fOTm5iIhIQEjRoyoV+BERNQ+DPLOPnx2ChGRPFp9xubw\n4cMxfDjfsomISA58j00iIgVjiRMRKRhLnIhIwVjiREQKxhInIlIwljgRkYKxxImIFIwlTkSkYCxx\nIiIFY4kTESkYS5yISMFY4kRECsYSJyJSMJY4EZGCscSJiBSMJU5EpGAscSIiBWOJExEpGEuciEjB\nWOJERArGEiciUjCWOBGRgrHEiYgUjCVORKRgLHEiIgVjiRMRKRhLnIhIwVjiREQKpleJ5+fnIzg4\nGG5ubggKCsK2bdsMnYuIiLRgqs9KZmZmWL16NTw9PVFUVAQfHx+EhobCxsbG0PmIiKgZeu2Jd+/e\nHZ6engAAOzs7uLm54fjx4wYNRkRELWv1MfGcnBxkZWXBx8fHEHmIiEgHrSrxiooKTJw4EatXr0aH\nDh0MlYmIiLSk1zFxAKitrUV4eDgmT56MsLCwRpf59r6PHQH01ffGiIgeULkA8n79WMTF6by+Xnvi\nQghERkZi4MCBmDdvXpPLBd93YYETETXUF7/1ZFx7lfiRI0ewdetWHDx4EF5eXvDy8kJKSoo+myIi\nolbQ63DKk08+ibq6OkNnISIiHfGMTSIiBWOJExEpGEuciEjBWOJERArGEiciUjCWOBGRgrHEiYgU\njCVORKRgLHEiIgVjiRMRKRhLnIhIwVjiREQKxhInIlIwljgRkYKxxImIFEwSQog22bAkAYhri00/\ndISIBQBI0lKZkygfZ2lYnKdhCRELSZKgSy1zT5yISMFY4m3o6tUFGDy4BwDg0KFpmDRpYL2vu7jY\nYe/eP6C4eBGysl7G668HyBFTMZqb54ABXZGY+DwuXJiNO3eW4O9/D5UrpmI0N8/p0z1x8OAUXLu2\nEPn587F+/bMYPdpJrqiK0Nw8R492wvffz8C1awtx48br+PrrSXjlFR+D3K7e73ZPzXNysoW1tRlO\nnrwCMzMVhg7tie++u6z5up2dNY4ejcTFi8WYMOFfGD3aCXFxQTA1VeHddw/LmNw4tTRPKytT5OWV\nISnpAl59dZhO/44+jFqaZ3CwI3bsOI+FC/fhzp06/P737ti1KwL9+3+M3NxS+YIbqZbmWVZWjdWr\n03HmzDXcuVOHJ590wMcfj0VRURU+//xMq26bJd5GAgIckJFRCCEAb+9eKC6uQkFBuebrs2YNgUol\nwcfnHwCAgwdzUV5eg/nz/bBq1fe4fVstV3Sj1NI8//OfK/jPf64AACIjveSKqRgtzXPKlH/XW/7U\nqV8QFOSIBQv8MXv2N+0d1+i1NM+MjEJkZBRqPr94sQRBQY6YOXMwS9zY3LjxOoQQsLAwhUoloaRk\nEczMTGBhYYKSkkUQAujSZSUCAvrgxx+v1lv35MkrePRRK7i62uHHH3+R6R4YF23nSdppzTwlCVCp\npHZObNz0mee9PfWQEGf85S/ftToDS9zABg1aB0mSkJ4eiZde2o0ffriKhIRwbNt2BklJ5zXL9erV\nCampefXWPXnybqn37t2JJf4rbedJ2tF3ni++OARubt0wefKOdkxr/HSdZ37+fHTtag0zMxMsWrQP\nH36Y3uoMLHEDy88vh7t7N5iZmWDnzgvo2NEcnp7dMW5cAoqKqjTL8ZitdrSdJ2lHn3mOG9cfq1eP\nQVTU17hwobidExs3XecZEBAPOztrPP10X7z2mj+srMzwzjtprcrAEjegM2ei4eDQGaamKpiZmaCs\nbDFUKgkWFqb46ac5AABX17UoLKxAYWGF5pHse7y8ugNAvWNpDzNd5kkt02eeEye6IT4+DDNn7mz1\nsdsHjT7zvHy5DJcvl+HEiSuQJAmLFvnjL385DLVa/506lrgBhYR8BnNzE8THj0Nycg4SE7MQGzsc\nNTVqLF9+99jXlSuVAIAjR/KxeHEAJAm4t1Pu5dUDxcVVOHeuSK67YFR0mSe1TNd5RkUNxpo1IfjD\nH3bgq6/OyRXbaLX259Pc3AQdO5pDpZJaVeJ8nrgBFRSUIy+vFIMG2WPHjvPIzS2Fu7s9du3KRm5u\nKXJzS1FXd/ebtX79cdy5U4f09Cg8/XRfLFv2NGJiAvHhhxl8ZsqvdJmnqakKHh728PCwh42NBbp0\nsYKHhz1cXe1kvhfGQ5d5zpvnh7/9bSzmzEnBkSOXYW/fAfb2HWBraynzvTAeuszz1VeH4ZlnnOHs\n/CiGDu2JefP8MG+eLxISzqC2tq5VObgnbmBeXt1RU6NGdnYxOnWygJtbV6Sl/dxgueLiWxg27FOs\nWfMMEhMn4OrVSsTFHcLKlUdkSG28tJ1nr142OHFiFoC7jzcMHtwDzz3niry8Ujg5rWnv2EZL23nO\nmeMDlUrC+vXPYv36ZzXXp6bm4emnN7dnZKOm7TxNTVVYuXIUHB0fQVFRFQ4ezMXcuSlITMxqdQa+\ndooC8PUpDIezNCzO07Da9bVT0tLS4Orqin79+uGvf/2rvpshIqJW0LvE586di/Xr12P//v1Yu3Yt\nioqU+mBcrtwBtJKamip3BC0Z/zw5S8PiPOWlV4mXlZUBAJ566ik89thjGD16NDIyMgwarP3kyR1A\nK8r5RcmTO0CLOEvD4jzlpVeJHzt2DC4uLprPBwwYgPT01p95REREumnTZ6fce9DDmMXFCcTFGX9O\ngPM0JM7SsDhPGQk9lJaWCk9PT83ns2fPFrt27aq3jJOTkwDACy+88MKLDhcnJyed+livPfHOnTsD\nuPsMFQcHB+zbtw+xsbH1lsnJydFn00REpAO9D6d8+OGHmDVrFmprazFnzhzY2fHMOCKi9tZmJ/sQ\nEVHba5PXTlHCiUD5+fkIDg6Gm5sbgoKCsG3bNrkjNUmtVsPLywuhocb7vpE3b97E1KlT8cQTTxj1\ns5U2bNgAf39/DBkyBPPmzZM7jsaMGTNgb28Pd3d3zXUVFRUICwuDg4MDxo8fj8pK+V/sq7Gcr732\nGlxdXTF48GDMmzcPt27dkjHhXY3lvOf999+HSqVCSUmJDMl+01TGjRs3wtXVFW5ubnj99ddb3pA+\nD2y2xNPTUxw6dEjk5eWJ/v37i+vXr7fFzbTKlStXxMmTJ4UQQly/fl307dtXlJeXy5yqce+//774\n3//9XxEaGip3lCYtWLBAxMTEiFu3bona2lpRWloqd6QGiouLhaOjo6isrBRqtVo888wzIiUlRe5Y\nQggh0tIZdlOxAAAEp0lEQVTSxIkTJ8TAgQM1161YsULMnj1bVFdXiz/+8Y9i1apVMia8q7Gce/fu\nFWq1WqjVahEVFSX+8Y9/yJjwrsZyCiHE5cuXxZgxY4Sjo6MoLi6WKd1djWU8ffq08PPzE9nZ2UII\nIa5du9bidgy+J66UE4G6d+8OT09PAICdnR3c3Nxw/PhxmVM1VFBQgG+++QZRUVFG/UYS+/fvxxtv\nvAFLS0uYmppqHvw2JlZWVhBCoKysDLdu3UJVVRVsbW3ljgUACAwMbJAlMzMTkZGRsLCwwIwZM4zi\n96ixnKNGjYJKpYJKpcKYMWNw6NAhmdL9prGcAPDqq69i5UrjeDu/xjImJycjMjIS/fr1AwB07dq1\nxe0YvMSVeCJQTk4OsrKy4OPjI3eUBubPn49Vq1ZBpTLeVw0uKChAdXU1oqOj4evrixUrVqC6ulru\nWA1YWVlh3bp1cHR0RPfu3REQEGCU3/N77v9dcnFxQWZmpsyJWrZhwwajPeyXlJSE3r17Y9CgQXJH\nadLevXtx5swZDB06FFFRUTh79myL6xhvM7STiooKTJw4EatXr0aHDh3kjlPPrl270K1bN3h5eRn1\nXnh1dTWys7MRHh6O1NRUZGVlITExUe5YDVy/fh3R0dE4e/Ys8vLycPToUezevVvuWE0y5u95Y95+\n+23Y2NhgwoQJckdpoKqqCsuWLcPSpb+92qIxzre6uholJSU4fPgwwsLCMHv27BbXMXiJe3t74/z5\n394gNCsrC35+foa+GYOora1FeHg4Jk+ejLCwMLnjNPD999/j66+/Rt++fREREYGDBw9iypQpcsdq\nwNnZGf3790doaCisrKwQERGB5ORkuWM1kJmZCT8/Pzg7O6NLly6YMGEC0tJa9/6Gbcnb2xvnzt19\nR51z587B29tb5kRN27RpE/bs2YOtW7fKHaVRly5dQl5eHjw8PNC3b18UFBRgyJAhuHbtmtzR6vHz\n88PEiRNhZWWF0NBQnD9/vsX/ag1e4vefCJSXl4d9+/bB19fX0DfTakIIREZGYuDAgUb1LIX7LVu2\nDPn5+cjNzUVCQgJGjBiBzZuN8wX5+/Xrh4yMDNTV1WH37t0YOXKk3JEaCAwMxPHjx1FSUoKamhok\nJydj9OjRcsdqkq+vL+Lj43Hr1i3Ex8cb7c5QSkoKVq1aha+//hqWlsb5zj/u7u745ZdfkJubi9zc\nXPTu3RsnTpxAt27d5I5Wz7Bhw5CcnAwhBDIyMuDk5NTyTA3/mKsQqampwsXFRTg5OYmPPvqoLW6i\n1Q4fPiwkSRIeHh7C09NTeHp6iuTkZLljNSk1NdWon51y4cIF4evrKzw8PMSCBQtEZWWl3JEatXHj\nRvHUU0+JoUOHipiYGKFWq+WOJIQQYtKkSaJHjx7C3Nxc9O7dW8THx4vy8nIxbtw40adPHxEWFiYq\nKirkjqnJaWZmJnr37i0+/fRT4ezsLBwcHDS/R9HR0XLHbHSe9+vbt6/sz05pLOOdO3fErFmzhIuL\nixg/frzIzMxscTs82YeISMEe+gc2iYiUjCVORKRgLHEiIgVjiRMRKRhLnIhIwVjiREQKxhInIlIw\nljgRkYL9Px5JJb38BetZAAAAAElFTkSuQmCC\n", - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n/x835ZZaYjxPhgAAAABJRU5ErkJggg==\n", - "text": [ - "" - ] - }, - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 7, - "text": [ - "" - ] - } - ], - "prompt_number": 7 - } - ], - "metadata": {} - } - ] -} \ No newline at end of file From 57320fb2bca79bd39f4389cf46347c379ab89fa0 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 24 Jan 2014 09:55:24 -0700 Subject: [PATCH 25/28] Documentation updates. --- SimPEG/Data.py | 4 +-- SimPEG/Problem.py | 2 +- SimPEG/Utils/__init__.py | 11 ++++--- docs/{api_Problem.rst => api_Forward.rst} | 40 +++++++++++------------ docs/index.rst | 2 +- 5 files changed, 30 insertions(+), 29 deletions(-) rename docs/{api_Problem.rst => api_Forward.rst} (67%) diff --git a/SimPEG/Data.py b/SimPEG/Data.py index 948b1c83..fa37b09a 100644 --- a/SimPEG/Data.py +++ b/SimPEG/Data.py @@ -21,7 +21,7 @@ class BaseData(object): """ The geophysical problem that explains this data, use:: - data.setProblem(prob) + data.pair(prob) """ return getattr(self, '_prob', None) @@ -67,7 +67,7 @@ class BaseData(object): .. math:: - d_\\text{pred} = Pu(m) + d_\\text{pred} = P(u(m)) """ return u diff --git a/SimPEG/Problem.py b/SimPEG/Problem.py index e53c4675..386fac9d 100644 --- a/SimPEG/Problem.py +++ b/SimPEG/Problem.py @@ -48,7 +48,7 @@ class BaseProblem(object): @property def data(self): """ - The data object for this problem. Data + The data object for this problem. """ return getattr(self, '_data', None) diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 437f1387..1daa2e29 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -152,11 +152,14 @@ def requires(var): def requiresVar(f): if var is 'prob': extra = """ - To use data.%s(), SimPEG requires that a problem be bound to the data. - If a problem has not been bound, an Exception will be raised. - To bind a problem to the Data object:: - data.setProblem(myProblem) + .. note:: + + To use data.%s(), SimPEG requires that a problem be bound to the data. + If a problem has not been bound, an Exception will be raised. + To bind a problem to the Data object:: + + data.pair(myProblem) """ % f.__name__ else: diff --git a/docs/api_Problem.rst b/docs/api_Forward.rst similarity index 67% rename from docs/api_Problem.rst rename to docs/api_Forward.rst index 09a4d5b6..91009294 100644 --- a/docs/api_Problem.rst +++ b/docs/api_Forward.rst @@ -1,6 +1,24 @@ -.. _api_Problem: +.. _api_Forward: +Model +***** + +.. automodule:: SimPEG.Model + :show-inheritance: + :members: + :undoc-members: + :inherited-members: + +Data +**** + +.. automodule:: SimPEG.Data + :show-inheritance: + :members: + :undoc-members: + :inherited-members: + Problem ******* @@ -10,23 +28,3 @@ Problem :undoc-members: :inherited-members: - -DCProblem -********* - -.. automodule:: SimPEG.Examples.DC - :show-inheritance: - :members: - :undoc-members: - :inherited-members: - - - -Linear Problem -************** - -.. automodule:: SimPEG.Examples.Linear - :show-inheritance: - :members: - :undoc-members: - :inherited-members: diff --git a/docs/index.rst b/docs/index.rst index 5ba56947..9ed98291 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -40,7 +40,7 @@ Forward Problems .. toctree:: :maxdepth: 2 - api_Problem + api_Forward Inversion ========= From cffb0762beba51ff6c0e241b366f4620902b9ba7 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 24 Jan 2014 10:17:00 -0700 Subject: [PATCH 26/28] Fixed Example Problems. --- SimPEG/Examples/DC.py | 17 ++++++++--------- SimPEG/Examples/Linear.py | 26 ++++++++++++++------------ 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/SimPEG/Examples/DC.py b/SimPEG/Examples/DC.py index 28b1466f..074f5e3d 100644 --- a/SimPEG/Examples/DC.py +++ b/SimPEG/Examples/DC.py @@ -208,7 +208,7 @@ if __name__ == '__main__': q, Q, rxmidloc = genTxRxmat(nelec, spacelec, surfloc, elecini, M) P = Q.T - model = Model.LogModel() + model = Model.LogModel(M) prob = DCProblem(M, model) # Create some data @@ -224,18 +224,17 @@ if __name__ == '__main__': # prob.std = dobs*0 + 0.05 m0 = M.gridCC[:,0]*0+sig2 - opt = Inverse.InexactGaussNewton(maxIterLS=20, maxIter=3, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) - reg = Inverse.Regularization(M) - inv = Inverse.Inversion(prob, reg, opt, data, beta0=1e4) + reg = Regularization.Tikhonov(model) + objFunc = ObjFunction.BaseObjFunction(data, reg) + opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=3, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) + inv = Inversion.BaseInversion(objFunc, opt) # Check Derivative - derChk = lambda m: [inv.dataObj(m), inv.dataObjDeriv(m)] + derChk = lambda m: [objFunc.dataObj(m), objFunc.dataObjDeriv(m)] # Tests.checkDerivative(derChk, mSynth) - - - print inv.dataObj(m0) - print inv.dataObj(mSynth) + print objFunc.dataObj(m0) + print objFunc.dataObj(mSynth) m = inv.run(m0) diff --git a/SimPEG/Examples/Linear.py b/SimPEG/Examples/Linear.py index acaaf38b..a83b26f1 100644 --- a/SimPEG/Examples/Linear.py +++ b/SimPEG/Examples/Linear.py @@ -1,14 +1,15 @@ -from SimPEG import Mesh, Model, Problem, Data, Inversion, np +from SimPEG import * import matplotlib.pyplot as plt class LinearProblem(Problem.BaseProblem): """docstring for LinearProblem""" - def __init__(self, *args, **kwargs): - problem.BaseProblem.__init__(self, *args, **kwargs) + def __init__(self, mesh, model, G, **kwargs): + Problem.BaseProblem.__init__(self, mesh, model, **kwargs) + self.G = G - def dpred(self, m, u=None): + def field(self, m, u=None): return self.G.dot(m) def J(self, m, v, u=None): @@ -20,7 +21,7 @@ class LinearProblem(Problem.BaseProblem): def example(N): h = np.ones(N)/N - M = mesh.TensorMesh([h]) + M = Mesh.TensorMesh([h]) nk = 20 jk = np.linspace(1.,20.,nk) @@ -41,21 +42,22 @@ def example(N): - prob = LinearProblem(M, None) - prob.G = G + model = Model.BaseModel(M) + prob = LinearProblem(M, model, G) data = prob.createSyntheticData(mtrue, std=0.01) - return prob, data + return prob, data, model if __name__ == '__main__': - prob, data = example(100) + prob, data, model = example(100) M = prob.mesh - reg = inverse.Regularization(M) - opt = inverse.InexactGaussNewton(maxIter=20) - inv = inverse.Inversion(prob,reg,opt,data) + reg = Regularization.Tikhonov(model) + objFunc = ObjFunction.BaseObjFunction(data, reg) + opt = Optimization.InexactGaussNewton(maxIter=20) + inv = Inversion.BaseInversion(objFunc, opt) m0 = np.zeros_like(data.mtrue) mrec = inv.run(m0) From 06dbdf0262b9a6eb3def384d06c39b486fa90be3 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 24 Jan 2014 10:43:13 -0700 Subject: [PATCH 27/28] updated licence --- LICENSE | 20 ++++++++++++++++++++ SimPEG/license.txt | 21 --------------------- 2 files changed, 20 insertions(+), 21 deletions(-) create mode 100644 LICENSE delete mode 100644 SimPEG/license.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f94a23fd --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013-2014 SimPEG Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/SimPEG/license.txt b/SimPEG/license.txt deleted file mode 100644 index 3110a4fb..00000000 --- a/SimPEG/license.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 SimPEG Developers - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. From 8fcaf57e0c1637decfb13cd259a28f4b7fa02aba Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 3 Feb 2014 11:21:38 -0800 Subject: [PATCH 28/28] Removing unused methods from the inversion class. --- SimPEG/Inversion.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/SimPEG/Inversion.py b/SimPEG/Inversion.py index 5b2dfa4d..813d201b 100644 --- a/SimPEG/Inversion.py +++ b/SimPEG/Inversion.py @@ -1,6 +1,6 @@ import SimPEG from SimPEG import Utils, sp, np -from Optimization import Remember, IterationPrinters, StoppingCriteria +from Optimization import Remember, IterationPrinters class BaseInversion(object): @@ -13,7 +13,6 @@ class BaseInversion(object): debug = False #: Print debugging information - comment = '' #: Used by some functions to indicate what is going on in the algorithm counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things def __init__(self, objFunc, opt, **kwargs): @@ -39,6 +38,7 @@ class BaseInversion(object): opt.bfgsH0 = SimPEG.Solver(objFunc.reg.modelObj2Deriv()) + #TODO: Move this to the data class? @property def phi_d_target(self): """ @@ -69,11 +69,6 @@ class BaseInversion(object): return self.m - def stoppingCriteria(self): - if self.debug: print 'checking stoppingCriteria' - return Utils.checkStoppers(self, self.stoppers) - - @Utils.callHooks('finish') def finish(self): """finish()